@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,8 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/jszip.min-DPdj3o0t.js","assets/index-Cb4fQgom.js","assets/index-Bed0I5IL.css","assets/_commonjs-dynamic-modules-TDtrdbi3.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{u as ye,r as o,_ as Se,j as t,I as Ne,B as F,M as me}from"./index-Cb4fQgom.js";import{a as je,O as le}from"./OverflowTooltip-CE5PjAb-.js";import{n as Ee}from"./skill-options-cache-D1BJGTCU.js";import{A as Le}from"./Alert-D88Fk6to.js";const M={maxFiles:100,maxFileBytes:1024*1024,maxTotalBytes:4*1024*1024},we=/^[A-Za-z0-9-]+$/,J=100,Ie="ZIP 文件只能单个上传",Re="上传内容根目录必须包含名为 SKILL.md 的文件",_e="ZIP 压缩包根目录必须包含名为 SKILL.md 的文件",Ce="技能文件不合法:SKILL.md 头部缺少 name 字段",oe=3,ce="max-w-[280px]",Oe="rgb(242,48,48)",Fe="rgb(252,227,225)",Me="/icons/file-html.svg",Pe={zip:"/icons/file-zip.svg",csv:"/icons/files-csv.svg",doc:"/icons/file-docx.svg",docx:"/icons/file-docx.svg",htm:"/icons/file-html.svg",html:"/icons/file-html.svg",ini:"/icons/file-ini.svg",json:"/icons/file-json.svg",md:"/icons/file-md.svg",pdf:"/icons/files-pdf.svg",ppt:"/icons/files-ppt.svg",pptx:"/icons/files-ppt.svg",py:"/icons/file-py.svg",sh:"/icons/file-sh.svg",txt:"/icons/file-txt.svg",xls:"/icons/files-xlsx.svg",xlsx:"/icons/files-xlsx.svg",xlsm:"/icons/files-xlsx.svg",xlsb:"/icons/files-xlsx.svg"};function Ae(s){return/\.zip$/i.test(s.name)}function De(s){var l;const n=s.trim().toLowerCase(),a=n.split("/").pop()??n;if(a===".gitignore")return"/icons/file-gitignore.svg";const i=((l=a.split(".").pop())==null?void 0:l.toLowerCase())??"";return Pe[i]??Me}function Q(s){return s.replace(/\\/g,"/").replace(/^\.?\//,"").replace(/\/+/g,"/").replace(/\/$/,"")}function fe(s){return s.startsWith("__MACOSX/")}function Te(){return t.jsx(me,{name:"close",className:"h-4 w-4"})}function ze(){return t.jsx(me,{name:"edit",className:"h-4 w-4"})}function Be(){return t.jsx("span",{"aria-hidden":"true",className:"block h-4 w-4 bg-current","data-testid":"upload-skill-file-delete-icon",style:{maskImage:"url('/icons/common-delete.svg')",maskRepeat:"no-repeat",maskPosition:"center",maskSize:"contain",WebkitMaskImage:"url('/icons/common-delete.svg')",WebkitMaskRepeat:"no-repeat",WebkitMaskPosition:"center",WebkitMaskSize:"contain"}})}function We(s){return`${(s/(1024*1024)).toFixed(0)} MB`}function Ke(s){return new Promise((n,a)=>{const i=new FileReader;i.onload=()=>{const l=i.result,h=l.includes(",")?l.split(",")[1]:l;n(h)},i.onerror=a,i.readAsDataURL(s)})}function Ue(s){return new Promise((n,a)=>{const i=new FileReader;i.onload=()=>n(i.result),i.onerror=a,i.readAsArrayBuffer(s)})}function $e(s){let a="";for(let i=0;i<s.length;i+=32768)a+=String.fromCharCode(...s.subarray(i,i+32768));return btoa(a)}function Ve(s){const n=atob(s),a=Uint8Array.from(n,i=>i.charCodeAt(0));return new TextDecoder().decode(a)}function Ze(s){const n=s.trim();return n.startsWith('"')&&n.endsWith('"')||n.startsWith("'")&&n.endsWith("'")?n.slice(1,-1).trim():n}function de(s,n){var l,h;const a=s.split(`
|
|
3
|
+
`),i=new RegExp(`^${n}:\\s*(.*)$`);for(let p=0;p<a.length;p+=1){const c=(l=a[p])==null?void 0:l.match(i);if(!c)continue;const b=((h=c[1])==null?void 0:h.trim())??"";if(!b)return"";if(b.startsWith(">")||b.startsWith("|")){const _=[];for(let N=p+1;N<a.length;N+=1){const g=a[N]??"";if(g.trim()&&!g.startsWith(" ")&&!g.startsWith(" "))break;_.push(g.trim())}const x=_.filter(Boolean);return b.startsWith("|")?x.join(`
|
|
4
|
+
`).trim():x.join(" ").trim()}return Ze(b)}return""}function Xe(s){const n=s.replace(/\r\n?/g,`
|
|
5
|
+
`);let a="";if(n.startsWith(`---
|
|
6
|
+
`)){const i=n.indexOf(`
|
|
7
|
+
---`,4);i!==-1&&(a=n.slice(4,i))}return{name:a?de(a,"name"):"",description:a?de(a,"description"):""}}function pe(s,n){if(!n)return{name:"",description:""};const a=s.find(i=>Q(i.path)===n);if(!a)return{name:"",description:""};try{return Xe(Ve(a.content))}catch{return{name:"",description:""}}}function H(s){const n=s.map(Q).filter(c=>c.length>0&&!fe(c));if(n.includes("SKILL.md"))return"SKILL.md";const a=n.filter(c=>c.endsWith("/SKILL.md")&&c.split("/").length===2);if(a.length!==1)return null;const i=a[0]??null;if(!i)return null;const l=i.split("/")[0];return n.some(c=>!c.includes("/"))||n.some(c=>c.split("/")[0]!==l)?null:i}function Ge(s){return pe(s,H(s.map(n=>n.path)))}function ue(s){return s.name.trim()?null:Ce}function R(s){if(s.length===0)return{kind:"empty",message:"请选择文件"};const n=s.find(i=>i.size>M.maxFileBytes);return n?{kind:"fileTooLarge",message:`文件 ${n.path} 单个文件大小不能超过1MB`}:s.length>M.maxFiles?{kind:"tooManyFiles",message:`文件数量不能超过 ${M.maxFiles} 个`}:s.reduce((i,l)=>i+l.size,0)>M.maxTotalBytes?{kind:"totalTooLarge",message:`文件总大小不能超过 ${We(M.maxTotalBytes)}`}:H(s.map(i=>i.path))?null:{kind:"missingSkill",message:Re}}function Je(s){const n=R(s);return(n==null?void 0:n.kind)==="missingSkill"?n.message:null}function G(s){const n=s.trim();return n?n.length>J?`技能名称不能超过 ${J} 个字符`:we.test(n)?null:"技能名称仅支持英文、数字和中划线":"请输入技能名称"}function et({open:s,onClose:n,onSuccess:a}){const i=ye(e=>e.addToast),[l,h]=o.useState(""),[p,c]=o.useState(""),[b,_]=o.useState(""),[x,N]=o.useState([]),[g,Y]=o.useState([]),[W,q]=o.useState(!1),[K,j]=o.useState(null),[P,C]=o.useState(!1),[ee,A]=o.useState(!1),D=o.useRef(null),T=o.useRef(null),U=o.useRef(null),xe=p.trim().length>0,E=R(x),L=!E&&x.length>0?ue({name:p}):null,te=K??(E&&E.kind!=="empty"?E.message:null)??L,$=G(l),z=P?$:null,V=W?"正在导入技能,请稍候":x.length===0?"请选择文件或文件夹后再导入":K||(E?E.message:L||$||null),se=V!=null,he=(ee?g:g.slice(0,oe)).map((e,r)=>({fileName:e,index:r})),ge=g.length>oe,B=o.useCallback(()=>{D.current&&(D.current.value=""),T.current&&(T.current.value="")},[]),ne=o.useCallback(()=>{h(""),c(""),_(""),N([]),Y([]),j(null),C(!1),A(!1),B()},[B]),w=o.useCallback(()=>{ne(),n()},[ne,n]);o.useEffect(()=>{if(!s)return;const e=r=>{r.key==="Escape"&&(r.preventDefault(),w())};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[s,w]),o.useEffect(()=>{var e,r;P&&((e=U.current)==null||e.focus(),(r=U.current)==null||r.select())},[P]);const d=o.useCallback((e,r,u)=>{i({type:e,title:r,message:u,duration:4e3})},[i]),O=o.useCallback((e,r={})=>{const u=r.parsedSkill??Ge(e),m=R(e),y=m?null:ue(u);N(e),Y(e.map(f=>f.path)),c(u.name),_(u.description),h(f=>{const I=f.trim();return!I||I===p?u.name:f}),C(!1),j(r.inlineError??Je(e)),m&&m.kind!=="empty"&&m.kind!=="missingSkill"&&d("error","上传失败",m.message),y&&d("error","上传失败",y)},[p,d]),ie=o.useCallback(async e=>{const r=Array.from(e);B();const u=r.filter(Ae);if(u.length>0&&r.length!==1){j(null),d("error","上传失败",Ie);return}if(u.length===1){try{const{default:f}=await Se(async()=>{const{default:k}=await import("./jszip.min-DPdj3o0t.js").then(S=>S.j);return{default:k}},__vite__mapDeps([0,1,2,3])),I=await f.loadAsync(await Ue(u[0])),v=[];for(const k of Object.values(I.files)){if(k.dir)continue;const S=Q(k.name);if(!S||fe(S))continue;const re=await k.async("uint8array");v.push({path:S,content:$e(re),size:re.byteLength})}v.sort((k,S)=>k.path.localeCompare(S.path)),A(!1);const be=H(v.map(k=>k.path)),X=R(v);if(X){d("error","上传失败",X.kind==="missingSkill"?_e:X.message);return}O(v,{inlineError:null,parsedSkill:pe(v,be)})}catch{j(null),d("error","上传失败","ZIP 文件解析失败")}return}const m=[];for(const f of r){const I=("webkitRelativePath"in f?f.webkitRelativePath:"")||f.name,v=await Ke(f);m.push({path:I,content:v,size:f.size})}A(!1);const y=R(m);if(y){d("error","上传失败",y.message);return}O(m)},[B,d,O]),ke=o.useCallback(e=>{const r=x.filter((u,m)=>m!==e);O(r)},[x,O]),ve=o.useCallback(e=>{h(e)},[]),Z=o.useCallback((e="blur")=>{if(e==="cancel"){h(p),C(!1);return}G(l)||C(!1)},[l,p]),ae=o.useCallback(async()=>{const e=R(x);if(e){j(e.kind==="missingSkill"?e.message:null),e.kind!=="missingSkill"&&d("error","上传失败",e.message);return}if(L){d("error","上传失败",L);return}const r=G(l);if(r){d("error","上传失败",r);return}q(!0),j(null);try{const u=await je("/api/skills/upload",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:l.trim(),files:x.map(({path:y,content:f})=>({path:y,content:f}))})}),m=await u.json().catch(()=>({}));m.success?(Ee(),w(),a()):d("error","上传失败",m.error??(u.status===413?"上传内容过大,请减少文件数量或体积":"上传失败"))}catch{d("error","上传失败","网络错误,请确认本地 API 服务已启动,或减少上传文件数量后重试")}finally{q(!1)}},[x,w,L,l,a,d]);return s?t.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-strong)] p-4","data-testid":"upload-skill-overlay",children:t.jsxs("div",{role:"dialog","aria-modal":"true",className:"flex w-[550px] max-h-[calc(100vh-32px)] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-xl border border-[var(--modal-border)] bg-[var(--modal-surface)] p-6 shadow-[var(--modal-shadow)]",children:[t.jsxs("div",{className:"mb-5 flex items-center justify-between",children:[t.jsx("h3",{className:"text-sm font-bold",children:"导入技能"}),t.jsx(Ne,{label:"close",size:"sm",onClick:w,icon:t.jsx(Te,{})})]}),t.jsxs("div",{className:"min-h-0 flex-1 overflow-y-auto pr-1",children:[t.jsxs(Le,{mode:"prompt",closable:!1,className:"mb-4",children:["1.支持上传文件或文件夹:单个文件 ≤ 1MB,文件总数 ≤ 100 个,总大小 ≤ 4MB;",t.jsx("br",{}),"2.上传内容的根目录必须包含 SKILL.md 文件。"]}),t.jsxs("div",{className:"mb-4 flex gap-2",children:[t.jsx(F,{variant:"default",onClick:()=>{var e;return(e=D.current)==null?void 0:e.click()},children:"选择文件"}),t.jsx(F,{variant:"default",onClick:()=>{var e;return(e=T.current)==null?void 0:e.click()},children:"选择文件夹"})]}),t.jsx("input",{ref:D,type:"file",multiple:!0,onChange:e=>e.target.files&&void ie(e.target.files),className:"hidden"}),t.jsx("input",{ref:T,type:"file",webkitdirectory:"",multiple:!0,onChange:e=>e.target.files&&void ie(e.target.files),className:"hidden"}),t.jsx("div",{className:"mb-4",children:g.length>0?t.jsxs("div",{className:"space-y-1 pr-1 text-xs text-[var(--modal-text-muted)]",children:[he.map(({fileName:e,index:r})=>t.jsxs("div",{className:"group flex items-center gap-2 rounded-[6px] px-2 py-1 transition-colors hover:bg-[var(--modal-muted-surface-hover)]","data-testid":"upload-skill-file-row",children:[t.jsxs("div",{className:"min-w-0 flex flex-1 items-center gap-1",children:[t.jsx("img",{src:De(e),alt:"","aria-hidden":"true",className:"h-4 w-4 shrink-0","data-testid":"upload-skill-file-icon"}),t.jsx("span",{className:"min-w-0 flex-1 truncate",children:e})]}),t.jsx("button",{type:"button",onClick:()=>ke(r),"aria-label":`remove-file-${r}`,className:"shrink-0 text-[var(--modal-text-subtle)] opacity-0 transition-[opacity,color] group-hover:opacity-100 hover:text-[var(--modal-accent-text)]","data-testid":"upload-skill-file-delete-button",children:t.jsx(Be,{})})]},`${e}-${r}`)),ge?t.jsx("button",{type:"button","data-testid":"file-list-toggle",onClick:()=>A(e=>!e),className:"pt-1 text-xs text-[var(--modal-text-muted)] transition-colors hover:text-[var(--modal-text)]",children:ee?"收起":`展开全部 (${g.length})`}):null]}):null}),x.length>0?t.jsxs("div",{children:[t.jsx("div",{className:"mb-3 text-xs font-medium text-[var(--modal-text-muted)]",children:"解析结果"}),te?t.jsx("p",{"data-testid":"parsed-skill-error",className:"text-xs text-[#f23030]",children:te}):t.jsxs("div",{className:"space-y-3",children:[t.jsxs("div",{className:"flex items-start gap-3 text-xs",children:[t.jsx("div",{className:"w-[72px] shrink-0 pt-2 text-[var(--modal-text-muted)]",children:"Skill名称"}),t.jsx("div",{className:"min-w-0 flex-1",children:P?t.jsxs("div",{className:"space-y-1",children:[t.jsx("input",{ref:U,type:"text",value:l,maxLength:J,"aria-invalid":z?"true":"false",onChange:e=>ve(e.target.value),onBlur:()=>Z("blur"),onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),Z("submit")),e.key==="Escape"&&(e.preventDefault(),Z("cancel"))},placeholder:"请输入技能名称",className:"ui-input w-full rounded px-3 py-2 text-xs",style:z?{borderColor:Oe,backgroundColor:Fe}:void 0}),z?t.jsx("p",{"data-testid":"upload-skill-name-error",className:"text-xs text-[var(--state-error-text)]",children:z}):null]}):t.jsxs("div",{className:"inline-flex min-h-8 max-w-full items-center gap-1",children:[l?t.jsx(le,{content:l,className:ce,children:t.jsx("span",{"data-testid":"parsed-skill-name-text",className:`block truncate whitespace-nowrap text-[var(--modal-text)] ${ce}`,children:l})}):t.jsx("span",{className:"text-[var(--modal-text)]",children:"--"}),xe?t.jsx("button",{type:"button","aria-label":"edit-skill-name",onClick:()=>C(!0),className:"shrink-0 text-[var(--modal-text-subtle)] transition-colors hover:text-[var(--modal-text)]",children:t.jsx(ze,{})}):null]})})]}),t.jsxs("div",{className:"flex items-start gap-3 text-xs",children:[t.jsx("div",{className:"w-[72px] shrink-0 text-[var(--modal-text-muted)]",children:"Skill描述"}),t.jsx("div",{className:"min-w-0 flex-1 leading-5 text-[var(--modal-text)]",children:t.jsx("span",{"data-testid":"parsed-skill-description-text",className:"whitespace-pre-wrap break-words",children:b||"--"})})]})]})]}):null]}),t.jsxs("div",{className:"mt-4 flex justify-end gap-2",children:[t.jsx(F,{variant:"default",onClick:w,children:"取消"}),V?t.jsx(le,{content:V,forceShow:!0,className:"inline-flex shrink-0",children:t.jsx("span",{"data-testid":"upload-skill-submit-trigger",className:"inline-flex shrink-0",children:t.jsx(F,{onClick:ae,disabled:se,children:W?"导入中...":"导入"})})}):t.jsx("span",{"data-testid":"upload-skill-submit-trigger",className:"inline-flex shrink-0",children:t.jsx(F,{onClick:ae,disabled:se,children:W?"导入中...":"导入"})})]})]})}):null}export{et as U};
|
|
8
|
+
//# sourceMappingURL=UploadSkillModal-DHZL12vm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":"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","names":["SKILL_UPLOAD_LIMITS","SKILL_NAME_ALLOWED_RE","SKILL_NAME_MAX_LENGTH","ZIP_SINGLE_UPLOAD_ERROR","ROOT_SKILL_REQUIRED_ERROR","ZIP_ROOT_SKILL_ERROR","SKILL_NAME_REQUIRED_ERROR","COLLAPSED_FILE_COUNT","PARSED_NAME_MAX_WIDTH_CLASS","SKILL_NAME_ERROR_BORDER_COLOR","SKILL_NAME_ERROR_BG_COLOR","DEFAULT_FILE_ICON_SRC","FILE_ICON_BY_EXTENSION","isZipFile","file","resolveUploadFileIcon","filePath","normalizedPath","fileName","extension","_a","normalizeUploadPath","path","isIgnoredZipEntryPath","CloseIcon","jsx","MaskIcon","EditIcon","DeleteFileIcon","formatBytes","bytes","fileToBase64","resolve","reject","reader","result","base64","fileToArrayBuffer","uint8ArrayToBase64","binary","index","decodeBase64Utf8","char","stripYamlQuotes","value","trimmed","parseFrontmatterValue","frontmatter","key","lines","keyPattern","match","rawValue","_b","blockLines","cursor","line","nonEmptyLines","parseSkillMetadata","markdown","normalized","endIndex","extractSkillMetadataFromManifest","files","manifestPath","skillMdFile","findRootSkillMarkdownPath","paths","normalizedPaths","rootSkillFiles","rootSkillPath","rootDir","extractSkillMetadata","getSkillMetadataValidationError","parsedSkill","getUploadValidationIssue","oversizedFile","sum","getInlineValidationError","issue","validateSkillName","name","trimmedName","UploadSkillModal","open","onClose","onSuccess","addToast","useToastStore","state","setName","useState","parsedName","setParsedName","description","setDescription","setFiles","fileNames","setFileNames","uploading","setUploading","error","setError","isEditingName","setIsEditingName","isFileListExpanded","setIsFileListExpanded","fileInputRef","useRef","folderInputRef","nameInputRef","canEditName","fileValidationIssue","metadataValidationError","parseResultError","nameValidationError","editingNameValidationError","uploadDisabledReason","isSubmitDisabled","visibleFileEntries","hasExpandableFileList","resetUploadPickers","useCallback","reset","handleClose","useEffect","onKeyDown","event","showToast","type","title","message","syncUploadState","nextFiles","options","nextParsedSkill","nextValidationIssue","nextMetadataValidationError","currentName","trimmedCurrentName","readFiles","fileList","selectedFiles","zipFiles","JSZip","__vitePreload","n","zip","zipEntries","entry","left","right","rootSkillMarkdownPath","uploadIssue","newEntries","relPath","removeFile","_","currentIndex","handleNameChange","nextName","handleNameEditComplete","action","handleSubmit","res","apiFetch","content","data","notifySkillOptionsChanged","jsxs","IconButton","Alert","Button","currentValue","OverflowTooltip"],"ignoreList":[],"sources":["../../src/components/skills-panel/components/UploadSkillModal.tsx"],"sourcesContent":["/*\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 { useToastStore } from '@/stores/toastStore';\nimport { apiFetch } from '@/utils/api-client';\nimport { notifySkillOptionsChanged } from '@/utils/skill-options-cache';\nimport { Button } from '../../shared/Button';\nimport { IconButton } from '../../shared/IconButton';\nimport { MaskIcon } from '@/components/shared/MaskIcon';\nimport { Alert } from '../../shared/Alert';\nimport { OverflowTooltip } from '../../shared/OverflowTooltip';\n\ninterface UploadFile {\n path: string;\n content: string; // base64\n size: number;\n}\n\ninterface UploadSkillModalProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\ninterface ParsedSkillMetadata {\n name: string;\n description: string;\n}\n\ninterface UploadStateOptions {\n inlineError?: string | null;\n parsedSkill?: ParsedSkillMetadata;\n}\n\ntype UploadValidationIssueKind = 'empty' | 'fileTooLarge' | 'tooManyFiles' | 'totalTooLarge' | 'missingSkill';\n\ninterface UploadValidationIssue {\n kind: UploadValidationIssueKind;\n message: string;\n}\n\nexport const SKILL_UPLOAD_LIMITS = {\n maxFiles: 100,\n maxFileBytes: 1024 * 1024,\n maxTotalBytes: 4 * 1024 * 1024,\n} as const;\n\nconst SKILL_NAME_ALLOWED_RE = /^[A-Za-z0-9-]+$/;\nconst SKILL_NAME_MAX_LENGTH = 100;\nconst ZIP_SINGLE_UPLOAD_ERROR = 'ZIP 文件只能单个上传';\nconst ROOT_SKILL_REQUIRED_ERROR = '上传内容根目录必须包含名为 SKILL.md 的文件';\nconst ZIP_ROOT_SKILL_ERROR = 'ZIP 压缩包根目录必须包含名为 SKILL.md 的文件';\nconst SKILL_NAME_REQUIRED_ERROR = '技能文件不合法:SKILL.md 头部缺少 name 字段';\nconst COLLAPSED_FILE_COUNT = 3;\nconst PARSED_NAME_MAX_WIDTH_CLASS = 'max-w-[280px]';\nconst SKILL_NAME_ERROR_BORDER_COLOR = 'rgb(242,48,48)';\nconst SKILL_NAME_ERROR_BG_COLOR = 'rgb(252,227,225)';\nconst DEFAULT_FILE_ICON_SRC = '/icons/file-html.svg';\nconst FILE_ICON_BY_EXTENSION: Record<string, string> = {\n zip: '/icons/file-zip.svg',\n csv: '/icons/files-csv.svg',\n doc: '/icons/file-docx.svg',\n docx: '/icons/file-docx.svg',\n htm: '/icons/file-html.svg',\n html: '/icons/file-html.svg',\n ini: '/icons/file-ini.svg',\n json: '/icons/file-json.svg',\n md: '/icons/file-md.svg',\n pdf: '/icons/files-pdf.svg',\n ppt: '/icons/files-ppt.svg',\n pptx: '/icons/files-ppt.svg',\n py: '/icons/file-py.svg',\n sh: '/icons/file-sh.svg',\n txt: '/icons/file-txt.svg',\n xls: '/icons/files-xlsx.svg',\n xlsx: '/icons/files-xlsx.svg',\n xlsm: '/icons/files-xlsx.svg',\n xlsb: '/icons/files-xlsx.svg',\n};\n\nfunction isZipFile(file: File): boolean {\n return /\\.zip$/i.test(file.name);\n}\n\nfunction resolveUploadFileIcon(filePath: string): string {\n const normalizedPath = filePath.trim().toLowerCase();\n const fileName = normalizedPath.split('/').pop() ?? normalizedPath;\n if (fileName === '.gitignore') {\n return '/icons/file-gitignore.svg';\n }\n const extension = fileName.split('.').pop()?.toLowerCase() ?? '';\n return FILE_ICON_BY_EXTENSION[extension] ?? DEFAULT_FILE_ICON_SRC;\n}\n\nfunction normalizeUploadPath(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/^\\.?\\//, '').replace(/\\/+/g, '/').replace(/\\/$/, '');\n}\n\nfunction isIgnoredZipEntryPath(path: string): boolean {\n return path.startsWith('__MACOSX/');\n}\n\nfunction CloseIcon() {\n return <MaskIcon name=\"close\" className=\"h-4 w-4\" />;\n}\n\nfunction EditIcon() {\n return <MaskIcon name=\"edit\" className=\"h-4 w-4\" />;\n}\n\nfunction DeleteFileIcon() {\n return (\n <span\n aria-hidden=\"true\"\n className=\"block h-4 w-4 bg-current\"\n data-testid=\"upload-skill-file-delete-icon\"\n style={{\n maskImage: \"url('/icons/common-delete.svg')\",\n maskRepeat: 'no-repeat',\n maskPosition: 'center',\n maskSize: 'contain',\n WebkitMaskImage: \"url('/icons/common-delete.svg')\",\n WebkitMaskRepeat: 'no-repeat',\n WebkitMaskPosition: 'center',\n WebkitMaskSize: 'contain',\n }}\n />\n );\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes >= 1024 * 1024) {\n return `${(bytes / (1024 * 1024)).toFixed(bytes % (1024 * 1024) === 0 ? 0 : 1)} MB`;\n }\n if (bytes >= 1024) return `${Math.ceil(bytes / 1024)} KB`;\n return `${bytes} B`;\n}\n\nfunction fileToBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const result = reader.result as string;\n const base64 = result.includes(',') ? result.split(',')[1] : result;\n resolve(base64);\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n\nfunction fileToArrayBuffer(file: File): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = reject;\n reader.readAsArrayBuffer(file);\n });\n}\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n const chunkSize = 0x8000;\n let binary = '';\n\n for (let index = 0; index < bytes.length; index += chunkSize) {\n binary += String.fromCharCode(...bytes.subarray(index, index + chunkSize));\n }\n\n return btoa(binary);\n}\n\nfunction decodeBase64Utf8(base64: string): string {\n const binary = atob(base64);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return new TextDecoder().decode(bytes);\n}\n\nfunction stripYamlQuotes(value: string): string {\n const trimmed = value.trim();\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1).trim();\n }\n return trimmed;\n}\n\nfunction parseFrontmatterValue(frontmatter: string, key: string): string {\n const lines = frontmatter.split('\\n');\n const keyPattern = new RegExp(`^${key}:\\\\s*(.*)$`);\n\n for (let index = 0; index < lines.length; index += 1) {\n const match = lines[index]?.match(keyPattern);\n if (!match) continue;\n\n const rawValue = match[1]?.trim() ?? '';\n if (!rawValue) return '';\n if (rawValue.startsWith('>') || rawValue.startsWith('|')) {\n const blockLines: string[] = [];\n for (let cursor = index + 1; cursor < lines.length; cursor += 1) {\n const line = lines[cursor] ?? '';\n if (line.trim() && !line.startsWith(' ') && !line.startsWith('\\t')) break;\n blockLines.push(line.trim());\n }\n const nonEmptyLines = blockLines.filter(Boolean);\n return rawValue.startsWith('|') ? nonEmptyLines.join('\\n').trim() : nonEmptyLines.join(' ').trim();\n }\n\n return stripYamlQuotes(rawValue);\n }\n\n return '';\n}\n\nexport function parseSkillMetadata(markdown: string): ParsedSkillMetadata {\n const normalized = markdown.replace(/\\r\\n?/g, '\\n');\n let frontmatter = '';\n\n if (normalized.startsWith('---\\n')) {\n const endIndex = normalized.indexOf('\\n---', 4);\n if (endIndex !== -1) {\n frontmatter = normalized.slice(4, endIndex);\n }\n }\n\n return {\n name: frontmatter ? parseFrontmatterValue(frontmatter, 'name') : '',\n description: frontmatter ? parseFrontmatterValue(frontmatter, 'description') : '',\n };\n}\n\nfunction extractSkillMetadataFromManifest(files: UploadFile[], manifestPath: string | null): ParsedSkillMetadata {\n if (!manifestPath) {\n return { name: '', description: '' };\n }\n\n const skillMdFile = files.find((file) => normalizeUploadPath(file.path) === manifestPath);\n if (!skillMdFile) {\n return { name: '', description: '' };\n }\n\n try {\n return parseSkillMetadata(decodeBase64Utf8(skillMdFile.content));\n } catch {\n return { name: '', description: '' };\n }\n}\n\nfunction findRootSkillMarkdownPath(paths: string[]): string | null {\n const normalizedPaths = paths.map(normalizeUploadPath).filter((path) => path.length > 0 && !isIgnoredZipEntryPath(path));\n\n if (normalizedPaths.includes('SKILL.md')) {\n return 'SKILL.md';\n }\n\n const rootSkillFiles = normalizedPaths.filter((path) => path.endsWith('/SKILL.md') && path.split('/').length === 2);\n if (rootSkillFiles.length !== 1) {\n return null;\n }\n\n const rootSkillPath = rootSkillFiles[0] ?? null;\n if (!rootSkillPath) {\n return null;\n }\n\n const rootDir = rootSkillPath.split('/')[0];\n const hasLooseRootFiles = normalizedPaths.some((path) => !path.includes('/'));\n if (hasLooseRootFiles) {\n return null;\n }\n\n const hasDifferentTopLevelDir = normalizedPaths.some((path) => path.split('/')[0] !== rootDir);\n return hasDifferentTopLevelDir ? null : rootSkillPath;\n}\n\nfunction extractSkillMetadata(files: UploadFile[]): ParsedSkillMetadata {\n return extractSkillMetadataFromManifest(files, findRootSkillMarkdownPath(files.map((file) => file.path)));\n}\n\nfunction getSkillMetadataValidationError(parsedSkill: ParsedSkillMetadata): string | null {\n return parsedSkill.name.trim() ? null : SKILL_NAME_REQUIRED_ERROR;\n}\n\nfunction getUploadValidationIssue(files: UploadFile[]): UploadValidationIssue | null {\n if (files.length === 0) {\n return { kind: 'empty', message: '请选择文件' };\n }\n\n const oversizedFile = files.find((file) => file.size > SKILL_UPLOAD_LIMITS.maxFileBytes);\n if (oversizedFile) {\n return {\n kind: 'fileTooLarge',\n message: `文件 ${oversizedFile.path} 单个文件大小不能超过1MB`,\n };\n }\n\n if (files.length > SKILL_UPLOAD_LIMITS.maxFiles) {\n return {\n kind: 'tooManyFiles',\n message: `文件数量不能超过 ${SKILL_UPLOAD_LIMITS.maxFiles} 个`,\n };\n }\n\n const totalBytes = files.reduce((sum, file) => sum + file.size, 0);\n if (totalBytes > SKILL_UPLOAD_LIMITS.maxTotalBytes) {\n return {\n kind: 'totalTooLarge',\n message: `文件总大小不能超过 ${formatBytes(SKILL_UPLOAD_LIMITS.maxTotalBytes)}`,\n };\n }\n\n if (!findRootSkillMarkdownPath(files.map((file) => file.path))) {\n return {\n kind: 'missingSkill',\n message: ROOT_SKILL_REQUIRED_ERROR,\n };\n }\n\n return null;\n}\n\nfunction getInlineValidationError(files: UploadFile[]): string | null {\n const issue = getUploadValidationIssue(files);\n return issue?.kind === 'missingSkill' ? issue.message : null;\n}\n\nexport function validateSkillName(name: string): string | null {\n const trimmedName = name.trim();\n\n if (!trimmedName) return '请输入技能名称';\n if (trimmedName.length > SKILL_NAME_MAX_LENGTH) {\n return `技能名称不能超过 ${SKILL_NAME_MAX_LENGTH} 个字符`;\n }\n if (!SKILL_NAME_ALLOWED_RE.test(trimmedName)) {\n return '技能名称仅支持英文、数字和中划线';\n }\n\n return null;\n}\n\nexport function validateSkillUpload(name: string, files: UploadFile[]): string | null {\n return validateSkillUploadFiles(files) ?? validateSkillName(name);\n}\n\nexport function validateSkillUploadFiles(files: UploadFile[]): string | null {\n return getUploadValidationIssue(files)?.message ?? null;\n}\n\nexport function UploadSkillModal({ open, onClose, onSuccess }: UploadSkillModalProps) {\n const addToast = useToastStore((state) => state.addToast);\n const [name, setName] = useState('');\n const [parsedName, setParsedName] = useState('');\n const [description, setDescription] = useState('');\n const [files, setFiles] = useState<UploadFile[]>([]);\n const [fileNames, setFileNames] = useState<string[]>([]);\n const [uploading, setUploading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isEditingName, setIsEditingName] = useState(false);\n const [isFileListExpanded, setIsFileListExpanded] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const folderInputRef = useRef<HTMLInputElement>(null);\n const nameInputRef = useRef<HTMLInputElement>(null);\n const canEditName = parsedName.trim().length > 0;\n const fileValidationIssue = getUploadValidationIssue(files);\n const metadataValidationError = !fileValidationIssue && files.length > 0\n ? getSkillMetadataValidationError({ name: parsedName, description })\n : null;\n const parseResultError = error\n ?? (fileValidationIssue && fileValidationIssue.kind !== 'empty' ? fileValidationIssue.message : null)\n ?? metadataValidationError;\n const nameValidationError = validateSkillName(name);\n const editingNameValidationError = isEditingName ? nameValidationError : null;\n const uploadDisabledReason = (() => {\n if (uploading) return '正在导入技能,请稍候';\n if (files.length === 0) return '请选择文件或文件夹后再导入';\n if (error) return error;\n if (fileValidationIssue) return fileValidationIssue.message;\n if (metadataValidationError) return metadataValidationError;\n if (nameValidationError) return nameValidationError;\n return null;\n })();\n const isSubmitDisabled = uploadDisabledReason != null;\n const visibleFileEntries = (isFileListExpanded ? fileNames : fileNames.slice(0, COLLAPSED_FILE_COUNT)).map((fileName, index) => ({\n fileName,\n index,\n }));\n const hasExpandableFileList = fileNames.length > COLLAPSED_FILE_COUNT;\n\n const resetUploadPickers = useCallback(() => {\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n if (folderInputRef.current) {\n folderInputRef.current.value = '';\n }\n }, []);\n\n const reset = useCallback(() => {\n setName('');\n setParsedName('');\n setDescription('');\n setFiles([]);\n setFileNames([]);\n setError(null);\n setIsEditingName(false);\n setIsFileListExpanded(false);\n resetUploadPickers();\n }, [resetUploadPickers]);\n\n const handleClose = useCallback(() => {\n reset();\n onClose();\n }, [reset, onClose]);\n\n useEffect(() => {\n if (!open) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n handleClose();\n }\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [open, handleClose]);\n\n useEffect(() => {\n if (!isEditingName) return;\n nameInputRef.current?.focus();\n nameInputRef.current?.select();\n }, [isEditingName]);\n\n const showToast = useCallback(\n (type: 'success' | 'error' | 'info', title: string, message: string) => {\n addToast({\n type,\n title,\n message,\n duration: 4000,\n });\n },\n [addToast],\n );\n\n const syncUploadState = useCallback(\n (nextFiles: UploadFile[], options: UploadStateOptions = {}) => {\n const nextParsedSkill = options.parsedSkill ?? extractSkillMetadata(nextFiles);\n const nextValidationIssue = getUploadValidationIssue(nextFiles);\n const nextMetadataValidationError = nextValidationIssue ? null : getSkillMetadataValidationError(nextParsedSkill);\n\n setFiles(nextFiles);\n setFileNames(nextFiles.map((file) => file.path));\n setParsedName(nextParsedSkill.name);\n setDescription(nextParsedSkill.description);\n setName((currentName) => {\n const trimmedCurrentName = currentName.trim();\n if (!trimmedCurrentName || trimmedCurrentName === parsedName) {\n return nextParsedSkill.name;\n }\n return currentName;\n });\n setIsEditingName(false);\n setError(options.inlineError ?? getInlineValidationError(nextFiles));\n\n if (nextValidationIssue && nextValidationIssue.kind !== 'empty' && nextValidationIssue.kind !== 'missingSkill') {\n showToast('error', '上传失败', nextValidationIssue.message);\n }\n if (nextMetadataValidationError) {\n showToast('error', '上传失败', nextMetadataValidationError);\n }\n },\n [parsedName, showToast],\n );\n\n const readFiles = useCallback(async (fileList: FileList) => {\n const selectedFiles = Array.from(fileList);\n resetUploadPickers();\n const zipFiles = selectedFiles.filter(isZipFile);\n\n if (zipFiles.length > 0 && selectedFiles.length !== 1) {\n setError(null);\n showToast('error', '上传失败', ZIP_SINGLE_UPLOAD_ERROR);\n return;\n }\n\n if (zipFiles.length === 1) {\n try {\n const { default: JSZip } = await import('jszip');\n const zip = await JSZip.loadAsync(await fileToArrayBuffer(zipFiles[0]));\n const zipEntries: UploadFile[] = [];\n\n for (const entry of Object.values(zip.files)) {\n if (entry.dir) continue;\n\n const normalizedPath = normalizeUploadPath(entry.name);\n if (!normalizedPath || isIgnoredZipEntryPath(normalizedPath)) continue;\n\n const bytes = await entry.async('uint8array');\n zipEntries.push({\n path: normalizedPath,\n content: uint8ArrayToBase64(bytes),\n size: bytes.byteLength,\n });\n }\n\n zipEntries.sort((left, right) => left.path.localeCompare(right.path));\n setIsFileListExpanded(false);\n\n const rootSkillMarkdownPath = findRootSkillMarkdownPath(zipEntries.map((entry) => entry.path));\n const uploadIssue = getUploadValidationIssue(zipEntries);\n if (uploadIssue) {\n showToast('error', '上传失败', uploadIssue.kind === 'missingSkill' ? ZIP_ROOT_SKILL_ERROR : uploadIssue.message);\n return;\n }\n\n syncUploadState(zipEntries, {\n inlineError: null,\n parsedSkill: extractSkillMetadataFromManifest(zipEntries, rootSkillMarkdownPath),\n });\n } catch {\n setError(null);\n showToast('error', '上传失败', 'ZIP 文件解析失败');\n }\n\n return;\n }\n\n const newEntries: UploadFile[] = [];\n\n for (const file of selectedFiles) {\n const relPath = ('webkitRelativePath' in file ? (file.webkitRelativePath as string) : '') || file.name;\n const base64 = await fileToBase64(file);\n newEntries.push({ path: relPath, content: base64, size: file.size });\n }\n\n setIsFileListExpanded(false);\n const uploadIssue = getUploadValidationIssue(newEntries);\n if (uploadIssue) {\n showToast('error', '上传失败', uploadIssue.message);\n return;\n }\n\n syncUploadState(newEntries);\n }, [resetUploadPickers, showToast, syncUploadState]);\n\n const removeFile = useCallback((index: number) => {\n const nextFiles = files.filter((_, currentIndex) => currentIndex !== index);\n syncUploadState(nextFiles);\n }, [files, syncUploadState]);\n\n const handleNameChange = useCallback((nextName: string) => {\n setName(nextName);\n }, []);\n\n const handleNameEditComplete = useCallback((action: 'submit' | 'blur' | 'cancel' = 'blur') => {\n if (action === 'cancel') {\n setName(parsedName);\n setIsEditingName(false);\n return;\n }\n\n if (validateSkillName(name)) {\n return;\n }\n\n setIsEditingName(false);\n }, [name, parsedName]);\n\n const handleSubmit = useCallback(async () => {\n const fileValidationIssue = getUploadValidationIssue(files);\n if (fileValidationIssue) {\n setError(fileValidationIssue.kind === 'missingSkill' ? fileValidationIssue.message : null);\n if (fileValidationIssue.kind !== 'missingSkill') {\n showToast('error', '上传失败', fileValidationIssue.message);\n }\n return;\n }\n\n if (metadataValidationError) {\n showToast('error', '上传失败', metadataValidationError);\n return;\n }\n\n const nameValidationError = validateSkillName(name);\n if (nameValidationError) {\n showToast('error', '上传失败', nameValidationError);\n return;\n }\n\n setUploading(true);\n setError(null);\n try {\n const res = await apiFetch('/api/skills/upload', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n name: name.trim(),\n files: files.map(({ path, content }) => ({ path, content })),\n }),\n });\n const data = (await res.json().catch(() => ({}))) as { success?: boolean; error?: string };\n if (data.success) {\n notifySkillOptionsChanged();\n handleClose();\n onSuccess();\n } else {\n showToast('error', '上传失败', data.error ?? (res.status === 413 ? '上传内容过大,请减少文件数量或体积' : '上传失败'));\n }\n } catch {\n showToast('error', '上传失败', '网络错误,请确认本地 API 服务已启动,或减少上传文件数量后重试');\n } finally {\n setUploading(false);\n }\n }, [files, handleClose, metadataValidationError, name, onSuccess, showToast]);\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-strong)] p-4\" data-testid=\"upload-skill-overlay\">\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n className=\"flex w-[550px] max-h-[calc(100vh-32px)] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-xl border border-[var(--modal-border)] bg-[var(--modal-surface)] p-6 shadow-[var(--modal-shadow)]\"\n >\n <div className=\"mb-5 flex items-center justify-between\">\n <h3 className=\"text-sm font-bold\">导入技能</h3>\n <IconButton\n label=\"close\"\n size=\"sm\"\n onClick={handleClose}\n icon={<CloseIcon />}\n />\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto pr-1\">\n <Alert mode=\"prompt\" closable={false} className=\"mb-4\">\n 1.支持上传文件或文件夹:单个文件 ≤ 1MB,文件总数 ≤ 100 个,总大小 ≤ 4MB;\n <br />\n 2.上传内容的根目录必须包含 SKILL.md 文件。\n </Alert>\n\n <div className=\"mb-4 flex gap-2\">\n <Button variant=\"default\" onClick={() => fileInputRef.current?.click()}>\n 选择文件\n </Button>\n <Button variant=\"default\" onClick={() => folderInputRef.current?.click()}>\n 选择文件夹\n </Button>\n </div>\n\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n onChange={(e) => e.target.files && void readFiles(e.target.files)}\n className=\"hidden\"\n />\n <input\n ref={folderInputRef}\n type=\"file\"\n {...({ webkitdirectory: '' } as Record<string, string>)}\n multiple\n onChange={(e) => e.target.files && void readFiles(e.target.files)}\n className=\"hidden\"\n />\n\n <div className=\"mb-4\">\n {fileNames.length > 0 ? (\n <div className=\"space-y-1 pr-1 text-xs text-[var(--modal-text-muted)]\">\n {visibleFileEntries.map(({ fileName, index }) => (\n <div\n key={`${fileName}-${index}`}\n className=\"group flex items-center gap-2 rounded-[6px] px-2 py-1 transition-colors hover:bg-[var(--modal-muted-surface-hover)]\"\n data-testid=\"upload-skill-file-row\"\n >\n <div className=\"min-w-0 flex flex-1 items-center gap-1\">\n <img\n src={resolveUploadFileIcon(fileName)}\n alt=\"\"\n aria-hidden=\"true\"\n className=\"h-4 w-4 shrink-0\"\n data-testid=\"upload-skill-file-icon\"\n />\n <span className=\"min-w-0 flex-1 truncate\">{fileName}</span>\n </div>\n <button\n type=\"button\"\n onClick={() => removeFile(index)}\n aria-label={`remove-file-${index}`}\n className=\"shrink-0 text-[var(--modal-text-subtle)] opacity-0 transition-[opacity,color] group-hover:opacity-100 hover:text-[var(--modal-accent-text)]\"\n data-testid=\"upload-skill-file-delete-button\"\n >\n <DeleteFileIcon />\n </button>\n </div>\n ))}\n {hasExpandableFileList ? (\n <button\n type=\"button\"\n data-testid=\"file-list-toggle\"\n onClick={() => setIsFileListExpanded((currentValue) => !currentValue)}\n className=\"pt-1 text-xs text-[var(--modal-text-muted)] transition-colors hover:text-[var(--modal-text)]\"\n >\n {isFileListExpanded ? '收起' : `展开全部 (${fileNames.length})`}\n </button>\n ) : null}\n </div>\n ) : null}\n </div>\n\n {files.length > 0 ? (\n <div>\n <div className=\"mb-3 text-xs font-medium text-[var(--modal-text-muted)]\">解析结果</div>\n\n {parseResultError ? (\n <p data-testid=\"parsed-skill-error\" className=\"text-xs text-[#f23030]\">\n {parseResultError}\n </p>\n ) : (\n <div className=\"space-y-3\">\n <div className=\"flex items-start gap-3 text-xs\">\n <div className=\"w-[72px] shrink-0 pt-2 text-[var(--modal-text-muted)]\">Skill名称</div>\n <div className=\"min-w-0 flex-1\">\n {isEditingName ? (\n <div className=\"space-y-1\">\n <input\n ref={nameInputRef}\n type=\"text\"\n value={name}\n maxLength={SKILL_NAME_MAX_LENGTH}\n aria-invalid={editingNameValidationError ? 'true' : 'false'}\n onChange={(e) => handleNameChange(e.target.value)}\n onBlur={() => handleNameEditComplete('blur')}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n handleNameEditComplete('submit');\n }\n if (event.key === 'Escape') {\n event.preventDefault();\n handleNameEditComplete('cancel');\n }\n }}\n placeholder=\"请输入技能名称\"\n className=\"ui-input w-full rounded px-3 py-2 text-xs\"\n style={editingNameValidationError\n ? {\n borderColor: SKILL_NAME_ERROR_BORDER_COLOR,\n backgroundColor: SKILL_NAME_ERROR_BG_COLOR,\n }\n : undefined}\n />\n {editingNameValidationError ? (\n <p data-testid=\"upload-skill-name-error\" className=\"text-xs text-[var(--state-error-text)]\">\n {editingNameValidationError}\n </p>\n ) : null}\n </div>\n ) : (\n <div className=\"inline-flex min-h-8 max-w-full items-center gap-1\">\n {name ? (\n <OverflowTooltip content={name} className={PARSED_NAME_MAX_WIDTH_CLASS}>\n <span\n data-testid=\"parsed-skill-name-text\"\n className={`block truncate whitespace-nowrap text-[var(--modal-text)] ${PARSED_NAME_MAX_WIDTH_CLASS}`}\n >\n {name}\n </span>\n </OverflowTooltip>\n ) : (\n <span className=\"text-[var(--modal-text)]\">--</span>\n )}\n {canEditName ? (\n <button\n type=\"button\"\n aria-label=\"edit-skill-name\"\n onClick={() => setIsEditingName(true)}\n className=\"shrink-0 text-[var(--modal-text-subtle)] transition-colors hover:text-[var(--modal-text)]\"\n >\n <EditIcon />\n </button>\n ) : null}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"flex items-start gap-3 text-xs\">\n <div className=\"w-[72px] shrink-0 text-[var(--modal-text-muted)]\">Skill描述</div>\n <div className=\"min-w-0 flex-1 leading-5 text-[var(--modal-text)]\">\n <span data-testid=\"parsed-skill-description-text\" className=\"whitespace-pre-wrap break-words\">\n {description || '--'}\n </span>\n </div>\n </div>\n </div>\n )}\n </div>\n ) : null}\n\n </div>\n <div className=\"mt-4 flex justify-end gap-2\">\n <Button variant=\"default\" onClick={handleClose}>\n 取消\n </Button>\n {uploadDisabledReason ? (\n <OverflowTooltip content={uploadDisabledReason} forceShow className=\"inline-flex shrink-0\">\n <span data-testid=\"upload-skill-submit-trigger\" className=\"inline-flex shrink-0\">\n <Button\n onClick={handleSubmit}\n disabled={isSubmitDisabled}\n >\n {uploading ? '导入中...' : '导入'}\n </Button>\n </span>\n </OverflowTooltip>\n ) : (\n <span data-testid=\"upload-skill-submit-trigger\" className=\"inline-flex shrink-0\">\n <Button\n onClick={handleSubmit}\n disabled={isSubmitDisabled}\n >\n {uploading ? '导入中...' : '导入'}\n </Button>\n </span>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"file":"assets/UploadSkillModal-DHZL12vm.js"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/docx-preview-zfB-orwa.js","assets/jszip.min-DPdj3o0t.js","assets/index-Cb4fQgom.js","assets/index-Bed0I5IL.css","assets/_commonjs-dynamic-modules-TDtrdbi3.js","assets/exceljs.min-BY7KKJsM.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{r as m,j as l,u as B,c as V,K as X,_ as W}from"./index-Cb4fQgom.js";import{a as w}from"./OverflowTooltip-CE5PjAb-.js";import{M as K,r as q,a as Q}from"./index-DQ2vVjmV.js";function Vt(t,e){const n=Number.parseInt(t.slice(1,3),16),r=Number.parseInt(t.slice(3,5),16),o=Number.parseInt(t.slice(5,7),16),s=Math.round(n+(255-n)*e),a=Math.round(r+(255-r)*e),i=Math.round(o+(255-o)*e);return`rgb(${s}, ${a}, ${i})`}const Y=["[PERMISSION_DENIED]","[PERMISSION_REJECTED]","[APPROVAL_REQUIRED]","PERMISSION_DENIED:","[permission denied]","command rejected for safety"];function tt(t){return t?Y.some(e=>t.includes(e)):!1}function Xt(t,e){const n=t.filter(r=>r.kind==="tool_use").length;return e==="streaming"?"正在执行工具调用":e==="interrupted"?"工具调用已停止":`已执行${n}次工具调用`}function Kt(t,e,n,r){const o=n!=null,a=t==="streaming"&&e.kind==="tool_use"&&!r,i=!!r&&!a&&(tt(n)||!!(n&&(n.startsWith("[ERROR]:")||n.startsWith("Error:")||n.startsWith("[PERMISSION_REJECTED]")))),c=t==="interrupted"&&e.kind==="tool_use"&&!r&&!i;return{shouldRenderMarkdown:o,showLoading:a,showError:i,showCheck:!!r&&!a&&!i&&!c,showStopped:c}}function R(t,e){if(!t.toolCallId)return;const n=e.filter(r=>r.toolCallId===t.toolCallId);if(n.length!==0)return[...n].reverse().find(r=>(r.detail??"").trim().length>0)??n[n.length-1]}function et(t,e,n,r){if(t.toolCallId){const a=R(t,e);if(((a==null?void 0:a.detail)??"").trim().length>0)return a;const i=r?R(t,r):void 0;return((i==null?void 0:i.detail)??"").trim().length>0?i:a??i}const o=e[n];if(((o==null?void 0:o.detail)??"").trim().length>0)return o;const s=r==null?void 0:r[n];return((s==null?void 0:s.detail)??"").trim().length>0?s:o??s}function qt(t,e){if(t[e])return e;const n=e.replace(/\\/g,"/").replace(/\/+$/,"");return Object.keys(t).find(o=>{const s=o.replace(/\\/g,"/").replace(/\/+$/,"");return s.endsWith(n)||n.endsWith(s)})??e}function nt(t,e,n){return et(t,e,n)}function rt(t){const e=t.filter(n=>n.kind==="tool_use");if(e.length!==0)for(let n=0;n<e.length;n++){const r=t.filter(s=>s.kind==="tool_result"),o=e[n];nt(o,r,n)||t.push({id:`pad-tool-result-${o.id}`,kind:"tool_result",timestamp:o.timestamp+1,label:"",detail:"",toolCallId:o.toolCallId})}}function ot(t){const e=t.indexOf(" → ");return e>=0?t.slice(e+3):t}function T(t,e=60){return t.length>e?`${t.slice(0,e-3)}...`:t}const O=["file_path","abs_file_path_list","file_uri","command","pattern","url","query","prompt"];function st(t){if(t)try{const e=JSON.parse(t);for(const n of O){const r=e[n];if(typeof r=="string"&&r.length>0)return T(r)}for(const n of Object.values(e))if(typeof n=="string"&&n.length>0&&n.length<=80)return T(n)}catch{for(const e of O){const n=new RegExp(`"${e}"\\s*:\\s*"([^"]+)"`),r=t.match(n);if(r!=null&&r[1])return T(r[1])}}}function it(t,e,n){const r=[];if(t)for(const o of t)if(o.type==="tool_use"){const s=ot(o.label),a=st(o.detail);r.push({id:o.id,kind:o.type,timestamp:o.timestamp,label:a?`${s} ${a}`:s,detail:o.detail,toolCallId:o.toolCallId})}else r.push({id:o.id,kind:o.type,timestamp:o.timestamp,label:o.label,detail:o.detail,toolCallId:o.toolCallId});return n!=null&&n.padUnmatchedToolResults&&rt(r),e!=null&&e.trim()&&r.push({id:"stdout-text",kind:"text",timestamp:r.length>0?r[r.length-1].timestamp+1:Date.now(),content:e}),r}function Qt({panelTestId:t,title:e,fullScreenContainerRef:n,onRequestClose:r,onOpenFolder:o,folderButtonTitle:s="打开所在文件夹",headerActions:a,extraHeaderContent:i,hideBorderLeft:c=!1,hideHeaderActions:u=!1,fullScreen:f,onFullScreenChange:d,titleContent:g,children:h}){const[C,H]=m.useState(!1),L=f!==void 0,x=L?f:C,U=n!=null,v=m.useCallback(_=>{d==null||d(_),L||H(_)},[L,d]),J=m.useCallback(()=>{v(!x)},[x,v]),G=m.useCallback(()=>{v(!1),r()},[r,v]);return l.jsxs("section",{"data-testid":t,className:`flex min-h-0 flex-col ${x?U?"absolute inset-0 z-[100] min-h-0 overflow-hidden":"fixed inset-0 z-[100] h-screen w-screen min-h-0 overflow-hidden":`h-full min-h-0 w-full min-w-0${c?"":" border-l border-gray-200"}`} bg-white shadow-xl`,children:[l.jsxs("header",{className:"flex h-[52px] shrink-0 items-center justify-between border-b border-[#F0F0F0] bg-white px-5",children:[g!=null?l.jsx("div",{className:"mr-3 min-h-0 min-w-0 flex-1",children:g}):l.jsx("h2",{className:"mr-3 min-w-0 flex-1 truncate text-[14px] font-semibold leading-5 text-[#1F1F1F]",title:e,children:e}),l.jsxs("div",{className:"flex shrink-0 items-center gap-1 text-[#191919]",children:[i??null,a,u?null:l.jsxs(l.Fragment,{children:[o?l.jsx("button",{type:"button",onClick:()=>{o()},className:"flex size-8 items-center justify-center rounded-md transition-colors hover:bg-[#F5F5F7]",title:s,children:l.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 16.2673 16.2673",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":!0,children:[l.jsx("title",{children:s}),l.jsx("path",{fill:"currentColor",fillRule:"nonzero",transform:"matrix(0.999858 0.0168466 -0.0168466 0.999858 1.66809 2.20746)",d:"M3.81828 0C3.98772 0 4.1517 0.0599236 4.28122 0.169172L6.478 2.022L11.4008 2.0227C12.2302 2.0227 12.9112 2.65767 12.9843 3.46798L12.9908 3.6127L12.9907 4.216L13.6391 4.21663L13.7626 4.22557C14.0338 4.27753 14.2115 4.53952 14.1596 4.81073L13.0108 10.8057C12.9993 10.8661 12.9773 10.9218 12.9471 10.9714C12.6555 11.5117 12.0462 11.8345 11.4008 11.8345L2.68082 11.8345C1.20085 11.8343 0.00106351 10.6346 0.000718276 9.15453L0 1.58991C0 0.711781 0.711863 0 1.59 0L3.81828 0ZM13.0633 5.216L3.152 5.216L2.0962 10.7299C2.2783 10.7975 2.47529 10.8344 2.6809 10.8345L11.4008 10.8345C11.668 10.8345 11.8887 10.7435 12.0063 10.5974L13.0633 5.216ZM3.715 1L1.59 1C1.29671 1 1.05344 1.21391 1.00772 1.49418L1 1.58986L1.00072 9.15436C1.00079 9.45657 1.08064 9.74015 1.22034 9.98516L2.24806 4.62254C2.25354 4.59396 2.26135 4.56642 2.27125 4.54007C2.27663 4.52849 2.29689 4.4827 2.30313 4.47161C2.31207 4.45959 2.35474 4.39649 2.36486 4.38508C2.37554 4.37663 2.45096 4.30775 2.46224 4.30024C2.53624 4.25649 2.64651 4.21663 2.73913 4.21663L11.9907 4.216L11.9908 3.6127C11.9908 3.28686 11.7267 3.0227 11.4008 3.0227L6.37559 3.0227C6.20615 3.0227 6.04217 2.96278 5.91265 2.85353L3.715 1Z"})]})}):null,l.jsx("button",{type:"button",onClick:J,className:"flex size-8 items-center justify-center rounded-md transition-colors hover:bg-[#F5F5F7]",title:x?"退出全屏":"全屏预览",children:x?l.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":!0,children:[l.jsx("title",{children:"退出全屏"}),l.jsx("path",{fill:"currentColor",fillRule:"nonzero",d:"M5.96105 8.53895C6.78948 8.53895 7.46105 9.21052 7.46105 10.0389L7.46105 13.5C7.46105 13.7761 7.23719 14 6.96105 14C6.68491 14 6.46105 13.7761 6.46105 13.5L6.46067 10.2453L3.15939 13.5477C2.96413 13.743 2.64755 13.743 2.45228 13.5477C2.25702 13.3525 2.25702 13.0359 2.45228 12.8406L5.754 9.53867L2.5 9.53895C2.24687 9.53895 2.03767 9.35085 2.00456 9.1068L2 9.03895C2 8.76281 2.22386 8.53895 2.5 8.53895L5.96105 8.53895ZM9.03895 2C9.31509 2 9.53895 2.22386 9.53895 2.5L9.53867 5.754L12.8406 2.45228C13.0359 2.25702 13.3525 2.25702 13.5477 2.45228C13.743 2.64755 13.743 2.96413 13.5477 3.15939L10.2453 6.46067L13.5 6.46105C13.7531 6.46105 13.9623 6.64915 13.9954 6.8932L14 6.96105C14 7.23719 13.7761 7.46105 13.5 7.46105L10.0389 7.46105C9.21052 7.46105 8.53895 6.78948 8.53895 5.96105L8.53895 2.5C8.53895 2.22386 8.76281 2 9.03895 2Z"})]}):l.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":!0,children:[l.jsx("title",{children:"全屏预览"}),l.jsx("path",{fill:"currentColor",fillRule:"nonzero",d:"M2.5 8.53895C2.77614 8.53895 3 8.76281 3 9.03895L3 12.292L6.30166 8.99123C6.49692 8.79597 6.8135 8.79597 7.00877 8.99123C7.20403 9.1865 7.20403 9.50308 7.00877 9.69834L3.70667 13L6.96105 13C7.21418 13 7.42338 13.1881 7.45649 13.4322L7.46105 13.5C7.46105 13.7761 7.23719 14 6.96105 14L3.5 14C2.67157 14 2 13.3284 2 12.5L2 9.03895C2 8.76281 2.22386 8.53895 2.5 8.53895ZM12.5 2C13.3284 2 14 2.67157 14 3.5L14 6.96105C14 7.23719 13.7761 7.46105 13.5 7.46105C13.2239 7.46105 13 7.23719 13 6.96105L13 3.70667L9.69834 7.00877C9.50308 7.20403 9.1865 7.20403 8.99123 7.00877C8.79597 6.8135 8.79597 6.49692 8.99123 6.30166L12.2927 2.99933L9.03895 3C8.78582 3 8.57662 2.8119 8.54351 2.56785L8.53895 2.5C8.53895 2.22386 8.76281 2 9.03895 2L12.5 2Z"})]})}),l.jsx("button",{type:"button",onClick:G,className:"flex size-8 items-center justify-center rounded-md transition-colors hover:bg-[#F5F5F7]",title:"关闭预览","aria-label":"关闭预览",children:l.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":!0,children:[l.jsx("title",{children:"关闭"}),l.jsx("path",{d:"M18 6L6 18M6 6l12 12"})]})})]})]})]}),h]})}function I({title:t,"aria-label":e,onClick:n,children:r}){return l.jsx("button",{type:"button",onClick:n,className:"flex size-8 shrink-0 items-center justify-center rounded-md text-[#434343] transition-colors hover:bg-[#F5F5F7]",title:t,"aria-label":e??t,children:r})}function at({className:t="size-[18px]"}){return l.jsxs("svg",{className:t,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","aria-hidden":!0,children:[l.jsx("title",{children:"复制"}),l.jsx("path",{strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",d:"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"})]})}function lt({text:t,copyKindLabel:e="源代码",icon:n}){const r=B(s=>s.addToast),o=m.useCallback(async()=>{try{await navigator.clipboard.writeText(t),r({type:"success",title:"已复制",message:`${e}已复制到剪贴板`,duration:2200})}catch{r({type:"error",title:"复制失败",message:"无法访问剪贴板",duration:3500})}},[r,e,t]);return l.jsx(I,{title:`复制${e}`,onClick:o,children:n??l.jsx(at,{})})}const ut="/api/inspiration/products/";function ct(t){return t.startsWith(ut)}async function ft(t,e){const n=await w(t,{signal:e});return n.ok?{ok:!0,content:await n.text()}:{ok:!1,message:`HTTP ${n.status}`}}async function dt(t,e,n){const r=await w("/api/projects/read-local-text",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t,...e&&e!=="default"?{projectPath:e}:{}}),signal:n}),o=await r.json().catch(()=>null);return r.ok?typeof(o==null?void 0:o.content)!="string"?{ok:!1,message:"Invalid response"}:{ok:!0,content:o.content}:{ok:!1,message:(o==null?void 0:o.error)??`HTTP ${r.status}`}}function Yt(t,e,n=0,r=0){const[o,s]=m.useState({status:"idle"});return m.useEffect(()=>{if(!(t!=null&&t.trim())){s({status:"idle"});return}const a=t.trim(),i=new AbortController;return s({status:"loading"}),(ct(a)?ft(a,i.signal):dt(a,e??void 0,i.signal)).then(u=>{if(!i.signal.aborted){if(!u.ok){s({status:"error",message:u.message});return}s({status:"ok",content:u.content})}}).catch(u=>{i.signal.aborted||s({status:"error",message:u instanceof Error?u.message:"Request failed"})}),()=>i.abort()},[t,e,n,r]),o}const mt=[];function ht(t){var n;const e=[];for(const r of t)(n=r.toolEvents)!=null&&n.length&&e.push(...it(r.toolEvents,void 0,{padUnmatchedToolResults:!0}));return e}function te(t,e){const n=V(r=>{var o;return t===r.currentThreadId?r.messages:((o=r.threadStates[t])==null?void 0:o.messages)??mt});return m.useMemo(()=>{if(!(e!=null&&e.trim()))return 0;const r=ht(n);return X(r,e.trim())},[n,e])}function gt(t){const e=atob(t),n=e.length,r=new Uint8Array(n);for(let o=0;o<n;o++)r[o]=e.charCodeAt(o);return new Blob([r],{type:"application/vnd.openxmlformats-officedocument.wordprocessingml.document"})}function ee({contentBase64:t,title:e}){const n=m.useRef(null),r=m.useRef(null),[o,s]=m.useState(null);return m.useEffect(()=>{const a=n.current,i=r.current;if(!a||!i||!t)return;let c=!1;return s(null),a.replaceChildren(),i.replaceChildren(),(async()=>{try{const{renderAsync:u}=await W(async()=>{const{renderAsync:d}=await import("./docx-preview-zfB-orwa.js");return{renderAsync:d}},__vite__mapDeps([0,1,2,3,4]));if(c)return;const f=gt(t);await u(f,a,i,{className:"docx-oc-preview",inWrapper:!0,breakPages:!0,renderFootnotes:!0,renderEndnotes:!0,renderHeaders:!0,renderFooters:!0})}catch(u){c||s(u instanceof Error?u.message:"Word 预览失败")}})(),()=>{c=!0}},[t]),o?l.jsx("div",{className:"flex flex-1 items-center justify-center p-6 text-sm text-red-600",role:"alert",children:o}):l.jsxs("div",{className:"flex min-h-0 flex-1 flex-col gap-2","aria-label":e,children:[l.jsx("div",{ref:r,className:"docx-oc-styles flex-shrink-0"}),l.jsx("div",{ref:n,className:"docx-oc-body min-h-0 flex-1 overflow-auto"})]})}function pt(t,e){const n=(e==null?void 0:e.error)??`HTTP ${t.status}`;return t.status===404&&(n==="Not Found"||/route .+ not found/i.test(String((e==null?void 0:e.message)??"")))?"预览服务未就绪:后端未注册文档预览接口。请重启 API(pnpm dev / pnpm start)后再试。":n}async function xt(t,e,n){const r=await w("/api/projects/read-local-binary-preview",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t,...e&&e!=="default"?{projectPath:e}:{}}),signal:n}),o=await r.json().catch(()=>null);return r.ok?typeof(o==null?void 0:o.contentBase64)!="string"||!o.contentBase64.length?{ok:!1,message:"Invalid response"}:{ok:!0,contentBase64:o.contentBase64}:{ok:!1,message:pt(r,o)}}function ne(t,e,n=0){const[r,o]=m.useState({status:"idle"});return m.useEffect(()=>{if(!(t!=null&&t.trim())){o({status:"idle"});return}const s=t.trim(),a=new AbortController;return o({status:"loading"}),xt(s,e??void 0,a.signal).then(i=>{if(!a.signal.aborted){if(!i.ok){o({status:"error",message:i.message});return}o({status:"ok",contentBase64:i.contentBase64})}}).catch(i=>{a.signal.aborted||o({status:"error",message:i instanceof Error?i.message:"Request failed"})}),()=>a.abort()},[t,e,n]),r}function re({html:t,title:e}){return l.jsx("iframe",{title:e,className:"box-border h-full min-h-[20rem] w-full flex-1 rounded-md border border-[var(--border-default)] bg-[var(--surface-neutral-white,#fff)]",referrerPolicy:"no-referrer",sandbox:"allow-scripts",srcDoc:t})}const N={copy:"/images/html-preview-toolbar/copy.svg",refresh:"/images/html-preview-toolbar/refresh.svg",openExternal:"/images/html-preview-toolbar/open-external.svg"};function E({src:t}){return l.jsx("img",{src:t,alt:"",width:18,height:18,className:"size-[18px] shrink-0 object-contain select-none",draggable:!1})}function oe({html:t,filePath:e,projectPath:n,onRefresh:r}){const o=B(a=>a.addToast),s=m.useCallback(async()=>{try{const a=await w("/api/projects/open-local",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,...n&&n!=="default"?{projectPath:n}:{}})});if(!a.ok){const i=await a.json().catch(()=>null);o({type:"error",title:"打开失败",message:(i==null?void 0:i.error)??`HTTP ${a.status}`,duration:3500});return}o({type:"success",title:"已打开",message:"已在默认程序中打开",duration:2200})}catch(a){o({type:"error",title:"打开失败",message:a instanceof Error?a.message:"请求失败",duration:3500})}},[o,e,n]);return l.jsxs(l.Fragment,{children:[l.jsx(lt,{text:t,copyKindLabel:"HTML",icon:l.jsx(E,{src:N.copy})}),l.jsx(I,{title:"刷新",onClick:r,children:l.jsx(E,{src:N.refresh})}),l.jsx(I,{title:"在默认程序中打开",onClick:s,children:l.jsx(E,{src:N.openExternal})})]})}const bt={a:({href:t,children:e,...n})=>l.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer",...n,children:e})};function se({source:t,className:e}){return l.jsx("div",{className:`markdown-content prose prose-base max-w-none font-sans break-words leading-relaxed ${e??""}`,children:l.jsx(K,{remarkPlugins:[[q,{singleTilde:!1}],Q],components:bt,children:t})})}function yt(t,e){const n=(e==null?void 0:e.error)??`HTTP ${t.status}`;return t.status===404&&(n==="Not Found"||/route .+ not found/i.test(String((e==null?void 0:e.message)??"")))?"预览服务未就绪:后端未注册文档预览接口。请重启 API(pnpm dev / pnpm start)后再试。":n}async function wt(t,e,n){const r=await w("/api/projects/read-local-binary-preview",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t,...e&&e!=="default"?{projectPath:e}:{}}),signal:n}),o=await r.json().catch(()=>null);return r.ok?typeof(o==null?void 0:o.contentBase64)!="string"||!o.contentBase64.length?{ok:!1,message:"Invalid response"}:{ok:!0,contentBase64:o.contentBase64}:{ok:!1,message:yt(r,o)}}function ie(t,e,n=0){const[r,o]=m.useState({status:"idle"});return m.useEffect(()=>{if(!(t!=null&&t.trim())){o({status:"idle"});return}const s=t.trim(),a=new AbortController;return o({status:"loading"}),wt(s,e??void 0,a.signal).then(i=>{if(!a.signal.aborted){if(!i.ok){o({status:"error",message:i.message});return}o({status:"ok",contentBase64:i.contentBase64})}}).catch(i=>{a.signal.aborted||o({status:"error",message:i instanceof Error?i.message:"Request failed"})}),()=>a.abort()},[t,e,n]),r}const Ct=(t,e)=>Math.max(64,t*e*2);function k(t){let e=0;const n=t.toUpperCase();for(let r=0;r<n.length;r+=1)e=e*26+(n.charCodeAt(r)-64);return e}function y(t,e){return`${t}:${e}`}function p(t,e,n){const r=k(e);return t.get(y(n,r))}function P(t){return t.replace(/^=/u,"").replace(/\s+/gu,"")}function vt(t){const e=t.value;if(typeof e=="number"&&Number.isFinite(e))return e;if(!e||typeof e!="object"||!("formula"in e)&&!("sharedFormula"in e))return;const n=e.result;return typeof n=="number"&&Number.isFinite(n)?n:void 0}function St(t,e){const n=/^SUM\(([A-Z]+)(\d+):([A-Z]+)(\d+)\)$/iu.exec(t);if(!n)return;const r=k(n[1]),o=parseInt(n[2],10),s=k(n[3]),a=parseInt(n[4],10),i=Math.min(o,a),c=Math.max(o,a),u=Math.min(r,s),f=Math.max(r,s);let d=0;for(let g=i;g<=c;g+=1)for(let h=u;h<=f;h+=1){const C=e.get(y(g,h));if(C===void 0)return;d+=C}return d}function jt(t,e,n){if(n>48)return;const r=/^IF\(([A-Z]+)(\d+)=0,0,(.+)\)$/iu.exec(t);if(!r)return;const o=parseInt(r[2],10),s=k(r[1]),a=e.get(y(o,s));if(a!==void 0)return a===0?0:A(r[3],e,n+1)}function A(t,e,n){if(n>48)return;const r=jt(t,e,n);if(r!=null)return r;const o=St(t,e);if(o!=null)return o;const s=/^\(([A-Z]+)(\d+)-([A-Z]+)(\d+)\)\/([A-Z]+)(\d+)$/iu.exec(t);if(s){const u=p(e,s[1],parseInt(s[2],10)),f=p(e,s[3],parseInt(s[4],10)),d=p(e,s[5],parseInt(s[6],10));return u===void 0||f===void 0||d===void 0?void 0:d===0?0:(u-f)/d}const a=/^([A-Z]+)(\d+)\/([A-Z]+)(\d+)$/iu.exec(t);if(a){const u=p(e,a[1],parseInt(a[2],10)),f=p(e,a[3],parseInt(a[4],10));return u===void 0||f===void 0?void 0:f===0?0:u/f}const i=/^([A-Z]+)(\d+)([+\-*/])([A-Z]+)(\d+)$/iu.exec(t);if(i){const u=p(e,i[1],parseInt(i[2],10)),f=p(e,i[4],parseInt(i[5],10));if(u===void 0||f===void 0)return;const d=i[3];if(d==="+")return u+f;if(d==="-")return u-f;if(d==="*")return u*f;if(d==="/")return f===0?0:u/f}const c=/^([A-Z]+)(\d+)$/iu.exec(t);if(c)return p(e,c[1],parseInt(c[2],10))}function z(t){const e=t.formula;return typeof e=="string"&&e.length>0?e:void 0}function kt(t){const e=new Map,n=t.actualRowCount,r=t.actualColumnCount;if(n===0||r===0)return e;for(let s=1;s<=n;s+=1)for(let a=1;a<=r;a+=1){const i=vt(t.getCell(s,a));i!=null&&e.set(y(s,a),i)}const o=Ct(n,r);for(let s=0;s<o;s+=1){let a=!1;for(let i=1;i<=n;i+=1)for(let c=1;c<=r;c+=1){const u=y(i,c);if(e.has(u))continue;const f=t.getCell(i,c),d=z(f);if(!d)continue;const g=P(d),h=A(g,e,0);h!=null&&Number.isFinite(h)&&(e.set(u,h),a=!0)}if(!a)break}return e}function Lt(t,e){const n=z(t);if(!n)return;const r=P(n);return A(r,e,0)}function Tt(t){return t.replace(/"[^"]*"|'[^']*'/gu,"")}function Nt(t){const e=Tt(t).trim(),n=e.indexOf(";");return n>=0?e.slice(0,n):e}function Et(t){return/#,\s*##|#,##|,##0/u.test(t)}function Ft(t){const e=t.split("%")[0]??"",n=/\.(0+)/u.exec(e);return n?n[1].length:0}function It(t){if(/%/u.test(t)||/^\s*General\s*$/iu.test(t)||/[dmyh]([^a-z]|$)|^[\s]*\[/iu.test(t))return null;const e=/\.(0+)/u.exec(t);return e?e[1].length:!/\./u.test(t)&&/[0#]/.test(t)?0:null}function M(t,e=1e-9){if(!Number.isFinite(t))return t;const n=Math.round(t);return Math.abs(t-n)<e?n:t}function $(t,e){if(e<=0){const r=Math.round(t);return Math.abs(t-r)<1e-12?r:Math.round(t+Number.EPSILON*Math.sign(t))}const n=10**e;return Math.round((t+Number.EPSILON*Math.sign(t))*n)/n}function D(t){let e=M(t,1e-7);return Math.abs(e-Math.round(e))<1e-7?String(Math.round(e)):(e=Number.parseFloat(e.toPrecision(12)),String(e))}function b(t,e){if(!Number.isFinite(t))return String(t);const n=(e??"").trim();if(!n||/^General$/iu.test(n))return D(t);const r=Nt(n);if(/%/u.test(r)){const s=Ft(r),a=$(t*100,s);return`${M(a,1e-9)}%`}const o=It(r);if(o!=null){let s=$(t,o);return s=M(s,o===0?1e-7:1e-9),Et(r)?s.toLocaleString("en-US",{minimumFractionDigits:o,maximumFractionDigits:o,useGrouping:!0}):o===0?String(Math.round(s)):s.toFixed(o)}return D(t)}function Mt(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e.charCodeAt(r);return n}function Z(t){let e="",n=t;for(;n>=0;)e=String.fromCharCode(n%26+65)+e,n=Math.floor(n/26)-1;return e}function j(t){if(t==null)return;const e=typeof t=="string"?t:t.argb;return typeof e!="string"||e.length<6?void 0:`#${e.length>=8?e.slice(2):e}`}function At(t){if(t){if(t.type==="pattern"){const e=j(t.fgColor);return e||j(t.bgColor)}if(t.type==="gradient"&&t.stops.length>0)return j(t.stops[0].color)}}function _t(t){if(!t)return;const e={};if(t.color){const n=j(t.color);n&&(e.color=n)}return t.bold&&(e.fontWeight="bold"),t.italic&&(e.fontStyle="italic"),Object.keys(e).length?e:void 0}function Rt(t){var s;const e={},n=At(t.fill);n&&(e.backgroundColor=n);const r=_t(t.font);r!=null&&r.color&&(e.color=r.color),r!=null&&r.fontWeight&&(e.fontWeight=r.fontWeight),r!=null&&r.fontStyle&&(e.fontStyle=r.fontStyle);const o=(s=t.alignment)==null?void 0:s.horizontal;return(o==="center"||o==="left"||o==="right"||o==="justify")&&(e.textAlign=o),Object.keys(e).length?e:void 0}function S(t){if(t&&typeof t=="object"&&"error"in t){const e=t.error;if(typeof e=="string")return e}return null}function F(t){const e=t.richText;return Array.isArray(e)?e.map(n=>n.text).join(""):""}function Ot(t,e){const n=t.text;if(typeof n=="string"&&n.trim().length>0)return n;const r=t.value,o=t.numFmt;if(r==null||r==="")return"";if(Array.isArray(r))return r.map(s=>{if(s==null)return"";const a=S(s);return a||(typeof s=="number"?b(s,void 0):typeof s=="string"||typeof s=="boolean"?String(s):s instanceof Date?s.toLocaleString():typeof s=="object"&&s!==null&&"richText"in s?F(s):"")}).join(", ");if(typeof r=="string"||typeof r=="number"||typeof r=="boolean")return typeof r=="number"?b(r,o):String(r);if(r instanceof Date)return r.toLocaleString();if(typeof r=="object"&&r!==null){const s=S(r);if(s)return s;if("richText"in r)return F(r);if("hyperlink"in r){const i=r;return typeof i.text=="string"?i.text:""}const a=r;if(typeof a.formula=="string"||typeof a.sharedFormula=="string"){const i=a.result;if(i==null||i===""){const u=Lt(t,e);return u!=null?b(u,o):typeof a.formula=="string"?a.formula:a.sharedFormula??""}const c=S(i);return c||(typeof i=="string"||typeof i=="boolean"?String(i):typeof i=="number"?b(i,o):i instanceof Date?i.toLocaleString():i&&typeof i=="object"&&"richText"in i?F(i):typeof a.formula=="string"?a.formula:a.sharedFormula??"")}if("result"in a){const i=a.result;if(i==null||i==="")return"";const c=S(i);if(c)return c;if(typeof i=="string"||typeof i=="boolean")return String(i);if(typeof i=="number")return b(i,o);if(i instanceof Date)return i.toLocaleString()}}return""}function $t(t){const e=t.actualRowCount,n=t.actualColumnCount;if(e===0||n===0)return{name:t.name,rows:[],headers:[]};const r=kt(t),o=Array.from({length:n},(a,i)=>Z(i)),s=[];for(let a=1;a<=e;a+=1){const i=[];for(let c=1;c<=n;c+=1){const u=t.getCell(a,c);i.push({text:Ot(u,r),style:Rt(u)})}s.push(i)}return{name:t.name,rows:s,headers:o}}async function Dt(t){const e=(await W(async()=>{const{default:o}=await import("./exceljs.min-BY7KKJsM.js").then(s=>s.e);return{default:o}},__vite__mapDeps([5,2,3,4]))).default,n=new e.Workbook,r=t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength);return await n.xlsx.load(r),n.worksheets.map(o=>$t(o))}function Bt(t,e){const n=[];let r=[],o="",s=0,a=!1;for(;s<t.length;){const i=t[s];if(a){i==='"'?t[s+1]==='"'?(o+='"',s+=2):(a=!1,s+=1):(o+=i,s+=1);continue}if(i==='"'){a=!0,s+=1;continue}if(i===e){r.push(o),o="",s+=1;continue}if(i===`
|
|
3
|
+
`||i==="\r"){i==="\r"&&t[s+1]===`
|
|
4
|
+
`&&(s+=1),r.push(o),o="",n.push(r),r=[],s+=1;continue}o+=i,s+=1}for(r.push(o),n.push(r);n.length>0&&n[n.length-1].every(i=>i==="");)n.pop();return n}function Wt(t){const e=t.split(/\r?\n/u).find(o=>o.trim().length>0)??"",n=(e.match(/\t/g)??[]).length,r=(e.match(/,/g)??[]).length;return n>r?" ":","}function Pt(t,e){const n=e.reduce((s,a)=>Math.max(s,a.length),0);if(n===0)return{name:t,rows:[],headers:[]};const r=Array.from({length:n},(s,a)=>Z(a)),o=e.map(s=>r.map((a,i)=>({text:s[i]??""})));return{name:t,rows:o,headers:r}}function zt(t){let e;try{e=new TextDecoder("utf-8",{fatal:!0}).decode(t)}catch{return null}if(e.includes("\0"))return null;const n=e.replace(/^\uFEFF/u,"");if(!/[\r\n]/u.test(n))return null;const r=Wt(n),o=Bt(n,r);return o.length===0?null:[Pt("Sheet1",o)]}async function Zt(t){const e=Mt(t);try{const r=await Dt(e);if(r.length>0)return r}catch{}const n=zt(e);if(n)return n;throw new Error("无法预览:请使用 .xlsx / .xlsm,或 UTF-8 编码的 .csv。旧版 .xls 请用 Excel 另存为 .xlsx 后再预览。")}function ae(t){const[e,n]=m.useState({status:"idle"});return m.useEffect(()=>{if(!(t!=null&&t.trim())){n({status:"idle"});return}const r=t.trim();let o=!1;return n({status:"parsing"}),Zt(r).then(s=>{o||n({status:"ok",sheets:s})}).catch(s=>{o||n({status:"error",message:s instanceof Error?s.message:"Excel 预览失败"})}),()=>{o=!0}},[t]),e}function Ht({sheet:t}){return t.rows.length===0?l.jsx("p",{className:"p-4 text-sm text-gray-400",children:"(空工作表)"}):l.jsx("div",{className:"overflow-auto",children:l.jsxs("table",{className:"xlsx-oc-grid min-w-full border-collapse text-xs",children:[l.jsx("thead",{children:l.jsxs("tr",{children:[l.jsx("th",{className:"sticky left-0 z-10 w-8 border border-neutral-300 bg-neutral-100 px-2 py-1 text-center text-neutral-500"}),t.headers.map(e=>l.jsx("th",{className:"min-w-[80px] border border-neutral-300 bg-neutral-100 px-2 py-1 text-center font-medium text-neutral-600",children:e},e))]})}),l.jsx("tbody",{children:t.rows.map((e,n)=>l.jsxs("tr",{children:[l.jsx("td",{className:"sticky left-0 z-10 border border-neutral-300 bg-neutral-50 px-2 py-1 text-center text-neutral-400",children:n+1}),t.headers.map((r,o)=>{const s=e[o]??{text:""};return l.jsx("td",{className:"border border-neutral-300 px-2 py-1 text-neutral-900",style:s.style,children:s.text},o)})]},n))})]})})}function le({sheets:t,title:e}){const[n,r]=m.useState(0),o=t.length>0?Math.min(n,t.length-1):0,s=t[o];return l.jsxs("div",{className:"flex min-h-0 flex-1 flex-col","aria-label":e,children:[t.length>1&&l.jsx("div",{className:"flex shrink-0 gap-1 overflow-x-auto border-b border-gray-200 bg-gray-50 px-3 py-1",children:t.map((a,i)=>l.jsx("button",{type:"button",onClick:()=>r(i),className:["whitespace-nowrap rounded px-3 py-1 text-xs font-medium transition-colors",i===o?"bg-white text-blue-600 shadow-sm ring-1 ring-gray-200":"text-gray-500 hover:bg-white hover:text-gray-800"].join(" "),children:a.name},a.name))}),l.jsx("div",{className:"min-h-0 flex-1 overflow-auto",children:s&&l.jsx(Ht,{sheet:s})})]})}export{ee as D,oe as H,se as M,lt as P,le as X,it as a,Xt as b,Yt as c,ne as d,I as e,et as f,re as g,ie as h,ae as i,Qt as j,Vt as l,qt as r,Kt as t,te as u};
|
|
5
|
+
//# sourceMappingURL=XlsxDocumentPreview-BY-ht09K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"mappings":"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","names":["lighten","hex","ratio","r","g","b","lr","lg","lb","PERMISSION_DENIED_MARKERS","isPermissionDeniedResult","detail","marker","buildSummary","events","status","toolCount","e","toolRowOutcomeFlags","event","resultDetail","hasResultMatch","shouldRenderMarkdown","showLoading","showError","showStopped","pickToolResultByCallId","toolUse","toolResults","matches","findMatchingResult","index","extraToolResults","local","remote","resolvePptSessionStoreKey","sessions","markerPagesDir","norm","k","nk","findMatchingToolResult","appendSyntheticToolResults","toolUses","i","use","cleanToolLabel","label","arrowIdx","truncateArg","val","max","ARG_KEYS","extractPrimaryArg","obj","key","re","m","toCliEvents","toolEvents","streamContent","options","te","toolName","primaryArg","PreviewPanelShell","panelTestId","title","fullScreenContainerRef","onRequestClose","onOpenFolder","folderButtonTitle","headerActions","extraHeaderContent","hideBorderLeft","hideHeaderActions","fullScreenControlled","onFullScreenChange","titleContent","children","internalFullScreen","setInternalFullScreen","useState","isControlledFs","isFullScreen","useAnchoredFullScreen","setFullScreen","useCallback","next","handleToggleFullScreen","handleClose","jsxs","jsx","Fragment","PreviewToolbarIconButton","ariaLabel","onClick","CopyDocumentIcon","className","PreviewCopyButton","text","copyKindLabel","icon","addToast","useToastStore","handleCopy","INSPIRATION_PRODUCT_API_PREFIX","isInspirationProductApiPath","path","fetchApiPreviewText","signal","res","apiFetch","fetchLocalPreviewText","projectPath","body","useEmbeddedTextPreviewSource","resolvedPath","reloadRevision","refreshNonce","state","setState","useEffect","ac","result","EMPTY_MESSAGES","chronologicalCliEventsFromMessages","messages","_a","useSendFilePreviewReloadRevision","threadId","resolvedPreviewPath","useChatStore","s","useMemo","cli","countSendFileToUserHitsForResolvedPreviewPath","base64ToDocxBlob","b64","bin","len","u8","DocxDocumentPreview","contentBase64","bodyRef","useRef","styleHostRef","renderError","setRenderError","styleHost","cancelled","renderAsync","__vitePreload","blob","messageForFailedBinaryPreview","err","fetchLocalDocxBase64","useLocalDocxPreviewSource","HtmlDocumentPreview","html","HTML_PREVIEW_TOOLBAR_ICONS","HtmlPreviewToolbarRasterIcon","src","HtmlPreviewToolbarActions","filePath","onRefresh","handleOpenExternal","DOC_COMPONENTS","href","props","MarkdownDocumentPreview","source","ReactMarkdown","remarkGfm","remarkBreaks","fetchLocalXlsxBase64","useLocalXlsxPreviewSource","MAX_PASS","rows","cols","colLettersToIndex","letters","n","u","cellKey","row","col","getFromCache","cache","colLetters","normalizeFormulaInput","formula","seedNumericFromCell","cell","v","evalSum","c1","r1","c2","r2","lowR","highR","lowC","highC","sum","c","evalIf","depth","testR","testC","testV","evalArithmetic","ifVal","sumVal","divG","a","divS","op","single","formulaString","f","buildWorksheetNumericCache","worksheet","maxRow","maxCol","limit","pass","progressed","fs","inferFormulaNumeric","stripQuotedChunks","numFmt","firstPositiveSection","semi","wantsThousandsSeparator","section","percentFractionDigits","beforePct","numberFractionDigits","snapNearInteger","eps","roundToDecimalPlaces","places","p","formatGeneral","x","formatNumericForDisplay","value","raw","fd","pct","fdNum","base64ToUint8Array","colIndexToLetter","argbToCss","color","fillToBackground","fill","fg","fontToStyle","font","cellToStyle","bg","h","errorCellToString","richTextToString","rt","normalizedCellText","numericCache","t","asFormula","inferred","errR","excelWorksheetToSheetData","headers","_","dataRow","parseWithExcelJs","data","ExcelJS","__vite_default__","workbook","buffer","ws","parseDelimitedText","delimiter","field","inQuotes","sniffDelimiter","line","l","tabs","commas","gridToSheetData","name","grid","maxCols","tryParseUtf8Delimited","stripped","delim","parseXlsxBase64ToSheets","sheets","delimited","useXlsxSheetParse","SheetTable","sheet","rowIdx","colIdx","XlsxDocumentPreview","activeSheet","setActiveSheet","safeIndex","currentSheet"],"ignoreList":[],"sources":["../../src/components/cli-output/cli-output-block/cli-output-block-helpers.ts","../../src/components/cli-output/toCliEvents.ts","../../src/components/preview-panels/PreviewPanelShell.tsx","../../src/components/document-preview/PreviewToolbarShared.tsx","../../src/components/document-preview/useEmbeddedTextPreviewSource.ts","../../src/components/document-preview/useSendFilePreviewReloadRevision.ts","../../src/components/document-preview/docx/DocxDocumentPreview.tsx","../../src/components/document-preview/docx/useLocalDocxPreviewSource.ts","../../src/components/document-preview/HtmlDocumentPreview.tsx","../../src/components/document-preview/HtmlPreviewToolbar.tsx","../../src/components/document-preview/MarkdownDocumentPreview.tsx","../../src/components/document-preview/xlsx/useLocalXlsxPreviewSource.ts","../../src/components/document-preview/xlsx/xlsxFormulaFallback.ts","../../src/components/document-preview/xlsx/xlsxNumberFormat.ts","../../src/components/document-preview/xlsx/xlsxWorkbook.ts","../../src/components/document-preview/xlsx/useXlsxSheetParse.ts","../../src/components/document-preview/xlsx/XlsxDocumentPreview.tsx"],"sourcesContent":["/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport type { CliEvent, CliStatus } from '@/stores/chat-types';\nimport type { PptStudioSession } from '../../ppt-studio/ppt-studio-types';\n\n/** Lighten a hex color toward white by ratio (0-1) */\nexport function lighten(hex: string, ratio: number): string {\n const r = Number.parseInt(hex.slice(1, 3), 16);\n const g = Number.parseInt(hex.slice(3, 5), 16);\n const b = Number.parseInt(hex.slice(5, 7), 16);\n const lr = Math.round(r + (255 - r) * ratio);\n const lg = Math.round(g + (255 - g) * ratio);\n const lb = Math.round(b + (255 - b) * ratio);\n return `rgb(${lr}, ${lg}, ${lb})`;\n}\n\nexport const PERMISSION_DENIED_MARKERS = [\n '[PERMISSION_DENIED]',\n '[PERMISSION_REJECTED]',\n '[APPROVAL_REQUIRED]',\n 'PERMISSION_DENIED:',\n '[permission denied]',\n 'command rejected for safety',\n];\n\nexport function isPermissionDeniedResult(detail: string | undefined): boolean {\n if (!detail) return false;\n return PERMISSION_DENIED_MARKERS.some((marker) => detail.includes(marker));\n}\n\nexport function buildSummary(events: CliEvent[], status: CliStatus): string {\n const toolCount = events.filter((e) => e.kind === 'tool_use').length;\n if (status === 'streaming') {\n return '正在执行工具调用';\n }\n if (status === 'interrupted') {\n return '工具调用已停止';\n }\n return `已执行${toolCount}次工具调用`;\n}\n\n/** F142: Find matching tool_result for a tool_use by toolCallId.\n * Falls back to index-based matching when toolCallId is missing. */\nexport function toolRowOutcomeFlags(\n status: CliStatus,\n event: CliEvent,\n resultDetail: string | undefined,\n hasResultMatch: boolean | undefined,\n): {\n shouldRenderMarkdown: boolean;\n showLoading: boolean;\n showError: boolean;\n showCheck: boolean;\n showStopped: boolean;\n} {\n const shouldRenderMarkdown = resultDetail != null;\n const isWaitingForResult = status === 'streaming' && event.kind === 'tool_use' && !hasResultMatch;\n /** Only wait-for-result drives loading — do not OR with \"last tool in this CliOutputBlock\" (isActive): per-task UI\n * splits tools into multiple blocks, so each block's last tool_use often already has a result but was still marked active. */\n const showLoading = isWaitingForResult;\n const showError =\n Boolean(hasResultMatch) &&\n !showLoading &&\n (isPermissionDeniedResult(resultDetail) ||\n Boolean(\n resultDetail &&\n (resultDetail.startsWith('[ERROR]:') ||\n resultDetail.startsWith('Error:') ||\n resultDetail.startsWith('[PERMISSION_REJECTED]')),\n ));\n const showStopped =\n status === 'interrupted' && event.kind === 'tool_use' && !hasResultMatch && !showError;\n const showCheck = Boolean(hasResultMatch) && !showLoading && !showError && !showStopped;\n return { shouldRenderMarkdown, showLoading, showError, showCheck, showStopped };\n}\n\nfunction pickToolResultByCallId(toolUse: CliEvent, toolResults: CliEvent[]): CliEvent | undefined {\n if (!toolUse.toolCallId) return undefined;\n const matches = toolResults.filter((r) => r.toolCallId === toolUse.toolCallId);\n if (matches.length === 0) return undefined;\n return [...matches].reverse().find((r) => (r.detail ?? '').trim().length > 0) ?? matches[matches.length - 1];\n}\n\n/** Match tool_result to tool_use; optional extraToolResults searches other task segments (orphaned results). */\nexport function findMatchingResult(\n toolUse: CliEvent,\n toolResults: CliEvent[],\n index: number,\n extraToolResults?: CliEvent[],\n): CliEvent | undefined {\n if (toolUse.toolCallId) {\n const local = pickToolResultByCallId(toolUse, toolResults);\n if ((local?.detail ?? '').trim().length > 0) return local;\n const remote = extraToolResults ? pickToolResultByCallId(toolUse, extraToolResults) : undefined;\n if ((remote?.detail ?? '').trim().length > 0) return remote;\n return local ?? remote;\n }\n const local = toolResults[index];\n if ((local?.detail ?? '').trim().length > 0) return local;\n const remote = extraToolResults?.[index];\n if ((remote?.detail ?? '').trim().length > 0) return remote;\n return local ?? remote;\n}\n\nexport function resolvePptSessionStoreKey(sessions: Record<string, PptStudioSession>, markerPagesDir: string): string {\n if (sessions[markerPagesDir]) return markerPagesDir;\n const norm = markerPagesDir.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n const hit = Object.keys(sessions).find((k) => {\n const nk = k.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n return nk.endsWith(norm) || norm.endsWith(nk);\n });\n return hit ?? markerPagesDir;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport type { CliEvent, ToolEvent } from '@/stores/chat-types';\n\nimport { findMatchingResult } from './cli-output-block/cli-output-block-helpers';\n\n/** Same pairing as CliOutputBlock.findMatchingResult — keep in sync when changing either. */\nfunction findMatchingToolResult(toolUse: CliEvent, toolResults: CliEvent[], index: number): CliEvent | undefined {\n return findMatchingResult(toolUse, toolResults, index);\n}\n\n/** When the stream is finalized but tool_result never arrived (stop/disconnect), pad so UI sees a paired result. */\nfunction appendSyntheticToolResults(events: CliEvent[]): void {\n const toolUses = events.filter((e) => e.kind === 'tool_use');\n if (toolUses.length === 0) return;\n\n for (let i = 0; i < toolUses.length; i++) {\n const toolResults = events.filter((e) => e.kind === 'tool_result');\n const use = toolUses[i]!;\n if (findMatchingToolResult(use, toolResults, i)) continue;\n events.push({\n id: `pad-tool-result-${use.id}`,\n kind: 'tool_result',\n timestamp: use.timestamp + 1,\n label: '',\n detail: '',\n toolCallId: use.toolCallId,\n });\n }\n}\n\nexport type ToCliEventsOptions = {\n /** When true (non-streaming bubble), append placeholder tool_result rows for unmatched tool_use. */\n padUnmatchedToolResults?: boolean;\n};\n\n/** Strip \"agentId → \" prefix from tool_use labels → clean tool name.\n * e.g. \"opus → Read\" → \"Read\", \"opus → Bash\" → \"Bash\" */\nfunction cleanToolLabel(label: string): string {\n const arrowIdx = label.indexOf(' → ');\n return arrowIdx >= 0 ? label.slice(arrowIdx + 3) : label;\n}\n\nfunction truncateArg(val: string, max = 60): string {\n return val.length > max ? `${val.slice(0, max - 3)}...` : val;\n}\n\n/** Regex patterns for extracting args from truncated JSON (safeJsonPreview truncates at 200 chars) */\nconst ARG_KEYS = [\n 'file_path',\n 'abs_file_path_list',\n 'file_uri',\n 'command',\n 'pattern',\n 'url',\n 'query',\n 'prompt',\n] as const;\n\n/** Extract primary argument from JSON tool input detail for inline display.\n * Handles both valid and truncated JSON (common when safeJsonPreview cuts at 200 chars). */\nfunction extractPrimaryArg(detail?: string): string | undefined {\n if (!detail) return undefined;\n try {\n const obj = JSON.parse(detail) as Record<string, unknown>;\n for (const key of ARG_KEYS) {\n const val = obj[key];\n if (typeof val === 'string' && val.length > 0) return truncateArg(val);\n }\n for (const val of Object.values(obj)) {\n if (typeof val === 'string' && val.length > 0 && val.length <= 80) return truncateArg(val);\n }\n } catch {\n // Truncated JSON — use regex to extract known arg values\n for (const key of ARG_KEYS) {\n const re = new RegExp(`\"${key}\"\\\\s*:\\\\s*\"([^\"]+)\"`);\n const m = detail.match(re);\n if (m?.[1]) return truncateArg(m[1]);\n }\n }\n return undefined;\n}\n\n/** F097: Adapt existing ToolEvent[] + stream content → CliEvent[] unified timeline.\n * Phase A: N tool events + 1 text block. Phase B: backend pushes CliEvent[] directly. */\nexport function toCliEvents(\n toolEvents: ToolEvent[] | undefined,\n streamContent: string | undefined,\n options?: ToCliEventsOptions,\n): CliEvent[] {\n const events: CliEvent[] = [];\n\n if (toolEvents) {\n for (const te of toolEvents) {\n if (te.type === 'tool_use') {\n const toolName = cleanToolLabel(te.label);\n const primaryArg = extractPrimaryArg(te.detail);\n events.push({\n id: te.id,\n kind: te.type,\n timestamp: te.timestamp,\n label: primaryArg ? `${toolName} ${primaryArg}` : toolName,\n detail: te.detail,\n toolCallId: te.toolCallId,\n });\n } else {\n // tool_result: strip \"agentId ← result\" label, keep detail\n events.push({\n id: te.id,\n kind: te.type,\n timestamp: te.timestamp,\n label: te.label,\n detail: te.detail,\n toolCallId: te.toolCallId,\n });\n }\n }\n }\n\n if (options?.padUnmatchedToolResults) {\n appendSyntheticToolResults(events);\n }\n\n if (streamContent?.trim()) {\n events.push({\n id: 'stdout-text',\n kind: 'text',\n timestamp: events.length > 0 ? events[events.length - 1].timestamp + 1 : Date.now(),\n content: streamContent,\n });\n }\n\n return events;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { type ReactNode, type RefObject, useCallback, useState } from 'react';\n\nexport interface PreviewPanelShellProps {\n panelTestId: string;\n title: string;\n /**\n * 传入时全屏使用 `absolute inset-0`,相对于祖先中已设置 `position: relative` 的「会话 + 侧栏」根容器\n * (如 ChatContainer 内层 `flex-1`),避免 `fixed` + `getBoundingClientRect` 在缩放下的偏差。\n * 省略时全屏为视口级 `fixed inset-0`。\n */\n fullScreenContainerRef?: RefObject<HTMLDivElement | null>;\n /** 关闭时先退出全屏,再调用(例如收起 store 中的预览态) */\n onRequestClose: () => void;\n onOpenFolder?: () => void;\n folderButtonTitle?: string;\n /** 自定义header按钮区域,放在全屏/关闭按钮之前 */\n headerActions?: ReactNode;\n /**\n * 插入到 header 右侧按钮组最左侧的自定义内容(不影响现有使用方)。\n * 用于在小屏时插入文件切换下拉按钮等自定义控件。\n */\n extraHeaderContent?: ReactNode;\n /**\n * 隐藏 shell 自带的左侧边框(当外层已有 ResizeHandle 提供分割线时使用,避免双边框)。\n */\n hideBorderLeft?: boolean;\n /** 仅展示标题与 extraHeaderContent,不渲染文件夹 / 全屏 / 关闭(由外层顶栏承担时) */\n hideHeaderActions?: boolean;\n /** 受控全屏;与 onFullScreenChange 同时传入时由内层与外层同步 */\n fullScreen?: boolean;\n onFullScreenChange?: (next: boolean) => void;\n /** 替换默认 `<h2>` 标题(如窄屏下整块标题区可点击下拉) */\n titleContent?: ReactNode;\n children: ReactNode;\n}\n\nexport function PreviewPanelShell({\n panelTestId,\n title,\n fullScreenContainerRef,\n onRequestClose,\n onOpenFolder,\n folderButtonTitle = '打开所在文件夹',\n headerActions,\n extraHeaderContent,\n hideBorderLeft = false,\n hideHeaderActions = false,\n fullScreen: fullScreenControlled,\n onFullScreenChange,\n titleContent,\n children,\n}: PreviewPanelShellProps) {\n const [internalFullScreen, setInternalFullScreen] = useState(false);\n const isControlledFs = fullScreenControlled !== undefined;\n const isFullScreen = isControlledFs ? fullScreenControlled : internalFullScreen;\n const useAnchoredFullScreen = fullScreenContainerRef != null;\n\n const setFullScreen = useCallback(\n (next: boolean) => {\n onFullScreenChange?.(next);\n if (!isControlledFs) setInternalFullScreen(next);\n },\n [isControlledFs, onFullScreenChange],\n );\n\n const handleToggleFullScreen = useCallback(() => {\n setFullScreen(!isFullScreen);\n }, [isFullScreen, setFullScreen]);\n\n const handleClose = useCallback(() => {\n setFullScreen(false);\n onRequestClose();\n }, [onRequestClose, setFullScreen]);\n\n return (\n <section\n data-testid={panelTestId}\n className={`flex min-h-0 flex-col ${\n isFullScreen\n ? useAnchoredFullScreen\n ? 'absolute inset-0 z-[100] min-h-0 overflow-hidden'\n : 'fixed inset-0 z-[100] h-screen w-screen min-h-0 overflow-hidden'\n : `h-full min-h-0 w-full min-w-0${hideBorderLeft ? '' : ' border-l border-gray-200'}`\n } bg-white shadow-xl`}\n >\n <header className=\"flex h-[52px] shrink-0 items-center justify-between border-b border-[#F0F0F0] bg-white px-5\">\n {titleContent != null ? (\n <div className=\"mr-3 min-h-0 min-w-0 flex-1\">{titleContent}</div>\n ) : (\n <h2 className=\"mr-3 min-w-0 flex-1 truncate text-[14px] font-semibold leading-5 text-[#1F1F1F]\" title={title}>\n {title}\n </h2>\n )}\n <div className=\"flex shrink-0 items-center gap-1 text-[#191919]\">\n {extraHeaderContent ?? null}\n {headerActions}\n {hideHeaderActions ? null : (\n <>\n {onOpenFolder ? (\n <button\n type=\"button\"\n onClick={() => {\n void onOpenFolder();\n }}\n className=\"flex size-8 items-center justify-center rounded-md transition-colors hover:bg-[#F5F5F7]\"\n title={folderButtonTitle}\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 16.2673 16.2673\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden\n >\n <title>{folderButtonTitle}</title>\n <path\n fill=\"currentColor\"\n fillRule=\"nonzero\"\n transform=\"matrix(0.999858 0.0168466 -0.0168466 0.999858 1.66809 2.20746)\"\n d=\"M3.81828 0C3.98772 0 4.1517 0.0599236 4.28122 0.169172L6.478 2.022L11.4008 2.0227C12.2302 2.0227 12.9112 2.65767 12.9843 3.46798L12.9908 3.6127L12.9907 4.216L13.6391 4.21663L13.7626 4.22557C14.0338 4.27753 14.2115 4.53952 14.1596 4.81073L13.0108 10.8057C12.9993 10.8661 12.9773 10.9218 12.9471 10.9714C12.6555 11.5117 12.0462 11.8345 11.4008 11.8345L2.68082 11.8345C1.20085 11.8343 0.00106351 10.6346 0.000718276 9.15453L0 1.58991C0 0.711781 0.711863 0 1.59 0L3.81828 0ZM13.0633 5.216L3.152 5.216L2.0962 10.7299C2.2783 10.7975 2.47529 10.8344 2.6809 10.8345L11.4008 10.8345C11.668 10.8345 11.8887 10.7435 12.0063 10.5974L13.0633 5.216ZM3.715 1L1.59 1C1.29671 1 1.05344 1.21391 1.00772 1.49418L1 1.58986L1.00072 9.15436C1.00079 9.45657 1.08064 9.74015 1.22034 9.98516L2.24806 4.62254C2.25354 4.59396 2.26135 4.56642 2.27125 4.54007C2.27663 4.52849 2.29689 4.4827 2.30313 4.47161C2.31207 4.45959 2.35474 4.39649 2.36486 4.38508C2.37554 4.37663 2.45096 4.30775 2.46224 4.30024C2.53624 4.25649 2.64651 4.21663 2.73913 4.21663L11.9907 4.216L11.9908 3.6127C11.9908 3.28686 11.7267 3.0227 11.4008 3.0227L6.37559 3.0227C6.20615 3.0227 6.04217 2.96278 5.91265 2.85353L3.715 1Z\"\n />\n </svg>\n </button>\n ) : null}\n\n <button\n type=\"button\"\n onClick={handleToggleFullScreen}\n className=\"flex size-8 items-center justify-center rounded-md transition-colors hover:bg-[#F5F5F7]\"\n title={isFullScreen ? '退出全屏' : '全屏预览'}\n >\n {isFullScreen ? (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden\n >\n <title>退出全屏</title>\n <path\n fill=\"currentColor\"\n fillRule=\"nonzero\"\n d=\"M5.96105 8.53895C6.78948 8.53895 7.46105 9.21052 7.46105 10.0389L7.46105 13.5C7.46105 13.7761 7.23719 14 6.96105 14C6.68491 14 6.46105 13.7761 6.46105 13.5L6.46067 10.2453L3.15939 13.5477C2.96413 13.743 2.64755 13.743 2.45228 13.5477C2.25702 13.3525 2.25702 13.0359 2.45228 12.8406L5.754 9.53867L2.5 9.53895C2.24687 9.53895 2.03767 9.35085 2.00456 9.1068L2 9.03895C2 8.76281 2.22386 8.53895 2.5 8.53895L5.96105 8.53895ZM9.03895 2C9.31509 2 9.53895 2.22386 9.53895 2.5L9.53867 5.754L12.8406 2.45228C13.0359 2.25702 13.3525 2.25702 13.5477 2.45228C13.743 2.64755 13.743 2.96413 13.5477 3.15939L10.2453 6.46067L13.5 6.46105C13.7531 6.46105 13.9623 6.64915 13.9954 6.8932L14 6.96105C14 7.23719 13.7761 7.46105 13.5 7.46105L10.0389 7.46105C9.21052 7.46105 8.53895 6.78948 8.53895 5.96105L8.53895 2.5C8.53895 2.22386 8.76281 2 9.03895 2Z\"\n />\n </svg>\n ) : (\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden\n >\n <title>全屏预览</title>\n <path\n fill=\"currentColor\"\n fillRule=\"nonzero\"\n d=\"M2.5 8.53895C2.77614 8.53895 3 8.76281 3 9.03895L3 12.292L6.30166 8.99123C6.49692 8.79597 6.8135 8.79597 7.00877 8.99123C7.20403 9.1865 7.20403 9.50308 7.00877 9.69834L3.70667 13L6.96105 13C7.21418 13 7.42338 13.1881 7.45649 13.4322L7.46105 13.5C7.46105 13.7761 7.23719 14 6.96105 14L3.5 14C2.67157 14 2 13.3284 2 12.5L2 9.03895C2 8.76281 2.22386 8.53895 2.5 8.53895ZM12.5 2C13.3284 2 14 2.67157 14 3.5L14 6.96105C14 7.23719 13.7761 7.46105 13.5 7.46105C13.2239 7.46105 13 7.23719 13 6.96105L13 3.70667L9.69834 7.00877C9.50308 7.20403 9.1865 7.20403 8.99123 7.00877C8.79597 6.8135 8.79597 6.49692 8.99123 6.30166L12.2927 2.99933L9.03895 3C8.78582 3 8.57662 2.8119 8.54351 2.56785L8.53895 2.5C8.53895 2.22386 8.76281 2 9.03895 2L12.5 2Z\"\n />\n </svg>\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={handleClose}\n className=\"flex size-8 items-center justify-center rounded-md transition-colors hover:bg-[#F5F5F7]\"\n title=\"关闭预览\"\n aria-label=\"关闭预览\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n <title>关闭</title>\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n </>\n )}\n </div>\n </header>\n\n {children}\n </section>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport type { ReactNode } from 'react';\nimport { useCallback } from 'react';\nimport { useToastStore } from '@/stores/toastStore';\n\n/** 嵌入预览顶部工具条(与 Html 三按钮同行视觉一致) */\nexport const PREVIEW_TOOLBAR_ROW_CLASS =\n 'flex shrink-0 items-center justify-end gap-0.5 border-b border-[#F0F0F0] bg-white px-1 pb-2 pt-0';\n\nexport function PreviewToolbarIconButton({\n title,\n 'aria-label': ariaLabel,\n onClick,\n children,\n}: {\n title: string;\n 'aria-label'?: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex size-8 shrink-0 items-center justify-center rounded-md text-[#434343] transition-colors hover:bg-[#F5F5F7]\"\n title={title}\n aria-label={ariaLabel ?? title}\n >\n {children}\n </button>\n );\n}\n\nexport function CopyDocumentIcon({ className = 'size-[18px]' }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" aria-hidden>\n <title>复制</title>\n <path\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n </svg>\n );\n}\n\nexport interface PreviewCopyButtonProps {\n text: string;\n /** toast 明细前缀,例如「HTML」「Markdown」「代码」 */\n copyKindLabel?: string;\n /** 覆盖默认矢量复制图标 */\n icon?: ReactNode;\n}\n\n/**\n * 纯文本类预览共用的复制按钮(样式与 Html 预览条中的复制一致)\n */\nexport function PreviewCopyButton({ text, copyKindLabel = '源代码', icon }: PreviewCopyButtonProps) {\n const addToast = useToastStore((s) => s.addToast);\n\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(text);\n addToast({\n type: 'success',\n title: '已复制',\n message: `${copyKindLabel}已复制到剪贴板`,\n duration: 2200,\n });\n } catch {\n addToast({ type: 'error', title: '复制失败', message: '无法访问剪贴板', duration: 3500 });\n }\n }, [addToast, copyKindLabel, text]);\n\n return (\n <PreviewToolbarIconButton title={`复制${copyKindLabel}`} onClick={handleCopy}>\n {icon ?? <CopyDocumentIcon />}\n </PreviewToolbarIconButton>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useEffect, useState } from 'react';\nimport { apiFetch } from '@/utils/api-client';\n\nexport type EmbeddedTextPreviewLoadState =\n | { status: 'idle' }\n | { status: 'loading' }\n | { status: 'ok'; content: string }\n | { status: 'error'; message: string };\n\ntype ReadResponse = { error?: string; content?: string };\n\nconst INSPIRATION_PRODUCT_API_PREFIX = '/api/inspiration/products/';\n\nfunction isInspirationProductApiPath(path: string): boolean {\n return path.startsWith(INSPIRATION_PRODUCT_API_PREFIX);\n}\n\nasync function fetchApiPreviewText(\n path: string,\n signal: AbortSignal,\n): Promise<{ ok: true; content: string } | { ok: false; message: string }> {\n const res = await apiFetch(path, { signal });\n if (!res.ok) {\n return { ok: false, message: `HTTP ${res.status}` };\n }\n return { ok: true, content: await res.text() };\n}\n\nasync function fetchLocalPreviewText(\n path: string,\n projectPath: string | undefined,\n signal: AbortSignal,\n): Promise<{ ok: true; content: string } | { ok: false; message: string }> {\n const res = await apiFetch('/api/projects/read-local-text', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n path,\n ...(projectPath && projectPath !== 'default' ? { projectPath } : {}),\n }),\n signal,\n });\n const body = (await res.json().catch(() => null)) as ReadResponse | null;\n if (!res.ok) {\n return { ok: false, message: body?.error ?? `HTTP ${res.status}` };\n }\n if (typeof body?.content !== 'string') {\n return { ok: false, message: 'Invalid response' };\n }\n return { ok: true, content: body.content };\n}\n\n/** UTF-8 bodies from `POST /api/projects/read-local-text` (Markdown / HTML / txt, …). */\nexport function useEmbeddedTextPreviewSource(\n resolvedPath: string | null,\n projectPath?: string | null,\n reloadRevision = 0,\n /** 用户点击「刷新」等触发的递增键,便于重新请求磁盘正文 */\n refreshNonce = 0,\n): EmbeddedTextPreviewLoadState {\n const [state, setState] = useState<EmbeddedTextPreviewLoadState>({ status: 'idle' });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: reloadRevision / refreshNonce 需触发重新读取磁盘\n useEffect(() => {\n if (!resolvedPath?.trim()) {\n setState({ status: 'idle' });\n return;\n }\n const path = resolvedPath.trim();\n const ac = new AbortController();\n setState({ status: 'loading' });\n\n const load = isInspirationProductApiPath(path)\n ? fetchApiPreviewText(path, ac.signal)\n : fetchLocalPreviewText(path, projectPath ?? undefined, ac.signal);\n\n void load\n .then((result) => {\n if (ac.signal.aborted) return;\n if (!result.ok) {\n setState({ status: 'error', message: result.message });\n return;\n }\n setState({ status: 'ok', content: result.content });\n })\n .catch((e: unknown) => {\n if (ac.signal.aborted) return;\n setState({ status: 'error', message: e instanceof Error ? e.message : 'Request failed' });\n });\n\n return () => ac.abort();\n }, [resolvedPath, projectPath, reloadRevision, refreshNonce]);\n\n return state;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useMemo } from 'react';\nimport { countSendFileToUserHitsForResolvedPreviewPath } from '@/components/cli-output/local-generated-files';\nimport { toCliEvents } from '@/components/cli-output/toCliEvents';\nimport type { ChatMessage, CliEvent } from '@/stores/chat-types';\nimport { useChatStore } from '@/stores/chatStore';\n\nconst EMPTY_MESSAGES: readonly ChatMessage[] = [];\n\n/** CLI timeline preserved in message order — matches chat bubble sequence. */\nexport function chronologicalCliEventsFromMessages(messages: readonly ChatMessage[]): CliEvent[] {\n const events: CliEvent[] = [];\n for (const m of messages) {\n if (!m.toolEvents?.length) continue;\n events.push(...toCliEvents(m.toolEvents, undefined, { padUnmatchedToolResults: true }));\n }\n return events;\n}\n\n/** When the assistant calls `send_file_to_user` for the previewed path again, this count increases so embedded fetch hooks can reload. */\nexport function useSendFilePreviewReloadRevision(threadId: string, resolvedPreviewPath: string | null | undefined): number {\n const messages = useChatStore((s) => {\n if (threadId === s.currentThreadId) return s.messages;\n return s.threadStates[threadId]?.messages ?? EMPTY_MESSAGES;\n });\n\n return useMemo(() => {\n if (!resolvedPreviewPath?.trim()) return 0;\n const cli = chronologicalCliEventsFromMessages(messages);\n return countSendFileToUserHitsForResolvedPreviewPath(cli, resolvedPreviewPath.trim());\n }, [messages, resolvedPreviewPath]);\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\nfunction base64ToDocxBlob(b64: string): Blob {\n const bin = atob(b64);\n const len = bin.length;\n const u8 = new Uint8Array(len);\n for (let i = 0; i < len; i++) u8[i] = bin.charCodeAt(i);\n return new Blob([u8], {\n type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n });\n}\n\n/** Renders .docx via [docx-preview](https://github.com/VolodymyrBaydalka/docxjs); general preview, not PPT Studio. */\nexport function DocxDocumentPreview({ contentBase64, title }: { contentBase64: string; title: string }) {\n const bodyRef = useRef<HTMLDivElement>(null);\n const styleHostRef = useRef<HTMLDivElement>(null);\n const [renderError, setRenderError] = useState<string | null>(null);\n\n useEffect(() => {\n const body = bodyRef.current;\n const styleHost = styleHostRef.current;\n if (!body || !styleHost || !contentBase64) return undefined;\n\n let cancelled = false;\n setRenderError(null);\n body.replaceChildren();\n styleHost.replaceChildren();\n\n void (async () => {\n try {\n const { renderAsync } = await import('docx-preview');\n if (cancelled) return;\n const blob = base64ToDocxBlob(contentBase64);\n await renderAsync(blob, body, styleHost, {\n className: 'docx-oc-preview',\n inWrapper: true,\n breakPages: true,\n renderFootnotes: true,\n renderEndnotes: true,\n renderHeaders: true,\n renderFooters: true,\n });\n } catch (e) {\n if (!cancelled) setRenderError(e instanceof Error ? e.message : 'Word 预览失败');\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [contentBase64]);\n\n if (renderError) {\n return (\n <div className=\"flex flex-1 items-center justify-center p-6 text-sm text-red-600\" role=\"alert\">\n {renderError}\n </div>\n );\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col gap-2\" aria-label={title}>\n <div ref={styleHostRef} className=\"docx-oc-styles flex-shrink-0\" />\n <div ref={bodyRef} className=\"docx-oc-body min-h-0 flex-1 overflow-auto\" />\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, useState } from 'react';\nimport { apiFetch } from '@/utils/api-client';\n\nexport type DocxPreviewLoadState =\n | { status: 'idle' }\n | { status: 'loading' }\n | { status: 'ok'; contentBase64: string }\n | { status: 'error'; message: string };\n\ntype ReadResponse = { error?: string; message?: string; contentBase64?: string };\n\nfunction messageForFailedBinaryPreview(res: Response, body: ReadResponse | null): string {\n const err = body?.error ?? `HTTP ${res.status}`;\n if (\n res.status === 404 &&\n (err === 'Not Found' || /route .+ not found/i.test(String(body?.message ?? '')))\n ) {\n return '预览服务未就绪:后端未注册文档预览接口。请重启 API(pnpm dev / pnpm start)后再试。';\n }\n return err;\n}\n\nasync function fetchLocalDocxBase64(\n path: string,\n projectPath: string | undefined,\n signal: AbortSignal,\n): Promise<{ ok: true; contentBase64: string } | { ok: false; message: string }> {\n const res = await apiFetch('/api/projects/read-local-binary-preview', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n path,\n ...(projectPath && projectPath !== 'default' ? { projectPath } : {}),\n }),\n signal,\n });\n const body = (await res.json().catch(() => null)) as ReadResponse | null;\n if (!res.ok) {\n return { ok: false, message: messageForFailedBinaryPreview(res, body) };\n }\n if (typeof body?.contentBase64 !== 'string' || !body.contentBase64.length) {\n return { ok: false, message: 'Invalid response' };\n }\n return { ok: true, contentBase64: body.contentBase64 };\n}\n\n/** Loads .docx bytes (base64) from `POST /api/projects/read-local-binary-preview` for docx-preview. */\nexport function useLocalDocxPreviewSource(\n resolvedPath: string | null,\n projectPath?: string | null,\n reloadRevision = 0,\n): DocxPreviewLoadState {\n const [state, setState] = useState<DocxPreviewLoadState>({ status: 'idle' });\n\n useEffect(() => {\n if (!resolvedPath?.trim()) {\n setState({ status: 'idle' });\n return;\n }\n const path = resolvedPath.trim();\n const ac = new AbortController();\n setState({ status: 'loading' });\n\n void fetchLocalDocxBase64(path, projectPath ?? undefined, ac.signal)\n .then((result) => {\n if (ac.signal.aborted) return;\n if (!result.ok) {\n setState({ status: 'error', message: result.message });\n return;\n }\n setState({ status: 'ok', contentBase64: result.contentBase64 });\n })\n .catch((e: unknown) => {\n if (ac.signal.aborted) return;\n setState({ status: 'error', message: e instanceof Error ? e.message : 'Request failed' });\n });\n\n return () => ac.abort();\n }, [resolvedPath, projectPath, reloadRevision]);\n\n return state;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\n/**\n * Renders a **single** HTML file from disk in an isolated frame (general preview, not PPT Studio).\n * `sandbox=\"\"` disables scripts/navigation to the parent app; inline CSS still applies.\n */\nexport function HtmlDocumentPreview({ html, title }: { html: string; title: string }) {\n return (\n <iframe\n title={title}\n className=\"box-border h-full min-h-[20rem] w-full flex-1 rounded-md border border-[var(--border-default)] bg-[var(--surface-neutral-white,#fff)]\"\n referrerPolicy=\"no-referrer\"\n sandbox=\"allow-scripts\"\n srcDoc={html}\n />\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useCallback } from 'react';\nimport {\n PREVIEW_TOOLBAR_ROW_CLASS,\n PreviewCopyButton,\n PreviewToolbarIconButton,\n} from '@/components/document-preview/PreviewToolbarShared';\nimport { useToastStore } from '@/stores/toastStore';\nimport { apiFetch } from '@/utils/api-client';\n\nexport interface HtmlPreviewToolbarProps {\n html: string;\n filePath: string;\n projectPath?: string;\n onRefresh: () => void;\n}\n\n/** 与用户提供的预览条图标一致(.svg,内嵌位图) */\nconst HTML_PREVIEW_TOOLBAR_ICONS = {\n copy: '/images/html-preview-toolbar/copy.svg',\n refresh: '/images/html-preview-toolbar/refresh.svg',\n openExternal: '/images/html-preview-toolbar/open-external.svg',\n} as const;\n\nfunction HtmlPreviewToolbarRasterIcon({ src }: { src: string }) {\n return (\n <img\n src={src}\n alt=\"\"\n width={18}\n height={18}\n className=\"size-[18px] shrink-0 object-contain select-none\"\n draggable={false}\n />\n );\n}\n\n/** 用于 PreviewPanelShell.extraHeaderContent:与标题同行,无单独底边 */\nexport function HtmlPreviewToolbarActions({ html, filePath, projectPath, onRefresh }: HtmlPreviewToolbarProps) {\n const addToast = useToastStore((s) => s.addToast);\n\n const handleOpenExternal = useCallback(async () => {\n try {\n const res = await apiFetch('/api/projects/open-local', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n path: filePath,\n ...(projectPath && projectPath !== 'default' ? { projectPath } : {}),\n }),\n });\n if (!res.ok) {\n const body = (await res.json().catch(() => null)) as { error?: string } | null;\n addToast({ type: 'error', title: '打开失败', message: body?.error ?? `HTTP ${res.status}`, duration: 3500 });\n return;\n }\n addToast({ type: 'success', title: '已打开', message: '已在默认程序中打开', duration: 2200 });\n } catch (e) {\n addToast({\n type: 'error',\n title: '打开失败',\n message: e instanceof Error ? e.message : '请求失败',\n duration: 3500,\n });\n }\n }, [addToast, filePath, projectPath]);\n\n return (\n <>\n <PreviewCopyButton\n text={html}\n copyKindLabel=\"HTML\"\n icon={<HtmlPreviewToolbarRasterIcon src={HTML_PREVIEW_TOOLBAR_ICONS.copy} />}\n />\n <PreviewToolbarIconButton title=\"刷新\" onClick={onRefresh}>\n <HtmlPreviewToolbarRasterIcon src={HTML_PREVIEW_TOOLBAR_ICONS.refresh} />\n </PreviewToolbarIconButton>\n <PreviewToolbarIconButton title=\"在默认程序中打开\" onClick={handleOpenExternal}>\n <HtmlPreviewToolbarRasterIcon src={HTML_PREVIEW_TOOLBAR_ICONS.openExternal} />\n </PreviewToolbarIconButton>\n </>\n );\n}\n\n/** 内容区内独立一行工具条(含底部分割线) */\nexport function HtmlPreviewToolbar(props: HtmlPreviewToolbarProps) {\n return (\n <div className={PREVIEW_TOOLBAR_ROW_CLASS}>\n <HtmlPreviewToolbarActions {...props} />\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 ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkBreaks from 'remark-breaks';\nimport remarkGfm from 'remark-gfm';\n\nconst DOC_COMPONENTS = {\n a: ({ href, children, ...props }) => (\n <a href={href} target=\"_blank\" rel=\"noopener noreferrer\" {...props}>\n {children}\n </a>\n ),\n} satisfies Components;\n\nexport function MarkdownDocumentPreview({ source, className }: { source: string; className?: string }) {\n return (\n <div\n className={`markdown-content prose prose-base max-w-none font-sans break-words leading-relaxed ${className ?? ''}`}\n >\n <ReactMarkdown remarkPlugins={[[remarkGfm, { singleTilde: false }], remarkBreaks]} components={DOC_COMPONENTS}>\n {source}\n </ReactMarkdown>\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, useState } from 'react';\nimport { apiFetch } from '@/utils/api-client';\n\nexport type XlsxPreviewLoadState =\n | { status: 'idle' }\n | { status: 'loading' }\n | { status: 'ok'; contentBase64: string }\n | { status: 'error'; message: string };\n\ntype ReadResponse = { error?: string; message?: string; contentBase64?: string };\n\nfunction messageForFailedBinaryPreview(res: Response, body: ReadResponse | null): string {\n const err = body?.error ?? `HTTP ${res.status}`;\n if (\n res.status === 404 &&\n (err === 'Not Found' || /route .+ not found/i.test(String(body?.message ?? '')))\n ) {\n return '预览服务未就绪:后端未注册文档预览接口。请重启 API(pnpm dev / pnpm start)后再试。';\n }\n return err;\n}\n\nasync function fetchLocalXlsxBase64(\n path: string,\n projectPath: string | undefined,\n signal: AbortSignal,\n): Promise<{ ok: true; contentBase64: string } | { ok: false; message: string }> {\n const res = await apiFetch('/api/projects/read-local-binary-preview', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n path,\n ...(projectPath && projectPath !== 'default' ? { projectPath } : {}),\n }),\n signal,\n });\n const body = (await res.json().catch(() => null)) as ReadResponse | null;\n if (!res.ok) {\n return { ok: false, message: messageForFailedBinaryPreview(res, body) };\n }\n if (typeof body?.contentBase64 !== 'string' || !body.contentBase64.length) {\n return { ok: false, message: 'Invalid response' };\n }\n return { ok: true, contentBase64: body.contentBase64 };\n}\n\n/** Loads .xlsx/.xls/.csv bytes (base64) from `POST /api/projects/read-local-binary-preview` for ExcelJS / CSV preview. */\nexport function useLocalXlsxPreviewSource(\n resolvedPath: string | null,\n projectPath?: string | null,\n reloadRevision = 0,\n): XlsxPreviewLoadState {\n const [state, setState] = useState<XlsxPreviewLoadState>({ status: 'idle' });\n\n useEffect(() => {\n if (!resolvedPath?.trim()) {\n setState({ status: 'idle' });\n return;\n }\n const path = resolvedPath.trim();\n const ac = new AbortController();\n setState({ status: 'loading' });\n\n void fetchLocalXlsxBase64(path, projectPath ?? undefined, ac.signal)\n .then((result) => {\n if (ac.signal.aborted) return;\n if (!result.ok) {\n setState({ status: 'error', message: result.message });\n return;\n }\n setState({ status: 'ok', contentBase64: result.contentBase64 });\n })\n .catch((e: unknown) => {\n if (ac.signal.aborted) return;\n setState({ status: 'error', message: e instanceof Error ? e.message : 'Request failed' });\n });\n\n return () => ac.abort();\n }, [resolvedPath, projectPath, reloadRevision]);\n\n return state;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n * ExcelJS does not evaluate formulas; cached values must exist in the file (see\n * https://github.com/exceljs/exceljs#formula-value ). When `<v>` is missing, this\n * module performs a **narrow, heuristic** multi-pass resolve for common spreadsheet\n * patterns (SUM, IF, binary ops, simple refs) using already-known numeric cells.\n */\n\nimport type { Cell, Worksheet } from 'exceljs';\n\nconst MAX_PASS = (rows: number, cols: number) => Math.max(64, rows * cols * 2);\n\nexport function colLettersToIndex(letters: string): number {\n let n = 0;\n const u = letters.toUpperCase();\n for (let i = 0; i < u.length; i += 1) {\n n = n * 26 + (u.charCodeAt(i) - 64);\n }\n return n;\n}\n\nfunction cellKey(row: number, col: number): string {\n return `${row}:${col}`;\n}\n\nfunction getFromCache(cache: Map<string, number>, colLetters: string, row: number): number | undefined {\n const col = colLettersToIndex(colLetters);\n return cache.get(cellKey(row, col));\n}\n\n/** Strip formula and whitespace for pattern matching. */\nfunction normalizeFormulaInput(formula: string): string {\n return formula.replace(/^=/u, '').replace(/\\s+/gu, '');\n}\n\nfunction seedNumericFromCell(cell: Cell): number | undefined {\n const v = cell.value;\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (!v || typeof v !== 'object') return undefined;\n if (!('formula' in v) && !('sharedFormula' in v)) return undefined;\n const r = (v as { result?: unknown }).result;\n return typeof r === 'number' && Number.isFinite(r) ? r : undefined;\n}\n\nfunction evalSum(norm: string, cache: Map<string, number>): number | undefined {\n const m = /^SUM\\(([A-Z]+)(\\d+):([A-Z]+)(\\d+)\\)$/iu.exec(norm);\n if (!m) return undefined;\n const c1 = colLettersToIndex(m[1]);\n const r1 = parseInt(m[2], 10);\n const c2 = colLettersToIndex(m[3]);\n const r2 = parseInt(m[4], 10);\n const lowR = Math.min(r1, r2);\n const highR = Math.max(r1, r2);\n const lowC = Math.min(c1, c2);\n const highC = Math.max(c1, c2);\n let sum = 0;\n for (let r = lowR; r <= highR; r += 1) {\n for (let c = lowC; c <= highC; c += 1) {\n const v = cache.get(cellKey(r, c));\n if (v === undefined) return undefined;\n sum += v;\n }\n }\n return sum;\n}\n\nfunction evalIf(norm: string, cache: Map<string, number>, depth: number): number | undefined {\n if (depth > 48) return undefined;\n const m = /^IF\\(([A-Z]+)(\\d+)=0,0,(.+)\\)$/iu.exec(norm);\n if (!m) return undefined;\n const testR = parseInt(m[2], 10);\n const testC = colLettersToIndex(m[1]);\n const testV = cache.get(cellKey(testR, testC));\n if (testV === undefined) return undefined;\n if (testV === 0) return 0;\n return evalArithmetic(m[3], cache, depth + 1);\n}\n\nfunction evalArithmetic(norm: string, cache: Map<string, number>, depth: number): number | undefined {\n if (depth > 48) return undefined;\n\n const ifVal = evalIf(norm, cache, depth);\n if (ifVal != null) return ifVal;\n\n const sumVal = evalSum(norm, cache);\n if (sumVal != null) return sumVal;\n\n const divG = /^\\(([A-Z]+)(\\d+)-([A-Z]+)(\\d+)\\)\\/([A-Z]+)(\\d+)$/iu.exec(norm);\n if (divG) {\n const a = getFromCache(cache, divG[1], parseInt(divG[2], 10));\n const b = getFromCache(cache, divG[3], parseInt(divG[4], 10));\n const c = getFromCache(cache, divG[5], parseInt(divG[6], 10));\n if (a === undefined || b === undefined || c === undefined) return undefined;\n if (c === 0) return 0;\n return (a - b) / c;\n }\n\n const divS = /^([A-Z]+)(\\d+)\\/([A-Z]+)(\\d+)$/iu.exec(norm);\n if (divS) {\n const a = getFromCache(cache, divS[1], parseInt(divS[2], 10));\n const b = getFromCache(cache, divS[3], parseInt(divS[4], 10));\n if (a === undefined || b === undefined) return undefined;\n if (b === 0) return 0;\n return a / b;\n }\n\n const bin = /^([A-Z]+)(\\d+)([+\\-*/])([A-Z]+)(\\d+)$/iu.exec(norm);\n if (bin) {\n const a = getFromCache(cache, bin[1], parseInt(bin[2], 10));\n const b = getFromCache(cache, bin[4], parseInt(bin[5], 10));\n if (a === undefined || b === undefined) return undefined;\n const op = bin[3];\n if (op === '+') return a + b;\n if (op === '-') return a - b;\n if (op === '*') return a * b;\n if (op === '/') return b === 0 ? 0 : a / b;\n }\n\n const single = /^([A-Z]+)(\\d+)$/iu.exec(norm);\n if (single) {\n return getFromCache(cache, single[1], parseInt(single[2], 10));\n }\n\n return undefined;\n}\n\nfunction formulaString(cell: Cell): string | undefined {\n const f = cell.formula;\n return typeof f === 'string' && f.length > 0 ? f : undefined;\n}\n\n/**\n * Fill `cache` with numeric values: literals, stored formula results, then iterative\n * evaluation of supported formula shapes until fixed point.\n */\nexport function buildWorksheetNumericCache(worksheet: Worksheet): Map<string, number> {\n const cache = new Map<string, number>();\n const maxRow = worksheet.actualRowCount;\n const maxCol = worksheet.actualColumnCount;\n if (maxRow === 0 || maxCol === 0) return cache;\n\n for (let r = 1; r <= maxRow; r += 1) {\n for (let c = 1; c <= maxCol; c += 1) {\n const n = seedNumericFromCell(worksheet.getCell(r, c));\n if (n != null) cache.set(cellKey(r, c), n);\n }\n }\n\n const limit = MAX_PASS(maxRow, maxCol);\n for (let pass = 0; pass < limit; pass += 1) {\n let progressed = false;\n for (let r = 1; r <= maxRow; r += 1) {\n for (let c = 1; c <= maxCol; c += 1) {\n const k = cellKey(r, c);\n if (cache.has(k)) continue;\n const cell = worksheet.getCell(r, c);\n const fs = formulaString(cell);\n if (!fs) continue;\n const norm = normalizeFormulaInput(fs);\n const val = evalArithmetic(norm, cache, 0);\n if (val != null && Number.isFinite(val)) {\n cache.set(k, val);\n progressed = true;\n }\n }\n }\n if (!progressed) break;\n }\n\n return cache;\n}\n\n/** When ExcelJS has no cached `result`, try the numeric resolution map. */\nexport function inferFormulaNumeric(cell: Cell, cache: Map<string, number>): number | undefined {\n const fs = formulaString(cell);\n if (!fs) return undefined;\n const norm = normalizeFormulaInput(fs);\n return evalArithmetic(norm, cache, 0);\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n * Best-effort display formatting from Excel `numFmt` + float cleanup (IEEE-754 noise).\n */\n\n/** Strip quoted literals in Excel formats (\"USD\" etc.). */\nfunction stripQuotedChunks(numFmt: string): string {\n return numFmt.replace(/\"[^\"]*\"|'[^']*'/gu, '');\n}\n\nfunction firstPositiveSection(numFmt: string): string {\n const s = stripQuotedChunks(numFmt).trim();\n const semi = s.indexOf(';');\n return semi >= 0 ? s.slice(0, semi) : s;\n}\n\nfunction wantsThousandsSeparator(section: string): boolean {\n return /#,\\s*##|#,##|,##0/u.test(section);\n}\n\n/** Decimal places before `%` in `0.0%`-style formats. */\nfunction percentFractionDigits(section: string): number {\n const beforePct = section.split('%')[0] ?? '';\n const m = /\\.(0+)/u.exec(beforePct);\n if (m) return m[1].length;\n return 0;\n}\n\n/**\n * Fraction digits for non-percent numeric formats (first positive section).\n * No `.` → treated as integer pattern when section looks numeric.\n */\nfunction numberFractionDigits(section: string): number | null {\n if (/%/u.test(section)) return null;\n if (/^\\s*General\\s*$/iu.test(section)) return null;\n if (/[dmyh]([^a-z]|$)|^[\\s]*\\[/iu.test(section)) return null;\n\n const m = /\\.(0+)/u.exec(section);\n if (m) return m[1].length;\n\n if (!/\\./u.test(section) && /[0#]/.test(section)) return 0;\n return null;\n}\n\nfunction snapNearInteger(n: number, eps = 1e-9): number {\n if (!Number.isFinite(n)) return n;\n const r = Math.round(n);\n if (Math.abs(n - r) < eps) return r;\n return n;\n}\n\nfunction roundToDecimalPlaces(n: number, places: number): number {\n if (places <= 0) {\n const r = Math.round(n);\n return Math.abs(n - r) < 1e-12 ? r : Math.round(n + Number.EPSILON * Math.sign(n));\n }\n const p = 10 ** places;\n return Math.round((n + Number.EPSILON * Math.sign(n)) * p) / p;\n}\n\nfunction formatGeneral(n: number): string {\n let x = snapNearInteger(n, 1e-7);\n if (Math.abs(x - Math.round(x)) < 1e-7) return String(Math.round(x));\n x = Number.parseFloat(x.toPrecision(12));\n return String(x);\n}\n\n/**\n * Format a numeric cell for grid display (aligned with `numFmt` when parsable).\n */\nexport function formatNumericForDisplay(value: number, numFmt: string | undefined): string {\n if (!Number.isFinite(value)) return String(value);\n\n const raw = (numFmt ?? '').trim();\n if (!raw || /^General$/iu.test(raw)) {\n return formatGeneral(value);\n }\n\n const section = firstPositiveSection(raw);\n\n if (/%/u.test(section)) {\n const fd = percentFractionDigits(section);\n const pct = roundToDecimalPlaces(value * 100, fd);\n const cleaned = snapNearInteger(pct, 1e-9);\n return `${cleaned}%`;\n }\n\n const fdNum = numberFractionDigits(section);\n if (fdNum != null) {\n let n = roundToDecimalPlaces(value, fdNum);\n n = snapNearInteger(n, fdNum === 0 ? 1e-7 : 1e-9);\n if (wantsThousandsSeparator(section)) {\n return n.toLocaleString('en-US', {\n minimumFractionDigits: fdNum,\n maximumFractionDigits: fdNum,\n useGrouping: true,\n });\n }\n if (fdNum === 0) return String(Math.round(n));\n return n.toFixed(fdNum);\n }\n\n return formatGeneral(value);\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport type { Cell, Fill, Font, Worksheet } from 'exceljs';\nimport { buildWorksheetNumericCache, inferFormulaNumeric } from './xlsxFormulaFallback';\nimport { formatNumericForDisplay } from './xlsxNumberFormat';\n\n/** Inline styles mapped from Excel cell model (via ExcelJS). */\nexport type SheetCellCss = {\n backgroundColor?: string;\n color?: string;\n fontWeight?: string;\n fontStyle?: string;\n textAlign?: 'left' | 'center' | 'right' | 'justify';\n};\n\nexport type SheetCell = {\n text: string;\n style?: SheetCellCss;\n};\n\nexport interface SheetData {\n name: string;\n rows: SheetCell[][];\n /** Column header letters (A, B, C …) derived from the widest row */\n headers: string[];\n}\n\nfunction base64ToUint8Array(b64: string): Uint8Array {\n const bin = atob(b64);\n const u8 = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i);\n return u8;\n}\n\nfunction colIndexToLetter(index: number): string {\n let result = '';\n let n = index;\n while (n >= 0) {\n result = String.fromCharCode((n % 26) + 65) + result;\n n = Math.floor(n / 26) - 1;\n }\n return result;\n}\n\nfunction argbToCss(color: { argb?: string } | string | undefined): string | undefined {\n if (color == null) return undefined;\n const raw = typeof color === 'string' ? color : color.argb;\n if (typeof raw !== 'string' || raw.length < 6) return undefined;\n const rgb = raw.length >= 8 ? raw.slice(2) : raw;\n return `#${rgb}`;\n}\n\nfunction fillToBackground(fill: Fill | undefined): string | undefined {\n if (!fill) return undefined;\n if (fill.type === 'pattern') {\n const fg = argbToCss(fill.fgColor);\n if (fg) return fg;\n return argbToCss(fill.bgColor);\n }\n if (fill.type === 'gradient' && fill.stops.length > 0) {\n return argbToCss(fill.stops[0].color);\n }\n return undefined;\n}\n\nfunction fontToStyle(font: Partial<Font> | undefined): SheetCellCss | undefined {\n if (!font) return undefined;\n const s: SheetCellCss = {};\n if (font.color) {\n const c = argbToCss(font.color as { argb: string });\n if (c) s.color = c;\n }\n if (font.bold) s.fontWeight = 'bold';\n if (font.italic) s.fontStyle = 'italic';\n return Object.keys(s).length ? s : undefined;\n}\n\nfunction cellToStyle(cell: Cell): SheetCellCss | undefined {\n const s: SheetCellCss = {};\n const bg = fillToBackground(cell.fill);\n if (bg) s.backgroundColor = bg;\n const fs = fontToStyle(cell.font);\n if (fs?.color) s.color = fs.color;\n if (fs?.fontWeight) s.fontWeight = fs.fontWeight;\n if (fs?.fontStyle) s.fontStyle = fs.fontStyle;\n const h = cell.alignment?.horizontal;\n if (h === 'center' || h === 'left' || h === 'right' || h === 'justify') {\n s.textAlign = h;\n }\n return Object.keys(s).length ? s : undefined;\n}\n\nfunction errorCellToString(v: unknown): string | null {\n if (v && typeof v === 'object' && 'error' in v) {\n const e = (v as { error: unknown }).error;\n if (typeof e === 'string') return e;\n }\n return null;\n}\n\nfunction richTextToString(v: { richText?: Array<{ text: string }> }): string {\n const rt = v.richText;\n return Array.isArray(rt) ? rt.map((x) => x.text).join('') : '';\n}\n\n/** Display text for grid cells — avoid `String(object)` → `[object Object]` (formulas, errors, shared formulas). */\nfunction normalizedCellText(cell: Cell, numericCache: Map<string, number>): string {\n const t = cell.text;\n if (typeof t === 'string' && t.trim().length > 0) return t;\n\n const v = cell.value as unknown;\n const numFmt = cell.numFmt;\n if (v == null || v === '') return '';\n if (Array.isArray(v)) {\n return v\n .map((x) => {\n if (x == null) return '';\n const err = errorCellToString(x);\n if (err) return err;\n if (typeof x === 'number') return formatNumericForDisplay(x, undefined);\n if (typeof x === 'string' || typeof x === 'boolean') return String(x);\n if (x instanceof Date) return x.toLocaleString();\n if (typeof x === 'object' && x !== null && 'richText' in x) {\n return richTextToString(x as { richText?: Array<{ text: string }> });\n }\n return '';\n })\n .join(', ');\n }\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n return typeof v === 'number' ? formatNumericForDisplay(v, numFmt) : String(v);\n }\n if (v instanceof Date) return v.toLocaleString();\n\n if (typeof v === 'object' && v !== null) {\n const err = errorCellToString(v);\n if (err) return err;\n\n if ('richText' in v) return richTextToString(v as { richText?: Array<{ text: string }> });\n\n if ('hyperlink' in v) {\n const h = v as { text?: string };\n return typeof h.text === 'string' ? h.text : '';\n }\n\n const asFormula = v as { formula?: string; sharedFormula?: string; result?: unknown };\n if (typeof asFormula.formula === 'string' || typeof asFormula.sharedFormula === 'string') {\n const r = asFormula.result;\n if (r == null || r === '') {\n const inferred = inferFormulaNumeric(cell, numericCache);\n if (inferred != null) return formatNumericForDisplay(inferred, numFmt);\n return typeof asFormula.formula === 'string' ? asFormula.formula : asFormula.sharedFormula ?? '';\n }\n const errR = errorCellToString(r);\n if (errR) return errR;\n if (typeof r === 'string' || typeof r === 'boolean') return String(r);\n if (typeof r === 'number') return formatNumericForDisplay(r, numFmt);\n if (r instanceof Date) return r.toLocaleString();\n if (r && typeof r === 'object' && 'richText' in r) {\n return richTextToString(r as { richText?: Array<{ text: string }> });\n }\n return typeof asFormula.formula === 'string' ? asFormula.formula : asFormula.sharedFormula ?? '';\n }\n\n if ('result' in asFormula) {\n const r = asFormula.result;\n if (r == null || r === '') return '';\n const errR = errorCellToString(r);\n if (errR) return errR;\n if (typeof r === 'string' || typeof r === 'boolean') return String(r);\n if (typeof r === 'number') return formatNumericForDisplay(r, numFmt);\n if (r instanceof Date) return r.toLocaleString();\n }\n }\n\n return '';\n}\n\nfunction excelWorksheetToSheetData(worksheet: Worksheet): SheetData {\n const maxRow = worksheet.actualRowCount;\n const maxCol = worksheet.actualColumnCount;\n if (maxRow === 0 || maxCol === 0) {\n return { name: worksheet.name, rows: [], headers: [] };\n }\n const numericCache = buildWorksheetNumericCache(worksheet);\n const headers = Array.from({ length: maxCol }, (_, i) => colIndexToLetter(i));\n const rows: SheetCell[][] = [];\n for (let r = 1; r <= maxRow; r += 1) {\n const dataRow: SheetCell[] = [];\n for (let c = 1; c <= maxCol; c += 1) {\n const cell = worksheet.getCell(r, c);\n dataRow.push({\n text: normalizedCellText(cell, numericCache),\n style: cellToStyle(cell),\n });\n }\n rows.push(dataRow);\n }\n return { name: worksheet.name, rows, headers };\n}\n\nasync function parseWithExcelJs(data: Uint8Array): Promise<SheetData[]> {\n const ExcelJS = (await import('exceljs')).default;\n const workbook = new ExcelJS.Workbook();\n const buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);\n await workbook.xlsx.load(buffer as never);\n return workbook.worksheets.map((ws) => excelWorksheetToSheetData(ws));\n}\n\n/** RFC4180-style: quoted fields, `\"\"` escape; delimiter `,` or `\\t`. */\nfunction parseDelimitedText(text: string, delimiter: ',' | '\\t'): string[][] {\n const rows: string[][] = [];\n let row: string[] = [];\n let field = '';\n let i = 0;\n let inQuotes = false;\n while (i < text.length) {\n const c = text[i];\n if (inQuotes) {\n if (c === '\"') {\n if (text[i + 1] === '\"') {\n field += '\"';\n i += 2;\n } else {\n inQuotes = false;\n i += 1;\n }\n } else {\n field += c;\n i += 1;\n }\n continue;\n }\n if (c === '\"') {\n inQuotes = true;\n i += 1;\n continue;\n }\n if (c === delimiter) {\n row.push(field);\n field = '';\n i += 1;\n continue;\n }\n if (c === '\\n' || c === '\\r') {\n if (c === '\\r' && text[i + 1] === '\\n') i += 1;\n row.push(field);\n field = '';\n rows.push(row);\n row = [];\n i += 1;\n continue;\n }\n field += c;\n i += 1;\n }\n row.push(field);\n rows.push(row);\n while (rows.length > 0 && rows[rows.length - 1].every((cell) => cell === '')) {\n rows.pop();\n }\n return rows;\n}\n\nfunction sniffDelimiter(text: string): ',' | '\\t' {\n const line = text.split(/\\r?\\n/u).find((l) => l.trim().length > 0) ?? '';\n const tabs = (line.match(/\\t/g) ?? []).length;\n const commas = (line.match(/,/g) ?? []).length;\n return tabs > commas ? '\\t' : ',';\n}\n\nfunction gridToSheetData(name: string, grid: string[][]): SheetData {\n const maxCols = grid.reduce((m, r) => Math.max(m, r.length), 0);\n if (maxCols === 0) {\n return { name, rows: [], headers: [] };\n }\n const headers = Array.from({ length: maxCols }, (_, i) => colIndexToLetter(i));\n const rows: SheetCell[][] = grid.map((r) =>\n headers.map((_, i) => ({ text: r[i] ?? '' })),\n );\n return { name, rows, headers };\n}\n\n/** When bytes are not OOXML (zip), try UTF-8 CSV / TSV (no extra dependency). */\nfunction tryParseUtf8Delimited(data: Uint8Array): SheetData[] | null {\n let text: string;\n try {\n text = new TextDecoder('utf-8', { fatal: true }).decode(data);\n } catch {\n return null;\n }\n if (text.includes('\\0')) return null;\n const stripped = text.replace(/^\\uFEFF/u, '');\n if (!/[\\r\\n]/u.test(stripped)) return null;\n const delim = sniffDelimiter(stripped);\n const grid = parseDelimitedText(stripped, delim);\n if (grid.length === 0) return null;\n return [gridToSheetData('Sheet1', grid)];\n}\n\n/**\n * Parse from base64: **ExcelJS** for `.xlsx` / `.xlsm` (styles via cell fill/font).\n * Fallback: UTF-8 **CSV/TSV** parsed in-app (no styles). Legacy `.xls` (BIFF) is not supported.\n */\nexport async function parseXlsxBase64ToSheets(b64: string): Promise<SheetData[]> {\n const data = base64ToUint8Array(b64);\n try {\n const sheets = await parseWithExcelJs(data);\n if (sheets.length > 0) return sheets;\n } catch {\n // not OOXML\n }\n const delimited = tryParseUtf8Delimited(data);\n if (delimited) return delimited;\n throw new Error(\n '无法预览:请使用 .xlsx / .xlsm,或 UTF-8 编码的 .csv。旧版 .xls 请用 Excel 另存为 .xlsx 后再预览。',\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { useEffect, useState } from 'react';\nimport type { SheetData } from './xlsxWorkbook';\nimport { parseXlsxBase64ToSheets } from './xlsxWorkbook';\n\nexport type XlsxSheetParseState =\n | { status: 'idle' }\n | { status: 'parsing' }\n | { status: 'ok'; sheets: SheetData[] }\n | { status: 'error'; message: string };\n\n/** Runs SheetJS parse when base64 payload is ready (keeps `useEffect` out of the preview UI component). */\nexport function useXlsxSheetParse(contentBase64: string | null | undefined): XlsxSheetParseState {\n const [state, setState] = useState<XlsxSheetParseState>({ status: 'idle' });\n\n useEffect(() => {\n if (!contentBase64?.trim()) {\n setState({ status: 'idle' });\n return;\n }\n const b64 = contentBase64.trim();\n let cancelled = false;\n setState({ status: 'parsing' });\n\n void parseXlsxBase64ToSheets(b64)\n .then((sheets) => {\n if (cancelled) return;\n setState({ status: 'ok', sheets });\n })\n .catch((e: unknown) => {\n if (cancelled) return;\n setState({ status: 'error', message: e instanceof Error ? e.message : 'Excel 预览失败' });\n });\n\n return () => {\n cancelled = true;\n };\n }, [contentBase64]);\n\n return state;\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 type { SheetData } from './xlsxWorkbook';\n\nfunction SheetTable({ sheet }: { sheet: SheetData }) {\n if (sheet.rows.length === 0) {\n return <p className=\"p-4 text-sm text-gray-400\">(空工作表)</p>;\n }\n\n return (\n <div className=\"overflow-auto\">\n <table className=\"xlsx-oc-grid min-w-full border-collapse text-xs\">\n <thead>\n <tr>\n <th className=\"sticky left-0 z-10 w-8 border border-neutral-300 bg-neutral-100 px-2 py-1 text-center text-neutral-500\" />\n {sheet.headers.map((h) => (\n <th\n key={h}\n className=\"min-w-[80px] border border-neutral-300 bg-neutral-100 px-2 py-1 text-center font-medium text-neutral-600\"\n >\n {h}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {sheet.rows.map((row, rowIdx) => (\n // eslint-disable-next-line react/no-array-index-key\n <tr key={rowIdx}>\n <td className=\"sticky left-0 z-10 border border-neutral-300 bg-neutral-50 px-2 py-1 text-center text-neutral-400\">\n {rowIdx + 1}\n </td>\n {sheet.headers.map((_, colIdx) => {\n const cell = row[colIdx] ?? { text: '' };\n return (\n // eslint-disable-next-line react/no-array-index-key\n <td\n key={colIdx}\n className=\"border border-neutral-300 px-2 py-1 text-neutral-900\"\n style={cell.style}\n >\n {cell.text}\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n/** Spreadsheet grid only — parsing lives in `useXlsxSheetParse` (avoids effect compilation issues in this module). */\nexport function XlsxDocumentPreview({ sheets, title }: { sheets: SheetData[]; title: string }) {\n const [activeSheet, setActiveSheet] = useState(0);\n const safeIndex = sheets.length > 0 ? Math.min(activeSheet, sheets.length - 1) : 0;\n const currentSheet = sheets[safeIndex];\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\" aria-label={title}>\n {sheets.length > 1 && (\n <div className=\"flex shrink-0 gap-1 overflow-x-auto border-b border-gray-200 bg-gray-50 px-3 py-1\">\n {sheets.map((s, i) => (\n <button\n key={s.name}\n type=\"button\"\n onClick={() => setActiveSheet(i)}\n className={[\n 'whitespace-nowrap rounded px-3 py-1 text-xs font-medium transition-colors',\n i === safeIndex\n ? 'bg-white text-blue-600 shadow-sm ring-1 ring-gray-200'\n : 'text-gray-500 hover:bg-white hover:text-gray-800',\n ].join(' ')}\n >\n {s.name}\n </button>\n ))}\n </div>\n )}\n <div className=\"min-h-0 flex-1 overflow-auto\">{currentSheet && <SheetTable sheet={currentSheet} />}</div>\n </div>\n );\n}\n"],"file":"assets/XlsxDocumentPreview-BY-ht09K.js"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function r(o){throw new Error('Could not dynamically require "'+o+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}export{r as c};
|
|
2
|
+
//# sourceMappingURL=_commonjs-dynamic-modules-TDtrdbi3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_commonjs-dynamic-modules-TDtrdbi3.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{A as c}from"./OverflowTooltip-CE5PjAb-.js";import{b as a}from"./helpers-CCilgpNy.js";const u=/\{\{file:/,s=/[/\\]+$/,p=/[<>:"/\\|?*\u0000-\u001f]/g;function i(t){return String(t).padStart(2,"0")}function f(t=new Date){return`${t.getFullYear()}${i(t.getMonth()+1)}${i(t.getDate())}${i(t.getHours())}${i(t.getMinutes())}${i(t.getSeconds())}`}function R(t,n=new Date){const e=t.trim().replace(s,"");return e?`${e}/${f(n)}`:""}function d(t){return t.trim().replace(p,"_")||"upload"}function v(t,n){const e=t.trim().replace(s,""),r=d(n);return e?`${e}/upload/${r}`:`upload/${r}`}function D(t){return u.test(t)}function m(t){return t.variantLabel?`@${t.displayName} (${t.variantLabel})`:`@${t.displayName}`}function $(t){var n;return((n=t.roster)==null?void 0:n.available)!==!1}function A(t){return!t.expert&&t.mentionPatterns.length>0&&$(t)}function l(t){const n=t.trim();return n?n.startsWith("/uploads/")?`${c}${n}`:n:""}function b(t){return t.filter(A).map(n=>({id:n.id,label:m(n),desc:n.roleDescription,insert:`${a(n)??""} `,color:n.color.primary,avatar:l(n.avatar)}))}function F(t,n){return[...b(t),...n]}function _(t){return{id:t.expertId,label:`@${t.displayName}`,desc:t.roleDescription,insert:`${a(t)??`@${t.expertId}`} `,color:E(t.category),avatar:l(t.avatar)}}function E(t){return{design:"#FF6B6B",marketing:"#4ECDC4",growth:"#45B7D1",content:"#96CEB4"}[t]??"#7AAEFF"}function L(t,n){const e=t.slice(0,n),r=e.lastIndexOf("@");if(r>=0){const o=e.slice(r+1);if(o.length<=12&&!/\s/.test(o))return{type:"mention",start:r,filter:o}}return null}export{R as a,v as b,_ as c,L as d,F as e,b as f,D as p};
|
|
2
|
+
//# sourceMappingURL=chat-input-options-CpkOtPgQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-input-options-CpkOtPgQ.js","sources":["../../src/utils/inspiration-workspace-path.ts","../../src/components/chat-input/chat-input-options.ts"],"sourcesContent":["/*\n * *\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nconst FILE_PLACEHOLDER_RE = /\\{\\{file:/;\nconst TRAILING_PATH_SEPARATORS_RE = /[/\\\\]+$/;\nconst FORBIDDEN_FILE_NAME_CHARS_RE = /[<>:\"/\\\\|?*\\u0000-\\u001f]/g;\n\nfunction pad2(value: number): string {\n return String(value).padStart(2, '0');\n}\n\nexport function formatInspirationWorkspaceTimestamp(date = new Date()): string {\n return `${date.getFullYear()}${pad2(date.getMonth() + 1)}${pad2(date.getDate())}${pad2(date.getHours())}${pad2(date.getMinutes())}${pad2(date.getSeconds())}`;\n}\n\nexport function buildDefaultInspirationWorkspacePath(workspaceRoot: string, date = new Date()): string {\n const trimmedRoot = workspaceRoot.trim().replace(TRAILING_PATH_SEPARATORS_RE, '');\n if (!trimmedRoot) return '';\n return `${trimmedRoot}/${formatInspirationWorkspaceTimestamp(date)}`;\n}\n\nexport function sanitizeInspirationUploadFileName(fileName: string): string {\n const cleaned = fileName.trim().replace(FORBIDDEN_FILE_NAME_CHARS_RE, '_');\n return cleaned || 'upload';\n}\n\nexport function buildInspirationUploadPath(workspacePath: string, fileName: string): string {\n const trimmedWorkspace = workspacePath.trim().replace(TRAILING_PATH_SEPARATORS_RE, '');\n const sanitizedFileName = sanitizeInspirationUploadFileName(fileName);\n if (!trimmedWorkspace) return `upload/${sanitizedFileName}`;\n return `${trimmedWorkspace}/upload/${sanitizedFileName}`;\n}\n\nexport function promptHasFilePlaceholder(prompt: string): boolean {\n return FILE_PLACEHOLDER_RE.test(prompt);\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport type { AgentData } from '@/hooks/useAgentData';\nimport { API_URL } from '@/utils/api-client';\nimport { buildResolvedMention } from './utils/helpers';\n\nexport interface AgentOption {\n id: string;\n label: string;\n desc: string;\n insert: string;\n color: string; // hex color (for inline style)\n avatar: string;\n}\n\n/** Build @mention autocomplete options from roster data.\n * Filters out agents with no mentionPatterns (not routable via @mention). */\nfunction formatAgentMentionLabel(agent: AgentData): string {\n return agent.variantLabel ? `@${agent.displayName} (${agent.variantLabel})` : `@${agent.displayName}`;\n}\n\nfunction isAvailable(agent: AgentData): boolean {\n return agent.roster?.available !== false;\n}\n\nfunction isGenericMentionAgent(agent: AgentData): boolean {\n return !agent.expert && agent.mentionPatterns.length > 0 && isAvailable(agent);\n}\n\nfunction resolveAgentAvatar(avatar: string): string {\n const trimmed = avatar.trim();\n if (!trimmed) return '';\n return trimmed.startsWith('/uploads/') ? `${API_URL}${trimmed}` : trimmed;\n}\n\nexport function buildAgentOptions(agents: AgentData[]): AgentOption[] {\n return agents\n .filter(isGenericMentionAgent)\n .map((agent) => ({\n id: agent.id,\n label: formatAgentMentionLabel(agent),\n desc: agent.roleDescription,\n insert: `${buildResolvedMention(agent) ?? ''} `,\n color: agent.color.primary,\n avatar: resolveAgentAvatar(agent.avatar),\n }));\n}\n\n/** Build whisper target options from roster data.\n * Includes all agents — whisper routing accepts any agentId regardless of mentionPatterns. */\nexport function buildWhisperOptions(agents: AgentData[]): AgentOption[] {\n return agents.filter((agent) => isAvailable(agent) && !agent.expert).map((agent) => {\n const mention = buildResolvedMention(agent);\n return {\n id: agent.id,\n label: formatAgentMentionLabel(agent),\n desc: agent.roleDescription,\n insert: mention ? `${mention} ` : '',\n color: agent.color.primary,\n avatar: resolveAgentAvatar(agent.avatar),\n };\n });\n}\n\nexport function buildMentionOptions(agents: AgentData[], expertOptions: AgentOption[]): AgentOption[] {\n return [...buildAgentOptions(agents), ...expertOptions];\n}\n\nexport function buildExpertOption(expert: {\n expertId: string;\n displayName: string;\n avatar: string;\n mentionPatterns: string[];\n roleDescription: string;\n category: string;\n}): AgentOption {\n return {\n id: expert.expertId,\n label: `@${expert.displayName}`,\n desc: expert.roleDescription,\n insert: `${buildResolvedMention(expert) ?? `@${expert.expertId}`} `,\n color: getExpertColor(expert.category),\n avatar: resolveAgentAvatar(expert.avatar),\n };\n}\n\nfunction getExpertColor(category: string): string {\n const colors: Record<string, string> = {\n design: '#FF6B6B',\n marketing: '#4ECDC4',\n growth: '#45B7D1',\n content: '#96CEB4',\n };\n return colors[category] ?? '#7AAEFF';\n}\n\n/** Pure detection — returns menu trigger type from current input, or null. */\nexport function detectMenuTrigger(\n val: string,\n selectionStart: number,\n): { type: 'mention'; start: number; filter: string } | null {\n const textBefore = val.slice(0, selectionStart);\n const atIdx = textBefore.lastIndexOf('@');\n if (atIdx >= 0) {\n const fragment = textBefore.slice(atIdx + 1);\n if (fragment.length <= 12 && !/\\s/.test(fragment)) {\n return { type: 'mention', start: atIdx, filter: fragment };\n }\n }\n return null;\n}\n"],"names":["FILE_PLACEHOLDER_RE","TRAILING_PATH_SEPARATORS_RE","FORBIDDEN_FILE_NAME_CHARS_RE","pad2","value","formatInspirationWorkspaceTimestamp","date","buildDefaultInspirationWorkspacePath","workspaceRoot","trimmedRoot","sanitizeInspirationUploadFileName","fileName","buildInspirationUploadPath","workspacePath","trimmedWorkspace","sanitizedFileName","promptHasFilePlaceholder","prompt","formatAgentMentionLabel","agent","isAvailable","_a","isGenericMentionAgent","resolveAgentAvatar","avatar","trimmed","API_URL","buildAgentOptions","agents","buildResolvedMention","buildMentionOptions","expertOptions","buildExpertOption","expert","getExpertColor","category","detectMenuTrigger","val","selectionStart","textBefore","atIdx","fragment"],"mappings":"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"}
|