@nextclaw/ui 0.15.24 → 0.15.26

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 (312) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-BcFJp_1X.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-Dp2ezlQn.js} +1 -1
  4. package/dist/assets/{api-BxPNDp30.js → api-CK3Fro7z.js} +6 -6
  5. package/dist/assets/appearance-settings-page-zqwWO8Dy.js +1 -0
  6. package/dist/assets/{arc-BvhODBXv.js → arc-CkgyPMyW.js} +1 -1
  7. package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +1 -0
  8. package/dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-CMd4cIjI.js} +1 -1
  9. package/dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-Bz3tbhet.js} +1 -1
  10. package/dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-D9hFNAGv.js} +1 -1
  11. package/dist/assets/channel-nBvMaVyP.js +1 -0
  12. package/dist/assets/{channels-list-page-DRaNWAxC.js → channels-list-page-CVCZBlCL.js} +2 -2
  13. package/dist/assets/chat-page-D4wehRTz.js +1 -0
  14. package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +1 -0
  15. package/dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-7NrjEITq.js} +1 -1
  16. package/dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-viIcqj9q.js} +1 -1
  17. package/dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-Vsu4J-VM.js} +1 -1
  18. package/dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-C-w6CQZK.js} +1 -1
  19. package/dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-CuKgJQ4W.js} +1 -1
  20. package/dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CYeiWZKb.js} +1 -1
  21. package/dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-DRCbfwIn.js} +1 -1
  22. package/dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-BvydOcm3.js} +1 -1
  23. package/dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-RlppOXKo.js} +1 -1
  24. package/dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-DAizzYwr.js} +1 -1
  25. package/dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-5eChJHca.js} +1 -1
  26. package/dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-YHPr53fv.js} +1 -1
  27. package/dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CK4D7Hz5.js} +1 -1
  28. package/dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-BmlDFIRW.js} +1 -1
  29. package/dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-D0ksHZZ9.js} +2 -2
  30. package/dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-DPkq8FCm.js} +1 -1
  31. package/dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-FAatv5fC.js} +1 -1
  32. package/dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DLkIi4F7.js} +1 -1
  33. package/dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DawOjNE3.js} +1 -1
  34. package/dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-Di52TorW.js} +1 -1
  35. package/dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-PfyK9w1-.js} +1 -1
  36. package/dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-C3jdH3Ty.js} +1 -1
  37. package/dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-CecHo-f0.js} +1 -1
  38. package/dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-f3IJh3sN.js} +1 -1
  39. package/dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DQFeUPxZ.js} +1 -1
  40. package/dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-BhUeG0y2.js} +1 -1
  41. package/dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-C3XpZ-2u.js} +1 -1
  42. package/dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-CAqa5klQ.js} +1 -1
  43. package/dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-D_WXezeD.js} +1 -1
  44. package/dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-CZ70oOtp.js} +1 -1
  45. package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +1 -0
  46. package/dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-B7AHEYYk.js} +1 -1
  47. package/dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-Dn9To_OI.js} +2 -2
  48. package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +1 -0
  49. package/dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BYEgRBk3.js} +1 -1
  50. package/dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-C6YtZDU0.js} +1 -1
  51. package/dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-DMuYtnHF.js} +1 -1
  52. package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +1 -0
  53. package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +1 -0
  54. package/dist/assets/config-split-page-CceNFvlY.js +1 -0
  55. package/dist/assets/confirm-dialog-CWeNYWZY.js +5 -0
  56. package/dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-Bc2Ex5Y3.js} +1 -1
  57. package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +1 -0
  58. package/dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-DVysQoGz.js} +1 -1
  59. package/dist/assets/{dagre-CMe101gk.js → dagre-CMhQ1cAG.js} +1 -1
  60. package/dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-RYyWpPJZ.js} +1 -1
  61. package/dist/assets/desktop-update-config-Dirc3bpt.js +1 -0
  62. package/dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-BD6KONdF.js} +1 -1
  63. package/dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-CGB2ptRR.js} +1 -1
  64. package/dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-DnkOI6cU.js} +1 -1
  65. package/dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-DF82RZ7P.js} +1 -1
  66. package/dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-Be2v7Ck9.js} +1 -1
  67. package/dist/assets/{dist-B4Pf5X3Q.js → dist-AYxkFx2B.js} +1 -1
  68. package/dist/assets/{dist-DHEWkGWX.js → dist-D9xtGgdL.js} +1 -1
  69. package/dist/assets/doc-browser-4Sud6dWw.js +1 -0
  70. package/dist/assets/doc-browser-D4x_yH5F.js +1 -0
  71. package/dist/assets/doc-browser-context-Cb7Z0j90.js +1 -0
  72. package/dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-BqwAjrj3.js} +1 -1
  73. package/dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-CP98OYk8.js} +1 -1
  74. package/dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-ZLlx8xfs.js} +1 -1
  75. package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +1 -0
  76. package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +1 -0
  77. package/dist/assets/form-actions-B2q4jgjE.js +1 -0
  78. package/dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-DXCDjHR2.js} +1 -1
  79. package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +1 -0
  80. package/dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-l2HWrTJp.js} +1 -1
  81. package/dist/assets/index-CdyTsSBu.css +1 -0
  82. package/dist/assets/index-Das_bw2h.js +107 -0
  83. package/dist/assets/info-DKCQHKI2-BIporNWb.js +1 -0
  84. package/dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-D-DjX-bn.js} +1 -1
  85. package/dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-y_Xy128F.js} +1 -1
  86. package/dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-DJn5xYcQ.js} +1 -1
  87. package/dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-DJVIOR21.js} +1 -1
  88. package/dist/assets/{line-CbyFs065.js → line-Cos7PIOj.js} +1 -1
  89. package/dist/assets/{linear-4DKtnZBS.js → linear-BtDLqtzF.js} +1 -1
  90. package/dist/assets/loader-circle-CpmBdaon.js +1 -0
  91. package/dist/assets/{map-CcZzEoz6.js → map-BKnQyvd0.js} +1 -1
  92. package/dist/assets/mcp-marketplace-page-CdOY3Sop.js +1 -0
  93. package/dist/assets/mcp-marketplace-page-DvjrfqEt.js +9 -0
  94. package/dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-XUNZhr2W.js} +2 -2
  95. package/dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-ySrvolIe.js} +3 -3
  96. package/dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-BypL9tei.js} +1 -1
  97. package/dist/assets/model-config-page-DfOLyQqR.js +1 -0
  98. package/dist/assets/{navigation-link-CAFOcXNg.js → navigation-link-MiiyoIjH.js} +2 -2
  99. package/dist/assets/{ordinal-BgLYtOZE.js → ordinal-CxxVWxYU.js} +1 -1
  100. package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +1 -0
  101. package/dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-D-U2KBGv.js} +1 -1
  102. package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +1 -0
  103. package/dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-CBi3GusJ.js} +1 -1
  104. package/dist/assets/plus-C8FkjpSZ.js +1 -0
  105. package/dist/assets/provider-scoped-model-input-DXzjr5l0.js +1 -0
  106. package/dist/assets/providers-config-page-CaO8WfZH.js +1 -0
  107. package/dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js} +1 -1
  108. package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +1 -0
  109. package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +1 -0
  110. package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +1 -0
  111. package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +1 -0
  112. package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +1 -0
  113. package/dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-D7Y2EqSd.js} +1 -1
  114. package/dist/assets/react-C8XFFvuz.js +8 -0
  115. package/dist/assets/{refresh-cw-CWDp_JnN.js → refresh-cw-a2VVeeAF.js} +1 -1
  116. package/dist/assets/remote-BJHXa4mB.js +1 -0
  117. package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-BiXNX1NN.js} +1 -1
  118. package/dist/assets/rotate-cw-DJ7UF3F2.js +1 -0
  119. package/dist/assets/runtime-config-page-BuA4A02z.js +1 -0
  120. package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-qzDeLztW.js} +1 -1
  121. package/dist/assets/{save-Cnr71JON.js → save-CGm23Yww.js} +1 -1
  122. package/dist/assets/{search-CCX11X2m.js → search-CH2t--sH.js} +1 -1
  123. package/dist/assets/search-config-page-BAmYqoAz.js +1 -0
  124. package/dist/assets/secrets-config-page-BlPOuql_.js +3 -0
  125. package/dist/assets/security-config-CbDiY2xr.js +1 -0
  126. package/dist/assets/{select-DvwBu99K.js → select-DnxxDpcV.js} +2 -2
  127. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-BtRbPQtL.js} +1 -1
  128. package/dist/assets/{settings-2-Dmv6zMne.js → settings-2-agnMYc8a.js} +1 -1
  129. package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-CMYvM3SL.js} +1 -1
  130. package/dist/assets/skeleton-XpqeWL62.js +1 -0
  131. package/dist/assets/{src-vgz8E_-O.js → src-Bw-mzbQb.js} +1 -1
  132. package/dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-BJ-mFeOz.js} +1 -1
  133. package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +1 -0
  134. package/dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-BsucVOO2.js} +2 -2
  135. package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +8 -0
  136. package/dist/assets/{tag-chip-gMPvx7n_.js → tag-chip-CPOc8b2N.js} +1 -1
  137. package/dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-Bicewlzo.js} +1 -1
  138. package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +1 -0
  139. package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +1 -0
  140. package/dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-BxOOnO9x.js} +1 -1
  141. package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +1 -0
  142. package/dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-Cl7NltMv.js} +1 -1
  143. package/dist/assets/x-odTHAtLZ.js +1 -0
  144. package/dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-DiMIxQ7N.js} +1 -1
  145. package/dist/index.html +21 -22
  146. package/package.json +8 -8
  147. package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +234 -0
  148. package/src/features/apps/components/app-marketplace-dialog.tsx +262 -0
  149. package/src/features/apps/components/app-package-card.tsx +268 -0
  150. package/src/features/apps/components/app-packages-panel.tsx +301 -0
  151. package/src/features/apps/components/apps-panel.tsx +11 -4
  152. package/src/features/apps/hooks/use-app-marketplace.ts +95 -0
  153. package/src/features/apps/hooks/use-app-packages.ts +59 -0
  154. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +27 -4
  155. package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +36 -5
  156. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +12 -13
  157. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +79 -2
  158. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +4 -4
  159. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +26 -5
  160. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +3 -0
  161. package/src/features/chat/features/conversation/hooks/use-system-object-reference-select.ts +27 -0
  162. package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +5 -0
  163. package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +102 -0
  164. package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +71 -120
  165. package/src/features/chat/features/input/input-surface-plugins/__tests__/context-reference-plugin.test.ts +265 -18
  166. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +7 -2
  167. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.utils.ts +124 -0
  168. package/src/features/chat/features/input/input-surface-plugins/context-reference-items.utils.ts +99 -15
  169. package/src/features/chat/features/input/input-surface-plugins/context-reference-plugin.utils.ts +143 -139
  170. package/src/features/chat/features/input/input-surface-plugins/panel-app-input-surface-items.utils.ts +116 -0
  171. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +1 -1
  172. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +53 -1
  173. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +5 -0
  174. package/src/features/chat/features/input/utils/chat-inline-token-composer.utils.ts +134 -0
  175. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +30 -101
  176. package/src/features/chat/features/input/utils/chat-system-object-reference.utils.test.ts +44 -0
  177. package/src/features/chat/features/input/utils/chat-system-object-reference.utils.ts +46 -0
  178. package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +40 -3
  179. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +66 -0
  180. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +13 -1
  181. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +653 -90
  182. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +12 -8
  183. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +401 -288
  184. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +54 -35
  185. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +79 -148
  186. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +156 -94
  187. package/src/features/chat/features/workspace/components/project-files/__tests__/workspace-directory-entry-menu.test.tsx +50 -0
  188. package/src/features/chat/features/workspace/components/project-files/workspace-directory-entry-menu.tsx +209 -0
  189. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +459 -0
  190. package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +112 -0
  191. package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +64 -0
  192. package/src/features/chat/features/workspace/hooks/use-workspace-explorer-layout.ts +85 -0
  193. package/src/features/chat/features/workspace/hooks/use-workspace-file-actions.ts +357 -0
  194. package/src/features/chat/features/workspace/utils/chat-workspace-file-path-mutation.utils.ts +58 -0
  195. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +23 -22
  196. package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -4
  197. package/src/features/chat/index.ts +1 -1
  198. package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +86 -60
  199. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +103 -99
  200. package/src/features/chat/managers/chat-composer-intent.manager.ts +37 -33
  201. package/src/features/chat/managers/chat-draft-intent.manager.ts +18 -2
  202. package/src/features/chat/managers/chat-thread.manager.ts +132 -128
  203. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +26 -40
  204. package/src/features/chat/stores/chat-thread.store.ts +53 -74
  205. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +38 -5
  206. package/src/features/inbox/components/inbox-reader-dialog.tsx +5 -3
  207. package/src/features/inbox/managers/inbox.manager.test.ts +28 -3
  208. package/src/features/inbox/managers/inbox.manager.ts +14 -4
  209. package/src/features/inbox/pages/inbox-page.test.ts +121 -2
  210. package/src/features/inbox/pages/inbox-page.tsx +5 -3
  211. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +85 -1
  212. package/src/features/marketplace/hooks/__tests__/use-marketplace.test.tsx +44 -1
  213. package/src/features/marketplace/hooks/use-marketplace-item-actions.ts +23 -2
  214. package/src/features/marketplace/hooks/use-marketplace.ts +10 -0
  215. package/src/features/marketplace/index.ts +4 -0
  216. package/src/features/panel-apps/index.ts +5 -1
  217. package/src/features/panel-apps/utils/__tests__/panel-app-doc-browser.utils.test.ts +13 -6
  218. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +6 -3
  219. package/src/features/right-panel-resources/index.ts +1 -0
  220. package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +7 -4
  221. package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +20 -1
  222. package/src/features/system-status/components/desktop-update-config.tsx +14 -13
  223. package/src/features/system-status/managers/__tests__/runtime-update.manager.test.ts +99 -0
  224. package/src/features/system-status/managers/runtime-update.manager.ts +22 -0
  225. package/src/features/system-status/stores/runtime-update.store.ts +1 -0
  226. package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +35 -38
  227. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +25 -19
  228. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +15 -0
  229. package/src/shared/components/ui/actions/icon-action-button.tsx +4 -2
  230. package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +60 -34
  231. package/src/shared/components/ui/context-menu/context-menu.tsx +95 -68
  232. package/src/shared/hooks/use-system-object-references.ts +22 -0
  233. package/src/shared/lib/api/managers/client.manager.ts +31 -17
  234. package/src/shared/lib/api/server-path/server-path.types.ts +66 -0
  235. package/src/shared/lib/api/types.ts +155 -116
  236. package/src/shared/lib/api/utils/server-path.utils.ts +35 -11
  237. package/src/shared/lib/i18n/locales/en-US/chat.json +58 -9
  238. package/src/shared/lib/i18n/locales/en-US/desktop-update.json +7 -4
  239. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +40 -0
  240. package/src/shared/lib/i18n/locales/en-US/marketplace.json +3 -0
  241. package/src/shared/lib/i18n/locales/zh-CN/chat.json +60 -11
  242. package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +7 -4
  243. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +40 -0
  244. package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +3 -0
  245. package/dist/assets/appearance-settings-page-DpVJjvkB.js +0 -1
  246. package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
  247. package/dist/assets/channel-5T3pdR-s.js +0 -1
  248. package/dist/assets/chat-page-BuFDmG5_.js +0 -1
  249. package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
  250. package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
  251. package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
  252. package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
  253. package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
  254. package/dist/assets/config-split-page-BVWVDbvG.js +0 -1
  255. package/dist/assets/confirm-dialog-mA2iVzxh.js +0 -5
  256. package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
  257. package/dist/assets/desktop-update-config-DyQb1LXr.js +0 -1
  258. package/dist/assets/doc-browser-CtO_HtRy.js +0 -1
  259. package/dist/assets/doc-browser-context-CuGI6PQc.js +0 -1
  260. package/dist/assets/doc-browser-eMUagyBV.js +0 -1
  261. package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
  262. package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
  263. package/dist/assets/form-actions-BOfIyG3O.js +0 -1
  264. package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
  265. package/dist/assets/index-BjBdWHV1.js +0 -107
  266. package/dist/assets/index-DmpmjAGQ.css +0 -1
  267. package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
  268. package/dist/assets/loader-circle-Df8wF2Pr.js +0 -1
  269. package/dist/assets/mcp-marketplace-page-DI49IKxp.js +0 -1
  270. package/dist/assets/mcp-marketplace-page-ofDqbOIF.js +0 -9
  271. package/dist/assets/model-config-page-D73Tu3jW.js +0 -1
  272. package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
  273. package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
  274. package/dist/assets/plus-DVU5RLCS.js +0 -1
  275. package/dist/assets/provider-scoped-model-input-BaJJJYMX.js +0 -1
  276. package/dist/assets/providers-config-page-BL6IRVBm.js +0 -1
  277. package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
  278. package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
  279. package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
  280. package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
  281. package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
  282. package/dist/assets/react-BC_orpAj.js +0 -8
  283. package/dist/assets/remote-T24O58lH.js +0 -1
  284. package/dist/assets/rotate-cw-BqhwSV5p.js +0 -1
  285. package/dist/assets/runtime-config-page-CXUx017t.js +0 -1
  286. package/dist/assets/search-config-page-BB6d5gT7.js +0 -1
  287. package/dist/assets/secrets-config-page-DYsDeT9K.js +0 -3
  288. package/dist/assets/security-config-CVPgqL7G.js +0 -1
  289. package/dist/assets/skeleton-C5tWata3.js +0 -1
  290. package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
  291. package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
  292. package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
  293. package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
  294. package/dist/assets/use-confirm-dialog-D_3-QpZU.js +0 -1
  295. package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
  296. package/dist/assets/x-BEWSqeux.js +0 -1
  297. /package/dist/assets/{array-NADKd9aU.js → array-BQVzeGRt.js} +0 -0
  298. /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-f9psyCXK.js} +0 -0
  299. /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-D1mAU_Po.js} +0 -0
  300. /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-nV5HPOvq.js} +0 -0
  301. /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-0uDtdD0l.js} +0 -0
  302. /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-DSWXGgt0.js} +0 -0
  303. /package/dist/assets/{dist-DAPEIJbz.js → dist--ta5rX12.js} +0 -0
  304. /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CQ6QV4yP.js} +0 -0
  305. /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-Tk038i04.js} +0 -0
  306. /package/dist/assets/{init-D8wZg9xq.js → init-Y6h9jGtZ.js} +0 -0
  307. /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-8hyJpgpx.js} +0 -0
  308. /package/dist/assets/{katex-TZJFa0J_.js → katex-ARhY9PS1.js} +0 -0
  309. /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-DXsbf9xI.js} +0 -0
  310. /package/dist/assets/{path-DodfxcX7.js → path-10BjdyLh.js} +0 -0
  311. /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DxgC_14r.js} +0 -0
  312. /package/dist/assets/{xlsx-CxByi7bR.js → xlsx-DrDuDNAa.js} +0 -0
@@ -1,22 +1,32 @@
1
- import type { ReactNode } from "react";
1
+ import type { ReactNode } from 'react';
2
+ import type { ChatFileOpenActionViewModel } from '@nextclaw/agent-chat-ui';
2
3
  import {
3
4
  AlarmClock,
4
5
  ChevronRight,
5
6
  FolderTree,
6
7
  GitBranch,
7
8
  MessageSquarePlus,
8
- } from "lucide-react";
9
- import type { CronJobView } from "@/shared/lib/api";
10
- import { usePresenter } from "@/features/chat/components/providers/chat-presenter.provider";
11
- import { SessionConversationArea } from "@/features/chat/features/conversation/components/session-conversation-area";
12
- import { ChatSessionWorkspaceFilePreview } from "@/features/chat/features/workspace/components/chat-session-workspace-file-preview";
13
- import { ChatSessionWorkspaceDirectoryBrowser } from "@/features/chat/features/workspace/components/chat-session-workspace-directory-browser";
14
- import { SessionCronJobContent } from "@/features/chat/features/workspace/components/session-cron-job-content";
15
- import type { ResolvedChildSessionTab } from "@/features/chat/features/ncp/hooks/use-ncp-child-session-tabs-view";
16
- import type { WorkspaceSelection } from "@/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils";
17
- import { useServerPathBrowse } from "@/shared/hooks/use-server-path-browse";
18
- import { t } from "@/shared/lib/i18n";
19
- import { cn } from "@/shared/lib/utils";
9
+ PanelLeftClose,
10
+ PanelLeftOpen,
11
+ } from 'lucide-react';
12
+ import type { CronJobView } from '@/shared/lib/api';
13
+ import { usePresenter } from '@/features/chat/components/providers/chat-presenter.provider';
14
+ import { SessionConversationArea } from '@/features/chat/features/conversation/components/session-conversation-area';
15
+ import { ChatSessionWorkspaceFilePreview } from '@/features/chat/features/workspace/components/chat-session-workspace-file-preview';
16
+ import { ChatSessionWorkspaceDirectoryBrowser } from '@/features/chat/features/workspace/components/chat-session-workspace-directory-browser';
17
+ import { SessionCronJobContent } from '@/features/chat/features/workspace/components/session-cron-job-content';
18
+ import type { ResolvedChildSessionTab } from '@/features/chat/features/ncp/hooks/use-ncp-child-session-tabs-view';
19
+ import type { WorkspaceSelection } from '@/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils';
20
+ import { useServerPathBrowse } from '@/shared/hooks/use-server-path-browse';
21
+ import {
22
+ CHAT_WORKSPACE_EXPLORER_MAX_WIDTH,
23
+ CHAT_WORKSPACE_EXPLORER_MIN_WIDTH,
24
+ } from '@/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils';
25
+ import { useWorkspaceExplorerLayout } from '@/features/chat/features/workspace/hooks/use-workspace-explorer-layout';
26
+ import { t } from '@/shared/lib/i18n';
27
+ import { resolveWorkspaceRelativePath } from '@/shared/lib/session-project';
28
+ import { cn } from '@/shared/lib/utils';
29
+ import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
20
30
 
21
31
  type ChatSessionWorkspacePanelContentProps = {
22
32
  activeSelection: WorkspaceSelection;
@@ -53,15 +63,13 @@ function WorkspaceOverviewEntry({
53
63
  <span className="min-w-0 flex-1">
54
64
  <span className="flex items-center gap-2 text-sm font-medium text-gray-900">
55
65
  <span className="truncate">{title}</span>
56
- {typeof count === "number" ? (
66
+ {typeof count === 'number' ? (
57
67
  <span className="rounded-full bg-gray-100 px-1.5 py-0.5 text-[10px] font-semibold tabular-nums text-gray-500">
58
68
  {count}
59
69
  </span>
60
70
  ) : null}
61
71
  </span>
62
- <span className="mt-0.5 block text-xs leading-5 text-gray-500">
63
- {description}
64
- </span>
72
+ <span className="mt-0.5 block text-xs leading-5 text-gray-500">{description}</span>
65
73
  </span>
66
74
  <ChevronRight className="h-4 w-4 shrink-0 text-gray-300 transition-transform group-hover:translate-x-0.5 group-hover:text-gray-500" />
67
75
  </button>
@@ -82,18 +90,14 @@ function WorkspaceOverview({
82
90
  return (
83
91
  <div className="h-full overflow-auto bg-gray-50/45 px-4 py-5 custom-scrollbar">
84
92
  <div className="mx-auto max-w-xl">
85
- <h2 className="text-base font-semibold text-gray-900">
86
- {t("chatWorkspaceOverview")}
87
- </h2>
88
- <p className="mt-1 text-xs leading-5 text-gray-500">
89
- {t("chatWorkspaceOverviewDescription")}
90
- </p>
93
+ <h2 className="text-base font-semibold text-gray-900">{t('chatWorkspaceOverview')}</h2>
94
+ <p className="mt-1 text-xs leading-5 text-gray-500">{t('chatWorkspaceOverviewDescription')}</p>
91
95
  <div className="mt-4 space-y-2">
92
96
  <WorkspaceOverviewEntry
93
97
  count={childSessionTabs.length}
94
- description={t("chatWorkspaceChildSessionsDescription")}
98
+ description={t('chatWorkspaceChildSessionsDescription')}
95
99
  icon={<GitBranch className="h-4 w-4" />}
96
- title={t("chatWorkspaceChildSessions")}
100
+ title={t('chatWorkspaceChildSessions')}
97
101
  onClick={() => {
98
102
  if (sessionKey) {
99
103
  presenter.chatThreadManager.openChildSessions(sessionKey);
@@ -102,9 +106,9 @@ function WorkspaceOverview({
102
106
  />
103
107
  <WorkspaceOverviewEntry
104
108
  count={sessionCronJobs.length}
105
- description={t("chatWorkspaceSessionCronJobsDescription")}
109
+ description={t('chatWorkspaceSessionCronJobsDescription')}
106
110
  icon={<AlarmClock className="h-4 w-4" />}
107
- title={t("chatWorkspaceSessionCronJobs")}
111
+ title={t('chatWorkspaceSessionCronJobs')}
108
112
  onClick={() => {
109
113
  if (sessionKey) {
110
114
  presenter.chatThreadManager.openSessionCronPanel(sessionKey);
@@ -112,9 +116,9 @@ function WorkspaceOverview({
112
116
  }}
113
117
  />
114
118
  <WorkspaceOverviewEntry
115
- description={t("chatWorkspaceProjectFilesDescription")}
119
+ description={t('chatWorkspaceProjectFilesDescription')}
116
120
  icon={<FolderTree className="h-4 w-4" />}
117
- title={t("chatWorkspaceProjectFiles")}
121
+ title={t('chatWorkspaceProjectFiles')}
118
122
  onClick={() => {
119
123
  if (sessionKey) {
120
124
  presenter.chatThreadManager.openProjectFiles(sessionKey);
@@ -127,28 +131,20 @@ function WorkspaceOverview({
127
131
  );
128
132
  }
129
133
 
130
- function WorkspaceChildSessions({
131
- childSessionTabs,
132
- }: {
133
- childSessionTabs: readonly ResolvedChildSessionTab[];
134
- }) {
134
+ function WorkspaceChildSessions({ childSessionTabs }: { childSessionTabs: readonly ResolvedChildSessionTab[] }) {
135
135
  const presenter = usePresenter();
136
136
 
137
137
  return (
138
138
  <div className="h-full overflow-auto bg-gray-50/45 px-4 py-5 custom-scrollbar">
139
139
  <div className="mx-auto max-w-xl">
140
140
  <div className="flex items-center gap-2">
141
- <h2 className="text-base font-semibold text-gray-900">
142
- {t("chatWorkspaceChildSessions")}
143
- </h2>
141
+ <h2 className="text-base font-semibold text-gray-900">{t('chatWorkspaceChildSessions')}</h2>
144
142
  <span className="rounded-full bg-gray-100 px-1.5 py-0.5 text-[10px] font-semibold tabular-nums text-gray-500">
145
143
  {childSessionTabs.length}
146
144
  </span>
147
145
  </div>
148
146
  {childSessionTabs.length === 0 ? (
149
- <div className="py-10 text-center text-sm text-gray-500">
150
- {t("chatWorkspaceChildSessionsEmpty")}
151
- </div>
147
+ <div className="py-10 text-center text-sm text-gray-500">{t('chatWorkspaceChildSessionsEmpty')}</div>
152
148
  ) : (
153
149
  <div className="mt-4 space-y-2">
154
150
  {childSessionTabs.map((tab) => (
@@ -156,24 +152,16 @@ function WorkspaceChildSessions({
156
152
  key={tab.sessionKey}
157
153
  type="button"
158
154
  className="group flex w-full items-center gap-3 rounded-lg border border-gray-200/80 bg-white px-3 py-3 text-left transition-colors hover:border-gray-300 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/25"
159
- onClick={() =>
160
- presenter.chatThreadManager.selectChildSessionDetail(
161
- tab.sessionKey,
162
- )
163
- }
155
+ onClick={() => presenter.chatThreadManager.selectChildSessionDetail(tab.sessionKey)}
164
156
  >
165
157
  <span className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-600">
166
158
  <GitBranch className="h-4 w-4" />
167
159
  </span>
168
160
  <span className="min-w-0 flex-1">
169
- <span className="block truncate text-sm font-medium text-gray-900">
170
- {tab.title}
171
- </span>
161
+ <span className="block truncate text-sm font-medium text-gray-900">{tab.title}</span>
172
162
  {tab.projectName || tab.sessionTypeLabel ? (
173
163
  <span className="mt-0.5 block truncate text-xs text-gray-500">
174
- {[tab.sessionTypeLabel, tab.projectName]
175
- .filter(Boolean)
176
- .join(" · ")}
164
+ {[tab.sessionTypeLabel, tab.projectName].filter(Boolean).join(' · ')}
177
165
  </span>
178
166
  ) : null}
179
167
  </span>
@@ -188,10 +176,14 @@ function WorkspaceChildSessions({
188
176
  }
189
177
 
190
178
  function WorkspaceProjectFiles({
179
+ activePath,
180
+ onFileOpen,
191
181
  projectRoot,
192
182
  sessionKey,
193
183
  workingDir,
194
184
  }: {
185
+ activePath: string | null;
186
+ onFileOpen?: (action: ChatFileOpenActionViewModel) => void;
195
187
  projectRoot: string | null;
196
188
  sessionKey: string | null;
197
189
  workingDir: string | null;
@@ -207,22 +199,25 @@ function WorkspaceProjectFiles({
207
199
  if (!rootPath) {
208
200
  return (
209
201
  <div className="flex h-full items-center justify-center px-6 text-center text-sm text-gray-500">
210
- {t("chatWorkspaceProjectFilesUnavailable")}
202
+ {t('chatWorkspaceProjectFilesUnavailable')}
211
203
  </div>
212
204
  );
213
205
  }
214
206
 
215
207
  return (
216
208
  <ChatSessionWorkspaceDirectoryBrowser
209
+ activeRelativePath={
210
+ activePath ? resolveWorkspaceRelativePath({ path: activePath, sessionProjectRoot: rootPath }) : null
211
+ }
217
212
  key={rootPath}
218
213
  browseQuery={browseQuery}
219
- onFileOpen={presenter.chatThreadManager.openFilePreview}
214
+ onFileOpen={onFileOpen ?? presenter.chatThreadManager.openFilePreview}
220
215
  sessionKey={sessionKey}
221
- renderStatus={({ text, tone = "muted" }) => (
216
+ renderStatus={({ text, tone = 'muted' }) => (
222
217
  <div
223
218
  className={cn(
224
- "flex h-full items-center justify-center px-6 text-center text-sm",
225
- tone === "error" ? "text-rose-600" : "text-gray-500",
219
+ 'flex h-full items-center justify-center px-6 text-center text-sm',
220
+ tone === 'error' ? 'text-rose-600' : 'text-gray-500',
226
221
  )}
227
222
  >
228
223
  {text}
@@ -242,11 +237,9 @@ function ChildSessionMetaChip({ value }: { value: string }) {
242
237
  }
243
238
 
244
239
  function ChildSessionMetaStrip({ tab }: { tab: ResolvedChildSessionTab }) {
245
- const metaItems = [
246
- tab.sessionTypeLabel,
247
- tab.preferredModel,
248
- tab.projectName,
249
- ].filter((value): value is string => Boolean(value?.trim()));
240
+ const metaItems = [tab.sessionTypeLabel, tab.preferredModel, tab.projectName].filter((value): value is string =>
241
+ Boolean(value?.trim()),
242
+ );
250
243
 
251
244
  if (metaItems.length === 0 && !tab.projectRoot) {
252
245
  return null;
@@ -274,11 +267,9 @@ function WorkspaceSideChatDraftHeader() {
274
267
  <div className="border-b border-gray-200/70 px-4 py-3">
275
268
  <div className="flex min-w-0 items-center gap-2 text-sm font-semibold text-gray-900">
276
269
  <MessageSquarePlus className="h-4 w-4 shrink-0 text-primary" />
277
- <span className="truncate">{t("chatWorkspaceSideChatDraftTitle")}</span>
270
+ <span className="truncate">{t('chatWorkspaceSideChatDraftTitle')}</span>
278
271
  </div>
279
- <p className="mt-1 text-xs leading-5 text-gray-500">
280
- {t("chatWorkspaceSideChatDraftSubtitle")}
281
- </p>
272
+ <p className="mt-1 text-xs leading-5 text-gray-500">{t('chatWorkspaceSideChatDraftSubtitle')}</p>
282
273
  </div>
283
274
  );
284
275
  }
@@ -291,10 +282,13 @@ function WorkspaceSelectedContent({
291
282
  sessionCronJobs,
292
283
  sessionProjectRoot,
293
284
  sessionWorkingDir,
294
- }: ChatSessionWorkspacePanelContentProps) {
285
+ explorerControl,
286
+ }: ChatSessionWorkspacePanelContentProps & {
287
+ explorerControl?: { open: boolean; onToggle: () => void };
288
+ }) {
295
289
  const presenter = usePresenter();
296
290
 
297
- if (activeSelection.kind === "overview") {
291
+ if (activeSelection.kind === 'overview') {
298
292
  return (
299
293
  <WorkspaceOverview
300
294
  childSessionTabs={childSessionTabs}
@@ -304,18 +298,18 @@ function WorkspaceSelectedContent({
304
298
  );
305
299
  }
306
300
 
307
- if (activeSelection.kind === "child-sessions") {
301
+ if (activeSelection.kind === 'child-sessions') {
308
302
  return <WorkspaceChildSessions childSessionTabs={childSessionTabs} />;
309
303
  }
310
304
 
311
- if (activeSelection.kind === "side-chat-draft") {
305
+ if (activeSelection.kind === 'side-chat-draft') {
312
306
  return (
313
307
  <>
314
308
  <WorkspaceSideChatDraftHeader />
315
309
  <div className="flex min-h-0 flex-1 flex-col">
316
310
  <SessionConversationArea
317
311
  materializationContext={{
318
- kind: "child",
312
+ kind: 'child',
319
313
  parentSessionKey: activeSelection.draft.parentSessionKey,
320
314
  inheritContext: true,
321
315
  }}
@@ -333,7 +327,7 @@ function WorkspaceSelectedContent({
333
327
  );
334
328
  }
335
329
 
336
- if (activeSelection.kind === "child-session") {
330
+ if (activeSelection.kind === 'child-session') {
337
331
  return (
338
332
  <>
339
333
  <ChildSessionMetaStrip tab={activeSelection.tab} />
@@ -344,9 +338,21 @@ function WorkspaceSelectedContent({
344
338
  );
345
339
  }
346
340
 
347
- if (activeSelection.kind === "file") {
341
+ if (activeSelection.kind === 'file') {
348
342
  return (
349
343
  <ChatSessionWorkspaceFilePreview
344
+ breadcrumbLeading={
345
+ <IconActionButton
346
+ data-testid="workspace-explorer-toggle"
347
+ icon={
348
+ explorerControl?.open ? <PanelLeftClose className="h-4 w-4" /> : <PanelLeftOpen className="h-4 w-4" />
349
+ }
350
+ label={t(explorerControl?.open ? 'chatWorkspaceHideProjectFiles' : 'chatWorkspaceShowProjectFiles')}
351
+ size="sm"
352
+ tooltipSide="bottom"
353
+ onClick={explorerControl?.onToggle}
354
+ />
355
+ }
350
356
  file={activeSelection.file}
351
357
  refreshVersion={filePreviewRefreshVersion}
352
358
  sessionProjectRoot={sessionProjectRoot}
@@ -365,41 +371,97 @@ function WorkspaceSelectedContent({
365
371
  return <SessionCronJobContent jobs={sessionCronJobs} />;
366
372
  }
367
373
 
368
- export function ChatSessionWorkspacePanelContent(
369
- {
370
- activeSelection,
371
- sessionKey,
372
- sessionProjectRoot,
373
- sessionWorkingDir,
374
- ...selectedContentProps
375
- }: ChatSessionWorkspacePanelContentProps,
376
- ) {
377
- const projectFilesActive = activeSelection.kind === "project-files";
374
+ export function ChatSessionWorkspacePanelContent({
375
+ activeSelection,
376
+ sessionKey,
377
+ sessionProjectRoot,
378
+ sessionWorkingDir,
379
+ ...selectedContentProps
380
+ }: ChatSessionWorkspacePanelContentProps) {
381
+ const projectFilesActive = activeSelection.kind === 'project-files';
382
+ const fileActive = activeSelection.kind === 'file';
383
+ const presenter = usePresenter();
384
+ const {
385
+ compact,
386
+ containerRef,
387
+ explorerOpen,
388
+ explorerOverlay,
389
+ explorerWidth,
390
+ onResizeStart,
391
+ setExplorerOpen,
392
+ showExplorer,
393
+ } = useWorkspaceExplorerLayout({ fileActive, projectFilesActive });
378
394
 
379
395
  return (
380
- <>
396
+ <div
397
+ ref={containerRef}
398
+ data-testid="workspace-shared-explorer-layout"
399
+ className="relative flex h-full min-h-0 flex-1 overflow-hidden"
400
+ >
401
+ {explorerOverlay ? (
402
+ <button
403
+ data-testid="workspace-explorer-scrim"
404
+ type="button"
405
+ aria-label={t('chatWorkspaceHideProjectFiles')}
406
+ className="absolute inset-0 z-10 bg-black/15"
407
+ onClick={() => setExplorerOpen(false)}
408
+ />
409
+ ) : null}
381
410
  <div
411
+ data-testid="workspace-shared-explorer"
412
+ data-mode={projectFilesActive ? 'full' : explorerOverlay ? 'overlay' : 'side'}
382
413
  className={cn(
383
- "min-h-0 flex-1 flex-col",
384
- projectFilesActive ? "flex" : "hidden",
414
+ 'relative min-h-0 shrink-0 flex-col border-r border-gray-200/80 bg-white',
415
+ showExplorer ? 'flex' : 'hidden',
416
+ projectFilesActive ? 'flex-1 border-r-0' : null,
417
+ explorerOverlay ? 'absolute inset-y-0 left-0 z-20 w-[min(320px,86%)] shadow-xl' : null,
385
418
  )}
386
- aria-hidden={!projectFilesActive}
419
+ style={!projectFilesActive && !explorerOverlay ? { width: explorerWidth } : undefined}
420
+ aria-hidden={!showExplorer}
387
421
  >
388
422
  <WorkspaceProjectFiles
423
+ activePath={fileActive ? activeSelection.file.path : null}
424
+ onFileOpen={(action) => {
425
+ if (compact) setExplorerOpen(false);
426
+ presenter.chatThreadManager.openFilePreview(action);
427
+ }}
389
428
  projectRoot={sessionProjectRoot}
390
429
  sessionKey={sessionKey}
391
430
  workingDir={sessionWorkingDir}
392
431
  />
432
+ {fileActive && !compact ? (
433
+ <div
434
+ data-testid="workspace-explorer-resize-handle"
435
+ aria-label={t('chatWorkspaceResizeProjectFiles')}
436
+ aria-orientation="vertical"
437
+ aria-valuemax={CHAT_WORKSPACE_EXPLORER_MAX_WIDTH}
438
+ aria-valuemin={CHAT_WORKSPACE_EXPLORER_MIN_WIDTH}
439
+ aria-valuenow={explorerWidth}
440
+ role="separator"
441
+ className="absolute inset-y-0 right-[-4px] z-20 w-2 cursor-ew-resize hover:bg-primary/10"
442
+ onPointerDown={onResizeStart}
443
+ />
444
+ ) : null}
393
445
  </div>
394
446
  {projectFilesActive ? null : (
395
- <WorkspaceSelectedContent
396
- {...selectedContentProps}
397
- activeSelection={activeSelection}
398
- sessionKey={sessionKey}
399
- sessionProjectRoot={sessionProjectRoot}
400
- sessionWorkingDir={sessionWorkingDir}
401
- />
447
+ <div className="min-w-0 min-h-0 flex-1">
448
+ <WorkspaceSelectedContent
449
+ {...selectedContentProps}
450
+ activeSelection={activeSelection}
451
+ explorerControl={
452
+ fileActive
453
+ ? {
454
+ open: explorerOpen,
455
+ onToggle: () => setExplorerOpen(!explorerOpen),
456
+ }
457
+ : undefined
458
+ }
459
+ sessionKey={sessionKey}
460
+ sessionProjectRoot={sessionProjectRoot}
461
+ sessionWorkingDir={sessionWorkingDir}
462
+ />
463
+ </div>
402
464
  )}
403
- </>
465
+ </div>
404
466
  );
405
467
  }
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { buildWorkspaceEntryContextMenuGroups } from "@/features/chat/features/workspace/components/project-files/workspace-directory-entry-menu";
3
+ import type { ServerPathEntryView } from "@/shared/lib/api";
4
+
5
+ function buildMenu(entry: ServerPathEntryView) {
6
+ return buildWorkspaceEntryContextMenuGroups({
7
+ busy: false,
8
+ downloadUrl: entry.kind === "file" ? "/download" : null,
9
+ entry,
10
+ onAddToChat: vi.fn(),
11
+ onCreateFile: vi.fn(),
12
+ onCreateFolder: vi.fn(),
13
+ onDelete: vi.fn(),
14
+ onOpen: vi.fn(),
15
+ onRenameRequest: vi.fn(),
16
+ onRevealPath: vi.fn(),
17
+ onUpload: vi.fn(),
18
+ ownCreateTarget: { label: entry.name, path: entry.path, refresh: vi.fn() },
19
+ parentRefresh: vi.fn(),
20
+ relativePath: entry.name,
21
+ });
22
+ }
23
+
24
+ function visibleGroupKeys(entry: ServerPathEntryView) {
25
+ return buildMenu(entry)
26
+ .filter((group) => group.items.length > 0)
27
+ .map((group) => group.key);
28
+ }
29
+
30
+ describe("workspace directory entry context menus", () => {
31
+ it("keeps Open exclusive to files", () => {
32
+ expect(
33
+ visibleGroupKeys({
34
+ name: "src",
35
+ path: "/workspace/src",
36
+ kind: "directory",
37
+ hidden: false,
38
+ }),
39
+ ).toEqual(["nextclaw", "manage", "path", "rename", "danger"]);
40
+
41
+ expect(
42
+ visibleGroupKeys({
43
+ name: "app.ts",
44
+ path: "/workspace/app.ts",
45
+ kind: "file",
46
+ hidden: false,
47
+ }),
48
+ ).toEqual(["open", "nextclaw", "path", "rename", "danger"]);
49
+ });
50
+ });