@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
@@ -25,13 +25,34 @@ function renderSessionArea(isProjectFirstView: boolean) {
25
25
  }
26
26
 
27
27
  describe("ChatSidebarSessionArea", () => {
28
- it("reserves the action-row height while switching list modes", () => {
28
+ it("renders an accessible animated segmented control for list modes", () => {
29
29
  const { onSelectMode } = renderSessionArea(false);
30
+ const modeGroup = screen.getByRole("group", { name: "Session list view" });
31
+ const timeButton = screen.getByRole("button", { name: "Time" });
32
+ const projectButton = screen.getByRole("button", { name: "Project" });
30
33
 
31
- expect(
32
- screen.getByRole("button", { name: "Time" }).parentElement?.parentElement?.className,
33
- ).toContain("h-7");
34
- fireEvent.click(screen.getByRole("button", { name: "Project" }));
34
+ expect(modeGroup.className).toContain("h-7");
35
+ expect(modeGroup.className).toContain("rounded-full");
36
+ expect(modeGroup.className).toContain("bg-foreground/[0.04]");
37
+ expect(modeGroup.className).not.toContain("border");
38
+ expect(modeGroup.className).not.toContain("shadow-inner");
39
+ const modeIndicator = modeGroup.querySelector("span[aria-hidden='true']");
40
+ expect(modeIndicator?.className).toContain("rounded-full");
41
+ expect(modeIndicator?.className).toContain("bg-gray-200/70");
42
+ expect(modeIndicator?.className).not.toContain("shadow-");
43
+ expect(modeIndicator?.className).not.toContain("ring-");
44
+ expect(modeIndicator?.className).toContain("transition-transform");
45
+ expect(timeButton.getAttribute("aria-pressed")).toBe("true");
46
+ expect(projectButton.getAttribute("aria-pressed")).toBe("false");
47
+ expect(timeButton.className).toContain("rounded-full");
48
+ expect(projectButton.className).toContain("rounded-full");
49
+ expect(timeButton.querySelector("svg")).not.toBeNull();
50
+ expect(projectButton.querySelector("svg")).not.toBeNull();
51
+ expect(modeGroup.parentElement?.className).toContain("justify-end");
52
+ expect(modeGroup.parentElement?.className).toContain("h-8");
53
+ expect(modeGroup.parentElement?.lastElementChild).toBe(modeGroup);
54
+
55
+ fireEvent.click(projectButton);
35
56
 
36
57
  expect(onSelectMode).toHaveBeenCalledWith("project-first");
37
58
  });
@@ -39,12 +60,22 @@ describe("ChatSidebarSessionArea", () => {
39
60
  it("uses a folder-plus icon for the add-project action", () => {
40
61
  const { onAddProject } = renderSessionArea(true);
41
62
  const addProjectButton = screen.getByRole("button", { name: "Add Project" });
63
+ const modeIndicator = screen
64
+ .getByRole("group", { name: "Session list view" })
65
+ .querySelector("span[aria-hidden='true']");
42
66
 
43
67
  expect(
44
68
  addProjectButton
45
69
  .querySelector("svg")
46
70
  ?.classList.contains("lucide-folder-plus"),
47
71
  ).toBe(true);
72
+ expect(addProjectButton.className).toContain("hover:bg-gray-200/60");
73
+ expect(modeIndicator?.className).toContain("translate-x-full");
74
+ expect(modeIndicator?.className).toContain("motion-reduce:transition-none");
75
+ expect(screen.getByRole("button", { name: "Project" }).getAttribute("aria-pressed")).toBe(
76
+ "true",
77
+ );
78
+ expect(modeIndicator?.parentElement?.previousElementSibling).toBe(addProjectButton);
48
79
  fireEvent.click(addProjectButton);
49
80
 
50
81
  expect(onAddProject).toHaveBeenCalledOnce();
@@ -165,20 +165,19 @@ export function ChatSidebarSessionArea({
165
165
 
166
166
  return (
167
167
  <>
168
- <div className="flex items-center justify-end px-4 pb-1 pt-2">
169
- <div className="flex h-7 items-center gap-1.5">
170
- {isProjectFirstView ? (
171
- <IconActionButton
172
- icon={<FolderPlus className="h-3.5 w-3.5" />}
173
- label={t("chatProjectAdd")}
174
- onClick={onAddProject}
175
- />
176
- ) : null}
177
- <ChatSidebarListModeSwitch
178
- isProjectFirstView={isProjectFirstView}
179
- onSelectMode={onSelectMode}
168
+ <div className="flex h-8 items-center justify-end gap-1 px-3">
169
+ {isProjectFirstView ? (
170
+ <IconActionButton
171
+ icon={<FolderPlus className="h-3.5 w-3.5" />}
172
+ label={t("chatProjectAdd")}
173
+ tone="surface"
174
+ onClick={onAddProject}
180
175
  />
181
- </div>
176
+ ) : null}
177
+ <ChatSidebarListModeSwitch
178
+ isProjectFirstView={isProjectFirstView}
179
+ onSelectMode={onSelectMode}
180
+ />
182
181
  </div>
183
182
 
184
183
  <div
@@ -4,6 +4,7 @@ import { MemoryRouter } from "react-router-dom";
4
4
  import { describe, expect, it, vi, beforeEach } from "vitest";
5
5
 
6
6
  import { SessionConversationArea } from "@/features/chat/features/conversation/components/session-conversation-area";
7
+ import type { ChatDraftIntent } from "@/features/chat/managers/chat-draft-intent.manager";
7
8
 
8
9
  const mocks = vi.hoisted(() => {
9
10
  const inputRenderSpy = vi.fn();
@@ -118,7 +119,7 @@ const mocks = vi.hoisted(() => {
118
119
  },
119
120
  appPresenter: {
120
121
  chatDraftIntentManager: {
121
- consumePending: vi.fn(() => null),
122
+ consumePending: vi.fn<() => ChatDraftIntent | null>(() => null),
122
123
  markConsumed: vi.fn(),
123
124
  subscribe: vi.fn(() => vi.fn()),
124
125
  },
@@ -409,6 +410,53 @@ describe("SessionConversationArea input boundary", () => {
409
410
  );
410
411
  });
411
412
 
413
+ it("consumes a system object draft intent as a visible composer token", () => {
414
+ const reference = {
415
+ uri: "nextclaw://objects/inbox-delivery/delivery-1",
416
+ objectType: "inbox-delivery",
417
+ objectId: "delivery-1",
418
+ label: "OOM investigation report",
419
+ description: "Root cause and mitigation",
420
+ updatedAt: "2026-08-11T00:00:00.000Z",
421
+ version: "sha256-report",
422
+ assetUri: "asset://store/report",
423
+ fileName: "oom-investigation-report.md",
424
+ mimeType: "text/markdown",
425
+ sizeBytes: 128,
426
+ };
427
+ mocks.appPresenter.chatDraftIntentManager.consumePending.mockReturnValueOnce({
428
+ id: 1,
429
+ kind: "system-object-reference",
430
+ reference,
431
+ });
432
+
433
+ render(
434
+ <MemoryRouter>
435
+ <SessionConversationArea
436
+ consumeDraftIntent
437
+ sessionKey={null}
438
+ />
439
+ </MemoryRouter>,
440
+ );
441
+
442
+ expect(mocks.presenter.chatSessionListManager.createSession).toHaveBeenCalledOnce();
443
+ expect(mocks.appPresenter.chatDraftIntentManager.markConsumed).toHaveBeenCalledWith(1);
444
+ const update = mocks.inputActions.update.mock.calls.at(-1)?.[0] as (
445
+ current: { nodes: []; text: string },
446
+ ) => { nodes: Array<Record<string, unknown>>; text: string };
447
+ const next = update({ nodes: [], text: "" });
448
+ expect(next.nodes).toEqual([
449
+ expect.objectContaining({
450
+ type: "token",
451
+ tokenKind: "system_object",
452
+ tokenKey: reference.uri,
453
+ label: reference.label,
454
+ data: { reference },
455
+ }),
456
+ ]);
457
+ expect(next.text).toBe("");
458
+ });
459
+
412
460
  it("syncs draft preferences with the selected runtime context", () => {
413
461
  mocks.inputQuery.defaultModel = "openai/gpt-5";
414
462
  mocks.inputQuery.fallbackPreferredModel = "minimax/MiniMax-M3";
@@ -349,7 +349,7 @@ describe('SessionConversationInput streaming stability', () => {
349
349
 
350
350
  it('inserts a project file reference at the saved composer caret', async () => {
351
351
  const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
352
- render(
352
+ renderInput(
353
353
  <StreamingSessionConversationInputHarness
354
354
  controlRef={controlRef}
355
355
  initialText="Hello"
@@ -427,11 +427,31 @@ describe('SessionConversationInput streaming stability', () => {
427
427
  expect(deleteQueuedInput).toHaveBeenCalledWith('queued-2');
428
428
  });
429
429
 
430
+ it('renders a submitting queue row immediately without premature edit actions', () => {
431
+ const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
432
+ renderInput(
433
+ <StreamingSessionConversationInputHarness
434
+ controlRef={controlRef}
435
+ controllerOverride={{
436
+ ...controller,
437
+ queuedInputs: [
438
+ { id: 'submitting-1', isSubmitting: true, preview: '正在提交的任务' },
439
+ ],
440
+ }}
441
+ />,
442
+ );
443
+
444
+ expect(screen.getByText('正在提交的任务')).toBeTruthy();
445
+ expect(screen.getByLabelText('Adding to queue…')).toBeTruthy();
446
+ expect(screen.queryByRole('button', { name: 'Edit queued input' })).toBeNull();
447
+ expect(screen.queryByRole('button', { name: 'Delete queued input' })).toBeNull();
448
+ });
449
+
430
450
  it('leaves send-error rendering to the conversation surface', () => {
431
451
  const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
432
452
  const providerError = 'Chat Completions API failed (402): raw provider error';
433
453
 
434
- render(
454
+ renderInput(
435
455
  <StreamingSessionConversationInputHarness
436
456
  controlRef={controlRef}
437
457
  sendError={providerError}
@@ -456,9 +476,13 @@ function createAttachmentRunHandle(): NcpRunHandle {
456
476
 
457
477
  function AttachmentSubmitHarness({
458
478
  initialPrompt,
479
+ isRunning = false,
480
+ refreshQueuedInputs = async () => [],
459
481
  send,
460
482
  }: {
461
483
  readonly initialPrompt?: string;
484
+ readonly isRunning?: boolean;
485
+ readonly refreshQueuedInputs?: () => Promise<readonly never[]>;
462
486
  readonly send: AttachmentSubmitAgentSend;
463
487
  }) {
464
488
  const { inputActions, inputSnapshot } = useSessionConversationInputState(
@@ -503,14 +527,14 @@ function AttachmentSubmitHarness({
503
527
  continueRun: vi.fn(),
504
528
  editMessage: vi.fn(),
505
529
  isHydrating: false,
506
- isRunning: false,
530
+ isRunning,
507
531
  isSending: false,
508
532
  send,
509
533
  snapshot: {
510
- activeRun: null,
534
+ activeRun: isRunning ? { sessionId: 'session-attachment' } : null,
511
535
  },
512
536
  visibleMessages: [],
513
- }), [send]);
537
+ }), [isRunning, send]);
514
538
  const controller = useSessionConversationController({
515
539
  agent,
516
540
  inputSnapshot,
@@ -518,6 +542,7 @@ function AttachmentSubmitHarness({
518
542
  isRuntimeBlocked: false,
519
543
  runQueue: {
520
544
  inputs: [],
545
+ refreshQueuedInputs,
521
546
  removeQueuedInput: async () => null,
522
547
  },
523
548
  selectedAgentId: 'main',
@@ -543,10 +568,46 @@ function AttachmentSubmitHarness({
543
568
  }
544
569
 
545
570
  describe('SessionConversationInput attachment submit', () => {
571
+ it('shows immediate queue feedback from the real send button before backend acknowledgement', async () => {
572
+ let resolveSend!: (handle: NcpRunHandle) => void;
573
+ const send = vi.fn<AttachmentSubmitAgentSend>(() => new Promise((resolve) => {
574
+ resolveSend = resolve;
575
+ }));
576
+ const refreshQueuedInputs = vi.fn(async () => [] as const);
577
+
578
+ renderInput(
579
+ <AttachmentSubmitHarness
580
+ initialPrompt="稍后继续这个任务"
581
+ isRunning
582
+ refreshQueuedInputs={refreshQueuedInputs}
583
+ send={send}
584
+ />,
585
+ );
586
+
587
+ await act(async () => {
588
+ fireEvent.click(screen.getByRole('button', { name: /Queue|排队发送/ }));
589
+ await Promise.resolve();
590
+ });
591
+
592
+ expect(send).toHaveBeenCalledTimes(1);
593
+ const submittingStatus = screen.getByLabelText('Adding to queue…');
594
+ expect(submittingStatus.parentElement?.textContent).toContain('稍后继续这个任务');
595
+ await waitFor(() => expect(screen.getByRole('textbox').textContent).toBe(''));
596
+ expect(refreshQueuedInputs).not.toHaveBeenCalled();
597
+
598
+ await act(async () => {
599
+ resolveSend({ ...createAttachmentRunHandle(), runId: null });
600
+ await Promise.resolve();
601
+ });
602
+
603
+ await waitFor(() => expect(refreshQueuedInputs).toHaveBeenCalledTimes(1));
604
+ await waitFor(() => expect(screen.queryByLabelText('Adding to queue…')).toBeNull());
605
+ });
606
+
546
607
  it('preserves a project file reference in the outgoing user message and AI context', async () => {
547
608
  const send = vi.fn<AttachmentSubmitAgentSend>(async () => createAttachmentRunHandle());
548
609
 
549
- render(<AttachmentSubmitHarness initialPrompt="这里面有啥" send={send} />);
610
+ renderInput(<AttachmentSubmitHarness initialPrompt="这里面有啥" send={send} />);
550
611
 
551
612
  const textbox = screen.getByRole('textbox');
552
613
  fireEvent.focus(textbox);
@@ -605,7 +666,7 @@ describe('SessionConversationInput attachment submit', () => {
605
666
 
606
667
  it('preserves an exact workspace excerpt in the outgoing message metadata', async () => {
607
668
  const send = vi.fn<AttachmentSubmitAgentSend>(async () => createAttachmentRunHandle());
608
- render(<AttachmentSubmitHarness initialPrompt="解释一下" send={send} />);
669
+ renderInput(<AttachmentSubmitHarness initialPrompt="解释一下" send={send} />);
609
670
 
610
671
  const textbox = screen.getByRole('textbox');
611
672
  await waitFor(() => expect(textbox.textContent).toBe('解释一下'));
@@ -18,6 +18,10 @@ import { ChatConversationWelcome } from "@/features/chat/features/welcome/compon
18
18
  import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
19
19
  import { useSystemStatus } from "@/features/system-status";
20
20
  import { t } from "@/shared/lib/i18n";
21
+ import type { SystemObjectResolvedReference } from "@nextclaw/shared";
22
+ import { deriveChatComposerDraft } from "@/features/chat/features/input/utils/chat-composer-state.utils";
23
+ import { appendSystemObjectReferenceToken } from "@/features/chat/features/input/utils/chat-system-object-reference.utils";
24
+ import type { ChatDraftIntent } from "@/features/chat/managers/chat-draft-intent.manager";
21
25
 
22
26
  import {
23
27
  useSessionConversationController,
@@ -42,18 +46,23 @@ type SessionConversationAreaProps = {
42
46
  function useSessionConversationDraftIntent(params: {
43
47
  readonly consumeDraftIntent: boolean;
44
48
  readonly applyPromptSuggestion: (prompt: string) => void;
49
+ readonly applySystemObjectReference: (reference: SystemObjectResolvedReference) => void;
45
50
  }) {
46
- const { applyPromptSuggestion, consumeDraftIntent } = params;
51
+ const { applyPromptSuggestion, applySystemObjectReference, consumeDraftIntent } = params;
47
52
  const appPresenter = useAppPresenter();
48
53
  const presenter = usePresenter();
49
54
  useEffect(() => {
50
55
  if (!consumeDraftIntent) {
51
56
  return undefined;
52
57
  }
53
- const applyIntent = (intent: { id: number; prompt: string }) => {
58
+ const applyIntent = (intent: ChatDraftIntent) => {
54
59
  presenter.chatSessionListManager.createSession();
55
60
  presenter.chatSessionListManager.setSelectedAgentId("main");
56
- applyPromptSuggestion(intent.prompt);
61
+ if (intent.kind === 'prompt') {
62
+ applyPromptSuggestion(intent.prompt);
63
+ } else {
64
+ applySystemObjectReference(intent.reference);
65
+ }
57
66
  appPresenter.chatDraftIntentManager.markConsumed(intent.id);
58
67
  };
59
68
  const unsubscribe =
@@ -63,7 +72,7 @@ function useSessionConversationDraftIntent(params: {
63
72
  applyIntent(pendingIntent);
64
73
  }
65
74
  return unsubscribe;
66
- }, [appPresenter, applyPromptSuggestion, consumeDraftIntent, presenter]);
75
+ }, [appPresenter, applyPromptSuggestion, applySystemObjectReference, consumeDraftIntent, presenter]);
67
76
  }
68
77
 
69
78
  type ChatDraftRouteState = {
@@ -204,6 +213,17 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
204
213
  initialPrompt,
205
214
  sessionKey,
206
215
  );
216
+ const applySystemObjectReference = useCallback((reference: SystemObjectResolvedReference) => {
217
+ inputActions.update((current) => {
218
+ const nodes = appendSystemObjectReferenceToken(current.nodes, reference);
219
+ return {
220
+ nodes,
221
+ text: deriveChatComposerDraft(nodes),
222
+ composerFocusRequestId: Date.now(),
223
+ sendError: null,
224
+ };
225
+ });
226
+ }, [inputActions]);
207
227
  const inputQuery = useSessionConversationInputQuery({
208
228
  sessionKey,
209
229
  inputSnapshot,
@@ -355,6 +375,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
355
375
  useSessionConversationDraftIntent({
356
376
  consumeDraftIntent,
357
377
  applyPromptSuggestion: inputActions.applyPromptSuggestion,
378
+ applySystemObjectReference,
358
379
  });
359
380
  const renderInput = useCallback(
360
381
  (surface: "default" | "embedded", placeholder?: string) => (
@@ -47,6 +47,7 @@ import { useSessionConversationInputAttachments } from '@/features/chat/features
47
47
  import { useChatComposerReferenceIntent } from '@/features/chat/features/conversation/hooks/use-chat-composer-reference-intent';
48
48
  import { useSessionConversationComposerNodes } from '@/features/chat/features/conversation/hooks/use-session-conversation-composer-nodes';
49
49
  import { useSessionConversationSlashCommands } from '@/features/chat/features/conversation/hooks/use-session-conversation-slash-commands';
50
+ import { useSystemObjectReferenceSelect } from '@/features/chat/features/conversation/hooks/use-system-object-reference-select';
50
51
  import { ChatConversationTrack } from '@/features/chat/components/conversation/chat-conversation-track';
51
52
  import { useChatMessageLayoutStore } from '@/features/chat/stores/chat-message-layout.store';
52
53
  import type { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
@@ -231,6 +232,7 @@ export const SessionConversationInput = memo(function SessionConversationInput(p
231
232
  const contextReferenceProjectRoot = inputQuery.selectedSessionKey
232
233
  ? inputQuery.selectedSession?.projectRoot ?? inputQuery.defaultProjectRoot ?? ''
233
234
  : inputSnapshot.pendingProjectRoot ?? inputQuery.defaultProjectRoot ?? '';
235
+ const handleSystemObjectSelect = useSystemObjectReferenceSelect(inputBarRef);
234
236
  const { inputSurfaceState, setInputSurfaceTrigger } = useChatInputSurfaceState({
235
237
  commands: slashCommands,
236
238
  isSkillsLoading: inputQuery.isSkillsLoading,
@@ -240,6 +242,7 @@ export const SessionConversationInput = memo(function SessionConversationInput(p
240
242
  language,
241
243
  onSelectPanelApp: handleSlashPanelAppSelect,
242
244
  onSelectSkill: chatRecentSkillsManager.remember,
245
+ onSelectSystemObject: handleSystemObjectSelect,
243
246
  projectRoot: contextReferenceProjectRoot,
244
247
  recentSkillValues,
245
248
  skillRecords,
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import { CornerDownRight, Pencil, Trash2 } from 'lucide-react';
2
+ import { CornerDownRight, LoaderCircle, Pencil, Trash2 } from 'lucide-react';
3
3
 
4
4
  import {
5
5
  Tooltip,
@@ -74,20 +74,30 @@ export function SessionQueuedInputRows({
74
74
  <span className="min-w-0 flex-1 truncate font-medium text-foreground/80">
75
75
  {item.preview || t('chatQueuedBannerAttachmentFallback')}
76
76
  </span>
77
- <div className="flex shrink-0 items-center gap-1.5">
78
- <QueuedInputIconButton
79
- label={t('chatQueuedEdit')}
80
- onClick={() => controller.editQueuedInput(item.id)}
77
+ {item.isSubmitting ? (
78
+ <span
79
+ aria-label={t('chatQueuedSubmitting')}
80
+ className="inline-flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground"
81
81
  >
82
- <Pencil className="h-4 w-4" />
83
- </QueuedInputIconButton>
84
- <QueuedInputIconButton
85
- label={t('chatQueuedDelete')}
86
- onClick={() => controller.deleteQueuedInput(item.id)}
87
- >
88
- <Trash2 className="h-4 w-4" />
89
- </QueuedInputIconButton>
90
- </div>
82
+ <LoaderCircle className="h-3.5 w-3.5 animate-spin" />
83
+ {t('chatQueuedSubmitting')}
84
+ </span>
85
+ ) : (
86
+ <div className="flex shrink-0 items-center gap-1.5">
87
+ <QueuedInputIconButton
88
+ label={t('chatQueuedEdit')}
89
+ onClick={() => controller.editQueuedInput(item.id)}
90
+ >
91
+ <Pencil className="h-4 w-4" />
92
+ </QueuedInputIconButton>
93
+ <QueuedInputIconButton
94
+ label={t('chatQueuedDelete')}
95
+ onClick={() => controller.deleteQueuedInput(item.id)}
96
+ >
97
+ <Trash2 className="h-4 w-4" />
98
+ </QueuedInputIconButton>
99
+ </div>
100
+ )}
91
101
  </div>
92
102
  ))}
93
103
  </div>
@@ -59,6 +59,7 @@ function createControllerParams(params: {
59
59
  const removeQueuedInput = vi.fn(async (id: string) =>
60
60
  queuedInputs.find((item) => item.id === id) ?? null,
61
61
  );
62
+ const refreshQueuedInputs = vi.fn(async () => queuedInputs);
62
63
  return {
63
64
  agent: {
64
65
  abort: vi.fn(),
@@ -116,6 +117,7 @@ function createControllerParams(params: {
116
117
  isRuntimeBlocked: false,
117
118
  runQueue: {
118
119
  inputs: queuedInputs,
120
+ refreshQueuedInputs,
119
121
  removeQueuedInput,
120
122
  },
121
123
  selectedAgentId: 'main',
@@ -178,6 +180,57 @@ describe('useSessionConversationController backend run queue', () => {
178
180
  expect(params.resetComposer).toHaveBeenCalledTimes(1);
179
181
  });
180
182
 
183
+ it('projects a submitting queue row before the backend acknowledges the message', async () => {
184
+ let resolveSend!: (handle: NcpRunHandle) => void;
185
+ const send = vi.fn<TestAgentSend>(() => new Promise((resolve) => {
186
+ resolveSend = resolve;
187
+ }));
188
+ const params = createControllerParams({ isRunning: true, send });
189
+ const { result } = renderHook(() => useSessionConversationController(params));
190
+ let submission!: Promise<void>;
191
+
192
+ act(() => {
193
+ submission = result.current.send();
194
+ });
195
+
196
+ expect(params.resetComposer).toHaveBeenCalledTimes(1);
197
+ expect(result.current.queuedInputs).toEqual([
198
+ expect.objectContaining({
199
+ isSubmitting: true,
200
+ preview: 'next task',
201
+ }),
202
+ ]);
203
+ expect(params.runQueue.refreshQueuedInputs).not.toHaveBeenCalled();
204
+
205
+ await act(async () => {
206
+ resolveSend(createRunHandle({ runId: null }));
207
+ await submission;
208
+ });
209
+
210
+ expect(params.runQueue.refreshQueuedInputs).toHaveBeenCalledTimes(1);
211
+ expect(result.current.queuedInputs).toEqual([]);
212
+ });
213
+
214
+ it('removes the submitting queue row and restores the draft when submission fails', async () => {
215
+ const sendError = new Error('queue submission failed');
216
+ const send = vi.fn<TestAgentSend>(async () => {
217
+ throw sendError;
218
+ });
219
+ const params = createControllerParams({ isRunning: true, send });
220
+ const { result } = renderHook(() => useSessionConversationController(params));
221
+
222
+ await act(async () => {
223
+ await expect(result.current.send()).rejects.toThrow(sendError);
224
+ });
225
+
226
+ expect(result.current.queuedInputs).toEqual([]);
227
+ expect(params.restoreComposer).toHaveBeenCalledWith(expect.objectContaining({
228
+ text: 'next task',
229
+ }));
230
+ expect(params.setSendError).toHaveBeenLastCalledWith(sendError.message);
231
+ expect(params.runQueue.refreshQueuedInputs).not.toHaveBeenCalled();
232
+ });
233
+
181
234
  it('keeps an existing session bound to its agent instead of the global draft selection', async () => {
182
235
  const send = createSendMock();
183
236
  const params = createControllerParams({ isRunning: false, send });
@@ -83,6 +83,24 @@ describe('useSessionRunQueue', () => {
83
83
  unmount();
84
84
  });
85
85
 
86
+ it('refreshes the authoritative queue on demand after a submission is accepted', async () => {
87
+ const listQueuedInputs = vi.spyOn(nextclawClient.sessions, 'listQueuedInputs')
88
+ .mockResolvedValue(createQueue('session-1', 'queued'));
89
+ const { result } = renderHook(
90
+ () => useSessionRunQueue('session-1'),
91
+ { wrapper: createWrapper() },
92
+ );
93
+ await waitFor(() => expect(listQueuedInputs).toHaveBeenCalledTimes(1));
94
+
95
+ let refreshed: UiNcpSessionQueuedInputsView['inputs'] = [];
96
+ await act(async () => {
97
+ refreshed = [...await result.current.refreshQueuedInputs()];
98
+ });
99
+
100
+ expect(listQueuedInputs).toHaveBeenCalledTimes(2);
101
+ expect(refreshed[0]?.message.parts[0]).toMatchObject({ text: 'queued' });
102
+ });
103
+
86
104
  it('replaces an in-flight stale queue read after the queue changes', async () => {
87
105
  let resolveInitialRead!: (queue: UiNcpSessionQueuedInputsView) => void;
88
106
  const initialRead = new Promise<UiNcpSessionQueuedInputsView>((resolve) => {
@@ -2,6 +2,7 @@ import { useEffect, type RefObject } from 'react';
2
2
  import { type ChatInputBarHandle } from '@nextclaw/agent-chat-ui';
3
3
  import {
4
4
  CHAT_CONVERSATION_EXCERPT_TOKEN_KIND,
5
+ CHAT_UI_RESOURCE_TOKEN_KIND,
5
6
  CHAT_WORKSPACE_EXCERPT_TOKEN_KIND,
6
7
  } from '@nextclaw/shared';
7
8
 
@@ -41,7 +42,9 @@ export function useChatComposerReferenceIntent(params: {
41
42
  role: intent.role,
42
43
  excerpt: intent.excerpt,
43
44
  }
44
- : undefined,
45
+ : intent.kind === CHAT_UI_RESOURCE_TOKEN_KIND
46
+ ? { reference: intent.reference }
47
+ : undefined,
45
48
  });
46
49
  intentManager.markConsumed(intent.id);
47
50
  };