@nextclaw/ui 0.15.21 → 0.15.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (476) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/assets/{abnfDiagram-VRR7QNED-M4g_AyR8.js → abnfDiagram-VRR7QNED-DvTjgVMf.js} +1 -1
  3. package/dist/assets/{aiden0z-pptx-renderer.es-Bd99vut2.js → aiden0z-pptx-renderer.es-C1nfBAXR.js} +1 -1
  4. package/dist/assets/api-Glw2OGXK.js +13 -0
  5. package/dist/assets/appearance-settings-page-Bl_W_9m7.js +1 -0
  6. package/dist/assets/{arc-IO7WNWOB.js → arc-BvhODBXv.js} +1 -1
  7. package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +1 -0
  8. package/dist/assets/{architectureDiagram-ZJ3FMSHR-Dc-lvdUh.js → architectureDiagram-ZJ3FMSHR-BKO9RgNS.js} +1 -1
  9. package/dist/assets/{blockDiagram-677ZJIJ3-CcsoWpIY.js → blockDiagram-677ZJIJ3-DHpDXy7D.js} +1 -1
  10. package/dist/assets/{c4Diagram-LMCZKHZV-Bsrtg6b2.js → c4Diagram-LMCZKHZV-BG_iQnDr.js} +1 -1
  11. package/dist/assets/channel-5T3pdR-s.js +1 -0
  12. package/dist/assets/channels-list-page-C7E4Sxwd.js +8 -0
  13. package/dist/assets/chat-page-BT6dNI-4.js +1 -0
  14. package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +1 -0
  15. package/dist/assets/{chunk-32BRIVSS-Bt08t8oG.js → chunk-32BRIVSS-DR9M0LLx.js} +1 -1
  16. package/dist/assets/{chunk-52WLFC77-Ddx68Xzx.js → chunk-52WLFC77-698iC3BB.js} +1 -1
  17. package/dist/assets/{chunk-5FCAYU7R-B7p9_q55.js → chunk-5FCAYU7R-DikTj9Ey.js} +1 -1
  18. package/dist/assets/{chunk-5HE753X5-D52KvdTm.js → chunk-5HE753X5-ko0o7_q0.js} +1 -1
  19. package/dist/assets/{chunk-5JV3BV7I-C329h8nI.js → chunk-5JV3BV7I-CEHufhgo.js} +1 -1
  20. package/dist/assets/{chunk-5TONJI2A-BZyUBxWt.js → chunk-5TONJI2A-CGgno1cu.js} +1 -1
  21. package/dist/assets/{chunk-5VM5RSS4-BUiYXZmu.js → chunk-5VM5RSS4-DkiB4cUQ.js} +1 -1
  22. package/dist/assets/{chunk-7BUUIJ7U-B7o-mn4r.js → chunk-7BUUIJ7U-DzptcytQ.js} +1 -1
  23. package/dist/assets/{chunk-BIQX33UG-Bey9GoRP.js → chunk-BIQX33UG-DMRSQJvT.js} +1 -1
  24. package/dist/assets/{chunk-C7G6YPKG-C6tosszM.js → chunk-C7G6YPKG-Bw1BwwuY.js} +1 -1
  25. package/dist/assets/{chunk-CQNSW5MT-BNrdkgGQ.js → chunk-CQNSW5MT-C0z6eHBk.js} +1 -1
  26. package/dist/assets/{chunk-CYSBUYHQ-DHODFeyB.js → chunk-CYSBUYHQ-ByPyAouO.js} +1 -1
  27. package/dist/assets/{chunk-EMLP6XTP-BcmLjrcq.js → chunk-EMLP6XTP-CJlAXWZg.js} +1 -1
  28. package/dist/assets/{chunk-EX3LRPZG-r-_eEtJI.js → chunk-EX3LRPZG-Dqq4zKJu.js} +1 -1
  29. package/dist/assets/{chunk-FWX5IMBZ-DOObDWbf.js → chunk-FWX5IMBZ-B0SNoCmi.js} +2 -2
  30. package/dist/assets/{chunk-HOUHSVGY-Bd0FnbWZ.js → chunk-HOUHSVGY-DG_GJih_.js} +1 -1
  31. package/dist/assets/{chunk-ICXQ74PX-ntNwAm4_.js → chunk-ICXQ74PX-Drxk_6bE.js} +1 -1
  32. package/dist/assets/{chunk-JG7HCLWE-YtRpblZN.js → chunk-JG7HCLWE-DdLFPpnd.js} +1 -1
  33. package/dist/assets/{chunk-JWPE2WC7-De5-D9ta.js → chunk-JWPE2WC7-B8M4G76F.js} +1 -1
  34. package/dist/assets/{chunk-MOJQB5TN-CdvKhyp2.js → chunk-MOJQB5TN-XP6FJHY_.js} +1 -1
  35. package/dist/assets/{chunk-MOZMSUNE-DJMMN_lu.js → chunk-MOZMSUNE-C_6x18Qw.js} +1 -1
  36. package/dist/assets/{chunk-OGEWGWER-DOFWVw3O.js → chunk-OGEWGWER-N25BzCmG.js} +1 -1
  37. package/dist/assets/{chunk-OSBZ3O6U-DZkrIN9r.js → chunk-OSBZ3O6U-ASDEm7y0.js} +1 -1
  38. package/dist/assets/{chunk-PUDLZKDR-D1wma2Yf.js → chunk-PUDLZKDR-CTlvAcn7.js} +1 -1
  39. package/dist/assets/{chunk-Q4XR5HBZ-CjPy94Lz.js → chunk-Q4XR5HBZ-Da9BWfB6.js} +1 -1
  40. package/dist/assets/{chunk-QBLGF6JB-Hy1bEgS-.js → chunk-QBLGF6JB-Bi6RpTJO.js} +1 -1
  41. package/dist/assets/{chunk-R7FJI6CG-CUPIHyh-.js → chunk-R7FJI6CG-DkMsSPvK.js} +1 -1
  42. package/dist/assets/{chunk-RYQCIY6F-D5Ua4pcv.js → chunk-RYQCIY6F-DZp0eU-j.js} +1 -1
  43. package/dist/assets/{chunk-U6XO7XAA-DaUQcqb7.js → chunk-U6XO7XAA-vfinDSrj.js} +1 -1
  44. package/dist/assets/{chunk-V7JOEXUC-DX2zLfQe.js → chunk-V7JOEXUC-C9Nksccs.js} +1 -1
  45. package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +1 -0
  46. package/dist/assets/{chunk-VR4S4FIN-CFA-WQik.js → chunk-VR4S4FIN-Xv6zfwXs.js} +1 -1
  47. package/dist/assets/{chunk-WYO6CB5R-Bk2HeDvJ.js → chunk-WYO6CB5R-mOJNzbWl.js} +2 -2
  48. package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +1 -0
  49. package/dist/assets/{chunk-YOTPTUD7-DUG4FpBN.js → chunk-YOTPTUD7-1-aKSu4o.js} +1 -1
  50. package/dist/assets/{chunk-ZGVPDNZ5-70JdIGo0.js → chunk-ZGVPDNZ5-OJ8veMpK.js} +1 -1
  51. package/dist/assets/{chunk-ZIRB5QZD-XZdgBt5L.js → chunk-ZIRB5QZD-SR_Nq_PP.js} +1 -1
  52. package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +1 -0
  53. package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +1 -0
  54. package/dist/assets/config-split-page-D5BgtKrm.js +1 -0
  55. package/dist/assets/confirm-dialog-Bf907Azu.js +5 -0
  56. package/dist/assets/{cose-bilkent-JH36ORCC-B-PQoGX-.js → cose-bilkent-JH36ORCC-NjVgz2Bw.js} +1 -1
  57. package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +1 -0
  58. package/dist/assets/{cynefinDiagram-TSTJHNR4-BoLCPEM0.js → cynefinDiagram-TSTJHNR4-B_17LDqD.js} +1 -1
  59. package/dist/assets/{dagre-D7Ie4eXr.js → dagre-CMe101gk.js} +1 -1
  60. package/dist/assets/{dagre-VKFMJZFB-CKRrwZA-.js → dagre-VKFMJZFB-qo8nLb3B.js} +1 -1
  61. package/dist/assets/desktop-update-config-BwuyBPJb.js +1 -0
  62. package/dist/assets/{diagram-FQU43EPY-CASL1J3_.js → diagram-FQU43EPY-Ba3XIklC.js} +1 -1
  63. package/dist/assets/{diagram-G47NLZAW-CvLPBIzf.js → diagram-G47NLZAW-CG45TcUx.js} +1 -1
  64. package/dist/assets/{diagram-NH7WQ7WH-Ba6fGdYP.js → diagram-NH7WQ7WH-2F2HrwV-.js} +1 -1
  65. package/dist/assets/{diagram-OA4YK3LP-DkpfgEjM.js → diagram-OA4YK3LP-CXfWH9NZ.js} +1 -1
  66. package/dist/assets/{diagram-WEI45ONY-BP5UMVsN.js → diagram-WEI45ONY-CH_4yepc.js} +1 -1
  67. package/dist/assets/dist-CtLyEJeO.js +1 -0
  68. package/dist/assets/dist-dv_SUR54.js +1 -0
  69. package/dist/assets/doc-browser-C23NDGh5.js +1 -0
  70. package/dist/assets/doc-browser-DlOOhBxI.js +1 -0
  71. package/dist/assets/doc-browser-context-BIBjkwfV.js +1 -0
  72. package/dist/assets/{docx-preview-D0tp3a9T.js → docx-preview-CoM4JK7_.js} +1 -1
  73. package/dist/assets/{ebnfDiagram-CCIWWBDH-TJKbUcmc.js → ebnfDiagram-CCIWWBDH-BwiG4Ea1.js} +1 -1
  74. package/dist/assets/{erDiagram-Q63AITRT-DzGPKkKH.js → erDiagram-Q63AITRT-BML3hpnQ.js} +1 -1
  75. package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +1 -0
  76. package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +1 -0
  77. package/dist/assets/{form-actions-DvvxCpL4.js → form-actions-DAzi68Cn.js} +1 -1
  78. package/dist/assets/{ganttDiagram-NO4QXBWP-JhJzsGp2.js → ganttDiagram-NO4QXBWP-80enfWbD.js} +1 -1
  79. package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +1 -0
  80. package/dist/assets/{gitGraphDiagram-IHSO6WYX-DZ1CKMj8.js → gitGraphDiagram-IHSO6WYX-CVLqXr-b.js} +1 -1
  81. package/dist/assets/host-capabilities-D9C4CBK5.js +1 -0
  82. package/dist/assets/index-BLNg2yg0.css +1 -0
  83. package/dist/assets/index-D3EKjEyK.js +107 -0
  84. package/dist/assets/info-DKCQHKI2-DNlNGH90.js +1 -0
  85. package/dist/assets/{infoDiagram-FWYZ7A6U-BNXNKfRQ.js → infoDiagram-FWYZ7A6U-Dyvs2t0i.js} +1 -1
  86. package/dist/assets/{ishikawaDiagram-FXEZZL3T-DoiEfjNw.js → ishikawaDiagram-FXEZZL3T-sSnxDKfh.js} +1 -1
  87. package/dist/assets/{journeyDiagram-5HDEW3XC-D6oK2HSy.js → journeyDiagram-5HDEW3XC-D22V71Mf.js} +1 -1
  88. package/dist/assets/{kanban-definition-HUTT4EX6-B2UnLOH-.js → kanban-definition-HUTT4EX6-D3ds0p-g.js} +1 -1
  89. package/dist/assets/{line-BM7PoxY5.js → line-CbyFs065.js} +1 -1
  90. package/dist/assets/{linear-B3DiqMjk.js → linear-4DKtnZBS.js} +1 -1
  91. package/dist/assets/loader-circle-BSg5u0r4.js +1 -0
  92. package/dist/assets/{map-BAAdHTqR.js → map-CcZzEoz6.js} +1 -1
  93. package/dist/assets/mcp-marketplace-page-ByhvQQj5.js +9 -0
  94. package/dist/assets/mcp-marketplace-page-CytXwnUs.js +1 -0
  95. package/dist/assets/{mermaid-parser.core-BeMviefY.js → mermaid-parser.core-DPmMOjXD.js} +2 -2
  96. package/dist/assets/{mermaid.core-D0Q77r9I.js → mermaid.core-BSf-ddRa.js} +3 -3
  97. package/dist/assets/{mindmap-definition-LN4V7U3C-BQ7r7bR8.js → mindmap-definition-LN4V7U3C-BUTwWPyx.js} +1 -1
  98. package/dist/assets/model-config-page-bgEx3MjQ.js +1 -0
  99. package/dist/assets/navigation-link-CB0OQbnY.js +3 -0
  100. package/dist/assets/{ordinal-Bt2N4IkA.js → ordinal-BgLYtOZE.js} +1 -1
  101. package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +1 -0
  102. package/dist/assets/{pegDiagram-2B236MQR-B-C9-LGz.js → pegDiagram-2B236MQR-BEu_ZBjc.js} +1 -1
  103. package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +1 -0
  104. package/dist/assets/{pieDiagram-ENE6RG2P-CtirZLtn.js → pieDiagram-ENE6RG2P-CAwAwuBd.js} +1 -1
  105. package/dist/assets/plus-CNjWdLhZ.js +1 -0
  106. package/dist/assets/provider-scoped-model-input-8F6JMd2n.js +1 -0
  107. package/dist/assets/providers-config-page-CxpTjR81.js +1 -0
  108. package/dist/assets/{quadrantDiagram-ABIIQ3AL-DiBWAzDU.js → quadrantDiagram-ABIIQ3AL-CwE6F-_2.js} +1 -1
  109. package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +1 -0
  110. package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +1 -0
  111. package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +1 -0
  112. package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +1 -0
  113. package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +1 -0
  114. package/dist/assets/{railroadDiagram-RFXS5EU6-CP6b3PBI.js → railroadDiagram-RFXS5EU6-xgLekU3B.js} +1 -1
  115. package/dist/assets/react-Bk2ydNTe.js +8 -0
  116. package/dist/assets/{refresh-cw-C2e94pmp.js → refresh-cw-Ba0LZou4.js} +1 -1
  117. package/dist/assets/remote-Dv38PuMV.js +1 -0
  118. package/dist/assets/{requirementDiagram-TGXJPOKE-D8YV0-Jz.js → requirementDiagram-TGXJPOKE-CyVUzEX5.js} +1 -1
  119. package/dist/assets/rotate-cw-IkYVk9JX.js +1 -0
  120. package/dist/assets/runtime-config-page-C0ByyUVr.js +1 -0
  121. package/dist/assets/{sankeyDiagram-HTMAVEWB-C2vA4ojE.js → sankeyDiagram-HTMAVEWB-JK6bFmYB.js} +1 -1
  122. package/dist/assets/{save-CkwDOgvt.js → save-DTOAvqzt.js} +1 -1
  123. package/dist/assets/{search-CLXM2reO.js → search-D4X5DNMe.js} +1 -1
  124. package/dist/assets/search-config-page-Cr6254K5.js +1 -0
  125. package/dist/assets/{secrets-config-page-DQ_Curaj.js → secrets-config-page-W2Hx332d.js} +2 -2
  126. package/dist/assets/security-config-1E8OF4kR.js +1 -0
  127. package/dist/assets/select-CDv0g2Pj.js +41 -0
  128. package/dist/assets/{sequenceDiagram-DBY2YBRQ-B9LBmpUo.js → sequenceDiagram-DBY2YBRQ-BR5IokXV.js} +1 -1
  129. package/dist/assets/{settings-2-B9IT2HGd.js → settings-2-CoxzNABp.js} +1 -1
  130. package/dist/assets/{sizeCapture-X5ZJPWSS-9UIfya9-.js → sizeCapture-X5ZJPWSS-SxG_YnMA.js} +1 -1
  131. package/dist/assets/skeleton-DW018fJv.js +1 -0
  132. package/dist/assets/{src-DKf77Yzo.js → src-vgz8E_-O.js} +1 -1
  133. package/dist/assets/{stateDiagram-2N3HPSRC-oTW44vds.js → stateDiagram-2N3HPSRC-DD4OoYhn.js} +1 -1
  134. package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +1 -0
  135. package/dist/assets/{swimlanes-5IMT3BWC-Cf7lcsay.js → swimlanes-5IMT3BWC-BWkFeyCT.js} +2 -2
  136. package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +8 -0
  137. package/dist/assets/{tag-chip-CDkB5smU.js → tag-chip-CjkZEoS2.js} +1 -1
  138. package/dist/assets/{timeline-definition-FHXFAJF6-DoCuWKDJ.js → timeline-definition-FHXFAJF6-VTRPy6KA.js} +1 -1
  139. package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +1 -0
  140. package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +1 -0
  141. package/dist/assets/use-confirm-dialog-CavtY1vJ.js +1 -0
  142. package/dist/assets/{vennDiagram-L72KCM5P-CpU0pzGe.js → vennDiagram-L72KCM5P-Bvk42Pek.js} +1 -1
  143. package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +1 -0
  144. package/dist/assets/{wardleyDiagram-EHGQE667-CkN6nn6-.js → wardleyDiagram-EHGQE667-DOFjx2s3.js} +1 -1
  145. package/dist/assets/x-PTXYTEwz.js +1 -0
  146. package/dist/assets/{xychartDiagram-FW5EYKEG-DATpapm2.js → xychartDiagram-FW5EYKEG-DY5yRTUc.js} +1 -1
  147. package/dist/index.html +30 -32
  148. package/index.html +8 -0
  149. package/package.json +8 -8
  150. package/src/app/components/layout/page-layout.tsx +15 -6
  151. package/src/app/components/layout/sidebar-rail.styles.ts +0 -2
  152. package/src/app/components/layout/sidebar.tsx +2 -2
  153. package/src/app/styles/charcoal-theme.css +85 -0
  154. package/src/app/styles/design-system.css +23 -13
  155. package/src/features/agents/components/__tests__/agents-page.test.tsx +36 -24
  156. package/src/features/agents/components/agent-advanced-config-fields.tsx +7 -7
  157. package/src/features/agents/components/agent-details-dialog.tsx +8 -8
  158. package/src/features/agents/components/agent-dialogs.tsx +7 -7
  159. package/src/features/agents/components/agents-page.tsx +42 -62
  160. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +2 -2
  161. package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +46 -4
  162. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +17 -1
  163. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +8 -22
  164. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +69 -3
  165. package/src/features/chat/components/conversation/chat-conversation-content.tsx +24 -11
  166. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +30 -31
  167. package/src/features/chat/components/conversation/chat-conversation-header.tsx +1 -1
  168. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -8
  169. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +16 -4
  170. package/src/features/chat/components/layout/__tests__/chat-page-shell.test.tsx +23 -0
  171. package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +1 -1
  172. package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +52 -0
  173. package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +6 -0
  174. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +11 -17
  175. package/src/features/chat/components/layout/chat-page-shell.tsx +7 -15
  176. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +32 -42
  177. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +16 -67
  178. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +1 -4
  179. package/src/features/chat/components/providers/chat-presenter.provider.tsx +2 -0
  180. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +84 -12
  181. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +258 -9
  182. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +51 -34
  183. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +50 -39
  184. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +128 -1
  185. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +67 -1
  186. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-slash-commands.test.tsx +4 -0
  187. package/src/features/chat/features/conversation/hooks/__tests__/use-session-provider-model-catalog.test.tsx +109 -0
  188. package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +46 -0
  189. package/src/features/chat/features/conversation/hooks/use-session-conversation-composer-nodes.ts +26 -0
  190. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +45 -12
  191. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +1 -0
  192. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-query.ts +28 -3
  193. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +91 -37
  194. package/src/features/chat/features/conversation/hooks/use-session-conversation-recovery-actions.ts +64 -0
  195. package/src/features/chat/features/conversation/hooks/use-session-conversation-slash-commands.ts +2 -0
  196. package/src/features/chat/features/conversation/hooks/use-session-provider-model-catalog.ts +84 -0
  197. package/src/features/chat/features/conversation/utils/__tests__/session-message-composer.utils.test.ts +34 -0
  198. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +18 -0
  199. package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +117 -0
  200. package/src/features/chat/features/conversation/utils/session-queued-input.utils.ts +10 -97
  201. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +2 -1
  202. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +3 -1
  203. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
  204. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +23 -0
  205. package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +105 -0
  206. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +27 -2
  207. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +5 -0
  208. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +97 -32
  209. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +1 -1
  210. package/src/features/chat/features/input/utils/chat-input-toolbar.utils.ts +64 -10
  211. package/src/features/chat/features/message/components/__tests__/chat-message-assistant-header.container.test.tsx +149 -0
  212. package/src/features/chat/features/message/components/__tests__/chat-message-inline-editor.test.tsx +59 -0
  213. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +123 -90
  214. package/src/features/chat/features/message/components/__tests__/chat-message-timeline-dividers.test.tsx +43 -0
  215. package/src/features/chat/features/message/components/chat-message-inline-editor.tsx +111 -0
  216. package/src/features/chat/features/message/components/chat-message-list.container.tsx +81 -172
  217. package/src/features/chat/features/message/components/chat-message-timeline-dividers.tsx +75 -0
  218. package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +125 -0
  219. package/src/features/chat/features/message/hooks/use-chat-message-actions.tsx +187 -0
  220. package/src/features/chat/features/message/utils/__tests__/chat-message-action-targets.utils.test.ts +89 -0
  221. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-compaction.utils.test.ts +194 -0
  222. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline-continuation-compaction.utils.test.ts +167 -0
  223. package/src/features/chat/features/message/utils/__tests__/chat-message-timeline.utils.test.ts +203 -0
  224. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +26 -0
  225. package/src/features/chat/features/message/utils/chat-message-action-targets.utils.ts +28 -0
  226. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +38 -0
  227. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +1 -0
  228. package/src/features/chat/features/message/utils/chat-message-timeline.utils.ts +204 -7
  229. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-agent-runtime.test.tsx +180 -1
  230. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-conversation.test.tsx +184 -10
  231. package/src/features/chat/features/ncp/hooks/use-hydrated-ncp-agent.integration.test.tsx +57 -0
  232. package/src/features/chat/features/ncp/hooks/use-ncp-session-conversation.ts +90 -1
  233. package/src/features/chat/features/ncp/utils/__tests__/ncp-chat-query-derived.utils.test.ts +110 -0
  234. package/src/features/chat/features/ncp/utils/ncp-chat-query-derived.utils.ts +65 -3
  235. package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +10 -10
  236. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +2 -2
  237. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +17 -0
  238. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +63 -54
  239. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
  240. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +1 -1
  241. package/src/features/chat/features/session/components/session-header/chat-session-switcher-groups.tsx +1 -1
  242. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +1 -1
  243. package/src/features/chat/features/session/hooks/__tests__/use-selected-session-context-window-indicator.test.tsx +87 -0
  244. package/src/features/chat/features/session/utils/__tests__/chat-session-display.utils.test.ts +26 -0
  245. package/src/features/chat/features/session/utils/__tests__/ncp-session-adapter.utils.test.ts +23 -2
  246. package/src/features/chat/features/session/utils/chat-context-window-indicator.utils.ts +44 -5
  247. package/src/features/chat/features/session/utils/chat-session-display.utils.ts +48 -12
  248. package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +23 -4
  249. package/src/features/chat/features/session/utils/ncp-session-context-metadata.utils.ts +42 -4
  250. package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +6 -0
  251. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +27 -9
  252. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +1 -1
  253. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +11 -17
  254. package/src/features/chat/features/welcome/components/chat-welcome-prompt-suggestions.tsx +37 -0
  255. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +1 -1
  256. package/src/features/chat/features/welcome/components/chat-welcome.tsx +35 -33
  257. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +22 -6
  258. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +13 -0
  259. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +73 -3
  260. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +22 -2
  261. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +75 -0
  262. package/src/features/chat/features/workspace/components/__tests__/workspace-text-selection-menu.test.tsx +102 -0
  263. package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +145 -26
  264. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +42 -18
  265. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +50 -10
  266. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +48 -22
  267. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +13 -2
  268. package/src/features/chat/features/workspace/components/workspace-text-selection-menu.tsx +223 -0
  269. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +80 -0
  270. package/src/features/chat/features/workspace/utils/__tests__/workspace-text-excerpt.utils.test.ts +54 -0
  271. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +47 -0
  272. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +16 -0
  273. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +22 -1
  274. package/src/features/chat/features/workspace/utils/workspace-text-excerpt.utils.ts +53 -0
  275. package/src/features/chat/index.ts +1 -0
  276. package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +106 -0
  277. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +53 -5
  278. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +93 -1
  279. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +3 -10
  280. package/src/features/chat/managers/__tests__/provider-model-catalog-notice.manager.test.ts +57 -0
  281. package/src/features/chat/managers/chat-composer-intent.manager.ts +145 -0
  282. package/src/features/chat/managers/chat-session-list.manager.ts +14 -25
  283. package/src/features/chat/managers/chat-thread.manager.ts +32 -16
  284. package/src/features/chat/managers/provider-model-catalog-notice.manager.ts +121 -0
  285. package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +3 -9
  286. package/src/features/chat/pages/ncp-chat-page.tsx +0 -1
  287. package/src/features/chat/presenters/chat.presenter.ts +3 -0
  288. package/src/features/chat/stores/__tests__/chat-composer-draft.store.test.ts +55 -0
  289. package/src/features/chat/stores/chat-composer-draft.store.ts +92 -0
  290. package/src/features/chat/stores/chat-thread.store.ts +2 -4
  291. package/src/features/chat/types/chat-input-bar.types.ts +6 -0
  292. package/src/features/chat/types/chat-input.types.ts +5 -0
  293. package/src/features/chat/types/chat-message.types.ts +5 -0
  294. package/src/features/cron/components/__tests__/cron-config.test.tsx +100 -19
  295. package/src/features/cron/components/cron-config.tsx +19 -33
  296. package/src/features/cron/components/cron-job-detail-dialog.tsx +42 -16
  297. package/src/features/cron/components/cron-job-row.tsx +18 -1
  298. package/src/features/cron/components/cron-task-discovery.tsx +1 -1
  299. package/src/features/inbox/components/inbox-delivery-content.test.tsx +8 -2
  300. package/src/features/inbox/components/inbox-delivery-content.tsx +1 -1
  301. package/src/features/inbox/components/inbox-reader-dialog.test.tsx +10 -4
  302. package/src/features/inbox/components/inbox-reader-dialog.tsx +37 -61
  303. package/src/features/inbox/pages/inbox-page.tsx +90 -98
  304. package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
  305. package/src/features/notifications/components/__tests__/app-notification-toast.test.tsx +31 -6
  306. package/src/features/notifications/components/app-notification-toast.tsx +54 -15
  307. package/src/features/notifications/managers/__tests__/app-notification.manager.test.ts +2 -0
  308. package/src/features/notifications/managers/app-notification.manager.ts +3 -0
  309. package/src/features/panel-apps/components/panel-app-list-item.tsx +1 -1
  310. package/src/features/panel-apps/components/panel-app-toolbar.tsx +2 -2
  311. package/src/features/panel-apps/components/panel-apps-list.tsx +4 -4
  312. package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +1 -0
  313. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +9 -0
  314. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +1 -0
  315. package/src/features/service-apps/components/__tests__/service-apps-panel.test.tsx +5 -4
  316. package/src/features/service-apps/components/service-app-list-item.tsx +470 -0
  317. package/src/features/service-apps/components/service-apps-panel.tsx +76 -490
  318. package/src/features/settings/components/config/__tests__/provider-models-section.test.tsx +239 -0
  319. package/src/features/settings/components/config/provider-auth-section.tsx +90 -59
  320. package/src/features/settings/components/config/provider-form-detail-pane.tsx +307 -0
  321. package/src/features/settings/components/config/provider-form.tsx +149 -367
  322. package/src/features/settings/components/config/provider-model-list.tsx +293 -0
  323. package/src/features/settings/components/config/provider-model-suggestions-panel.tsx +151 -0
  324. package/src/features/settings/components/config/provider-models-section.tsx +178 -149
  325. package/src/features/settings/components/config/provider-status-badge.tsx +4 -2
  326. package/src/features/settings/hooks/__tests__/use-provider-connectivity.test.tsx +98 -0
  327. package/src/features/settings/hooks/__tests__/use-provider-model-suggestions.test.tsx +107 -0
  328. package/src/features/settings/hooks/use-provider-connectivity.ts +132 -0
  329. package/src/features/settings/hooks/use-provider-model-suggestions.ts +51 -0
  330. package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +2 -2
  331. package/src/features/settings/pages/__tests__/providers-config-page.test.tsx +12 -0
  332. package/src/features/settings/pages/__tests__/search-config-page.test.tsx +48 -0
  333. package/src/features/settings/pages/providers-config-page.tsx +2 -1
  334. package/src/features/settings/pages/search-config-page.tsx +17 -8
  335. package/src/features/settings/utils/__tests__/provider-form-support.utils.test.ts +42 -0
  336. package/src/features/settings/utils/provider-form-context.utils.ts +2 -0
  337. package/src/features/settings/utils/provider-form-model.utils.ts +25 -0
  338. package/src/features/settings/utils/provider-form-support.utils.ts +21 -5
  339. package/src/index.css +1 -1
  340. package/src/platforms/desktop/types/desktop-update.types.ts +5 -0
  341. package/src/platforms/mobile/components/__tests__/mobile-app-shell.test.tsx +13 -7
  342. package/src/platforms/mobile/components/__tests__/mobile-bottom-nav.test.tsx +18 -20
  343. package/src/shared/components/actions/__tests__/navigation-link.test.tsx +14 -3
  344. package/src/shared/components/actions/navigation-link.tsx +35 -15
  345. package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -2
  346. package/src/shared/components/common/agent-avatar.tsx +3 -3
  347. package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +66 -0
  348. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +5 -2
  349. package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +1 -0
  350. package/src/shared/components/doc-browser/doc-browser.tsx +9 -0
  351. package/src/shared/components/doc-browser/hooks/use-doc-browser-scroll-restoration.ts +126 -0
  352. package/src/shared/components/path-picker/server-path-picker-directory-list.tsx +1 -1
  353. package/src/shared/components/path-picker/server-path-picker-locations.tsx +1 -1
  354. package/src/shared/components/path-picker/server-path-picker-navigation-bar.tsx +3 -3
  355. package/src/shared/components/settings/settings-page.tsx +1 -1
  356. package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +1 -1
  357. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  358. package/src/shared/components/ui/button.tsx +4 -4
  359. package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +103 -0
  360. package/src/shared/components/ui/context-menu/context-menu.tsx +263 -0
  361. package/src/shared/components/ui/dialog.tsx +1 -1
  362. package/src/shared/components/ui/input.tsx +1 -1
  363. package/src/shared/components/ui/scroll-area.tsx +2 -0
  364. package/src/shared/components/ui/select.tsx +1 -1
  365. package/src/shared/components/ui/switch.tsx +1 -1
  366. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +19 -6
  367. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +28 -67
  368. package/src/shared/components/ui/tabs.tsx +1 -1
  369. package/src/shared/components/ui/textarea.tsx +1 -1
  370. package/src/shared/hooks/use-config.ts +33 -1
  371. package/src/shared/lib/api/__tests__/ncp-session-query-cache.utils.test.ts +26 -0
  372. package/src/shared/lib/api/ncp-session-query-cache.utils.ts +7 -10
  373. package/src/shared/lib/api/ncp-session.types.ts +7 -0
  374. package/src/shared/lib/api/types.ts +38 -1
  375. package/src/shared/lib/api/utils/config.utils.ts +14 -0
  376. package/src/shared/lib/cron/cron-job-view.utils.ts +4 -0
  377. package/src/shared/lib/host-capabilities/__tests__/host-capability.manager.test.ts +26 -0
  378. package/src/shared/lib/host-capabilities/host-capability.manager.ts +28 -0
  379. package/src/shared/lib/i18n/locales/en-US/chat.json +45 -17
  380. package/src/shared/lib/i18n/locales/en-US/core.json +26 -0
  381. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +1 -0
  382. package/src/shared/lib/i18n/locales/en-US/search.json +1 -0
  383. package/src/shared/lib/i18n/locales/zh-CN/chat.json +45 -17
  384. package/src/shared/lib/i18n/locales/zh-CN/core.json +26 -0
  385. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +1 -0
  386. package/src/shared/lib/i18n/locales/zh-CN/search.json +1 -0
  387. package/src/shared/lib/provider-models/__tests__/anonymous-provider-configuration.test.ts +40 -0
  388. package/src/shared/lib/provider-models/index.ts +4 -3
  389. package/src/shared/lib/session-project/__tests__/workspace-file-breadcrumb.test.ts +28 -1
  390. package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +23 -0
  391. package/src/shared/lib/theme/index.test.ts +11 -0
  392. package/src/shared/lib/theme/index.ts +2 -0
  393. package/dist/assets/api-CHo2gekJ.js +0 -13
  394. package/dist/assets/app-presenter-provider-2_DmWYT9.js +0 -108
  395. package/dist/assets/app-presenter-provider-D3BuuOyZ.css +0 -1
  396. package/dist/assets/appearance-settings-page-BEy2UE7R.js +0 -1
  397. package/dist/assets/architecture-TIHT7OUA-Cii4JyA2.js +0 -1
  398. package/dist/assets/book-open-BrZL4o9L.js +0 -1
  399. package/dist/assets/card-B5rRLu_6.js +0 -1
  400. package/dist/assets/channel-BSKkTPe8.js +0 -1
  401. package/dist/assets/channels-list-page-C1dnm68I.js +0 -8
  402. package/dist/assets/chat-page-Dz6tvZ91.js +0 -1
  403. package/dist/assets/chunk-2Q5K7J3B-CDMOR1xZ.js +0 -1
  404. package/dist/assets/chunk-VAUOI2AC-BRvqNW76.js +0 -1
  405. package/dist/assets/chunk-XXDRQBXY-CwX_mqJ3.js +0 -1
  406. package/dist/assets/classDiagram-OUVF2IWQ-RzbGxG77.js +0 -1
  407. package/dist/assets/classDiagram-v2-EOCWNBFH-C_gWB7WT.js +0 -1
  408. package/dist/assets/config-split-page-6y6W6dz4.js +0 -1
  409. package/dist/assets/confirm-dialog-q1CpEmR8.js +0 -5
  410. package/dist/assets/cynefin-VYW2F7L2-fSLIS0X3.js +0 -1
  411. package/dist/assets/desktop-update-config-DrdlwP4j.js +0 -1
  412. package/dist/assets/dist-C9EX46wM.js +0 -41
  413. package/dist/assets/doc-browser-BfttDSti.js +0 -1
  414. package/dist/assets/doc-browser-DH-3hDnI.js +0 -1
  415. package/dist/assets/doc-browser-context-TU2heon0.js +0 -1
  416. package/dist/assets/eventmodeling-45OFAUF4-XVcQGgha.js +0 -1
  417. package/dist/assets/eye-B-3dyZNA.js +0 -1
  418. package/dist/assets/flowDiagram-23GEKE2U-BiFSctqz.js +0 -1
  419. package/dist/assets/gitGraph-TEB2WS4Q-C014uXqS.js +0 -1
  420. package/dist/assets/host-capabilities-B-TtABsP.js +0 -1
  421. package/dist/assets/index-CXDPLDFD.css +0 -1
  422. package/dist/assets/index-k_eWScvN.js +0 -2
  423. package/dist/assets/info-DKCQHKI2-CQ2qjGhU.js +0 -1
  424. package/dist/assets/loader-circle-B35NlHTI.js +0 -1
  425. package/dist/assets/logo-badge-DB51c0cS.js +0 -1
  426. package/dist/assets/mcp-marketplace-page-CkPtwPBk.js +0 -1
  427. package/dist/assets/mcp-marketplace-page-DWtsIqml.js +0 -9
  428. package/dist/assets/model-config-page-D6cGNnMM.js +0 -1
  429. package/dist/assets/navigation-link-BSJEUiwD.js +0 -1
  430. package/dist/assets/packet-7NZHBO7P-6IFyydij.js +0 -1
  431. package/dist/assets/pie-RZYD4A2V-spXQC_wr.js +0 -1
  432. package/dist/assets/plus-BRVe5jSJ.js +0 -1
  433. package/dist/assets/popover-Bp9IpE_N.js +0 -1
  434. package/dist/assets/provider-models-CXUgDxGR.js +0 -1
  435. package/dist/assets/provider-scoped-model-input-dk7fz9NL.js +0 -1
  436. package/dist/assets/providers-config-page-DTP2YfxA.js +0 -1
  437. package/dist/assets/radar-I7S5WNFK-DWVA8lvY.js +0 -1
  438. package/dist/assets/railroad-3IZDKUUU-Ce51u8y1.js +0 -1
  439. package/dist/assets/railroad-abnf-AHOZXSZD-D7i7cqI_.js +0 -1
  440. package/dist/assets/railroad-ebnf-EBAXGLYW-BEg2hcPs.js +0 -1
  441. package/dist/assets/railroad-peg-LSFZ7HO6-CxROSzbi.js +0 -1
  442. package/dist/assets/react-D6ShNq95.js +0 -8
  443. package/dist/assets/remote-FllhXW3o.js +0 -1
  444. package/dist/assets/rotate-cw-CTC-Qszi.js +0 -1
  445. package/dist/assets/runtime-config-page-C57OLdPm.js +0 -1
  446. package/dist/assets/search-config-page-tnJXaaSr.js +0 -1
  447. package/dist/assets/security-config-S00DjFfO.js +0 -1
  448. package/dist/assets/select-CNFBf00l.js +0 -1
  449. package/dist/assets/skeleton-Dc06gatK.js +0 -1
  450. package/dist/assets/stateDiagram-v2-6OUMAXLB-Bui4RXQK.js +0 -1
  451. package/dist/assets/swimlanesDiagram-G3AALYLV-DTwUsCBz.js +0 -8
  452. package/dist/assets/tabs-BuNr8LSO.js +0 -1
  453. package/dist/assets/trash-2-GchaJuEM.js +0 -1
  454. package/dist/assets/treeView-QDETBFTQ-D5zsTiuL.js +0 -1
  455. package/dist/assets/treemap-6X3UGDF4-CR3dxqNs.js +0 -1
  456. package/dist/assets/use-config-C69rR15i.js +0 -1
  457. package/dist/assets/use-confirm-dialog-DF_EgPYx.js +0 -1
  458. package/dist/assets/use-viewport-layout-BACNZyMY.js +0 -1
  459. package/dist/assets/wardley-OPB4EBWU-LatRT_Lx.js +0 -1
  460. package/dist/assets/x-BXFquY9e.js +0 -1
  461. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +0 -59
  462. /package/dist/assets/{array-CAkJT3no.js → array-NADKd9aU.js} +0 -0
  463. /package/dist/assets/{chunk-KEIR6QF5-BgdDoWEH.js → chunk-KEIR6QF5-BuyuzJJL.js} +0 -0
  464. /package/dist/assets/{chunk-Y2CYZVJY-pTllD0P3.js → chunk-Y2CYZVJY-D_B2ZRNt.js} +0 -0
  465. /package/dist/assets/{config-hints-S3g-UVZb.js → config-hints-BcfVUMij.js} +0 -0
  466. /package/dist/assets/{cytoscape.esm-DmURt-5G.js → cytoscape.esm-BANTlgza.js} +0 -0
  467. /package/dist/assets/{defaultLocale-BKy_KP3O.js → defaultLocale-C4_L0aEs.js} +0 -0
  468. /package/dist/assets/{dist-IgNNB7K9.js → dist-DAPEIJbz.js} +0 -0
  469. /package/dist/assets/{graphlib-xw_TBHyH.js → graphlib-ChqXg0dI.js} +0 -0
  470. /package/dist/assets/{init-C9xlLIAu.js → init-D8wZg9xq.js} +0 -0
  471. /package/dist/assets/{jszip.min-Das2IAnb.js → jszip.min-CkbBfwAQ.js} +0 -0
  472. /package/dist/assets/{katex-DSy1eD2d.js → katex-TZJFa0J_.js} +0 -0
  473. /package/dist/assets/{middleware-Df-a4x-q.js → middleware-B3k-TSmZ.js} +0 -0
  474. /package/dist/assets/{path-DB0USYHi.js → path-DodfxcX7.js} +0 -0
  475. /package/dist/assets/{rough.esm-B1B52ZQS.js → rough.esm-CUaa1Rbe.js} +0 -0
  476. /package/dist/assets/{xlsx-DfjC_iml.js → xlsx-CxByi7bR.js} +0 -0
@@ -0,0 +1,223 @@
1
+ import {
2
+ useCallback,
3
+ useEffect,
4
+ useRef,
5
+ useState,
6
+ type ReactNode,
7
+ } from "react";
8
+ import { createPortal } from "react-dom";
9
+ import { MessageSquarePlus } from "lucide-react";
10
+ import {
11
+ buildWorkspaceTextExcerpt,
12
+ WORKSPACE_TEXT_EXCERPT_MAX_CHARACTERS,
13
+ type WorkspaceTextExcerpt,
14
+ } from "@/features/chat/features/workspace/utils/workspace-text-excerpt.utils";
15
+ import { t } from "@/shared/lib/i18n";
16
+
17
+ type SelectionMenuState = {
18
+ anchorBottom: number;
19
+ anchorCenter: number;
20
+ anchorTop: number;
21
+ excerpt: WorkspaceTextExcerpt;
22
+ tooLong: boolean;
23
+ };
24
+
25
+ type SelectionMenuPosition = {
26
+ left: number;
27
+ top: number;
28
+ };
29
+
30
+ const SELECTION_MENU_VIEWPORT_GAP = 12;
31
+ const SELECTION_MENU_ANCHOR_GAP = 10;
32
+
33
+ function containsSelection(
34
+ root: HTMLElement,
35
+ selection: Selection,
36
+ ): selection is Selection & { rangeCount: number } {
37
+ if (selection.rangeCount === 0 || selection.isCollapsed) {
38
+ return false;
39
+ }
40
+ const range = selection.getRangeAt(0);
41
+ return root.contains(range.commonAncestorContainer);
42
+ }
43
+
44
+ function getSelectionAnchorRect(range: Range): DOMRect {
45
+ const rects = typeof range.getClientRects === "function"
46
+ ? Array.from(range.getClientRects()).filter((rect) => rect.width > 0 || rect.height > 0)
47
+ : [];
48
+ return rects.at(-1) ?? range.getBoundingClientRect();
49
+ }
50
+
51
+ function clamp(value: number, minimum: number, maximum: number): number {
52
+ return Math.min(Math.max(value, minimum), Math.max(minimum, maximum));
53
+ }
54
+
55
+ export function WorkspaceTextSelectionMenu({
56
+ children,
57
+ fileLabel,
58
+ filePath,
59
+ onAddToChat,
60
+ sourceStartLine,
61
+ sourceText,
62
+ }: {
63
+ children: ReactNode;
64
+ fileLabel: string;
65
+ filePath: string;
66
+ onAddToChat?: (excerpt: WorkspaceTextExcerpt) => void;
67
+ sourceStartLine?: number | null;
68
+ sourceText: string;
69
+ }) {
70
+ const rootRef = useRef<HTMLDivElement>(null);
71
+ const menuButtonRef = useRef<HTMLButtonElement | null>(null);
72
+ const selectionReadFrameRef = useRef<number | null>(null);
73
+ const [menu, setMenu] = useState<SelectionMenuState | null>(null);
74
+ const [menuPosition, setMenuPosition] = useState<SelectionMenuPosition | null>(null);
75
+
76
+ const readSelection = useCallback(() => {
77
+ const root = rootRef.current;
78
+ const selection = window.getSelection();
79
+ if (!root || !selection || !containsSelection(root, selection)) {
80
+ setMenu(null);
81
+ return;
82
+ }
83
+ const excerpt = buildWorkspaceTextExcerpt({
84
+ path: filePath,
85
+ label: fileLabel,
86
+ selectedText: selection.toString(),
87
+ sourceText,
88
+ sourceStartLine,
89
+ });
90
+ if (!excerpt) {
91
+ setMenu(null);
92
+ return;
93
+ }
94
+ const rect = getSelectionAnchorRect(selection.getRangeAt(0));
95
+ setMenuPosition(null);
96
+ setMenu({
97
+ anchorBottom: rect.bottom,
98
+ anchorCenter: rect.left + rect.width / 2,
99
+ anchorTop: rect.top,
100
+ excerpt,
101
+ tooLong: excerpt.excerpt.length > WORKSPACE_TEXT_EXCERPT_MAX_CHARACTERS,
102
+ });
103
+ }, [fileLabel, filePath, sourceStartLine, sourceText]);
104
+
105
+ const scheduleSelectionRead = useCallback(() => {
106
+ if (selectionReadFrameRef.current !== null) {
107
+ window.cancelAnimationFrame(selectionReadFrameRef.current);
108
+ }
109
+ selectionReadFrameRef.current = window.requestAnimationFrame(() => {
110
+ selectionReadFrameRef.current = null;
111
+ readSelection();
112
+ });
113
+ }, [readSelection]);
114
+
115
+ const captureMenuButton = useCallback((button: HTMLButtonElement | null) => {
116
+ menuButtonRef.current = button;
117
+ if (!menu || !button) {
118
+ return;
119
+ }
120
+ const buttonRect = button.getBoundingClientRect();
121
+ const left = clamp(
122
+ menu.anchorCenter - buttonRect.width / 2,
123
+ SELECTION_MENU_VIEWPORT_GAP,
124
+ window.innerWidth - SELECTION_MENU_VIEWPORT_GAP - buttonRect.width,
125
+ );
126
+ const belowTop = menu.anchorBottom + SELECTION_MENU_ANCHOR_GAP;
127
+ const aboveTop = menu.anchorTop - SELECTION_MENU_ANCHOR_GAP - buttonRect.height;
128
+ const fitsBelow = belowTop + buttonRect.height <= window.innerHeight - SELECTION_MENU_VIEWPORT_GAP;
129
+ const preferredTop = fitsBelow ? belowTop : aboveTop;
130
+ const top = clamp(
131
+ preferredTop,
132
+ SELECTION_MENU_VIEWPORT_GAP,
133
+ window.innerHeight - SELECTION_MENU_VIEWPORT_GAP - buttonRect.height,
134
+ );
135
+ setMenuPosition({ left, top });
136
+ }, [menu]);
137
+
138
+ useEffect(() => {
139
+ const handleSelectionChange = () => {
140
+ const selection = window.getSelection();
141
+ if (!selection || selection.isCollapsed) {
142
+ setMenu(null);
143
+ return;
144
+ }
145
+ scheduleSelectionRead();
146
+ };
147
+ const handlePointerUp = (event: PointerEvent) => {
148
+ if (menuButtonRef.current?.contains(event.target as Node)) {
149
+ return;
150
+ }
151
+ scheduleSelectionRead();
152
+ };
153
+ const handleKeyDown = (event: KeyboardEvent) => {
154
+ if (event.key === "Escape") {
155
+ setMenu(null);
156
+ }
157
+ };
158
+ const closeMenu = () => setMenu(null);
159
+ document.addEventListener("selectionchange", handleSelectionChange);
160
+ document.addEventListener("pointerup", handlePointerUp, true);
161
+ document.addEventListener("keydown", handleKeyDown);
162
+ document.addEventListener("scroll", closeMenu, true);
163
+ window.addEventListener("resize", closeMenu);
164
+ return () => {
165
+ document.removeEventListener("selectionchange", handleSelectionChange);
166
+ document.removeEventListener("pointerup", handlePointerUp, true);
167
+ document.removeEventListener("keydown", handleKeyDown);
168
+ document.removeEventListener("scroll", closeMenu, true);
169
+ window.removeEventListener("resize", closeMenu);
170
+ if (selectionReadFrameRef.current !== null) {
171
+ window.cancelAnimationFrame(selectionReadFrameRef.current);
172
+ }
173
+ };
174
+ }, [scheduleSelectionRead]);
175
+
176
+ const addSelectionToChat = () => {
177
+ if (!menu || menu.tooLong) {
178
+ return;
179
+ }
180
+ onAddToChat?.(menu.excerpt);
181
+ window.getSelection()?.removeAllRanges();
182
+ setMenu(null);
183
+ };
184
+
185
+ const menuNode = menu && onAddToChat
186
+ ? createPortal(
187
+ <button
188
+ ref={captureMenuButton}
189
+ type="button"
190
+ className="fixed z-[var(--z-popover,10100)] inline-flex max-w-[calc(100vw-24px)] items-center gap-1.5 overflow-hidden whitespace-nowrap rounded-xl border border-border bg-popover px-3 py-2 text-xs font-medium text-popover-foreground shadow-lg transition-colors hover:bg-[var(--interaction-hover)] hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 disabled:cursor-not-allowed disabled:text-muted-foreground"
191
+ style={{
192
+ left: menuPosition?.left ?? 0,
193
+ top: menuPosition?.top ?? 0,
194
+ visibility: menuPosition ? "visible" : "hidden",
195
+ }}
196
+ disabled={menu.tooLong}
197
+ onMouseDown={(event) => event.preventDefault()}
198
+ onClick={addSelectionToChat}
199
+ >
200
+ <MessageSquarePlus aria-hidden="true" className="h-3.5 w-3.5 shrink-0" />
201
+ <span className="truncate">
202
+ {menu.tooLong
203
+ ? t("chatWorkspaceExcerptSelectionTooLong")
204
+ : t("chatWorkspaceAddToChat")}
205
+ </span>
206
+ </button>,
207
+ document.body,
208
+ )
209
+ : null;
210
+
211
+ return (
212
+ <div
213
+ ref={rootRef}
214
+ className="h-full min-h-0"
215
+ data-workspace-text-selection-root="true"
216
+ onMouseUp={scheduleSelectionRead}
217
+ onKeyUp={scheduleSelectionRead}
218
+ >
219
+ {children}
220
+ {menuNode}
221
+ </div>
222
+ );
223
+ }
@@ -153,6 +153,7 @@ describe("fixed workspace tabs", () => {
153
153
  };
154
154
  const onCloseTab = vi.fn();
155
155
  const tabs = buildWorkspaceTabsViewModel({
156
+ hasSession: true,
156
157
  resolvedChildTabs: [childTab],
157
158
  activeSideChatDraft: draft,
158
159
  closedWorkspaceTabEntries: [],
@@ -194,6 +195,7 @@ describe("fixed workspace tabs", () => {
194
195
 
195
196
  it("keeps fixed workspace tabs even when legacy closed entries exist", () => {
196
197
  const tabs = buildWorkspaceTabsViewModel({
198
+ hasSession: true,
197
199
  resolvedChildTabs: [createChildTab()],
198
200
  activeSideChatDraft: null,
199
201
  closedWorkspaceTabEntries: [
@@ -227,6 +229,7 @@ describe("fixed workspace tabs", () => {
227
229
  setLanguage("zh");
228
230
 
229
231
  const tabs = buildWorkspaceTabsViewModel({
232
+ hasSession: true,
230
233
  resolvedChildTabs: [],
231
234
  activeSideChatDraft: null,
232
235
  closedWorkspaceTabEntries: [],
@@ -264,6 +267,7 @@ describe("buildWorkspaceTabsViewModel", () => {
264
267
  const onSelectSession = vi.fn();
265
268
 
266
269
  const tabs = buildWorkspaceTabsViewModel({
270
+ hasSession: true,
267
271
  resolvedChildTabs: [childTab],
268
272
  activeSideChatDraft: null,
269
273
  closedWorkspaceTabEntries: [],
@@ -300,6 +304,7 @@ describe("buildWorkspaceTabsViewModel", () => {
300
304
  const childTab = createChildTab();
301
305
 
302
306
  const tabs = buildWorkspaceTabsViewModel({
307
+ hasSession: true,
303
308
  resolvedChildTabs: [childTab],
304
309
  activeSideChatDraft: draft,
305
310
  closedWorkspaceTabEntries: [],
@@ -353,6 +358,7 @@ describe("buildWorkspaceTabsViewModel", () => {
353
358
 
354
359
  const onOpenFileViewer = vi.fn();
355
360
  const tabs = buildWorkspaceTabsViewModel({
361
+ hasSession: true,
356
362
  resolvedChildTabs: [],
357
363
  activeSideChatDraft: null,
358
364
  closedWorkspaceTabEntries: [],
@@ -401,4 +407,78 @@ describe("buildWorkspaceTabsViewModel", () => {
401
407
  "rendered",
402
408
  );
403
409
  });
410
+
411
+ it("adds project files to chat with a normalized relative reference", () => {
412
+ const onAddFileToChat = vi.fn();
413
+ const projectFile = {
414
+ key: "project-file",
415
+ parentSessionKey: "parent-1",
416
+ path: "/workspace/docs/guide.md",
417
+ viewMode: "preview" as const,
418
+ };
419
+ const externalFile = {
420
+ key: "external-file",
421
+ parentSessionKey: "parent-1",
422
+ path: "/tmp/notes.md",
423
+ viewMode: "preview" as const,
424
+ };
425
+
426
+ const tabs = buildWorkspaceTabsViewModel({
427
+ hasSession: true,
428
+ resolvedChildTabs: [],
429
+ activeSideChatDraft: null,
430
+ closedWorkspaceTabEntries: [],
431
+ workspaceFileTabs: [projectFile, externalFile],
432
+ activeSelection: { kind: "file", file: projectFile },
433
+ optimisticReadAtBySessionKey: {},
434
+ sessionProjectRoot: "/workspace",
435
+ onAddFileToChat,
436
+ onSelectSession: vi.fn(),
437
+ onSelectFile: vi.fn(),
438
+ onOpenFileViewer: vi.fn(),
439
+ onCloseTab: vi.fn(),
440
+ onSelectOverview: vi.fn(),
441
+ onSelectChildSessions: vi.fn(),
442
+ onSelectProjectFiles: vi.fn(),
443
+ onSelectCronJobs: vi.fn(),
444
+ });
445
+
446
+ tabs.find((tab) => tab.key === "file:project-file")?.onAddToChat?.();
447
+
448
+ expect(onAddFileToChat).toHaveBeenCalledWith({
449
+ label: "guide.md",
450
+ tokenKey: "docs/guide.md",
451
+ });
452
+ expect(
453
+ tabs.find((tab) => tab.key === "file:external-file")?.onAddToChat,
454
+ ).toBeUndefined();
455
+ });
456
+
457
+ it("shows only project files before a draft session is materialized", () => {
458
+ const tabs = buildWorkspaceTabsViewModel({
459
+ hasSession: false,
460
+ resolvedChildTabs: [],
461
+ activeSideChatDraft: null,
462
+ closedWorkspaceTabEntries: [],
463
+ workspaceFileTabs: [],
464
+ activeSelection: { kind: "project-files" },
465
+ optimisticReadAtBySessionKey: {},
466
+ onSelectSession: vi.fn(),
467
+ onSelectFile: vi.fn(),
468
+ onOpenFileViewer: vi.fn(),
469
+ onCloseTab: vi.fn(),
470
+ onSelectOverview: vi.fn(),
471
+ onSelectChildSessions: vi.fn(),
472
+ onSelectProjectFiles: vi.fn(),
473
+ onSelectCronJobs: vi.fn(),
474
+ });
475
+
476
+ expect(tabs).toEqual([
477
+ expect.objectContaining({
478
+ key: "project-files",
479
+ kind: "project-files",
480
+ active: true,
481
+ }),
482
+ ]);
483
+ });
404
484
  });
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { buildWorkspaceTextExcerpt } from "@/features/chat/features/workspace/utils/workspace-text-excerpt.utils";
3
+
4
+ describe("buildWorkspaceTextExcerpt", () => {
5
+ it("keeps the exact snapshot and maps a cross-line selection", () => {
6
+ expect(buildWorkspaceTextExcerpt({
7
+ path: "docs/guide.md",
8
+ label: "guide.md",
9
+ selectedText: "second\nthird",
10
+ sourceText: "first\nsecond\nthird\nfourth",
11
+ sourceStartLine: 10,
12
+ })).toEqual({
13
+ path: "docs/guide.md",
14
+ label: "guide.md",
15
+ excerpt: "second\nthird",
16
+ startLine: 11,
17
+ endLine: 12,
18
+ });
19
+ });
20
+
21
+ it("keeps a rendered selection without inventing a source position", () => {
22
+ expect(buildWorkspaceTextExcerpt({
23
+ path: "README.md",
24
+ label: "README.md",
25
+ selectedText: "Rendered sentence",
26
+ sourceText: "**Rendered** sentence",
27
+ })).toMatchObject({
28
+ excerpt: "Rendered sentence",
29
+ startLine: null,
30
+ endLine: null,
31
+ });
32
+ });
33
+
34
+ it("omits a line number when repeated text makes the location ambiguous", () => {
35
+ expect(buildWorkspaceTextExcerpt({
36
+ path: "src/example.ts",
37
+ label: "example.ts",
38
+ selectedText: "return value;",
39
+ sourceText: "return value;\nnext();\nreturn value;",
40
+ })).toMatchObject({
41
+ startLine: null,
42
+ endLine: null,
43
+ });
44
+ });
45
+
46
+ it("rejects whitespace-only selections", () => {
47
+ expect(buildWorkspaceTextExcerpt({
48
+ path: "README.md",
49
+ label: "README.md",
50
+ selectedText: " \n ",
51
+ sourceText: "content",
52
+ })).toBeNull();
53
+ });
54
+ });
@@ -8,6 +8,7 @@ import {
8
8
  filterNavigationHistoryEntries,
9
9
  pushNavigationHistoryEntry,
10
10
  } from "@/shared/lib/navigation-history";
11
+ import { reparentWorkspaceFileTab } from "@/features/chat/features/workspace/utils/chat-workspace-file-tab.utils";
11
12
 
12
13
  export function areWorkspaceNavigationEntriesEqual(
13
14
  current: ChatWorkspaceNavigationEntry,
@@ -206,6 +207,52 @@ export function upsertChildSessionTab(
206
207
  return nextTabs;
207
208
  }
208
209
 
210
+ export function materializeDraftWorkspaceSnapshot(
211
+ snapshot: ChatThreadSnapshot,
212
+ sessionKey: string,
213
+ ): Partial<ChatThreadSnapshot> | null {
214
+ const normalizedSessionKey = sessionKey.trim();
215
+ if (!normalizedSessionKey) {
216
+ return null;
217
+ }
218
+ const materializedFileKeys = new Map<string, string>();
219
+ const workspaceFileTabs = snapshot.workspaceFileTabs.map((tab) => {
220
+ if (tab.parentSessionKey !== null) {
221
+ return tab;
222
+ }
223
+ const materializedTab = reparentWorkspaceFileTab(tab, normalizedSessionKey);
224
+ materializedFileKeys.set(tab.key, materializedTab.key);
225
+ return materializedTab;
226
+ });
227
+ const materializeNavigationEntry = (
228
+ entry: ChatWorkspaceNavigationEntry,
229
+ ): ChatWorkspaceNavigationEntry => {
230
+ if (entry.kind !== 'file') {
231
+ return entry;
232
+ }
233
+ const materializedKey = materializedFileKeys.get(entry.key);
234
+ return materializedKey ? { ...entry, key: materializedKey } : entry;
235
+ };
236
+ return {
237
+ draftProjectRoot: null,
238
+ workspaceFileTabs,
239
+ activeWorkspaceFileKey: snapshot.activeWorkspaceFileKey
240
+ ? materializedFileKeys.get(snapshot.activeWorkspaceFileKey) ??
241
+ snapshot.activeWorkspaceFileKey
242
+ : null,
243
+ closedWorkspaceTabEntries: snapshot.closedWorkspaceTabEntries.map(
244
+ materializeNavigationEntry,
245
+ ),
246
+ workspaceNavigationHistory: snapshot.workspaceNavigationHistory.map(
247
+ materializeNavigationEntry,
248
+ ),
249
+ workspacePanelParentKey:
250
+ snapshot.workspacePanelParentKey === null && snapshot.activeWorkspacePanelKind
251
+ ? normalizedSessionKey
252
+ : snapshot.workspacePanelParentKey,
253
+ };
254
+ }
255
+
209
256
  export function materializeSideChatDraftSnapshot(params: {
210
257
  snapshot: ChatThreadSnapshot;
211
258
  draftKey: string;
@@ -65,3 +65,19 @@ export function upsertWorkspaceFileTab(
65
65
  ...tabs.slice(adjacentIndex + 1),
66
66
  ];
67
67
  }
68
+
69
+ export function reparentWorkspaceFileTab(
70
+ tab: ChatWorkspaceFileTab,
71
+ parentSessionKey: string,
72
+ ): ChatWorkspaceFileTab {
73
+ const normalizedParentSessionKey = parentSessionKey.trim();
74
+ const identitySeparatorIndex = tab.key.indexOf('::');
75
+ const tabIdentity = identitySeparatorIndex >= 0
76
+ ? tab.key.slice(identitySeparatorIndex)
77
+ : `::${tab.key}`;
78
+ return {
79
+ ...tab,
80
+ key: `${normalizedParentSessionKey}${tabIdentity}`,
81
+ parentSessionKey: normalizedParentSessionKey,
82
+ };
83
+ }
@@ -13,6 +13,7 @@ import {
13
13
  type ChatWorkspaceFileViewer,
14
14
  } from "@/features/chat/features/workspace/utils/chat-workspace-file-viewer.utils";
15
15
  import { areWorkspaceNavigationEntriesEqual } from "@/features/chat/features/workspace/utils/chat-thread-workspace-session.utils";
16
+ import { resolveWorkspaceRelativePath } from "@/shared/lib/session-project";
16
17
 
17
18
  export type WorkspaceSelection =
18
19
  | {
@@ -56,6 +57,7 @@ export type WorkspaceTabViewModel = {
56
57
  viewer: ChatWorkspaceFileViewer;
57
58
  onSelect: () => void;
58
59
  } | null;
60
+ onAddToChat?: () => void;
59
61
  onSelect: () => void;
60
62
  onClose?: () => void;
61
63
  };
@@ -154,12 +156,15 @@ export function resolveWorkspaceSelection(params: {
154
156
  }
155
157
 
156
158
  type WorkspaceTabsViewModelParams = {
159
+ hasSession: boolean;
157
160
  resolvedChildTabs: ResolvedChildSessionTab[];
158
161
  activeSideChatDraft: ChatWorkspaceSideChatDraft | null;
159
162
  closedWorkspaceTabEntries: readonly ChatWorkspaceNavigationEntry[];
160
163
  workspaceFileTabs: readonly ChatWorkspaceFileTab[];
161
164
  activeSelection: WorkspaceSelection | null;
162
165
  optimisticReadAtBySessionKey: Record<string, string>;
166
+ sessionProjectRoot?: string | null;
167
+ onAddFileToChat?: (reference: { label: string; tokenKey: string }) => void;
163
168
  onSelectSession: (sessionKey: string) => void;
164
169
  onSelectFile: (fileKey: string) => void;
165
170
  onOpenFileViewer: (fileKey: string, viewer: ChatWorkspaceFileViewer) => void;
@@ -172,6 +177,7 @@ type WorkspaceTabsViewModelParams = {
172
177
 
173
178
  function buildWorkspacePageTabs({
174
179
  activeSelection,
180
+ hasSession,
175
181
  onSelectChildSessions,
176
182
  onSelectCronJobs,
177
183
  onSelectOverview,
@@ -179,12 +185,13 @@ function buildWorkspacePageTabs({
179
185
  }: Pick<
180
186
  WorkspaceTabsViewModelParams,
181
187
  | "activeSelection"
188
+ | "hasSession"
182
189
  | "onSelectChildSessions"
183
190
  | "onSelectCronJobs"
184
191
  | "onSelectOverview"
185
192
  | "onSelectProjectFiles"
186
193
  >): WorkspaceTabViewModel[] {
187
- return [
194
+ const pageTabs: WorkspaceTabViewModel[] = [
188
195
  {
189
196
  key: "overview",
190
197
  kind: "overview",
@@ -218,18 +225,24 @@ function buildWorkspacePageTabs({
218
225
  onSelect: onSelectProjectFiles,
219
226
  },
220
227
  ];
228
+ return hasSession
229
+ ? pageTabs
230
+ : pageTabs.filter((tab) => tab.kind === "project-files");
221
231
  }
222
232
 
223
233
  export function buildWorkspaceTabsViewModel(
224
234
  params: WorkspaceTabsViewModelParams,
225
235
  ): WorkspaceTabViewModel[] {
226
236
  const {
237
+ hasSession,
227
238
  activeSideChatDraft,
228
239
  closedWorkspaceTabEntries,
229
240
  resolvedChildTabs,
230
241
  workspaceFileTabs,
231
242
  activeSelection,
232
243
  optimisticReadAtBySessionKey,
244
+ sessionProjectRoot,
245
+ onAddFileToChat,
233
246
  onSelectSession,
234
247
  onSelectFile,
235
248
  onOpenFileViewer,
@@ -242,6 +255,7 @@ export function buildWorkspaceTabsViewModel(
242
255
 
243
256
  const workspacePages = buildWorkspacePageTabs({
244
257
  activeSelection,
258
+ hasSession,
245
259
  onSelectChildSessions,
246
260
  onSelectCronJobs,
247
261
  onSelectOverview,
@@ -317,6 +331,10 @@ export function buildWorkspaceTabsViewModel(
317
331
  ? resolveAlternateWorkspaceFileViewer(file.path, file.previewViewer)
318
332
  : null;
319
333
  const fileTitle = readWorkspaceFileTitle(file);
334
+ const tokenKey = resolveWorkspaceRelativePath({
335
+ path: file.path,
336
+ sessionProjectRoot: sessionProjectRoot ?? null,
337
+ });
320
338
  return {
321
339
  key: `file:${file.key}`,
322
340
  kind: "file" as const,
@@ -336,6 +354,9 @@ export function buildWorkspaceTabsViewModel(
336
354
  onSelect: () => onOpenFileViewer(file.key, alternateViewer),
337
355
  }
338
356
  : null,
357
+ onAddToChat: tokenKey && onAddFileToChat
358
+ ? () => onAddFileToChat({ label: fileTitle, tokenKey })
359
+ : undefined,
339
360
  active:
340
361
  activeSelection?.kind === "file" && activeSelection.file.key === file.key,
341
362
  onSelect: () => onSelectFile(file.key),
@@ -0,0 +1,53 @@
1
+ export const WORKSPACE_TEXT_EXCERPT_MAX_CHARACTERS = 8_000;
2
+
3
+ export type WorkspaceTextExcerpt = {
4
+ path: string;
5
+ label: string;
6
+ excerpt: string;
7
+ startLine: number | null;
8
+ endLine: number | null;
9
+ };
10
+
11
+ function countLineBreaks(value: string): number {
12
+ return value.match(/\n/g)?.length ?? 0;
13
+ }
14
+
15
+ export function buildWorkspaceTextExcerpt(params: {
16
+ path: string;
17
+ label: string;
18
+ selectedText: string;
19
+ sourceText: string;
20
+ sourceStartLine?: number | null;
21
+ }): WorkspaceTextExcerpt | null {
22
+ const {
23
+ label: rawLabel,
24
+ path: rawPath,
25
+ selectedText,
26
+ sourceStartLine = 1,
27
+ sourceText,
28
+ } = params;
29
+ const path = rawPath.trim();
30
+ const label = rawLabel.trim();
31
+ const excerpt = selectedText.trim();
32
+ if (!path || !label || !excerpt) {
33
+ return null;
34
+ }
35
+
36
+ const sourceIndex = sourceText.indexOf(excerpt);
37
+ const hasUniqueSourceMatch = sourceIndex >= 0 && sourceIndex === sourceText.lastIndexOf(excerpt);
38
+ const baseLine = sourceStartLine ?? 1;
39
+ const startLine = hasUniqueSourceMatch
40
+ ? baseLine + countLineBreaks(sourceText.slice(0, sourceIndex))
41
+ : null;
42
+ const endLine = startLine === null
43
+ ? null
44
+ : startLine + countLineBreaks(excerpt);
45
+
46
+ return {
47
+ path,
48
+ label,
49
+ excerpt,
50
+ startLine,
51
+ endLine,
52
+ };
53
+ }
@@ -5,6 +5,7 @@ export { usePresenter } from "./components/providers/chat-presenter.provider";
5
5
  export { ChatPresenter } from "./presenters/chat.presenter";
6
6
  export { ChatDraftIntentManager } from "./managers/chat-draft-intent.manager";
7
7
  export { ChatCompletionNotificationManager } from "./managers/chat-completion-notification.manager";
8
+ export { buildSessionPath } from "./features/session/utils/chat-session-route.utils";
8
9
  export { useChatSessionListStore } from "./stores/chat-session-list.store";
9
10
  export { useChatThreadStore } from "./stores/chat-thread.store";
10
11
  export { useChatMessageLayoutStore } from "./stores/chat-message-layout.store";