@nextclaw/ui 0.26.0 → 0.26.1
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/CHANGELOG.md +28 -0
- package/dist/.vite/manifest.json +1143 -1133
- package/dist/assets/{abnfDiagram-VRR7QNED-Bjrmb5-o.js → abnfDiagram-VRR7QNED-Dcw10Yt1.js} +1 -1
- package/dist/assets/{account-panel-C1S3xtUB.js → account-panel-ZM2qzKF4.js} +1 -1
- package/dist/assets/{aiden0z-pptx-renderer.es-DO4DCX3e.js → aiden0z-pptx-renderer.es--oNqetPA.js} +1 -1
- package/dist/assets/api-Cjq-o1VN.js +20 -0
- package/dist/assets/app-presenter-provider-C02YPoMr.js +124 -0
- package/dist/assets/{appearance-settings-page-BljTr6nB.js → appearance-settings-page-B4zouKzg.js} +1 -1
- package/dist/assets/{arc-g4XaP3S4.js → arc-DBRedCax.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-CvnC-LeA.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-CAP7YDux.js → architectureDiagram-ZJ3FMSHR-Dufhtuv-.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-DhaP0zUG.js → blockDiagram-677ZJIJ3-BUk0vtJ7.js} +1 -1
- package/dist/assets/{book-open-vxpV2eSM.js → book-open-AteA89HX.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-DHCQJJkD.js → c4Diagram-LMCZKHZV-CxDcVE9p.js} +1 -1
- package/dist/assets/{card-D9NYhSdf.js → card-BLXvBstA.js} +1 -1
- package/dist/assets/channel-CpMstUPF.js +1 -0
- package/dist/assets/{channels-list-page-BiHA1zZd.js → channels-list-page-fj8kMo-T.js} +1 -1
- package/dist/assets/chunk-2Q5K7J3B-Djp3VF0s.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-BcQlxl4v.js → chunk-32BRIVSS-DSF3KElA.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-ClPpG-2S.js → chunk-52WLFC77-Costxzr3.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-B_qmYOdX.js → chunk-5FCAYU7R-rhqzGGZo.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-DTO-V56q.js → chunk-5HE753X5-BsEsmIao.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CU1SOaaG.js → chunk-5JV3BV7I-Dqw_DCoN.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CzSDkWNa.js → chunk-5TONJI2A-Cft82fp8.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-ChkfqIRE.js → chunk-5VM5RSS4-DqNHn9Dl.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-Du3Ozi62.js → chunk-7BUUIJ7U-A5SBEMYY.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-C-HVafHB.js → chunk-BIQX33UG-1Ng3mTrH.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-BSjZ86D0.js → chunk-C7G6YPKG-DRJEy8ZI.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-1D1W2lF6.js → chunk-CQNSW5MT-Bydv_J3J.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-ISpyj_lK.js → chunk-CYSBUYHQ-HkMIg12u.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-Cp8iUBt2.js → chunk-EMLP6XTP-C5ndDvm3.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-BN5RzF5j.js → chunk-EX3LRPZG-DzeloZRo.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-DecJDW4r.js → chunk-FWX5IMBZ-n_2_CLTQ.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-BE_XNgGk.js → chunk-HOUHSVGY-kx_slvu3.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-BFOKMkWV.js → chunk-ICXQ74PX-sQLMURqL.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DL-pl8VB.js → chunk-JG7HCLWE-CMUn5Elc.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-B-bcwfmh.js → chunk-JWPE2WC7-Cra3s-Uk.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-BC0taFro.js → chunk-MOJQB5TN-umcrg5Bi.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-RrhfU6MO.js → chunk-MOZMSUNE-BnljD1ig.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-TuI7SR7i.js → chunk-OGEWGWER-BXx5pQjU.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-C5jMBKlU.js → chunk-OSBZ3O6U-D-1qfdWu.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-C5lMBn0K.js → chunk-PUDLZKDR-DLzX78LC.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-B-kzUbwT.js → chunk-Q4XR5HBZ-DTK-rtW6.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-CRb_WAEj.js → chunk-QBLGF6JB-CsFeIGfr.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-De6Y7ozO.js → chunk-R7FJI6CG-4xNYUeng.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-Igv92q8k.js → chunk-RYQCIY6F-DJiHiTE5.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-bCjRshkT.js → chunk-U6XO7XAA-BVYkauHz.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-0J1s_Kgq.js → chunk-V7JOEXUC-BsazE8cS.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-BrbiIC1Q.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-DX6lXnNx.js → chunk-VR4S4FIN-7RoZQffO.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-DLqMXfFC.js → chunk-WYO6CB5R-DEuS6N1R.js} +1 -1
- package/dist/assets/chunk-XXDRQBXY-Cx9N40wF.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-CY4obsV0.js → chunk-YOTPTUD7-9KBrosZL.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-BleImZKe.js → chunk-ZGVPDNZ5-IYgN9f5A.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-C1TfdjpX.js → chunk-ZIRB5QZD-BUo0-zcp.js} +1 -1
- package/dist/assets/{circle-dashed-CEEssYIw.js → circle-dashed-LSYZTzM7.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DFN1v3PQ.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-DRvglADa.js +1 -0
- package/dist/assets/{client-C6YQx7A-.js → client-DudCRJw4.js} +1 -1
- package/dist/assets/{config-split-page-DKPelvjR.js → config-split-page-G7Kt2BnV.js} +1 -1
- package/dist/assets/confirm-dialog-DShT64F6.js +1 -0
- package/dist/assets/context-menu-rd7b_kVD.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-CVgUHXkj.js → cose-bilkent-JH36ORCC-DhqbC1fR.js} +1 -1
- package/dist/assets/{createLucideIcon-CF8U9dh7.js → createLucideIcon-D7hvIHV-.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-DXUGnpJH.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-cdfImbfI.js → cynefinDiagram-TSTJHNR4-C-TBRi5V.js} +1 -1
- package/dist/assets/{dagre-CHNN9L9I.js → dagre-CrgsRasE.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-PscaENwr.js → dagre-VKFMJZFB-BmafJymp.js} +1 -1
- package/dist/assets/{desktop-capabilities-page-BENHdKfk.js → desktop-capabilities-page-CzqzFZUY.js} +1 -1
- package/dist/assets/desktop-update-config-CgeQ0Ffo.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-CH_wye41.js → diagram-FQU43EPY-BoOMwa6D.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-Dtjpmi6D.js → diagram-G47NLZAW-Le7N6Uym.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-UdjLHyaz.js → diagram-NH7WQ7WH-Fbpj3-MO.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DYsToEaL.js → diagram-OA4YK3LP-D3QuGGuu.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CA7kuIer.js → diagram-WEI45ONY-Cxu1uiN6.js} +1 -1
- package/dist/assets/dialog-C7glmAQJ.js +5 -0
- package/dist/assets/{doc-browser-context-CPLWVFLd.js → doc-browser-context-BlhBAOLH.js} +1 -1
- package/dist/assets/doc-browser-dBiR9Qi0.js +1 -0
- package/dist/assets/{docx-preview-D--EsUWi.js → docx-preview-CkU2psnd.js} +1 -1
- package/dist/assets/download-BYgECE0n.js +1 -0
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BrjaoOuq.js → ebnfDiagram-CCIWWBDH-CCAjuQM6.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-nZQa2kCM.js → erDiagram-Q63AITRT-BuzUAq-d.js} +1 -1
- package/dist/assets/es2015-CsjAAQ6X.js +41 -0
- package/dist/assets/eventmodeling-45OFAUF4-ZBfVS3ZC.js +1 -0
- package/dist/assets/{extensions-CsWT7x3v.js → extensions-qYL-NpL3.js} +1 -1
- package/dist/assets/{eye-DJtw5KJ5.js → eye-BBuTzJ53.js} +1 -1
- package/dist/assets/flowDiagram-23GEKE2U-CqdsKk6x.js +1 -0
- package/dist/assets/{form-actions-DDQk0END.js → form-actions-CLGWO52v.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-CyFZHIHN.js → ganttDiagram-NO4QXBWP-cJmWVY8F.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-fHYFd9Es.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-Dfpq3z2M.js → gitGraphDiagram-IHSO6WYX-F58o-vtP.js} +1 -1
- package/dist/assets/{i18n-BjPkAKMQ.js → i18n-qBGEbcW6.js} +2 -2
- package/dist/assets/info-DKCQHKI2-CSaOL_bb.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Diiz0k1E.js → infoDiagram-FWYZ7A6U-Gt59b83C.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-B3R3SN4M.js → ishikawaDiagram-FXEZZL3T-1u4IAj1I.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-DFOLKiNv.js → journeyDiagram-5HDEW3XC-CCQsfV-5.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-BMXpDp3g.js → kanban-definition-HUTT4EX6-vlB6O_Zn.js} +1 -1
- package/dist/assets/{keyboard-shortcuts-settings-page-hqTP7akj.js → keyboard-shortcuts-settings-page-B-wK_6zG.js} +1 -1
- package/dist/assets/{line-64_FhCoJ.js → line-D_bHubTL.js} +1 -1
- package/dist/assets/{linear-aF1fg7bK.js → linear-ChlwuS5y.js} +1 -1
- package/dist/assets/loader-circle-BA7EMkih.js +1 -0
- package/dist/assets/{login-page-BUwshAq4.js → login-page-Cd84lpVV.js} +1 -1
- package/dist/assets/login-page-VdMyNkFf.js +1 -0
- package/dist/assets/main-CR0SrTBf.js +2 -0
- package/dist/assets/main-DXH6EdXI.css +1 -0
- package/dist/assets/main-i18n-catalog.config-Btp_OowF.js +1 -0
- package/dist/assets/{map-BC3Amra3.js → map-oGHTsIu8.js} +1 -1
- package/dist/assets/mcp-marketplace-page-jacRwiI-.js +1 -0
- package/dist/assets/{mermaid-parser.core-DdMcZwnE.js → mermaid-parser.core-CuRe1ZG4.js} +2 -2
- package/dist/assets/{mermaid.core-BHdiEBbI.js → mermaid.core-u4YCFKRf.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-CtHVaZyV.js → mindmap-definition-LN4V7U3C-DeJAQYTu.js} +1 -1
- package/dist/assets/{model-config-page-BSsHOhV7.js → model-config-page-D0DQlSDa.js} +1 -1
- package/dist/assets/{navigation-link-D-fxdv0i.js → navigation-link-32iM1-e6.js} +1 -1
- package/dist/assets/{ordinal-6b3jw4cz.js → ordinal-C6JFfkKN.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-D-YFTczs.js +1 -0
- package/dist/assets/panel-app-CC0bVSu4.js +1 -0
- package/dist/assets/panel-app-i18n-catalog.config-LUSBp5Ce.js +1 -0
- package/dist/assets/{panelStandalone-BeI0Ndsx.js → panelStandalone-C9EKaApN.js} +2 -2
- package/dist/assets/{pegDiagram-2B236MQR-BtbG3Bgu.js → pegDiagram-2B236MQR-nVMkxShH.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-VEnYu9s5.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-FmLl2hzN.js → pieDiagram-ENE6RG2P-8aUH44QZ.js} +1 -1
- package/dist/assets/{privacy-settings-page-pW_1naDz.js → privacy-settings-page-Bxxx12OO.js} +1 -1
- package/dist/assets/projects-D56yAPNT.js +1 -0
- package/dist/assets/provider-models-C3frdXeW.js +1 -0
- package/dist/assets/{provider-scoped-model-input-CVbtT8L9.js → provider-scoped-model-input-CYetrPYZ.js} +1 -1
- package/dist/assets/providers-config-page-DESB1h8g.js +1 -0
- package/dist/assets/{puzzle-kKiVft9-.js → puzzle-CWHfFyYN.js} +1 -1
- package/dist/assets/pwa-CiGUjpcd.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-7-OzMNpF.js → quadrantDiagram-ABIIQ3AL-EY8hpFv8.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-BFNIekC1.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-lVqJ3Hak.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-DYaefdFC.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-CTAk6lVq.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Cob294tg.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-B_UVtLJO.js → railroadDiagram-RFXS5EU6-CNhcIeji.js} +1 -1
- package/dist/assets/{refresh-cw-BeG0y6yZ.js → refresh-cw-y3L6PyLt.js} +1 -1
- package/dist/assets/remote-DiGFV8nP.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-D8TO2YeZ.js → requirementDiagram-TGXJPOKE-D8Dcs-Rt.js} +1 -1
- package/dist/assets/{rotate-cw-Ci2dcTO5.js → rotate-cw-CNE9qSHi.js} +1 -1
- package/dist/assets/{runtime-config-page-DCXN0nkS.js → runtime-config-page-5o98T-TD.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-CUzIcq0B.js → sankeyDiagram-HTMAVEWB-HTrb6aa-.js} +1 -1
- package/dist/assets/{save-Cr895abt.js → save-B0p5a0ET.js} +1 -1
- package/dist/assets/{search-config-page-CNQd481d.js → search-config-page-CpGcnIzi.js} +1 -1
- package/dist/assets/{secrets-config-page--q7M58L8.js → secrets-config-page-C4VTiW3r.js} +1 -1
- package/dist/assets/security-config-C5-RQVpS.js +1 -0
- package/dist/assets/select-CctTN205.js +1 -0
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-kqJzXbwu.js → sequenceDiagram-DBY2YBRQ-6f_4X16Y.js} +1 -1
- package/dist/assets/service-apps-panel-CKE5HKNY.js +1 -0
- package/dist/assets/{settings-2-IodCcaXd.js → settings-2-EPflrNk6.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-D9ISogq1.js → sizeCapture-X5ZJPWSS-Ck9rsuwL.js} +1 -1
- package/dist/assets/{src-Bc0PoUJ1.js → src-C8AUg09O.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-CqH5xc9W.js → stateDiagram-2N3HPSRC-Cm33MLHu.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BrNv-raG.js +1 -0
- package/dist/assets/{status-dot-DUYSKRCU.js → status-dot-CensgJZC.js} +1 -1
- package/dist/assets/{swimlanes-5IMT3BWC-mwejV-rW.js → swimlanes-5IMT3BWC-B107vmvM.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-ntcxaPXp.js +8 -0
- package/dist/assets/{tag-chip-CQU51ST3.js → tag-chip-Bjzb4-qW.js} +1 -1
- package/dist/assets/{theme-provider-D-zZkXxS.js → theme-provider-hlle7Skk.js} +1 -1
- package/dist/assets/{timeline-definition-FHXFAJF6-CuikIDlX.js → timeline-definition-FHXFAJF6-CJEoAj33.js} +1 -1
- package/dist/assets/{trash-2-BDdqDh6E.js → trash-2-C5KH5Rw9.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-DbFmr-gw.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-C8aY96pi.js +1 -0
- package/dist/assets/{use-config-Bxx7DdaL.js → use-config-CPl_F79t.js} +1 -1
- package/dist/assets/use-desktop-capabilities-CEg9-DrQ.js +1 -0
- package/dist/assets/{use-viewport-layout-CDcca0YL.js → use-viewport-layout-CPZUmTPi.js} +1 -1
- package/dist/assets/{vennDiagram-L72KCM5P-BD0P0qHh.js → vennDiagram-L72KCM5P-DzsUHk5I.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-D8d6DbbJ.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-C6ma3t5D.js → wardleyDiagram-EHGQE667-1NfFs5ua.js} +1 -1
- package/dist/assets/x--xxUvHKW.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-D7E40NBk.js → xychartDiagram-FW5EYKEG-Ci8AI3Qo.js} +1 -1
- package/dist/index.html +37 -36
- package/dist/panel-standalone.html +11 -11
- package/package.json +8 -8
- package/src/app/components/layout/__tests__/app-layout.test.tsx +0 -1
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +36 -16
- package/src/app/components/layout/sidebar-items.tsx +27 -18
- package/src/app/components/layout/sidebar-rail.styles.ts +11 -2
- package/src/app/components/layout/sidebar.tsx +3 -2
- package/src/app/configs/app-navigation.config.ts +39 -86
- package/src/features/agents/components/agent-details-dialog.tsx +3 -3
- package/src/features/agents/components/agents-page.tsx +5 -4
- package/src/features/chat/components/layout/__tests__/chat-page-shell.test.tsx +0 -2
- package/src/features/chat/components/layout/chat-page-shell.tsx +0 -2
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -1
- package/src/features/chat/features/conversation/components/chat-voice-input-panel.tsx +3 -2
- package/src/features/chat/features/conversation/hooks/__tests__/use-chat-voice-input.test.tsx +4 -0
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +32 -47
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +6 -10
- package/src/features/chat/features/message/utils/__tests__/chat-message-process-summary.utils.test.ts +52 -6
- package/src/features/chat/features/message/utils/chat-message-process-summary.utils.ts +22 -37
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +1 -1
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +2 -1
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +4 -2
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +9 -6
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +2 -2
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +17 -17
- package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +4 -4
- package/src/features/chat/features/session/components/session-header/chat-session-more-actions-menu.tsx +13 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +1 -1
- package/src/features/chat/managers/chat-voice-input.manager.ts +5 -3
- package/src/features/chat/utils/chat-voice-permissions.utils.test.ts +12 -1
- package/src/features/chat/utils/chat-voice-permissions.utils.ts +6 -1
- package/src/features/cron/components/cron-job-row.tsx +11 -9
- package/src/features/inbox/components/inbox-reader-dialog.tsx +4 -2
- package/src/features/inbox/pages/inbox-page.tsx +10 -5
- package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +1 -1
- package/src/features/panel-apps/components/__tests__/panel-app-list-item.test.tsx +6 -4
- package/src/features/panel-apps/components/__tests__/panel-app-toolbar.test.tsx +6 -4
- package/src/features/panel-apps/components/panel-app-list-item.tsx +1 -1
- package/src/features/panel-apps/components/panel-app-toolbar.tsx +7 -7
- package/src/features/projects/components/project-skills.tsx +2 -2
- package/src/features/right-panel-resources/components/__tests__/page-resource-sidebar-nav.test.tsx +27 -2
- package/src/features/right-panel-resources/components/page-resource-actions-menu.tsx +4 -22
- package/src/features/right-panel-resources/components/page-resource-sidebar-nav.tsx +10 -13
- package/src/features/right-panel-resources/hooks/use-page-resource-actions.ts +56 -3
- package/src/features/right-panel-resources/index.ts +0 -1
- package/src/features/service-apps/components/service-app-list-item.tsx +3 -2
- package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +40 -0
- package/src/features/system-status/components/desktop-update-config.tsx +19 -1
- package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +0 -1
- package/src/platforms/desktop/components/desktop-app-shell.tsx +0 -2
- package/src/platforms/mobile/components/mobile-app-shell.tsx +0 -2
- package/src/platforms/mobile/components/mobile-settings-shell.tsx +8 -3
- package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +83 -1
- package/src/shared/components/ui/context-menu/context-menu-items.tsx +173 -0
- package/src/shared/components/ui/context-menu/context-menu.tsx +93 -114
- package/src/shared/components/ui/dialog.tsx +4 -0
- package/src/shared/components/ui/overlays/sheet.tsx +4 -0
- package/src/shared/components/ui/popover.tsx +10 -4
- package/src/shared/lib/i18n/locales/en-US/chat.json +8 -1
- package/src/shared/lib/i18n/locales/en-US/core.json +3 -1
- package/src/shared/lib/i18n/locales/en-US/desktop-update.json +1 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +8 -1
- package/src/shared/lib/i18n/locales/zh-CN/core.json +11 -9
- package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +1 -0
- package/src/shared/lib/transport/__tests__/browser-realtime-recovery.service.test.ts +27 -2
- package/src/shared/lib/transport/__tests__/local-transport.service.test.ts +20 -0
- package/src/shared/lib/transport/__tests__/remote.transport.test.ts +26 -0
- package/src/shared/lib/transport/browser-realtime-recovery.service.ts +32 -5
- package/src/shared/lib/transport/local-transport.service.ts +1 -6
- package/src/shared/lib/transport/remote-transport.service.ts +22 -1
- package/dist/assets/api-D9e9cHtW.js +0 -20
- package/dist/assets/app-presenter-provider-J9IgTbc9.js +0 -124
- package/dist/assets/architecture-TIHT7OUA-BWywYH_m.js +0 -1
- package/dist/assets/channel-1nKIAEXr.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-CAwv72v4.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-DnaryNw2.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-BToo1uqb.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-D_TusZGx.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-B1NFZTmS.js +0 -1
- package/dist/assets/confirm-dialog-BCGeh61X.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-CJZSs5s_.js +0 -1
- package/dist/assets/desktop-update-config-BJMTQMRS.js +0 -1
- package/dist/assets/dialog-DQXou6pg.js +0 -5
- package/dist/assets/dist-CiC9Fd9J.js +0 -1
- package/dist/assets/doc-browser-CCYS_csH.js +0 -1
- package/dist/assets/es2015-DHRpDU-q.js +0 -41
- package/dist/assets/eventmodeling-45OFAUF4-rc7kUq4V.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-DAjaeGO8.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Ce0gf6ps.js +0 -1
- package/dist/assets/info-DKCQHKI2-Cp-Tr78m.js +0 -1
- package/dist/assets/loader-circle-B-4WwzBj.js +0 -1
- package/dist/assets/login-page-CdlI6B8e.js +0 -1
- package/dist/assets/main-BVYdyT60.css +0 -1
- package/dist/assets/main-DYEALeoQ.js +0 -2
- package/dist/assets/main-i18n-catalog.config-1o2hjZ0m.js +0 -1
- package/dist/assets/mcp-marketplace-page-CRRQT6SP.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BOJuCraS.js +0 -1
- package/dist/assets/panel-app-2EACRB8p.js +0 -1
- package/dist/assets/panel-app-i18n-catalog.config-kQO7QAwH.js +0 -1
- package/dist/assets/pie-RZYD4A2V-D-FEO81x.js +0 -1
- package/dist/assets/projects-k6SLda_A.js +0 -1
- package/dist/assets/provider-models-mVzuEQBS.js +0 -1
- package/dist/assets/providers-config-page-rBlVrHkb.js +0 -1
- package/dist/assets/pwa-BgGM4kkY.js +0 -1
- package/dist/assets/radar-I7S5WNFK-Bq3eK1vK.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-C3uZ1esg.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-D3iZd1KT.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-Dl0FWqZu.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-B51SbzGp.js +0 -1
- package/dist/assets/remote-wYWqir2w.js +0 -1
- package/dist/assets/security-config-CJb2pK2O.js +0 -1
- package/dist/assets/select-Bq-UmfCK.js +0 -1
- package/dist/assets/service-apps-panel-iLLEByRF.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-CcOGfDdx.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-BMI2k8RZ.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-C0_07QI1.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-Djpx6ccG.js +0 -1
- package/dist/assets/use-desktop-capabilities-BTgdFgJy.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-DZVFxu81.js +0 -1
- package/dist/assets/x-LUUwl8rK.js +0 -1
- package/src/features/right-panel-resources/components/current-page-actions.tsx +0 -36
- /package/dist/assets/{array-B0sEvCP9.js → array-BV9OtnO8.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-BeO7fxDQ.js → chunk-KEIR6QF5-Cx-8EJ4_.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-JQfgEV36.js → chunk-Y2CYZVJY-Dy1ufvjf.js} +0 -0
- /package/dist/assets/{config-hints-D3OuwoEY.js → config-hints-DbmiyTKg.js} +0 -0
- /package/dist/assets/{cytoscape.esm-CzJ9uXgi.js → cytoscape.esm-CSCjuT4Z.js} +0 -0
- /package/dist/assets/{defaultLocale-USmzX3VG.js → defaultLocale-DWTiNsbT.js} +0 -0
- /package/dist/assets/{dist-BYF6XVna.js → dist-BVCSkfWY.js} +0 -0
- /package/dist/assets/{graphlib-DEFMkHdW.js → graphlib-B1yb1Wl8.js} +0 -0
- /package/dist/assets/{host-capabilities-C0MmWd3M.js → host-capabilities-DuIFVsvM.js} +0 -0
- /package/dist/assets/{init-04ErALoz.js → init-BF6GH5oe.js} +0 -0
- /package/dist/assets/{jszip.min-BnQ5NRy2.js → jszip.min-D12teKzP.js} +0 -0
- /package/dist/assets/{middleware-CAXxl-af.js → middleware-B--6mAUM.js} +0 -0
- /package/dist/assets/{navigation-history-CyawyVz0.js → navigation-history-CzErJuPG.js} +0 -0
- /package/dist/assets/{path-CzxQ9n2G.js → path-C56XkznJ.js} +0 -0
- /package/dist/assets/{rough.esm-pT9fdsW3.js → rough.esm-CGfeEbtE.js} +0 -0
- /package/dist/assets/{xlsx-BRpCSiE4.js → xlsx-sds5nUpL.js} +0 -0
package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx
CHANGED
|
@@ -10,6 +10,7 @@ import type { ChatMessageListProps } from "@nextclaw/agent-chat-ui";
|
|
|
10
10
|
import { beforeEach, expect, it, vi } from "vitest";
|
|
11
11
|
import { ChatMessageListContainer as RuntimeChatMessageListContainer } from "@/features/chat/features/message/components/chat-message-list.container";
|
|
12
12
|
import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
|
|
13
|
+
import type * as I18nModule from "@/shared/lib/i18n";
|
|
13
14
|
|
|
14
15
|
type AgentChatUiModule = {
|
|
15
16
|
ChatMessageList: ComponentType<ChatMessageListProps>;
|
|
@@ -112,10 +113,15 @@ vi.mock("@/app/components/i18n-provider", () => ({
|
|
|
112
113
|
useI18n: () => ({ language: captures.language }),
|
|
113
114
|
}));
|
|
114
115
|
|
|
115
|
-
vi.mock("@/shared/lib/i18n", () =>
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
vi.mock("@/shared/lib/i18n", async (importOriginal) => {
|
|
117
|
+
const actual = await importOriginal<typeof I18nModule>();
|
|
118
|
+
return {
|
|
119
|
+
...actual,
|
|
120
|
+
formatDateTime: (value: string) => `formatted:${value}`,
|
|
121
|
+
t: (key: string) => key.startsWith("chatProcessDuration") || (captures.language === "zh" && key.startsWith("chatProcessSummary"))
|
|
122
|
+
? actual.t(key, captures.language === "zh" ? "zh" : "en") : key,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
119
125
|
|
|
120
126
|
vi.mock(
|
|
121
127
|
"@/features/chat/features/workspace/components/chat-session-workspace-file-preview",
|
|
@@ -325,51 +331,30 @@ it("adds a completed assistant process summary without inventing a duration", ()
|
|
|
325
331
|
});
|
|
326
332
|
});
|
|
327
333
|
|
|
328
|
-
it("
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
role: "assistant",
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
},
|
|
334
|
+
it("renders a minimal Chinese history summary and still expands its process", () => {
|
|
335
|
+
captures.language = "zh";
|
|
336
|
+
captures.renderActualChatMessageList = true;
|
|
337
|
+
const message: NcpMessage = {
|
|
338
|
+
id: "assistant-minimal-summary", sessionId: "session-1", role: "assistant", status: "final",
|
|
339
|
+
timestamp: "2026-03-31T10:02:07.000Z",
|
|
340
|
+
lifecycle: { startedAt: "2026-03-31T10:00:00.000Z", endedAt: "2026-03-31T10:02:07.000Z" },
|
|
341
|
+
metadata: { nextclawUiHistoryToolPayloadSummary: {
|
|
342
|
+
toolCallCount: 67, toolNames: ["tool_schema", "projects_list", "project_work_list"],
|
|
343
|
+
} },
|
|
339
344
|
parts: [
|
|
340
|
-
{
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
type: "tool-invocation",
|
|
346
|
-
toolCallId: "tool-1",
|
|
347
|
-
toolName: "exec_command",
|
|
348
|
-
state: "result",
|
|
349
|
-
args: '{"cmd":"git status"}',
|
|
350
|
-
result: "clean",
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
type: "text",
|
|
354
|
-
text: "Done.",
|
|
355
|
-
},
|
|
345
|
+
{ type: "reasoning", text: "核对项目详情" },
|
|
346
|
+
{ type: "tool-invocation", toolCallId: "tool-1", toolName: "projects_list", state: "result" },
|
|
347
|
+
{ type: "text", text: "项目已整理" },
|
|
356
348
|
],
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
);
|
|
365
|
-
|
|
366
|
-
const renderedMessages =
|
|
367
|
-
captures.renders[captures.renders.length - 1]?.messages ?? [];
|
|
368
|
-
expect(renderedMessages[0]).toMatchObject({
|
|
369
|
-
processSummary: {
|
|
370
|
-
label: "chatProcessSummaryProcessed 3m 51s",
|
|
371
|
-
},
|
|
372
|
-
});
|
|
349
|
+
};
|
|
350
|
+
render(<ChatMessageListContainer messages={[message]} isSending={false} />);
|
|
351
|
+
const summary = screen.getByRole("button", { name: "已处理 2分钟7秒" });
|
|
352
|
+
expect(summary.getAttribute("aria-expanded")).toBe("false");
|
|
353
|
+
expect(screen.queryByText(/67|tool_schema|project_work_list/)).toBeNull();
|
|
354
|
+
expect(screen.getByText("项目已整理")).toBeTruthy();
|
|
355
|
+
fireEvent.click(summary);
|
|
356
|
+
expect(summary.getAttribute("aria-expanded")).toBe("true");
|
|
357
|
+
expect(screen.getByRole("button", { name: "projects list" })).toBeTruthy();
|
|
373
358
|
});
|
|
374
359
|
|
|
375
360
|
it("keeps unavailable ai usage in metadata but out of the footer", () => {
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
import { useChatMessageActions } from "@/features/chat/features/message/hooks/use-chat-message-actions";
|
|
67
67
|
import { useChatInlineTokenActions } from "@/features/chat/features/message/hooks/use-chat-inline-token-actions";
|
|
68
68
|
import { buildServerPathContentUrl } from "@/shared/lib/api";
|
|
69
|
-
import { formatDateTime,
|
|
69
|
+
import { formatDateTime, t, type I18nLanguage } from "@/shared/lib/i18n";
|
|
70
70
|
import { cn } from "@/shared/lib/utils";
|
|
71
71
|
import type { SessionMessageToolPayloadState } from "@/features/chat/features/ncp/hooks/use-ncp-session-message-history";
|
|
72
72
|
import { ChatMessageObservationEvent } from "@/features/chat/features/message/components/chat-message-observation-event";
|
|
@@ -96,7 +96,7 @@ class ChatMessageViewModelAdapter {
|
|
|
96
96
|
private readonly cache = new WeakMap<
|
|
97
97
|
NcpMessage,
|
|
98
98
|
{
|
|
99
|
-
language:
|
|
99
|
+
language: I18nLanguage;
|
|
100
100
|
processSummaryLabel: string | null;
|
|
101
101
|
executionPresentationKey: string | null;
|
|
102
102
|
triggerDetailsKey: string | null;
|
|
@@ -108,7 +108,7 @@ class ChatMessageViewModelAdapter {
|
|
|
108
108
|
continuationRunning: boolean;
|
|
109
109
|
executionLabels: ReturnType<typeof buildChatMessageExecutionLabels>;
|
|
110
110
|
triggerLabels: ReturnType<typeof buildChatMessageTriggerLabels>;
|
|
111
|
-
language:
|
|
111
|
+
language: I18nLanguage;
|
|
112
112
|
processedLabel: string;
|
|
113
113
|
rawMessages: readonly NcpMessage[];
|
|
114
114
|
texts: ReturnType<typeof buildChatMessageAdapterTexts>;
|
|
@@ -120,13 +120,9 @@ class ChatMessageViewModelAdapter {
|
|
|
120
120
|
const processSummary = buildChatMessageProcessSummary({
|
|
121
121
|
message,
|
|
122
122
|
processedLabel,
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (toolNames.length === 0) return countLabel;
|
|
127
|
-
const separator = language === "zh" ? "、" : ", ";
|
|
128
|
-
return `${countLabel} · ${toolNames.join(separator)}`;
|
|
129
|
-
},
|
|
123
|
+
language,
|
|
124
|
+
failedLabel: t("chatProcessSummaryError", language),
|
|
125
|
+
stoppedLabel: t("chatProcessSummaryStopped", language),
|
|
130
126
|
});
|
|
131
127
|
const processSummaryLabel = processSummary?.label ?? null;
|
|
132
128
|
const executionPresentation = buildChatMessageExecutionPresentation({
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NcpEventType, type NcpMessage } from "@nextclaw/ncp";
|
|
1
|
+
import { createUnavailableNcpAiExecutionMetadata, NcpEventType, type NcpMessage } from "@nextclaw/ncp";
|
|
2
2
|
import { DefaultNcpAgentConversationStateManager } from "@nextclaw/ncp-toolkit";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
import { buildChatMessageProcessSummary } from "@/features/chat/features/message/utils/chat-message-process-summary.utils";
|
|
@@ -29,6 +29,13 @@ const baseAssistantMessage = {
|
|
|
29
29
|
],
|
|
30
30
|
} satisfies NcpMessage;
|
|
31
31
|
|
|
32
|
+
const summaryLabels = {
|
|
33
|
+
processedLabel: "已处理",
|
|
34
|
+
failedLabel: "处理失败",
|
|
35
|
+
stoppedLabel: "已停止",
|
|
36
|
+
language: "zh" as const,
|
|
37
|
+
};
|
|
38
|
+
|
|
32
39
|
describe("buildChatMessageProcessSummary", () => {
|
|
33
40
|
it("shows elapsed time from the real completed-message then run-finished event sequence", async () => {
|
|
34
41
|
const manager = new DefaultNcpAgentConversationStateManager();
|
|
@@ -44,12 +51,13 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
44
51
|
},
|
|
45
52
|
]);
|
|
46
53
|
const message = manager.getSnapshot().messages[0]!;
|
|
47
|
-
expect(buildChatMessageProcessSummary({
|
|
54
|
+
expect(buildChatMessageProcessSummary({ ...summaryLabels, message })?.label).toBe("已处理 3分钟51秒");
|
|
48
55
|
});
|
|
49
56
|
|
|
50
57
|
it("does not invent duration when lifecycle timing is absent", () => {
|
|
51
58
|
expect(
|
|
52
59
|
buildChatMessageProcessSummary({
|
|
60
|
+
...summaryLabels,
|
|
53
61
|
message: baseAssistantMessage,
|
|
54
62
|
processedLabel: "Processed",
|
|
55
63
|
}),
|
|
@@ -61,6 +69,8 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
61
69
|
it("derives duration from lifecycle startedAt and endedAt", () => {
|
|
62
70
|
expect(
|
|
63
71
|
buildChatMessageProcessSummary({
|
|
72
|
+
...summaryLabels,
|
|
73
|
+
language: "en",
|
|
64
74
|
message: {
|
|
65
75
|
...baseAssistantMessage,
|
|
66
76
|
lifecycle: {
|
|
@@ -77,6 +87,7 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
77
87
|
|
|
78
88
|
it("stays free of tool-activity semantics", () => {
|
|
79
89
|
const summary = buildChatMessageProcessSummary({
|
|
90
|
+
...summaryLabels,
|
|
80
91
|
message: baseAssistantMessage,
|
|
81
92
|
processedLabel: "Processed",
|
|
82
93
|
});
|
|
@@ -85,8 +96,9 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
85
96
|
expect(summary?.label.toLowerCase()).not.toContain("read");
|
|
86
97
|
});
|
|
87
98
|
|
|
88
|
-
it("
|
|
99
|
+
it("keeps deferred history summaries identical to fully loaded messages", () => {
|
|
89
100
|
const summary = buildChatMessageProcessSummary({
|
|
101
|
+
...summaryLabels,
|
|
90
102
|
message: {
|
|
91
103
|
...baseAssistantMessage,
|
|
92
104
|
metadata: {
|
|
@@ -97,12 +109,46 @@ describe("buildChatMessageProcessSummary", () => {
|
|
|
97
109
|
},
|
|
98
110
|
},
|
|
99
111
|
processedLabel: "Processed",
|
|
100
|
-
formatDeferredToolSummary: (count, names) =>
|
|
101
|
-
`${count} tool calls · ${names.join(", ")}`,
|
|
102
112
|
});
|
|
103
113
|
|
|
104
114
|
expect(summary?.label).toBe(
|
|
105
|
-
"Processed
|
|
115
|
+
"Processed",
|
|
106
116
|
);
|
|
107
117
|
});
|
|
118
|
+
|
|
119
|
+
it.each([
|
|
120
|
+
[0, "0秒"], [7, "7秒"], [127, "2分钟7秒"],
|
|
121
|
+
[3600, "1小时"], [3720, "1小时2分钟"],
|
|
122
|
+
])("localizes a %i-second duration without separators", (seconds, expected) => {
|
|
123
|
+
const startedAt = "2026-03-31T10:00:00.000Z";
|
|
124
|
+
const message: NcpMessage = {
|
|
125
|
+
...baseAssistantMessage,
|
|
126
|
+
lifecycle: { startedAt, endedAt: new Date(Date.parse(startedAt) + seconds * 1000).toISOString() },
|
|
127
|
+
};
|
|
128
|
+
expect(buildChatMessageProcessSummary({ ...summaryLabels, message })?.label).toBe(`已处理 ${expected}`);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it.each(["pending", "streaming"] as const)("does not label %s messages as processed", (status) => {
|
|
132
|
+
expect(buildChatMessageProcessSummary({
|
|
133
|
+
...summaryLabels, message: { ...baseAssistantMessage, status },
|
|
134
|
+
})).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it.each([
|
|
138
|
+
["failed", "处理失败"], ["aborted", "已停止"], ["completed", "已处理"],
|
|
139
|
+
] as const)("uses the recorded %s outcome", (outcome, expected) => {
|
|
140
|
+
const message: NcpMessage = {
|
|
141
|
+
...baseAssistantMessage,
|
|
142
|
+
metadata: { ai_execution: createUnavailableNcpAiExecutionMetadata({
|
|
143
|
+
runId: "run-1", runtimeId: "native", model: "test", requestedModel: null, outcome,
|
|
144
|
+
}) },
|
|
145
|
+
};
|
|
146
|
+
expect(buildChatMessageProcessSummary({ ...summaryLabels, message })?.label).toBe(expected);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("shows failure for an error message without execution metadata", () => {
|
|
150
|
+
expect(buildChatMessageProcessSummary({
|
|
151
|
+
...summaryLabels, message: { ...baseAssistantMessage, status: "error" },
|
|
152
|
+
})?.label).toBe("处理失败");
|
|
153
|
+
});
|
|
108
154
|
});
|
|
@@ -1,29 +1,15 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { readNcpAiExecutionMetadata, type NcpMessage } from "@nextclaw/ncp";
|
|
2
2
|
import type { ChatMessageProcessSummarySource } from "@/features/chat/types/chat-message.types";
|
|
3
|
+
import { t, type I18nLanguage } from "@/shared/lib/i18n";
|
|
3
4
|
|
|
4
5
|
type BuildChatMessageProcessSummaryParams = {
|
|
5
6
|
message: NcpMessage;
|
|
6
7
|
processedLabel: string;
|
|
7
|
-
|
|
8
|
+
failedLabel: string;
|
|
9
|
+
stoppedLabel: string;
|
|
10
|
+
language: I18nLanguage;
|
|
8
11
|
};
|
|
9
12
|
|
|
10
|
-
const UI_HISTORY_TOOL_PAYLOAD_SUMMARY_METADATA_KEY =
|
|
11
|
-
"nextclawUiHistoryToolPayloadSummary";
|
|
12
|
-
|
|
13
|
-
function readDeferredToolSummary(
|
|
14
|
-
message: NcpMessage,
|
|
15
|
-
): { toolCallCount: number; toolNames: string[] } | null {
|
|
16
|
-
const value = message.metadata?.[UI_HISTORY_TOOL_PAYLOAD_SUMMARY_METADATA_KEY];
|
|
17
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
18
|
-
const record = value as Record<string, unknown>;
|
|
19
|
-
const { toolCallCount } = record;
|
|
20
|
-
if (!Number.isInteger(toolCallCount) || (toolCallCount as number) <= 0) return null;
|
|
21
|
-
const toolNames = Array.isArray(record.toolNames)
|
|
22
|
-
? record.toolNames.filter((name): name is string => typeof name === "string" && name.trim().length > 0)
|
|
23
|
-
: [];
|
|
24
|
-
return { toolCallCount: toolCallCount as number, toolNames };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
13
|
function isAssistantProcessPart(part: NcpMessage["parts"][number]): boolean {
|
|
28
14
|
return part.type === "reasoning" || part.type === "tool-invocation";
|
|
29
15
|
}
|
|
@@ -62,7 +48,7 @@ function hasCollapsibleAssistantProcess(message: NcpMessage): boolean {
|
|
|
62
48
|
);
|
|
63
49
|
}
|
|
64
50
|
|
|
65
|
-
function formatLifecycleDuration(message: NcpMessage): string | null {
|
|
51
|
+
function formatLifecycleDuration(message: NcpMessage, language: I18nLanguage): string | null {
|
|
66
52
|
const startedAt = message.lifecycle?.startedAt;
|
|
67
53
|
const endedAt = message.lifecycle?.endedAt;
|
|
68
54
|
if (!startedAt || !endedAt) {
|
|
@@ -77,13 +63,13 @@ function formatLifecycleDuration(message: NcpMessage): string | null {
|
|
|
77
63
|
const hours = Math.floor(totalSeconds / 3600);
|
|
78
64
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
79
65
|
const seconds = totalSeconds % 60;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
66
|
+
const key = hours > 0
|
|
67
|
+
? (minutes > 0 ? "chatProcessDurationHoursMinutes" : "chatProcessDurationHours")
|
|
68
|
+
: (minutes > 0 ? "chatProcessDurationMinutesSeconds" : "chatProcessDurationSeconds");
|
|
69
|
+
return t(key, language)
|
|
70
|
+
.replace("{hours}", String(hours))
|
|
71
|
+
.replace("{minutes}", String(minutes))
|
|
72
|
+
.replace("{seconds}", String(seconds));
|
|
87
73
|
}
|
|
88
74
|
|
|
89
75
|
/**
|
|
@@ -92,22 +78,21 @@ function formatLifecycleDuration(message: NcpMessage): string | null {
|
|
|
92
78
|
* and must not be mixed into this summary.
|
|
93
79
|
*/
|
|
94
80
|
export function buildChatMessageProcessSummary({
|
|
95
|
-
|
|
81
|
+
failedLabel,
|
|
82
|
+
stoppedLabel,
|
|
96
83
|
message,
|
|
97
84
|
processedLabel,
|
|
85
|
+
language,
|
|
98
86
|
}: BuildChatMessageProcessSummaryParams): ChatMessageProcessSummarySource | undefined {
|
|
99
87
|
if (!hasCollapsibleAssistantProcess(message)) {
|
|
100
88
|
return undefined;
|
|
101
89
|
}
|
|
102
|
-
const duration = formatLifecycleDuration(message);
|
|
103
|
-
const
|
|
104
|
-
const
|
|
90
|
+
const duration = formatLifecycleDuration(message, language);
|
|
91
|
+
const outcome = readNcpAiExecutionMetadata(message.metadata)?.outcome;
|
|
92
|
+
const statusLabel = message.status === "error" || outcome === "failed"
|
|
93
|
+
? failedLabel
|
|
94
|
+
: outcome === "aborted" ? stoppedLabel : processedLabel;
|
|
105
95
|
return {
|
|
106
|
-
label:
|
|
107
|
-
? `${baseLabel} · ${formatDeferredToolSummary(
|
|
108
|
-
deferredToolSummary.toolCallCount,
|
|
109
|
-
deferredToolSummary.toolNames,
|
|
110
|
-
)}`
|
|
111
|
-
: baseLabel,
|
|
96
|
+
label: duration ? `${statusLabel} ${duration}` : statusLabel,
|
|
112
97
|
};
|
|
113
98
|
}
|
package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx
CHANGED
|
@@ -113,7 +113,7 @@ describe("ChatSidebarProjectGroups", () => {
|
|
|
113
113
|
const projectRow = projectLink.parentElement?.parentElement;
|
|
114
114
|
expect(container.firstElementChild?.className).toBe("space-y-0.5");
|
|
115
115
|
expect(projectRow?.className).toContain("h-8");
|
|
116
|
-
expect(projectRow?.className).toContain("hover:bg-gray-200/
|
|
116
|
+
expect(projectRow?.className).toContain("hover:bg-[hsl(var(--gray-200)/0.6)]");
|
|
117
117
|
const projectContent = projectLink.parentElement;
|
|
118
118
|
expect(projectContent?.classList.contains("pr-14")).toBe(false);
|
|
119
119
|
expect(projectContent?.className).toContain("group-hover/project:pr-20");
|
package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx
CHANGED
|
@@ -87,7 +87,8 @@ it("shows session actions only on hover or when an action owns focus", () => {
|
|
|
87
87
|
it("opens any sidebar session as a floating conversation", async () => {
|
|
88
88
|
const user = userEvent.setup();
|
|
89
89
|
await user.click(screen.getByRole('button', { name: 'More actions' }));
|
|
90
|
-
await user.click(screen.getByRole('
|
|
90
|
+
await user.click(screen.getByRole('menuitem', { name: 'Layout and position' }));
|
|
91
|
+
await user.click(screen.getByRole('menuitem', { name: 'Open in floating window' }));
|
|
91
92
|
expect(useFloatingSessionStore.getState().session).toEqual({
|
|
92
93
|
sessionKey: 'session:current', title: 'Current Task',
|
|
93
94
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useMemo, useState, type ReactNode } from "react";
|
|
2
|
+
import { SIDEBAR_ITEM_SURFACE_CLASS, SIDEBAR_ITEM_ACTIVE_SURFACE_CLASS } from "@/app/components/layout/sidebar-rail.styles";
|
|
2
3
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
|
3
4
|
import {
|
|
4
5
|
AlarmClock,
|
|
@@ -116,8 +117,9 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
116
117
|
<div key={group.projectRoot}>
|
|
117
118
|
<div
|
|
118
119
|
className={cn(
|
|
119
|
-
"group/project relative h-8
|
|
120
|
-
|
|
120
|
+
"group/project relative h-8 px-1",
|
|
121
|
+
SIDEBAR_ITEM_SURFACE_CLASS,
|
|
122
|
+
isSelected && SIDEBAR_ITEM_ACTIVE_SURFACE_CLASS,
|
|
121
123
|
)}
|
|
122
124
|
>
|
|
123
125
|
<ChatSidebarContextCard
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentAvatar } from "@/shared/components/common/agent-avatar";
|
|
2
|
+
import { SIDEBAR_ITEM_SURFACE_CLASS, SIDEBAR_ITEM_ACTIVE_SURFACE_CLASS } from "@/app/components/layout/sidebar-rail.styles";
|
|
2
3
|
import { ChatMobileSessionRow } from './chat-mobile-session-row';
|
|
3
4
|
import { SessionContextIconNode } from "@/features/chat/features/session/components/session-context-icon";
|
|
4
5
|
import { SessionRunBadge } from "@/features/chat/features/session/components/session-run-badge";
|
|
@@ -309,20 +310,22 @@ export function ChatSidebarSessionItem(props: ChatSidebarSessionItemProps) {
|
|
|
309
310
|
onCancel,
|
|
310
311
|
onTogglePinned,
|
|
311
312
|
onDelete,
|
|
313
|
+
variant,
|
|
312
314
|
} = props;
|
|
313
315
|
return (
|
|
314
316
|
<div
|
|
315
317
|
className={cn(
|
|
316
|
-
|
|
318
|
+
variant === 'mobile'
|
|
317
319
|
? 'w-full border-b border-border/50 bg-background text-left'
|
|
318
|
-
: "w-full
|
|
319
|
-
active
|
|
320
|
+
: cn("w-full px-3 py-2 text-left text-[13px]", SIDEBAR_ITEM_SURFACE_CLASS, active && SIDEBAR_ITEM_ACTIVE_SURFACE_CLASS),
|
|
321
|
+
variant === 'mobile' && (active
|
|
320
322
|
? "bg-background/90 font-medium text-foreground"
|
|
321
|
-
: "text-foreground/80 hover:bg-background/65 hover:text-foreground",
|
|
323
|
+
: "text-foreground/80 hover:bg-background/65 hover:text-foreground"),
|
|
324
|
+
active && "font-medium",
|
|
322
325
|
)}
|
|
323
326
|
>
|
|
324
327
|
{isEditing ? (
|
|
325
|
-
<div className={
|
|
328
|
+
<div className={variant === 'mobile' ? 'p-4' : undefined}>
|
|
326
329
|
<ChatSidebarSessionEditingView
|
|
327
330
|
sessionKey={sessionKey}
|
|
328
331
|
draftLabel={draftLabel}
|
|
@@ -332,7 +335,7 @@ export function ChatSidebarSessionItem(props: ChatSidebarSessionItemProps) {
|
|
|
332
335
|
onCancel={onCancel}
|
|
333
336
|
/>
|
|
334
337
|
</div>
|
|
335
|
-
) :
|
|
338
|
+
) : variant === 'mobile' ? <ChatMobileSessionRow {...props} /> : (
|
|
336
339
|
<ChatSidebarSessionDisplayView
|
|
337
340
|
sessionKey={sessionKey}
|
|
338
341
|
active={active}
|
|
@@ -192,7 +192,7 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
192
192
|
expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('w-7');
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
it('places
|
|
195
|
+
it('places more actions at the far right of the visible header actions', () => {
|
|
196
196
|
render(
|
|
197
197
|
<ChatSessionHeaderActions
|
|
198
198
|
sessionKey="session-actions"
|
|
@@ -208,7 +208,7 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
208
208
|
const menuButton = screen.getByRole('button', { name: 'More actions' });
|
|
209
209
|
const workspaceButton = screen.getByRole('button', { name: 'Open session workspace' });
|
|
210
210
|
|
|
211
|
-
expect(
|
|
211
|
+
expect(workspaceButton.compareDocumentPosition(menuButton)).toBe(
|
|
212
212
|
Node.DOCUMENT_POSITION_FOLLOWING,
|
|
213
213
|
);
|
|
214
214
|
});
|
package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx
CHANGED
|
@@ -61,6 +61,23 @@ export function ChatSessionHeaderActions({
|
|
|
61
61
|
|
|
62
62
|
return (
|
|
63
63
|
<div className={SESSION_HEADER_ACTION_GROUP_CLASS}>
|
|
64
|
+
<IconActionButton
|
|
65
|
+
icon={
|
|
66
|
+
isWorkspaceOpen ? (
|
|
67
|
+
<PanelRightClose className="h-4 w-4" />
|
|
68
|
+
) : (
|
|
69
|
+
<PanelRightOpen className="h-4 w-4" />
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
label={t(
|
|
73
|
+
isWorkspaceOpen
|
|
74
|
+
? 'chatSessionCloseWorkspace'
|
|
75
|
+
: 'chatSessionOpenWorkspace',
|
|
76
|
+
)}
|
|
77
|
+
aria-pressed={isWorkspaceOpen}
|
|
78
|
+
onClick={onToggleWorkspace}
|
|
79
|
+
disabled={isBusy}
|
|
80
|
+
/>
|
|
64
81
|
{sessionKey ? (
|
|
65
82
|
<ChatSessionMoreActionsMenu
|
|
66
83
|
sessionKey={sessionKey}
|
|
@@ -88,23 +105,6 @@ export function ChatSessionHeaderActions({
|
|
|
88
105
|
/>
|
|
89
106
|
</ChatSessionMoreActionsMenu>
|
|
90
107
|
) : null}
|
|
91
|
-
<IconActionButton
|
|
92
|
-
icon={
|
|
93
|
-
isWorkspaceOpen ? (
|
|
94
|
-
<PanelRightClose className="h-4 w-4" />
|
|
95
|
-
) : (
|
|
96
|
-
<PanelRightOpen className="h-4 w-4" />
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
label={t(
|
|
100
|
-
isWorkspaceOpen
|
|
101
|
-
? 'chatSessionCloseWorkspace'
|
|
102
|
-
: 'chatSessionOpenWorkspace',
|
|
103
|
-
)}
|
|
104
|
-
aria-pressed={isWorkspaceOpen}
|
|
105
|
-
onClick={onToggleWorkspace}
|
|
106
|
-
disabled={isBusy}
|
|
107
|
-
/>
|
|
108
108
|
|
|
109
109
|
{sessionKey ? (
|
|
110
110
|
<>
|
|
@@ -20,15 +20,15 @@ export function ChatSessionHeaderMenuItem({
|
|
|
20
20
|
<button
|
|
21
21
|
type="button"
|
|
22
22
|
className={cn(
|
|
23
|
-
'flex w-full items-center gap-2 rounded-
|
|
23
|
+
'flex h-8 w-full items-center gap-2 rounded-lg px-2.5 text-left text-[13px] font-medium outline-none transition-colors disabled:cursor-not-allowed disabled:opacity-50',
|
|
24
24
|
destructive
|
|
25
|
-
? 'text-destructive hover:bg-destructive/10'
|
|
26
|
-
: 'text-
|
|
25
|
+
? 'text-destructive hover:bg-destructive/10 focus-visible:bg-destructive/10'
|
|
26
|
+
: 'text-foreground hover:bg-muted focus-visible:bg-muted'
|
|
27
27
|
)}
|
|
28
28
|
onClick={onClick}
|
|
29
29
|
disabled={disabled}
|
|
30
30
|
>
|
|
31
|
-
<Icon className="h-4 w-4 shrink-0" />
|
|
31
|
+
<Icon className={cn("h-4 w-4 shrink-0", !destructive && "text-muted-foreground")} />
|
|
32
32
|
<span>{label}</span>
|
|
33
33
|
</button>
|
|
34
34
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PageResourceActionItems } from '@/features/right-panel-resources';
|
|
2
2
|
import { pageResourceFromTarget } from '@/features/right-panel-resources';
|
|
3
3
|
import { buildSessionPanelUrl } from '@/features/chat/features/session/utils/chat-session-route.utils';
|
|
4
|
-
import { useState, type ReactNode } from 'react';
|
|
4
|
+
import { Children, isValidElement, useState, type ReactNode } from 'react';
|
|
5
5
|
import { copyText } from '@nextclaw/agent-chat-ui';
|
|
6
6
|
import { Copy, MoreVertical } from 'lucide-react';
|
|
7
7
|
import { toast } from 'sonner';
|
|
@@ -42,6 +42,9 @@ export function ChatSessionMoreActionsMenu({
|
|
|
42
42
|
className,
|
|
43
43
|
}: ChatSessionMoreActionsMenuProps) {
|
|
44
44
|
const [isOpen, setIsOpen] = useState(false);
|
|
45
|
+
const menuItems = Children.toArray(children);
|
|
46
|
+
const isDestructive = (item: ReactNode) => isValidElement<{ destructive?: boolean }>(item) && item.props.destructive;
|
|
47
|
+
const destructiveItems = menuItems.filter(isDestructive);
|
|
45
48
|
|
|
46
49
|
const handleCopySessionId = () => {
|
|
47
50
|
setIsOpen(false);
|
|
@@ -54,7 +57,6 @@ export function ChatSessionMoreActionsMenu({
|
|
|
54
57
|
<IconActionButton
|
|
55
58
|
icon={<MoreVertical className="h-4 w-4" />}
|
|
56
59
|
label={t('chatSessionMoreActions')}
|
|
57
|
-
tooltip={false}
|
|
58
60
|
size={triggerSize}
|
|
59
61
|
tone={triggerTone}
|
|
60
62
|
className={className}
|
|
@@ -62,17 +64,22 @@ export function ChatSessionMoreActionsMenu({
|
|
|
62
64
|
onClick={(event) => event.stopPropagation()}
|
|
63
65
|
/>
|
|
64
66
|
</PopoverTrigger>
|
|
65
|
-
<ChatPopoverContent align="end"
|
|
66
|
-
<div
|
|
67
|
-
|
|
67
|
+
<ChatPopoverContent align="end" variant="menu">
|
|
68
|
+
<div onClick={() => setIsOpen(false)}>
|
|
69
|
+
{menuItems.filter((item) => !isDestructive(item))}
|
|
68
70
|
<ChatSessionHeaderMenuItem
|
|
69
71
|
icon={Copy}
|
|
70
72
|
label={t('chatSessionCopyId')}
|
|
71
73
|
onClick={handleCopySessionId}
|
|
72
74
|
disabled={disabled}
|
|
73
75
|
/>
|
|
74
|
-
{children}
|
|
75
76
|
</div>
|
|
77
|
+
<div className="my-1 h-px bg-border" />
|
|
78
|
+
<PageResourceActionItems page={pageResourceFromTarget({ kind: 'chat-session', title: sessionTitle || t('chatFloatingConversation'), url: buildSessionPanelUrl(sessionKey), resourceUri: buildSessionPanelUrl(sessionKey), historyPolicy: 'none' })} onSelect={() => setIsOpen(false)} />
|
|
79
|
+
{destructiveItems.length > 0 ? <>
|
|
80
|
+
<div className="my-1 h-px bg-border" />
|
|
81
|
+
<div onClick={() => setIsOpen(false)}>{destructiveItems}</div>
|
|
82
|
+
</> : null}
|
|
76
83
|
</ChatPopoverContent>
|
|
77
84
|
</Popover>
|
|
78
85
|
);
|
|
@@ -205,7 +205,7 @@ export function ChatSessionWorkspacePanel({
|
|
|
205
205
|
const file = workspaceFileTabs.find((item) => `file:${item.key}` === tab.key);
|
|
206
206
|
const target = file ? createWorkspaceFilePanelTarget(file, { workingDir: sessionWorkingDir, projectRoot: sessionProjectRoot })
|
|
207
207
|
: tab.sessionKey ? { kind: 'chat-session', title: tab.title, url: buildSessionPanelUrl(tab.sessionKey), resourceUri: buildSessionPanelUrl(tab.sessionKey), historyPolicy: 'none' as const } : tab.kind !== 'side-chat-draft' ? { kind: 'workspace', title: tab.title, url: `nextclaw://workspace?${new URLSearchParams({ session: sessionKey ?? '', page: tab.kind })}`, historyPolicy: 'none' as const } : null;
|
|
208
|
-
return target ? [...pageActions(pageResourceFromTarget(target), 'workspace')
|
|
208
|
+
return target ? [...(tab.menuGroups ?? []), ...pageActions(pageResourceFromTarget(target), 'workspace')] : tab.menuGroups;
|
|
209
209
|
})(),
|
|
210
210
|
onMoveGlobal: tab.kind === 'file' ? () => presenter.chatThreadManager.moveFileToGlobal(tab.key.slice('file:'.length), { workingDir: sessionWorkingDir, projectRoot: sessionProjectRoot }, getAppPresenter().docBrowserManager)
|
|
211
211
|
: tab.kind === 'child-session' && tab.sessionKey ? () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ChatComposerDictationSession } from '@nextclaw/agent-chat-ui';
|
|
2
|
-
import { checkMicrophoneAccess, classifyMicrophoneError } from '@/features/chat/utils/chat-voice-permissions.utils';
|
|
2
|
+
import { checkMicrophoneAccess, classifyMicrophoneError, isMicrophoneSecureContext } from '@/features/chat/utils/chat-voice-permissions.utils';
|
|
3
3
|
|
|
4
4
|
export type VoicePhase = 'idle' | 'ready' | 'starting' | 'recording' | 'stopping' | 'error';
|
|
5
|
-
export type VoiceError = 'unsupported' | 'permission' | 'service-denied' | 'no-device' | 'device-busy' | 'network' | 'audio-capture' | 'no-speech' | 'interrupted' | 'timeout' | 'failed';
|
|
5
|
+
export type VoiceError = 'insecure-context' | 'unsupported' | 'permission' | 'service-denied' | 'no-device' | 'device-busy' | 'network' | 'audio-capture' | 'no-speech' | 'interrupted' | 'timeout' | 'failed';
|
|
6
6
|
export type VoiceSnapshot = { phase: VoicePhase; text: string; interim: string; seconds: number; error: VoiceError | null };
|
|
7
7
|
export type SpeechRecognitionLike = {
|
|
8
8
|
lang: string;
|
|
@@ -38,7 +38,8 @@ export class ChatVoiceInputManager {
|
|
|
38
38
|
private draft: ChatComposerDictationSession | null = null;
|
|
39
39
|
|
|
40
40
|
constructor(private readonly createRecognition = createBrowserRecognition,
|
|
41
|
-
private readonly checkMicrophone = checkMicrophoneAccess
|
|
41
|
+
private readonly checkMicrophone = checkMicrophoneAccess,
|
|
42
|
+
private readonly isSecureContext = isMicrophoneSecureContext) {}
|
|
42
43
|
|
|
43
44
|
getSnapshot = (): VoiceSnapshot => this.snapshot;
|
|
44
45
|
subscribe = (listener: () => void): (() => void) => {
|
|
@@ -70,6 +71,7 @@ export class ChatVoiceInputManager {
|
|
|
70
71
|
this.draft = draft;
|
|
71
72
|
this.update({ ...initialSnapshot(), phase: 'starting' });
|
|
72
73
|
try {
|
|
74
|
+
if (!this.isSecureContext()) { this.fail('insecure-context'); return; }
|
|
73
75
|
const recognition = this.createRecognition();
|
|
74
76
|
if (!recognition) { this.fail('unsupported'); return; }
|
|
75
77
|
this.recognition = recognition;
|