@nextclaw/ui 0.12.19 → 0.12.20-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/assets/api-BcqDx0tm.js +15 -0
  3. package/dist/assets/app-manager-provider-DVYBjif-.js +1 -0
  4. package/dist/assets/app-navigation.config-CMoWvFEI.js +1 -0
  5. package/dist/assets/{book-open-CVEuA0y5.js → book-open-DgLqYpNY.js} +1 -1
  6. package/dist/assets/{channels-list-page-BqhqaBf1.js → channels-list-page-CsoI4OJm.js} +2 -2
  7. package/dist/assets/{chat-D4KecKjB.js → chat-CA3aRmhx.js} +13 -12
  8. package/dist/assets/chat-page-gdSN6Pr6.js +1 -0
  9. package/dist/assets/chunk-JZWAC4HX-u4uYphxM.js +3 -0
  10. package/dist/assets/{config-split-page-BGjVACdO.js → config-split-page-BMRGuCJQ.js} +1 -1
  11. package/dist/assets/{createLucideIcon-PPrXCGK8.js → createLucideIcon-BZkY6emz.js} +1 -1
  12. package/dist/assets/desktop-update-config-CD6-2PfI.js +1 -0
  13. package/dist/assets/{dialog-CTCX7oLf.js → dialog-csshWetU.js} +1 -1
  14. package/dist/assets/{dist-FL5e8mMi.js → dist-Bl94Ahwx.js} +1 -1
  15. package/dist/assets/{doc-browser-C02neCIE.js → doc-browser-BUlCkZo2.js} +1 -1
  16. package/dist/assets/doc-browser-CzCV73NJ.js +1 -0
  17. package/dist/assets/doc-browser-Doh2541x.js +1 -0
  18. package/dist/assets/{doc-browser-context-C-WPOji4.js → doc-browser-context-DfLHAWbG.js} +1 -1
  19. package/dist/assets/{es2015-BNy4R8AC.js → es2015-JCM5-KtW.js} +1 -1
  20. package/dist/assets/{external-link-BNtqJE01.js → external-link-Sw3ah_JD.js} +1 -1
  21. package/dist/assets/{folder-QyJHVUNz.js → folder-D7-VTnkz.js} +1 -1
  22. package/dist/assets/{hash-BGYUE-zr.js → hash-zajSTDXZ.js} +1 -1
  23. package/dist/assets/i18n-C5Mibli1.js +1 -0
  24. package/dist/assets/index-BTDFuKka.js +2 -0
  25. package/dist/assets/index-CUmk8xFK.css +1 -0
  26. package/dist/assets/{key-round-DenCfA2w.js → key-round-CnI1mc9F.js} +1 -1
  27. package/dist/assets/loader-circle-B5i8oMMY.js +1 -0
  28. package/dist/assets/{logo-badge-CKAxvQFc.js → logo-badge-BQgKnVtz.js} +1 -1
  29. package/dist/assets/{logos-CqXnaJIm.js → logos-CqVm0q0W.js} +1 -1
  30. package/dist/assets/marketplace-page-DJGDpTAo.js +1 -0
  31. package/dist/assets/{marketplace-page-XnDa2ulT.js → marketplace-page-DxlxHCFm.js} +2 -2
  32. package/dist/assets/mcp-marketplace-page-5UjYRWOR.js +40 -0
  33. package/dist/assets/mcp-marketplace-page-C1XaHZZO.js +1 -0
  34. package/dist/assets/message-square-D6Z4NwpG.js +1 -0
  35. package/dist/assets/{model-config-ByeL6Toe.js → model-config-PccJ9XyH.js} +1 -1
  36. package/dist/assets/{notice-card-D00-02yg.js → notice-card-CCgk6FvF.js} +1 -1
  37. package/dist/assets/play-D8WJLnJe.js +1 -0
  38. package/dist/assets/plus-Di0KAkiO.js +1 -0
  39. package/dist/assets/{popover-AmJkxio3.js → popover-YAsxDBhY.js} +1 -1
  40. package/dist/assets/{provider-scoped-model-input-CfFJsJp-.js → provider-scoped-model-input-CzpF7cug.js} +1 -1
  41. package/dist/assets/{providers-list-HMQzW2WV.js → providers-list-8qDMER8o.js} +1 -1
  42. package/dist/assets/{refresh-ccw-B-dhb3yS.js → refresh-ccw-Bii4w8aB.js} +1 -1
  43. package/dist/assets/refresh-cw-BxojR62w.js +1 -0
  44. package/dist/assets/remote-D4TtLPAp.js +1 -0
  45. package/dist/assets/{rotate-cw-BWqAG3Fv.js → rotate-cw-1Xqa7LZ8.js} +1 -1
  46. package/dist/assets/runtime-config-page-D-4c5H5z.js +1 -0
  47. package/dist/assets/{save-DpdkGieJ.js → save--BVI5wZX.js} +1 -1
  48. package/dist/assets/search-config-D3a65l3r.js +1 -0
  49. package/dist/assets/{search-CQUdr7j_.js → search-vChioOoe.js} +1 -1
  50. package/dist/assets/{secrets-config-YCsGd1am.js → secrets-config-CoMlR_7i.js} +2 -2
  51. package/dist/assets/{select-DVUtSFHZ.js → select-DIZrwsKU.js} +1 -1
  52. package/dist/assets/{sessions-config-page-BKN-XdKr.js → sessions-config-page-Cc0TJStn.js} +2 -2
  53. package/dist/assets/{setting-row-Cb5-lFs-.js → setting-row-DiQyrE81.js} +1 -1
  54. package/dist/assets/{settings-DgtZZlnF.js → settings-CiRChctQ.js} +1 -1
  55. package/dist/assets/skeleton-CFQRIUzt.js +1 -0
  56. package/dist/assets/{sparkles-DNSCyDhL.js → sparkles-D1ZKWdm4.js} +1 -1
  57. package/dist/assets/{status-dot-X_j51OfA.js → status-dot-Dv_hiUVa.js} +1 -1
  58. package/dist/assets/{tabs-custom-CcWmekaF.js → tabs-custom-CsACkVji.js} +1 -1
  59. package/dist/assets/{tag-chip-fdbK2wE6.js → tag-chip-C3wDBe_-.js} +1 -1
  60. package/dist/assets/theme-provider-aOmrJ9J6.js +1 -0
  61. package/dist/assets/{tooltip-BkZCQcKw.js → tooltip-Dq5Xehpk.js} +1 -1
  62. package/dist/assets/{trash-2-CqciSCsg.js → trash-2-rY9ZteZX.js} +1 -1
  63. package/dist/assets/use-config-BQJjq1mP.js +1 -0
  64. package/dist/assets/{use-confirm-dialog-DSrb9205.js → use-confirm-dialog-DBoV5n5P.js} +1 -1
  65. package/dist/assets/{use-infinite-scroll-loader-DmowtyTI.js → use-infinite-scroll-loader-JAicqVC5.js} +1 -1
  66. package/dist/assets/{use-viewport-layout-CaALCA51.js → use-viewport-layout-BX3XqzJ4.js} +1 -1
  67. package/dist/assets/x-DpTzXQcX.js +1 -0
  68. package/dist/index.html +40 -39
  69. package/package.json +9 -6
  70. package/src/app/hooks/use-realtime-query-bridge.ts +5 -5
  71. package/src/app/index.tsx +7 -1
  72. package/src/features/channels/components/config/channel-form.tsx +3 -3
  73. package/src/features/channels/components/config/weixin-channel-auth-section.tsx +1 -1
  74. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -0
  75. package/src/features/chat/components/conversation/chat-input-bar.container.tsx +9 -4
  76. package/src/features/chat/components/conversation/chat-message-list.container.test.tsx +64 -6
  77. package/src/features/chat/components/conversation/chat-message-list.container.tsx +185 -17
  78. package/src/features/chat/components/session/session-context-icon.tsx +1 -4
  79. package/src/features/chat/hooks/use-ncp-chat-derived-state.ts +3 -1
  80. package/src/features/chat/hooks/use-ncp-chat-page-data.ts +7 -6
  81. package/src/features/chat/hooks/use-ncp-session-conversation.test.tsx +74 -2
  82. package/src/features/chat/hooks/use-ncp-session-conversation.ts +32 -10
  83. package/src/features/chat/hooks/use-selected-session-context-window-indicator.ts +20 -0
  84. package/src/features/chat/managers/ncp-chat-input.manager.test.ts +25 -0
  85. package/src/features/chat/managers/ncp-chat-input.manager.ts +5 -1
  86. package/src/features/chat/pages/ncp-chat-page.test.ts +22 -8
  87. package/src/features/chat/pages/ncp-chat-page.tsx +15 -11
  88. package/src/features/chat/stores/chat-thread.store.ts +8 -2
  89. package/src/features/chat/utils/chat-context-window-indicator.utils.ts +50 -0
  90. package/src/features/chat/utils/chat-runtime.utils.ts +1 -1
  91. package/src/features/chat/utils/chat-session-preference-governance.utils.test.tsx +114 -0
  92. package/src/features/chat/utils/chat-session-preference-governance.utils.ts +30 -36
  93. package/src/features/chat/utils/ncp-chat-runtime-availability.utils.test.ts +165 -0
  94. package/src/features/chat/utils/ncp-chat-runtime-availability.utils.ts +50 -0
  95. package/src/features/chat/utils/ncp-session-adapter.utils.test.ts +27 -0
  96. package/src/features/chat/utils/ncp-session-adapter.utils.ts +6 -4
  97. package/src/features/chat/utils/ncp-session-context-metadata.utils.ts +121 -0
  98. package/src/features/chat/utils/session-context.utils.ts +1 -2
  99. package/src/features/system-status/components/config/runtime-config-editor.tsx +6 -0
  100. package/src/features/system-status/components/config/runtime-settings-card.tsx +12 -0
  101. package/src/features/system-status/components/desktop-update-config.test.tsx +17 -7
  102. package/src/features/system-status/components/desktop-update-config.tsx +75 -30
  103. package/src/features/system-status/hooks/use-system-status.ts +0 -11
  104. package/src/features/system-status/index.ts +4 -1
  105. package/src/features/system-status/managers/runtime-update.manager.ts +330 -0
  106. package/src/features/system-status/managers/system-status.manager.test.ts +0 -25
  107. package/src/features/system-status/managers/system-status.manager.ts +1 -30
  108. package/src/features/system-status/stores/runtime-update.store.ts +24 -0
  109. package/src/features/system-status/types/system-status.types.ts +0 -2
  110. package/src/features/system-status/utils/runtime-config-agent.utils.ts +6 -1
  111. package/src/features/system-status/utils/system-status.utils.test.ts +1 -85
  112. package/src/features/system-status/utils/system-status.utils.ts +1 -23
  113. package/src/platforms/desktop/managers/desktop-update.manager.ts +6 -0
  114. package/src/platforms/desktop/types/desktop-update.types.ts +21 -19
  115. package/src/shared/components/common/brand-header.test.tsx +142 -0
  116. package/src/shared/components/common/brand-header.tsx +93 -0
  117. package/src/shared/components/cron-config.tsx +1 -1
  118. package/src/shared/components/doc-browser/doc-browser-context.test.tsx +1 -1
  119. package/src/shared/components/doc-browser/doc-browser.tsx +1 -1
  120. package/src/shared/components/search-config.tsx +3 -3
  121. package/src/shared/lib/api/README.md +3 -0
  122. package/src/shared/lib/api/index.ts +13 -11
  123. package/src/shared/lib/api/ncp-session.test.ts +17 -18
  124. package/src/shared/lib/api/ncp-session.types.ts +92 -0
  125. package/src/shared/lib/api/raw-client.utils.ts +3 -126
  126. package/src/shared/lib/api/services/agents.service.ts +18 -0
  127. package/src/shared/lib/api/services/channel-auth.service.ts +21 -0
  128. package/src/shared/lib/api/{client.ts → services/client.service.ts} +45 -1
  129. package/src/shared/lib/api/services/config.service.ts +171 -0
  130. package/src/shared/lib/api/services/marketplace.service.ts +66 -0
  131. package/src/shared/lib/api/services/mcp-marketplace.service.ts +70 -0
  132. package/src/shared/lib/api/services/ncp-attachments.service.ts +14 -0
  133. package/src/shared/lib/api/services/ncp-session.service.ts +39 -0
  134. package/src/shared/lib/api/services/remote.service.ts +50 -0
  135. package/src/shared/lib/api/services/runtime-control.service.ts +18 -0
  136. package/src/shared/lib/api/services/runtime-update.service.ts +26 -0
  137. package/src/shared/lib/api/services/server-path.service.ts +16 -0
  138. package/src/shared/lib/api/types.ts +9 -74
  139. package/src/shared/lib/i18n/{chat.ts → chat-labels.utils.ts} +13 -1
  140. package/src/shared/lib/i18n/desktop-update-labels.utils.ts +65 -0
  141. package/src/shared/lib/i18n/index.ts +4 -5
  142. package/src/shared/lib/i18n/runtime/i18n-language-owner.ts +5 -5
  143. package/src/shared/lib/transport/index.ts +1 -0
  144. package/src/shared/lib/transport/local-transport.service.ts +24 -4
  145. package/src/shared/lib/transport/remote-transport.service.ts +2 -2
  146. package/src/shared/lib/transport/request-raw-api-response.utils.ts +133 -0
  147. package/src/shared/lib/transport/transport.types.ts +8 -2
  148. package/src/shared/lib/ui-document-title/index.ts +1 -1
  149. package/tsconfig.json +1 -0
  150. package/dist/assets/api-BurjmW4A.js +0 -15
  151. package/dist/assets/app-manager-provider-DhxUmyTv.js +0 -1
  152. package/dist/assets/app-navigation.config-Bpd16Pem.js +0 -1
  153. package/dist/assets/chat-page-Cc7n80lW.js +0 -1
  154. package/dist/assets/chunk-JZWAC4HX-24FLdHl7.js +0 -3
  155. package/dist/assets/desktop-update-config-fMLlSStv.js +0 -1
  156. package/dist/assets/doc-browser-COj7x090.js +0 -1
  157. package/dist/assets/doc-browser-fyn7eDTp.js +0 -1
  158. package/dist/assets/i18n-CM4y8Mw9.js +0 -1
  159. package/dist/assets/index-CtVSzMPM.js +0 -2
  160. package/dist/assets/index-N3hjuljD.css +0 -1
  161. package/dist/assets/loader-circle-R23uEPkM.js +0 -1
  162. package/dist/assets/marketplace-page-mF-M5mku.js +0 -1
  163. package/dist/assets/mcp-marketplace-page-BArKWcRZ.js +0 -40
  164. package/dist/assets/mcp-marketplace-page-DBUcIIHJ.js +0 -1
  165. package/dist/assets/message-square-Dm34zD6k.js +0 -1
  166. package/dist/assets/play-ul4L6MWm.js +0 -1
  167. package/dist/assets/plus-D14303DH.js +0 -1
  168. package/dist/assets/remote-B4ELSd3u.js +0 -1
  169. package/dist/assets/runtime-config-page-N4FP6H0M.js +0 -1
  170. package/dist/assets/search-config-B62TY-z2.js +0 -1
  171. package/dist/assets/skeleton-BCPi52jT.js +0 -1
  172. package/dist/assets/theme-provider-WTWq_jYq.js +0 -1
  173. package/dist/assets/use-config-CyvhbRhf.js +0 -1
  174. package/dist/assets/x-tYcSDsrY.js +0 -1
  175. package/src/shared/lib/api/agents.ts +0 -34
  176. package/src/shared/lib/api/channel-auth.ts +0 -35
  177. package/src/shared/lib/api/config.ts +0 -362
  178. package/src/shared/lib/api/marketplace.ts +0 -156
  179. package/src/shared/lib/api/mcp-marketplace.ts +0 -138
  180. package/src/shared/lib/api/ncp-attachments.ts +0 -41
  181. package/src/shared/lib/api/ncp-session.ts +0 -78
  182. package/src/shared/lib/api/remote.ts +0 -86
  183. package/src/shared/lib/api/runtime-control.ts +0 -34
  184. package/src/shared/lib/api/server-path.ts +0 -46
  185. /package/dist/assets/{config-hints-CPNzbMEp.js → config-hints-MogHYQ8G.js} +0 -0
@@ -24,7 +24,6 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
24
24
  chatSessionTypeClaude: { zh: 'Claude Code', en: 'Claude Code' },
25
25
  chatSessionTypeWeixin: { zh: '微信', en: 'WeChat' },
26
26
  chatSessionTypeFeishu: { zh: '飞书', en: 'Feishu' },
27
- chatSessionTypeHeartbeat: { zh: '心跳', en: 'Heartbeat' },
28
27
  chatSessionTypeCron: { zh: '定时任务', en: 'Cron' },
29
28
  chatSessionTypeUnavailableSuffix: {
30
29
  zh: '当前不可用,请启用对应插件或新建 Native 会话。',
@@ -92,6 +91,19 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
92
91
  chatStop: { zh: '停止', en: 'Stop' },
93
92
  chatStopPreparing: { zh: '正在建立可停止会话,请稍候…', en: 'Preparing stoppable run…' },
94
93
  chatStopUnavailable: { zh: '当前后端引擎不支持手动停止。', en: 'Manual stop is not supported by the current backend engine.' },
94
+ chatContextWindow: { zh: '上下文窗口', en: 'Context window' },
95
+ chatContextWindowUsed: { zh: '预计占用', en: 'Projected use' },
96
+ chatContextWindowTotal: { zh: '总窗口', en: 'Total' },
97
+ chatContextWindowAvailable: { zh: '剩余', en: 'Available' },
98
+ chatContextWindowPruned: { zh: '安全裁剪后', en: 'After safety pruning' },
99
+ chatContextWindowDroppedHistory: { zh: '已丢弃历史消息', en: 'Dropped history' },
100
+ chatContextWindowTruncatedTools: { zh: '已截断工具结果', en: 'Truncated tool results' },
101
+ chatContextWindowUpdatedAt: { zh: '更新时间', en: 'Updated' },
102
+ chatContextCompactionCompressing: { zh: '正在压缩较早上下文', en: 'Compressing earlier context' },
103
+ chatContextCompactionCompressed: { zh: '较早上下文已自动压缩', en: 'Earlier context was auto-compacted' },
104
+ chatContextCompactionCoveredMessages: { zh: '覆盖消息数', en: 'Covered messages' },
105
+ chatContextCompactionOriginalTokens: { zh: '压缩前估算', en: 'Estimated before compaction' },
106
+ chatContextCompactionProjectedTokens: { zh: '压缩后估算', en: 'Estimated after compaction' },
95
107
  chatSending: { zh: '发送中...', en: 'Sending...' },
96
108
  chatQueueSend: { zh: '排队发送', en: 'Queue' },
97
109
  chatQueuedHintPrefix: { zh: '当前有', en: 'Queued' },
@@ -1,5 +1,47 @@
1
1
  export const DESKTOP_UPDATE_LABELS: Record<string, { zh: string; en: string }> = {
2
2
  updates: { zh: '更新', en: 'Updates' },
3
+ runtimeUpdatesPageTitle: { zh: '版本更新', en: 'Runtime Updates' },
4
+ runtimeUpdatesPageDescription: {
5
+ zh: '自动检查并后台下载新版本,由你决定何时切换到新的运行版本。',
6
+ en: 'Check and download new versions automatically, then decide when to switch to the new runtime.'
7
+ },
8
+ runtimeUpdatesUnavailableTitle: { zh: '当前环境暂不支持更新', en: 'Updates Are Currently Unavailable' },
9
+ runtimeUpdatesUnavailableDescription: {
10
+ zh: '这个运行环境暂时没有可用的更新宿主。',
11
+ en: 'This runtime environment does not currently expose an update host.'
12
+ },
13
+ runtimeUpdatesUnavailableHint: {
14
+ zh: '更新入口会在宿主支持后自动出现,不需要前端单独区分环境。',
15
+ en: 'The update entry appears automatically once the host supports updates.'
16
+ },
17
+ runtimeUpdatesHostVersion: { zh: '宿主版本', en: 'Host Version' },
18
+ runtimeUpdatesDownloadedBannerDescription: {
19
+ zh: '版本 {version} 已下载完成,确认后即可切换到新版本。',
20
+ en: 'Version {version} has finished downloading and is ready to switch over when you confirm.'
21
+ },
22
+ runtimeUpdatesActionsDescription: {
23
+ zh: '支持手动检查、手动下载,以及在你准备好之后切换到已下载的新版本。',
24
+ en: 'Manually check, manually download, and switch to a downloaded version whenever you are ready.'
25
+ },
26
+ runtimeUpdatesApplyNow: { zh: '立即更新', en: 'Update Now' },
27
+ runtimeUpdatesLoadFailed: { zh: '读取更新状态失败', en: 'Failed to load update state' },
28
+ runtimeUpdatesCheckFailed: { zh: '检查更新失败', en: 'Failed to check for updates' },
29
+ runtimeUpdatesDownloadFailed: { zh: '下载更新失败', en: 'Failed to download update' },
30
+ runtimeUpdatesApplyFailed: { zh: '应用更新失败', en: 'Failed to apply update' },
31
+ runtimeUpdatesPreferencesFailed: { zh: '保存更新偏好失败', en: 'Failed to save update preferences' },
32
+ runtimeUpdatesChannelChangeFailed: { zh: '切换更新通道失败', en: 'Failed to change the release channel' },
33
+ runtimeUpdatesAlreadyLatest: { zh: '当前已经是最新版本。', en: 'You already have the latest version.' },
34
+ runtimeUpdatesReadyToApply: { zh: '更新已下载完成,已经可以切换到新版本。', en: 'The update is ready and can be applied now.' },
35
+ runtimeUpdatesAvailable: { zh: '发现新版本 {version}。', en: 'Version {version} is available.' },
36
+ runtimeUpdatesUnknownVersion: { zh: '新版本', en: 'a new version' },
37
+ runtimeUpdatesChannelChanged: {
38
+ zh: '已切换到 {channel} 更新通道。',
39
+ en: 'Switched to the {channel} release channel.'
40
+ },
41
+ runtimeUpdatesChannelChangedWithUpdate: {
42
+ zh: '已切换到 {channel} 通道,发现版本 {version}。',
43
+ en: 'Switched to the {channel} channel and found version {version}.'
44
+ },
3
45
  desktopUpdatesPageTitle: { zh: '桌面端更新', en: 'Desktop Updates' },
4
46
  desktopUpdatesPageDescription: {
5
47
  zh: '在应用内检查、下载并决定何时应用新的桌面端版本。',
@@ -26,7 +68,14 @@ export const DESKTOP_UPDATE_LABELS: Record<string, { zh: string; en: string }> =
26
68
  desktopUpdatesStatusDownloading: { zh: '下载中', en: 'Downloading' },
27
69
  desktopUpdatesStatusDownloaded: { zh: '已下载待应用', en: 'Downloaded' },
28
70
  desktopUpdatesStatusUpToDate: { zh: '已是最新', en: 'Up to Date' },
71
+ desktopUpdatesStatusBlocked: { zh: '更新被阻塞', en: 'Blocked' },
29
72
  desktopUpdatesStatusFailed: { zh: '更新失败', en: 'Failed' },
73
+ desktopUpdatesInlineDownload: { zh: '下载', en: 'Download' },
74
+ desktopUpdatesInlineDownloading: { zh: '下载中', en: 'Downloading' },
75
+ desktopUpdatesInlineDownloadingPercent: { zh: '下载 {percent}%', en: '{percent}%' },
76
+ desktopUpdatesInlineReady: { zh: '更新', en: 'Update' },
77
+ desktopUpdatesInlineApplying: { zh: '应用中', en: 'Applying' },
78
+ desktopUpdatesInlineAttention: { zh: '更新异常', en: 'Update Issue' },
30
79
  desktopUpdatesLauncherVersion: { zh: '桌面壳版本', en: 'Launcher Version' },
31
80
  desktopUpdatesCurrentBundleVersion: { zh: '当前内核版本', en: 'Current Kernel Version' },
32
81
  desktopUpdatesAvailableVersion: { zh: '可用版本', en: 'Available Version' },
@@ -37,6 +86,22 @@ export const DESKTOP_UPDATE_LABELS: Record<string, { zh: string; en: string }> =
37
86
  zh: '版本 {version} 已下载完成,等你确认后即可重启应用并完成更新。',
38
87
  en: 'Version {version} is ready. Restart the app whenever you want to apply it.'
39
88
  },
89
+ desktopUpdatesDownloadProgressPercent: {
90
+ zh: '正在下载 {percent}%',
91
+ en: 'Downloading {percent}%'
92
+ },
93
+ desktopUpdatesDownloadProgressUnknown: {
94
+ zh: '正在下载',
95
+ en: 'Downloading'
96
+ },
97
+ desktopUpdatesBlockedTitle: {
98
+ zh: '更新暂时无法继续',
99
+ en: 'Update Blocked'
100
+ },
101
+ desktopUpdatesBlockedDescription: {
102
+ zh: '当前安装环境需要先处理阻塞项,之后才能继续更新。',
103
+ en: 'Resolve the current installation requirement before continuing the update.'
104
+ },
40
105
  desktopUpdatesPreferencesTitle: { zh: '更新偏好', en: 'Update Preferences' },
41
106
  desktopUpdatesPreferencesDescription: {
42
107
  zh: '默认自动检查更新,但是否后台下载由你决定。',
@@ -1,7 +1,7 @@
1
1
  import { AGENT_LABELS } from './agents';
2
2
  import { CHANNEL_LABELS } from './channels';
3
3
  import { CHANNEL_AUTH_LABELS } from './channel-auth';
4
- import { CHAT_LABELS } from './chat';
4
+ import { CHAT_LABELS } from './chat-labels.utils';
5
5
  import {
6
6
  getLanguage,
7
7
  getLocale,
@@ -343,14 +343,13 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
343
343
  authPasswordAction: { zh: '更新密码', en: 'Update Password' },
344
344
  authPasswordUpdating: { zh: '更新中...', en: 'Updating...' },
345
345
  authLogoutAction: { zh: '退出当前标签页', en: 'Sign Out This Tab' },
346
- authSessionMemoryNotice: {
347
- zh: '当前版本的会话只保存在服务端内存里。NextClaw UI 进程重启后,需要重新登录。',
348
- en: 'Sessions are stored only in server memory for now. You will need to sign in again after the NextClaw UI process restarts.'
349
- },
346
+ authSessionMemoryNotice: { zh: '当前版本的会话只保存在服务端内存里。NextClaw UI 进程重启后,需要重新登录。', en: 'Sessions are stored only in server memory for now. You will need to sign in again after the NextClaw UI process restarts.' },
350
347
  dmScope: { zh: '私聊范围', en: 'DM Scope' },
351
348
  dmScopeHelp: { zh: '控制私聊会话如何隔离。', en: 'Control how direct-message sessions are isolated.' },
352
349
  defaultContextTokens: { zh: '默认上下文 Token', en: 'Default Context Tokens' },
353
350
  defaultContextTokensHelp: { zh: '当 Agent 未设置单独值时使用该上下文预算。', en: 'Input context budget for agents when no per-agent override is set.' },
351
+ runtimeCompanionEnabled: { zh: '桌宠 Companion', en: 'Companion' },
352
+ runtimeCompanionEnabledHelp: { zh: '开启后会自动拉起悬浮 Companion;关闭后会立即停止,并在下次启动时保持关闭。', en: 'When enabled, NextClaw auto-starts the floating companion. When disabled, it stops immediately and stays off after restart.' },
354
353
  defaultEngine: { zh: '默认 Runtime', en: 'Default Runtime' },
355
354
  defaultEngineHelp: { zh: '默认使用的 Agent Runtime,例如 native、codex 或 claude。', en: 'Default agent runtime, for example native, codex, or claude.' },
356
355
  agentList: { zh: 'Agent 列表', en: 'Agent List' },
@@ -100,9 +100,9 @@ class I18nLanguageOwner {
100
100
 
101
101
  const owner = new I18nLanguageOwner();
102
102
 
103
- export const resolveInitialLanguage = owner.resolveInitialLanguage;
103
+ export const { resolveInitialLanguage } = owner;
104
104
  export const initializeI18n = owner.initialize;
105
- export const getLanguage = owner.getLanguage;
106
- export const setLanguage = owner.setLanguage;
107
- export const subscribeLanguageChange = owner.subscribeLanguageChange;
108
- export const getLocale = owner.getLocale;
105
+ export const { getLanguage } = owner;
106
+ export const { setLanguage } = owner;
107
+ export const { subscribeLanguageChange } = owner;
108
+ export const { getLocale } = owner;
@@ -1,4 +1,5 @@
1
1
  export { appClient } from './app-client.service';
2
+ export { requestRawApiResponse } from './request-raw-api-response.utils';
2
3
  export type {
3
4
  AppEvent,
4
5
  AppTransport,
@@ -1,5 +1,6 @@
1
1
  import { systemStatusManager } from '@/features/system-status';
2
2
  import type { AppEvent, AppTransport, RequestInput, StreamInput, StreamSession } from './transport.types';
3
+ import { requestRawApiResponse } from './request-raw-api-response.utils';
3
4
  import { readSseStreamResult } from './sse-stream.utils';
4
5
  import { resolveTransportWebSocketUrl } from './transport-websocket-url.utils';
5
6
 
@@ -139,13 +140,14 @@ export class LocalAppTransport implements AppTransport {
139
140
  const timeoutId = timeoutMs
140
141
  ? window.setTimeout(() => controller?.abort(`Request timed out after ${timeoutMs}ms: ${input.method} ${input.path}`), timeoutMs)
141
142
  : null;
143
+ const requestBody = normalizeRequestBody(input.body);
142
144
 
143
145
  try {
144
- const { requestRawApiResponse } = await import('@/shared/lib/api');
145
- const response = await requestRawApiResponse<T>(input.path, {
146
+ const response = await requestRawApiResponse<T>(this.apiBase, input.path, {
146
147
  method: input.method,
147
- ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),
148
- ...(controller ? { signal: controller.signal } : {})
148
+ ...(requestBody !== undefined ? { body: requestBody } : {}),
149
+ ...(input.headers ? { headers: input.headers } : {}),
150
+ signal: controller?.signal ?? input.signal
149
151
  });
150
152
  if (!response.ok) {
151
153
  throw createTransportError(response, `Request failed for ${input.method} ${input.path}`);
@@ -228,3 +230,21 @@ export class LocalAppTransport implements AppTransport {
228
230
  return this.realtimeGateway.subscribe(handler);
229
231
  };
230
232
  }
233
+
234
+ function normalizeRequestBody(body: unknown): BodyInit | undefined {
235
+ if (body === undefined) {
236
+ return undefined;
237
+ }
238
+ if (
239
+ body instanceof FormData ||
240
+ body instanceof URLSearchParams ||
241
+ body instanceof Blob ||
242
+ body instanceof ArrayBuffer
243
+ ) {
244
+ return body;
245
+ }
246
+ if (typeof body === 'string') {
247
+ return body;
248
+ }
249
+ return JSON.stringify(body);
250
+ }
@@ -1,4 +1,4 @@
1
- import type { ApiError } from '@/shared/lib/api';
1
+ import type { ApiError } from '@nextclaw/server';
2
2
  import type { AppEvent, AppTransport, RemoteRuntimeInfo, RequestInput, StreamInput, StreamSession } from './transport.types';
3
3
  import { resolveTransportWebSocketUrl } from './transport-websocket-url.utils';
4
4
 
@@ -291,7 +291,7 @@ export class RemoteSessionMultiplexTransport implements AppTransport {
291
291
  };
292
292
  });
293
293
 
294
- const connectPromise = this.connectPromise;
294
+ const { connectPromise } = this;
295
295
  return await connectPromise;
296
296
  }
297
297
 
@@ -0,0 +1,133 @@
1
+ import type { ApiResponse } from '@nextclaw/server';
2
+ import { systemStatusManager } from '@/features/system-status';
3
+
4
+ function compactSnippet(text: string) {
5
+ return text.replace(/\s+/g, ' ').trim().slice(0, 200);
6
+ }
7
+
8
+ function inferNonJsonHint(endpoint: string, status: number): string | undefined {
9
+ if (
10
+ status === 404 &&
11
+ endpoint.startsWith('/api/config/providers/') &&
12
+ endpoint.endsWith('/test')
13
+ ) {
14
+ return 'Provider test endpoint is missing. This usually means nextclaw runtime version is outdated.';
15
+ }
16
+ if (status === 401 || status === 403) {
17
+ return 'Authentication failed. Check apiKey and custom headers.';
18
+ }
19
+ if (status === 429) {
20
+ return 'Rate limited by upstream provider. Retry later or switch model/provider.';
21
+ }
22
+ if (status >= 500) {
23
+ return 'Upstream service error. Retry later and inspect server logs if it persists.';
24
+ }
25
+ return undefined;
26
+ }
27
+
28
+ function formatUnknownFetchError(error: unknown): {
29
+ summary: string;
30
+ details: Record<string, unknown>;
31
+ } {
32
+ if (error instanceof Error) {
33
+ const name = error.name?.trim() || 'Error';
34
+ const message = error.message?.trim() || 'Unknown error';
35
+ return {
36
+ summary: `${name}: ${message}`,
37
+ details: {
38
+ errorName: name,
39
+ errorMessage: message,
40
+ ...(error.stack?.trim() ? { errorStack: error.stack.trim() } : {})
41
+ }
42
+ };
43
+ }
44
+ return {
45
+ summary: String(error ?? 'Unknown error'),
46
+ details: {
47
+ errorName: 'NonError',
48
+ errorMessage: String(error ?? 'Unknown error')
49
+ }
50
+ };
51
+ }
52
+
53
+ export async function requestRawApiResponse<T>(
54
+ apiBase: string,
55
+ endpoint: string,
56
+ options: RequestInit = {}
57
+ ): Promise<ApiResponse<T>> {
58
+ const url = `${apiBase}${endpoint}`;
59
+ const method = (options.method || 'GET').toUpperCase();
60
+
61
+ let response: Response;
62
+ try {
63
+ const headers = new Headers(options.headers);
64
+ if (!(options.body instanceof FormData) && !headers.has('Content-Type')) {
65
+ headers.set('Content-Type', 'application/json');
66
+ }
67
+ response = await fetch(url, {
68
+ credentials: 'include',
69
+ headers,
70
+ ...options
71
+ });
72
+ } catch (error) {
73
+ const formatted = formatUnknownFetchError(error);
74
+ systemStatusManager.reportTransportFailure(formatted.summary);
75
+ return {
76
+ ok: false,
77
+ error: {
78
+ code: 'NETWORK_ERROR',
79
+ message: `Fetch failed on ${method} ${endpoint} | ${formatted.summary}`,
80
+ details: {
81
+ method,
82
+ endpoint,
83
+ url,
84
+ ...formatted.details
85
+ }
86
+ }
87
+ };
88
+ }
89
+
90
+ const text = await response.text();
91
+ let data: ApiResponse<T> | null = null;
92
+ if (text) {
93
+ try {
94
+ data = JSON.parse(text) as ApiResponse<T>;
95
+ } catch {
96
+ // fall through to build a synthetic error response
97
+ }
98
+ }
99
+
100
+ if (!data) {
101
+ const snippet = text ? compactSnippet(text) : '';
102
+ const hint = inferNonJsonHint(endpoint, response.status);
103
+ const parts = [`Non-JSON response (${response.status} ${response.statusText}) on ${method} ${endpoint}`];
104
+ if (snippet) {
105
+ parts.push(`body=${snippet}`);
106
+ }
107
+ if (hint) {
108
+ parts.push(`hint=${hint}`);
109
+ }
110
+ return {
111
+ ok: false,
112
+ error: {
113
+ code: 'INVALID_RESPONSE',
114
+ message: parts.join(' | '),
115
+ details: {
116
+ status: response.status,
117
+ statusText: response.statusText,
118
+ method,
119
+ endpoint,
120
+ url,
121
+ bodySnippet: snippet || undefined,
122
+ hint
123
+ }
124
+ }
125
+ };
126
+ }
127
+
128
+ if (!response.ok) {
129
+ return data as ApiResponse<T>;
130
+ }
131
+
132
+ return data as ApiResponse<T>;
133
+ }
@@ -1,4 +1,4 @@
1
- import type { WsEvent } from '@/shared/lib/api';
1
+ import type { UiServerEvent } from '@nextclaw/server';
2
2
 
3
3
  export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
4
4
 
@@ -6,6 +6,8 @@ export type RequestInput = {
6
6
  method: RequestMethod;
7
7
  path: string;
8
8
  body?: unknown;
9
+ headers?: Record<string, string>;
10
+ signal?: AbortSignal;
9
11
  timeoutMs?: number;
10
12
  };
11
13
 
@@ -27,7 +29,11 @@ export type StreamSession<TFinal = unknown> = {
27
29
  cancel: () => void;
28
30
  };
29
31
 
30
- export type AppEvent = WsEvent;
32
+ export type AppEvent =
33
+ | UiServerEvent
34
+ | { type: 'connection.open'; payload?: Record<string, never> }
35
+ | { type: 'connection.close'; payload?: Record<string, never> }
36
+ | { type: 'connection.error'; payload?: { message?: string } };
31
37
 
32
38
  export type AppTransport = {
33
39
  request<T>(input: RequestInput): Promise<T>;
@@ -16,7 +16,7 @@ const ROUTE_TITLE_KEYS: Array<{ prefix: string; key: string }> = [
16
16
  { prefix: '/providers', key: 'providersPageTitle' },
17
17
  { prefix: '/channels', key: 'channelsPageTitle' },
18
18
  { prefix: '/runtime', key: 'runtimePageTitle' },
19
- { prefix: '/updates', key: 'desktopUpdatesPageTitle' },
19
+ { prefix: '/updates', key: 'runtimeUpdatesPageTitle' },
20
20
  { prefix: '/remote', key: 'remotePageTitle' },
21
21
  { prefix: '/security', key: 'authSecurityTitle' },
22
22
  { prefix: '/sessions', key: 'sessionsPageTitle' },
package/tsconfig.json CHANGED
@@ -34,6 +34,7 @@
34
34
  "@/*": ["./src/*"],
35
35
  "@nextclaw/agent-chat": ["../nextclaw-agent-chat/src/index.ts"],
36
36
  "@nextclaw/agent-chat-ui": ["../nextclaw-agent-chat-ui/src/index.ts"],
37
+ "@nextclaw/kernel": ["../nextclaw-kernel/src/types/update.types.ts"],
37
38
  "@nextclaw/ncp": ["../ncp-packages/nextclaw-ncp/src/index.ts"],
38
39
  "@nextclaw/ncp-http-agent-client": ["../ncp-packages/nextclaw-ncp-http-agent-client/src/index.ts"],
39
40
  "@nextclaw/ncp-react": ["../ncp-packages/nextclaw-ncp-react/src/index.ts"]