@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
@@ -43,6 +43,7 @@ function DetailRow({
43
43
  }
44
44
 
45
45
  type CronJobDetailDialogProps = {
46
+ readonly embedded?: boolean;
46
47
  readonly job: CronJobView | null;
47
48
  readonly open: boolean;
48
49
  readonly onDelete: (job: CronJobView) => void;
@@ -52,6 +53,7 @@ type CronJobDetailDialogProps = {
52
53
  };
53
54
 
54
55
  export function CronJobDetailDialog({
56
+ embedded = false,
55
57
  job,
56
58
  open,
57
59
  onDelete,
@@ -74,13 +76,8 @@ export function CronJobDetailDialog({
74
76
  )
75
77
  : t("cronNeverRun");
76
78
 
77
- return (
78
- <Sheet open={open} onOpenChange={onOpenChange}>
79
- <SheetContent
80
- side="right"
81
- closeLabel={t("cronCloseDetails")}
82
- className="flex w-full flex-col overflow-hidden p-0 sm:max-w-[510px]"
83
- >
79
+ const content = (
80
+ <>
84
81
  <SheetHeader className="shrink-0 border-b border-border/60 px-5 pb-5 pt-6 pr-14 sm:px-7 sm:pt-7">
85
82
  <div className="mb-1 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
86
83
  <span>{describeCronSchedule(job)}</span>
@@ -232,7 +229,11 @@ export function CronJobDetailDialog({
232
229
  {t("cronRunNow")}
233
230
  </Button>
234
231
  </SheetFooter>
235
- </SheetContent>
236
- </Sheet>
232
+ </>
237
233
  );
234
+ return <Sheet open={!embedded && open} onOpenChange={onOpenChange}>
235
+ {embedded ? <div className="flex h-full min-h-0 flex-col" data-testid="cron-job-detail">{content}</div> : (
236
+ <SheetContent side="right" closeLabel={t("cronCloseDetails")} className="flex w-full flex-col overflow-hidden p-0 sm:max-w-[510px]">{content}</SheetContent>
237
+ )}
238
+ </Sheet>;
238
239
  }
@@ -0,0 +1,51 @@
1
+ import { CronJobDetailDialog } from "./cron-job-detail-dialog";
2
+ import { useCronJobs } from "@/features/cron/hooks/use-cron-jobs";
3
+ import { useCronJobActions } from "@/features/cron/hooks/use-cron-job-actions";
4
+ import { t } from "@/shared/lib/i18n";
5
+
6
+ export function CronJobResource({ jobId }: { jobId: string }) {
7
+ const query = useCronJobs({ all: true });
8
+ const actions = useCronJobActions();
9
+ const job = query.data?.jobs.find((item) => item.id === jobId);
10
+ if (query.isPending)
11
+ return (
12
+ <p role="status" className="p-4">
13
+ {t("loading")}
14
+ </p>
15
+ );
16
+ if (query.isError)
17
+ return (
18
+ <div className="p-4">
19
+ <p role="alert">{t("resourceLoadFailed")}</p>
20
+ <button onClick={() => void query.refetch()}>
21
+ {t("resourceRetry")}
22
+ </button>
23
+ </div>
24
+ );
25
+ if (!job)
26
+ return (
27
+ <p role="alert" className="p-4">
28
+ {t("resourceNotFound")}
29
+ </p>
30
+ );
31
+ return (
32
+ <>
33
+ <CronJobDetailDialog
34
+ embedded
35
+ job={job}
36
+ open
37
+ onOpenChange={() => {}}
38
+ onDelete={(value) => {
39
+ void actions.deleteJob(value);
40
+ }}
41
+ onRun={(value) => {
42
+ void actions.runJob(value);
43
+ }}
44
+ onToggle={(value, enabled) => {
45
+ void actions.toggleJob(value, enabled);
46
+ }}
47
+ />
48
+ <actions.ConfirmDialog />
49
+ </>
50
+ );
51
+ }
@@ -1,4 +1,5 @@
1
1
  export { CronConfig } from "./components/cron-config";
2
+ export { CronJobResource } from "./components/cron-job-resource";
2
3
  export { CronJobDetailDialog } from "./components/cron-job-detail-dialog";
3
4
  export { useCronJobActions } from "./hooks/use-cron-job-actions";
4
5
  export {
@@ -271,9 +271,10 @@ function InboxDetailPane({
271
271
  );
272
272
  }
273
273
 
274
- export function InboxPage() {
274
+ export function InboxPage({ resourceId }: { resourceId?: string } = {}) {
275
275
  const navigate = useNavigate();
276
- const { deliveryId } = useParams<{ deliveryId?: string }>();
276
+ const { deliveryId: routeDeliveryId } = useParams<{ deliveryId?: string }>();
277
+ const deliveryId = resourceId ?? routeDeliveryId;
277
278
  const { isMobile } = useViewportLayout();
278
279
  const { chatComposerIntentManager, docBrowserManager, inboxManager } = useAppPresenter();
279
280
  const deliveriesQuery = useInboxDeliveries();
@@ -366,12 +367,14 @@ export function InboxPage() {
366
367
  });
367
368
  };
368
369
 
369
- const showList = !isMobile || !deliveryId;
370
+ const showList = !resourceId && (!isMobile || !deliveryId);
370
371
  const showDetail = !isMobile || Boolean(deliveryId);
372
+ if (resourceId && deliveriesQuery.isPending) return <p role="status" className="p-4">{t("loading")}</p>;
373
+ if (resourceId && !deliveriesQuery.isError && !activeDelivery) return <p role="alert" className="p-4">{t("resourceNotFound")}</p>;
371
374
 
372
375
  return (
373
376
  <div className="flex h-full min-h-0 flex-col md:gap-6">
374
- {!isMobile ? <PageHeader
377
+ {!isMobile && !resourceId ? <PageHeader
375
378
  headingLevel={1}
376
379
  title={t("inboxTitle")}
377
380
  className="px-4 sm:px-0"
@@ -381,7 +384,7 @@ export function InboxPage() {
381
384
  {deliveriesQuery.isError ? (
382
385
  <div className="p-4">{isMobile && deliveryId ? <IconActionButton icon={<ArrowLeft className="h-4 w-4" />} label={t("inboxTitle")} onClick={() => navigate('/inbox')} /> : null}<p role="alert" className="text-sm text-destructive">{t("inboxLoadError")}</p></div>
383
386
  ) : (
384
- <div className="grid h-full min-h-0 grid-cols-1 md:grid-cols-[300px_minmax(0,1fr)]">
387
+ <div className={cn("grid h-full min-h-0 grid-cols-1", !resourceId && "md:grid-cols-[300px_minmax(0,1fr)]")}>
385
388
  {showList ? <InboxListPane
386
389
  activeDeliveryId={activeDelivery?.id ?? null}
387
390
  deliveries={deliveries}
@@ -28,6 +28,7 @@ const mocks = vi.hoisted(() => ({
28
28
  fetchMarketplaceSkillContent: vi.fn(),
29
29
  }));
30
30
 
31
+ vi.mock("@/app/components/app-presenter-provider", () => ({ useAppPresenter: () => ({ pageResourceManager: { resolve: vi.fn(), open: vi.fn() } }) }));
31
32
  vi.mock("react-router-dom", async () => {
32
33
  const actual = await vi.importActual("react-router-dom");
33
34
  return {
@@ -47,6 +47,7 @@ const mocks = vi.hoisted(() => ({
47
47
  },
48
48
  }));
49
49
 
50
+ vi.mock("@/app/components/app-presenter-provider", () => ({ useAppPresenter: () => ({ pageResourceManager: { resolve: vi.fn(), open: vi.fn() } }) }));
50
51
  vi.mock("react-router-dom", async () => {
51
52
  const actual = await vi.importActual("react-router-dom");
52
53
  return {
@@ -6,6 +6,8 @@ import type {
6
6
  MarketplaceListView,
7
7
  } from "@/shared/lib/api";
8
8
  import type * as ReactQueryModule from "@tanstack/react-query";
9
+ vi.mock("@/app/components/app-presenter-provider", () => ({ useAppPresenter: () => ({ pageResourceManager: { open: vi.fn() } }) }));
10
+ vi.mock("react-router-dom", () => ({ useNavigate: () => vi.fn() }));
9
11
 
10
12
  type ItemsQueryState = {
11
13
  data?: MarketplaceListView;
@@ -13,7 +13,7 @@ export function McpMarketplaceCard(props: {
13
13
  item?: MarketplaceItemSummary;
14
14
  record?: MarketplaceInstalledRecord;
15
15
  localeFallbacks: string[];
16
- onOpen: () => void;
16
+ onOpen?: () => void;
17
17
  onInstall?: () => void;
18
18
  onToggle?: () => void;
19
19
  onDoctor?: () => void;
@@ -42,7 +42,7 @@ export function McpMarketplaceCard(props: {
42
42
  return (
43
43
  <article
44
44
  onClick={onOpen}
45
- className="cursor-pointer rounded-2xl border border-gray-200/70 bg-white p-4 shadow-sm transition hover:border-blue-300 hover:shadow-md"
45
+ className={`rounded-2xl border border-gray-200/70 bg-white p-4 shadow-sm transition${onOpen ? " cursor-pointer hover:border-blue-300 hover:shadow-md" : ""}`}
46
46
  >
47
47
  <div className="flex items-start justify-between gap-3">
48
48
  <div className="min-w-0">
@@ -50,12 +50,17 @@ import { useInfiniteScrollLoader } from "@/shared/hooks/use-infinite-scroll-load
50
50
  import { cn } from "@/shared/lib/utils";
51
51
  import { Sparkles, PackageCheck } from "lucide-react";
52
52
  import { Button } from "@/shared/components/ui/button";
53
+ import { useAppPresenter } from "@/app/components/app-presenter-provider";
54
+ import { useNavigate } from "react-router-dom";
55
+ import { pageResourceFromSystemObject } from "@/features/right-panel-resources";
53
56
 
54
57
  type ScopeType = "catalog" | "installed";
55
58
 
56
59
  const PAGE_SIZE = 12;
57
60
 
58
- export function McpMarketplacePage() {
61
+ export function McpMarketplacePage({ resourceId }: { resourceId?: string } = {}) {
62
+ const app = useAppPresenter();
63
+ const navigate = useNavigate();
59
64
  const [scope, setScope] = useState<ScopeType>("catalog");
60
65
  const [searchText, setSearchText] = useState("");
61
66
  const [query, setQuery] = useState("");
@@ -142,6 +147,10 @@ export function McpMarketplacePage() {
142
147
  item?: MarketplaceItemSummary,
143
148
  record?: MarketplaceInstalledRecord,
144
149
  ) => {
150
+ if (record?.id) {
151
+ app.pageResourceManager.open(pageResourceFromSystemObject("mcp-server", record.id, record.label || record.id), "default", navigate);
152
+ return;
153
+ }
145
154
  const title = item?.name ?? record?.label ?? record?.id ?? "MCP";
146
155
  const detailId = createMarketplaceDetailDocId(
147
156
  item ? "mcp" : "mcp-local",
@@ -260,6 +269,19 @@ export function McpMarketplacePage() {
260
269
  });
261
270
  };
262
271
 
272
+ if (resourceId) {
273
+ const record = installedQuery.data?.records.find((item) => item.id === resourceId);
274
+ if (installedQuery.isPending) return <p role="status" className="p-4">{t("loading")}</p>;
275
+ if (!record) return <p role="alert" className="p-4">{t(installedQuery.isError ? "resourceLoadFailed" : "resourceNotFound")}</p>;
276
+ return <div className="h-full overflow-auto p-4">
277
+ <McpMarketplaceCard record={record} localeFallbacks={localeFallbacks}
278
+ onToggle={() => void handleManage(record.enabled === false ? "enable" : "disable", record)}
279
+ onDoctor={() => { setDoctorTarget(record.id ?? null); setDoctorResult(null); void doctorMutation.mutateAsync(record.id ?? ""); }}
280
+ onRemove={() => void handleManage("remove", record)} />
281
+ <DoctorDialog open={Boolean(doctorTarget)} targetName={doctorTarget} result={doctorResult} pending={doctorMutation.isPending} onOpenChange={(open) => !open && setDoctorTarget(null)} />
282
+ <ConfirmDialog />
283
+ </div>;
284
+ }
263
285
  const scopeTabs = [
264
286
  { id: "catalog", label: t("marketplaceMcpTabCatalog"), icon: Sparkles },
265
287
  {
@@ -11,8 +11,13 @@ import {
11
11
  import { pickLocalizedText } from "@/features/marketplace/components/marketplace-localization";
12
12
  import { t } from "@/shared/lib/i18n";
13
13
  import { useRef } from "react";
14
+ import { useAppPresenter } from "@/app/components/app-presenter-provider";
15
+ import { useNavigate } from "react-router-dom";
16
+ import { toast } from "sonner";
14
17
 
15
18
  export function useMarketplaceItemDetail(localeFallbacks: string[]) {
19
+ const app = useAppPresenter();
20
+ const navigate = useNavigate();
16
21
  const docBrowser = useDocBrowser();
17
22
  const detailRequestRef = useRef({ byKey: new Map<string, number>(), seq: 0 });
18
23
 
@@ -20,6 +25,12 @@ export function useMarketplaceItemDetail(localeFallbacks: string[]) {
20
25
  item?: MarketplaceItemSummary,
21
26
  record?: MarketplaceInstalledRecord,
22
27
  ) => {
28
+ if (record?.resourceUri) {
29
+ const page = app.pageResourceManager.resolve(record.resourceUri);
30
+ if (page) app.pageResourceManager.open(page, "default", navigate);
31
+ else toast.error(t("pageUnavailable"));
32
+ return;
33
+ }
23
34
  const title =
24
35
  item?.name ??
25
36
  record?.label ??
@@ -1,4 +1,5 @@
1
1
  export { PanelAppsList } from './components/panel-apps-list';
2
+ export { PanelAppRuntimeSurface } from './components/panel-app-runtime-surface';
2
3
  export { PanelAppMainPage } from './pages/panel-app-main-page';
3
4
  export { PanelAppStandalonePage } from './pages/panel-app-standalone-page';
4
5
  export { PanelAppServiceActionAuthorizationDialog } from './components/panel-app-service-action-authorization-dialog';
@@ -39,12 +39,14 @@ import { getProjectWorkStateLabel } from "@/features/projects/utils/project-work
39
39
  import { joinProjectPath } from "@/features/projects/utils/project-artifact-view.utils";
40
40
 
41
41
  export function ProjectWorkItemDrawer({
42
+ embedded = false,
42
43
  onOpenArtifact,
43
44
  onOpenChange,
44
45
  projectId,
45
46
  projectRoot,
46
47
  workItemId,
47
48
  }: {
49
+ embedded?: boolean;
48
50
  onOpenArtifact: (path: string, label: string) => void;
49
51
  onOpenChange: (open: boolean) => void;
50
52
  projectId: string;
@@ -55,13 +57,7 @@ export function ProjectWorkItemDrawer({
55
57
  const activity = useProjectWorkActivity(projectId, workItemId);
56
58
  useProjectWorkEvents(projectId);
57
59
  const states = useProjectWorkStates(projectId);
58
- return (
59
- <Sheet open={Boolean(workItemId)} onOpenChange={onOpenChange}>
60
- <SheetContent
61
- side="right"
62
- closeLabel={t("projectsCloseDetails")}
63
- className="flex h-full w-full flex-col overflow-hidden p-0 sm:max-w-[680px]"
64
- >
60
+ const content = <>
65
61
  {item.isLoading ? (
66
62
  <div className="p-6 text-sm text-muted-foreground">
67
63
  {t("projectsLoading")}
@@ -84,9 +80,10 @@ export function ProjectWorkItemDrawer({
84
80
  onClose={() => onOpenChange(false)}
85
81
  />
86
82
  ) : null}
87
- </SheetContent>
88
- </Sheet>
89
- );
83
+ </>;
84
+ return <Sheet open={!embedded && Boolean(workItemId)} onOpenChange={onOpenChange}>
85
+ {embedded ? <div className="flex h-full min-h-0 flex-col">{content}</div> : <SheetContent side="right" closeLabel={t("projectsCloseDetails")} className="flex h-full w-full flex-col overflow-hidden p-0 sm:max-w-[680px]">{content}</SheetContent>}
86
+ </Sheet>;
90
87
  }
91
88
 
92
89
  function ProjectWorkItemEditor({
@@ -28,6 +28,8 @@ import {
28
28
  type ProjectHomeTab,
29
29
  } from "@/features/projects/presenters/project-home.presenter";
30
30
  import { joinProjectPath } from "@/features/projects/utils/project-artifact-view.utils";
31
+ import { useAppPresenter } from "@/app/components/app-presenter-provider";
32
+ import { pageResourceFromSystemObject } from "@/features/right-panel-resources";
31
33
 
32
34
  const PROJECT_TABS: ProjectHomeTab[] = [
33
35
  "overview",
@@ -37,19 +39,21 @@ const PROJECT_TABS: ProjectHomeTab[] = [
37
39
  "agreement",
38
40
  ];
39
41
 
40
- export function ProjectsPage() {
41
- const { projectId, tab: tabParam } = useParams<{
42
+ export function ProjectsPage({ resourceId, resourceWorkId }: { resourceId?: string; resourceWorkId?: string } = {}) {
43
+ const app = useAppPresenter();
44
+ const { projectId: routeProjectId, tab: routeTab } = useParams<{
42
45
  projectId?: string;
43
46
  tab?: string;
44
47
  }>();
48
+ const projectId = resourceId ?? routeProjectId;
49
+ const [resourceTab, setResourceTab] = useState<ProjectHomeTab>("overview");
50
+ const tabParam = resourceId ? resourceTab : routeTab;
45
51
  const navigate = useNavigate();
46
52
  const { state } = useLocation();
47
53
  const presenter = usePresenter();
48
54
  const { isMobile } = useViewportLayout();
49
55
  const projects = useProjects();
50
- const [selectedWorkItemId, setSelectedWorkItemId] = useState<string | null>(
51
- null,
52
- );
56
+ const openWorkItem = (id: string) => app.pageResourceManager.open(pageResourceFromSystemObject("project-work", JSON.stringify([projectId, id]), id), "default", navigate);
53
57
  const registered = projects.data?.projects ?? [];
54
58
  const selectedProject =
55
59
  registered.find((project) => project.id === projectId) ?? null;
@@ -74,6 +78,7 @@ export function ProjectsPage() {
74
78
  {t("projectsLoadFailed")}: {projects.error.message}
75
79
  </main>
76
80
  );
81
+ if (resourceId && !selectedProject) return <p role="alert" className="p-4">{t("resourceNotFound")}</p>;
77
82
  if (!registered.length)
78
83
  return (
79
84
  <main className="p-6 text-sm text-muted-foreground">
@@ -103,6 +108,8 @@ export function ProjectsPage() {
103
108
  viewMode: "preview",
104
109
  previewViewer: "rendered",
105
110
  });
111
+ if (resourceWorkId) return <ProjectWorkItemDrawer embedded projectId={selectedProject.id} projectRoot={selectedProject.rootPath}
112
+ workItemId={resourceWorkId} onOpenChange={(open) => { if (!open) navigate(`/projects/${encodeURIComponent(selectedProject.id)}/work`); }} onOpenArtifact={openProjectFile} />;
106
113
  return (
107
114
  <>
108
115
  <main className="h-full min-w-0 flex-1 overflow-y-auto p-3 sm:p-4 md:p-6">
@@ -116,7 +123,7 @@ export function ProjectsPage() {
116
123
  <Tabs
117
124
  value={tab}
118
125
  onValueChange={(value) =>
119
- navigate(
126
+ resourceId && isProjectHomeTab(value) ? setResourceTab(value) : navigate(
120
127
  `/projects/${encodeURIComponent(selectedProject.id)}/${value}`,
121
128
  { state },
122
129
  )
@@ -140,13 +147,13 @@ export function ProjectsPage() {
140
147
  label,
141
148
  )
142
149
  }
143
- onOpenWorkItem={setSelectedWorkItemId}
150
+ onOpenWorkItem={openWorkItem}
144
151
  />
145
152
  </TabsContent>
146
153
  <TabsContent value="work" className="mt-4">
147
154
  <ProjectWorkItems
148
155
  projectId={selectedProject.id}
149
- onOpenWorkItem={setSelectedWorkItemId}
156
+ onOpenWorkItem={openWorkItem}
150
157
  />
151
158
  </TabsContent>
152
159
  <TabsContent value="artifacts" className="mt-4">
@@ -166,10 +173,7 @@ export function ProjectsPage() {
166
173
  isLoading={skills.isLoading}
167
174
  isError={skills.isError}
168
175
  onOpen={(skill) =>
169
- openProjectFile(
170
- joinProjectPath(selectedProject.rootPath, skill.path),
171
- skill.name,
172
- )
176
+ app.pageResourceManager.open(pageResourceFromSystemObject("skill", skill.ref, skill.name), "default", navigate)
173
177
  }
174
178
  />
175
179
  </TabsContent>
@@ -189,20 +193,11 @@ export function ProjectsPage() {
189
193
  </Tabs>
190
194
  </div>
191
195
  </main>
192
- <ProjectWorkItemDrawer
193
- projectId={selectedProject.id}
194
- projectRoot={selectedProject.rootPath}
195
- workItemId={selectedWorkItemId}
196
- onOpenChange={(open) => {
197
- if (!open) setSelectedWorkItemId(null);
198
- }}
199
- onOpenArtifact={openProjectFile}
200
- />
201
- <ChatConversationWorkspaceSection
196
+ {!resourceId && <ChatConversationWorkspaceSection
202
197
  layoutMode={isMobile ? "mobile" : "desktop"}
203
198
  sessionKey={null}
204
199
  projectRoot={selectedProject.rootPath}
205
- />
200
+ />}
206
201
  </>
207
202
  );
208
203
  }
@@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { ProjectsPage } from "./project-home-page";
6
6
 
7
7
  const mocks = vi.hoisted(() => ({
8
+ openResource: vi.fn(),
8
9
  agreementProps: vi.fn(),
9
10
  artifactsProps: vi.fn(),
10
11
  drawerProps: vi.fn(),
@@ -13,6 +14,8 @@ const mocks = vi.hoisted(() => ({
13
14
  useProjectSkills: vi.fn(),
14
15
  useProjects: vi.fn(),
15
16
  }));
17
+ vi.mock("@/app/components/app-presenter-provider", () => ({ useAppPresenter: () => ({ pageResourceManager: { open: mocks.openResource } }) }));
18
+ vi.mock("@/features/right-panel-resources", () => ({ pageResourceFromSystemObject: (type: string, id: string) => ({ type, id }) }));
16
19
 
17
20
  vi.mock("@/shared/hooks/use-projects", () => ({
18
21
  useProjects: mocks.useProjects,
@@ -117,7 +120,7 @@ describe("ProjectsPage", () => {
117
120
  expect(mocks.useProjectSkills).toHaveBeenCalledWith(null);
118
121
  expect(screen.getAllByRole("tab")).toHaveLength(5);
119
122
  fireEvent.click(screen.getByRole("button", { name: "Overview work" }));
120
- expect(screen.getByTestId("work-drawer").textContent).toBe("work-overview");
123
+ expect(mocks.openResource).toHaveBeenCalledWith({ type: "project-work", id: JSON.stringify(["project-1", "work-overview"]) }, "default", expect.any(Function));
121
124
  });
122
125
 
123
126
  it("loads artifacts from project work without material observation", () => {
@@ -1,8 +1,41 @@
1
1
  import type * as ReactQuery from "@tanstack/react-query";
2
- import { cleanup, render, screen } from "@testing-library/react";
2
+ import type { ReactNode } from "react";
3
+ import type * as ReactRouter from "react-router-dom";
4
+ import { cleanup, fireEvent, render, screen } from "@testing-library/react";
3
5
  import { afterEach, describe, expect, it, vi } from "vitest";
4
6
  import { SYSTEM_OBJECT_RESOURCE_RENDERERS } from "@/features/right-panel-resources/components/system-object-resource";
7
+ import { WORKSPACE_FILE_PANEL_RENDERERS } from "@/features/right-panel-resources/components/workspace-file-resource";
8
+ import { createWorkspaceFilePanelTarget } from "@/features/chat";
5
9
  import type { DocBrowserCustomTabRenderParams } from "@/shared/components/doc-browser/doc-browser-renderer.types";
10
+ import type { WorkspaceTextExcerpt } from "@/features/chat";
11
+ import { NativeObjectResource } from "@/features/right-panel-resources/components/native-object-resource";
12
+
13
+ vi.mock("@/features/agents", () => ({ AgentsPage: ({ resourceId }: { resourceId: string }) => <div>agent:{resourceId}</div> }));
14
+ vi.mock("@/features/cron", () => ({ CronJobResource: ({ jobId }: { jobId: string }) => <div>cron-job:{jobId}</div> }));
15
+ vi.mock("@/features/projects", () => ({ ProjectsPage: ({ resourceId, resourceWorkId }: { resourceId: string; resourceWorkId?: string }) => <div>project:{resourceId}{resourceWorkId ? `/${resourceWorkId}` : ""}</div> }));
16
+ vi.mock("@/features/inbox", () => ({ InboxPage: ({ resourceId }: { resourceId: string }) => <div>inbox-delivery:{resourceId}</div> }));
17
+ vi.mock("@/features/apps", () => ({ AppsPanel: ({ serviceResourceId }: { serviceResourceId: string }) => <div>service-app:{serviceResourceId}</div> }));
18
+ vi.mock("@/features/marketplace", () => ({ McpMarketplacePage: ({ resourceId }: { resourceId: string }) => <div>mcp-server:{resourceId}</div> }));
19
+ vi.mock("@/features/panel-apps", () => ({
20
+ PanelAppRuntimeSurface: ({ appId }: { appId: string }) => <div>panel-app:{appId}</div>,
21
+ PanelAppHostProvider: ({ children }: { children: ReactNode }) => children,
22
+ }));
23
+
24
+ const actions = vi.hoisted(() => ({ addExcerptToChat: vi.fn(), navigate: vi.fn() }));
25
+ vi.mock("@/features/chat", async () => ({
26
+ ...await import("@/features/chat/features/workspace/utils/workspace-file-panel-route.utils"),
27
+ ...await import("@/features/chat/features/workspace/utils/chat-workspace-file-tab.utils"),
28
+ ...await import("@/features/chat/features/workspace/utils/workspace-text-excerpt.utils"),
29
+ ...await import("@/features/chat/features/workspace/components/chat-session-workspace-file-preview"),
30
+ }));
31
+ vi.mock("@/app/components/app-presenter-provider", () => ({
32
+ useAppPresenter: () => ({ pageResourceManager: actions }),
33
+ }));
34
+ vi.mock("react-router-dom", async (importOriginal) => ({
35
+ ...await importOriginal<typeof ReactRouter>(),
36
+ useLocation: () => ({ pathname: "/chat/current-session" }),
37
+ useNavigate: () => actions.navigate,
38
+ }));
6
39
 
7
40
  vi.mock("@tanstack/react-query", async (importOriginal) => ({
8
41
  ...await importOriginal<typeof ReactQuery>(),
@@ -14,13 +47,44 @@ vi.mock("@tanstack/react-query", async (importOriginal) => ({
14
47
  }),
15
48
  }));
16
49
  vi.mock("@/features/chat/features/workspace/components/chat-session-workspace-file-preview", () => ({
17
- ChatSessionWorkspaceFilePreview: ({ file }: { file: { key: string; rawText: string } }) => (
18
- <div data-testid="preview" data-resource-key={file.key}>{file.rawText}</div>
50
+ ChatSessionWorkspaceFilePreview: ({ file, onTextExcerptAdd }: {
51
+ file: { key: string; rawText: string };
52
+ onTextExcerptAdd?: (excerpt: WorkspaceTextExcerpt) => void;
53
+ }) => (
54
+ <div data-testid="preview" data-resource-key={file.key}>{file.rawText}
55
+ <button onClick={() => onTextExcerptAdd?.({ path: "agent.md", label: "agent.md", excerpt: "Agent snapshot", startLine: 1, endLine: 1 })}>Add selection</button>
56
+ </div>
19
57
  ),
20
58
  }));
21
59
  afterEach(cleanup);
22
60
 
23
61
  describe("system object reading identity", () => {
62
+ it.each(["agent", "cron-job", "project", "inbox-delivery", "service-app", "mcp-server", "panel-app"])("opens %s with its native renderer and unchanged identity", async (objectType) => {
63
+ render(<NativeObjectResource objectType={objectType} objectId="raw:id" openTarget={vi.fn()} />);
64
+ expect(await screen.findByText(`${objectType}:raw:id`)).toBeTruthy();
65
+ expect(screen.queryByTestId("preview")).toBeNull();
66
+ });
67
+
68
+ it("keeps project and work item identities separate", async () => {
69
+ render(<NativeObjectResource objectType="project-work" objectId={JSON.stringify(["project", "work"])} openTarget={vi.fn()} />);
70
+ expect(await screen.findByText("project:project/work")).toBeTruthy();
71
+ });
72
+
73
+ it("retains a global file's source context when quoting into a different conversation", () => {
74
+ const target = createWorkspaceFilePanelTarget({
75
+ key: "source-file", path: "agent.md", label: "agent.md", parentSessionKey: "source-session", viewMode: "preview",
76
+ }, { workingDir: "/source/workspace", projectRoot: "/source/workspace" });
77
+ render(WORKSPACE_FILE_PANEL_RENDERERS["workspace-file"].renderContent!({
78
+ currentUrl: target.url,
79
+ tab: { ...target, id: target.url, currentUrl: target.url, history: [target.url], historyIndex: 0, navVersion: 0 },
80
+ open: vi.fn(), openTarget: vi.fn(), refreshIframe: vi.fn(),
81
+ }));
82
+ fireEvent.click(screen.getByRole("button", { name: "Add selection" }));
83
+ expect(actions.addExcerptToChat).toHaveBeenLastCalledWith({
84
+ path: target.resourceUri, label: "agent.md", excerpt: "Agent snapshot", startLine: 1, endLine: 1,
85
+ }, "/chat/current-session", actions.navigate);
86
+ });
87
+
24
88
  it("isolates same-named snapshots by resource URI and preserves identity on reopen", () => {
25
89
  const content = (uri: string) => SYSTEM_OBJECT_RESOURCE_RENDERERS["system-object"].renderContent!({
26
90
  currentUrl: uri,
@@ -29,14 +93,18 @@ describe("system object reading identity", () => {
29
93
  openTarget: vi.fn(),
30
94
  refreshIframe: vi.fn(),
31
95
  } satisfies DocBrowserCustomTabRenderParams);
32
- const first = "nextclaw://objects/agent/first";
33
- const second = "nextclaw://objects/agent/second";
96
+ const first = "nextclaw://objects/skill/first";
97
+ const second = "nextclaw://objects/skill/second";
34
98
  const view = render(content(first));
35
99
  expect(screen.getByTestId("preview").getAttribute("data-resource-key")).toBe(first);
36
100
  view.rerender(content(second));
37
101
  expect(screen.getByTestId("preview").getAttribute("data-resource-key")).toBe(second);
38
102
  view.rerender(content(first));
39
103
  expect(screen.getByTestId("preview").getAttribute("data-resource-key")).toBe(first);
40
- expect(screen.getByTestId("preview").textContent).toBe("# Agent snapshot");
104
+ expect(screen.getByTestId("preview").textContent).toContain("# Agent snapshot");
105
+ fireEvent.click(screen.getByRole("button", { name: "Add selection" }));
106
+ expect(actions.addExcerptToChat).toHaveBeenCalledWith({
107
+ path: first, label: "Agent", excerpt: "Agent snapshot", startLine: null, endLine: null,
108
+ }, "/chat/current-session", actions.navigate);
41
109
  });
42
110
  });