@nextclaw/ui 0.15.25 → 0.15.27

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 (334) hide show
  1. package/CHANGELOG.md +34 -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-FK7tikI1.js → api-a_GaOFc7.js} +6 -6
  5. package/dist/assets/appearance-settings-page-DlGXLgff.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-CocdcIko.js → channels-list-page-BEEk4Uc9.js} +2 -2
  13. package/dist/assets/chat-page-DUQXXqQm.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-ps1Aod3g.js +1 -0
  55. package/dist/assets/confirm-dialog-DJSUNG33.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--zagjHic.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-CaYdVVeO.js → dist-BkTYNzm_.js} +1 -1
  68. package/dist/assets/{dist-BH7W5yCi.js → dist-DkR7_Dpl.js} +1 -1
  69. package/dist/assets/doc-browser-DahzJEWj.js +1 -0
  70. package/dist/assets/doc-browser-Q67TOGVS.js +1 -0
  71. package/dist/assets/doc-browser-context-BQim8SqD.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-0c0aw_bl.js → form-actions-B2-bpFie.js} +1 -1
  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-Ba_o5fu9.js +109 -0
  82. package/dist/assets/index-DSLK7zgR.css +1 -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-DyXZU92l.js +1 -0
  91. package/dist/assets/{map-CcZzEoz6.js → map-BKnQyvd0.js} +1 -1
  92. package/dist/assets/mcp-marketplace-page-B0dBE5CV.js +1 -0
  93. package/dist/assets/mcp-marketplace-page-w8panjZG.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-rrhFaque.js +1 -0
  98. package/dist/assets/{navigation-link-CVy0_kVl.js → navigation-link-mpHFXwRr.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-Dhb4KuMH.js +1 -0
  105. package/dist/assets/provider-scoped-model-input-CFsfWEt9.js +1 -0
  106. package/dist/assets/providers-config-page-D-TYFZsF.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-BlXwvOLo.js +8 -0
  115. package/dist/assets/{refresh-cw-j2bl79Ea.js → refresh-cw-JFuyDj_P.js} +1 -1
  116. package/dist/assets/remote-BwVv_Qq-.js +1 -0
  117. package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-BiXNX1NN.js} +1 -1
  118. package/dist/assets/rotate-cw-DjbbiIW_.js +1 -0
  119. package/dist/assets/runtime-config-page-Br9j9Vxe.js +1 -0
  120. package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-qzDeLztW.js} +1 -1
  121. package/dist/assets/{save-BKNrtK81.js → save-BL8P8CLX.js} +1 -1
  122. package/dist/assets/{search-CkOm65W_.js → search-bZL75Pgc.js} +1 -1
  123. package/dist/assets/search-config-page-B3fvzMd1.js +1 -0
  124. package/dist/assets/secrets-config-page-ClwTxtXd.js +3 -0
  125. package/dist/assets/security-config-DmJw9QZA.js +1 -0
  126. package/dist/assets/{select-Ea7ffKCE.js → select-rUZ8nIZu.js} +2 -2
  127. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-BtRbPQtL.js} +1 -1
  128. package/dist/assets/{settings-2-CtyN3m_V.js → settings-2-BI4SCkxQ.js} +1 -1
  129. package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-CMYvM3SL.js} +1 -1
  130. package/dist/assets/skeleton-CVmEPG43.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-C9l4xsKp.js → tag-chip-BdI_yIOA.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-BcEayhV6.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 +6 -6
  147. package/src/app/components/layout/app-layout.tsx +38 -2
  148. package/src/app/hooks/__tests__/use-app-event-consumers.test.ts +20 -0
  149. package/src/app/hooks/use-app-event-consumers.ts +21 -0
  150. package/src/app/presenters/app.presenter.ts +6 -0
  151. package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +312 -0
  152. package/src/features/apps/components/__tests__/apps-panel.test.tsx +58 -0
  153. package/src/features/apps/components/app-artwork.tsx +49 -0
  154. package/src/features/apps/components/app-marketplace-catalog.tsx +332 -0
  155. package/src/features/apps/components/app-marketplace-cover.tsx +64 -0
  156. package/src/features/apps/components/app-marketplace-detail.tsx +161 -0
  157. package/src/features/apps/components/app-marketplace-dialog.tsx +152 -0
  158. package/src/features/apps/components/app-marketplace-operation.tsx +84 -0
  159. package/src/features/apps/components/app-package-card.tsx +417 -0
  160. package/src/features/apps/components/app-packages-panel.tsx +373 -0
  161. package/src/features/apps/components/apps-panel.tsx +31 -23
  162. package/src/features/apps/hooks/use-app-marketplace.test.ts +144 -0
  163. package/src/features/apps/hooks/use-app-marketplace.ts +65 -0
  164. package/src/features/apps/hooks/use-app-packages.ts +114 -0
  165. package/src/features/apps/index.ts +1 -0
  166. package/src/features/apps/managers/__tests__/app-package-operation-settlement.manager.test.ts +81 -0
  167. package/src/features/apps/managers/app-package-operation-settlement.manager.ts +80 -0
  168. package/src/features/apps/services/app-marketplace.service.ts +223 -0
  169. package/src/features/apps/types/app-marketplace.types.ts +75 -0
  170. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +27 -4
  171. package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +36 -5
  172. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +12 -13
  173. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +49 -1
  174. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +68 -7
  175. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +25 -4
  176. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +3 -0
  177. package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +24 -14
  178. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +53 -0
  179. package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +18 -0
  180. package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +4 -1
  181. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +126 -32
  182. package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +12 -2
  183. package/src/features/chat/features/conversation/hooks/use-system-object-reference-select.ts +27 -0
  184. package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +5 -0
  185. package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +102 -0
  186. package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +71 -120
  187. package/src/features/chat/features/input/input-surface-plugins/__tests__/context-reference-plugin.test.ts +265 -18
  188. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +7 -2
  189. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.utils.ts +124 -0
  190. package/src/features/chat/features/input/input-surface-plugins/context-reference-items.utils.ts +99 -15
  191. package/src/features/chat/features/input/input-surface-plugins/context-reference-plugin.utils.ts +143 -139
  192. package/src/features/chat/features/input/input-surface-plugins/panel-app-input-surface-items.utils.ts +116 -0
  193. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +1 -1
  194. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +84 -1
  195. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +10 -0
  196. package/src/features/chat/features/input/utils/chat-inline-token-composer.utils.ts +148 -0
  197. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +55 -101
  198. package/src/features/chat/features/input/utils/chat-system-object-reference.utils.test.ts +44 -0
  199. package/src/features/chat/features/input/utils/chat-system-object-reference.utils.ts +46 -0
  200. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +8 -1
  201. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +155 -18
  202. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +12 -8
  203. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +80 -62
  204. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +9 -2
  205. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +83 -13
  206. package/src/features/chat/features/workspace/components/project-files/workspace-project-tree-view.tsx +93 -0
  207. package/src/features/chat/features/workspace/hooks/use-workspace-explorer-layout.ts +8 -11
  208. package/src/features/chat/features/workspace/hooks/use-workspace-file-actions.ts +68 -46
  209. package/src/features/chat/features/workspace/stores/__tests__/workspace-project-tree.store.test.ts +38 -0
  210. package/src/features/chat/features/workspace/stores/workspace-project-tree.store.ts +160 -0
  211. package/src/features/chat/index.ts +2 -1
  212. package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +29 -0
  213. package/src/features/chat/managers/chat-composer-intent.manager.ts +29 -2
  214. package/src/features/chat/managers/chat-draft-intent.manager.ts +18 -2
  215. package/src/features/chat/presenters/chat.presenter.ts +2 -2
  216. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +6 -0
  217. package/src/features/chat/stores/chat-thread.store.ts +6 -0
  218. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +38 -5
  219. package/src/features/inbox/components/inbox-reader-dialog.tsx +5 -3
  220. package/src/features/inbox/managers/inbox.manager.test.ts +28 -3
  221. package/src/features/inbox/managers/inbox.manager.ts +14 -4
  222. package/src/features/inbox/pages/inbox-page.test.ts +121 -2
  223. package/src/features/inbox/pages/inbox-page.tsx +5 -3
  224. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +85 -1
  225. package/src/features/marketplace/hooks/__tests__/use-marketplace.test.tsx +44 -1
  226. package/src/features/marketplace/hooks/use-marketplace-item-actions.ts +23 -2
  227. package/src/features/marketplace/hooks/use-marketplace.ts +10 -0
  228. package/src/features/marketplace/index.ts +4 -0
  229. package/src/features/panel-apps/components/__tests__/panel-apps-list.test.tsx +1 -1
  230. package/src/features/panel-apps/components/panel-apps-list.tsx +1 -6
  231. package/src/features/panel-apps/index.ts +5 -1
  232. package/src/features/panel-apps/utils/__tests__/panel-app-doc-browser.utils.test.ts +13 -6
  233. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +6 -3
  234. package/src/features/right-panel-resources/index.ts +1 -0
  235. package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-uri.utils.test.ts +34 -0
  236. package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +36 -4
  237. package/src/features/service-apps/components/service-apps-panel.tsx +3 -17
  238. package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +20 -1
  239. package/src/features/system-status/components/desktop-update-config.tsx +14 -13
  240. package/src/features/system-status/managers/__tests__/runtime-update.manager.test.ts +99 -0
  241. package/src/features/system-status/managers/runtime-update.manager.ts +22 -0
  242. package/src/features/system-status/stores/runtime-update.store.ts +1 -0
  243. package/src/platforms/desktop/components/desktop-app-shell.tsx +5 -0
  244. package/src/platforms/mobile/components/mobile-app-shell.tsx +9 -1
  245. package/src/shared/components/actions/__tests__/navigation-link.test.tsx +12 -0
  246. package/src/shared/components/actions/navigation-link.tsx +6 -3
  247. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +34 -0
  248. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +5 -0
  249. package/src/shared/components/doc-browser/doc-browser.tsx +11 -1
  250. package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +13 -0
  251. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +15 -0
  252. package/src/shared/components/ui/actions/icon-action-button.tsx +4 -2
  253. package/src/shared/components/ui/tabs.tsx +24 -1
  254. package/src/shared/hooks/use-server-path-watch.ts +42 -0
  255. package/src/shared/hooks/use-system-object-references.ts +22 -0
  256. package/src/shared/lib/api/server-path/server-path.types.ts +10 -0
  257. package/src/shared/lib/api/types.ts +13 -0
  258. package/src/shared/lib/api/utils/server-path.utils.ts +10 -0
  259. package/src/shared/lib/i18n/locales/en-US/chat.json +17 -9
  260. package/src/shared/lib/i18n/locales/en-US/desktop-update.json +7 -4
  261. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +82 -0
  262. package/src/shared/lib/i18n/locales/en-US/marketplace.json +3 -0
  263. package/src/shared/lib/i18n/locales/zh-CN/chat.json +19 -11
  264. package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +7 -4
  265. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +82 -0
  266. package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +3 -0
  267. package/vite.config.ts +32 -1
  268. package/dist/assets/appearance-settings-page-BYbvl2wj.js +0 -1
  269. package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
  270. package/dist/assets/channel-5T3pdR-s.js +0 -1
  271. package/dist/assets/chat-page-C5E-LLVd.js +0 -1
  272. package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
  273. package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
  274. package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
  275. package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
  276. package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
  277. package/dist/assets/config-split-page-CA_a0AJ5.js +0 -1
  278. package/dist/assets/confirm-dialog-CxZfenjK.js +0 -5
  279. package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
  280. package/dist/assets/desktop-update-config-BEKC8Ly9.js +0 -1
  281. package/dist/assets/doc-browser-Cl2ldE3f.js +0 -1
  282. package/dist/assets/doc-browser-DXCSd63E.js +0 -1
  283. package/dist/assets/doc-browser-context-FDPs3gJf.js +0 -1
  284. package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
  285. package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
  286. package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
  287. package/dist/assets/i18n-provider-DkITJNz8.js +0 -1
  288. package/dist/assets/index-CQ2LcI2p.css +0 -1
  289. package/dist/assets/index-CrdfvBVg.js +0 -107
  290. package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
  291. package/dist/assets/loader-circle-DHtUxCIA.js +0 -1
  292. package/dist/assets/mcp-marketplace-page-Bc_jI5iH.js +0 -9
  293. package/dist/assets/mcp-marketplace-page-CzCieD9r.js +0 -1
  294. package/dist/assets/model-config-page-C4jw-pcj.js +0 -1
  295. package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
  296. package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
  297. package/dist/assets/plus-CG1RwZQq.js +0 -1
  298. package/dist/assets/provider-scoped-model-input-CmH4BFvc.js +0 -1
  299. package/dist/assets/providers-config-page-CJQjwzaw.js +0 -1
  300. package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
  301. package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
  302. package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
  303. package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
  304. package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
  305. package/dist/assets/react-DjFBVA0n.js +0 -8
  306. package/dist/assets/remote-BIlpD3yL.js +0 -1
  307. package/dist/assets/rotate-cw-bKG8zH8M.js +0 -1
  308. package/dist/assets/runtime-config-page-B_x2Glz5.js +0 -1
  309. package/dist/assets/search-config-page-BaIijtmO.js +0 -1
  310. package/dist/assets/secrets-config-page-CJjtdFAl.js +0 -3
  311. package/dist/assets/security-config-DB8apj09.js +0 -1
  312. package/dist/assets/skeleton-Bt6zxcAB.js +0 -1
  313. package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
  314. package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
  315. package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
  316. package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
  317. package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
  318. package/dist/assets/x-CowtCu9Z.js +0 -1
  319. /package/dist/assets/{array-NADKd9aU.js → array-BQVzeGRt.js} +0 -0
  320. /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-f9psyCXK.js} +0 -0
  321. /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-D1mAU_Po.js} +0 -0
  322. /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-nV5HPOvq.js} +0 -0
  323. /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-0uDtdD0l.js} +0 -0
  324. /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-DSWXGgt0.js} +0 -0
  325. /package/dist/assets/{dist-DAPEIJbz.js → dist--ta5rX12.js} +0 -0
  326. /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CQ6QV4yP.js} +0 -0
  327. /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-Tk038i04.js} +0 -0
  328. /package/dist/assets/{init-D8wZg9xq.js → init-Y6h9jGtZ.js} +0 -0
  329. /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-8hyJpgpx.js} +0 -0
  330. /package/dist/assets/{katex-TZJFa0J_.js → katex-ARhY9PS1.js} +0 -0
  331. /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-DXsbf9xI.js} +0 -0
  332. /package/dist/assets/{path-DodfxcX7.js → path-10BjdyLh.js} +0 -0
  333. /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DxgC_14r.js} +0 -0
  334. /package/dist/assets/{xlsx-CxByi7bR.js → xlsx-DrDuDNAa.js} +0 -0
@@ -0,0 +1,160 @@
1
+ import { create } from 'zustand';
2
+ import { createJSONStorage, persist } from 'zustand/middleware';
3
+
4
+ const WORKSPACE_PROJECT_TREE_STORAGE_KEY = 'nextclaw.chat.workspace-project-tree.state';
5
+ const WORKSPACE_PROJECT_TREE_STORAGE_VERSION = 1;
6
+ const MAX_PERSISTED_PROJECT_TREES = 12;
7
+ const MAX_PERSISTED_EXPANDED_PATHS = 256;
8
+ const MAX_PERSISTED_SCROLL_TOP = 10_000_000;
9
+
10
+ export type WorkspaceProjectTreeViewState = {
11
+ expandedPaths: string[];
12
+ scrollTop: number;
13
+ updatedAt: number;
14
+ };
15
+
16
+ type WorkspaceProjectTreeStore = {
17
+ trees: Record<string, WorkspaceProjectTreeViewState>;
18
+ collapseAll: (rootPath: string) => void;
19
+ setDirectoryExpanded: (rootPath: string, relativePath: string, expanded: boolean) => void;
20
+ setScrollTop: (rootPath: string, scrollTop: number) => void;
21
+ };
22
+
23
+ type PersistedWorkspaceProjectTreeStore = Pick<WorkspaceProjectTreeStore, 'trees'>;
24
+
25
+ function isRecord(value: unknown): value is Record<string, unknown> {
26
+ return !!value && typeof value === 'object';
27
+ }
28
+
29
+ export function normalizeWorkspaceProjectTreeRootKey(path: string | null | undefined): string {
30
+ const normalized = path?.trim().replace(/\\/g, '/').replace(/\/+$/g, '') ?? '';
31
+ return normalized || (path?.trim() === '/' ? '/' : '');
32
+ }
33
+
34
+ export function normalizeWorkspaceProjectTreeRelativePath(path: string | null | undefined): string {
35
+ return path?.trim().replace(/\\/g, '/').replace(/^\/+|\/+$/g, '').replace(/\/{2,}/g, '/') ?? '';
36
+ }
37
+
38
+ function normalizeScrollTop(value: unknown): number {
39
+ if (typeof value !== 'number' || !Number.isFinite(value)) return 0;
40
+ return Math.min(Math.max(0, Math.round(value)), MAX_PERSISTED_SCROLL_TOP);
41
+ }
42
+
43
+ function normalizeUpdatedAt(value: unknown): number {
44
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : 0;
45
+ }
46
+
47
+ function normalizeExpandedPaths(value: unknown): string[] {
48
+ if (!Array.isArray(value)) return [];
49
+ return Array.from(
50
+ new Set(
51
+ value
52
+ .map((path) => (typeof path === 'string' ? normalizeWorkspaceProjectTreeRelativePath(path) : ''))
53
+ .filter(Boolean),
54
+ ),
55
+ ).slice(0, MAX_PERSISTED_EXPANDED_PATHS);
56
+ }
57
+
58
+ function normalizePersistedTrees(value: unknown): Record<string, WorkspaceProjectTreeViewState> {
59
+ if (!isRecord(value)) return {};
60
+ return Object.entries(value)
61
+ .map(([rootPath, tree]) => {
62
+ const rootKey = normalizeWorkspaceProjectTreeRootKey(rootPath);
63
+ if (!rootKey || !isRecord(tree)) return null;
64
+ return [
65
+ rootKey,
66
+ {
67
+ expandedPaths: normalizeExpandedPaths(tree.expandedPaths),
68
+ scrollTop: normalizeScrollTop(tree.scrollTop),
69
+ updatedAt: normalizeUpdatedAt(tree.updatedAt),
70
+ },
71
+ ] as const;
72
+ })
73
+ .filter((entry): entry is readonly [string, WorkspaceProjectTreeViewState] => entry !== null)
74
+ .sort((left, right) => right[1].updatedAt - left[1].updatedAt)
75
+ .slice(0, MAX_PERSISTED_PROJECT_TREES)
76
+ .reduce<Record<string, WorkspaceProjectTreeViewState>>((trees, [rootKey, tree]) => {
77
+ trees[rootKey] = tree;
78
+ return trees;
79
+ }, {});
80
+ }
81
+
82
+ function retainRecentTrees(
83
+ trees: Record<string, WorkspaceProjectTreeViewState>,
84
+ ): Record<string, WorkspaceProjectTreeViewState> {
85
+ return normalizePersistedTrees(trees);
86
+ }
87
+
88
+ function createTreeViewState(): WorkspaceProjectTreeViewState {
89
+ return { expandedPaths: [], scrollTop: 0, updatedAt: Date.now() };
90
+ }
91
+
92
+ export const useWorkspaceProjectTreeStore = create<WorkspaceProjectTreeStore>()(
93
+ persist(
94
+ (set) => ({
95
+ trees: {},
96
+ collapseAll: (rootPath) => {
97
+ const rootKey = normalizeWorkspaceProjectTreeRootKey(rootPath);
98
+ if (!rootKey) return;
99
+ set((state) => {
100
+ const current = state.trees[rootKey];
101
+ if (!current || current.expandedPaths.length === 0) return state;
102
+ return {
103
+ trees: retainRecentTrees({
104
+ ...state.trees,
105
+ [rootKey]: { ...current, expandedPaths: [], updatedAt: Date.now() },
106
+ }),
107
+ };
108
+ });
109
+ },
110
+ setDirectoryExpanded: (rootPath, relativePath, expanded) => {
111
+ const rootKey = normalizeWorkspaceProjectTreeRootKey(rootPath);
112
+ const pathKey = normalizeWorkspaceProjectTreeRelativePath(relativePath);
113
+ if (!rootKey || !pathKey) return;
114
+ set((state) => {
115
+ const current = state.trees[rootKey] ?? createTreeViewState();
116
+ const expandedPaths = expanded
117
+ ? Array.from(new Set([...current.expandedPaths, pathKey])).slice(0, MAX_PERSISTED_EXPANDED_PATHS)
118
+ : current.expandedPaths.filter((path) => path !== pathKey);
119
+ if (
120
+ expandedPaths.length === current.expandedPaths.length &&
121
+ expandedPaths.every((path, index) => path === current.expandedPaths[index])
122
+ ) {
123
+ return state;
124
+ }
125
+ return {
126
+ trees: retainRecentTrees({
127
+ ...state.trees,
128
+ [rootKey]: { ...current, expandedPaths, updatedAt: Date.now() },
129
+ }),
130
+ };
131
+ });
132
+ },
133
+ setScrollTop: (rootPath, scrollTop) => {
134
+ const rootKey = normalizeWorkspaceProjectTreeRootKey(rootPath);
135
+ if (!rootKey) return;
136
+ const normalizedScrollTop = normalizeScrollTop(scrollTop);
137
+ set((state) => {
138
+ const current = state.trees[rootKey] ?? createTreeViewState();
139
+ if (current.scrollTop === normalizedScrollTop) return state;
140
+ return {
141
+ trees: retainRecentTrees({
142
+ ...state.trees,
143
+ [rootKey]: { ...current, scrollTop: normalizedScrollTop, updatedAt: Date.now() },
144
+ }),
145
+ };
146
+ });
147
+ },
148
+ }),
149
+ {
150
+ name: WORKSPACE_PROJECT_TREE_STORAGE_KEY,
151
+ version: WORKSPACE_PROJECT_TREE_STORAGE_VERSION,
152
+ storage: createJSONStorage(() => window.localStorage),
153
+ partialize: (state): PersistedWorkspaceProjectTreeStore => ({ trees: state.trees }),
154
+ merge: (persistedState, currentState) => ({
155
+ ...currentState,
156
+ trees: normalizePersistedTrees(isRecord(persistedState) ? persistedState.trees : null),
157
+ }),
158
+ },
159
+ ),
160
+ );
@@ -4,8 +4,9 @@ export { ChatPresenterProvider } from "./components/providers/chat-presenter.pro
4
4
  export { usePresenter } from "./components/providers/chat-presenter.provider";
5
5
  export { ChatPresenter } from "./presenters/chat.presenter";
6
6
  export { ChatDraftIntentManager } from "./managers/chat-draft-intent.manager";
7
+ export { ChatComposerIntentManager } from "./managers/chat-composer-intent.manager";
7
8
  export { ChatCompletionNotificationManager } from "./managers/chat-completion-notification.manager";
8
- export { buildSessionPath } from "./features/session/utils/chat-session-route.utils";
9
+ export { buildSessionPath, CHAT_DRAFT_SESSION_PATH } from "./features/session/utils/chat-session-route.utils";
9
10
  export { useChatSessionListStore } from "./stores/chat-session-list.store";
10
11
  export { useChatThreadStore } from "./stores/chat-thread.store";
11
12
  export { useChatMessageLayoutStore } from "./stores/chat-message-layout.store";
@@ -152,4 +152,33 @@ describe('ChatComposerIntentManager', () => {
152
152
  }),
153
153
  );
154
154
  });
155
+
156
+ it('publishes an immutable UI resource reference to the targeted composer', () => {
157
+ const manager = new ChatComposerIntentManager();
158
+ const listener = vi.fn();
159
+ manager.subscribe('session-1', listener);
160
+ const reference = {
161
+ uri: 'nextclaw://panel-app/task-board',
162
+ resourceKind: 'panel-app',
163
+ title: 'Task board',
164
+ currentUrl: '/api/panel-apps/task-board/content',
165
+ contentParams: { boardId: 'today' },
166
+ };
167
+
168
+ manager.requestUiResourceReference({
169
+ targetSessionKey: 'session-1',
170
+ reference,
171
+ });
172
+ reference.contentParams.boardId = 'mutated';
173
+
174
+ expect(listener).toHaveBeenCalledWith(expect.objectContaining({
175
+ kind: 'ui_resource',
176
+ targetSessionKey: 'session-1',
177
+ tokenKey: 'nextclaw://panel-app/task-board',
178
+ label: 'Task board',
179
+ reference: expect.objectContaining({
180
+ contentParams: { boardId: 'today' },
181
+ }),
182
+ }));
183
+ });
155
184
  });
@@ -1,8 +1,11 @@
1
1
  import {
2
2
  CHAT_CONVERSATION_EXCERPT_TOKEN_KIND,
3
+ CHAT_UI_RESOURCE_TOKEN_KIND,
3
4
  CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND,
4
5
  CHAT_WORKSPACE_EXCERPT_TOKEN_KIND,
5
6
  CHAT_WORKSPACE_FILE_TOKEN_KIND,
7
+ readChatUiResourceReference,
8
+ type ChatUiResourceReference,
6
9
  } from '@nextclaw/shared';
7
10
 
8
11
  type ChatComposerReferenceIntentBase = {
@@ -35,17 +38,24 @@ export type ChatComposerConversationExcerptIntent = ChatComposerReferenceIntentB
35
38
  excerpt: string;
36
39
  };
37
40
 
41
+ export type ChatComposerUiResourceReferenceIntent = ChatComposerReferenceIntentBase & {
42
+ kind: typeof CHAT_UI_RESOURCE_TOKEN_KIND;
43
+ reference: ChatUiResourceReference;
44
+ };
45
+
38
46
  export type ChatComposerReferenceIntent =
39
47
  | ChatComposerFileReferenceIntent
40
48
  | ChatComposerDirectoryReferenceIntent
41
49
  | ChatComposerExcerptReferenceIntent
42
- | ChatComposerConversationExcerptIntent;
50
+ | ChatComposerConversationExcerptIntent
51
+ | ChatComposerUiResourceReferenceIntent;
43
52
 
44
53
  type ChatComposerReferenceRequest =
45
54
  | Omit<ChatComposerFileReferenceIntent, 'id'>
46
55
  | Omit<ChatComposerDirectoryReferenceIntent, 'id'>
47
56
  | Omit<ChatComposerExcerptReferenceIntent, 'id'>
48
- | Omit<ChatComposerConversationExcerptIntent, 'id'>;
57
+ | Omit<ChatComposerConversationExcerptIntent, 'id'>
58
+ | Omit<ChatComposerUiResourceReferenceIntent, 'id'>;
49
59
 
50
60
  function createExcerptTokenKey(prefix: string, identity: string): string {
51
61
  let hash = 2166136261;
@@ -169,6 +179,23 @@ export class ChatComposerIntentManager {
169
179
  });
170
180
  };
171
181
 
182
+ requestUiResourceReference = (params: {
183
+ targetSessionKey: string | null;
184
+ reference: ChatUiResourceReference;
185
+ }) => {
186
+ const reference = readChatUiResourceReference(params.reference);
187
+ if (!reference) return;
188
+ const tokenKey = reference.uri.trim();
189
+ const label = reference.title.trim();
190
+ this.publish({
191
+ kind: CHAT_UI_RESOURCE_TOKEN_KIND,
192
+ targetSessionKey: params.targetSessionKey,
193
+ tokenKey,
194
+ label,
195
+ reference,
196
+ });
197
+ };
198
+
172
199
  consumePending = (targetSessionKey: string | null): ChatComposerReferenceIntent | null => {
173
200
  if (this.pendingIntent?.targetSessionKey !== targetSessionKey) {
174
201
  return null;
@@ -1,7 +1,11 @@
1
+ import type { SystemObjectResolvedReference } from '@nextclaw/shared';
2
+
1
3
  export type ChatDraftIntent = {
2
4
  id: number;
3
- prompt: string;
4
- };
5
+ } & (
6
+ | { kind: 'prompt'; prompt: string }
7
+ | { kind: 'system-object-reference'; reference: SystemObjectResolvedReference }
8
+ );
5
9
 
6
10
  type ChatDraftIntentListener = (intent: ChatDraftIntent) => void;
7
11
 
@@ -17,6 +21,7 @@ export class ChatDraftIntentManager {
17
21
  }
18
22
  const intent: ChatDraftIntent = {
19
23
  id: this.nextId + 1,
24
+ kind: 'prompt',
20
25
  prompt: normalizedPrompt,
21
26
  };
22
27
  this.nextId = intent.id;
@@ -24,6 +29,17 @@ export class ChatDraftIntentManager {
24
29
  this.listeners.forEach((listener) => listener(intent));
25
30
  };
26
31
 
32
+ requestSystemObjectReference = (reference: SystemObjectResolvedReference) => {
33
+ const intent: ChatDraftIntent = {
34
+ id: this.nextId + 1,
35
+ kind: 'system-object-reference',
36
+ reference: structuredClone(reference),
37
+ };
38
+ this.nextId = intent.id;
39
+ this.pendingIntent = intent;
40
+ this.listeners.forEach((listener) => listener(intent));
41
+ };
42
+
27
43
  consumePending = (): ChatDraftIntent | null => {
28
44
  const intent = this.pendingIntent;
29
45
  this.pendingIntent = null;
@@ -2,7 +2,7 @@ import { ChatSessionListManager } from '@/features/chat/managers/chat-session-li
2
2
  import { ChatUiManager } from '@/features/chat/managers/chat-ui.manager';
3
3
  import { ChatQueryManager } from '@/features/chat/managers/chat-query.manager';
4
4
  import { ChatThreadManager } from '@/features/chat/managers/chat-thread.manager';
5
- import { ChatComposerIntentManager } from '@/features/chat/managers/chat-composer-intent.manager';
5
+ import type { ChatComposerIntentManager } from '@/features/chat/managers/chat-composer-intent.manager';
6
6
  import type { AppPresenter } from '@/app/presenters/app.presenter';
7
7
 
8
8
  export class ChatPresenter {
@@ -16,7 +16,7 @@ export class ChatPresenter {
16
16
  this.chatUiManager = new ChatUiManager(appPresenter.docBrowserManager);
17
17
  this.chatSessionListManager = new ChatSessionListManager(this.chatUiManager);
18
18
  this.chatQueryManager = new ChatQueryManager();
19
- this.chatComposerIntentManager = new ChatComposerIntentManager();
19
+ this.chatComposerIntentManager = appPresenter.chatComposerIntentManager;
20
20
  this.chatThreadManager = new ChatThreadManager(
21
21
  this.chatUiManager,
22
22
  this.chatSessionListManager,
@@ -32,6 +32,7 @@ function resetChatThreadStore() {
32
32
  closedWorkspaceTabEntries: [],
33
33
  workspaceNavigationHistory: [],
34
34
  workspaceNavigationHistoryIndex: 0,
35
+ workspaceExplorerOpen: false,
35
36
  workspaceExplorerWidth: CHAT_WORKSPACE_EXPLORER_DEFAULT_WIDTH,
36
37
  workspacePanelWidth: CHAT_WORKSPACE_PANEL_DEFAULT_WIDTH,
37
38
  },
@@ -74,6 +75,7 @@ describe('chat thread workspace panel persistence', () => {
74
75
  { kind: 'file', key: 'session-1::preview::README.md' },
75
76
  ],
76
77
  workspaceNavigationHistoryIndex: 1,
78
+ workspaceExplorerOpen: true,
77
79
  });
78
80
 
79
81
  const persisted = JSON.parse(window.localStorage.getItem(chatThreadWorkspaceStorageKey) ?? '{}');
@@ -88,6 +90,7 @@ describe('chat thread workspace panel persistence', () => {
88
90
  { kind: 'file', key: 'session-1::preview::README.md' },
89
91
  ],
90
92
  workspaceNavigationHistoryIndex: 1,
93
+ workspaceExplorerOpen: true,
91
94
  });
92
95
  expect(persisted.state.snapshot.sessionKey).toBeUndefined();
93
96
  expect(persisted.state.snapshot.isSending).toBeUndefined();
@@ -131,6 +134,7 @@ describe('chat thread workspace panel persistence', () => {
131
134
  activeWorkspacePanelKind: 'project-files',
132
135
  workspaceNavigationHistory: [{ kind: 'overview' }, { kind: 'child-sessions' }, { kind: 'project-files' }],
133
136
  workspaceNavigationHistoryIndex: 2,
137
+ workspaceExplorerOpen: true,
134
138
  workspaceExplorerWidth: 318,
135
139
  workspacePanelWidth: 620,
136
140
  });
@@ -147,6 +151,7 @@ describe('chat thread workspace panel persistence', () => {
147
151
  activeWorkspacePanelKind: 'project-files',
148
152
  workspaceNavigationHistory: [{ kind: 'overview' }, { kind: 'child-sessions' }, { kind: 'project-files' }],
149
153
  workspaceNavigationHistoryIndex: 2,
154
+ workspaceExplorerOpen: true,
150
155
  workspaceExplorerWidth: 318,
151
156
  workspacePanelWidth: 620,
152
157
  });
@@ -234,6 +239,7 @@ describe('chat thread workspace panel persistence', () => {
234
239
  activeWorkspacePanelKind: 'file',
235
240
  activeWorkspaceFileKey: 'session-1::preview::README.md',
236
241
  workspaceExplorerWidth: 400,
242
+ workspaceExplorerOpen: false,
237
243
  activeChildSessionKey: 'child-session-1',
238
244
  workspaceNavigationHistory: [{ kind: 'file', key: 'session-1::preview::README.md' }],
239
245
  workspaceNavigationHistoryIndex: 0,
@@ -95,6 +95,7 @@ export type ChatThreadSnapshot = {
95
95
  closedWorkspaceTabEntries: ChatWorkspaceNavigationEntry[];
96
96
  workspaceNavigationHistory: ChatWorkspaceNavigationEntry[];
97
97
  workspaceNavigationHistoryIndex: number;
98
+ workspaceExplorerOpen: boolean;
98
99
  workspaceExplorerWidth: number;
99
100
  workspacePanelWidth: number;
100
101
  contextWindow?: SessionContextWindowView | null;
@@ -119,6 +120,7 @@ type PersistedChatThreadStore = {
119
120
  closedWorkspaceTabEntries?: unknown;
120
121
  workspaceNavigationHistory?: unknown;
121
122
  workspaceNavigationHistoryIndex?: unknown;
123
+ workspaceExplorerOpen?: unknown;
122
124
  workspaceExplorerWidth?: unknown;
123
125
  workspacePanelWidth?: unknown;
124
126
  };
@@ -134,6 +136,7 @@ type PersistedChatWorkspaceSnapshot = Pick<
134
136
  | 'closedWorkspaceTabEntries'
135
137
  | 'workspaceNavigationHistory'
136
138
  | 'workspaceNavigationHistoryIndex'
139
+ | 'workspaceExplorerOpen'
137
140
  | 'workspaceExplorerWidth'
138
141
  | 'workspacePanelWidth'
139
142
  >;
@@ -167,6 +170,7 @@ const initialSnapshot: ChatThreadSnapshot = {
167
170
  closedWorkspaceTabEntries: [],
168
171
  workspaceNavigationHistory: [],
169
172
  workspaceNavigationHistoryIndex: 0,
173
+ workspaceExplorerOpen: false,
170
174
  workspaceExplorerWidth: CHAT_WORKSPACE_EXPLORER_DEFAULT_WIDTH,
171
175
  workspacePanelWidth: CHAT_WORKSPACE_PANEL_DEFAULT_WIDTH,
172
176
  contextWindow: null,
@@ -281,6 +285,7 @@ function normalizePersistedWorkspaceSnapshot(value: unknown): PersistedChatWorks
281
285
  closedWorkspaceTabEntries,
282
286
  workspaceNavigationHistory,
283
287
  workspaceNavigationHistoryIndex,
288
+ workspaceExplorerOpen: value.workspaceExplorerOpen === true,
284
289
  workspaceExplorerWidth: normalizeChatWorkspaceExplorerWidth(value.workspaceExplorerWidth),
285
290
  workspacePanelWidth: normalizeChatWorkspacePanelWidth(value.workspacePanelWidth),
286
291
  };
@@ -329,6 +334,7 @@ export const useChatThreadStore = create<ChatThreadStore>()(
329
334
  ),
330
335
  workspaceNavigationHistory,
331
336
  workspaceNavigationHistoryIndex,
337
+ workspaceExplorerOpen: state.snapshot.workspaceExplorerOpen,
332
338
  workspaceExplorerWidth: state.snapshot.workspaceExplorerWidth,
333
339
  workspacePanelWidth: state.snapshot.workspacePanelWidth,
334
340
  },
@@ -1,6 +1,7 @@
1
- import { render, screen } from "@testing-library/react";
2
- import { MemoryRouter } from "react-router-dom";
1
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2
+ import { MemoryRouter, useLocation } from "react-router-dom";
3
3
  import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { CHAT_DRAFT_SESSION_PATH } from "@/features/chat";
4
5
  import { InboxReaderDialog } from "@/features/inbox/components/inbox-reader-dialog";
5
6
  import { useInboxStore } from "@/features/inbox/stores/inbox.store";
6
7
  import { t } from "@/shared/lib/i18n";
@@ -8,13 +9,17 @@ import { t } from "@/shared/lib/i18n";
8
9
  const mocks = vi.hoisted(() => ({
9
10
  closeReader: vi.fn(),
10
11
  contentType: "markdown",
11
- continueInChat: vi.fn(),
12
+ prepareChatReference: vi.fn(),
13
+ requestSystemObjectReference: vi.fn(),
12
14
  markRead: vi.fn(),
13
15
  selectInReader: vi.fn(),
14
16
  }));
15
17
 
16
18
  vi.mock("@/app/components/app-presenter-provider", () => ({
17
- useAppPresenter: () => ({ inboxManager: mocks }),
19
+ useAppPresenter: () => ({
20
+ inboxManager: mocks,
21
+ chatDraftIntentManager: { requestSystemObjectReference: mocks.requestSystemObjectReference },
22
+ }),
18
23
  }));
19
24
 
20
25
  vi.mock("@/features/inbox/hooks/use-inbox-deliveries", () => ({
@@ -34,7 +39,6 @@ vi.mock("@/features/inbox/hooks/use-inbox-deliveries", () => ({
34
39
  presentedAt: "2026-08-06T00:01:00.000Z",
35
40
  readAt: null,
36
41
  archivedAt: null,
37
- conversationSessionId: null,
38
42
  }],
39
43
  },
40
44
  }),
@@ -46,10 +50,20 @@ vi.mock("@nextclaw/agent-chat-ui", () => ({
46
50
  ),
47
51
  }));
48
52
 
53
+ function CurrentPath() {
54
+ return <span data-testid="current-path">{useLocation().pathname}</span>;
55
+ }
56
+
49
57
  describe("InboxReaderDialog", () => {
50
58
  beforeEach(() => {
51
59
  vi.clearAllMocks();
52
60
  mocks.contentType = "markdown";
61
+ mocks.prepareChatReference.mockResolvedValue({
62
+ reference: {
63
+ uri: "nextclaw://objects/inbox-delivery/delivery-1",
64
+ label: "A considered report",
65
+ },
66
+ });
53
67
  useInboxStore.setState({
54
68
  snapshot: { readerOpen: true, activeDeliveryId: "delivery-1" },
55
69
  });
@@ -80,4 +94,23 @@ describe("InboxReaderDialog", () => {
80
94
  .find((element) => element.tagName === "IFRAME");
81
95
  expect(htmlPreview?.className).toContain("h-full");
82
96
  });
97
+
98
+ it("opens a draft with a visible system object reference intent", async () => {
99
+ render(
100
+ <MemoryRouter initialEntries={["/inbox"]}>
101
+ <InboxReaderDialog />
102
+ <CurrentPath />
103
+ </MemoryRouter>,
104
+ );
105
+
106
+ fireEvent.click(screen.getByRole("button", { name: t("inboxContinueChat") }));
107
+
108
+ await waitFor(() => {
109
+ expect(screen.getByTestId("current-path").textContent).toBe(CHAT_DRAFT_SESSION_PATH);
110
+ });
111
+ expect(mocks.prepareChatReference).toHaveBeenCalledWith("delivery-1");
112
+ expect(mocks.requestSystemObjectReference).toHaveBeenCalledWith(
113
+ expect.objectContaining({ uri: "nextclaw://objects/inbox-delivery/delivery-1" }),
114
+ );
115
+ });
83
116
  });
@@ -2,6 +2,7 @@ import { useRef, useState } from "react";
2
2
  import { ChevronLeft, ChevronRight, Inbox } from "lucide-react";
3
3
  import { useNavigate } from "react-router-dom";
4
4
  import { useAppPresenter } from "@/app/components/app-presenter-provider";
5
+ import { CHAT_DRAFT_SESSION_PATH } from "@/features/chat";
5
6
  import { InboxDeliveryContent } from "@/features/inbox/components/inbox-delivery-content";
6
7
  import { useInboxDeliveries } from "@/features/inbox/hooks/use-inbox-deliveries";
7
8
  import { useInboxStore } from "@/features/inbox/stores/inbox.store";
@@ -25,7 +26,7 @@ function formatPosition(current: number, total: number): string {
25
26
  export function InboxReaderDialog() {
26
27
  const titleRef = useRef<HTMLHeadingElement>(null);
27
28
  const navigate = useNavigate();
28
- const { inboxManager } = useAppPresenter();
29
+ const { chatDraftIntentManager, inboxManager } = useAppPresenter();
29
30
  const { data } = useInboxDeliveries();
30
31
  const { activeDeliveryId, readerOpen } = useInboxStore((state) => state.snapshot);
31
32
  const [pendingAction, setPendingAction] = useState<string | null>(null);
@@ -74,8 +75,9 @@ export function InboxReaderDialog() {
74
75
  return;
75
76
  }
76
77
  void runAction("continue", async () => {
77
- const result = await inboxManager.continueInChat(activeDelivery.id);
78
- navigate(`/chat/${encodeURIComponent(result.sessionId)}`);
78
+ const { reference } = await inboxManager.prepareChatReference(activeDelivery.id);
79
+ chatDraftIntentManager.requestSystemObjectReference(reference);
80
+ navigate(CHAT_DRAFT_SESSION_PATH);
79
81
  });
80
82
  };
81
83
 
@@ -6,7 +6,7 @@ import { useInboxStore } from "@/features/inbox/stores/inbox.store";
6
6
 
7
7
  const mocks = vi.hoisted(() => ({
8
8
  delete: vi.fn(),
9
- continueInChat: vi.fn(),
9
+ resolveReference: vi.fn(),
10
10
  list: vi.fn(),
11
11
  on: vi.fn(() => vi.fn()),
12
12
  updateState: vi.fn(),
@@ -17,10 +17,12 @@ vi.mock("@/shared/lib/api", () => ({
17
17
  eventBus: { on: mocks.on },
18
18
  inboxDeliveries: {
19
19
  delete: mocks.delete,
20
- continueInChat: mocks.continueInChat,
21
20
  list: mocks.list,
22
21
  updateState: mocks.updateState,
23
22
  },
23
+ systemObjectReferences: {
24
+ resolve: mocks.resolveReference,
25
+ },
24
26
  },
25
27
  }));
26
28
 
@@ -36,7 +38,6 @@ const delivery: InboxDelivery = {
36
38
  presentedAt: null,
37
39
  readAt: null,
38
40
  archivedAt: null,
39
- conversationSessionId: null,
40
41
  };
41
42
 
42
43
  describe("InboxManager", () => {
@@ -57,6 +58,19 @@ describe("InboxManager", () => {
57
58
  presentedAt: action === "present" || action === "read" ? "2026-08-06T01:00:00.000Z" : null,
58
59
  readAt: action === "read" ? "2026-08-06T01:00:00.000Z" : null,
59
60
  }));
61
+ mocks.resolveReference.mockResolvedValue({
62
+ uri: "nextclaw://objects/inbox-delivery/delivery-1",
63
+ objectType: "inbox-delivery",
64
+ objectId: "delivery-1",
65
+ label: "Brief",
66
+ description: null,
67
+ updatedAt: delivery.updatedAt,
68
+ version: "version-1",
69
+ assetUri: "asset://store/report",
70
+ fileName: "brief.md",
71
+ mimeType: "text/markdown",
72
+ sizeBytes: 7,
73
+ });
60
74
  });
61
75
 
62
76
  it("auto-opens the oldest unpresented item and only marks it presented", async () => {
@@ -83,4 +97,15 @@ describe("InboxManager", () => {
83
97
  expect(mocks.updateState).toHaveBeenCalledTimes(1);
84
98
  expect(mocks.updateState).toHaveBeenCalledWith(delivery.id, "present");
85
99
  });
100
+
101
+ it("prepares a generic immutable report reference before marking it read", async () => {
102
+ const manager = new InboxManager(new QueryClient());
103
+ const result = await manager.prepareChatReference(delivery.id);
104
+
105
+ expect(mocks.resolveReference).toHaveBeenCalledWith(
106
+ "nextclaw://objects/inbox-delivery/delivery-1",
107
+ );
108
+ expect(mocks.updateState).toHaveBeenCalledWith(delivery.id, "read");
109
+ expect(result.reference.assetUri).toBe("asset://store/report");
110
+ });
86
111
  });
@@ -5,6 +5,11 @@ import type {
5
5
  InboxDeliveryStateAction,
6
6
  } from "@nextclaw/shared";
7
7
  import { eventKeys } from "@nextclaw/shared";
8
+ import {
9
+ createSystemObjectReferenceUri,
10
+ SYSTEM_OBJECT_TYPE_INBOX_DELIVERY,
11
+ type SystemObjectResolvedReference,
12
+ } from "@nextclaw/shared";
8
13
  import { appQueryClient } from "@/app-query-client";
9
14
  import { useInboxStore } from "@/features/inbox/stores/inbox.store";
10
15
  import { nextclawClient } from "@/shared/lib/api";
@@ -104,11 +109,16 @@ export class InboxManager {
104
109
  return deleted;
105
110
  };
106
111
 
107
- continueInChat = async (deliveryId: string) => {
108
- const result = await nextclawClient.inboxDeliveries.continueInChat(deliveryId);
109
- this.replaceCachedDelivery(result.delivery);
112
+ prepareChatReference = async (deliveryId: string): Promise<{
113
+ delivery: InboxDelivery;
114
+ reference: SystemObjectResolvedReference;
115
+ }> => {
116
+ const reference = await nextclawClient.systemObjectReferences.resolve(
117
+ createSystemObjectReferenceUri(SYSTEM_OBJECT_TYPE_INBOX_DELIVERY, deliveryId),
118
+ );
119
+ const delivery = await this.updateState(deliveryId, "read");
110
120
  this.closeReader();
111
- return result;
121
+ return { delivery, reference };
112
122
  };
113
123
 
114
124
  private updateState = async (