vite-plugin-aipanel 1.2.7 → 1.2.8
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/es/core/proxy-server.d.ts +7 -0
- package/es/core/proxy-server.mjs +6 -0
- package/es/core/service.d.ts +8 -1
- package/es/core/service.mjs +30 -12
- package/es/endpoints/host-events.d.ts +8 -0
- package/es/endpoints/host-events.mjs +77 -0
- package/es/endpoints/index.mjs +2 -0
- package/es/endpoints/sessions.mjs +3 -1
- package/es/endpoints/start.mjs +1 -1
- package/es/endpoints/types.d.ts +7 -2
- package/es/index.mjs +8 -2
- package/lib/client.js +505 -505
- package/lib/core/proxy-server.cjs +6 -0
- package/lib/core/proxy-server.d.ts +7 -0
- package/lib/core/service.cjs +30 -12
- package/lib/core/service.d.ts +8 -1
- package/lib/endpoints/host-events.cjs +100 -0
- package/lib/endpoints/host-events.d.ts +8 -0
- package/lib/endpoints/index.cjs +2 -0
- package/lib/endpoints/sessions.cjs +3 -1
- package/lib/endpoints/start.cjs +1 -1
- package/lib/endpoints/types.d.ts +7 -2
- package/lib/index.cjs +8 -2
- package/package.json +5 -5
|
@@ -37,6 +37,7 @@ function startProxyServer(targetUrl, port, options = {}) {
|
|
|
37
37
|
return new Promise((resolve, reject) => {
|
|
38
38
|
const target = new URL(targetUrl);
|
|
39
39
|
const bridgeScript = options.bridgeScript ?? "";
|
|
40
|
+
const webAuthCookie = options.webAuthCookie ?? "";
|
|
40
41
|
const agent = new import_http.default.Agent({
|
|
41
42
|
keepAlive: true,
|
|
42
43
|
keepAliveMsecs: 3e4,
|
|
@@ -64,6 +65,9 @@ function startProxyServer(targetUrl, port, options = {}) {
|
|
|
64
65
|
headers: {
|
|
65
66
|
...req.headers,
|
|
66
67
|
host: target.host,
|
|
68
|
+
// 注入 Provider Web 服务的 browser-session 认证 Cookie:代理作为已认证客户端
|
|
69
|
+
// 替 iframe 里的浏览器完成 dsh 0.1.2+ 的会话认证(浏览器无需换取/携带该 Cookie)。
|
|
70
|
+
...webAuthCookie ? { cookie: webAuthCookie } : {},
|
|
67
71
|
// 上游(如 dsh 的 trust fence)校验 Origin 必须匹配自身 origin;
|
|
68
72
|
// 页面经代理访问时浏览器发的 Origin 是代理端口,须改写为目标 origin 否则 403
|
|
69
73
|
origin: `http://${target.host}`,
|
|
@@ -136,6 +140,8 @@ function startProxyServer(targetUrl, port, options = {}) {
|
|
|
136
140
|
headers: {
|
|
137
141
|
...req.headers,
|
|
138
142
|
host: target.host,
|
|
143
|
+
// 与 HTTP 分支一致:注入认证 Cookie,通过 dsh 0.1.2+ 的 browser-auth 门禁
|
|
144
|
+
...webAuthCookie ? { cookie: webAuthCookie } : {},
|
|
139
145
|
// 与 HTTP 分支一致:改写 Origin 为目标 origin,通过 dsh 的 trust fence
|
|
140
146
|
origin: `http://${target.host}`
|
|
141
147
|
}
|
|
@@ -4,6 +4,13 @@ export interface ProxyServerOptions {
|
|
|
4
4
|
bridgeScript?: string;
|
|
5
5
|
/** 绑定地址,需与端口检查使用的地址族一致,避免 IPv4/IPv6 不匹配 */
|
|
6
6
|
hostname?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Provider Web 服务的 browser-session 认证 Cookie(dsh 0.1.2+ 需要)。
|
|
9
|
+
* 代理在转发每个请求(含 WebSocket 升级)时把该 Cookie 注入到上游请求头,
|
|
10
|
+
* 使浏览器免于亲自换取/携带会话 Cookie(避免跨端口/跨站 SameSite 限制),
|
|
11
|
+
* 同时通过上游 /api 的 browser-auth 门禁。
|
|
12
|
+
*/
|
|
13
|
+
webAuthCookie?: string;
|
|
7
14
|
}
|
|
8
15
|
export interface ProxyServerResult {
|
|
9
16
|
server: http.Server;
|
package/lib/core/service.cjs
CHANGED
|
@@ -22,6 +22,7 @@ __export(service_exports, {
|
|
|
22
22
|
AIPanelService: () => AIPanelService
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(service_exports);
|
|
25
|
+
var import_node_crypto = require("node:crypto");
|
|
25
26
|
var import_core = require("@aipanel/core");
|
|
26
27
|
var import_node = require("@aipanel/core/node");
|
|
27
28
|
var import_system = require("../utils/system.cjs");
|
|
@@ -47,6 +48,11 @@ class AIPanelService {
|
|
|
47
48
|
__publicField(this, "mcp", null);
|
|
48
49
|
__publicField(this, "provider", null);
|
|
49
50
|
__publicField(this, "unsubscribeEvents", null);
|
|
51
|
+
/**
|
|
52
|
+
* 宿主事件推送令牌(每轮 start 随机生成)。Provider 侧 Host 插件(dsh-plugin)推送
|
|
53
|
+
* ProviderEvent 时须携带该令牌,core 校验通过后按 SESSION_EVENT 广播给 SSE 客户端。
|
|
54
|
+
*/
|
|
55
|
+
__publicField(this, "eventsToken", null);
|
|
50
56
|
this.actualWebPort = config.webPort;
|
|
51
57
|
this.actualProxyPort = config.proxyPort ?? import_core.DEFAULT_PROXY_PORT;
|
|
52
58
|
}
|
|
@@ -81,6 +87,7 @@ class AIPanelService {
|
|
|
81
87
|
throw new Error("Provider \u672A\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u8C03\u7528 setProvider");
|
|
82
88
|
}
|
|
83
89
|
this.startPromise = (async () => {
|
|
90
|
+
this.eventsToken = (0, import_node_crypto.randomUUID)();
|
|
84
91
|
const timer = log.timer("startServices", {
|
|
85
92
|
corsOrigins,
|
|
86
93
|
contextApiUrl,
|
|
@@ -117,6 +124,7 @@ class AIPanelService {
|
|
|
117
124
|
this.sendTaskUpdate("preparing_runtime");
|
|
118
125
|
this.sendTaskUpdate("starting_web");
|
|
119
126
|
let webUrl;
|
|
127
|
+
let webAuthCookie;
|
|
120
128
|
try {
|
|
121
129
|
const startResult = await provider.start({
|
|
122
130
|
port: this.actualWebPort,
|
|
@@ -127,11 +135,14 @@ class AIPanelService {
|
|
|
127
135
|
contextApiUrl,
|
|
128
136
|
logsApiUrl,
|
|
129
137
|
verbose: this.config.verbose,
|
|
130
|
-
vueDevtoolsApiUrl
|
|
138
|
+
vueDevtoolsApiUrl,
|
|
139
|
+
// 宿主事件推送令牌:provider 将其注入 Host 插件(dsh-plugin)配置,用于回推事件鉴权
|
|
140
|
+
eventsToken: this.eventsToken ?? void 0
|
|
131
141
|
});
|
|
132
142
|
this.webProcess = startResult.processHandle ?? null;
|
|
133
143
|
timer.checkpoint("Web process started");
|
|
134
144
|
webUrl = startResult.url;
|
|
145
|
+
webAuthCookie = startResult.webAuthCookie;
|
|
135
146
|
log.debug(`Waiting for Web UI to become ready at ${webUrl}...`);
|
|
136
147
|
this.sendTaskUpdate("waiting_web_ready");
|
|
137
148
|
await (0, import_system.waitForServer)(webUrl, import_core.SERVER_START_TIMEOUT, this.webProcess ?? void 0);
|
|
@@ -168,7 +179,8 @@ class AIPanelService {
|
|
|
168
179
|
try {
|
|
169
180
|
const result = await (0, import_proxy_server.startProxyServer)(webUrl, this.actualProxyPort, {
|
|
170
181
|
bridgeScript: provider.bridgeScript,
|
|
171
|
-
hostname: this.config.hostname
|
|
182
|
+
hostname: this.config.hostname,
|
|
183
|
+
webAuthCookie
|
|
172
184
|
});
|
|
173
185
|
this.proxyServer = result.server;
|
|
174
186
|
if (result.actualPort !== this.actualProxyPort) {
|
|
@@ -185,7 +197,8 @@ class AIPanelService {
|
|
|
185
197
|
const nextPort = await (0, import_node.findAvailablePort)(this.actualProxyPort + 1, this.config.hostname);
|
|
186
198
|
const result = await (0, import_proxy_server.startProxyServer)(webUrl, nextPort, {
|
|
187
199
|
bridgeScript: provider.bridgeScript,
|
|
188
|
-
hostname: this.config.hostname
|
|
200
|
+
hostname: this.config.hostname,
|
|
201
|
+
webAuthCookie
|
|
189
202
|
});
|
|
190
203
|
this.proxyServer = result.server;
|
|
191
204
|
this.actualProxyPort = result.actualPort;
|
|
@@ -220,15 +233,7 @@ class AIPanelService {
|
|
|
220
233
|
this.isStarted = true;
|
|
221
234
|
this.unsubscribeEvents?.();
|
|
222
235
|
this.unsubscribeEvents = provider.subscribeEvents((event) => {
|
|
223
|
-
this.
|
|
224
|
-
try {
|
|
225
|
-
client.write(`data: ${JSON.stringify({ type: "SESSION_EVENT", event })}
|
|
226
|
-
|
|
227
|
-
`);
|
|
228
|
-
} catch (e) {
|
|
229
|
-
log.debug("Failed to send SESSION_EVENT", { error: e });
|
|
230
|
-
}
|
|
231
|
-
});
|
|
236
|
+
this.pushProviderEvent(event);
|
|
232
237
|
});
|
|
233
238
|
if (warmupFailed) {
|
|
234
239
|
this.sendTaskUpdate("chrome_mcp_failed", {
|
|
@@ -242,6 +247,18 @@ class AIPanelService {
|
|
|
242
247
|
})();
|
|
243
248
|
return this.startPromise;
|
|
244
249
|
}
|
|
250
|
+
/** 把一条 ProviderEvent 广播给所有 SSE 客户端(SESSION_EVENT 载荷) */
|
|
251
|
+
pushProviderEvent(event) {
|
|
252
|
+
this.sseClients.forEach((client) => {
|
|
253
|
+
try {
|
|
254
|
+
client.write(`data: ${JSON.stringify({ type: "SESSION_EVENT", event })}
|
|
255
|
+
|
|
256
|
+
`);
|
|
257
|
+
} catch (e) {
|
|
258
|
+
log.debug("Failed to send SESSION_EVENT", { error: e });
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
245
262
|
async retryWarmupChromeMcp() {
|
|
246
263
|
if (!this.mcp) {
|
|
247
264
|
return { success: false, errorType: "UNKNOWN", errorMessage: "MCP not initialized" };
|
|
@@ -271,6 +288,7 @@ class AIPanelService {
|
|
|
271
288
|
log.info("Stopping Web UI services...");
|
|
272
289
|
this.unsubscribeEvents?.();
|
|
273
290
|
this.unsubscribeEvents = null;
|
|
291
|
+
this.eventsToken = null;
|
|
274
292
|
if (this.proxyServer) {
|
|
275
293
|
log.debug("Closing proxy server");
|
|
276
294
|
this.proxyServer.close();
|
package/lib/core/service.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ResultPromise } from "execa";
|
|
2
2
|
import type http from "http";
|
|
3
|
-
import type { PluginOptions, ServiceStartupTask, WebProvider } from "@aipanel/core";
|
|
3
|
+
import type { PluginOptions, ProviderEvent, ServiceStartupTask, WebProvider } from "@aipanel/core";
|
|
4
4
|
import { ChromeMcpWarmupErrorType } from "@aipanel/core";
|
|
5
5
|
import type { McpProxy } from "./mcp-proxy";
|
|
6
6
|
export declare class AIPanelService {
|
|
@@ -25,11 +25,18 @@ export declare class AIPanelService {
|
|
|
25
25
|
private mcp;
|
|
26
26
|
private provider;
|
|
27
27
|
private unsubscribeEvents;
|
|
28
|
+
/**
|
|
29
|
+
* 宿主事件推送令牌(每轮 start 随机生成)。Provider 侧 Host 插件(dsh-plugin)推送
|
|
30
|
+
* ProviderEvent 时须携带该令牌,core 校验通过后按 SESSION_EVENT 广播给 SSE 客户端。
|
|
31
|
+
*/
|
|
32
|
+
eventsToken: string | null;
|
|
28
33
|
constructor(config: Required<PluginOptions>, sseClients: Set<http.ServerResponse>, onPortAllocated: (port: number) => void, onProxyPortAllocated: (port: number) => void);
|
|
29
34
|
/** 设置 Provider(由编排层动态加载后调用) */
|
|
30
35
|
setProvider(provider: WebProvider): void;
|
|
31
36
|
private sendTaskUpdate;
|
|
32
37
|
start(vitePort: number, corsOrigins: string[], contextApiUrl: string, logsApiUrl: string, viteOrigin: string, mcp: McpProxy, vueDevtoolsApiUrl?: string): Promise<void>;
|
|
38
|
+
/** 把一条 ProviderEvent 广播给所有 SSE 客户端(SESSION_EVENT 载荷) */
|
|
39
|
+
pushProviderEvent(event: ProviderEvent): void;
|
|
33
40
|
retryWarmupChromeMcp(): Promise<{
|
|
34
41
|
success: boolean;
|
|
35
42
|
errorType?: string;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var host_events_exports = {};
|
|
19
|
+
__export(host_events_exports, {
|
|
20
|
+
setupHostEventsEndpoint: () => setupHostEventsEndpoint
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(host_events_exports);
|
|
23
|
+
var import_core = require("@aipanel/core");
|
|
24
|
+
var import_node = require("@aipanel/core/node");
|
|
25
|
+
const log = (0, import_node.createLogger)("Endpoints:HostEvents");
|
|
26
|
+
function setupHostEventsEndpoint(server, ctx) {
|
|
27
|
+
server.middlewares.use(import_core.HOST_EVENTS_API_PATH, async (req, res) => {
|
|
28
|
+
const reqCtx = new import_node.RequestContext(req.method || "GET", import_core.HOST_EVENTS_API_PATH);
|
|
29
|
+
res.setHeader("Content-Type", "application/json");
|
|
30
|
+
if (req.headers.origin) {
|
|
31
|
+
res.writeHead(403);
|
|
32
|
+
res.end(JSON.stringify({ error: "forbidden" }));
|
|
33
|
+
reqCtx.end(403);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (req.method === "OPTIONS") {
|
|
37
|
+
res.writeHead(204);
|
|
38
|
+
res.end();
|
|
39
|
+
reqCtx.end(204);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (req.method !== "POST") {
|
|
43
|
+
res.writeHead(405);
|
|
44
|
+
res.end(JSON.stringify({ error: "method not allowed" }));
|
|
45
|
+
reqCtx.end(405);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let body = "";
|
|
49
|
+
req.on("data", (chunk) => body += chunk.toString());
|
|
50
|
+
req.on("error", () => {
|
|
51
|
+
res.writeHead(400);
|
|
52
|
+
res.end(JSON.stringify({ error: "request error" }));
|
|
53
|
+
reqCtx.end(400);
|
|
54
|
+
});
|
|
55
|
+
req.on("end", () => {
|
|
56
|
+
try {
|
|
57
|
+
const data = JSON.parse(body);
|
|
58
|
+
const expected = ctx.eventsToken;
|
|
59
|
+
if (!expected || data.token !== expected) {
|
|
60
|
+
res.writeHead(403);
|
|
61
|
+
res.end(JSON.stringify({ error: "invalid token" }));
|
|
62
|
+
reqCtx.end(403);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const event = data.event;
|
|
66
|
+
if (!isProviderEvent(event)) {
|
|
67
|
+
res.writeHead(400);
|
|
68
|
+
res.end(JSON.stringify({ error: "invalid event" }));
|
|
69
|
+
reqCtx.end(400);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
ctx.pushProviderEvent(event);
|
|
73
|
+
res.writeHead(200);
|
|
74
|
+
res.end(JSON.stringify({ ok: true }));
|
|
75
|
+
reqCtx.end(200);
|
|
76
|
+
} catch {
|
|
77
|
+
res.writeHead(400);
|
|
78
|
+
res.end(JSON.stringify({ error: "invalid json" }));
|
|
79
|
+
reqCtx.end(400);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function isProviderEvent(value) {
|
|
85
|
+
if (typeof value !== "object" || value === null) return false;
|
|
86
|
+
const v = value;
|
|
87
|
+
if (v.type === "session.status" || v.type === "thinking") {
|
|
88
|
+
return typeof v.sessionId === "string" && v.sessionId.length > 0;
|
|
89
|
+
}
|
|
90
|
+
if (v.type === "session.updated") {
|
|
91
|
+
const s = v.session;
|
|
92
|
+
return typeof s === "object" && s !== null && typeof s.id === "string";
|
|
93
|
+
}
|
|
94
|
+
if (v.type === "connected") return true;
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
98
|
+
0 && (module.exports = {
|
|
99
|
+
setupHostEventsEndpoint
|
|
100
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ViteDevServer } from "vite";
|
|
2
|
+
import type { EndpointContext } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* 宿主侧事件推送端点(dsh-plugin 等 Host 插件 → core → SSE 广播)。
|
|
5
|
+
* 只允许无浏览器 Origin 的服务端请求:携带每轮启动随机令牌(x-aipanel-token 头或 body.token),
|
|
6
|
+
* 通过校验后按 SESSION_EVENT 广播给全部 SSE 客户端(与 provider.subscribeEvents 同一通道)。
|
|
7
|
+
*/
|
|
8
|
+
export declare function setupHostEventsEndpoint(server: ViteDevServer, ctx: EndpointContext): void;
|
package/lib/endpoints/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ var import_widget = require("./widget.cjs");
|
|
|
28
28
|
var import_context = require("./context.cjs");
|
|
29
29
|
var import_start = require("./start.cjs");
|
|
30
30
|
var import_sse = require("./sse.cjs");
|
|
31
|
+
var import_host_events = require("./host-events.cjs");
|
|
31
32
|
var import_sessions = require("./sessions.cjs");
|
|
32
33
|
var import_warmup = require("./warmup.cjs");
|
|
33
34
|
var import_logs = require("./logs.cjs");
|
|
@@ -40,6 +41,7 @@ function setupMiddlewares(server, ctx, mcp, logFiles) {
|
|
|
40
41
|
(0, import_context.setupContextEndpoint)(server, ctx);
|
|
41
42
|
(0, import_start.setupStartEndpoint)(server, ctx);
|
|
42
43
|
(0, import_sse.setupSseEndpoint)(server, ctx);
|
|
44
|
+
(0, import_host_events.setupHostEventsEndpoint)(server, ctx);
|
|
43
45
|
(0, import_sessions.setupSessionsEndpoint)(server, ctx);
|
|
44
46
|
(0, import_warmup.setupWarmupEndpoint)(server, ctx);
|
|
45
47
|
(0, import_logs.setupLogsEndpoint)(server);
|
|
@@ -39,8 +39,10 @@ function setupSessionsEndpoint(server, ctx) {
|
|
|
39
39
|
try {
|
|
40
40
|
if (req.method === "GET") {
|
|
41
41
|
reqCtx.checkpoint("Fetching sessions");
|
|
42
|
+
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
43
|
+
const activeSessionId = url.searchParams.get("current") || void 0;
|
|
42
44
|
const [sessions, capabilities] = await Promise.all([
|
|
43
|
-
ctx.getSessions(),
|
|
45
|
+
ctx.getSessions(activeSessionId),
|
|
44
46
|
ctx.getCapabilities()
|
|
45
47
|
]);
|
|
46
48
|
res.writeHead(200);
|
package/lib/endpoints/start.cjs
CHANGED
|
@@ -24,7 +24,7 @@ var import_core = require("@aipanel/core");
|
|
|
24
24
|
var import_node = require("@aipanel/core/node");
|
|
25
25
|
function setupStartEndpoint(server, ctx) {
|
|
26
26
|
server.middlewares.use(import_core.START_API_PATH, async (_req, res) => {
|
|
27
|
-
const reqCtx = new import_node.RequestContext("GET", import_core.START_API_PATH);
|
|
27
|
+
const reqCtx = new import_node.RequestContext("GET", import_core.START_API_PATH, { quiet: true });
|
|
28
28
|
res.setHeader("Content-Type", "application/json");
|
|
29
29
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
30
30
|
res.writeHead(200);
|
package/lib/endpoints/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatSession, PageContext, ProviderCapabilities, ServiceStartupTask } from "@aipanel/core";
|
|
1
|
+
import type { ChatSession, PageContext, ProviderCapabilities, ProviderEvent, ServiceStartupTask } from "@aipanel/core";
|
|
2
2
|
import type http from "http";
|
|
3
3
|
export interface EndpointContext {
|
|
4
4
|
get webUrl(): string | null;
|
|
@@ -19,11 +19,16 @@ export interface EndpointContext {
|
|
|
19
19
|
get actualProxyPort(): number;
|
|
20
20
|
get actualWebPort(): number;
|
|
21
21
|
get serviceInstanceId(): string;
|
|
22
|
-
|
|
22
|
+
/** 获取会话列表;activeSessionId(当前选中会话)由客户端传入,供 Provider 对齐 UI 可见性规则 */
|
|
23
|
+
getSessions: (activeSessionId?: string) => Promise<ChatSession[]>;
|
|
23
24
|
createSession: () => Promise<ChatSession>;
|
|
24
25
|
deleteSession: (id: string) => Promise<void>;
|
|
25
26
|
/** 获取当前 Provider 能力描述(客户端自适应行为依据) */
|
|
26
27
|
getCapabilities: () => ProviderCapabilities;
|
|
28
|
+
/** 宿主事件推送令牌(Host 插件回推 ProviderEvent 时鉴权用;未启动时 null) */
|
|
29
|
+
get eventsToken(): string | null;
|
|
30
|
+
/** 广播一条 ProviderEvent 给所有 SSE 客户端(SESSION_EVENT 载荷;Host 插件回推与 Provider 订阅共用) */
|
|
31
|
+
pushProviderEvent: (event: ProviderEvent) => void;
|
|
27
32
|
resolveWidgetPath: () => string;
|
|
28
33
|
resolveWidgetStylePath: () => string;
|
|
29
34
|
retryWarmupChromeMcp: () => Promise<{
|
package/lib/index.cjs
CHANGED
|
@@ -180,9 +180,15 @@ function createAIPanelPlugin(options = {}) {
|
|
|
180
180
|
get serviceInstanceId() {
|
|
181
181
|
return serviceInstanceId;
|
|
182
182
|
},
|
|
183
|
-
|
|
183
|
+
get eventsToken() {
|
|
184
|
+
return service.eventsToken;
|
|
185
|
+
},
|
|
186
|
+
pushProviderEvent(event) {
|
|
187
|
+
service.pushProviderEvent(event);
|
|
188
|
+
},
|
|
189
|
+
getSessions: (activeSessionId) => {
|
|
184
190
|
if (!provider) return Promise.reject(new Error("Provider \u672A\u521D\u59CB\u5316"));
|
|
185
|
-
return provider.listSessions(service.workspaceRoot);
|
|
191
|
+
return provider.listSessions(service.workspaceRoot, activeSessionId);
|
|
186
192
|
},
|
|
187
193
|
createSession: () => {
|
|
188
194
|
if (!provider) return Promise.reject(new Error("Provider \u672A\u521D\u59CB\u5316"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-aipanel",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
4
4
|
"description": "Embed OpenCode Web UI in your Vite dev server for real-time code modification and preview",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.cjs",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"execa": "^9.6.1",
|
|
42
42
|
"typescript-language-server": "^5.3.0",
|
|
43
43
|
"unplugin-vue-inspector": "^3.0.0",
|
|
44
|
-
"@aipanel/core": "1.2.
|
|
45
|
-
"@aipanel/provider-opencode": "1.2.
|
|
44
|
+
"@aipanel/core": "1.2.8",
|
|
45
|
+
"@aipanel/provider-opencode": "1.2.8"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"vite": ">=5.0.0",
|
|
49
|
-
"@aipanel/provider-deepseek": "1.2.
|
|
49
|
+
"@aipanel/provider-deepseek": "1.2.8"
|
|
50
50
|
},
|
|
51
51
|
"peerDependenciesMeta": {
|
|
52
52
|
"@aipanel/provider-deepseek": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"sharp": "^0.34.5",
|
|
58
|
-
"@aipanel/client": "1.2.
|
|
58
|
+
"@aipanel/client": "1.2.8"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "pagoda-cli build && vite build -c vite.client.config.ts",
|