@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.
- package/CHANGELOG.md +12 -0
- package/dist/assets/ChannelsList-ZBPiF0y2.js +1 -0
- package/dist/assets/ChatPage-BOgoolWK.js +38 -0
- package/dist/assets/{DocBrowser-LpzGe8An.js → DocBrowser-BUYNHg0Y.js} +1 -1
- package/dist/assets/LogoBadge-DXPq99LJ.js +1 -0
- package/dist/assets/MarketplacePage-Dx7nexYN.js +49 -0
- package/dist/assets/McpMarketplacePage-064wdotP.js +40 -0
- package/dist/assets/{ModelConfig-DuImUHIX.js → ModelConfig-BDIfLesG.js} +1 -1
- package/dist/assets/ProvidersList-DrlIr46m.js +1 -0
- package/dist/assets/RemoteAccessPage-ZkUBA-Av.js +1 -0
- package/dist/assets/{RuntimeConfig-C6iqpJR_.js → RuntimeConfig-BPxXEGzM.js} +1 -1
- package/dist/assets/{SearchConfig-Dvp1TAXu.js → SearchConfig-BIqnlpne.js} +1 -1
- package/dist/assets/{SecretsConfig-D5Ymlvt9.js → SecretsConfig-jKZEVF2q.js} +2 -2
- package/dist/assets/{SessionsConfig-CIA_jA1P.js → SessionsConfig-C_FXgVe1.js} +2 -2
- package/dist/assets/{chat-message-B60Fh9kI.js → chat-message-DmzpZJc_.js} +1 -1
- package/dist/assets/index-Byfw276e.js +8 -0
- package/dist/assets/{index-CPDASUXh.js → index-Ct7FQpxN.js} +1 -1
- package/dist/assets/index-bhNuQis7.css +1 -0
- package/dist/assets/{label-D4fGx6Wb.js → label-B1MloEtn.js} +1 -1
- package/dist/assets/marketplace-localization-Dk31LJJJ.js +1 -0
- package/dist/assets/{page-layout-twy8gmBE.js → page-layout-BGg1EhM5.js} +1 -1
- package/dist/assets/{popover-DYbYpt1j.js → popover-jJMv74Fp.js} +1 -1
- package/dist/assets/{security-config-BcIZ4rpb.js → security-config-Boh9NIMz.js} +1 -1
- package/dist/assets/skeleton-CmATs_b3.js +1 -0
- package/dist/assets/status-dot-DNyCdxPZ.js +1 -0
- package/dist/assets/{switch-DqA6r5XR.js → switch-DE_MYk7x.js} +1 -1
- package/dist/assets/{tabs-custom-C6enKKs1.js → tabs-custom-B-zErYPr.js} +1 -1
- package/dist/assets/{useConfirmDialog-CHBf5Of7.js → useConfirmDialog-BqQ6QfhB.js} +2 -2
- package/dist/assets/{vendor-DKBNiC31.js → vendor-CwsIoNvJ.js} +128 -93
- package/dist/index.html +3 -3
- package/package.json +4 -4
- package/src/App.tsx +4 -0
- package/src/api/auth.types.ts +24 -0
- package/src/api/chat-session-type.types.ts +21 -0
- package/src/api/marketplace.ts +8 -2
- package/src/api/mcp-marketplace.ts +138 -0
- package/src/api/remote.ts +57 -0
- package/src/api/remote.types.ts +80 -0
- package/src/api/types.ts +91 -37
- package/src/components/chat/ChatSidebar.test.tsx +31 -2
- package/src/components/chat/ChatSidebar.tsx +26 -2
- package/src/components/chat/chat-page-data.ts +37 -53
- package/src/components/chat/chat-page-runtime.test.ts +122 -2
- package/src/components/chat/chat-page-runtime.ts +1 -118
- package/src/components/chat/chat-session-preference-governance.ts +303 -0
- package/src/components/chat/legacy/LegacyChatPage.tsx +4 -34
- package/src/components/chat/ncp/NcpChatPage.tsx +4 -34
- package/src/components/chat/ncp/ncp-chat-page-data.test.ts +36 -0
- package/src/components/chat/ncp/ncp-chat-page-data.ts +63 -36
- package/src/components/chat/ncp/ncp-session-adapter.test.ts +2 -0
- package/src/components/chat/ncp/ncp-session-adapter.ts +2 -0
- package/src/components/chat/stores/chat-input.store.ts +14 -1
- package/src/components/chat/useChatSessionTypeState.test.tsx +29 -0
- package/src/components/chat/useChatSessionTypeState.ts +55 -12
- package/src/components/layout/Sidebar.tsx +11 -1
- package/src/components/marketplace/MarketplacePage.test.tsx +152 -0
- package/src/components/marketplace/MarketplacePage.tsx +52 -199
- package/src/components/marketplace/marketplace-installed-cache.test.ts +110 -0
- package/src/components/marketplace/marketplace-installed-cache.ts +149 -0
- package/src/components/marketplace/marketplace-localization.ts +77 -0
- package/src/components/marketplace/marketplace-page-parts.tsx +102 -0
- package/src/components/marketplace/mcp/McpMarketplacePage.test.tsx +208 -0
- package/src/components/marketplace/mcp/McpMarketplacePage.tsx +578 -0
- package/src/components/remote/RemoteAccessPage.tsx +320 -0
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/label.tsx +1 -1
- package/src/hooks/useMarketplace.ts +36 -7
- package/src/hooks/useMcpMarketplace.ts +99 -0
- package/src/hooks/useRemoteAccess.ts +92 -0
- package/src/hooks/useWebSocket.ts +25 -16
- package/src/lib/i18n.marketplace.ts +91 -0
- package/src/lib/i18n.remote.ts +115 -0
- package/src/lib/i18n.ts +10 -68
- package/dist/assets/ChannelsList-DhvjpZcs.js +0 -1
- package/dist/assets/ChatPage-B8VBaMQm.js +0 -38
- package/dist/assets/LogoBadge-Be4lktJN.js +0 -1
- package/dist/assets/MarketplacePage-Cx9AI3_h.js +0 -49
- package/dist/assets/ProvidersList-Ccleg25k.js +0 -1
- package/dist/assets/index-BiPDnzv0.js +0 -8
- package/dist/assets/index-C8GsgIUn.css +0 -1
- 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-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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.
|
|
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/
|
|
30
|
+
"@nextclaw/ncp-react": "0.3.2",
|
|
31
31
|
"@nextclaw/agent-chat-ui": "0.2.1",
|
|
32
|
-
"@nextclaw/
|
|
32
|
+
"@nextclaw/agent-chat": "0.1.1",
|
|
33
33
|
"@nextclaw/ncp-http-agent-client": "0.3.1",
|
|
34
|
-
"@nextclaw/ncp
|
|
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
|
+
};
|
package/src/api/marketplace.ts
CHANGED
|
@@ -23,8 +23,14 @@ export type MarketplaceListParams = {
|
|
|
23
23
|
pageSize?: number;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
function toMarketplaceTypeSegment(type: MarketplaceItemType): 'plugins' | 'skills' {
|
|
27
|
-
|
|
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
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
|
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: {
|