@nextclaw/ui 0.15.9 → 0.15.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/assets/{abnfDiagram-VRR7QNED-BYpK0F5F.js → abnfDiagram-VRR7QNED-M4g_AyR8.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-D87ywFdC.js → aiden0z-pptx-renderer.es-Bd99vut2.js} +1 -1
  4. package/dist/assets/api-pbx14YAL.js +13 -0
  5. package/dist/assets/app-presenter-provider-Q6u2xBAn.js +106 -0
  6. package/dist/assets/appearance-settings-page-D9wJdf-0.js +1 -0
  7. package/dist/assets/{arc-DFELHWM2.js → arc-IO7WNWOB.js} +1 -1
  8. package/dist/assets/architecture-TIHT7OUA-Cii4JyA2.js +1 -0
  9. package/dist/assets/{architectureDiagram-ZJ3FMSHR-CvRhdovL.js → architectureDiagram-ZJ3FMSHR-Dc-lvdUh.js} +1 -1
  10. package/dist/assets/{blockDiagram-677ZJIJ3-DVYNkbR_.js → blockDiagram-677ZJIJ3-CcsoWpIY.js} +1 -1
  11. package/dist/assets/{book-open-w3160PZf.js → book-open-DZyssdCc.js} +1 -1
  12. package/dist/assets/{c4Diagram-LMCZKHZV-B1w-iwRe.js → c4Diagram-LMCZKHZV-Bsrtg6b2.js} +1 -1
  13. package/dist/assets/card-D7l-gWkY.js +1 -0
  14. package/dist/assets/channel-BSKkTPe8.js +1 -0
  15. package/dist/assets/channels-list-page-B3qW3T-B.js +8 -0
  16. package/dist/assets/chat-page-DUI_Jm6r.js +1 -0
  17. package/dist/assets/chunk-2Q5K7J3B-CDMOR1xZ.js +1 -0
  18. package/dist/assets/{chunk-32BRIVSS-kG3lg0bC.js → chunk-32BRIVSS-Bt08t8oG.js} +1 -1
  19. package/dist/assets/{chunk-52WLFC77-BLeB7iGk.js → chunk-52WLFC77-Ddx68Xzx.js} +1 -1
  20. package/dist/assets/{chunk-5FCAYU7R-BQga1Rr7.js → chunk-5FCAYU7R-B7p9_q55.js} +1 -1
  21. package/dist/assets/{chunk-5HE753X5-DU81hkcF.js → chunk-5HE753X5-D52KvdTm.js} +1 -1
  22. package/dist/assets/{chunk-5JV3BV7I-C2bAx0m7.js → chunk-5JV3BV7I-C329h8nI.js} +1 -1
  23. package/dist/assets/{chunk-5TONJI2A-BExIIgWY.js → chunk-5TONJI2A-BZyUBxWt.js} +1 -1
  24. package/dist/assets/{chunk-5VM5RSS4-C3XB05yh.js → chunk-5VM5RSS4-BUiYXZmu.js} +1 -1
  25. package/dist/assets/{chunk-7BUUIJ7U-JiyRtrGu.js → chunk-7BUUIJ7U-B7o-mn4r.js} +1 -1
  26. package/dist/assets/{chunk-BIQX33UG-BZRV20pI.js → chunk-BIQX33UG-Bey9GoRP.js} +1 -1
  27. package/dist/assets/{chunk-C7G6YPKG-AsyDSQ9j.js → chunk-C7G6YPKG-C6tosszM.js} +1 -1
  28. package/dist/assets/{chunk-CQNSW5MT-iN-fiXVA.js → chunk-CQNSW5MT-BNrdkgGQ.js} +1 -1
  29. package/dist/assets/{chunk-CYSBUYHQ-DhC_TRzI.js → chunk-CYSBUYHQ-DHODFeyB.js} +1 -1
  30. package/dist/assets/{chunk-EMLP6XTP-QFLK8R6d.js → chunk-EMLP6XTP-BcmLjrcq.js} +1 -1
  31. package/dist/assets/{chunk-EX3LRPZG-DzUwhkCz.js → chunk-EX3LRPZG-r-_eEtJI.js} +1 -1
  32. package/dist/assets/{chunk-FWX5IMBZ-DFelpZBy.js → chunk-FWX5IMBZ-DOObDWbf.js} +2 -2
  33. package/dist/assets/{chunk-HOUHSVGY-BMPwFEwN.js → chunk-HOUHSVGY-Bd0FnbWZ.js} +1 -1
  34. package/dist/assets/{chunk-ICXQ74PX-DH8NJMok.js → chunk-ICXQ74PX-ntNwAm4_.js} +1 -1
  35. package/dist/assets/{chunk-JG7HCLWE-D-95AsO4.js → chunk-JG7HCLWE-YtRpblZN.js} +1 -1
  36. package/dist/assets/{chunk-JWPE2WC7-DIaTv8kx.js → chunk-JWPE2WC7-De5-D9ta.js} +1 -1
  37. package/dist/assets/{chunk-MOJQB5TN-BPFLzWgj.js → chunk-MOJQB5TN-CdvKhyp2.js} +1 -1
  38. package/dist/assets/{chunk-MOZMSUNE-DR_fzxG0.js → chunk-MOZMSUNE-DJMMN_lu.js} +1 -1
  39. package/dist/assets/{chunk-OGEWGWER-TIcEoPPH.js → chunk-OGEWGWER-DOFWVw3O.js} +1 -1
  40. package/dist/assets/{chunk-OSBZ3O6U-BALNvSfG.js → chunk-OSBZ3O6U-DZkrIN9r.js} +1 -1
  41. package/dist/assets/{chunk-PUDLZKDR-I-EXhf_k.js → chunk-PUDLZKDR-D1wma2Yf.js} +1 -1
  42. package/dist/assets/{chunk-Q4XR5HBZ-uvIGstBS.js → chunk-Q4XR5HBZ-CjPy94Lz.js} +1 -1
  43. package/dist/assets/{chunk-QBLGF6JB-r-TjLdxa.js → chunk-QBLGF6JB-Hy1bEgS-.js} +1 -1
  44. package/dist/assets/{chunk-R7FJI6CG-N-1LDgvy.js → chunk-R7FJI6CG-CUPIHyh-.js} +1 -1
  45. package/dist/assets/{chunk-RYQCIY6F-jxNASx65.js → chunk-RYQCIY6F-D5Ua4pcv.js} +1 -1
  46. package/dist/assets/{chunk-U6XO7XAA-Cphbuc7q.js → chunk-U6XO7XAA-DaUQcqb7.js} +1 -1
  47. package/dist/assets/{chunk-V7JOEXUC-BLEuBf1s.js → chunk-V7JOEXUC-DX2zLfQe.js} +1 -1
  48. package/dist/assets/chunk-VAUOI2AC-BRvqNW76.js +1 -0
  49. package/dist/assets/{chunk-VR4S4FIN-BAUbR0ke.js → chunk-VR4S4FIN-CFA-WQik.js} +1 -1
  50. package/dist/assets/{chunk-WYO6CB5R-Do6SJrnY.js → chunk-WYO6CB5R-Bk2HeDvJ.js} +2 -2
  51. package/dist/assets/chunk-XXDRQBXY-CwX_mqJ3.js +1 -0
  52. package/dist/assets/{chunk-YOTPTUD7-CQqvMTCr.js → chunk-YOTPTUD7-DUG4FpBN.js} +1 -1
  53. package/dist/assets/{chunk-ZGVPDNZ5-B7kWWaXv.js → chunk-ZGVPDNZ5-70JdIGo0.js} +1 -1
  54. package/dist/assets/{chunk-ZIRB5QZD-DTU0cDNh.js → chunk-ZIRB5QZD-XZdgBt5L.js} +1 -1
  55. package/dist/assets/classDiagram-OUVF2IWQ-RzbGxG77.js +1 -0
  56. package/dist/assets/classDiagram-v2-EOCWNBFH-C_gWB7WT.js +1 -0
  57. package/dist/assets/config-split-page-DFEKStD7.js +1 -0
  58. package/dist/assets/confirm-dialog-7wpxfMCp.js +5 -0
  59. package/dist/assets/{cose-bilkent-JH36ORCC-B9LrtV-q.js → cose-bilkent-JH36ORCC-B-PQoGX-.js} +1 -1
  60. package/dist/assets/cynefin-VYW2F7L2-fSLIS0X3.js +1 -0
  61. package/dist/assets/{cynefinDiagram-TSTJHNR4-BfjvW4su.js → cynefinDiagram-TSTJHNR4-BoLCPEM0.js} +1 -1
  62. package/dist/assets/{dagre-DkiXZKkL.js → dagre-D7Ie4eXr.js} +1 -1
  63. package/dist/assets/{dagre-VKFMJZFB-B1pQKQSY.js → dagre-VKFMJZFB-CKRrwZA-.js} +1 -1
  64. package/dist/assets/desktop-update-config-DP6IbxBO.js +1 -0
  65. package/dist/assets/{diagram-FQU43EPY-cB4EZdaP.js → diagram-FQU43EPY-CASL1J3_.js} +1 -1
  66. package/dist/assets/{diagram-G47NLZAW-CtW8im1B.js → diagram-G47NLZAW-CvLPBIzf.js} +1 -1
  67. package/dist/assets/{diagram-NH7WQ7WH-BDCtrCCm.js → diagram-NH7WQ7WH-Ba6fGdYP.js} +1 -1
  68. package/dist/assets/{diagram-OA4YK3LP-DEMJ42Gt.js → diagram-OA4YK3LP-DkpfgEjM.js} +1 -1
  69. package/dist/assets/{diagram-WEI45ONY-CdCcxSYU.js → diagram-WEI45ONY-BP5UMVsN.js} +1 -1
  70. package/dist/assets/{dist-DEJlYi0E.js → dist-B9UN0HrS.js} +1 -1
  71. package/dist/assets/doc-browser-D7klPMHs.js +1 -0
  72. package/dist/assets/{doc-browser-context-CpvHiuQG.js → doc-browser-context-Bw9m83Jp.js} +1 -1
  73. package/dist/assets/doc-browser-wgEeLkn1.js +1 -0
  74. package/dist/assets/{docx-preview-zis3U0Fa.js → docx-preview-D0tp3a9T.js} +1 -1
  75. package/dist/assets/{ebnfDiagram-CCIWWBDH-DBZETBwE.js → ebnfDiagram-CCIWWBDH-TJKbUcmc.js} +1 -1
  76. package/dist/assets/{erDiagram-Q63AITRT-y2zDXprP.js → erDiagram-Q63AITRT-DzGPKkKH.js} +1 -1
  77. package/dist/assets/eventmodeling-45OFAUF4-XVcQGgha.js +1 -0
  78. package/dist/assets/eye-IVMB0Rrz.js +1 -0
  79. package/dist/assets/flowDiagram-23GEKE2U-BiFSctqz.js +1 -0
  80. package/dist/assets/{form-actions-5OsDRt0g.js → form-actions-DrFAgO58.js} +1 -1
  81. package/dist/assets/{ganttDiagram-NO4QXBWP-D2DP344e.js → ganttDiagram-NO4QXBWP-JhJzsGp2.js} +1 -1
  82. package/dist/assets/gitGraph-TEB2WS4Q-C014uXqS.js +1 -0
  83. package/dist/assets/{gitGraphDiagram-IHSO6WYX-D37uiwA2.js → gitGraphDiagram-IHSO6WYX-DZ1CKMj8.js} +1 -1
  84. package/dist/assets/index-D297NGOb.js +2 -0
  85. package/dist/assets/index-DqZoodZL.css +1 -0
  86. package/dist/assets/info-DKCQHKI2-CQ2qjGhU.js +1 -0
  87. package/dist/assets/{infoDiagram-FWYZ7A6U-CG-WAIRi.js → infoDiagram-FWYZ7A6U-BNXNKfRQ.js} +1 -1
  88. package/dist/assets/{ishikawaDiagram-FXEZZL3T-WeCTnW0f.js → ishikawaDiagram-FXEZZL3T-DoiEfjNw.js} +1 -1
  89. package/dist/assets/{journeyDiagram-5HDEW3XC-DUFBW9Td.js → journeyDiagram-5HDEW3XC-D6oK2HSy.js} +1 -1
  90. package/dist/assets/{kanban-definition-HUTT4EX6-B0lxgMpg.js → kanban-definition-HUTT4EX6-B2UnLOH-.js} +1 -1
  91. package/dist/assets/{line-B78frP_c.js → line-BM7PoxY5.js} +1 -1
  92. package/dist/assets/{linear-C6lVEcb2.js → linear-B3DiqMjk.js} +1 -1
  93. package/dist/assets/loader-circle-DDgFo4Kv.js +1 -0
  94. package/dist/assets/{logo-badge-TdPa95AC.js → logo-badge-DoZOVuPr.js} +1 -1
  95. package/dist/assets/{map-Bdri5UL5.js → map-BAAdHTqR.js} +1 -1
  96. package/dist/assets/mcp-marketplace-page-BtNExfMn.js +1 -0
  97. package/dist/assets/{mcp-marketplace-page-cm3ifaKu.js → mcp-marketplace-page-C151EGP-.js} +2 -2
  98. package/dist/assets/{mermaid-parser.core-Cue18vLo.js → mermaid-parser.core-BeMviefY.js} +2 -2
  99. package/dist/assets/{mermaid.core-CXwWRh5i.js → mermaid.core-D0Q77r9I.js} +3 -3
  100. package/dist/assets/{mindmap-definition-LN4V7U3C-CFxz0P0-.js → mindmap-definition-LN4V7U3C-BQ7r7bR8.js} +1 -1
  101. package/dist/assets/model-config-page-BmfQzc52.js +1 -0
  102. package/dist/assets/navigation-link-CJw6FLOj.js +1 -0
  103. package/dist/assets/{ordinal-Cbd8t4LB.js → ordinal-Bt2N4IkA.js} +1 -1
  104. package/dist/assets/packet-7NZHBO7P-6IFyydij.js +1 -0
  105. package/dist/assets/{pegDiagram-2B236MQR-B_Qt9zyT.js → pegDiagram-2B236MQR-B-C9-LGz.js} +1 -1
  106. package/dist/assets/pie-RZYD4A2V-spXQC_wr.js +1 -0
  107. package/dist/assets/{pieDiagram-ENE6RG2P-CRQdSuwS.js → pieDiagram-ENE6RG2P-CtirZLtn.js} +1 -1
  108. package/dist/assets/plus-CYxLSfLh.js +1 -0
  109. package/dist/assets/{popover-EulxhA0q.js → popover-DitLJE6k.js} +1 -1
  110. package/dist/assets/provider-scoped-model-input-CuAtduIc.js +1 -0
  111. package/dist/assets/providers-config-page-CrmuY4DC.js +1 -0
  112. package/dist/assets/{quadrantDiagram-ABIIQ3AL-D5kPpttq.js → quadrantDiagram-ABIIQ3AL-DiBWAzDU.js} +1 -1
  113. package/dist/assets/radar-I7S5WNFK-DWVA8lvY.js +1 -0
  114. package/dist/assets/railroad-3IZDKUUU-Ce51u8y1.js +1 -0
  115. package/dist/assets/railroad-abnf-AHOZXSZD-D7i7cqI_.js +1 -0
  116. package/dist/assets/railroad-ebnf-EBAXGLYW-BEg2hcPs.js +1 -0
  117. package/dist/assets/railroad-peg-LSFZ7HO6-CxROSzbi.js +1 -0
  118. package/dist/assets/{railroadDiagram-RFXS5EU6-DGh_TGlQ.js → railroadDiagram-RFXS5EU6-CP6b3PBI.js} +1 -1
  119. package/dist/assets/{react-Bb0EYsLS.js → react-CTDaaQ9V.js} +1 -1
  120. package/dist/assets/{refresh-cw-CexL11m1.js → refresh-cw-E5qTlQY6.js} +1 -1
  121. package/dist/assets/remote-YzPpOPmK.js +1 -0
  122. package/dist/assets/{requirementDiagram-TGXJPOKE-EmFph0H_.js → requirementDiagram-TGXJPOKE-D8YV0-Jz.js} +1 -1
  123. package/dist/assets/rotate-cw-BXeiDT6C.js +1 -0
  124. package/dist/assets/runtime-config-page-1fPJJvo5.js +1 -0
  125. package/dist/assets/{sankeyDiagram-HTMAVEWB-BXWB5Ugi.js → sankeyDiagram-HTMAVEWB-C2vA4ojE.js} +1 -1
  126. package/dist/assets/{save-DtccrZld.js → save-CTiZvAd2.js} +1 -1
  127. package/dist/assets/{search-BArc_WOX.js → search-CztGmpnR.js} +1 -1
  128. package/dist/assets/search-config-page-D3jVALZU.js +1 -0
  129. package/dist/assets/secrets-config-page-CxWLQCjZ.js +3 -0
  130. package/dist/assets/security-config-DEyj4WBh.js +1 -0
  131. package/dist/assets/{select-C9FB0jlt.js → select-BPVI2dQ_.js} +1 -1
  132. package/dist/assets/{sequenceDiagram-DBY2YBRQ-ClKnO7v0.js → sequenceDiagram-DBY2YBRQ-B9LBmpUo.js} +1 -1
  133. package/dist/assets/settings-2-Cd7QaBsq.js +1 -0
  134. package/dist/assets/{sizeCapture-X5ZJPWSS-DSo-t5ou.js → sizeCapture-X5ZJPWSS-9UIfya9-.js} +1 -1
  135. package/dist/assets/skeleton-CUpAXGoe.js +1 -0
  136. package/dist/assets/{src-Dad2ZbCt.js → src-DKf77Yzo.js} +1 -1
  137. package/dist/assets/{stateDiagram-2N3HPSRC-BvAalBfz.js → stateDiagram-2N3HPSRC-oTW44vds.js} +1 -1
  138. package/dist/assets/stateDiagram-v2-6OUMAXLB-Bui4RXQK.js +1 -0
  139. package/dist/assets/{swimlanes-5IMT3BWC-DdVqVa1a.js → swimlanes-5IMT3BWC-Cf7lcsay.js} +2 -2
  140. package/dist/assets/swimlanesDiagram-G3AALYLV-DTwUsCBz.js +8 -0
  141. package/dist/assets/{tabs-D_mjyOOf.js → tabs-DrUmYwEQ.js} +1 -1
  142. package/dist/assets/{tag-chip-C011rd9q.js → tag-chip-CmViAZKK.js} +1 -1
  143. package/dist/assets/{timeline-definition-FHXFAJF6-D4ar8IQY.js → timeline-definition-FHXFAJF6-DoCuWKDJ.js} +1 -1
  144. package/dist/assets/{trash-2-bDhfsO1O.js → trash-2-DMRJ63AB.js} +1 -1
  145. package/dist/assets/treeView-QDETBFTQ-D5zsTiuL.js +1 -0
  146. package/dist/assets/treemap-6X3UGDF4-CR3dxqNs.js +1 -0
  147. package/dist/assets/{use-config-BNrlfEck.js → use-config-gpXy2Iyc.js} +1 -1
  148. package/dist/assets/use-confirm-dialog-Du33bHPz.js +1 -0
  149. package/dist/assets/{use-viewport-layout-P0q6Nt_N.js → use-viewport-layout-D80O1d90.js} +1 -1
  150. package/dist/assets/{vennDiagram-L72KCM5P-CDXJ_i3p.js → vennDiagram-L72KCM5P-CpU0pzGe.js} +1 -1
  151. package/dist/assets/wardley-OPB4EBWU-LatRT_Lx.js +1 -0
  152. package/dist/assets/{wardleyDiagram-EHGQE667-D-dSuT_7.js → wardleyDiagram-EHGQE667-CkN6nn6-.js} +1 -1
  153. package/dist/assets/x-CsLMuNFe.js +1 -0
  154. package/dist/assets/{xychartDiagram-FW5EYKEG-C9JCzsZF.js → xychartDiagram-FW5EYKEG-DATpapm2.js} +1 -1
  155. package/dist/index.html +31 -32
  156. package/dist/runtime-icons/opencode.svg +16 -0
  157. package/package.json +10 -9
  158. package/public/runtime-icons/opencode.svg +16 -0
  159. package/src/app/components/layout/__tests__/settings-entry-page.test.tsx +6 -4
  160. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +24 -12
  161. package/src/app/components/layout/sidebar-items.tsx +11 -2
  162. package/src/app/components/layout/sidebar.tsx +33 -234
  163. package/src/app/configs/app-navigation.config.ts +10 -24
  164. package/src/app/index.tsx +0 -5
  165. package/src/features/channels/components/config/channel-form.tsx +26 -26
  166. package/src/features/channels/components/config/weixin-channel-auth-section.tsx +6 -7
  167. package/src/features/channels/pages/__tests__/channels-list-page.test.tsx +2 -2
  168. package/src/features/channels/pages/channels-list-page.tsx +33 -32
  169. package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +68 -7
  170. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +27 -0
  171. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +0 -8
  172. package/src/features/chat/components/conversation/chat-conversation-content.tsx +65 -21
  173. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +36 -12
  174. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +0 -7
  175. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +0 -1
  176. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +17 -8
  177. package/src/features/chat/components/layout/chat-page-shell.tsx +2 -2
  178. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +2 -23
  179. package/src/features/chat/components/layout/chat-sidebar.tsx +3 -12
  180. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +155 -93
  181. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +126 -93
  182. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +8 -0
  183. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +27 -13
  184. package/src/features/chat/features/message/components/__tests__/chat-inline-file-preview.test.tsx +15 -9
  185. package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +127 -49
  186. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +187 -20
  187. package/src/features/chat/features/message/components/chat-inline-content-surface.tsx +55 -0
  188. package/src/features/chat/features/message/components/chat-inline-file-preview.tsx +49 -71
  189. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +65 -55
  190. package/src/features/chat/features/message/components/chat-message-list.container.tsx +275 -267
  191. package/src/features/chat/features/message/hooks/__tests__/use-chat-message-virtualizer.test.tsx +163 -0
  192. package/src/features/chat/features/message/hooks/use-chat-message-virtualizer.ts +68 -0
  193. package/src/features/chat/features/message/utils/__tests__/chat-message-execution-summary.utils.test.ts +188 -0
  194. package/src/features/chat/features/message/utils/__tests__/chat-message-texts.utils.test.ts +14 -1
  195. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +33 -0
  196. package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +24 -9
  197. package/src/features/chat/features/message/utils/chat-message-execution-summary.utils.ts +178 -0
  198. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +44 -0
  199. package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +194 -0
  200. package/src/features/chat/features/message/utils/chat-message.utils.ts +5 -0
  201. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +151 -13
  202. package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +44 -70
  203. package/src/features/chat/features/ncp/hooks/use-ncp-session-message-history.ts +197 -0
  204. package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +21 -3
  205. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +7 -7
  206. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +2 -2
  207. package/src/features/chat/features/session/components/session-context-icon.tsx +1 -1
  208. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +5 -1
  209. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +1 -1
  210. package/src/features/chat/features/workspace/components/__tests__/workspace-file-content-preview.test.tsx +32 -10
  211. package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +5 -15
  212. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +62 -9
  213. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +6 -1
  214. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +1 -25
  215. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +190 -109
  216. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +9 -10
  217. package/src/features/chat/managers/chat-session-list.manager.ts +68 -27
  218. package/src/features/cron/components/__tests__/cron-config.test.tsx +260 -0
  219. package/src/features/cron/components/cron-config.tsx +392 -388
  220. package/src/features/cron/components/cron-job-detail-dialog.tsx +210 -0
  221. package/src/features/cron/components/cron-job-row.tsx +271 -0
  222. package/src/features/cron/components/cron-task-discovery.tsx +157 -0
  223. package/src/features/cron/hooks/use-cron-jobs.ts +3 -1
  224. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +3 -2
  225. package/src/features/marketplace/components/marketplace-external-skill-source-action.tsx +8 -6
  226. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +26 -40
  227. package/src/features/pwa/components/pwa-install-entry.tsx +45 -58
  228. package/src/features/remote/components/remote-access-page.tsx +128 -208
  229. package/src/features/settings/components/config/provider-auth-section.tsx +32 -17
  230. package/src/features/settings/components/config/provider-form.tsx +6 -6
  231. package/src/features/settings/components/config/provider-models-section.tsx +52 -46
  232. package/src/features/settings/components/config/secrets-config-form.tsx +78 -84
  233. package/src/features/settings/index.ts +0 -1
  234. package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +35 -1
  235. package/src/features/settings/pages/__tests__/model-config-page.test.tsx +18 -1
  236. package/src/features/settings/pages/__tests__/search-config-page.test.tsx +8 -0
  237. package/src/features/settings/pages/__tests__/secrets-config-page.test.tsx +18 -17
  238. package/src/features/settings/pages/appearance-settings-page.tsx +87 -64
  239. package/src/features/settings/pages/model-config-page.tsx +75 -70
  240. package/src/features/settings/pages/providers-config-page.tsx +107 -73
  241. package/src/features/settings/pages/search-config-page.tsx +159 -152
  242. package/src/features/settings/pages/secrets-config-page.tsx +6 -1
  243. package/src/features/system-status/components/config/runtime-agent-list-card.tsx +23 -22
  244. package/src/features/system-status/components/config/runtime-binding-list-card.tsx +23 -22
  245. package/src/features/system-status/components/config/runtime-config-editor.tsx +17 -7
  246. package/src/features/system-status/components/config/runtime-config-overview.tsx +0 -3
  247. package/src/features/system-status/components/config/runtime-entry-list-card.tsx +24 -23
  248. package/src/features/system-status/components/config/runtime-settings-card.tsx +59 -52
  249. package/src/features/system-status/components/desktop-update-config.tsx +117 -112
  250. package/src/features/system-status/components/runtime-control-card.tsx +62 -59
  251. package/src/features/system-status/components/runtime-presence-card.tsx +79 -98
  252. package/src/features/system-status/components/runtime-security-card.tsx +74 -62
  253. package/src/features/system-status/components/security-config.tsx +3 -4
  254. package/src/features/system-status/pages/runtime-config-page.tsx +6 -1
  255. package/src/platforms/desktop/components/desktop-app-shell.tsx +1 -1
  256. package/src/platforms/mobile/components/mobile-settings-shell.tsx +2 -2
  257. package/src/shared/components/__tests__/config-split-page.test.tsx +15 -3
  258. package/src/shared/components/__tests__/settings-page.test.tsx +31 -0
  259. package/src/shared/components/actions/__tests__/navigation-link.test.tsx +47 -0
  260. package/src/shared/components/actions/navigation-link.tsx +116 -0
  261. package/src/shared/components/common/__tests__/brand-header.test.tsx +5 -5
  262. package/src/shared/components/common/__tests__/searchable-model-input.test.tsx +24 -0
  263. package/src/shared/components/common/brand-header.tsx +12 -10
  264. package/src/shared/components/common/searchable-model-input.tsx +9 -10
  265. package/src/shared/components/config-split-page.tsx +70 -65
  266. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +6 -7
  267. package/src/shared/components/settings/setting-row.tsx +61 -30
  268. package/src/shared/components/settings/settings-page.tsx +34 -0
  269. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +23 -2
  270. package/src/shared/components/ui/actions/icon-action-button.tsx +9 -2
  271. package/src/shared/components/ui/overlays/sheet.tsx +142 -0
  272. package/src/shared/lib/api/ncp-session.types.ts +8 -2
  273. package/src/shared/lib/api/types.ts +22 -1
  274. package/src/shared/lib/api/utils/config.utils.ts +2 -1
  275. package/src/shared/lib/api/utils/ncp-session.utils.ts +25 -11
  276. package/src/shared/lib/i18n/locales/en-US/chat.json +32 -1
  277. package/src/shared/lib/i18n/locales/en-US/core.json +3 -3
  278. package/src/shared/lib/i18n/locales/en-US/cron.json +87 -17
  279. package/src/shared/lib/i18n/locales/zh-CN/chat.json +34 -3
  280. package/src/shared/lib/i18n/locales/zh-CN/core.json +6 -6
  281. package/src/shared/lib/i18n/locales/zh-CN/cron.json +80 -10
  282. package/src/shared/lib/transport/__tests__/remote.transport.test.ts +16 -4
  283. package/dist/assets/api-D0U10BcF.js +0 -13
  284. package/dist/assets/app-presenter-provider-Dffdm_Ek.js +0 -106
  285. package/dist/assets/appearance-settings-page-sfusZc2d.js +0 -1
  286. package/dist/assets/architecture-TIHT7OUA-ClwVFq-K.js +0 -1
  287. package/dist/assets/channel-BEHOSFc5.js +0 -1
  288. package/dist/assets/channels-list-page-Dkfe87Zq.js +0 -8
  289. package/dist/assets/chat-page-CeapbQnG.js +0 -1
  290. package/dist/assets/chunk-2Q5K7J3B-DrIhesSX.js +0 -1
  291. package/dist/assets/chunk-VAUOI2AC-Dpcz6BhT.js +0 -1
  292. package/dist/assets/chunk-XXDRQBXY-C2QjjwYX.js +0 -1
  293. package/dist/assets/classDiagram-OUVF2IWQ-DESMaY3_.js +0 -1
  294. package/dist/assets/classDiagram-v2-EOCWNBFH-DwOlByYH.js +0 -1
  295. package/dist/assets/config-split-page-CnQI8cKT.js +0 -1
  296. package/dist/assets/confirm-dialog-RZUWA_j9.js +0 -5
  297. package/dist/assets/cynefin-VYW2F7L2-CzjeeOq9.js +0 -1
  298. package/dist/assets/desktop-update-config-CbSYQMYz.js +0 -1
  299. package/dist/assets/doc-browser-DwXHr-mm.js +0 -1
  300. package/dist/assets/doc-browser-jVTq8iY_2.js +0 -1
  301. package/dist/assets/download-BP7ZxrwI.js +0 -1
  302. package/dist/assets/eventmodeling-45OFAUF4-C38BqG8w.js +0 -1
  303. package/dist/assets/external-link-DvHCEe3h.js +0 -1
  304. package/dist/assets/eye-C--6dxv_.js +0 -1
  305. package/dist/assets/flowDiagram-23GEKE2U-BoKk8RRq.js +0 -1
  306. package/dist/assets/folder-BfeO1zCY.js +0 -1
  307. package/dist/assets/gitGraph-TEB2WS4Q-IsQHHJuS.js +0 -1
  308. package/dist/assets/index-BlKbckX4.css +0 -1
  309. package/dist/assets/index-DoZR11Nh.js +0 -2
  310. package/dist/assets/info-DKCQHKI2-ofy2qlHI.js +0 -1
  311. package/dist/assets/loader-circle-BWdgwVnn.js +0 -1
  312. package/dist/assets/mcp-marketplace-page-XnRWiC8c.js +0 -1
  313. package/dist/assets/model-config-page-CXnqSbSI.js +0 -1
  314. package/dist/assets/packet-7NZHBO7P-Rfopfa1o.js +0 -1
  315. package/dist/assets/pie-RZYD4A2V-CJR1xKEv.js +0 -1
  316. package/dist/assets/plus-BeApS21t.js +0 -1
  317. package/dist/assets/provider-scoped-model-input-ll_Btc9h.js +0 -1
  318. package/dist/assets/providers-config-page-Bcuhqkdl.js +0 -1
  319. package/dist/assets/radar-I7S5WNFK-CDg8Z-1r.js +0 -1
  320. package/dist/assets/railroad-3IZDKUUU-BHnNmjxO.js +0 -1
  321. package/dist/assets/railroad-abnf-AHOZXSZD-DGtNcusW.js +0 -1
  322. package/dist/assets/railroad-ebnf-EBAXGLYW-BRFtsQmm.js +0 -1
  323. package/dist/assets/railroad-peg-LSFZ7HO6-Bj5IypCA.js +0 -1
  324. package/dist/assets/remote-CqKpuOP9.js +0 -1
  325. package/dist/assets/rotate-cw-DHXoiqFB.js +0 -1
  326. package/dist/assets/runtime-config-page-D-Aqxizs.js +0 -1
  327. package/dist/assets/search-config-page-XTKf5rc0.js +0 -1
  328. package/dist/assets/secrets-config-page-Cx-qptcj.js +0 -3
  329. package/dist/assets/security-config-DWGFM2u9.js +0 -1
  330. package/dist/assets/setting-row-DFvioO2a.js +0 -1
  331. package/dist/assets/settings-2-RMWqf-ey.js +0 -1
  332. package/dist/assets/skeleton-DQ5WhuDG.js +0 -1
  333. package/dist/assets/stateDiagram-v2-6OUMAXLB-CfMU38yc.js +0 -1
  334. package/dist/assets/swimlanesDiagram-G3AALYLV-D9Zb9X57.js +0 -8
  335. package/dist/assets/treeView-QDETBFTQ-Uy7M0WvH.js +0 -1
  336. package/dist/assets/treemap-6X3UGDF4-BJfGV7KX.js +0 -1
  337. package/dist/assets/use-confirm-dialog-CTNA1PC0.js +0 -1
  338. package/dist/assets/wardley-OPB4EBWU-q263iF3K.js +0 -1
  339. package/dist/assets/x-qvh05iyu.js +0 -1
  340. package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +0 -86
  341. package/src/features/settings/pages/__tests__/language-settings-page.test.tsx +0 -36
  342. package/src/features/settings/pages/language-settings-page.tsx +0 -56
  343. package/src/shared/components/actions/action-link.tsx +0 -49
  344. /package/dist/assets/{array-BqYdCIE6.js → array-CAkJT3no.js} +0 -0
  345. /package/dist/assets/{chunk-KEIR6QF5-A3jEqwzn.js → chunk-KEIR6QF5-BgdDoWEH.js} +0 -0
  346. /package/dist/assets/{chunk-Y2CYZVJY-BGrd8tLy.js → chunk-Y2CYZVJY-pTllD0P3.js} +0 -0
  347. /package/dist/assets/{config-hints-LxG80Uj5.js → config-hints-S3g-UVZb.js} +0 -0
  348. /package/dist/assets/{cytoscape.esm-CRW8q92n.js → cytoscape.esm-DmURt-5G.js} +0 -0
  349. /package/dist/assets/{defaultLocale-Cdv9x6q7.js → defaultLocale-BKy_KP3O.js} +0 -0
  350. /package/dist/assets/{dist-dw-gAfM_.js → dist-IgNNB7K9.js} +0 -0
  351. /package/dist/assets/{graphlib-BcNFQr5y.js → graphlib-xw_TBHyH.js} +0 -0
  352. /package/dist/assets/{host-capabilities-CFbAfrrA.js → host-capabilities-B-TtABsP.js} +0 -0
  353. /package/dist/assets/{init-D8TjIqfm.js → init-C9xlLIAu.js} +0 -0
  354. /package/dist/assets/{jszip.min-CP5uPNQa.js → jszip.min-Das2IAnb.js} +0 -0
  355. /package/dist/assets/{katex-wEmrEFTg.js → katex-DSy1eD2d.js} +0 -0
  356. /package/dist/assets/{middleware-CAXxl-af.js → middleware-Df-a4x-q.js} +0 -0
  357. /package/dist/assets/{path-DzBnMI1r.js → path-DB0USYHi.js} +0 -0
  358. /package/dist/assets/{provider-models-BoUhFo9R.js → provider-models-CXUgDxGR.js} +0 -0
  359. /package/dist/assets/{rough.esm-wJ1d3nQl.js → rough.esm-B1B52ZQS.js} +0 -0
  360. /package/dist/assets/{xlsx-DUqJhg5u.js → xlsx-DfjC_iml.js} +0 -0
@@ -0,0 +1,210 @@
1
+ import { ExternalLink, Play, Trash2 } from "lucide-react";
2
+
3
+ import type { CronJobView } from "@/shared/lib/api";
4
+ import { Button } from "@/shared/components/ui/button";
5
+ import {
6
+ Sheet,
7
+ SheetContent,
8
+ SheetDescription,
9
+ SheetFooter,
10
+ SheetHeader,
11
+ SheetTitle,
12
+ } from "@/shared/components/ui/overlays/sheet";
13
+ import { Switch } from "@/shared/components/ui/switch";
14
+ import {
15
+ describeCronSchedule,
16
+ describeCronSession,
17
+ formatCronDate,
18
+ } from "@/shared/lib/cron";
19
+ import { t } from "@/shared/lib/i18n";
20
+ import { cn } from "@/shared/lib/utils";
21
+
22
+ function DetailRow({
23
+ label,
24
+ value,
25
+ }: {
26
+ readonly label: string;
27
+ readonly value: string;
28
+ }) {
29
+ return (
30
+ <div className="flex items-start justify-between gap-4 border-b border-border/50 py-3 last:border-b-0">
31
+ <span className="text-xs text-muted-foreground">{label}</span>
32
+ <span className="max-w-[65%] break-words text-right text-xs font-medium text-foreground">
33
+ {value}
34
+ </span>
35
+ </div>
36
+ );
37
+ }
38
+
39
+ type CronJobDetailDialogProps = {
40
+ readonly job: CronJobView | null;
41
+ readonly open: boolean;
42
+ readonly onDelete: (job: CronJobView) => void;
43
+ readonly onOpenChange: (open: boolean) => void;
44
+ readonly onOpenSession: (job: CronJobView) => void;
45
+ readonly onRun: (job: CronJobView) => void;
46
+ readonly onToggle: (job: CronJobView, enabled: boolean) => void;
47
+ };
48
+
49
+ export function CronJobDetailDialog({
50
+ job,
51
+ open,
52
+ onDelete,
53
+ onOpenChange,
54
+ onOpenSession,
55
+ onRun,
56
+ onToggle,
57
+ }: CronJobDetailDialogProps) {
58
+ if (!job) {
59
+ return null;
60
+ }
61
+
62
+ const sessionKey = describeCronSession(job);
63
+ const isBound = Boolean(job.payload.sessionId?.trim());
64
+ const canOpenSession = isBound || Boolean(job.state.lastRunAt);
65
+ const status = job.state.lastStatus
66
+ ? t(
67
+ `cronLastStatus${job.state.lastStatus[0].toUpperCase()}${job.state.lastStatus.slice(1)}`,
68
+ )
69
+ : t("cronNeverRun");
70
+
71
+ return (
72
+ <Sheet open={open} onOpenChange={onOpenChange}>
73
+ <SheetContent
74
+ side="right"
75
+ closeLabel={t("cronCloseDetails")}
76
+ className="flex w-full flex-col overflow-hidden p-0 sm:max-w-[510px]"
77
+ >
78
+ <SheetHeader className="shrink-0 border-b border-border/60 px-5 pb-5 pt-6 pr-14 sm:px-7 sm:pt-7">
79
+ <div className="mb-1 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
80
+ <span>{describeCronSchedule(job)}</span>
81
+ <span aria-hidden="true">·</span>
82
+ <span>
83
+ {isBound ? t("cronBoundSession") : t("cronDedicatedSession")}
84
+ </span>
85
+ </div>
86
+ <SheetTitle>{job.name || job.id}</SheetTitle>
87
+ <SheetDescription>{t("cronDetailDescription")}</SheetDescription>
88
+ </SheetHeader>
89
+
90
+ <div className="min-h-0 flex-1 space-y-6 overflow-y-auto px-5 py-6 sm:px-7">
91
+ <section>
92
+ <h3 className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
93
+ {t("cronTaskPrompt")}
94
+ </h3>
95
+ <div className="rounded-2xl bg-muted/55 px-4 py-3 text-sm leading-6 text-foreground">
96
+ {job.payload.message}
97
+ </div>
98
+ </section>
99
+
100
+ <section>
101
+ <h3 className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
102
+ {t("cronTaskDetails")}
103
+ </h3>
104
+ <div>
105
+ <DetailRow
106
+ label={t("cronScheduleLabel")}
107
+ value={describeCronSchedule(job)}
108
+ />
109
+ <DetailRow
110
+ label={t("cronNextRun")}
111
+ value={formatCronDate(job.state.nextRunAt)}
112
+ />
113
+ <DetailRow
114
+ label={t("cronAgentLabel")}
115
+ value={job.payload.agentId?.trim() || "main"}
116
+ />
117
+ <DetailRow label={t("cronSessionLabel")} value={sessionKey} />
118
+ <DetailRow
119
+ label={t("cronCreatedAt")}
120
+ value={formatCronDate(job.createdAt)}
121
+ />
122
+ </div>
123
+ </section>
124
+
125
+ <section>
126
+ <div className="mb-2 flex items-center justify-between gap-4">
127
+ <div>
128
+ <h3 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
129
+ {t("cronLatestRun")}
130
+ </h3>
131
+ <p className="mt-1 text-xs text-muted-foreground">
132
+ {t("cronLatestRunHint")}
133
+ </p>
134
+ </div>
135
+ <span
136
+ className={cn(
137
+ "rounded-full px-2.5 py-1 text-xs font-medium",
138
+ job.state.lastStatus === "error"
139
+ ? "bg-red-50 text-red-700"
140
+ : job.state.lastStatus === "ok"
141
+ ? "bg-emerald-50 text-emerald-700"
142
+ : "bg-muted text-muted-foreground",
143
+ )}
144
+ >
145
+ {status}
146
+ </span>
147
+ </div>
148
+ <div className="rounded-2xl border border-border/60 px-4 py-1">
149
+ <DetailRow
150
+ label={t("cronLastRun")}
151
+ value={formatCronDate(job.state.lastRunAt)}
152
+ />
153
+ {job.state.lastError ? (
154
+ <DetailRow
155
+ label={t("cronLastError")}
156
+ value={job.state.lastError}
157
+ />
158
+ ) : null}
159
+ </div>
160
+ </section>
161
+
162
+ <section className="flex items-center justify-between rounded-2xl border border-border/60 px-4 py-3">
163
+ <div>
164
+ <div className="text-sm font-medium text-foreground">
165
+ {job.enabled ? t("cronEnabledState") : t("cronPaused")}
166
+ </div>
167
+ <div className="mt-0.5 text-xs text-muted-foreground">
168
+ {t("cronToggleHint")}
169
+ </div>
170
+ </div>
171
+ <Switch
172
+ checked={job.enabled}
173
+ onCheckedChange={(checked) => onToggle(job, checked)}
174
+ aria-label={job.enabled ? t("cronDisable") : t("cronEnable")}
175
+ />
176
+ </section>
177
+
178
+ {!canOpenSession ? (
179
+ <p className="text-xs text-muted-foreground">
180
+ {t("cronSessionAvailableAfterRun")}
181
+ </p>
182
+ ) : null}
183
+ </div>
184
+
185
+ <SheetFooter className="shrink-0 border-t border-border/60 bg-background px-5 py-4 sm:px-7">
186
+ <Button
187
+ variant="ghost"
188
+ className="text-red-600 hover:bg-red-50 hover:text-red-700"
189
+ onClick={() => onDelete(job)}
190
+ >
191
+ <Trash2 className="mr-2 h-4 w-4" />
192
+ {t("delete")}
193
+ </Button>
194
+ <Button
195
+ variant="outline"
196
+ onClick={() => onOpenSession(job)}
197
+ disabled={!canOpenSession}
198
+ >
199
+ <ExternalLink className="mr-2 h-4 w-4" />
200
+ {t("cronOpenSession")}
201
+ </Button>
202
+ <Button onClick={() => onRun(job)}>
203
+ <Play className="mr-2 h-4 w-4" />
204
+ {t("cronRunNow")}
205
+ </Button>
206
+ </SheetFooter>
207
+ </SheetContent>
208
+ </Sheet>
209
+ );
210
+ }
@@ -0,0 +1,271 @@
1
+ import { useState } from "react";
2
+ import {
3
+ CalendarClock,
4
+ Check,
5
+ Clock,
6
+ MoreVertical,
7
+ Pencil,
8
+ Play,
9
+ Trash2,
10
+ TriangleAlert,
11
+ } from "lucide-react";
12
+
13
+ import type { CronJobView } from "@/shared/lib/api";
14
+ import { Button } from "@/shared/components/ui/button";
15
+ import {
16
+ Popover,
17
+ PopoverContent,
18
+ PopoverTrigger,
19
+ } from "@/shared/components/ui/popover";
20
+ import { Switch } from "@/shared/components/ui/switch";
21
+ import {
22
+ Tooltip,
23
+ TooltipContent,
24
+ TooltipProvider,
25
+ TooltipTrigger,
26
+ } from "@/shared/components/ui/tooltip";
27
+ import {
28
+ describeCronSchedule,
29
+ describeCronSession,
30
+ formatCronDate,
31
+ formatRelativeTime,
32
+ } from "@/shared/lib/cron";
33
+ import { t } from "@/shared/lib/i18n";
34
+ import { cn } from "@/shared/lib/utils";
35
+
36
+ function CronJobStatus({ job }: { readonly job: CronJobView }) {
37
+ const needsAttention = job.state.lastStatus === "error";
38
+ const label = needsAttention
39
+ ? t("cronNeedsAttention")
40
+ : job.enabled
41
+ ? t("cronRunningNormally")
42
+ : t("cronPaused");
43
+
44
+ return (
45
+ <span
46
+ className={cn(
47
+ "inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] font-medium",
48
+ needsAttention
49
+ ? "bg-red-50 text-red-700"
50
+ : job.enabled
51
+ ? "bg-emerald-50 text-emerald-700"
52
+ : "bg-muted text-muted-foreground",
53
+ )}
54
+ >
55
+ <span
56
+ className={cn(
57
+ "h-1.5 w-1.5 rounded-full",
58
+ needsAttention
59
+ ? "bg-red-500"
60
+ : job.enabled
61
+ ? "bg-emerald-500"
62
+ : "bg-muted-foreground/50",
63
+ )}
64
+ />
65
+ {label}
66
+ </span>
67
+ );
68
+ }
69
+
70
+ type CronJobRowProps = {
71
+ readonly expanded: boolean;
72
+ readonly job: CronJobView;
73
+ readonly onDelete: (job: CronJobView) => void;
74
+ readonly onEdit: (job: CronJobView) => void;
75
+ readonly onRun: (job: CronJobView) => void;
76
+ readonly onToggleExpanded: (job: CronJobView) => void;
77
+ readonly onToggle: (job: CronJobView, enabled: boolean) => void;
78
+ };
79
+
80
+ export function CronJobRow({
81
+ expanded,
82
+ job,
83
+ onDelete,
84
+ onEdit,
85
+ onRun,
86
+ onToggleExpanded,
87
+ onToggle,
88
+ }: CronJobRowProps) {
89
+ const [menuOpen, setMenuOpen] = useState(false);
90
+ const isBound = Boolean(job.payload.sessionId?.trim());
91
+ const needsAttention = job.state.lastStatus === "error";
92
+ const StatusIcon = needsAttention ? TriangleAlert : Check;
93
+ const jobLabel = job.name || job.id;
94
+ const previewId = `cron-job-preview-${job.id}`;
95
+
96
+ return (
97
+ <div
98
+ className={cn(
99
+ "group relative rounded-xl border-b border-border/55 transition-colors duration-150 last:border-b-0 hover:bg-muted/35 focus-within:bg-muted/35",
100
+ expanded && "bg-muted/35",
101
+ )}
102
+ >
103
+ <div className="flex items-center gap-3 px-1 py-3.5">
104
+ <button
105
+ type="button"
106
+ className="grid min-w-0 flex-1 grid-cols-[36px_minmax(0,1fr)] items-center gap-3 rounded-lg pr-16 text-left focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
107
+ aria-controls={previewId}
108
+ aria-expanded={expanded}
109
+ aria-label={`${t(expanded ? "cronCollapseTask" : "cronExpandTask")} ${jobLabel}`}
110
+ onClick={() => onToggleExpanded(job)}
111
+ >
112
+ <span
113
+ className={cn(
114
+ "flex h-9 w-9 items-center justify-center rounded-xl",
115
+ needsAttention
116
+ ? "bg-amber-50 text-amber-600"
117
+ : "bg-emerald-50 text-emerald-600",
118
+ )}
119
+ >
120
+ <StatusIcon className="h-4 w-4" aria-hidden="true" />
121
+ </span>
122
+ <span className="min-w-0">
123
+ <span className="flex flex-wrap items-center gap-2">
124
+ <strong className="truncate text-[13px] font-semibold text-foreground">
125
+ {jobLabel}
126
+ </strong>
127
+ <CronJobStatus job={job} />
128
+ <span className="rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
129
+ {isBound ? t("cronBoundSession") : t("cronDedicatedSession")}
130
+ </span>
131
+ {job.deleteAfterRun ? (
132
+ <span className="rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground">
133
+ {t("cronOneShot")}
134
+ </span>
135
+ ) : null}
136
+ </span>
137
+ <span className="mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-muted-foreground">
138
+ <span className="inline-flex items-center gap-1">
139
+ <CalendarClock className="h-3.5 w-3.5" aria-hidden="true" />
140
+ {describeCronSchedule(job)}
141
+ </span>
142
+ {job.state.nextRunAt ? (
143
+ <span className="inline-flex items-center gap-1">
144
+ <Clock className="h-3.5 w-3.5" aria-hidden="true" />
145
+ {t("cronNextRun")} {formatRelativeTime(job.state.nextRunAt)}
146
+ </span>
147
+ ) : null}
148
+ </span>
149
+ </span>
150
+ </button>
151
+
152
+ <TooltipProvider delayDuration={250}>
153
+ <div className="relative flex shrink-0 items-center">
154
+ <div className="absolute right-11 top-1/2 flex -translate-y-1/2 items-center gap-0.5 opacity-100 transition-opacity duration-150 [@media(hover:hover)]:pointer-events-none [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-focus-within:pointer-events-auto [@media(hover:hover)]:group-focus-within:opacity-100 [@media(hover:hover)]:group-hover:pointer-events-auto [@media(hover:hover)]:group-hover:opacity-100">
155
+ <Tooltip>
156
+ <TooltipTrigger asChild>
157
+ <Button
158
+ variant="ghost"
159
+ size="icon"
160
+ className="h-8 w-8"
161
+ onClick={() => onEdit(job)}
162
+ aria-label={`${t("edit")} ${jobLabel}`}
163
+ >
164
+ <Pencil className="h-3.5 w-3.5" />
165
+ </Button>
166
+ </TooltipTrigger>
167
+ <TooltipContent>{t("cronEditDetails")}</TooltipContent>
168
+ </Tooltip>
169
+
170
+ <Popover open={menuOpen} onOpenChange={setMenuOpen}>
171
+ <Tooltip>
172
+ <TooltipTrigger asChild>
173
+ <PopoverTrigger asChild>
174
+ <Button
175
+ variant="ghost"
176
+ size="icon"
177
+ className="h-8 w-8"
178
+ aria-label={`${t("cronMoreActions")} ${jobLabel}`}
179
+ >
180
+ <MoreVertical className="h-4 w-4" />
181
+ </Button>
182
+ </PopoverTrigger>
183
+ </TooltipTrigger>
184
+ <TooltipContent>{t("cronMoreActions")}</TooltipContent>
185
+ </Tooltip>
186
+ <PopoverContent align="end" sideOffset={4} className="w-40 p-1">
187
+ <button
188
+ type="button"
189
+ onClick={() => {
190
+ setMenuOpen(false);
191
+ onRun(job);
192
+ }}
193
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-foreground transition-colors hover:bg-muted"
194
+ >
195
+ <Play className="h-3.5 w-3.5 text-muted-foreground" />
196
+ {t("cronRunNow")}
197
+ </button>
198
+ <button
199
+ type="button"
200
+ onClick={() => {
201
+ setMenuOpen(false);
202
+ onDelete(job);
203
+ }}
204
+ className="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm text-red-600 transition-colors hover:bg-red-50"
205
+ >
206
+ <Trash2 className="h-3.5 w-3.5" />
207
+ {t("delete")}
208
+ </button>
209
+ </PopoverContent>
210
+ </Popover>
211
+ </div>
212
+ <Switch
213
+ checked={job.enabled}
214
+ onCheckedChange={(checked) => onToggle(job, checked)}
215
+ aria-label={job.enabled ? t("cronDisable") : t("cronEnable")}
216
+ />
217
+ </div>
218
+ </TooltipProvider>
219
+ </div>
220
+
221
+ <div
222
+ id={previewId}
223
+ aria-hidden={!expanded}
224
+ className={cn(
225
+ "grid transition-[grid-template-rows,opacity] duration-200 ease-out",
226
+ expanded
227
+ ? "grid-rows-[1fr] opacity-100"
228
+ : "grid-rows-[0fr] opacity-0",
229
+ )}
230
+ >
231
+ <div className="overflow-hidden">
232
+ <div className="mb-3 ml-12 mr-1 rounded-xl bg-background/70 px-4 py-3">
233
+ <div className="text-[10px] font-semibold uppercase tracking-[0.1em] text-muted-foreground">
234
+ {t("cronTaskPrompt")}
235
+ </div>
236
+ <p className="mt-1.5 line-clamp-4 text-xs leading-5 text-foreground">
237
+ {job.payload.message}
238
+ </p>
239
+ <dl className="mt-3 grid gap-x-5 gap-y-2 border-t border-border/50 pt-3 text-[11px] sm:grid-cols-3">
240
+ <div className="min-w-0">
241
+ <dt className="text-muted-foreground">{t("cronAgentLabel")}</dt>
242
+ <dd className="mt-0.5 truncate font-medium text-foreground">
243
+ {job.payload.agentId?.trim() || "main"}
244
+ </dd>
245
+ </div>
246
+ <div className="min-w-0">
247
+ <dt className="text-muted-foreground">
248
+ {t("cronSessionLabel")}
249
+ </dt>
250
+ <dd className="mt-0.5 truncate font-medium text-foreground">
251
+ {describeCronSession(job)}
252
+ </dd>
253
+ </div>
254
+ <div className="min-w-0">
255
+ <dt className="text-muted-foreground">{t("cronLastRun")}</dt>
256
+ <dd className="mt-0.5 truncate font-medium text-foreground">
257
+ {formatCronDate(job.state.lastRunAt)}
258
+ </dd>
259
+ </div>
260
+ </dl>
261
+ {job.state.lastError ? (
262
+ <p className="mt-3 line-clamp-2 border-t border-red-100 pt-3 text-[11px] leading-5 text-red-700">
263
+ {job.state.lastError}
264
+ </p>
265
+ ) : null}
266
+ </div>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ );
271
+ }
@@ -0,0 +1,157 @@
1
+ import { forwardRef, type FormEvent } from "react";
2
+ import {
3
+ ArrowUp,
4
+ BookOpen,
5
+ CalendarDays,
6
+ ChartNoAxesColumnIncreasing,
7
+ Heart,
8
+ Lightbulb,
9
+ Newspaper,
10
+ Sparkles,
11
+ type LucideIcon,
12
+ } from "lucide-react";
13
+
14
+ import { Button } from "@/shared/components/ui/button";
15
+ import { Input } from "@/shared/components/ui/input";
16
+ import { t } from "@/shared/lib/i18n";
17
+ import { cn } from "@/shared/lib/utils";
18
+
19
+ type CronTemplate = {
20
+ readonly descriptionKey: string;
21
+ readonly icon: LucideIcon;
22
+ readonly promptKey: string;
23
+ readonly titleKey: string;
24
+ };
25
+
26
+ const CRON_TEMPLATES: readonly CronTemplate[] = [
27
+ {
28
+ titleKey: "cronTemplateAiNewsTitle",
29
+ descriptionKey: "cronTemplateAiNewsDescription",
30
+ promptKey: "cronTemplateAiNewsPrompt",
31
+ icon: Newspaper,
32
+ },
33
+ {
34
+ titleKey: "cronTemplateWeeklyReviewTitle",
35
+ descriptionKey: "cronTemplateWeeklyReviewDescription",
36
+ promptKey: "cronTemplateWeeklyReviewPrompt",
37
+ icon: ChartNoAxesColumnIncreasing,
38
+ },
39
+ {
40
+ titleKey: "cronTemplateMeetingPrepTitle",
41
+ descriptionKey: "cronTemplateMeetingPrepDescription",
42
+ promptKey: "cronTemplateMeetingPrepPrompt",
43
+ icon: CalendarDays,
44
+ },
45
+ {
46
+ titleKey: "cronTemplateLearningTitle",
47
+ descriptionKey: "cronTemplateLearningDescription",
48
+ promptKey: "cronTemplateLearningPrompt",
49
+ icon: BookOpen,
50
+ },
51
+ {
52
+ titleKey: "cronTemplateCompetitorTitle",
53
+ descriptionKey: "cronTemplateCompetitorDescription",
54
+ promptKey: "cronTemplateCompetitorPrompt",
55
+ icon: Lightbulb,
56
+ },
57
+ {
58
+ titleKey: "cronTemplateFamilyTitle",
59
+ descriptionKey: "cronTemplateFamilyDescription",
60
+ promptKey: "cronTemplateFamilyPrompt",
61
+ icon: Heart,
62
+ },
63
+ ];
64
+
65
+ type CronTaskComposerProps = {
66
+ readonly prominent?: boolean;
67
+ readonly value: string;
68
+ readonly onChange: (value: string) => void;
69
+ readonly onSubmit: () => void;
70
+ };
71
+
72
+ export const CronTaskComposer = forwardRef<
73
+ HTMLInputElement,
74
+ CronTaskComposerProps
75
+ >(function CronTaskComposer(
76
+ { prominent = false, value, onChange, onSubmit },
77
+ ref,
78
+ ) {
79
+ const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
80
+ event.preventDefault();
81
+ onSubmit();
82
+ };
83
+
84
+ return (
85
+ <form
86
+ className={cn("relative w-full", prominent && "mx-auto max-w-3xl")}
87
+ onSubmit={handleSubmit}
88
+ >
89
+ <Sparkles
90
+ className="pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground/70"
91
+ aria-hidden="true"
92
+ />
93
+ <Input
94
+ ref={ref}
95
+ value={value}
96
+ onChange={(event) => onChange(event.target.value)}
97
+ className="pl-9 pr-11 focus:border-border/75"
98
+ placeholder={t("cronComposerPlaceholder")}
99
+ aria-label={t("cronComposerLabel")}
100
+ />
101
+ <Button
102
+ type="submit"
103
+ size="icon"
104
+ className="absolute right-1 top-1/2 h-7 w-7 -translate-y-1/2 rounded-full shadow-none"
105
+ disabled={!value.trim()}
106
+ aria-label={t("cronComposerSubmit")}
107
+ >
108
+ <ArrowUp className="h-4 w-4" />
109
+ </Button>
110
+ </form>
111
+ );
112
+ });
113
+
114
+ type CronTemplateGalleryProps = {
115
+ readonly compact?: boolean;
116
+ readonly onSelect: (prompt: string) => void;
117
+ };
118
+
119
+ export function CronTemplateGallery({
120
+ compact = false,
121
+ onSelect,
122
+ }: CronTemplateGalleryProps) {
123
+ const templates = compact ? CRON_TEMPLATES.slice(0, 4) : CRON_TEMPLATES;
124
+
125
+ return (
126
+ <div
127
+ className={cn(
128
+ "grid gap-3 sm:grid-cols-2",
129
+ compact ? "xl:grid-cols-4" : "lg:grid-cols-3",
130
+ )}
131
+ >
132
+ {templates.map((template) => {
133
+ const Icon = template.icon;
134
+ return (
135
+ <button
136
+ key={template.titleKey}
137
+ type="button"
138
+ onClick={() => onSelect(t(template.promptKey))}
139
+ className="group grid min-h-24 grid-cols-[38px_minmax(0,1fr)] items-center gap-3 rounded-2xl border border-border/60 bg-card px-4 py-4 text-left transition-all hover:-translate-y-0.5 hover:border-primary/20 hover:shadow-[0_12px_30px_rgba(30,45,52,0.08)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border"
140
+ >
141
+ <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary">
142
+ <Icon className="h-4 w-4" aria-hidden="true" />
143
+ </span>
144
+ <span className="min-w-0">
145
+ <strong className="block text-sm font-medium text-foreground">
146
+ {t(template.titleKey)}
147
+ </strong>
148
+ <span className="mt-1 block text-xs leading-5 text-muted-foreground">
149
+ {t(template.descriptionKey)}
150
+ </span>
151
+ </span>
152
+ </button>
153
+ );
154
+ })}
155
+ </div>
156
+ );
157
+ }
@@ -7,11 +7,13 @@ import {
7
7
  } from '@/shared/lib/api';
8
8
  import { toast } from 'sonner';
9
9
  import { t } from '@/shared/lib/i18n';
10
+ import type { CronListQuery } from '@/shared/lib/api';
10
11
 
11
- export function useCronJobs(params: { all?: boolean } = { all: true }) {
12
+ export function useCronJobs(params: CronListQuery = { all: true }) {
12
13
  return useQuery({
13
14
  queryKey: ['cron', params],
14
15
  queryFn: () => fetchCronJobs(params),
16
+ placeholderData: (previousData) => previousData,
15
17
  staleTime: 10_000
16
18
  });
17
19
  }
@@ -356,10 +356,11 @@ describe("MarketplacePage", () => {
356
356
 
357
357
  render(<MarketplacePage forcedType="skills" />);
358
358
 
359
- const openButton = screen.getByRole("button", {
359
+ const sourceLink = screen.getByRole("link", {
360
360
  name: /SkillHub/i,
361
361
  });
362
- fireEvent.click(openButton);
362
+ expect(sourceLink.getAttribute("href")).toBe("https://skillhub.cn/");
363
+ fireEvent.click(sourceLink);
363
364
 
364
365
  expect(mocks.openExternalUrl).toHaveBeenCalledWith("https://skillhub.cn/");
365
366
  });
@@ -1,14 +1,16 @@
1
- import { ExternalActionLink } from "@/shared/components/actions/action-link";
2
- import { hostCapabilityManager } from "@/shared/lib/host-capabilities";
1
+ import { NavigationLink } from "@/shared/components/actions/navigation-link";
3
2
  import { t } from "@/shared/lib/i18n";
4
3
 
5
4
  const SKILLHUB_URL = "https://skillhub.cn/";
6
5
 
7
6
  export function MarketplaceExternalSkillSourceAction() {
8
7
  return (
9
- <ExternalActionLink
10
- label={t("marketplaceExternalSkillSourceTitle")}
11
- onClick={() => void hostCapabilityManager.openExternalUrl(SKILLHUB_URL)}
12
- />
8
+ <NavigationLink
9
+ href={SKILLHUB_URL}
10
+ external
11
+ className="h-7 shrink-0 px-1.5 text-[13px]"
12
+ >
13
+ {t("marketplaceExternalSkillSourceTitle")}
14
+ </NavigationLink>
13
15
  );
14
16
  }