@nextclaw/ui 0.15.22 → 0.15.24

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 (428) hide show
  1. package/CHANGELOG.md +66 -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-BxPNDp30.js +13 -0
  5. package/dist/assets/appearance-settings-page-DpVJjvkB.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-DRaNWAxC.js +8 -0
  13. package/dist/assets/chat-page-BuFDmG5_.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-BVWVDbvG.js +1 -0
  55. package/dist/assets/confirm-dialog-mA2iVzxh.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-DyQb1LXr.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-B4Pf5X3Q.js +1 -0
  68. package/dist/assets/dist-DHEWkGWX.js +1 -0
  69. package/dist/assets/doc-browser-CtO_HtRy.js +1 -0
  70. package/dist/assets/doc-browser-context-CuGI6PQc.js +1 -0
  71. package/dist/assets/doc-browser-eMUagyBV.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-BOfIyG3O.js +1 -0
  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-BjBdWHV1.js +107 -0
  83. package/dist/assets/index-DmpmjAGQ.css +1 -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-Df8wF2Pr.js +1 -0
  92. package/dist/assets/{map-BAAdHTqR.js → map-CcZzEoz6.js} +1 -1
  93. package/dist/assets/mcp-marketplace-page-DI49IKxp.js +1 -0
  94. package/dist/assets/mcp-marketplace-page-ofDqbOIF.js +9 -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-D73Tu3jW.js +1 -0
  99. package/dist/assets/navigation-link-CAFOcXNg.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-DVU5RLCS.js +1 -0
  106. package/dist/assets/provider-scoped-model-input-BaJJJYMX.js +1 -0
  107. package/dist/assets/providers-config-page-BL6IRVBm.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-BC_orpAj.js +8 -0
  116. package/dist/assets/{refresh-cw-CkKwPztT.js → refresh-cw-CWDp_JnN.js} +1 -1
  117. package/dist/assets/remote-T24O58lH.js +1 -0
  118. package/dist/assets/{requirementDiagram-TGXJPOKE-D8YV0-Jz.js → requirementDiagram-TGXJPOKE-CyVUzEX5.js} +1 -1
  119. package/dist/assets/rotate-cw-BqhwSV5p.js +1 -0
  120. package/dist/assets/runtime-config-page-CXUx017t.js +1 -0
  121. package/dist/assets/{sankeyDiagram-HTMAVEWB-C2vA4ojE.js → sankeyDiagram-HTMAVEWB-JK6bFmYB.js} +1 -1
  122. package/dist/assets/{save-BINMWate.js → save-Cnr71JON.js} +1 -1
  123. package/dist/assets/{search-7M38azRp.js → search-CCX11X2m.js} +1 -1
  124. package/dist/assets/search-config-page-BB6d5gT7.js +1 -0
  125. package/dist/assets/{secrets-config-page-2mVejXf2.js → secrets-config-page-DYsDeT9K.js} +2 -2
  126. package/dist/assets/security-config-CVPgqL7G.js +1 -0
  127. package/dist/assets/select-DvwBu99K.js +41 -0
  128. package/dist/assets/{sequenceDiagram-DBY2YBRQ-B9LBmpUo.js → sequenceDiagram-DBY2YBRQ-BR5IokXV.js} +1 -1
  129. package/dist/assets/{settings-2-DqZstREV.js → settings-2-Dmv6zMne.js} +1 -1
  130. package/dist/assets/{sizeCapture-X5ZJPWSS-9UIfya9-.js → sizeCapture-X5ZJPWSS-SxG_YnMA.js} +1 -1
  131. package/dist/assets/skeleton-C5tWata3.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-BoDaLnWt.js → tag-chip-gMPvx7n_.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-D_3-QpZU.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-BEWSqeux.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 +9 -9
  150. package/src/app/components/layout/page-layout.tsx +15 -6
  151. package/src/app/styles/charcoal-theme.css +85 -0
  152. package/src/app/styles/design-system.css +11 -13
  153. package/src/features/agents/components/__tests__/agents-page.test.tsx +36 -24
  154. package/src/features/agents/components/agent-advanced-config-fields.tsx +7 -7
  155. package/src/features/agents/components/agent-details-dialog.tsx +8 -8
  156. package/src/features/agents/components/agent-dialogs.tsx +7 -7
  157. package/src/features/agents/components/agents-page.tsx +42 -62
  158. package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +27 -3
  159. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +16 -0
  160. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +8 -22
  161. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +69 -3
  162. package/src/features/chat/components/conversation/chat-conversation-content.tsx +20 -6
  163. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +30 -31
  164. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -8
  165. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +16 -4
  166. package/src/features/chat/components/layout/__tests__/chat-page-shell.test.tsx +23 -0
  167. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +6 -0
  168. package/src/features/chat/components/layout/chat-page-shell.tsx +5 -4
  169. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +4 -4
  170. package/src/features/chat/components/providers/chat-presenter.provider.tsx +2 -0
  171. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +84 -12
  172. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +243 -5
  173. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +48 -31
  174. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +46 -37
  175. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +128 -1
  176. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +67 -1
  177. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-slash-commands.test.tsx +4 -0
  178. package/src/features/chat/features/conversation/hooks/__tests__/use-session-provider-model-catalog.test.tsx +161 -0
  179. package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +55 -0
  180. package/src/features/chat/features/conversation/hooks/use-session-conversation-composer-nodes.ts +26 -0
  181. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +45 -12
  182. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +28 -3
  183. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +91 -37
  184. package/src/features/chat/features/conversation/hooks/use-session-conversation-recovery-actions.ts +64 -0
  185. package/src/features/chat/features/conversation/hooks/use-session-conversation-slash-commands.ts +2 -0
  186. package/src/features/chat/features/conversation/hooks/use-session-provider-model-catalog.ts +159 -0
  187. package/src/features/chat/features/conversation/utils/__tests__/session-message-composer.utils.test.ts +34 -0
  188. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +23 -1
  189. package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +117 -0
  190. package/src/features/chat/features/conversation/utils/session-queued-input.utils.ts +10 -98
  191. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +2 -1
  192. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +3 -1
  193. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
  194. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +52 -0
  195. package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +111 -0
  196. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +27 -2
  197. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +10 -0
  198. package/src/features/chat/features/input/utils/chat-conversation-excerpt-token.utils.ts +59 -0
  199. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +123 -32
  200. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +1 -0
  201. package/src/features/chat/features/input/utils/chat-input-toolbar.utils.ts +97 -10
  202. package/src/features/chat/features/message/components/__tests__/chat-message-assistant-header.container.test.tsx +149 -0
  203. package/src/features/chat/features/message/components/__tests__/chat-message-inline-editor.test.tsx +59 -0
  204. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +123 -90
  205. package/src/features/chat/features/message/components/__tests__/chat-message-timeline-dividers.test.tsx +43 -0
  206. package/src/features/chat/features/message/components/chat-message-inline-editor.tsx +111 -0
  207. package/src/features/chat/features/message/components/chat-message-list.container.tsx +120 -171
  208. package/src/features/chat/features/message/components/chat-message-timeline-dividers.tsx +75 -0
  209. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +125 -0
  210. package/src/features/chat/features/message/hooks/use-chat-message-actions.tsx +187 -0
  211. package/src/features/chat/features/message/utils/__tests__/chat-message-action-targets.utils.test.ts +89 -0
  212. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-compaction.utils.test.ts +194 -0
  213. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-continuation-compaction.utils.test.ts +167 -0
  214. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +175 -1
  215. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +26 -0
  216. package/src/features/chat/features/message/utils/chat-message-action-targets.utils.ts +28 -0
  217. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +38 -0
  218. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +6 -0
  219. package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +201 -7
  220. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-agent-runtime.test.tsx +180 -1
  221. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +184 -10
  222. package/src/features/chat/features/ncp/hooks/use-hydrated-ncp-agent.integration.test.tsx +57 -0
  223. package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +90 -1
  224. package/src/features/chat/features/ncp/utils/__tests__/ncp-chat-query-derived.utils.test.ts +110 -0
  225. package/src/features/chat/features/ncp/utils/ncp-chat-query-derived.utils.ts +65 -3
  226. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +17 -0
  227. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +63 -54
  228. package/src/features/chat/features/session/hooks/__tests__/use-selected-session-context-window-indicator.test.tsx +87 -0
  229. package/src/features/chat/features/session/utils/__tests__/ncp-session-adapter.utils.test.ts +19 -0
  230. package/src/features/chat/features/session/utils/chat-context-window-indicator.utils.ts +44 -5
  231. package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +10 -0
  232. package/src/features/chat/features/session/utils/ncp-session-context-metadata.utils.ts +42 -4
  233. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +17 -2
  234. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +8 -3
  235. package/src/features/chat/features/welcome/components/chat-welcome.tsx +2 -2
  236. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +22 -6
  237. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +13 -0
  238. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +72 -2
  239. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +21 -1
  240. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +75 -0
  241. package/src/features/chat/features/workspace/components/__tests__/workspace-text-selection-menu.test.tsx +109 -0
  242. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +145 -26
  243. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +42 -18
  244. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +50 -10
  245. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +48 -22
  246. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +13 -2
  247. package/src/features/chat/features/workspace/components/workspace-text-selection-menu.tsx +45 -0
  248. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +80 -0
  249. package/src/features/chat/features/workspace/utils/__tests__/workspace-text-excerpt.utils.test.ts +54 -0
  250. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +47 -0
  251. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +16 -0
  252. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +22 -1
  253. package/src/features/chat/features/workspace/utils/workspace-text-excerpt.utils.ts +53 -0
  254. package/src/features/chat/index.ts +1 -0
  255. package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +129 -0
  256. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +38 -2
  257. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +93 -1
  258. package/src/features/chat/managers/__tests__/provider-model-catalog-notice.manager.test.ts +57 -0
  259. package/src/features/chat/managers/chat-composer-intent.manager.ts +190 -0
  260. package/src/features/chat/managers/chat-session-list.manager.ts +13 -4
  261. package/src/features/chat/managers/chat-thread.manager.ts +30 -11
  262. package/src/features/chat/managers/provider-model-catalog-notice.manager.ts +121 -0
  263. package/src/features/chat/presenters/chat.presenter.ts +3 -0
  264. package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +55 -0
  265. package/src/features/chat/stores/chat-composer-draft.store.ts +92 -0
  266. package/src/features/chat/stores/chat-thread.store.ts +2 -4
  267. package/src/features/chat/types/chat-input-bar.types.ts +8 -0
  268. package/src/features/chat/types/chat-input.types.ts +5 -0
  269. package/src/features/chat/types/chat-message.types.ts +5 -0
  270. package/src/features/cron/components/__tests__/cron-config.test.tsx +100 -19
  271. package/src/features/cron/components/cron-config.tsx +19 -33
  272. package/src/features/cron/components/cron-job-detail-dialog.tsx +42 -16
  273. package/src/features/cron/components/cron-job-row.tsx +18 -1
  274. package/src/features/inbox/components/inbox-delivery-content.test.tsx +8 -2
  275. package/src/features/inbox/components/inbox-delivery-content.tsx +1 -1
  276. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +10 -4
  277. package/src/features/inbox/components/inbox-reader-dialog.tsx +37 -61
  278. package/src/features/inbox/pages/inbox-page.tsx +90 -98
  279. package/src/features/notifications/components/__tests__/app-notification-toast.test.tsx +28 -6
  280. package/src/features/notifications/components/app-notification-toast.tsx +54 -15
  281. package/src/features/notifications/managers/__tests__/app-notification.manager.test.ts +2 -0
  282. package/src/features/notifications/managers/app-notification.manager.ts +3 -0
  283. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +1 -0
  284. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +9 -0
  285. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +1 -0
  286. package/src/features/service-apps/components/__tests__/service-apps-panel.test.tsx +5 -4
  287. package/src/features/service-apps/components/service-app-list-item.tsx +470 -0
  288. package/src/features/service-apps/components/service-apps-panel.tsx +76 -490
  289. package/src/features/settings/components/config/__tests__/provider-models-section.test.tsx +239 -0
  290. package/src/features/settings/components/config/provider-form-detail-pane.tsx +307 -0
  291. package/src/features/settings/components/config/provider-form.tsx +149 -360
  292. package/src/features/settings/components/config/provider-model-list.tsx +293 -0
  293. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +151 -0
  294. package/src/features/settings/components/config/provider-models-section.tsx +178 -149
  295. package/src/features/settings/hooks/__tests__/use-provider-connectivity.test.tsx +98 -0
  296. package/src/features/settings/hooks/__tests__/use-provider-model-suggestions.test.tsx +107 -0
  297. package/src/features/settings/hooks/use-provider-connectivity.ts +132 -0
  298. package/src/features/settings/hooks/use-provider-model-suggestions.ts +51 -0
  299. package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +2 -2
  300. package/src/features/settings/pages/__tests__/search-config-page.test.tsx +48 -0
  301. package/src/features/settings/pages/search-config-page.tsx +17 -8
  302. package/src/features/settings/utils/__tests__/provider-form-support.utils.test.ts +42 -0
  303. package/src/features/settings/utils/provider-form-context.utils.ts +2 -0
  304. package/src/features/settings/utils/provider-form-model.utils.ts +25 -0
  305. package/src/features/settings/utils/provider-form-support.utils.ts +21 -5
  306. package/src/features/side-dock/components/__tests__/side-dock.test.tsx +1 -0
  307. package/src/features/side-dock/configs/side-dock-built-in-items.config.ts +0 -9
  308. package/src/index.css +1 -1
  309. package/src/platforms/desktop/types/desktop-update.types.ts +5 -0
  310. package/src/shared/components/actions/__tests__/navigation-link.test.tsx +14 -3
  311. package/src/shared/components/actions/navigation-link.tsx +35 -15
  312. package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -2
  313. package/src/shared/components/common/agent-avatar.tsx +3 -3
  314. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +66 -0
  315. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +4 -1
  316. package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +1 -0
  317. package/src/shared/components/doc-browser/doc-browser.tsx +9 -0
  318. package/src/shared/components/doc-browser/hooks/use-doc-browser-scroll-restoration.ts +126 -0
  319. package/src/shared/components/settings/settings-page.tsx +1 -1
  320. package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +103 -0
  321. package/src/shared/components/ui/context-menu/context-menu.tsx +263 -0
  322. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +19 -6
  323. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +28 -67
  324. package/src/shared/hooks/use-config.ts +33 -1
  325. package/src/shared/lib/api/__tests__/ncp-session-query-cache.utils.test.ts +26 -0
  326. package/src/shared/lib/api/ncp-session-query-cache.utils.ts +7 -10
  327. package/src/shared/lib/api/ncp-session.types.ts +6 -0
  328. package/src/shared/lib/api/types.ts +36 -1
  329. package/src/shared/lib/api/utils/config.utils.ts +14 -0
  330. package/src/shared/lib/cron/cron-job-view.utils.ts +4 -0
  331. package/src/shared/lib/host-capabilities/__tests__/host-capability.manager.test.ts +26 -0
  332. package/src/shared/lib/host-capabilities/host-capability.manager.ts +28 -0
  333. package/src/shared/lib/i18n/locales/en-US/chat.json +39 -4
  334. package/src/shared/lib/i18n/locales/en-US/core.json +26 -0
  335. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +1 -0
  336. package/src/shared/lib/i18n/locales/en-US/search.json +1 -0
  337. package/src/shared/lib/i18n/locales/zh-CN/chat.json +39 -4
  338. package/src/shared/lib/i18n/locales/zh-CN/core.json +26 -0
  339. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +1 -0
  340. package/src/shared/lib/i18n/locales/zh-CN/search.json +1 -0
  341. package/src/shared/lib/session-project/__tests__/workspace-file-breadcrumb.test.ts +28 -1
  342. package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +23 -0
  343. package/src/shared/lib/theme/index.test.ts +11 -0
  344. package/src/shared/lib/theme/index.ts +2 -0
  345. package/dist/assets/api-B1yHQYs-.js +0 -13
  346. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +0 -1
  347. package/dist/assets/app-presenter-provider-uP9waOzv.js +0 -108
  348. package/dist/assets/appearance-settings-page-C9Zq3hP9.js +0 -1
  349. package/dist/assets/architecture-TIHT7OUA-Cii4JyA2.js +0 -1
  350. package/dist/assets/book-open-oSmyVXea.js +0 -1
  351. package/dist/assets/card-CGvJZTZp.js +0 -1
  352. package/dist/assets/channel-BSKkTPe8.js +0 -1
  353. package/dist/assets/channels-list-page-5BTxpQHw.js +0 -8
  354. package/dist/assets/chat-page-jTvli8Jp.js +0 -1
  355. package/dist/assets/chunk-2Q5K7J3B-CDMOR1xZ.js +0 -1
  356. package/dist/assets/chunk-VAUOI2AC-BRvqNW76.js +0 -1
  357. package/dist/assets/chunk-XXDRQBXY-CwX_mqJ3.js +0 -1
  358. package/dist/assets/classDiagram-OUVF2IWQ-RzbGxG77.js +0 -1
  359. package/dist/assets/classDiagram-v2-EOCWNBFH-C_gWB7WT.js +0 -1
  360. package/dist/assets/config-split-page-BgBsUmp1.js +0 -1
  361. package/dist/assets/confirm-dialog-h849QRWO.js +0 -5
  362. package/dist/assets/cynefin-VYW2F7L2-fSLIS0X3.js +0 -1
  363. package/dist/assets/desktop-update-config-BGGHxClR.js +0 -1
  364. package/dist/assets/dist-CxUhurq9.js +0 -41
  365. package/dist/assets/doc-browser-0eL8AX42.js +0 -1
  366. package/dist/assets/doc-browser-DEqE9lsh.js +0 -1
  367. package/dist/assets/doc-browser-context-DkzFIUoK.js +0 -1
  368. package/dist/assets/eventmodeling-45OFAUF4-XVcQGgha.js +0 -1
  369. package/dist/assets/eye-gOWQGt8N.js +0 -1
  370. package/dist/assets/flowDiagram-23GEKE2U-BiFSctqz.js +0 -1
  371. package/dist/assets/form-actions-CgjYZUzM.js +0 -1
  372. package/dist/assets/gitGraph-TEB2WS4Q-C014uXqS.js +0 -1
  373. package/dist/assets/host-capabilities-B-TtABsP.js +0 -1
  374. package/dist/assets/index-DSAUWCfl.js +0 -2
  375. package/dist/assets/index-G7cBryJ4.css +0 -1
  376. package/dist/assets/info-DKCQHKI2-CQ2qjGhU.js +0 -1
  377. package/dist/assets/loader-circle-BAuycGf6.js +0 -1
  378. package/dist/assets/logo-badge-BNcsDsUM.js +0 -1
  379. package/dist/assets/mcp-marketplace-page-BX39MtPa.js +0 -9
  380. package/dist/assets/mcp-marketplace-page-CkDtOEA4.js +0 -1
  381. package/dist/assets/model-config-page-7MIXg2fQ.js +0 -1
  382. package/dist/assets/navigation-link-B3iFOdxx.js +0 -1
  383. package/dist/assets/packet-7NZHBO7P-6IFyydij.js +0 -1
  384. package/dist/assets/pie-RZYD4A2V-spXQC_wr.js +0 -1
  385. package/dist/assets/plus-yvhFgfal.js +0 -1
  386. package/dist/assets/popover-Cpep_rJe.js +0 -1
  387. package/dist/assets/provider-models-CUrptZ-o.js +0 -1
  388. package/dist/assets/provider-scoped-model-input-CHmOzz7x.js +0 -1
  389. package/dist/assets/providers-config-page-A6J7Y0II.js +0 -1
  390. package/dist/assets/radar-I7S5WNFK-DWVA8lvY.js +0 -1
  391. package/dist/assets/railroad-3IZDKUUU-Ce51u8y1.js +0 -1
  392. package/dist/assets/railroad-abnf-AHOZXSZD-D7i7cqI_.js +0 -1
  393. package/dist/assets/railroad-ebnf-EBAXGLYW-BEg2hcPs.js +0 -1
  394. package/dist/assets/railroad-peg-LSFZ7HO6-CxROSzbi.js +0 -1
  395. package/dist/assets/react-BCJGCjrP.js +0 -8
  396. package/dist/assets/remote-FD-ZfSIn.js +0 -1
  397. package/dist/assets/rotate-cw-DrJMfHhp.js +0 -1
  398. package/dist/assets/runtime-config-page-DwjO-Vs6.js +0 -1
  399. package/dist/assets/search-config-page-T6tMhXbP.js +0 -1
  400. package/dist/assets/security-config-DD5RrjDe.js +0 -1
  401. package/dist/assets/select-BvidP5Oa.js +0 -1
  402. package/dist/assets/skeleton-BEQW2Dva.js +0 -1
  403. package/dist/assets/stateDiagram-v2-6OUMAXLB-Bui4RXQK.js +0 -1
  404. package/dist/assets/swimlanesDiagram-G3AALYLV-DTwUsCBz.js +0 -8
  405. package/dist/assets/tabs-BeLxVmkt.js +0 -1
  406. package/dist/assets/trash-2-CYUskMMN.js +0 -1
  407. package/dist/assets/treeView-QDETBFTQ-D5zsTiuL.js +0 -1
  408. package/dist/assets/treemap-6X3UGDF4-CR3dxqNs.js +0 -1
  409. package/dist/assets/use-config-CxKRXXCl.js +0 -1
  410. package/dist/assets/use-confirm-dialog-HASTvOP2.js +0 -1
  411. package/dist/assets/use-viewport-layout-CJxkjoRz.js +0 -1
  412. package/dist/assets/wardley-OPB4EBWU-LatRT_Lx.js +0 -1
  413. package/dist/assets/x-DdUwjre5.js +0 -1
  414. /package/dist/assets/{array-CAkJT3no.js → array-NADKd9aU.js} +0 -0
  415. /package/dist/assets/{chunk-KEIR6QF5-BgdDoWEH.js → chunk-KEIR6QF5-BuyuzJJL.js} +0 -0
  416. /package/dist/assets/{chunk-Y2CYZVJY-pTllD0P3.js → chunk-Y2CYZVJY-D_B2ZRNt.js} +0 -0
  417. /package/dist/assets/{config-hints-S3g-UVZb.js → config-hints-BcfVUMij.js} +0 -0
  418. /package/dist/assets/{cytoscape.esm-DmURt-5G.js → cytoscape.esm-BANTlgza.js} +0 -0
  419. /package/dist/assets/{defaultLocale-BKy_KP3O.js → defaultLocale-C4_L0aEs.js} +0 -0
  420. /package/dist/assets/{dist-IgNNB7K9.js → dist-DAPEIJbz.js} +0 -0
  421. /package/dist/assets/{graphlib-xw_TBHyH.js → graphlib-ChqXg0dI.js} +0 -0
  422. /package/dist/assets/{init-C9xlLIAu.js → init-D8wZg9xq.js} +0 -0
  423. /package/dist/assets/{jszip.min-Das2IAnb.js → jszip.min-CkbBfwAQ.js} +0 -0
  424. /package/dist/assets/{katex-DSy1eD2d.js → katex-TZJFa0J_.js} +0 -0
  425. /package/dist/assets/{middleware-Df-a4x-q.js → middleware-B3k-TSmZ.js} +0 -0
  426. /package/dist/assets/{path-DB0USYHi.js → path-DodfxcX7.js} +0 -0
  427. /package/dist/assets/{rough.esm-B1B52ZQS.js → rough.esm-CUaa1Rbe.js} +0 -0
  428. /package/dist/assets/{xlsx-DfjC_iml.js → xlsx-CxByi7bR.js} +0 -0
@@ -29,6 +29,7 @@ import type {
29
29
  } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-state';
30
30
  import { useSessionConversationInputState } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-state';
31
31
  import { useChatMessageLayoutStore } from '@/features/chat/stores/chat-message-layout.store';
32
+ import { ChatComposerIntentManager } from '@/features/chat/managers/chat-composer-intent.manager';
32
33
 
33
34
  const uploadNcpAssetsMock = vi.hoisted(() => vi.fn());
34
35
 
@@ -41,6 +42,21 @@ function renderInput(input: ReactElement) {
41
42
  );
42
43
  }
43
44
 
45
+ Object.defineProperty(Range.prototype, 'getBoundingClientRect', {
46
+ value: vi.fn(() => ({
47
+ bottom: 0,
48
+ height: 0,
49
+ left: 0,
50
+ right: 0,
51
+ top: 0,
52
+ width: 0,
53
+ x: 0,
54
+ y: 0,
55
+ toJSON: () => ({}),
56
+ })),
57
+ writable: true,
58
+ });
59
+
44
60
  afterEach(() => {
45
61
  useChatMessageLayoutStore.getState().setLayout('card');
46
62
  });
@@ -83,6 +99,14 @@ vi.mock('@/shared/hooks/use-server-path-search', () => ({
83
99
  }),
84
100
  }));
85
101
 
102
+ vi.mock('@/shared/hooks/use-projects', () => ({
103
+ useProjects: () => ({
104
+ data: { projects: [] },
105
+ isFetching: false,
106
+ isLoading: false,
107
+ }),
108
+ }));
109
+
86
110
  vi.mock('@/shared/lib/api', async (importOriginal) => {
87
111
  const actual = await importOriginal();
88
112
  return {
@@ -96,7 +120,9 @@ type StreamingInputControl = {
96
120
  bumpStream: () => void;
97
121
  };
98
122
 
123
+ const chatComposerIntentManager = new ChatComposerIntentManager();
99
124
  const presenter = {
125
+ chatComposerIntentManager,
100
126
  chatThreadManager: {
101
127
  openSideChatDraft: vi.fn(),
102
128
  },
@@ -111,6 +137,7 @@ const controller: SessionConversationInputController = {
111
137
  deleteQueuedInput: vi.fn(),
112
138
  editQueuedInput: vi.fn(),
113
139
  isSending: true,
140
+ primaryAction: 'send',
114
141
  queuedInputs: [],
115
142
  send: vi.fn(),
116
143
  sendDisabled: true,
@@ -120,6 +147,7 @@ const controller: SessionConversationInputController = {
120
147
 
121
148
  function createStreamingInputSnapshot(
122
149
  nodes: readonly ChatComposerNode[],
150
+ sendError: string | null = null,
123
151
  ): SessionConversationInputSnapshot {
124
152
  return {
125
153
  attachments: [],
@@ -131,7 +159,7 @@ function createStreamingInputSnapshot(
131
159
  selectedSessionType: 'default',
132
160
  selectedSkills: [],
133
161
  selectedThinkingLevel: null,
134
- sendError: null,
162
+ sendError,
135
163
  skillRecords: [],
136
164
  text: nodes
137
165
  .map((node) => (node.type === 'text' ? node.text : ''))
@@ -178,12 +206,16 @@ async function insertText(textbox: HTMLElement, text: string): Promise<void> {
178
206
  function StreamingSessionConversationInputHarness({
179
207
  controllerOverride = controller,
180
208
  controlRef,
209
+ initialText = '',
210
+ sendError = null,
181
211
  }: {
182
212
  controllerOverride?: SessionConversationInputController;
183
213
  controlRef: MutableRefObject<StreamingInputControl | null>;
214
+ initialText?: string;
215
+ sendError?: string | null;
184
216
  }) {
185
217
  const [nodes, setNodes] = useState<readonly ChatComposerNode[]>([
186
- createChatComposerTextNode(''),
218
+ createChatComposerTextNode(initialText),
187
219
  ]);
188
220
  const [streamChunk, setStreamChunk] = useState(0);
189
221
  const bumpStream = useCallback(() => setStreamChunk((chunk) => chunk + 1), []);
@@ -195,7 +227,10 @@ function StreamingSessionConversationInputHarness({
195
227
  };
196
228
  }, [bumpStream, controlRef]);
197
229
 
198
- const inputSnapshot = useMemo(() => createStreamingInputSnapshot(nodes), [nodes]);
230
+ const inputSnapshot = useMemo(
231
+ () => createStreamingInputSnapshot(nodes, sendError),
232
+ [nodes, sendError],
233
+ );
199
234
  const inputActions: SessionConversationInputActions = useMemo(() => ({
200
235
  addAttachments: vi.fn(() => []),
201
236
  applyPromptSuggestion: vi.fn(),
@@ -223,13 +258,18 @@ function StreamingSessionConversationInputHarness({
223
258
  },
224
259
  }), []);
225
260
  const inputQuery = useMemo(() => ({
261
+ addDiscoveredModel: vi.fn(async () => null),
262
+ dismissDiscoveredModels: vi.fn(),
226
263
  defaultModel: undefined,
227
264
  defaultProjectRoot: null,
265
+ discoveredModelOptions: [],
228
266
  fallbackPreferredModel: undefined,
229
267
  fallbackPreferredThinking: undefined,
230
268
  isProviderStateResolved: true,
231
269
  isSkillsLoading: false,
232
270
  modelOptions: [],
271
+ providersView: null,
272
+ refreshProviderModelCatalog: vi.fn(),
233
273
  selectedSession: null,
234
274
  selectedSessionKey: null,
235
275
  sessionTypeState: {
@@ -307,6 +347,54 @@ describe('SessionConversationInput streaming stability', () => {
307
347
  await waitFor(() => expect(window.getSelection()?.anchorOffset).toBe(1));
308
348
  });
309
349
 
350
+ it('inserts a project file reference at the saved composer caret', async () => {
351
+ const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
352
+ render(
353
+ <StreamingSessionConversationInputHarness
354
+ controlRef={controlRef}
355
+ initialText="Hello"
356
+ />,
357
+ );
358
+
359
+ const textbox = screen.getByRole('textbox');
360
+ fireEvent.focus(textbox);
361
+ expect(textbox.textContent).toBe('Hello');
362
+ const paragraph = textbox.querySelector('p');
363
+ expect(paragraph).toBeTruthy();
364
+ const textNode = document
365
+ .createTreeWalker(paragraph!, NodeFilter.SHOW_TEXT)
366
+ .nextNode();
367
+ expect(textNode).toBeTruthy();
368
+ const range = document.createRange();
369
+ range.setStart(textNode!, 2);
370
+ range.collapse(true);
371
+ const selection = window.getSelection();
372
+ selection?.removeAllRanges();
373
+ selection?.addRange(range);
374
+ fireEvent(document, new Event('selectionchange'));
375
+ await act(async () => Promise.resolve());
376
+
377
+ act(() => {
378
+ chatComposerIntentManager.requestFileReference({
379
+ targetSessionKey: null,
380
+ tokenKey: 'docs/guide.md',
381
+ label: 'guide.md',
382
+ });
383
+ });
384
+
385
+ await waitFor(() => {
386
+ expect(
387
+ textbox.querySelector(
388
+ '[data-composer-token-kind="workspace_file"][data-composer-token-key="docs/guide.md"]',
389
+ ),
390
+ ).toBeTruthy();
391
+ });
392
+ expect(textbox.textContent).toContain('He');
393
+ expect(textbox.textContent).toContain('guide.md');
394
+ expect(textbox.textContent).toContain('llo');
395
+ expect(textbox.textContent).toBe('Heguide.mdllo');
396
+ });
397
+
310
398
  it('renders queued inputs above the composer with edit and delete actions', () => {
311
399
  const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
312
400
  const deleteQueuedInput = vi.fn();
@@ -338,6 +426,20 @@ describe('SessionConversationInput streaming stability', () => {
338
426
  expect(editQueuedInput).toHaveBeenCalledWith('queued-1');
339
427
  expect(deleteQueuedInput).toHaveBeenCalledWith('queued-2');
340
428
  });
429
+
430
+ it('leaves send-error rendering to the conversation surface', () => {
431
+ const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
432
+ const providerError = 'Chat Completions API failed (402): raw provider error';
433
+
434
+ render(
435
+ <StreamingSessionConversationInputHarness
436
+ controlRef={controlRef}
437
+ sendError={providerError}
438
+ />,
439
+ );
440
+
441
+ expect(screen.queryByText(providerError)).toBeNull();
442
+ });
341
443
  });
342
444
 
343
445
  type AttachmentSubmitAgentSend = (envelope: NcpAgentSendEnvelope) => Promise<NcpRunHandle | null>;
@@ -352,11 +454,23 @@ function createAttachmentRunHandle(): NcpRunHandle {
352
454
  };
353
455
  }
354
456
 
355
- function AttachmentSubmitHarness({ send }: { readonly send: AttachmentSubmitAgentSend }) {
356
- const { inputActions, inputSnapshot } = useSessionConversationInputState();
457
+ function AttachmentSubmitHarness({
458
+ initialPrompt,
459
+ send,
460
+ }: {
461
+ readonly initialPrompt?: string;
462
+ readonly send: AttachmentSubmitAgentSend;
463
+ }) {
464
+ const { inputActions, inputSnapshot } = useSessionConversationInputState(
465
+ initialPrompt,
466
+ `attachment-test:${initialPrompt ?? 'empty'}`,
467
+ );
357
468
  const inputQuery = useMemo(() => ({
469
+ addDiscoveredModel: vi.fn(async () => null),
470
+ dismissDiscoveredModels: vi.fn(),
358
471
  defaultModel: 'test-model',
359
472
  defaultProjectRoot: null,
473
+ discoveredModelOptions: [],
360
474
  fallbackPreferredModel: undefined,
361
475
  fallbackPreferredThinking: undefined,
362
476
  isProviderStateResolved: true,
@@ -369,6 +483,8 @@ function AttachmentSubmitHarness({ send }: { readonly send: AttachmentSubmitAgen
369
483
  thinkingCapability: null,
370
484
  },
371
485
  ],
486
+ providersView: null,
487
+ refreshProviderModelCatalog: vi.fn(),
372
488
  selectedSession: null,
373
489
  selectedSessionKey: 'session-attachment',
374
490
  sessionTypeState: {
@@ -384,6 +500,8 @@ function AttachmentSubmitHarness({ send }: { readonly send: AttachmentSubmitAgen
384
500
  }), []);
385
501
  const agent = useMemo(() => ({
386
502
  abort: vi.fn(),
503
+ continueRun: vi.fn(),
504
+ editMessage: vi.fn(),
387
505
  isHydrating: false,
388
506
  isRunning: false,
389
507
  isSending: false,
@@ -425,6 +543,126 @@ function AttachmentSubmitHarness({ send }: { readonly send: AttachmentSubmitAgen
425
543
  }
426
544
 
427
545
  describe('SessionConversationInput attachment submit', () => {
546
+ it('preserves a project file reference in the outgoing user message and AI context', async () => {
547
+ const send = vi.fn<AttachmentSubmitAgentSend>(async () => createAttachmentRunHandle());
548
+
549
+ render(<AttachmentSubmitHarness initialPrompt="这里面有啥" send={send} />);
550
+
551
+ const textbox = screen.getByRole('textbox');
552
+ fireEvent.focus(textbox);
553
+ const textNode = document
554
+ .createTreeWalker(textbox, NodeFilter.SHOW_TEXT)
555
+ .nextNode();
556
+ expect(textNode).toBeTruthy();
557
+ const range = document.createRange();
558
+ range.setStart(textNode!, 0);
559
+ range.collapse(true);
560
+ const selection = window.getSelection();
561
+ selection?.removeAllRanges();
562
+ selection?.addRange(range);
563
+ fireEvent(document, new Event('selectionchange'));
564
+ await act(async () => Promise.resolve());
565
+
566
+ act(() => {
567
+ chatComposerIntentManager.requestFileReference({
568
+ targetSessionKey: 'session-attachment',
569
+ tokenKey: 'docs/guide.md',
570
+ label: 'guide.md',
571
+ });
572
+ });
573
+
574
+ await waitFor(() => {
575
+ expect(
576
+ document.querySelector(
577
+ '[data-composer-token-kind="workspace_file"][data-composer-token-key="docs/guide.md"]',
578
+ ),
579
+ ).toBeTruthy();
580
+ });
581
+
582
+ fireEvent.click(screen.getByRole('button', { name: /Send|发送/ }));
583
+
584
+ await waitFor(() => expect(send).toHaveBeenCalledTimes(1));
585
+ expect(send.mock.calls[0]?.[0].message.parts).toEqual([
586
+ {
587
+ type: 'text',
588
+ text: '这里面有啥 @file:docs%2Fguide.md',
589
+ },
590
+ ]);
591
+ expect(send.mock.calls[0]?.[0].message.metadata).toMatchObject({
592
+ ui_inline_tokens: {
593
+ schemaVersion: 2,
594
+ items: [
595
+ {
596
+ kind: 'workspace_file',
597
+ key: 'docs/guide.md',
598
+ label: 'guide.md',
599
+ rawText: '@file:docs%2Fguide.md',
600
+ },
601
+ ],
602
+ },
603
+ });
604
+ });
605
+
606
+ it('preserves an exact workspace excerpt in the outgoing message metadata', async () => {
607
+ const send = vi.fn<AttachmentSubmitAgentSend>(async () => createAttachmentRunHandle());
608
+ render(<AttachmentSubmitHarness initialPrompt="解释一下" send={send} />);
609
+
610
+ const textbox = screen.getByRole('textbox');
611
+ await waitFor(() => expect(textbox.textContent).toBe('解释一下'));
612
+ fireEvent.focus(textbox);
613
+ const paragraph = textbox.querySelector('p');
614
+ const textNode = document.createTreeWalker(
615
+ paragraph!,
616
+ NodeFilter.SHOW_TEXT,
617
+ ).nextNode();
618
+ const range = document.createRange();
619
+ range.setStart(textNode!, '解释一下'.length);
620
+ range.collapse(true);
621
+ window.getSelection()?.removeAllRanges();
622
+ window.getSelection()?.addRange(range);
623
+ fireEvent(document, new Event('selectionchange'));
624
+ await act(async () => Promise.resolve());
625
+
626
+ act(() => {
627
+ chatComposerIntentManager.requestExcerptReference({
628
+ targetSessionKey: 'session-attachment',
629
+ path: 'docs/guide.md',
630
+ label: 'guide.md',
631
+ excerpt: 'Requests must include an authorization header.',
632
+ startLine: 32,
633
+ endLine: 34,
634
+ });
635
+ });
636
+
637
+ await waitFor(() => expect(document.querySelector(
638
+ '[data-composer-token-kind="workspace_excerpt"]',
639
+ )).toBeTruthy());
640
+ fireEvent.click(screen.getByRole('button', { name: /Send|发送/ }));
641
+
642
+ await waitFor(() => expect(send).toHaveBeenCalledTimes(1));
643
+ const envelope = send.mock.calls[0]?.[0];
644
+ const metadata = envelope.message.metadata?.ui_inline_tokens as {
645
+ items: Array<Record<string, unknown>>;
646
+ };
647
+ expect(metadata.items).toEqual([
648
+ expect.objectContaining({
649
+ kind: 'workspace_excerpt',
650
+ path: 'docs/guide.md',
651
+ label: 'guide.md',
652
+ excerpt: 'Requests must include an authorization header.',
653
+ startLine: 32,
654
+ endLine: 34,
655
+ rawText: expect.stringMatching(/^@excerpt:/),
656
+ }),
657
+ ]);
658
+ expect(envelope.message.parts).toEqual([
659
+ {
660
+ type: 'text',
661
+ text: expect.stringMatching(/^解释一下 @excerpt:/),
662
+ },
663
+ ]);
664
+ });
665
+
428
666
  it('keeps uploaded file attachments in the outgoing send envelope after token insertion', async () => {
429
667
  uploadNcpAssetsMock.mockResolvedValueOnce([
430
668
  {
@@ -13,7 +13,6 @@ import {
13
13
  resolveNcpChatSendErrorMessage,
14
14
  } from "@/features/chat/features/runtime/utils/ncp-chat-runtime-availability.utils";
15
15
  import { buildChatContextWindowIndicator } from "@/features/chat/features/session/utils/chat-context-window-indicator.utils";
16
- import { sessionActivityPreviewText } from "@/features/chat/features/session/utils/chat-session-display.utils";
17
16
  import { readNcpContextWindowValue } from "@/features/chat/features/session/utils/ncp-session-context-metadata.utils";
18
17
  import { ChatConversationWelcome } from "@/features/chat/features/welcome/components/chat-conversation-welcome";
19
18
  import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
@@ -85,11 +84,13 @@ function readChatDraftRouteState(value: unknown): ChatDraftRouteState | null {
85
84
  }
86
85
 
87
86
  function useSessionConversationDraftRouteState(params: {
87
+ readonly applyPromptSuggestion: (prompt: string) => void;
88
88
  readonly sessionKey: string | null;
89
89
  readonly setPendingProjectRoot: (projectRoot: string | null) => void;
90
90
  readonly setPendingSessionType: (sessionType: string) => void;
91
91
  }) {
92
92
  const {
93
+ applyPromptSuggestion,
93
94
  sessionKey,
94
95
  setPendingProjectRoot,
95
96
  setPendingSessionType,
@@ -120,6 +121,9 @@ function useSessionConversationDraftRouteState(params: {
120
121
  ) {
121
122
  setPendingSessionType(draftState.sessionType);
122
123
  }
124
+ if (typeof draftState.prompt === "string" && draftState.prompt.trim()) {
125
+ applyPromptSuggestion(draftState.prompt);
126
+ }
123
127
  setPendingProjectRoot(
124
128
  typeof draftState.projectRoot === "string" &&
125
129
  draftState.projectRoot.trim()
@@ -127,6 +131,7 @@ function useSessionConversationDraftRouteState(params: {
127
131
  : null,
128
132
  );
129
133
  }, [
134
+ applyPromptSuggestion,
130
135
  location.key,
131
136
  location.state,
132
137
  sessionKey,
@@ -195,7 +200,10 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
195
200
  );
196
201
  const agent = useNcpSessionConversation(sessionKey ?? undefined);
197
202
  const runQueue = useSessionRunQueue(sessionKey);
198
- const { inputActions, inputSnapshot } = useSessionConversationInputState(initialPrompt);
203
+ const { inputActions, inputSnapshot } = useSessionConversationInputState(
204
+ initialPrompt,
205
+ sessionKey,
206
+ );
199
207
  const inputQuery = useSessionConversationInputQuery({
200
208
  sessionKey,
201
209
  inputSnapshot,
@@ -243,6 +251,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
243
251
  inputQuery.sessionTypeState.selectedSessionType,
244
252
  ]);
245
253
  useSessionConversationDraftRouteState({
254
+ applyPromptSuggestion: inputActions.applyPromptSuggestion,
246
255
  sessionKey,
247
256
  setPendingProjectRoot: inputActions.setPendingProjectRoot,
248
257
  setPendingSessionType: inputActions.setPendingSessionType,
@@ -250,8 +259,10 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
250
259
  const isRuntimeBlocked = isNcpChatRuntimeBlocked(systemStatus);
251
260
  const currentSessionRunning =
252
261
  agent.isRunning || inputQuery.selectedSession?.status === "running";
253
- const rawLastSendError =
254
- agent.hydrateError?.message ?? agent.snapshot.error?.message ?? null;
262
+ const runtimeError = agent.snapshot.error;
263
+ const rawLastSendError = agent.hydrateError?.message
264
+ ?? (runtimeError?.code === "run-interrupted" ? null : runtimeError?.message)
265
+ ?? null;
255
266
  const filteredLastSendError =
256
267
  systemStatus.phase === "ready" &&
257
268
  isNcpAgentStartupUnavailableErrorMessage(rawLastSendError)
@@ -299,6 +310,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
299
310
  editQueuedInput: (id: string) =>
300
311
  controllerRef.current.editQueuedInput(id),
301
312
  isSending: controller.isSending,
313
+ primaryAction: controller.primaryAction,
302
314
  queuedInputs: controller.queuedInputs,
303
315
  send: () => controllerRef.current.send(),
304
316
  sendDisabled: controller.sendDisabled,
@@ -308,6 +320,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
308
320
  [
309
321
  controller.canStopGeneration,
310
322
  controller.isSending,
323
+ controller.primaryAction,
311
324
  controller.queuedInputs,
312
325
  controller.sendDisabled,
313
326
  controller.stopDisabled,
@@ -320,26 +333,23 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
320
333
  ),
321
334
  [agent.snapshot.contextWindow],
322
335
  );
323
- const displayInputSnapshot = useMemo(
324
- () => ({
325
- ...inputSnapshot,
326
- sendError: lastSendError ?? inputSnapshot.sendError,
327
- }),
328
- [inputSnapshot, lastSendError],
329
- );
330
336
  const { selectedSession } = inputQuery;
331
- const sessionFailureMessage =
332
- selectedSession?.activityPreview?.state === "failed"
333
- ? sessionActivityPreviewText(selectedSession)
334
- : null;
335
- const sessionFailureSlot = sessionFailureMessage ? (
336
- <div className="rounded-lg border border-red-200/80 bg-red-50/80 px-3 py-2.5 shadow-sm">
337
- <div className="text-xs font-semibold text-red-800">
338
- {t("chatSessionErrorTitle")}
339
- </div>
340
- <div className="mt-1 whitespace-pre-wrap break-words text-xs leading-5 text-red-700">
341
- {sessionFailureMessage}
342
- </div>
337
+ const conversationFailureMessage =
338
+ inputSnapshot.sendError?.trim() ||
339
+ lastSendError?.trim() ||
340
+ (selectedSession?.activityPreview?.state === "failed" &&
341
+ selectedSession.activityPreview.statusKind !== "run-interrupted"
342
+ ? selectedSession.activityPreview.statusText?.trim()
343
+ : null) ||
344
+ null;
345
+ const conversationFailureSlot = conversationFailureMessage ? (
346
+ <div
347
+ className="rounded-lg border-l-2 border-destructive/40 bg-muted/45 px-3 py-2.5"
348
+ role="status"
349
+ >
350
+ <pre className="max-h-32 select-text overflow-auto whitespace-pre-wrap break-words font-mono text-[11px] leading-5 text-muted-foreground">
351
+ {conversationFailureMessage}
352
+ </pre>
343
353
  </div>
344
354
  ) : null;
345
355
  useSessionConversationDraftIntent({
@@ -353,7 +363,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
353
363
  controller={inputController}
354
364
  inputActions={inputActions}
355
365
  inputQuery={inputQuery}
356
- inputSnapshot={displayInputSnapshot}
366
+ inputSnapshot={inputSnapshot}
357
367
  onContextCompactingChange={handleContextCompactingChange}
358
368
  placeholder={placeholder}
359
369
  surface={surface}
@@ -361,10 +371,10 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
361
371
  ),
362
372
  [
363
373
  contextWindow,
364
- displayInputSnapshot,
365
374
  inputController,
366
375
  inputActions,
367
376
  inputQuery,
377
+ inputSnapshot,
368
378
  handleContextCompactingChange,
369
379
  ],
370
380
  );
@@ -372,7 +382,8 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
372
382
  showWelcomeForDraft &&
373
383
  !sessionKey &&
374
384
  agent.visibleMessages.length === 0 &&
375
- !agent.isHydrating;
385
+ !agent.isHydrating &&
386
+ !controller.isSending;
376
387
 
377
388
  return (
378
389
  <>
@@ -380,23 +391,29 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
380
391
  <ChatConversationContent
381
392
  hasPreviousMessages={agent.hasPreviousMessages}
382
393
  historyError={agent.historyError}
383
- isAwaitingAssistantOutput={
384
- controller.isSending && currentSessionRunning
385
- }
386
394
  isHistoryLoading={agent.isHydrating}
387
395
  isLoadingPreviousMessages={agent.isLoadingPreviousMessages}
388
396
  isSending={controller.isSending}
397
+ canContinue={controller.canContinue}
398
+ messageActionsDisabled={controller.isSending}
389
399
  isContextCompacting={Boolean(
390
400
  sessionKey && compactingSessionIds.has(sessionKey),
391
401
  )}
392
- bottomSlot={sessionFailureSlot}
402
+ bottomSlot={showWelcome ? null : conversationFailureSlot}
393
403
  messages={agent.visibleMessages}
394
404
  sessionKey={sessionKey}
395
405
  showWelcome={showWelcome}
396
406
  onLoadPreviousMessages={agent.loadPreviousMessages}
407
+ onContinueRun={() => controllerRef.current.continueRun()}
408
+ onEditMessage={(payload) => controllerRef.current.editMessage(payload)}
397
409
  welcomeSlot={
398
410
  <ChatConversationWelcome
399
- inputSlot={renderInput("embedded", t("chatWelcomeInputPlaceholder"))}
411
+ inputSlot={
412
+ <div className="space-y-2">
413
+ {renderInput("embedded", t("chatWelcomeInputPlaceholder"))}
414
+ {conversationFailureSlot}
415
+ </div>
416
+ }
400
417
  pendingProjectRoot={inputSnapshot.pendingProjectRoot}
401
418
  pendingSessionType={inputSnapshot.pendingSessionType}
402
419
  selectedSessionTypeValue={inputSnapshot.selectedSessionType}