@zhin.js/client 1.1.4 → 1.1.6
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/README.md +94 -432
- package/client/agent-stream.ts +121 -0
- package/client/app.test.ts +37 -0
- package/client/app.ts +130 -138
- package/client/bootstrap/loadConsoleEntries.test.ts +23 -12
- package/client/bootstrap/loadConsoleEntries.ts +40 -27
- package/client/console-client-context.ts +24 -0
- package/client/console-client.test.ts +46 -0
- package/client/console-client.ts +70 -0
- package/client/console-events.ts +38 -0
- package/client/console-utils/remoteApi.test.ts +91 -0
- package/client/console-utils/remoteApi.ts +47 -9
- package/client/index.ts +92 -28
- package/client/mediaSrc.test.ts +49 -0
- package/client/mediaSrc.ts +84 -11
- package/client/message-content/MarkdownContent.tsx +128 -0
- package/client/message-content/markdown.test.ts +48 -0
- package/client/message-content/markdown.ts +247 -0
- package/client/persistence/idb-store.test.ts +121 -0
- package/client/persistence/idb-store.ts +40 -21
- package/client/segments.test.ts +16 -0
- package/client/segments.ts +39 -0
- package/client/transport/console-transport.test.ts +394 -0
- package/client/transport/console-transport.ts +676 -0
- package/client/transport/hooks.test.ts +21 -0
- package/client/transport/hooks.ts +535 -0
- package/client/transport/index.ts +23 -0
- package/client/{websocket → transport}/types.ts +16 -17
- package/client/types.ts +5 -8
- package/client/workroom/WorkroomRunsPage.tsx +355 -0
- package/client/workroom/registerWorkroomConsole.test.ts +25 -0
- package/client/workroom/registerWorkroomConsole.ts +17 -0
- package/dist/agent-stream.d.ts +17 -0
- package/dist/agent-stream.d.ts.map +1 -0
- package/dist/agent-stream.js +73 -0
- package/dist/agent-stream.js.map +1 -0
- package/dist/app.d.ts +17 -52
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +110 -95
- package/dist/app.js.map +1 -1
- package/dist/bootstrap/loadConsoleEntries.d.ts +10 -7
- package/dist/bootstrap/loadConsoleEntries.d.ts.map +1 -1
- package/dist/bootstrap/loadConsoleEntries.js +37 -11
- package/dist/bootstrap/loadConsoleEntries.js.map +1 -1
- package/dist/console-client-context.d.ts +9 -0
- package/dist/console-client-context.d.ts.map +1 -0
- package/dist/console-client-context.js +13 -0
- package/dist/console-client-context.js.map +1 -0
- package/dist/console-client.d.ts +25 -0
- package/dist/console-client.d.ts.map +1 -0
- package/dist/console-client.js +45 -0
- package/dist/console-client.js.map +1 -0
- package/dist/console-events.d.ts +8 -0
- package/dist/console-events.d.ts.map +1 -0
- package/dist/console-events.js +26 -0
- package/dist/console-events.js.map +1 -0
- package/dist/console-utils/remoteApi.d.ts +2 -1
- package/dist/console-utils/remoteApi.d.ts.map +1 -1
- package/dist/console-utils/remoteApi.js +46 -8
- package/dist/console-utils/remoteApi.js.map +1 -1
- package/dist/index.d.ts +14 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -1
- package/dist/mediaSrc.d.ts +1 -1
- package/dist/mediaSrc.d.ts.map +1 -1
- package/dist/mediaSrc.js +91 -11
- package/dist/mediaSrc.js.map +1 -1
- package/dist/message-content/MarkdownContent.d.ts +11 -0
- package/dist/message-content/MarkdownContent.d.ts.map +1 -0
- package/dist/message-content/MarkdownContent.js +68 -0
- package/dist/message-content/MarkdownContent.js.map +1 -0
- package/dist/message-content/markdown.d.ts +47 -0
- package/dist/message-content/markdown.d.ts.map +1 -0
- package/dist/message-content/markdown.js +219 -0
- package/dist/message-content/markdown.js.map +1 -0
- package/dist/persistence/idb-store.d.ts +5 -2
- package/dist/persistence/idb-store.d.ts.map +1 -1
- package/dist/persistence/idb-store.js +29 -20
- package/dist/persistence/idb-store.js.map +1 -1
- package/dist/segments.d.ts +9 -0
- package/dist/segments.d.ts.map +1 -0
- package/dist/segments.js +35 -0
- package/dist/segments.js.map +1 -0
- package/dist/transport/console-transport.d.ts +217 -0
- package/dist/transport/console-transport.d.ts.map +1 -0
- package/dist/transport/console-transport.js +563 -0
- package/dist/transport/console-transport.js.map +1 -0
- package/dist/transport/hooks.d.ts +253 -0
- package/dist/transport/hooks.d.ts.map +1 -0
- package/dist/transport/hooks.js +483 -0
- package/dist/transport/hooks.js.map +1 -0
- package/dist/transport/index.d.ts +4 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +4 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/{websocket → transport}/types.d.ts +14 -13
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/{websocket → transport}/types.js +4 -9
- package/dist/transport/types.js.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/workroom/WorkroomRunsPage.d.ts +2 -0
- package/dist/workroom/WorkroomRunsPage.d.ts.map +1 -0
- package/dist/workroom/WorkroomRunsPage.js +111 -0
- package/dist/workroom/WorkroomRunsPage.js.map +1 -0
- package/dist/workroom/registerWorkroomConsole.d.ts +4 -0
- package/dist/workroom/registerWorkroomConsole.d.ts.map +1 -0
- package/dist/workroom/registerWorkroomConsole.js +16 -0
- package/dist/workroom/registerWorkroomConsole.js.map +1 -0
- package/package.json +18 -8
- package/client/runtime/index.ts +0 -12
- package/client/websocket/hooks.ts +0 -289
- package/client/websocket/index.ts +0 -6
- package/client/websocket/instance.ts +0 -24
- package/client/websocket/manager.ts +0 -426
- package/client/websocket/remote-settings.ts +0 -25
- package/dist/bootstrap/loadConsoleEntries.test.d.ts +0 -2
- package/dist/bootstrap/loadConsoleEntries.test.d.ts.map +0 -1
- package/dist/bootstrap/loadConsoleEntries.test.js +0 -27
- package/dist/bootstrap/loadConsoleEntries.test.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -6
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/index.js +0 -10
- package/dist/runtime/index.js.map +0 -1
- package/dist/websocket/hooks.d.ts +0 -105
- package/dist/websocket/hooks.d.ts.map +0 -1
- package/dist/websocket/hooks.js +0 -247
- package/dist/websocket/hooks.js.map +0 -1
- package/dist/websocket/index.d.ts +0 -7
- package/dist/websocket/index.d.ts.map +0 -1
- package/dist/websocket/index.js +0 -7
- package/dist/websocket/index.js.map +0 -1
- package/dist/websocket/instance.d.ts +0 -5
- package/dist/websocket/instance.d.ts.map +0 -1
- package/dist/websocket/instance.js +0 -21
- package/dist/websocket/instance.js.map +0 -1
- package/dist/websocket/manager.d.ts +0 -113
- package/dist/websocket/manager.d.ts.map +0 -1
- package/dist/websocket/manager.js +0 -403
- package/dist/websocket/manager.js.map +0 -1
- package/dist/websocket/remote-settings.d.ts +0 -5
- package/dist/websocket/remote-settings.d.ts.map +0 -1
- package/dist/websocket/remote-settings.js +0 -23
- package/dist/websocket/remote-settings.js.map +0 -1
- package/dist/websocket/types.d.ts.map +0 -1
- package/dist/websocket/types.js.map +0 -1
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useConsoleClient } from "../console-client-context.js";
|
|
3
|
+
import type { UseConsoleTransportOptions } from "./types.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 每次连接会话只对同一 key 自动加载一次:失败后不再零退避死循环
|
|
7
|
+
* (旧行为:加载失败 → 状态保持空 → effect 反复立即重试,打爆 /api/console/request)。
|
|
8
|
+
* 断连后重置;key 变化(如 pluginName 切换)视为新目标重新尝试;手动重试走各 hook 返回的 load 函数。
|
|
9
|
+
*/
|
|
10
|
+
function useAutoLoadOnce(connected: boolean, key: unknown, ready: boolean, fire: () => void) {
|
|
11
|
+
const attemptedRef = useRef<unknown>(undefined);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!connected) {
|
|
14
|
+
attemptedRef.current = undefined;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (ready || attemptedRef.current === key) return;
|
|
18
|
+
attemptedRef.current = key;
|
|
19
|
+
fire();
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useConsoleTransport(options: UseConsoleTransportOptions = {}) {
|
|
24
|
+
const { autoConnect = true } = options;
|
|
25
|
+
const wsManager = useConsoleClient().transport;
|
|
26
|
+
const [connected, setConnected] = useState(wsManager.isConnected());
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
return wsManager.onConnectionChange(setConnected);
|
|
30
|
+
}, [wsManager]);
|
|
31
|
+
|
|
32
|
+
const connect = useCallback(() => wsManager.connect(), [wsManager]);
|
|
33
|
+
const disconnect = useCallback(() => wsManager.disconnect(), [wsManager]);
|
|
34
|
+
const send = useCallback((message: unknown) => wsManager.send(message), [wsManager]);
|
|
35
|
+
const sendRequest = useCallback(
|
|
36
|
+
<T = unknown>(message: unknown) => wsManager.sendRequest<T>(message),
|
|
37
|
+
[wsManager],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (autoConnect && !connected) connect();
|
|
42
|
+
}, [autoConnect, connected, connect]);
|
|
43
|
+
|
|
44
|
+
return { connected, connect, disconnect, send, sendRequest, manager: wsManager };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 按 key 绑定异步加载结果:key(如 pluginName)切换后,旧 key 的残留值视为 null,
|
|
49
|
+
* 避免 useConfig 的 ready 判断(config != null)被上一插件的 state 挡住而不再加载新配置。
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
export function resolveKeyedValue<T>(
|
|
53
|
+
entry: { readonly key: string; readonly value: T } | null,
|
|
54
|
+
key: string,
|
|
55
|
+
): T | null {
|
|
56
|
+
return entry && entry.key === key ? entry.value : null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function useConfig(pluginName: string, options?: { autoLoad?: boolean; autoLoadSchema?: boolean }) {
|
|
60
|
+
const { autoLoad = true, autoLoadSchema = true } = options ?? {};
|
|
61
|
+
const wsManager = useConsoleClient().transport;
|
|
62
|
+
const [connected, setConnected] = useState(wsManager.isConnected());
|
|
63
|
+
const [configEntry, setConfigEntry] = useState<{ key: string; value: unknown } | null>(null);
|
|
64
|
+
const [schemaEntry, setSchemaEntry] = useState<{ key: string; value: unknown } | null>(null);
|
|
65
|
+
const [loading, setLoading] = useState(false);
|
|
66
|
+
const [error, setError] = useState<string | null>(null);
|
|
67
|
+
const config = resolveKeyedValue(configEntry, pluginName);
|
|
68
|
+
const schema = resolveKeyedValue(schemaEntry, pluginName);
|
|
69
|
+
|
|
70
|
+
useEffect(() => wsManager.onConnectionChange(setConnected), [wsManager]);
|
|
71
|
+
|
|
72
|
+
const getConfig = useCallback(async () => {
|
|
73
|
+
setLoading(true);
|
|
74
|
+
setError(null);
|
|
75
|
+
try {
|
|
76
|
+
const result = await wsManager.getConfig(pluginName);
|
|
77
|
+
setConfigEntry({ key: pluginName, value: result });
|
|
78
|
+
return result;
|
|
79
|
+
} catch (e) {
|
|
80
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
81
|
+
throw e;
|
|
82
|
+
} finally {
|
|
83
|
+
setLoading(false);
|
|
84
|
+
}
|
|
85
|
+
}, [pluginName, wsManager]);
|
|
86
|
+
|
|
87
|
+
const setConfig = useCallback(
|
|
88
|
+
async (newConfig: unknown) => {
|
|
89
|
+
setLoading(true);
|
|
90
|
+
setError(null);
|
|
91
|
+
try {
|
|
92
|
+
return await wsManager.setConfig(pluginName, newConfig);
|
|
93
|
+
} catch (e) {
|
|
94
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
95
|
+
throw e;
|
|
96
|
+
} finally {
|
|
97
|
+
setLoading(false);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
[pluginName, wsManager],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const getSchema = useCallback(async () => {
|
|
104
|
+
try {
|
|
105
|
+
const result = await wsManager.getSchema(pluginName);
|
|
106
|
+
if (result) setSchemaEntry({ key: pluginName, value: result });
|
|
107
|
+
return result;
|
|
108
|
+
} catch (e) {
|
|
109
|
+
throw e;
|
|
110
|
+
}
|
|
111
|
+
}, [pluginName, wsManager]);
|
|
112
|
+
|
|
113
|
+
useAutoLoadOnce(connected, `config:${pluginName}`, !autoLoad || config != null || loading, () => {
|
|
114
|
+
getConfig().catch(() => {});
|
|
115
|
+
});
|
|
116
|
+
useAutoLoadOnce(connected, `schema:${pluginName}`, !autoLoadSchema || schema != null, () => {
|
|
117
|
+
getSchema().catch(() => {});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return useMemo(
|
|
121
|
+
() => ({ config, schema, loading, error, connected, getConfig, setConfig, getSchema }),
|
|
122
|
+
[config, schema, loading, error, connected, getConfig, setConfig, getSchema],
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function useConfigSource() {
|
|
127
|
+
const wsManager = useConsoleClient().transport;
|
|
128
|
+
const [connected, setConnected] = useState(wsManager.isConnected());
|
|
129
|
+
const [source, setSource] = useState("");
|
|
130
|
+
const [format, setFormat] = useState<'yaml' | 'json'>('yaml');
|
|
131
|
+
const [revision, setRevision] = useState("");
|
|
132
|
+
const [configKeys, setConfigKeys] = useState<string[]>([]);
|
|
133
|
+
const [loading, setLoading] = useState(false);
|
|
134
|
+
const [error, setError] = useState<string | null>(null);
|
|
135
|
+
|
|
136
|
+
useEffect(() => wsManager.onConnectionChange(setConnected), [wsManager]);
|
|
137
|
+
|
|
138
|
+
const load = useCallback(async () => {
|
|
139
|
+
setLoading(true);
|
|
140
|
+
setError(null);
|
|
141
|
+
try {
|
|
142
|
+
const result = await wsManager.getConfigSource();
|
|
143
|
+
setSource(result.source);
|
|
144
|
+
setFormat(result.format);
|
|
145
|
+
setRevision(result.revision);
|
|
146
|
+
setConfigKeys([...result.configKeys]);
|
|
147
|
+
return result;
|
|
148
|
+
} catch (e) {
|
|
149
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
150
|
+
throw e;
|
|
151
|
+
} finally {
|
|
152
|
+
setLoading(false);
|
|
153
|
+
}
|
|
154
|
+
}, [wsManager]);
|
|
155
|
+
|
|
156
|
+
const save = useCallback(
|
|
157
|
+
async (content: string) => {
|
|
158
|
+
setLoading(true);
|
|
159
|
+
setError(null);
|
|
160
|
+
try {
|
|
161
|
+
if (!revision) throw new Error('Config source must be loaded before it can be replaced');
|
|
162
|
+
const result = await wsManager.replaceConfigSource(content, revision);
|
|
163
|
+
setSource(content);
|
|
164
|
+
setRevision(result.revision);
|
|
165
|
+
return result;
|
|
166
|
+
} catch (e) {
|
|
167
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
168
|
+
throw e;
|
|
169
|
+
} finally {
|
|
170
|
+
setLoading(false);
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
[revision, wsManager],
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
useAutoLoadOnce(connected, "config-source", !!revision || loading, () => {
|
|
177
|
+
load().catch(() => {});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return useMemo(
|
|
181
|
+
() => ({ source, format, revision, configKeys, loading, error, load, save }),
|
|
182
|
+
[source, format, revision, configKeys, loading, error, load, save],
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Shared Console flow for previewing and committing a plugin installation. */
|
|
187
|
+
export function usePluginInstall() {
|
|
188
|
+
const wsManager = useConsoleClient().transport;
|
|
189
|
+
const [loading, setLoading] = useState(false);
|
|
190
|
+
const [error, setError] = useState<string | null>(null);
|
|
191
|
+
const [plan, setPlan] = useState<Awaited<ReturnType<typeof wsManager.planPluginInstall>> | null>(null);
|
|
192
|
+
|
|
193
|
+
const preview = useCallback(async (packageName: string) => {
|
|
194
|
+
setLoading(true);
|
|
195
|
+
setError(null);
|
|
196
|
+
try {
|
|
197
|
+
const next = await wsManager.planPluginInstall(packageName);
|
|
198
|
+
setPlan(next);
|
|
199
|
+
return next;
|
|
200
|
+
} catch (e) {
|
|
201
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
202
|
+
throw e;
|
|
203
|
+
} finally {
|
|
204
|
+
setLoading(false);
|
|
205
|
+
}
|
|
206
|
+
}, [wsManager]);
|
|
207
|
+
|
|
208
|
+
const install = useCallback(async (packageName: string, expectedRevision?: string) => {
|
|
209
|
+
setLoading(true);
|
|
210
|
+
setError(null);
|
|
211
|
+
try {
|
|
212
|
+
return await wsManager.installPlugin(packageName, expectedRevision);
|
|
213
|
+
} catch (e) {
|
|
214
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
215
|
+
throw e;
|
|
216
|
+
} finally {
|
|
217
|
+
setLoading(false);
|
|
218
|
+
}
|
|
219
|
+
}, [wsManager]);
|
|
220
|
+
|
|
221
|
+
return useMemo(() => ({ plan, loading, error, preview, install }), [
|
|
222
|
+
plan, loading, error, preview, install,
|
|
223
|
+
]);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function usePluginConfigValidation(pluginName: string) {
|
|
227
|
+
const wsManager = useConsoleClient().transport;
|
|
228
|
+
const [loading, setLoading] = useState(false);
|
|
229
|
+
const [error, setError] = useState<string | null>(null);
|
|
230
|
+
const validate = useCallback(async (data: unknown) => {
|
|
231
|
+
setLoading(true);
|
|
232
|
+
setError(null);
|
|
233
|
+
try {
|
|
234
|
+
return await wsManager.validatePluginConfig(pluginName, data);
|
|
235
|
+
} catch (e) {
|
|
236
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
237
|
+
throw e;
|
|
238
|
+
} finally {
|
|
239
|
+
setLoading(false);
|
|
240
|
+
}
|
|
241
|
+
}, [pluginName, wsManager]);
|
|
242
|
+
return useMemo(() => ({ loading, error, validate }), [loading, error, validate]);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function usePluginDiagnostics(pluginName: string) {
|
|
246
|
+
const wsManager = useConsoleClient().transport;
|
|
247
|
+
const [loading, setLoading] = useState(false);
|
|
248
|
+
const [error, setError] = useState<string | null>(null);
|
|
249
|
+
const diagnose = useCallback(async () => {
|
|
250
|
+
setLoading(true);
|
|
251
|
+
setError(null);
|
|
252
|
+
try {
|
|
253
|
+
return await wsManager.diagnosePlugin(pluginName);
|
|
254
|
+
} catch (e) {
|
|
255
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
256
|
+
throw e;
|
|
257
|
+
} finally {
|
|
258
|
+
setLoading(false);
|
|
259
|
+
}
|
|
260
|
+
}, [pluginName, wsManager]);
|
|
261
|
+
return useMemo(() => ({ loading, error, diagnose }), [loading, error, diagnose]);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function usePluginLifecycle(instanceKey: string) {
|
|
265
|
+
const wsManager = useConsoleClient().transport;
|
|
266
|
+
const [loading, setLoading] = useState(false);
|
|
267
|
+
const [error, setError] = useState<string | null>(null);
|
|
268
|
+
const setEnabled = useCallback(async (enabled: boolean) => {
|
|
269
|
+
setLoading(true);
|
|
270
|
+
setError(null);
|
|
271
|
+
try {
|
|
272
|
+
return await wsManager.setPluginEnabled(instanceKey, enabled);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
275
|
+
throw e;
|
|
276
|
+
} finally {
|
|
277
|
+
setLoading(false);
|
|
278
|
+
}
|
|
279
|
+
}, [instanceKey, wsManager]);
|
|
280
|
+
return useMemo(() => ({ loading, error, setEnabled }), [loading, error, setEnabled]);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function usePluginUninstall() {
|
|
284
|
+
const wsManager = useConsoleClient().transport;
|
|
285
|
+
const [loading, setLoading] = useState(false);
|
|
286
|
+
const [error, setError] = useState<string | null>(null);
|
|
287
|
+
const preview = useCallback(async (packageName: string) => {
|
|
288
|
+
setLoading(true);
|
|
289
|
+
setError(null);
|
|
290
|
+
try {
|
|
291
|
+
return await wsManager.planPluginUninstall(packageName);
|
|
292
|
+
} catch (e) {
|
|
293
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
294
|
+
throw e;
|
|
295
|
+
} finally {
|
|
296
|
+
setLoading(false);
|
|
297
|
+
}
|
|
298
|
+
}, [wsManager]);
|
|
299
|
+
const uninstall = useCallback(async (packageName: string, expectedRevision?: string) => {
|
|
300
|
+
setLoading(true);
|
|
301
|
+
setError(null);
|
|
302
|
+
try {
|
|
303
|
+
return await wsManager.uninstallPlugin(packageName, expectedRevision);
|
|
304
|
+
} catch (e) {
|
|
305
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
306
|
+
throw e;
|
|
307
|
+
} finally {
|
|
308
|
+
setLoading(false);
|
|
309
|
+
}
|
|
310
|
+
}, [wsManager]);
|
|
311
|
+
return useMemo(() => ({ loading, error, preview, uninstall }), [
|
|
312
|
+
loading, error, preview, uninstall,
|
|
313
|
+
]);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function usePluginUpdate() {
|
|
317
|
+
const wsManager = useConsoleClient().transport;
|
|
318
|
+
const [loading, setLoading] = useState(false);
|
|
319
|
+
const [error, setError] = useState<string | null>(null);
|
|
320
|
+
const preview = useCallback((packageName: string, targetVersion: string) => {
|
|
321
|
+
setLoading(true);
|
|
322
|
+
setError(null);
|
|
323
|
+
return wsManager.planPluginUpdate(packageName, targetVersion)
|
|
324
|
+
.catch((e) => {
|
|
325
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
326
|
+
throw e;
|
|
327
|
+
})
|
|
328
|
+
.finally(() => setLoading(false));
|
|
329
|
+
}, [wsManager]);
|
|
330
|
+
const update = useCallback((packageName: string, targetVersion: string, expectedRevision?: string) => {
|
|
331
|
+
setLoading(true);
|
|
332
|
+
setError(null);
|
|
333
|
+
return wsManager.updatePlugin(packageName, targetVersion, expectedRevision)
|
|
334
|
+
.catch((e) => {
|
|
335
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
336
|
+
throw e;
|
|
337
|
+
})
|
|
338
|
+
.finally(() => setLoading(false));
|
|
339
|
+
}, [wsManager]);
|
|
340
|
+
return useMemo(() => ({ loading, error, preview, update }), [loading, error, preview, update]);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function useEndpointTest(adapter: string, endpointKey: string) {
|
|
344
|
+
const wsManager = useConsoleClient().transport;
|
|
345
|
+
const [loading, setLoading] = useState(false);
|
|
346
|
+
const [error, setError] = useState<string | null>(null);
|
|
347
|
+
const test = useCallback(async () => {
|
|
348
|
+
setLoading(true);
|
|
349
|
+
setError(null);
|
|
350
|
+
try {
|
|
351
|
+
return await wsManager.testEndpoint(adapter, endpointKey);
|
|
352
|
+
} catch (e) {
|
|
353
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
354
|
+
throw e;
|
|
355
|
+
} finally {
|
|
356
|
+
setLoading(false);
|
|
357
|
+
}
|
|
358
|
+
}, [adapter, endpointKey, wsManager]);
|
|
359
|
+
return useMemo(() => ({ loading, error, test }), [loading, error, test]);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function usePluginMarketplace() {
|
|
363
|
+
const wsManager = useConsoleClient().transport;
|
|
364
|
+
const [loading, setLoading] = useState(false);
|
|
365
|
+
const [error, setError] = useState<string | null>(null);
|
|
366
|
+
const run = useCallback(async <T>(operation: () => Promise<T>) => {
|
|
367
|
+
setLoading(true);
|
|
368
|
+
setError(null);
|
|
369
|
+
try {
|
|
370
|
+
return await operation();
|
|
371
|
+
} catch (e) {
|
|
372
|
+
setError(e instanceof Error ? e.message : 'Unknown error');
|
|
373
|
+
throw e;
|
|
374
|
+
} finally {
|
|
375
|
+
setLoading(false);
|
|
376
|
+
}
|
|
377
|
+
}, []);
|
|
378
|
+
const search = useCallback(
|
|
379
|
+
(query?: Parameters<typeof wsManager.searchMarketplace>[0]) =>
|
|
380
|
+
run(() => wsManager.searchMarketplace(query)),
|
|
381
|
+
[run, wsManager],
|
|
382
|
+
);
|
|
383
|
+
const detail = useCallback(
|
|
384
|
+
(packageName: string) => run(() => wsManager.getMarketplacePlugin(packageName)),
|
|
385
|
+
[run, wsManager],
|
|
386
|
+
);
|
|
387
|
+
const updates = useCallback(() => run(() => wsManager.getPluginUpdates()), [run, wsManager]);
|
|
388
|
+
const installed = useCallback(() => run(() => wsManager.listPlugins()), [run, wsManager]);
|
|
389
|
+
return useMemo(() => ({ loading, error, search, detail, updates, installed }), [
|
|
390
|
+
loading, error, search, detail, updates, installed,
|
|
391
|
+
]);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export function useFiles() {
|
|
395
|
+
const wsManager = useConsoleClient().transport;
|
|
396
|
+
const [connected, setConnected] = useState(wsManager.isConnected());
|
|
397
|
+
const [tree, setTree] = useState<import("./types.js").FileTreeNode[]>([]);
|
|
398
|
+
const [loading, setLoading] = useState(false);
|
|
399
|
+
const [error, setError] = useState<string | null>(null);
|
|
400
|
+
|
|
401
|
+
useEffect(() => wsManager.onConnectionChange(setConnected), [wsManager]);
|
|
402
|
+
|
|
403
|
+
const loadTree = useCallback(async () => {
|
|
404
|
+
setLoading(true);
|
|
405
|
+
setError(null);
|
|
406
|
+
try {
|
|
407
|
+
const result = await wsManager.getFileTree();
|
|
408
|
+
setTree(result.tree);
|
|
409
|
+
return result.tree;
|
|
410
|
+
} catch (e) {
|
|
411
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
412
|
+
throw e;
|
|
413
|
+
} finally {
|
|
414
|
+
setLoading(false);
|
|
415
|
+
}
|
|
416
|
+
}, [wsManager]);
|
|
417
|
+
|
|
418
|
+
const readFile = useCallback(async (filePath: string) => (await wsManager.readFile(filePath)).content, [wsManager]);
|
|
419
|
+
const saveFile = useCallback(
|
|
420
|
+
async (filePath: string, content: string) => wsManager.saveFile(filePath, content),
|
|
421
|
+
[wsManager],
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
useAutoLoadOnce(connected, "file-tree", tree.length > 0 || loading, () => {
|
|
425
|
+
loadTree().catch(() => {});
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
return useMemo(() => ({ tree, loading, error, loadTree, readFile, saveFile }), [tree, loading, error, loadTree, readFile, saveFile]);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export function useEnvFiles() {
|
|
432
|
+
const wsManager = useConsoleClient().transport;
|
|
433
|
+
const [connected, setConnected] = useState(wsManager.isConnected());
|
|
434
|
+
const [files, setFiles] = useState<Array<{ name: string; exists: boolean }>>([]);
|
|
435
|
+
const [loading, setLoading] = useState(false);
|
|
436
|
+
const [error, setError] = useState<string | null>(null);
|
|
437
|
+
|
|
438
|
+
useEffect(() => wsManager.onConnectionChange(setConnected), [wsManager]);
|
|
439
|
+
|
|
440
|
+
const listFiles = useCallback(async () => {
|
|
441
|
+
setLoading(true);
|
|
442
|
+
setError(null);
|
|
443
|
+
try {
|
|
444
|
+
const result = await wsManager.getEnvList();
|
|
445
|
+
setFiles(result.files);
|
|
446
|
+
return result.files;
|
|
447
|
+
} catch (e) {
|
|
448
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
449
|
+
throw e;
|
|
450
|
+
} finally {
|
|
451
|
+
setLoading(false);
|
|
452
|
+
}
|
|
453
|
+
}, [wsManager]);
|
|
454
|
+
|
|
455
|
+
const getFile = useCallback(
|
|
456
|
+
async (filename: string) => {
|
|
457
|
+
const result = await wsManager.getEnvFile(filename);
|
|
458
|
+
return result.content;
|
|
459
|
+
},
|
|
460
|
+
[wsManager],
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
const saveFile = useCallback(
|
|
464
|
+
async (filename: string, content: string) => wsManager.saveEnvFile(filename, content),
|
|
465
|
+
[wsManager],
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
useAutoLoadOnce(connected, "env-files", files.length > 0 || loading, () => {
|
|
469
|
+
listFiles().catch(() => {});
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
return useMemo(
|
|
473
|
+
() => ({ files, loading, error, listFiles, getFile, saveFile }),
|
|
474
|
+
[files, loading, error, listFiles, getFile, saveFile],
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
export function useDatabase() {
|
|
479
|
+
const wsManager = useConsoleClient().transport;
|
|
480
|
+
const [connected, setConnected] = useState(wsManager.isConnected());
|
|
481
|
+
const [info, setInfo] = useState<import("./types.js").DatabaseInfo | null>(null);
|
|
482
|
+
const [tables, setTables] = useState<import("./types.js").TableInfo[]>([]);
|
|
483
|
+
const [loading, setLoading] = useState(false);
|
|
484
|
+
const [error, setError] = useState<string | null>(null);
|
|
485
|
+
|
|
486
|
+
useEffect(() => wsManager.onConnectionChange(setConnected), [wsManager]);
|
|
487
|
+
|
|
488
|
+
const loadInfo = useCallback(async () => {
|
|
489
|
+
setLoading(true);
|
|
490
|
+
try {
|
|
491
|
+
const result = await wsManager.getDbInfo();
|
|
492
|
+
setInfo(result);
|
|
493
|
+
return result;
|
|
494
|
+
} catch (e) {
|
|
495
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
496
|
+
throw e;
|
|
497
|
+
} finally {
|
|
498
|
+
setLoading(false);
|
|
499
|
+
}
|
|
500
|
+
}, [wsManager]);
|
|
501
|
+
|
|
502
|
+
const loadTables = useCallback(async () => {
|
|
503
|
+
setLoading(true);
|
|
504
|
+
try {
|
|
505
|
+
const result = await wsManager.getDbTables();
|
|
506
|
+
setTables(result.tables);
|
|
507
|
+
return result.tables;
|
|
508
|
+
} catch (e) {
|
|
509
|
+
setError(e instanceof Error ? e.message : "Unknown error");
|
|
510
|
+
throw e;
|
|
511
|
+
} finally {
|
|
512
|
+
setLoading(false);
|
|
513
|
+
}
|
|
514
|
+
}, [wsManager]);
|
|
515
|
+
|
|
516
|
+
const select = useCallback(async (table: string, page?: number, pageSize?: number, where?: unknown) => wsManager.dbSelect(table, page, pageSize, where), [wsManager]);
|
|
517
|
+
const insert = useCallback(async (table: string, row: unknown) => wsManager.dbInsert(table, row), [wsManager]);
|
|
518
|
+
const update = useCallback(async (table: string, row: unknown, where: unknown) => wsManager.dbUpdate(table, row, where), [wsManager]);
|
|
519
|
+
const remove = useCallback(async (table: string, where: unknown) => wsManager.dbDelete(table, where), [wsManager]);
|
|
520
|
+
const dropTable = useCallback(async (table: string) => { const r = await wsManager.dbDropTable(table); await loadTables(); return r; }, [wsManager, loadTables]);
|
|
521
|
+
const kvGet = useCallback(async (table: string, key: string) => wsManager.kvGet(table, key), [wsManager]);
|
|
522
|
+
const kvSet = useCallback(async (table: string, key: string, value: unknown, ttl?: number) => wsManager.kvSet(table, key, value, ttl), [wsManager]);
|
|
523
|
+
const kvDelete = useCallback(async (table: string, key: string) => wsManager.kvDelete(table, key), [wsManager]);
|
|
524
|
+
const kvEntries = useCallback(async (table: string) => wsManager.kvGetEntries(table), [wsManager]);
|
|
525
|
+
|
|
526
|
+
useAutoLoadOnce(connected, "db-info", info != null || loading, () => {
|
|
527
|
+
loadInfo().catch(() => {});
|
|
528
|
+
loadTables().catch(() => {});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
return useMemo(
|
|
532
|
+
() => ({ info, tables, loading, error, loadInfo, loadTables, dropTable, select, insert, update, remove, kvGet, kvSet, kvDelete, kvEntries }),
|
|
533
|
+
[info, tables, loading, error, loadInfo, loadTables, dropTable, select, insert, update, remove, kvGet, kvSet, kvDelete, kvEntries],
|
|
534
|
+
);
|
|
535
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export {
|
|
3
|
+
ConsoleTransport,
|
|
4
|
+
type ConsoleEventListener,
|
|
5
|
+
type ConsoleEventRecoveryGap,
|
|
6
|
+
type ConsoleEventRecoveryGapListener,
|
|
7
|
+
} from "./console-transport.js";
|
|
8
|
+
export {
|
|
9
|
+
useConsoleTransport,
|
|
10
|
+
useConfig,
|
|
11
|
+
useConfigSource,
|
|
12
|
+
usePluginInstall,
|
|
13
|
+
usePluginConfigValidation,
|
|
14
|
+
usePluginDiagnostics,
|
|
15
|
+
usePluginLifecycle,
|
|
16
|
+
usePluginUninstall,
|
|
17
|
+
usePluginUpdate,
|
|
18
|
+
useEndpointTest,
|
|
19
|
+
usePluginMarketplace,
|
|
20
|
+
useFiles,
|
|
21
|
+
useEnvFiles,
|
|
22
|
+
useDatabase,
|
|
23
|
+
} from "./hooks.js";
|
|
@@ -1,27 +1,32 @@
|
|
|
1
|
+
import type { ConsoleEventDelivery } from '@zhin.js/console-protocol';
|
|
2
|
+
|
|
1
3
|
export interface BaseMessage {
|
|
2
4
|
type: string;
|
|
3
5
|
timestamp?: number;
|
|
6
|
+
runtimeId?: string;
|
|
7
|
+
eventId?: number;
|
|
8
|
+
delivery?: ConsoleEventDelivery;
|
|
4
9
|
requestId?: number;
|
|
5
10
|
error?: string;
|
|
6
11
|
}
|
|
7
12
|
|
|
8
|
-
export type
|
|
13
|
+
export type ConsoleTransportMessage = BaseMessage & { data?: unknown; [key: string]: unknown };
|
|
9
14
|
|
|
10
|
-
export interface
|
|
11
|
-
|
|
15
|
+
export interface ConsoleTransportConfig {
|
|
16
|
+
fetch?: typeof globalThis.fetch;
|
|
12
17
|
reconnectInterval?: number;
|
|
13
18
|
maxReconnectAttempts?: number;
|
|
14
19
|
requestTimeout?: number;
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
export interface
|
|
22
|
+
export interface ConsoleTransportCallbacks {
|
|
18
23
|
onConnect?: () => void;
|
|
19
24
|
onDisconnect?: () => void;
|
|
20
|
-
onError?: (error:
|
|
21
|
-
onMessage?: (message:
|
|
25
|
+
onError?: (error: Error) => void;
|
|
26
|
+
onMessage?: (message: ConsoleTransportMessage) => void;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
|
-
export interface
|
|
29
|
+
export interface UseConsoleTransportOptions {
|
|
25
30
|
autoConnect?: boolean;
|
|
26
31
|
}
|
|
27
32
|
|
|
@@ -33,30 +38,24 @@ export enum ConnectionState {
|
|
|
33
38
|
ERROR = "error",
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
export class
|
|
41
|
+
export class ConsoleTransportError extends Error {
|
|
37
42
|
constructor(
|
|
38
43
|
message: string,
|
|
39
44
|
public code: string,
|
|
40
45
|
public originalError?: Error,
|
|
41
46
|
) {
|
|
42
47
|
super(message);
|
|
43
|
-
this.name = "
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export class RequestTimeoutError extends WebSocketError {
|
|
48
|
-
constructor(requestId: number) {
|
|
49
|
-
super(`Request ${requestId} timed out`, "REQUEST_TIMEOUT");
|
|
48
|
+
this.name = "ConsoleTransportError";
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
export class ConnectionError extends
|
|
52
|
+
export class ConnectionError extends ConsoleTransportError {
|
|
54
53
|
constructor(message: string, originalError?: Error) {
|
|
55
54
|
super(message, "CONNECTION_ERROR", originalError);
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
export class MessageError extends
|
|
58
|
+
export class MessageError extends ConsoleTransportError {
|
|
60
59
|
constructor(message: string, originalError?: Error) {
|
|
61
60
|
super(message, "MESSAGE_ERROR", originalError);
|
|
62
61
|
}
|
package/client/types.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
// 消息段类型定义 -
|
|
1
|
+
// 消息段类型定义 - 客户端版本(对齐 core Segment SSOT)
|
|
2
2
|
export interface MessageSegment {
|
|
3
|
-
/** record:如 ICQQ
|
|
4
|
-
type: 'text' | '
|
|
5
|
-
data: Record<string,
|
|
3
|
+
/** record:如 ICQQ 语音等,展示时按音频处理;thinking/tool_call 仅 agent 面板展示 */
|
|
4
|
+
type: 'text' | 'mention' | 'at' | 'image' | 'face' | 'video' | 'audio' | 'record' | 'file' | 'reply' | 'forward' | 'keyboard' | 'action' | 'thinking' | 'tool_call' | string
|
|
5
|
+
data: Record<string, unknown>
|
|
6
|
+
platform?: Record<string, unknown>
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
// 消息元素别名(兼容不同命名习惯)
|
|
9
|
-
export type MessageElement = MessageSegment
|
|
10
|
-
|
|
11
9
|
// 发送内容类型
|
|
12
10
|
export type SendContent = MessageSegment | MessageSegment[] | string
|
|
13
|
-
|