@nextclaw/ui 0.9.1 → 0.9.3

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 (81) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/assets/ChannelsList-ZBPiF0y2.js +1 -0
  3. package/dist/assets/ChatPage-BOgoolWK.js +38 -0
  4. package/dist/assets/{DocBrowser-LpzGe8An.js → DocBrowser-BUYNHg0Y.js} +1 -1
  5. package/dist/assets/LogoBadge-DXPq99LJ.js +1 -0
  6. package/dist/assets/MarketplacePage-Dx7nexYN.js +49 -0
  7. package/dist/assets/McpMarketplacePage-064wdotP.js +40 -0
  8. package/dist/assets/{ModelConfig-DuImUHIX.js → ModelConfig-BDIfLesG.js} +1 -1
  9. package/dist/assets/ProvidersList-DrlIr46m.js +1 -0
  10. package/dist/assets/RemoteAccessPage-ZkUBA-Av.js +1 -0
  11. package/dist/assets/{RuntimeConfig-C6iqpJR_.js → RuntimeConfig-BPxXEGzM.js} +1 -1
  12. package/dist/assets/{SearchConfig-Dvp1TAXu.js → SearchConfig-BIqnlpne.js} +1 -1
  13. package/dist/assets/{SecretsConfig-D5Ymlvt9.js → SecretsConfig-jKZEVF2q.js} +2 -2
  14. package/dist/assets/{SessionsConfig-CIA_jA1P.js → SessionsConfig-C_FXgVe1.js} +2 -2
  15. package/dist/assets/{chat-message-B60Fh9kI.js → chat-message-DmzpZJc_.js} +1 -1
  16. package/dist/assets/index-Byfw276e.js +8 -0
  17. package/dist/assets/{index-CPDASUXh.js → index-Ct7FQpxN.js} +1 -1
  18. package/dist/assets/index-bhNuQis7.css +1 -0
  19. package/dist/assets/{label-D4fGx6Wb.js → label-B1MloEtn.js} +1 -1
  20. package/dist/assets/marketplace-localization-Dk31LJJJ.js +1 -0
  21. package/dist/assets/{page-layout-twy8gmBE.js → page-layout-BGg1EhM5.js} +1 -1
  22. package/dist/assets/{popover-DYbYpt1j.js → popover-jJMv74Fp.js} +1 -1
  23. package/dist/assets/{security-config-BcIZ4rpb.js → security-config-Boh9NIMz.js} +1 -1
  24. package/dist/assets/skeleton-CmATs_b3.js +1 -0
  25. package/dist/assets/status-dot-DNyCdxPZ.js +1 -0
  26. package/dist/assets/{switch-DqA6r5XR.js → switch-DE_MYk7x.js} +1 -1
  27. package/dist/assets/{tabs-custom-C6enKKs1.js → tabs-custom-B-zErYPr.js} +1 -1
  28. package/dist/assets/{useConfirmDialog-CHBf5Of7.js → useConfirmDialog-BqQ6QfhB.js} +2 -2
  29. package/dist/assets/{vendor-DKBNiC31.js → vendor-CwsIoNvJ.js} +128 -93
  30. package/dist/index.html +3 -3
  31. package/package.json +4 -4
  32. package/src/App.tsx +4 -0
  33. package/src/api/auth.types.ts +24 -0
  34. package/src/api/chat-session-type.types.ts +21 -0
  35. package/src/api/marketplace.ts +8 -2
  36. package/src/api/mcp-marketplace.ts +138 -0
  37. package/src/api/remote.ts +57 -0
  38. package/src/api/remote.types.ts +80 -0
  39. package/src/api/types.ts +91 -37
  40. package/src/components/chat/ChatSidebar.test.tsx +31 -2
  41. package/src/components/chat/ChatSidebar.tsx +26 -2
  42. package/src/components/chat/chat-page-data.ts +37 -53
  43. package/src/components/chat/chat-page-runtime.test.ts +122 -2
  44. package/src/components/chat/chat-page-runtime.ts +1 -118
  45. package/src/components/chat/chat-session-preference-governance.ts +303 -0
  46. package/src/components/chat/legacy/LegacyChatPage.tsx +4 -34
  47. package/src/components/chat/ncp/NcpChatPage.tsx +4 -34
  48. package/src/components/chat/ncp/ncp-chat-page-data.test.ts +36 -0
  49. package/src/components/chat/ncp/ncp-chat-page-data.ts +63 -36
  50. package/src/components/chat/ncp/ncp-session-adapter.test.ts +2 -0
  51. package/src/components/chat/ncp/ncp-session-adapter.ts +2 -0
  52. package/src/components/chat/stores/chat-input.store.ts +14 -1
  53. package/src/components/chat/useChatSessionTypeState.test.tsx +29 -0
  54. package/src/components/chat/useChatSessionTypeState.ts +55 -12
  55. package/src/components/layout/Sidebar.tsx +11 -1
  56. package/src/components/marketplace/MarketplacePage.test.tsx +152 -0
  57. package/src/components/marketplace/MarketplacePage.tsx +52 -199
  58. package/src/components/marketplace/marketplace-installed-cache.test.ts +110 -0
  59. package/src/components/marketplace/marketplace-installed-cache.ts +149 -0
  60. package/src/components/marketplace/marketplace-localization.ts +77 -0
  61. package/src/components/marketplace/marketplace-page-parts.tsx +102 -0
  62. package/src/components/marketplace/mcp/McpMarketplacePage.test.tsx +208 -0
  63. package/src/components/marketplace/mcp/McpMarketplacePage.tsx +578 -0
  64. package/src/components/remote/RemoteAccessPage.tsx +320 -0
  65. package/src/components/ui/input.tsx +1 -1
  66. package/src/components/ui/label.tsx +1 -1
  67. package/src/hooks/useMarketplace.ts +36 -7
  68. package/src/hooks/useMcpMarketplace.ts +99 -0
  69. package/src/hooks/useRemoteAccess.ts +92 -0
  70. package/src/hooks/useWebSocket.ts +25 -16
  71. package/src/lib/i18n.marketplace.ts +91 -0
  72. package/src/lib/i18n.remote.ts +115 -0
  73. package/src/lib/i18n.ts +10 -68
  74. package/dist/assets/ChannelsList-DhvjpZcs.js +0 -1
  75. package/dist/assets/ChatPage-B8VBaMQm.js +0 -38
  76. package/dist/assets/LogoBadge-Be4lktJN.js +0 -1
  77. package/dist/assets/MarketplacePage-Cx9AI3_h.js +0 -49
  78. package/dist/assets/ProvidersList-Ccleg25k.js +0 -1
  79. package/dist/assets/index-BiPDnzv0.js +0 -8
  80. package/dist/assets/index-C8GsgIUn.css +0 -1
  81. package/dist/assets/skeleton-DypBy7jp.js +0 -1
package/dist/index.html CHANGED
@@ -6,9 +6,9 @@
6
6
  <link rel="icon" type="image/svg+xml" href="/logo.svg" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
8
  <title>NextClaw - 系统配置</title>
9
- <script type="module" crossorigin src="/assets/index-BiPDnzv0.js"></script>
10
- <link rel="modulepreload" crossorigin href="/assets/vendor-DKBNiC31.js">
11
- <link rel="stylesheet" crossorigin href="/assets/index-C8GsgIUn.css">
9
+ <script type="module" crossorigin src="/assets/index-Byfw276e.js"></script>
10
+ <link rel="modulepreload" crossorigin href="/assets/vendor-CwsIoNvJ.js">
11
+ <link rel="stylesheet" crossorigin href="/assets/index-bhNuQis7.css">
12
12
  </head>
13
13
 
14
14
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/ui",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,11 +27,11 @@
27
27
  "tailwind-merge": "^2.5.4",
28
28
  "zod": "^3.23.8",
29
29
  "zustand": "^5.0.2",
30
- "@nextclaw/agent-chat": "0.1.1",
30
+ "@nextclaw/ncp-react": "0.3.2",
31
31
  "@nextclaw/agent-chat-ui": "0.2.1",
32
- "@nextclaw/ncp": "0.3.1",
32
+ "@nextclaw/agent-chat": "0.1.1",
33
33
  "@nextclaw/ncp-http-agent-client": "0.3.1",
34
- "@nextclaw/ncp-react": "0.3.2"
34
+ "@nextclaw/ncp": "0.3.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@testing-library/react": "^16.3.0",
package/src/App.tsx CHANGED
@@ -25,7 +25,9 @@ const RuntimeConfigPage = lazy(async () => ({ default: (await import('@/componen
25
25
  const SecurityConfigPage = lazy(async () => ({ default: (await import('@/components/config/security-config')).SecurityConfig }));
26
26
  const SessionsConfigPage = lazy(async () => ({ default: (await import('@/components/config/SessionsConfig')).SessionsConfig }));
27
27
  const SecretsConfigPage = lazy(async () => ({ default: (await import('@/components/config/SecretsConfig')).SecretsConfig }));
28
+ const RemoteAccessPage = lazy(async () => ({ default: (await import('@/components/remote/RemoteAccessPage')).RemoteAccessPage }));
28
29
  const MarketplacePage = lazy(async () => ({ default: (await import('@/components/marketplace/MarketplacePage')).MarketplacePage }));
30
+ const McpMarketplacePage = lazy(async () => ({ default: (await import('@/components/marketplace/mcp/McpMarketplacePage')).McpMarketplacePage }));
29
31
 
30
32
  function RouteFallback() {
31
33
  return <div className="h-full w-full animate-pulse rounded-2xl border border-border/40 bg-card/40" />;
@@ -52,12 +54,14 @@ function ProtectedApp() {
52
54
  <Route path="/providers" element={<LazyRoute><ProvidersListPage /></LazyRoute>} />
53
55
  <Route path="/channels" element={<LazyRoute><ChannelsListPage /></LazyRoute>} />
54
56
  <Route path="/runtime" element={<LazyRoute><RuntimeConfigPage /></LazyRoute>} />
57
+ <Route path="/remote" element={<LazyRoute><RemoteAccessPage /></LazyRoute>} />
55
58
  <Route path="/security" element={<LazyRoute><SecurityConfigPage /></LazyRoute>} />
56
59
  <Route path="/sessions" element={<LazyRoute><SessionsConfigPage /></LazyRoute>} />
57
60
  <Route path="/secrets" element={<LazyRoute><SecretsConfigPage /></LazyRoute>} />
58
61
  <Route path="/settings" element={<Navigate to="/model" replace />} />
59
62
  <Route path="/marketplace/skills" element={<Navigate to="/skills" replace />} />
60
63
  <Route path="/marketplace" element={<Navigate to="/marketplace/plugins" replace />} />
64
+ <Route path="/marketplace/mcp" element={<LazyRoute><McpMarketplacePage /></LazyRoute>} />
61
65
  <Route path="/marketplace/:type" element={<LazyRoute><MarketplacePage /></LazyRoute>} />
62
66
  <Route path="/" element={<Navigate to="/chat" replace />} />
63
67
  <Route path="*" element={<Navigate to="/chat" replace />} />
@@ -0,0 +1,24 @@
1
+ export type AuthStatusView = {
2
+ enabled: boolean;
3
+ configured: boolean;
4
+ authenticated: boolean;
5
+ username?: string;
6
+ };
7
+
8
+ export type AuthSetupRequest = {
9
+ username: string;
10
+ password: string;
11
+ };
12
+
13
+ export type AuthLoginRequest = {
14
+ username: string;
15
+ password: string;
16
+ };
17
+
18
+ export type AuthPasswordUpdateRequest = {
19
+ password: string;
20
+ };
21
+
22
+ export type AuthEnabledUpdateRequest = {
23
+ enabled: boolean;
24
+ };
@@ -0,0 +1,21 @@
1
+ export type ChatSessionTypeCtaView = {
2
+ kind: string;
3
+ label?: string;
4
+ href?: string;
5
+ };
6
+
7
+ export type ChatSessionTypeOptionView = {
8
+ value: string;
9
+ label: string;
10
+ ready?: boolean;
11
+ reason?: string | null;
12
+ reasonMessage?: string | null;
13
+ supportedModels?: string[];
14
+ recommendedModel?: string | null;
15
+ cta?: ChatSessionTypeCtaView | null;
16
+ };
17
+
18
+ export type ChatSessionTypesView = {
19
+ defaultType: string;
20
+ options: ChatSessionTypeOptionView[];
21
+ };
@@ -23,8 +23,14 @@ export type MarketplaceListParams = {
23
23
  pageSize?: number;
24
24
  };
25
25
 
26
- function toMarketplaceTypeSegment(type: MarketplaceItemType): 'plugins' | 'skills' {
27
- return type === 'plugin' ? 'plugins' : 'skills';
26
+ function toMarketplaceTypeSegment(type: MarketplaceItemType): 'plugins' | 'skills' | 'mcp' {
27
+ if (type === 'plugin') {
28
+ return 'plugins';
29
+ }
30
+ if (type === 'skill') {
31
+ return 'skills';
32
+ }
33
+ return 'mcp';
28
34
  }
29
35
 
30
36
  export async function fetchMarketplaceItems(params: MarketplaceListParams): Promise<MarketplaceListView> {
@@ -0,0 +1,138 @@
1
+ import { api } from './client';
2
+ import type {
3
+ MarketplaceInstalledView,
4
+ MarketplaceItemView,
5
+ MarketplaceListView,
6
+ MarketplaceMcpContentView,
7
+ MarketplaceMcpDoctorResult,
8
+ MarketplaceRecommendationView,
9
+ MarketplaceSort
10
+ } from './types';
11
+
12
+ export type McpMarketplaceListParams = {
13
+ q?: string;
14
+ tag?: string;
15
+ sort?: MarketplaceSort;
16
+ page?: number;
17
+ pageSize?: number;
18
+ };
19
+
20
+ export async function fetchMcpMarketplaceItems(params: McpMarketplaceListParams): Promise<MarketplaceListView> {
21
+ const query = new URLSearchParams();
22
+ if (params.q?.trim()) {
23
+ query.set('q', params.q.trim());
24
+ }
25
+ if (params.tag?.trim()) {
26
+ query.set('tag', params.tag.trim());
27
+ }
28
+ if (params.sort) {
29
+ query.set('sort', params.sort);
30
+ }
31
+ if (typeof params.page === 'number' && Number.isFinite(params.page)) {
32
+ query.set('page', String(Math.max(1, Math.trunc(params.page))));
33
+ }
34
+ if (typeof params.pageSize === 'number' && Number.isFinite(params.pageSize)) {
35
+ query.set('pageSize', String(Math.max(1, Math.trunc(params.pageSize))));
36
+ }
37
+
38
+ const suffix = query.toString();
39
+ const response = await api.get<MarketplaceListView>(
40
+ suffix ? `/api/marketplace/mcp/items?${suffix}` : '/api/marketplace/mcp/items'
41
+ );
42
+ if (!response.ok) {
43
+ throw new Error(response.error.message);
44
+ }
45
+ return response.data;
46
+ }
47
+
48
+ export async function fetchMcpMarketplaceInstalled(): Promise<MarketplaceInstalledView> {
49
+ const response = await api.get<MarketplaceInstalledView>('/api/marketplace/mcp/installed');
50
+ if (!response.ok) {
51
+ throw new Error(response.error.message);
52
+ }
53
+ return response.data;
54
+ }
55
+
56
+ export async function fetchMcpMarketplaceItem(slug: string): Promise<MarketplaceItemView> {
57
+ const response = await api.get<MarketplaceItemView>(`/api/marketplace/mcp/items/${encodeURIComponent(slug)}`);
58
+ if (!response.ok) {
59
+ throw new Error(response.error.message);
60
+ }
61
+ return response.data;
62
+ }
63
+
64
+ export async function fetchMcpMarketplaceContent(slug: string): Promise<MarketplaceMcpContentView> {
65
+ const response = await api.get<MarketplaceMcpContentView>(`/api/marketplace/mcp/items/${encodeURIComponent(slug)}/content`);
66
+ if (!response.ok) {
67
+ throw new Error(response.error.message);
68
+ }
69
+ return response.data;
70
+ }
71
+
72
+ export async function fetchMcpMarketplaceRecommendations(params: {
73
+ scene?: string;
74
+ limit?: number;
75
+ } = {}): Promise<MarketplaceRecommendationView> {
76
+ const query = new URLSearchParams();
77
+ if (params.scene?.trim()) {
78
+ query.set('scene', params.scene.trim());
79
+ }
80
+ if (typeof params.limit === 'number' && Number.isFinite(params.limit)) {
81
+ query.set('limit', String(Math.max(1, Math.trunc(params.limit))));
82
+ }
83
+ const suffix = query.toString();
84
+ const response = await api.get<MarketplaceRecommendationView>(
85
+ suffix ? `/api/marketplace/mcp/recommendations?${suffix}` : '/api/marketplace/mcp/recommendations'
86
+ );
87
+ if (!response.ok) {
88
+ throw new Error(response.error.message);
89
+ }
90
+ return response.data;
91
+ }
92
+
93
+ export async function installMcpMarketplaceItem(request: {
94
+ spec: string;
95
+ name?: string;
96
+ enabled?: boolean;
97
+ allAgents?: boolean;
98
+ agents?: string[];
99
+ inputs?: Record<string, string>;
100
+ }): Promise<{ type: 'mcp'; spec: string; name?: string; message: string; output?: string }> {
101
+ const response = await api.post<{ type: 'mcp'; spec: string; name?: string; message: string; output?: string }>(
102
+ '/api/marketplace/mcp/install',
103
+ {
104
+ type: 'mcp',
105
+ ...request
106
+ }
107
+ );
108
+ if (!response.ok) {
109
+ throw new Error(response.error.message);
110
+ }
111
+ return response.data;
112
+ }
113
+
114
+ export async function manageMcpMarketplaceItem(request: {
115
+ action: 'enable' | 'disable' | 'remove';
116
+ id?: string;
117
+ spec?: string;
118
+ }): Promise<{ type: 'mcp'; action: 'enable' | 'disable' | 'remove'; id: string; message: string; output?: string }> {
119
+ const response = await api.post<{ type: 'mcp'; action: 'enable' | 'disable' | 'remove'; id: string; message: string; output?: string }>(
120
+ '/api/marketplace/mcp/manage',
121
+ {
122
+ type: 'mcp',
123
+ ...request
124
+ }
125
+ );
126
+ if (!response.ok) {
127
+ throw new Error(response.error.message);
128
+ }
129
+ return response.data;
130
+ }
131
+
132
+ export async function doctorMcpMarketplaceItem(name: string): Promise<MarketplaceMcpDoctorResult> {
133
+ const response = await api.post<MarketplaceMcpDoctorResult>('/api/marketplace/mcp/doctor', { name });
134
+ if (!response.ok) {
135
+ throw new Error(response.error.message);
136
+ }
137
+ return response.data;
138
+ }
@@ -0,0 +1,57 @@
1
+ import { api } from './client';
2
+ import type {
3
+ RemoteAccessView,
4
+ RemoteDoctorView,
5
+ RemoteLoginRequest,
6
+ RemoteServiceAction,
7
+ RemoteServiceActionResult,
8
+ RemoteSettingsUpdateRequest
9
+ } from './remote.types';
10
+
11
+ export async function fetchRemoteStatus(): Promise<RemoteAccessView> {
12
+ const response = await api.get<RemoteAccessView>('/api/remote/status');
13
+ if (!response.ok) {
14
+ throw new Error(response.error.message);
15
+ }
16
+ return response.data;
17
+ }
18
+
19
+ export async function fetchRemoteDoctor(): Promise<RemoteDoctorView> {
20
+ const response = await api.get<RemoteDoctorView>('/api/remote/doctor');
21
+ if (!response.ok) {
22
+ throw new Error(response.error.message);
23
+ }
24
+ return response.data;
25
+ }
26
+
27
+ export async function loginRemote(data: RemoteLoginRequest): Promise<RemoteAccessView> {
28
+ const response = await api.post<RemoteAccessView>('/api/remote/login', data);
29
+ if (!response.ok) {
30
+ throw new Error(response.error.message);
31
+ }
32
+ return response.data;
33
+ }
34
+
35
+ export async function logoutRemote(): Promise<RemoteAccessView> {
36
+ const response = await api.post<RemoteAccessView>('/api/remote/logout', {});
37
+ if (!response.ok) {
38
+ throw new Error(response.error.message);
39
+ }
40
+ return response.data;
41
+ }
42
+
43
+ export async function updateRemoteSettings(data: RemoteSettingsUpdateRequest): Promise<RemoteAccessView> {
44
+ const response = await api.put<RemoteAccessView>('/api/remote/settings', data);
45
+ if (!response.ok) {
46
+ throw new Error(response.error.message);
47
+ }
48
+ return response.data;
49
+ }
50
+
51
+ export async function controlRemoteService(action: RemoteServiceAction): Promise<RemoteServiceActionResult> {
52
+ const response = await api.post<RemoteServiceActionResult>(`/api/remote/service/${action}`, {});
53
+ if (!response.ok) {
54
+ throw new Error(response.error.message);
55
+ }
56
+ return response.data;
57
+ }
@@ -0,0 +1,80 @@
1
+ export type RemoteAccountView = {
2
+ loggedIn: boolean;
3
+ email?: string;
4
+ role?: string;
5
+ platformBase?: string | null;
6
+ apiBase?: string | null;
7
+ };
8
+
9
+ export type RemoteRuntimeView = {
10
+ enabled: boolean;
11
+ mode: "service" | "foreground";
12
+ state: "disabled" | "connecting" | "connected" | "disconnected" | "error";
13
+ deviceId?: string;
14
+ deviceName?: string;
15
+ platformBase?: string;
16
+ localOrigin?: string;
17
+ lastConnectedAt?: string | null;
18
+ lastError?: string | null;
19
+ updatedAt: string;
20
+ };
21
+
22
+ export type RemoteServiceView = {
23
+ running: boolean;
24
+ pid?: number;
25
+ uiUrl?: string;
26
+ uiPort?: number;
27
+ currentProcess: boolean;
28
+ };
29
+
30
+ export type RemoteSettingsView = {
31
+ enabled: boolean;
32
+ deviceName: string;
33
+ platformApiBase: string;
34
+ };
35
+
36
+ export type RemoteAccessView = {
37
+ account: RemoteAccountView;
38
+ settings: RemoteSettingsView;
39
+ service: RemoteServiceView;
40
+ localOrigin: string;
41
+ configuredEnabled: boolean;
42
+ platformBase?: string | null;
43
+ runtime: RemoteRuntimeView | null;
44
+ };
45
+
46
+ export type RemoteDoctorCheckView = {
47
+ name: string;
48
+ ok: boolean;
49
+ detail: string;
50
+ };
51
+
52
+ export type RemoteDoctorView = {
53
+ generatedAt: string;
54
+ checks: RemoteDoctorCheckView[];
55
+ snapshot: {
56
+ configuredEnabled: boolean;
57
+ runtime: RemoteRuntimeView | null;
58
+ };
59
+ };
60
+
61
+ export type RemoteLoginRequest = {
62
+ email: string;
63
+ password: string;
64
+ apiBase?: string;
65
+ register?: boolean;
66
+ };
67
+
68
+ export type RemoteSettingsUpdateRequest = {
69
+ enabled?: boolean;
70
+ deviceName?: string;
71
+ platformApiBase?: string;
72
+ };
73
+
74
+ export type RemoteServiceAction = "start" | "restart" | "stop";
75
+
76
+ export type RemoteServiceActionResult = {
77
+ accepted: boolean;
78
+ action: RemoteServiceAction;
79
+ message: string;
80
+ };
package/src/api/types.ts CHANGED
@@ -160,30 +160,27 @@ export type ProviderAuthImportResult = {
160
160
  expiresAt?: string;
161
161
  };
162
162
 
163
- export type AuthStatusView = {
164
- enabled: boolean;
165
- configured: boolean;
166
- authenticated: boolean;
167
- username?: string;
168
- };
169
-
170
- export type AuthSetupRequest = {
171
- username: string;
172
- password: string;
173
- };
174
-
175
- export type AuthLoginRequest = {
176
- username: string;
177
- password: string;
178
- };
179
-
180
- export type AuthPasswordUpdateRequest = {
181
- password: string;
182
- };
183
-
184
- export type AuthEnabledUpdateRequest = {
185
- enabled: boolean;
186
- };
163
+ export type {
164
+ AuthEnabledUpdateRequest,
165
+ AuthLoginRequest,
166
+ AuthPasswordUpdateRequest,
167
+ AuthSetupRequest,
168
+ AuthStatusView
169
+ } from './auth.types';
170
+
171
+ export type {
172
+ RemoteAccessView,
173
+ RemoteAccountView,
174
+ RemoteDoctorCheckView,
175
+ RemoteDoctorView,
176
+ RemoteLoginRequest,
177
+ RemoteRuntimeView,
178
+ RemoteServiceAction,
179
+ RemoteServiceActionResult,
180
+ RemoteServiceView,
181
+ RemoteSettingsUpdateRequest,
182
+ RemoteSettingsView
183
+ } from './remote.types';
187
184
 
188
185
  export type AgentProfileView = {
189
186
  id: string;
@@ -223,6 +220,7 @@ export type SessionEntryView = {
223
220
  updatedAt: string;
224
221
  label?: string;
225
222
  preferredModel?: string;
223
+ preferredThinking?: ThinkingLevel | null;
226
224
  sessionType: string;
227
225
  sessionTypeMutable: boolean;
228
226
  messageCount: number;
@@ -316,6 +314,12 @@ export type ChatTurnStreamReadyEvent = {
316
314
  stopReason?: string;
317
315
  };
318
316
 
317
+ export type {
318
+ ChatSessionTypeCtaView,
319
+ ChatSessionTypeOptionView,
320
+ ChatSessionTypesView,
321
+ } from './chat-session-type.types';
322
+
319
323
  export type ChatTurnStreamDeltaEvent = {
320
324
  delta: string;
321
325
  };
@@ -334,16 +338,6 @@ export type ChatCapabilitiesView = {
334
338
  stopReason?: string;
335
339
  };
336
340
 
337
- export type ChatSessionTypeOptionView = {
338
- value: string;
339
- label: string;
340
- };
341
-
342
- export type ChatSessionTypesView = {
343
- defaultType: string;
344
- options: ChatSessionTypeOptionView[];
345
- };
346
-
347
341
  export type ChatCommandOptionView = {
348
342
  name: string;
349
343
  description: string;
@@ -703,13 +697,14 @@ export type WsEvent =
703
697
  | { type: 'connection.close'; payload?: Record<string, unknown> }
704
698
  | { type: 'connection.error'; payload?: { message?: string } };
705
699
 
706
- export type MarketplaceItemType = 'plugin' | 'skill';
700
+ export type MarketplaceItemType = 'plugin' | 'skill' | 'mcp';
707
701
 
708
702
  export type MarketplaceSort = 'relevance' | 'updated';
709
703
 
710
704
  export type MarketplacePluginInstallKind = 'npm';
711
705
  export type MarketplaceSkillInstallKind = 'builtin' | 'marketplace';
712
- export type MarketplaceInstallKind = MarketplacePluginInstallKind | MarketplaceSkillInstallKind;
706
+ export type MarketplaceMcpInstallKind = 'template';
707
+ export type MarketplaceInstallKind = MarketplacePluginInstallKind | MarketplaceSkillInstallKind | MarketplaceMcpInstallKind;
713
708
 
714
709
  export type MarketplaceInstallSpec = {
715
710
  kind: MarketplaceInstallKind;
@@ -717,6 +712,23 @@ export type MarketplaceInstallSpec = {
717
712
  command: string;
718
713
  };
719
714
 
715
+ export type MarketplaceMcpTemplateInput = {
716
+ id: string;
717
+ label: string;
718
+ description?: string;
719
+ required?: boolean;
720
+ secret?: boolean;
721
+ defaultValue?: string;
722
+ };
723
+
724
+ export type MarketplaceMcpInstallSpec = MarketplaceInstallSpec & {
725
+ kind: 'template';
726
+ defaultName: string;
727
+ transportTypes: Array<'stdio' | 'http' | 'sse'>;
728
+ template: Record<string, unknown>;
729
+ inputs: MarketplaceMcpTemplateInput[];
730
+ };
731
+
720
732
  export type MarketplaceLocalizedTextMap = Record<string, string>;
721
733
 
722
734
  export type MarketplaceItemSummary = {
@@ -764,6 +776,18 @@ export type MarketplacePluginContentView = {
764
776
  sourceUrl?: string;
765
777
  };
766
778
 
779
+ export type MarketplaceMcpContentView = {
780
+ type: 'mcp';
781
+ slug: string;
782
+ name: string;
783
+ install: MarketplaceMcpInstallSpec;
784
+ source: 'marketplace' | 'remote';
785
+ raw: string;
786
+ metadataRaw?: string;
787
+ bodyRaw: string;
788
+ sourceUrl?: string;
789
+ };
790
+
767
791
  export type MarketplaceListView = {
768
792
  total: number;
769
793
  page: number;
@@ -796,6 +820,21 @@ export type MarketplaceInstalledRecord = {
796
820
  runtimeStatus?: string;
797
821
  origin?: string;
798
822
  installPath?: string;
823
+ transport?: 'stdio' | 'http' | 'sse';
824
+ scope?: {
825
+ allAgents: boolean;
826
+ agents: string[];
827
+ };
828
+ catalogSlug?: string;
829
+ vendor?: string;
830
+ docsUrl?: string;
831
+ homepage?: string;
832
+ trustLevel?: 'official' | 'verified' | 'community';
833
+ toolCount?: number;
834
+ accessible?: boolean;
835
+ lastReadyAt?: string;
836
+ lastDoctorAt?: string;
837
+ lastError?: string;
799
838
  };
800
839
 
801
840
  export type MarketplaceInstalledView = {
@@ -812,6 +851,11 @@ export type MarketplaceInstallRequest = {
812
851
  skill?: string;
813
852
  installPath?: string;
814
853
  force?: boolean;
854
+ name?: string;
855
+ enabled?: boolean;
856
+ allAgents?: boolean;
857
+ agents?: string[];
858
+ inputs?: Record<string, string>;
815
859
  };
816
860
 
817
861
  export type MarketplaceInstallResult = {
@@ -819,9 +863,10 @@ export type MarketplaceInstallResult = {
819
863
  spec: string;
820
864
  message: string;
821
865
  output?: string;
866
+ name?: string;
822
867
  };
823
868
 
824
- export type MarketplaceManageAction = 'enable' | 'disable' | 'uninstall';
869
+ export type MarketplaceManageAction = 'enable' | 'disable' | 'uninstall' | 'remove';
825
870
 
826
871
  export type MarketplaceManageRequest = {
827
872
  type: MarketplaceItemType;
@@ -837,3 +882,12 @@ export type MarketplaceManageResult = {
837
882
  message: string;
838
883
  output?: string;
839
884
  };
885
+
886
+ export type MarketplaceMcpDoctorResult = {
887
+ name: string;
888
+ enabled: boolean;
889
+ transport: 'stdio' | 'http' | 'sse';
890
+ accessible: boolean;
891
+ toolCount: number;
892
+ error?: string;
893
+ };
@@ -68,8 +68,8 @@ describe('ChatSidebar', () => {
68
68
  ...useChatInputStore.getState().snapshot,
69
69
  defaultSessionType: 'native',
70
70
  sessionTypeOptions: [
71
- { value: 'native', label: 'Native' },
72
- { value: 'codex', label: 'Codex' }
71
+ { value: 'native', label: 'Native', ready: true },
72
+ { value: 'codex', label: 'Codex', ready: true }
73
73
  ]
74
74
  }
75
75
  });
@@ -105,6 +105,35 @@ describe('ChatSidebar', () => {
105
105
  });
106
106
  });
107
107
 
108
+ it('shows setup required status for runtime session types that are not ready yet', () => {
109
+ useChatInputStore.setState({
110
+ snapshot: {
111
+ ...useChatInputStore.getState().snapshot,
112
+ sessionTypeOptions: [
113
+ { value: 'native', label: 'Native', ready: true },
114
+ {
115
+ value: 'claude',
116
+ label: 'Claude',
117
+ ready: false,
118
+ reasonMessage: 'Configure a provider API key first.'
119
+ }
120
+ ]
121
+ }
122
+ });
123
+
124
+ render(
125
+ <MemoryRouter>
126
+ <ChatSidebar />
127
+ </MemoryRouter>
128
+ );
129
+
130
+ fireEvent.click(screen.getByLabelText('Session Type'));
131
+
132
+ expect(screen.getByText('Claude')).not.toBeNull();
133
+ expect(screen.getByText('Setup')).not.toBeNull();
134
+ expect(screen.getByText('Configure a provider API key first.')).not.toBeNull();
135
+ });
136
+
108
137
  it('shows a session type badge for non-native sessions in the list', () => {
109
138
  useChatSessionListStore.setState({
110
139
  snapshot: {