@nextclaw/ui 0.15.21 → 0.15.23

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 (476) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/assets/{abnfDiagram-VRR7QNED-M4g_AyR8.js → abnfDiagram-VRR7QNED-DvTjgVMf.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-Bd99vut2.js → aiden0z-pptx-renderer.es-C1nfBAXR.js} +1 -1
  4. package/dist/assets/api-Glw2OGXK.js +13 -0
  5. package/dist/assets/appearance-settings-page-Bl_W_9m7.js +1 -0
  6. package/dist/assets/{arc-IO7WNWOB.js → arc-BvhODBXv.js} +1 -1
  7. package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +1 -0
  8. package/dist/assets/{architectureDiagram-ZJ3FMSHR-Dc-lvdUh.js → architectureDiagram-ZJ3FMSHR-BKO9RgNS.js} +1 -1
  9. package/dist/assets/{blockDiagram-677ZJIJ3-CcsoWpIY.js → blockDiagram-677ZJIJ3-DHpDXy7D.js} +1 -1
  10. package/dist/assets/{c4Diagram-LMCZKHZV-Bsrtg6b2.js → c4Diagram-LMCZKHZV-BG_iQnDr.js} +1 -1
  11. package/dist/assets/channel-5T3pdR-s.js +1 -0
  12. package/dist/assets/channels-list-page-C7E4Sxwd.js +8 -0
  13. package/dist/assets/chat-page-BT6dNI-4.js +1 -0
  14. package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +1 -0
  15. package/dist/assets/{chunk-32BRIVSS-Bt08t8oG.js → chunk-32BRIVSS-DR9M0LLx.js} +1 -1
  16. package/dist/assets/{chunk-52WLFC77-Ddx68Xzx.js → chunk-52WLFC77-698iC3BB.js} +1 -1
  17. package/dist/assets/{chunk-5FCAYU7R-B7p9_q55.js → chunk-5FCAYU7R-DikTj9Ey.js} +1 -1
  18. package/dist/assets/{chunk-5HE753X5-D52KvdTm.js → chunk-5HE753X5-ko0o7_q0.js} +1 -1
  19. package/dist/assets/{chunk-5JV3BV7I-C329h8nI.js → chunk-5JV3BV7I-CEHufhgo.js} +1 -1
  20. package/dist/assets/{chunk-5TONJI2A-BZyUBxWt.js → chunk-5TONJI2A-CGgno1cu.js} +1 -1
  21. package/dist/assets/{chunk-5VM5RSS4-BUiYXZmu.js → chunk-5VM5RSS4-DkiB4cUQ.js} +1 -1
  22. package/dist/assets/{chunk-7BUUIJ7U-B7o-mn4r.js → chunk-7BUUIJ7U-DzptcytQ.js} +1 -1
  23. package/dist/assets/{chunk-BIQX33UG-Bey9GoRP.js → chunk-BIQX33UG-DMRSQJvT.js} +1 -1
  24. package/dist/assets/{chunk-C7G6YPKG-C6tosszM.js → chunk-C7G6YPKG-Bw1BwwuY.js} +1 -1
  25. package/dist/assets/{chunk-CQNSW5MT-BNrdkgGQ.js → chunk-CQNSW5MT-C0z6eHBk.js} +1 -1
  26. package/dist/assets/{chunk-CYSBUYHQ-DHODFeyB.js → chunk-CYSBUYHQ-ByPyAouO.js} +1 -1
  27. package/dist/assets/{chunk-EMLP6XTP-BcmLjrcq.js → chunk-EMLP6XTP-CJlAXWZg.js} +1 -1
  28. package/dist/assets/{chunk-EX3LRPZG-r-_eEtJI.js → chunk-EX3LRPZG-Dqq4zKJu.js} +1 -1
  29. package/dist/assets/{chunk-FWX5IMBZ-DOObDWbf.js → chunk-FWX5IMBZ-B0SNoCmi.js} +2 -2
  30. package/dist/assets/{chunk-HOUHSVGY-Bd0FnbWZ.js → chunk-HOUHSVGY-DG_GJih_.js} +1 -1
  31. package/dist/assets/{chunk-ICXQ74PX-ntNwAm4_.js → chunk-ICXQ74PX-Drxk_6bE.js} +1 -1
  32. package/dist/assets/{chunk-JG7HCLWE-YtRpblZN.js → chunk-JG7HCLWE-DdLFPpnd.js} +1 -1
  33. package/dist/assets/{chunk-JWPE2WC7-De5-D9ta.js → chunk-JWPE2WC7-B8M4G76F.js} +1 -1
  34. package/dist/assets/{chunk-MOJQB5TN-CdvKhyp2.js → chunk-MOJQB5TN-XP6FJHY_.js} +1 -1
  35. package/dist/assets/{chunk-MOZMSUNE-DJMMN_lu.js → chunk-MOZMSUNE-C_6x18Qw.js} +1 -1
  36. package/dist/assets/{chunk-OGEWGWER-DOFWVw3O.js → chunk-OGEWGWER-N25BzCmG.js} +1 -1
  37. package/dist/assets/{chunk-OSBZ3O6U-DZkrIN9r.js → chunk-OSBZ3O6U-ASDEm7y0.js} +1 -1
  38. package/dist/assets/{chunk-PUDLZKDR-D1wma2Yf.js → chunk-PUDLZKDR-CTlvAcn7.js} +1 -1
  39. package/dist/assets/{chunk-Q4XR5HBZ-CjPy94Lz.js → chunk-Q4XR5HBZ-Da9BWfB6.js} +1 -1
  40. package/dist/assets/{chunk-QBLGF6JB-Hy1bEgS-.js → chunk-QBLGF6JB-Bi6RpTJO.js} +1 -1
  41. package/dist/assets/{chunk-R7FJI6CG-CUPIHyh-.js → chunk-R7FJI6CG-DkMsSPvK.js} +1 -1
  42. package/dist/assets/{chunk-RYQCIY6F-D5Ua4pcv.js → chunk-RYQCIY6F-DZp0eU-j.js} +1 -1
  43. package/dist/assets/{chunk-U6XO7XAA-DaUQcqb7.js → chunk-U6XO7XAA-vfinDSrj.js} +1 -1
  44. package/dist/assets/{chunk-V7JOEXUC-DX2zLfQe.js → chunk-V7JOEXUC-C9Nksccs.js} +1 -1
  45. package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +1 -0
  46. package/dist/assets/{chunk-VR4S4FIN-CFA-WQik.js → chunk-VR4S4FIN-Xv6zfwXs.js} +1 -1
  47. package/dist/assets/{chunk-WYO6CB5R-Bk2HeDvJ.js → chunk-WYO6CB5R-mOJNzbWl.js} +2 -2
  48. package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +1 -0
  49. package/dist/assets/{chunk-YOTPTUD7-DUG4FpBN.js → chunk-YOTPTUD7-1-aKSu4o.js} +1 -1
  50. package/dist/assets/{chunk-ZGVPDNZ5-70JdIGo0.js → chunk-ZGVPDNZ5-OJ8veMpK.js} +1 -1
  51. package/dist/assets/{chunk-ZIRB5QZD-XZdgBt5L.js → chunk-ZIRB5QZD-SR_Nq_PP.js} +1 -1
  52. package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +1 -0
  53. package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +1 -0
  54. package/dist/assets/config-split-page-D5BgtKrm.js +1 -0
  55. package/dist/assets/confirm-dialog-Bf907Azu.js +5 -0
  56. package/dist/assets/{cose-bilkent-JH36ORCC-B-PQoGX-.js → cose-bilkent-JH36ORCC-NjVgz2Bw.js} +1 -1
  57. package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +1 -0
  58. package/dist/assets/{cynefinDiagram-TSTJHNR4-BoLCPEM0.js → cynefinDiagram-TSTJHNR4-B_17LDqD.js} +1 -1
  59. package/dist/assets/{dagre-D7Ie4eXr.js → dagre-CMe101gk.js} +1 -1
  60. package/dist/assets/{dagre-VKFMJZFB-CKRrwZA-.js → dagre-VKFMJZFB-qo8nLb3B.js} +1 -1
  61. package/dist/assets/desktop-update-config-BwuyBPJb.js +1 -0
  62. package/dist/assets/{diagram-FQU43EPY-CASL1J3_.js → diagram-FQU43EPY-Ba3XIklC.js} +1 -1
  63. package/dist/assets/{diagram-G47NLZAW-CvLPBIzf.js → diagram-G47NLZAW-CG45TcUx.js} +1 -1
  64. package/dist/assets/{diagram-NH7WQ7WH-Ba6fGdYP.js → diagram-NH7WQ7WH-2F2HrwV-.js} +1 -1
  65. package/dist/assets/{diagram-OA4YK3LP-DkpfgEjM.js → diagram-OA4YK3LP-CXfWH9NZ.js} +1 -1
  66. package/dist/assets/{diagram-WEI45ONY-BP5UMVsN.js → diagram-WEI45ONY-CH_4yepc.js} +1 -1
  67. package/dist/assets/dist-CtLyEJeO.js +1 -0
  68. package/dist/assets/dist-dv_SUR54.js +1 -0
  69. package/dist/assets/doc-browser-C23NDGh5.js +1 -0
  70. package/dist/assets/doc-browser-DlOOhBxI.js +1 -0
  71. package/dist/assets/doc-browser-context-BIBjkwfV.js +1 -0
  72. package/dist/assets/{docx-preview-D0tp3a9T.js → docx-preview-CoM4JK7_.js} +1 -1
  73. package/dist/assets/{ebnfDiagram-CCIWWBDH-TJKbUcmc.js → ebnfDiagram-CCIWWBDH-BwiG4Ea1.js} +1 -1
  74. package/dist/assets/{erDiagram-Q63AITRT-DzGPKkKH.js → erDiagram-Q63AITRT-BML3hpnQ.js} +1 -1
  75. package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +1 -0
  76. package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +1 -0
  77. package/dist/assets/{form-actions-DvvxCpL4.js → form-actions-DAzi68Cn.js} +1 -1
  78. package/dist/assets/{ganttDiagram-NO4QXBWP-JhJzsGp2.js → ganttDiagram-NO4QXBWP-80enfWbD.js} +1 -1
  79. package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +1 -0
  80. package/dist/assets/{gitGraphDiagram-IHSO6WYX-DZ1CKMj8.js → gitGraphDiagram-IHSO6WYX-CVLqXr-b.js} +1 -1
  81. package/dist/assets/host-capabilities-D9C4CBK5.js +1 -0
  82. package/dist/assets/index-BLNg2yg0.css +1 -0
  83. package/dist/assets/index-D3EKjEyK.js +107 -0
  84. package/dist/assets/info-DKCQHKI2-DNlNGH90.js +1 -0
  85. package/dist/assets/{infoDiagram-FWYZ7A6U-BNXNKfRQ.js → infoDiagram-FWYZ7A6U-Dyvs2t0i.js} +1 -1
  86. package/dist/assets/{ishikawaDiagram-FXEZZL3T-DoiEfjNw.js → ishikawaDiagram-FXEZZL3T-sSnxDKfh.js} +1 -1
  87. package/dist/assets/{journeyDiagram-5HDEW3XC-D6oK2HSy.js → journeyDiagram-5HDEW3XC-D22V71Mf.js} +1 -1
  88. package/dist/assets/{kanban-definition-HUTT4EX6-B2UnLOH-.js → kanban-definition-HUTT4EX6-D3ds0p-g.js} +1 -1
  89. package/dist/assets/{line-BM7PoxY5.js → line-CbyFs065.js} +1 -1
  90. package/dist/assets/{linear-B3DiqMjk.js → linear-4DKtnZBS.js} +1 -1
  91. package/dist/assets/loader-circle-BSg5u0r4.js +1 -0
  92. package/dist/assets/{map-BAAdHTqR.js → map-CcZzEoz6.js} +1 -1
  93. package/dist/assets/mcp-marketplace-page-ByhvQQj5.js +9 -0
  94. package/dist/assets/mcp-marketplace-page-CytXwnUs.js +1 -0
  95. package/dist/assets/{mermaid-parser.core-BeMviefY.js → mermaid-parser.core-DPmMOjXD.js} +2 -2
  96. package/dist/assets/{mermaid.core-D0Q77r9I.js → mermaid.core-BSf-ddRa.js} +3 -3
  97. package/dist/assets/{mindmap-definition-LN4V7U3C-BQ7r7bR8.js → mindmap-definition-LN4V7U3C-BUTwWPyx.js} +1 -1
  98. package/dist/assets/model-config-page-bgEx3MjQ.js +1 -0
  99. package/dist/assets/navigation-link-CB0OQbnY.js +3 -0
  100. package/dist/assets/{ordinal-Bt2N4IkA.js → ordinal-BgLYtOZE.js} +1 -1
  101. package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +1 -0
  102. package/dist/assets/{pegDiagram-2B236MQR-B-C9-LGz.js → pegDiagram-2B236MQR-BEu_ZBjc.js} +1 -1
  103. package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +1 -0
  104. package/dist/assets/{pieDiagram-ENE6RG2P-CtirZLtn.js → pieDiagram-ENE6RG2P-CAwAwuBd.js} +1 -1
  105. package/dist/assets/plus-CNjWdLhZ.js +1 -0
  106. package/dist/assets/provider-scoped-model-input-8F6JMd2n.js +1 -0
  107. package/dist/assets/providers-config-page-CxpTjR81.js +1 -0
  108. package/dist/assets/{quadrantDiagram-ABIIQ3AL-DiBWAzDU.js → quadrantDiagram-ABIIQ3AL-CwE6F-_2.js} +1 -1
  109. package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +1 -0
  110. package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +1 -0
  111. package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +1 -0
  112. package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +1 -0
  113. package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +1 -0
  114. package/dist/assets/{railroadDiagram-RFXS5EU6-CP6b3PBI.js → railroadDiagram-RFXS5EU6-xgLekU3B.js} +1 -1
  115. package/dist/assets/react-Bk2ydNTe.js +8 -0
  116. package/dist/assets/{refresh-cw-C2e94pmp.js → refresh-cw-Ba0LZou4.js} +1 -1
  117. package/dist/assets/remote-Dv38PuMV.js +1 -0
  118. package/dist/assets/{requirementDiagram-TGXJPOKE-D8YV0-Jz.js → requirementDiagram-TGXJPOKE-CyVUzEX5.js} +1 -1
  119. package/dist/assets/rotate-cw-IkYVk9JX.js +1 -0
  120. package/dist/assets/runtime-config-page-C0ByyUVr.js +1 -0
  121. package/dist/assets/{sankeyDiagram-HTMAVEWB-C2vA4ojE.js → sankeyDiagram-HTMAVEWB-JK6bFmYB.js} +1 -1
  122. package/dist/assets/{save-CkwDOgvt.js → save-DTOAvqzt.js} +1 -1
  123. package/dist/assets/{search-CLXM2reO.js → search-D4X5DNMe.js} +1 -1
  124. package/dist/assets/search-config-page-Cr6254K5.js +1 -0
  125. package/dist/assets/{secrets-config-page-DQ_Curaj.js → secrets-config-page-W2Hx332d.js} +2 -2
  126. package/dist/assets/security-config-1E8OF4kR.js +1 -0
  127. package/dist/assets/select-CDv0g2Pj.js +41 -0
  128. package/dist/assets/{sequenceDiagram-DBY2YBRQ-B9LBmpUo.js → sequenceDiagram-DBY2YBRQ-BR5IokXV.js} +1 -1
  129. package/dist/assets/{settings-2-B9IT2HGd.js → settings-2-CoxzNABp.js} +1 -1
  130. package/dist/assets/{sizeCapture-X5ZJPWSS-9UIfya9-.js → sizeCapture-X5ZJPWSS-SxG_YnMA.js} +1 -1
  131. package/dist/assets/skeleton-DW018fJv.js +1 -0
  132. package/dist/assets/{src-DKf77Yzo.js → src-vgz8E_-O.js} +1 -1
  133. package/dist/assets/{stateDiagram-2N3HPSRC-oTW44vds.js → stateDiagram-2N3HPSRC-DD4OoYhn.js} +1 -1
  134. package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +1 -0
  135. package/dist/assets/{swimlanes-5IMT3BWC-Cf7lcsay.js → swimlanes-5IMT3BWC-BWkFeyCT.js} +2 -2
  136. package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +8 -0
  137. package/dist/assets/{tag-chip-CDkB5smU.js → tag-chip-CjkZEoS2.js} +1 -1
  138. package/dist/assets/{timeline-definition-FHXFAJF6-DoCuWKDJ.js → timeline-definition-FHXFAJF6-VTRPy6KA.js} +1 -1
  139. package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +1 -0
  140. package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +1 -0
  141. package/dist/assets/use-confirm-dialog-CavtY1vJ.js +1 -0
  142. package/dist/assets/{vennDiagram-L72KCM5P-CpU0pzGe.js → vennDiagram-L72KCM5P-Bvk42Pek.js} +1 -1
  143. package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +1 -0
  144. package/dist/assets/{wardleyDiagram-EHGQE667-CkN6nn6-.js → wardleyDiagram-EHGQE667-DOFjx2s3.js} +1 -1
  145. package/dist/assets/x-PTXYTEwz.js +1 -0
  146. package/dist/assets/{xychartDiagram-FW5EYKEG-DATpapm2.js → xychartDiagram-FW5EYKEG-DY5yRTUc.js} +1 -1
  147. package/dist/index.html +30 -32
  148. package/index.html +8 -0
  149. package/package.json +8 -8
  150. package/src/app/components/layout/page-layout.tsx +15 -6
  151. package/src/app/components/layout/sidebar-rail.styles.ts +0 -2
  152. package/src/app/components/layout/sidebar.tsx +2 -2
  153. package/src/app/styles/charcoal-theme.css +85 -0
  154. package/src/app/styles/design-system.css +23 -13
  155. package/src/features/agents/components/__tests__/agents-page.test.tsx +36 -24
  156. package/src/features/agents/components/agent-advanced-config-fields.tsx +7 -7
  157. package/src/features/agents/components/agent-details-dialog.tsx +8 -8
  158. package/src/features/agents/components/agent-dialogs.tsx +7 -7
  159. package/src/features/agents/components/agents-page.tsx +42 -62
  160. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +2 -2
  161. package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +46 -4
  162. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +17 -1
  163. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +8 -22
  164. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +69 -3
  165. package/src/features/chat/components/conversation/chat-conversation-content.tsx +24 -11
  166. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +30 -31
  167. package/src/features/chat/components/conversation/chat-conversation-header.tsx +1 -1
  168. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -8
  169. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +16 -4
  170. package/src/features/chat/components/layout/__tests__/chat-page-shell.test.tsx +23 -0
  171. package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +1 -1
  172. package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +52 -0
  173. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +6 -0
  174. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +11 -17
  175. package/src/features/chat/components/layout/chat-page-shell.tsx +7 -15
  176. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +32 -42
  177. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +16 -67
  178. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +1 -4
  179. package/src/features/chat/components/providers/chat-presenter.provider.tsx +2 -0
  180. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +84 -12
  181. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +258 -9
  182. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +51 -34
  183. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +50 -39
  184. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +128 -1
  185. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +67 -1
  186. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-slash-commands.test.tsx +4 -0
  187. package/src/features/chat/features/conversation/hooks/__tests__/use-session-provider-model-catalog.test.tsx +109 -0
  188. package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +46 -0
  189. package/src/features/chat/features/conversation/hooks/use-session-conversation-composer-nodes.ts +26 -0
  190. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +45 -12
  191. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +1 -0
  192. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +28 -3
  193. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +91 -37
  194. package/src/features/chat/features/conversation/hooks/use-session-conversation-recovery-actions.ts +64 -0
  195. package/src/features/chat/features/conversation/hooks/use-session-conversation-slash-commands.ts +2 -0
  196. package/src/features/chat/features/conversation/hooks/use-session-provider-model-catalog.ts +84 -0
  197. package/src/features/chat/features/conversation/utils/__tests__/session-message-composer.utils.test.ts +34 -0
  198. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +18 -0
  199. package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +117 -0
  200. package/src/features/chat/features/conversation/utils/session-queued-input.utils.ts +10 -97
  201. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +2 -1
  202. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +3 -1
  203. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
  204. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +23 -0
  205. package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +105 -0
  206. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +27 -2
  207. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +5 -0
  208. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +97 -32
  209. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +1 -1
  210. package/src/features/chat/features/input/utils/chat-input-toolbar.utils.ts +64 -10
  211. package/src/features/chat/features/message/components/__tests__/chat-message-assistant-header.container.test.tsx +149 -0
  212. package/src/features/chat/features/message/components/__tests__/chat-message-inline-editor.test.tsx +59 -0
  213. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +123 -90
  214. package/src/features/chat/features/message/components/__tests__/chat-message-timeline-dividers.test.tsx +43 -0
  215. package/src/features/chat/features/message/components/chat-message-inline-editor.tsx +111 -0
  216. package/src/features/chat/features/message/components/chat-message-list.container.tsx +81 -172
  217. package/src/features/chat/features/message/components/chat-message-timeline-dividers.tsx +75 -0
  218. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +125 -0
  219. package/src/features/chat/features/message/hooks/use-chat-message-actions.tsx +187 -0
  220. package/src/features/chat/features/message/utils/__tests__/chat-message-action-targets.utils.test.ts +89 -0
  221. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-compaction.utils.test.ts +194 -0
  222. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-continuation-compaction.utils.test.ts +167 -0
  223. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +203 -0
  224. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +26 -0
  225. package/src/features/chat/features/message/utils/chat-message-action-targets.utils.ts +28 -0
  226. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +38 -0
  227. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
  228. package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +204 -7
  229. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-agent-runtime.test.tsx +180 -1
  230. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +184 -10
  231. package/src/features/chat/features/ncp/hooks/use-hydrated-ncp-agent.integration.test.tsx +57 -0
  232. package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +90 -1
  233. package/src/features/chat/features/ncp/utils/__tests__/ncp-chat-query-derived.utils.test.ts +110 -0
  234. package/src/features/chat/features/ncp/utils/ncp-chat-query-derived.utils.ts +65 -3
  235. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +10 -10
  236. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +2 -2
  237. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +17 -0
  238. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +63 -54
  239. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
  240. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +1 -1
  241. package/src/features/chat/features/session/components/session-header/chat-session-switcher-groups.tsx +1 -1
  242. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +1 -1
  243. package/src/features/chat/features/session/hooks/__tests__/use-selected-session-context-window-indicator.test.tsx +87 -0
  244. package/src/features/chat/features/session/utils/__tests__/chat-session-display.utils.test.ts +26 -0
  245. package/src/features/chat/features/session/utils/__tests__/ncp-session-adapter.utils.test.ts +23 -2
  246. package/src/features/chat/features/session/utils/chat-context-window-indicator.utils.ts +44 -5
  247. package/src/features/chat/features/session/utils/chat-session-display.utils.ts +48 -12
  248. package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +23 -4
  249. package/src/features/chat/features/session/utils/ncp-session-context-metadata.utils.ts +42 -4
  250. package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +6 -0
  251. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +27 -9
  252. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +1 -1
  253. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +11 -17
  254. package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +37 -0
  255. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
  256. package/src/features/chat/features/welcome/components/chat-welcome.tsx +35 -33
  257. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +22 -6
  258. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +13 -0
  259. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +73 -3
  260. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +22 -2
  261. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +75 -0
  262. package/src/features/chat/features/workspace/components/__tests__/workspace-text-selection-menu.test.tsx +102 -0
  263. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +145 -26
  264. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +42 -18
  265. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +50 -10
  266. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +48 -22
  267. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +13 -2
  268. package/src/features/chat/features/workspace/components/workspace-text-selection-menu.tsx +223 -0
  269. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +80 -0
  270. package/src/features/chat/features/workspace/utils/__tests__/workspace-text-excerpt.utils.test.ts +54 -0
  271. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +47 -0
  272. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +16 -0
  273. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +22 -1
  274. package/src/features/chat/features/workspace/utils/workspace-text-excerpt.utils.ts +53 -0
  275. package/src/features/chat/index.ts +1 -0
  276. package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +106 -0
  277. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +53 -5
  278. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +93 -1
  279. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +3 -10
  280. package/src/features/chat/managers/__tests__/provider-model-catalog-notice.manager.test.ts +57 -0
  281. package/src/features/chat/managers/chat-composer-intent.manager.ts +145 -0
  282. package/src/features/chat/managers/chat-session-list.manager.ts +14 -25
  283. package/src/features/chat/managers/chat-thread.manager.ts +32 -16
  284. package/src/features/chat/managers/provider-model-catalog-notice.manager.ts +121 -0
  285. package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +3 -9
  286. package/src/features/chat/pages/ncp-chat-page.tsx +0 -1
  287. package/src/features/chat/presenters/chat.presenter.ts +3 -0
  288. package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +55 -0
  289. package/src/features/chat/stores/chat-composer-draft.store.ts +92 -0
  290. package/src/features/chat/stores/chat-thread.store.ts +2 -4
  291. package/src/features/chat/types/chat-input-bar.types.ts +6 -0
  292. package/src/features/chat/types/chat-input.types.ts +5 -0
  293. package/src/features/chat/types/chat-message.types.ts +5 -0
  294. package/src/features/cron/components/__tests__/cron-config.test.tsx +100 -19
  295. package/src/features/cron/components/cron-config.tsx +19 -33
  296. package/src/features/cron/components/cron-job-detail-dialog.tsx +42 -16
  297. package/src/features/cron/components/cron-job-row.tsx +18 -1
  298. package/src/features/cron/components/cron-task-discovery.tsx +1 -1
  299. package/src/features/inbox/components/inbox-delivery-content.test.tsx +8 -2
  300. package/src/features/inbox/components/inbox-delivery-content.tsx +1 -1
  301. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +10 -4
  302. package/src/features/inbox/components/inbox-reader-dialog.tsx +37 -61
  303. package/src/features/inbox/pages/inbox-page.tsx +90 -98
  304. package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
  305. package/src/features/notifications/components/__tests__/app-notification-toast.test.tsx +31 -6
  306. package/src/features/notifications/components/app-notification-toast.tsx +54 -15
  307. package/src/features/notifications/managers/__tests__/app-notification.manager.test.ts +2 -0
  308. package/src/features/notifications/managers/app-notification.manager.ts +3 -0
  309. package/src/features/panel-apps/components/panel-app-list-item.tsx +1 -1
  310. package/src/features/panel-apps/components/panel-app-toolbar.tsx +2 -2
  311. package/src/features/panel-apps/components/panel-apps-list.tsx +4 -4
  312. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +1 -0
  313. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +9 -0
  314. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +1 -0
  315. package/src/features/service-apps/components/__tests__/service-apps-panel.test.tsx +5 -4
  316. package/src/features/service-apps/components/service-app-list-item.tsx +470 -0
  317. package/src/features/service-apps/components/service-apps-panel.tsx +76 -490
  318. package/src/features/settings/components/config/__tests__/provider-models-section.test.tsx +239 -0
  319. package/src/features/settings/components/config/provider-auth-section.tsx +90 -59
  320. package/src/features/settings/components/config/provider-form-detail-pane.tsx +307 -0
  321. package/src/features/settings/components/config/provider-form.tsx +149 -367
  322. package/src/features/settings/components/config/provider-model-list.tsx +293 -0
  323. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +151 -0
  324. package/src/features/settings/components/config/provider-models-section.tsx +178 -149
  325. package/src/features/settings/components/config/provider-status-badge.tsx +4 -2
  326. package/src/features/settings/hooks/__tests__/use-provider-connectivity.test.tsx +98 -0
  327. package/src/features/settings/hooks/__tests__/use-provider-model-suggestions.test.tsx +107 -0
  328. package/src/features/settings/hooks/use-provider-connectivity.ts +132 -0
  329. package/src/features/settings/hooks/use-provider-model-suggestions.ts +51 -0
  330. package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +2 -2
  331. package/src/features/settings/pages/__tests__/providers-config-page.test.tsx +12 -0
  332. package/src/features/settings/pages/__tests__/search-config-page.test.tsx +48 -0
  333. package/src/features/settings/pages/providers-config-page.tsx +2 -1
  334. package/src/features/settings/pages/search-config-page.tsx +17 -8
  335. package/src/features/settings/utils/__tests__/provider-form-support.utils.test.ts +42 -0
  336. package/src/features/settings/utils/provider-form-context.utils.ts +2 -0
  337. package/src/features/settings/utils/provider-form-model.utils.ts +25 -0
  338. package/src/features/settings/utils/provider-form-support.utils.ts +21 -5
  339. package/src/index.css +1 -1
  340. package/src/platforms/desktop/types/desktop-update.types.ts +5 -0
  341. package/src/platforms/mobile/components/__tests__/mobile-app-shell.test.tsx +13 -7
  342. package/src/platforms/mobile/components/__tests__/mobile-bottom-nav.test.tsx +18 -20
  343. package/src/shared/components/actions/__tests__/navigation-link.test.tsx +14 -3
  344. package/src/shared/components/actions/navigation-link.tsx +35 -15
  345. package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -2
  346. package/src/shared/components/common/agent-avatar.tsx +3 -3
  347. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +66 -0
  348. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +5 -2
  349. package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +1 -0
  350. package/src/shared/components/doc-browser/doc-browser.tsx +9 -0
  351. package/src/shared/components/doc-browser/hooks/use-doc-browser-scroll-restoration.ts +126 -0
  352. package/src/shared/components/path-picker/server-path-picker-directory-list.tsx +1 -1
  353. package/src/shared/components/path-picker/server-path-picker-locations.tsx +1 -1
  354. package/src/shared/components/path-picker/server-path-picker-navigation-bar.tsx +3 -3
  355. package/src/shared/components/settings/settings-page.tsx +1 -1
  356. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +1 -1
  357. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  358. package/src/shared/components/ui/button.tsx +4 -4
  359. package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +103 -0
  360. package/src/shared/components/ui/context-menu/context-menu.tsx +263 -0
  361. package/src/shared/components/ui/dialog.tsx +1 -1
  362. package/src/shared/components/ui/input.tsx +1 -1
  363. package/src/shared/components/ui/scroll-area.tsx +2 -0
  364. package/src/shared/components/ui/select.tsx +1 -1
  365. package/src/shared/components/ui/switch.tsx +1 -1
  366. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +19 -6
  367. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +28 -67
  368. package/src/shared/components/ui/tabs.tsx +1 -1
  369. package/src/shared/components/ui/textarea.tsx +1 -1
  370. package/src/shared/hooks/use-config.ts +33 -1
  371. package/src/shared/lib/api/__tests__/ncp-session-query-cache.utils.test.ts +26 -0
  372. package/src/shared/lib/api/ncp-session-query-cache.utils.ts +7 -10
  373. package/src/shared/lib/api/ncp-session.types.ts +7 -0
  374. package/src/shared/lib/api/types.ts +38 -1
  375. package/src/shared/lib/api/utils/config.utils.ts +14 -0
  376. package/src/shared/lib/cron/cron-job-view.utils.ts +4 -0
  377. package/src/shared/lib/host-capabilities/__tests__/host-capability.manager.test.ts +26 -0
  378. package/src/shared/lib/host-capabilities/host-capability.manager.ts +28 -0
  379. package/src/shared/lib/i18n/locales/en-US/chat.json +45 -17
  380. package/src/shared/lib/i18n/locales/en-US/core.json +26 -0
  381. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +1 -0
  382. package/src/shared/lib/i18n/locales/en-US/search.json +1 -0
  383. package/src/shared/lib/i18n/locales/zh-CN/chat.json +45 -17
  384. package/src/shared/lib/i18n/locales/zh-CN/core.json +26 -0
  385. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +1 -0
  386. package/src/shared/lib/i18n/locales/zh-CN/search.json +1 -0
  387. package/src/shared/lib/provider-models/__tests__/anonymous-provider-configuration.test.ts +40 -0
  388. package/src/shared/lib/provider-models/index.ts +4 -3
  389. package/src/shared/lib/session-project/__tests__/workspace-file-breadcrumb.test.ts +28 -1
  390. package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +23 -0
  391. package/src/shared/lib/theme/index.test.ts +11 -0
  392. package/src/shared/lib/theme/index.ts +2 -0
  393. package/dist/assets/api-CHo2gekJ.js +0 -13
  394. package/dist/assets/app-presenter-provider-2_DmWYT9.js +0 -108
  395. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +0 -1
  396. package/dist/assets/appearance-settings-page-BEy2UE7R.js +0 -1
  397. package/dist/assets/architecture-TIHT7OUA-Cii4JyA2.js +0 -1
  398. package/dist/assets/book-open-BrZL4o9L.js +0 -1
  399. package/dist/assets/card-B5rRLu_6.js +0 -1
  400. package/dist/assets/channel-BSKkTPe8.js +0 -1
  401. package/dist/assets/channels-list-page-C1dnm68I.js +0 -8
  402. package/dist/assets/chat-page-Dz6tvZ91.js +0 -1
  403. package/dist/assets/chunk-2Q5K7J3B-CDMOR1xZ.js +0 -1
  404. package/dist/assets/chunk-VAUOI2AC-BRvqNW76.js +0 -1
  405. package/dist/assets/chunk-XXDRQBXY-CwX_mqJ3.js +0 -1
  406. package/dist/assets/classDiagram-OUVF2IWQ-RzbGxG77.js +0 -1
  407. package/dist/assets/classDiagram-v2-EOCWNBFH-C_gWB7WT.js +0 -1
  408. package/dist/assets/config-split-page-6y6W6dz4.js +0 -1
  409. package/dist/assets/confirm-dialog-q1CpEmR8.js +0 -5
  410. package/dist/assets/cynefin-VYW2F7L2-fSLIS0X3.js +0 -1
  411. package/dist/assets/desktop-update-config-DrdlwP4j.js +0 -1
  412. package/dist/assets/dist-C9EX46wM.js +0 -41
  413. package/dist/assets/doc-browser-BfttDSti.js +0 -1
  414. package/dist/assets/doc-browser-DH-3hDnI.js +0 -1
  415. package/dist/assets/doc-browser-context-TU2heon0.js +0 -1
  416. package/dist/assets/eventmodeling-45OFAUF4-XVcQGgha.js +0 -1
  417. package/dist/assets/eye-B-3dyZNA.js +0 -1
  418. package/dist/assets/flowDiagram-23GEKE2U-BiFSctqz.js +0 -1
  419. package/dist/assets/gitGraph-TEB2WS4Q-C014uXqS.js +0 -1
  420. package/dist/assets/host-capabilities-B-TtABsP.js +0 -1
  421. package/dist/assets/index-CXDPLDFD.css +0 -1
  422. package/dist/assets/index-k_eWScvN.js +0 -2
  423. package/dist/assets/info-DKCQHKI2-CQ2qjGhU.js +0 -1
  424. package/dist/assets/loader-circle-B35NlHTI.js +0 -1
  425. package/dist/assets/logo-badge-DB51c0cS.js +0 -1
  426. package/dist/assets/mcp-marketplace-page-CkPtwPBk.js +0 -1
  427. package/dist/assets/mcp-marketplace-page-DWtsIqml.js +0 -9
  428. package/dist/assets/model-config-page-D6cGNnMM.js +0 -1
  429. package/dist/assets/navigation-link-BSJEUiwD.js +0 -1
  430. package/dist/assets/packet-7NZHBO7P-6IFyydij.js +0 -1
  431. package/dist/assets/pie-RZYD4A2V-spXQC_wr.js +0 -1
  432. package/dist/assets/plus-BRVe5jSJ.js +0 -1
  433. package/dist/assets/popover-Bp9IpE_N.js +0 -1
  434. package/dist/assets/provider-models-CXUgDxGR.js +0 -1
  435. package/dist/assets/provider-scoped-model-input-dk7fz9NL.js +0 -1
  436. package/dist/assets/providers-config-page-DTP2YfxA.js +0 -1
  437. package/dist/assets/radar-I7S5WNFK-DWVA8lvY.js +0 -1
  438. package/dist/assets/railroad-3IZDKUUU-Ce51u8y1.js +0 -1
  439. package/dist/assets/railroad-abnf-AHOZXSZD-D7i7cqI_.js +0 -1
  440. package/dist/assets/railroad-ebnf-EBAXGLYW-BEg2hcPs.js +0 -1
  441. package/dist/assets/railroad-peg-LSFZ7HO6-CxROSzbi.js +0 -1
  442. package/dist/assets/react-D6ShNq95.js +0 -8
  443. package/dist/assets/remote-FllhXW3o.js +0 -1
  444. package/dist/assets/rotate-cw-CTC-Qszi.js +0 -1
  445. package/dist/assets/runtime-config-page-C57OLdPm.js +0 -1
  446. package/dist/assets/search-config-page-tnJXaaSr.js +0 -1
  447. package/dist/assets/security-config-S00DjFfO.js +0 -1
  448. package/dist/assets/select-CNFBf00l.js +0 -1
  449. package/dist/assets/skeleton-Dc06gatK.js +0 -1
  450. package/dist/assets/stateDiagram-v2-6OUMAXLB-Bui4RXQK.js +0 -1
  451. package/dist/assets/swimlanesDiagram-G3AALYLV-DTwUsCBz.js +0 -8
  452. package/dist/assets/tabs-BuNr8LSO.js +0 -1
  453. package/dist/assets/trash-2-GchaJuEM.js +0 -1
  454. package/dist/assets/treeView-QDETBFTQ-D5zsTiuL.js +0 -1
  455. package/dist/assets/treemap-6X3UGDF4-CR3dxqNs.js +0 -1
  456. package/dist/assets/use-config-C69rR15i.js +0 -1
  457. package/dist/assets/use-confirm-dialog-DF_EgPYx.js +0 -1
  458. package/dist/assets/use-viewport-layout-BACNZyMY.js +0 -1
  459. package/dist/assets/wardley-OPB4EBWU-LatRT_Lx.js +0 -1
  460. package/dist/assets/x-BXFquY9e.js +0 -1
  461. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +0 -59
  462. /package/dist/assets/{array-CAkJT3no.js → array-NADKd9aU.js} +0 -0
  463. /package/dist/assets/{chunk-KEIR6QF5-BgdDoWEH.js → chunk-KEIR6QF5-BuyuzJJL.js} +0 -0
  464. /package/dist/assets/{chunk-Y2CYZVJY-pTllD0P3.js → chunk-Y2CYZVJY-D_B2ZRNt.js} +0 -0
  465. /package/dist/assets/{config-hints-S3g-UVZb.js → config-hints-BcfVUMij.js} +0 -0
  466. /package/dist/assets/{cytoscape.esm-DmURt-5G.js → cytoscape.esm-BANTlgza.js} +0 -0
  467. /package/dist/assets/{defaultLocale-BKy_KP3O.js → defaultLocale-C4_L0aEs.js} +0 -0
  468. /package/dist/assets/{dist-IgNNB7K9.js → dist-DAPEIJbz.js} +0 -0
  469. /package/dist/assets/{graphlib-xw_TBHyH.js → graphlib-ChqXg0dI.js} +0 -0
  470. /package/dist/assets/{init-C9xlLIAu.js → init-D8wZg9xq.js} +0 -0
  471. /package/dist/assets/{jszip.min-Das2IAnb.js → jszip.min-CkbBfwAQ.js} +0 -0
  472. /package/dist/assets/{katex-DSy1eD2d.js → katex-TZJFa0J_.js} +0 -0
  473. /package/dist/assets/{middleware-Df-a4x-q.js → middleware-B3k-TSmZ.js} +0 -0
  474. /package/dist/assets/{path-DB0USYHi.js → path-DodfxcX7.js} +0 -0
  475. /package/dist/assets/{rough.esm-B1B52ZQS.js → rough.esm-CUaa1Rbe.js} +0 -0
  476. /package/dist/assets/{xlsx-DfjC_iml.js → xlsx-CxByi7bR.js} +0 -0
@@ -0,0 +1,26 @@
1
+ import { useCallback } from 'react';
2
+
3
+ import type {
4
+ SessionConversationInputActions,
5
+ SessionConversationInputSnapshot,
6
+ } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-state';
7
+ import {
8
+ deriveChatComposerDraft,
9
+ deriveSelectedSkillsFromComposer,
10
+ pruneComposerAttachments,
11
+ } from '@/features/chat/features/input/utils/chat-composer-state.utils';
12
+
13
+ export function useSessionConversationComposerNodes(
14
+ inputActions: SessionConversationInputActions,
15
+ ) {
16
+ return useCallback((nodes: SessionConversationInputSnapshot['nodes']) => {
17
+ const nextNodes = [...nodes];
18
+ inputActions.update((current) => ({
19
+ nodes: nextNodes,
20
+ attachments: pruneComposerAttachments(nextNodes, current.attachments),
21
+ text: deriveChatComposerDraft(nextNodes),
22
+ selectedSkills: deriveSelectedSkillsFromComposer(nextNodes),
23
+ sendError: null,
24
+ }));
25
+ }, [inputActions]);
26
+ }
@@ -1,17 +1,22 @@
1
1
  import { useCallback, useMemo } from 'react';
2
2
  import { buildNcpRequestEnvelope } from '@nextclaw/ncp-react';
3
3
  import type { UiNcpSessionQueuedInputView } from '@nextclaw/client-sdk';
4
- import type { NcpAgentSendEnvelope, NcpMessage, NcpRunHandle } from '@nextclaw/ncp';
4
+ import type { NcpAgentSendEnvelope, NcpRunHandle } from '@nextclaw/ncp';
5
5
 
6
6
  import { deriveNcpMessagePartsFromComposer } from '@/features/chat/features/input/utils/chat-composer-state.utils';
7
7
  import { isNcpChatSendDisabled } from '@/features/chat/features/input/utils/ncp-chat-input-availability.utils';
8
8
  import { buildChatRunMetadata } from '@/features/chat/features/session/utils/chat-run-metadata.utils';
9
+ import { createNcpSessionId } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
9
10
  import {
10
11
  buildSessionQueuedInputComposerSnapshot,
11
12
  buildSessionQueuedInputPreview,
12
13
  } from '@/features/chat/features/conversation/utils/session-queued-input.utils';
13
14
  import type { SessionConversationInputSnapshot } from './use-session-conversation-input-state';
14
15
  import type { useSessionConversationInputQuery } from './use-session-conversation-input-query';
16
+ import {
17
+ useSessionConversationRecoveryActions,
18
+ type SessionConversationRecoveryAgent,
19
+ } from './use-session-conversation-recovery-actions';
15
20
 
16
21
  type SessionConversationInputQuery = ReturnType<typeof useSessionConversationInputQuery>;
17
22
  type ComposerDraftSnapshot = Pick<
@@ -19,11 +24,8 @@ type ComposerDraftSnapshot = Pick<
19
24
  'text' | 'nodes' | 'selectedSkills' | 'skillRecords' | 'attachments'
20
25
  >;
21
26
 
22
- type SessionConversationAgent = {
27
+ type SessionConversationAgent = SessionConversationRecoveryAgent & {
23
28
  readonly isHydrating: boolean;
24
- readonly isSending: boolean;
25
- readonly isRunning: boolean;
26
- readonly visibleMessages: readonly NcpMessage[];
27
29
  readonly snapshot: {
28
30
  readonly activeRun?: {
29
31
  readonly sessionId?: string | null;
@@ -133,7 +135,9 @@ function buildSubmissionDraft(params: BuildSubmissionDraftParams): SubmissionDra
133
135
  return {
134
136
  composerSnapshot,
135
137
  metadata: buildChatRunMetadata({
136
- agentId: materializationContext ? undefined : selectedAgentId,
138
+ agentId: materializationContext
139
+ ? undefined
140
+ : inputQuery.selectedSession?.agentId?.trim() || selectedAgentId,
137
141
  model: materializationContext
138
142
  ? resolveModelForSend(inputSnapshot.selectedModel)
139
143
  : resolveModelForSend(
@@ -205,13 +209,34 @@ export function useSessionConversationController(params: UseSessionConversationC
205
209
  );
206
210
  const hasSendableDraft = hasSendableMessagePart(parts);
207
211
  const isSending = agent.isSending || agent.isRunning;
208
- const sendDisabled = isNcpChatSendDisabled({
209
- snapshot: buildInputAvailabilitySnapshot(inputQuery),
210
- hasSendableDraft,
211
- isRuntimeBlocked,
212
- }) || agent.isSending;
212
+ const activityState = inputQuery.selectedSession?.activityPreview?.state;
213
+ const canContinue = Boolean(
214
+ sessionKey &&
215
+ !isSending &&
216
+ !isRuntimeBlocked &&
217
+ (activityState === 'cancelled' || activityState === 'failed'),
218
+ );
219
+ const primaryAction: 'continue' | 'send' =
220
+ canContinue && !hasSendableDraft ? 'continue' : 'send';
221
+ const sendDisabled = primaryAction === 'continue'
222
+ ? false
223
+ : isNcpChatSendDisabled({
224
+ snapshot: buildInputAvailabilitySnapshot(inputQuery),
225
+ hasSendableDraft,
226
+ isRuntimeBlocked,
227
+ }) || agent.isSending;
228
+
229
+ const { continueRun, editMessage } = useSessionConversationRecoveryActions({
230
+ agent,
231
+ sessionKey,
232
+ setSendError,
233
+ });
213
234
 
214
235
  const send = useCallback(async () => {
236
+ if (primaryAction === 'continue') {
237
+ await continueRun();
238
+ return;
239
+ }
215
240
  const draft = buildSubmissionDraft({
216
241
  agentIsSending: agent.isSending,
217
242
  inputSnapshot,
@@ -224,7 +249,9 @@ export function useSessionConversationController(params: UseSessionConversationC
224
249
  if (!draft) {
225
250
  return;
226
251
  }
227
- const envelope = buildSubmissionEnvelope(draft, sessionKey);
252
+ const submissionSessionKey =
253
+ sessionKey ?? (materializationContext ? null : createNcpSessionId());
254
+ const envelope = buildSubmissionEnvelope(draft, submissionSessionKey);
228
255
  if (!envelope) {
229
256
  return;
230
257
  }
@@ -246,6 +273,7 @@ export function useSessionConversationController(params: UseSessionConversationC
246
273
  }
247
274
  }, [
248
275
  agent,
276
+ continueRun,
249
277
  inputQuery,
250
278
  inputSnapshot,
251
279
  isRuntimeBlocked,
@@ -256,6 +284,7 @@ export function useSessionConversationController(params: UseSessionConversationC
256
284
  selectedAgentId,
257
285
  sessionKey,
258
286
  setSendError,
287
+ primaryAction,
259
288
  ]);
260
289
 
261
290
  const editQueuedInput = useCallback((id: string) => {
@@ -290,8 +319,11 @@ export function useSessionConversationController(params: UseSessionConversationC
290
319
  }, [agent]);
291
320
 
292
321
  return {
322
+ canContinue,
293
323
  canStopGeneration: agent.isRunning,
324
+ continueRun,
294
325
  deleteQueuedInput,
326
+ editMessage,
295
327
  editQueuedInput,
296
328
  hasSendableDraft,
297
329
  isSending,
@@ -301,6 +333,7 @@ export function useSessionConversationController(params: UseSessionConversationC
301
333
  })),
302
334
  send,
303
335
  sendDisabled,
336
+ primaryAction,
304
337
  stop,
305
338
  stopDisabled: !agent.isRunning,
306
339
  };
@@ -46,6 +46,7 @@ export function useSessionConversationInputAttachments(params: UseSessionConvers
46
46
  insertedAttachments.map((attachment) => ({
47
47
  tokenKey: attachment.id,
48
48
  label: attachment.name,
49
+ previewUrl: attachment.mimeType.startsWith('image/') ? attachment.url : undefined,
49
50
  })),
50
51
  );
51
52
  }
@@ -16,6 +16,7 @@ import { resolveRecentSessionPreferredValue } from '@/features/chat/features/ses
16
16
  import { useChatSessionTypeState } from '@/features/chat/features/session-type/hooks/use-chat-session-type-state';
17
17
  import { chatRecentModelsManager } from '@/features/chat/managers/chat-recent-models.manager';
18
18
  import { useChatQueryStore } from '@/features/chat/stores/ncp-chat-query.store';
19
+ import { useSessionProviderModelCatalog } from './use-session-provider-model-catalog';
19
20
 
20
21
  import type { SessionConversationInputSnapshot } from './use-session-conversation-input-state';
21
22
 
@@ -38,6 +39,8 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
38
39
  const isProviderStateResolved = useNcpChatProviderStateResolved();
39
40
  const querySnapshot = useChatQueryStore((state) => state.snapshot);
40
41
  const config = querySnapshot.configQuery?.data ?? null;
42
+ const providersView = querySnapshot.providersQuery?.data ?? null;
43
+ const templatesView = querySnapshot.providerTemplatesQuery?.data ?? null;
41
44
  const sessionSummaries =
42
45
  querySnapshot.sessionsQuery?.data?.sessions ?? EMPTY_NCP_SESSION_SUMMARIES;
43
46
  const sessionSkillsQuery = useNcpSessionSkills({
@@ -68,10 +71,10 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
68
71
  () =>
69
72
  buildNcpChatProviderModelOptions({
70
73
  config,
71
- providersView: querySnapshot.providersQuery?.data ?? null,
72
- templatesView: querySnapshot.providerTemplatesQuery?.data ?? null,
74
+ providersView,
75
+ templatesView,
73
76
  }),
74
- [config, querySnapshot.providerTemplatesQuery?.data, querySnapshot.providersQuery?.data],
77
+ [config, providersView, templatesView],
75
78
  );
76
79
  const modelOptions = useMemo(
77
80
  () =>
@@ -90,6 +93,18 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
90
93
  sessionTypeState.selectedSessionTypeOption?.supportedModels,
91
94
  ],
92
95
  );
96
+ const {
97
+ addDiscoveredModel,
98
+ dismissDiscoveredModels,
99
+ discoveredModelOptions,
100
+ refreshProviderModelCatalog,
101
+ } = useSessionProviderModelCatalog({
102
+ config,
103
+ providersView,
104
+ templatesView,
105
+ modelSelectionMode: sessionTypeState.selectedSessionTypeOption?.modelSelectionMode,
106
+ supportedModels: sessionTypeState.selectedSessionTypeOption?.supportedModels,
107
+ });
93
108
  const availableModelValueSet = useMemo(
94
109
  () => new Set(modelOptions.map((option) => option.value)),
95
110
  [modelOptions],
@@ -124,13 +139,18 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
124
139
  );
125
140
 
126
141
  return useMemo(() => ({
142
+ addDiscoveredModel,
127
143
  defaultModel: sessionTypeState.selectedSessionTypeOption?.recommendedModel ?? config?.agents.defaults.model,
128
144
  defaultProjectRoot,
145
+ dismissDiscoveredModels,
146
+ discoveredModelOptions,
129
147
  fallbackPreferredModel,
130
148
  fallbackPreferredThinking,
131
149
  isProviderStateResolved,
132
150
  isSkillsLoading,
133
151
  modelOptions,
152
+ providersView,
153
+ refreshProviderModelCatalog,
134
154
  selectedSession,
135
155
  selectedSessionKey,
136
156
  sessionTypeState,
@@ -143,6 +163,11 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
143
163
  isProviderStateResolved,
144
164
  isSkillsLoading,
145
165
  modelOptions,
166
+ addDiscoveredModel,
167
+ dismissDiscoveredModels,
168
+ discoveredModelOptions,
169
+ refreshProviderModelCatalog,
170
+ providersView,
146
171
  selectedSession,
147
172
  selectedSessionKey,
148
173
  sessionTypeState,
@@ -1,10 +1,16 @@
1
- import { useCallback, useMemo, useState, type SetStateAction } from 'react';
1
+ import { useCallback, useEffect, useMemo, type SetStateAction } from 'react';
2
2
  import type { ChatComposerNode } from '@nextclaw/agent-chat-ui';
3
3
  import type { NcpDraftAttachment } from '@nextclaw/ncp-react';
4
4
 
5
5
  import type { ThinkingLevel } from '@/shared/lib/api';
6
6
  import { DEFAULT_SESSION_TYPE } from '@/features/chat/features/session-type/utils/chat-session-type.utils';
7
7
  import { createChatComposerNodesFromDraft } from '@/features/chat/features/input/utils/chat-composer-state.utils';
8
+ import { useChatThreadStore } from '@/features/chat/stores/chat-thread.store';
9
+ import {
10
+ resolveChatComposerDraftKey,
11
+ useChatComposerDraftStore,
12
+ type ChatComposerDraftSnapshot,
13
+ } from '@/features/chat/stores/chat-composer-draft.store';
8
14
  import {
9
15
  useSessionConversationPreferenceActions,
10
16
  type SessionConversationPreferenceSyncParams,
@@ -34,9 +40,11 @@ export type SessionConversationInputSnapshot = SessionConversationComposerState
34
40
  readonly sendError: string | null;
35
41
  };
36
42
 
43
+ type SessionConversationOwnedInputSnapshot = ChatComposerDraftSnapshot;
44
+
37
45
  export type SessionConversationInputPatch =
38
- Partial<SessionConversationInputSnapshot> |
39
- ((snapshot: SessionConversationInputSnapshot) => Partial<SessionConversationInputSnapshot>);
46
+ Partial<SessionConversationOwnedInputSnapshot> |
47
+ ((snapshot: SessionConversationInputSnapshot) => Partial<SessionConversationOwnedInputSnapshot>);
40
48
 
41
49
  export type SessionConversationInputActions = {
42
50
  readonly update: (patch: SessionConversationInputPatch) => void;
@@ -73,7 +81,7 @@ const EMPTY_COMPOSER_STATE: SessionConversationComposerState = {
73
81
 
74
82
  const createInitialInputSnapshot = (
75
83
  initialPrompt?: string | null,
76
- ): SessionConversationInputSnapshot => {
84
+ ): SessionConversationOwnedInputSnapshot => {
77
85
  const prompt = initialPrompt?.trim() ?? '';
78
86
  const composer = prompt
79
87
  ? {
@@ -89,7 +97,6 @@ const createInitialInputSnapshot = (
89
97
  selectedThinkingLevel: null,
90
98
  pendingSessionType: DEFAULT_SESSION_TYPE,
91
99
  selectedSessionType: DEFAULT_SESSION_TYPE,
92
- pendingProjectRoot: null,
93
100
  composerFocusRequestId: prompt ? 1 : 0,
94
101
  sendError: null,
95
102
  };
@@ -127,20 +134,80 @@ const mergeAttachments = (
127
134
  return merged;
128
135
  };
129
136
 
130
- export const useSessionConversationInputState = (initialPrompt?: string | null) => {
131
- const [snapshot, setSnapshot] = useState<SessionConversationInputSnapshot>(
137
+ function useSessionConversationAttachmentActions(params: {
138
+ attachments: readonly NcpDraftAttachment[];
139
+ update: (patch: SessionConversationInputPatch) => void;
140
+ }) {
141
+ const { attachments: currentAttachments, update } = params;
142
+ const setAttachments = useCallback((attachments: readonly NcpDraftAttachment[]) => {
143
+ update({ attachments });
144
+ }, [update]);
145
+ const addAttachments = useCallback((attachments: readonly NcpDraftAttachment[]) => {
146
+ if (attachments.length === 0) {
147
+ return [];
148
+ }
149
+ const existingKeys = new Set(currentAttachments.map(buildAttachmentKey));
150
+ const nextAttachments = mergeAttachments(currentAttachments, attachments);
151
+ const insertedAttachments = nextAttachments.filter(
152
+ (attachment) => !existingKeys.has(buildAttachmentKey(attachment)),
153
+ );
154
+ if (insertedAttachments.length > 0) {
155
+ update({ attachments: nextAttachments });
156
+ }
157
+ return insertedAttachments;
158
+ }, [currentAttachments, update]);
159
+ const removeAttachment = useCallback((attachmentId: string) => {
160
+ update((current) => ({
161
+ attachments: current.attachments.filter((attachment) => attachment.id !== attachmentId),
162
+ }));
163
+ }, [update]);
164
+ return { addAttachments, removeAttachment, setAttachments };
165
+ }
166
+
167
+ function usePersistedConversationInputSnapshot(
168
+ initialPrompt: string | null | undefined,
169
+ sessionKey: string | null,
170
+ ) {
171
+ const draftKey = resolveChatComposerDraftKey(sessionKey);
172
+ const initialSnapshot = useMemo(
132
173
  () => createInitialInputSnapshot(initialPrompt),
174
+ [initialPrompt],
133
175
  );
176
+ const snapshot = useChatComposerDraftStore(
177
+ (state) => state.drafts[draftKey] ?? initialSnapshot,
178
+ );
179
+
180
+ useEffect(() => {
181
+ useChatComposerDraftStore.getState().ensureDraft(draftKey, initialSnapshot);
182
+ }, [draftKey, initialSnapshot]);
134
183
 
135
184
  const update = useCallback((patch: SessionConversationInputPatch) => {
136
- setSnapshot((current) => {
137
- const resolvedPatch = typeof patch === 'function' ? patch(current) : patch;
185
+ useChatComposerDraftStore.getState().updateDraft(draftKey, initialSnapshot, (current) => {
186
+ const resolvedPatch = typeof patch === 'function'
187
+ ? patch({
188
+ ...current,
189
+ pendingProjectRoot: useChatThreadStore.getState().snapshot.draftProjectRoot,
190
+ })
191
+ : patch;
138
192
  return {
139
193
  ...current,
140
194
  ...resolvedPatch,
141
195
  };
142
196
  });
143
- }, []);
197
+ }, [draftKey, initialSnapshot]);
198
+
199
+ return { snapshot, update };
200
+ }
201
+
202
+ export const useSessionConversationInputState = (
203
+ initialPrompt?: string | null,
204
+ sessionKey: string | null = null,
205
+ ) => {
206
+ const pendingProjectRoot = useChatThreadStore((state) => state.snapshot.draftProjectRoot);
207
+ const { snapshot, update } = usePersistedConversationInputSnapshot(
208
+ initialPrompt,
209
+ sessionKey,
210
+ );
144
211
 
145
212
  const syncComposer = useCallback((composer: SessionConversationComposerState) => {
146
213
  update({
@@ -191,30 +258,14 @@ export const useSessionConversationInputState = (initialPrompt?: string | null)
191
258
  update({ composerFocusRequestId: 0 });
192
259
  }, [update]);
193
260
 
194
- const setAttachments = useCallback((attachments: readonly NcpDraftAttachment[]) => {
195
- update({ attachments });
196
- }, [update]);
197
-
198
- const addAttachments = useCallback((attachments: readonly NcpDraftAttachment[]) => {
199
- if (attachments.length === 0) {
200
- return [];
201
- }
202
- const existingKeys = new Set(snapshot.attachments.map(buildAttachmentKey));
203
- const nextAttachments = mergeAttachments(snapshot.attachments, attachments);
204
- const insertedAttachments = nextAttachments.filter(
205
- (attachment) => !existingKeys.has(buildAttachmentKey(attachment)),
206
- );
207
- if (insertedAttachments.length > 0) {
208
- update({ attachments: nextAttachments });
209
- }
210
- return insertedAttachments;
211
- }, [snapshot.attachments, update]);
212
-
213
- const removeAttachment = useCallback((attachmentId: string) => {
214
- update((current) => ({
215
- attachments: current.attachments.filter((attachment) => attachment.id !== attachmentId),
216
- }));
217
- }, [update]);
261
+ const {
262
+ addAttachments,
263
+ removeAttachment,
264
+ setAttachments,
265
+ } = useSessionConversationAttachmentActions({
266
+ attachments: snapshot.attachments,
267
+ update,
268
+ });
218
269
 
219
270
  const preferenceActions = useSessionConversationPreferenceActions({
220
271
  selectedModel: snapshot.selectedModel,
@@ -236,8 +287,8 @@ export const useSessionConversationInputState = (initialPrompt?: string | null)
236
287
  }, [update]);
237
288
 
238
289
  const setPendingProjectRoot = useCallback((projectRoot: string | null) => {
239
- update({ pendingProjectRoot: projectRoot });
240
- }, [update]);
290
+ useChatThreadStore.getState().setSnapshot({ draftProjectRoot: projectRoot });
291
+ }, []);
241
292
 
242
293
  const setSelectedSkills = useCallback((
243
294
  selectedSkills: readonly string[],
@@ -289,7 +340,10 @@ export const useSessionConversationInputState = (initialPrompt?: string | null)
289
340
  ]);
290
341
 
291
342
  return {
292
- inputSnapshot: snapshot,
343
+ inputSnapshot: {
344
+ ...snapshot,
345
+ pendingProjectRoot,
346
+ },
293
347
  inputActions: actions,
294
348
  };
295
349
  };
@@ -0,0 +1,64 @@
1
+ import { useCallback } from 'react';
2
+ import type { NcpMessage, NcpRunHandle } from '@nextclaw/ncp';
3
+ import type {
4
+ AgentRunContinueIngressPayload,
5
+ AgentRunEditMessageIngressPayload,
6
+ } from '@nextclaw/shared';
7
+
8
+ export type SessionConversationRecoveryAgent = {
9
+ readonly isRunning: boolean;
10
+ readonly isSending: boolean;
11
+ readonly continueRun: (
12
+ payload: AgentRunContinueIngressPayload,
13
+ ) => Promise<NcpRunHandle>;
14
+ readonly editMessage: (
15
+ payload: AgentRunEditMessageIngressPayload,
16
+ ) => Promise<NcpRunHandle>;
17
+ };
18
+
19
+ export type SessionConversationMessageEdit = {
20
+ readonly message: NcpMessage;
21
+ readonly messageId: string;
22
+ };
23
+
24
+ export function useSessionConversationRecoveryActions({
25
+ agent,
26
+ sessionKey,
27
+ setSendError,
28
+ }: {
29
+ readonly agent: SessionConversationRecoveryAgent;
30
+ readonly sessionKey: string | null;
31
+ readonly setSendError: (message: string | null) => void;
32
+ }) {
33
+ const continueRun = useCallback(async () => {
34
+ if (!sessionKey || agent.isSending || agent.isRunning) {
35
+ return;
36
+ }
37
+ setSendError(null);
38
+ try {
39
+ await agent.continueRun({ sessionId: sessionKey });
40
+ } catch (error) {
41
+ setSendError(error instanceof Error ? error.message : String(error));
42
+ throw error;
43
+ }
44
+ }, [agent, sessionKey, setSendError]);
45
+
46
+ const editMessage = useCallback(async (payload: SessionConversationMessageEdit) => {
47
+ if (!sessionKey || agent.isSending || agent.isRunning) {
48
+ return;
49
+ }
50
+ setSendError(null);
51
+ try {
52
+ await agent.editMessage({
53
+ message: payload.message,
54
+ messageId: payload.messageId,
55
+ sessionId: sessionKey,
56
+ });
57
+ } catch (error) {
58
+ setSendError(error instanceof Error ? error.message : String(error));
59
+ throw error;
60
+ }
61
+ }, [agent, sessionKey, setSendError]);
62
+
63
+ return { continueRun, editMessage };
64
+ }
@@ -39,6 +39,7 @@ export function useSessionConversationSlashCommands(params: {
39
39
  return [
40
40
  {
41
41
  key: 'side-chat',
42
+ icon: 'message-square-plus',
42
43
  title: t('chatSlashCommandSideChatTitle', language),
43
44
  description: t('chatSlashCommandSideChatDescription', language),
44
45
  detailLines: [t('chatSlashCommandSideChatDetail', language)],
@@ -47,6 +48,7 @@ export function useSessionConversationSlashCommands(params: {
47
48
  },
48
49
  {
49
50
  key: 'compact-context',
51
+ icon: 'list-collapse',
50
52
  title: t('chatSlashCommandCompactContextTitle', language),
51
53
  description: t('chatSlashCommandCompactContextDescription', language),
52
54
  detailLines: [t('chatSlashCommandCompactContextDetail', language)],
@@ -0,0 +1,84 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import type { RuntimeModelSelectionMode } from '@nextclaw/shared';
3
+
4
+ import type { ConfigView, ProvidersView, ProviderTemplatesView } from '@/shared/lib/api';
5
+ import { useProviderModelCatalog, useUpdateProvider } from '@/shared/hooks/use-config';
6
+ import { normalizeStringList } from '@/shared/lib/provider-models';
7
+ import {
8
+ buildNcpChatDiscoveredModelOptions,
9
+ filterNcpChatDiscoveredModelOptionsBySessionType,
10
+ } from '@/features/chat/features/ncp/utils/ncp-chat-query-derived.utils';
11
+ import { providerModelCatalogNoticeManager } from '@/features/chat/managers/provider-model-catalog-notice.manager';
12
+
13
+ type UseSessionProviderModelCatalogParams = {
14
+ readonly config: ConfigView | null;
15
+ readonly providersView: ProvidersView | null;
16
+ readonly templatesView: ProviderTemplatesView | null;
17
+ readonly modelSelectionMode?: RuntimeModelSelectionMode;
18
+ readonly supportedModels?: string[];
19
+ };
20
+
21
+ export function useSessionProviderModelCatalog(params: UseSessionProviderModelCatalogParams) {
22
+ const {
23
+ config,
24
+ modelSelectionMode,
25
+ providersView,
26
+ supportedModels,
27
+ templatesView,
28
+ } = params;
29
+ const catalogQuery = useProviderModelCatalog();
30
+ const { mutateAsync: updateProvider } = useUpdateProvider();
31
+ const [noticeRevision, setNoticeRevision] = useState(0);
32
+ const catalogModelOptions = useMemo(
33
+ () => buildNcpChatDiscoveredModelOptions({
34
+ catalogView: catalogQuery.data ?? null,
35
+ config,
36
+ providersView,
37
+ templatesView,
38
+ }),
39
+ [catalogQuery.data, config, providersView, templatesView],
40
+ );
41
+ useEffect(() => {
42
+ providerModelCatalogNoticeManager.initializeLargeCatalogs(catalogModelOptions);
43
+ }, [catalogModelOptions]);
44
+ const discoveredModelOptions = useMemo(
45
+ () => {
46
+ void noticeRevision;
47
+ return filterNcpChatDiscoveredModelOptionsBySessionType({
48
+ modelOptions: providerModelCatalogNoticeManager.filterUnseen(catalogModelOptions),
49
+ modelSelectionMode,
50
+ supportedModels,
51
+ });
52
+ },
53
+ [catalogModelOptions, modelSelectionMode, noticeRevision, supportedModels],
54
+ );
55
+ const addDiscoveredModel = useCallback(async (value: string) => {
56
+ const option = discoveredModelOptions.find((candidate) => candidate.value === value);
57
+ const provider = option ? providersView?.providers[option.providerId] : undefined;
58
+ if (!option || !provider) {
59
+ return null;
60
+ }
61
+ await updateProvider({
62
+ provider: option.providerId,
63
+ data: {
64
+ models: normalizeStringList([...(provider.models ?? []), option.providerModel]),
65
+ },
66
+ silentSuccess: true,
67
+ });
68
+ providerModelCatalogNoticeManager.acknowledge([option]);
69
+ setNoticeRevision((current) => current + 1);
70
+ return option;
71
+ }, [discoveredModelOptions, providersView, updateProvider]);
72
+ const dismissDiscoveredModels = useCallback(() => {
73
+ if (providerModelCatalogNoticeManager.acknowledge(discoveredModelOptions)) {
74
+ setNoticeRevision((current) => current + 1);
75
+ }
76
+ }, [discoveredModelOptions]);
77
+
78
+ return {
79
+ addDiscoveredModel,
80
+ dismissDiscoveredModels,
81
+ discoveredModelOptions,
82
+ refreshProviderModelCatalog: catalogQuery.refetch,
83
+ };
84
+ }
@@ -0,0 +1,34 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import { buildSessionMessageComposerSnapshot } from '@/features/chat/features/conversation/utils/session-message-composer.utils';
4
+
5
+ describe('buildSessionMessageComposerSnapshot', () => {
6
+ it('round-trips text, attachment and requested skill state into the shared composer', () => {
7
+ const snapshot = buildSessionMessageComposerSnapshot({
8
+ attachmentIdPrefix: 'edit-user-1',
9
+ availableSkills: [{ ref: 'skill://review', name: 'Review' }],
10
+ message: {
11
+ id: 'user-1',
12
+ sessionId: 'session-1',
13
+ role: 'user',
14
+ status: 'final',
15
+ timestamp: '2026-08-08T10:00:00.000Z',
16
+ metadata: { requested_skill_refs: ['skill://review'] },
17
+ parts: [
18
+ { type: 'text', text: 'check this' },
19
+ { type: 'file', name: 'notes.txt', mimeType: 'text/plain', sizeBytes: 12 },
20
+ ],
21
+ },
22
+ });
23
+
24
+ expect(snapshot.text).toContain('check this');
25
+ expect(snapshot.selectedSkills).toEqual(['skill://review']);
26
+ expect(snapshot.skillRecords).toEqual([{ ref: 'skill://review', name: 'Review' }]);
27
+ expect(snapshot.attachments).toEqual([
28
+ expect.objectContaining({ id: 'edit-user-1-1', name: 'notes.txt' }),
29
+ ]);
30
+ expect(snapshot.nodes).toEqual(expect.arrayContaining([
31
+ expect.objectContaining({ type: 'token', tokenKind: 'file' }),
32
+ ]));
33
+ });
34
+ });