@hualinge/relay-web 1.0.0
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/LICENSE +21 -0
- package/README.md +31 -0
- package/dist/assets/AgentsPage-2u2kFBCH.js +68 -0
- package/dist/assets/AgentsPage-2u2kFBCH.js.map +1 -0
- package/dist/assets/AgentsPage-BGbbVmeL.css +1 -0
- package/dist/assets/Alert-D88Fk6to.js +2 -0
- package/dist/assets/Alert-D88Fk6to.js.map +1 -0
- package/dist/assets/AppModal-BYZTSuch.js +2 -0
- package/dist/assets/AppModal-BYZTSuch.js.map +1 -0
- package/dist/assets/CenteredLoadingState-DHor-9vF.js +2 -0
- package/dist/assets/CenteredLoadingState-DHor-9vF.js.map +1 -0
- package/dist/assets/ChannelsPage-CbI0kqkd.js +2 -0
- package/dist/assets/ChannelsPage-CbI0kqkd.js.map +1 -0
- package/dist/assets/EmptyDataState-6mNx2Xhl.js +2 -0
- package/dist/assets/EmptyDataState-6mNx2Xhl.js.map +1 -0
- package/dist/assets/HelpPrompt-BPzDcC8F.js +2 -0
- package/dist/assets/HelpPrompt-BPzDcC8F.js.map +1 -0
- package/dist/assets/HomePage-t78sDDUj.js +2 -0
- package/dist/assets/HomePage-t78sDDUj.js.map +1 -0
- package/dist/assets/InspirationPage-BTqLpcHY.js +3 -0
- package/dist/assets/InspirationPage-BTqLpcHY.js.map +1 -0
- package/dist/assets/ModelsPage-YF0gpUxy.js +2 -0
- package/dist/assets/ModelsPage-YF0gpUxy.js.map +1 -0
- package/dist/assets/NameInitialIcon-DP-6_HQY.js +7 -0
- package/dist/assets/NameInitialIcon-DP-6_HQY.js.map +1 -0
- package/dist/assets/NoSearchResultsState-BiiYdZ_Z.js +2 -0
- package/dist/assets/NoSearchResultsState-BiiYdZ_Z.js.map +1 -0
- package/dist/assets/OverflowTooltip-CE5PjAb-.js +2 -0
- package/dist/assets/OverflowTooltip-CE5PjAb-.js.map +1 -0
- package/dist/assets/PasswordField-DmzjtnCg.js +2 -0
- package/dist/assets/PasswordField-DmzjtnCg.js.map +1 -0
- package/dist/assets/RefreshButton-BzYzeo5A.js +2 -0
- package/dist/assets/RefreshButton-BzYzeo5A.js.map +1 -0
- package/dist/assets/RightContentHeader-DoNDQ9Lo.js +3 -0
- package/dist/assets/RightContentHeader-DoNDQ9Lo.js.map +1 -0
- package/dist/assets/SchedulePage-CfW6lZVI.js +2 -0
- package/dist/assets/SchedulePage-CfW6lZVI.js.map +1 -0
- package/dist/assets/SearchInput-tux8xXH1.js +2 -0
- package/dist/assets/SearchInput-tux8xXH1.js.map +1 -0
- package/dist/assets/SkillAvatar-DwGvsY4f.js +2 -0
- package/dist/assets/SkillAvatar-DwGvsY4f.js.map +1 -0
- package/dist/assets/SkillsPage-ppqwKMvj.js +2 -0
- package/dist/assets/SkillsPage-ppqwKMvj.js.map +1 -0
- package/dist/assets/SkillsTab-c_As1DIr.css +1 -0
- package/dist/assets/SkillsTab-kY7MNdxy.js +2 -0
- package/dist/assets/SkillsTab-kY7MNdxy.js.map +1 -0
- package/dist/assets/Tab-FE0F2EQP.js +2 -0
- package/dist/assets/Tab-FE0F2EQP.js.map +1 -0
- package/dist/assets/ThreadPage-B0jElW5R.js +53 -0
- package/dist/assets/ThreadPage-B0jElW5R.js.map +1 -0
- package/dist/assets/UploadSkillModal-DHZL12vm.js +8 -0
- package/dist/assets/UploadSkillModal-DHZL12vm.js.map +1 -0
- package/dist/assets/XlsxDocumentPreview-BY-ht09K.js +5 -0
- package/dist/assets/XlsxDocumentPreview-BY-ht09K.js.map +1 -0
- package/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js +2 -0
- package/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js.map +1 -0
- package/dist/assets/chat-input-options-CpkOtPgQ.js +2 -0
- package/dist/assets/chat-input-options-CpkOtPgQ.js.map +1 -0
- package/dist/assets/docx-preview-zfB-orwa.js +28 -0
- package/dist/assets/docx-preview-zfB-orwa.js.map +1 -0
- package/dist/assets/exceljs.min-BY7KKJsM.js +58 -0
- package/dist/assets/exceljs.min-BY7KKJsM.js.map +1 -0
- package/dist/assets/helpers-CCilgpNy.js +2 -0
- package/dist/assets/helpers-CCilgpNy.js.map +1 -0
- package/dist/assets/hub-agent-editor.client-2DmCRGuY.js +2 -0
- package/dist/assets/hub-agent-editor.client-2DmCRGuY.js.map +1 -0
- package/dist/assets/hub-agent-editor.payload-D4sgJRSH.js +4 -0
- package/dist/assets/hub-agent-editor.payload-D4sgJRSH.js.map +1 -0
- package/dist/assets/hub-tag-editor-BBdd-aHK.js +2 -0
- package/dist/assets/hub-tag-editor-BBdd-aHK.js.map +1 -0
- package/dist/assets/index-Bed0I5IL.css +1 -0
- package/dist/assets/index-Bxf2_cvh.js +2 -0
- package/dist/assets/index-Bxf2_cvh.js.map +1 -0
- package/dist/assets/index-Cb4fQgom.js +103 -0
- package/dist/assets/index-Cb4fQgom.js.map +1 -0
- package/dist/assets/index-DQ2vVjmV.js +30 -0
- package/dist/assets/index-DQ2vVjmV.js.map +1 -0
- package/dist/assets/index-UBJEdbMO.js +2 -0
- package/dist/assets/index-UBJEdbMO.js.map +1 -0
- package/dist/assets/jszip.min-DPdj3o0t.js +13 -0
- package/dist/assets/jszip.min-DPdj3o0t.js.map +1 -0
- package/dist/assets/quick-actions-DzZE-zyP.js +2 -0
- package/dist/assets/quick-actions-DzZE-zyP.js.map +1 -0
- package/dist/assets/skill-options-cache-D1BJGTCU.js +2 -0
- package/dist/assets/skill-options-cache-D1BJGTCU.js.map +1 -0
- package/dist/assets/status-helpers-BILdm2MI.js +2 -0
- package/dist/assets/status-helpers-BILdm2MI.js.map +1 -0
- package/dist/assets/thread-title-Cerb2mHa.js +2 -0
- package/dist/assets/thread-title-Cerb2mHa.js.map +1 -0
- package/dist/assets/thread-utils-Ct3yp4R3.js +2 -0
- package/dist/assets/thread-utils-Ct3yp4R3.js.map +1 -0
- package/dist/assets/useAgentData-D-k9cXfg.js +2 -0
- package/dist/assets/useAgentData-D-k9cXfg.js.map +1 -0
- package/dist/assets/useEscapeKey-CEQ6-8GR.js +2 -0
- package/dist/assets/useEscapeKey-CEQ6-8GR.js.map +1 -0
- package/dist/assets/useExpertCatalog-BZdw1CYs.js +2 -0
- package/dist/assets/useExpertCatalog-BZdw1CYs.js.map +1 -0
- package/dist/assets/usePromptBlocks-5sz8Qh51.js +2 -0
- package/dist/assets/usePromptBlocks-5sz8Qh51.js.map +1 -0
- package/dist/assets/useSocket-YigidotN.css +1 -0
- package/dist/assets/useSocket-y3-zWhVL.js +11 -0
- package/dist/assets/useSocket-y3-zWhVL.js.map +1 -0
- package/dist/assets/utils--_pbLpCq.js +2 -0
- package/dist/assets/utils--_pbLpCq.js.map +1 -0
- package/dist/assets/vad-web-C_R267y1.js +2 -0
- package/dist/assets/vad-web-C_R267y1.js.map +1 -0
- package/dist/avatars/agent-avatar-1.png +0 -0
- package/dist/avatars/agent-avatar-2.png +0 -0
- package/dist/avatars/agent-avatar-3.png +0 -0
- package/dist/avatars/agent-avatar-4.png +0 -0
- package/dist/avatars/agent-avatar-5.png +0 -0
- package/dist/avatars/agent-avatar-6.png +0 -0
- package/dist/avatars/agent-avatar-7.png +0 -0
- package/dist/avatars/agent-avatar-8.png +0 -0
- package/dist/avatars/agent-avatar-9.png +0 -0
- package/dist/avatars/agentteams.png +0 -0
- package/dist/avatars/antig-opus.png +0 -0
- package/dist/avatars/antigravity.png +0 -0
- package/dist/avatars/assistant.svg +17 -0
- package/dist/avatars/codex-kawaii.png +0 -0
- package/dist/avatars/codex.png +0 -0
- package/dist/avatars/codex_box.png +0 -0
- package/dist/avatars/codex_iquid.png +0 -0
- package/dist/avatars/dare.png +0 -0
- package/dist/avatars/gemini-kawaii.png +0 -0
- package/dist/avatars/gemini.png +0 -0
- package/dist/avatars/gemini25.png +0 -0
- package/dist/avatars/gpt52.png +0 -0
- package/dist/avatars/jiuwenclaw.png +0 -0
- package/dist/avatars/office.svg +17 -0
- package/dist/avatars/opencode.png +0 -0
- package/dist/avatars/opus-45.png +0 -0
- package/dist/avatars/opus-kawaii.png +0 -0
- package/dist/avatars/opus.png +0 -0
- package/dist/avatars/sonnet.png +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/icons/arrow-left.svg +3 -0
- package/dist/icons/arrow-right.svg +3 -0
- package/dist/icons/attach.svg +9 -0
- package/dist/icons/chart/dislike.svg +3 -0
- package/dist/icons/chart/disliked.svg +3 -0
- package/dist/icons/chart/folder.svg +15 -0
- package/dist/icons/chart/home-loading.webp +0 -0
- package/dist/icons/chart/like.svg +3 -0
- package/dist/icons/chart/liked.svg +5 -0
- package/dist/icons/chart/loading.svg +26 -0
- package/dist/icons/chart/success.svg +7 -0
- package/dist/icons/check-line.svg +3 -0
- package/dist/icons/chevron-left.svg +3 -0
- package/dist/icons/chevron-right.svg +3 -0
- package/dist/icons/collapse.svg +14 -0
- package/dist/icons/common-delete.svg +4 -0
- package/dist/icons/common-folder.svg +4 -0
- package/dist/icons/copy.svg +4 -0
- package/dist/icons/cross-line.svg +4 -0
- package/dist/icons/data-analysis.svg +7 -0
- package/dist/icons/data-visualization.svg +10 -0
- package/dist/icons/deep-research.svg +4 -0
- package/dist/icons/document-processing.svg +5 -0
- package/dist/icons/edit.svg +4 -0
- package/dist/icons/expand.svg +6 -0
- package/dist/icons/expert-debate.svg +4 -0
- package/dist/icons/eye.svg +4 -0
- package/dist/icons/favicon.svg +7 -0
- package/dist/icons/file-docx.svg +60 -0
- package/dist/icons/file-folder.svg +4 -0
- package/dist/icons/file-gitignore.svg +35 -0
- package/dist/icons/file-html.svg +6 -0
- package/dist/icons/file-ini.svg +63 -0
- package/dist/icons/file-json.svg +4 -0
- package/dist/icons/file-md.svg +68 -0
- package/dist/icons/file-py.svg +4 -0
- package/dist/icons/file-sh.svg +7 -0
- package/dist/icons/file-txt.svg +37 -0
- package/dist/icons/file-zip.svg +21 -0
- package/dist/icons/file.svg +4 -0
- package/dist/icons/files-csv.svg +14 -0
- package/dist/icons/files-docx.svg +10 -0
- package/dist/icons/files-pdf.svg +14 -0
- package/dist/icons/files-ppt.svg +14 -0
- package/dist/icons/files-txt.svg +16 -0
- package/dist/icons/files-xlsx.svg +14 -0
- package/dist/icons/financial-services.svg +8 -0
- package/dist/icons/flie-html.svg +60 -0
- package/dist/icons/guided-mode.svg +9 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-arrow-down.svg +4 -0
- package/dist/icons/icon-arrow-up.svg +4 -0
- package/dist/icons/icon-clear-all.svg +3 -0
- package/dist/icons/icon-close.svg +4 -0
- package/dist/icons/icon-code.svg +38 -0
- package/dist/icons/icon-drag-file.svg +26 -0
- package/dist/icons/icon-help.svg +4 -0
- package/dist/icons/icon-md.svg +53 -0
- package/dist/icons/icon-refresh.svg +4 -0
- package/dist/icons/icon-toggle.svg +6 -0
- package/dist/icons/icon-top.svg +7 -0
- package/dist/icons/icon-upload.svg +5 -0
- package/dist/icons/information.svg +6 -0
- package/dist/icons/inspiration/icon-excel.svg +14 -0
- package/dist/icons/inspiration/icon-inspiration.svg +5 -0
- package/dist/icons/inspiration/icon-markdown.svg +12 -0
- package/dist/icons/inspiration/icon-word.svg +10 -0
- package/dist/icons/link.svg +6 -0
- package/dist/icons/lock.svg +4 -0
- package/dist/icons/menu/agents.svg +39 -0
- package/dist/icons/menu/channels.svg +4 -0
- package/dist/icons/menu/icon-inspiration.svg +5 -0
- package/dist/icons/menu/models.svg +4 -0
- package/dist/icons/menu/new-chat.svg +59 -0
- package/dist/icons/menu/schedule.svg +4 -0
- package/dist/icons/menu/skills.svg +4 -0
- package/dist/icons/message-error.svg +6 -0
- package/dist/icons/message-prompt.svg +9 -0
- package/dist/icons/message-success.svg +6 -0
- package/dist/icons/message-warn.svg +8 -0
- package/dist/icons/more-trigger.svg +4 -0
- package/dist/icons/nss/1.svg +14 -0
- package/dist/icons/nss/2.svg +14 -0
- package/dist/icons/nss/3.svg +14 -0
- package/dist/icons/outline.svg +6 -0
- package/dist/icons/query_the_optical_power_border.svg +99 -0
- package/dist/icons/schedule.svg +4 -0
- package/dist/icons/settings-feedback/feedback-bug.svg +20 -0
- package/dist/icons/settings-feedback/feedback-file.svg +4 -0
- package/dist/icons/settings-feedback/feedback-idea.svg +14 -0
- package/dist/icons/settings-feedback/settings-gear.svg +4 -0
- package/dist/icons/settings-feedback/settings-link.svg +4 -0
- package/dist/icons/settings-feedback/settings-memory.svg +7 -0
- package/dist/icons/settings-feedback/settings-privacy.svg +37 -0
- package/dist/icons/settings-feedback/settings-search.svg +2 -0
- package/dist/icons/slides.svg +4 -0
- package/dist/icons/status/info-error.svg +9 -0
- package/dist/icons/style-template.svg +11 -0
- package/dist/icons/tool-error.svg +4 -0
- package/dist/icons/userprofile/help.svg +5 -0
- package/dist/icons/userprofile/keep-awake.svg +4 -0
- package/dist/icons/userprofile/question.svg +4 -0
- package/dist/icons/userprofile/security.svg +7 -0
- package/dist/icons/userprofile/style-template.svg +11 -0
- package/dist/icons/userprofile/theme.svg +14 -0
- package/dist/icons/userprofile/usage.svg +4 -0
- package/dist/icons/userprofile/version.svg +85 -0
- package/dist/icons/video-generation.svg +4 -0
- package/dist/images/OfficeClaw.svg +21 -0
- package/dist/images/add.svg +4 -0
- package/dist/images/agent-management-icons/agent-check.svg +23 -0
- package/dist/images/agent-management-icons/agent-close.svg +4 -0
- package/dist/images/agent-management-icons/agent-collab.svg +4 -0
- package/dist/images/agent-management-icons/agent-delete.svg +18 -0
- package/dist/images/agent-management-icons/agent-edit.svg +18 -0
- package/dist/images/agent-management-icons/agent-more.svg +4 -0
- package/dist/images/agent-management-icons/agent-persona.svg +4 -0
- package/dist/images/agent-management-icons/agent-random-avatar.svg +39 -0
- package/dist/images/agent-management-icons/agent-refresh.svg +4 -0
- package/dist/images/agent-management-icons/agent-skills.svg +4 -0
- package/dist/images/agent-management-icons/agent-template.svg +12 -0
- package/dist/images/agent-management-icons/anchor-current.svg +5 -0
- package/dist/images/agent-management-icons/anchor-other.svg +4 -0
- package/dist/images/chat-empty-agent.svg +12 -0
- package/dist/images/chat-empty-im.svg +14 -0
- package/dist/images/connectors/dingtalk.png +0 -0
- package/dist/images/connectors/dingtalk.svg +18 -0
- package/dist/images/connectors/feishu.png +0 -0
- package/dist/images/connectors/feishu.svg +12 -0
- package/dist/images/connectors/imessage.png +0 -0
- package/dist/images/connectors/wecom-agent.png +0 -0
- package/dist/images/connectors/wecom-bot.png +0 -0
- package/dist/images/connectors/weixin.png +0 -0
- package/dist/images/connectors/weixin.svg +19 -0
- package/dist/images/connectors/xiaoyi.png +0 -0
- package/dist/images/connectors/xiaoyi.svg +12 -0
- package/dist/images/create-agent-random-avatar.svg +39 -0
- package/dist/images/deepseek.svg +1 -0
- package/dist/images/default-ppt-template.png +0 -0
- package/dist/images/file-browser-tree/code.svg +60 -0
- package/dist/images/file-browser-tree/gitignore.svg +35 -0
- package/dist/images/file-browser-tree/image.svg +12 -0
- package/dist/images/file-browser-tree/markdown.svg +68 -0
- package/dist/images/file-browser-tree/pdf.svg +4 -0
- package/dist/images/file-browser-tree/ppt.svg +4 -0
- package/dist/images/file-browser-tree/public-file.svg +37 -0
- package/dist/images/file-browser-tree/word.svg +60 -0
- package/dist/images/file-browser-tree/xlsx.svg +4 -0
- package/dist/images/html-preview-toolbar/copy.svg +4 -0
- package/dist/images/html-preview-toolbar/open-external.svg +4 -0
- package/dist/images/html-preview-toolbar/refresh.svg +4 -0
- package/dist/images/information.svg +4 -0
- package/dist/images/inspiration/blue-bg.png +0 -0
- package/dist/images/inspiration/doc-example.png +0 -0
- package/dist/images/inspiration/excel-example.png +0 -0
- package/dist/images/inspiration/green-bg.png +0 -0
- package/dist/images/inspiration/markdown-example.png +0 -0
- package/dist/images/inspiration/orange-bg.png +0 -0
- package/dist/images/inspiration/purple-bg.png +0 -0
- package/dist/images/inspiration/task-bg.png +0 -0
- package/dist/images/inspiration-bg.png +0 -0
- package/dist/images/inspiration-products/default.svg +11 -0
- package/dist/images/invitation-background-4x.png +0 -0
- package/dist/images/kimi.svg +1 -0
- package/dist/images/link-blue.svg +4 -0
- package/dist/images/link.svg +4 -0
- package/dist/images/lobster.svg +118 -0
- package/dist/images/login1.svg +93 -0
- package/dist/images/login2.svg +80 -0
- package/dist/images/login3.svg +44 -0
- package/dist/images/login4.svg +18 -0
- package/dist/images/mode-default-icon.svg +22 -0
- package/dist/images/no-data.svg +26 -0
- package/dist/images/no-search-results.svg +25 -0
- package/dist/images/ppt-preview/placeholder-main.webp +0 -0
- package/dist/images/ppt-preview/placeholder-thumb.webp +0 -0
- package/dist/images/ppt-template/dark-tech.png +0 -0
- package/dist/images/ppt-template/huawei.png +0 -0
- package/dist/images/ppt-template/light-tech.png +0 -0
- package/dist/images/ppt-template/paper-humanities.png +0 -0
- package/dist/images/ppt-template/template-default.png +0 -0
- package/dist/images/ppt-template/template-error.png +0 -0
- package/dist/images/ppt-template/template-generate-bg.svg +9639 -0
- package/dist/images/qwen.svg +1 -0
- package/dist/images/task-list/empty-state.svg +4 -0
- package/dist/images/task-list.svg +1 -0
- package/dist/images/vendor.svg +4 -0
- package/dist/images/version-bg.svg +85 -0
- package/dist/images/version.svg +9 -0
- package/dist/images/zhipu.svg +1 -0
- package/dist/index.html +74 -0
- package/dist/loading-point-style.webp +0 -0
- package/dist/loading-small.webp +0 -0
- package/dist/manifest.json +25 -0
- package/package.json +126 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Bxf2_cvh.js","sources":["../../../shared/src/types/session.ts","../../src/components/thread-sidebar/AgentSelector.tsx","../../src/components/thread-sidebar/DirectoryBrowser.tsx","../../src/components/thread-sidebar/active-workspace.ts","../../src/components/thread-sidebar/DirectoryPickerModal.tsx","../../src/components/thread-sidebar/SectionGroup.tsx","../../src/utils/thread-export.ts","../../src/components/thread-sidebar/ThreadItem.tsx","../../src/hooks/usePreventSleep.ts","../../src/components/icons/SettingsFeedbackIcons.tsx","../../src/components/FeedbackModal.tsx","../../src/services/usageStats.ts","../../src/components/UsageStatsModal.tsx","../../src/hooks/useDesktopCloseActionSetting.ts","../../src/components/DesktopCloseActionSetting.tsx","../../src/constants/userThemeOptions.ts","../../src/components/UserThemePicker.tsx","../../src/components/GeneralSettingsTab.tsx","../../src/stores/downloadStore.ts","../../src/components/VersionUpdatePanel.tsx","../../src/components/search-engine-config/components/SearchEngineCard.tsx","../../src/components/search-engine-config/components/SearchEngineEditView.tsx","../../src/components/search-engine-config/search-engine-config.types.ts","../../src/components/search-engine-config/hooks/useSearchEngineConfig.ts","../../src/components/search-engine-config/SearchEngineConfig.tsx","../../src/components/UserSettingsModal.tsx","../../src/components/UserProfile.tsx","../../src/components/thread-sidebar/WechatGroupInvite.tsx","../../src/components/thread-sidebar/ThreadSidebarFooter.tsx","../../src/components/thread-sidebar/ThreadSidebarDeleteDialog.tsx","../../src/components/thread-sidebar/thread-sidebar-constants.ts","../../src/components/thread-sidebar/thread-sidebar-utils.ts","../../src/components/thread-sidebar/ThreadSidebarView.tsx","../../src/components/thread-sidebar/toggle-with-reconcile.ts","../../src/components/thread-sidebar/useThreadSidebarActions.ts","../../src/components/thread-sidebar/collapse-state.ts","../../src/components/thread-sidebar/useCollapseState.ts","../../src/components/thread-sidebar/useProjectPins.ts","../../src/components/thread-sidebar/useThreadSidebarData.ts","../../src/components/thread-sidebar/useThreadSidebarLayout.ts","../../src/components/thread-sidebar/useThreadSidebarController.ts","../../src/components/thread-sidebar/ThreadSidebar.tsx"],"sourcesContent":["/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n/**\n * Session Chain Types\n * F24: Thread → N Sessions per agent, with context health tracking.\n *\n * Session lifecycle: active → sealing → sealed\n * - active: currently in use (one per agent per thread)\n * - sealing: writing transcript + generating digest (Phase B)\n * - sealed: immutable snapshot, readable by sub-agents (Phase C+)\n */\n\nimport type { AgentId } from './ids.js';\n\nexport type SessionStatus = 'active' | 'sealing' | 'sealed';\nexport const SESSION_USAGE_TIMEZONE = 'Asia/Shanghai';\n\nconst sessionUsageDayFormatter = new Intl.DateTimeFormat('en-CA', {\n timeZone: SESSION_USAGE_TIMEZONE,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n});\n\nexport function toDateBucketAtTimezone(timestamp: number, timezone: string): string {\n const formatter =\n timezone === SESSION_USAGE_TIMEZONE\n ? sessionUsageDayFormatter\n : new Intl.DateTimeFormat('en-CA', {\n timeZone: timezone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n\n const parts = formatter.formatToParts(new Date(timestamp));\n const year = parts.find((part) => part.type === 'year')?.value;\n const month = parts.find((part) => part.type === 'month')?.value;\n const day = parts.find((part) => part.type === 'day')?.value;\n if (!year || !month || !day) {\n throw new Error(`Failed to format date bucket for timezone \"${timezone}\"`);\n }\n return `${year}-${month}-${day}`;\n}\n\nexport interface SessionRecord {\n readonly id: string;\n /** CLI-reported session ID (from session_init event) */\n cliSessionId: string;\n readonly threadId: string;\n readonly agentId: AgentId;\n readonly userId: string;\n /** Chain sequence number (0-based) */\n readonly seq: number;\n status: SessionStatus;\n /** Latest context health snapshot after last invocation */\n contextHealth?: ContextHealth;\n /** Latest token usage snapshot (persisted for frontend display after reload) */\n lastUsage?: SessionUsageSnapshot;\n /** Timestamp of the latest persisted usage snapshot */\n lastUsageAt?: number;\n /** Accumulated token usage across the whole session */\n totalUsage?: SessionUsageSnapshot;\n /** Daily usage buckets keyed by YYYY-MM-DD in SESSION_USAGE_TIMEZONE */\n usageByDay?: Record<string, SessionUsageSnapshot>;\n messageCount: number;\n /** Seal reason (Phase B) */\n sealReason?: 'threshold' | 'manual' | 'error' | (string & {});\n /** F33: Number of CLI compressions in this session (hybrid strategy) */\n compressionCount?: number;\n /** F118 AC-C6: Consecutive restore failures for overflow circuit breaker */\n consecutiveRestoreFailures?: number;\n readonly createdAt: number;\n updatedAt: number;\n sealedAt?: number;\n}\n\n/** Slim usage snapshot persisted per session (subset of full TokenUsage). */\nexport interface SessionUsageSnapshot {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n}\n\nexport interface ContextHealth {\n /** Current used tokens (= inputTokens from last invocation) */\n usedTokens: number;\n /** Total context window capacity */\n windowTokens: number;\n /** usedTokens / windowTokens (0.0 ~ 1.0) */\n fillRatio: number;\n /** exact = CLI reported; approx = hardcoded fallback */\n source: 'exact' | 'approx';\n measuredAt: number;\n}\n\nexport interface ContextHealthConfig {\n /** Warning threshold — frontend shows yellow */\n warnThreshold: number;\n /** Seal threshold — triggers auto-seal (Phase B) */\n sealThreshold: number;\n /** Extra budget per turn (tokens) to prevent single-turn overflow */\n turnBudget?: number;\n /** Safety margin above turnBudget (tokens) */\n safetyMargin?: number;\n}\n\nexport interface SealResult {\n /** Whether the seal request was accepted */\n accepted: boolean;\n /** Current status after the attempt */\n status: SessionStatus;\n /** Session ID that was sealed (if accepted) */\n sessionId?: string;\n}\n\n// ── F33: Session Strategy Configurability ──\n\n/** Session lifecycle strategy type */\nexport type SessionStrategy = 'handoff' | 'compress' | 'hybrid';\n\n/** Per-agent session lifecycle strategy configuration */\nexport interface SessionStrategyConfig {\n /** Strategy type */\n strategy: SessionStrategy;\n /** Context health thresholds */\n thresholds: {\n /** Frontend warning (yellow) fillRatio */\n warn: number;\n /** Trigger strategy action fillRatio */\n action: number;\n };\n /** handoff strategy parameters */\n handoff?: {\n /** Attempt MEMORY.md dump before seal */\n preSealMemoryDump: boolean;\n /** Bootstrap injection depth */\n bootstrapDepth: 'extractive' | 'generative';\n };\n /** compress strategy parameters */\n compress?: {\n /** Max compressions (unlimited for compress; effective for hybrid) */\n maxCompressions?: number;\n /** Track context_health after compression */\n trackPostCompression: boolean;\n };\n /** hybrid-specific parameters (Phase 1: hook-capable providers only) */\n hybrid?: {\n /** Switch to handoff after N compressions */\n maxCompressions: number;\n };\n /** Per-turn token budget */\n turnBudget?: number;\n /** Safety margin above turnBudget */\n safetyMargin?: number;\n}\n\n/** Seal reason for strategy-driven actions */\nexport type SealReason = 'threshold' | 'budget_exhausted' | 'max_compressions' | 'manual' | 'error' | (string & {});\n\n/** Strategy action returned by shouldTakeAction() */\nexport type StrategyAction =\n | { type: 'none' }\n | { type: 'warn' }\n | { type: 'seal'; reason: SealReason }\n | { type: 'allow_compress' }\n | { type: 'seal_after_compress'; reason: SealReason };\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { formatAgentName, useAgentData } from '@/hooks/useAgentData';\nimport { hexToRgba } from '@/lib/color-utils';\n\ninterface AgentSelectorProps {\n selectedAgentIds: string[];\n onSelectionChange: (ids: string[]) => void;\n}\n\n/**\n * F32-b Phase 3: Breed-grouped agent chip selector.\n * Used in thread creation (DirectoryPickerModal) and thread settings.\n */\nexport function AgentSelector({ selectedAgentIds, onSelectionChange }: AgentSelectorProps) {\n const { getAgentsByBreed } = useAgentData();\n const groups = getAgentsByBreed();\n\n const toggleAgent = (agentId: string) => {\n if (selectedAgentIds.includes(agentId)) {\n onSelectionChange(selectedAgentIds.filter((id) => id !== agentId));\n } else {\n onSelectionChange([...selectedAgentIds, agentId]);\n }\n };\n\n // Provider display name mapping\n const providerLabel = (provider: string) => {\n const map: Record<string, string> = {\n anthropic: 'Anthropic',\n openai: 'OpenAI',\n google: 'Google',\n };\n return map[provider] ?? provider;\n };\n\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs text-gray-500 font-medium\">默认智能体 (可选)</div>\n {[...groups.entries()].map(([breedId, breedAgents]) => {\n const breedName = breedAgents[0].breedDisplayName ?? breedAgents[0].displayName;\n return (\n <div key={breedId}>\n <div className=\"text-[10px] text-gray-400 mb-1\">\n {breedName}家族 · {providerLabel(breedAgents[0].provider)}\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {breedAgents.map((agent) => {\n const isSelected = selectedAgentIds.includes(agent.id);\n return (\n <button\n key={agent.id}\n type=\"button\"\n onClick={() => toggleAgent(agent.id)}\n className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs transition-colors border ${\n isSelected ? 'font-medium border-current' : 'border-gray-200 text-gray-500 hover:border-gray-400'\n }`}\n style={\n isSelected\n ? {\n color: agent.color.primary,\n backgroundColor: hexToRgba(agent.color.primary, 0.1),\n borderColor: agent.color.primary,\n }\n : undefined\n }\n >\n <span\n className=\"inline-block w-2 h-2 rounded-full flex-shrink-0\"\n style={{ backgroundColor: agent.color.primary }}\n />\n {formatAgentName(agent)}\n {!agent.variantLabel && agent.nickname ? `(${agent.nickname})` : ''}\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n/**\n * F113 Phase D: Cross-platform directory browser.\n * Replaces macOS-only osascript folder picker with a web-based solution.\n * Calls GET /api/projects/browse to list directories.\n */\nimport { useCallback, useEffect, useState } from 'react';\nimport { apiFetch } from '@/utils/api-client';\nimport { Button } from '../shared/Button';\n\ninterface BrowseEntry {\n name: string;\n path: string;\n isDirectory: boolean;\n}\n\ninterface BrowseResult {\n current: string;\n name: string;\n parent: string | null;\n homePath: string;\n drives?: BrowseEntry[];\n entries: BrowseEntry[];\n}\n\ninterface DirectoryBrowserProps {\n initialPath?: string;\n activeProjectPath?: string;\n onSelect: (path: string) => void;\n onCancel: () => void;\n}\n\ninterface BreadcrumbSegment {\n label: string;\n path: string;\n}\n\nconst MY_COMPUTER_LABEL = '\\u6211\\u7684\\u7535\\u8111';\nconst CURRENT_PROJECT_LABEL = '\\u5f53\\u524d\\u9879\\u76ee';\nconst FALLBACK_INFO_LABEL = '\\u914d\\u7f6e\\u8def\\u5f84\\u4e0d\\u53ef\\u7528\\uff0c\\u5df2\\u5207\\u6362\\u5230\\u4e3b\\u76ee\\u5f55';\nconst CANCEL_LABEL = '\\u53d6\\u6d88';\nconst CONFIRM_LABEL = '\\u786e\\u5b9a';\nconst COMPUTER_VIEW_PATH = '__my_computer__';\n\nfunction isWindowsPath(path: string): boolean {\n return /^[A-Za-z]:[\\\\/]/.test(path);\n}\n\nfunction isWindowsBrowseResult(result: BrowseResult | null): boolean {\n if (!result) return false;\n return isWindowsPath(result.current) || isWindowsPath(result.homePath) || Array.isArray(result.drives);\n}\n\nfunction pathToSegments(absPath: string, homePath: string): BreadcrumbSegment[] {\n const sep = absPath.includes('\\\\') ? '\\\\' : '/';\n\n if (isWindowsPath(absPath)) {\n const parts = absPath.split(/[/\\\\]/).filter(Boolean);\n if (parts.length === 0) return [];\n\n const driveRoot = `${parts[0]}\\\\`;\n const segments: BreadcrumbSegment[] = [{ label: parts[0], path: driveRoot }];\n let accumulated = driveRoot;\n\n for (let i = 1; i < parts.length; i++) {\n accumulated = accumulated.endsWith(sep) ? `${accumulated}${parts[i]}` : `${accumulated}${sep}${parts[i]}`;\n segments.push({ label: parts[i], path: accumulated });\n }\n\n return segments;\n }\n\n if (absPath === homePath || absPath.startsWith(homePath + sep)) {\n const segments: BreadcrumbSegment[] = [{ label: 'Home', path: '' }];\n if (absPath === homePath) return segments;\n\n const relative = absPath.slice(homePath.length + 1);\n if (!relative) return segments;\n\n const parts = relative.split(/[/\\\\]/).filter(Boolean);\n let accumulated = homePath;\n for (const part of parts) {\n accumulated += sep + part;\n segments.push({ label: part, path: accumulated });\n }\n return segments;\n }\n\n const parts = absPath.split(/[/\\\\]/).filter(Boolean);\n const segments: BreadcrumbSegment[] = [];\n\n let accumulated = absPath.startsWith('/') ? '' : parts[0] ?? '';\n const startIdx = absPath.startsWith('/') ? 0 : 1;\n for (let i = startIdx; i < parts.length; i++) {\n accumulated += sep + parts[i];\n segments.push({ label: parts[i], path: accumulated });\n }\n\n return segments;\n}\n\nexport function DirectoryBrowser({ initialPath, activeProjectPath, onSelect, onCancel }: DirectoryBrowserProps) {\n const [browseResult, setBrowseResult] = useState<BrowseResult | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [info, setInfo] = useState<string | null>(null);\n const [pathInput, setPathInput] = useState('');\n const [showComputerView, setShowComputerView] = useState(false);\n\n const fetchDirectory = useCallback(async (path?: string, fallbackOnForbidden = false) => {\n setIsLoading(true);\n setError(null);\n try {\n const url = path ? `/api/projects/browse?path=${encodeURIComponent(path)}` : '/api/projects/browse';\n const res = await apiFetch(url);\n if (!res.ok) {\n if (fallbackOnForbidden && path && res.status === 403) {\n setInfo(FALLBACK_INFO_LABEL);\n await fetchDirectory(undefined, false);\n return;\n }\n const data = await res.json();\n setError(data.error || 'Failed to browse directory');\n return;\n }\n const data: BrowseResult = await res.json();\n setBrowseResult(data);\n setPathInput(data.current);\n setShowComputerView(false);\n } catch {\n setError('Unable to connect to server');\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n useEffect(() => {\n fetchDirectory(initialPath, !!initialPath);\n }, [fetchDirectory, initialPath]);\n\n const handlePathSubmit = useCallback(() => {\n const trimmed = pathInput.trim();\n if (trimmed) fetchDirectory(trimmed);\n }, [pathInput, fetchDirectory]);\n\n const isWindowsBrowse = isWindowsBrowseResult(browseResult);\n const pathSegments = browseResult ? pathToSegments(browseResult.current, browseResult.homePath) : [];\n const breadcrumbSegments =\n browseResult && isWindowsBrowse\n ? showComputerView\n ? [{ label: MY_COMPUTER_LABEL, path: COMPUTER_VIEW_PATH }]\n : [{ label: MY_COMPUTER_LABEL, path: COMPUTER_VIEW_PATH }, ...pathSegments]\n : pathSegments;\n const listedEntries = browseResult ? (showComputerView ? (browseResult.drives ?? []) : browseResult.entries) : [];\n\n return (\n <div className=\"flex h-full min-h-0 flex-col overflow-hidden rounded-xl border border-[var(--border-default)] bg-[var(--surface-panel)]\">\n <div className=\"flex h-10 flex-shrink-0 items-center gap-1 overflow-x-auto border-b border-[var(--border-default)] bg-[var(--surface-panel)] px-5\">\n {breadcrumbSegments.map((seg, i) => (\n <span key={seg.path || `_${i}`} className=\"flex flex-shrink-0 items-center gap-1\">\n {i > 0 && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3 w-3 text-[var(--text-label-secondary)]\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n )}\n <button\n type=\"button\"\n onClick={() => {\n if (seg.path === COMPUTER_VIEW_PATH) {\n setShowComputerView(true);\n setError(null);\n return;\n }\n fetchDirectory(seg.path || undefined);\n }}\n className={`text-xs transition-colors hover:text-[var(--text-primary)] hover:underline ${\n i === breadcrumbSegments.length - 1\n ? 'font-semibold text-[var(--text-primary)]'\n : 'font-medium text-[var(--text-secondary)]'\n }`}\n >\n {i === 0 && (seg.label === 'Home' || seg.label === MY_COMPUTER_LABEL) ? (\n <span className=\"flex items-center gap-1\">\n <HomeIcon />\n {seg.label}\n </span>\n ) : (\n seg.label\n )}\n </button>\n </span>\n ))}\n </div>\n\n <div className=\"min-h-0 flex-1 space-y-0.5 overflow-y-auto px-3 py-2\">\n {isLoading && (\n <div className=\"flex items-center justify-center py-8\">\n <span className=\"animate-pulse text-xs text-[var(--text-label-secondary)]\">Loading...</span>\n </div>\n )}\n\n {info && (\n <div className=\"mb-1 px-3 py-1.5\">\n <p className=\"text-[10px] text-[var(--text-secondary)]\">{info}</p>\n </div>\n )}\n\n {error && (\n <div className=\"mb-1 px-3 py-1.5\">\n <p className=\"text-xs text-[var(--state-error-text)]\">{error}</p>\n </div>\n )}\n\n {!isLoading && browseResult && listedEntries.length === 0 && (\n <div className=\"flex items-center justify-center py-8\">\n <span className=\"text-xs text-[var(--text-label-secondary)]\">\n {showComputerView ? 'No drives' : 'No subdirectories'}\n </span>\n </div>\n )}\n\n {!isLoading &&\n listedEntries.map((entry) => {\n const isActive = !showComputerView && activeProjectPath === entry.path;\n return (\n <button\n key={entry.path}\n type=\"button\"\n onClick={() => fetchDirectory(entry.path)}\n className={`flex w-full items-center gap-2.5 rounded-lg px-3 py-2.5 text-left text-sm transition-colors ${\n isActive ? 'bg-[var(--overlay-item-hover-bg)]' : 'hover:bg-[var(--overlay-item-hover-bg)]'\n }`}\n title={entry.path}\n >\n <FolderIcon className={isActive ? 'text-[var(--text-primary)]' : 'text-[var(--text-label-secondary)]'} />\n <span className=\"flex-1 truncate font-medium text-[var(--text-primary)]\">{entry.name}</span>\n {isActive && (\n <span className=\"flex-shrink-0 text-[10px] text-[var(--text-secondary)]\">{CURRENT_PROJECT_LABEL}</span>\n )}\n <svg\n aria-hidden=\"true\"\n className=\"h-3.5 w-3.5 flex-shrink-0 text-[var(--text-label-secondary)]\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n );\n })}\n </div>\n\n <div className=\"flex-shrink-0 space-y-2 border-t border-[var(--border-default)] px-5 py-3\">\n <div className=\"flex gap-2\">\n <TerminalIcon />\n <input\n type=\"text\"\n value={pathInput}\n onChange={(event) => setPathInput(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && !event.nativeEvent.isComposing) handlePathSubmit();\n }}\n placeholder=\"Enter path...\"\n className=\"ui-input flex-1 rounded-[6px] px-3 py-2 text-sm\"\n />\n {pathInput.trim() && (\n <button\n type=\"button\"\n onClick={handlePathSubmit}\n className=\"rounded-[6px] border border-[var(--input-border)] bg-[var(--surface-panel)] px-2.5 py-2 text-[var(--text-secondary)] transition-colors hover:bg-[var(--overlay-item-hover-bg)]\"\n aria-label=\"Go to path\"\n >\n <svg aria-hidden=\"true\" className=\"h-3.5 w-3.5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n )}\n </div>\n\n <div className=\"flex items-center gap-2 pt-1\">\n {browseResult && (\n <span className=\"flex-1 truncate text-[11px] text-[var(--text-secondary)]\" title={browseResult.current}>\n {showComputerView ? MY_COMPUTER_LABEL : browseResult.current}\n </span>\n )}\n <Button variant=\"default\" onClick={onCancel}>\n {CANCEL_LABEL}\n </Button>\n <Button\n onClick={() => browseResult && !showComputerView && onSelect(browseResult.current)}\n disabled={!browseResult || showComputerView}\n >\n {CONFIRM_LABEL}\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction HomeIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n className=\"h-3.5 w-3.5 text-[var(--text-label-secondary)]\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path d=\"M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z\" />\n </svg>\n );\n}\n\nfunction FolderIcon({ className }: { className?: string }) {\n return (\n <svg\n aria-hidden=\"true\"\n className={`h-4 w-4 flex-shrink-0 ${className ?? ''}`}\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <path d=\"M1 3.5A1.5 1.5 0 012.5 2h3.879a1.5 1.5 0 011.06.44l1.122 1.12A1.5 1.5 0 009.62 4H13.5A1.5 1.5 0 0115 5.5v7a1.5 1.5 0 01-1.5 1.5h-11A1.5 1.5 0 011 12.5v-9z\" />\n </svg>\n );\n}\n\nfunction TerminalIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n className=\"mt-2.5 h-3.5 w-3.5 text-[var(--text-label-secondary)]\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M2 4.25A2.25 2.25 0 014.25 2h11.5A2.25 2.25 0 0118 4.25v11.5A2.25 2.25 0 0115.75 18H4.25A2.25 2.25 0 012 15.75V4.25zM7.664 6.23a.75.75 0 00-1.078 1.04l2.705 2.805-2.705 2.805a.75.75 0 001.078 1.04l3.25-3.37a.75.75 0 000-1.04l-3.25-3.28zM11 13a.75.75 0 000 1.5h3a.75.75 0 000-1.5h-3z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n/**\n * F095 Phase B: Active workspace logic (pure functions, no React).\n * Splits project groups into active vs archived based on recency + user pins.\n */\n\nimport type { Thread } from '@/stores/chat-types';\nimport type { StorageLike } from './collapse-state';\nimport type { ThreadGroup } from './thread-utils';\n\nexport const PROJECT_PIN_KEY = 'office-claw:sidebar:pinned-projects';\nconst LEGACY_PROJECT_PIN_KEY = 'cat-cafe:sidebar:pinned-projects';\n\n/**\n * Get the N most recently active threads (cross-project).\n * Excludes default thread and pinned threads (those have their own section).\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function getRecentThreads(threads: Thread[], limit: number, _now?: number): Thread[] {\n return threads\n .filter((t) => t.id !== 'default' && !t.pinned)\n .sort((a, b) => b.lastActiveAt - a.lastActiveAt)\n .slice(0, limit);\n}\n\n/** Get the most recent activity timestamp for a project path. Returns 0 if none. */\nexport function getProjectLatestActivity(threads: Thread[], projectPath: string): number {\n let max = 0;\n for (const t of threads) {\n if (t.projectPath === projectPath && t.lastActiveAt > max) {\n max = t.lastActiveAt;\n }\n }\n return max;\n}\n\n/**\n * Split project groups into active and archived.\n * Active = pinned OR has activity within cutoffMs of now.\n * Active sort: pinned first, then by latest activity desc.\n * Archived sort: alphabetically by projectPath.\n */\nexport function splitIntoActiveAndArchived(\n projectGroups: ThreadGroup[],\n allThreads: Thread[],\n pinnedProjects: Set<string>,\n cutoffMs: number,\n now: number = Date.now(),\n): { active: ThreadGroup[]; archived: ThreadGroup[] } {\n const active: ThreadGroup[] = [];\n const archived: ThreadGroup[] = [];\n\n for (const group of projectGroups) {\n const path = group.projectPath ?? group.label;\n const isPinned = pinnedProjects.has(path);\n const latestActivity = getProjectLatestActivity(allThreads, path);\n const isActive = isPinned || now - latestActivity <= cutoffMs;\n\n if (isActive) {\n active.push(group);\n } else {\n archived.push(group);\n }\n }\n\n // Sort active: pinned first, then by latest activity desc\n active.sort((a, b) => {\n const aPath = a.projectPath ?? a.label;\n const bPath = b.projectPath ?? b.label;\n const aPinned = pinnedProjects.has(aPath) ? 1 : 0;\n const bPinned = pinnedProjects.has(bPath) ? 1 : 0;\n if (aPinned !== bPinned) return bPinned - aPinned;\n const aActivity = getProjectLatestActivity(allThreads, aPath);\n const bActivity = getProjectLatestActivity(allThreads, bPath);\n return bActivity - aActivity;\n });\n\n // Sort archived alphabetically\n archived.sort((a, b) => {\n const aPath = a.projectPath ?? a.label;\n const bPath = b.projectPath ?? b.label;\n return aPath.localeCompare(bPath);\n });\n\n return { active, archived };\n}\n\n/** Read pinned project paths from storage. */\nexport function readPinnedProjects(storage: StorageLike): Set<string> {\n try {\n let raw = storage.getItem(PROJECT_PIN_KEY);\n if (!raw) raw = storage.getItem(LEGACY_PROJECT_PIN_KEY);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((k: unknown) => typeof k === 'string')) {\n return new Set(parsed as string[]);\n }\n }\n } catch {\n // storage unavailable or corrupted\n }\n return new Set();\n}\n\n/** Persist pinned project paths to storage. */\nexport function writePinnedProjects(projects: Set<string>, storage: StorageLike): void {\n try {\n storage.setItem(PROJECT_PIN_KEY, JSON.stringify([...projects]));\n try {\n storage.removeItem?.(LEGACY_PROJECT_PIN_KEY);\n } catch {\n /* ignore */\n }\n } catch {\n // Best effort\n }\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { formatAgentName, useAgentData } from '@/hooks/useAgentData';\nimport { apiFetch } from '@/utils/api-client';\nimport { AgentSelector } from './AgentSelector';\nimport { DirectoryBrowser } from './DirectoryBrowser';\nimport { projectDisplayName } from './thread-utils';\n\n/** F33: Session binding passed alongside thread creation */\nexport interface SessionBinding {\n agentId: string;\n cliSessionId: string;\n}\n\n/** F095 Phase C: All options collected by the new-thread modal */\nexport interface NewThreadOptions {\n projectPath?: string;\n preferredAgentIds?: string[];\n sessionBindings?: SessionBinding[];\n title?: string;\n pinned?: boolean;\n backlogItemId?: string;\n}\n\ninterface BacklogItemSummary {\n id: string;\n title: string;\n status: string;\n}\n\nexport function DirectoryPickerModal({\n existingProjects,\n onSelect,\n onCancel,\n}: {\n existingProjects: string[];\n onSelect: (opts: NewThreadOptions) => void;\n onCancel: () => void;\n}) {\n const [selectedAgentIds, setSelectedAgentIds] = useState<string[]>([]);\n const [sessionInputs, setSessionInputs] = useState<Record<string, string>>({});\n const [bindExpanded, setBindExpanded] = useState(false);\n const [cwdPath, setCwdPath] = useState<string | null>(null);\n const [defaultWorkspacePath, setDefaultWorkspacePath] = useState<string | null>(null);\n const [showBrowser, setShowBrowser] = useState(false);\n const [pathInput, setPathInput] = useState('');\n const [pathError, setPathError] = useState<string | null>(null);\n const { getAgentById } = useAgentData();\n const modalRef = useRef<HTMLDivElement>(null);\n\n // F068-R7: Two-step flow — select project first, then confirm\n // 'lobby' sentinel means user explicitly chose \"大厅 (无项目)\"\n const [selectedPath, setSelectedPath] = useState<string | 'lobby' | null>(null);\n // P2 fix: clear stale pathError whenever user selects a project\n const handleSelectPath = useCallback((path: string | 'lobby') => {\n setPathError(null);\n setSelectedPath(path);\n }, []);\n\n // F095 Phase C: new fields\n const [threadTitle, setThreadTitle] = useState('');\n const [pinOnCreate, setPinOnCreate] = useState(false);\n const [backlogItems, setBacklogItems] = useState<BacklogItemSummary[]>([]);\n const [selectedBacklogItemId, setSelectedBacklogItemId] = useState('');\n\n // Fetch active backlog items for feat dropdown\n useEffect(() => {\n (async () => {\n try {\n const res = await apiFetch('/api/backlog/items');\n if (res.ok) {\n const data = await res.json();\n const active = (data.items ?? []).filter(\n (item: BacklogItemSummary) => item.status !== 'done' && item.status !== 'cancelled',\n );\n setBacklogItems(active);\n }\n } catch {\n // ignore — backlog is optional\n }\n })();\n }, []);\n\n const selectWithOptions = useCallback(\n (projectPath: string | undefined) => {\n const bindings: SessionBinding[] = [];\n for (const [agentId, sid] of Object.entries(sessionInputs)) {\n const trimmed = sid.trim();\n if (trimmed && selectedAgentIds.includes(agentId)) {\n bindings.push({ agentId, cliSessionId: trimmed });\n }\n }\n onSelect({\n projectPath,\n preferredAgentIds: selectedAgentIds.length > 0 ? selectedAgentIds : undefined,\n sessionBindings: bindings.length > 0 ? bindings : undefined,\n title: threadTitle.trim() || undefined,\n pinned: pinOnCreate || undefined,\n backlogItemId: selectedBacklogItemId || undefined,\n });\n },\n [onSelect, selectedAgentIds, sessionInputs, threadTitle, pinOnCreate, selectedBacklogItemId],\n );\n\n // F068-R7: Confirm creation with currently selected project\n const confirmCreate = useCallback(() => {\n if (selectedPath === null) return;\n selectWithOptions(selectedPath === 'lobby' ? undefined : selectedPath);\n }, [selectedPath, selectWithOptions]);\n\n // F113: Handle directory selection from the web-based browser\n const handleBrowserSelect = useCallback(\n (path: string) => {\n handleSelectPath(path);\n setShowBrowser(false);\n },\n [handleSelectPath],\n );\n\n // F068: Submit path from text input — validate via browse endpoint before accepting\n const handlePathSubmit = useCallback(async () => {\n const trimmed = pathInput.trim();\n if (!trimmed) return;\n setPathError(null);\n try {\n const res = await apiFetch(`/api/projects/browse?path=${encodeURIComponent(trimmed)}`);\n if (!res.ok) {\n const data = await res.json();\n setPathError(data.error || '路径无效');\n return;\n }\n // Valid directory — select the canonicalized path\n const data = await res.json();\n handleSelectPath(data.current);\n } catch {\n setPathError('无法连接到服务器');\n }\n }, [pathInput, handleSelectPath]);\n\n // Fetch cwd for \"推荐\" badge\n useEffect(() => {\n (async () => {\n try {\n const res = await apiFetch('/api/projects/cwd');\n if (res.ok) {\n const data = await res.json();\n setCwdPath(typeof data?.path === 'string' ? data.path : null);\n setDefaultWorkspacePath(typeof data?.workspacePath === 'string' ? data.workspacePath : null);\n }\n } catch {\n // ignore — cwd is optional\n }\n })();\n }, []);\n\n // Escape to close\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onCancel();\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [onCancel]);\n\n const [agentsExpanded, setAgentsExpanded] = useState(false);\n const recommendedPath = defaultWorkspacePath ?? cwdPath;\n const selectionSummary = selectedAgentIds.length > 0 ? `已选 ${selectedAgentIds.length}` : '';\n\n return (\n <div\n role=\"presentation\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-medium)]\"\n >\n <div\n ref={modalRef}\n className=\"mx-4 flex max-h-[85vh] w-full max-w-[640px] flex-col overflow-hidden rounded-xl border border-[var(--modal-border)] bg-[var(--modal-surface)] shadow-[var(--modal-shadow)]\"\n >\n {/* ── Header + Title ── */}\n <div className=\"border-b border-[var(--modal-divider)] px-5 pb-3 pt-4\">\n <div className=\"flex items-center justify-between mb-3\">\n <h2 className=\"text-base font-semibold text-[var(--modal-title-text)]\">新建会话</h2>\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-md p-1 text-[var(--modal-close-icon)] transition-colors hover:bg-[var(--modal-close-hover-bg)] hover:text-[var(--modal-close-icon-hover)]\"\n >\n <svg aria-hidden=\"true\" className=\"w-5 h-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n <input\n type=\"text\"\n value={threadTitle}\n onChange={(e) => setThreadTitle(e.target.value)}\n placeholder=\"会话标题(可选)\"\n maxLength={200}\n className=\"ui-input w-full text-sm px-3 py-2 rounded-lg\"\n />\n </div>\n\n {/* ── Project list (PRIMARY ACTION — takes most space, hidden when browser is open) ── */}\n <div className={`overflow-y-auto px-5 py-3 space-y-1 ${showBrowser ? 'hidden' : 'flex-1 min-h-[180px]'}`}>\n <div className=\"text-[10px] text-[var(--modal-empty-text)] font-medium mb-1\">选择项目</div>\n\n {recommendedPath && !existingProjects.includes(recommendedPath) && (\n <button\n type=\"button\"\n onClick={() => handleSelectPath(recommendedPath)}\n className={`w-full text-left px-3 py-2.5 text-sm text-[var(--modal-text)] hover:bg-[var(--modal-selected-surface)] rounded-lg transition-colors flex items-center gap-2 ${selectedPath === recommendedPath ? 'border border-[var(--modal-selected-border)] bg-[var(--modal-selected-surface)]' : 'border border-[var(--modal-selected-border)] bg-[var(--modal-muted-surface)]'}`}\n title={recommendedPath}\n >\n <FolderIcon />\n <div className=\"min-w-0 flex-1\">\n <span className=\"font-medium block truncate\">{projectDisplayName(recommendedPath)}</span>\n <span className=\"text-[10px] text-[var(--modal-empty-text)] block truncate\">{recommendedPath}</span>\n </div>\n <span className=\"text-[10px] text-[var(--modal-accent-text)] flex-shrink-0\">推荐</span>\n </button>\n )}\n\n {existingProjects.map((path) => (\n <button\n type=\"button\"\n key={path}\n onClick={() => handleSelectPath(path)}\n className={`w-full text-left px-3 py-2.5 text-sm text-[var(--modal-text)] hover:bg-[var(--modal-selected-surface)] rounded-lg transition-colors flex items-center gap-2 ${selectedPath === path ? 'border border-[var(--modal-selected-border)] bg-[var(--modal-selected-surface)]' : ''}`}\n title={path}\n >\n <FolderIcon />\n <div className=\"min-w-0 flex-1\">\n <span className=\"font-medium block truncate\">{projectDisplayName(path)}</span>\n <span className=\"text-[10px] text-[var(--modal-empty-text)] block truncate\">{path}</span>\n </div>\n </button>\n ))}\n\n <button\n type=\"button\"\n onClick={() => handleSelectPath('lobby')}\n className={`w-full text-left px-3 py-2.5 text-sm text-[var(--modal-text-muted)] hover:bg-[var(--modal-selected-surface)] rounded-lg transition-colors flex items-center gap-2 ${selectedPath === 'lobby' ? 'border border-[var(--modal-selected-border)] bg-[var(--modal-selected-surface)]' : ''}`}\n >\n <span className=\"text-base\">🏠</span>\n <span>大厅 (无项目)</span>\n </button>\n </div>\n\n {/* ── Options bar: feat + pin + cats toggle (hidden when browser is open) ── */}\n <div\n className={`px-5 py-2 border-t border-[var(--modal-divider)] flex items-center gap-3 flex-wrap ${showBrowser ? 'hidden' : ''}`}\n >\n {backlogItems.length > 0 && (\n <div className=\"flex-1 min-w-[140px]\">\n <select\n value={selectedBacklogItemId}\n onChange={(e) => setSelectedBacklogItemId(e.target.value)}\n className=\"w-full text-xs px-2 py-1.5 rounded border border-[var(--modal-muted-border)] bg-[var(--modal-surface)] focus:outline-none focus:ring-1 focus:ring-[var(--border-accent)] text-[var(--modal-text-muted)]\"\n >\n <option value=\"\">关联 Feature(可选)</option>\n {backlogItems.map((item) => (\n <option key={item.id} value={item.id}>\n {item.title}\n </option>\n ))}\n </select>\n </div>\n )}\n <label className=\"flex items-center gap-1.5 text-xs text-[var(--modal-text-muted)] cursor-pointer flex-shrink-0\">\n <input\n type=\"checkbox\"\n checked={pinOnCreate}\n onChange={(e) => setPinOnCreate(e.target.checked)}\n className=\"rounded border-[var(--modal-muted-border)] text-[var(--modal-accent-text)] focus:ring-[var(--border-accent)]\"\n />\n <span>创建后置顶</span>\n </label>\n <button\n type=\"button\"\n onClick={() => setAgentsExpanded((v) => !v)}\n className=\"flex items-center gap-1 text-xs text-[var(--modal-text-muted)] hover:text-[var(--modal-text)] transition-colors ml-auto\"\n >\n <span>{agentsExpanded ? '收起列表' : '选智能体'}</span>\n {selectionSummary && <span className=\"text-[var(--modal-accent-text)]\">({selectionSummary})</span>}\n <svg\n aria-hidden=\"true\"\n className={`w-3 h-3 transition-transform ${agentsExpanded ? 'rotate-180' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n\n {/* ── Cat selector (collapsed by default, hidden when browser is open) ── */}\n {agentsExpanded && !showBrowser && (\n <div className=\"px-5 py-2 border-t border-[var(--modal-divider)]\">\n <AgentSelector selectedAgentIds={selectedAgentIds} onSelectionChange={setSelectedAgentIds} />\n {/* F33: Session binding */}\n {selectedAgentIds.length > 0 && (\n <div className=\"mt-2\">\n <button\n type=\"button\"\n onClick={() => setBindExpanded((v) => !v)}\n className=\"w-full text-xs text-[var(--modal-text-muted)] hover:text-[var(--modal-text)] flex items-center justify-between transition-colors py-1\"\n >\n <span>绑定外部 Session (可选)</span>\n <svg\n aria-hidden=\"true\"\n className={`w-3.5 h-3.5 transition-transform ${bindExpanded ? 'rotate-180' : ''}`}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n {bindExpanded && (\n <div className=\"mt-1.5 space-y-2\">\n <p className=\"text-[10px] text-[var(--modal-empty-text)]\">粘贴 Claude Code / Codex 的 Session ID,创建后自动绑定</p>\n {selectedAgentIds.map((agentId) => {\n const agent = getAgentById(agentId);\n const label = agent ? formatAgentName(agent) : agentId;\n return (\n <div key={agentId} className=\"flex items-center gap-2\">\n <span className=\"text-[11px] text-[var(--modal-text-muted)] w-16 truncate flex-shrink-0\" title={label}>\n {label}\n </span>\n <input\n value={sessionInputs[agentId] ?? ''}\n onChange={(e) => setSessionInputs((prev) => ({ ...prev, [agentId]: e.target.value }))}\n placeholder=\"CLI Session ID\"\n maxLength={500}\n className=\"ui-input ui-input-soft flex-1 text-[11px] font-mono px-2 py-1 rounded\"\n />\n </div>\n );\n })}\n </div>\n )}\n </div>\n )}\n </div>\n )}\n\n {/* ── F113: Inline directory browser (replaces osascript picker) ── */}\n {showBrowser && (\n <div className=\"border-t border-[var(--modal-divider)] flex-1 min-h-0 flex flex-col overflow-hidden\">\n <DirectoryBrowser\n initialPath={\n selectedPath && selectedPath !== 'lobby'\n ? selectedPath\n : defaultWorkspacePath ?? cwdPath ?? undefined\n }\n activeProjectPath={\n selectedPath && selectedPath !== 'lobby'\n ? selectedPath\n : defaultWorkspacePath ?? undefined\n }\n onSelect={handleBrowserSelect}\n onCancel={() => setShowBrowser(false)}\n />\n </div>\n )}\n\n {/* ── Bottom: browse button + path input + confirm ── */}\n <div className=\"px-5 py-3 border-t border-[var(--modal-divider)] space-y-2 flex-shrink-0\">\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => setShowBrowser((v) => !v)}\n className={`flex items-center justify-center gap-1.5 px-4 py-2 rounded-lg text-xs font-medium transition-colors ${\n showBrowser ? 'bg-[var(--button-primary-bg)] text-[var(--button-primary-text)]' : 'bg-[var(--modal-button-muted-bg)] hover:bg-[var(--modal-button-muted-bg-hover)] text-[var(--modal-text)]'\n }`}\n >\n <FolderOpenIcon />\n <span>{showBrowser ? '收起浏览' : '浏览文件夹...'}</span>\n </button>\n <input\n type=\"text\"\n value={pathInput}\n onChange={(e) => setPathInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.nativeEvent.isComposing) handlePathSubmit();\n }}\n placeholder=\"或输入路径...\"\n className=\"ui-input flex-1 text-xs px-3 py-2 rounded-lg\"\n />\n {pathInput.trim() && (\n <button\n type=\"button\"\n onClick={handlePathSubmit}\n className=\"px-2.5 py-2 rounded-lg bg-[var(--modal-button-muted-bg)] text-[var(--modal-text)] hover:bg-[var(--modal-button-muted-bg-hover)] transition-colors\"\n aria-label=\"跳转到路径\"\n >\n <svg aria-hidden=\"true\" className=\"w-3.5 h-3.5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </button>\n )}\n </div>\n {pathError && <p className=\"text-[10px] text-[var(--modal-danger-text)]\">{pathError}</p>}\n {/* F068-R7: Selected path hint + confirm button */}\n <div className=\"flex items-center gap-2 pt-1\">\n {selectedPath && (\n <span\n className={`truncate flex-1 ${\n showBrowser\n ? 'text-xs font-medium text-[var(--modal-accent-text)] bg-[var(--modal-selected-surface)] px-2 py-1 rounded-md'\n : 'text-[11px] text-[var(--modal-text-muted)]'\n }`}\n title={selectedPath === 'lobby' ? '大厅' : selectedPath}\n >\n 已选:{selectedPath === 'lobby' ? '大厅 (无项目)' : projectDisplayName(selectedPath)}\n </span>\n )}\n <button\n type=\"button\"\n onClick={confirmCreate}\n disabled={selectedPath === null}\n className=\"ml-auto px-5 py-2 rounded-lg bg-[var(--button-primary-bg)] hover:bg-[var(--button-primary-bg-hover)] text-[var(--button-primary-text)] text-sm font-medium transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n 创建会话\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction FolderIcon({ className }: { className?: string }) {\n return (\n <svg\n aria-hidden=\"true\"\n className={`w-4 h-4 flex-shrink-0 ${className ?? ''}`}\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <path d=\"M1 3.5A1.5 1.5 0 012.5 2h3.879a1.5 1.5 0 011.06.44l1.122 1.12A1.5 1.5 0 009.62 4H13.5A1.5 1.5 0 0115 5.5v7a1.5 1.5 0 01-1.5 1.5h-11A1.5 1.5 0 011 12.5v-9z\" />\n </svg>\n );\n}\n\nfunction FolderOpenIcon() {\n return (\n <svg aria-hidden=\"true\" className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z\" />\n <path fillRule=\"evenodd\" d=\"M2 8h16v4a2 2 0 01-2 2H4a2 2 0 01-2-2V8z\" clipRule=\"evenodd\" opacity=\"0.4\" />\n </svg>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport React from 'react';\n\n/** F070: governance status dot colors */\nconst GOV_STATUS_DOT: Record<string, { color: string; title: string }> = {\n healthy: { color: 'var(--state-success-text)', title: '治理正常' },\n stale: { color: 'var(--state-warning-text)', title: '治理过期' },\n missing: { color: 'var(--state-error-text)', title: '治理缺失' },\n 'never-synced': { color: 'var(--text-disabled)', title: '未同步治理' },\n};\n\ninterface SectionGroupProps {\n label: string;\n icon?: 'pin' | 'star' | 'clock' | 'archive';\n count: number;\n isCollapsed: boolean;\n onToggle: () => void;\n hideToggle?: boolean;\n hideCount?: boolean;\n projectPath?: string;\n governanceStatus?: string;\n onToggleProjectPin?: () => void;\n isProjectPinned?: boolean;\n children: React.ReactNode;\n}\n\n/** Collapsible section group for pinned / favorites / project threads. */\nexport function SectionGroup({\n label,\n icon,\n count,\n isCollapsed,\n onToggle,\n hideToggle,\n hideCount,\n projectPath,\n governanceStatus,\n onToggleProjectPin,\n isProjectPinned,\n children,\n}: SectionGroupProps) {\n return (\n <div className=\"mt-0\">\n <button\n type=\"button\"\n onClick={onToggle}\n className={`flex w-full items-center gap-1.5 px-4 py-1.5 text-left transition-colors ${\n hideToggle ? 'cursor-default' : 'hover:bg-[var(--overlay-item-hover-bg)]'\n }`}\n title={projectPath && projectPath !== 'default' ? projectPath : undefined}\n >\n {!hideToggle && (\n <svg\n aria-hidden=\"true\"\n className={`h-3 w-3 flex-shrink-0 text-[var(--text-label-secondary)] transition-transform ${\n isCollapsed ? '' : 'rotate-90'\n }`}\n viewBox=\"0 0 12 12\"\n fill=\"currentColor\"\n >\n <path d=\"M4 2l4 4-4 4V2z\" />\n </svg>\n )}\n {icon === 'pin' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3 w-3 flex-shrink-0 text-[var(--text-accent)]\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <path d=\"M4.456 2.013a.75.75 0 011.06-.034l6.5 6a.75.75 0 01-.034 1.06l-1.99 1.838.637 3.22a.75.75 0 01-1.196.693L6.5 12.526l-2.933 2.264a.75.75 0 01-1.196-.693l.637-3.22-1.99-1.838a.75.75 0 01-.034-1.06l5.472-5.966z\" />\n </svg>\n )}\n {icon === 'star' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3 w-3 flex-shrink-0 text-[var(--state-warning-text)]\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <path d=\"M8 1.5l2.09 4.26 4.71.68-3.41 3.32.8 4.69L8 12.26l-4.19 2.19.8-4.69L1.2 6.44l4.71-.68L8 1.5z\" />\n </svg>\n )}\n {icon === 'clock' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3 w-3 flex-shrink-0 text-[var(--text-label-secondary)]\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <path d=\"M8 1a7 7 0 110 14A7 7 0 018 1zm0 1.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM8 4a.75.75 0 01.75.75v2.69l1.78 1.78a.75.75 0 01-1.06 1.06l-2-2A.75.75 0 017.25 8V4.75A.75.75 0 018 4z\" />\n </svg>\n )}\n {icon === 'archive' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3 w-3 flex-shrink-0 text-[var(--text-label-secondary)]\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n >\n <path d=\"M1.75 2A1.75 1.75 0 000 3.75v1.5C0 5.99.84 6.73 1.91 6.95L2 7v5.25c0 .97.78 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 12.25V7l.09-.05A1.75 1.75 0 0016 5.25v-1.5A1.75 1.75 0 0014.25 2H1.75zM1.5 3.75a.25.25 0 01.25-.25h12.5a.25.25 0 01.25.25v1.5a.25.25 0 01-.25.25H1.75a.25.25 0 01-.25-.25v-1.5zM3.5 7h9v5.25a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25V7z\" />\n </svg>\n )}\n <span className=\"truncate text-xs font-medium text-[var(--text-label-secondary)]\">{label}</span>\n {(() => {\n const dot = governanceStatus ? GOV_STATUS_DOT[governanceStatus] : undefined;\n return dot ? (\n <span className=\"h-2 w-2 flex-shrink-0 rounded-full\" style={{ backgroundColor: dot.color }} title={dot.title} />\n ) : null;\n })()}\n {!hideCount && <span className=\"ml-auto flex-shrink-0 text-[10px] text-[var(--text-disabled)]\">{count}</span>}\n {onToggleProjectPin && (\n <span\n role=\"button\"\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation();\n onToggleProjectPin();\n }}\n onKeyDown={(e) => {\n if ((e.key === 'Enter' || e.key === ' ') && !e.repeat) {\n e.preventDefault();\n e.stopPropagation();\n onToggleProjectPin();\n }\n }}\n className={`ml-1 flex-shrink-0 cursor-pointer transition-colors ${\n isProjectPinned\n ? 'text-[var(--text-accent)]'\n : 'text-[var(--text-disabled)] hover:text-[var(--text-label-secondary)]'\n }`}\n title={\n isProjectPinned ? '取消固定项目' : '固定项目到活跃区'\n }\n data-testid=\"project-pin-btn\"\n >\n <svg aria-hidden=\"true\" className=\"h-3 w-3\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M4.456 2.013a.75.75 0 011.06-.034l6.5 6a.75.75 0 01-.034 1.06l-1.99 1.838.637 3.22a.75.75 0 01-1.196.693L6.5 12.526l-2.933 2.264a.75.75 0 01-1.196-.693l.637-3.22-1.99-1.838a.75.75 0 01-.034-1.06l5.472-5.966z\" />\n </svg>\n </span>\n )}\n </button>\n {!isCollapsed && children}\n </div>\n );\n}\n","import { apiFetch } from './api-client';\nimport { downloadBlob } from './protected-resource';\n\nexport type ThreadExportTextFormat = 'md' | 'txt';\n\nexport async function exportThreadImage(threadId: string): Promise<void> {\n const res = await apiFetch(`/api/threads/${threadId}/export-image`, {\n method: 'POST',\n });\n if (!res.ok) {\n const data = (await res.json()) as { error?: string; message?: string };\n throw new Error(data.message || data.error || '导出失败');\n }\n const blob = await res.blob();\n downloadBlob(blob, `chat-${threadId}-${Date.now()}.png`);\n}\n\nexport async function exportThreadText(threadId: string, format: ThreadExportTextFormat): Promise<void> {\n const res = await apiFetch(`/api/export/thread/${threadId}?format=${format}`);\n if (!res.ok) {\n const data = (await res.json()) as { error?: string; message?: string };\n throw new Error(data.message || data.error || '导出失败');\n }\n const text = await res.text();\n const ext = format === 'md' ? 'md' : 'txt';\n const mime = format === 'md' ? 'text/markdown' : 'text/plain';\n const blob = new Blob([text], { type: `${mime}; charset=utf-8` });\n downloadBlob(blob, `thread-${threadId}.${ext}`);\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useAgentData } from \"@/hooks/useAgentData\";\nimport { useExpertCatalog } from \"@/hooks/useExpertCatalog\";\nimport {\n getMentionLabel,\n getMentionRe,\n getMentionToAgentId,\n} from \"@/lib/mention-highlight\";\nimport { useAuthorizationPendingStore } from \"@/stores/authorizationPendingStore\";\nimport type { ThreadState } from \"@/stores/chat-types\";\nimport { API_URL } from \"@/utils/api-client\";\nimport { exportThreadText } from \"@/utils/thread-export\";\nimport { AppModal } from \"../AppModal\";\nimport { MaskIcon } from \"../shared/MaskIcon\";\nimport { OverflowTooltip } from \"../shared/OverflowTooltip\";\nimport { formatRelativeTime } from \"./thread-utils\";\n\nexport interface ThreadItemProps {\n id: string;\n title: string | null;\n participants: string[];\n lastActiveAt: number;\n isActive: boolean;\n onSelect: (id: string) => void;\n onDelete?: (id: string) => void;\n onRename?: (id: string, title: string) => void | Promise<void>;\n onTogglePin?: (id: string, pinned: boolean) => void | Promise<void>;\n onToggleFavorite?: (id: string, favorited: boolean) => void | Promise<void>;\n onUpdatePreferredAgents?: (id: string, agentIds: string[]) => void | Promise<void>;\n isPinned?: boolean;\n isFavorited?: boolean;\n threadState?: ThreadState;\n indented?: boolean;\n preferredAgentIds?: string[];\n invitedExpertIds?: string[];\n isHubThread?: boolean;\n sourceLabel?: string;\n iconOnly?: boolean;\n}\n\ntype ContextMenuState = {\n x: number;\n y: number;\n anchorLeft: number;\n anchorTop: number;\n anchorBottom: number;\n};\n\nfunction resolveMoreMenuAnchor(\n container: HTMLDivElement,\n fallbackEvent?: MouseEvent,\n) {\n const moreButton = container.querySelector<HTMLButtonElement>(\n 'button[aria-label=\"更多操作\"]',\n );\n if (moreButton) {\n const rect = moreButton.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n return { left: rect.left, top: rect.top, bottom: rect.bottom };\n }\n }\n\n const rowRect = container.getBoundingClientRect();\n const fallbackLeft = rowRect.right - 28;\n const fallbackTop = rowRect.top + rowRect.height * 0.62;\n const fallbackBottom = fallbackTop + 16;\n if (fallbackEvent) {\n return {\n left: fallbackLeft,\n top: fallbackTop,\n bottom: fallbackBottom,\n x: fallbackEvent.clientX,\n y: fallbackEvent.clientY,\n };\n }\n return { left: fallbackLeft, top: fallbackTop, bottom: fallbackBottom };\n}\n\nfunction getMentionedAgentIdsFromMessages(\n messages: ThreadState[\"messages\"] | undefined,\n resolveById: (id: string) => unknown,\n): string[] {\n if (!messages?.length) return [];\n const mentionAliasToAgentId = getMentionToAgentId();\n const mentionRe = getMentionRe();\n const ids: string[] = [];\n const seen = new Set<string>();\n\n for (\n let messageIndex = messages.length - 1;\n messageIndex >= 0;\n messageIndex -= 1\n ) {\n const message = messages[messageIndex];\n if (!message?.content) continue;\n\n mentionRe.lastIndex = 0;\n const matches = [...message.content.matchAll(mentionRe)];\n for (const match of matches) {\n const alias = match[1]?.toLowerCase();\n if (!alias) continue;\n const candidateId = mentionAliasToAgentId[alias] ?? match[1];\n if (!candidateId) continue;\n if (!resolveById(candidateId)) continue;\n if (seen.has(candidateId)) continue;\n seen.add(candidateId);\n ids.push(candidateId);\n }\n }\n\n return ids;\n}\n\nfunction getRecentAssistantAgentIdsFromMessages(\n messages: ThreadState[\"messages\"] | undefined,\n resolveById: (id: string) => unknown,\n): string[] {\n if (!messages?.length) return [];\n\n const ids: string[] = [];\n const seen = new Set<string>();\n\n for (\n let messageIndex = messages.length - 1;\n messageIndex >= 0;\n messageIndex -= 1\n ) {\n const message = messages[messageIndex];\n const agentId = message?.type === \"assistant\" ? message.agentId : undefined;\n if (!agentId) continue;\n if (seen.has(agentId)) continue;\n if (!resolveById(agentId)) continue;\n seen.add(agentId);\n ids.push(agentId);\n }\n\n return ids;\n}\n\nfunction normalizeTitleMentions(\n title: string,\n agents: Array<{ id: string; displayName: string; mentionPatterns: string[] }>,\n): string {\n const mentionLabel = getMentionLabel();\n const knownAliases = new Set<string>(\n Object.keys(mentionLabel).map((alias) => alias.toLowerCase()),\n );\n\n for (const agent of agents) {\n const display = agent.displayName.trim();\n if (!display) continue;\n knownAliases.add(agent.id.toLowerCase());\n knownAliases.add(display.replace(/^@/, \"\").toLowerCase());\n for (const pattern of agent.mentionPatterns) {\n const alias = pattern.replace(/^@/, \"\").trim().toLowerCase();\n if (alias) knownAliases.add(alias);\n }\n }\n\n const tokenRe =\n /@([^\\s,.:;!?()\\[\\]{}<>,。!?、:;()【】《》「」『』〈〉]+)/g;\n return title\n .replace(tokenRe, (fullMatch: string, alias: string) =>\n knownAliases.has(alias.toLowerCase()) ? \"\" : fullMatch,\n )\n .replace(/\\s{2,}/g, \" \")\n .replace(/\\s+([,.:;!?,。!?、:;])/g, \"$1\")\n .trim();\n}\n\ntype ThreadFallbackAvatarMeta = {\n avatar: string;\n color: string;\n displayName: string;\n};\n\nfunction resolveThreadFallbackAvatar(\n agents: Array<{\n id: string;\n displayName: string;\n mentionPatterns: string[];\n avatar: string;\n color?: { primary?: string };\n }>,\n): ThreadFallbackAvatarMeta {\n const officeAgent =\n agents.find((agent) => agent.id.toLowerCase() === \"office\") ??\n agents.find((agent) => agent.id.toLowerCase() === \"jiuwenclaw\") ??\n agents.find((agent) =>\n agent.mentionPatterns.some(\n (pattern) => pattern.replace(/^@/, \"\").toLowerCase() === \"office\",\n ),\n ) ??\n agents.find((agent) => agent.displayName.includes(\"办公\"));\n\n const avatar = officeAgent?.avatar?.trim() ?? \"\";\n return {\n avatar: avatar\n ? avatar.startsWith(\"/uploads/\")\n ? `${API_URL}${avatar}`\n : avatar\n : \"/avatars/assistant.svg\",\n color: officeAgent?.color?.primary ?? \"var(--accent-primary)\",\n displayName: officeAgent?.displayName ?? \"办公智能体\",\n };\n}\n\nfunction isImageAvatar(avatar: string): boolean {\n return /^(https?:\\/\\/|\\/|data:image)/.test(avatar);\n}\n\nfunction getAvatarInitial(name?: string): string {\n const normalized = (name ?? \"\").replace(/^@/, \"\").trim();\n const first = normalized.slice(0, 1);\n return (first || \"智\").toUpperCase();\n}\n\nexport function ThreadItem({\n id,\n title,\n participants,\n lastActiveAt,\n isActive,\n onSelect,\n onDelete,\n onRename,\n onTogglePin,\n isPinned,\n threadState,\n indented,\n preferredAgentIds,\n invitedExpertIds,\n isHubThread,\n sourceLabel,\n iconOnly,\n}: ThreadItemProps) {\n const { agents = [], getAgentById } = useAgentData();\n const hasPendingApproval = useAuthorizationPendingStore(\n useCallback((state) => state.hasPending(id), [id]),\n );\n const { getExpertById } = useExpertCatalog();\n const resolveParticipantById = useCallback(\n (agentId: string) => getAgentById(agentId) ?? getExpertById(agentId),\n [getAgentById, getExpertById],\n );\n const unreadCount = Math.max(0, threadState?.unreadCount ?? 0);\n const showUnreadBadge = unreadCount > 0;\n const unreadLabel = unreadCount > 99 ? \"99+\" : String(unreadCount);\n const isThreadRunning = !!threadState?.hasActiveInvocation;\n const canDelete = id !== \"default\" && onDelete && !isThreadRunning;\n const canRename = id !== \"default\" && onRename;\n const canPin = id !== \"default\" && onTogglePin;\n\n const [isSaving, setIsSaving] = useState(false);\n const [showRenameDialog, setShowRenameDialog] = useState(false);\n const [draftTitle, setDraftTitle] = useState(title ?? \"\");\n const [contextMenu, setContextMenu] = useState<ContextMenuState | null>(null);\n\n const menuRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!showRenameDialog) setDraftTitle(title ?? \"\");\n }, [title, showRenameDialog]);\n\n useEffect(() => {\n if (!contextMenu) return;\n const closeMenu = () => setContextMenu(null);\n const onPointerDown = (event: MouseEvent) => {\n if (!menuRef.current) return;\n const target = event.target as Node | null;\n if (target && !menuRef.current.contains(target)) {\n closeMenu();\n }\n };\n\n window.addEventListener(\"mousedown\", onPointerDown);\n window.addEventListener(\"scroll\", closeMenu, true);\n window.addEventListener(\"blur\", closeMenu);\n\n return () => {\n window.removeEventListener(\"mousedown\", onPointerDown);\n window.removeEventListener(\"scroll\", closeMenu, true);\n window.removeEventListener(\"blur\", closeMenu);\n };\n }, [contextMenu]);\n\n useEffect(() => {\n if (!contextMenu || !menuRef.current) return;\n const viewportPadding = 8;\n const anchorGap = 6;\n const rect = menuRef.current.getBoundingClientRect();\n const maxX = window.innerWidth - rect.width - viewportPadding;\n const nextX = Math.min(\n Math.max(contextMenu.anchorLeft, viewportPadding),\n Math.max(viewportPadding, maxX),\n );\n\n const topBoundY = viewportPadding;\n const bottomBoundY = Math.max(\n viewportPadding,\n window.innerHeight - rect.height - viewportPadding,\n );\n const preferredBelowY = contextMenu.anchorBottom + anchorGap;\n const preferredAboveY = contextMenu.anchorTop - rect.height - anchorGap;\n const fitsBelow =\n preferredBelowY + rect.height <= window.innerHeight - viewportPadding;\n const targetRawY = fitsBelow ? preferredBelowY : preferredAboveY;\n const nextY = Math.min(Math.max(targetRawY, topBoundY), bottomBoundY);\n\n if (nextX !== contextMenu.x || nextY !== contextMenu.y) {\n setContextMenu({\n x: nextX,\n y: nextY,\n anchorLeft: contextMenu.anchorLeft,\n anchorTop: contextMenu.anchorTop,\n anchorBottom: contextMenu.anchorBottom,\n });\n }\n }, [contextMenu]);\n\n const submitRename = useCallback(async () => {\n if (!onRename) return;\n const next = draftTitle.trim();\n if (!next) {\n setDraftTitle(title ?? \"\");\n setShowRenameDialog(false);\n return;\n }\n if (next === (title ?? \"\")) {\n setShowRenameDialog(false);\n return;\n }\n\n setIsSaving(true);\n try {\n await onRename(id, next);\n setShowRenameDialog(false);\n } finally {\n setIsSaving(false);\n }\n }, [onRename, draftTitle, title, id]);\n\n const rawTitle = title ?? (id === \"default\" ? \"大厅\" : \"未命名会话\");\n const displayTitle = normalizeTitleMentions(rawTitle, agents);\n const recentAssistantAgentIds = getRecentAssistantAgentIdsFromMessages(\n threadState?.messages,\n resolveParticipantById,\n );\n const recentAssistantNames = recentAssistantAgentIds\n .map((agentId) => resolveParticipantById(agentId)?.displayName ?? agentId)\n .join(\", \");\n const participantNames = participants\n .map((agentId) => resolveParticipantById(agentId)?.displayName ?? agentId)\n .join(\", \");\n const description =\n recentAssistantNames ||\n participantNames ||\n (isHubThread ? \"Hub 会话\" : \"暂无智能体\");\n const fallbackAvatar = resolveThreadFallbackAvatar(agents);\n const mentionedAgentIds = getMentionedAgentIdsFromMessages(\n threadState?.messages,\n resolveParticipantById,\n );\n const subtitle = hasPendingApproval ? \"审批待处理\" : description;\n const fallbackAvatarAgentIds = Array.from(\n new Set(\n [\n ...(threadState?.targetAgents ?? []),\n ...participants,\n ...(preferredAgentIds ?? []),\n ...mentionedAgentIds,\n ...(invitedExpertIds ?? []),\n ].filter((agentId) => !!agentId && !!resolveParticipantById(agentId)),\n ),\n );\n const avatarAgentIds = (\n recentAssistantAgentIds.length > 0\n ? recentAssistantAgentIds\n : fallbackAvatarAgentIds\n ).slice(0, 4);\n const contextMenuItemClass =\n \"ui-overlay-item block w-full whitespace-nowrap rounded-[4px] px-3 py-2 text-left text-xs text-[var(--overlay-text)] transition-colors focus-visible:outline-none\";\n const isContextMenuOpen = contextMenu !== null;\n const openContextMenu = useCallback(\n (anchorLeft: number, anchorTop: number, anchorBottom: number) => {\n setContextMenu({\n x: anchorLeft,\n y: anchorBottom + 6,\n anchorLeft,\n anchorTop,\n anchorBottom,\n });\n },\n [],\n );\n\n const renderAgentAvatar = useCallback(\n (agentId: string, size: number) => {\n const rowAgent = getAgentById(agentId);\n const expert = rowAgent ? null : getExpertById(agentId);\n const avatar = (rowAgent ?? expert)?.avatar?.trim() ?? '';\n const color = rowAgent?.color?.primary ?? expert?.color?.primary ?? 'var(--accent-primary)';\n const displayName = rowAgent?.displayName ?? expert?.displayName ?? agentId;\n const avatarSrc = avatar.startsWith(\"/uploads/\")\n ? `${API_URL}${avatar}`\n : avatar;\n const imageAvatar = isImageAvatar(avatarSrc);\n\n if (imageAvatar) {\n return (\n <div\n className=\"overflow-hidden rounded-full bg-gray-100\"\n style={{ width: size, height: size }}\n >\n <img\n src={avatarSrc}\n alt={displayName}\n width={size}\n height={size}\n className=\"h-full w-full object-cover\"\n />\n </div>\n );\n }\n\n return (\n <div\n className=\"inline-flex items-center justify-center rounded-full font-semibold text-[var(--thread-avatar-initial-text)]\"\n style={{\n width: size,\n height: size,\n backgroundColor: color,\n fontSize: size <= 16 ? 10 : 12,\n lineHeight: 1,\n }}\n aria-hidden=\"true\"\n title={displayName}\n >\n {avatar || getAvatarInitial(displayName)}\n </div>\n );\n },\n [getAgentById, getExpertById],\n );\n\n const avatarNode = (\n <>\n {avatarAgentIds.length === 1 ? (\n renderAgentAvatar(avatarAgentIds[0]!, 32)\n ) : avatarAgentIds.length > 1 ? (\n <div className=\"relative h-8 w-8\">\n {avatarAgentIds.length === 2 && (\n <>\n <div className=\"absolute left-[1px] top-[6px] z-10\">\n {renderAgentAvatar(avatarAgentIds[0]!, 20)}\n </div>\n <div className=\"absolute left-[11px] top-[6px] z-0\">\n {renderAgentAvatar(avatarAgentIds[1]!, 20)}\n </div>\n </>\n )}\n {avatarAgentIds.length === 3 && (\n <>\n <div className=\"absolute left-[8px] top-0\">\n {renderAgentAvatar(avatarAgentIds[0]!, 16)}\n </div>\n <div className=\"absolute left-0 top-[16px]\">\n {renderAgentAvatar(avatarAgentIds[1]!, 16)}\n </div>\n <div className=\"absolute left-[16px] top-[16px]\">\n {renderAgentAvatar(avatarAgentIds[2]!, 16)}\n </div>\n </>\n )}\n {avatarAgentIds.length >= 4 && (\n <>\n <div className=\"absolute left-0 top-0\">\n {renderAgentAvatar(avatarAgentIds[0]!, 16)}\n </div>\n <div className=\"absolute left-[16px] top-0\">\n {renderAgentAvatar(avatarAgentIds[1]!, 16)}\n </div>\n <div className=\"absolute left-0 top-[16px]\">\n {renderAgentAvatar(avatarAgentIds[2]!, 16)}\n </div>\n <div className=\"absolute left-[16px] top-[16px]\">\n {renderAgentAvatar(avatarAgentIds[3]!, 16)}\n </div>\n </>\n )}\n </div>\n ) : (\n <div className=\"ui-avatar-fallback-shell h-8 w-8\">\n {isImageAvatar(fallbackAvatar.avatar) ? (\n <>\n {/* biome-ignore lint/performance/noImgElement: fallback avatar uses static local asset */}\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={fallbackAvatar.avatar}\n alt=\"\"\n aria-hidden=\"true\"\n className=\"h-full w-full object-cover\"\n />\n </>\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"inline-flex h-full w-full items-center justify-center rounded-full text-[12px] font-semibold text-[var(--thread-avatar-initial-text)]\"\n style={{ backgroundColor: fallbackAvatar.color }}\n >\n {fallbackAvatar.avatar ||\n getAvatarInitial(fallbackAvatar.displayName)}\n </span>\n )}\n </div>\n )}\n {showUnreadBadge && (\n <span\n className=\"ui-thread-unread-badge absolute -right-1 -top-1 inline-flex h-4 min-w-4 items-center justify-center rounded-full border px-1 text-[10px] font-medium leading-none\"\n aria-label={`未读消息 ${unreadCount}`}\n >\n {unreadLabel}\n </span>\n )}\n </>\n );\n\n const compactAvatarNode = (\n <>\n {avatarAgentIds.length === 1 ? (\n renderAgentAvatar(avatarAgentIds[0]!, 20)\n ) : avatarAgentIds.length > 1 ? (\n <div className=\"relative h-5 w-5\">\n <div className=\"absolute left-0 top-0 origin-top-left scale-[0.625]\">\n {avatarNode}\n </div>\n </div>\n ) : (\n <div className=\"ui-avatar-fallback-shell h-5 w-5\">\n {isImageAvatar(fallbackAvatar.avatar) ? (\n <>\n {/* biome-ignore lint/performance/noImgElement: fallback avatar uses static local asset */}\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={fallbackAvatar.avatar}\n alt=\"\"\n aria-hidden=\"true\"\n className=\"h-full w-full object-cover\"\n />\n </>\n ) : (\n <span\n aria-hidden=\"true\"\n className=\"inline-flex h-full w-full items-center justify-center rounded-full text-[10px] font-semibold text-[var(--thread-avatar-initial-text)]\"\n style={{ backgroundColor: fallbackAvatar.color }}\n >\n {fallbackAvatar.avatar ||\n getAvatarInitial(fallbackAvatar.displayName)}\n </span>\n )}\n </div>\n )}\n {showUnreadBadge && avatarAgentIds.length <= 1 && (\n <span\n className=\"ui-thread-unread-badge absolute -right-1 -top-1 inline-flex h-3.5 min-w-3.5 items-center justify-center rounded-full border px-1 text-[9px] font-medium leading-none\"\n aria-label={`未读消息 ${unreadCount}`}\n >\n {unreadLabel}\n </span>\n )}\n </>\n );\n\n if (iconOnly) {\n return (\n <OverflowTooltip content={displayTitle} forceShow placement=\"right\" className=\"inline-flex\">\n <div\n className={`ui-thread-item group relative mx-auto mb-0.5 flex h-8 w-8 cursor-pointer items-center rounded-[6px] border-0 border-b-0 transition-colors justify-center ${\n isActive ? \"ui-thread-item-active\" : \"ui-thread-item-inactive\"\n }`}\n style={{ minHeight: 0, padding: 0 }}\n onClick={() => onSelect(id)}\n aria-label={displayTitle}\n data-testid=\"thread-item-icon-only\"\n >\n <div className=\"relative flex h-5 w-5 shrink-0 items-center justify-center\">\n {compactAvatarNode}\n </div>\n </div>\n </OverflowTooltip>\n );\n }\n\n return (\n <div\n className={`ui-thread-item group relative cursor-pointer transition-colors ${\n indented ? \"pl-7\" : \"\"\n } mx-4 mb-0.5 last:mb-0 border-0 border-b-0 rounded-[8px] ${isActive ? \"ui-thread-item-active\" : \"ui-thread-item-inactive\"}`}\n onClick={() => onSelect(id)}\n onContextMenu={(e) => {\n e.preventDefault();\n e.stopPropagation();\n const anchor = resolveMoreMenuAnchor(e.currentTarget, e.nativeEvent);\n openContextMenu(anchor.left, anchor.top, anchor.bottom);\n }}\n >\n <div className=\"flex items-center gap-[10px]\">\n <div className=\"relative shrink-0\">{avatarNode}</div>\n\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <OverflowTooltip content={displayTitle} className=\"min-w-0 flex-1\">\n <span className=\"ui-thread-title block min-w-0 truncate font-semibold\">\n {displayTitle}\n </span>\n </OverflowTooltip>\n {sourceLabel && (\n <span className=\"ui-thread-source-badge shrink-0 rounded-full px-2 py-[1px] text-[10px] leading-4\">\n {sourceLabel}\n </span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center justify-between gap-2\">\n <OverflowTooltip content={subtitle} className=\"min-w-0 flex-1\">\n <span\n className=\"ui-thread-description block min-w-0 truncate\"\n style={hasPendingApproval ? { color: \"rgb(255, 136, 0)\" } : undefined}\n >\n {subtitle}\n </span>\n </OverflowTooltip>\n <div className=\"flex shrink-0 items-center gap-1.5\">\n <span\n className={`ui-thread-meta shrink-0 ${isContextMenuOpen ? \"hidden\" : \"group-hover:hidden\"}`}\n >\n {formatRelativeTime(lastActiveAt, true)}\n </span>\n <button\n type=\"button\"\n aria-label=\"更多操作\"\n className={`ui-thread-action h-4 w-4 items-center justify-center ${\n isContextMenuOpen\n ? \"inline-flex\"\n : \"hidden group-hover:inline-flex focus-visible:inline-flex\"\n }`}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n const rect = (\n e.currentTarget as HTMLButtonElement\n ).getBoundingClientRect();\n openContextMenu(rect.left, rect.top, rect.bottom);\n }}\n >\n <MaskIcon name=\"more\" className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {contextMenu &&\n typeof document !== \"undefined\" &&\n createPortal(\n <div\n ref={menuRef}\n className=\"ui-overlay-card fixed z-50 inline-block w-[100px] rounded-[6px] py-2 shadow-[var(--overlay-shadow)]\"\n data-testid=\"thread-context-menu\"\n style={{ left: contextMenu.x, top: contextMenu.y }}\n onClick={(e) => e.stopPropagation()}\n onContextMenu={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n >\n {canRename && (\n <button\n type=\"button\"\n onClick={() => {\n setContextMenu(null);\n setDraftTitle(title ?? \"\");\n setShowRenameDialog(true);\n }}\n className={contextMenuItemClass}\n >\n 重命名\n </button>\n )}\n\n {canPin && (\n <button\n type=\"button\"\n onClick={() => {\n setContextMenu(null);\n void onTogglePin?.(id, !isPinned);\n }}\n className={contextMenuItemClass}\n >\n {isPinned ? \"取消置顶\" : \"置顶\"}\n </button>\n )}\n\n {id !== \"default\" && (\n <button\n type=\"button\"\n onClick={() => {\n setContextMenu(null);\n void exportThreadText(id, \"md\").catch((error) => {\n console.error(\"导出失败:\", error);\n alert(\n `导出失败:${error instanceof Error ? error.message : \"未知错误\"}`,\n );\n });\n }}\n className={contextMenuItemClass}\n >\n 导出会话\n </button>\n )}\n\n {canDelete && (\n <button\n type=\"button\"\n onClick={() => {\n setContextMenu(null);\n onDelete?.(id);\n }}\n className={contextMenuItemClass}\n >\n 删除会话\n </button>\n )}\n </div>,\n document.body,\n )}\n\n <AppModal\n open={showRenameDialog}\n onClose={() => setShowRenameDialog(false)}\n disableBackdropClose\n title=\"编辑会话名称\"\n panelClassName=\"w-[500px]\"\n bodyClassName=\"pt-5\"\n zIndexClassName=\"z-[120]\"\n backdropTestId=\"thread-rename-modal\"\n panelTestId=\"thread-rename-modal-panel\"\n >\n <div\n className=\"flex flex-col gap-5\"\n data-testid=\"thread-rename-modal-content\"\n >\n <input\n value={draftTitle}\n onChange={(e) => setDraftTitle(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n void submitRename();\n }\n if (e.key === \"Escape\") {\n e.preventDefault();\n setShowRenameDialog(false);\n }\n }}\n autoFocus\n maxLength={200}\n disabled={isSaving}\n className=\"ui-input h-7 w-full px-3 text-sm\"\n />\n\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setShowRenameDialog(false)}\n className=\"ui-button-default\"\n >\n 取消\n </button>\n <button\n type=\"button\"\n onClick={() => void submitRename()}\n disabled={isSaving}\n className=\"ui-button-primary\"\n >\n 确定\n </button>\n </div>\n </div>\n </AppModal>\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\n\ntype PreventSleepStatePayload = {\n enabled?: boolean;\n error?: string | null;\n};\n\ntype PreventSleepStateMessage = {\n type?: string;\n payload?: PreventSleepStatePayload;\n};\n\ntype WebViewMessageEvent = {\n data?: unknown;\n};\n\ntype WebViewBridge = {\n postMessage(message: string): void;\n addEventListener?(eventName: 'message', listener: (event: WebViewMessageEvent) => void): void;\n removeEventListener?(eventName: 'message', listener: (event: WebViewMessageEvent) => void): void;\n};\n\ndeclare global {\n interface Window {\n chrome?: {\n webview?: WebViewBridge;\n };\n }\n}\n\nconst PREVENT_SLEEP_ENABLE_MESSAGE = 'preventSleep.enable';\nconst PREVENT_SLEEP_DISABLE_MESSAGE = 'preventSleep.disable';\nconst PREVENT_SLEEP_SYNC_STATE_MESSAGE = 'preventSleep.syncState';\nconst PREVENT_SLEEP_STATE_MESSAGE = 'preventSleep.state';\n\nfunction getWebViewBridge(): WebViewBridge | null {\n if (typeof window === 'undefined') {\n return null;\n }\n\n return window.chrome?.webview ?? null;\n}\n\nfunction isPreventSleepStateMessage(value: unknown): value is PreventSleepStateMessage {\n if (!value || typeof value !== 'object') {\n return false;\n }\n\n const message = value as PreventSleepStateMessage;\n return message.type === PREVENT_SLEEP_STATE_MESSAGE;\n}\n\nexport function usePreventSleep() {\n const [enabled, setEnabled] = useState<boolean>(false);\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [isSaving, setIsSaving] = useState<boolean>(false);\n\n const isDesktopHost = getWebViewBridge() !== null;\n\n useEffect(() => {\n const webview = getWebViewBridge();\n if (!webview?.addEventListener) {\n // 非 WebView2 环境,标记加载完成\n setIsLoading(false);\n return;\n }\n\n const handleMessage = (event: WebViewMessageEvent) => {\n const message = event.data;\n if (!isPreventSleepStateMessage(message)) {\n return;\n }\n\n const payload = message.payload;\n setEnabled(Boolean(payload?.enabled));\n setError(payload?.error ?? null);\n setIsLoading(false);\n setIsSaving(false);\n };\n\n webview.addEventListener('message', handleMessage);\n // 请求同步当前状态\n webview.postMessage(PREVENT_SLEEP_SYNC_STATE_MESSAGE);\n\n return () => {\n webview.removeEventListener?.('message', handleMessage);\n };\n }, []);\n\n const enable = useCallback(() => {\n const webview = getWebViewBridge();\n if (!webview) {\n return;\n }\n\n setIsSaving(true);\n webview.postMessage(PREVENT_SLEEP_ENABLE_MESSAGE);\n }, []);\n\n const disable = useCallback(() => {\n const webview = getWebViewBridge();\n if (!webview) {\n return;\n }\n\n setIsSaving(true);\n webview.postMessage(PREVENT_SLEEP_DISABLE_MESSAGE);\n }, []);\n\n const toggle = useCallback((value: boolean) => {\n if (value) {\n enable();\n } else {\n disable();\n }\n }, [enable, disable]);\n\n return {\n isDesktopHost,\n enabled,\n error,\n isLoading,\n isSaving,\n enable,\n disable,\n toggle,\n };\n}","export function ModalCloseIcon({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden=\"true\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n );\n}\n\nexport function FeedbackHelpCircleIcon({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M15 8c0-3.87-3.14-7-7-7-3.87 0-7 3.13-7 7 0 3.86 3.13 7 7 7 3.86 0 7-3.14 7-7ZM2 8c0-3.32 2.68-6 6-6 3.31 0 6 2.68 6 6 0 3.31-2.69 6-6 6-3.32 0-6-2.69-6-6Zm8.2-1.28c0-1.23-1-2.22-2.23-2.22s-2.22.99-2.22 2.22c0 .27.22.5.5.5.27 0 .5-.23.5-.5 0-.68.54-1.22 1.22-1.22.68 0 1.23.54 1.23 1.22 0 .67-.55 1.21-1.23 1.21-.27 0-.5.23-.5.5v1.23c0 .27.23.5.5.5l.09-.01c.24-.04.41-.24.41-.49v-.78l.12-.03c.93-.27 1.61-1.12 1.61-2.13Zm-2.27 3.87c.31 0 .57.25.57.56 0 .31-.26.56-.57.56a.56.56 0 0 1-.56-.56c0-.31.25-.56.56-.56Z\"\n clipRule=\"evenodd\"\n fillRule=\"evenodd\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type ChangeEvent,\n type ClipboardEvent,\n type DragEvent,\n} from 'react';\nimport { useEscapeKey } from '@/hooks/useEscapeKey';\nimport { FeedbackHelpCircleIcon } from '@/components/icons/SettingsFeedbackIcons';\nimport { AppModal } from './AppModal';\nimport { Button } from './shared/Button';\nimport { OverflowTooltip } from './shared/OverflowTooltip';\n\nconst MAX_DESC = 1000;\nconst MAX_FILES = 10;\nconst MAX_TOTAL_BYTES = 5 * 1024 * 1024;\nconst ACCEPT_MIME = new Set([\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/jpg',\n 'image/pjpeg',\n 'image/x-png',\n]);\n\nconst OFFICE_CLAW_FAQ_DOC_URL =\n 'https://support.huaweicloud.com/officeclaw-agentarts-pc/officeclaw-agentarts-pc-0040.html';\n\nexport interface FeedbackModalProps {\n open: boolean;\n onClose: () => void;\n}\n\ntype FeedbackType = 'bug' | 'suggestion';\n\ntype AttachedFile = { id: string; file: File };\n\nfunction extensionLooksLikeAllowedImage(name: string): boolean {\n return /\\.(jpe?g|png|gif)$/i.test(name);\n}\n\nfunction isAllowedImage(file: File): boolean {\n const rawType = (file.type ?? '').trim().toLowerCase();\n if (ACCEPT_MIME.has(rawType)) return true;\n if (rawType.startsWith('image/')) return extensionLooksLikeAllowedImage(file.name);\n if (!rawType || rawType === 'application/octet-stream') return extensionLooksLikeAllowedImage(file.name);\n return extensionLooksLikeAllowedImage(file.name);\n}\n\nfunction dataTransferMightContainFiles(dt: DataTransfer | null): boolean {\n if (!dt?.types) return false;\n const types = dt.types;\n const len = types.length;\n for (let i = 0; i < len; i++) {\n const t = types[i];\n if (t === 'Files') return true;\n if (typeof t === 'string' && t.startsWith('image/')) return true;\n }\n return false;\n}\n\nfunction formatTotalMB(bytes: number): string {\n return (bytes / (1024 * 1024)).toFixed(2);\n}\n\nfunction FeedbackScreenshotZoneHints() {\n return (\n <>\n <p className=\"text-[12px] leading-[18px] tracking-[1px] text-[var(--text-label-secondary)]\">\n 点击后进行添加,或拖拽/粘贴到此区域,支持添加多个图片\n </p>\n <p className=\"mt-1 text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">\n 格式为 jpg、png、gif,数量不超过10个,总大小 ≤ 5MB\n </p>\n </>\n );\n}\n\nfunction FeedbackFieldTip({ text }: { text: string }) {\n return (\n <OverflowTooltip content={text} forceShow placement=\"top\" className=\"inline-flex shrink-0\">\n <button\n type=\"button\"\n className=\"inline-flex h-[18px] w-[18px] cursor-pointer items-center justify-center bg-transparent text-[var(--text-label-secondary)] transition-colors hover:bg-[var(--surface-panel)] hover:text-[var(--text-primary)]\"\n aria-label={`说明:${text}`}\n >\n <FeedbackHelpCircleIcon className=\"h-4 w-4 shrink-0 text-[var(--text-primary)]\" />\n </button>\n </OverflowTooltip>\n );\n}\n\nexport default function FeedbackModal({ open, onClose }: FeedbackModalProps) {\n const headingId = useId();\n const fieldIds = useId();\n const fileInputRef = useRef<HTMLInputElement>(null);\n const focusAreaRef = useRef<HTMLDivElement>(null);\n const dragDepthRef = useRef(0);\n\n const [feedbackType, setFeedbackType] = useState<FeedbackType>('bug');\n const [description, setDescription] = useState('');\n const [contactInfo, setContactInfo] = useState('');\n const [attachPluginInfo, setAttachPluginInfo] = useState(false);\n const [attachAppLogs, setAttachAppLogs] = useState(false);\n const [files, setFiles] = useState<AttachedFile[]>([]);\n const [dropHighlight, setDropHighlight] = useState(false);\n\n useEscapeKey({ enabled: open, onEscape: onClose });\n\n useEffect(() => {\n if (!open) return;\n const id = window.requestAnimationFrame(() => focusAreaRef.current?.focus());\n return () => window.cancelAnimationFrame(id);\n }, [open]);\n\n useEffect(() => {\n if (open) return;\n setFeedbackType('bug');\n setDescription('');\n setContactInfo('');\n setAttachPluginInfo(false);\n setAttachAppLogs(false);\n setFiles([]);\n setDropHighlight(false);\n dragDepthRef.current = 0;\n }, [open]);\n\n const totalBytes = files.reduce((sum, { file }) => sum + file.size, 0);\n\n const tryAddFiles = useCallback(\n (incoming: File[]) => {\n const allowed = incoming.filter(isAllowedImage);\n if (allowed.length === 0) return;\n\n setFiles((prev) => {\n let next = [...prev];\n let bytes = next.reduce((s, { file }) => s + file.size, 0);\n\n for (const file of allowed) {\n if (next.length >= MAX_FILES) break;\n const nextBytes = bytes + file.size;\n if (nextBytes > MAX_TOTAL_BYTES) break;\n next = [...next, { id: `${Date.now()}-${Math.random().toString(36).slice(2)}`, file }];\n bytes = nextBytes;\n }\n return next;\n });\n },\n [],\n );\n\n const handleFileInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n const picked = e.target.files?.length ? Array.from(e.target.files) : [];\n e.target.value = '';\n /* 推迟到当前调用栈结束:避免部分环境下文件对话框关闭后仍误触发遮罩逻辑干扰本轮渲染 */\n queueMicrotask(() => tryAddFiles(picked));\n };\n\n const removeFile = (id: string) => {\n setFiles((prev) => prev.filter((f) => f.id !== id));\n };\n\n const handleDragEnter = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!dataTransferMightContainFiles(e.dataTransfer)) return;\n dragDepthRef.current += 1;\n setDropHighlight(true);\n };\n\n const handleDragLeave = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragDepthRef.current = Math.max(0, dragDepthRef.current - 1);\n if (dragDepthRef.current === 0) setDropHighlight(false);\n };\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (dataTransferMightContainFiles(e.dataTransfer)) {\n e.dataTransfer.dropEffect = 'copy';\n }\n };\n\n const handleDrop = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragDepthRef.current = 0;\n setDropHighlight(false);\n const dropped = Array.from(e.dataTransfer.files ?? []);\n tryAddFiles(dropped);\n };\n\n const handlePaste = (e: ClipboardEvent) => {\n const items = Array.from(e.clipboardData?.items ?? []);\n const pasted: File[] = [];\n for (const item of items) {\n if (item.kind !== 'file') continue;\n const f = item.getAsFile();\n if (f) pasted.push(f);\n }\n if (pasted.length === 0) return;\n e.preventDefault();\n tryAddFiles(pasted);\n };\n\n const descLen = description.length > MAX_DESC ? MAX_DESC : description.length;\n const descValue = description.slice(0, MAX_DESC);\n\n return (\n <AppModal\n open={open}\n onClose={onClose}\n title={\n <span\n id={headingId}\n className=\"text-[18px] font-bold leading-[28px] text-[var(--modal-title-text,var(--text-primary))]\"\n >\n 问题反馈\n </span>\n }\n panelStyle={{ width: 700, maxWidth: 'calc(100vw - 32px)' }}\n panelClassName=\"flex max-h-[min(640px,calc(100vh-120px))] min-h-0 flex-col overflow-hidden rounded-xl bg-[var(--modal-surface)] p-0 shadow-xl\"\n headerClassName=\"flex shrink-0 items-center justify-between px-6 pb-4 pt-5\"\n bodyClassName=\"flex min-h-0 flex-1 flex-col overflow-hidden p-0\"\n backdropClassName=\"p-4\"\n disableBackdropClose\n backdropAriaModal\n backdropAriaLabel=\"问题反馈\"\n panelTestId=\"feedback-modal\"\n >\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div\n ref={focusAreaRef}\n className=\"flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-6 pb-4 pt-4 outline-none\"\n onPaste={handlePaste}\n tabIndex={0}\n role=\"presentation\"\n >\n {/* 反馈类型 */}\n <section className=\"flex flex-col gap-2\">\n <span className=\"text-[14px] font-medium leading-[22px] text-[var(--text-primary)]\">反馈类型</span>\n <div className=\"flex gap-4\">\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => setFeedbackType('bug')}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n setFeedbackType('bug');\n }\n }}\n className={`flex flex-1 cursor-pointer flex-col rounded-lg border text-left transition-colors ${\n feedbackType === 'bug'\n ? 'border-[var(--switch-on-bg)] bg-[var(--surface-panel)]'\n : 'border-[var(--panel-divider)] hover:border-[var(--text-label-secondary)]'\n }`}\n style={{ padding: '12px 24px' }}\n aria-pressed={feedbackType === 'bug'}\n data-testid=\"feedback-type-bug\"\n >\n <div className=\"flex items-center gap-2\">\n <img src=\"/icons/settings-feedback/feedback-bug.svg\" alt=\"\" aria-hidden className=\"h-[18px] w-[18px] shrink-0\" />\n <span className=\"text-[14px] leading-[22px] text-[var(--text-primary)]\">提交BUG</span>\n </div>\n <p className=\"mt-2 text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">\n 报告软件问题;如遇到 BUG 类问题,可先查询 \n <a\n href={OFFICE_CLAW_FAQ_DOC_URL}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"cursor-pointer border-none text-[var(--switch-on-bg)] hover:text-[var(--switch-on-bg)]\"\n onClick={(ev) => ev.stopPropagation()}\n >\n 官方FAQ文档\n </a>\n </p>\n </div>\n\n <button\n type=\"button\"\n onClick={() => setFeedbackType('suggestion')}\n className={`flex flex-1 flex-col rounded-lg border text-left transition-colors ${\n feedbackType === 'suggestion'\n ? 'border-[var(--switch-on-bg)] bg-[var(--surface-panel)]'\n : 'border-[var(--panel-divider)] hover:border-[var(--text-label-secondary)]'\n }`}\n style={{ padding: '12px 24px' }}\n aria-pressed={feedbackType === 'suggestion'}\n data-testid=\"feedback-type-suggestion\"\n >\n <div className=\"flex items-center gap-2\">\n <img src=\"/icons/settings-feedback/feedback-idea.svg\" alt=\"\" aria-hidden className=\"h-[18px] w-[18px] shrink-0\" />\n <span className=\"text-[14px] leading-[22px] text-[var(--text-primary)]\">我有建议</span>\n </div>\n <p className=\"mt-2 text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">提交新功能或者改进措施</p>\n </button>\n </div>\n </section>\n\n {/* 描述 */}\n <section className=\"flex flex-col\">\n <span className=\"text-[14px] font-medium leading-[22px] text-[var(--text-primary)]\">描述</span>\n <p className=\"mt-1 text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">\n 若涉及 AI 对话的相关反馈,请尽可能附带会话信息\n </p>\n <div className=\"relative mt-1 pt-2\">\n <textarea\n value={descValue}\n onChange={(e) => setDescription(e.target.value.slice(0, MAX_DESC))}\n className=\"box-border w-full resize-none rounded-md border border-[var(--panel-divider)] bg-[var(--modal-surface)] px-3 py-2 text-[14px] leading-[22px] text-[var(--text-label-secondary)] outline-none focus:border-[var(--text-primary)] focus:ring-0 placeholder:text-[var(--text-label-secondary)]\"\n style={{ minHeight: 136, maxHeight: 136, paddingBottom: 28 }}\n placeholder=\"请描述您遇到的问题或建议…\"\n aria-labelledby={headingId}\n data-testid=\"feedback-description\"\n />\n <span\n className=\"pointer-events-none absolute bottom-[7px] right-2 rounded px-1.5 text-[12px] leading-[18px] text-[var(--text-label-secondary)] bg-[var(--modal-surface)]\"\n aria-live=\"polite\"\n >\n {descLen}/{MAX_DESC}\n </span>\n </div>\n </section>\n\n {/* 截图 */}\n <section className=\"flex flex-col gap-2\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-[14px] font-medium leading-[22px] text-[var(--text-primary)]\">\n 问题截图\n <span className=\"font-normal text-[var(--text-label-secondary)]\">(可选)</span>\n </span>\n <button\n type=\"button\"\n className=\"cursor-pointer border-none bg-transparent p-0 text-[14px] font-medium leading-[22px] text-[var(--switch-on-bg)] underline-offset-2 hover:underline\"\n onClick={() => fileInputRef.current?.click()}\n data-testid=\"feedback-upload-trigger\"\n >\n 上传图片\n </button>\n </div>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/jpeg,image/png,image/gif,.jpg,.jpeg,.png,.gif\"\n multiple\n className=\"hidden\"\n onChange={handleFileInputChange}\n />\n\n <div\n className=\"relative\"\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n >\n {files.length === 0 ? (\n <button\n type=\"button\"\n className=\"flex h-[100px] w-full flex-col items-center justify-center rounded-[5px] border border-dashed px-4 text-center bg-transparent cursor-pointer\"\n style={{ borderColor: 'rgba(194,194,194,1)' }}\n onClick={() => fileInputRef.current?.click()}\n >\n <FeedbackScreenshotZoneHints />\n </button>\n ) : (\n <div className=\"flex min-h-[100px] flex-col gap-2 rounded-[5px] border border-dashed p-3\" style={{ borderColor: 'rgba(194,194,194,1)' }}>\n {files.map(({ id, file }) => (\n <div\n key={id}\n className=\"group flex items-center gap-1 px-2 rounded-[2px] rounded-[4px] hover:bg-[rgba(245,245,245,1)]\"\n >\n <img src=\"/icons/file.svg\" alt=\"\" className=\"h-5 w-5 shrink-0\" aria-hidden />\n <span\n className=\"min-w-0 flex-1 truncate pl-1 text-[12px] leading-[18px]\"\n style={{ color: 'rgba(89,89,89,1)' }}\n title={file.name}\n >\n {file.name}\n </span>\n <button\n type=\"button\"\n aria-label={`删除 ${file.name}`}\n className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-[2px] border-none bg-transparent opacity-0 transition-opacity group-hover:opacity-100\"\n onClick={() => removeFile(id)}\n >\n <img src=\"/icons/common-delete.svg\" alt=\"\" className=\"h-4 w-4\" aria-hidden />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {dropHighlight ? (\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center rounded-[5px] bg-[rgba(245,245,245,0.92)] px-4 text-center\">\n {files.length > 0 ? (\n <FeedbackScreenshotZoneHints />\n ) : (\n <span className=\"text-[14px] font-medium text-[var(--text-primary)]\">松开以上传到列表</span>\n )}\n </div>\n ) : null}\n </div>\n\n {totalBytes > 0 ? (\n <p className=\"text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">\n 已选 {files.length} 张,约 {formatTotalMB(totalBytes)} MB / 5 MB\n </p>\n ) : null}\n </section>\n\n {feedbackType === 'bug' ? (\n <>\n {/* 联系方式 */}\n <section className=\"flex flex-col\">\n <span className=\"text-[14px] font-medium leading-[22px] text-[var(--text-primary)]\">联系方式</span>\n <p className=\"mt-1 text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">\n 问题排查过程中可能需要补充信息,辛苦提供您的联系方式,帮助我们更好的定位问题\n </p>\n <input\n id={`${fieldIds}-contact`}\n type=\"text\"\n value={contactInfo}\n onChange={(e) => setContactInfo(e.target.value)}\n placeholder=\"可提供电子邮件、手机号等联系方式\"\n className=\"mt-2 box-border w-full rounded-md border border-[var(--panel-divider)] bg-[var(--modal-surface)] px-3 py-1 text-[14px] leading-[22px] text-[var(--text-primary)] outline-none placeholder:text-[var(--text-label-secondary)] focus:border-[var(--text-primary)] focus:ring-0\"\n data-testid=\"feedback-contact\"\n />\n </section>\n\n {/* 辅助信息 */}\n <section className=\"flex flex-col\">\n <span className=\"text-[14px] font-medium leading-[22px] text-[var(--text-primary)]\">辅助信息</span>\n <p className=\"mt-1 text-[12px] leading-[18px] text-[var(--text-label-secondary)]\">\n 以上信息仅用于问题排查、复现和解决\n </p>\n <div className=\"mt-1 flex gap-6 pt-2\">\n <div className=\"flex items-center gap-2\">\n <input\n id={`${fieldIds}-plugins`}\n type=\"checkbox\"\n checked={attachPluginInfo}\n onChange={(e) => setAttachPluginInfo(e.target.checked)}\n className=\"h-4 w-4 shrink-0 cursor-pointer rounded-[4px] border border-[rgba(194,194,194,1)] accent-[var(--switch-on-bg)] text-[var(--switch-on-bg)] focus:ring-0 focus:ring-offset-0\"\n data-testid=\"feedback-attach-plugins\"\n />\n <label\n htmlFor={`${fieldIds}-plugins`}\n className=\"cursor-pointer select-none text-[14px] leading-[22px] text-[var(--text-primary)]\"\n >\n 插件信息\n </label>\n <FeedbackFieldTip text=\"上传已安装的插件的名称、版本及运行状态等信息\" />\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n id={`${fieldIds}-logs`}\n type=\"checkbox\"\n checked={attachAppLogs}\n onChange={(e) => setAttachAppLogs(e.target.checked)}\n className=\"h-4 w-4 shrink-0 cursor-pointer rounded-[4px] border border-[rgba(194,194,194,1)] accent-[var(--switch-on-bg)] text-[var(--switch-on-bg)] focus:ring-0 focus:ring-offset-0\"\n data-testid=\"feedback-attach-logs\"\n />\n <label\n htmlFor={`${fieldIds}-logs`}\n className=\"cursor-pointer select-none text-[14px] leading-[22px] text-[var(--text-primary)]\"\n >\n 应用日志\n </label>\n <FeedbackFieldTip text=\"使用OfficeClaw时产生的日志内容\" />\n </div>\n </div>\n </section>\n </>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 justify-end gap-2 px-6 pb-6 pt-4\">\n <Button variant=\"default\" type=\"button\" onClick={onClose}>\n 取消\n </Button>\n <Button type=\"button\" onClick={onClose} data-testid=\"feedback-submit\">\n 确定\n </Button>\n </div>\n </div>\n </AppModal>\n );\n}\n","'use client';\n\nimport { SESSION_USAGE_TIMEZONE, toDateBucketAtTimezone } from '@hualinge/relay-shared/types';\nimport { apiFetch } from '@/utils/api-client';\n\nexport type UsageRange = 'today' | '3d' | '7d' | '30d';\n\ninterface ThreadSummary {\n id: string;\n title?: string | null;\n}\n\ninterface SessionSummary {\n id: string;\n updatedAt?: number;\n lastUsageAt?: number;\n lastUsage?: {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n };\n totalUsage?: {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n };\n usageByDay?: Record<\n string,\n {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n }\n >;\n}\n\nexport interface UsageStatsDataset {\n threads: Array<{\n id: string;\n title?: string | null;\n }>;\n sessionsByThreadId: Record<\n string,\n Array<{\n id: string;\n updatedAt?: number;\n lastUsageAt?: number;\n lastUsage?: {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n };\n totalUsage?: {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n };\n usageByDay?: Record<\n string,\n {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n }\n >;\n }>\n >;\n}\n\nexport interface UsageStatsItem {\n id: string;\n sessionName: string;\n totalTokensUsed: number | null;\n inputTokensUsed: number | null;\n outputTokensUsed: number | null;\n occurredAt: string;\n}\n\nexport interface UsageStatsPageResult {\n items: UsageStatsItem[];\n page: number;\n pageSize: number;\n total: number;\n}\n\nexport interface UsageStatsPageQuery {\n page: number;\n pageSize: number;\n range: UsageRange;\n}\n\nexport interface UsageStatsFetchOptions {\n signal?: AbortSignal;\n}\n\nconst DEFAULT_USAGE_STATS_TIMEOUT_MS = 60 * 60 * 1000;\n\nasync function fetchUsageStatsResponse(path: string, signal?: AbortSignal): Promise<Response> {\n return await apiFetch(path, { signal, timeoutMs: DEFAULT_USAGE_STATS_TIMEOUT_MS });\n}\n\nconst RANGE_TO_DAY_COUNT: Record<UsageRange, number> = {\n today: 1,\n '3d': 3,\n '7d': 7,\n '30d': 30,\n};\n\ninterface UsageSnapshot {\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n costUsd?: number;\n}\n\ninterface SessionRangeContribution {\n inputTokensUsed: number | null;\n outputTokensUsed: number | null;\n latestUsageTimestampInRange: number | null;\n}\n\nasync function readApiError(response: Response): Promise<string> {\n try {\n const payload = (await response.json()) as Record<string, unknown>;\n if (typeof payload.error === 'string' && payload.error.trim().length > 0) {\n return payload.error;\n }\n if (typeof payload.detail === 'string' && payload.detail.trim().length > 0) {\n return payload.detail;\n }\n } catch {\n // Ignore JSON parse errors and fallback to generic message.\n }\n\n return `Server error: ${response.status}`;\n}\n\nfunction normalizeThreads(payload: unknown): ThreadSummary[] {\n if (Array.isArray(payload)) {\n return payload as ThreadSummary[];\n }\n\n if (payload && typeof payload === 'object' && Array.isArray((payload as { threads?: unknown[] }).threads)) {\n return (payload as { threads: ThreadSummary[] }).threads;\n }\n\n return [];\n}\n\nfunction normalizeSessions(payload: unknown): SessionSummary[] {\n if (Array.isArray(payload)) {\n return payload as SessionSummary[];\n }\n\n if (payload && typeof payload === 'object' && Array.isArray((payload as { sessions?: unknown[] }).sessions)) {\n return (payload as { sessions: SessionSummary[] }).sessions;\n }\n\n return [];\n}\n\nfunction addUsageSnapshots(base: UsageSnapshot | undefined, delta: UsageSnapshot | undefined): UsageSnapshot | undefined {\n if (!base && !delta) return undefined;\n\n const merged: UsageSnapshot = {\n ...(base?.inputTokens != null || delta?.inputTokens != null\n ? { inputTokens: (base?.inputTokens ?? 0) + (delta?.inputTokens ?? 0) }\n : {}),\n ...(base?.outputTokens != null || delta?.outputTokens != null\n ? { outputTokens: (base?.outputTokens ?? 0) + (delta?.outputTokens ?? 0) }\n : {}),\n ...(base?.cacheReadTokens != null || delta?.cacheReadTokens != null\n ? { cacheReadTokens: (base?.cacheReadTokens ?? 0) + (delta?.cacheReadTokens ?? 0) }\n : {}),\n ...(base?.costUsd != null || delta?.costUsd != null\n ? { costUsd: (base?.costUsd ?? 0) + (delta?.costUsd ?? 0) }\n : {}),\n };\n\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\nfunction buildRangeDayKeys(now: number, range: UsageRange): string[] {\n const dayCount = RANGE_TO_DAY_COUNT[range];\n const result: string[] = [];\n for (let offset = 0; offset < dayCount; offset += 1) {\n result.push(toDateBucketAtTimezone(now - offset * 24 * 60 * 60 * 1000, SESSION_USAGE_TIMEZONE));\n }\n return result;\n}\n\nfunction toLocalDateTime(timestamp: number): string {\n return new Date(timestamp).toLocaleString();\n}\n\nfunction getThreadTitle(thread: ThreadSummary): string {\n const title = thread.title?.trim();\n return title && title.length > 0 ? title : '未命名对话';\n}\n\nfunction buildSyntheticUsageByDay(session: SessionSummary): Record<string, UsageSnapshot> | undefined {\n const legacyUsage = session.totalUsage ?? session.lastUsage;\n const legacyUsageAt = session.lastUsageAt ?? session.updatedAt;\n if (!legacyUsage || typeof legacyUsageAt !== 'number') return undefined;\n return {\n [toDateBucketAtTimezone(legacyUsageAt, SESSION_USAGE_TIMEZONE)]: legacyUsage,\n };\n}\n\nfunction getSessionUsageByDay(session: SessionSummary): Record<string, UsageSnapshot> | undefined {\n return session.usageByDay ?? buildSyntheticUsageByDay(session);\n}\n\nfunction getDayBucketTimestamp(day: string): number | null {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(day);\n if (!match) return null;\n\n const [, year, month, date] = match;\n const timestamp = Date.parse(`${year}-${month}-${date}T23:59:59.999+08:00`);\n return Number.isNaN(timestamp) ? null : timestamp;\n}\n\nfunction sumUsageKey(snapshot: UsageSnapshot | undefined, key: 'inputTokens' | 'outputTokens'): number | null {\n const value = snapshot?.[key];\n return typeof value === 'number' ? value : null;\n}\n\nfunction resolveSessionRangeContribution(session: SessionSummary, dayKeys: string[]): SessionRangeContribution {\n const usageByDay = getSessionUsageByDay(session);\n if (!usageByDay) {\n return {\n inputTokensUsed: null,\n outputTokensUsed: null,\n latestUsageTimestampInRange: null,\n };\n }\n\n let mergedUsage: UsageSnapshot | undefined;\n let matched = false;\n let latestMatchedDay: string | null = null;\n for (const day of dayKeys) {\n const snapshot = usageByDay[day];\n if (!snapshot) continue;\n mergedUsage = addUsageSnapshots(mergedUsage, snapshot);\n matched = true;\n if (latestMatchedDay == null) {\n latestMatchedDay = day;\n }\n }\n\n if (!matched) {\n return {\n inputTokensUsed: null,\n outputTokensUsed: null,\n latestUsageTimestampInRange: null,\n };\n }\n\n const hasRealUsageByDay = session.usageByDay != null;\n let latestUsageTimestampInRange: number | null = null;\n\n if (!hasRealUsageByDay) {\n latestUsageTimestampInRange =\n typeof session.lastUsageAt === 'number'\n ? session.lastUsageAt\n : typeof session.updatedAt === 'number'\n ? session.updatedAt\n : latestMatchedDay != null\n ? getDayBucketTimestamp(latestMatchedDay)\n : null;\n } else {\n latestUsageTimestampInRange =\n latestMatchedDay != null ? getDayBucketTimestamp(latestMatchedDay) : null;\n if (latestMatchedDay != null && typeof session.lastUsageAt === 'number') {\n const lastUsageDay = toDateBucketAtTimezone(session.lastUsageAt, SESSION_USAGE_TIMEZONE);\n if (lastUsageDay === latestMatchedDay) {\n latestUsageTimestampInRange = session.lastUsageAt;\n }\n }\n }\n\n return {\n inputTokensUsed: sumUsageKey(mergedUsage, 'inputTokens'),\n outputTokensUsed: sumUsageKey(mergedUsage, 'outputTokens'),\n latestUsageTimestampInRange,\n };\n}\n\nexport function buildUsageStatsPageFromDataset(\n dataset: UsageStatsDataset,\n query: UsageStatsPageQuery,\n now = Date.now(),\n): UsageStatsPageResult {\n const dayKeys = buildRangeDayKeys(now, query.range);\n\n const filteredItems = dataset.threads\n .map((thread) => {\n const sessions = dataset.sessionsByThreadId[thread.id] ?? [];\n let latestUsageTimestampInRange: number | null = null;\n let inputTotal = 0;\n let outputTotal = 0;\n let hasInput = false;\n let hasOutput = false;\n\n for (const session of sessions) {\n const contribution = resolveSessionRangeContribution(session, dayKeys);\n if (typeof contribution.inputTokensUsed === 'number') {\n inputTotal += contribution.inputTokensUsed;\n hasInput = true;\n }\n if (typeof contribution.outputTokensUsed === 'number') {\n outputTotal += contribution.outputTokensUsed;\n hasOutput = true;\n }\n if (\n typeof contribution.latestUsageTimestampInRange === 'number' &&\n (latestUsageTimestampInRange == null || contribution.latestUsageTimestampInRange > latestUsageTimestampInRange)\n ) {\n latestUsageTimestampInRange = contribution.latestUsageTimestampInRange;\n }\n }\n\n if (latestUsageTimestampInRange == null) {\n return null;\n }\n\n const inputTokensUsed = hasInput ? inputTotal : null;\n const outputTokensUsed = hasOutput ? outputTotal : null;\n const totalTokensUsed =\n inputTokensUsed == null && outputTokensUsed == null\n ? null\n : (inputTokensUsed ?? 0) + (outputTokensUsed ?? 0);\n\n return {\n sortKey: latestUsageTimestampInRange,\n item: {\n id: thread.id,\n sessionName: getThreadTitle(thread),\n totalTokensUsed,\n inputTokensUsed,\n outputTokensUsed,\n occurredAt: toLocalDateTime(latestUsageTimestampInRange),\n } satisfies UsageStatsItem,\n };\n })\n .filter((entry): entry is { sortKey: number; item: UsageStatsItem } => entry != null)\n .sort((left, right) => right.sortKey - left.sortKey)\n .map((entry) => entry.item);\n\n const startIndex = Math.max(0, (query.page - 1) * query.pageSize);\n const items = filteredItems.slice(startIndex, startIndex + query.pageSize);\n\n return {\n items,\n page: query.page,\n pageSize: query.pageSize,\n total: filteredItems.length,\n };\n}\n\nexport async function fetchUsageStatsDataset(options?: UsageStatsFetchOptions): Promise<UsageStatsDataset> {\n const threadsResponse = await fetchUsageStatsResponse('/api/threads', options?.signal);\n if (!threadsResponse.ok) {\n throw new Error(await readApiError(threadsResponse));\n }\n\n const threads = normalizeThreads(await threadsResponse.json());\n const sessionEntries = await Promise.all(\n threads.map(async (thread) => {\n const sessionsResponse = await fetchUsageStatsResponse(`/api/threads/${thread.id}/sessions`, options?.signal);\n if (!sessionsResponse.ok) {\n throw new Error(await readApiError(sessionsResponse));\n }\n\n const sessions = normalizeSessions(await sessionsResponse.json());\n return [thread.id, sessions] as const;\n }),\n );\n\n return {\n threads,\n sessionsByThreadId: Object.fromEntries(sessionEntries),\n };\n}\n\nexport async function fetchUsageStatsPage(query: UsageStatsPageQuery): Promise<UsageStatsPageResult> {\n const dataset = await fetchUsageStatsDataset();\n return buildUsageStatsPageFromDataset(dataset, query);\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useEscapeKey } from '@/hooks/useEscapeKey';\nimport {\n buildUsageStatsPageFromDataset,\n fetchUsageStatsDataset,\n type UsageRange,\n type UsageStatsFetchOptions,\n type UsageStatsDataset,\n type UsageStatsPageResult,\n} from '@/services/usageStats';\nimport { AppModal } from './AppModal';\nimport { CenteredLoadingState } from './shared/CenteredLoadingState';\nimport { EmptyDataState } from './shared/EmptyDataState';\nimport { OverflowTooltip } from './shared/OverflowTooltip';\nimport { RefreshButton } from './shared/RefreshButton';\nimport { formatTokenCount } from './status-helpers';\n\ninterface UsageStatsModalProps {\n open: boolean;\n onClose: () => void;\n fetchDataset?: (options?: UsageStatsFetchOptions) => Promise<UsageStatsDataset>;\n}\n\nconst PAGE_SIZE = 5;\nconst MIN_LOADING_MS = 300;\n\nconst RANGE_OPTIONS: Array<{ value: UsageRange; label: string }> = [\n { value: 'today', label: '今日' },\n { value: '3d', label: '近3日' },\n { value: '7d', label: '近7日' },\n { value: '30d', label: '近30日' },\n];\n\nconst EMPTY_RESULT: UsageStatsPageResult = {\n items: [],\n page: 1,\n pageSize: PAGE_SIZE,\n total: 0,\n};\n\nconst TABLE_STATE_ROW_HEIGHT_CLASS = 'h-40';\n\nexport function formatPaginationPages(currentPage: number, totalPages: number): Array<number | 'ellipsis'> {\n if (totalPages <= 8) {\n return Array.from({ length: totalPages }, (_, index) => index + 1);\n }\n\n const pages = new Set<number>([\n 1,\n 2,\n totalPages - 1,\n totalPages,\n currentPage - 2,\n currentPage - 1,\n currentPage,\n currentPage + 1,\n currentPage + 2,\n ]);\n const sortedPages = Array.from(pages)\n .filter((page) => page >= 1 && page <= totalPages)\n .sort((a, b) => a - b);\n const result: Array<number | 'ellipsis'> = [];\n\n for (let index = 0; index < sortedPages.length; index += 1) {\n const page = sortedPages[index];\n const previous = sortedPages[index - 1];\n if (previous != null && page - previous > 1) {\n result.push('ellipsis');\n }\n result.push(page);\n }\n\n return result;\n}\n\nfunction renderTokenValue(value: number | null): string {\n if (value == null) return '';\n return formatTokenCount(value);\n}\n\nexport function UsageStatsModal({ open, onClose, fetchDataset = fetchUsageStatsDataset }: UsageStatsModalProps) {\n const rangeMenuRef = useRef<HTMLDivElement | null>(null);\n const [range, setRange] = useState<UsageRange>('7d');\n const [page, setPage] = useState(1);\n const [refreshKey, setRefreshKey] = useState(0);\n const [isRangeMenuOpen, setIsRangeMenuOpen] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [dataset, setDataset] = useState<UsageStatsDataset | null>(null);\n\n useEffect(() => {\n if (!open) return;\n\n let cancelled = false;\n const controller = new AbortController();\n let loadingDelayId: ReturnType<typeof setTimeout> | null = null;\n\n const waitForMinimumLoadingTime = async (elapsed: number) => {\n if (cancelled || elapsed >= MIN_LOADING_MS) return;\n\n await new Promise<void>((resolve) => {\n const cleanupDelay = () => {\n if (loadingDelayId != null) {\n clearTimeout(loadingDelayId);\n loadingDelayId = null;\n }\n controller.signal.removeEventListener('abort', handleAbort);\n };\n\n const handleAbort = () => {\n cleanupDelay();\n resolve();\n };\n\n loadingDelayId = setTimeout(() => {\n cleanupDelay();\n resolve();\n }, MIN_LOADING_MS - elapsed);\n\n controller.signal.addEventListener('abort', handleAbort, { once: true });\n });\n };\n\n const load = async () => {\n const startedAt = Date.now();\n setIsLoading(true);\n setError(null);\n\n try {\n const next = await fetchDataset({ signal: controller.signal });\n if (cancelled) return;\n setDataset(next);\n } catch (error) {\n if (cancelled) return;\n if (error instanceof DOMException && error.name === 'AbortError') return;\n setError('用量数据加载失败,请稍后重试');\n setDataset(null);\n } finally {\n const elapsed = Date.now() - startedAt;\n await waitForMinimumLoadingTime(elapsed);\n\n if (!cancelled) {\n setIsLoading(false);\n }\n }\n };\n\n void load();\n\n return () => {\n cancelled = true;\n controller.abort();\n if (loadingDelayId != null) {\n clearTimeout(loadingDelayId);\n loadingDelayId = null;\n }\n };\n }, [fetchDataset, open, refreshKey]);\n\n useEscapeKey({\n enabled: open,\n onEscape: onClose,\n });\n\n useEffect(() => {\n if (!open) {\n setIsRangeMenuOpen(false);\n setDataset(null);\n setError(null);\n setPage(1);\n setRange('7d');\n }\n }, [open]);\n\n useEffect(() => {\n if (!isRangeMenuOpen) return;\n\n const handlePointerDown = (event: MouseEvent) => {\n if (rangeMenuRef.current?.contains(event.target as Node)) return;\n setIsRangeMenuOpen(false);\n };\n\n document.addEventListener('mousedown', handlePointerDown);\n return () => {\n document.removeEventListener('mousedown', handlePointerDown);\n };\n }, [isRangeMenuOpen]);\n\n const result =\n dataset == null ? EMPTY_RESULT : buildUsageStatsPageFromDataset(dataset, { page, pageSize: PAGE_SIZE, range });\n const totalPages = Math.max(1, Math.ceil(result.total / PAGE_SIZE));\n const showPagination = result.total > PAGE_SIZE;\n const paginationItems = showPagination ? formatPaginationPages(page, totalPages) : [];\n\n useEffect(() => {\n if (page > totalPages) {\n setPage(totalPages);\n }\n }, [page, totalPages]);\n\n const handleRefresh = () => {\n if (isLoading) return;\n setRefreshKey((current) => current + 1);\n };\n\n const handleChangeRange = (nextRange: UsageRange) => {\n if (isLoading) return;\n setRange(nextRange);\n setPage(1);\n setIsRangeMenuOpen(false);\n };\n\n return (\n <AppModal\n open={open}\n onClose={onClose}\n title=\"用量统计\"\n backdropRole=\"dialog\"\n backdropAriaModal\n backdropAriaLabel=\"用量统计弹窗\"\n panelClassName=\"w-full max-w-[900px] overflow-x-auto\"\n bodyClassName=\"pt-6\"\n disableBackdropClose\n panelTestId=\"usage-stats-modal-panel\"\n bodyTestId=\"usage-stats-modal-body\"\n closeButtonAriaLabel=\"关闭用量统计弹窗\"\n >\n <div className=\"space-y-4 min-w-[300px]\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"text-[14px] font-semibold leading-none text-[var(--modal-title-text)]\">Tokens消耗</h4>\n\n <div className=\"flex items-center gap-2\">\n <div className=\"relative\" ref={rangeMenuRef}>\n <button\n type=\"button\"\n className=\"flex items-center gap-1 text-[12px] font-medium text-[var(--modal-text)]\"\n onClick={() => {\n if (isLoading) return;\n setIsRangeMenuOpen((current) => !current);\n }}\n disabled={isLoading}\n data-testid=\"usage-stats-range-trigger\"\n >\n {RANGE_OPTIONS.find((option) => option.value === range)?.label ?? '近7日'}\n <svg className=\"h-4 w-4 text-[var(--modal-text-subtle)]\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M5 7.5L10 12.5L15 7.5\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" />\n </svg>\n </button>\n\n {isRangeMenuOpen ? (\n <div\n className=\"absolute right-0 top-full z-10 mt-2 min-w-[104px] rounded-xl border border-[var(--modal-border)] bg-[var(--modal-surface)] p-1.5 shadow-[var(--modal-shadow)]\"\n data-testid=\"usage-stats-range-menu\"\n >\n {RANGE_OPTIONS.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n className={`flex w-full rounded-lg px-3 py-2 text-left text-[12px] ${\n option.value === range\n ? 'text-[var(--modal-accent-text)]'\n : 'text-[var(--modal-text)] hover:bg-[var(--modal-muted-surface)]'\n }`}\n onClick={() => handleChangeRange(option.value)}\n >\n {option.label}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n\n <div className=\"h-4 w-px bg-[var(--modal-table-divider)]\" aria-hidden=\"true\" />\n\n <RefreshButton\n bordered={false}\n onClick={handleRefresh}\n aria-label=\"刷新\"\n disabled={isLoading}\n data-testid=\"usage-stats-refresh\"\n >\n <img\n src=\"/images/agent-management-icons/agent-refresh.svg\"\n alt=\"\"\n aria-hidden=\"true\"\n width={16}\n height={16}\n className=\"shrink-0\"\n />\n </RefreshButton>\n </div>\n </div>\n\n <div className=\"relative overflow-x-auto overflow-y-hidden rounded-[0.5rem] border border-[var(--modal-muted-border)] bg-[var(--modal-surface)] [scrollbar-gutter:auto]\">\n <div className=\"w-full rounded-[0.5rem]\">\n <table className=\"w-full border-collapse table-fixed min-w-[49.5rem]\">\n <thead className=\"bg-[var(--modal-table-header-bg)]\">\n <tr className=\"text-left text-[12px] text-[var(--modal-text-muted)]\">\n <th className=\"relative h-12 border-b border-[var(--modal-table-divider)] px-4 py-0\">\n 会话\n <span\n className=\"absolute right-0 top-1/2 h-4 w-px -translate-y-1/2 bg-[var(--modal-table-divider)]\"\n aria-hidden=\"true\"\n />\n </th>\n <th className=\"relative h-12 w-[150px] border-b border-[var(--modal-table-divider)] px-4 py-0\">\n Input Tokens消耗\n <span\n className=\"absolute right-0 top-1/2 h-4 w-px -translate-y-1/2 bg-[var(--modal-table-divider)]\"\n aria-hidden=\"true\"\n />\n </th>\n <th className=\"relative h-12 w-[150px] border-b border-[var(--modal-table-divider)] px-4 py-0\">\n Output Tokens消耗\n <span\n className=\"absolute right-0 top-1/2 h-4 w-px -translate-y-1/2 bg-[var(--modal-table-divider)]\"\n aria-hidden=\"true\"\n />\n </th>\n <th className=\"relative h-12 w-[132px] border-b border-[var(--modal-table-divider)] px-4 py-0\">\n 总Tokens消耗\n <span\n className=\"absolute right-0 top-1/2 h-4 w-px -translate-y-1/2 bg-[var(--modal-table-divider)]\"\n aria-hidden=\"true\"\n />\n </th>\n <th className=\"h-12 w-[200px] border-b border-[var(--modal-table-divider)] px-4 py-0\">时间</th>\n </tr>\n </thead>\n <tbody>\n {error ? (\n <tr>\n <td colSpan={5} className={`${TABLE_STATE_ROW_HEIGHT_CLASS} px-4 py-0`}>\n <div className=\"flex h-full items-center justify-center\">\n <EmptyDataState />\n </div>\n </td>\n </tr>\n ) : isLoading && result.items.length === 0 ? (\n <tr>\n <td colSpan={5} className={`${TABLE_STATE_ROW_HEIGHT_CLASS} px-4 py-0`} />\n </tr>\n ) : !isLoading && result.items.length === 0 ? (\n <tr>\n <td colSpan={5} className={`${TABLE_STATE_ROW_HEIGHT_CLASS} px-4 py-0`}>\n <div className=\"flex h-full items-center justify-center\">\n <EmptyDataState />\n </div>\n </td>\n </tr>\n ) : (\n result.items.map((item) => (\n <tr key={item.id} className=\"border-t border-[var(--modal-table-divider)]\" data-testid={`usage-stats-row-${item.id}`}>\n <td className=\"h-16 px-4 py-0 text-[14px] text-[var(--modal-text)]\">\n <OverflowTooltip content={item.sessionName} className=\"w-full\">\n <span className=\"block truncate\">{item.sessionName}</span>\n </OverflowTooltip>\n </td>\n <td\n className=\"h-16 px-4 py-0 text-[14px] text-[var(--modal-text)]\"\n title={item.inputTokensUsed != null ? item.inputTokensUsed.toLocaleString() : undefined}\n >\n {renderTokenValue(item.inputTokensUsed)}\n </td>\n <td\n className=\"h-16 px-4 py-0 text-[14px] text-[var(--modal-text)]\"\n title={item.outputTokensUsed != null ? item.outputTokensUsed.toLocaleString() : undefined}\n >\n {renderTokenValue(item.outputTokensUsed)}\n </td>\n <td\n className=\"h-16 px-4 py-0 text-[14px] text-[var(--modal-text)]\"\n title={item.totalTokensUsed != null ? item.totalTokensUsed.toLocaleString() : undefined}\n >\n {renderTokenValue(item.totalTokensUsed)}\n </td>\n <td className=\"h-16 px-4 py-0 text-[12px] text-[var(--modal-text)]\">{item.occurredAt}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {isLoading ? (\n <div\n className=\"absolute inset-x-0 bottom-0 top-12 flex items-center justify-center bg-[var(--modal-loading-overlay)]\"\n data-testid=\"usage-stats-loading-overlay\"\n >\n <CenteredLoadingState />\n </div>\n ) : null}\n </div>\n\n {showPagination ? (\n <div className=\"flex items-center justify-end gap-1\" data-testid=\"usage-stats-pagination\">\n <button\n type=\"button\"\n className=\"flex h-8 w-8 items-center justify-center rounded-full text-[var(--modal-text-subtle)] disabled:cursor-not-allowed disabled:opacity-40\"\n onClick={() => {\n if (isLoading) return;\n setPage((current) => Math.max(1, current - 1));\n }}\n disabled={isLoading || page <= 1}\n aria-label=\"上一页\"\n >\n <svg className=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M11.5 5L6.5 10L11.5 15\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" />\n </svg>\n </button>\n\n {paginationItems.map((item, index) =>\n item === 'ellipsis' ? (\n <span key={`ellipsis-${index}`} className=\"px-2 text-[14px] text-[var(--modal-text-subtle)]\">\n ...\n </span>\n ) : (\n <button\n key={item}\n type=\"button\"\n className={`flex h-8 min-w-8 items-center justify-center rounded-full px-2 text-[12px] ${\n item === page\n ? 'bg-[var(--modal-muted-surface)] text-[var(--modal-text)]'\n : 'text-[var(--modal-text-muted)] hover:bg-[var(--modal-muted-surface)]'\n }`}\n onClick={() => {\n if (isLoading) return;\n setPage(item);\n }}\n disabled={isLoading}\n >\n {item}\n </button>\n ),\n )}\n\n <button\n type=\"button\"\n className=\"flex h-8 w-8 items-center justify-center rounded-full text-[var(--modal-text-subtle)] disabled:cursor-not-allowed disabled:opacity-40\"\n onClick={() => {\n if (isLoading) return;\n setPage((current) => Math.min(totalPages, current + 1));\n }}\n disabled={isLoading || page >= totalPages}\n aria-label=\"下一页\"\n >\n <svg className=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8.5 5L13.5 10L8.5 15\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" />\n </svg>\n </button>\n </div>\n ) : null}\n </div>\n </AppModal>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nexport type DesktopCloseAction = 'ask' | 'minimize' | 'exit';\n\ntype DesktopCloseActionStateMessage = {\n type?: string;\n value: DesktopCloseAction;\n};\n\ntype WebViewMessageEvent = {\n data?: unknown;\n};\n\ntype WebViewBridge = {\n postMessage(message: string): void;\n addEventListener?(eventName: 'message', listener: (event: WebViewMessageEvent) => void): void;\n removeEventListener?(eventName: 'message', listener: (event: WebViewMessageEvent) => void): void;\n};\n\ndeclare global {\n interface Window {\n chrome?: {\n webview?: WebViewBridge;\n };\n }\n}\n\nconst CLOSE_ACTION_SYNC_MESSAGE = 'desktop.closeAction.sync';\nconst CLOSE_ACTION_SET_MESSAGE = 'desktop.closeAction.set';\nconst CLOSE_ACTION_STATE_MESSAGE = 'desktop.closeAction.state';\n\nfunction getWebViewBridge(): WebViewBridge | null {\n if (typeof window === 'undefined') {\n return null;\n }\n\n return window.chrome?.webview ?? null;\n}\n\nfunction isCloseAction(value: unknown): value is DesktopCloseAction {\n return value === 'ask' || value === 'minimize' || value === 'exit';\n}\n\nfunction isCloseActionStateMessage(value: unknown): value is DesktopCloseActionStateMessage {\n if (!value || typeof value !== 'object') {\n return false;\n }\n\n const message = value as DesktopCloseActionStateMessage;\n return message.type === CLOSE_ACTION_STATE_MESSAGE && isCloseAction(message.value);\n}\n\nexport function useDesktopCloseActionSetting(enabled: boolean) {\n const [closeAction, setCloseActionState] = useState<DesktopCloseAction>('ask');\n const isDesktopHost = useMemo(() => getWebViewBridge() !== null, []);\n\n useEffect(() => {\n if (!enabled || !isDesktopHost) {\n return;\n }\n\n const webview = getWebViewBridge();\n if (!webview) {\n return;\n }\n\n const handleMessage = (event: WebViewMessageEvent) => {\n if (!isCloseActionStateMessage(event.data)) {\n return;\n }\n\n setCloseActionState(event.data.value);\n };\n\n webview.addEventListener?.('message', handleMessage);\n webview.postMessage(JSON.stringify({ type: CLOSE_ACTION_SYNC_MESSAGE }));\n\n return () => {\n webview.removeEventListener?.('message', handleMessage);\n };\n }, [enabled, isDesktopHost]);\n\n const setCloseAction = useCallback(\n (value: DesktopCloseAction) => {\n setCloseActionState(value);\n getWebViewBridge()?.postMessage(JSON.stringify({ type: CLOSE_ACTION_SET_MESSAGE, value }));\n },\n [],\n );\n\n return {\n closeAction,\n isDesktopHost,\n setCloseAction,\n };\n}\n","'use client';\n\nimport {\n type DesktopCloseAction,\n useDesktopCloseActionSetting,\n} from '@/hooks/useDesktopCloseActionSetting';\n\nconst CLOSE_ACTION_OPTIONS: Array<{ value: DesktopCloseAction; label: string }> = [\n { value: 'ask', label: '每次询问' },\n { value: 'minimize', label: '最小化到托盘' },\n { value: 'exit', label: '直接退出' },\n];\n\nexport function DesktopCloseActionSetting({ enabled }: { enabled: boolean }) {\n const { closeAction, setCloseAction } = useDesktopCloseActionSetting(enabled);\n\n return (\n <section>\n <div className='flex items-center justify-between gap-3'>\n <div className='min-w-0 flex-1'>\n <h4 className='text-[14px] font-medium leading-[22px] text-[var(--text-primary)]'>关闭窗口行为设置</h4>\n </div>\n <select\n value={closeAction}\n onChange={(event) => setCloseAction(event.target.value as DesktopCloseAction)}\n aria-label='选择关闭窗口行为'\n data-testid='user-settings-desktop-close-action-select'\n className='h-[28px] w-[200px] rounded-[8px] border border-[var(--border-default)] bg-[var(--surface-panel)] px-2.5 text-[13px] leading-5 text-[var(--text-primary)] outline-none transition-colors hover:border-[var(--text-secondary)] focus:border-[var(--switch-on-bg)]'\n >\n {CLOSE_ACTION_OPTIONS.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n </section>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport { type ThemeType } from '@/utils/theme-persistence';\n\nexport interface UserThemeOption {\n id: ThemeType;\n label: string;\n swatchBackground: string;\n selectedBadgeBackground: string;\n selectedBadgeColor: string;\n}\n\n/** Theme choices shown in the profile theme popover and settings modal (subset of ThemeType). */\nexport const USER_THEME_OPTIONS: UserThemeOption[] = [\n {\n id: 'business',\n label: '灰白',\n swatchBackground: 'var(--theme-preview-business-bg)',\n selectedBadgeBackground: 'var(--theme-preview-business-badge)',\n selectedBadgeColor: 'var(--theme-preview-business-check)',\n },\n {\n id: 'warm',\n label: '橙白',\n swatchBackground: 'var(--theme-preview-warm-bg)',\n selectedBadgeBackground: 'var(--theme-preview-warm-badge)',\n selectedBadgeColor: 'var(--theme-preview-warm-check)',\n },\n // {\n // id: 'dark',\n // label: '暗黑',\n // swatchBackground: 'var(--theme-preview-dark-bg)',\n // selectedBadgeBackground: 'var(--theme-preview-dark-badge)',\n // selectedBadgeColor: 'var(--theme-preview-dark-check)',\n // },\n];\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { type ThemeType } from '@/utils/theme-persistence';\nimport { USER_THEME_OPTIONS } from '@/constants/userThemeOptions';\n\nexport interface UserThemePickerProps {\n theme: ThemeType;\n onSelectTheme: (theme: ThemeType) => void;\n optionsTestId?: string;\n}\n\nexport function UserThemePicker({\n theme,\n onSelectTheme,\n optionsTestId = 'user-theme-options',\n}: UserThemePickerProps) {\n return (\n <div className='flex items-start gap-4' data-testid={optionsTestId}>\n {USER_THEME_OPTIONS.map((option) => {\n const isActive = theme === option.id;\n return (\n <button\n key={option.id}\n type='button'\n onClick={() => onSelectTheme(option.id)}\n className={`ui-overlay-item flex flex-col items-center gap-2 text-center text-[var(--overlay-text)] hover:border-transparent hover:bg-transparent hover:text-[var(--overlay-text)] focus-visible:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--overlay-text)]`}\n data-testid={`user-theme-option-${option.id}`}\n >\n <div className='relative'>\n <div\n className='h-9 w-9 rounded-full'\n data-testid={`user-theme-swatch-${option.id}`}\n style={{ background: option.swatchBackground }}\n />\n {isActive ? (\n <div\n className='absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full'\n data-testid={`user-theme-selected-badge-${option.id}`}\n style={{\n backgroundColor: option.selectedBadgeBackground,\n color: option.selectedBadgeColor,\n }}\n >\n <svg className='h-[12px] w-[12px]' viewBox='0 0 16 16' fill='none' aria-hidden='true'>\n <path\n d='M4 8.25 6.5 10.75 12 5.25'\n stroke='currentColor'\n strokeWidth='2'\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n </svg>\n </div>\n ) : null}\n </div>\n <span className='whitespace-nowrap text-[12px] font-medium leading-[18px] text-[var(--overlay-text)]'>\n {option.label}\n </span>\n </button>\n );\n })}\n </div>\n );\n}\n","'use client';\n\nimport { type ThemeType } from '@/hooks/useTheme';\nimport { DesktopCloseActionSetting } from './DesktopCloseActionSetting';\nimport { UserThemePicker } from './UserThemePicker';\nimport { ToggleSwitch } from './shared/ToggleSwitch';\n\ninterface GeneralSettingsTabProps {\n keepAwakeEnabled: boolean;\n isKeepAwakeLoading: boolean;\n isKeepAwakeSaving: boolean;\n onToggleKeepAwake: (checked: boolean) => void;\n theme: ThemeType;\n onSelectTheme: (theme: ThemeType) => void;\n active: boolean;\n}\n\nexport function GeneralSettingsTab({\n keepAwakeEnabled,\n isKeepAwakeLoading,\n isKeepAwakeSaving,\n onToggleKeepAwake,\n theme,\n onSelectTheme,\n active,\n}: GeneralSettingsTabProps) {\n return (\n <>\n <section>\n <div className='flex items-center justify-between gap-3'>\n <h4 className='min-w-0 flex-1 text-[14px] font-medium leading-[22px] text-[var(--text-primary)]'>防休眠</h4>\n <ToggleSwitch\n checked={keepAwakeEnabled}\n onToggle={onToggleKeepAwake}\n ariaLabel='切换防休眠'\n disabled={isKeepAwakeLoading || isKeepAwakeSaving}\n testId='user-settings-keep-awake-switch'\n />\n </div>\n <p className='mt-1 text-[12px] leading-[20px] text-[var(--text-secondary)]'>\n 开启后电脑不会进入休眠模式,方便远程操控以及自动化任务持续执行。\n </p>\n </section>\n <section>\n <h4 className='text-[14px] font-medium leading-[22px] text-[var(--text-primary)]'>主题模式</h4>\n <div className='mt-2'>\n <UserThemePicker theme={theme} onSelectTheme={onSelectTheme} />\n </div>\n </section>\n <DesktopCloseActionSetting enabled={active} />\n </>\n );\n}\n","'use client';\n\nimport { create } from 'zustand';\n\nexport type DownloadStatus = 'idle' | 'downloading' | 'success' | 'error' | 'cancelled' | 'installing';\n\nexport interface DownloadProgress {\n status: DownloadStatus;\n progress: number;\n totalBytes: number;\n receivedBytes: number;\n fileName: string;\n filePath: string | null;\n errorMessage: string | null;\n startTime: number | null;\n endTime: number | null;\n}\n\nexport interface DownloadState {\n taskId: string;\n progress: DownloadProgress;\n isLoading: boolean;\n setTaskId: (taskId: string) => void;\n updateProgress: (progress: DownloadProgress) => void;\n setLoading: (loading: boolean) => void;\n setInstalling: () => void;\n reset: () => void;\n}\n\nconst initialProgress: DownloadProgress = {\n status: 'idle',\n progress: 0,\n totalBytes: 0,\n receivedBytes: 0,\n fileName: '',\n filePath: null,\n errorMessage: null,\n startTime: null,\n endTime: null,\n};\n\nexport const useDownloadStore = create<DownloadState>((set) => ({\n taskId: '',\n progress: initialProgress,\n isLoading: false,\n\n setTaskId: (taskId) => set({ taskId }),\n\n updateProgress: (progress) => set({ progress, isLoading: false }),\n\n setLoading: (loading) => set({ isLoading: loading }),\n\n setInstalling: () => set({ progress: { ...initialProgress, status: 'installing' } }),\n\n reset: () =>\n set({\n taskId: '',\n progress: initialProgress,\n isLoading: false,\n }),\n}));\n","import React, { useEffect, useRef } from 'react';\nimport { type DownloadProgress, useDownloadStore } from '@/stores/downloadStore';\nimport { apiFetch } from '@/utils/api-client';\nimport { Button } from './shared/Button';\nimport { IconButton } from './shared/IconButton';\n\nexport interface VersionInfo {\n curversion: string;\n lastversion: string;\n description: string;\n downloadUrl?: string;\n download_url?: string;\n}\n\nexport interface VersionUpdatePanelProps {\n versionInfo?: VersionInfo | null;\n /** When false, clear polling / download UI state (same as closing the modal). */\n active: boolean;\n /** e.g. close modal — optional for embedded usage */\n onDismiss?: () => void;\n variant?: 'modal' | 'embedded';\n}\n\nconst newVersionTitleStyle = {\n background:\n 'linear-gradient(160deg, rgba(249, 146, 53, 1), rgba(250, 106, 52, 1) 50%, rgba(253, 77, 99, 1) 72%, rgba(248, 68, 51, 1) 100%)',\n WebkitBackgroundClip: 'text',\n WebkitTextFillColor: 'transparent',\n backgroundClip: 'text',\n textFillColor: 'transparent',\n fontFamily: '.PingFang SC',\n fontSize: '20px',\n fontWeight: 700,\n lineHeight: '30px',\n} as React.CSSProperties & { textFillColor: string };\n\nfunction normalizeVersion(version: string): number[] {\n return version\n .trim()\n .replace(/^[^\\d]*/, '')\n .split(/[.\\-+_]/)\n .map((part) => Number.parseInt(part, 10))\n .map((part) => (Number.isFinite(part) ? part : 0));\n}\n\nfunction compareVersions(a: string, b: string): number {\n const aParts = normalizeVersion(a);\n const bParts = normalizeVersion(b);\n const maxLen = Math.max(aParts.length, bParts.length);\n\n for (let i = 0; i < maxLen; i += 1) {\n const aVal = aParts[i] ?? 0;\n const bVal = bParts[i] ?? 0;\n if (aVal > bVal) return 1;\n if (aVal < bVal) return -1;\n }\n\n return 0;\n}\n\nconst VersionUpdatePanel: React.FC<VersionUpdatePanelProps> = ({\n active,\n onDismiss,\n versionInfo,\n variant = 'modal',\n}) => {\n const downloadState = useDownloadStore();\n const pollIntervalRef = useRef<NodeJS.Timeout | null>(null);\n const resetRef = useRef(downloadState.reset);\n const taskIdRef = useRef(downloadState.taskId);\n const setTaskIdRef = useRef(downloadState.setTaskId);\n const updateProgressRef = useRef(downloadState.updateProgress);\n\n resetRef.current = downloadState.reset;\n taskIdRef.current = downloadState.taskId;\n setTaskIdRef.current = downloadState.setTaskId;\n updateProgressRef.current = downloadState.updateProgress;\n\n const currentVersion = versionInfo?.curversion ?? '';\n const hasNewVersion =\n !!versionInfo?.lastversion &&\n !!versionInfo?.curversion &&\n compareVersions(versionInfo.lastversion, currentVersion) > 0;\n\n const iconAlignmentClassName =\n variant === 'embedded' || (variant === 'modal' && hasNewVersion) ? 'justify-start' : 'justify-center';\n const contentAlignmentClassName =\n variant === 'embedded' || (variant === 'modal' && hasNewVersion) ? 'text-left' : 'text-center';\n\n useEffect(() => {\n if (!active || !versionInfo?.lastversion || !hasNewVersion) return;\n\n const taskId = `version-${versionInfo.lastversion}`;\n if (taskIdRef.current && taskIdRef.current !== taskId) {\n resetRef.current();\n }\n\n if (!hasNewVersion) return;\n\n const checkDownloadStatus = async (tid: string) => {\n try {\n const res = await apiFetch(`/api/download/status?taskId=${tid}`);\n if (res.ok) {\n const progress = (await res.json()) as DownloadProgress;\n setTaskIdRef.current(tid);\n updateProgressRef.current(progress);\n }\n } catch (error) {\n console.error('查询下载状态失败:', error);\n }\n };\n\n void checkDownloadStatus(taskId);\n }, [active, hasNewVersion, versionInfo?.lastversion, versionInfo?.curversion]);\n\n useEffect(() => {\n if (!active) {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n resetRef.current();\n }\n }, [active]);\n\n useEffect(() => {\n if (!active) return;\n if (hasNewVersion) return;\n if (downloadState.progress.status === 'idle' && !downloadState.taskId) return;\n resetRef.current();\n }, [active, hasNewVersion, downloadState.progress.status, downloadState.taskId]);\n\n useEffect(() => {\n if (downloadState.progress.status !== 'downloading' || !downloadState.taskId) {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n return;\n }\n\n if (pollIntervalRef.current) return;\n\n const pollDownloadProgress = async () => {\n try {\n const res = await apiFetch(`/api/download/status?taskId=${downloadState.taskId}`);\n if (res.ok) {\n const progress = (await res.json()) as DownloadProgress;\n updateProgressRef.current(progress);\n\n if (progress.status === 'success' || progress.status === 'error' || progress.status === 'cancelled') {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n }\n }\n } catch (error) {\n console.error('查询下载进度失败:', error);\n }\n };\n\n pollIntervalRef.current = setInterval(pollDownloadProgress, 1000);\n\n return () => {\n if (pollIntervalRef.current) {\n clearInterval(pollIntervalRef.current);\n pollIntervalRef.current = null;\n }\n };\n }, [downloadState.progress.status, downloadState.taskId]);\n\n const handleDownload = async () => {\n const taskId = `version-${versionInfo?.lastversion || 'latest'}`;\n\n downloadState.setTaskId(taskId);\n downloadState.setLoading(true);\n\n try {\n const res = await apiFetch('/api/download/start', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ taskId }),\n });\n\n if (res.ok) {\n const progress = (await res.json()) as DownloadProgress;\n downloadState.updateProgress(progress);\n } else {\n const error = await res.json();\n downloadState.updateProgress({\n status: 'error',\n progress: 0,\n totalBytes: 0,\n receivedBytes: 0,\n fileName: '',\n filePath: null,\n errorMessage: error.error || '启动下载失败',\n startTime: null,\n endTime: null,\n });\n }\n } catch (error) {\n downloadState.updateProgress({\n status: 'error',\n progress: 0,\n totalBytes: 0,\n receivedBytes: 0,\n fileName: '',\n filePath: null,\n errorMessage: error instanceof Error ? error.message : '启动下载失败',\n startTime: null,\n endTime: null,\n });\n }\n };\n\n const handleDismiss = () => {\n if (downloadState.progress.status === 'success' || downloadState.progress.status === 'error') {\n downloadState.reset();\n }\n onDismiss?.();\n };\n\n const openDownloadFile = async () => {\n if (!downloadState.taskId) return;\n\n downloadState.setInstalling();\n\n try {\n const res = await apiFetch(`/api/download/open?taskId=${downloadState.taskId}`, { method: 'POST' });\n if (res.ok) {\n downloadState.reset();\n onDismiss?.();\n }\n } catch (error) {\n console.error('打开文件失败:', error);\n downloadState.updateProgress({\n ...downloadState.progress,\n status: 'error',\n errorMessage: '打开安装程序失败',\n });\n }\n };\n\n const renderButtonArea = () => {\n if (!hasNewVersion) return null;\n\n if (downloadState.progress.status === 'downloading') {\n return (\n <div className=\"text-left w-full flex justify-end\">\n <Button size=\"lg\" disabled>\n 更新中\n </Button>\n </div>\n );\n }\n\n if (downloadState.progress.status === 'installing') {\n return (\n <div className=\"text-left\">\n <Button size=\"sm\" disabled>\n 安装中\n </Button>\n </div>\n );\n }\n\n if (downloadState.progress.status === 'success') {\n return (\n <div className=\"text-left w-full flex justify-end\">\n <Button size=\"lg\" onClick={openDownloadFile}>\n 重启更新\n </Button>\n </div>\n );\n }\n\n if (downloadState.progress.status === 'error') {\n return (\n <div className=\"flex gap-3 justify-start\">\n <Button variant=\"default\" size=\"sm\" onClick={handleDismiss}>\n 关闭\n </Button>\n <Button\n size=\"sm\"\n onClick={() => {\n downloadState.reset();\n void handleDownload();\n }}\n >\n 重试\n </Button>\n </div>\n );\n }\n\n return (\n <div className=\"flex w-full flex-wrap justify-end\">\n <Button size=\"lg\" data-testid=\"version-update-confirm\" onClick={() => void handleDownload()}>\n 立即更新\n </Button>\n </div>\n );\n };\n\n const iconMb = variant === 'modal' ? 'mb-8' : 'mb-4';\n const lobsterClass = variant === 'modal' ? 'h-[64px] w-[64px]' : 'h-[56px] w-[56px]';\n\n const titleBlock = (\n <>\n <div className={`flex ${iconAlignmentClassName} ${iconMb}`}>\n <img src=\"/images/lobster.svg\" alt=\"版本更新\" className={`${lobsterClass} object-contain`} />\n </div>\n\n <div className=\"mb-1\">\n {hasNewVersion && downloadState.progress.status === 'error' ? (\n <span data-testid=\"version-update-title\" style={newVersionTitleStyle}>\n 下载失败\n </span>\n ) : hasNewVersion && downloadState.progress.status === 'success' ? (\n <span data-testid=\"version-update-title\" style={newVersionTitleStyle}>\n 更新已就绪\n </span>\n ) : hasNewVersion ? (\n <span data-testid=\"version-update-title\" style={newVersionTitleStyle}>\n 发现新版本V{versionInfo?.lastversion}\n </span>\n ) : (\n <span\n data-testid=\"version-update-title\"\n className=\"text-[20px] font-bold leading-[30px] text-[var(--text-primary)]\"\n >\n 暂无新版本\n </span>\n )}\n </div>\n\n <div\n className={`mb-4 text-[12px] leading-[18px] text-[var(--text-secondary)] ${variant === 'modal' && !hasNewVersion ? 'text-center' : ''}`}\n >\n {hasNewVersion && downloadState.progress.status === 'success' ? (\n <>新版本v{versionInfo?.lastversion}已下载完成,重启应用即可完成更新</>\n ) : (\n <>当前版本V{currentVersion || '-'}</>\n )}\n </div>\n </>\n );\n\n const descriptionBlock = (\n <>\n {hasNewVersion && versionInfo ? (\n <div className={`mb-8 min-h-[226px] max-h-[252px] overflow-y-auto rounded-2xl border border-[#DBDBDB] p-4 text-left text-sm ${ downloadState.progress.status === 'downloading' ? 'min-h-[152px]' : ''}`}>\n <pre className=\"whitespace-pre-wrap font-sans\">{versionInfo.description}</pre>\n </div>\n ) : null}\n\n {hasNewVersion && downloadState.progress.status === 'downloading' ? (\n <div className=\"mb-6 text-left w-full \">\n <div className=\"mb-4 text-[12px]\" style={{ color: 'rgb(128, 128, 128)' }}>\n 下载中......可关闭后台下载\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"h-[4px] flex-1 rounded-full\" style={{ backgroundColor: 'rgb(230, 230, 230)' }}>\n <div\n className=\"h-[4px] rounded-full transition-all duration-300\"\n style={{\n width: `${downloadState.progress.progress}%`,\n backgroundColor: 'rgb(92, 179, 0)',\n }}\n />\n </div>\n <span className=\"text-sm text-[var(--modal-text-muted)]\">{downloadState.progress.progress}%</span>\n </div>\n </div>\n ) : null}\n </>\n );\n\n const buttons = renderButtonArea();\n\n if (variant === 'embedded' && !hasNewVersion) {\n return (\n <section\n data-testid=\"user-settings-version-update\"\n className=\"flex w-full h-[stretch] flex-col items-center justify-center px-6 text-center overflow-hidden\"\n >\n <div className=\"mb-[32px] flex justify-center\">\n <img src=\"/images/lobster.svg\" alt=\"\" className=\"h-[56px] w-[56px] object-contain\" aria-hidden />\n </div>\n <div\n className=\"text-center w-full text-[20px] font-bold leading-[30px] text-[var(--text-primary)]\"\n data-testid=\"version-update-title\"\n >\n 暂无新版本\n </div>\n <div className=\"mt-2 text-[12px] leading-[18px] text-[var(--text-secondary)]\">\n 当前版本V{currentVersion || '-'}\n </div>\n </section>\n );\n }\n\n if (variant === 'embedded') {\n return (\n <section data-testid=\"user-settings-version-update\" className=\"text-left flex flex-col items-center content-center\">\n {titleBlock}\n {descriptionBlock}\n {buttons}\n </section>\n );\n }\n\n return (\n <>\n <IconButton\n label=\"关闭\"\n size=\"sm\"\n className=\"absolute right-5 top-5 text-[var(--modal-close-icon)] transition-colors hover:text-[var(--modal-close-icon-hover)]\"\n onClick={handleDismiss}\n icon={\n <svg className=\"h-6 w-6\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n }\n />\n\n <div data-testid=\"version-update-content\" className={`px-8 pt-8 pb-0 ${contentAlignmentClassName}`}>\n {titleBlock}\n </div>\n\n <div className=\"px-8 pb-0\">{descriptionBlock}</div>\n\n <div className=\"px-8 pb-8\">{buttons}</div>\n </>\n );\n};\n\nexport default VersionUpdatePanel;\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { MaskIcon } from '@/components/shared/MaskIcon';\nimport type { SearchEngine } from '../search-engine-config.types';\n\ninterface SearchEngineCardProps {\n engine: SearchEngine;\n hasValue: boolean;\n onClick?: () => void;\n}\n\nexport function SearchEngineCard({ engine, hasValue, onClick }: SearchEngineCardProps) {\n return (\n <div\n className=\"flex w-full items-center justify-between rounded-xl bg-[var(--modal-surface)]\"\n style={{ height: '76px', padding: '16px', border: '1px solid rgba(230, 230, 230, 1)' }}\n >\n <div className=\"flex flex-col justify-center w-[calc(100%-80px)]\">\n <div className=\"flex items-center\">\n <span className=\"text-[14px] font-medium\" style={{ color: 'rgba(25, 25, 25, 1)' }}>\n {engine.name}\n </span>\n <span\n className=\"ml-1 inline-flex h-[18px] items-center rounded-[2px] px-1.5 text-[12px]\"\n style={{\n backgroundColor: hasValue ? 'rgba(213, 242, 220, 1)' : 'rgba(245, 245, 245, 1)',\n color: hasValue ? 'rgba(2, 153, 49, 1)' : 'rgba(25, 25, 25, 1)',\n }}\n >\n {hasValue ? '已配置' : '未配置'}\n </span>\n </div>\n <span\n className=\"mt-[6px] truncate text-[12px]\"\n style={{ color: 'rgba(128, 128, 128, 1)' }}\n title={engine.description}\n >\n {engine.description}\n </span>\n </div>\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex items-center gap-1 rounded-md p-1 text-[12px] hover:bg-[var(--surface-hover-muted)] transition-colors\"\n style={{ color: 'rgba(25, 25, 25, 1)' }}\n >\n {hasValue ? '修改' : '立即配置'}\n <MaskIcon name=\"chevronRight\" className=\"h-4 w-4\" />\n </button>\n </div>\n );\n}","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useState } from 'react';\nimport { MaskIcon } from '@/components/shared/MaskIcon';\nimport { Alert } from '@/components/shared/Alert';\nimport { Button } from '@/components/shared/Button';\nimport { PasswordField } from '@/components/shared/PasswordField';\nimport type { SearchEngine, SearchEngineId } from '../search-engine-config.types';\n\nconst API_URLS: Record<string, string> = {\n perplexity: 'https://console.perplexity.ai/',\n serper: 'https://serper.dev/',\n jina: 'https://jina.ai/api-dashboard/',\n bocha: 'https://open.bochaai.com/api-keys',\n};\n\ninterface SearchEngineEditViewProps {\n engine: SearchEngine;\n value: string;\n configured?: boolean;\n onSave: (engineId: SearchEngineId, value: string) => void | Promise<void>;\n onCancel: () => void;\n saving?: boolean;\n}\n\nexport function SearchEngineEditView({\n engine,\n value,\n configured = false,\n onSave,\n onCancel,\n saving = false,\n}: SearchEngineEditViewProps) {\n const [inputValue, setInputValue] = useState(value);\n const [showTip, setShowTip] = useState(true);\n\n const handleSave = () => {\n // 空值视为删除配置,提交给后端处理\n onSave(engine.id, inputValue.trim());\n };\n\n return (\n <div className=\"flex flex-col h-full gap-4\">\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"inline-flex items-center justify-center rounded-md p-1 text-[var(--text-primary)] hover:bg-[var(--surface-hover-muted)] transition-colors\"\n >\n <MaskIcon name=\"chevronLeft\" className=\"h-4 w-4\" />\n </button>\n <span className=\"text-[16px] font-medium\" style={{ color: 'rgba(25, 25, 25, 1)' }}>\n 配置\n </span>\n </div>\n\n {showTip && (\n <Alert mode=\"prompt\" closable onClose={() => setShowTip(false)}>\n <span className=\"text-[12px]\">\n 请前往对应网站获取API key后填入此处;如需后续修改,请勿在智能体任务运行期间操作。\n <a\n href={API_URLS[engine.id] ?? '#'}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-[var(--text-accent)] hover:underline\"\n >\n 前往获取\n <MaskIcon name=\"link-blue\" className=\"h-4 w-4\" />\n </a>\n </span>\n </Alert>\n )}\n\n <div className=\"space-y-1.5\">\n <label htmlFor={`search-engine-${engine.id}`} className=\"text-[12px] text-[var(--text-primary)]\">\n {engine.inputLabel}\n </label>\n <PasswordField\n id={`search-engine-${engine.id}`}\n value={inputValue}\n onChange={(e) => setInputValue(e.target.value)}\n placeholder={'请输入'}\n autoComplete=\"new-password\"\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n spellCheck={false}\n data-form-type=\"other\"\n data-1p-ignore=\"true\"\n data-lpignore=\"true\"\n className=\"ui-input w-full\"\n disabled={saving}\n />\n </div>\n\n {/*\n 底部按钮区始终贴底:\n - 父容器 flex-col h-full 使内容区占满可用高度\n - mt-auto 将此 div 推至flex主轴末端\n - 内容少时与 form 之间保持 gap-4;内容多时自然向下撑开\n */}\n <div className=\"flex justify-end gap-2 pt-4 mt-auto\">\n <Button variant=\"default\" onClick={onCancel} disabled={saving}>\n 取消\n </Button>\n <Button variant=\"major\" onClick={handleSave} disabled={saving}>\n {saving ? '保存中...' : '保存'}\n </Button>\n </div>\n </div>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nexport type SearchEngineId = 'perplexity' | 'serper' | 'jina' | 'bocha';\n\nexport interface SearchEngine {\n id: SearchEngineId;\n name: string;\n description: string;\n type: 'paid';\n inputLabel: string;\n envVar: string;\n}\n\nexport interface SearchEngineConfig {\n perplexityApiKey?: string;\n serperApiKey?: string;\n jinaApiKey?: string;\n bochaApiKey?: string;\n}\n\nexport interface SearchEngineConfiguredState {\n perplexity: boolean;\n serper: boolean;\n jina: boolean;\n bocha: boolean;\n}\n\nexport interface SearchEngineState {\n config: SearchEngineConfig;\n loading: boolean;\n saving: boolean;\n error: string | null;\n editingEngineId: SearchEngineId | null;\n}\n\nexport interface SearchEngineEditPayload {\n engineId: SearchEngineId;\n value: string;\n}\n\nexport const PAID_SEARCH_ENGINES: SearchEngine[] = [\n { id: 'bocha', name: 'Bocha(博查)', description: '基于多模态混合检索和语义排序技术的新一代搜索引擎', type: 'paid', inputLabel: 'bocha_api_key', envVar: 'BOCHA_API_KEY' },\n { id: 'jina', name: 'Jina(Jina AI)', description: '面向企业与开发者的神经搜索基础设施,提供多语言、多模态向量搜索与重排序能力,助力构建高性能RAG与企业搜索', type: 'paid', inputLabel: 'jina_api_key', envVar: 'JINA_API_KEY' },\n { id: 'perplexity', name: 'Perplexity', description: 'AI驱动的对话式答案引擎,实时联网搜索并直接给出带权威引用的精准回答,重塑知识探索方式', type: 'paid', inputLabel: 'perplexity_api_key', envVar: 'PERPLEXITY_API_KEY' },\n { id: 'serper', name: 'Serper', description: '通过SerperAPI,将Google搜索功能集成到启用MCP的应用程序中,提供丰富的搜索结果,可配置的参数和高效的响应处理', type: 'paid', inputLabel: 'serper_api_key', envVar: 'SERPER_API_KEY' },\n];\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useCallback, useState } from 'react';\nimport {\n type SearchEngineConfig,\n type SearchEngineConfiguredState,\n type SearchEngineEditPayload,\n type SearchEngineId,\n PAID_SEARCH_ENGINES,\n} from '../search-engine-config.types';\nimport { useToastStore } from '@/stores/toastStore';\nimport { apiFetch } from '@/utils/api-client';\n\nconst DEFAULT_CONFIG: SearchEngineConfig = {\n perplexityApiKey: '',\n serperApiKey: '',\n jinaApiKey: '',\n bochaApiKey: '',\n};\n\nconst DEFAULT_CONFIGURED: SearchEngineConfiguredState = {\n perplexity: false,\n serper: false,\n jina: false,\n bocha: false,\n};\n\n/**\n * 环境变量名 → SearchEngineConfig 内部字段的双向映射\n * 前端用短字段名(perplexityApiKey)存储,后端用标准 env var 名称\n */\nconst ENV_VAR_TO_KEY: Record<string, keyof SearchEngineConfig> = {\n PERPLEXITY_API_KEY: 'perplexityApiKey',\n SERPER_API_KEY: 'serperApiKey',\n JINA_API_KEY: 'jinaApiKey',\n BOCHA_API_KEY: 'bochaApiKey',\n};\n\n/**\n * 环境变量名 → SearchEngineId 的映射\n * 用于从 env var 名称直接确定当前在配置哪个搜索引擎\n */\nconst ENV_VAR_TO_ENGINE_ID: Record<string, SearchEngineId> = {\n PERPLEXITY_API_KEY: 'perplexity',\n SERPER_API_KEY: 'serper',\n JINA_API_KEY: 'jina',\n BOCHA_API_KEY: 'bocha',\n};\n\n/**\n * 判断返回值是否为掩码占位符\n * 后端对已配置的 secret 值返回 '***' 而非真实内容;\n * 掩码说明密钥已配置(应显示\"已配置\"),但前端无法获取明文\n */\nfunction isMaskedSecretValue(value: string | null | undefined): boolean {\n return value === '***';\n}\n\nasync function readErrorMessage(response: Response, fallback: string): Promise<string> {\n try {\n const data = (await response.clone().json()) as { error?: string; message?: string };\n return data.error || data.message || fallback;\n } catch {\n return fallback;\n }\n}\n\nexport function useSearchEngineConfig() {\n const [config, setConfig] = useState<SearchEngineConfig>(DEFAULT_CONFIG);\n const [configured, setConfigured] = useState<SearchEngineConfiguredState>(DEFAULT_CONFIGURED);\n const [loading, setLoading] = useState(false);\n const [saving, setSaving] = useState(false);\n const [editingEngineId, setEditingEngineId] = useState<SearchEngineId | null>(null);\n\n const addToast = useToastStore((s) => s.addToast);\n\n /**\n * 从 /api/config/env-summary 加载所有搜索引擎的配置状态\n *\n * 判断逻辑:\n * - env var 有值(非 null、非空)→ configured = true\n * - env var 值为 '***'(掩码)→ configured = true,但 config 中不存明文(安全性)\n * - env var 不存在或为空 → configured = false\n */\n const loadConfig = useCallback(async () => {\n setLoading(true);\n try {\n const res = await apiFetch('/api/config/env-summary');\n if (!res.ok) throw new Error(await readErrorMessage(res, '加载搜索引擎配置失败'));\n const data = (await res.json()) as { variables?: Array<{ name: string; currentValue: string | null }> };\n const variables = data.variables ?? [];\n const nextConfig: SearchEngineConfig = { ...DEFAULT_CONFIG };\n const nextConfigured: SearchEngineConfiguredState = { ...DEFAULT_CONFIGURED };\n\n for (const v of variables) {\n const configKey = ENV_VAR_TO_KEY[v.name];\n const engineId = ENV_VAR_TO_ENGINE_ID[v.name];\n if (!configKey || !engineId || v.currentValue == null || v.currentValue === '') continue;\n\n nextConfigured[engineId] = true;\n if (!isMaskedSecretValue(v.currentValue)) {\n nextConfig[configKey] = v.currentValue;\n }\n }\n\n setConfig(nextConfig);\n setConfigured(nextConfigured);\n } catch (err) {\n const msg = err instanceof Error ? err.message : '加载搜索引擎配置失败';\n addToast({ type: 'error', title: '加载失败', message: msg, duration: 3000 });\n } finally {\n setLoading(false);\n }\n }, [addToast]);\n\n /**\n * 保存单个搜索引擎的 API key\n * 成功:更新本地 config + configured 状态,关闭编辑视图\n * 失败:只 toast 错误,状态不变(不残留脏数据)\n * 注意:editingEngineId 不在 deps 中,因为它仅通过 setEditingEngineId(null) 使用,引用始终稳定\n */\n const saveConfig = useCallback(\n async (payload: SearchEngineEditPayload) => {\n setSaving(true);\n try {\n const envVar = PAID_SEARCH_ENGINES.find((e) => e.id === payload.engineId)?.envVar;\n if (!envVar) throw new Error('未知的搜索引擎');\n const key = ENV_VAR_TO_KEY[envVar];\n if (!key) throw new Error('未知的搜索引擎');\n\n // 空值视为删除配置\n const isDelete = payload.value === '';\n const res = await apiFetch('/api/config/env', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n updates: [{ name: envVar, value: payload.value }],\n }),\n });\n if (!res.ok) throw new Error(await readErrorMessage(res, '保存失败'));\n\n setConfig((prev) => ({ ...prev, [key]: payload.value }));\n setConfigured((prev) => ({ ...prev, [payload.engineId]: !isDelete }));\n addToast({ type: 'success', title: isDelete ? '已删除' : '保存成功', message: '', duration: 2000 });\n setEditingEngineId(null);\n } catch (err) {\n const msg = err instanceof Error ? err.message : '保存失败';\n addToast({ type: 'error', title: '保存失败', message: msg, duration: 3000 });\n setEditingEngineId(null);\n } finally {\n setSaving(false);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- editingEngineId not used in scope\n },\n [addToast],\n );\n\n const startEdit = useCallback((engineId: SearchEngineId) => {\n setEditingEngineId(engineId);\n }, []);\n\n const cancelEdit = useCallback(() => {\n setEditingEngineId(null);\n }, []);\n\n const getEngineValue = useCallback(\n (engineId: SearchEngineId): string => {\n switch (engineId) {\n case 'perplexity':\n return config.perplexityApiKey ?? '';\n case 'serper':\n return config.serperApiKey ?? '';\n case 'jina':\n return config.jinaApiKey ?? '';\n case 'bocha':\n return config.bochaApiKey ?? '';\n default:\n return '';\n }\n },\n [config],\n );\n\n const isEngineConfigured = useCallback(\n (engineId: SearchEngineId): boolean => configured[engineId],\n [configured],\n );\n\n /**\n * 派生状态:当前视图的标题\n * - 非编辑状态:显示\"搜索引擎\"(标题区标题)\n * - 编辑状态:显示\"配置\"(单引擎配置页标题)\n * 不使用 useState,避免与 editingEngineId 不同步\n */\n const title = editingEngineId\n ? '配置'\n : '搜索引擎';\n\n return {\n loading,\n saving,\n editingEngineId,\n title,\n loadConfig,\n saveConfig,\n startEdit,\n cancelEdit,\n getEngineValue,\n isEngineConfigured,\n };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useEffect, useCallback } from 'react';\nimport { CenteredLoadingState } from '@/components/shared/CenteredLoadingState';\nimport { SearchEngineCard } from './components/SearchEngineCard';\nimport { SearchEngineEditView } from './components/SearchEngineEditView';\nimport { useSearchEngineConfig } from './hooks/useSearchEngineConfig';\nimport { PAID_SEARCH_ENGINES, type SearchEngine } from './search-engine-config.types';\n\nexport function SearchEngineConfig() {\n const {\n loading,\n saving,\n editingEngineId,\n title,\n loadConfig,\n saveConfig,\n startEdit,\n cancelEdit,\n getEngineValue,\n isEngineConfigured,\n } = useSearchEngineConfig();\n\n useEffect(() => {\n void loadConfig();\n }, [loadConfig]);\n\n /**\n * 稳定的 onSave 回调,供 SearchEngineEditView 使用\n * 使用 useCallback 包装避免每次渲染创建新函数引用,\n * 防止 EditView 误判 props 变化而触发额外渲染\n */\n const handleSave = useCallback(\n (engineId: SearchEngine['id'], value: string) => saveConfig({ engineId, value }),\n [saveConfig],\n );\n\n const editingEngine =\n editingEngineId ? PAID_SEARCH_ENGINES.find((e) => e.id === editingEngineId) ?? null : null;\n\n if (loading) {\n return (\n <div className=\"flex h-[200px] items-center justify-center\">\n <CenteredLoadingState />\n </div>\n );\n }\n\n if (editingEngine) {\n return (\n <SearchEngineEditView\n engine={editingEngine}\n value={getEngineValue(editingEngine.id)}\n configured={isEngineConfigured(editingEngine.id)}\n onSave={handleSave}\n onCancel={cancelEdit}\n saving={saving}\n />\n );\n }\n\n return (\n <div className=\"space-y-6\">\n <h2 className=\"text-[16px] font-medium\" style={{ color: 'rgba(25, 25, 25, 1)' }}>\n {title}\n </h2>\n <section>\n <h3 className=\"mb-3 text-[14px] font-medium leading-[22px] text-[var(--text-primary)]\">付费搜索引擎</h3>\n <div className=\"space-y-2\">\n {PAID_SEARCH_ENGINES.map((engine) => {\n const hasValue = isEngineConfigured(engine.id);\n return (\n <SearchEngineCard\n key={engine.id}\n engine={engine}\n hasValue={hasValue}\n onClick={() => startEdit(engine.id)}\n />\n );\n })}\n </div>\n </section>\n </div>\n );\n}\n","'use client';\n\nimport { type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport { useEscapeKey } from '@/hooks/useEscapeKey';\nimport { type ThemeType } from '@/hooks/useTheme';\nimport { ModalCloseIcon } from '@/components/icons/SettingsFeedbackIcons';\nimport { apiFetch } from '@/utils/api-client';\nimport { AppModal } from './AppModal';\nimport { GeneralSettingsTab } from './GeneralSettingsTab';\nimport VersionUpdatePanel, { type VersionInfo } from './VersionUpdatePanel';\nimport { MaskIcon } from './shared/MaskIcon';\nimport { ToggleSwitch } from './shared/ToggleSwitch';\nimport { SearchEngineConfig } from './search-engine-config/SearchEngineConfig';\n\nconst AGENT_ARTS_SERVICE_DECLARATION_URL = 'https://www.huaweicloud.com/declaration/agentarts.html';\n\ntype SettingsTabId = 'general' | 'memory' | 'search' | 'privacy' | 'about';\n\nconst SETTINGS_TABS: Array<{ id: SettingsTabId; label: string; iconSrc: string }> = [\n { id: 'general', label: '通用设置', iconSrc: '/icons/settings-feedback/settings-gear.svg' },\n { id: 'memory', label: '记忆', iconSrc: '/icons/settings-feedback/settings-memory.svg' },\n { id: 'search', label: '搜索引擎', iconSrc: '/icons/settings-feedback/settings-search.svg' },\n { id: 'privacy', label: '隐私与数据', iconSrc: '/icons/settings-feedback/settings-privacy.svg' },\n { id: 'about', label: '关于我们', iconSrc: '/images/information.svg' },\n];\n\ninterface UserSettingsModalProps {\n open: boolean;\n onClose: () => void;\n keepAwakeEnabled: boolean;\n isKeepAwakeLoading: boolean;\n isKeepAwakeSaving: boolean;\n onToggleKeepAwake: (checked: boolean) => void;\n theme: ThemeType;\n onSelectTheme: (theme: ThemeType) => void;\n onOpenPrivacyDeclaration: () => void;\n /** 切换到「关于我们」时拉取最新版本信息(/api/lastversion) */\n onAboutTabEnter?: () => void;\n versionInfo: VersionInfo | null;\n}\n\ntype ConfigResponse = {\n config?: {\n memory?: {\n enabled?: unknown;\n };\n };\n};\n\nfunction SettingItem({\n title,\n description,\n switchNode,\n}: {\n title: string;\n description?: string;\n switchNode?: ReactNode;\n}) {\n return (\n <section>\n <div className='flex items-center justify-between gap-3'>\n <h4 className='min-w-0 flex-1 text-[14px] font-medium leading-[22px] text-[var(--text-primary)]'>{title}</h4>\n {switchNode ?? null}\n </div>\n {description ? <p className='mt-1 text-[12px] leading-[20px] text-[var(--text-secondary)]'>{description}</p> : null}\n </section>\n );\n}\n\nexport default function UserSettingsModal({\n open,\n onClose,\n keepAwakeEnabled,\n isKeepAwakeLoading,\n isKeepAwakeSaving,\n onToggleKeepAwake,\n theme,\n onSelectTheme,\n onOpenPrivacyDeclaration,\n onAboutTabEnter,\n versionInfo,\n}: UserSettingsModalProps) {\n const [activeTab, setActiveTab] = useState<SettingsTabId>('general');\n const [memoryEnabled, setMemoryEnabled] = useState(false);\n const [isMemorySaving, setIsMemorySaving] = useState(false);\n const [improveDataEnabled, setImproveDataEnabled] = useState(false);\n /** 停留在「关于我们」时不会重复请求;离开该 tab 后再进入会再拉取一次 */\n const aboutVersionFetchedRef = useRef(false);\n\n useEscapeKey({ enabled: open, onEscape: onClose });\n\n useEffect(() => {\n if (!open) return;\n setActiveTab('general');\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n let cancelled = false;\n void apiFetch('/api/config')\n .then(async (response) => {\n if (!response.ok) return null;\n return (await response.json()) as ConfigResponse;\n })\n .then((data) => {\n const enabled = data?.config?.memory?.enabled;\n if (!cancelled && typeof enabled === 'boolean') {\n setMemoryEnabled(enabled);\n }\n })\n .catch(() => {});\n return () => {\n cancelled = true;\n };\n }, [open]);\n\n useEffect(() => {\n if (!open) {\n aboutVersionFetchedRef.current = false;\n return;\n }\n if (activeTab !== 'about') {\n aboutVersionFetchedRef.current = false;\n return;\n }\n if (aboutVersionFetchedRef.current) return;\n aboutVersionFetchedRef.current = true;\n onAboutTabEnter?.();\n }, [open, activeTab, onAboutTabEnter]);\n\n const activeTabLabel = useMemo(\n () => SETTINGS_TABS.find((tab) => tab.id === activeTab)?.label ?? '设置',\n [activeTab],\n );\n\n const handleMemoryToggle = async (checked: boolean) => {\n const previous = memoryEnabled;\n setMemoryEnabled(checked);\n setIsMemorySaving(true);\n try {\n const response = await apiFetch('/api/handle_memory_toggle', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ enabled: checked }),\n });\n if (!response.ok) {\n setMemoryEnabled(previous);\n }\n } catch {\n setMemoryEnabled(previous);\n } finally {\n setIsMemorySaving(false);\n }\n };\n\n return (\n <AppModal\n open={open}\n onClose={onClose}\n disableBackdropClose\n showCloseButton={false}\n backdropClassName='p-0'\n panelClassName='relative flex max-h-[90vh] w-[900px] min-h-[480px] h-[550px] max-w-[calc(100vw-32px)] flex-col overflow-hidden !p-0 rounded-[12px] bg-[var(--modal-surface)]'\n bodyClassName='flex min-h-0 flex-1 flex-row p-0'\n panelTestId='user-settings-modal'\n bodyTestId='user-settings-modal-body'\n backdropTestId='user-settings-modal-backdrop'\n >\n <button\n type='button'\n onClick={onClose}\n aria-label='关闭设置弹窗'\n className='absolute right-4 top-4 flex h-8 w-8 items-center justify-center rounded-full text-[var(--text-secondary)] transition-colors hover:text-[var(--text-primary)]'\n >\n <ModalCloseIcon className=\"h-4 w-4\" />\n </button>\n <aside className='ui-sidebar-shell flex w-[180px] shrink-0 flex-col self-stretch px-[12px] py-[24px]'>\n <h3 className='px-[12px] text-[18px] font-medium leading-[28px] text-[var(--text-primary)]'>设置</h3>\n <nav className='mt-4 flex flex-col gap-[10px]'>\n {SETTINGS_TABS.map((tab) => {\n const isActive = tab.id === activeTab;\n return (\n <button\n key={tab.id}\n type='button'\n onClick={() => setActiveTab(tab.id)}\n data-testid={`user-settings-tab-${tab.id}`}\n className={`flex h-[38px] w-[156px] items-center text-[var(--text-primary)] gap-2 rounded-[8px] py-[8px] pl-[8px] pr-[12px] text-left text-[14px] leading-[22px] transition-colors ${\n isActive\n ? 'bg-[var(--surface-selected)] font-medium'\n : 'font-normal hover:bg-[var(--surface-neutral-white)]'\n }`}\n >\n <MaskIcon src={tab.iconSrc} className='h-5 w-5 shrink-0 object-contain' />\n <span className='min-w-0 flex-1 truncate'>{tab.label}</span>\n </button>\n );\n })}\n </nav>\n </aside>\n <section className='w-[720px] min-h-0 shrink-0 self-stretch bg-[var(--surface-panel)] px-[24px] py-[24px] overflow-hidden'>\n {activeTab !== 'search' && (\n <h3 className='text-[16px] font-medium leading-[24px] text-[var(--text-primary)]'>{activeTabLabel}</h3>\n )}\n <div className={`h-full flex flex-col divide-y divide-[var(--panel-divider)] overflow-y-auto pr-1 [&>*]:py-4 [&>*:first-child]:pt-0 ${activeTab === 'search' ? '':'pt-6'} ${activeTab === 'about' ? 'content-center' : ''}`}>\n {activeTab === 'general' ? (\n <GeneralSettingsTab\n keepAwakeEnabled={keepAwakeEnabled}\n isKeepAwakeLoading={isKeepAwakeLoading}\n isKeepAwakeSaving={isKeepAwakeSaving}\n onToggleKeepAwake={onToggleKeepAwake}\n theme={theme}\n onSelectTheme={onSelectTheme}\n active={open && activeTab === 'general'}\n />\n ) : null}\n\n {activeTab === 'memory' ? (\n <SettingItem\n title='长期记忆'\n description='开启后,大模型会记住你对话中提到的偏好和习惯,提供个性化的回复。'\n switchNode={\n <ToggleSwitch\n checked={memoryEnabled}\n onToggle={(checked) => void handleMemoryToggle(checked)}\n ariaLabel='切换长期记忆'\n disabled={isMemorySaving}\n testId='user-settings-memory-switch'\n />\n }\n />\n ) : null}\n\n {activeTab === 'search' ? (\n <SearchEngineConfig />\n ) : null}\n\n {activeTab === 'privacy' ? (\n <>\n <section>\n <div className='flex items-center justify-between gap-3'>\n <h4 className='text-[14px] font-medium leading-[22px] text-[var(--text-primary)]'>\n 数据用于帮助模型改进效果\n </h4>\n <ToggleSwitch\n checked={improveDataEnabled}\n onToggle={setImproveDataEnabled}\n ariaLabel='切换数据用于帮助模型改进效果'\n testId='user-settings-improve-data-switch'\n />\n </div>\n <p className='mt-1 text-[12px] leading-[20px] text-[var(--text-secondary)]'>\n 开启后,我们将收集您提交的对话内容、OfficeClaw 相应生成的内容及执行链路日志等数据,相关数据会在脱敏处理后用于模型优化和服务改进。您可随时开启或关闭。详情见\n <button\n type='button'\n className='ml-1 cursor-pointer border-none bg-transparent p-0 text-[var(--switch-on-bg)] underline-offset-2 hover:bg-transparent'\n onClick={() => window.open(AGENT_ARTS_SERVICE_DECLARATION_URL, '_blank', 'noopener,noreferrer')}\n >\n 《AgentArts服务声明》\n </button>\n </p>\n </section>\n <div className='flex items-center'>\n <button\n type='button'\n onClick={onOpenPrivacyDeclaration}\n aria-label='打开隐私声明'\n className='inline-flex items-center gap-1.5 border-none bg-transparent p-0 text-left hover:bg-transparent focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--switch-on-bg)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--surface-panel)]'\n data-testid='user-settings-privacy-declaration'\n >\n <span className='text-[14px] font-medium leading-[22px] text-[var(--text-primary)]'>隐私声明</span>\n <MaskIcon src='/icons/settings-feedback/settings-link.svg' className='h-4 w-4 shrink-0' />\n </button>\n </div>\n </>\n ) : null}\n\n {activeTab === 'about' ? (\n <VersionUpdatePanel\n variant='embedded'\n active={open && activeTab === 'about'}\n versionInfo={versionInfo}\n />\n ) : null}\n </div>\n </section>\n </AppModal>\n );\n}\n","\"use client\";\n\nimport {\n type CSSProperties,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Button } from \"./shared/Button\";\nimport { type ThemeType, useTheme } from \"@/hooks/useTheme\";\nimport { usePreventSleep } from \"@/hooks/usePreventSleep\";\nimport { apiFetch } from \"@/utils/api-client\";\nimport { readPublicEnv } from \"@/utils/client-env\";\nimport {\n clearAuthIdentity,\n getIsSkipAuth,\n getUserId,\n getUserName,\n} from \"@/utils/userId\";\nimport { MaskIcon } from \"./shared/MaskIcon\";\nimport SecurityManagementModal from \"./SecurityManagementModal\";\nimport FeedbackModal from \"./FeedbackModal\";\nimport { OverflowTooltip } from \"./shared/OverflowTooltip\";\nimport { UsageStatsModal } from \"./UsageStatsModal\";\nimport UserSettingsModal from \"./UserSettingsModal\";\n\ninterface VersionInfo {\n curversion: string;\n lastversion: string;\n description: string;\n is_need_force_upgrade?: boolean;\n downloadUrl?: string;\n download_url?: string;\n}\n\nfunction normalizeVersion(version: string): number[] {\n return version\n .trim()\n .replace(/^[^\\d]*/, \"\")\n .split(/[.\\-+_]/)\n .map((part) => Number.parseInt(part, 10))\n .map((part) => (Number.isFinite(part) ? part : 0));\n}\n\nfunction compareVersions(a: string, b: string): number {\n const aParts = normalizeVersion(a);\n const bParts = normalizeVersion(b);\n const maxLen = Math.max(aParts.length, bParts.length);\n\n for (let i = 0; i < maxLen; i += 1) {\n const aVal = aParts[i] ?? 0;\n const bVal = bParts[i] ?? 0;\n if (aVal > bVal) return 1;\n if (aVal < bVal) return -1;\n }\n\n return 0;\n}\n\ninterface UserProfileProps {\n className?: string;\n collapsed?: boolean;\n}\n\ntype CollapsedPanelPosition = {\n left: number;\n bottom: number;\n};\n\nconst HELP_URL =\n \"https://support.huaweicloud.com/officeclaw-agentarts-pc/officeclaw-agentarts-pc-0001.html\";\nconst PRIVACY_DECLARATION_URL =\n \"https://www.huaweicloud.com/declaration/sa_prp.html\";\n\nconst DEFAULT_LOGOUT_URL =\n readPublicEnv('NEXT_PUBLIC_CAS_LOGOUT_URL') ||\n 'https://auth.huaweicloud.com/authui/login.html?service=https://auth.huaweicloud.com/authui/v1/oauth2/authorize?';\n\ntype LogoutResponse = {\n logoutUrl?: string;\n};\n\nasync function readLogoutResponse(response: Response): Promise<LogoutResponse | null> {\n const contentType = response.headers.get('content-type') || '';\n if (!contentType.includes('application/json')) return null;\n try {\n const data = (await response.json()) as LogoutResponse;\n return data;\n } catch {\n return null;\n }\n}\n\nexport function UserProfile({ className, collapsed }: UserProfileProps) {\n const [showPanel, setShowPanel] = useState(false);\n const [showUserSettings, setShowUserSettings] = useState(false);\n const [showAboutPanel, setShowAboutPanel] = useState(false);\n const [showUsageStats, setShowUsageStats] = useState(false);\n const [showFeedbackModal, setShowFeedbackModal] = useState(false);\n const [showSecurityManagement, setShowSecurityManagement] = useState(false);\n const [isLoading, setIsLoading] = useState(false);\n const [isSkipAuth, setIsSkipAuth] = useState(false);\n const [aboutPopoverTop, setAboutPopoverTop] = useState(0);\n const [aboutPopoverLeft, setAboutPopoverLeft] = useState(0);\n const [collapsedPanelPosition, setCollapsedPanelPosition] =\n useState<CollapsedPanelPosition | null>(null);\n const [versionInfo, setVersionInfo] = useState<VersionInfo | null>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const profilePanelRef = useRef<HTMLDivElement>(null);\n const panelScrollRef = useRef<HTMLDivElement>(null);\n const aboutAnchorRef = useRef<HTMLDivElement>(null);\n const aboutPopoverRef = useRef<HTMLDivElement>(null);\n const userId = getUserId();\n const storedUserName = getUserName();\n const { theme, setTheme } = useTheme();\n const {\n enabled: keepAwakeEnabled,\n isLoading: isKeepAwakeLoading,\n isSaving: isKeepAwakeSaving,\n toggle: handleKeepAwakeToggle,\n } = usePreventSleep();\n\n const checkVersion = useCallback(async () => {\n if (typeof window === \"undefined\") return;\n\n try {\n const res = await apiFetch(\"/api/lastversion\");\n if (!res.ok) return;\n\n const data = (await res.json()) as VersionInfo;\n if (!data?.curversion) return;\n\n setVersionInfo(data);\n\n const isNewVersionAvailable =\n !!data.lastversion &&\n !!data.curversion &&\n compareVersions(data.lastversion, data.curversion) > 0;\n\n if (!isNewVersionAvailable) {\n const taskId = `version-${data.curversion}`;\n try {\n await apiFetch(\"/api/download/clear\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ taskId }),\n });\n } catch {}\n }\n } catch {}\n }, []);\n\n const handleAboutTabEnter = useCallback(() => {\n void checkVersion();\n }, [checkVersion]);\n\n const userName =\n storedUserName || (userId === \"default-user\" ? \"未登录\" : userId);\n const avatarLetter = userName.charAt(0).toUpperCase();\n const profileActionClass =\n \"ui-overlay-item flex w-full items-center gap-2 rounded-[8px] px-3 py-2 text-[14px] font-normal leading-[22px] text-[var(--overlay-text)]\";\n const profileSubActionClass =\n \"ui-overlay-item flex w-full items-center justify-between gap-3 rounded-[8px] px-3 py-2 text-left text-[14px] font-normal leading-[22px] text-[var(--overlay-text)]\";\n\n const calculatePopoverPosition = (anchorElement: HTMLDivElement | null) => {\n if (!profilePanelRef.current || !anchorElement) return null;\n\n const profilePanelRect = profilePanelRef.current.getBoundingClientRect();\n const anchorRect = anchorElement.getBoundingClientRect();\n\n return {\n top: anchorRect.top,\n left: profilePanelRect.right,\n };\n };\n\n const updateAboutPopoverPosition = () => {\n const position = calculatePopoverPosition(aboutAnchorRef.current);\n if (!position) return;\n setAboutPopoverTop(position.top);\n setAboutPopoverLeft(position.left);\n };\n\n const updateCollapsedPanelPosition = useCallback(() => {\n if (!collapsed || !panelRef.current) return;\n const rect = panelRef.current.getBoundingClientRect();\n setCollapsedPanelPosition({\n left: rect.right + 8,\n bottom: Math.max(8, window.innerHeight - rect.bottom),\n });\n }, [collapsed]);\n\n const handleTogglePanel = () => {\n setShowPanel((prev) => {\n const next = !prev;\n if (next && collapsed) {\n updateCollapsedPanelPosition();\n }\n if (!next) {\n setShowAboutPanel(false);\n }\n return next;\n });\n };\n\n const handleOpenUsageStats = () => {\n setShowUsageStats(true);\n setShowAboutPanel(false);\n setShowPanel(false);\n };\n\n const handleOpenUserSettings = () => {\n setShowUserSettings(true);\n setShowAboutPanel(false);\n setShowPanel(false);\n };\n\n const handleCloseUserSettings = () => {\n setShowUserSettings(false);\n };\n\n const handleCloseUsageStats = () => {\n setShowUsageStats(false);\n };\n\n const handleOpenFeedbackModal = () => {\n setShowFeedbackModal(true);\n setShowAboutPanel(false);\n setShowPanel(false);\n };\n\n const handleCloseFeedbackModal = () => {\n setShowFeedbackModal(false);\n };\n\n const handleOpenSecurityManagement = () => {\n setShowSecurityManagement(true);\n setShowAboutPanel(false);\n setShowPanel(false);\n };\n\n const handleCloseSecurityManagement = () => {\n setShowSecurityManagement(false);\n };\n\n const handleSelectTheme = (nextTheme: ThemeType) => {\n setTheme(nextTheme);\n };\n\n const handleOpenHelp = () => {\n window.open(HELP_URL, \"_blank\", \"noopener,noreferrer\");\n setShowAboutPanel(false);\n setShowPanel(false);\n };\n\n const openAboutPanel = () => {\n updateAboutPopoverPosition();\n setShowAboutPanel(true);\n };\n\n const handleToggleAboutPanel = () => {\n if (showAboutPanel) {\n setShowAboutPanel(false);\n return;\n }\n openAboutPanel();\n };\n\n const handleOpenPrivacyDeclaration = () => {\n window.open(PRIVACY_DECLARATION_URL, \"_blank\", \"noopener,noreferrer\");\n setShowAboutPanel(false);\n setShowPanel(false);\n };\n\n const finishLogout = (logoutUrl?: string) => {\n clearAuthIdentity();\n setShowAboutPanel(false);\n setShowPanel(false);\n window.location.assign(logoutUrl || DEFAULT_LOGOUT_URL);\n };\n\n const handleLogout = async () => {\n setIsLoading(true);\n let redirected = false;\n try {\n const response = await apiFetch(\"/api/logout\", {\n method: \"POST\",\n });\n\n if (response.ok) {\n const data = await readLogoutResponse(response);\n redirected = true;\n finishLogout(\n typeof data?.logoutUrl === \"string\" ? data.logoutUrl : undefined,\n );\n return;\n }\n\n redirected = true;\n finishLogout();\n return;\n } catch (err) {\n console.error(\"退出登录错误:\", err);\n redirected = true;\n finishLogout();\n return;\n } finally {\n if (!redirected) {\n setIsLoading(false);\n }\n }\n };\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as Node;\n const isInsideUserProfile =\n panelRef.current?.contains(target) ||\n aboutPopoverRef.current?.contains(target);\n\n if (!isInsideUserProfile) {\n setShowPanel(false);\n setShowAboutPanel(false);\n }\n };\n\n if (showPanel || showAboutPanel) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [showPanel, showAboutPanel]);\n\n useEffect(() => {\n if (!showPanel || !showAboutPanel) return;\n\n updateAboutPopoverPosition();\n\n const handlePositionChange = () => {\n if (showAboutPanel) {\n updateAboutPopoverPosition();\n }\n };\n\n const scrollElement = panelScrollRef.current;\n window.addEventListener(\"resize\", handlePositionChange);\n scrollElement?.addEventListener(\"scroll\", handlePositionChange, {\n passive: true,\n });\n\n return () => {\n window.removeEventListener(\"resize\", handlePositionChange);\n scrollElement?.removeEventListener(\"scroll\", handlePositionChange);\n };\n }, [showPanel, showAboutPanel]);\n\n useEffect(() => {\n if (!showPanel || !collapsed) return;\n updateCollapsedPanelPosition();\n window.addEventListener(\"resize\", updateCollapsedPanelPosition);\n window.addEventListener(\"scroll\", updateCollapsedPanelPosition, true);\n return () => {\n window.removeEventListener(\"resize\", updateCollapsedPanelPosition);\n window.removeEventListener(\"scroll\", updateCollapsedPanelPosition, true);\n };\n }, [collapsed, showPanel, updateCollapsedPanelPosition]);\n\n useEffect(() => {\n setIsSkipAuth(getIsSkipAuth());\n }, []);\n\n const collapsedPanelStyle: CSSProperties | undefined =\n collapsed && collapsedPanelPosition\n ? {\n left: collapsedPanelPosition.left,\n bottom: collapsedPanelPosition.bottom,\n }\n : undefined;\n\n const profileButton = (\n <button\n type=\"button\"\n onClick={handleTogglePanel}\n className={`group border-none flex w-full items-center text-left text-[var(--text-primary)] transition-colors hover:bg-[var(--overlay-item-hover-bg)] ${\n collapsed ? \"h-12 justify-center px-0 py-0\" : \"gap-3 px-3 py-3\"\n }`}\n data-testid=\"user-profile-toggle\"\n aria-label={collapsed ? userName : undefined}\n >\n <div\n className={`flex flex-shrink-0 items-center justify-center rounded-full bg-[var(--surface-avatar-shell)] ${collapsed ? \"h-[20px] w-[20px]\" : \"h-9 w-9\"}`}\n >\n <span\n className={`font-bold text-[var(--text-primary)] ${collapsed ? \"text-xs\" : \"text-sm\"}`}\n >\n {avatarLetter}\n </span>\n </div>\n\n {!collapsed && (\n <>\n <OverflowTooltip content={userName} className=\"min-w-0 flex-1\">\n <div\n data-testid=\"user-profile-name\"\n className=\"truncate text-[16px] font-medium text-[var(--text-primary)]\"\n >\n {userName}\n </div>\n </OverflowTooltip>\n\n <svg\n className=\"h-4 w-4 shrink-0 text-[var(--text-primary)] transition-transform\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M9 5l7 7-7 7\" />\n </svg>\n </>\n )}\n </button>\n );\n\n return (\n <div className={`border-none relative ${className ?? \"\"}`} ref={panelRef}>\n {collapsed ? (\n <OverflowTooltip content={userName} forceShow placement=\"right\" className=\"block\">\n {profileButton}\n </OverflowTooltip>\n ) : (\n profileButton\n )}\n\n {showPanel && (\n <div\n className={`ui-overlay-card z-50 rounded-[var(--radius-lg)] ${\n collapsed\n ? \"fixed w-[240px]\"\n : \"absolute bottom-full left-3 right-3 -mb-[4px]\"\n }`}\n style={collapsedPanelStyle}\n data-testid=\"user-profile-panel\"\n ref={profilePanelRef}\n >\n <div\n className=\"p-4 border-none\"\n data-testid=\"user-profile-panel-scroll\"\n ref={panelScrollRef}\n >\n <div className=\"mb-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[var(--surface-avatar-shell)]\">\n <span className=\"text-base font-bold text-[var(--text-primary)]\">\n {avatarLetter}\n </span>\n </div>\n <OverflowTooltip content={userName} className=\"min-w-0 flex-1\">\n <div\n data-testid=\"user-profile-panel-name\"\n className=\"truncate text-[16px] font-normal text-[var(--text-primary)]\"\n >\n {userName}\n </div>\n </OverflowTooltip>\n </div>\n </div>\n\n <div className=\"mb-3 border-t border-[var(--panel-divider)]\" />\n\n <div\n className=\"space-y-3\"\n data-testid=\"user-profile-content-actions\"\n >\n <button\n type=\"button\"\n className={profileActionClass}\n onClick={handleOpenUserSettings}\n data-testid=\"user-profile-settings-trigger\"\n >\n <MaskIcon src=\"/icons/settings-feedback/settings-gear.svg\" className=\"h-5 w-5 shrink-0\" />\n 设置\n </button>\n\n <button\n className={profileActionClass}\n onClick={handleOpenSecurityManagement}\n >\n <MaskIcon src=\"/icons/userprofile/security.svg\" className=\"h-5 w-5 text-[var(--mask-icon)]\" />\n 安全管理\n </button>\n\n <button\n className={profileActionClass}\n onClick={handleOpenUsageStats}\n >\n <MaskIcon src=\"/icons/userprofile/usage.svg\" className=\"h-5 w-5 text-[var(--mask-icon)]\" />\n 用量统计\n </button>\n\n <div\n className=\"relative\"\n data-testid=\"user-profile-about-anchor\"\n ref={aboutAnchorRef}\n >\n <button\n type=\"button\"\n className={profileActionClass}\n onClick={handleToggleAboutPanel}\n data-testid=\"user-profile-about-trigger\"\n >\n <span className=\"flex-1 text-left\">帮助与反馈</span>\n <svg\n data-testid=\"user-profile-about-arrow\"\n className=\"h-4 w-4 shrink-0 text-[var(--overlay-text)]\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n </div>\n\n {!isSkipAuth && (\n <>\n <div className=\"mt-3 border-t border-[var(--panel-divider)]\" />\n <Button\n onClick={handleLogout}\n disabled={isLoading}\n variant=\"default\"\n className=\"mt-4 h-7 w-full text-[12px]\"\n >\n {isLoading ? \"退出中...\" : \"退出登录\"}\n </Button>\n </>\n )}\n </div>\n </div>\n )}\n\n {showPanel && showAboutPanel && typeof document !== \"undefined\"\n ? createPortal(\n <div\n ref={aboutPopoverRef}\n className=\"ui-overlay-card fixed z-[99999] min-w-[180px] rounded-[var(--radius-md)] shadow-[var(--overlay-shadow)]\"\n data-testid=\"user-about-popover\"\n style={{\n top: `${aboutPopoverTop}px`,\n left: `${aboutPopoverLeft}px`,\n }}\n >\n <div className=\"p-[16px]\">\n <div className=\"flex flex-col\" data-testid=\"user-about-options\">\n <button\n type=\"button\"\n className={profileSubActionClass + \" hidden\"}\n data-testid=\"user-about-feedback-action\"\n onClick={handleOpenFeedbackModal}\n >\n <span className=\"flex-1 text-left\">问题反馈</span>\n </button>\n <button\n type=\"button\"\n className={profileSubActionClass}\n data-testid=\"user-about-help-action\"\n onClick={handleOpenHelp}\n >\n <span className=\"flex-1 text-left\">帮助文档</span>\n <MaskIcon name=\"link\" className=\"h-4 w-4 shrink-0\" />\n </button>\n </div>\n </div>\n </div>,\n document.body,\n )\n : null}\n\n {showUsageStats ? (\n <UsageStatsModal\n open={showUsageStats}\n onClose={handleCloseUsageStats}\n />\n ) : null}\n <SecurityManagementModal\n open={showSecurityManagement}\n onClose={handleCloseSecurityManagement}\n />\n <FeedbackModal open={showFeedbackModal} onClose={handleCloseFeedbackModal} />\n <UserSettingsModal\n open={showUserSettings}\n onClose={handleCloseUserSettings}\n keepAwakeEnabled={keepAwakeEnabled}\n isKeepAwakeLoading={isKeepAwakeLoading}\n isKeepAwakeSaving={isKeepAwakeSaving}\n onToggleKeepAwake={handleKeepAwakeToggle}\n theme={theme}\n onSelectTheme={handleSelectTheme}\n onOpenPrivacyDeclaration={handleOpenPrivacyDeclaration}\n onAboutTabEnter={handleAboutTabEnter}\n versionInfo={versionInfo}\n />\n </div>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nexport function WechatGroupInvite() {\n const [showPopover, setShowPopover] = useState(false);\n const triggerRef = useRef<HTMLDivElement>(null);\n const popoverRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!showPopover) return;\n const handlePointerDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target) return;\n if (containerRef.current?.contains(target)) return;\n setShowPopover(false);\n };\n document.addEventListener('mousedown', handlePointerDown);\n return () => document.removeEventListener('mousedown', handlePointerDown);\n }, [showPopover]);\n\n return (\n <div ref={containerRef} className=\"relative px-4 mx-4 mb-[12px] rounded-[8px]\" style={{ background: 'var(--menu-hover-bg)' }}>\n <div\n ref={triggerRef}\n className=\"relative flex items-center gap-2 h-[44px] cursor-pointer transition-colors group\"\n onMouseEnter={() => setShowPopover(true)}\n onMouseLeave={() => setShowPopover(false)}\n data-testid=\"wechat-group-invite\"\n >\n <img src=\"/images/connectors/weixin.svg\" alt=\"\" className=\"w-[24px] h-[24px] shrink-0 relative z-10\" />\n <span className=\"text-[14px] font-normal text-[var(--text-primary)] truncate relative z-10\">扫码加入体验官交流群</span>\n {showPopover && (\n <div\n ref={popoverRef}\n className=\"ui-overlay-card absolute left-[-12px] right-[-12px] bottom-[calc(100%+12px)] z-50\"\n onMouseEnter={() => setShowPopover(true)}\n onMouseLeave={() => setShowPopover(false)}\n data-testid=\"wechat-group-qr-popover\"\n >\n <div className=\"p-4 flex items-center justify-center rounded-[inherit]\" style={{ aspectRatio: '1/1' }}>\n <img src=\"https://openjiuwen-ci.obs.cn-north-4.myhuaweicloud.com/office-claw/image/wechat-officeclaw.jpg\" alt=\"微信交流群二维码\" className=\"w-full h-full object-contain\" />\n </div>\n </div>\n )}\n </div>\n </div>\n );\n}","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport React from 'react';\nimport { UserProfile } from '../UserProfile';\nimport { WechatGroupInvite } from './WechatGroupInvite';\n\ninterface ThreadSidebarFooterProps {\n isSidebarCollapsedLayout: boolean;\n sidebarContentRevealClassName: string;\n}\n\nexport function ThreadSidebarFooter({\n isSidebarCollapsedLayout,\n sidebarContentRevealClassName,\n}: ThreadSidebarFooterProps) {\n return (\n <>\n {!isSidebarCollapsedLayout && (\n <div className={`transition-[opacity,transform] duration-150 ease-out ${sidebarContentRevealClassName}`}>\n <WechatGroupInvite />\n </div>\n )}\n\n {!isSidebarCollapsedLayout && <div className=\"mx-4 border-t border-[var(--border-default)]\" />}\n\n <UserProfile collapsed={isSidebarCollapsedLayout} />\n </>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport React from 'react';\nimport { Button } from '../shared/Button';\nimport { AppModal } from '../AppModal';\nimport type { Thread } from '@/stores/chatStore';\n\ninterface ThreadSidebarDeleteDialogProps {\n deleteTarget: Thread | null;\n deleteTargetSharedCount: number;\n deleteTargetIsShared: boolean;\n deleteWorkspace: boolean;\n setDeleteWorkspace: (value: boolean) => void;\n onClose: () => void;\n onConfirm: () => Promise<void>;\n}\n\nexport function ThreadSidebarDeleteDialog({\n deleteTarget,\n deleteTargetSharedCount,\n deleteTargetIsShared,\n deleteWorkspace,\n setDeleteWorkspace,\n onClose,\n onConfirm,\n}: ThreadSidebarDeleteDialogProps) {\n return (\n <AppModal\n open={!!deleteTarget}\n onClose={onClose}\n disableBackdropClose\n title={\n <div className=\"flex items-center gap-2\">\n <svg className=\"h-6 w-6 text-[var(--state-warning-text)]\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"M12.866 3.5a1 1 0 0 0-1.732 0l-8.25 14.5A1 1 0 0 0 3.75 19.5h16.5a1 1 0 0 0 .866-1.5l-8.25-14.5ZM12 8a1 1 0 0 1 1 1v4a1 1 0 1 1-2 0V9a1 1 0 0 1 1-1Zm0 9a1.25 1.25 0 1 1 0-2.5A1.25 1.25 0 0 1 12 17Z\" />\n </svg>\n <h3 className=\"text-[16px] font-bold text-[var(--modal-title-text)]\">确认删除会话</h3>\n </div>\n }\n panelClassName=\"w-[500px]\"\n bodyClassName=\"pt-5\"\n backdropTestId=\"thread-delete-modal\"\n panelTestId=\"thread-delete-modal-panel\"\n >\n <div className=\"flex flex-col gap-5\" data-testid=\"thread-delete-modal-content\">\n <div className=\"space-y-1\">\n <p className=\"text-sm text-[var(--modal-text-muted)]\">删除后,该会话及相关聊天记录将全部清空且不可恢复,关联的定时任务也会一并删除。</p>\n </div>\n\n <div className=\"space-y-2 rounded-[10px] border border-[var(--border-default)] bg-[var(--surface-secondary)] px-4 py-3\">\n <div className=\"text-xs font-semibold text-[var(--text-secondary)]\">工作目录</div>\n <div className=\"break-all font-mono text-xs text-[var(--text-primary)]\" data-testid=\"thread-delete-project-path\">\n {deleteTarget?.projectPath ?? '未设置'}\n </div>\n </div>\n\n <div className=\"space-y-1\" data-testid=\"thread-delete-shared-status\">\n <div className=\"text-xs font-semibold text-[var(--text-secondary)]\">共享状态</div>\n <p className={`text-sm ${deleteTargetIsShared ? 'text-[var(--state-warning-text)]' : 'text-[var(--text-muted)]'}`}>\n {deleteTargetIsShared\n ? `该工作目录当前被 ${deleteTargetSharedCount} 个其他会话共享,不能在删除会话时一并删除。`\n : '该工作目录当前未发现其他会话共享。'}\n </p>\n </div>\n\n <label className={`flex items-start gap-3 ${deleteTargetIsShared ? 'cursor-not-allowed opacity-70' : ''}`} data-testid=\"thread-delete-workspace-option\">\n <input\n type=\"checkbox\"\n className=\"mt-0.5 h-4 w-4 rounded border-[var(--border-strong)]\"\n checked={deleteTargetIsShared ? false : deleteWorkspace}\n disabled={deleteTargetIsShared}\n onChange={(event) => setDeleteWorkspace(event.target.checked)}\n />\n <div className=\"space-y-1\">\n <div className=\"text-sm font-medium text-[var(--text-primary)]\">同时删除工作目录(危险操作)</div>\n <p className=\"text-xs text-[var(--text-muted)]\">\n 危险操作:将永久删除该目录及其中所有文件,请确认这不是需要保留的重要目录。\n </p>\n {deleteTargetIsShared && (\n <p className=\"text-xs text-[var(--state-warning-text)]\">\n 共享工作目录不可在这里删除,请先处理其他会话后再手动清理该目录。\n </p>\n )}\n </div>\n </label>\n\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"default\" onClick={onClose}>\n 取消\n </Button>\n <Button onClick={onConfirm}>确定</Button>\n </div>\n </div>\n </AppModal>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nexport type ThreadFilterOption = 'all' | '1m' | '3m' | '6m';\n\nexport const MAX_SIDEBAR_RESTORE_FRAMES = 90;\nexport const SIDEBAR_SCROLL_STORAGE_KEY = 'office-claw:sidebar-scroll:v1';\nexport const LEGACY_SIDEBAR_SCROLL_STORAGE_KEY = 'cat-cafe:sidebar-scroll:v1';\nexport const MAX_SESSIONS = 200;\nexport const COLLAPSE_BREAKPOINT_PX = 1280;\nexport const PPT_PREVIEW_COLLAPSE_BREAKPOINT_PX = 1920;\nexport const SIDEBAR_CONTENT_REVEAL_MS = 80;\nexport const FILTER_PANEL_WIDTH_PX = 200;\nexport const FILTER_PANEL_GAP_PX = 8;\n\nexport const FILTER_OPTION_LABELS: Record<ThreadFilterOption, string> = {\n all: '全部',\n '1m': '近1个月',\n '3m': '近3个月',\n '6m': '近6个月',\n};\n\nexport const CONNECTOR_SOURCE_LABELS: Record<string, string> = {\n feishu: '飞书',\n wechat: '微信',\n slack: 'Slack',\n discord: 'Discord',\n dingtalk: '钉钉',\n};\n\nexport const THREAD_FILTER_OPTIONS: Array<{ key: ThreadFilterOption; label: string }> = [\n { key: 'all', label: '全部' },\n { key: '1m', label: '近1个月' },\n { key: '3m', label: '近3个月' },\n { key: '6m', label: '近6个月' },\n];\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport type { Thread } from '@/stores/chat-types';\nimport {\n COLLAPSE_BREAKPOINT_PX,\n CONNECTOR_SOURCE_LABELS,\n LEGACY_SIDEBAR_SCROLL_STORAGE_KEY,\n PPT_PREVIEW_COLLAPSE_BREAKPOINT_PX,\n SIDEBAR_SCROLL_STORAGE_KEY,\n} from './thread-sidebar-constants';\n\nexport function readSidebarScrollTop(): number {\n if (typeof window === 'undefined') return 0;\n try {\n let raw = window.sessionStorage.getItem(SIDEBAR_SCROLL_STORAGE_KEY);\n if (!raw) raw = window.sessionStorage.getItem(LEGACY_SIDEBAR_SCROLL_STORAGE_KEY);\n if (!raw) return 0;\n const value = Number(raw);\n return Number.isFinite(value) && value > 0 ? value : 0;\n } catch {\n return 0;\n }\n}\n\nexport function writeSidebarScrollTop(nextTop: number): void {\n if (typeof window === 'undefined') return;\n const safeTop = Number.isFinite(nextTop) && nextTop > 0 ? nextTop : 0;\n try {\n window.sessionStorage.setItem(SIDEBAR_SCROLL_STORAGE_KEY, String(safeTop));\n try {\n window.sessionStorage.removeItem(LEGACY_SIDEBAR_SCROLL_STORAGE_KEY);\n } catch {\n /* ignore */\n }\n } catch {\n // ignore storage failures\n }\n}\n\nexport function shouldCollapseSidebar(hasPptPreview = false): boolean {\n if (typeof window === 'undefined') return false;\n const breakpoint = hasPptPreview ? PPT_PREVIEW_COLLAPSE_BREAKPOINT_PX : COLLAPSE_BREAKPOINT_PX;\n return window.innerWidth <= breakpoint;\n}\n\nexport function getSidebarShellClassName(className: string | undefined, isCollapsed: boolean): string {\n const externalClasses = (className ?? 'shrink-0')\n .split(/\\s+/)\n .filter((token) => token && !token.startsWith('w-'))\n .join(' ');\n const widthClassName = isCollapsed ? 'w-12' : 'w-[256px]';\n return [externalClasses, widthClassName, 'ui-sidebar-shell flex h-full flex-col overflow-hidden transition-[width] duration-200 ease-out']\n .filter(Boolean)\n .join(' ');\n}\n\nexport function getThreadSourceLabel(thread: Thread): string | undefined {\n const connectorId = thread.connectorHubState?.connectorId;\n if (!connectorId) return undefined;\n return CONNECTOR_SOURCE_LABELS[connectorId] ?? connectorId;\n}\n\nexport function getThreadLastActiveAtMs(thread: Thread): number {\n const lastActiveAt = Number(thread.lastActiveAt);\n return Number.isFinite(lastActiveAt) ? lastActiveAt : 0;\n}\n\nexport function normalizeThreadSearchQuery(value: string): string {\n return value.trim().toLowerCase();\n}\n\nexport function closeSidebarOnMobile(onClose?: () => void): void {\n if (typeof window !== 'undefined' && window.innerWidth < 768) {\n onClose?.();\n }\n}\n\nexport function countNonDefaultThreads(threads: Thread[]): number {\n return threads.filter((thread) => thread.id !== 'default').length;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport React, { useCallback, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { Thread } from '@/stores/chatStore';\nimport { useDesktopWindowControls } from '@/hooks/useDesktopWindowControls';\nimport type { ThreadSidebarControllerResult } from './thread-sidebar-types';\nimport { DirectoryPickerModal } from './DirectoryPickerModal';\nimport { SectionGroup } from './SectionGroup';\nimport { ThreadItem } from './ThreadItem';\nimport { SearchInput } from '../shared/SearchInput';\nimport { MaskIcon } from '../shared/MaskIcon';\nimport { ThreadSidebarFooter } from './ThreadSidebarFooter';\nimport { ThreadSidebarDeleteDialog } from './ThreadSidebarDeleteDialog';\nimport { getSidebarShellClassName, getThreadSourceLabel } from './thread-sidebar-utils';\nimport { THREAD_FILTER_OPTIONS } from './thread-sidebar-constants';\nimport type { ThreadGroup } from './thread-utils';\nimport { OverflowTooltip } from '../shared/OverflowTooltip';\n\ninterface MenuButtonProps {\n label: string;\n testId: string;\n icon: string;\n active: boolean;\n onClick: () => void;\n collapsed: boolean;\n revealClassName: string;\n hidden?: boolean;\n}\n\ntype MenuItem = Omit<MenuButtonProps, 'collapsed' | 'revealClassName'>;\n\nfunction SidebarToggleIcon({ direction }: { direction: 'collapse' | 'expand' }) {\n const iconSrc = direction === 'collapse' ? '/icons/collapse.svg' : '/icons/expand.svg';\n return <img src={iconSrc} alt=\"\" aria-hidden=\"true\" className=\"h-4 w-4\" />;\n}\n\nfunction MenuButton({ label, testId, icon, active, onClick, collapsed, revealClassName, hidden }: MenuButtonProps) {\n const button = (\n <button\n type=\"button\"\n onClick={onClick}\n className={`ui-menu-item flex ${collapsed ? 'h-8 w-8 items-center justify-center px-0' : 'h-[38px] w-full items-center gap-2 px-2.5'} ${active ? 'ui-menu-item-active' : 'ui-menu-item-inactive'}`}\n data-testid={testId}\n aria-label={collapsed ? label : undefined}\n hidden={hidden}\n >\n <MaskIcon src={icon} className=\"h-5 w-5 text-[var(--mask-icon)]\" />\n <span className={collapsed ? 'sr-only' : `whitespace-nowrap transition-[opacity,transform] duration-150 ease-out ${revealClassName}`}>\n {label}\n </span>\n </button>\n );\n\n if (!collapsed || hidden) return button;\n\n return (\n <OverflowTooltip content={label} forceShow placement=\"right\" className=\"inline-flex\">\n {button}\n </OverflowTooltip>\n );\n}\n\nexport function ThreadSidebarView(controller: ThreadSidebarControllerResult) {\n const { startDrag } = useDesktopWindowControls();\n const sidebarBrandDragStateRef = useRef<{ isDragging: boolean; startX: number; startY: number }>({\n isDragging: false,\n startX: 0,\n startY: 0,\n });\n const {\n className,\n pathname,\n threads,\n isLoadingThreads,\n getThreadState,\n scrollRegionRef,\n normalizedQuery,\n displayThreadGroups,\n collapsedThreadItems,\n showNoResults,\n activeThreadIdFromRoute,\n existingProjects,\n govHealth,\n pinnedProjects,\n isCollapsed,\n toggleGroup,\n toggleProjectPin,\n handleNewChat,\n handleMenuNavigate,\n handleRename,\n handleDeleteRequest,\n handleTogglePin,\n handleToggleFavorite,\n handleUpdatePreferredAgents,\n handleSelect,\n showPicker,\n createInProject,\n bindWarning,\n filterPanelStyle,\n filterPanelRef,\n filterToggleRef,\n isSidebarCollapsed,\n isSidebarCollapsedLayout,\n sidebarContentRevealClassName,\n toggleSidebarCollapsed,\n searchQuery,\n isSearchOpen,\n showFilter,\n filterOption,\n handleSearchChange,\n handleSearchClear,\n toggleSearch,\n toggleFilter,\n selectFilter,\n deleteTarget,\n deleteTargetSharedCount,\n deleteTargetIsShared,\n deleteWorkspace,\n setDeleteWorkspace,\n closePicker,\n closeDeleteDialog,\n handleDeleteConfirm,\n } = controller;\n\n const handleSidebarBrandMouseDown = useCallback((event: React.MouseEvent<HTMLDivElement>) => {\n if (event.button !== 0) return;\n sidebarBrandDragStateRef.current = {\n isDragging: false,\n startX: event.clientX,\n startY: event.clientY,\n };\n }, []);\n\n useEffect(() => {\n const handleMouseMove = (event: MouseEvent) => {\n const state = sidebarBrandDragStateRef.current;\n if (state.startX === 0 || state.isDragging) return;\n\n const deltaX = Math.abs(event.clientX - state.startX);\n const deltaY = Math.abs(event.clientY - state.startY);\n if (deltaX <= 5 && deltaY <= 5) return;\n\n state.isDragging = true;\n startDrag();\n };\n\n const handleMouseUp = () => {\n sidebarBrandDragStateRef.current = {\n isDragging: false,\n startX: 0,\n startY: 0,\n };\n };\n\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n return () => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n };\n }, [startDrag]);\n\n const isChatMenu = pathname === '/';\n const isModelsMenu = pathname === '/models';\n const isAgentsMenu = pathname === '/agents';\n const isChannelsMenu = pathname === '/channels';\n const isSkillsMenu = pathname === '/skills';\n const isScheduledTasksMenu = pathname === '/schedule';\n const isInspirationMenu = pathname === '/inspiration';\n const menuItems: MenuItem[] = [\n { label: '新建会话', testId: 'sidebar-new-chat', icon: '/icons/menu/new-chat.svg', active: isChatMenu, onClick: handleNewChat },\n { label: '模型', testId: 'sidebar-menu-models', icon: '/icons/menu/models.svg', active: isModelsMenu, onClick: () => handleMenuNavigate('/models') },\n { label: '智能体', testId: 'sidebar-menu-agents', icon: '/icons/menu/agents.svg', active: isAgentsMenu, onClick: () => handleMenuNavigate('/agents') },\n { label: '渠道', testId: 'sidebar-menu-channels', icon: '/icons/menu/channels.svg', active: isChannelsMenu, onClick: () => handleMenuNavigate('/channels') },\n { label: '技能', testId: 'sidebar-menu-skills', icon: '/icons/menu/skills.svg', active: isSkillsMenu, onClick: () => handleMenuNavigate('/skills') },\n { label: '定时任务', testId: 'sidebar-menu-scheduled-tasks', icon: '/icons/menu/schedule.svg', active: isScheduledTasksMenu, onClick: () => handleMenuNavigate('/schedule') },\n { label: '灵感广场', testId: 'sidebar-menu-inspiration', icon: '/icons/menu/icon-inspiration.svg', active: isInspirationMenu, onClick: () => handleMenuNavigate('/inspiration') },\n ];\n\n const renderThreadItem = (thread: Thread, indented = false, iconOnly = false) => (\n <ThreadItem\n key={thread.id}\n id={thread.id}\n title={thread.title}\n participants={thread.participants}\n lastActiveAt={thread.lastActiveAt}\n isActive={activeThreadIdFromRoute === thread.id}\n onSelect={handleSelect}\n onDelete={handleDeleteRequest}\n onRename={handleRename}\n onTogglePin={handleTogglePin}\n onToggleFavorite={handleToggleFavorite}\n onUpdatePreferredAgents={handleUpdatePreferredAgents}\n isPinned={thread.pinned}\n isFavorited={thread.favorited}\n threadState={getThreadState(thread.id)}\n indented={indented}\n preferredAgentIds={thread.preferredAgentIds}\n invitedExpertIds={thread.invitedExpertIds}\n isHubThread={!!thread.connectorHubState}\n sourceLabel={getThreadSourceLabel(thread)}\n iconOnly={iconOnly}\n />\n );\n\n const renderGroup = (group: ThreadGroup) => {\n const groupKey = group.projectPath ?? group.type;\n const groupIcon =\n group.type === 'favorites' ? 'star' : group.type === 'archived-container' ? 'archive' : undefined;\n\n if (group.type === 'archived-container') {\n return (\n <SectionGroup\n key=\"archived-container\"\n label={group.label}\n icon=\"archive\"\n count={group.archivedGroups?.length ?? 0}\n isCollapsed={isCollapsed('archived-container')}\n onToggle={() => toggleGroup('archived-container')}\n >\n {group.archivedGroups?.map((subgroup) => {\n const subgroupKey = subgroup.projectPath ?? subgroup.type;\n return (\n <SectionGroup\n key={subgroupKey}\n label={subgroup.label}\n count={subgroup.threads.length}\n isCollapsed={isCollapsed(subgroupKey)}\n onToggle={() => toggleGroup(subgroupKey)}\n projectPath={subgroup.projectPath}\n governanceStatus={subgroup.projectPath ? govHealth[subgroup.projectPath] : undefined}\n onToggleProjectPin={subgroup.projectPath ? () => toggleProjectPin(subgroup.projectPath!) : undefined}\n isProjectPinned={subgroup.projectPath ? pinnedProjects.has(subgroup.projectPath) : undefined}\n >\n {subgroup.threads.map((thread) => renderThreadItem(thread, true))}\n </SectionGroup>\n );\n })}\n </SectionGroup>\n );\n }\n\n return (\n <SectionGroup\n key={groupKey}\n label={group.label}\n icon={groupIcon}\n count={group.threads.length}\n isCollapsed={group.type === 'pinned' || group.type === 'recent' ? false : isCollapsed(groupKey)}\n onToggle={group.type === 'pinned' || group.type === 'recent' ? () => { } : () => toggleGroup(groupKey)}\n hideToggle={group.type === 'pinned' || group.type === 'recent'}\n hideCount={group.type === 'pinned' || group.type === 'recent'}\n projectPath={group.projectPath}\n governanceStatus={group.projectPath ? govHealth[group.projectPath] : undefined}\n onToggleProjectPin={group.type === 'project' && group.projectPath ? () => toggleProjectPin(group.projectPath!) : undefined}\n isProjectPinned={group.type === 'project' && group.projectPath ? pinnedProjects.has(group.projectPath) : undefined}\n >\n {group.threads.map((thread) => renderThreadItem(thread, group.type === 'project'))}\n </SectionGroup>\n );\n };\n\n return (\n <>\n <aside className={getSidebarShellClassName(className, isSidebarCollapsed)} data-testid=\"thread-sidebar-shell\">\n <div\n className={`ui-sidebar-section ui-sidebar-section-no-divider flex ${isSidebarCollapsedLayout\n ? 'flex-col items-center gap-2 px-0 pt-[3px] pb-1'\n : 'items-center justify-between border-0 px-3 py-[14px]'\n }`}\n >\n {isSidebarCollapsed && (\n <div className=\"flex w-8 flex-col items-center border-b border-[var(--border-default)]\">\n <OverflowTooltip content=\"展开侧边栏\" forceShow placement=\"right\" className=\"inline-flex\">\n <button\n type=\"button\"\n onClick={toggleSidebarCollapsed}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-[6px] text-[var(--text-secondary)] transition-colors hover:bg-[var(--menu-hover-bg)] hover:text-[var(--text-primary)]\"\n aria-label=\"展开侧边栏\"\n >\n <SidebarToggleIcon direction=\"expand\" />\n </button>\n </OverflowTooltip>\n </div>\n )}\n {!isSidebarCollapsedLayout && (\n <div className=\"flex select-none items-center gap-3\" onMouseDown={handleSidebarBrandMouseDown} data-testid=\"thread-sidebar-brand-drag\">\n <img src=\"/images/lobster.svg\" alt=\"OfficeClaw\" draggable={false} className=\"h-[48px] w-[48px] rounded-lg\" />\n <span className={`whitespace-nowrap text-[20px] font-semibold leading-none tracking-tight text-[var(--text-primary)] transition-[opacity,transform] duration-150 ease-out ${sidebarContentRevealClassName}`}>\n OfficeClaw\n </span>\n </div>\n )}\n {!isSidebarCollapsedLayout && (\n <button\n type=\"button\"\n onClick={toggleSidebarCollapsed}\n className=\"inline-flex h-8 w-8 items-center justify-center rounded-[6px] text-[var(--text-secondary)] transition-colors hover:bg-[var(--menu-hover-bg)] hover:text-[var(--text-primary)]\"\n aria-label=\"收起侧边栏\"\n title=\"收起侧边栏\"\n >\n <SidebarToggleIcon direction=\"collapse\" />\n </button>\n )}\n </div>\n\n <div className={`ui-sidebar-section ${isSidebarCollapsedLayout ? 'ui-sidebar-section-no-divider px-0 py-2.5' : 'px-3 py-2.5'}`}>\n <div className={`flex flex-col ${isSidebarCollapsedLayout ? 'items-center gap-0.5' : 'items-start gap-1.5'}`}>\n {menuItems.map((item) => (\n <MenuButton key={item.testId} {...item} collapsed={isSidebarCollapsedLayout} revealClassName={sidebarContentRevealClassName} />\n ))}\n </div>\n </div>\n\n {isSidebarCollapsedLayout && (\n <div className=\"mx-auto flex h-6 w-8 items-center justify-center\" aria-hidden=\"true\">\n <div className=\"h-1 w-1 rounded-full bg-[#dbdbdb]\" />\n </div>\n )}\n\n {!isSidebarCollapsedLayout && bindWarning && (\n <div className=\"ui-status-warning border-b border-[var(--border-default)] px-3 py-1.5 text-[10px]\">{bindWarning}</div>\n )}\n\n {!isSidebarCollapsedLayout && (\n <div className={`relative px-4 pb-1 pt-2 transition-[opacity,transform] duration-150 ease-out ${sidebarContentRevealClassName}`}>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-xs font-semibold text-[var(--text-secondary)]\">会话消息</span>\n <div className=\"flex items-center\">\n <button\n ref={filterToggleRef}\n type=\"button\"\n onClick={toggleFilter}\n className={`rounded p-1 transition-colors ${showFilter || filterOption !== 'all' ? 'text-[var(--text-accent)]' : 'text-[var(--text-muted)] hover:text-[var(--text-accent)]'}`}\n title=\"筛选会话\"\n data-testid=\"thread-filter-toggle\"\n >\n <svg className=\"h-4 w-4 align-middle\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path\n id=\"_减去顶层\"\n d=\"M12.308 1.84961L3.68802 1.84961C3.38802 1.84961 3.09802 1.94961 2.86802 2.13961C2.40802 2.60961 2.26802 3.44961 2.68802 3.96961L5.86802 7.85961L5.86802 13.6396C5.86802 13.9196 6.08802 14.1396 6.36802 14.1396L9.72802 14.1396C9.95802 14.0896 10.138 13.8896 10.138 13.6396L10.138 7.85961L13.328 3.96961C13.518 3.73961 13.618 3.44961 13.618 3.14961C13.618 2.42961 13.028 1.84961 12.308 1.84961ZM12.608 3.14961C12.608 2.97961 12.478 2.84961 12.308 2.84961L3.68802 2.84961C3.61802 2.84961 3.54802 2.86961 3.49802 2.91961C3.36802 3.01961 3.34802 3.20961 3.45802 3.33961L6.74802 7.36961C6.81802 7.45961 6.85802 7.56961 6.85802 7.68961L6.85802 13.1496L9.12802 13.1496L9.12802 7.68961C9.12802 7.59961 9.14802 7.51961 9.19802 7.43961L12.548 3.33961C12.588 3.28961 12.608 3.21961 12.608 3.14961Z\"\n fillRule=\"evenodd\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n onClick={toggleSearch}\n className={`rounded p-1 transition-colors ${isSearchOpen || normalizedQuery.length > 0 ? 'text-[var(--text-accent)]' : 'text-[var(--text-muted)] hover:text-[var(--text-accent)]'}`}\n title=\"搜索会话\"\n data-testid=\"thread-search-toggle\"\n >\n <svg className=\"h-4 w-4\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n d=\"M1.72656 7.17676C1.72656 4.13919 4.189 1.67676 7.22656 1.67676C10.2641 1.67676 12.7266 4.13919 12.7266 7.17676C12.7266 8.50784 12.2537 9.72845 11.4668 10.6798L14.2009 13.3786C14.3974 13.5726 14.3995 13.8892 14.2055 14.0857C14.033 14.2604 13.7637 14.2814 13.568 14.1477L10.7625 11.3897C9.80641 12.1929 8.57299 12.6768 7.22656 12.6768C4.189 12.6768 1.72656 10.2143 1.72656 7.17676ZM11.7266 7.17676C11.7266 4.69147 9.71184 2.67676 7.22656 2.67676C4.74128 2.67676 2.72656 4.69147 2.72656 7.17676C2.72656 9.66205 4.74128 11.6768 7.22656 11.6768C9.71184 11.6768 11.7266 9.66205 11.7266 7.17676Z\"\n fillRule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {(isSearchOpen || normalizedQuery.length > 0) && (\n <SearchInput\n wrapperClassName=\"mt-2\"\n value={searchQuery}\n onChange={handleSearchChange}\n onClear={handleSearchClear}\n placeholder=\"搜索会话\"\n autoComplete=\"off\"\n aria-label=\"搜索会话\"\n />\n )}\n\n {showFilter &&\n filterPanelStyle &&\n typeof document !== 'undefined' &&\n createPortal(\n <div ref={filterPanelRef} className=\"ui-overlay-card fixed z-[99999] w-[200px] rounded-[6px] p-4\" style={filterPanelStyle}>\n <div className=\"text-[12px] font-[400] leading-[18px] text-[var(--text-label-secondary)]\">会话时间</div>\n <div className=\"mt-3 flex flex-col\">\n {THREAD_FILTER_OPTIONS.map((item) => (\n <button\n key={item.key}\n type=\"button\"\n className={`block w-full whitespace-nowrap px-3 py-2 text-left text-xs font-[400] leading-[18px] text-[var(--overlay-text)] transition-colors hover:bg-[var(--overlay-item-hover-bg)] focus-visible:bg-[var(--overlay-item-hover-bg)] focus-visible:outline-none ${filterOption === item.key ? 'text-[var(--text-accent)]' : ''}`}\n style={{ marginBottom: item.key === '6m' ? '0' : '14px' }}\n onClick={() => selectFilter(item.key)}\n >\n {item.label}\n </button>\n ))}\n </div>\n </div>,\n document.body,\n )}\n </div>\n )}\n\n <div\n ref={scrollRegionRef}\n className={`flex-1 overflow-y-auto ${!isSidebarCollapsedLayout ? `transition-[opacity,transform] duration-150 ease-out ${sidebarContentRevealClassName}` : 'ui-sidebar-collapsed-scroll overflow-x-hidden'}`}\n data-testid=\"thread-sidebar-scroll-region\"\n >\n {isLoadingThreads && threads.length === 0 && <div className=\"py-4 text-center text-xs text-[var(--text-label-secondary)]\">加载中..</div>}\n\n {isSidebarCollapsedLayout ? (\n <div className=\"flex flex-col items-center gap-1 py-2\">{collapsedThreadItems.map((thread: Thread) => renderThreadItem(thread, false, true))}</div>\n ) : showNoResults ? (\n <div className=\"flex h-full min-h-[120px] flex-col items-center justify-center px-3 py-4 text-center text-xs text-[var(--text-label-secondary)]\">\n <div className=\"text-[14px] font-[400] text-[var(--text-primary)]\">没有结果</div>\n <div className=\"mt-1 flex gap-1 text-[12px] font-[400] text-[var(--text-secondary)]\">\n 请\n <button type=\"button\" onClick={handleNewChat} className=\"text-[12px] font-[400] text-[var(--text-accent)]\">\n 新建会话\n </button>\n </div>\n </div>\n ) : (\n displayThreadGroups.map((group: ThreadGroup) => renderGroup(group))\n )}\n </div>\n\n <ThreadSidebarFooter isSidebarCollapsedLayout={isSidebarCollapsedLayout} sidebarContentRevealClassName={sidebarContentRevealClassName} />\n </aside>\n\n {showPicker && <DirectoryPickerModal existingProjects={existingProjects} onSelect={createInProject} onCancel={closePicker} />}\n\n <ThreadSidebarDeleteDialog\n deleteTarget={deleteTarget}\n deleteTargetSharedCount={deleteTargetSharedCount}\n deleteTargetIsShared={deleteTargetIsShared}\n deleteWorkspace={deleteWorkspace}\n setDeleteWorkspace={setDeleteWorkspace}\n onClose={closeDeleteDialog}\n onConfirm={handleDeleteConfirm}\n />\n </>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n/**\n * Sequenced toggle with failure reconciliation.\n *\n * Maintains per-key request sequence counters so that:\n * - Stale successful responses (from an older toggle) are discarded\n * - On failure, a reconcile GET fetches server truth, but only applies\n * if no newer toggle has fired since the reconcile was triggered\n *\n * Used by ThreadSidebar for pin/favorite toggles.\n */\n\nexport type FetchFn = (path: string, init?: RequestInit) => Promise<Response>;\n\nexport interface ToggleWithReconcileOptions {\n /** The fetch function to use (e.g. apiFetch) */\n fetch: FetchFn;\n /** Called when a new value should be applied to the store */\n onUpdate: (threadId: string, value: boolean) => void;\n /** JSON field name in the thread object (e.g. 'pinned' or 'favorited') */\n field: string;\n /** Pre-existing seq map to use (allows sharing across instances) */\n seqMap?: Map<string, number>;\n /** Sibling seq map — used to guard the sibling field during reconcile */\n siblingSeqMap: Map<string, number>;\n /** Called to apply sibling field value during reconcile */\n onUpdateSibling?: (threadId: string, value: boolean) => void;\n /** Sibling field name (e.g. 'favorited' when field is 'pinned') */\n siblingField?: string;\n}\n\nexport function createToggleWithReconcile(opts: ToggleWithReconcileOptions) {\n const seqMap = opts.seqMap ?? new Map<string, number>();\n\n async function reconcile(threadId: string, expectedSeq: number, expectedSiblingSeq: number): Promise<void> {\n try {\n const res = await opts.fetch(`/api/threads/${threadId}`);\n if (!res.ok) return;\n const t = await res.json();\n const val = t[opts.field];\n if (val !== undefined && seqMap.get(threadId) === expectedSeq) {\n opts.onUpdate(threadId, val);\n }\n if (opts.siblingField && opts.onUpdateSibling) {\n const sibVal = t[opts.siblingField];\n if (sibVal !== undefined && (opts.siblingSeqMap.get(threadId) ?? 0) === expectedSiblingSeq) {\n opts.onUpdateSibling(threadId, sibVal);\n }\n }\n } catch {\n // best-effort\n }\n }\n\n async function toggle(threadId: string, value: boolean): Promise<void> {\n const seq = (seqMap.get(threadId) ?? 0) + 1;\n seqMap.set(threadId, seq);\n const siblingSeq = opts.siblingSeqMap.get(threadId) ?? 0;\n try {\n const res = await opts.fetch(`/api/threads/${threadId}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ [opts.field]: value }),\n });\n if (!res.ok) {\n if (seqMap.get(threadId) === seq) {\n void reconcile(threadId, seq, siblingSeq);\n }\n return;\n }\n if (seqMap.get(threadId) !== seq) return;\n const updated = await res.json();\n opts.onUpdate(threadId, updated[opts.field] ?? value);\n } catch {\n if (seqMap.get(threadId) === seq) {\n void reconcile(threadId, seq, siblingSeq);\n }\n }\n }\n\n return { toggle, seqMap };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type RefObject } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { type Thread, useChatStore } from '@/stores/chatStore';\nimport { useToastStore } from '@/stores/toastStore';\nimport { apiFetch } from '@/utils/api-client';\nimport { useEscapeKey } from '@/hooks/useEscapeKey';\nimport { createToggleWithReconcile } from './toggle-with-reconcile';\nimport { MAX_SESSIONS } from './thread-sidebar-constants';\nimport { closeSidebarOnMobile, countNonDefaultThreads, writeSidebarScrollTop } from './thread-sidebar-utils';\n\ninterface ThreadSidebarActionParams {\n pathname: string;\n currentThreadId: string;\n threads: Thread[];\n showTrash: boolean;\n trashedThreads: Thread[];\n loadThreads: () => Promise<void>;\n loadTrash: () => Promise<void>;\n resetSearchAndFilter: () => void;\n onClose?: () => void;\n onThreadSelect?: () => void;\n getThreadState: (threadId: string) => { hasActiveInvocation?: boolean } | undefined;\n scrollRegionRef: RefObject<HTMLDivElement>;\n}\n\nexport interface ThreadSidebarActionResult {\n isCreating: boolean;\n showPicker: boolean;\n bindWarning: string | null;\n deleteTarget: Thread | null;\n deleteWorkspace: boolean;\n deleteTargetSharedCount: number;\n deleteTargetIsShared: boolean;\n handleNewChat: () => void;\n handleMenuNavigate: (path: string) => void;\n createInProject: (opts: {\n projectPath?: string;\n preferredAgentIds?: string[];\n title?: string;\n pinned?: boolean;\n backlogItemId?: string;\n sessionBindings?: Array<{ agentId: string; cliSessionId: string }>;\n }) => Promise<void>;\n handleDeleteRequest: (threadId: string) => void;\n handleDeleteConfirm: () => Promise<void>;\n handleRename: (threadId: string, title: string) => Promise<void>;\n handleTogglePin: (threadId: string, pinned: boolean) => void;\n handleToggleFavorite: (threadId: string, favorited: boolean) => void;\n handleUpdatePreferredAgents: (threadId: string, agentIds: string[]) => Promise<void>;\n handleSelect: (threadId: string) => void;\n setShowPicker: (value: boolean) => void;\n setDeleteWorkspace: (value: boolean) => void;\n closePicker: () => void;\n closeDeleteDialog: () => void;\n}\n\nexport function useThreadSidebarActions({\n pathname,\n currentThreadId,\n threads,\n showTrash,\n trashedThreads,\n loadThreads,\n loadTrash,\n resetSearchAndFilter,\n onClose,\n onThreadSelect,\n getThreadState,\n scrollRegionRef,\n}: ThreadSidebarActionParams): ThreadSidebarActionResult {\n const navigate = useNavigate();\n const { addToast } = useToastStore();\n const {\n setCurrentThread,\n setCurrentProject,\n updateThreadTitle,\n } = useChatStore();\n const [isCreating, setIsCreating] = useState(false);\n const [showPicker, setShowPicker] = useState(false);\n const [bindWarning, setBindWarning] = useState<string | null>(null);\n const [deleteTarget, setDeleteTarget] = useState<Thread | null>(null);\n const [deleteWorkspace, setDeleteWorkspace] = useState(false);\n const bindWarningTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const pinSeqMap = useRef(new Map<string, number>());\n const favSeqMap = useRef(new Map<string, number>());\n const pinToggle = useRef<ReturnType<typeof createToggleWithReconcile>>();\n const favToggle = useRef<ReturnType<typeof createToggleWithReconcile>>();\n\n if (!pinToggle.current) {\n pinToggle.current = createToggleWithReconcile({\n fetch: apiFetch,\n onUpdate: (threadId, value) => useChatStore.getState().updateThreadPin(threadId, value),\n field: 'pinned',\n seqMap: pinSeqMap.current,\n siblingSeqMap: favSeqMap.current,\n onUpdateSibling: (threadId, value) => useChatStore.getState().updateThreadFavorite(threadId, value),\n siblingField: 'favorited',\n });\n }\n\n if (!favToggle.current) {\n favToggle.current = createToggleWithReconcile({\n fetch: apiFetch,\n onUpdate: (threadId, value) => useChatStore.getState().updateThreadFavorite(threadId, value),\n field: 'favorited',\n seqMap: favSeqMap.current,\n siblingSeqMap: pinSeqMap.current,\n onUpdateSibling: (threadId, value) => useChatStore.getState().updateThreadPin(threadId, value),\n siblingField: 'pinned',\n });\n }\n\n useEscapeKey({\n enabled: deleteTarget !== null,\n onEscape: () => setDeleteTarget(null),\n });\n\n useEffect(() => {\n if (deleteTarget) setDeleteWorkspace(false);\n }, [deleteTarget]);\n\n const deleteTargetSharedCount = useMemo(() => {\n if (!deleteTarget?.projectPath) return 0;\n const relatedThreads = [...threads, ...trashedThreads];\n const sharedThreadIds = new Set(\n relatedThreads\n .filter((thread) => thread.id !== deleteTarget.id && thread.projectPath === deleteTarget.projectPath)\n .map((thread) => thread.id),\n );\n return sharedThreadIds.size;\n }, [deleteTarget, threads, trashedThreads]);\n\n const deleteTargetIsShared = deleteTargetSharedCount > 0;\n\n useEffect(() => {\n if (deleteTargetIsShared) setDeleteWorkspace(false);\n }, [deleteTargetIsShared]);\n\n useEffect(() => {\n return () => {\n if (bindWarningTimerRef.current) {\n clearTimeout(bindWarningTimerRef.current);\n }\n };\n }, []);\n\n const clearBindWarningLater = useCallback((message: string) => {\n setBindWarning(message);\n if (bindWarningTimerRef.current) {\n clearTimeout(bindWarningTimerRef.current);\n }\n bindWarningTimerRef.current = setTimeout(() => {\n setBindWarning(null);\n bindWarningTimerRef.current = null;\n }, 6000);\n }, []);\n\n const navigateToThread = useCallback(\n (threadId: string) => {\n navigate(threadId === 'default' ? '/' : `/thread/${threadId}`, { preventScrollReset: true });\n },\n [navigate],\n );\n\n const handleNewChat = useCallback(() => {\n const actualThreadCount = countNonDefaultThreads(threads);\n if (actualThreadCount >= MAX_SESSIONS) {\n addToast({\n type: 'error',\n title: '会话数量已达上限',\n message: `当前会话数量已达到 ${MAX_SESSIONS} 个上限,请删除一些会话后再创建新会话。`,\n duration: 5000,\n });\n return;\n }\n\n resetSearchAndFilter();\n setCurrentThread('default');\n setCurrentProject('default');\n navigateToThread('default');\n closeSidebarOnMobile(onClose);\n }, [\n addToast,\n navigateToThread,\n onClose,\n resetSearchAndFilter,\n setCurrentProject,\n setCurrentThread,\n threads,\n ]);\n\n const createInProject = useCallback(\n async (opts: {\n projectPath?: string;\n preferredAgentIds?: string[];\n title?: string;\n pinned?: boolean;\n backlogItemId?: string;\n sessionBindings?: Array<{ agentId: string; cliSessionId: string }>;\n }) => {\n const actualThreadCount = countNonDefaultThreads(threads);\n if (actualThreadCount >= MAX_SESSIONS) {\n addToast({\n type: 'error',\n title: '会话数量已达上限',\n message: `当前会话数量已达到 ${MAX_SESSIONS} 个上限,请删除一些会话后再创建新会话。`,\n duration: 5000,\n });\n return;\n }\n\n setIsCreating(true);\n setShowPicker(false);\n try {\n const res = await apiFetch('/api/threads', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...(opts.projectPath ? { projectPath: opts.projectPath } : {}),\n ...(opts.preferredAgentIds?.length ? { preferredAgentIds: opts.preferredAgentIds } : {}),\n ...(opts.title ? { title: opts.title } : {}),\n ...(opts.pinned ? { pinned: opts.pinned } : {}),\n ...(opts.backlogItemId ? { backlogItemId: opts.backlogItemId } : {}),\n }),\n });\n if (!res.ok) return;\n const thread: Thread = await res.json();\n\n if (opts.sessionBindings?.length) {\n const results = await Promise.allSettled(\n opts.sessionBindings.map(({ agentId, cliSessionId }) =>\n apiFetch(`/api/threads/${thread.id}/sessions/${agentId}/bind`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ cliSessionId }),\n }),\n ),\n );\n const failed = results.filter((result) => result.status === 'rejected' || (result.status === 'fulfilled' && !result.value.ok));\n if (failed.length > 0) {\n clearBindWarningLater(`Session 绑定部分失败(${failed.length}/${results.length}),可在 Session 面板重试`);\n }\n }\n\n if (opts.projectPath) setCurrentProject(opts.projectPath);\n navigateToThread(thread.id);\n closeSidebarOnMobile(onClose);\n await loadThreads();\n } catch {\n // Silently ignore\n } finally {\n setIsCreating(false);\n }\n },\n [addToast, loadThreads, navigateToThread, onClose, setCurrentProject, threads, clearBindWarningLater],\n );\n\n const handleDeleteRequest = useCallback(\n (threadId: string) => {\n const threadState = getThreadState(threadId);\n if (threadState?.hasActiveInvocation) return;\n const thread = threads.find((item) => item.id === threadId);\n if (thread) setDeleteTarget(thread);\n },\n [getThreadState, threads],\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (!deleteTarget) return;\n const threadId = deleteTarget.id;\n const sharedCountAtDelete = deleteTargetSharedCount;\n const shouldDeleteWorkspace = deleteWorkspace && !deleteTargetIsShared;\n setDeleteTarget(null);\n try {\n const query = shouldDeleteWorkspace ? '?deleteWorkspace=true' : '';\n const res = await apiFetch(`/api/threads/${threadId}${query}`, { method: 'DELETE' });\n if (!res.ok && res.status !== 204) return;\n if (shouldDeleteWorkspace) {\n const workspaceDeleteSucceeded = res.headers.get('x-office-claw-workspace-delete-succeeded') === 'true';\n const workspaceDeleteReason = res.headers.get('x-office-claw-workspace-delete-reason');\n const workspaceWasShared = res.headers.get('x-office-claw-workspace-delete-shared') === 'true';\n const workspaceSharedCount = Number(res.headers.get('x-office-claw-workspace-delete-shared-count') ?? sharedCountAtDelete);\n const memoryPreserved = res.headers.get('x-office-claw-memory-preserved') === 'true';\n\n if (workspaceDeleteSucceeded) {\n if (memoryPreserved) {\n addToast({\n type: 'success',\n title: '工作目录已删除',\n message: '工作目录内容已删除,memory 目录已保留(包含 agent 索引缓存)。如需彻底清理可手动删除。',\n duration: 5000,\n });\n } else if (workspaceWasShared) {\n addToast({\n type: 'info',\n title: '工作目录删除成功',\n message: `工作目录已删除。该目录在删除前被 ${workspaceSharedCount} 个其他会话共享,其他会话可能异常。`,\n duration: 5000,\n });\n } else {\n addToast({\n type: 'success',\n title: '工作目录已删除',\n message: '工作目录已完全删除。',\n duration: 5000,\n });\n }\n } else {\n const workspaceSharedSkip = workspaceDeleteReason === 'shared_workspace';\n const reasonMessage =\n workspaceSharedSkip\n ? '该工作目录正在被其他会话共享,系统已保留,避免影响其他会话。'\n : workspaceDeleteReason === 'unsafe_root'\n ? '系统判定该路径过于危险,已跳过删除。'\n : workspaceDeleteReason === 'not_directory'\n ? '该路径不是目录,已跳过删除。'\n : workspaceDeleteReason === 'path_resolution_failed'\n ? '目录路径解析失败,请检查目录是否仍然存在。'\n : workspaceDeleteReason === 'delete_failed'\n ? '目录删除失败,可能是文件占用或权限不足。'\n : '工作目录未删除,请手动检查。';\n\n addToast({\n type: workspaceSharedSkip ? 'info' : 'error',\n title: workspaceSharedSkip ? '工作目录已保留' : '工作目录未删除',\n message: reasonMessage,\n duration: 6000,\n });\n }\n }\n if (threadId === currentThreadId) {\n navigateToThread('default');\n }\n await loadThreads();\n if (showTrash) void loadTrash();\n } catch {\n // Silently ignore\n }\n }, [\n addToast,\n currentThreadId,\n deleteTarget,\n deleteTargetIsShared,\n deleteTargetSharedCount,\n deleteWorkspace,\n loadThreads,\n loadTrash,\n navigateToThread,\n showTrash,\n ]);\n\n const handleRename = useCallback(\n async (threadId: string, title: string) => {\n const nextTitle = title.trim();\n if (!nextTitle) return;\n try {\n const res = await apiFetch(`/api/threads/${threadId}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ title: nextTitle }),\n });\n if (!res.ok) return;\n const updated = await res.json();\n updateThreadTitle(threadId, updated.title ?? nextTitle);\n } catch {\n // Silently ignore\n }\n },\n [updateThreadTitle],\n );\n\n const handleTogglePin = useCallback(\n (threadId: string, pinned: boolean) => void pinToggle.current?.toggle(threadId, pinned),\n [],\n );\n\n const handleToggleFavorite = useCallback(\n (threadId: string, favorited: boolean) => void favToggle.current?.toggle(threadId, favorited),\n [],\n );\n\n const handleUpdatePreferredAgents = useCallback(async (threadId: string, agentIds: string[]) => {\n const res = await apiFetch(`/api/threads/${threadId}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ preferredAgentIds: agentIds }),\n });\n if (!res.ok) throw new Error('保存失败');\n useChatStore.getState().updateThreadPreferredAgents(threadId, agentIds);\n }, []);\n\n const handleSelect = useCallback(\n (threadId: string) => {\n onThreadSelect?.();\n const scrollRegion = scrollRegionRef.current;\n if (scrollRegion) {\n writeSidebarScrollTop(scrollRegion.scrollTop);\n }\n const isAlreadyOnThreadRoute = (threadId === 'default' && pathname === '/') || pathname === `/thread/${threadId}`;\n if (threadId === currentThreadId && isAlreadyOnThreadRoute) return;\n const target = threads.find((thread) => thread.id === threadId);\n setCurrentProject(target?.projectPath ?? 'default');\n setCurrentThread(threadId);\n navigateToThread(threadId);\n closeSidebarOnMobile(onClose);\n },\n [currentThreadId, navigateToThread, onClose, onThreadSelect, pathname, scrollRegionRef, setCurrentProject, setCurrentThread, threads],\n );\n\n const handleMenuNavigate = useCallback(\n (path: string) => {\n navigate(path);\n closeSidebarOnMobile(onClose);\n },\n [onClose, navigate],\n );\n\n return {\n isCreating,\n showPicker,\n bindWarning,\n deleteTarget,\n deleteWorkspace,\n deleteTargetSharedCount,\n deleteTargetIsShared,\n handleNewChat,\n handleMenuNavigate,\n createInProject,\n handleDeleteRequest,\n handleDeleteConfirm,\n handleRename,\n handleTogglePin,\n handleToggleFavorite,\n handleUpdatePreferredAgents,\n handleSelect,\n setShowPicker,\n setDeleteWorkspace,\n closePicker: () => setShowPicker(false),\n closeDeleteDialog: () => setDeleteTarget(null),\n };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n/**\n * F095 Phase A: Collapse state persistence logic (pure functions, no React).\n */\n\nexport const STORAGE_KEY = 'office-claw:sidebar:collapsed-groups';\nconst LEGACY_STORAGE_KEY = 'cat-cafe:sidebar:collapsed-groups';\n\nexport interface StorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem?(key: string): void;\n}\n\n/** Read persisted collapsed groups from storage. Returns null if nothing stored/invalid. */\nexport function readCollapsedGroups(storage: StorageLike): string[] | null {\n try {\n let raw = storage.getItem(STORAGE_KEY);\n if (!raw) raw = storage.getItem(LEGACY_STORAGE_KEY);\n if (raw) {\n const parsed = JSON.parse(raw);\n if (Array.isArray(parsed) && parsed.every((k) => typeof k === 'string')) {\n return parsed;\n }\n }\n } catch {\n // storage unavailable or corrupted\n }\n return null;\n}\n\n/** Persist collapsed groups to storage. */\nexport function writeCollapsedGroups(groupKeys: string[], storage: StorageLike): void {\n try {\n storage.setItem(STORAGE_KEY, JSON.stringify(groupKeys));\n try {\n storage.removeItem?.(LEGACY_STORAGE_KEY);\n } catch {\n /* ignore */\n }\n } catch {\n // Best effort\n }\n}\n\n/** Compute initial collapsed set: restore from storage, or default to all collapsed. */\nexport function initCollapsedSet(allGroupKeys: string[], storage: StorageLike): Set<string> {\n const stored = readCollapsedGroups(storage);\n if (stored !== null) return new Set(stored);\n return new Set(allGroupKeys);\n}\n\n/** Determine if a group should render as collapsed. */\nexport function shouldCollapse(groupKey: string, collapsedSet: Set<string>, searchQuery: string): boolean {\n if (searchQuery.length > 0) return false;\n return collapsedSet.has(groupKey);\n}\n\n/** Before storage is read, default to collapsed (prevents first-render flicker). */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport function shouldCollapseBeforeInit(_groupKey: string): boolean {\n return true;\n}\n\n/**\n * Resolve collapse state for a group, handling pre-init + search priority.\n * This is the pure-function equivalent of the hook's isCollapsed callback.\n */\nexport function resolveCollapse(\n groupKey: string,\n collapsedSet: Set<string>,\n searchQuery: string,\n isInitialized: boolean,\n): boolean {\n if (searchQuery.length > 0) return false;\n if (!isInitialized) return shouldCollapseBeforeInit(groupKey);\n return shouldCollapse(groupKey, collapsedSet, searchQuery);\n}\n\n/** Return empty set (all expanded). */\nexport function expandAllGroups(): Set<string> {\n return new Set();\n}\n\n/** Return set containing all provided keys (all collapsed). */\nexport function collapseAllGroups(allKnownKeys: string[]): Set<string> {\n return new Set(allKnownKeys);\n}\n\n/**\n * Find the group key that contains a given thread ID.\n * When a thread appears in multiple groups (e.g. both 'recent' and a project group),\n * prefer project/pinned groups over 'recent' to avoid sidebar jumping when ordering threads.\n */\nexport function findGroupKeyForThread(\n threadId: string,\n groups: { groupKey: string; threadIds: string[]; type?: string }[],\n): string | undefined {\n let recentFallback: string | undefined;\n for (const g of groups) {\n if (g.threadIds.includes(threadId)) {\n if (g.type === 'recent') {\n if (!recentFallback) recentFallback = g.groupKey;\n } else {\n return g.groupKey;\n }\n }\n }\n return recentFallback;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n collapseAllGroups,\n expandAllGroups,\n findGroupKeyForThread,\n initCollapsedSet,\n resolveCollapse,\n type StorageLike,\n writeCollapsedGroups,\n} from './collapse-state';\nimport type { ThreadGroup } from './thread-utils';\n\n/** Group key extraction — matches ThreadSidebar's groupKey logic */\nfunction getGroupKey(group: ThreadGroup): string {\n return group.projectPath ?? group.type;\n}\n\nfunction getStorage(): StorageLike {\n return typeof window !== 'undefined' ? window.localStorage : { getItem: () => null, setItem: () => {} };\n}\n\nexport interface UseCollapseStateOptions {\n threadGroups: ThreadGroup[];\n searchQuery: string;\n currentThreadId: string | undefined;\n}\n\nexport function useCollapseState({ threadGroups, searchQuery, currentThreadId }: UseCollapseStateOptions) {\n const initialized = useRef(false);\n const allKnownKeys = useRef<Set<string>>(new Set());\n const lastAutoExpandedThreadId = useRef<string | undefined>(undefined);\n const [collapsed, setCollapsed] = useState<Set<string>>(() => new Set());\n\n // Accumulate all ever-seen group keys (P1-1 fix: collapseAll needs full set)\n for (const g of threadGroups) {\n allKnownKeys.current.add(getGroupKey(g));\n }\n\n // Initialize from localStorage once we know the group keys\n useEffect(() => {\n if (initialized.current) return;\n if (threadGroups.length === 0) return;\n const allKeys = threadGroups.map(getGroupKey);\n setCollapsed(initCollapsedSet(allKeys, getStorage()));\n initialized.current = true;\n }, [threadGroups]);\n\n // Persist whenever collapsed state changes\n useEffect(() => {\n if (!initialized.current) return;\n writeCollapsedGroups([...collapsed], getStorage());\n }, [collapsed]);\n\n // Auto-expand group containing the current active thread\n useEffect(() => {\n // Reset guard when navigating away (including to undefined/\"no thread\"),\n // so returning to the same thread will auto-expand its group again.\n if (lastAutoExpandedThreadId.current && lastAutoExpandedThreadId.current !== currentThreadId) {\n lastAutoExpandedThreadId.current = undefined;\n }\n if (!currentThreadId || !initialized.current) return;\n if (lastAutoExpandedThreadId.current === currentThreadId) return;\n const groupsMeta = threadGroups.map((g) => ({\n groupKey: getGroupKey(g),\n threadIds: g.threads.map((t) => t.id),\n type: g.type,\n }));\n const key = findGroupKeyForThread(currentThreadId, groupsMeta);\n if (!key) return;\n lastAutoExpandedThreadId.current = currentThreadId;\n setCollapsed((prev) => {\n if (!prev.has(key)) return prev;\n const next = new Set(prev);\n next.delete(key);\n return next;\n });\n }, [currentThreadId, threadGroups]);\n\n const isCollapsed = useCallback(\n (groupKey: string): boolean => resolveCollapse(groupKey, collapsed, searchQuery, initialized.current),\n [collapsed, searchQuery],\n );\n\n const toggleGroup = useCallback((groupKey: string) => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(groupKey)) next.delete(groupKey);\n else next.add(groupKey);\n return next;\n });\n }, []);\n\n const expandAll = useCallback(() => setCollapsed(expandAllGroups()), []);\n\n // P1-1 fix: use allKnownKeys (accumulated), not filtered threadGroups\n const collapseAll = useCallback(() => {\n setCollapsed(collapseAllGroups([...allKnownKeys.current]));\n }, []);\n\n return { isCollapsed, toggleGroup, expandAll, collapseAll };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { readPinnedProjects, writePinnedProjects } from './active-workspace';\nimport type { StorageLike } from './collapse-state';\n\nfunction getStorage(): StorageLike {\n return typeof window !== 'undefined' ? window.localStorage : { getItem: () => null, setItem: () => {} };\n}\n\nexport function useProjectPins() {\n const initialized = useRef(false);\n const [pinnedProjects, setPinnedProjects] = useState<Set<string>>(() => new Set());\n\n // Read from localStorage on mount\n useEffect(() => {\n if (initialized.current) return;\n setPinnedProjects(readPinnedProjects(getStorage()));\n initialized.current = true;\n }, []);\n\n // Persist on change\n useEffect(() => {\n if (!initialized.current) return;\n writePinnedProjects(pinnedProjects, getStorage());\n }, [pinnedProjects]);\n\n const toggleProjectPin = useCallback((projectPath: string) => {\n setPinnedProjects((prev) => {\n const next = new Set(prev);\n if (next.has(projectPath)) next.delete(projectPath);\n else next.add(projectPath);\n return next;\n });\n }, []);\n\n return { pinnedProjects, toggleProjectPin };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { type RefObject, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { io } from 'socket.io-client';\nimport { useAuthorizationPendingStore } from '@/stores/authorizationPendingStore';\nimport type { ThreadState } from '@/stores/chat-types';\nimport { type Thread, useChatStore } from '@/stores/chatStore';\nimport { API_URL, apiFetch } from '@/utils/api-client';\nimport { getUserId } from '@/utils/userId';\nimport { FILTER_OPTION_LABELS, MAX_SIDEBAR_RESTORE_FRAMES, type ThreadFilterOption } from './thread-sidebar-constants';\nimport {\n getThreadLastActiveAtMs,\n normalizeThreadSearchQuery,\n readSidebarScrollTop,\n writeSidebarScrollTop,\n} from './thread-sidebar-utils';\nimport { normalizeStoredThreadTitleOrNull } from './thread-title';\nimport { getProjectPaths, type ThreadGroup } from './thread-utils';\nimport { useCollapseState } from './useCollapseState';\nimport { useProjectPins } from './useProjectPins';\n\nexport interface UseThreadSidebarDataParams {\n searchQuery: string;\n filterOption: ThreadFilterOption;\n}\n\nexport interface UseThreadSidebarDataResult {\n pathname: string;\n threads: Thread[];\n currentThreadId: string;\n isLoadingThreads: boolean;\n getThreadState: (threadId: string) => ThreadState | undefined;\n scrollRegionRef: RefObject<HTMLDivElement>;\n normalizedQuery: string;\n displayThreadGroups: ThreadGroup[];\n collapsedThreadItems: Thread[];\n showNoResults: boolean;\n activeThreadIdFromRoute: string | null;\n existingProjects: string[];\n govHealth: Record<string, string>;\n pinnedProjects: Set<string>;\n isCollapsed: (groupKey: string) => boolean;\n toggleGroup: (groupKey: string) => void;\n toggleProjectPin: (projectPath: string) => void;\n loadThreads: () => Promise<void>;\n showTrash: boolean;\n trashedThreads: Thread[];\n isLoadingTrash: boolean;\n loadTrash: () => Promise<void>;\n toggleTrashVisibility: () => void;\n restoreThread: (threadId: string) => Promise<void>;\n isMarkingAllRead: boolean;\n handleMarkAllRead: () => Promise<void>;\n}\n\ninterface PendingAuthorizationSummary {\n threadId?: string;\n requestId?: string;\n}\n\nexport function useThreadSidebarData({\n searchQuery,\n filterOption,\n}: UseThreadSidebarDataParams): UseThreadSidebarDataResult {\n const { pathname } = useLocation();\n const { threads, currentThreadId, setThreads, isLoadingThreads, setLoadingThreads, getThreadState } = useChatStore();\n const [showTrash, setShowTrash] = useState(false);\n const [trashedThreads, setTrashedThreads] = useState<Thread[]>([]);\n const [isLoadingTrash, setIsLoadingTrash] = useState(false);\n const [govHealth, setGovHealth] = useState<Record<string, string>>({});\n const [isMarkingAllRead, setIsMarkingAllRead] = useState(false);\n const scrollRegionRef = useRef<HTMLDivElement>(null);\n const restoreFrameRef = useRef<number | null>(null);\n const normalizedQuery = normalizeThreadSearchQuery(searchQuery);\n\n const loadThreads = useCallback(async () => {\n setLoadingThreads(true);\n try {\n const res = await apiFetch('/api/threads');\n if (!res.ok) return;\n const data = await res.json();\n const nextThreads = (data.threads ?? []).map((thread: Thread) => ({\n ...thread,\n title: normalizeStoredThreadTitleOrNull(thread.title),\n }));\n setThreads(nextThreads);\n const initThreadUnread = useChatStore.getState().initThreadUnread;\n if (typeof initThreadUnread === 'function') {\n for (const thread of nextThreads) {\n initThreadUnread(thread.id, thread.unreadCount ?? 0, !!thread.hasUserMention);\n }\n }\n } catch {\n // Silently ignore\n } finally {\n setLoadingThreads(false);\n }\n }, [setLoadingThreads, setThreads]);\n\n useEffect(() => {\n void loadThreads();\n }, [loadThreads]);\n\n useEffect(() => {\n let cancelled = false;\n\n void (async () => {\n try {\n const res = await apiFetch('/api/authorization/pending');\n if (!res.ok) return;\n const data = (await res.json()) as { pending?: PendingAuthorizationSummary[] };\n if (cancelled) return;\n useAuthorizationPendingStore.getState().syncAllPending(data.pending ?? []);\n } catch {\n // Best effort\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n useEffect(() => {\n const refresh = () => void loadThreads();\n window.addEventListener('office-claw:threads-refresh', refresh);\n return () => window.removeEventListener('office-claw:threads-refresh', refresh);\n }, [loadThreads]);\n\n useEffect(() => {\n const userId = getUserId();\n const socket = io(API_URL, {\n transports: ['websocket', 'polling'],\n auth: { userId },\n });\n\n socket.on('connect', () => {\n socket.emit('join_room', `user:${userId}`);\n });\n\n socket.on('thread_created', (data: { threadId: string; source?: string }) => {\n if (data.source === 'connector_auto') {\n void loadThreads();\n }\n });\n\n socket.on('connector_message', (data: { threadId: string; message?: { timestamp?: number } }) => {\n const store = useChatStore.getState();\n const threadExists = store.threads.some((thread) => thread.id === data.threadId);\n if (!threadExists) {\n void loadThreads();\n return;\n }\n store.updateThreadLastActive?.(data.threadId, data.message?.timestamp ?? Date.now());\n });\n\n return () => {\n socket.disconnect();\n };\n }, [loadThreads]);\n\n const cancelPendingScrollRestore = useCallback(() => {\n if (restoreFrameRef.current !== null) {\n cancelAnimationFrame(restoreFrameRef.current);\n restoreFrameRef.current = null;\n }\n }, []);\n\n useEffect(() => {\n const element = scrollRegionRef.current;\n if (!element) return;\n const handleScroll = () => {\n writeSidebarScrollTop(element.scrollTop);\n };\n element.addEventListener('scroll', handleScroll, { passive: true });\n return () => element.removeEventListener('scroll', handleScroll);\n }, []);\n\n const scheduleScrollRestore = useCallback(\n (targetTop: number) => {\n cancelPendingScrollRestore();\n if (!Number.isFinite(targetTop) || targetTop <= 0) return;\n\n let framesRemaining = MAX_SIDEBAR_RESTORE_FRAMES;\n const apply = () => {\n const element = scrollRegionRef.current;\n if (!element) {\n restoreFrameRef.current = null;\n return;\n }\n\n const maxTop = Math.max(0, element.scrollHeight - element.clientHeight);\n const clampedTop = Math.min(targetTop, maxTop);\n element.scrollTop = clampedTop;\n\n const canSettle = maxTop >= targetTop;\n const reachedTarget = Math.abs(element.scrollTop - clampedTop) <= 1;\n if ((canSettle && reachedTarget) || framesRemaining <= 0) {\n writeSidebarScrollTop(element.scrollTop);\n restoreFrameRef.current = null;\n return;\n }\n\n framesRemaining -= 1;\n restoreFrameRef.current = requestAnimationFrame(apply);\n };\n\n apply();\n },\n [cancelPendingScrollRestore],\n );\n\n useLayoutEffect(() => {\n scheduleScrollRestore(readSidebarScrollTop());\n return cancelPendingScrollRestore;\n }, [threads.length, isLoadingThreads, pathname, scheduleScrollRestore, cancelPendingScrollRestore]);\n\n useEffect(() => {\n void (async () => {\n try {\n const res = await apiFetch('/api/governance/health');\n if (!res.ok) return;\n const data = (await res.json()) as { projects: { projectPath: string; status: string }[] };\n const nextHealth: Record<string, string> = {};\n for (const project of data.projects) {\n nextHealth[project.projectPath] = project.status;\n }\n setGovHealth(nextHealth);\n } catch {\n // Best effort\n }\n })();\n }, []);\n\n const loadTrash = useCallback(async () => {\n setIsLoadingTrash(true);\n try {\n const res = await apiFetch('/api/threads?deleted=true');\n if (!res.ok) return;\n const data = await res.json();\n setTrashedThreads(data.threads ?? []);\n } catch {\n // Silently ignore\n } finally {\n setIsLoadingTrash(false);\n }\n }, []);\n\n const toggleTrashVisibility = useCallback(() => {\n setShowTrash((prev) => {\n const next = !prev;\n if (next) void loadTrash();\n return next;\n });\n }, [loadTrash]);\n\n const restoreThread = useCallback(\n async (threadId: string) => {\n try {\n const res = await apiFetch(`/api/threads/${threadId}/restore`, { method: 'POST' });\n if (!res.ok) return;\n await loadThreads();\n await loadTrash();\n } catch {\n // Silently ignore\n }\n },\n [loadThreads, loadTrash],\n );\n\n const filteredThreads = useMemo(() => {\n let result = threads;\n if (normalizedQuery) {\n result = result.filter((thread) => {\n const title = (thread.title?.trim() || (thread.id === 'default' ? '大厅' : '未命名会话')).toLowerCase();\n return title.includes(normalizedQuery);\n });\n }\n if (filterOption !== 'all') {\n const now = Date.now();\n const days = filterOption === '1m' ? 30 : filterOption === '3m' ? 90 : 180;\n const threshold = now - days * 24 * 60 * 60 * 1000;\n result = result.filter((thread) => getThreadLastActiveAtMs(thread) >= threshold);\n }\n return result;\n }, [filterOption, normalizedQuery, threads]);\n\n const threadGroups = useMemo<ThreadGroup[]>(() => {\n const sortable = filteredThreads.filter((thread) => thread.id !== 'default');\n const sortedAll = [...sortable].sort((a, b) => b.lastActiveAt - a.lastActiveAt);\n const sortedPinned = sortedAll.filter((thread) => thread.pinned);\n const sortedUnpinned = sortedAll.filter((thread) => !thread.pinned);\n const groups: ThreadGroup[] = [];\n if (sortedPinned.length > 0) {\n groups.push({ type: 'pinned', label: '置顶', threads: sortedPinned });\n }\n groups.push({ type: 'recent', label: FILTER_OPTION_LABELS[filterOption], threads: sortedUnpinned });\n return groups;\n }, [filterOption, filteredThreads]);\n\n const displayThreadGroups = useMemo(() => threadGroups, [threadGroups]);\n const collapsedThreadItems = useMemo(\n () =>\n displayThreadGroups.flatMap((group) =>\n group.type === 'archived-container'\n ? (group.archivedGroups?.flatMap((subgroup) => subgroup.threads) ?? group.threads)\n : group.threads,\n ),\n [displayThreadGroups],\n );\n const hasVisibleThreads = useMemo(\n () => displayThreadGroups.some((group) => (group.threads?.length ?? 0) > 0),\n [displayThreadGroups],\n );\n const showDefaultThread = normalizedQuery.length === 0 || '大厅'.includes(normalizedQuery);\n const showNoResults =\n !hasVisibleThreads && !showDefaultThread && (normalizedQuery.length > 0 || filterOption !== 'all');\n const { pinnedProjects, toggleProjectPin } = useProjectPins();\n const { isCollapsed, toggleGroup } = useCollapseState({\n threadGroups,\n searchQuery: normalizedQuery,\n currentThreadId,\n });\n\n const activeThreadIdFromRoute = pathname.startsWith('/thread/') ? pathname.slice('/thread/'.length) : null;\n const existingProjects = useMemo(() => getProjectPaths(threads), [threads]);\n\n const handleMarkAllRead = useCallback(async () => {\n setIsMarkingAllRead(true);\n try {\n const res = await apiFetch('/api/threads/read/mark-all', { method: 'POST' });\n if (res.ok) {\n useChatStore.getState().clearAllUnread?.();\n }\n } catch (err) {\n console.debug('[F072] mark-all-read failed:', err);\n } finally {\n setIsMarkingAllRead(false);\n }\n }, []);\n\n return {\n pathname,\n threads,\n currentThreadId,\n isLoadingThreads,\n getThreadState,\n scrollRegionRef,\n normalizedQuery,\n displayThreadGroups,\n collapsedThreadItems,\n showNoResults,\n activeThreadIdFromRoute,\n existingProjects,\n govHealth,\n pinnedProjects,\n isCollapsed,\n toggleGroup,\n toggleProjectPin,\n loadThreads,\n showTrash,\n trashedThreads,\n isLoadingTrash,\n loadTrash,\n toggleTrashVisibility,\n restoreThread,\n isMarkingAllRead,\n handleMarkAllRead,\n };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { type CSSProperties, type RefObject, useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport { useChatStore } from '@/stores/chatStore';\nimport {\n FILTER_PANEL_GAP_PX,\n FILTER_PANEL_WIDTH_PX,\n SIDEBAR_CONTENT_REVEAL_MS,\n type ThreadFilterOption,\n} from './thread-sidebar-constants';\nimport { shouldCollapseSidebar } from './thread-sidebar-utils';\n\nfunction useResponsiveSidebarCollapse(hasPptPreview: boolean) {\n const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);\n const [isExpandedContentVisible, setIsExpandedContentVisible] = useState(true);\n const breakpointCollapsedRef = useRef<boolean | null>(null);\n const hasManualSidebarToggleRef = useRef(false);\n const revealContentTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearRevealContentTimer = useCallback(() => {\n if (revealContentTimerRef.current) {\n clearTimeout(revealContentTimerRef.current);\n revealContentTimerRef.current = null;\n }\n }, []);\n\n const applySidebarCollapsed = useCallback(\n (nextCollapsed: boolean, revealExpandedContentImmediately: boolean) => {\n clearRevealContentTimer();\n setIsSidebarCollapsed(nextCollapsed);\n\n if (nextCollapsed) {\n setIsExpandedContentVisible(false);\n return;\n }\n\n if (revealExpandedContentImmediately) {\n setIsExpandedContentVisible(true);\n return;\n }\n\n setIsExpandedContentVisible(false);\n revealContentTimerRef.current = setTimeout(() => {\n setIsExpandedContentVisible(true);\n revealContentTimerRef.current = null;\n }, SIDEBAR_CONTENT_REVEAL_MS);\n },\n [clearRevealContentTimer],\n );\n\n useLayoutEffect(() => {\n const syncToBreakpoint = () => {\n const nextBreakpointCollapsed = shouldCollapseSidebar(hasPptPreview);\n if (breakpointCollapsedRef.current === nextBreakpointCollapsed) return;\n const isInitialSync = breakpointCollapsedRef.current === null;\n breakpointCollapsedRef.current = nextBreakpointCollapsed;\n if (hasManualSidebarToggleRef.current) return;\n applySidebarCollapsed(nextBreakpointCollapsed, isInitialSync);\n };\n\n syncToBreakpoint();\n window.addEventListener('resize', syncToBreakpoint);\n return () => {\n window.removeEventListener('resize', syncToBreakpoint);\n clearRevealContentTimer();\n };\n }, [applySidebarCollapsed, clearRevealContentTimer, hasPptPreview]);\n\n const toggleSidebarCollapsed = useCallback(() => {\n hasManualSidebarToggleRef.current = true;\n applySidebarCollapsed(!isSidebarCollapsed, false);\n }, [applySidebarCollapsed, isSidebarCollapsed]);\n\n return { isSidebarCollapsed, isExpandedContentVisible, toggleSidebarCollapsed };\n}\n\nexport interface UseThreadSidebarLayoutResult {\n searchQuery: string;\n isSearchOpen: boolean;\n showFilter: boolean;\n filterOption: ThreadFilterOption;\n filterPanelStyle: CSSProperties | null;\n filterPanelRef: RefObject<HTMLDivElement>;\n filterToggleRef: RefObject<HTMLButtonElement>;\n isSidebarCollapsed: boolean;\n isExpandedContentVisible: boolean;\n isSidebarCollapsedLayout: boolean;\n sidebarContentRevealClassName: string;\n toggleSidebarCollapsed: () => void;\n handleSearchChange: (value: string) => void;\n handleSearchClear: () => void;\n toggleSearch: () => void;\n toggleFilter: () => void;\n selectFilter: (value: ThreadFilterOption) => void;\n resetSearchAndFilter: () => void;\n}\n\nexport function useThreadSidebarLayout(): UseThreadSidebarLayoutResult {\n const [searchQuery, setSearchQuery] = useState('');\n const [isSearchOpen, setIsSearchOpen] = useState(false);\n const [showFilter, setShowFilter] = useState(false);\n const [filterOption, setFilterOption] = useState<ThreadFilterOption>('all');\n const [filterPanelStyle, setFilterPanelStyle] = useState<CSSProperties | null>(null);\n const filterPanelRef = useRef<HTMLDivElement>(null);\n const filterToggleRef = useRef<HTMLButtonElement>(null);\n const rightPanelMode = useChatStore((state) => state.rightPanelMode);\n const hasWidePreviewLayout =\n rightPanelMode === 'pptStudio' || rightPanelMode === 'fileBrowser' || rightPanelMode === 'documentPreview' || rightPanelMode === 'outlinePreview';\n const { isSidebarCollapsed, isExpandedContentVisible, toggleSidebarCollapsed } =\n useResponsiveSidebarCollapse(hasWidePreviewLayout);\n const isSidebarCollapsedLayout = isSidebarCollapsed;\n const sidebarContentRevealClassName = isExpandedContentVisible\n ? 'opacity-100 translate-x-0'\n : 'opacity-0 -translate-x-1 pointer-events-none';\n\n useLayoutEffect(() => {\n if (!showFilter) {\n setFilterPanelStyle(null);\n return;\n }\n\n const updateFilterPanelPosition = () => {\n const rect = filterToggleRef.current?.getBoundingClientRect();\n if (!rect) return;\n\n const maxRight = Math.max(FILTER_PANEL_GAP_PX, window.innerWidth - FILTER_PANEL_WIDTH_PX - FILTER_PANEL_GAP_PX);\n setFilterPanelStyle({\n top: Math.max(FILTER_PANEL_GAP_PX, rect.bottom + FILTER_PANEL_GAP_PX),\n right: Math.min(Math.max(FILTER_PANEL_GAP_PX, window.innerWidth - rect.right), maxRight),\n });\n };\n\n updateFilterPanelPosition();\n window.addEventListener('resize', updateFilterPanelPosition);\n window.addEventListener('scroll', updateFilterPanelPosition, true);\n return () => {\n window.removeEventListener('resize', updateFilterPanelPosition);\n window.removeEventListener('scroll', updateFilterPanelPosition, true);\n };\n }, [showFilter]);\n\n useLayoutEffect(() => {\n if (!showFilter) return;\n const onPointerDown = (event: MouseEvent) => {\n const target = event.target as Node | null;\n if (!target) return;\n if (filterPanelRef.current?.contains(target)) return;\n if (filterToggleRef.current?.contains(target)) return;\n setShowFilter(false);\n };\n document.addEventListener('mousedown', onPointerDown);\n return () => document.removeEventListener('mousedown', onPointerDown);\n }, [showFilter]);\n\n const handleSearchChange = useCallback((value: string) => {\n setSearchQuery(value);\n setFilterOption('all');\n }, []);\n\n const handleSearchClear = useCallback(() => {\n setSearchQuery('');\n setShowFilter(false);\n }, []);\n\n const toggleSearch = useCallback(() => {\n setIsSearchOpen((prev) => !prev);\n setShowFilter(false);\n setFilterOption('all');\n }, []);\n\n const toggleFilter = useCallback(() => {\n setShowFilter((prev) => !prev);\n setIsSearchOpen(false);\n setSearchQuery('');\n }, []);\n\n const selectFilter = useCallback((value: ThreadFilterOption) => {\n setFilterOption(value);\n setShowFilter(false);\n }, []);\n\n const resetSearchAndFilter = useCallback(() => {\n setSearchQuery('');\n setIsSearchOpen(false);\n setShowFilter(false);\n setFilterOption('all');\n }, []);\n\n return {\n searchQuery,\n isSearchOpen,\n showFilter,\n filterOption,\n filterPanelStyle,\n filterPanelRef,\n filterToggleRef,\n isSidebarCollapsed,\n isExpandedContentVisible,\n isSidebarCollapsedLayout,\n sidebarContentRevealClassName,\n toggleSidebarCollapsed,\n handleSearchChange,\n handleSearchClear,\n toggleSearch,\n toggleFilter,\n selectFilter,\n resetSearchAndFilter,\n };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport type { ThreadSidebarControllerResult, ThreadSidebarProps } from './thread-sidebar-types';\nimport { useThreadSidebarActions } from './useThreadSidebarActions';\nimport { useThreadSidebarData } from './useThreadSidebarData';\nimport { useThreadSidebarLayout } from './useThreadSidebarLayout';\n\nexport function useThreadSidebarController({\n onClose,\n className,\n onThreadSelect,\n}: ThreadSidebarProps): ThreadSidebarControllerResult {\n const layout = useThreadSidebarLayout();\n const data = useThreadSidebarData({\n searchQuery: layout.searchQuery,\n filterOption: layout.filterOption,\n });\n const actions = useThreadSidebarActions({\n pathname: data.pathname,\n currentThreadId: data.currentThreadId,\n threads: data.threads,\n showTrash: data.showTrash,\n trashedThreads: data.trashedThreads,\n loadThreads: data.loadThreads,\n loadTrash: data.loadTrash,\n resetSearchAndFilter: layout.resetSearchAndFilter,\n onClose,\n onThreadSelect,\n getThreadState: data.getThreadState,\n scrollRegionRef: data.scrollRegionRef,\n });\n\n return {\n className,\n ...layout,\n ...data,\n ...actions,\n };\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { ThreadSidebarView } from './ThreadSidebarView';\nimport { useThreadSidebarController } from './useThreadSidebarController';\n\ninterface ThreadSidebarProps {\n onClose?: () => void;\n className?: string;\n onThreadSelect?: () => void;\n}\n\nexport function ThreadSidebar(props: ThreadSidebarProps) {\n const controller = useThreadSidebarController(props);\n return <ThreadSidebarView {...controller} />;\n}\n"],"names":["SESSION_USAGE_TIMEZONE","sessionUsageDayFormatter","toDateBucketAtTimezone","timestamp","timezone","parts","year","_a","part","month","_b","day","_c","AgentSelector","selectedAgentIds","onSelectionChange","getAgentsByBreed","useAgentData","groups","toggleAgent","agentId","id","providerLabel","provider","jsxs","jsx","breedId","breedAgents","breedName","agent","isSelected","hexToRgba","formatAgentName","MY_COMPUTER_LABEL","CURRENT_PROJECT_LABEL","FALLBACK_INFO_LABEL","CANCEL_LABEL","CONFIRM_LABEL","COMPUTER_VIEW_PATH","isWindowsPath","path","isWindowsBrowseResult","result","pathToSegments","absPath","homePath","sep","driveRoot","segments","accumulated","i","relative","startIdx","DirectoryBrowser","initialPath","activeProjectPath","onSelect","onCancel","browseResult","setBrowseResult","useState","isLoading","setIsLoading","error","setError","info","setInfo","pathInput","setPathInput","showComputerView","setShowComputerView","fetchDirectory","useCallback","fallbackOnForbidden","url","res","apiFetch","data","useEffect","handlePathSubmit","trimmed","isWindowsBrowse","pathSegments","breadcrumbSegments","listedEntries","seg","HomeIcon","entry","isActive","FolderIcon","TerminalIcon","event","Button","className","PROJECT_PIN_KEY","LEGACY_PROJECT_PIN_KEY","readPinnedProjects","storage","raw","parsed","k","writePinnedProjects","projects","DirectoryPickerModal","existingProjects","setSelectedAgentIds","sessionInputs","setSessionInputs","bindExpanded","setBindExpanded","cwdPath","setCwdPath","defaultWorkspacePath","setDefaultWorkspacePath","showBrowser","setShowBrowser","pathError","setPathError","getAgentById","modalRef","useRef","selectedPath","setSelectedPath","handleSelectPath","threadTitle","setThreadTitle","pinOnCreate","setPinOnCreate","backlogItems","setBacklogItems","selectedBacklogItemId","setSelectedBacklogItemId","active","item","selectWithOptions","projectPath","bindings","sid","confirmCreate","handleBrowserSelect","handler","e","agentsExpanded","setAgentsExpanded","recommendedPath","selectionSummary","projectDisplayName","v","label","prev","FolderOpenIcon","GOV_STATUS_DOT","SectionGroup","icon","count","isCollapsed","onToggle","hideToggle","hideCount","governanceStatus","onToggleProjectPin","isProjectPinned","children","dot","exportThreadText","threadId","format","text","ext","mime","blob","downloadBlob","resolveMoreMenuAnchor","container","fallbackEvent","moreButton","rect","rowRect","fallbackLeft","fallbackTop","fallbackBottom","getMentionedAgentIdsFromMessages","messages","resolveById","mentionAliasToAgentId","getMentionToAgentId","mentionRe","getMentionRe","ids","seen","messageIndex","message","matches","match","alias","candidateId","getRecentAssistantAgentIdsFromMessages","normalizeTitleMentions","title","agents","mentionLabel","getMentionLabel","knownAliases","display","pattern","tokenRe","fullMatch","resolveThreadFallbackAvatar","officeAgent","avatar","API_URL","isImageAvatar","getAvatarInitial","name","ThreadItem","participants","lastActiveAt","onDelete","onRename","onTogglePin","isPinned","threadState","indented","preferredAgentIds","invitedExpertIds","isHubThread","sourceLabel","iconOnly","hasPendingApproval","useAuthorizationPendingStore","state","getExpertById","useExpertCatalog","resolveParticipantById","unreadCount","showUnreadBadge","unreadLabel","isThreadRunning","canDelete","canRename","canPin","isSaving","setIsSaving","showRenameDialog","setShowRenameDialog","draftTitle","setDraftTitle","contextMenu","setContextMenu","menuRef","closeMenu","onPointerDown","target","viewportPadding","anchorGap","maxX","nextX","topBoundY","bottomBoundY","preferredBelowY","preferredAboveY","targetRawY","nextY","submitRename","next","displayTitle","recentAssistantAgentIds","recentAssistantNames","participantNames","description","fallbackAvatar","mentionedAgentIds","subtitle","fallbackAvatarAgentIds","avatarAgentIds","contextMenuItemClass","isContextMenuOpen","openContextMenu","anchorLeft","anchorTop","anchorBottom","renderAgentAvatar","size","rowAgent","expert","color","_d","displayName","avatarSrc","avatarNode","Fragment","compactAvatarNode","OverflowTooltip","anchor","formatRelativeTime","MaskIcon","createPortal","AppModal","PREVENT_SLEEP_ENABLE_MESSAGE","PREVENT_SLEEP_DISABLE_MESSAGE","PREVENT_SLEEP_SYNC_STATE_MESSAGE","PREVENT_SLEEP_STATE_MESSAGE","getWebViewBridge","isPreventSleepStateMessage","value","usePreventSleep","enabled","setEnabled","isDesktopHost","webview","handleMessage","payload","enable","disable","toggle","ModalCloseIcon","FeedbackHelpCircleIcon","MAX_DESC","MAX_FILES","MAX_TOTAL_BYTES","ACCEPT_MIME","OFFICE_CLAW_FAQ_DOC_URL","extensionLooksLikeAllowedImage","isAllowedImage","file","rawType","dataTransferMightContainFiles","dt","types","len","t","formatTotalMB","bytes","FeedbackScreenshotZoneHints","FeedbackFieldTip","FeedbackModal","open","onClose","headingId","useId","fieldIds","fileInputRef","focusAreaRef","dragDepthRef","feedbackType","setFeedbackType","setDescription","contactInfo","setContactInfo","attachPluginInfo","setAttachPluginInfo","attachAppLogs","setAttachAppLogs","files","setFiles","dropHighlight","setDropHighlight","useEscapeKey","totalBytes","sum","tryAddFiles","incoming","allowed","s","nextBytes","handleFileInputChange","picked","removeFile","f","handleDragEnter","handleDragLeave","handleDragOver","handleDrop","dropped","handlePaste","items","pasted","descLen","descValue","ev","DEFAULT_USAGE_STATS_TIMEOUT_MS","fetchUsageStatsResponse","signal","RANGE_TO_DAY_COUNT","readApiError","response","normalizeThreads","normalizeSessions","addUsageSnapshots","base","delta","merged","buildRangeDayKeys","now","range","dayCount","offset","toLocalDateTime","getThreadTitle","thread","buildSyntheticUsageByDay","session","legacyUsage","legacyUsageAt","getSessionUsageByDay","getDayBucketTimestamp","date","sumUsageKey","snapshot","key","resolveSessionRangeContribution","dayKeys","usageByDay","mergedUsage","matched","latestMatchedDay","hasRealUsageByDay","latestUsageTimestampInRange","buildUsageStatsPageFromDataset","dataset","query","filteredItems","sessions","inputTotal","outputTotal","hasInput","hasOutput","contribution","inputTokensUsed","outputTokensUsed","totalTokensUsed","left","right","startIndex","fetchUsageStatsDataset","options","threadsResponse","threads","sessionEntries","sessionsResponse","PAGE_SIZE","MIN_LOADING_MS","RANGE_OPTIONS","EMPTY_RESULT","TABLE_STATE_ROW_HEIGHT_CLASS","formatPaginationPages","currentPage","totalPages","_","index","pages","sortedPages","page","a","b","previous","renderTokenValue","formatTokenCount","UsageStatsModal","fetchDataset","rangeMenuRef","setRange","setPage","refreshKey","setRefreshKey","isRangeMenuOpen","setIsRangeMenuOpen","setDataset","cancelled","controller","loadingDelayId","waitForMinimumLoadingTime","elapsed","resolve","cleanupDelay","handleAbort","startedAt","handlePointerDown","showPagination","paginationItems","handleRefresh","current","handleChangeRange","nextRange","option","RefreshButton","EmptyDataState","CenteredLoadingState","CLOSE_ACTION_SYNC_MESSAGE","CLOSE_ACTION_SET_MESSAGE","CLOSE_ACTION_STATE_MESSAGE","isCloseAction","isCloseActionStateMessage","useDesktopCloseActionSetting","closeAction","setCloseActionState","useMemo","setCloseAction","CLOSE_ACTION_OPTIONS","DesktopCloseActionSetting","USER_THEME_OPTIONS","UserThemePicker","theme","onSelectTheme","optionsTestId","GeneralSettingsTab","keepAwakeEnabled","isKeepAwakeLoading","isKeepAwakeSaving","onToggleKeepAwake","ToggleSwitch","initialProgress","useDownloadStore","create","set","taskId","progress","loading","newVersionTitleStyle","normalizeVersion","version","compareVersions","aParts","bParts","maxLen","aVal","bVal","VersionUpdatePanel","onDismiss","versionInfo","variant","downloadState","pollIntervalRef","resetRef","taskIdRef","setTaskIdRef","updateProgressRef","currentVersion","hasNewVersion","iconAlignmentClassName","contentAlignmentClassName","tid","pollDownloadProgress","handleDownload","handleDismiss","openDownloadFile","renderButtonArea","iconMb","lobsterClass","titleBlock","descriptionBlock","buttons","IconButton","SearchEngineCard","engine","hasValue","onClick","API_URLS","SearchEngineEditView","configured","onSave","saving","inputValue","setInputValue","showTip","setShowTip","handleSave","Alert","PasswordField","PAID_SEARCH_ENGINES","DEFAULT_CONFIG","DEFAULT_CONFIGURED","ENV_VAR_TO_KEY","ENV_VAR_TO_ENGINE_ID","isMaskedSecretValue","readErrorMessage","fallback","useSearchEngineConfig","config","setConfig","setConfigured","setLoading","setSaving","editingEngineId","setEditingEngineId","addToast","useToastStore","loadConfig","variables","nextConfig","nextConfigured","configKey","engineId","err","msg","saveConfig","envVar","isDelete","startEdit","cancelEdit","getEngineValue","isEngineConfigured","SearchEngineConfig","editingEngine","AGENT_ARTS_SERVICE_DECLARATION_URL","SETTINGS_TABS","SettingItem","switchNode","UserSettingsModal","onOpenPrivacyDeclaration","onAboutTabEnter","activeTab","setActiveTab","memoryEnabled","setMemoryEnabled","isMemorySaving","setIsMemorySaving","improveDataEnabled","setImproveDataEnabled","aboutVersionFetchedRef","activeTabLabel","tab","handleMemoryToggle","checked","HELP_URL","PRIVACY_DECLARATION_URL","DEFAULT_LOGOUT_URL","readPublicEnv","readLogoutResponse","UserProfile","collapsed","showPanel","setShowPanel","showUserSettings","setShowUserSettings","showAboutPanel","setShowAboutPanel","showUsageStats","setShowUsageStats","showFeedbackModal","setShowFeedbackModal","showSecurityManagement","setShowSecurityManagement","isSkipAuth","setIsSkipAuth","aboutPopoverTop","setAboutPopoverTop","aboutPopoverLeft","setAboutPopoverLeft","collapsedPanelPosition","setCollapsedPanelPosition","setVersionInfo","panelRef","profilePanelRef","panelScrollRef","aboutAnchorRef","aboutPopoverRef","userId","getUserId","storedUserName","getUserName","setTheme","useTheme","handleKeepAwakeToggle","checkVersion","handleAboutTabEnter","userName","avatarLetter","profileActionClass","profileSubActionClass","calculatePopoverPosition","anchorElement","profilePanelRect","updateAboutPopoverPosition","position","updateCollapsedPanelPosition","handleTogglePanel","handleOpenUsageStats","handleOpenUserSettings","handleCloseUserSettings","handleCloseUsageStats","handleOpenFeedbackModal","handleCloseFeedbackModal","handleOpenSecurityManagement","handleCloseSecurityManagement","handleSelectTheme","nextTheme","handleOpenHelp","openAboutPanel","handleToggleAboutPanel","handleOpenPrivacyDeclaration","finishLogout","logoutUrl","clearAuthIdentity","handleLogout","redirected","handleClickOutside","handlePositionChange","scrollElement","getIsSkipAuth","collapsedPanelStyle","profileButton","SecurityManagementModal","WechatGroupInvite","showPopover","setShowPopover","triggerRef","popoverRef","containerRef","ThreadSidebarFooter","isSidebarCollapsedLayout","sidebarContentRevealClassName","ThreadSidebarDeleteDialog","deleteTarget","deleteTargetSharedCount","deleteTargetIsShared","deleteWorkspace","setDeleteWorkspace","onConfirm","MAX_SIDEBAR_RESTORE_FRAMES","SIDEBAR_SCROLL_STORAGE_KEY","LEGACY_SIDEBAR_SCROLL_STORAGE_KEY","MAX_SESSIONS","COLLAPSE_BREAKPOINT_PX","PPT_PREVIEW_COLLAPSE_BREAKPOINT_PX","SIDEBAR_CONTENT_REVEAL_MS","FILTER_PANEL_WIDTH_PX","FILTER_PANEL_GAP_PX","FILTER_OPTION_LABELS","CONNECTOR_SOURCE_LABELS","THREAD_FILTER_OPTIONS","readSidebarScrollTop","writeSidebarScrollTop","nextTop","safeTop","shouldCollapseSidebar","hasPptPreview","breakpoint","getSidebarShellClassName","token","getThreadSourceLabel","connectorId","getThreadLastActiveAtMs","normalizeThreadSearchQuery","closeSidebarOnMobile","countNonDefaultThreads","SidebarToggleIcon","direction","iconSrc","MenuButton","testId","revealClassName","hidden","button","ThreadSidebarView","startDrag","useDesktopWindowControls","sidebarBrandDragStateRef","pathname","isLoadingThreads","getThreadState","scrollRegionRef","normalizedQuery","displayThreadGroups","collapsedThreadItems","showNoResults","activeThreadIdFromRoute","govHealth","pinnedProjects","toggleGroup","toggleProjectPin","handleNewChat","handleMenuNavigate","handleRename","handleDeleteRequest","handleTogglePin","handleToggleFavorite","handleUpdatePreferredAgents","handleSelect","showPicker","createInProject","bindWarning","filterPanelStyle","filterPanelRef","filterToggleRef","isSidebarCollapsed","toggleSidebarCollapsed","searchQuery","isSearchOpen","showFilter","filterOption","handleSearchChange","handleSearchClear","toggleSearch","toggleFilter","selectFilter","closePicker","closeDeleteDialog","handleDeleteConfirm","handleSidebarBrandMouseDown","handleMouseMove","deltaX","deltaY","handleMouseUp","menuItems","renderThreadItem","renderGroup","group","groupKey","groupIcon","subgroup","subgroupKey","SearchInput","createToggleWithReconcile","opts","seqMap","reconcile","expectedSeq","expectedSiblingSeq","val","sibVal","seq","siblingSeq","updated","useThreadSidebarActions","currentThreadId","showTrash","trashedThreads","loadThreads","loadTrash","resetSearchAndFilter","onThreadSelect","navigate","useNavigate","setCurrentThread","setCurrentProject","updateThreadTitle","useChatStore","isCreating","setIsCreating","setShowPicker","setBindWarning","setDeleteTarget","bindWarningTimerRef","pinSeqMap","favSeqMap","pinToggle","favToggle","relatedThreads","clearBindWarningLater","navigateToThread","results","cliSessionId","failed","sharedCountAtDelete","shouldDeleteWorkspace","workspaceDeleteSucceeded","workspaceDeleteReason","workspaceWasShared","workspaceSharedCount","memoryPreserved","workspaceSharedSkip","nextTitle","pinned","favorited","agentIds","scrollRegion","isAlreadyOnThreadRoute","STORAGE_KEY","LEGACY_STORAGE_KEY","readCollapsedGroups","writeCollapsedGroups","groupKeys","initCollapsedSet","allGroupKeys","stored","shouldCollapse","collapsedSet","shouldCollapseBeforeInit","_groupKey","resolveCollapse","isInitialized","expandAllGroups","collapseAllGroups","allKnownKeys","findGroupKeyForThread","recentFallback","g","getGroupKey","getStorage","useCollapseState","threadGroups","initialized","lastAutoExpandedThreadId","setCollapsed","allKeys","groupsMeta","expandAll","collapseAll","useProjectPins","setPinnedProjects","useThreadSidebarData","useLocation","setThreads","setLoadingThreads","setShowTrash","setTrashedThreads","isLoadingTrash","setIsLoadingTrash","setGovHealth","isMarkingAllRead","setIsMarkingAllRead","restoreFrameRef","nextThreads","normalizeStoredThreadTitleOrNull","initThreadUnread","refresh","socket","io","store","cancelPendingScrollRestore","element","handleScroll","scheduleScrollRestore","targetTop","framesRemaining","apply","maxTop","clampedTop","canSettle","reachedTarget","useLayoutEffect","nextHealth","project","toggleTrashVisibility","restoreThread","filteredThreads","threshold","sortedAll","sortedPinned","sortedUnpinned","hasVisibleThreads","showDefaultThread","getProjectPaths","handleMarkAllRead","useResponsiveSidebarCollapse","setIsSidebarCollapsed","isExpandedContentVisible","setIsExpandedContentVisible","breakpointCollapsedRef","hasManualSidebarToggleRef","revealContentTimerRef","clearRevealContentTimer","applySidebarCollapsed","nextCollapsed","revealExpandedContentImmediately","syncToBreakpoint","nextBreakpointCollapsed","isInitialSync","useThreadSidebarLayout","setSearchQuery","setIsSearchOpen","setShowFilter","setFilterOption","setFilterPanelStyle","rightPanelMode","hasWidePreviewLayout","updateFilterPanelPosition","maxRight","useThreadSidebarController","layout","actions","ThreadSidebar","props"],"mappings":"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"}
|