@nextclaw/ui 0.27.0 → 0.27.2

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 (320) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/.vite/manifest.json +1246 -1175
  3. package/dist/assets/{abnfDiagram-VRR7QNED-DmeCRAkd.js → abnfDiagram-VRR7QNED-BT0_ycaq.js} +1 -1
  4. package/dist/assets/account-panel-svU9I6E6.js +1 -0
  5. package/dist/assets/agents-CtI89gpb.js +1 -0
  6. package/dist/assets/agents-DWygCmAK.js +1 -0
  7. package/dist/assets/{aiden0z-pptx-renderer.es-ChX5DHqP.js → aiden0z-pptx-renderer.es-ClCaf_Wh.js} +1 -1
  8. package/dist/assets/api-CI6_8Qt1.js +20 -0
  9. package/dist/assets/app-presenter-provider-_UK6sArj.js +28 -0
  10. package/dist/assets/appearance-settings-page-BhedtMx9.js +1 -0
  11. package/dist/assets/apps-C4c4NXqB.js +1 -0
  12. package/dist/assets/{arc-Cu6Ols44.js → arc-cmSdpq1Z.js} +1 -1
  13. package/dist/assets/architecture-TIHT7OUA-BImoGh10.js +1 -0
  14. package/dist/assets/{architectureDiagram-ZJ3FMSHR-DrNB0eLE.js → architectureDiagram-ZJ3FMSHR-aYglVeoS.js} +1 -1
  15. package/dist/assets/{blockDiagram-677ZJIJ3-08rHt6DJ.js → blockDiagram-677ZJIJ3-Di_PBl5q.js} +1 -1
  16. package/dist/assets/{book-open-ClbJmmxP.js → book-open-i_BjUBqL.js} +1 -1
  17. package/dist/assets/{c4Diagram-LMCZKHZV-CCVgRG-u.js → c4Diagram-LMCZKHZV-CfuxybOL.js} +1 -1
  18. package/dist/assets/{card-BdC01NFF.js → card-DokH7OBp.js} +1 -1
  19. package/dist/assets/channel-BDQry0ob.js +1 -0
  20. package/dist/assets/{channels-list-page-BrIvJlop.js → channels-list-page-B7G9lHUm.js} +2 -2
  21. package/dist/assets/chunk-2Q5K7J3B-DkgSFfIy.js +1 -0
  22. package/dist/assets/{chunk-32BRIVSS-BeCaI-JN.js → chunk-32BRIVSS-CCGc4qg4.js} +1 -1
  23. package/dist/assets/{chunk-52WLFC77-ZXIcYPYs.js → chunk-52WLFC77-aJoxU2Ow.js} +1 -1
  24. package/dist/assets/{chunk-5FCAYU7R-DDwTPcy8.js → chunk-5FCAYU7R-CGwtZSax.js} +1 -1
  25. package/dist/assets/{chunk-5HE753X5-WygrMYPL.js → chunk-5HE753X5-DqaMSMeS.js} +1 -1
  26. package/dist/assets/{chunk-5JV3BV7I-o8T3KZgk.js → chunk-5JV3BV7I-DnabINcd.js} +1 -1
  27. package/dist/assets/{chunk-5TONJI2A-BKFbUT7J.js → chunk-5TONJI2A-BhpKv1k2.js} +1 -1
  28. package/dist/assets/{chunk-5VM5RSS4-DYxCRV86.js → chunk-5VM5RSS4-DvkRPit_.js} +1 -1
  29. package/dist/assets/{chunk-7BUUIJ7U-CvSeJlKZ.js → chunk-7BUUIJ7U-CgDQOLnC.js} +1 -1
  30. package/dist/assets/{chunk-BIQX33UG-BhH3RHCY.js → chunk-BIQX33UG-9FEv5b7T.js} +1 -1
  31. package/dist/assets/{chunk-C7G6YPKG-BTL0-xL3.js → chunk-C7G6YPKG-CNGFAFYL.js} +1 -1
  32. package/dist/assets/{chunk-CQNSW5MT-DWAU4QaD.js → chunk-CQNSW5MT-DovTZx0M.js} +1 -1
  33. package/dist/assets/{chunk-CYSBUYHQ-B7ZBMXTx.js → chunk-CYSBUYHQ-DpLEgYa1.js} +1 -1
  34. package/dist/assets/{chunk-EMLP6XTP-D92HvnHE.js → chunk-EMLP6XTP-D4NuN01W.js} +1 -1
  35. package/dist/assets/{chunk-EX3LRPZG-DfOGKwW8.js → chunk-EX3LRPZG-D8Jf4kc2.js} +1 -1
  36. package/dist/assets/{chunk-FWX5IMBZ-DUuJUrXJ.js → chunk-FWX5IMBZ-BdHymAs0.js} +2 -2
  37. package/dist/assets/{chunk-HOUHSVGY-i3MDyUY5.js → chunk-HOUHSVGY-Dd_Ycn9Z.js} +1 -1
  38. package/dist/assets/{chunk-ICXQ74PX-F_pmNX6t.js → chunk-ICXQ74PX-BRPUu3ff.js} +1 -1
  39. package/dist/assets/{chunk-JG7HCLWE-DygOelrU.js → chunk-JG7HCLWE-DnCasQja.js} +1 -1
  40. package/dist/assets/{chunk-JWPE2WC7-BpiZMeRl.js → chunk-JWPE2WC7-C3CkbEj1.js} +1 -1
  41. package/dist/assets/{chunk-MOJQB5TN-CV10sB1I.js → chunk-MOJQB5TN-Pi--K4-1.js} +1 -1
  42. package/dist/assets/{chunk-MOZMSUNE-Cf1WZNm0.js → chunk-MOZMSUNE-3VTspvlh.js} +1 -1
  43. package/dist/assets/{chunk-OGEWGWER-DuSw54VR.js → chunk-OGEWGWER-BetLLyJt.js} +1 -1
  44. package/dist/assets/{chunk-OSBZ3O6U-_rt_XKSZ.js → chunk-OSBZ3O6U-D1VcupAj.js} +1 -1
  45. package/dist/assets/{chunk-PUDLZKDR-BFPaAGNW.js → chunk-PUDLZKDR-Cy4G8SjV.js} +1 -1
  46. package/dist/assets/{chunk-Q4XR5HBZ-GE0v_E5y.js → chunk-Q4XR5HBZ-UYxXzi7_.js} +1 -1
  47. package/dist/assets/{chunk-QBLGF6JB-BK_FpnlJ.js → chunk-QBLGF6JB-CHiGeRY1.js} +1 -1
  48. package/dist/assets/{chunk-R7FJI6CG-CpYh6rGo.js → chunk-R7FJI6CG-C5kVJus8.js} +1 -1
  49. package/dist/assets/{chunk-RYQCIY6F-htnxL_Cl.js → chunk-RYQCIY6F-C6cuuEBn.js} +1 -1
  50. package/dist/assets/{chunk-U6XO7XAA-wDbE4BZ7.js → chunk-U6XO7XAA-CM0EK7Y0.js} +1 -1
  51. package/dist/assets/{chunk-V7JOEXUC-DDRSVFTB.js → chunk-V7JOEXUC-DWJZIsME.js} +1 -1
  52. package/dist/assets/chunk-VAUOI2AC-CsTIB8qD.js +1 -0
  53. package/dist/assets/{chunk-VR4S4FIN-COdhHR1o.js → chunk-VR4S4FIN-CY5KYeEi.js} +1 -1
  54. package/dist/assets/{chunk-WYO6CB5R-DPDGhyF6.js → chunk-WYO6CB5R-B30N3ZP8.js} +3 -3
  55. package/dist/assets/chunk-XXDRQBXY-DK6dz0Q3.js +1 -0
  56. package/dist/assets/{chunk-YOTPTUD7-D8ir9Nx5.js → chunk-YOTPTUD7-CBu82JpO.js} +1 -1
  57. package/dist/assets/{chunk-ZGVPDNZ5-BuNKD836.js → chunk-ZGVPDNZ5-BN5NX5qA.js} +1 -1
  58. package/dist/assets/{chunk-ZIRB5QZD-DyHzq8jH.js → chunk-ZIRB5QZD-DcDXK29L.js} +1 -1
  59. package/dist/assets/{circle-dashed-nDaMRmP-.js → circle-dashed-Cx8CIEbg.js} +1 -1
  60. package/dist/assets/classDiagram-OUVF2IWQ-BYygHCrp.js +1 -0
  61. package/dist/assets/classDiagram-v2-EOCWNBFH-BgQ0XKYz.js +1 -0
  62. package/dist/assets/{client-DlFB5dW5.js → client-CUJUci3r.js} +1 -1
  63. package/dist/assets/{config-split-page-C06fU9OQ.js → config-split-page-hY1xug28.js} +1 -1
  64. package/dist/assets/{confirm-dialog-DpcmlXhd.js → confirm-dialog-B-ejV666.js} +1 -1
  65. package/dist/assets/{context-menu-DKIEaY7f.js → context-menu-dGVv8klA.js} +9 -9
  66. package/dist/assets/{cose-bilkent-JH36ORCC-B1I1_P6a.js → cose-bilkent-JH36ORCC-CmeJVoTw.js} +1 -1
  67. package/dist/assets/{createLucideIcon-Lnt-4LMC.js → createLucideIcon-reFMl-W-.js} +1 -1
  68. package/dist/assets/cron-DkYSmE-f.js +1 -0
  69. package/dist/assets/cynefin-VYW2F7L2-DKbotNWS.js +1 -0
  70. package/dist/assets/{cynefinDiagram-TSTJHNR4-DcOnhnCo.js → cynefinDiagram-TSTJHNR4-DGOUMgPP.js} +1 -1
  71. package/dist/assets/{dagre-nSYhf9yY.js → dagre-CMxSkbJJ.js} +1 -1
  72. package/dist/assets/{dagre-VKFMJZFB-hAX89lg3.js → dagre-VKFMJZFB-3YUBEXwo.js} +1 -1
  73. package/dist/assets/{desktop-capabilities-page-DPORyZAu.js → desktop-capabilities-page-CYJTQ3nC.js} +1 -1
  74. package/dist/assets/{desktop-update-config-BMTeWZmn.js → desktop-update-config-guKAozXO.js} +1 -1
  75. package/dist/assets/{diagram-FQU43EPY-C1mRMD2k.js → diagram-FQU43EPY-Br1g--ww.js} +1 -1
  76. package/dist/assets/{diagram-G47NLZAW-D2XBn5al.js → diagram-G47NLZAW-D1wJCBgr.js} +1 -1
  77. package/dist/assets/{diagram-NH7WQ7WH-3LmRsmkC.js → diagram-NH7WQ7WH-Cgg2auLH.js} +1 -1
  78. package/dist/assets/{diagram-OA4YK3LP-CFWn-osC.js → diagram-OA4YK3LP-R-wHiWqh.js} +1 -1
  79. package/dist/assets/{diagram-WEI45ONY-BqNRbUvU.js → diagram-WEI45ONY-CsNnKV0P.js} +1 -1
  80. package/dist/assets/{dialog-BNXSPMX_.js → dialog-DLOwdjT1.js} +1 -1
  81. package/dist/assets/{dist-Cuiqqp1O.js → dist-ZaFFmAGl.js} +1 -1
  82. package/dist/assets/doc-browser-B0zg0EXA.js +1 -0
  83. package/dist/assets/doc-browser-context-CTmOmuqa.js +1 -0
  84. package/dist/assets/{docx-preview-CunAATyC.js → docx-preview-kPn_EtAr.js} +1 -1
  85. package/dist/assets/{download-f_sPcoLZ.js → download-DovI3Yvf.js} +1 -1
  86. package/dist/assets/{ebnfDiagram-CCIWWBDH-CYb8IwqD.js → ebnfDiagram-CCIWWBDH-DCyhIPdi.js} +1 -1
  87. package/dist/assets/{erDiagram-Q63AITRT-H47mUoeK.js → erDiagram-Q63AITRT-D0ZJYAUf.js} +1 -1
  88. package/dist/assets/eventmodeling-45OFAUF4-SIhbIFIw.js +1 -0
  89. package/dist/assets/{extensions-B-0xQz3L.js → extensions-BZ3qrM8M.js} +1 -1
  90. package/dist/assets/{external-link-CbVlnlNy.js → external-link-DUD3AbsF.js} +1 -1
  91. package/dist/assets/flowDiagram-23GEKE2U-DdAjkU7I.js +1 -0
  92. package/dist/assets/{form-actions-BoTqELHB.js → form-actions-B8VniHts.js} +1 -1
  93. package/dist/assets/{ganttDiagram-NO4QXBWP-hSX45zfV.js → ganttDiagram-NO4QXBWP-CiXDcXZD.js} +1 -1
  94. package/dist/assets/gitGraph-TEB2WS4Q-DnMNpESZ.js +1 -0
  95. package/dist/assets/{gitGraphDiagram-IHSO6WYX-Br0UW2qg.js → gitGraphDiagram-IHSO6WYX-BSiIV48S.js} +1 -1
  96. package/dist/assets/{i18n-B0V5NkFj.js → i18n-IGQbjBqS.js} +2 -2
  97. package/dist/assets/inbox-CJBCLB1X.js +1 -0
  98. package/dist/assets/{inbox-Bna8iUy0.js → inbox-ClAG7SI_.js} +1 -1
  99. package/dist/assets/info-DKCQHKI2-BSm-69p_.js +1 -0
  100. package/dist/assets/{infoDiagram-FWYZ7A6U-DQmP_67w.js → infoDiagram-FWYZ7A6U-CCIgBCVq.js} +1 -1
  101. package/dist/assets/{ishikawaDiagram-FXEZZL3T-BHAV2oes.js → ishikawaDiagram-FXEZZL3T-nQ_baN5u.js} +1 -1
  102. package/dist/assets/{journeyDiagram-5HDEW3XC-CFHax4_d.js → journeyDiagram-5HDEW3XC-ABueIPzj.js} +1 -1
  103. package/dist/assets/{kanban-definition-HUTT4EX6-B4ZA9rp5.js → kanban-definition-HUTT4EX6-8FKS3fmQ.js} +1 -1
  104. package/dist/assets/katex-DPgHtix3.js +1 -0
  105. package/dist/assets/keyboard-shortcuts-settings-page-B5oxyPS2.js +1 -0
  106. package/dist/assets/{line-BboM0HLF.js → line-Biw8iEUz.js} +1 -1
  107. package/dist/assets/{linear-4K_M1oYM.js → linear-D7CWUHTF.js} +1 -1
  108. package/dist/assets/login-page-BxSMwUsc.js +1 -0
  109. package/dist/assets/{login-page-JNr5JCEw.js → login-page-DYaozpzz.js} +1 -1
  110. package/dist/assets/main-D_zmSVS1.css +1 -0
  111. package/dist/assets/main-gFUvLF57.js +2 -0
  112. package/dist/assets/main-i18n-catalog.config-itg3Gvzp.js +1 -0
  113. package/dist/assets/{map-26GpO1wn.js → map-CDu47gTf.js} +1 -1
  114. package/dist/assets/marketplace-DsAf_rnt.js +1 -0
  115. package/dist/assets/mcp-marketplace-page-BqUz09cj.js +1 -0
  116. package/dist/assets/{mermaid-parser.core-BTJFnvRC.js → mermaid-parser.core-Cc9wjl82.js} +2 -2
  117. package/dist/assets/{mermaid.core-B7ufoXgq.js → mermaid.core-GWlaVWz1.js} +3 -3
  118. package/dist/assets/{mindmap-definition-LN4V7U3C-BHyru6KE.js → mindmap-definition-LN4V7U3C-oqnKsz-R.js} +1 -1
  119. package/dist/assets/{model-config-page-C-wbM6Fe.js → model-config-page-Cduyz2Hy.js} +1 -1
  120. package/dist/assets/{navigation-link-DFLSVIut.js → navigation-link-D-JSWFxj.js} +1 -1
  121. package/dist/assets/{ordinal-BqFe2ePF.js → ordinal-DImbxqBz.js} +1 -1
  122. package/dist/assets/packet-7NZHBO7P-1YQvC6mT.js +1 -0
  123. package/dist/assets/panel-app-i18n-catalog.config-BfLHr1tc.js +1 -0
  124. package/dist/assets/panel-apps-Bg5Fzm3T.js +1 -0
  125. package/dist/assets/panelStandalone-oHxbXvYt.js +2 -0
  126. package/dist/assets/{pegDiagram-2B236MQR-PVTatU5j.js → pegDiagram-2B236MQR-DYAB8CEz.js} +1 -1
  127. package/dist/assets/pie-RZYD4A2V-BGoNOSwu.js +1 -0
  128. package/dist/assets/{pieDiagram-ENE6RG2P-CGc-QCc7.js → pieDiagram-ENE6RG2P-DGsH0Kk5.js} +1 -1
  129. package/dist/assets/plus-DUdl68Eo.js +1 -0
  130. package/dist/assets/{privacy-settings-page-CPdEiouE.js → privacy-settings-page-DG9E8N-F.js} +1 -1
  131. package/dist/assets/projects-DvHyoKIF.js +1 -0
  132. package/dist/assets/{provider-models-XRArsply.js → provider-models-COzjYl29.js} +1 -1
  133. package/dist/assets/{provider-scoped-model-input-C8JI-hus.js → provider-scoped-model-input-Cvy74uj8.js} +1 -1
  134. package/dist/assets/{providers-config-page-fyMlVgvq.js → providers-config-page-7rCwVnhh.js} +1 -1
  135. package/dist/assets/{puzzle-Bk3ud1KI.js → puzzle-C5Wfpjk_.js} +1 -1
  136. package/dist/assets/{pwa-Cx6Fnox4.js → pwa-CAg_9zFs.js} +1 -1
  137. package/dist/assets/{quadrantDiagram-ABIIQ3AL-DGL36riv.js → quadrantDiagram-ABIIQ3AL-BegGcT3l.js} +1 -1
  138. package/dist/assets/radar-I7S5WNFK-uPku9RRq.js +1 -0
  139. package/dist/assets/railroad-3IZDKUUU-DHnmbuIo.js +1 -0
  140. package/dist/assets/railroad-abnf-AHOZXSZD-DiZs--Iw.js +1 -0
  141. package/dist/assets/railroad-ebnf-EBAXGLYW-Nr53gnNE.js +1 -0
  142. package/dist/assets/railroad-peg-LSFZ7HO6-Cm_PuwJS.js +1 -0
  143. package/dist/assets/{railroadDiagram-RFXS5EU6-CyNwvhSb.js → railroadDiagram-RFXS5EU6-B3yJ2yxE.js} +1 -1
  144. package/dist/assets/{refresh-cw-Ca2napNx.js → refresh-cw-OhwaPDn1.js} +1 -1
  145. package/dist/assets/remote-Dhr4K1oK.js +1 -0
  146. package/dist/assets/{requirementDiagram-TGXJPOKE-C31NMKJ0.js → requirementDiagram-TGXJPOKE-DtEyoEXG.js} +1 -1
  147. package/dist/assets/{rotate-cw-DXg7sNUE.js → rotate-cw-aBponvp7.js} +1 -1
  148. package/dist/assets/runtime-config-page-FI2pk3HH.js +1 -0
  149. package/dist/assets/{sankeyDiagram-HTMAVEWB-CwrQ_7PA.js → sankeyDiagram-HTMAVEWB-h9AYS2UB.js} +1 -1
  150. package/dist/assets/{save-DNigywZ9.js → save-394QCMXn.js} +1 -1
  151. package/dist/assets/{search-U9C0oTQJ.js → search-BG2qAlNZ.js} +1 -1
  152. package/dist/assets/{search-config-page-Bdx_RR1q.js → search-config-page-D4LeiB9y.js} +1 -1
  153. package/dist/assets/{secrets-config-page-CvMIcsfJ.js → secrets-config-page-BzGcr5Vw.js} +2 -2
  154. package/dist/assets/security-config-vD_V0BQF.js +1 -0
  155. package/dist/assets/{select-DxwDeKUR.js → select-xUXYV0Gr.js} +1 -1
  156. package/dist/assets/{sequenceDiagram-DBY2YBRQ-EFD482_y.js → sequenceDiagram-DBY2YBRQ-D-uxCkob.js} +1 -1
  157. package/dist/assets/service-apps-panel-BTqXn0pg.js +1 -0
  158. package/dist/assets/{settings-2-BrBUdRoY.js → settings-2-CWOGRRaA.js} +1 -1
  159. package/dist/assets/{sizeCapture-X5ZJPWSS-TDvULTE1.js → sizeCapture-X5ZJPWSS-DBzZytQo.js} +1 -1
  160. package/dist/assets/{src-CI2AvEMj.js → src-zrGbZsfc.js} +1 -1
  161. package/dist/assets/{stateDiagram-2N3HPSRC-JdPsIYHo.js → stateDiagram-2N3HPSRC-DyDy7AHq.js} +1 -1
  162. package/dist/assets/stateDiagram-v2-6OUMAXLB-CtkpO6aA.js +1 -0
  163. package/dist/assets/{status-dot-BbGsrkIX.js → status-dot-CYifnSnt.js} +1 -1
  164. package/dist/assets/{swimlanes-5IMT3BWC-BnxpKeK_.js → swimlanes-5IMT3BWC-BzOduS38.js} +2 -2
  165. package/dist/assets/swimlanesDiagram-G3AALYLV-BSdi6mvi.js +8 -0
  166. package/dist/assets/{tag-chip-BDbxcf6P.js → tag-chip-CjM6lyeh.js} +1 -1
  167. package/dist/assets/theme-provider-BToFZGZG.js +1 -0
  168. package/dist/assets/{timeline-definition-FHXFAJF6-2IL22-uC.js → timeline-definition-FHXFAJF6-CmgnEF2t.js} +1 -1
  169. package/dist/assets/{trash-2-DwSkRfeB.js → trash-2-DvJ6duOW.js} +1 -1
  170. package/dist/assets/treeView-QDETBFTQ-DBoqypPR.js +1 -0
  171. package/dist/assets/treemap-6X3UGDF4-BMeL3P0q.js +1 -0
  172. package/dist/assets/use-config-COusaY5p.js +1 -0
  173. package/dist/assets/{use-desktop-capabilities-D7odgaTB.js → use-desktop-capabilities-B-u6ojjW.js} +1 -1
  174. package/dist/assets/{use-viewport-layout-BANU5E1t.js → use-viewport-layout-IKKGpjzF.js} +1 -1
  175. package/dist/assets/{vennDiagram-L72KCM5P-Cjf6n5Va.js → vennDiagram-L72KCM5P-DwS7D2kg.js} +1 -1
  176. package/dist/assets/wardley-OPB4EBWU-Dqxe7zN6.js +1 -0
  177. package/dist/assets/{wardleyDiagram-EHGQE667-yv4qKbBO.js → wardleyDiagram-EHGQE667-B4X8OOL4.js} +1 -1
  178. package/dist/assets/{x-BqGj6_Vq.js → x-E9VB4HQx.js} +1 -1
  179. package/dist/assets/{xychartDiagram-FW5EYKEG-Bmp8Ck8X.js → xychartDiagram-FW5EYKEG-BjRQ_0nx.js} +1 -1
  180. package/dist/index.html +41 -40
  181. package/dist/panel-standalone.html +16 -16
  182. package/package.json +6 -6
  183. package/src/features/agents/components/__tests__/agents-page.test.tsx +8 -5
  184. package/src/features/agents/components/agent-details-dialog.tsx +19 -15
  185. package/src/features/agents/components/agents-page.tsx +27 -38
  186. package/src/features/app-data/components/app-retained-data-section.tsx +2 -2
  187. package/src/features/apps/components/app-marketplace-catalog.tsx +5 -5
  188. package/src/features/apps/components/app-marketplace-detail.tsx +11 -2
  189. package/src/features/apps/components/app-packages-panel.tsx +4 -4
  190. package/src/features/apps/components/apps-panel.tsx +3 -1
  191. package/src/features/chat/components/providers/chat-runtime.provider.tsx +1 -1
  192. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +0 -1
  193. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +13 -2
  194. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +8 -1
  195. package/src/features/chat/features/conversation/components/session-conversation-input-top-slot.tsx +44 -0
  196. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +4 -38
  197. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +127 -10
  198. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +12 -2
  199. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +88 -73
  200. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +5 -15
  201. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +53 -13
  202. package/src/features/chat/features/conversation/hooks/use-session-submission-recovery.ts +83 -0
  203. package/src/features/chat/features/conversation/types/session-conversation-input.types.ts +38 -0
  204. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +1 -29
  205. package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +1 -8
  206. package/src/features/chat/features/message/components/__tests__/chat-message-list-skill-preview.container.test.tsx +14 -1
  207. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +7 -2
  208. package/src/features/chat/features/session/utils/__tests__/chat-session-route.utils.test.ts +26 -0
  209. package/src/features/chat/features/session/utils/chat-session-preference-governance.utils.ts +14 -8
  210. package/src/features/chat/features/session/utils/chat-session-route.utils.ts +9 -12
  211. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +14 -2
  212. package/src/features/chat/features/workspace/components/__tests__/session-cron-job-content.test.tsx +5 -1
  213. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +1 -1
  214. package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +6 -22
  215. package/src/features/chat/index.ts +1 -0
  216. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +37 -47
  217. package/src/features/chat/pages/ncp-chat-page.tsx +3 -3
  218. package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +67 -1
  219. package/src/features/chat/stores/chat-composer-draft.store.ts +230 -29
  220. package/src/features/cron/components/__tests__/cron-config.test.tsx +8 -2
  221. package/src/features/cron/components/cron-config.tsx +6 -17
  222. package/src/features/cron/components/cron-job-detail-dialog.tsx +10 -9
  223. package/src/features/cron/components/cron-job-resource.tsx +51 -0
  224. package/src/features/cron/index.ts +1 -0
  225. package/src/features/inbox/pages/inbox-page.tsx +8 -5
  226. package/src/features/marketplace/components/__tests__/marketplace-page-detail.test.tsx +1 -0
  227. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +1 -0
  228. package/src/features/marketplace/components/mcp/__tests__/mcp-marketplace-page.test.tsx +2 -0
  229. package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +2 -2
  230. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +23 -1
  231. package/src/features/marketplace/hooks/use-marketplace-item-detail.ts +11 -0
  232. package/src/features/panel-apps/index.ts +1 -0
  233. package/src/features/projects/components/work/project-work-item-drawer.tsx +7 -10
  234. package/src/features/projects/pages/project-home-page.tsx +18 -23
  235. package/src/features/projects/pages/projects-page.test.tsx +4 -1
  236. package/src/features/right-panel-resources/components/__tests__/system-object-resource.test.tsx +74 -6
  237. package/src/features/right-panel-resources/components/native-object-resource.tsx +134 -0
  238. package/src/features/right-panel-resources/components/page-resource-icon.tsx +1 -1
  239. package/src/features/right-panel-resources/components/system-object-resource.tsx +66 -1
  240. package/src/features/right-panel-resources/components/workspace-file-resource.tsx +9 -0
  241. package/src/features/right-panel-resources/configs/right-panel-resource-routes.config.ts +11 -21
  242. package/src/features/right-panel-resources/managers/__tests__/page-resource.manager.test.ts +14 -4
  243. package/src/features/right-panel-resources/managers/page-resource.manager.ts +38 -21
  244. package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-route-resolver.utils.test.ts +12 -0
  245. package/src/features/service-apps/components/service-apps-panel.tsx +5 -2
  246. package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +16 -0
  247. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +2 -2
  248. package/src/shared/components/doc-browser/__tests__/resource-link-interceptor.test.tsx +29 -1
  249. package/src/shared/components/doc-browser/stores/doc-browser.store.ts +13 -7
  250. package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +2 -1
  251. package/src/shared/components/ui/skeleton.tsx +16 -2
  252. package/src/shared/lib/i18n/locales/en-US/chat.json +8 -0
  253. package/src/shared/lib/i18n/locales/zh-CN/chat.json +8 -0
  254. package/src/shared/lib/transport/__tests__/local-transport.service.test.ts +24 -0
  255. package/src/shared/lib/transport/local-transport.service.ts +8 -6
  256. package/dist/assets/account-panel-BYxGT4m4.js +0 -1
  257. package/dist/assets/api-CG22BskB.js +0 -20
  258. package/dist/assets/app-presenter-provider-CJFjhVYI.js +0 -28
  259. package/dist/assets/appearance-settings-page-BcXr0vHp.js +0 -1
  260. package/dist/assets/architecture-TIHT7OUA-CLjV_xu4.js +0 -1
  261. package/dist/assets/channel-BgpbPyEH.js +0 -1
  262. package/dist/assets/chunk-2Q5K7J3B-DjhMPqAC.js +0 -1
  263. package/dist/assets/chunk-VAUOI2AC-GYimZYx9.js +0 -1
  264. package/dist/assets/chunk-XXDRQBXY-KKCf0HV5.js +0 -1
  265. package/dist/assets/classDiagram-OUVF2IWQ-iRMPRR8M.js +0 -1
  266. package/dist/assets/classDiagram-v2-EOCWNBFH-BguFy_wj.js +0 -1
  267. package/dist/assets/cynefin-VYW2F7L2-CtbjXuCW.js +0 -1
  268. package/dist/assets/doc-browser-CDEapjmj.js +0 -1
  269. package/dist/assets/doc-browser-context-0QDWYorh.js +0 -1
  270. package/dist/assets/eventmodeling-45OFAUF4-Djd6id_u.js +0 -1
  271. package/dist/assets/flowDiagram-23GEKE2U-DUrsM_ZL.js +0 -1
  272. package/dist/assets/gitGraph-TEB2WS4Q-CU6P_2Cm.js +0 -1
  273. package/dist/assets/info-DKCQHKI2-Bj2P_7RC.js +0 -1
  274. package/dist/assets/katex-BprZ-Wwb.js +0 -1
  275. package/dist/assets/keyboard-shortcuts-settings-page-BluWKrSo.js +0 -1
  276. package/dist/assets/login-page-BMHW0Hh0.js +0 -1
  277. package/dist/assets/main-BCX_Untx.css +0 -1
  278. package/dist/assets/main-C5kbmGUV.js +0 -2
  279. package/dist/assets/main-i18n-catalog.config-DO4wNT7T.js +0 -1
  280. package/dist/assets/mcp-marketplace-page-CV-PHKTN.js +0 -1
  281. package/dist/assets/packet-7NZHBO7P-ti5ge2jr.js +0 -1
  282. package/dist/assets/panel-app-i18n-catalog.config-Bo52dPuF.js +0 -1
  283. package/dist/assets/panelStandalone-PuuMF65O.js +0 -2
  284. package/dist/assets/pie-RZYD4A2V-Bnep8TyV.js +0 -1
  285. package/dist/assets/plus-CywSlIbG.js +0 -1
  286. package/dist/assets/projects-D_cd_t4G.js +0 -1
  287. package/dist/assets/radar-I7S5WNFK-BYg-icAP.js +0 -1
  288. package/dist/assets/railroad-3IZDKUUU-_CHO-Fi1.js +0 -1
  289. package/dist/assets/railroad-abnf-AHOZXSZD-hbQDevHe.js +0 -1
  290. package/dist/assets/railroad-ebnf-EBAXGLYW-v4RZkOfi.js +0 -1
  291. package/dist/assets/railroad-peg-LSFZ7HO6-bC9BqkI5.js +0 -1
  292. package/dist/assets/remote-D5MBQNZE.js +0 -1
  293. package/dist/assets/runtime-config-page--ivCxBT4.js +0 -1
  294. package/dist/assets/security-config-CQmMqQ8v.js +0 -1
  295. package/dist/assets/service-apps-panel-CiYO1Be4.js +0 -1
  296. package/dist/assets/stateDiagram-v2-6OUMAXLB-4_aAQfB_.js +0 -1
  297. package/dist/assets/swimlanesDiagram-G3AALYLV-wCqfwsw-.js +0 -8
  298. package/dist/assets/theme-provider-D98XGa-c.js +0 -1
  299. package/dist/assets/treeView-QDETBFTQ-BAyOb14Z.js +0 -1
  300. package/dist/assets/treemap-6X3UGDF4-DgPDM0zS.js +0 -1
  301. package/dist/assets/use-config-D3cNzk2k.js +0 -1
  302. package/dist/assets/wardley-OPB4EBWU-eCElh8z5.js +0 -1
  303. /package/dist/assets/{array-DstOKG9P.js → array-DsNX3jRj.js} +0 -0
  304. /package/dist/assets/{chunk-KEIR6QF5-0TA8nwgf.js → chunk-KEIR6QF5-BOAXXeyv.js} +0 -0
  305. /package/dist/assets/{chunk-Y2CYZVJY-rfGCG6pM.js → chunk-Y2CYZVJY-CHjSjwoV.js} +0 -0
  306. /package/dist/assets/{config-hints-BfGoD7-o.js → config-hints-CaB3I7KP.js} +0 -0
  307. /package/dist/assets/{cytoscape.esm-DdIcNEda.js → cytoscape.esm-j4J9a91l.js} +0 -0
  308. /package/dist/assets/{defaultLocale-CzXix2iJ.js → defaultLocale-Bmxjp-V_.js} +0 -0
  309. /package/dist/assets/{dist-D5dwMwKA.js → dist-DwLj1Wg5.js} +0 -0
  310. /package/dist/assets/{graphlib-BKOe0eFe.js → graphlib-CC0HTn1v.js} +0 -0
  311. /package/dist/assets/{host-capabilities-CnSVTaot.js → host-capabilities-B107nwS3.js} +0 -0
  312. /package/dist/assets/{init-OCFb3zgY.js → init-Biz9Rus1.js} +0 -0
  313. /package/dist/assets/{jszip.min-B2uhSxvV.js → jszip.min-DQvBVV_R.js} +0 -0
  314. /package/dist/assets/{katex-dBrYsE7B.js → katex-BzT-4KBu.js} +0 -0
  315. /package/dist/assets/{middleware-CAXxl-af.js → middleware-B--6mAUM.js} +0 -0
  316. /package/dist/assets/{navigation-history-CzErJuPG.js → navigation-history-CCnxsAKR.js} +0 -0
  317. /package/dist/assets/{panel-app-CSQmm_7E.js → panel-app-BBTg0tVp.js} +0 -0
  318. /package/dist/assets/{path-T5eoIRSJ.js → path-4azsBPZv.js} +0 -0
  319. /package/dist/assets/{rough.esm-DmGXmZEB.js → rough.esm-w1lBArN6.js} +0 -0
  320. /package/dist/assets/{xlsx-CoYacou7.js → xlsx--SB9KlFl.js} +0 -0
@@ -0,0 +1,134 @@
1
+ import { lazy, Suspense, useState } from "react";
2
+ import type { DocBrowserCustomTabRenderParams } from "@/shared/components/doc-browser/doc-browser-renderer.types";
3
+ import { t } from "@/shared/lib/i18n";
4
+ import {
5
+ createPanelAppRightPanelResourceTarget,
6
+ type RightPanelAppsTab,
7
+ } from "@/features/right-panel-resources/utils/right-panel-resource-uri.utils";
8
+
9
+ const AgentsPage = lazy(async () => ({
10
+ default: (await import("@/features/agents"))
11
+ .AgentsPage,
12
+ }));
13
+ const CronJobResource = lazy(async () => ({
14
+ default: (await import("@/features/cron"))
15
+ .CronJobResource,
16
+ }));
17
+ const ProjectsPage = lazy(async () => ({
18
+ default: (await import("@/features/projects"))
19
+ .ProjectsPage,
20
+ }));
21
+ const InboxPage = lazy(async () => ({
22
+ default: (await import("@/features/inbox")).InboxPage,
23
+ }));
24
+ const AppsPanel = lazy(async () => ({
25
+ default: (await import("@/features/apps")).AppsPanel,
26
+ }));
27
+ const McpMarketplacePage = lazy(async () => ({
28
+ default: (
29
+ await import("@/features/marketplace")
30
+ ).McpMarketplacePage,
31
+ }));
32
+ const PanelAppRuntimeSurface = lazy(async () => ({
33
+ default: (
34
+ await import("@/features/panel-apps")
35
+ ).PanelAppRuntimeSurface,
36
+ }));
37
+ const PanelAppHostProvider = lazy(async () => ({
38
+ default: (
39
+ await import("@/features/panel-apps")
40
+ ).PanelAppHostProvider,
41
+ }));
42
+
43
+ function ServiceAppResource({
44
+ objectId,
45
+ openTarget,
46
+ }: {
47
+ objectId: string;
48
+ openTarget: DocBrowserCustomTabRenderParams["openTarget"];
49
+ }) {
50
+ const [activeTab, setActiveTab] = useState<RightPanelAppsTab>("service-apps");
51
+ return (
52
+ <AppsPanel
53
+ serviceResourceId={objectId}
54
+ activeTab={activeTab}
55
+ onActiveTabChange={setActiveTab}
56
+ onOpenPanelApp={(entry) =>
57
+ openTarget(createPanelAppRightPanelResourceTarget(entry))
58
+ }
59
+ />
60
+ );
61
+ }
62
+
63
+ /** Object identity chooses domain content; the workbench owns placement. */
64
+ export function NativeObjectResource({
65
+ objectType,
66
+ objectId,
67
+ openTarget,
68
+ }: {
69
+ objectType: string;
70
+ objectId: string;
71
+ openTarget: DocBrowserCustomTabRenderParams["openTarget"];
72
+ }) {
73
+ let content;
74
+ switch (objectType) {
75
+ case "agent":
76
+ content = <AgentsPage resourceId={objectId} />;
77
+ break;
78
+ case "cron-job":
79
+ content = <CronJobResource jobId={objectId} />;
80
+ break;
81
+ case "project":
82
+ content = <ProjectsPage resourceId={objectId} />;
83
+ break;
84
+ case "project-work": {
85
+ let ids: unknown;
86
+ try {
87
+ ids = JSON.parse(objectId);
88
+ } catch {
89
+ ids = null;
90
+ }
91
+ if (
92
+ !Array.isArray(ids) ||
93
+ ids.length !== 2 ||
94
+ ids.some((id) => typeof id !== "string" || !id)
95
+ )
96
+ break;
97
+ content = <ProjectsPage resourceId={ids[0]} resourceWorkId={ids[1]} />;
98
+ break;
99
+ }
100
+ case "inbox-delivery":
101
+ content = <InboxPage resourceId={objectId} />;
102
+ break;
103
+ case "mcp-server":
104
+ content = <McpMarketplacePage resourceId={objectId} />;
105
+ break;
106
+ case "service-app":
107
+ content = (
108
+ <ServiceAppResource objectId={objectId} openTarget={openTarget} />
109
+ );
110
+ break;
111
+ case "panel-app":
112
+ content = (
113
+ <PanelAppHostProvider>
114
+ <PanelAppRuntimeSurface appId={objectId} restorationScope="main" />
115
+ </PanelAppHostProvider>
116
+ );
117
+ break;
118
+ }
119
+ return (
120
+ <Suspense
121
+ fallback={
122
+ <p role="status" className="p-4">
123
+ {t("loading")}
124
+ </p>
125
+ }
126
+ >
127
+ {content ?? (
128
+ <p role="alert" className="p-4">
129
+ {t("resourceInvalid")}
130
+ </p>
131
+ )}
132
+ </Suspense>
133
+ );
134
+ }
@@ -81,6 +81,7 @@ function resourceTypeIcon(
81
81
  ? (kind as keyof typeof RESOURCE_ICONS)
82
82
  : "page";
83
83
  }
84
+ if (parseSessionKeyFromPanelUrl(uri)) return "session";
84
85
  const object = parseSystemObjectReferenceUri(uri);
85
86
  if (object) return OBJECT_TYPE_ICONS[object.objectType] ?? "generic";
86
87
  if (
@@ -89,7 +90,6 @@ function resourceTypeIcon(
89
90
  )
90
91
  return "skill";
91
92
  if (uri.startsWith("nextclaw://page?")) return "page";
92
- if (uri.startsWith("nextclaw://chat-session")) return "session";
93
93
  if (
94
94
  uri.startsWith("nextclaw://workspace-file") ||
95
95
  uri.startsWith("file:") ||
@@ -9,11 +9,63 @@ import type {
9
9
  DocBrowserCustomTabRenderers,
10
10
  } from "@/shared/components/doc-browser/doc-browser-renderer.types";
11
11
  import { t } from "@/shared/lib/i18n";
12
+ import { useAppPresenter } from "@/app/components/app-presenter-provider";
13
+ import { useLocation, useNavigate } from "react-router-dom";
14
+ import { parseSystemObjectReferenceUri } from "@nextclaw/shared";
15
+ import { NativeObjectResource } from "./native-object-resource";
16
+ import { ChatTextSelectionAction } from "@nextclaw/agent-chat-ui";
17
+ import { WORKSPACE_TEXT_EXCERPT_MAX_CHARACTERS } from "@/features/chat";
12
18
 
13
19
  function SystemObjectResource({
14
20
  tab,
15
21
  openTarget,
16
22
  }: DocBrowserCustomTabRenderParams) {
23
+ const app = useAppPresenter();
24
+ const { pathname } = useLocation();
25
+ const navigate = useNavigate();
26
+ const uri = tab.resourceUri ?? tab.currentUrl;
27
+ const identity = parseSystemObjectReferenceUri(uri);
28
+ if (!identity)
29
+ return (
30
+ <p role="alert" className="p-4">
31
+ {t("resourceInvalid")}
32
+ </p>
33
+ );
34
+ if (identity.objectType !== "skill") {
35
+ return (
36
+ <ChatTextSelectionAction
37
+ actionLabel={t("chatWorkspaceAddToChat")}
38
+ className="h-full min-h-0"
39
+ maxCharacters={WORKSPACE_TEXT_EXCERPT_MAX_CHARACTERS}
40
+ selectionTooLongLabel={t("chatWorkspaceExcerptSelectionTooLong")}
41
+ onAddToChat={({ text }) =>
42
+ app.pageResourceManager.addExcerptToChat(
43
+ {
44
+ path: uri,
45
+ label: tab.title,
46
+ excerpt: text,
47
+ startLine: null,
48
+ endLine: null,
49
+ },
50
+ pathname,
51
+ navigate,
52
+ )
53
+ }
54
+ >
55
+ <NativeObjectResource key={uri} {...identity} openTarget={openTarget} />
56
+ </ChatTextSelectionAction>
57
+ );
58
+ }
59
+ return <SystemObjectDocument tab={tab} openTarget={openTarget} />;
60
+ }
61
+
62
+ function SystemObjectDocument({
63
+ tab,
64
+ openTarget,
65
+ }: Pick<DocBrowserCustomTabRenderParams, "tab" | "openTarget">) {
66
+ const app = useAppPresenter();
67
+ const { pathname } = useLocation();
68
+ const navigate = useNavigate();
17
69
  const uri = tab.resourceUri ?? tab.currentUrl;
18
70
  const query = useQuery({
19
71
  queryKey: ["resource-object-snapshot", uri],
@@ -22,7 +74,7 @@ function SystemObjectResource({
22
74
  await nextclawClient.systemObjectReferences.resolve(uri);
23
75
  const response = await fetch(
24
76
  buildNcpAssetContentUrl(reference.assetUri),
25
- { signal },
77
+ { signal: AbortSignal.any([signal, AbortSignal.timeout(30_000)]) },
26
78
  );
27
79
  if (!response.ok)
28
80
  throw new Error(`Unable to read resource (${response.status})`);
@@ -77,6 +129,19 @@ function SystemObjectResource({
77
129
  file={{ ...file, key: uri }}
78
130
  sessionWorkingDir={null}
79
131
  sessionProjectRoot={null}
132
+ onTextExcerptAdd={(excerpt) =>
133
+ app.pageResourceManager.addExcerptToChat(
134
+ {
135
+ ...excerpt,
136
+ path: uri,
137
+ label: reference.label,
138
+ startLine: null,
139
+ endLine: null,
140
+ },
141
+ pathname,
142
+ navigate,
143
+ )
144
+ }
80
145
  onFileOpen={(action) => {
81
146
  const next = createWorkspaceFileTab(action, null);
82
147
  if (next)
@@ -11,11 +11,16 @@ import {
11
11
  } from "@/features/chat";
12
12
  import { createWorkspaceFileTab } from "@/features/chat";
13
13
  import { t } from "@/shared/lib/i18n";
14
+ import { useAppPresenter } from "@/app/components/app-presenter-provider";
15
+ import { useLocation, useNavigate } from "react-router-dom";
14
16
 
15
17
  function WorkspaceFilePanelContent({
16
18
  tab,
17
19
  openTarget,
18
20
  }: DocBrowserCustomTabRenderParams) {
21
+ const app = useAppPresenter();
22
+ const { pathname } = useLocation();
23
+ const navigate = useNavigate();
19
24
  const view = readWorkspaceFilePanelView(tab);
20
25
  if (!view)
21
26
  return (
@@ -32,6 +37,10 @@ function WorkspaceFilePanelContent({
32
37
  file={view.file}
33
38
  sessionWorkingDir={view.workingDir}
34
39
  sessionProjectRoot={view.projectRoot}
40
+ onTextExcerptAdd={(excerpt) => app.pageResourceManager.addExcerptToChat({
41
+ ...excerpt,
42
+ path: tab.resourceUri ?? tab.currentUrl,
43
+ }, pathname, navigate)}
35
44
  onFileOpen={(action) => {
36
45
  const file = createWorkspaceFileTab(
37
46
  action,
@@ -33,7 +33,8 @@ function isUrlWithPrefix(url: string, prefix: string): boolean {
33
33
  function resolveNextclawDocsUrl(uri: ParsedResourceUri): string {
34
34
  const docsPath = uri.pathSegments.join('/');
35
35
  const rawPath = docsPath ? `/${docsPath}` : '/';
36
- return normalizeUrlByKind(rawPath, 'docs');
36
+ const parsed = new URL(uri.raw);
37
+ return normalizeUrlByKind(`${rawPath}${parsed.search}${parsed.hash}`, 'docs');
37
38
  }
38
39
 
39
40
  function createDocsResourceUriFromSegments(pathSegments: string[]): string {
@@ -45,20 +46,9 @@ function createDocsResourceUriFromSegments(pathSegments: string[]): string {
45
46
  }
46
47
 
47
48
  function createDocsResourceUriFromUrl(url: string): string {
48
- const normalized = normalizeDocUrl(url);
49
- const pathname = normalized.startsWith('/')
50
- ? normalized
51
- : (() => {
52
- try {
53
- return new URL(url).pathname;
54
- } catch {
55
- return '';
56
- }
57
- })();
58
- if (!pathname) {
59
- return 'nextclaw://docs';
60
- }
61
- return createDocsResourceUriFromSegments(pathname.split('/'));
49
+ const parsed = new URL(url);
50
+ const pathname = parsed.pathname.replace(/\.html$/, '').replace(/\/$/, '');
51
+ return `${createDocsResourceUriFromSegments(pathname.split('/'))}${parsed.search}${parsed.hash}`;
62
52
  }
63
53
 
64
54
  function isPanelAppContentUri(uri: ParsedResourceUri): boolean {
@@ -97,7 +87,7 @@ function arePanelAppUrlsEquivalent(left: string, right: string): boolean {
97
87
  export const RIGHT_PANEL_RESOURCE_ROUTE_DEFINITIONS: RightPanelResourceRouteDefinition[] = [
98
88
  {
99
89
  id: 'system-object', kind: 'system-object', defaultUrl: () => 'nextclaw://objects',
100
- match: (uri) => Boolean(parseSystemObjectReferenceUri(uri.raw)),
90
+ match: (uri) => !parseSessionKeyFromPanelUrl(uri.raw) && Boolean(parseSystemObjectReferenceUri(uri.raw)),
101
91
  resolve: (uri) => ({ kind: 'system-object', title: parseSystemObjectReferenceUri(uri.raw)!.objectId, url: uri.raw, resourceUri: uri.raw, historyPolicy: 'none' }),
102
92
  areEquivalent: (left, right) => left === right,
103
93
  },
@@ -120,10 +110,10 @@ export const RIGHT_PANEL_RESOURCE_ROUTE_DEFINITIONS: RightPanelResourceRouteDefi
120
110
  areEquivalent: (left, right) => left === right,
121
111
  },
122
112
  {
123
- defaultUrl: () => 'nextclaw://chat-session/',
113
+ defaultUrl: () => 'nextclaw://sessions/',
124
114
  id: CHAT_SESSION_PANEL_KIND,
125
115
  kind: CHAT_SESSION_PANEL_KIND,
126
- match: (uri) => uri.scheme === 'nextclaw' && uri.authority === 'chat-session',
116
+ match: (uri) => parseSessionKeyFromPanelUrl(uri.raw) !== null,
127
117
  resolve: (uri) => {
128
118
  const sessionKey = parseSessionKeyFromPanelUrl(uri.raw);
129
119
  const url = sessionKey ? buildSessionPanelUrl(sessionKey) : uri.raw;
@@ -136,7 +126,7 @@ export const RIGHT_PANEL_RESOURCE_ROUTE_DEFINITIONS: RightPanelResourceRouteDefi
136
126
  historyPolicy: 'none',
137
127
  };
138
128
  },
139
- areEquivalent: (left, right) => left === right,
129
+ areEquivalent: (left, right) => parseSessionKeyFromPanelUrl(left) === parseSessionKeyFromPanelUrl(right),
140
130
  },
141
131
  {
142
132
  defaultUrl: () => RIGHT_PANEL_HOME_URL,
@@ -179,7 +169,7 @@ export const RIGHT_PANEL_RESOURCE_ROUTE_DEFINITIONS: RightPanelResourceRouteDefi
179
169
  return {
180
170
  historyPolicy: 'managed',
181
171
  kind: 'docs',
182
- resourceUri: createDocsResourceUriFromSegments(uri.pathSegments),
172
+ resourceUri: `${createDocsResourceUriFromSegments(uri.pathSegments)}${new URL(uri.raw).search}${new URL(uri.raw).hash}`,
183
173
  title: t('docBrowserHelp'),
184
174
  url,
185
175
  };
@@ -198,7 +188,7 @@ export const RIGHT_PANEL_RESOURCE_ROUTE_DEFINITIONS: RightPanelResourceRouteDefi
198
188
  historyPolicy: 'managed',
199
189
  kind: RIGHT_PANEL_APPS_TAB_KIND,
200
190
  resourceUri: url,
201
- title: t('appsTitle'),
191
+ title: t(new URL(url).searchParams.get('tab') === 'service-apps' ? 'serviceAppsTitle' : 'appsTitle'),
202
192
  url,
203
193
  };
204
194
  },
@@ -17,7 +17,7 @@ import {
17
17
  function setup() {
18
18
  const app = {
19
19
  rightPanelResourceRouteResolver: new RightPanelResourceRouteResolver(),
20
- docBrowserManager: { openTarget: vi.fn() },
20
+ docBrowserManager: { openTarget: vi.fn(), setActiveTab: vi.fn() },
21
21
  workbenchSurfaceManager: {
22
22
  restore: vi.fn(),
23
23
  toggleMaximize: vi.fn(),
@@ -28,6 +28,7 @@ function setup() {
28
28
  requestUiResourceReference: vi.fn(),
29
29
  requestFileReference: vi.fn(),
30
30
  requestSystemObjectReference: vi.fn(),
31
+ requestExcerptReference: vi.fn(),
31
32
  },
32
33
  };
33
34
  return {
@@ -38,6 +39,16 @@ function setup() {
38
39
  }
39
40
 
40
41
  describe("shared resource opening policy", () => {
42
+ it.each(["/chat/current-session", "/chat", "/agents"])("routes a selected resource excerpt from %s to its chat composer", (pathname) => {
43
+ const { manager, app, navigate } = setup();
44
+ const excerpt = { path: "nextclaw://objects/agent/philosopher", label: "灵魂哲学家", excerpt: "Runtime: native", startLine: null, endLine: null };
45
+ manager.addExcerptToChat(excerpt, pathname, navigate);
46
+ expect(app.chatComposerIntentManager.requestExcerptReference).toHaveBeenCalledWith({
47
+ ...excerpt, targetSessionKey: pathname === "/chat/current-session" ? "current-session" : null,
48
+ });
49
+ if (pathname === "/agents") expect(navigate).toHaveBeenCalledWith("/chat");
50
+ else expect(navigate).not.toHaveBeenCalled();
51
+ });
41
52
  beforeEach(() => {
42
53
  usePageNavigationStore.setState({ pinned: [] });
43
54
  useDocBrowserStore.setState({ snapshot: createDefaultDocBrowserState() });
@@ -74,9 +85,8 @@ describe("shared resource opening policy", () => {
74
85
  },
75
86
  });
76
87
  manager.open(page, "default", navigate);
77
- expect(app.docBrowserManager.openTarget).toHaveBeenCalledWith(page.target, {
78
- newTab: true,
79
- });
88
+ expect(app.docBrowserManager.setActiveTab).toHaveBeenCalledWith(page.uri);
89
+ expect(app.docBrowserManager.openTarget).not.toHaveBeenCalled();
80
90
  expect(navigate).not.toHaveBeenCalled();
81
91
  manager.open(page, "main", navigate);
82
92
  expect(navigate).toHaveBeenCalledWith("/apps/panel/example-notes");
@@ -6,6 +6,7 @@ import { GLOBAL_WORKBENCH_SURFACE } from "@/shared/components/workbench/types/wo
6
6
  import { useChatThreadStore } from "@/features/chat";
7
7
  import type { ChatThreadManager } from "@/features/chat";
8
8
  import type { AppPresenter } from "@/app/presenters/app.presenter";
9
+ import type { WorkspaceTextExcerpt } from "@/features/chat";
9
10
  import { useDocBrowserStore } from "@/shared/components/doc-browser/stores/doc-browser.store";
10
11
  import { useFloatingSessionStore } from "@/features/chat";
11
12
  import { sessionSurfaceManager } from "@/features/chat";
@@ -61,29 +62,28 @@ export class PageResourceManager {
61
62
  };
62
63
 
63
64
  resolve = (
64
- uri: string,
65
+ rawUri: string,
65
66
  context?: { workingDir?: string | null; sessionKey?: string | null },
66
67
  ): PageResource | null => {
67
- if (!/^(nextclaw:\/\/|https?:\/\/)/i.test(uri)) return null;
68
- if (uri.startsWith("nextclaw://file/")) {
69
- try {
68
+ if (!/^(nextclaw:\/\/|https?:\/\/)/i.test(rawUri)) return null;
69
+ try {
70
+ const uri = this.app.rightPanelResourceRouteResolver.normalize(rawUri);
71
+ if (uri.startsWith("nextclaw://file/")) {
70
72
  const target = resolveFileResourceTarget(uri, context);
71
73
  return target ? pageResourceFromTarget(target) : null;
72
- } catch {
73
- return null;
74
74
  }
75
- }
76
- const saved =
77
- this.remembered.get(uri) ??
78
- usePageNavigationStore.getState().pinned.find((page) => page.uri === uri);
79
- if (saved) return saved;
80
- const tab = useDocBrowserStore
81
- .getState()
82
- .snapshot.tabs.find(
83
- (item) => (item.resourceUri ?? item.currentUrl) === uri,
84
- );
85
- if (tab) return pageResourceFromTab(tab);
86
- try {
75
+ const saved =
76
+ this.remembered.get(uri) ??
77
+ usePageNavigationStore
78
+ .getState()
79
+ .pinned.find((page) => page.uri === uri);
80
+ if (saved) return saved;
81
+ const tab = useDocBrowserStore
82
+ .getState()
83
+ .snapshot.tabs.find(
84
+ (item) => (item.resourceUri ?? item.currentUrl) === uri,
85
+ );
86
+ if (tab) return pageResourceFromTab(tab);
87
87
  if (uri.startsWith("nextclaw://page?")) {
88
88
  const path = new URL(uri).searchParams.get("path");
89
89
  if (
@@ -190,7 +190,9 @@ export class PageResourceManager {
190
190
  location === "floating" ? "floating" : "docked",
191
191
  );
192
192
  if (location === "main")
193
- this.app.workbenchSurfaceManager.toggleMaximize(`session-workspace:${parent ?? "draft"}`);
193
+ this.app.workbenchSurfaceManager.toggleMaximize(
194
+ `session-workspace:${parent ?? "draft"}`,
195
+ );
194
196
  return;
195
197
  }
196
198
  const sessionKey = parseSessionKeyFromPanelUrl(page.uri);
@@ -208,7 +210,7 @@ export class PageResourceManager {
208
210
  (item) => (item.resourceUri ?? item.currentUrl) === page.uri,
209
211
  );
210
212
  if (existing.isOpen && tab) {
211
- this.app.docBrowserManager.openTarget(page.target, { newTab: true });
213
+ this.app.docBrowserManager.setActiveTab(tab.id);
212
214
  this.app.workbenchSurfaceManager.restore(GLOBAL_WORKBENCH_SURFACE);
213
215
  return;
214
216
  }
@@ -216,7 +218,9 @@ export class PageResourceManager {
216
218
  if (
217
219
  location === "main" ||
218
220
  page.target.kind === "route" ||
219
- (location === "default" && page.mainPath && page.target.kind !== "panel-app")
221
+ (location === "default" &&
222
+ page.mainPath &&
223
+ page.target.kind !== "panel-app")
220
224
  ) {
221
225
  navigate(pageResourceMainPath(page));
222
226
  } else if (location === "floating" && sessionKey) {
@@ -295,6 +299,19 @@ export class PageResourceManager {
295
299
  } else this.open(next, "default", navigate);
296
300
  };
297
301
 
302
+ addExcerptToChat = (
303
+ excerpt: WorkspaceTextExcerpt,
304
+ pathname: string,
305
+ navigate: (path: string) => void,
306
+ ): void => {
307
+ const isChat = pathname === "/chat" || pathname.startsWith("/chat/");
308
+ this.app.chatComposerIntentManager.requestExcerptReference({
309
+ ...excerpt,
310
+ targetSessionKey: isChat ? parseSessionKeyFromRoute(pathname.slice("/chat/".length)) : null,
311
+ });
312
+ if (!isChat) navigate("/chat");
313
+ };
314
+
298
315
  addToChat = (
299
316
  page: PageResource,
300
317
  pathname: string,
@@ -2,6 +2,18 @@ import { describe, expect, it } from 'vitest';
2
2
  import { RightPanelResourceRouteResolver } from '@/features/right-panel-resources';
3
3
 
4
4
  describe('RightPanelResourceRouteResolver', () => {
5
+ it('does not treat different document sections as the same destination', () => {
6
+ const resolver = new RightPanelResourceRouteResolver();
7
+ expect(resolver.areUrlsEquivalent('https://docs.nextclaw.io/en/guide/commands#one',
8
+ 'https://docs.nextclaw.io/en/guide/commands#two', 'docs', 'docs')).toBe(false);
9
+ });
10
+ it.each(['nextclaw://docs/guide/commands?source=chat#sessions', 'https://docs.nextclaw.io/zh/guide/commands?source=chat#sessions'])(
11
+ 'keeps document query and anchor in the resource and final destination: %s', (uri) => {
12
+ const target = new RightPanelResourceRouteResolver().resolve(uri);
13
+ expect(target.url).toContain('?source=chat#sessions');
14
+ expect(target.resourceUri).toContain('?source=chat#sessions');
15
+ },
16
+ );
5
17
  it('preserves the app marketplace through resource normalization', () => {
6
18
  expect(new RightPanelResourceRouteResolver().resolve('nextclaw://apps?tab=marketplace')).toMatchObject({
7
19
  kind: 'apps', dedupeKey: 'apps', url: 'nextclaw://apps?tab=marketplace', resourceUri: 'nextclaw://apps?tab=marketplace',
@@ -31,8 +31,10 @@ type ServiceActionView = ServiceActionListView["actions"][number];
31
31
 
32
32
  export function ServiceAppsPanel({
33
33
  onManagePackage,
34
+ resourceId,
34
35
  }: {
35
36
  onManagePackage: (packageId: string) => void;
37
+ resourceId?: string;
36
38
  }) {
37
39
  const serviceApps = useServiceApps();
38
40
  const appData = useAppData();
@@ -84,7 +86,8 @@ export function ServiceAppsPanel({
84
86
  );
85
87
  }
86
88
 
87
- const apps: ServiceAppRecordView[] = serviceApps.data?.entries ?? [];
89
+ const apps: ServiceAppRecordView[] = (serviceApps.data?.entries ?? []).filter((app) => !resourceId || app.id === resourceId);
90
+ if (resourceId && !apps.length) return <p role="alert" className="p-4">{t("resourceNotFound")}</p>;
88
91
  const diagnostics = serviceApps.data?.diagnostics ?? [];
89
92
  const actions: ServiceActionView[] = serviceActions.data?.actions ?? [];
90
93
  const grants: ServiceActionGrantView[] =
@@ -165,7 +168,7 @@ export function ServiceAppsPanel({
165
168
  discoveredActionsByApp[app.id] ??
166
169
  actions.filter((action) => action.appId === app.id)
167
170
  }
168
- actionsOpen={Boolean(expandedActionsByApp[app.id])}
171
+ actionsOpen={expandedActionsByApp[app.id] ?? Boolean(resourceId)}
169
172
  grants={grants}
170
173
  agents={agents.data?.agents ?? []}
171
174
  deletePending={deleteServiceApp.isPending}
@@ -55,6 +55,22 @@ async function resetMemoryThenRehydrate(savedState: string | null) {
55
55
  }
56
56
 
57
57
  describe('DocBrowserManager layout notifications', () => {
58
+ it.each(['nextclaw://objects/chat-session/example', 'nextclaw://chat-session/sid_ZXhhbXBsZQ'])(
59
+ 'restores historical conversation tabs as real session views: %s', async (uri) => {
60
+ window.localStorage.setItem(docBrowserStorageKey, JSON.stringify({ version: 1, state: { snapshot: {
61
+ isOpen: true, activeTabId: 'old',
62
+ tabs: [{ id: 'old', kind: 'system-object', title: 'Conversation', currentUrl: uri, resourceUri: uri }],
63
+ activeHistory: [{ tabId: 'old', kind: 'system-object', url: uri, resourceUri: uri }],
64
+ } } }));
65
+ await rehydrateDocBrowserFromStorage();
66
+ expect(useDocBrowserStore.getState().snapshot.tabs[0]).toMatchObject({
67
+ kind: 'chat-session', currentUrl: 'nextclaw://sessions/example', resourceUri: 'nextclaw://sessions/example',
68
+ });
69
+ expect(useDocBrowserStore.getState().snapshot.activeHistory[0]).toMatchObject({
70
+ kind: 'chat-session', url: 'nextclaw://sessions/example',
71
+ });
72
+ },
73
+ );
58
74
  it('notifies the app layout coordinator after opening the docked browser', () => {
59
75
  const onRightPanelOpened = vi.fn();
60
76
  const manager = new DocBrowserManager(new WorkbenchSurfaceManager(),
@@ -505,7 +505,7 @@ describe("DocBrowser", () => {
505
505
 
506
506
  render(<DocBrowser />);
507
507
 
508
- expect(screen.getByTitle("Local App").getAttribute("tabindex")).toBeNull();
508
+ expect(screen.getAllByTitle("Local App").find((element) => element.tagName === 'IFRAME')!.getAttribute("tabindex")).toBeNull();
509
509
  });
510
510
  });
511
511
 
@@ -875,7 +875,7 @@ describe("DocBrowser content tabs", () => {
875
875
  render(<DocBrowser />);
876
876
 
877
877
  const addressInput = screen.getByRole("textbox", { name: "Address" }) as HTMLInputElement;
878
- const iframe = screen.getByTitle("Local App") as HTMLIFrameElement;
878
+ const iframe = screen.getAllByTitle("Local App").find((element) => element.tagName === 'IFRAME') as HTMLIFrameElement;
879
879
  const externalLink = screen.getByRole("link", { name: /Open in Browser/i }) as HTMLAnchorElement;
880
880
 
881
881
  expect(addressInput.value).toBe("http://127.0.0.1:5173/dashboard");
@@ -54,7 +54,7 @@ describe("ordinary Markdown resource links end to end", () => {
54
54
  </QueryClientProvider>,
55
55
  );
56
56
  }
57
- it.each(["cron-job", "skill", "agent", "project", "inbox-delivery"])(
57
+ it.each(["cron-job", "skill", "agent", "project", "inbox-delivery", "panel-app", "service-app", "mcp-server", "project-work"])(
58
58
  "opens a normal Markdown %s object link in the shared resource viewer",
59
59
  (kind) => {
60
60
  const uri = "nextclaw://objects/" + kind + "/existing-object";
@@ -72,6 +72,34 @@ describe("ordinary Markdown resource links end to end", () => {
72
72
  expect(screen.getByTestId("route").textContent).toBe("/chat");
73
73
  },
74
74
  );
75
+ it.each(['sessions/ncp-mu2x4zdy-9wzl0otb', 'chat-session/ncp-mu2x4zdy-9wzl0otb',
76
+ 'chat-session/sid_bmNwLW11Mng0emR5LTl3emwwb3Ri', 'objects/chat-session/ncp-mu2x4zdy-9wzl0otb',
77
+ 'objects/chat-sessions/ncp-mu2x4zdy-9wzl0otb'])(
78
+ 'opens the actual conversation route from %s', (path) => {
79
+ setup(`[Conversation](nextclaw://${path})`);
80
+ fireEvent.click(screen.getByRole('link', { name: 'Conversation' }));
81
+ expect(screen.getByTestId('route').textContent).toBe('/chat/ncp-mu2x4zdy-9wzl0otb');
82
+ expect(useDocBrowserStore.getState().snapshot.isOpen).toBe(false);
83
+ },
84
+ );
85
+ it.each([
86
+ ['nextclaw://docs/guide/getting-started', 'docs'],
87
+ ['nextclaw://apps?tab=service-apps', 'apps'],
88
+ ['nextclaw://marketplace-detail/skill%3Aexample', 'marketplace-detail'],
89
+ ['nextclaw://file/absolute/tmp/readme.md', 'workspace-file'],
90
+ ])('opens the %s resource family through ordinary Markdown', (uri, kind) => {
91
+ setup(`[Resource](${uri})`);
92
+ fireEvent.click(screen.getByRole('link', { name: 'Resource' }));
93
+ const { snapshot } = useDocBrowserStore.getState();
94
+ expect(snapshot.tabs.find((item) => item.id === snapshot.activeTabId)?.kind).toBe(kind);
95
+ });
96
+ it.each([['nextclaw://marketplace', '/skills'], ['nextclaw://page?path=%2Fagents', '/agents']])(
97
+ 'navigates built-in page %s', (uri, path) => {
98
+ setup(`[Page](${uri})`);
99
+ fireEvent.click(screen.getByRole('link', { name: 'Page' }));
100
+ expect(screen.getByTestId('route').textContent).toBe(path);
101
+ },
102
+ );
75
103
  it("opens a normal Panel App link in the global sidebar without a catalog lookup", () => {
76
104
  setup();
77
105
  const link = screen.getByRole("link", { name: "Notes" });