@nextclaw/ui 0.15.4 → 0.15.6

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 (300) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/assets/abnfDiagram-VRR7QNED-BYpK0F5F.js +1 -0
  3. package/dist/assets/{aiden0z-pptx-renderer.es-Bd99vut2.js → aiden0z-pptx-renderer.es-D87ywFdC.js} +1 -1
  4. package/dist/assets/api-Dyb5rgh0.js +13 -0
  5. package/dist/assets/app-presenter-provider-7jV0nPiL.js +106 -0
  6. package/dist/assets/{appearance-settings-page-fLIJbx1C.js → appearance-settings-page-DFm3BbEb.js} +1 -1
  7. package/dist/assets/arc-DFELHWM2.js +1 -0
  8. package/dist/assets/architecture-TIHT7OUA-ClwVFq-K.js +1 -0
  9. package/dist/assets/architectureDiagram-ZJ3FMSHR-CvRhdovL.js +36 -0
  10. package/dist/assets/array-BqYdCIE6.js +1 -0
  11. package/dist/assets/blockDiagram-677ZJIJ3-DVYNkbR_.js +132 -0
  12. package/dist/assets/{book-open-DWUjS6aW.js → book-open-L6LCuqOr.js} +1 -1
  13. package/dist/assets/c4Diagram-LMCZKHZV-B1w-iwRe.js +10 -0
  14. package/dist/assets/channel-BEHOSFc5.js +1 -0
  15. package/dist/assets/{channels-list-page-CvCTJraa.js → channels-list-page-DOaPKNJA.js} +2 -2
  16. package/dist/assets/{chat-page-B42UUIFR.js → chat-page-Cw9uDhD_.js} +1 -1
  17. package/dist/assets/chunk-2Q5K7J3B-DrIhesSX.js +1 -0
  18. package/dist/assets/chunk-32BRIVSS-kG3lg0bC.js +1 -0
  19. package/dist/assets/chunk-52WLFC77-BLeB7iGk.js +10 -0
  20. package/dist/assets/chunk-5FCAYU7R-BQga1Rr7.js +1 -0
  21. package/dist/assets/chunk-5HE753X5-DU81hkcF.js +1 -0
  22. package/dist/assets/chunk-5JV3BV7I-C2bAx0m7.js +1 -0
  23. package/dist/assets/chunk-5TONJI2A-BExIIgWY.js +2 -0
  24. package/dist/assets/chunk-5VM5RSS4-C3XB05yh.js +15 -0
  25. package/dist/assets/chunk-7BUUIJ7U-JiyRtrGu.js +1 -0
  26. package/dist/assets/chunk-BIQX33UG-BZRV20pI.js +1 -0
  27. package/dist/assets/chunk-C7G6YPKG-AsyDSQ9j.js +1 -0
  28. package/dist/assets/chunk-CQNSW5MT-iN-fiXVA.js +1 -0
  29. package/dist/assets/chunk-CYSBUYHQ-DhC_TRzI.js +1 -0
  30. package/dist/assets/chunk-EMLP6XTP-QFLK8R6d.js +1 -0
  31. package/dist/assets/chunk-EX3LRPZG-DzUwhkCz.js +231 -0
  32. package/dist/assets/chunk-FWX5IMBZ-DFelpZBy.js +2 -0
  33. package/dist/assets/chunk-HOUHSVGY-BMPwFEwN.js +1 -0
  34. package/dist/assets/chunk-ICXQ74PX-DH8NJMok.js +2 -0
  35. package/dist/assets/chunk-JG7HCLWE-D-95AsO4.js +2 -0
  36. package/dist/assets/chunk-JWPE2WC7-DIaTv8kx.js +1 -0
  37. package/dist/assets/chunk-KEIR6QF5-A3jEqwzn.js +161 -0
  38. package/dist/assets/chunk-MOJQB5TN-BPFLzWgj.js +88 -0
  39. package/dist/assets/chunk-MOZMSUNE-DR_fzxG0.js +1 -0
  40. package/dist/assets/chunk-OGEWGWER-TIcEoPPH.js +1 -0
  41. package/dist/assets/chunk-OSBZ3O6U-BALNvSfG.js +1 -0
  42. package/dist/assets/chunk-PUDLZKDR-I-EXhf_k.js +156 -0
  43. package/dist/assets/chunk-Q4XR5HBZ-uvIGstBS.js +70 -0
  44. package/dist/assets/chunk-QBLGF6JB-r-TjLdxa.js +1 -0
  45. package/dist/assets/chunk-R7FJI6CG-N-1LDgvy.js +1 -0
  46. package/dist/assets/chunk-RYQCIY6F-jxNASx65.js +1 -0
  47. package/dist/assets/chunk-U6XO7XAA-Cphbuc7q.js +2 -0
  48. package/dist/assets/chunk-V7JOEXUC-BLEuBf1s.js +206 -0
  49. package/dist/assets/chunk-VAUOI2AC-Dpcz6BhT.js +1 -0
  50. package/dist/assets/chunk-VR4S4FIN-BAUbR0ke.js +1 -0
  51. package/dist/assets/chunk-WYO6CB5R-Do6SJrnY.js +127 -0
  52. package/dist/assets/chunk-XXDRQBXY-C2QjjwYX.js +1 -0
  53. package/dist/assets/chunk-Y2CYZVJY-BGrd8tLy.js +1 -0
  54. package/dist/assets/chunk-YOTPTUD7-CQqvMTCr.js +1 -0
  55. package/dist/assets/chunk-ZGVPDNZ5-B7kWWaXv.js +62 -0
  56. package/dist/assets/chunk-ZIRB5QZD-DTU0cDNh.js +32 -0
  57. package/dist/assets/classDiagram-OUVF2IWQ-DESMaY3_.js +1 -0
  58. package/dist/assets/classDiagram-v2-EOCWNBFH-DwOlByYH.js +1 -0
  59. package/dist/assets/{config-split-page-DBgt9S8b.js → config-split-page-CqlqjnCK.js} +1 -1
  60. package/dist/assets/{confirm-dialog-GSXIvoRU.js → confirm-dialog-bAp8NU93.js} +1 -1
  61. package/dist/assets/cose-bilkent-JH36ORCC-B9LrtV-q.js +1 -0
  62. package/dist/assets/cynefin-VYW2F7L2-CzjeeOq9.js +1 -0
  63. package/dist/assets/cynefinDiagram-TSTJHNR4-BfjvW4su.js +62 -0
  64. package/dist/assets/cytoscape.esm-CRW8q92n.js +321 -0
  65. package/dist/assets/dagre-DkiXZKkL.js +1 -0
  66. package/dist/assets/dagre-VKFMJZFB-B1pQKQSY.js +4 -0
  67. package/dist/assets/defaultLocale-Cdv9x6q7.js +1 -0
  68. package/dist/assets/desktop-update-config-2SjMfCMl.js +1 -0
  69. package/dist/assets/diagram-FQU43EPY-cB4EZdaP.js +3 -0
  70. package/dist/assets/diagram-G47NLZAW-CtW8im1B.js +24 -0
  71. package/dist/assets/diagram-NH7WQ7WH-BDCtrCCm.js +24 -0
  72. package/dist/assets/diagram-OA4YK3LP-DEMJ42Gt.js +30 -0
  73. package/dist/assets/diagram-WEI45ONY-CdCcxSYU.js +41 -0
  74. package/dist/assets/{dist-DC7f4TJH.js → dist-CrtbGLlh.js} +1 -1
  75. package/dist/assets/dist-dw-gAfM_.js +1 -0
  76. package/dist/assets/doc-browser-A5IRyDXQ2.js +1 -0
  77. package/dist/assets/{doc-browser-D0monHjG.js → doc-browser-BmnQa30-.js} +1 -1
  78. package/dist/assets/{doc-browser-context-CGwEOhBy.js → doc-browser-context-BlpUUFrR.js} +1 -1
  79. package/dist/assets/{docx-preview-eFH9DRsS.js → docx-preview-zis3U0Fa.js} +1 -1
  80. package/dist/assets/{download-DiP9zx-J.js → download-BhZZNXD8.js} +1 -1
  81. package/dist/assets/ebnfDiagram-CCIWWBDH-DBZETBwE.js +1 -0
  82. package/dist/assets/erDiagram-Q63AITRT-y2zDXprP.js +85 -0
  83. package/dist/assets/eventmodeling-45OFAUF4-C38BqG8w.js +1 -0
  84. package/dist/assets/{external-link-C6ZeSPef.js → external-link-B9Uoq5J7.js} +1 -1
  85. package/dist/assets/{eye-suvKmtwn.js → eye-K5knauEM.js} +1 -1
  86. package/dist/assets/flowDiagram-23GEKE2U-BoKk8RRq.js +1 -0
  87. package/dist/assets/{folder-CMELbQGG.js → folder-BIYZZWJv.js} +1 -1
  88. package/dist/assets/{form-actions-CUAzpNe_.js → form-actions-CKprWFeM.js} +1 -1
  89. package/dist/assets/ganttDiagram-NO4QXBWP-D2DP344e.js +292 -0
  90. package/dist/assets/gitGraph-TEB2WS4Q-IsQHHJuS.js +1 -0
  91. package/dist/assets/gitGraphDiagram-IHSO6WYX-D37uiwA2.js +106 -0
  92. package/dist/assets/graphlib-BcNFQr5y.js +1 -0
  93. package/dist/assets/index-BVn702m4.css +1 -0
  94. package/dist/assets/index-CFxJ1Fkg.js +2 -0
  95. package/dist/assets/info-DKCQHKI2-ofy2qlHI.js +1 -0
  96. package/dist/assets/infoDiagram-FWYZ7A6U-CG-WAIRi.js +2 -0
  97. package/dist/assets/init-D8TjIqfm.js +1 -0
  98. package/dist/assets/ishikawaDiagram-FXEZZL3T-WeCTnW0f.js +70 -0
  99. package/dist/assets/journeyDiagram-5HDEW3XC-DUFBW9Td.js +139 -0
  100. package/dist/assets/kanban-definition-HUTT4EX6-B0lxgMpg.js +89 -0
  101. package/dist/assets/katex-wEmrEFTg.js +257 -0
  102. package/dist/assets/line-B78frP_c.js +1 -0
  103. package/dist/assets/linear-C6lVEcb2.js +1 -0
  104. package/dist/assets/loader-circle-Bj2RMrCR.js +1 -0
  105. package/dist/assets/{logo-badge-Cu5UGH_4.js → logo-badge-BQ-XFZod.js} +1 -1
  106. package/dist/assets/map-Bdri5UL5.js +1 -0
  107. package/dist/assets/mcp-marketplace-page-BfA7A3n4.js +9 -0
  108. package/dist/assets/mcp-marketplace-page-CXHYO95j.js +1 -0
  109. package/dist/assets/mermaid-parser.core-Cue18vLo.js +4 -0
  110. package/dist/assets/mermaid.core-CXwWRh5i.js +11 -0
  111. package/dist/assets/mindmap-definition-LN4V7U3C-CFxz0P0-.js +96 -0
  112. package/dist/assets/{model-config-page-CWP6pyBm.js → model-config-page-BbWbW_qM.js} +1 -1
  113. package/dist/assets/ordinal-Cbd8t4LB.js +1 -0
  114. package/dist/assets/packet-7NZHBO7P-Rfopfa1o.js +1 -0
  115. package/dist/assets/path-DzBnMI1r.js +1 -0
  116. package/dist/assets/pegDiagram-2B236MQR-B_Qt9zyT.js +1 -0
  117. package/dist/assets/pie-RZYD4A2V-CJR1xKEv.js +1 -0
  118. package/dist/assets/pieDiagram-ENE6RG2P-CRQdSuwS.js +39 -0
  119. package/dist/assets/plus-TmFdwO3P.js +1 -0
  120. package/dist/assets/{popover-DImguRok.js → popover-CX9zFsuc.js} +1 -1
  121. package/dist/assets/preload-helper-D4M6sveU.js +1 -0
  122. package/dist/assets/{provider-scoped-model-input-CE7p4SbJ.js → provider-scoped-model-input-B-9_DtIP.js} +1 -1
  123. package/dist/assets/providers-config-page-xwIjGur2.js +1 -0
  124. package/dist/assets/quadrantDiagram-ABIIQ3AL-D5kPpttq.js +7 -0
  125. package/dist/assets/radar-I7S5WNFK-CDg8Z-1r.js +1 -0
  126. package/dist/assets/railroad-3IZDKUUU-BHnNmjxO.js +1 -0
  127. package/dist/assets/railroad-abnf-AHOZXSZD-DGtNcusW.js +1 -0
  128. package/dist/assets/railroad-ebnf-EBAXGLYW-BRFtsQmm.js +1 -0
  129. package/dist/assets/railroad-peg-LSFZ7HO6-Bj5IypCA.js +1 -0
  130. package/dist/assets/railroadDiagram-RFXS5EU6-DGh_TGlQ.js +1 -0
  131. package/dist/assets/{react-5sjAT_6d.js → react-DsgudwpT.js} +1 -1
  132. package/dist/assets/{refresh-cw-CHLBzWWj.js → refresh-cw-kXdvbhFf.js} +1 -1
  133. package/dist/assets/remote-B9F2uCk9.js +1 -0
  134. package/dist/assets/requirementDiagram-TGXJPOKE-EmFph0H_.js +84 -0
  135. package/dist/assets/rotate-cw-DEc6aihr.js +1 -0
  136. package/dist/assets/rough.esm-wJ1d3nQl.js +1 -0
  137. package/dist/assets/runtime-config-page-DTsi7czJ.js +1 -0
  138. package/dist/assets/sankeyDiagram-HTMAVEWB-BXWB5Ugi.js +40 -0
  139. package/dist/assets/{save-BABzyrjB.js → save-C9qpz2_2.js} +1 -1
  140. package/dist/assets/{search-BTqxG3ZG.js → search-_kEi29qo.js} +1 -1
  141. package/dist/assets/{search-config-page-BkKKmxmS.js → search-config-page-H7ug8f4D.js} +1 -1
  142. package/dist/assets/{secrets-config-page-CWJMyu-k.js → secrets-config-page-C1_6rINu.js} +2 -2
  143. package/dist/assets/security-config-Cr2ERKLu.js +1 -0
  144. package/dist/assets/{select-TYZDBNmq.js → select-MJKhKAWR.js} +1 -1
  145. package/dist/assets/sequenceDiagram-DBY2YBRQ-ClKnO7v0.js +162 -0
  146. package/dist/assets/{setting-row-DR23Z_5I.js → setting-row-DA3tJuew.js} +1 -1
  147. package/dist/assets/{settings-2-D8WWcBnw.js → settings-2-D_y7zXJz.js} +1 -1
  148. package/dist/assets/sizeCapture-X5ZJPWSS-DSo-t5ou.js +1 -0
  149. package/dist/assets/{skeleton-CloHeg0S.js → skeleton-0uTLUhm9.js} +1 -1
  150. package/dist/assets/src-Dad2ZbCt.js +1 -0
  151. package/dist/assets/stateDiagram-2N3HPSRC-BvAalBfz.js +1 -0
  152. package/dist/assets/stateDiagram-v2-6OUMAXLB-CfMU38yc.js +1 -0
  153. package/dist/assets/swimlanes-5IMT3BWC-DdVqVa1a.js +2 -0
  154. package/dist/assets/swimlanesDiagram-G3AALYLV-D9Zb9X57.js +8 -0
  155. package/dist/assets/{tabs-CX-ckWoo.js → tabs-h44XPocd.js} +1 -1
  156. package/dist/assets/{tag-chip-mCc23Rhb.js → tag-chip-bRZ04q3C.js} +1 -1
  157. package/dist/assets/timeline-definition-FHXFAJF6-D4ar8IQY.js +120 -0
  158. package/dist/assets/{trash-2-SAW1Z4Po.js → trash-2-BRpSE-Wt.js} +1 -1
  159. package/dist/assets/treeView-QDETBFTQ-Uy7M0WvH.js +1 -0
  160. package/dist/assets/treemap-6X3UGDF4-BJfGV7KX.js +1 -0
  161. package/dist/assets/use-config-CwDEAl6f.js +1 -0
  162. package/dist/assets/{use-confirm-dialog-C95F6sT1.js → use-confirm-dialog-BbnWw-8c.js} +1 -1
  163. package/dist/assets/{use-viewport-layout-C6m3Nte7.js → use-viewport-layout-CqgIMDQL.js} +1 -1
  164. package/dist/assets/vennDiagram-L72KCM5P-CDXJ_i3p.js +34 -0
  165. package/dist/assets/wardley-OPB4EBWU-q263iF3K.js +1 -0
  166. package/dist/assets/wardleyDiagram-EHGQE667-D-dSuT_7.js +78 -0
  167. package/dist/assets/x-DdEDL6ju.js +1 -0
  168. package/dist/assets/xychartDiagram-FW5EYKEG-C9JCzsZF.js +7 -0
  169. package/dist/index.html +33 -32
  170. package/package.json +8 -8
  171. package/src/features/chat/components/chat-popover-content.tsx +1 -26
  172. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +84 -1
  173. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +13 -2
  174. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +1 -0
  175. package/src/features/chat/components/layout/__tests__/chat-sidebar-test.utils.ts +22 -0
  176. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +13 -24
  177. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +16 -4
  178. package/src/features/chat/components/layout/chat-sidebar.tsx +38 -2
  179. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +1 -0
  180. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +52 -2
  181. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +22 -0
  182. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +36 -20
  183. package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-input-state.test.tsx +55 -0
  184. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +12 -11
  185. package/src/features/chat/features/conversation/hooks/use-session-conversation-preference-actions.ts +94 -0
  186. package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +37 -0
  187. package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +140 -63
  188. package/src/features/chat/features/input/input-surface-plugins/__tests__/context-reference-plugin.test.ts +175 -0
  189. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +66 -0
  190. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +8 -1
  191. package/src/features/chat/features/input/input-surface-plugins/context-reference-plugin.utils.ts +274 -0
  192. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +18 -11
  193. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +26 -0
  194. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +50 -4
  195. package/src/features/chat/features/input/utils/__tests__/chat-input-bar.utils.test.ts +51 -0
  196. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +4 -10
  197. package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +29 -0
  198. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +66 -8
  199. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +62 -21
  200. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +42 -10
  201. package/src/features/chat/features/message/components/chat-inline-file-preview.tsx +80 -0
  202. package/src/features/chat/features/message/components/chat-message-list.container.tsx +55 -60
  203. package/src/features/chat/features/message/utils/chat-message-texts.utils.ts +2 -0
  204. package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +41 -3
  205. package/src/features/chat/features/project/components/__tests__/chat-project-create-dialog.test.tsx +67 -0
  206. package/src/features/chat/features/project/components/chat-project-create-dialog.tsx +203 -0
  207. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +7 -7
  208. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-dialog.test.tsx +47 -0
  209. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +6 -3
  210. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -0
  211. package/src/features/chat/features/session/components/session-header/chat-session-project-dialog.tsx +3 -0
  212. package/src/features/chat/features/session/components/session-header/chat-session-switcher-groups.tsx +245 -0
  213. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +81 -127
  214. package/src/features/chat/features/session/utils/__tests__/chat-sidebar-session-groups.utils.test.ts +22 -0
  215. package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +6 -6
  216. package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +12 -1
  217. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +3 -0
  218. package/src/features/chat/features/welcome/components/chat-welcome.tsx +1 -0
  219. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +20 -0
  220. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +15 -2
  221. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +22 -24
  222. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +2 -1
  223. package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +6 -17
  224. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +41 -19
  225. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
  226. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +5 -1
  227. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +104 -3
  228. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +83 -0
  229. package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +4 -1
  230. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +96 -25
  231. package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +25 -0
  232. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +5 -1
  233. package/src/features/chat/managers/chat-session-list.manager.ts +1 -0
  234. package/src/features/chat/managers/chat-thread.manager.ts +15 -37
  235. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +23 -0
  236. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +9 -0
  237. package/src/features/chat/stores/chat-thread.store.ts +16 -36
  238. package/src/features/chat/types/chat-input-bar.types.ts +2 -0
  239. package/src/features/settings/components/config/provider-form.tsx +0 -4
  240. package/src/features/settings/utils/__tests__/provider-form-support.utils.test.ts +7 -9
  241. package/src/features/settings/utils/provider-form-model.utils.ts +0 -4
  242. package/src/features/system-status/hooks/use-current-version-release-notes-link.ts +33 -0
  243. package/src/features/system-status/index.ts +9 -0
  244. package/src/features/system-status/utils/update-release-notes.utils.ts +44 -3
  245. package/src/index.css +10 -16
  246. package/src/shared/components/common/__tests__/brand-header.test.tsx +127 -10
  247. package/src/shared/components/common/brand-header.tsx +142 -56
  248. package/src/shared/components/path-picker/__tests__/server-path-picker-dialog.test.tsx +288 -38
  249. package/src/shared/components/path-picker/server-path-picker-dialog.tsx +290 -199
  250. package/src/shared/components/path-picker/server-path-picker-directory-list.tsx +103 -0
  251. package/src/shared/components/path-picker/server-path-picker-footer.tsx +58 -0
  252. package/src/shared/components/path-picker/server-path-picker-locations.tsx +148 -0
  253. package/src/shared/components/path-picker/server-path-picker-navigation-bar.tsx +198 -0
  254. package/src/shared/components/path-picker/server-path-picker-new-folder.tsx +59 -0
  255. package/src/shared/components/path-picker/server-path-picker-toolbar.tsx +25 -0
  256. package/src/shared/hooks/use-projects.ts +28 -0
  257. package/src/shared/hooks/use-server-path-create-directory.ts +6 -0
  258. package/src/shared/hooks/use-server-path-read.ts +10 -5
  259. package/src/shared/hooks/use-server-path-search.ts +40 -0
  260. package/src/shared/lib/api/index.ts +1 -0
  261. package/src/shared/lib/api/projects/project.utils.ts +14 -0
  262. package/src/shared/lib/api/types.ts +30 -3
  263. package/src/shared/lib/api/utils/server-path.utils.ts +22 -1
  264. package/src/shared/lib/i18n/locales/en-US/chat.json +43 -2
  265. package/src/shared/lib/i18n/locales/en-US/core.json +2 -3
  266. package/src/shared/lib/i18n/locales/en-US/desktop-update.json +4 -0
  267. package/src/shared/lib/i18n/locales/en-US/path-picker.json +25 -0
  268. package/src/shared/lib/i18n/locales/zh-CN/chat.json +43 -2
  269. package/src/shared/lib/i18n/locales/zh-CN/core.json +2 -3
  270. package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +4 -0
  271. package/src/shared/lib/i18n/locales/zh-CN/path-picker.json +25 -0
  272. package/src/shared/lib/session-project/__tests__/workspace-file-breadcrumb.test.ts +1 -4
  273. package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +1 -18
  274. package/dist/assets/api-BOXOrpcJ.js +0 -13
  275. package/dist/assets/app-presenter-provider-CkHLbvZQ.js +0 -106
  276. package/dist/assets/desktop-update-config-7bmNeWIC.js +0 -1
  277. package/dist/assets/doc-browser-CgdoLUT92.js +0 -1
  278. package/dist/assets/index-BFeNDQ4R.css +0 -1
  279. package/dist/assets/index-D_6U-M94.js +0 -2
  280. package/dist/assets/loader-circle-tYHStefV.js +0 -1
  281. package/dist/assets/mcp-marketplace-page-BUzHDwW6.js +0 -9
  282. package/dist/assets/mcp-marketplace-page-ohUAdfqJ.js +0 -1
  283. package/dist/assets/plus-tywizkeY.js +0 -1
  284. package/dist/assets/providers-config-page-BKPo8SjH.js +0 -1
  285. package/dist/assets/remote-DXJryUxB.js +0 -1
  286. package/dist/assets/rotate-cw-BefO5brU.js +0 -1
  287. package/dist/assets/runtime-config-page-1Axv4QGu.js +0 -1
  288. package/dist/assets/security-config-DeQUIXfi.js +0 -1
  289. package/dist/assets/use-config-BucdaK23.js +0 -1
  290. package/dist/assets/x-DtCPHwCu.js +0 -1
  291. package/src/features/chat/components/__tests__/chat-popover-content.test.tsx +0 -41
  292. package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +0 -55
  293. package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +0 -77
  294. package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +0 -144
  295. /package/dist/assets/{config-hints-fDrYfl0l.js → config-hints-LxG80Uj5.js} +0 -0
  296. /package/dist/assets/{host-capabilities-zZvY9U63.js → host-capabilities-CFbAfrrA.js} +0 -0
  297. /package/dist/assets/{jszip.min-Das2IAnb.js → jszip.min-CP5uPNQa.js} +0 -0
  298. /package/dist/assets/{middleware-BLMHv9YF.js → middleware-CAXxl-af.js} +0 -0
  299. /package/dist/assets/{provider-models-C_yOh6DE.js → provider-models-BoUhFo9R.js} +0 -0
  300. /package/dist/assets/{xlsx-B6zVt1RK.js → xlsx-DUqJhg5u.js} +0 -0
@@ -0,0 +1,175 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { resolveChatInputSurfaceState } from '@nextclaw/agent-chat-ui';
3
+ import {
4
+ CONTEXT_REFERENCE_TRIGGER_SPEC,
5
+ createContextReferenceInputSurfacePlugin,
6
+ } from '@/features/chat/features/input/input-surface-plugins/context-reference-plugin.utils';
7
+ import type { PanelAppEntryView } from '@/shared/lib/api';
8
+
9
+ function createPanelApp(): PanelAppEntryView {
10
+ return {
11
+ id: 'task-board',
12
+ appId: 'task-board',
13
+ fileName: 'task-board.panel.html',
14
+ kind: 'single-file',
15
+ title: 'Task Board',
16
+ description: 'Track tasks',
17
+ contentPath: '/panels/task-board.panel.html',
18
+ createdAt: '2026-06-18T00:00:00.000Z',
19
+ updatedAt: '2026-06-18T00:00:00.000Z',
20
+ sizeBytes: 100,
21
+ favorite: false,
22
+ clientDeclared: false,
23
+ clientGranted: false,
24
+ openCount: 0,
25
+ };
26
+ }
27
+
28
+ function createPlugin(onNavigate = vi.fn()) {
29
+ return createContextReferenceInputSurfacePlugin({
30
+ itemTexts: {
31
+ context: {
32
+ backLabel: 'Back',
33
+ backDescription: 'Back to references',
34
+ backHintLabel: 'Enter to go back',
35
+ directoryDescription: 'Directory context',
36
+ fileDescription: 'File context',
37
+ filesDescription: 'Browse project files',
38
+ filesHintLabel: 'Enter to browse',
39
+ filesLabel: 'Files & Folders',
40
+ filesSubtitle: 'Project Context',
41
+ panelAppSectionLabel: 'Panel Apps',
42
+ projectRootLabel: 'Project directory',
43
+ searchFailedLabel: 'Search failed',
44
+ workspaceSectionLabel: 'Files & Folders',
45
+ },
46
+ panelApp: {
47
+ appIdLabel: 'App ID',
48
+ fileLabel: 'File',
49
+ noDescriptionLabel: 'No description',
50
+ subtitle: 'Panel App',
51
+ },
52
+ },
53
+ menuTexts: {
54
+ loadingLabel: 'Loading',
55
+ sectionLabel: 'References',
56
+ emptyLabel: 'Empty',
57
+ hintLabel: 'Type @',
58
+ itemHintLabel: 'Enter to reference',
59
+ },
60
+ onNavigate,
61
+ });
62
+ }
63
+
64
+ function createData(referenceMode: 'root' | 'files' = 'root') {
65
+ return {
66
+ isPanelAppsLoading: false,
67
+ isServerPathSearchLoading: false,
68
+ isSkillsLoading: false,
69
+ panelApps: [createPanelApp()],
70
+ projectRoot: '/tmp/project',
71
+ recentSkillValues: [],
72
+ referenceMode,
73
+ serverPathEntries: [
74
+ {
75
+ name: 'server-path.ts',
76
+ path: '/tmp/project/src/server-path.ts',
77
+ relativePath: 'src/server-path.ts',
78
+ parentRelativePath: 'src',
79
+ kind: 'file' as const,
80
+ hidden: false,
81
+ },
82
+ {
83
+ name: 'docs',
84
+ path: '/tmp/project/docs',
85
+ relativePath: 'docs',
86
+ parentRelativePath: '',
87
+ kind: 'directory' as const,
88
+ hidden: false,
89
+ },
90
+ ],
91
+ serverPathSearchError: null,
92
+ skillRecords: [],
93
+ };
94
+ }
95
+
96
+ describe('context reference input surface plugin', () => {
97
+ it('shows Files & Folders and panel apps in the root @ menu', () => {
98
+ const state = resolveChatInputSurfaceState({
99
+ plugins: [createPlugin()],
100
+ trigger: {
101
+ ...CONTEXT_REFERENCE_TRIGGER_SPEC,
102
+ query: '',
103
+ start: 0,
104
+ end: 1,
105
+ },
106
+ data: createData(),
107
+ });
108
+
109
+ expect(state.panel?.items).toEqual([
110
+ expect.objectContaining({
111
+ title: 'Files & Folders',
112
+ icon: 'files',
113
+ selectionBehavior: 'navigate',
114
+ }),
115
+ expect.objectContaining({
116
+ key: 'panel-app:task-board',
117
+ tokenKind: 'panel_app',
118
+ tokenKey: 'task-board',
119
+ }),
120
+ ]);
121
+ });
122
+
123
+ it('builds file and directory tokens with path previews in files mode', () => {
124
+ const state = resolveChatInputSurfaceState({
125
+ plugins: [createPlugin()],
126
+ trigger: {
127
+ ...CONTEXT_REFERENCE_TRIGGER_SPEC,
128
+ query: 'server',
129
+ start: 0,
130
+ end: 7,
131
+ },
132
+ data: createData('files'),
133
+ });
134
+
135
+ expect(state.panel?.items.slice(1)).toEqual([
136
+ expect.objectContaining({
137
+ title: 'server-path.ts',
138
+ tokenKind: 'workspace_file',
139
+ tokenKey: 'src/server-path.ts',
140
+ pathPreview: {
141
+ rootLabel: 'project',
142
+ segments: [
143
+ { label: 'src', kind: 'directory' },
144
+ { label: 'server-path.ts', kind: 'file' },
145
+ ],
146
+ },
147
+ }),
148
+ expect.objectContaining({
149
+ title: 'docs',
150
+ tokenKind: 'workspace_directory',
151
+ tokenKey: 'docs',
152
+ }),
153
+ ]);
154
+ });
155
+
156
+ it('navigates without producing a composer token', () => {
157
+ const onNavigate = vi.fn();
158
+ const state = resolveChatInputSurfaceState({
159
+ plugins: [createPlugin(onNavigate)],
160
+ trigger: {
161
+ ...CONTEXT_REFERENCE_TRIGGER_SPEC,
162
+ query: '',
163
+ start: 0,
164
+ end: 1,
165
+ },
166
+ data: createData(),
167
+ });
168
+ const item = state.panel?.items[0];
169
+
170
+ state.panel?.onSelectItem?.(item!);
171
+
172
+ expect(onNavigate).toHaveBeenCalledWith('files');
173
+ expect(item).not.toHaveProperty('tokenKind');
174
+ });
175
+ });
@@ -86,6 +86,7 @@ describe('createSlashCommandInputSurfacePlugin', () => {
86
86
  const state = resolveChatInputSurfaceState({
87
87
  data: {
88
88
  isPanelAppsLoading: false,
89
+ isServerPathSearchLoading: false,
89
90
  isSkillsLoading: false,
90
91
  panelApps: [
91
92
  createPanelApp({
@@ -94,7 +95,11 @@ describe('createSlashCommandInputSurfacePlugin', () => {
94
95
  description: 'Track tasks',
95
96
  }),
96
97
  ],
98
+ projectRoot: '/tmp/project',
97
99
  recentSkillValues: [],
100
+ referenceMode: 'root',
101
+ serverPathEntries: [],
102
+ serverPathSearchError: null,
98
103
  skillRecords: [
99
104
  {
100
105
  key: 'web-search',
@@ -125,30 +130,86 @@ describe('createSlashCommandInputSurfacePlugin', () => {
125
130
  { key: 'panel-apps', label: 'Panel Apps', sectionKeys: ['panel-apps'] },
126
131
  ]);
127
132
  expect(state.panel?.items[0]).toMatchObject({
133
+ icon: 'command',
128
134
  sectionKey: 'commands',
129
135
  sectionLabel: 'Commands',
130
136
  hintLabel: 'Run command',
131
137
  });
132
138
  expect(state.panel?.items[1]).toMatchObject({
139
+ icon: 'skill',
133
140
  sectionKey: 'skills',
134
141
  sectionLabel: 'Skills',
135
142
  hintLabel: 'Add skill',
136
143
  });
137
144
  expect(state.panel?.items[2]).toMatchObject({
145
+ icon: 'panel-app',
138
146
  sectionKey: 'panel-apps',
139
147
  sectionLabel: 'Panel Apps',
140
148
  hintLabel: 'Open panel app',
141
149
  });
142
150
  });
143
151
 
152
+ it('preserves source groups while the skills filter includes every skill section', () => {
153
+ const state = resolveChatInputSurfaceState({
154
+ data: {
155
+ isPanelAppsLoading: false,
156
+ isServerPathSearchLoading: false,
157
+ isSkillsLoading: false,
158
+ panelApps: [],
159
+ projectRoot: '/tmp/project',
160
+ recentSkillValues: [],
161
+ referenceMode: 'root',
162
+ serverPathEntries: [],
163
+ serverPathSearchError: null,
164
+ skillRecords: [
165
+ {
166
+ key: 'project:review',
167
+ label: 'Review',
168
+ groupKey: 'project',
169
+ groupLabel: 'Project skills',
170
+ },
171
+ {
172
+ key: 'global:browser',
173
+ label: 'Browser',
174
+ groupKey: 'global',
175
+ groupLabel: 'Global skills',
176
+ },
177
+ ],
178
+ },
179
+ plugins: [createPlugin()],
180
+ trigger: {
181
+ key: 'slash',
182
+ marker: '/',
183
+ query: '',
184
+ start: 0,
185
+ end: 1,
186
+ },
187
+ });
188
+
189
+ expect(state.panel?.filterOptions?.find((filter) => filter.key === 'skills')).toEqual({
190
+ key: 'skills',
191
+ label: 'Skills',
192
+ sectionKeys: ['skills:project', 'skills:global'],
193
+ });
194
+ expect(state.panel?.items.filter((item) => item.key.startsWith('skill:'))).toMatchObject([
195
+ { sectionKey: 'skills:project', sectionLabel: 'Project skills' },
196
+ { sectionKey: 'skills:global', sectionLabel: 'Global skills' },
197
+ ]);
198
+ });
199
+
144
200
  it('runs a command item through the panel selection handler', () => {
145
201
  const onSelectCommand = vi.fn();
146
202
  const state = resolveChatInputSurfaceState({
147
203
  data: {
148
204
  isPanelAppsLoading: false,
205
+ isServerPathSearchLoading: false,
149
206
  isSkillsLoading: false,
150
207
  panelApps: [],
208
+ projectRoot: '/tmp/project',
151
209
  recentSkillValues: [],
210
+ referenceMode: 'root',
211
+ serverPathEntries: [],
212
+ serverPathSearchError: null,
152
213
  skillRecords: [],
153
214
  },
154
215
  plugins: [createPlugin({ onSelectCommand })],
@@ -172,6 +233,7 @@ describe('createSlashCommandInputSurfacePlugin', () => {
172
233
  const state = resolveChatInputSurfaceState({
173
234
  data: {
174
235
  isPanelAppsLoading: false,
236
+ isServerPathSearchLoading: false,
175
237
  isSkillsLoading: false,
176
238
  panelApps: [
177
239
  createPanelApp({
@@ -180,7 +242,11 @@ describe('createSlashCommandInputSurfacePlugin', () => {
180
242
  description: 'Track tasks',
181
243
  }),
182
244
  ],
245
+ projectRoot: '/tmp/project',
183
246
  recentSkillValues: [],
247
+ referenceMode: 'root',
248
+ serverPathEntries: [],
249
+ serverPathSearchError: null,
184
250
  skillRecords: [],
185
251
  },
186
252
  plugins: [createPlugin({ onSelectPanelApp })],
@@ -1,10 +1,17 @@
1
1
  import type { ChatSkillRecord } from '@/features/chat/types/chat-input-bar.types';
2
- import type { PanelAppEntryView } from '@/shared/lib/api';
2
+ import type { PanelAppEntryView, ServerPathSearchEntryView } from '@/shared/lib/api';
3
+
4
+ export type ContextReferenceMode = 'root' | 'files';
3
5
 
4
6
  export type ChatInputProductPluginData = {
5
7
  isPanelAppsLoading: boolean;
8
+ isServerPathSearchLoading: boolean;
6
9
  isSkillsLoading: boolean;
7
10
  panelApps: readonly PanelAppEntryView[];
11
+ projectRoot: string;
8
12
  recentSkillValues: readonly string[];
13
+ referenceMode: ContextReferenceMode;
14
+ serverPathEntries: readonly ServerPathSearchEntryView[];
15
+ serverPathSearchError: string | null;
9
16
  skillRecords: readonly ChatSkillRecord[];
10
17
  };
@@ -0,0 +1,274 @@
1
+ import {
2
+ createInputSurfaceTriggeredPanelPlugin,
3
+ type ChatInputSurfaceItem,
4
+ type ChatInputSurfaceMenuTexts,
5
+ type ChatInputSurfacePlugin,
6
+ type ChatInputSurfaceTriggerSpec,
7
+ } from '@nextclaw/agent-chat-ui';
8
+ import {
9
+ CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND,
10
+ CHAT_WORKSPACE_FILE_TOKEN_KIND,
11
+ } from '@nextclaw/shared';
12
+ import type { PanelAppEntryView, ServerPathSearchEntryView } from '@/shared/lib/api';
13
+ import type {
14
+ ChatInputProductPluginData,
15
+ ContextReferenceMode,
16
+ } from './chat-input-product-plugin-adapters.types';
17
+ import {
18
+ scoreInputSurfaceSearchCandidate,
19
+ resolveInputSurfaceMatchTier,
20
+ } from './input-surface-search.utils';
21
+
22
+ const FILES_NAVIGATION_ITEM_KEY = 'context-reference:navigate:files';
23
+ const ROOT_NAVIGATION_ITEM_KEY = 'context-reference:navigate:root';
24
+ const WORKSPACE_SECTION_KEY = 'workspace';
25
+ const PANEL_APP_SECTION_KEY = 'panel-apps';
26
+
27
+ export const CONTEXT_REFERENCE_TRIGGER_SPEC: ChatInputSurfaceTriggerSpec = {
28
+ key: 'context-reference',
29
+ marker: '@',
30
+ };
31
+
32
+ export type PanelAppInputSurfaceItemTexts = {
33
+ appIdLabel: string;
34
+ fileLabel: string;
35
+ noDescriptionLabel: string;
36
+ subtitle: string;
37
+ };
38
+
39
+ export type ContextReferenceInputSurfaceTexts = {
40
+ backLabel: string;
41
+ backDescription: string;
42
+ backHintLabel: string;
43
+ directoryDescription: string;
44
+ fileDescription: string;
45
+ filesDescription: string;
46
+ filesHintLabel: string;
47
+ filesLabel: string;
48
+ filesSubtitle: string;
49
+ panelAppSectionLabel: string;
50
+ projectRootLabel: string;
51
+ searchFailedLabel: string;
52
+ workspaceSectionLabel: string;
53
+ };
54
+
55
+ function getPanelAppActivityTime(entry: PanelAppEntryView): number {
56
+ return Date.parse(entry.lastOpenedAt ?? entry.updatedAt) || 0;
57
+ }
58
+
59
+ function resolveProjectLabel(projectRoot: string): string {
60
+ return projectRoot.split(/[\\/]+/).filter(Boolean).at(-1) ?? projectRoot;
61
+ }
62
+
63
+ function resolvePanelAppInputSurfaceEntries(params: {
64
+ entries: readonly PanelAppEntryView[];
65
+ query: string;
66
+ }): PanelAppEntryView[] {
67
+ const collator = new Intl.Collator(undefined, { sensitivity: 'base', numeric: true });
68
+ return params.entries
69
+ .map((entry, order) => ({
70
+ entry,
71
+ order,
72
+ score: scoreInputSurfaceSearchCandidate(
73
+ {
74
+ id: entry.appId,
75
+ label: entry.title || entry.appId,
76
+ description: entry.description,
77
+ aliases: [entry.id, entry.fileName],
78
+ },
79
+ params.query,
80
+ ),
81
+ }))
82
+ .filter((entry) => entry.score > 0)
83
+ .sort((left, right) => {
84
+ const leftTier = resolveInputSurfaceMatchTier(left.score);
85
+ const rightTier = resolveInputSurfaceMatchTier(right.score);
86
+ if (rightTier !== leftTier) {
87
+ return rightTier - leftTier;
88
+ }
89
+ if (left.entry.favorite !== right.entry.favorite) {
90
+ return left.entry.favorite ? -1 : 1;
91
+ }
92
+ const rightActivity = getPanelAppActivityTime(right.entry);
93
+ const leftActivity = getPanelAppActivityTime(left.entry);
94
+ if (rightActivity !== leftActivity) {
95
+ return rightActivity - leftActivity;
96
+ }
97
+ if (right.score !== left.score) {
98
+ return right.score - left.score;
99
+ }
100
+ const labelCompare = collator.compare(left.entry.title || left.entry.appId, right.entry.title || right.entry.appId);
101
+ return labelCompare || left.order - right.order;
102
+ })
103
+ .map(({ entry }) => entry);
104
+ }
105
+
106
+ function buildPanelAppInputSurfaceItemEntries(params: {
107
+ entries: readonly PanelAppEntryView[];
108
+ keyPrefix?: string;
109
+ query: string;
110
+ texts: PanelAppInputSurfaceItemTexts;
111
+ }): Array<{ entry: PanelAppEntryView; item: ChatInputSurfaceItem }> {
112
+ const keyPrefix = params.keyPrefix ?? 'panel-app';
113
+ return resolvePanelAppInputSurfaceEntries({
114
+ entries: params.entries,
115
+ query: params.query,
116
+ }).map((entry) => ({
117
+ entry,
118
+ item: {
119
+ key: `${keyPrefix}:${entry.appId}`,
120
+ icon: 'panel-app',
121
+ title: entry.title || entry.appId,
122
+ subtitle: params.texts.subtitle,
123
+ description: (entry.description ?? '').trim() || params.texts.noDescriptionLabel,
124
+ detailLines: [
125
+ `${params.texts.appIdLabel}: ${entry.appId}`,
126
+ `${params.texts.fileLabel}: ${entry.fileName}`,
127
+ ],
128
+ },
129
+ }));
130
+ }
131
+
132
+ export function buildPanelAppInputSurfaceItems(params: {
133
+ entries: readonly PanelAppEntryView[];
134
+ keyPrefix?: string;
135
+ query: string;
136
+ texts: PanelAppInputSurfaceItemTexts;
137
+ }): ChatInputSurfaceItem[] {
138
+ return buildPanelAppInputSurfaceItemEntries(params).map(({ item }) => item);
139
+ }
140
+
141
+ function buildPanelAppReferenceItems(params: {
142
+ entries: readonly PanelAppEntryView[];
143
+ query: string;
144
+ sectionLabel: string;
145
+ texts: PanelAppInputSurfaceItemTexts;
146
+ }): ChatInputSurfaceItem[] {
147
+ return buildPanelAppInputSurfaceItemEntries(params).map(({ entry, item }) => ({
148
+ ...item,
149
+ sectionKey: PANEL_APP_SECTION_KEY,
150
+ sectionLabel: params.sectionLabel,
151
+ tokenKind: 'panel_app',
152
+ tokenKey: entry.appId,
153
+ value: entry.appId,
154
+ }));
155
+ }
156
+
157
+ function buildWorkspaceReferenceItems(params: {
158
+ entries: readonly ServerPathSearchEntryView[];
159
+ projectRoot: string;
160
+ texts: ContextReferenceInputSurfaceTexts;
161
+ }): ChatInputSurfaceItem[] {
162
+ const projectLabel = resolveProjectLabel(params.projectRoot);
163
+ return params.entries.map((entry) => {
164
+ const pathSegments = entry.relativePath.split('/').filter(Boolean);
165
+ return {
166
+ key: `workspace:${entry.kind}:${entry.relativePath}`,
167
+ icon: entry.kind === 'directory' ? 'folder' : 'file',
168
+ title: entry.name,
169
+ subtitle: entry.parentRelativePath || projectLabel,
170
+ description: entry.kind === 'directory'
171
+ ? params.texts.directoryDescription
172
+ : params.texts.fileDescription,
173
+ detailLines: [
174
+ `${params.texts.projectRootLabel}: ${params.projectRoot}`,
175
+ entry.relativePath,
176
+ ],
177
+ sectionKey: WORKSPACE_SECTION_KEY,
178
+ sectionLabel: params.texts.workspaceSectionLabel,
179
+ tokenKind: entry.kind === 'directory'
180
+ ? CHAT_WORKSPACE_DIRECTORY_TOKEN_KIND
181
+ : CHAT_WORKSPACE_FILE_TOKEN_KIND,
182
+ tokenKey: entry.relativePath,
183
+ pathPreview: {
184
+ rootLabel: projectLabel,
185
+ segments: pathSegments.map((label, index) => ({
186
+ label,
187
+ kind: index === pathSegments.length - 1 ? entry.kind : 'directory',
188
+ })),
189
+ },
190
+ } satisfies ChatInputSurfaceItem;
191
+ });
192
+ }
193
+
194
+ function buildFilesNavigationItem(texts: ContextReferenceInputSurfaceTexts): ChatInputSurfaceItem {
195
+ return {
196
+ key: FILES_NAVIGATION_ITEM_KEY,
197
+ icon: 'files',
198
+ title: texts.filesLabel,
199
+ subtitle: texts.filesSubtitle,
200
+ description: texts.filesDescription,
201
+ detailLines: [],
202
+ hintLabel: texts.filesHintLabel,
203
+ selectionBehavior: 'navigate',
204
+ };
205
+ }
206
+
207
+ function buildRootNavigationItem(texts: ContextReferenceInputSurfaceTexts): ChatInputSurfaceItem {
208
+ return {
209
+ key: ROOT_NAVIGATION_ITEM_KEY,
210
+ icon: 'back',
211
+ title: texts.backLabel,
212
+ subtitle: '',
213
+ description: texts.backDescription,
214
+ detailLines: [],
215
+ hintLabel: texts.backHintLabel,
216
+ selectionBehavior: 'navigate',
217
+ };
218
+ }
219
+
220
+ export function createContextReferenceInputSurfacePlugin(params: {
221
+ itemTexts: {
222
+ context: ContextReferenceInputSurfaceTexts;
223
+ panelApp: PanelAppInputSurfaceItemTexts;
224
+ };
225
+ menuTexts: ChatInputSurfaceMenuTexts;
226
+ onNavigate: (mode: ContextReferenceMode) => void;
227
+ }): ChatInputSurfacePlugin<ChatInputProductPluginData> {
228
+ return createInputSurfaceTriggeredPanelPlugin({
229
+ key: 'context-reference',
230
+ trigger: CONTEXT_REFERENCE_TRIGGER_SPEC,
231
+ resolvePanel: ({ data, trigger }) => {
232
+ const workspaceItems = buildWorkspaceReferenceItems({
233
+ entries: data.serverPathEntries,
234
+ projectRoot: data.projectRoot,
235
+ texts: params.itemTexts.context,
236
+ });
237
+ const items = data.referenceMode === 'files'
238
+ ? [buildRootNavigationItem(params.itemTexts.context), ...workspaceItems]
239
+ : [
240
+ buildFilesNavigationItem(params.itemTexts.context),
241
+ ...(trigger.query ? workspaceItems : []),
242
+ ...buildPanelAppReferenceItems({
243
+ entries: data.panelApps,
244
+ query: trigger.query,
245
+ sectionLabel: params.itemTexts.context.panelAppSectionLabel,
246
+ texts: params.itemTexts.panelApp,
247
+ }),
248
+ ];
249
+ const relevantLoading = data.referenceMode === 'files'
250
+ ? data.isServerPathSearchLoading
251
+ : data.isPanelAppsLoading || (Boolean(trigger.query) && data.isServerPathSearchLoading);
252
+ return {
253
+ isLoading: data.referenceMode === 'files'
254
+ ? relevantLoading
255
+ : relevantLoading && items.length === 0,
256
+ items,
257
+ notice: data.serverPathSearchError
258
+ ? {
259
+ message: `${params.itemTexts.context.searchFailedLabel}: ${data.serverPathSearchError}`,
260
+ tone: 'error',
261
+ }
262
+ : undefined,
263
+ onSelectItem: (item) => {
264
+ if (item.key === FILES_NAVIGATION_ITEM_KEY) {
265
+ params.onNavigate('files');
266
+ } else if (item.key === ROOT_NAVIGATION_ITEM_KEY) {
267
+ params.onNavigate('root');
268
+ }
269
+ },
270
+ texts: params.menuTexts,
271
+ };
272
+ },
273
+ });
274
+ }
@@ -11,7 +11,7 @@ import type { ChatInputBarAdapterTexts } from '@/features/chat/types/chat-input-
11
11
  import {
12
12
  buildPanelAppInputSurfaceItems,
13
13
  type PanelAppInputSurfaceItemTexts,
14
- } from './panel-app-reference-plugin.utils';
14
+ } from './context-reference-plugin.utils';
15
15
  import {
16
16
  resolveInputSurfaceMatchTier,
17
17
  scoreInputSurfaceSearchCandidate,
@@ -69,6 +69,7 @@ function buildSlashCommandItems(params: {
69
69
  })
70
70
  .map(({ command }) => ({
71
71
  key: `command:${command.key}`,
72
+ icon: 'command',
72
73
  title: command.title,
73
74
  subtitle: params.texts.commandSubtitle,
74
75
  description: command.description,
@@ -103,9 +104,12 @@ function buildSlashSkillItems(params: {
103
104
  [...data.recentSkillValues],
104
105
  ).map((item) => ({
105
106
  ...item,
107
+ icon: 'skill',
106
108
  hintLabel: skillHintLabel,
107
- sectionKey: SLASH_SKILL_SECTION_KEY,
108
- sectionLabel: skillSectionLabel,
109
+ sectionKey: item.sectionKey
110
+ ? `${SLASH_SKILL_SECTION_KEY}:${item.sectionKey}`
111
+ : SLASH_SKILL_SECTION_KEY,
112
+ sectionLabel: item.sectionLabel || skillSectionLabel,
109
113
  }));
110
114
  }
111
115
 
@@ -123,6 +127,7 @@ function buildSlashPanelAppItems(params: {
123
127
  texts: params.itemTexts,
124
128
  }).map((item) => ({
125
129
  ...item,
130
+ icon: 'panel-app',
126
131
  hintLabel: params.panelAppHintLabel,
127
132
  sectionKey: SLASH_PANEL_APP_SECTION_KEY,
128
133
  sectionLabel: params.panelAppSectionLabel,
@@ -165,6 +170,14 @@ export function createSlashCommandInputSurfacePlugin(params: {
165
170
  trigger: CHAT_INPUT_SURFACE_SLASH_TRIGGER_SPEC,
166
171
  resolvePanel: (context) => {
167
172
  const { data, trigger } = context;
173
+ const skillItems = buildSlashSkillItems({
174
+ data,
175
+ itemTexts: params.itemTexts.skillTexts,
176
+ query: trigger.query,
177
+ skillHintLabel: params.labels.skillHintLabel,
178
+ skillSectionLabel: params.labels.skillSectionLabel,
179
+ });
180
+ const skillSectionKeys = [...new Set(skillItems.flatMap((item) => item.sectionKey ? [item.sectionKey] : []))];
168
181
  return {
169
182
  filterOptions: [
170
183
  { key: 'all', label: params.labels.filterAllLabel },
@@ -176,7 +189,7 @@ export function createSlashCommandInputSurfacePlugin(params: {
176
189
  {
177
190
  key: SLASH_SKILL_SECTION_KEY,
178
191
  label: params.labels.filterSkillsLabel,
179
- sectionKeys: [SLASH_SKILL_SECTION_KEY],
192
+ sectionKeys: skillSectionKeys.length > 0 ? skillSectionKeys : [SLASH_SKILL_SECTION_KEY],
180
193
  },
181
194
  {
182
195
  key: SLASH_PANEL_APP_SECTION_KEY,
@@ -195,13 +208,7 @@ export function createSlashCommandInputSurfacePlugin(params: {
195
208
  commandSubtitle: params.labels.commandSubtitle,
196
209
  },
197
210
  }),
198
- ...buildSlashSkillItems({
199
- data,
200
- itemTexts: params.itemTexts.skillTexts,
201
- query: trigger.query,
202
- skillHintLabel: params.labels.skillHintLabel,
203
- skillSectionLabel: params.labels.skillSectionLabel,
204
- }),
211
+ ...skillItems,
205
212
  ...buildSlashPanelAppItems({
206
213
  data,
207
214
  itemTexts: params.itemTexts.panelAppTexts,
@@ -89,6 +89,32 @@ describe('deriveNcpMessagePartsFromComposer', () => {
89
89
  ]);
90
90
  });
91
91
 
92
+ it('serializes workspace references without turning them into uploaded file parts', () => {
93
+ expect(
94
+ deriveNcpMessagePartsFromComposer(
95
+ [
96
+ createChatComposerTokenNode({
97
+ tokenKind: 'workspace_file',
98
+ tokenKey: 'src/file name.ts',
99
+ label: 'file name.ts',
100
+ }),
101
+ createChatComposerTextNode(' and '),
102
+ createChatComposerTokenNode({
103
+ tokenKind: 'workspace_directory',
104
+ tokenKey: 'docs/设计',
105
+ label: '设计',
106
+ }),
107
+ ],
108
+ [],
109
+ ),
110
+ ).toEqual([
111
+ {
112
+ type: 'text',
113
+ text: '@file:src%2Ffile%20name.ts and @folder:docs%2F%E8%AE%BE%E8%AE%A1',
114
+ },
115
+ ]);
116
+ });
117
+
92
118
  it('preserves uploaded attachment references when the attachment has a server uri', () => {
93
119
  const parts = deriveNcpMessagePartsFromComposer(
94
120
  [