@nextclaw/ui 0.11.21 → 0.11.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/assets/{ChannelsList-ByHWHkQS.js → ChannelsList-DVDu1xvz.js} +6 -6
  3. package/dist/assets/ChatPage-Z9tRzm_n.js +43 -0
  4. package/dist/assets/DocBrowser-B9OaZjmg.js +1 -0
  5. package/dist/assets/{DocBrowser-3y_NHZ71.js → DocBrowser-BmtBLFU0.js} +1 -1
  6. package/dist/assets/{DocBrowserContext-CVJuwCcw.js → DocBrowserContext-YIKkPb76.js} +1 -1
  7. package/dist/assets/{LogoBadge-D8fyilO-.js → LogoBadge-F7ZWdxLT.js} +1 -1
  8. package/dist/assets/{MarketplacePage-CmhsZXr1.js → MarketplacePage-Buo9HrOz.js} +2 -2
  9. package/dist/assets/MarketplacePage-D6rVQEQR.js +1 -0
  10. package/dist/assets/{McpMarketplacePage-C7PkCYbp.js → McpMarketplacePage-JnkYwK7p.js} +2 -2
  11. package/dist/assets/ModelConfig-BYRhgp0c.js +1 -0
  12. package/dist/assets/ProvidersList-DmLyyHvX.js +1 -0
  13. package/dist/assets/RemoteAccessPage-CDSSvH7Z.js +1 -0
  14. package/dist/assets/RuntimeConfig-v7a7Fe3x.js +1 -0
  15. package/dist/assets/{SearchConfig-Dm7r2yfp.js → SearchConfig-D5f1EkLE.js} +1 -1
  16. package/dist/assets/{SecretsConfig-BBP_mbQh.js → SecretsConfig-D61IKcYt.js} +2 -2
  17. package/dist/assets/{SessionsConfig-6wNJloZN.js → SessionsConfig-BRIxVTEv.js} +2 -2
  18. package/dist/assets/{book-open-B26jGBjY.js → book-open-CXoF5nQC.js} +1 -1
  19. package/dist/assets/chat-session-display-D0WpnuRZ.js +1 -0
  20. package/dist/assets/{chunk-JZWAC4HX-B-4B29RN.js → chunk-JZWAC4HX-CvRWvTy5.js} +1 -1
  21. package/dist/assets/{config-BaC29Qf-.js → config-DJswxxE8.js} +1 -1
  22. package/dist/assets/{createLucideIcon-DiFAvXmK.js → createLucideIcon-CjGHOWb6.js} +1 -1
  23. package/dist/assets/{dist-pCfWPG1A.js → dist-Cl2QB-2y.js} +1 -1
  24. package/dist/assets/{dist-kW_O3kyZ.js → dist-nqTTbVdA.js} +1 -1
  25. package/dist/assets/{external-link-D5-p-Gmm.js → external-link-tIO7zING.js} +1 -1
  26. package/dist/assets/{hash-BlwrSV0q.js → hash-JWUyl1pT.js} +1 -1
  27. package/dist/assets/i18n-CDHMXlRZ.js +1 -0
  28. package/dist/assets/{index-DvKS3L9j.js → index-BuwbBgmT.js} +3 -3
  29. package/dist/assets/index-bZ8cqQIS.css +1 -0
  30. package/dist/assets/{label-RyXfZqkP.js → label-BIpeNu4r.js} +1 -1
  31. package/dist/assets/loader-circle-Cs8XVFTw.js +1 -0
  32. package/dist/assets/{logos-Bpl8QTgI.js → logos-DThdM9lk.js} +1 -1
  33. package/dist/assets/{page-layout--S0YBU0W.js → page-layout-D3Xo605Z.js} +1 -1
  34. package/dist/assets/plus-PHf8q-Ct.js +1 -0
  35. package/dist/assets/{popover-BEjfbEwy.js → popover-BJRUGA_H.js} +1 -1
  36. package/dist/assets/provider-models-bz5y28rq.js +1 -0
  37. package/dist/assets/{react-BuSP2-8B.js → react-7ZHqQtEV.js} +1 -1
  38. package/dist/assets/refresh-ccw-CC6-_QuL.js +1 -0
  39. package/dist/assets/{save-DPPPpD_c.js → save-DJM5RRWW.js} +1 -1
  40. package/dist/assets/search-C91yH_6y.js +1 -0
  41. package/dist/assets/{security-config-6t78Ph-I.js → security-config-DbUyWcQz.js} +1 -1
  42. package/dist/assets/{select-CT50pzod.js → select-DSkTc61S.js} +1 -1
  43. package/dist/assets/skeleton-Dzg-HOiN.js +1 -0
  44. package/dist/assets/{status-dot-BbBqRHfh.js → status-dot-LNBlDu3q.js} +1 -1
  45. package/dist/assets/{switch-D3l6AcCk.js → switch-Bo-Y46HZ.js} +1 -1
  46. package/dist/assets/tabs-custom-DXv507_2.js +1 -0
  47. package/dist/assets/{trash-2-B2_AGVE3.js → trash-2-DFZmW6Gg.js} +1 -1
  48. package/dist/assets/useConfirmDialog-COwYXDKm.js +1 -0
  49. package/dist/assets/{useMutation-BzCrO8j-.js → useMutation-DrZrOgVL.js} +1 -1
  50. package/dist/assets/x-D7Q1yqSF.js +1 -0
  51. package/dist/index.html +18 -18
  52. package/package.json +6 -6
  53. package/src/api/ncp-session.test.ts +37 -0
  54. package/src/api/ncp-session.ts +29 -1
  55. package/src/api/server-path.ts +23 -0
  56. package/src/api/types.ts +45 -0
  57. package/src/components/chat/ChatConversationPanel.test.tsx +53 -9
  58. package/src/components/chat/ChatConversationPanel.tsx +122 -79
  59. package/src/components/chat/ChatSidebar.test.tsx +2 -2
  60. package/src/components/chat/ChatSidebar.tsx +2 -2
  61. package/src/components/chat/adapters/chat-input-bar.adapter.test.ts +1 -0
  62. package/src/components/chat/adapters/chat-input-bar.adapter.ts +7 -2
  63. package/src/components/chat/adapters/chat-message-part.adapter.ts +26 -14
  64. package/src/components/chat/adapters/chat-message.adapter.test.ts +159 -13
  65. package/src/components/chat/adapters/chat-message.session-request-tool-card.ts +191 -0
  66. package/src/components/chat/adapters/{chat-message.file-operation-card.ts → file-operation/card.ts} +74 -181
  67. package/src/components/chat/adapters/{chat-message.file-operation-diff.ts → file-operation/diff.ts} +178 -188
  68. package/src/components/chat/adapters/file-operation/line-builder.ts +249 -0
  69. package/src/components/chat/adapters/file-operation/record-readers.ts +233 -0
  70. package/src/components/chat/chat-child-session-panel.tsx +100 -0
  71. package/src/components/chat/chat-composer-state.ts +3 -3
  72. package/src/components/chat/chat-page-runtime.test.ts +1 -0
  73. package/src/components/chat/chat-session-display.test.ts +22 -0
  74. package/src/components/chat/chat-session-display.ts +6 -1
  75. package/src/components/chat/containers/chat-input-bar.container.tsx +21 -24
  76. package/src/components/chat/containers/chat-message-list.container.tsx +4 -0
  77. package/src/components/chat/hooks/use-chat-session-label.ts +19 -0
  78. package/src/components/chat/hooks/use-chat-session-project.test.tsx +117 -0
  79. package/src/components/chat/hooks/use-chat-session-project.ts +40 -0
  80. package/src/components/chat/{chat-session-label.service.ts → hooks/use-chat-session-update.ts} +11 -7
  81. package/src/components/chat/managers/chat-session-list.manager.ts +5 -1
  82. package/src/components/chat/ncp/NcpChatPage.tsx +219 -116
  83. package/src/components/chat/ncp/ncp-chat-page-data.test.ts +33 -0
  84. package/src/components/chat/ncp/ncp-chat-page-data.ts +21 -15
  85. package/src/components/chat/ncp/ncp-chat-thread.manager.ts +49 -0
  86. package/src/components/chat/ncp/ncp-session-adapter.test.ts +24 -0
  87. package/src/components/chat/ncp/ncp-session-adapter.ts +47 -0
  88. package/src/components/chat/ncp/use-ncp-session-list-view.ts +10 -1
  89. package/src/components/chat/presenter/chat-presenter-context.tsx +4 -1
  90. package/src/components/chat/session-header/chat-session-header-actions.test.tsx +63 -0
  91. package/src/components/chat/session-header/chat-session-header-actions.tsx +95 -0
  92. package/src/components/chat/session-header/chat-session-header-menu-item.tsx +35 -0
  93. package/src/components/chat/session-header/chat-session-project-badge.test.tsx +66 -0
  94. package/src/components/chat/session-header/chat-session-project-badge.tsx +102 -0
  95. package/src/components/chat/session-header/chat-session-project-dialog.tsx +34 -0
  96. package/src/components/chat/stores/chat-input.store.ts +6 -3
  97. package/src/components/chat/stores/chat-thread.store.ts +17 -3
  98. package/src/components/chat/useHydratedNcpAgent.test.tsx +30 -23
  99. package/src/components/path-picker/server-path-picker-dialog.test.tsx +92 -0
  100. package/src/components/path-picker/server-path-picker-dialog.tsx +282 -0
  101. package/src/hooks/server-path/use-server-path-browse.ts +19 -0
  102. package/src/hooks/useConfig.ts +26 -1
  103. package/src/lib/i18n/i18n-language-owner.ts +94 -0
  104. package/src/lib/i18n/i18n.path-picker.ts +12 -0
  105. package/src/lib/i18n.chat.ts +23 -0
  106. package/src/lib/i18n.ts +21 -84
  107. package/src/lib/session-project/session-project.utils.ts +30 -0
  108. package/dist/assets/ChatPage-FdT3pDnw.js +0 -42
  109. package/dist/assets/DocBrowser-CMdPdbZj.js +0 -1
  110. package/dist/assets/MarketplacePage-9oKmxN2n.js +0 -1
  111. package/dist/assets/ModelConfig-DmCY6jWM.js +0 -1
  112. package/dist/assets/ProvidersList-ClT-34aX.js +0 -1
  113. package/dist/assets/RemoteAccessPage-B6hUZl1O.js +0 -1
  114. package/dist/assets/RuntimeConfig-C5aqliGk.js +0 -1
  115. package/dist/assets/chat-session-display-Bjmn4aIZ.js +0 -1
  116. package/dist/assets/i18n-CSytxMFI.js +0 -1
  117. package/dist/assets/index-CUy6doWo.css +0 -1
  118. package/dist/assets/loader-circle-B2J777gj.js +0 -1
  119. package/dist/assets/plus-CM9XJ0Tf.js +0 -1
  120. package/dist/assets/provider-models-C8JQUd1E.js +0 -1
  121. package/dist/assets/search-Ctaw34Kp.js +0 -1
  122. package/dist/assets/skeleton-Bycyb0zU.js +0 -1
  123. package/dist/assets/tabs-custom-TZQ5WPWP.js +0 -1
  124. package/dist/assets/useConfirmDialog-BDpdjfIO.js +0 -1
  125. package/dist/assets/x-CHOBE-63.js +0 -1
  126. package/src/components/chat/adapters/chat-message.subagent-tool-card.ts +0 -154
  127. /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-WtpHP_DW.js} +0 -0
  128. /package/dist/assets/{config-layout-B-7erZRN.js → config-layout-LQ10ozRC.js} +0 -0
  129. /package/dist/assets/{marketplace-localization-CXeGRf6E.js → marketplace-localization-CxSTG9wr.js} +0 -0
@@ -0,0 +1,12 @@
1
+ export const PATH_PICKER_LABELS: Record<string, { zh: string; en: string }> = {
2
+ browse: { zh: '浏览', en: 'Browse' },
3
+ openPath: { zh: '打开', en: 'Open' },
4
+ homeDirectory: { zh: '主目录', en: 'Home' },
5
+ currentDirectory: { zh: '当前目录', en: 'Current Directory' },
6
+ parentDirectory: { zh: '上一级', en: 'Up' },
7
+ pathPickerSearchPlaceholder: { zh: '搜索当前目录', en: 'Search current directory' },
8
+ pathPickerSearchEmpty: { zh: '当前目录下没有匹配结果。', en: 'No matching entries in the current directory.' },
9
+ selectCurrentDirectory: { zh: '选择当前目录', en: 'Select Current Directory' },
10
+ emptyDirectory: { zh: '当前目录下暂无可浏览项。', en: 'No entries in the current directory.' },
11
+ pathBrowseFailed: { zh: '读取目录失败', en: 'Failed to load directory' },
12
+ };
@@ -50,11 +50,18 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
50
50
  chatSlashTypeCommand: { zh: '命令', en: 'Command' },
51
51
  chatSlashTypeSkill: { zh: '技能', en: 'Skill' },
52
52
  chatSlashSkillSpec: { zh: '标识', en: 'Spec' },
53
+ chatSlashSkillScope: { zh: '作用域', en: 'Scope' },
53
54
  chatSlashLoading: { zh: '加载命令与技能中…', en: 'Loading commands and skills…' },
54
55
  chatSlashNoResult: { zh: '无匹配项', en: 'No matches' },
55
56
  chatSlashHint: { zh: '输入 / 触发命令或技能选择', en: 'Type / to access commands and skills' },
56
57
  chatSlashCommandHint: { zh: '回车插入命令,继续输入参数后发送。', en: 'Press Enter to insert command, then add args and send.' },
57
58
  chatSlashSkillHint: { zh: '回车把该技能加入本轮请求。', en: 'Press Enter to add this skill for the next turn.' },
59
+ chatSkillScopeProject: { zh: '项目', en: 'Project' },
60
+ chatSkillScopeWorkspace: { zh: '工作区', en: 'Workspace' },
61
+ chatPickerRecent: { zh: '最近使用', en: 'Recent' },
62
+ chatPickerRecentModels: { zh: '最近选择', en: 'Recent' },
63
+ chatPickerAllModels: { zh: '全部模型', en: 'All models' },
64
+ chatPickerAllSkills: { zh: '全部技能', en: 'All skills' },
58
65
  chatSend: { zh: '发送', en: 'Send' },
59
66
  chatStop: { zh: '停止', en: 'Stop' },
60
67
  chatStopPreparing: { zh: '正在建立可停止会话,请稍候…', en: 'Preparing stoppable run…' },
@@ -66,6 +73,22 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
66
73
  chatQueueMoveFirst: { zh: '置顶到下一条', en: 'Move to Next' },
67
74
  chatDeleteSession: { zh: '删除会话', en: 'Delete Session' },
68
75
  chatDeleteSessionConfirm: { zh: '确认删除当前会话?', en: 'Delete the current session?' },
76
+ chatSessionMoreActions: { zh: '更多操作', en: 'More actions' },
77
+ chatSessionSetProject: { zh: '设置项目目录', en: 'Set Project Directory' },
78
+ chatSessionClearProject: { zh: '清除项目目录', en: 'Clear Project Directory' },
79
+ chatSessionProjectDialogTitle: { zh: '设置项目目录', en: 'Set Project Directory' },
80
+ chatSessionProjectDialogDescription: {
81
+ zh: '把当前会话绑定到运行 NextClaw 服务的那台机器上的一个目录,让后续消息和工具执行围绕这个目录展开。',
82
+ en: 'Bind this session to a directory on the machine running the NextClaw service so future messages and tool runs work around that directory.'
83
+ },
84
+ chatSessionProjectPathLabel: { zh: '项目目录路径', en: 'Project Directory Path' },
85
+ chatSessionProjectPathPlaceholder: { zh: '/path/to/project', en: '/path/to/project' },
86
+ chatSessionProjectUpdateHint: {
87
+ zh: '这里浏览和选择的是服务端机器上的目录。修改项目目录只影响后续消息和后续工具执行,不会改写历史会话。',
88
+ en: 'The browser lists directories from the server machine. Changing the project directory only affects future messages and tool runs. History stays unchanged.'
89
+ },
90
+ chatSessionProjectUpdated: { zh: '项目目录已更新', en: 'Project directory updated' },
91
+ chatSessionProjectCleared: { zh: '项目目录已清除', en: 'Project directory cleared' },
69
92
  chatSendFailed: { zh: '发送消息失败', en: 'Failed to send message' },
70
93
  chatRoleUser: { zh: '你', en: 'You' },
71
94
  chatRoleAssistant: { zh: '助手', en: 'Assistant' },
package/src/lib/i18n.ts CHANGED
@@ -1,94 +1,30 @@
1
1
  import { CHANNEL_LABELS } from './i18n.channels';
2
2
  import { CHANNEL_AUTH_LABELS } from './i18n.channel-auth';
3
3
  import { CHAT_LABELS } from './i18n.chat';
4
+ import {
5
+ getLanguage,
6
+ getLocale,
7
+ initializeI18n,
8
+ LANGUAGE_OPTIONS,
9
+ resolveInitialLanguage,
10
+ setLanguage,
11
+ subscribeLanguageChange,
12
+ type I18nLanguage
13
+ } from './i18n/i18n-language-owner';
4
14
  import { MARKETPLACE_LABELS } from './i18n.marketplace';
15
+ import { PATH_PICKER_LABELS } from './i18n/i18n.path-picker';
5
16
  import { REMOTE_LABELS } from './i18n.remote';
6
- export type I18nLanguage = 'zh' | 'en';
7
- const I18N_STORAGE_KEY = 'nextclaw.ui.language';
8
- export const LANGUAGE_OPTIONS: Array<{ value: I18nLanguage; label: string }> = [
9
- { value: 'en', label: 'English' },
10
- { value: 'zh', label: '中文' }
11
- ];
12
- const LANGUAGE_TO_LOCALE: Record<I18nLanguage, string> = {
13
- en: 'en-US',
14
- zh: 'zh-CN'
17
+ export type { I18nLanguage };
18
+ export {
19
+ getLanguage,
20
+ getLocale,
21
+ initializeI18n,
22
+ LANGUAGE_OPTIONS,
23
+ resolveInitialLanguage,
24
+ setLanguage,
25
+ subscribeLanguageChange
15
26
  };
16
27
 
17
- let activeLanguage: I18nLanguage = 'en';
18
- let initialized = false;
19
- const listeners = new Set<(lang: I18nLanguage) => void>();
20
-
21
- function isLanguage(value: unknown): value is I18nLanguage {
22
- return value === 'en' || value === 'zh';
23
- }
24
-
25
- function detectBrowserLanguage(): I18nLanguage {
26
- if (typeof navigator === 'undefined') {
27
- return 'en';
28
- }
29
- const preferred = navigator.language?.toLowerCase() ?? 'en';
30
- return preferred.startsWith('zh') ? 'zh' : 'en';
31
- }
32
-
33
- export function resolveInitialLanguage(): I18nLanguage {
34
- if (typeof window === 'undefined') {
35
- return 'en';
36
- }
37
-
38
- try {
39
- const saved = window.localStorage.getItem(I18N_STORAGE_KEY);
40
- if (isLanguage(saved)) {
41
- return saved;
42
- }
43
- } catch {
44
- // ignore storage failures
45
- }
46
-
47
- return detectBrowserLanguage();
48
- }
49
-
50
- export function initializeI18n(): I18nLanguage {
51
- if (!initialized) {
52
- activeLanguage = resolveInitialLanguage();
53
- initialized = true;
54
- }
55
- return activeLanguage;
56
- }
57
-
58
- export function getLanguage(): I18nLanguage {
59
- return initialized ? activeLanguage : initializeI18n();
60
- }
61
-
62
- export function setLanguage(lang: I18nLanguage): void {
63
- initializeI18n();
64
- if (activeLanguage === lang) {
65
- return;
66
- }
67
-
68
- activeLanguage = lang;
69
-
70
- if (typeof window !== 'undefined') {
71
- try {
72
- window.localStorage.setItem(I18N_STORAGE_KEY, lang);
73
- } catch {
74
- // ignore storage failures
75
- }
76
- }
77
-
78
- listeners.forEach((listener) => listener(lang));
79
- }
80
-
81
- export function subscribeLanguageChange(listener: (lang: I18nLanguage) => void): () => void {
82
- listeners.add(listener);
83
- return () => {
84
- listeners.delete(listener);
85
- };
86
- }
87
-
88
- export function getLocale(lang: I18nLanguage = getLanguage()): string {
89
- return LANGUAGE_TO_LOCALE[lang];
90
- }
91
-
92
28
  export function formatDateTime(value?: string | Date, lang: I18nLanguage = getLanguage()): string {
93
29
  if (!value) {
94
30
  return '-';
@@ -624,6 +560,7 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
624
560
  docBrowserNewTab: { zh: '新建标签', en: 'New Tab' },
625
561
  docBrowserCloseTab: { zh: '关闭标签', en: 'Close Tab' },
626
562
  docBrowserTabUntitled: { zh: '未命名', en: 'Untitled' },
563
+ ...PATH_PICKER_LABELS,
627
564
  ...CHANNEL_AUTH_LABELS,
628
565
  };
629
566
 
@@ -0,0 +1,30 @@
1
+ function trimOptionalString(value: unknown): string | null {
2
+ if (typeof value !== "string") {
3
+ return null;
4
+ }
5
+ const trimmed = value.trim();
6
+ return trimmed.length > 0 ? trimmed : null;
7
+ }
8
+
9
+ export function normalizeSessionProjectRootValue(value: unknown): string | null {
10
+ return trimOptionalString(value);
11
+ }
12
+
13
+ export function getSessionProjectName(
14
+ projectRoot: string | null | undefined,
15
+ ): string | null {
16
+ const normalizedProjectRoot = trimOptionalString(projectRoot);
17
+ if (!normalizedProjectRoot) {
18
+ return null;
19
+ }
20
+
21
+ const trimmedTrailingSeparators = normalizedProjectRoot.replace(/[\\/]+$/, "");
22
+ if (!trimmedTrailingSeparators) {
23
+ return normalizedProjectRoot;
24
+ }
25
+
26
+ const pathSegments = trimmedTrailingSeparators
27
+ .split(/[\\/]/)
28
+ .filter(Boolean);
29
+ return pathSegments[pathSegments.length - 1] ?? trimmedTrailingSeparators;
30
+ }