@nextclaw/ui 0.26.5 → 0.27.1

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 (433) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/dist/.vite/manifest.json +1342 -1227
  3. package/dist/assets/{abnfDiagram-VRR7QNED-Dcw10Yt1.js → abnfDiagram-VRR7QNED-BT0_ycaq.js} +1 -1
  4. package/dist/assets/account-panel-BVNV8XqM.js +1 -0
  5. package/dist/assets/agents-CfpN8PQc.js +1 -0
  6. package/dist/assets/agents-E4nu-17c.js +1 -0
  7. package/dist/assets/{aiden0z-pptx-renderer.es--oNqetPA.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-2DwHRRle.js +28 -0
  10. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
  11. package/dist/assets/appearance-settings-page-Cn9w3F-K.js +1 -0
  12. package/dist/assets/apps-YFlJirpx.js +1 -0
  13. package/dist/assets/{arc-DBRedCax.js → arc-cmSdpq1Z.js} +1 -1
  14. package/dist/assets/architecture-TIHT7OUA-BImoGh10.js +1 -0
  15. package/dist/assets/{architectureDiagram-ZJ3FMSHR-Dufhtuv-.js → architectureDiagram-ZJ3FMSHR-aYglVeoS.js} +1 -1
  16. package/dist/assets/{blockDiagram-677ZJIJ3-BUk0vtJ7.js → blockDiagram-677ZJIJ3-Di_PBl5q.js} +1 -1
  17. package/dist/assets/{book-open-Bcnn2_uV.js → book-open-i_BjUBqL.js} +1 -1
  18. package/dist/assets/{c4Diagram-LMCZKHZV-CxDcVE9p.js → c4Diagram-LMCZKHZV-CfuxybOL.js} +1 -1
  19. package/dist/assets/{card-Cqs73hGI.js → card-DokH7OBp.js} +1 -1
  20. package/dist/assets/channel-BDQry0ob.js +1 -0
  21. package/dist/assets/channels-list-page-B7G9lHUm.js +8 -0
  22. package/dist/assets/chunk-2Q5K7J3B-DkgSFfIy.js +1 -0
  23. package/dist/assets/{chunk-32BRIVSS-DSF3KElA.js → chunk-32BRIVSS-CCGc4qg4.js} +1 -1
  24. package/dist/assets/{chunk-52WLFC77-Costxzr3.js → chunk-52WLFC77-aJoxU2Ow.js} +1 -1
  25. package/dist/assets/{chunk-5FCAYU7R-rhqzGGZo.js → chunk-5FCAYU7R-CGwtZSax.js} +1 -1
  26. package/dist/assets/{chunk-5HE753X5-BsEsmIao.js → chunk-5HE753X5-DqaMSMeS.js} +1 -1
  27. package/dist/assets/{chunk-5JV3BV7I-Dqw_DCoN.js → chunk-5JV3BV7I-DnabINcd.js} +1 -1
  28. package/dist/assets/{chunk-5TONJI2A-Cft82fp8.js → chunk-5TONJI2A-BhpKv1k2.js} +1 -1
  29. package/dist/assets/{chunk-5VM5RSS4-DqNHn9Dl.js → chunk-5VM5RSS4-DvkRPit_.js} +1 -1
  30. package/dist/assets/{chunk-7BUUIJ7U-A5SBEMYY.js → chunk-7BUUIJ7U-CgDQOLnC.js} +1 -1
  31. package/dist/assets/{chunk-BIQX33UG-1Ng3mTrH.js → chunk-BIQX33UG-9FEv5b7T.js} +1 -1
  32. package/dist/assets/{chunk-C7G6YPKG-DRJEy8ZI.js → chunk-C7G6YPKG-CNGFAFYL.js} +1 -1
  33. package/dist/assets/{chunk-CQNSW5MT-Bydv_J3J.js → chunk-CQNSW5MT-DovTZx0M.js} +1 -1
  34. package/dist/assets/{chunk-CYSBUYHQ-HkMIg12u.js → chunk-CYSBUYHQ-DpLEgYa1.js} +1 -1
  35. package/dist/assets/{chunk-EMLP6XTP-C5ndDvm3.js → chunk-EMLP6XTP-D4NuN01W.js} +1 -1
  36. package/dist/assets/{chunk-EX3LRPZG-DzeloZRo.js → chunk-EX3LRPZG-D8Jf4kc2.js} +1 -1
  37. package/dist/assets/{chunk-FWX5IMBZ-n_2_CLTQ.js → chunk-FWX5IMBZ-BdHymAs0.js} +2 -2
  38. package/dist/assets/{chunk-HOUHSVGY-kx_slvu3.js → chunk-HOUHSVGY-Dd_Ycn9Z.js} +1 -1
  39. package/dist/assets/{chunk-ICXQ74PX-sQLMURqL.js → chunk-ICXQ74PX-BRPUu3ff.js} +1 -1
  40. package/dist/assets/{chunk-JG7HCLWE-CMUn5Elc.js → chunk-JG7HCLWE-DnCasQja.js} +1 -1
  41. package/dist/assets/{chunk-JWPE2WC7-Cra3s-Uk.js → chunk-JWPE2WC7-C3CkbEj1.js} +1 -1
  42. package/dist/assets/{chunk-MOJQB5TN-umcrg5Bi.js → chunk-MOJQB5TN-Pi--K4-1.js} +1 -1
  43. package/dist/assets/{chunk-MOZMSUNE-BnljD1ig.js → chunk-MOZMSUNE-3VTspvlh.js} +1 -1
  44. package/dist/assets/{chunk-OGEWGWER-BXx5pQjU.js → chunk-OGEWGWER-BetLLyJt.js} +1 -1
  45. package/dist/assets/{chunk-OSBZ3O6U-D-1qfdWu.js → chunk-OSBZ3O6U-D1VcupAj.js} +1 -1
  46. package/dist/assets/{chunk-PUDLZKDR-DLzX78LC.js → chunk-PUDLZKDR-Cy4G8SjV.js} +1 -1
  47. package/dist/assets/{chunk-Q4XR5HBZ-DTK-rtW6.js → chunk-Q4XR5HBZ-UYxXzi7_.js} +1 -1
  48. package/dist/assets/{chunk-QBLGF6JB-CsFeIGfr.js → chunk-QBLGF6JB-CHiGeRY1.js} +1 -1
  49. package/dist/assets/{chunk-R7FJI6CG-4xNYUeng.js → chunk-R7FJI6CG-C5kVJus8.js} +1 -1
  50. package/dist/assets/{chunk-RYQCIY6F-DJiHiTE5.js → chunk-RYQCIY6F-C6cuuEBn.js} +1 -1
  51. package/dist/assets/{chunk-U6XO7XAA-BVYkauHz.js → chunk-U6XO7XAA-CM0EK7Y0.js} +1 -1
  52. package/dist/assets/{chunk-V7JOEXUC-BsazE8cS.js → chunk-V7JOEXUC-DWJZIsME.js} +1 -1
  53. package/dist/assets/chunk-VAUOI2AC-CsTIB8qD.js +1 -0
  54. package/dist/assets/{chunk-VR4S4FIN-7RoZQffO.js → chunk-VR4S4FIN-CY5KYeEi.js} +1 -1
  55. package/dist/assets/{chunk-WYO6CB5R-DEuS6N1R.js → chunk-WYO6CB5R-B30N3ZP8.js} +3 -3
  56. package/dist/assets/chunk-XXDRQBXY-DK6dz0Q3.js +1 -0
  57. package/dist/assets/{chunk-YOTPTUD7-9KBrosZL.js → chunk-YOTPTUD7-CBu82JpO.js} +1 -1
  58. package/dist/assets/{chunk-ZGVPDNZ5-IYgN9f5A.js → chunk-ZGVPDNZ5-BN5NX5qA.js} +1 -1
  59. package/dist/assets/{chunk-ZIRB5QZD-BUo0-zcp.js → chunk-ZIRB5QZD-DcDXK29L.js} +1 -1
  60. package/dist/assets/{circle-dashed-EY1ScSMe.js → circle-dashed-Cx8CIEbg.js} +1 -1
  61. package/dist/assets/classDiagram-OUVF2IWQ-BYygHCrp.js +1 -0
  62. package/dist/assets/classDiagram-v2-EOCWNBFH-BgQ0XKYz.js +1 -0
  63. package/dist/assets/{client-CH7w6yRV.js → client-CUJUci3r.js} +1 -1
  64. package/dist/assets/config-split-page-hY1xug28.js +1 -0
  65. package/dist/assets/confirm-dialog-B-ejV666.js +1 -0
  66. package/dist/assets/{app-presenter-provider-jNGlmBLe.css → context-menu-DEcVZfaU.css} +1 -1
  67. package/dist/assets/context-menu-dGVv8klA.js +211 -0
  68. package/dist/assets/{cose-bilkent-JH36ORCC-DhqbC1fR.js → cose-bilkent-JH36ORCC-CmeJVoTw.js} +1 -1
  69. package/dist/assets/{createLucideIcon-Cfo2ySi5.js → createLucideIcon-reFMl-W-.js} +1 -1
  70. package/dist/assets/cron-CH5c55CR.js +1 -0
  71. package/dist/assets/cynefin-VYW2F7L2-DKbotNWS.js +1 -0
  72. package/dist/assets/{cynefinDiagram-TSTJHNR4-C-TBRi5V.js → cynefinDiagram-TSTJHNR4-DGOUMgPP.js} +1 -1
  73. package/dist/assets/{dagre-CrgsRasE.js → dagre-CMxSkbJJ.js} +1 -1
  74. package/dist/assets/{dagre-VKFMJZFB-BmafJymp.js → dagre-VKFMJZFB-3YUBEXwo.js} +1 -1
  75. package/dist/assets/{desktop-capabilities-page-BDYITStl.js → desktop-capabilities-page-CYJTQ3nC.js} +1 -1
  76. package/dist/assets/desktop-update-config-guKAozXO.js +1 -0
  77. package/dist/assets/{diagram-FQU43EPY-BoOMwa6D.js → diagram-FQU43EPY-Br1g--ww.js} +1 -1
  78. package/dist/assets/{diagram-G47NLZAW-Le7N6Uym.js → diagram-G47NLZAW-D1wJCBgr.js} +1 -1
  79. package/dist/assets/{diagram-NH7WQ7WH-Fbpj3-MO.js → diagram-NH7WQ7WH-Cgg2auLH.js} +1 -1
  80. package/dist/assets/{diagram-OA4YK3LP-D3QuGGuu.js → diagram-OA4YK3LP-R-wHiWqh.js} +1 -1
  81. package/dist/assets/{diagram-WEI45ONY-Cxu1uiN6.js → diagram-WEI45ONY-CsNnKV0P.js} +1 -1
  82. package/dist/assets/dialog-DLOwdjT1.js +1 -0
  83. package/dist/assets/dist-ZaFFmAGl.js +41 -0
  84. package/dist/assets/doc-browser-ClDUWo9V.js +1 -0
  85. package/dist/assets/doc-browser-context-CTmOmuqa.js +1 -0
  86. package/dist/assets/{docx-preview-CkU2psnd.js → docx-preview-kPn_EtAr.js} +1 -1
  87. package/dist/assets/{download-BoaKzDJk.js → download-DovI3Yvf.js} +1 -1
  88. package/dist/assets/{ebnfDiagram-CCIWWBDH-CCAjuQM6.js → ebnfDiagram-CCIWWBDH-DCyhIPdi.js} +1 -1
  89. package/dist/assets/{erDiagram-Q63AITRT-BuzUAq-d.js → erDiagram-Q63AITRT-D0ZJYAUf.js} +1 -1
  90. package/dist/assets/eventmodeling-45OFAUF4-SIhbIFIw.js +1 -0
  91. package/dist/assets/extensions-BZ3qrM8M.js +1 -0
  92. package/dist/assets/external-link-DUD3AbsF.js +1 -0
  93. package/dist/assets/flowDiagram-23GEKE2U-DdAjkU7I.js +1 -0
  94. package/dist/assets/{form-actions-D9JWSFQu.js → form-actions-B8VniHts.js} +1 -1
  95. package/dist/assets/{ganttDiagram-NO4QXBWP-cJmWVY8F.js → ganttDiagram-NO4QXBWP-CiXDcXZD.js} +1 -1
  96. package/dist/assets/gitGraph-TEB2WS4Q-DnMNpESZ.js +1 -0
  97. package/dist/assets/{gitGraphDiagram-IHSO6WYX-F58o-vtP.js → gitGraphDiagram-IHSO6WYX-BSiIV48S.js} +1 -1
  98. package/dist/assets/{i18n-Bm3Ov7Fy.js → i18n-IGQbjBqS.js} +2 -2
  99. package/dist/assets/inbox-BjBZIbgx.js +1 -0
  100. package/dist/assets/inbox-ClAG7SI_.js +1 -0
  101. package/dist/assets/info-DKCQHKI2-BSm-69p_.js +1 -0
  102. package/dist/assets/{infoDiagram-FWYZ7A6U-Gt59b83C.js → infoDiagram-FWYZ7A6U-CCIgBCVq.js} +1 -1
  103. package/dist/assets/{ishikawaDiagram-FXEZZL3T-1u4IAj1I.js → ishikawaDiagram-FXEZZL3T-nQ_baN5u.js} +1 -1
  104. package/dist/assets/{journeyDiagram-5HDEW3XC-CCQsfV-5.js → journeyDiagram-5HDEW3XC-ABueIPzj.js} +1 -1
  105. package/dist/assets/{kanban-definition-HUTT4EX6-vlB6O_Zn.js → kanban-definition-HUTT4EX6-8FKS3fmQ.js} +1 -1
  106. package/dist/assets/katex-DPgHtix3.js +1 -0
  107. package/dist/assets/keyboard-shortcuts-settings-page-BqfbbKir.js +1 -0
  108. package/dist/assets/{line-D_bHubTL.js → line-Biw8iEUz.js} +1 -1
  109. package/dist/assets/{linear-ChlwuS5y.js → linear-D7CWUHTF.js} +1 -1
  110. package/dist/assets/login-page-BxSMwUsc.js +1 -0
  111. package/dist/assets/{login-page-C-DvcG3L.js → login-page-DYaozpzz.js} +1 -1
  112. package/dist/assets/main-CWYF9QU_.js +2 -0
  113. package/dist/assets/main-D_zmSVS1.css +1 -0
  114. package/dist/assets/main-i18n-catalog.config-itg3Gvzp.js +1 -0
  115. package/dist/assets/{map-oGHTsIu8.js → map-CDu47gTf.js} +1 -1
  116. package/dist/assets/marketplace-CnQ5USfr.js +1 -0
  117. package/dist/assets/mcp-marketplace-page-Dor6H9IC.js +1 -0
  118. package/dist/assets/{mermaid-parser.core-CuRe1ZG4.js → mermaid-parser.core-Cc9wjl82.js} +2 -2
  119. package/dist/assets/{mermaid.core-u4YCFKRf.js → mermaid.core-GWlaVWz1.js} +3 -3
  120. package/dist/assets/{mindmap-definition-LN4V7U3C-DeJAQYTu.js → mindmap-definition-LN4V7U3C-oqnKsz-R.js} +1 -1
  121. package/dist/assets/model-config-page-Cduyz2Hy.js +1 -0
  122. package/dist/assets/{navigation-link-CjxNC8aT.js → navigation-link-D-JSWFxj.js} +2 -2
  123. package/dist/assets/{ordinal-C6JFfkKN.js → ordinal-DImbxqBz.js} +1 -1
  124. package/dist/assets/packet-7NZHBO7P-1YQvC6mT.js +1 -0
  125. package/dist/assets/panel-app-BBTg0tVp.js +1 -0
  126. package/dist/assets/panel-app-i18n-catalog.config-BfLHr1tc.js +1 -0
  127. package/dist/assets/panel-apps-C-izvtu9.js +1 -0
  128. package/dist/assets/panelStandalone-XRlWxbRS.css +1 -0
  129. package/dist/assets/panelStandalone-oHxbXvYt.js +2 -0
  130. package/dist/assets/{pegDiagram-2B236MQR-nVMkxShH.js → pegDiagram-2B236MQR-DYAB8CEz.js} +1 -1
  131. package/dist/assets/pie-RZYD4A2V-BGoNOSwu.js +1 -0
  132. package/dist/assets/{pieDiagram-ENE6RG2P-8aUH44QZ.js → pieDiagram-ENE6RG2P-DGsH0Kk5.js} +1 -1
  133. package/dist/assets/plus-DUdl68Eo.js +1 -0
  134. package/dist/assets/privacy-settings-page-DG9E8N-F.js +1 -0
  135. package/dist/assets/projects-CzBaTOTL.js +1 -0
  136. package/dist/assets/provider-models-COzjYl29.js +1 -0
  137. package/dist/assets/provider-scoped-model-input-Cvy74uj8.js +1 -0
  138. package/dist/assets/providers-config-page-7rCwVnhh.js +1 -0
  139. package/dist/assets/puzzle-C5Wfpjk_.js +1 -0
  140. package/dist/assets/pwa-CAg_9zFs.js +1 -0
  141. package/dist/assets/{quadrantDiagram-ABIIQ3AL-EY8hpFv8.js → quadrantDiagram-ABIIQ3AL-BegGcT3l.js} +1 -1
  142. package/dist/assets/radar-I7S5WNFK-uPku9RRq.js +1 -0
  143. package/dist/assets/railroad-3IZDKUUU-DHnmbuIo.js +1 -0
  144. package/dist/assets/railroad-abnf-AHOZXSZD-DiZs--Iw.js +1 -0
  145. package/dist/assets/railroad-ebnf-EBAXGLYW-Nr53gnNE.js +1 -0
  146. package/dist/assets/railroad-peg-LSFZ7HO6-Cm_PuwJS.js +1 -0
  147. package/dist/assets/{railroadDiagram-RFXS5EU6-CNhcIeji.js → railroadDiagram-RFXS5EU6-B3yJ2yxE.js} +1 -1
  148. package/dist/assets/{refresh-cw-BlXDrVP0.js → refresh-cw-OhwaPDn1.js} +1 -1
  149. package/dist/assets/remote-DvCdHjzA.js +1 -0
  150. package/dist/assets/{requirementDiagram-TGXJPOKE-D8Dcs-Rt.js → requirementDiagram-TGXJPOKE-DtEyoEXG.js} +1 -1
  151. package/dist/assets/{rotate-cw-ei6rPD6z.js → rotate-cw-aBponvp7.js} +1 -1
  152. package/dist/assets/runtime-config-page-BF1wxvzR.js +1 -0
  153. package/dist/assets/{sankeyDiagram-HTMAVEWB-HTrb6aa-.js → sankeyDiagram-HTMAVEWB-h9AYS2UB.js} +1 -1
  154. package/dist/assets/{save-DdF-bXgC.js → save-394QCMXn.js} +1 -1
  155. package/dist/assets/search-BG2qAlNZ.js +1 -0
  156. package/dist/assets/search-config-page-D4LeiB9y.js +1 -0
  157. package/dist/assets/secrets-config-page-BzGcr5Vw.js +3 -0
  158. package/dist/assets/security-config-vD_V0BQF.js +1 -0
  159. package/dist/assets/select-xUXYV0Gr.js +1 -0
  160. package/dist/assets/{sequenceDiagram-DBY2YBRQ-6f_4X16Y.js → sequenceDiagram-DBY2YBRQ-D-uxCkob.js} +1 -1
  161. package/dist/assets/service-apps-panel-D3wwPRzV.js +1 -0
  162. package/dist/assets/{settings-2-CrNhfInU.js → settings-2-CWOGRRaA.js} +1 -1
  163. package/dist/assets/{sizeCapture-X5ZJPWSS-Ck9rsuwL.js → sizeCapture-X5ZJPWSS-DBzZytQo.js} +1 -1
  164. package/dist/assets/{src-C8AUg09O.js → src-zrGbZsfc.js} +1 -1
  165. package/dist/assets/{stateDiagram-2N3HPSRC-Cm33MLHu.js → stateDiagram-2N3HPSRC-DyDy7AHq.js} +1 -1
  166. package/dist/assets/stateDiagram-v2-6OUMAXLB-CtkpO6aA.js +1 -0
  167. package/dist/assets/{status-dot-C3SRFEta.js → status-dot-CYifnSnt.js} +1 -1
  168. package/dist/assets/{swimlanes-5IMT3BWC-B107vmvM.js → swimlanes-5IMT3BWC-BzOduS38.js} +2 -2
  169. package/dist/assets/swimlanesDiagram-G3AALYLV-BSdi6mvi.js +8 -0
  170. package/dist/assets/tag-chip-CjM6lyeh.js +1 -0
  171. package/dist/assets/theme-provider-BToFZGZG.js +1 -0
  172. package/dist/assets/{timeline-definition-FHXFAJF6-CJEoAj33.js → timeline-definition-FHXFAJF6-CmgnEF2t.js} +1 -1
  173. package/dist/assets/trash-2-DvJ6duOW.js +1 -0
  174. package/dist/assets/treeView-QDETBFTQ-DBoqypPR.js +1 -0
  175. package/dist/assets/treemap-6X3UGDF4-BMeL3P0q.js +1 -0
  176. package/dist/assets/use-config-COusaY5p.js +1 -0
  177. package/dist/assets/{use-desktop-capabilities-BYDjFlpt.js → use-desktop-capabilities-B-u6ojjW.js} +1 -1
  178. package/dist/assets/use-viewport-layout-IKKGpjzF.js +1 -0
  179. package/dist/assets/{vennDiagram-L72KCM5P-DzsUHk5I.js → vennDiagram-L72KCM5P-DwS7D2kg.js} +1 -1
  180. package/dist/assets/wardley-OPB4EBWU-Dqxe7zN6.js +1 -0
  181. package/dist/assets/{wardleyDiagram-EHGQE667-1NfFs5ua.js → wardleyDiagram-EHGQE667-B4X8OOL4.js} +1 -1
  182. package/dist/assets/x-E9VB4HQx.js +1 -0
  183. package/dist/assets/{xychartDiagram-FW5EYKEG-Ci8AI3Qo.js → xychartDiagram-FW5EYKEG-BjRQ_0nx.js} +1 -1
  184. package/dist/index.html +44 -106
  185. package/dist/panel-standalone.html +19 -13
  186. package/index.html +15 -66
  187. package/package.json +5 -5
  188. package/src/app/styles/design-system.css +85 -1
  189. package/src/app/styles/island-theme.css +8 -6
  190. package/src/features/agents/components/__tests__/agents-page.test.tsx +8 -5
  191. package/src/features/agents/components/agent-details-dialog.tsx +24 -18
  192. package/src/features/agents/components/agents-page.tsx +27 -38
  193. package/src/features/app-data/components/app-retained-data-section.tsx +4 -4
  194. package/src/features/apps/components/__tests__/app-marketplace-catalog.test.tsx +2 -2
  195. package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +94 -23
  196. package/src/features/apps/components/__tests__/apps-panel.test.tsx +5 -3
  197. package/src/features/apps/components/app-document-access-section.tsx +17 -14
  198. package/src/features/apps/components/app-marketplace-catalog.tsx +69 -42
  199. package/src/features/apps/components/app-marketplace-cover.tsx +5 -2
  200. package/src/features/apps/components/app-marketplace-detail.tsx +20 -8
  201. package/src/features/apps/components/app-marketplace-operation.tsx +8 -3
  202. package/src/features/apps/components/app-marketplace-panel.tsx +168 -0
  203. package/src/features/apps/components/app-package-card.tsx +224 -147
  204. package/src/features/apps/components/app-package-details-dialog.tsx +103 -0
  205. package/src/features/apps/components/app-packages-panel.tsx +162 -147
  206. package/src/features/apps/components/apps-panel.tsx +43 -12
  207. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +1 -1
  208. package/src/features/chat/components/conversation/chat-conversation-header.tsx +1 -1
  209. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +2 -2
  210. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +9 -7
  211. package/src/features/chat/components/providers/chat-runtime.provider.tsx +1 -1
  212. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +0 -1
  213. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +13 -2
  214. package/src/features/chat/features/conversation/components/floating-session-conversation.tsx +2 -3
  215. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +9 -1
  216. package/src/features/chat/features/conversation/components/session-conversation-input-top-slot.tsx +44 -0
  217. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +4 -38
  218. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +86 -10
  219. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +44 -1
  220. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +85 -73
  221. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +5 -15
  222. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +53 -13
  223. package/src/features/chat/features/conversation/hooks/use-session-submission-recovery.ts +83 -0
  224. package/src/features/chat/features/conversation/types/session-conversation-input.types.ts +38 -0
  225. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +1 -29
  226. package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +1 -8
  227. package/src/features/chat/features/message/components/__tests__/chat-message-list-skill-preview.container.test.tsx +14 -1
  228. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +7 -2
  229. package/src/features/chat/features/message/utils/chat-message-execution-summary.utils.ts +3 -0
  230. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
  231. package/src/features/chat/features/message/utils/chat-message-trigger-details.utils.ts +3 -0
  232. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +1 -1
  233. package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
  234. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +2 -2
  235. package/src/features/chat/features/session/utils/__tests__/chat-session-route.utils.test.ts +26 -0
  236. package/src/features/chat/features/session/utils/chat-session-preference-governance.utils.ts +14 -8
  237. package/src/features/chat/features/session/utils/chat-session-route.utils.ts +9 -12
  238. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +31 -6
  239. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +13 -1
  240. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +1 -1
  241. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +1 -1
  242. package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +56 -13
  243. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +3 -3
  244. package/src/features/chat/features/welcome/components/chat-welcome.tsx +14 -4
  245. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-continuation.utils.test.ts +40 -0
  246. package/src/features/chat/features/welcome/utils/chat-welcome-continuation.utils.ts +21 -0
  247. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +14 -2
  248. package/src/features/chat/features/workspace/components/__tests__/session-cron-job-content.test.tsx +5 -1
  249. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +1 -1
  250. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +3 -7
  251. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +6 -5
  252. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +27 -27
  253. package/src/features/chat/features/workspace/components/overview/chat-session-continuous-attention.tsx +11 -11
  254. package/src/features/chat/features/workspace/components/overview/chat-session-token-usage.tsx +15 -15
  255. package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +2 -2
  256. package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +1 -1
  257. package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +2 -2
  258. package/src/features/chat/features/workspace/components/session-cron-job-content.tsx +13 -26
  259. package/src/features/chat/index.ts +1 -0
  260. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +37 -47
  261. package/src/features/chat/pages/ncp-chat-page.tsx +3 -3
  262. package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +67 -1
  263. package/src/features/chat/stores/chat-composer-draft.store.ts +230 -29
  264. package/src/features/cron/components/__tests__/cron-config.test.tsx +8 -2
  265. package/src/features/cron/components/cron-config.tsx +6 -17
  266. package/src/features/cron/components/cron-job-detail-dialog.tsx +10 -9
  267. package/src/features/cron/components/cron-job-resource.tsx +51 -0
  268. package/src/features/cron/components/cron-job-row.tsx +5 -4
  269. package/src/features/cron/index.ts +1 -0
  270. package/src/features/desktop-capabilities/components/desktop-authorization-dialog.tsx +5 -5
  271. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +46 -6
  272. package/src/features/inbox/components/inbox-reader-dialog.tsx +38 -29
  273. package/src/features/inbox/managers/inbox.manager.test.ts +28 -0
  274. package/src/features/inbox/managers/inbox.manager.ts +18 -4
  275. package/src/features/inbox/pages/inbox-page.test.ts +4 -2
  276. package/src/features/inbox/pages/inbox-page.tsx +14 -10
  277. package/src/features/marketplace/components/__tests__/marketplace-page-detail.test.tsx +1 -0
  278. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +1 -0
  279. package/src/features/marketplace/components/mcp/__tests__/mcp-marketplace-page.test.tsx +2 -0
  280. package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +2 -2
  281. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +23 -1
  282. package/src/features/marketplace/hooks/use-marketplace-item-detail.ts +11 -0
  283. package/src/features/panel-apps/components/panel-app-list-item.tsx +4 -3
  284. package/src/features/panel-apps/components/panel-app-service-action-authorization-dialog.tsx +2 -2
  285. package/src/features/panel-apps/index.ts +1 -0
  286. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +5 -24
  287. package/src/features/projects/components/work/project-work-item-drawer.tsx +7 -10
  288. package/src/features/projects/components/work/project-work-items.tsx +1 -1
  289. package/src/features/projects/pages/project-home-page.tsx +18 -23
  290. package/src/features/projects/pages/projects-page.test.tsx +4 -1
  291. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +3 -3
  292. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +8 -3
  293. package/src/features/right-panel-resources/components/__tests__/page-resource-icon.test.tsx +13 -2
  294. package/src/features/right-panel-resources/components/__tests__/system-object-resource.test.tsx +74 -6
  295. package/src/features/right-panel-resources/components/native-object-resource.tsx +134 -0
  296. package/src/features/right-panel-resources/components/page-resource-icon.tsx +16 -8
  297. package/src/features/right-panel-resources/components/system-object-resource.tsx +66 -1
  298. package/src/features/right-panel-resources/components/workspace-file-resource.tsx +9 -0
  299. package/src/features/right-panel-resources/configs/right-panel-resource-routes.config.ts +11 -21
  300. package/src/features/right-panel-resources/index.ts +3 -0
  301. package/src/features/right-panel-resources/managers/__tests__/page-resource.manager.test.ts +14 -4
  302. package/src/features/right-panel-resources/managers/page-resource.manager.ts +38 -21
  303. package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-route-resolver.utils.test.ts +17 -0
  304. package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +3 -2
  305. package/src/features/service-apps/components/service-action-row.tsx +4 -3
  306. package/src/features/service-apps/components/service-app-delete-dialog.tsx +2 -2
  307. package/src/features/service-apps/components/service-app-list-item.tsx +5 -4
  308. package/src/features/service-apps/components/service-apps-panel.tsx +5 -2
  309. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +1 -1
  310. package/src/features/settings/pages/providers-config-page.tsx +3 -2
  311. package/src/index.css +42 -8
  312. package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +16 -0
  313. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +2 -2
  314. package/src/shared/components/doc-browser/__tests__/resource-link-interceptor.test.tsx +29 -1
  315. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +2 -2
  316. package/src/shared/components/doc-browser/stores/doc-browser.store.ts +13 -7
  317. package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +2 -1
  318. package/src/shared/components/path-picker/server-path-picker-dialog.tsx +5 -3
  319. package/src/shared/components/ui/__tests__/dialog.test.tsx +37 -1
  320. package/src/shared/components/ui/actions/action-feedback.ts +1 -8
  321. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  322. package/src/shared/components/ui/confirm-dialog.tsx +1 -2
  323. package/src/shared/components/ui/context-menu/context-menu-items.tsx +2 -2
  324. package/src/shared/components/ui/dialog.tsx +29 -7
  325. package/src/shared/components/ui/popover.tsx +14 -3
  326. package/src/shared/components/ui/skeleton.tsx +16 -2
  327. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -2
  328. package/src/shared/components/ui/tooltip.tsx +2 -1
  329. package/src/shared/components/workbench/__tests__/workbench-surface.test.tsx +21 -0
  330. package/src/shared/components/workbench/workbench-surface-toolbar.tsx +4 -0
  331. package/src/shared/components/workbench/workbench-surface.tsx +4 -1
  332. package/src/shared/lib/i18n/locales/en-US/chat.json +21 -7
  333. package/src/shared/lib/i18n/locales/en-US/core.json +5 -1
  334. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +10 -5
  335. package/src/shared/lib/i18n/locales/en-US/inbox.json +1 -0
  336. package/src/shared/lib/i18n/locales/zh-CN/chat.json +21 -7
  337. package/src/shared/lib/i18n/locales/zh-CN/core.json +5 -1
  338. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +11 -6
  339. package/src/shared/lib/i18n/locales/zh-CN/inbox.json +1 -0
  340. package/src/shared/lib/theme/index.test.ts +28 -1
  341. package/src/shared/lib/theme/index.ts +14 -3
  342. package/src/shared/lib/transport/__tests__/local-transport.service.test.ts +24 -0
  343. package/src/shared/lib/transport/local-transport.service.ts +8 -6
  344. package/dist/assets/account-panel-BAH7FW6z.js +0 -1
  345. package/dist/assets/api-DjiZvIa0.js +0 -20
  346. package/dist/assets/app-presenter-provider-CCRFsFYr.js +0 -232
  347. package/dist/assets/appearance-settings-page-CdP86QJ7.js +0 -1
  348. package/dist/assets/architecture-TIHT7OUA-CvnC-LeA.js +0 -1
  349. package/dist/assets/channel-CpMstUPF.js +0 -1
  350. package/dist/assets/channels-list-page-5qGagKuE.js +0 -8
  351. package/dist/assets/chunk-2Q5K7J3B-Djp3VF0s.js +0 -1
  352. package/dist/assets/chunk-VAUOI2AC-BrbiIC1Q.js +0 -1
  353. package/dist/assets/chunk-XXDRQBXY-Cx9N40wF.js +0 -1
  354. package/dist/assets/classDiagram-OUVF2IWQ-DFN1v3PQ.js +0 -1
  355. package/dist/assets/classDiagram-v2-EOCWNBFH-DRvglADa.js +0 -1
  356. package/dist/assets/config-split-page-CuEGQL8Z.js +0 -1
  357. package/dist/assets/confirm-dialog-CxfecBzO.js +0 -1
  358. package/dist/assets/context-menu-BsCj2fRs.js +0 -1
  359. package/dist/assets/cynefin-VYW2F7L2-DXUGnpJH.js +0 -1
  360. package/dist/assets/desktop-update-config-e-zhkJuS.js +0 -1
  361. package/dist/assets/dialog-QjQoKbIV.js +0 -5
  362. package/dist/assets/doc-browser-CLEdkH9z.js +0 -1
  363. package/dist/assets/doc-browser-context-DwgG6wrz.js +0 -1
  364. package/dist/assets/es2015-Bp6cuSGh.js +0 -41
  365. package/dist/assets/eventmodeling-45OFAUF4-ZBfVS3ZC.js +0 -1
  366. package/dist/assets/extensions-CgShSIkd.js +0 -1
  367. package/dist/assets/eye-kisejBFH.js +0 -1
  368. package/dist/assets/flowDiagram-23GEKE2U-CqdsKk6x.js +0 -1
  369. package/dist/assets/gitGraph-TEB2WS4Q-fHYFd9Es.js +0 -1
  370. package/dist/assets/info-DKCQHKI2-CSaOL_bb.js +0 -1
  371. package/dist/assets/katex-B4FQSo9k.js +0 -1
  372. package/dist/assets/keyboard-shortcuts-settings-page-DZ8A1iLg.js +0 -1
  373. package/dist/assets/loader-circle-Bd1fTm-x.js +0 -1
  374. package/dist/assets/login-page-D99JjH9F.js +0 -1
  375. package/dist/assets/main-Bt5r6b21.js +0 -2
  376. package/dist/assets/main-DXd_aKJV.css +0 -1
  377. package/dist/assets/main-i18n-catalog.config-D0Ll36J_.js +0 -1
  378. package/dist/assets/mcp-marketplace-page-DUoGfSmY.js +0 -1
  379. package/dist/assets/model-config-page-9NNf-mzK.js +0 -1
  380. package/dist/assets/packet-7NZHBO7P-D-YFTczs.js +0 -1
  381. package/dist/assets/panel-app-BYfQu_TS.js +0 -1
  382. package/dist/assets/panel-app-i18n-catalog.config-Ddf2Kv8A.js +0 -1
  383. package/dist/assets/panelStandalone-BRg7B1EI.css +0 -1
  384. package/dist/assets/panelStandalone-BaUzY8Wy.js +0 -2
  385. package/dist/assets/pie-RZYD4A2V-VEnYu9s5.js +0 -1
  386. package/dist/assets/privacy-settings-page-CVMBFuak.js +0 -1
  387. package/dist/assets/projects-BEsU3box.js +0 -1
  388. package/dist/assets/provider-models-Dm-pmWAA.js +0 -1
  389. package/dist/assets/provider-scoped-model-input-CzrXg4cX.js +0 -1
  390. package/dist/assets/providers-config-page-839uUADZ.js +0 -1
  391. package/dist/assets/puzzle-BGvD2DPZ.js +0 -1
  392. package/dist/assets/pwa-DNNK_8E9.js +0 -1
  393. package/dist/assets/radar-I7S5WNFK-BFNIekC1.js +0 -1
  394. package/dist/assets/railroad-3IZDKUUU-lVqJ3Hak.js +0 -1
  395. package/dist/assets/railroad-abnf-AHOZXSZD-DYaefdFC.js +0 -1
  396. package/dist/assets/railroad-ebnf-EBAXGLYW-CTAk6lVq.js +0 -1
  397. package/dist/assets/railroad-peg-LSFZ7HO6-Cob294tg.js +0 -1
  398. package/dist/assets/remote-B5qIuUbT.js +0 -1
  399. package/dist/assets/runtime-config-page-Bf-4JYxQ.js +0 -1
  400. package/dist/assets/search-config-page-C0qA3j-T.js +0 -1
  401. package/dist/assets/secrets-config-page-DxfZWpnk.js +0 -3
  402. package/dist/assets/security-config-CItfIQZ4.js +0 -1
  403. package/dist/assets/select-CWyjnar7.js +0 -1
  404. package/dist/assets/service-apps-panel-D3SOkRVv.js +0 -1
  405. package/dist/assets/stateDiagram-v2-6OUMAXLB-BrNv-raG.js +0 -1
  406. package/dist/assets/swimlanesDiagram-G3AALYLV-ntcxaPXp.js +0 -8
  407. package/dist/assets/tag-chip-BIuavK2K.js +0 -1
  408. package/dist/assets/theme-provider-CWUz4yO9.js +0 -1
  409. package/dist/assets/trash-2-hAbJh9VZ.js +0 -1
  410. package/dist/assets/treeView-QDETBFTQ-DbFmr-gw.js +0 -1
  411. package/dist/assets/treemap-6X3UGDF4-C8aY96pi.js +0 -1
  412. package/dist/assets/use-config-evzage09.js +0 -1
  413. package/dist/assets/use-viewport-layout-D_9XWGDV.js +0 -1
  414. package/dist/assets/wardley-OPB4EBWU-D8d6DbbJ.js +0 -1
  415. package/dist/assets/x-ChPbNv39.js +0 -1
  416. package/src/features/apps/components/app-marketplace-dialog.tsx +0 -168
  417. /package/dist/assets/{array-BV9OtnO8.js → array-DsNX3jRj.js} +0 -0
  418. /package/dist/assets/{chunk-KEIR6QF5-Cx-8EJ4_.js → chunk-KEIR6QF5-BOAXXeyv.js} +0 -0
  419. /package/dist/assets/{chunk-Y2CYZVJY-Dy1ufvjf.js → chunk-Y2CYZVJY-CHjSjwoV.js} +0 -0
  420. /package/dist/assets/{config-hints-DbmiyTKg.js → config-hints-CaB3I7KP.js} +0 -0
  421. /package/dist/assets/{cytoscape.esm-CSCjuT4Z.js → cytoscape.esm-j4J9a91l.js} +0 -0
  422. /package/dist/assets/{defaultLocale-DWTiNsbT.js → defaultLocale-Bmxjp-V_.js} +0 -0
  423. /package/dist/assets/{dist-BVCSkfWY.js → dist-DwLj1Wg5.js} +0 -0
  424. /package/dist/assets/{graphlib-B1yb1Wl8.js → graphlib-CC0HTn1v.js} +0 -0
  425. /package/dist/assets/{host-capabilities-DuIFVsvM.js → host-capabilities-B107nwS3.js} +0 -0
  426. /package/dist/assets/{init-BF6GH5oe.js → init-Biz9Rus1.js} +0 -0
  427. /package/dist/assets/{jszip.min-D12teKzP.js → jszip.min-DQvBVV_R.js} +0 -0
  428. /package/dist/assets/{katex-CsAM73R9.js → katex-BzT-4KBu.js} +0 -0
  429. /package/dist/assets/{navigation-history-CzErJuPG.js → navigation-history-CCnxsAKR.js} +0 -0
  430. /package/dist/assets/{path-C56XkznJ.js → path-4azsBPZv.js} +0 -0
  431. /package/dist/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  432. /package/dist/assets/{rough.esm-CGfeEbtE.js → rough.esm-w1lBArN6.js} +0 -0
  433. /package/dist/assets/{xlsx-sds5nUpL.js → xlsx--SB9KlFl.js} +0 -0
@@ -5,12 +5,14 @@ import type {
5
5
  UiNcpSessionQueuedInputView,
6
6
  } from '@nextclaw/client-sdk';
7
7
  import type { NcpAgentSendEnvelope, NcpRunHandle } from '@nextclaw/ncp';
8
+ import { NcpHttpSendError } from '@nextclaw/ncp-http-agent-client';
8
9
 
9
10
  import {
10
11
  createChatComposerNodesFromDraft,
11
12
  deriveNcpMessagePartsFromComposer,
12
13
  } from '@/features/chat/features/input/utils/chat-composer-state.utils';
13
14
  import { isNcpChatSendDisabled } from '@/features/chat/features/input/utils/ncp-chat-input-availability.utils';
15
+ import { t } from '@/shared/lib/i18n';
14
16
  import { buildChatRunMetadata } from '@/features/chat/features/session/utils/chat-run-metadata.utils';
15
17
  import { createNcpSessionId } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
16
18
  import type { SessionQueuedInputAttachmentPreview } from '@/features/chat/features/conversation/utils/session-queued-input.utils';
@@ -25,6 +27,7 @@ import {
25
27
  useSessionConversationRecoveryActions,
26
28
  type SessionConversationRecoveryAgent,
27
29
  } from './use-session-conversation-recovery-actions';
30
+ import { useSessionSubmissionRecovery } from './use-session-submission-recovery';
28
31
 
29
32
  type SessionConversationInputQuery = ReturnType<typeof useSessionConversationInputQuery>;
30
33
  type ComposerDraftSnapshot = Pick<
@@ -80,8 +83,12 @@ type UseSessionConversationControllerParams = {
80
83
  readonly selectedAgentId: string;
81
84
  readonly sessionKey: string | null;
82
85
  readonly onSessionMaterialized?: (sessionKey: string) => void;
83
- readonly resetComposer: () => void;
84
86
  readonly restoreComposer: (snapshot: ComposerDraftSnapshot) => void;
87
+ readonly beginSubmission: (envelope: NcpAgentSendEnvelope, composer: ComposerDraftSnapshot) => void;
88
+ readonly acceptSubmission: (messageId: string) => void;
89
+ readonly failSubmission: (messageId: string, status: 'uncertain' | 'rejected', message: string) => void;
90
+ readonly restoreSubmission: (messageId: string) => void;
91
+ readonly discardSubmission: (messageId: string) => void;
85
92
  readonly setSendError: (message: string | null) => void;
86
93
  };
87
94
 
@@ -90,7 +97,6 @@ type BuildSubmissionDraftParams = {
90
97
  readonly composerSnapshot?: ComposerDraftSnapshot;
91
98
  readonly inputSnapshot: SessionConversationInputSnapshot;
92
99
  readonly inputQuery: SessionConversationInputQuery;
93
- readonly isRuntimeBlocked: boolean;
94
100
  readonly materializationContext?: SessionConversationMaterializationContext | null;
95
101
  readonly selectedAgentId: string;
96
102
  readonly sessionKey: string | null;
@@ -111,21 +117,12 @@ const resolveModelForSend = (value: string | null | undefined): string | undefin
111
117
  return trimmed || undefined;
112
118
  };
113
119
 
114
- function buildInputAvailabilitySnapshot(inputQuery: SessionConversationInputQuery) {
115
- return {
116
- isProviderStateResolved: inputQuery.isProviderStateResolved,
117
- modelOptions: inputQuery.modelOptions,
118
- sessionTypeUnavailable: inputQuery.sessionTypeState.sessionTypeUnavailable,
119
- };
120
- }
121
-
122
120
  function buildSubmissionDraft(params: BuildSubmissionDraftParams): SubmissionDraft | null {
123
121
  const {
124
122
  agentIsSending,
125
123
  composerSnapshot: requestedComposerSnapshot,
126
124
  inputQuery,
127
125
  inputSnapshot,
128
- isRuntimeBlocked,
129
126
  materializationContext,
130
127
  selectedAgentId,
131
128
  sessionKey,
@@ -142,10 +139,9 @@ function buildSubmissionDraft(params: BuildSubmissionDraftParams): SubmissionDra
142
139
  composerSnapshot.attachments,
143
140
  );
144
141
  if (
142
+ inputSnapshot.pendingSubmission ||
145
143
  isNcpChatSendDisabled({
146
- snapshot: buildInputAvailabilitySnapshot(inputQuery),
147
144
  hasSendableDraft: hasSendableMessagePart(currentParts),
148
- isRuntimeBlocked,
149
145
  }) ||
150
146
  agentIsSending
151
147
  ) {
@@ -197,6 +193,7 @@ function buildSubmissionEnvelope(
197
193
  ): NcpAgentSendEnvelope | null {
198
194
  const envelope = buildNcpRequestEnvelope({
199
195
  sessionId: sessionKey ?? undefined,
196
+ messageId: `user-${crypto.randomUUID()}`,
200
197
  text: draft.composerSnapshot.text.trim(),
201
198
  attachments: [...draft.composerSnapshot.attachments],
202
199
  parts: deriveNcpMessagePartsFromComposer(
@@ -205,7 +202,7 @@ function buildSubmissionEnvelope(
205
202
  ),
206
203
  metadata: draft.metadata,
207
204
  });
208
- return envelope ? { ...envelope, delivery } : null;
205
+ return envelope ? { ...envelope, delivery, idempotencyKey: envelope.message.id } : null;
209
206
  }
210
207
 
211
208
  function useSubmissionDraftRunner(params: {
@@ -213,8 +210,9 @@ function useSubmissionDraftRunner(params: {
213
210
  readonly clearSubmittingInput: (input: SubmittingQueuedInput) => void;
214
211
  readonly materializationContext?: SessionConversationMaterializationContext | null;
215
212
  readonly onSessionMaterialized?: (sessionKey: string) => void;
216
- readonly resetComposer: () => void;
217
- readonly restoreComposer: (snapshot: ComposerDraftSnapshot) => void;
213
+ readonly beginSubmission: (envelope: NcpAgentSendEnvelope, composer: ComposerDraftSnapshot) => void;
214
+ readonly acceptSubmission: (messageId: string) => void;
215
+ readonly failSubmission: (messageId: string, status: 'uncertain' | 'rejected', message: string) => void;
218
216
  readonly runQueue: SessionRunQueue;
219
217
  readonly sessionKey: string | null;
220
218
  readonly setSendError: (message: string | null) => void;
@@ -225,8 +223,9 @@ function useSubmissionDraftRunner(params: {
225
223
  clearSubmittingInput,
226
224
  materializationContext,
227
225
  onSessionMaterialized,
228
- resetComposer,
229
- restoreComposer,
226
+ beginSubmission,
227
+ acceptSubmission,
228
+ failSubmission,
230
229
  runQueue,
231
230
  sessionKey,
232
231
  setSendError,
@@ -244,10 +243,16 @@ function useSubmissionDraftRunner(params: {
244
243
  const queuedSubmission = agent.isRunning && delivery === 'queue'
245
244
  ? stageSubmittingInput(envelope)
246
245
  : null;
247
- if (composerBehavior === 'reset-and-restore') resetComposer();
246
+ if (composerBehavior === 'reset-and-restore') beginSubmission(envelope, draft.composerSnapshot);
248
247
  setSendError(null);
248
+ let definitelyRejected = false;
249
249
  try {
250
250
  const handle = await agent.send(envelope);
251
+ if (!handle) {
252
+ definitelyRejected = true;
253
+ throw new Error(t('chatSendFailed'));
254
+ }
255
+ if (composerBehavior === 'reset-and-restore') acceptSubmission(envelope.message.id);
251
256
  if (handle?.delivery === 'steered') {
252
257
  await runQueue.refreshPendingInputs().catch(() => undefined);
253
258
  } else if (handle?.delivery === 'queued') {
@@ -261,8 +266,12 @@ function useSubmissionDraftRunner(params: {
261
266
  }
262
267
  } catch (error) {
263
268
  if (queuedSubmission) clearSubmittingInput(queuedSubmission);
264
- if (composerBehavior === 'reset-and-restore') restoreComposer(draft.composerSnapshot);
265
- setSendError(error instanceof Error ? error.message : String(error));
269
+ const message = error instanceof Error ? error.message : String(error);
270
+ if (composerBehavior === 'reset-and-restore') {
271
+ failSubmission(envelope.message.id,
272
+ definitelyRejected || (error instanceof NcpHttpSendError && error.sendRejected) ? 'rejected' : 'uncertain',
273
+ message);
274
+ } else setSendError(message);
266
275
  throw error;
267
276
  }
268
277
  }, [
@@ -270,8 +279,9 @@ function useSubmissionDraftRunner(params: {
270
279
  clearSubmittingInput,
271
280
  materializationContext,
272
281
  onSessionMaterialized,
273
- resetComposer,
274
- restoreComposer,
282
+ beginSubmission,
283
+ acceptSubmission,
284
+ failSubmission,
275
285
  runQueue,
276
286
  sessionKey,
277
287
  setSendError,
@@ -283,7 +293,6 @@ function useSteeringSubmission(params: {
283
293
  readonly agent: SessionConversationAgent;
284
294
  readonly inputSnapshot: SessionConversationInputSnapshot;
285
295
  readonly inputQuery: SessionConversationInputQuery;
286
- readonly isRuntimeBlocked: boolean;
287
296
  readonly materializationContext?: SessionConversationMaterializationContext | null;
288
297
  readonly selectedAgentId: string;
289
298
  readonly sessionKey: string | null;
@@ -297,7 +306,6 @@ function useSteeringSubmission(params: {
297
306
  agent,
298
307
  inputQuery,
299
308
  inputSnapshot,
300
- isRuntimeBlocked,
301
309
  materializationContext,
302
310
  selectedAgentId,
303
311
  sessionKey,
@@ -308,7 +316,6 @@ function useSteeringSubmission(params: {
308
316
  agentIsSending: agent.isSending,
309
317
  inputSnapshot,
310
318
  inputQuery,
311
- isRuntimeBlocked,
312
319
  materializationContext,
313
320
  selectedAgentId,
314
321
  sessionKey,
@@ -318,7 +325,6 @@ function useSteeringSubmission(params: {
318
325
  agent.isSending,
319
326
  inputQuery,
320
327
  inputSnapshot,
321
- isRuntimeBlocked,
322
328
  materializationContext,
323
329
  selectedAgentId,
324
330
  sessionKey,
@@ -331,7 +337,6 @@ function usePrimarySubmission(params: {
331
337
  readonly continueRun: () => Promise<void>;
332
338
  readonly inputSnapshot: SessionConversationInputSnapshot;
333
339
  readonly inputQuery: SessionConversationInputQuery;
334
- readonly isRuntimeBlocked: boolean;
335
340
  readonly materializationContext?: SessionConversationMaterializationContext | null;
336
341
  readonly primaryAction: 'continue' | 'send';
337
342
  readonly selectedAgentId: string;
@@ -346,7 +351,6 @@ function usePrimarySubmission(params: {
346
351
  continueRun,
347
352
  inputQuery,
348
353
  inputSnapshot,
349
- isRuntimeBlocked,
350
354
  materializationContext,
351
355
  primaryAction,
352
356
  selectedAgentId,
@@ -359,7 +363,6 @@ function usePrimarySubmission(params: {
359
363
  agentIsSending: agent.isSending,
360
364
  inputSnapshot,
361
365
  inputQuery,
362
- isRuntimeBlocked,
363
366
  materializationContext,
364
367
  selectedAgentId,
365
368
  sessionKey,
@@ -370,7 +373,6 @@ function usePrimarySubmission(params: {
370
373
  continueRun,
371
374
  inputQuery,
372
375
  inputSnapshot,
373
- isRuntimeBlocked,
374
376
  materializationContext,
375
377
  primaryAction,
376
378
  selectedAgentId,
@@ -379,6 +381,32 @@ function usePrimarySubmission(params: {
379
381
  ]);
380
382
  }
381
383
 
384
+ function usePresetSubmission(params: {
385
+ readonly agent: SessionConversationAgent;
386
+ readonly inputSnapshot: SessionConversationInputSnapshot;
387
+ readonly inputQuery: SessionConversationInputQuery;
388
+ readonly materializationContext?: SessionConversationMaterializationContext | null;
389
+ readonly selectedAgentId: string;
390
+ readonly sessionKey: string | null;
391
+ readonly submitDraft: (draft: SubmissionDraft, behavior: SubmissionComposerBehavior) => Promise<void>;
392
+ }) {
393
+ const { agent, inputSnapshot, inputQuery, materializationContext, selectedAgentId, sessionKey, submitDraft } = params;
394
+ return useCallback(async (message: string) => {
395
+ const text = message.trim();
396
+ if (!text) return;
397
+ const draft = buildSubmissionDraft({
398
+ agentIsSending: agent.isSending,
399
+ composerSnapshot: {
400
+ text,
401
+ nodes: createChatComposerNodesFromDraft(text),
402
+ selectedSkills: [], skillRecords: [], attachments: [],
403
+ },
404
+ inputSnapshot, inputQuery, materializationContext, selectedAgentId, sessionKey,
405
+ });
406
+ if (draft) await submitDraft(draft, 'preserve');
407
+ }, [agent.isSending, inputQuery, inputSnapshot, materializationContext, selectedAgentId, sessionKey, submitDraft]);
408
+ }
409
+
382
410
  export function useSessionConversationController(params: UseSessionConversationControllerParams) {
383
411
  const {
384
412
  agent,
@@ -390,8 +418,12 @@ export function useSessionConversationController(params: UseSessionConversationC
390
418
  selectedAgentId,
391
419
  sessionKey,
392
420
  onSessionMaterialized,
393
- resetComposer,
394
421
  restoreComposer,
422
+ beginSubmission,
423
+ acceptSubmission,
424
+ failSubmission,
425
+ restoreSubmission,
426
+ discardSubmission,
395
427
  setSendError,
396
428
  } = params;
397
429
  const {
@@ -421,12 +453,10 @@ export function useSessionConversationController(params: UseSessionConversationC
421
453
  );
422
454
  const primaryAction: 'continue' | 'send' =
423
455
  canContinue && !hasSendableDraft ? 'continue' : 'send';
424
- const sendDisabled = primaryAction === 'continue'
456
+ const sendDisabled = inputSnapshot.pendingSubmission ? true : primaryAction === 'continue'
425
457
  ? false
426
458
  : isNcpChatSendDisabled({
427
- snapshot: buildInputAvailabilitySnapshot(inputQuery),
428
459
  hasSendableDraft,
429
- isRuntimeBlocked,
430
460
  }) || agent.isSending;
431
461
 
432
462
  const { continueRun, editMessage } = useSessionConversationRecoveryActions({
@@ -440,8 +470,9 @@ export function useSessionConversationController(params: UseSessionConversationC
440
470
  clearSubmittingInput,
441
471
  materializationContext,
442
472
  onSessionMaterialized,
443
- resetComposer,
444
- restoreComposer,
473
+ beginSubmission,
474
+ acceptSubmission,
475
+ failSubmission,
445
476
  runQueue,
446
477
  sessionKey,
447
478
  setSendError,
@@ -453,7 +484,6 @@ export function useSessionConversationController(params: UseSessionConversationC
453
484
  continueRun,
454
485
  inputQuery,
455
486
  inputSnapshot,
456
- isRuntimeBlocked,
457
487
  materializationContext,
458
488
  primaryAction,
459
489
  selectedAgentId,
@@ -465,52 +495,33 @@ export function useSessionConversationController(params: UseSessionConversationC
465
495
  agent,
466
496
  inputQuery,
467
497
  inputSnapshot,
468
- isRuntimeBlocked,
469
498
  materializationContext,
470
499
  selectedAgentId,
471
500
  sessionKey,
472
501
  submitDraft,
473
502
  });
474
503
 
475
- const sendPresetMessage = useCallback(async (message: string) => {
476
- const text = message.trim();
477
- if (!text) {
478
- return;
479
- }
480
- const draft = buildSubmissionDraft({
481
- agentIsSending: agent.isSending,
482
- composerSnapshot: {
483
- text,
484
- nodes: createChatComposerNodesFromDraft(text),
485
- selectedSkills: [],
486
- skillRecords: [],
487
- attachments: [],
488
- },
489
- inputSnapshot,
490
- inputQuery,
491
- isRuntimeBlocked,
492
- materializationContext,
493
- selectedAgentId,
494
- sessionKey,
495
- });
496
- if (draft) {
497
- await submitDraft(draft, 'preserve');
498
- }
499
- }, [
500
- agent.isSending,
501
- inputQuery,
502
- inputSnapshot,
503
- isRuntimeBlocked,
504
- materializationContext,
505
- selectedAgentId,
506
- sessionKey,
507
- submitDraft,
508
- ]);
504
+ const sendPresetMessage = usePresetSubmission({
505
+ agent, inputSnapshot, inputQuery, materializationContext,
506
+ selectedAgentId, sessionKey, submitDraft,
507
+ });
509
508
 
510
509
  const stop = useCallback(async () => {
511
510
  await agent.abort();
512
511
  }, [agent]);
513
512
 
513
+ const submissionRecovery = useSessionSubmissionRecovery({
514
+ agent,
515
+ submission: inputSnapshot.pendingSubmission,
516
+ sessionKey,
517
+ onSessionMaterialized,
518
+ acceptSubmission,
519
+ failSubmission,
520
+ restoreSubmission,
521
+ discardSubmission,
522
+ setSendError,
523
+ });
524
+
514
525
  return {
515
526
  canContinue,
516
527
  canStopGeneration: agent.isRunning,
@@ -525,6 +536,7 @@ export function useSessionConversationController(params: UseSessionConversationC
525
536
  send,
526
537
  sendSteering,
527
538
  sendPresetMessage,
539
+ ...submissionRecovery,
528
540
  sendDisabled,
529
541
  primaryAction,
530
542
  stop,
@@ -12,7 +12,7 @@ import {
12
12
  filterNcpChatModelOptionsBySessionType,
13
13
  } from '@/features/chat/features/ncp/utils/ncp-chat-query-derived.utils';
14
14
  import { adaptNcpSessionSummaries } from '@/features/chat/features/session/utils/ncp-session-adapter.utils';
15
- import { resolveRecentSessionPreferredValue } from '@/features/chat/features/session/utils/chat-session-preference-governance.utils';
15
+ import { resolveRecentSessionPreferenceSnapshot } from '@/features/chat/features/session/utils/chat-session-preference-governance.utils';
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';
@@ -112,27 +112,17 @@ export function useSessionConversationInputQuery(params: UseSessionConversationI
112
112
  const recentSessionTypeModel = chatRecentModelsManager
113
113
  .read({ namespace: sessionTypeState.selectedSessionType })
114
114
  .find((value) => availableModelValueSet.has(value));
115
- const fallbackPreferredModel = useMemo(
115
+ const recentSessionPreferences = useMemo(
116
116
  () =>
117
- recentSessionTypeModel ??
118
- resolveRecentSessionPreferredValue<string>({
117
+ resolveRecentSessionPreferenceSnapshot({
119
118
  sessions,
120
119
  selectedSessionKey,
121
120
  sessionType: sessionTypeState.selectedSessionType,
122
- readPreference: (session) => session.preferredModel?.trim() || undefined,
123
- }),
124
- [recentSessionTypeModel, selectedSessionKey, sessionTypeState.selectedSessionType, sessions],
125
- );
126
- const fallbackPreferredThinking = useMemo(
127
- () =>
128
- resolveRecentSessionPreferredValue({
129
- sessions,
130
- selectedSessionKey,
131
- sessionType: sessionTypeState.selectedSessionType,
132
- readPreference: (session) => session.preferredThinking ?? undefined,
133
121
  }),
134
122
  [selectedSessionKey, sessionTypeState.selectedSessionType, sessions],
135
123
  );
124
+ const fallbackPreferredModel = recentSessionPreferences?.model ?? recentSessionTypeModel;
125
+ const fallbackPreferredThinking = recentSessionPreferences?.thinking;
136
126
 
137
127
  const defaultProjectRoot = normalizeSessionProjectRootValue(
138
128
  config?.agents.defaults.workspace,
@@ -1,6 +1,7 @@
1
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
+ import type { NcpAgentSendEnvelope } from '@nextclaw/ncp';
4
5
 
5
6
  import type { ThinkingLevel } from '@/shared/lib/api';
6
7
  import { DEFAULT_SESSION_TYPE } from '@/features/chat/features/session-type/utils/chat-session-type.utils';
@@ -10,6 +11,7 @@ import {
10
11
  resolveChatComposerDraftKey,
11
12
  useChatComposerDraftStore,
12
13
  type ChatComposerDraftSnapshot,
14
+ type ChatComposerSubmission,
13
15
  } from '@/features/chat/stores/chat-composer-draft.store';
14
16
  import {
15
17
  useSessionConversationPreferenceActions,
@@ -38,6 +40,7 @@ export type SessionConversationInputSnapshot = SessionConversationComposerState
38
40
  readonly pendingProjectRoot: string | null;
39
41
  readonly composerFocusRequestId: number;
40
42
  readonly sendError: string | null;
43
+ readonly pendingSubmission?: ChatComposerSubmission | null;
41
44
  };
42
45
 
43
46
  type SessionConversationOwnedInputSnapshot = ChatComposerDraftSnapshot;
@@ -49,7 +52,11 @@ export type SessionConversationInputPatch =
49
52
  export type SessionConversationInputActions = {
50
53
  readonly update: (patch: SessionConversationInputPatch) => void;
51
54
  readonly syncComposer: (composer: SessionConversationComposerState) => void;
52
- readonly resetComposer: () => void;
55
+ readonly beginSubmission: (envelope: NcpAgentSendEnvelope, composer: ChatComposerSubmission['composer']) => void;
56
+ readonly acceptSubmission: (messageId: string) => void;
57
+ readonly failSubmission: (messageId: string, status: 'uncertain' | 'rejected', message: string) => void;
58
+ readonly restoreSubmission: (messageId: string) => void;
59
+ readonly discardSubmission: (messageId: string) => void;
53
60
  readonly restoreComposer: (
54
61
  composer: SessionConversationComposerState & {
55
62
  readonly attachments?: readonly NcpDraftAttachment[];
@@ -176,6 +183,7 @@ function usePersistedConversationInputSnapshot(
176
183
  const snapshot = useChatComposerDraftStore(
177
184
  (state) => state.drafts[draftKey] ?? initialSnapshot,
178
185
  );
186
+ const pendingSubmission = useChatComposerDraftStore((state) => state.submissions[draftKey] ?? null);
179
187
 
180
188
  useEffect(() => {
181
189
  useChatComposerDraftStore.getState().ensureDraft(draftKey, initialSnapshot);
@@ -196,7 +204,35 @@ function usePersistedConversationInputSnapshot(
196
204
  });
197
205
  }, [draftKey, initialSnapshot]);
198
206
 
199
- return { draftKey, snapshot, update };
207
+ const beginSubmission = useCallback((
208
+ envelope: NcpAgentSendEnvelope,
209
+ composer: ChatComposerSubmission['composer'],
210
+ ) => {
211
+ useChatComposerDraftStore.getState().beginSubmission(draftKey, snapshot, {
212
+ envelope, composer, status: 'sending',
213
+ });
214
+ }, [draftKey, snapshot]);
215
+ const acceptSubmission = useCallback((messageId: string) => {
216
+ useChatComposerDraftStore.getState().acceptSubmission(draftKey, messageId);
217
+ }, [draftKey]);
218
+ const failSubmission = useCallback((
219
+ messageId: string,
220
+ status: 'uncertain' | 'rejected',
221
+ message: string,
222
+ ) => {
223
+ useChatComposerDraftStore.getState().failSubmission(draftKey, messageId, status, message);
224
+ }, [draftKey]);
225
+ const restoreSubmission = useCallback((messageId: string) => {
226
+ useChatComposerDraftStore.getState().restoreSubmission(draftKey, messageId);
227
+ }, [draftKey]);
228
+ const discardSubmission = useCallback((messageId: string) => {
229
+ useChatComposerDraftStore.getState().discardSubmission(draftKey, messageId);
230
+ }, [draftKey]);
231
+
232
+ return {
233
+ draftKey, snapshot, pendingSubmission, update,
234
+ beginSubmission, acceptSubmission, failSubmission, restoreSubmission, discardSubmission,
235
+ };
200
236
  }
201
237
 
202
238
  export const useSessionConversationInputState = (
@@ -204,7 +240,10 @@ export const useSessionConversationInputState = (
204
240
  sessionKey: string | null = null,
205
241
  ) => {
206
242
  const pendingProjectRoot = useChatThreadStore((state) => state.snapshot.draftProjectRoot);
207
- const { draftKey, snapshot, update } = usePersistedConversationInputSnapshot(
243
+ const {
244
+ draftKey, snapshot, pendingSubmission, update,
245
+ beginSubmission, acceptSubmission, failSubmission, restoreSubmission, discardSubmission,
246
+ } = usePersistedConversationInputSnapshot(
208
247
  initialPrompt,
209
248
  sessionKey,
210
249
  );
@@ -219,14 +258,6 @@ export const useSessionConversationInputState = (
219
258
  });
220
259
  }, [update]);
221
260
 
222
- const resetComposer = useCallback(() => {
223
- update({
224
- ...EMPTY_COMPOSER_STATE,
225
- attachments: [],
226
- sendError: null,
227
- });
228
- }, [update]);
229
-
230
261
  const restoreComposer = useCallback((
231
262
  composer: SessionConversationComposerState & {
232
263
  readonly attachments?: readonly NcpDraftAttachment[];
@@ -309,7 +340,11 @@ export const useSessionConversationInputState = (
309
340
  const actions = useMemo<SessionConversationInputActions>(() => ({
310
341
  update,
311
342
  syncComposer,
312
- resetComposer,
343
+ beginSubmission,
344
+ acceptSubmission,
345
+ failSubmission,
346
+ restoreSubmission,
347
+ discardSubmission,
313
348
  restoreComposer,
314
349
  applyPromptSuggestion,
315
350
  requestComposerFocusAtEnd,
@@ -325,7 +360,11 @@ export const useSessionConversationInputState = (
325
360
  }), [
326
361
  update,
327
362
  syncComposer,
328
- resetComposer,
363
+ beginSubmission,
364
+ acceptSubmission,
365
+ failSubmission,
366
+ restoreSubmission,
367
+ discardSubmission,
329
368
  restoreComposer,
330
369
  applyPromptSuggestion,
331
370
  requestComposerFocusAtEnd,
@@ -344,6 +383,7 @@ export const useSessionConversationInputState = (
344
383
  inputSnapshot: {
345
384
  ...snapshot,
346
385
  pendingProjectRoot,
386
+ pendingSubmission,
347
387
  },
348
388
  inputActions: actions,
349
389
  };
@@ -0,0 +1,83 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ import type { NcpAgentSendEnvelope, NcpRunHandle } from '@nextclaw/ncp';
3
+ import { NcpHttpSendError } from '@nextclaw/ncp-http-agent-client';
4
+ import { fetchNcpSessionMessages } from '@/shared/lib/api';
5
+ import { t } from '@/shared/lib/i18n';
6
+ import type { ChatComposerSubmission } from '@/features/chat/stores/chat-composer-draft.store';
7
+
8
+ async function hasAcceptedSubmission(submission: ChatComposerSubmission): Promise<boolean> {
9
+ const sessionId = submission.envelope.sessionId?.trim();
10
+ if (!sessionId) return false;
11
+ try {
12
+ const response = await fetchNcpSessionMessages(sessionId, { limit: 100 });
13
+ return response.messages.some((message) => message.id === submission.envelope.message.id);
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ export function useSessionSubmissionRecovery(params: {
20
+ readonly agent: { send: (envelope: NcpAgentSendEnvelope) => Promise<NcpRunHandle | null> };
21
+ readonly submission?: ChatComposerSubmission | null;
22
+ readonly sessionKey: string | null;
23
+ readonly onSessionMaterialized?: (sessionKey: string) => void;
24
+ readonly acceptSubmission: (messageId: string) => void;
25
+ readonly failSubmission: (messageId: string, status: 'uncertain' | 'rejected', message: string) => void;
26
+ readonly restoreSubmission: (messageId: string) => void;
27
+ readonly discardSubmission: (messageId: string) => void;
28
+ readonly setSendError: (message: string | null) => void;
29
+ }) {
30
+ const {
31
+ agent, submission, sessionKey, onSessionMaterialized,
32
+ acceptSubmission, failSubmission, restoreSubmission, discardSubmission, setSendError,
33
+ } = params;
34
+ const retryPendingSubmission = useCallback(async () => {
35
+ if (!submission || submission.status !== 'uncertain') return;
36
+ const { envelope } = submission;
37
+ if (await hasAcceptedSubmission(submission)) {
38
+ acceptSubmission(envelope.message.id);
39
+ if (!sessionKey && envelope.sessionId) onSessionMaterialized?.(envelope.sessionId);
40
+ return;
41
+ }
42
+ if (!envelope.sessionId) {
43
+ setSendError(t('chatSendResultUnknownChild'));
44
+ return;
45
+ }
46
+ try {
47
+ const handle = await agent.send(envelope);
48
+ if (!handle) throw new Error(t('chatSendFailed'));
49
+ acceptSubmission(envelope.message.id);
50
+ if (!sessionKey) onSessionMaterialized?.(handle.sessionId);
51
+ } catch (error) {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ failSubmission(envelope.message.id,
54
+ error instanceof NcpHttpSendError && error.sendRejected ? 'rejected' : 'uncertain',
55
+ message);
56
+ }
57
+ }, [acceptSubmission, agent, failSubmission, onSessionMaterialized, sessionKey, setSendError, submission]);
58
+
59
+ const checkedSubmissionRef = useRef<string | null>(null);
60
+ useEffect(() => {
61
+ if (!submission || submission.status !== 'uncertain' ||
62
+ checkedSubmissionRef.current === submission.envelope.message.id) return;
63
+ checkedSubmissionRef.current = submission.envelope.message.id;
64
+ void hasAcceptedSubmission(submission).then((accepted) => {
65
+ if (accepted) {
66
+ acceptSubmission(submission.envelope.message.id);
67
+ if (!sessionKey && submission.envelope.sessionId) {
68
+ onSessionMaterialized?.(submission.envelope.sessionId);
69
+ }
70
+ }
71
+ });
72
+ }, [acceptSubmission, onSessionMaterialized, sessionKey, submission]);
73
+
74
+ return {
75
+ retryPendingSubmission,
76
+ restorePendingSubmission: () => {
77
+ if (submission) restoreSubmission(submission.envelope.message.id);
78
+ },
79
+ discardPendingSubmission: () => {
80
+ if (submission?.status === 'rejected') discardSubmission(submission.envelope.message.id);
81
+ },
82
+ };
83
+ }
@@ -0,0 +1,38 @@
1
+ import type { ChatContextWindowIndicator } from '@nextclaw/agent-chat-ui';
2
+ import type { SessionConversationQueuedInput } from '@/features/chat/features/conversation/hooks/use-session-conversation-controller';
3
+ import type { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
4
+ import type {
5
+ SessionConversationInputActions,
6
+ SessionConversationInputSnapshot,
7
+ } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-state';
8
+
9
+ export type SessionConversationInputController = {
10
+ readonly canEditQueuedInput: boolean;
11
+ readonly canStopGeneration: boolean;
12
+ readonly deleteQueuedInput: (id: string) => void;
13
+ readonly editQueuedInput: (id: string) => void;
14
+ readonly isSending: boolean;
15
+ readonly queuedInputs: readonly SessionConversationQueuedInput[];
16
+ readonly primaryAction: 'continue' | 'send';
17
+ readonly sendDisabled: boolean;
18
+ readonly stopDisabled: boolean;
19
+ readonly send: () => Promise<void> | void;
20
+ readonly sendSteering: () => Promise<void> | void;
21
+ readonly sendPresetMessage: (message: string) => Promise<void> | void;
22
+ readonly retryPendingSubmission: () => Promise<void> | void;
23
+ readonly restorePendingSubmission: () => void;
24
+ readonly discardPendingSubmission: () => void;
25
+ readonly stop: () => Promise<void> | void;
26
+ readonly steerQueuedInput: (id: string) => void;
27
+ };
28
+
29
+ export type SessionConversationInputProps = {
30
+ readonly contextWindow: ChatContextWindowIndicator | null;
31
+ readonly controller: SessionConversationInputController;
32
+ readonly inputActions: SessionConversationInputActions;
33
+ readonly inputQuery: ReturnType<typeof useSessionConversationInputQuery>;
34
+ readonly inputSnapshot: SessionConversationInputSnapshot;
35
+ readonly onContextCompactingChange?: (sessionId: string, isCompacting: boolean) => void;
36
+ readonly placeholder?: string;
37
+ readonly surface?: 'default' | 'embedded';
38
+ };