@nextclaw/ui 0.13.13 → 0.14.1-beta.0

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 (399) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/assets/{api-D0hARyyl.js → api-C6EDHBDR.js} +7 -7
  3. package/dist/assets/channels-list-page-DKj6m1Hc.js +8 -0
  4. package/dist/assets/chat-page-BXngLJY6.js +105 -0
  5. package/dist/assets/config-split-page-CjlmJy8X.js +1 -0
  6. package/dist/assets/{confirm-dialog-CTcaBp-8.js → confirm-dialog-B39X0pYp.js} +2 -2
  7. package/dist/assets/desktop-update-config-DfUQ8nly.js +1 -0
  8. package/dist/assets/{dist-C59BKqbX.js → dist-BIYV2-Ia.js} +1 -1
  9. package/dist/assets/{dist-Di6EHp2x.js → dist-CmMro3nV.js} +1 -1
  10. package/dist/assets/doc-browser-B6Wc_TIY.js +1 -0
  11. package/dist/assets/doc-browser-CDtUtcim.js +1 -0
  12. package/dist/assets/doc-browser-context-DZbC9zVB.js +1 -0
  13. package/dist/assets/{ellipsis-hXUNwi63.js → ellipsis-DDpgTzgx.js} +1 -1
  14. package/dist/assets/{external-link-J0fCK-vu.js → external-link-D2cBOCqn.js} +1 -1
  15. package/dist/assets/index-DTb_XVIH.js +103 -0
  16. package/dist/assets/index-ayiPYhf1.css +1 -0
  17. package/dist/assets/mcp-marketplace-page-DZ9H0v05.js +1 -0
  18. package/dist/assets/mcp-marketplace-page-cnVWf7QQ.js +40 -0
  19. package/dist/assets/model-config-page-Bcb35AVv.js +1 -0
  20. package/dist/assets/plus-CYE1onU2.js +1 -0
  21. package/dist/assets/provider-scoped-model-input-kdoNp4HG.js +1 -0
  22. package/dist/assets/providers-config-page-CQSibSwO.js +1 -0
  23. package/dist/assets/{react-C7HsxuKH.js → react-DYQXXGbH.js} +1 -1
  24. package/dist/assets/remote-BlJDbXOI.js +1 -0
  25. package/dist/assets/rotate-cw-BWbvFDAX.js +1 -0
  26. package/dist/assets/runtime-config-page-Tn2yLQ0c.js +1 -0
  27. package/dist/assets/{save-Z1QTovIt.js → save-BNVTgBVn.js} +1 -1
  28. package/dist/assets/search-CKCzwLId.js +1 -0
  29. package/dist/assets/search-config-page-DG5Q2hF1.js +1 -0
  30. package/dist/assets/secrets-config-page-BXn5Uuwp.js +3 -0
  31. package/dist/assets/select-CIRwTNP4.js +41 -0
  32. package/dist/assets/{tag-chip-3kpiMTST.js → tag-chip-DKhVFtTE.js} +1 -1
  33. package/dist/assets/use-config-DgKM9VIU.js +1 -0
  34. package/dist/assets/x-Cm3JjYut.js +1 -0
  35. package/dist/index.html +14 -27
  36. package/package.json +9 -8
  37. package/src/app/index.tsx +8 -4
  38. package/src/app/presenters/app.presenter.ts +2 -0
  39. package/src/features/account/components/account-panel.tsx +3 -3
  40. package/src/features/account/hooks/{use-auth.test.ts → __tests__/use-auth.test.ts} +1 -1
  41. package/src/features/agents/components/{agents-page.test.tsx → __tests__/agents-page.test.tsx} +41 -2
  42. package/src/features/agents/components/agent-dialogs.tsx +2 -2
  43. package/src/features/agents/components/agents-page.tsx +1 -1
  44. package/src/features/channels/components/config/channel-form.tsx +1 -1
  45. package/src/features/channels/pages/channels-list-page.tsx +18 -15
  46. package/src/features/channels/utils/{channel-form-fields.utils.test.ts → __tests__/channel-form-fields.utils.test.ts} +1 -1
  47. package/src/features/chat/components/{chat-welcome.test.tsx → __tests__/chat-welcome.test.tsx} +1 -1
  48. package/src/features/chat/components/conversation/{chat-conversation-header.test.tsx → __tests__/chat-conversation-header.test.tsx} +25 -32
  49. package/src/features/chat/components/conversation/{chat-conversation-panel.test.tsx → __tests__/chat-conversation-panel.test.tsx} +132 -37
  50. package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +37 -0
  51. package/src/features/chat/components/conversation/chat-conversation-content.tsx +91 -0
  52. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +152 -0
  53. package/src/features/chat/components/conversation/chat-conversation-header.tsx +26 -89
  54. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +13 -379
  55. package/src/features/chat/components/conversation/chat-conversation-parent-banner.tsx +16 -0
  56. package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +86 -0
  57. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +42 -0
  58. package/src/features/chat/components/layout/{chat-page-shell.test.tsx → __tests__/chat-page-shell.test.tsx} +1 -1
  59. package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +167 -0
  60. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +834 -0
  61. package/src/features/chat/components/layout/chat-page-shell.tsx +11 -30
  62. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +33 -53
  63. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +1 -1
  64. package/src/features/chat/components/layout/chat-sidebar.tsx +156 -202
  65. package/src/features/chat/components/providers/chat-presenter.provider.tsx +13 -46
  66. package/src/features/chat/{components/conversation → features/input/components/__tests__}/chat-attachment-upload-limit.test.ts +1 -1
  67. package/src/features/chat/{components/conversation → features/input/components}/chat-input-bar.container.tsx +92 -31
  68. package/src/features/chat/features/input/hooks/use-chat-input-bar-query-state.ts +118 -0
  69. package/src/features/chat/{utils → features/input/utils/__tests__}/chat-composer-state.utils.test.ts +1 -1
  70. package/src/features/chat/{utils → features/input/utils/__tests__}/chat-inline-token.utils.test.ts +1 -1
  71. package/src/features/chat/{utils → features/input/utils/__tests__}/chat-input-bar.utils.test.ts +2 -17
  72. package/src/features/chat/{utils → features/input/utils/__tests__}/ncp-chat-input-availability.utils.test.ts +2 -1
  73. package/src/features/chat/{utils → features/input/utils}/chat-input-bar.utils.ts +1 -24
  74. package/src/features/chat/{utils → features/input/utils}/chat-input-toolbar.utils.ts +0 -27
  75. package/src/features/chat/{utils → features/input/utils}/ncp-chat-input-availability.utils.ts +6 -6
  76. package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +89 -0
  77. package/src/features/chat/{components/conversation → features/message/components/__tests__}/chat-message-list.container.test.tsx +46 -3
  78. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +115 -0
  79. package/src/features/chat/{components/conversation → features/message/components}/chat-message-list.container.tsx +13 -13
  80. package/src/features/chat/{utils → features/message/utils/__tests__}/chat-message-invalid-tool-arguments.utils.test.ts +2 -2
  81. package/src/features/chat/{utils → features/message/utils/__tests__}/chat-message-session-spawn-tool-card.utils.test.ts +2 -2
  82. package/src/features/chat/features/message/utils/__tests__/chat-message-show-content-tool-card.utils.test.ts +172 -0
  83. package/src/features/chat/{utils → features/message/utils/__tests__}/chat-message-summary-truncation.utils.test.ts +2 -2
  84. package/src/features/chat/{utils → features/message/utils/__tests__}/chat-message-tool-agent-id.utils.test.ts +1 -1
  85. package/src/features/chat/{utils → features/message/utils/__tests__}/chat-message.utils.test.ts +2 -2
  86. package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +51 -0
  87. package/src/features/chat/{utils → features/message/utils}/chat-message-inline-content.utils.ts +1 -1
  88. package/src/features/chat/{utils → features/message/utils}/chat-message-part.utils.ts +15 -2
  89. package/src/features/chat/{utils → features/message/utils}/chat-message-session-request-tool-card.utils.ts +1 -1
  90. package/src/features/chat/features/message/utils/chat-message-show-content-tool-card.utils.ts +188 -0
  91. package/src/features/chat/{utils → features/message/utils}/chat-message-tool-card.utils.ts +5 -1
  92. package/src/features/chat/{utils → features/message/utils}/chat-message.utils.ts +1 -1
  93. package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +57 -0
  94. package/src/features/chat/{hooks → features/ncp/hooks/__tests__}/use-ncp-agent-runtime.test.tsx +2 -2
  95. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-chat-derived-state.test.tsx +22 -0
  96. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-chat-query-store-sync.test.tsx +101 -0
  97. package/src/features/chat/{hooks → features/ncp/hooks/__tests__}/use-ncp-session-conversation.test.tsx +1 -1
  98. package/src/features/chat/features/ncp/hooks/__tests__/use-ui-show-content-event.test.tsx +53 -0
  99. package/src/features/chat/features/ncp/hooks/use-ncp-chat-derived-state.ts +37 -0
  100. package/src/features/chat/features/ncp/hooks/use-ncp-chat-query-store-sync.ts +28 -0
  101. package/src/features/chat/{hooks → features/ncp/hooks}/use-ncp-child-session-tabs-view.ts +4 -4
  102. package/src/features/chat/{hooks → features/ncp/hooks}/use-ncp-session-conversation.ts +1 -1
  103. package/src/features/chat/{hooks → features/ncp/hooks}/use-ncp-session-list-view.ts +3 -3
  104. package/src/features/chat/features/ncp/hooks/use-ncp-session-queries.ts +32 -0
  105. package/src/features/chat/features/ncp/hooks/use-ui-show-content-event.ts +14 -0
  106. package/src/features/chat/features/ncp/utils/ncp-chat-query-derived.utils.ts +85 -0
  107. package/src/features/chat/{utils → features/runtime/utils/__tests__}/ncp-app-client-fetch.utils.test.ts +1 -1
  108. package/src/features/chat/{utils → features/runtime/utils/__tests__}/ncp-chat-runtime-availability.utils.test.ts +1 -1
  109. package/src/features/chat/{utils → features/runtime/utils}/chat-runtime.utils.ts +1 -1
  110. package/src/features/chat/{components → features/session/components}/chat-sidebar-project-groups.tsx +21 -42
  111. package/src/features/chat/{components/layout → features/session/components}/chat-sidebar-session-entry.tsx +40 -13
  112. package/src/features/chat/{components → features/session/components}/chat-sidebar-session-item.tsx +36 -44
  113. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +78 -0
  114. package/src/features/chat/{components/session → features/session/components}/session-context-icon.tsx +1 -1
  115. package/src/features/chat/{components/conversation/session-header → features/session/components/session-header/__tests__}/chat-session-header-actions.test.tsx +30 -3
  116. package/src/features/chat/{components/conversation/session-header → features/session/components/session-header/__tests__}/chat-session-project-badge.test.tsx +3 -3
  117. package/src/features/chat/{components/conversation → features/session/components}/session-header/chat-session-header-actions.tsx +34 -28
  118. package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +46 -0
  119. package/src/features/chat/{components/conversation → features/session/components}/session-header/chat-session-project-badge.tsx +1 -1
  120. package/src/features/chat/{hooks → features/session/hooks/__tests__}/use-chat-session-project.test.tsx +2 -2
  121. package/src/features/chat/{hooks → features/session/hooks/__tests__}/use-chat-session-update.test.tsx +1 -1
  122. package/src/features/chat/features/session/hooks/__tests__/use-selected-session-context-window-indicator.test.tsx +63 -0
  123. package/src/features/chat/{hooks → features/session/hooks}/use-chat-session-project.ts +1 -1
  124. package/src/features/chat/{hooks → features/session/hooks}/use-chat-session-update.ts +17 -0
  125. package/src/features/chat/{hooks → features/session/hooks}/use-chat-sidebar-session-label-editor.ts +1 -1
  126. package/src/features/chat/features/session/hooks/use-selected-session-context-window-indicator.ts +15 -0
  127. package/src/features/chat/{utils → features/session/utils/__tests__}/chat-session-display.utils.test.ts +1 -1
  128. package/src/features/chat/{utils → features/session/utils/__tests__}/chat-session-route.utils.test.ts +1 -1
  129. package/src/features/chat/{utils → features/session/utils/__tests__}/ncp-session-adapter.utils.cancelled-tool.test.ts +2 -2
  130. package/src/features/chat/{utils → features/session/utils/__tests__}/ncp-session-adapter.utils.test.ts +10 -2
  131. package/src/features/chat/{utils → features/session/utils/__tests__}/session-context.utils.test.ts +1 -1
  132. package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +60 -0
  133. package/src/features/chat/{utils → features/session/utils}/chat-session-preference-governance.utils.ts +0 -128
  134. package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +144 -0
  135. package/src/features/chat/{utils → features/session/utils}/ncp-session-adapter.utils.ts +2 -0
  136. package/src/features/chat/{components → features/session-type/components/__tests__}/chat-session-type-option-item.test.tsx +1 -1
  137. package/src/features/chat/{components → features/session-type/components}/chat-session-type-option-item.tsx +7 -16
  138. package/src/features/chat/features/session-type/components/chat-sidebar-create-menu.tsx +42 -0
  139. package/src/features/chat/{hooks → features/session-type/hooks/__tests__}/use-chat-session-type-state.test.tsx +1 -1
  140. package/src/features/chat/{hooks → features/session-type/hooks}/use-chat-session-type-state.ts +24 -94
  141. package/src/features/chat/features/session-type/utils/chat-session-type.utils.ts +109 -0
  142. package/src/features/chat/{components → features/workspace/components/__tests__}/chat-session-workspace-file-preview.test.tsx +1 -1
  143. package/src/features/chat/{components → features/workspace/components}/chat-session-workspace-file-preview.tsx +2 -2
  144. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +156 -0
  145. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +84 -0
  146. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +138 -0
  147. package/src/features/chat/{components/workspace → features/workspace/components}/session-cron-job-content.tsx +1 -1
  148. package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +63 -0
  149. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +103 -0
  150. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +183 -0
  151. package/src/features/chat/index.ts +17 -6
  152. package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +383 -0
  153. package/src/features/chat/managers/__tests__/chat-query.manager.test.ts +39 -0
  154. package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +129 -0
  155. package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +236 -0
  156. package/src/features/chat/managers/{chat-session-list.manager.test.ts → __tests__/chat-session-list.manager.test.ts} +98 -78
  157. package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +219 -0
  158. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +652 -0
  159. package/src/features/chat/managers/__tests__/chat-ui.manager.test.ts +126 -0
  160. package/src/features/chat/managers/{recent-selection.manager.test.ts → __tests__/recent-selection.manager.test.ts} +37 -14
  161. package/src/features/chat/managers/chat-draft-intent.manager.ts +46 -0
  162. package/src/features/chat/managers/{ncp-chat-input.manager.ts → chat-input.manager.ts} +118 -45
  163. package/src/features/chat/managers/chat-query.manager.ts +48 -0
  164. package/src/features/chat/managers/chat-run.manager.ts +110 -0
  165. package/src/features/chat/managers/chat-session-list.manager.ts +45 -15
  166. package/src/features/chat/managers/chat-session-preference-sync.manager.ts +77 -5
  167. package/src/features/chat/managers/{ncp-chat-thread.manager.ts → chat-thread.manager.ts} +67 -36
  168. package/src/features/chat/managers/chat-ui.manager.ts +51 -9
  169. package/src/features/chat/managers/recent-selection.manager.ts +21 -67
  170. package/src/features/chat/pages/{ncp-chat-page.test.ts → __tests__/ncp-chat-page.test.ts} +95 -12
  171. package/src/features/chat/pages/ncp-chat-page.tsx +139 -397
  172. package/src/features/chat/presenters/chat.presenter.ts +39 -0
  173. package/src/features/chat/stores/chat-input.store.ts +12 -2
  174. package/src/features/chat/stores/chat-thread.store.ts +0 -19
  175. package/src/features/chat/stores/ncp-chat-query.store.ts +25 -0
  176. package/src/features/chat/stores/recent-selection.store.ts +85 -0
  177. package/src/features/chat/types/chat-input-bar.types.ts +0 -1
  178. package/src/features/chat/types/chat-input.types.ts +1 -0
  179. package/src/features/chat/types/chat-message.types.ts +1 -0
  180. package/src/features/chat/types/chat-run.types.ts +41 -0
  181. package/src/{shared → features/cron}/components/cron-config.tsx +1 -1
  182. package/src/features/cron/hooks/use-cron-jobs.ts +58 -0
  183. package/src/features/cron/index.ts +7 -0
  184. package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.tsx +15 -61
  185. package/src/features/marketplace/components/marketplace-external-skill-source-action.tsx +1 -1
  186. package/src/features/marketplace/components/marketplace-item-list-view.tsx +167 -0
  187. package/src/features/marketplace/components/marketplace-list-card.tsx +27 -31
  188. package/src/features/marketplace/components/marketplace-page-data.ts +0 -6
  189. package/src/features/marketplace/components/marketplace-page.tsx +105 -451
  190. package/src/features/marketplace/components/mcp/mcp-marketplace-card.tsx +1 -1
  191. package/src/features/marketplace/components/mcp/mcp-marketplace-dialogs.tsx +1 -1
  192. package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +1 -1
  193. package/src/features/marketplace/hooks/use-marketplace-item-actions.ts +101 -0
  194. package/src/features/marketplace/hooks/use-marketplace-item-detail.ts +109 -0
  195. package/src/features/marketplace/hooks/use-marketplace-list-model.ts +160 -0
  196. package/src/features/marketplace/utils/{marketplace-installed-cache.utils.test.ts → __tests__/marketplace-installed-cache.utils.test.ts} +1 -1
  197. package/src/features/panel-apps/components/{panel-app-list-item.test.tsx → __tests__/panel-app-list-item.test.tsx} +1 -1
  198. package/src/features/panel-apps/components/{panel-app-toolbar.test.tsx → __tests__/panel-app-toolbar.test.tsx} +1 -1
  199. package/src/features/panel-apps/components/__tests__/panel-apps-list.test.tsx +137 -0
  200. package/src/features/panel-apps/components/panel-apps-list.tsx +119 -5
  201. package/src/features/panel-apps/index.ts +2 -0
  202. package/src/features/panel-apps/utils/{panel-app-view.utils.test.ts → __tests__/panel-app-view.utils.test.ts} +1 -1
  203. package/src/features/panel-apps/utils/panel-app-entry-match.utils.ts +17 -0
  204. package/src/features/pwa/managers/{pwa-service-worker-cache.manager.test.ts → __tests__/pwa-service-worker-cache.manager.test.ts} +1 -1
  205. package/src/features/remote/components/remote-access-page.tsx +2 -2
  206. package/src/features/remote/services/{remote-access-feedback.service.test.ts → __tests__/remote-access-feedback.service.test.ts} +1 -1
  207. package/src/{shared → features/settings}/components/config/provider-form.tsx +5 -5
  208. package/src/{shared/components → features/settings/components/config}/provider-status-badge.tsx +1 -1
  209. package/src/{shared/components/model-config.test.tsx → features/settings/pages/__tests__/model-config-page.test.tsx} +40 -5
  210. package/src/{shared/components/config/providers-list.test.tsx → features/settings/pages/__tests__/providers-config-page.test.tsx} +48 -5
  211. package/src/{shared/components/search-config.test.tsx → features/settings/pages/__tests__/search-config-page.test.tsx} +3 -3
  212. package/src/{shared/components/config/secrets-config.test.tsx → features/settings/pages/__tests__/secrets-config-page.test.tsx} +3 -3
  213. package/src/{shared/components/model-config.tsx → features/settings/pages/model-config-page.tsx} +1 -1
  214. package/src/{shared/components/config/providers-list.tsx → features/settings/pages/providers-config-page.tsx} +3 -3
  215. package/src/{shared/components/search-config.tsx → features/settings/pages/search-config-page.tsx} +1 -1
  216. package/src/{shared/components/config/secrets-config.tsx → features/settings/pages/secrets-config-page.tsx} +2 -2
  217. package/src/{shared/components/config/provider-form-support.test.ts → features/settings/utils/__tests__/provider-form-support.utils.test.ts} +1 -1
  218. package/src/features/system-status/components/{runtime-control-card.test.tsx → __tests__/runtime-control-card.test.tsx} +1 -1
  219. package/src/features/system-status/components/{runtime-presence-card.test.tsx → __tests__/runtime-presence-card.test.tsx} +1 -1
  220. package/src/features/system-status/components/runtime-presence-card.tsx +2 -2
  221. package/src/features/system-status/managers/{system-status.manager.bootstrap-polling.test.ts → __tests__/system-status.manager.bootstrap-polling.test.ts} +1 -1
  222. package/src/features/system-status/managers/{system-status.manager.test.ts → __tests__/system-status.manager.test.ts} +1 -1
  223. package/src/features/system-status/utils/{system-status.utils.test.ts → __tests__/system-status.utils.test.ts} +1 -1
  224. package/src/shared/components/common/{agent-avatar.test.tsx → __tests__/agent-avatar.test.tsx} +1 -1
  225. package/src/shared/components/common/agent-identity/use-agent-identity.ts +3 -8
  226. package/src/shared/components/common/brand-header.tsx +1 -1
  227. package/src/shared/components/common/tag-input.tsx +1 -1
  228. package/src/shared/components/doc-browser/{doc-browser-context.test.tsx → __tests__/doc-browser-context.test.tsx} +1 -1
  229. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +64 -161
  230. package/src/shared/components/doc-browser/doc-browser.tsx +4 -4
  231. package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +66 -0
  232. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +11 -8
  233. package/src/shared/components/ui/actions/icon-action-button.tsx +53 -0
  234. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +52 -0
  235. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +228 -0
  236. package/src/shared/hooks/use-app-meta.ts +10 -0
  237. package/src/shared/hooks/use-config.ts +1 -148
  238. package/src/shared/lib/api/{ncp-session.test.ts → __tests__/ncp-session.test.ts} +3 -3
  239. package/src/shared/lib/api/{raw-client.test.ts → __tests__/raw-client.test.ts} +1 -1
  240. package/src/shared/lib/api/chat-session-type.types.ts +10 -0
  241. package/src/shared/lib/api/ncp-session.types.ts +1 -0
  242. package/src/shared/lib/api/types.ts +3 -0
  243. package/src/shared/lib/cadence/services/{adaptive-cadence.service.test.ts → __tests__/adaptive-cadence.service.test.ts} +1 -1
  244. package/src/shared/lib/i18n/locales/en-US/chat.json +6 -0
  245. package/src/shared/lib/i18n/locales/en-US/core.json +1 -0
  246. package/src/shared/lib/i18n/locales/en-US/doc-browser.json +10 -0
  247. package/src/shared/lib/i18n/locales/zh-CN/chat.json +6 -0
  248. package/src/shared/lib/i18n/locales/zh-CN/core.json +1 -0
  249. package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +10 -0
  250. package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +1 -1
  251. package/src/shared/lib/i18n/runtime/{i18n-language-owner.test.ts → __tests__/i18n-language-owner.test.ts} +2 -2
  252. package/src/shared/lib/navigation-history/{navigation-history.utils.test.ts → __tests__/navigation-history.utils.test.ts} +1 -1
  253. package/src/shared/lib/provider-models/{index.test.ts → __tests__/index.test.ts} +1 -1
  254. package/src/shared/lib/transport/{app-client.test.ts → __tests__/app-client.test.ts} +3 -3
  255. package/src/shared/lib/transport/{remote.transport.test.ts → __tests__/remote.transport.test.ts} +1 -1
  256. package/src/shared/lib/transport/{sse-stream.test.ts → __tests__/sse-stream.test.ts} +1 -1
  257. package/tsconfig.json +2 -5
  258. package/vite.config.ts +4 -4
  259. package/vitest.config.ts +4 -0
  260. package/dist/assets/app-presenter-provider-C7EsUuEJ.js +0 -3
  261. package/dist/assets/arrow-left-CzSkR5L6.js +0 -1
  262. package/dist/assets/book-open-DmeQPqkd.js +0 -1
  263. package/dist/assets/channels-list-page-B0yiiH01.js +0 -8
  264. package/dist/assets/chat-page-ChPjx_X9.js +0 -105
  265. package/dist/assets/config-split-page-BzfZSyAr.js +0 -1
  266. package/dist/assets/desktop-update-config-CExpdkqD.js +0 -1
  267. package/dist/assets/doc-browser-EZbnEcdk.js +0 -1
  268. package/dist/assets/doc-browser-XIwe1Tg-.js +0 -1
  269. package/dist/assets/doc-browser-context-BzEA1lm1.js +0 -1
  270. package/dist/assets/es2015-CJlVSTh-.js +0 -41
  271. package/dist/assets/host-capabilities-DjiRQ0Q9.js +0 -1
  272. package/dist/assets/index-DfZTO6Pi.js +0 -101
  273. package/dist/assets/index-mIb_YMrc.css +0 -1
  274. package/dist/assets/key-round-BzYZ0Nno.js +0 -1
  275. package/dist/assets/loader-circle-BbdIlBbQ.js +0 -1
  276. package/dist/assets/mcp-marketplace-page-L22aCzHX.js +0 -40
  277. package/dist/assets/mcp-marketplace-page-f80Jmv37.js +0 -1
  278. package/dist/assets/model-config-DkD7vSQT.js +0 -1
  279. package/dist/assets/notice-card-CD9Ok62G.js +0 -1
  280. package/dist/assets/play-DHuSeKs8.js +0 -1
  281. package/dist/assets/plus-DrV685KC.js +0 -1
  282. package/dist/assets/popover-CoBu3mbV.js +0 -1
  283. package/dist/assets/provider-models-C9VRroK3.js +0 -1
  284. package/dist/assets/provider-scoped-model-input-DZlmTCJU.js +0 -1
  285. package/dist/assets/providers-list-CVkWiqIy.js +0 -1
  286. package/dist/assets/refresh-cw-CVo4nWpq.js +0 -1
  287. package/dist/assets/remote-Bznw9iji.js +0 -1
  288. package/dist/assets/rotate-cw-CXDpRO6D.js +0 -1
  289. package/dist/assets/runtime-config-page-5IycbIxs.js +0 -1
  290. package/dist/assets/search-8nY6PGm0.js +0 -1
  291. package/dist/assets/search-config-DEH80WkC.js +0 -1
  292. package/dist/assets/secrets-config-Gzo5nDJG.js +0 -3
  293. package/dist/assets/status-dot-C1-FKgvv.js +0 -1
  294. package/dist/assets/tabs-BqkKwx1R.js +0 -1
  295. package/dist/assets/tabs-custom-DOkaJZmt.js +0 -1
  296. package/dist/assets/tooltip-Bw-mXQAM.js +0 -1
  297. package/dist/assets/trash-2-CmIwAJIT.js +0 -1
  298. package/dist/assets/x-CSRTOZnM.js +0 -1
  299. package/src/features/chat/components/chat-session-workspace-panel-nav.tsx +0 -264
  300. package/src/features/chat/components/chat-session-workspace-panel.tsx +0 -380
  301. package/src/features/chat/components/layout/chat-sidebar-read-state.test.tsx +0 -145
  302. package/src/features/chat/components/layout/chat-sidebar.test.tsx +0 -896
  303. package/src/features/chat/hooks/use-chat-input-bar-controller.test.tsx +0 -152
  304. package/src/features/chat/hooks/use-chat-input-bar-controller.ts +0 -142
  305. package/src/features/chat/hooks/use-chat-session-label.ts +0 -18
  306. package/src/features/chat/hooks/use-hydrated-ncp-agent.test.tsx +0 -90
  307. package/src/features/chat/hooks/use-ncp-chat-derived-state.ts +0 -181
  308. package/src/features/chat/hooks/use-ncp-chat-page-data.test.tsx +0 -70
  309. package/src/features/chat/hooks/use-ncp-chat-page-data.ts +0 -260
  310. package/src/features/chat/hooks/use-selected-session-context-window-indicator.ts +0 -18
  311. package/src/features/chat/managers/chat-session-preference-sync.manager.test.ts +0 -77
  312. package/src/features/chat/managers/chat-stream-actions.manager.ts +0 -35
  313. package/src/features/chat/managers/ncp-chat-input.manager.test.ts +0 -232
  314. package/src/features/chat/managers/ncp-chat-presenter.manager.ts +0 -28
  315. package/src/features/chat/managers/ncp-chat-thread.manager.test.ts +0 -369
  316. package/src/features/chat/types/chat-stream.types.ts +0 -32
  317. package/src/features/chat/utils/chat-session-preference-governance.utils.test.tsx +0 -114
  318. package/src/features/marketplace/components/marketplace-catalog-grid.tsx +0 -132
  319. package/src/shared/components/resizable-right-panel/resizable-right-panel.test.tsx +0 -38
  320. package/src/shared/components/ui/config-card.tsx +0 -71
  321. package/src/shared/components/ui/highlight-card.tsx +0 -40
  322. package/src/shared/components/ui/tabs-custom.tsx +0 -49
  323. /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-CTqBnCDp.js} +0 -0
  324. /package/src/{app.test.tsx → __tests__/app.test.tsx} +0 -0
  325. /package/src/app/components/layout/{app-layout.test.tsx → __tests__/app-layout.test.tsx} +0 -0
  326. /package/src/app/components/layout/{runtime-status-entry.test.tsx → __tests__/runtime-status-entry.test.tsx} +0 -0
  327. /package/src/app/components/layout/{settings-entry-page.test.tsx → __tests__/settings-entry-page.test.tsx} +0 -0
  328. /package/src/app/components/layout/{sidebar.layout.test.tsx → __tests__/sidebar.layout.test.tsx} +0 -0
  329. /package/src/features/channels/components/config/{channel-form.test.tsx → __tests__/channel-form.test.tsx} +0 -0
  330. /package/src/features/channels/components/config/{weixin-channel-auth-section.test.tsx → __tests__/weixin-channel-auth-section.test.tsx} +0 -0
  331. /package/src/features/channels/pages/{channels-list-page.test.tsx → __tests__/channels-list-page.test.tsx} +0 -0
  332. /package/src/features/chat/{utils → features/input/utils}/chat-composer-state.utils.ts +0 -0
  333. /package/src/features/chat/{utils → features/input/utils}/chat-inline-token.utils.ts +0 -0
  334. /package/src/features/chat/{utils → features/message/utils}/chat-message-core.utils.ts +0 -0
  335. /package/src/features/chat/{utils → features/message/utils}/chat-message-partial-json.utils.ts +0 -0
  336. /package/src/features/chat/{utils → features/message/utils}/chat-message-tool-agent-id.utils.ts +0 -0
  337. /package/src/features/chat/{utils → features/message/utils}/file-operation/card.utils.ts +0 -0
  338. /package/src/features/chat/{utils → features/message/utils}/file-operation/diff.utils.ts +0 -0
  339. /package/src/features/chat/{utils → features/message/utils}/file-operation/line-builder.utils.ts +0 -0
  340. /package/src/features/chat/{utils → features/message/utils}/file-operation/parsed-block.utils.ts +0 -0
  341. /package/src/features/chat/{utils → features/message/utils}/file-operation/record-readers.utils.ts +0 -0
  342. /package/src/features/chat/{utils → features/runtime/utils}/ncp-app-client-fetch.utils.ts +0 -0
  343. /package/src/features/chat/{utils → features/runtime/utils}/ncp-chat-runtime-availability.utils.ts +0 -0
  344. /package/src/features/chat/{components/conversation → features/session/components}/session-header/chat-session-header-menu-item.tsx +0 -0
  345. /package/src/features/chat/{components/conversation → features/session/components}/session-header/chat-session-project-dialog.tsx +0 -0
  346. /package/src/features/chat/{components/session → features/session/components}/session-run-badge.tsx +0 -0
  347. /package/src/features/chat/{utils → features/session/utils}/chat-context-window-indicator.utils.ts +0 -0
  348. /package/src/features/chat/{utils → features/session/utils}/chat-session-display.utils.ts +0 -0
  349. /package/src/features/chat/{utils → features/session/utils}/chat-session-route.utils.ts +0 -0
  350. /package/src/features/chat/{utils → features/session/utils}/ncp-session-context-metadata.utils.ts +0 -0
  351. /package/src/features/chat/{utils → features/session/utils}/session-context.utils.ts +0 -0
  352. /package/src/features/chat/{hooks → features/session-type/hooks}/use-ncp-chat-session-types.ts +0 -0
  353. /package/src/features/chat/{components/workspace → features/workspace/components}/chat-session-workspace-file-breadcrumbs.tsx +0 -0
  354. /package/src/features/chat/stores/{chat-thread.store.test.ts → __tests__/chat-thread.store.test.ts} +0 -0
  355. /package/src/features/marketplace/components/{marketplace-page-detail.test.tsx → __tests__/marketplace-page-detail.test.tsx} +0 -0
  356. /package/src/features/marketplace/components/{marketplace-page.test.tsx → __tests__/marketplace-page.test.tsx} +0 -0
  357. /package/src/features/marketplace/components/curated-shelves/{marketplace-curated-scene-route.test.tsx → __tests__/marketplace-curated-scene-route.test.tsx} +0 -0
  358. /package/src/features/marketplace/components/detail-doc/{marketplace-detail-doc.test.ts → __tests__/marketplace-detail-doc.test.ts} +0 -0
  359. /package/src/features/marketplace/components/mcp/{mcp-marketplace-page.test.tsx → __tests__/mcp-marketplace-page.test.tsx} +0 -0
  360. /package/src/features/marketplace/hooks/{use-marketplace.test.tsx → __tests__/use-marketplace.test.tsx} +0 -0
  361. /package/src/features/panel-apps/managers/{panel-app-bridge.manager.test.ts → __tests__/panel-app-bridge.manager.test.ts} +0 -0
  362. /package/src/features/panel-apps/utils/{panel-app-doc-browser.utils.test.ts → __tests__/panel-app-doc-browser.utils.test.ts} +0 -0
  363. /package/src/features/pwa/components/{pwa-install-entry.test.tsx → __tests__/pwa-install-entry.test.tsx} +0 -0
  364. /package/src/features/pwa/managers/{pwa-install.manager.test.ts → __tests__/pwa-install.manager.test.ts} +0 -0
  365. /package/src/features/pwa/managers/{pwa-shell-theme.manager.test.ts → __tests__/pwa-shell-theme.manager.test.ts} +0 -0
  366. /package/src/features/remote/components/{remote-access-page.test.tsx → __tests__/remote-access-page.test.tsx} +0 -0
  367. /package/src/features/right-panel-resources/utils/{right-panel-resource-route-resolver.utils.test.ts → __tests__/right-panel-resource-route-resolver.utils.test.ts} +0 -0
  368. /package/src/features/right-panel-resources/utils/{right-panel-resource-uri.utils.test.ts → __tests__/right-panel-resource-uri.utils.test.ts} +0 -0
  369. /package/src/features/service-apps/components/{service-apps-panel.test.tsx → __tests__/service-apps-panel.test.tsx} +0 -0
  370. /package/src/{shared/components → features/settings/components/config}/provider-advanced-settings-section.tsx +0 -0
  371. /package/src/{shared/components → features/settings/components/config}/provider-auth-section.tsx +0 -0
  372. /package/src/{shared → features/settings}/components/config/provider-models-section.tsx +0 -0
  373. /package/src/{shared/components → features/settings/components/config}/provider-pill-selector.tsx +0 -0
  374. /package/src/{shared → features/settings}/components/config/secrets-config-form.tsx +0 -0
  375. /package/src/features/settings/pages/{language-settings-page.test.tsx → __tests__/language-settings-page.test.tsx} +0 -0
  376. /package/src/{shared/components/config/provider-form-support.ts → features/settings/utils/provider-form-support.utils.ts} +0 -0
  377. /package/src/features/side-dock/components/{side-dock.test.tsx → __tests__/side-dock.test.tsx} +0 -0
  378. /package/src/features/side-dock/managers/{side-dock.manager.test.ts → __tests__/side-dock.manager.test.ts} +0 -0
  379. /package/src/features/side-dock/utils/{side-dock-item.utils.test.ts → __tests__/side-dock-item.utils.test.ts} +0 -0
  380. /package/src/features/system-status/components/{desktop-update-config.test.tsx → __tests__/desktop-update-config.test.tsx} +0 -0
  381. /package/src/features/system-status/pages/{runtime-config-page.test.tsx → __tests__/runtime-config-page.test.tsx} +0 -0
  382. /package/src/platforms/desktop/components/{desktop-app-shell.test.tsx → __tests__/desktop-app-shell.test.tsx} +0 -0
  383. /package/src/platforms/mobile/components/{mobile-app-shell.test.tsx → __tests__/mobile-app-shell.test.tsx} +0 -0
  384. /package/src/platforms/mobile/components/{mobile-bottom-nav.test.tsx → __tests__/mobile-bottom-nav.test.tsx} +0 -0
  385. /package/src/shared/components/{ui → actions}/action-link.tsx +0 -0
  386. /package/src/shared/components/common/{brand-header.test.tsx → __tests__/brand-header.test.tsx} +0 -0
  387. /package/src/shared/components/doc-browser/{doc-browser.test.tsx → __tests__/doc-browser.test.tsx} +0 -0
  388. /package/src/shared/components/{ui → feedback}/notice-card.tsx +0 -0
  389. /package/src/shared/components/path-picker/{server-path-picker-dialog.test.tsx → __tests__/server-path-picker-dialog.test.tsx} +0 -0
  390. /package/src/shared/components/{ui → settings}/setting-row.tsx +0 -0
  391. /package/src/shared/components/{ui → status}/status-dot.tsx +0 -0
  392. /package/src/shared/components/{ui → tags}/tag-chip.tsx +0 -0
  393. /package/src/shared/lib/api/{api-base.test.ts → __tests__/api-base.test.ts} +0 -0
  394. /package/src/shared/lib/api/{client.test.ts → __tests__/client.test.ts} +0 -0
  395. /package/src/shared/lib/api/{ncp-session-query-cache.utils.test.ts → __tests__/ncp-session-query-cache.utils.test.ts} +0 -0
  396. /package/src/shared/lib/app-resource-uri/{app-resource-uri.test.ts → __tests__/app-resource-uri.test.ts} +0 -0
  397. /package/src/shared/lib/host-capabilities/{host-capability.manager.test.ts → __tests__/host-capability.manager.test.ts} +0 -0
  398. /package/src/shared/lib/resource-uri/utils/{resource-uri-resolver.utils.test.ts → __tests__/resource-uri-resolver.utils.test.ts} +0 -0
  399. /package/src/shared/lib/session-project/{workspace-file-breadcrumb.test.ts → __tests__/workspace-file-breadcrumb.test.ts} +0 -0
@@ -1,896 +0,0 @@
1
- import { fireEvent, render, screen, waitFor } from '@testing-library/react';
2
- import { MemoryRouter } from 'react-router-dom';
3
- import { beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { ChatSidebar } from '@/features/chat/components/layout/chat-sidebar';
5
- import type { NcpSessionListItemView } from '@/features/chat/hooks/use-ncp-session-list-view';
6
- import { useChatInputStore } from '@/features/chat/stores/chat-input.store';
7
- import { useChatSessionListStore } from '@/features/chat/stores/chat-session-list.store';
8
-
9
- const mocks = vi.hoisted(() => ({
10
- createSession: vi.fn(() => 'draft-session-key'),
11
- goToSession: vi.fn(),
12
- goToChatRoot: vi.fn(),
13
- setQuery: vi.fn(),
14
- setListMode: vi.fn(),
15
- selectSession: vi.fn(),
16
- openChildSessionPanel: vi.fn(),
17
- docOpen: vi.fn(),
18
- setLanguage: vi.fn(),
19
- setTheme: vi.fn(),
20
- updateNcpSession: vi.fn(),
21
- agents: [] as Array<{ id: string; displayName?: string; avatarUrl?: string | null }>,
22
- sessionItems: [] as NcpSessionListItemView[],
23
- isLoading: false
24
- }));
25
-
26
- function createSessionItem(
27
- session: NcpSessionListItemView['session'],
28
- runStatus?: NcpSessionListItemView['runStatus'],
29
- ): NcpSessionListItemView {
30
- return { session, runStatus };
31
- }
32
-
33
- vi.mock('@/features/chat/components/providers/chat-presenter.provider', () => ({
34
- usePresenter: () => ({
35
- chatUiManager: {
36
- goToSession: mocks.goToSession,
37
- goToChatRoot: mocks.goToChatRoot,
38
- },
39
- chatSessionListManager: {
40
- createSession: mocks.createSession,
41
- setQuery: mocks.setQuery,
42
- setListMode: mocks.setListMode,
43
- selectSession: mocks.selectSession,
44
- markSessionRead: (
45
- sessionKey: string | null | undefined,
46
- readAt: string | null | undefined,
47
- ) => (sessionKey ? useChatSessionListStore.getState().markSessionRead(sessionKey, readAt) : undefined),
48
- },
49
- chatThreadManager: {
50
- openChildSessionPanel: mocks.openChildSessionPanel,
51
- },
52
- })
53
- }));
54
-
55
- vi.mock('@/shared/components/doc-browser', () => ({
56
- useDocBrowser: () => ({
57
- open: mocks.docOpen
58
- })
59
- }));
60
-
61
- vi.mock('@/features/chat/hooks/use-chat-session-label', () => ({
62
- useChatSessionLabel: () => async (params: {
63
- sessionKey: string;
64
- label: string | null;
65
- }) => {
66
- mocks.sessionItems = mocks.sessionItems.map((item) =>
67
- item.session.key === params.sessionKey
68
- ? {
69
- ...item,
70
- session: {
71
- ...item.session,
72
- ...(params.label ? { label: params.label } : { label: undefined })
73
- }
74
- }
75
- : item
76
- );
77
- return mocks.updateNcpSession(params.sessionKey, { label: params.label });
78
- }
79
- }));
80
-
81
- vi.mock('@/features/chat/hooks/use-ncp-session-list-view', () => ({
82
- useNcpSessionListView: () => ({
83
- isLoading: mocks.isLoading,
84
- items: mocks.sessionItems
85
- })
86
- }));
87
-
88
- vi.mock('@/shared/components/common/brand-header', () => ({
89
- BrandHeader: () => <div data-testid="brand-header" />
90
- }));
91
-
92
- vi.mock('@/shared/components/common/status-badge', () => ({
93
- StatusBadge: () => <div data-testid="status-badge" />
94
- }));
95
-
96
- vi.mock('@/shared/hooks/use-agents', () => ({
97
- useAgents: () => ({
98
- data: {
99
- agents: mocks.agents
100
- }
101
- })
102
- }));
103
-
104
- vi.mock('@/app/components/i18n-provider', () => ({
105
- useI18n: () => ({
106
- language: 'en',
107
- setLanguage: mocks.setLanguage
108
- })
109
- }));
110
-
111
- vi.mock('@/app/components/theme-provider', () => ({
112
- useTheme: () => ({
113
- theme: 'warm',
114
- setTheme: mocks.setTheme
115
- })
116
- }));
117
-
118
- vi.mock('@/features/system-status', () => ({
119
- useSystemStatus: () => ({
120
- connectionStatus: 'connected'
121
- })
122
- }));
123
-
124
- function resetSidebarTestState() {
125
- mocks.createSession.mockReset();
126
- mocks.createSession.mockReturnValue('draft-session-key');
127
- mocks.goToSession.mockReset();
128
- mocks.goToChatRoot.mockReset();
129
- mocks.setQuery.mockReset();
130
- mocks.setListMode.mockReset();
131
- mocks.selectSession.mockReset();
132
- mocks.openChildSessionPanel.mockReset();
133
- mocks.docOpen.mockReset();
134
- mocks.setLanguage.mockReset();
135
- mocks.setTheme.mockReset();
136
- mocks.updateNcpSession.mockReset();
137
- mocks.updateNcpSession.mockResolvedValue({});
138
- mocks.agents = [];
139
- mocks.sessionItems = [];
140
- mocks.isLoading = false;
141
-
142
- useChatInputStore.setState({
143
- snapshot: {
144
- ...useChatInputStore.getState().snapshot,
145
- defaultSessionType: 'native',
146
- sessionTypeOptions: [
147
- { value: 'native', label: 'Native', ready: true },
148
- { value: 'codex', label: 'Codex', ready: true }
149
- ]
150
- }
151
- });
152
- useChatSessionListStore.setState({
153
- optimisticReadAtBySessionKey: {},
154
- snapshot: {
155
- ...useChatSessionListStore.getState().snapshot,
156
- query: '',
157
- listMode: 'time-first',
158
- selectedSessionKey: null
159
- }
160
- });
161
- }
162
-
163
- describe('ChatSidebar create and list basics', () => {
164
- beforeEach(resetSidebarTestState);
165
-
166
- it('closes the create-session menu after choosing a non-default session type', async () => {
167
- render(
168
- <MemoryRouter>
169
- <ChatSidebar />
170
- </MemoryRouter>
171
- );
172
-
173
- fireEvent.click(screen.getByLabelText('Session Type'));
174
- fireEvent.click(screen.getByText('Codex'));
175
-
176
- expect(mocks.createSession).toHaveBeenCalledWith('codex', undefined);
177
- await waitFor(() => {
178
- expect(screen.queryByText('Codex')).toBeNull();
179
- });
180
- });
181
-
182
- it('does not animate the desktop create task button width during runtime option hydration', () => {
183
- render(
184
- <MemoryRouter>
185
- <ChatSidebar />
186
- </MemoryRouter>
187
- );
188
-
189
- const createButton = screen.getByRole('button', { name: 'New Task' });
190
- const sessionTypeButton = screen.getByLabelText('Session Type');
191
-
192
- expect(createButton.className).not.toContain('transition-all');
193
- expect(sessionTypeButton.className).not.toContain('transition-all');
194
- });
195
-
196
- it('keeps the desktop brand row compact with symmetric vertical padding', () => {
197
- render(
198
- <MemoryRouter>
199
- <ChatSidebar />
200
- </MemoryRouter>
201
- );
202
-
203
- expect(screen.getByTestId('brand-header').parentElement?.className).toContain('py-2.5');
204
- });
205
-
206
- it('shows setup required status for runtime session types that are not ready yet', () => {
207
- useChatInputStore.setState({
208
- snapshot: {
209
- ...useChatInputStore.getState().snapshot,
210
- sessionTypeOptions: [
211
- { value: 'native', label: 'Native', ready: true },
212
- {
213
- value: 'claude',
214
- label: 'Claude',
215
- ready: false,
216
- reasonMessage: 'Configure a provider API key first.'
217
- }
218
- ]
219
- }
220
- });
221
-
222
- render(
223
- <MemoryRouter>
224
- <ChatSidebar />
225
- </MemoryRouter>
226
- );
227
-
228
- fireEvent.click(screen.getByLabelText('Session Type'));
229
-
230
- expect(screen.getByText('Claude')).not.toBeNull();
231
- expect(screen.getByText('Setup')).not.toBeNull();
232
- expect(screen.getByText('Configure a provider API key first.')).not.toBeNull();
233
- });
234
-
235
- it('renders the lightweight list mode switch in the session header row and toggles to project view', () => {
236
- render(
237
- <MemoryRouter>
238
- <ChatSidebar />
239
- </MemoryRouter>
240
- );
241
-
242
- expect(screen.getByText('Sessions')).not.toBeNull();
243
- fireEvent.click(screen.getByRole('button', { name: 'Project' }));
244
-
245
- expect(mocks.setListMode).toHaveBeenCalledWith('project-first');
246
- });
247
-
248
- it('uses a compact mobile search and create toolbar', () => {
249
- render(
250
- <MemoryRouter>
251
- <ChatSidebar variant="mobile" />
252
- </MemoryRouter>
253
- );
254
-
255
- const searchInput = screen.getByPlaceholderText('Search conversations...');
256
- const createButton = screen.getByRole('button', { name: 'New Task' });
257
-
258
- expect(searchInput.className).toContain('rounded-full');
259
- expect(createButton.textContent).toBe('');
260
- expect(screen.queryByText('New Task')).toBeNull();
261
-
262
- fireEvent.change(searchInput, { target: { value: 'release notes' } });
263
- fireEvent.click(createButton);
264
- fireEvent.click(screen.getByText('Codex'));
265
-
266
- expect(mocks.setQuery).toHaveBeenCalledWith('release notes');
267
- expect(mocks.createSession).toHaveBeenCalledWith('codex', undefined);
268
- expect(mocks.goToChatRoot).not.toHaveBeenCalled();
269
- });
270
-
271
- it('keeps low-frequency utility choices behind nested selectors', () => {
272
- render(
273
- <MemoryRouter>
274
- <ChatSidebar />
275
- </MemoryRouter>
276
- );
277
-
278
- expect(screen.queryByRole('button', { name: 'Help Docs' })).toBeNull();
279
- expect(screen.queryByText('Language')).toBeNull();
280
- expect(screen.queryByRole('option', { name: 'Cool' })).toBeNull();
281
-
282
- fireEvent.click(screen.getByRole('button', { name: 'Settings menu' }));
283
- expect(screen.getByText('Theme')).not.toBeNull();
284
- expect(screen.queryByRole('option', { name: 'Cool' })).toBeNull();
285
-
286
- fireEvent.click(screen.getByRole('button', { name: 'Help Docs' }));
287
-
288
- expect(mocks.docOpen).toHaveBeenCalledWith(undefined, {
289
- kind: 'docs',
290
- title: 'Help Docs',
291
- });
292
-
293
- fireEvent.click(screen.getByRole('button', { name: 'Settings menu' }));
294
- fireEvent.click(screen.getByRole('combobox', { name: 'Theme' }));
295
- fireEvent.click(screen.getByRole('option', { name: 'Cool' }));
296
-
297
- expect(mocks.setTheme).toHaveBeenCalledWith('cool');
298
- });
299
-
300
- it('creates the default session directly from the compact mobile add button when no menu is needed', () => {
301
- useChatInputStore.setState({
302
- snapshot: {
303
- ...useChatInputStore.getState().snapshot,
304
- defaultSessionType: 'native',
305
- sessionTypeOptions: [{ value: 'native', label: 'Native', ready: true }]
306
- }
307
- });
308
-
309
- render(
310
- <MemoryRouter>
311
- <ChatSidebar variant="mobile" />
312
- </MemoryRouter>
313
- );
314
-
315
- fireEvent.click(screen.getByRole('button', { name: 'New Task' }));
316
-
317
- expect(mocks.createSession).toHaveBeenCalledWith('native', undefined);
318
- expect(mocks.goToChatRoot).not.toHaveBeenCalled();
319
- });
320
-
321
- it('shows a session type badge for non-native sessions in the list', () => {
322
- mocks.sessionItems = [
323
- createSessionItem({
324
- key: 'session:codex-1',
325
- createdAt: '2026-03-19T09:00:00.000Z',
326
- updatedAt: '2026-03-19T09:05:00.000Z',
327
- label: 'Codex Task',
328
- sessionType: 'codex',
329
- sessionTypeMutable: false,
330
- messageCount: 2
331
- })
332
- ];
333
-
334
- render(
335
- <MemoryRouter>
336
- <ChatSidebar />
337
- </MemoryRouter>
338
- );
339
-
340
- expect(screen.getByText('Codex Task')).not.toBeNull();
341
- expect(screen.getByText('Codex')).not.toBeNull();
342
- expect(screen.queryByText('session:codex-1')).toBeNull();
343
- });
344
-
345
- it('formats non-native session badges generically when the type is no longer in the available options', () => {
346
- useChatInputStore.setState({
347
- snapshot: {
348
- ...useChatInputStore.getState().snapshot,
349
- sessionTypeOptions: [{ value: 'native', label: 'Native' }]
350
- }
351
- });
352
- mocks.sessionItems = [
353
- createSessionItem({
354
- key: 'session:workspace-agent-1',
355
- createdAt: '2026-03-19T09:00:00.000Z',
356
- updatedAt: '2026-03-19T09:05:00.000Z',
357
- label: 'Workspace Task',
358
- sessionType: 'workspace-agent',
359
- sessionTypeMutable: false,
360
- messageCount: 2
361
- })
362
- ];
363
-
364
- render(
365
- <MemoryRouter>
366
- <ChatSidebar />
367
- </MemoryRouter>
368
- );
369
-
370
- expect(screen.getByText('Workspace Task')).not.toBeNull();
371
- expect(screen.getByText('Workspace Agent')).not.toBeNull();
372
- });
373
-
374
- it('does not show a session type badge for native sessions in the list', () => {
375
- useChatInputStore.setState({
376
- snapshot: {
377
- ...useChatInputStore.getState().snapshot,
378
- sessionTypeOptions: [{ value: 'native', label: 'Native' }]
379
- }
380
- });
381
- mocks.sessionItems = [
382
- createSessionItem({
383
- key: 'session:native-1',
384
- createdAt: '2026-03-19T09:00:00.000Z',
385
- updatedAt: '2026-03-19T09:05:00.000Z',
386
- label: 'Native Task',
387
- sessionType: 'native',
388
- sessionTypeMutable: false,
389
- messageCount: 1
390
- })
391
- ];
392
-
393
- render(
394
- <MemoryRouter>
395
- <ChatSidebar />
396
- </MemoryRouter>
397
- );
398
-
399
- expect(screen.getByText('Native Task')).not.toBeNull();
400
- expect(screen.queryByText('Native')).toBeNull();
401
- });
402
- });
403
-
404
- describe('ChatSidebar activity ordering', () => {
405
- beforeEach(resetSidebarTestState);
406
-
407
- it('orders sessions by last message time and ignores metadata updatedAt changes', () => {
408
- mocks.sessionItems = [
409
- createSessionItem({
410
- key: 'session:message-newer',
411
- createdAt: '2026-03-19T08:00:00.000Z',
412
- updatedAt: '2026-03-19T09:00:00.000Z',
413
- lastMessageAt: '2026-03-19T09:00:00.000Z',
414
- label: 'Message Newer',
415
- sessionType: 'native',
416
- sessionTypeMutable: false,
417
- messageCount: 1
418
- }),
419
- createSessionItem({
420
- key: 'session:metadata-newer',
421
- createdAt: '2026-03-19T07:00:00.000Z',
422
- updatedAt: '2026-03-19T12:00:00.000Z',
423
- lastMessageAt: '2026-03-19T08:00:00.000Z',
424
- label: 'Metadata Newer',
425
- sessionType: 'native',
426
- sessionTypeMutable: false,
427
- messageCount: 1
428
- })
429
- ];
430
-
431
- render(
432
- <MemoryRouter>
433
- <ChatSidebar />
434
- </MemoryRouter>
435
- );
436
-
437
- const messageNewer = screen.getByText('Message Newer');
438
- const metadataNewer = screen.getByText('Metadata Newer');
439
-
440
- expect(messageNewer.compareDocumentPosition(metadataNewer) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
441
- });
442
-
443
- it('uses createdAt for sorting sessions without messages', () => {
444
- mocks.sessionItems = [
445
- createSessionItem({
446
- key: 'session:created-older',
447
- createdAt: '2026-03-19T08:00:00.000Z',
448
- updatedAt: '2026-03-19T12:00:00.000Z',
449
- label: 'Created Older',
450
- sessionType: 'native',
451
- sessionTypeMutable: false,
452
- messageCount: 0
453
- }),
454
- createSessionItem({
455
- key: 'session:created-newer',
456
- createdAt: '2026-03-19T09:00:00.000Z',
457
- updatedAt: '2026-03-19T10:00:00.000Z',
458
- label: 'Created Newer',
459
- sessionType: 'native',
460
- sessionTypeMutable: false,
461
- messageCount: 0
462
- })
463
- ];
464
-
465
- render(
466
- <MemoryRouter>
467
- <ChatSidebar />
468
- </MemoryRouter>
469
- );
470
-
471
- const createdNewer = screen.getByText('Created Newer');
472
- const createdOlder = screen.getByText('Created Older');
473
-
474
- expect(createdNewer.compareDocumentPosition(createdOlder) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
475
- });
476
- });
477
-
478
- describe('ChatSidebar project-first mode', () => {
479
- beforeEach(resetSidebarTestState);
480
-
481
- it('shows project groups only in project-first mode and hides sessions without a project', () => {
482
- useChatSessionListStore.setState({
483
- snapshot: {
484
- ...useChatSessionListStore.getState().snapshot,
485
- listMode: 'project-first'
486
- }
487
- });
488
- mocks.sessionItems = [
489
- createSessionItem({
490
- key: 'session:project-1',
491
- createdAt: '2026-03-19T09:00:00.000Z',
492
- updatedAt: '2026-03-19T11:05:00.000Z',
493
- label: 'Project Alpha Task',
494
- projectRoot: '/tmp/project-alpha',
495
- projectName: 'project-alpha',
496
- sessionType: 'native',
497
- sessionTypeMutable: false,
498
- messageCount: 2
499
- }),
500
- createSessionItem({
501
- key: 'session:plain-1',
502
- createdAt: '2026-03-19T08:00:00.000Z',
503
- updatedAt: '2026-03-19T08:05:00.000Z',
504
- label: 'Loose Task',
505
- sessionType: 'native',
506
- sessionTypeMutable: false,
507
- messageCount: 1
508
- })
509
- ];
510
-
511
- render(
512
- <MemoryRouter>
513
- <ChatSidebar />
514
- </MemoryRouter>
515
- );
516
-
517
- expect(screen.getByText('project-alpha')).not.toBeNull();
518
- expect(screen.getByText('Project Alpha Task')).not.toBeNull();
519
- expect(screen.queryByText('Loose Task')).toBeNull();
520
- });
521
-
522
- it('lets the user choose a runtime type when creating a project-bound draft', () => {
523
- useChatSessionListStore.setState({
524
- snapshot: {
525
- ...useChatSessionListStore.getState().snapshot,
526
- listMode: 'project-first'
527
- }
528
- });
529
- mocks.sessionItems = [
530
- createSessionItem({
531
- key: 'session:project-2',
532
- createdAt: '2026-03-19T09:00:00.000Z',
533
- updatedAt: '2026-03-19T11:05:00.000Z',
534
- label: 'Grouped Task',
535
- projectRoot: '/tmp/project-beta',
536
- projectName: 'project-beta',
537
- sessionType: 'native',
538
- sessionTypeMutable: false,
539
- messageCount: 2
540
- })
541
- ];
542
-
543
- render(
544
- <MemoryRouter>
545
- <ChatSidebar />
546
- </MemoryRouter>
547
- );
548
-
549
- fireEvent.click(screen.getByRole('button', { name: 'New Task · project-beta' }));
550
- fireEvent.click(screen.getByText('Codex'));
551
-
552
- expect(mocks.createSession).toHaveBeenCalledWith('codex', '/tmp/project-beta');
553
- expect(mocks.goToSession).not.toHaveBeenCalled();
554
- });
555
-
556
- it('creates immediately when there is only one available runtime type', () => {
557
- useChatInputStore.setState({
558
- snapshot: {
559
- ...useChatInputStore.getState().snapshot,
560
- defaultSessionType: 'native',
561
- sessionTypeOptions: [{ value: 'native', label: 'Native', ready: true }]
562
- }
563
- });
564
- useChatSessionListStore.setState({
565
- snapshot: {
566
- ...useChatSessionListStore.getState().snapshot,
567
- listMode: 'project-first'
568
- }
569
- });
570
- mocks.sessionItems = [
571
- createSessionItem({
572
- key: 'session:project-3',
573
- createdAt: '2026-03-19T09:00:00.000Z',
574
- updatedAt: '2026-03-19T11:05:00.000Z',
575
- label: 'Single Runtime Task',
576
- projectRoot: '/tmp/project-gamma',
577
- projectName: 'project-gamma',
578
- sessionType: 'native',
579
- sessionTypeMutable: false,
580
- messageCount: 2
581
- })
582
- ];
583
-
584
- render(
585
- <MemoryRouter>
586
- <ChatSidebar />
587
- </MemoryRouter>
588
- );
589
-
590
- fireEvent.click(screen.getByRole('button', { name: 'New Task · project-gamma' }));
591
-
592
- expect(mocks.createSession).toHaveBeenCalledWith('native', '/tmp/project-gamma');
593
- expect(mocks.goToSession).not.toHaveBeenCalled();
594
- });
595
-
596
- it('opens the draft detail after creating a project-bound session on mobile', () => {
597
- useChatSessionListStore.setState({
598
- snapshot: {
599
- ...useChatSessionListStore.getState().snapshot,
600
- listMode: 'project-first'
601
- }
602
- });
603
- mocks.sessionItems = [
604
- createSessionItem({
605
- key: 'session:project-mobile-1',
606
- createdAt: '2026-03-19T09:00:00.000Z',
607
- updatedAt: '2026-03-19T11:05:00.000Z',
608
- label: 'Grouped Mobile Task',
609
- projectRoot: '/tmp/project-mobile',
610
- projectName: 'project-mobile',
611
- sessionType: 'native',
612
- sessionTypeMutable: false,
613
- messageCount: 2
614
- })
615
- ];
616
-
617
- render(
618
- <MemoryRouter>
619
- <ChatSidebar variant="mobile" />
620
- </MemoryRouter>
621
- );
622
-
623
- fireEvent.click(screen.getByRole('button', { name: 'New Task · project-mobile' }));
624
- fireEvent.click(screen.getByText('Codex'));
625
-
626
- expect(mocks.createSession).toHaveBeenCalledWith('codex', '/tmp/project-mobile');
627
- expect(mocks.goToChatRoot).not.toHaveBeenCalled();
628
- });
629
- });
630
-
631
- describe('ChatSidebar session item interactions', () => {
632
- beforeEach(resetSidebarTestState);
633
-
634
- it('hides the sidebar agent avatar for the main agent but keeps specialist avatars', () => {
635
- mocks.agents = [
636
- { id: 'main', displayName: 'Main' },
637
- { id: 'engineer', displayName: 'Engineer' }
638
- ];
639
- mocks.sessionItems = [
640
- createSessionItem({
641
- key: 'session:main-1',
642
- createdAt: '2026-03-19T09:00:00.000Z',
643
- updatedAt: '2026-03-19T09:05:00.000Z',
644
- label: 'Main Task',
645
- sessionType: 'native',
646
- sessionTypeMutable: false,
647
- messageCount: 1,
648
- agentId: 'main'
649
- }),
650
- createSessionItem({
651
- key: 'session:engineer-1',
652
- createdAt: '2026-03-19T10:00:00.000Z',
653
- updatedAt: '2026-03-19T10:05:00.000Z',
654
- label: 'Engineer Task',
655
- sessionType: 'native',
656
- sessionTypeMutable: false,
657
- messageCount: 1,
658
- agentId: 'engineer'
659
- })
660
- ];
661
-
662
- render(
663
- <MemoryRouter>
664
- <ChatSidebar />
665
- </MemoryRouter>
666
- );
667
-
668
- expect(screen.queryByLabelText('Main')).toBeNull();
669
- expect(screen.getByLabelText('Engineer')).not.toBeNull();
670
- });
671
-
672
- it('edits the session label inline and saves through the ncp session api by default', async () => {
673
- mocks.sessionItems = [
674
- createSessionItem({
675
- key: 'session:ncp-1',
676
- createdAt: '2026-03-19T09:00:00.000Z',
677
- updatedAt: '2026-03-19T09:05:00.000Z',
678
- label: 'Initial Label',
679
- sessionType: 'native',
680
- sessionTypeMutable: false,
681
- messageCount: 1
682
- })
683
- ];
684
-
685
- render(
686
- <MemoryRouter>
687
- <ChatSidebar />
688
- </MemoryRouter>
689
- );
690
-
691
- fireEvent.click(screen.getByLabelText('Edit'));
692
- fireEvent.change(screen.getByPlaceholderText('Session label (optional)'), {
693
- target: { value: 'Renamed Label' }
694
- });
695
- fireEvent.click(screen.getByLabelText('Save'));
696
-
697
- await waitFor(() => {
698
- expect(mocks.updateNcpSession).toHaveBeenCalledWith('session:ncp-1', {
699
- label: 'Renamed Label'
700
- });
701
- });
702
- expect(screen.getByText('Renamed Label')).not.toBeNull();
703
- });
704
-
705
- it('cancels inline session label editing without saving', () => {
706
- mocks.sessionItems = [
707
- createSessionItem({
708
- key: 'session:ncp-2',
709
- createdAt: '2026-03-19T09:00:00.000Z',
710
- updatedAt: '2026-03-19T09:05:00.000Z',
711
- label: 'Cancelable Label',
712
- sessionType: 'native',
713
- sessionTypeMutable: false,
714
- messageCount: 1
715
- })
716
- ];
717
-
718
- render(
719
- <MemoryRouter>
720
- <ChatSidebar />
721
- </MemoryRouter>
722
- );
723
-
724
- fireEvent.click(screen.getByLabelText('Edit'));
725
- fireEvent.change(screen.getByPlaceholderText('Session label (optional)'), {
726
- target: { value: 'Should Not Persist' }
727
- });
728
- fireEvent.click(screen.getByLabelText('Cancel'));
729
-
730
- expect(mocks.updateNcpSession).not.toHaveBeenCalled();
731
- expect(screen.queryByDisplayValue('Should Not Persist')).toBeNull();
732
- expect(screen.getByText('Cancelable Label')).not.toBeNull();
733
- });
734
-
735
- it('shows an unread dot only after a non-active session finishes its newer update', () => {
736
- mocks.sessionItems = [
737
- createSessionItem({
738
- key: 'session:ncp-1',
739
- createdAt: '2026-03-19T09:00:00.000Z',
740
- updatedAt: '2026-03-19T09:05:00.000Z',
741
- lastMessageAt: '2026-03-19T09:05:00.000Z',
742
- readAt: '2026-03-19T09:05:00.000Z',
743
- label: 'Current Task',
744
- sessionType: 'native',
745
- sessionTypeMutable: false,
746
- messageCount: 1
747
- }),
748
- createSessionItem({
749
- key: 'session:ncp-2',
750
- createdAt: '2026-03-19T10:00:00.000Z',
751
- updatedAt: '2026-03-19T10:05:00.000Z',
752
- lastMessageAt: '2026-03-19T10:05:00.000Z',
753
- readAt: '2026-03-19T10:05:00.000Z',
754
- label: 'Background Task',
755
- sessionType: 'native',
756
- sessionTypeMutable: false,
757
- messageCount: 1
758
- }, 'running')
759
- ];
760
- useChatSessionListStore.setState({
761
- snapshot: {
762
- ...useChatSessionListStore.getState().snapshot,
763
- selectedSessionKey: 'session:ncp-1'
764
- }
765
- });
766
-
767
- const { rerender } = render(
768
- <MemoryRouter>
769
- <ChatSidebar />
770
- </MemoryRouter>
771
- );
772
-
773
- expect(screen.queryByLabelText('Session has unread updates')).toBeNull();
774
-
775
- mocks.sessionItems = [
776
- mocks.sessionItems[0]!,
777
- createSessionItem({
778
- key: 'session:ncp-2',
779
- createdAt: '2026-03-19T10:00:00.000Z',
780
- updatedAt: '2026-03-19T10:06:00.000Z',
781
- lastMessageAt: '2026-03-19T10:06:00.000Z',
782
- readAt: '2026-03-19T10:05:00.000Z',
783
- label: 'Background Task',
784
- sessionType: 'native',
785
- sessionTypeMutable: false,
786
- messageCount: 2
787
- }, 'running')
788
- ];
789
-
790
- rerender(
791
- <MemoryRouter>
792
- <ChatSidebar />
793
- </MemoryRouter>
794
- );
795
-
796
- expect(screen.queryByLabelText('Session has unread updates')).toBeNull();
797
-
798
- mocks.sessionItems = [
799
- mocks.sessionItems[0]!,
800
- createSessionItem({
801
- key: 'session:ncp-2',
802
- createdAt: '2026-03-19T10:00:00.000Z',
803
- updatedAt: '2026-03-19T10:06:00.000Z',
804
- lastMessageAt: '2026-03-19T10:06:00.000Z',
805
- readAt: '2026-03-19T10:05:00.000Z',
806
- label: 'Background Task',
807
- sessionType: 'native',
808
- sessionTypeMutable: false,
809
- messageCount: 2
810
- })
811
- ];
812
-
813
- rerender(
814
- <MemoryRouter>
815
- <ChatSidebar />
816
- </MemoryRouter>
817
- );
818
-
819
- expect(screen.getByLabelText('Session has unread updates')).toBeTruthy();
820
-
821
- useChatSessionListStore.setState({
822
- snapshot: {
823
- ...useChatSessionListStore.getState().snapshot,
824
- selectedSessionKey: 'session:ncp-2'
825
- }
826
- });
827
-
828
- rerender(
829
- <MemoryRouter>
830
- <ChatSidebar />
831
- </MemoryRouter>
832
- );
833
-
834
- expect(screen.queryByLabelText('Session has unread updates')).toBeNull();
835
- });
836
-
837
- it('does not show an unread dot for sessions without a persisted ui read baseline', () => {
838
- mocks.sessionItems = [
839
- createSessionItem({
840
- key: 'session:ncp-legacy',
841
- createdAt: '2026-03-19T09:00:00.000Z',
842
- updatedAt: '2026-03-19T09:05:00.000Z',
843
- lastMessageAt: '2026-03-19T09:05:00.000Z',
844
- label: 'Legacy Session',
845
- sessionType: 'native',
846
- sessionTypeMutable: false,
847
- messageCount: 1
848
- })
849
- ];
850
-
851
- render(
852
- <MemoryRouter>
853
- <ChatSidebar />
854
- </MemoryRouter>
855
- );
856
-
857
- expect(screen.queryByLabelText('Session has unread updates')).toBeNull();
858
- });
859
-
860
- it('opens the child-session browser from a parent session row', () => {
861
- mocks.sessionItems = [
862
- createSessionItem({
863
- key: 'session:parent-1',
864
- createdAt: '2026-03-19T09:00:00.000Z',
865
- updatedAt: '2026-03-19T09:05:00.000Z',
866
- label: 'Parent Task',
867
- sessionType: 'native',
868
- sessionTypeMutable: false,
869
- messageCount: 1
870
- }),
871
- createSessionItem({
872
- key: 'session:child-1',
873
- createdAt: '2026-03-19T09:06:00.000Z',
874
- updatedAt: '2026-03-19T09:07:00.000Z',
875
- label: 'Child Task',
876
- sessionType: 'native',
877
- sessionTypeMutable: false,
878
- messageCount: 1,
879
- parentSessionId: 'session:parent-1'
880
- })
881
- ];
882
-
883
- render(
884
- <MemoryRouter>
885
- <ChatSidebar />
886
- </MemoryRouter>
887
- );
888
-
889
- fireEvent.click(screen.getByLabelText('View child sessions'));
890
-
891
- expect(mocks.openChildSessionPanel).toHaveBeenCalledWith({
892
- parentSessionKey: 'session:parent-1',
893
- activeChildSessionKey: 'session:child-1',
894
- });
895
- });
896
- });