@aipanel/provider-deepseek 1.2.7 → 1.2.9

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/lib/profile.cjs CHANGED
@@ -42,7 +42,12 @@ function buildDshOverlay(options) {
42
42
  pluginAvailable = true,
43
43
  clientAvailable = true,
44
44
  autoDiagnose,
45
- enableDiagnostics = true
45
+ enableDiagnostics = true,
46
+ eventsToken,
47
+ agentPreset,
48
+ permissionPreset,
49
+ busyEnter,
50
+ theme = "auto"
46
51
  } = options;
47
52
  const mcpUrl = `http://127.0.0.1:${vitePort}${import_node.MCP_API_PATH}`;
48
53
  const rows = [];
@@ -68,14 +73,25 @@ function buildDshOverlay(options) {
68
73
  ` vitePort: ${vitePort}`,
69
74
  ` contextApiPath: ${JSON.stringify(import_node.CONTEXT_API_PATH)}`,
70
75
  ` enableDiagnostics: ${enableDiagnostics ? "true" : "false"}`,
71
- ...autoDiagnose !== void 0 ? [` autoDiagnose: ${autoDiagnose ? "true" : "false"}`] : []
76
+ ...autoDiagnose !== void 0 ? [` autoDiagnose: ${autoDiagnose ? "true" : "false"}`] : [],
77
+ ...eventsToken ? [
78
+ ` eventsToken: ${JSON.stringify(eventsToken)}`,
79
+ ` eventsPath: ${JSON.stringify(import_node.HOST_EVENTS_API_PATH)}`
80
+ ] : [],
81
+ // providerOptions → 启动期设置(dsh-plugin/applyProviderSettings 经 ctx.settings 写入)
82
+ ...agentPreset !== void 0 ? [` agentPreset: ${JSON.stringify(agentPreset)}`] : [],
83
+ ...permissionPreset !== void 0 ? [` permissionPreset: ${JSON.stringify(permissionPreset)}`] : [],
84
+ ...busyEnter !== void 0 ? [` busyEnter: ${JSON.stringify(busyEnter)}`] : []
72
85
  ].join("\n")
73
86
  );
74
87
  rows.push(
75
88
  [
76
89
  " - id: aipanel-client",
77
90
  " name: '@aipanel/dsh-client'",
78
- ...clientAvailable ? [] : [" disabled: true"]
91
+ ...clientAvailable ? [] : [" disabled: true"],
92
+ " config:",
93
+ ` enableDiagnostics: ${enableDiagnostics ? "true" : "false"}`,
94
+ ...theme !== "auto" ? [` theme: ${JSON.stringify(theme)}`] : []
79
95
  ].join("\n")
80
96
  );
81
97
  return ["- insert:", rows.join("\n"), ""].join("\n");
package/lib/profile.d.ts CHANGED
@@ -1,21 +1,37 @@
1
+ import type { AIPanelWidgetTheme } from "@aipanel/core";
2
+ import type { DeepSeekBusyEnter, DeepSeekPermissionPreset } from "./types";
1
3
  /** 组装 overlay YAML */
2
4
  export declare function buildDshOverlay(options: {
3
5
  vitePort: number;
4
6
  cwd: string;
5
- /** host 插件(@aipanel/dsh-plugin)是否已被同步到 dsh profile;false 时停用该行,避免 fail-loud */
7
+ /** host 插件(@aipanel/dsh-plugin)是否已同步到 dsh profile;false 时停用该行,避免 fail-loud */
6
8
  pluginAvailable?: boolean;
7
- /** client 插件(@aipanel/dsh-client)是否可被 dsh 解析(provider 已同步到 dsh profile);false 时停用该行,避免 fail-loud */
9
+ /** client 插件(@aipanel/dsh-client)是否可被 dsh 解析;false 时停用该行,避免 fail-loud */
8
10
  clientAvailable?: boolean;
9
11
  /**
10
12
  * 编辑后自动诊断开关(provider option autoDiagnose)。
11
13
  * undefined 时不写入 overlay,由 dsh-plugin 回退到 OPENCODE_ENABLE_LINT=1(与 opencode 一致)。
12
14
  */
13
15
  autoDiagnose?: boolean;
16
+ /**
17
+ * 宿主事件推送令牌(core 每轮启动随机):随 plugin config 注入 dsh-plugin,
18
+ * 使其把归一化 ProviderEvent POST 到 core 的 HOST_EVENTS_API_PATH。
19
+ */
20
+ eventsToken?: string;
14
21
  /**
15
22
  * 诊断功能总开关(provider option enableDiagnostics)。
16
- * true(默认,对齐 opencode enableLsp)时 host 插件注册 run_diagnostics 工具与自动诊断逻辑。
23
+ * true(默认,对齐 opencode enableLsp)时 host 插件注册 run_diagnostics 工具与自动诊断逻辑,
24
+ * client 插件注册诊断卡片视图。
17
25
  */
18
26
  enableDiagnostics?: boolean;
27
+ /** provider option agentPreset:dsh settings agent-presets.default(随 host 插件 config 下发) */
28
+ agentPreset?: string;
29
+ /** provider option permissionPreset:dsh settings permission.defaultPreset(单一来源 ./types) */
30
+ permissionPreset?: DeepSeekPermissionPreset;
31
+ /** provider option busyEnter:dsh settings ui-conversation.busyEnter(单一来源 ./types) */
32
+ busyEnter?: DeepSeekBusyEnter;
33
+ /** AIPanel 侧主题偏好(applyConfig.theme,AIPanelWidgetTheme);auto 不干预(沿用 dsh 持久化偏好),light/dark 随 client 插件 config 下发 */
34
+ theme?: AIPanelWidgetTheme;
19
35
  }): string;
20
36
  /** 将 overlay 写入项目缓存目录(AIPANEL_CACHE_DIR 下按 provider 分二级目录),不污染用户项目根目录。 */
21
37
  export declare function writeDshOverlay(workspaceCwd: string, overlay: string): string;
package/lib/provider.cjs CHANGED
@@ -23,11 +23,11 @@ __export(provider_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(provider_exports);
25
25
  const import_meta = {};
26
+ var import_core = require("@aipanel/core");
26
27
  var import_node = require("@aipanel/core/node");
27
28
  var import_constants = require("./constants.cjs");
28
29
  var import_constants2 = require("./constants.cjs");
29
30
  var import_api = require("./api.cjs");
30
- var import_bridge_script = require("./bridge-script.cjs");
31
31
  var import_deepseek_web = require("./deepseek-web.cjs");
32
32
  var import_profile = require("./profile.cjs");
33
33
  var import_system = require("./system.cjs");
@@ -42,22 +42,17 @@ class DeepSeekWebProvider {
42
42
  __publicField(this, "api");
43
43
  __publicField(this, "deps");
44
44
  __publicField(this, "process", null);
45
- __publicField(this, "bridgeOptions", {});
45
+ /** AIPanel 侧下发的主题偏好(AIPanelWidgetTheme,default auto):随 client 插件 config 注入,作为启动初值 */
46
+ __publicField(this, "uiTheme", "auto");
46
47
  __publicField(this, "opts");
47
48
  this.deps = deps;
48
49
  this.opts = resolveDeepSeekOptions(options);
49
50
  this.api = new import_api.DeepSeekAPI(import_constants2.DSH_LOOPBACK_HOST, deps.getWebPort);
50
51
  }
51
- /** 代理注入到 HTML 的桥接脚本(Provider 资产) */
52
- get bridgeScript() {
53
- return (0, import_bridge_script.generateBridgeScript)(this.bridgeOptions);
54
- }
55
- /** 初始化桥接配置(主题、诊断开关等) */
52
+ /** 记录 AIPanel 侧主题偏好(applyConfig start 前调用;start 时随 client 插件 config 下发) */
56
53
  applyConfig(config) {
57
- this.bridgeOptions = {
58
- theme: config.theme ?? "auto",
59
- diagnosticsEnabled: this.opts.enableDiagnostics ?? false
60
- };
54
+ const t = config.theme;
55
+ this.uiTheme = t === "light" || t === "dark" || t === "auto" ? t : "auto";
61
56
  }
62
57
  async checkEnvironment() {
63
58
  if (!await (0, import_system.checkDeepSeekInstalled)()) {
@@ -76,6 +71,18 @@ or run without installing:
76
71
  };
77
72
  }
78
73
  const version = await (0, import_system.getDeepSeekVersion)();
74
+ const compatible = version === null ? true : (0, import_system.isDeepSeekVersionAtLeast)(version);
75
+ if (compatible === false) {
76
+ return {
77
+ ok: false,
78
+ message: `DeepSeek Harness (dsh) ${version} is too old: this provider requires dsh >= ${import_system.MIN_DSH_VERSION} (browser-session auth / Remote RPC protocol).
79
+
80
+ Please upgrade:
81
+
82
+ npm install -g @deepseek-ai/dsh@latest
83
+ `
84
+ };
85
+ }
79
86
  return { ok: true, version: version ?? void 0 };
80
87
  }
81
88
  async start(options) {
@@ -106,7 +113,7 @@ or run without installing:
106
113
  this.opts.home
107
114
  );
108
115
  if (!pluginAvailable) {
109
- log.warn("@aipanel/dsh-plugin unavailable; run_diagnostics & auto-diagnose disabled", {
116
+ log.warn("@aipanel/dsh-plugin unavailable; run_diagnostics & settings application disabled", {
110
117
  metaUrl: import_meta.url
111
118
  });
112
119
  }
@@ -116,48 +123,55 @@ or run without installing:
116
123
  pluginAvailable,
117
124
  clientAvailable,
118
125
  autoDiagnose: this.opts.autoDiagnose,
119
- enableDiagnostics: this.opts.enableDiagnostics
126
+ enableDiagnostics: this.opts.enableDiagnostics,
127
+ // 宿主事件推送令牌(core 每轮启动随机):随 plugin config 注入 dsh-plugin 用于回推鉴权
128
+ eventsToken: options.eventsToken,
129
+ agentPreset: this.opts.agentPreset,
130
+ permissionPreset: this.opts.permissionPreset,
131
+ busyEnter: this.opts.busyEnter,
132
+ theme: this.uiTheme
120
133
  });
121
134
  const patchPath = (0, import_profile.writeDshOverlay)(options.cwd, overlay);
135
+ const launchToken = new import_deepseek_web.LaunchToken();
136
+ this.api.setLaunchTokenSource(() => launchToken.wait());
122
137
  const proc = (0, import_deepseek_web.startDeepSeekWeb)({
123
138
  port: options.port,
124
139
  hostname: import_constants2.DSH_LOOPBACK_HOST,
125
140
  cwd: options.cwd,
126
141
  patchPath,
127
142
  home: this.opts.home,
128
- verbose: options.verbose
143
+ verbose: options.verbose,
144
+ launchToken
129
145
  });
130
146
  this.process = proc;
131
- const settings = this.buildSettingsToApply();
132
- if (Object.keys(settings).length > 0) {
133
- void this.api.applySettings(settings).catch((e) => {
134
- log.warn("failed to apply provider settings to dsh", {
135
- settings,
147
+ let webAuthCookie;
148
+ try {
149
+ const token = await launchToken.wait();
150
+ this.api.setLaunchToken(token);
151
+ const maxAuthAttempts = 3;
152
+ for (let attempt = 1; ; attempt++) {
153
+ try {
154
+ await this.api.authenticate();
155
+ break;
156
+ } catch (e) {
157
+ if (attempt >= maxAuthAttempts) throw e;
158
+ log.debug("dsh browser-session auth bootstrap attempt failed, retrying", {
159
+ attempt,
160
+ error: e instanceof Error ? e.message : String(e)
161
+ });
162
+ await (0, import_core.sleep)(250 * attempt);
163
+ }
164
+ }
165
+ webAuthCookie = this.api.getAuthCookie();
166
+ } catch (e) {
167
+ log.warn(
168
+ "failed to establish dsh web browser-session auth; UI may show authentication required",
169
+ {
136
170
  error: e instanceof Error ? e.message : String(e)
137
- });
138
- });
139
- }
140
- return { url: this.api.shellUrl, processHandle: proc };
141
- }
142
- /** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
143
- buildSettingsToApply() {
144
- const sections = {};
145
- if (this.opts.agentPreset !== void 0) {
146
- sections["agent-presets"] = { ...sections["agent-presets"], default: this.opts.agentPreset };
147
- }
148
- if (this.opts.permissionPreset !== void 0) {
149
- sections.permission = {
150
- ...sections.permission,
151
- defaultPreset: this.opts.permissionPreset
152
- };
153
- }
154
- if (this.opts.busyEnter !== void 0) {
155
- sections["ui-conversation"] = {
156
- ...sections["ui-conversation"],
157
- busyEnter: this.opts.busyEnter
158
- };
171
+ }
172
+ );
159
173
  }
160
- return sections;
174
+ return { url: this.api.shellUrl, processHandle: proc, webAuthCookie };
161
175
  }
162
176
  async stop() {
163
177
  if (this.process) {
@@ -169,8 +183,8 @@ or run without installing:
169
183
  async killOrphans() {
170
184
  return (0, import_system.killOrphanDeepSeekProcesses)();
171
185
  }
172
- async listSessions(projectDir) {
173
- const sessions = await this.api.listSessions(projectDir);
186
+ async listSessions(projectDir, activeSessionId) {
187
+ const sessions = await this.api.listSessions(projectDir, activeSessionId);
174
188
  const url = this.buildSessionUrl(projectDir, "");
175
189
  return sessions.map((s) => toChatSession(s, url));
176
190
  }
@@ -195,104 +209,12 @@ or run without installing:
195
209
  return `http://${import_constants2.DSH_LOOPBACK_HOST}:${this.deps.getProxyPort()}/`;
196
210
  }
197
211
  subscribeEvents(handler) {
198
- const port = this.deps.getWebPort();
199
- const base = `ws://${import_constants2.DSH_LOOPBACK_HOST}:${port}`;
200
- const endpoints = [import_constants2.DSH_MUX_EVENTS_PATH, import_constants2.DSH_HOST_EVENTS_PATH];
201
- log.debug("Subscribing to dsh event streams (WebSocket)", {
202
- endpoints: endpoints.map((p) => base + p)
203
- });
204
- let aborted = false;
205
- const sockets = /* @__PURE__ */ new Set();
206
- const retryTimers = /* @__PURE__ */ new Set();
207
- const cleanupAll = () => {
208
- for (const timer of retryTimers) clearTimeout(timer);
209
- retryTimers.clear();
210
- for (const ws of sockets) {
211
- try {
212
- ws.close();
213
- } catch {
214
- }
215
- }
216
- sockets.clear();
217
- };
218
- const connect = (path, attempt = 0) => {
219
- if (aborted) return;
220
- let socket;
221
- try {
222
- socket = new WebSocket(base + path);
223
- } catch (e) {
224
- log.warn("dsh event WebSocket create failed", { path, error: String(e) });
225
- scheduleReconnect(path, attempt + 1);
226
- return;
227
- }
228
- sockets.add(socket);
229
- socket.onmessage = (ev) => {
230
- try {
231
- const frame = JSON.parse(String(ev.data));
232
- const event = mapEvent(frame);
233
- if (event) handler(event);
234
- } catch {
235
- }
236
- };
237
- socket.onclose = () => {
238
- sockets.delete(socket);
239
- scheduleReconnect(path, attempt + 1);
240
- };
241
- socket.onerror = () => {
242
- try {
243
- socket.close();
244
- } catch {
245
- }
246
- };
247
- };
248
- const scheduleReconnect = (path, attempt) => {
249
- if (aborted) return;
250
- const delays = [250, 500, 1e3, 2e3, 5e3];
251
- const after = delays[Math.min(attempt, delays.length - 1)];
252
- const timer = setTimeout(() => {
253
- retryTimers.delete(timer);
254
- connect(path);
255
- }, after);
256
- retryTimers.add(timer);
257
- };
258
- endpoints.forEach((p) => connect(p));
212
+ void handler;
213
+ log.debug("dsh \u4E8B\u4EF6\u7ECF\u5BBF\u4E3B\u63D2\u4EF6(dsh-plugin)\u4E2D\u7EE7\u63A8\u9001\uFF0Cprovider \u76F4\u8FDE\u4E8B\u4EF6\u901A\u9053\u4E3A\u7A7A");
259
214
  return () => {
260
- aborted = true;
261
- cleanupAll();
262
215
  };
263
216
  }
264
217
  }
265
- function mapEvent(frame) {
266
- if (!frame || typeof frame.method !== "string" || !frame.payload) return null;
267
- const payload = frame.payload;
268
- const sessionId = payload.sessionId ?? "";
269
- switch (frame.method) {
270
- case "host/session-status": {
271
- if (!sessionId) return null;
272
- const running = payload.running === true;
273
- return { type: "session.status", sessionId, status: running ? "running" : "idle" };
274
- }
275
- case "session/event": {
276
- const event = payload.event;
277
- const type = event?.type ?? "";
278
- if (!sessionId || !type) return null;
279
- switch (type) {
280
- case "assistant/message":
281
- case "turn/end":
282
- return { type: "thinking", sessionId, thinking: false };
283
- case "assistant/chunk":
284
- case "thinking/delta":
285
- case "turn/start":
286
- case "step/start":
287
- return { type: "thinking", sessionId, thinking: true };
288
- default:
289
- return null;
290
- }
291
- }
292
- default:
293
- return null;
294
- }
295
- }
296
218
  function toChatSession(s, url) {
297
219
  return {
298
220
  id: s.sessionId,
@@ -309,7 +231,7 @@ function resolveDeepSeekOptions(options) {
309
231
  return {
310
232
  ...import_constants.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
311
233
  home: po.home ?? options.home,
312
- agentPreset: po.agentPreset ?? options.agentPreset ?? import_constants.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS.agentPreset,
234
+ agentPreset: po.agentPreset ?? options.agentPreset,
313
235
  permissionPreset: po.permissionPreset ?? options.permissionPreset,
314
236
  busyEnter: po.busyEnter ?? options.busyEnter,
315
237
  autoDiagnose: po.autoDiagnose ?? options.autoDiagnose ?? import_constants.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS.autoDiagnose,
package/lib/provider.d.ts CHANGED
@@ -13,7 +13,9 @@ export interface DeepSeekWebProviderDeps {
13
13
  }
14
14
  /**
15
15
  * DeepSeek Harness Web Provider
16
- * 组合 CLI 进程管理、RPC 会话 API、桥接脚本,向核心层暴露 WebProvider 契约。
16
+ * 组合 CLI 进程管理、RPC 会话 API、dsh 侧插件编排(host 插件 + 浏览器 client 插件),
17
+ * 向核心层暴露 WebProvider 契约。dsh 页内行为(会话聚焦/主题/布局/选中元素)全部
18
+ * 由浏览器插件 @aipanel/dsh-client 承担,不再注入 bridge 脚本。
17
19
  */
18
20
  export declare class DeepSeekWebProvider implements WebProvider {
19
21
  readonly id = "deepseek";
@@ -25,20 +27,17 @@ export declare class DeepSeekWebProvider implements WebProvider {
25
27
  private readonly api;
26
28
  private deps;
27
29
  private process;
28
- private bridgeOptions;
30
+ /** AIPanel 侧下发的主题偏好(AIPanelWidgetTheme,default auto):随 client 插件 config 注入,作为启动初值 */
31
+ private uiTheme;
29
32
  private readonly opts;
30
33
  constructor(config: DeepSeekWebProviderConfig, deps: DeepSeekWebProviderDeps, options?: Record<string, unknown>);
31
- /** 代理注入到 HTML 的桥接脚本(Provider 资产) */
32
- get bridgeScript(): string | undefined;
33
- /** 初始化桥接配置(主题、诊断开关等) */
34
+ /** 记录 AIPanel 侧主题偏好(applyConfig start 前调用;start 时随 client 插件 config 下发) */
34
35
  applyConfig(config: ProviderConfig): void;
35
36
  checkEnvironment(): Promise<ProviderEnvironmentInfo>;
36
37
  start(options: ProviderStartOptions): Promise<ProviderStartResult>;
37
- /** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
38
- private buildSettingsToApply;
39
38
  stop(): Promise<void>;
40
39
  killOrphans(): Promise<number>;
41
- listSessions(projectDir: string): Promise<ChatSession[]>;
40
+ listSessions(projectDir: string, activeSessionId?: string): Promise<ChatSession[]>;
42
41
  createSession(projectDir: string, title?: string): Promise<ChatSession>;
43
42
  deleteSession(sessionId: string): Promise<void>;
44
43
  buildSessionUrl(projectDir: string, sessionId: string): string;
package/lib/system.cjs CHANGED
@@ -17,8 +17,10 @@ var __copyProps = (to, from, except, desc) => {
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
  var system_exports = {};
19
19
  __export(system_exports, {
20
+ MIN_DSH_VERSION: () => MIN_DSH_VERSION,
20
21
  checkDeepSeekInstalled: () => checkDeepSeekInstalled,
21
22
  getDeepSeekVersion: () => getDeepSeekVersion,
23
+ isDeepSeekVersionAtLeast: () => isDeepSeekVersionAtLeast,
22
24
  killOrphanDeepSeekProcesses: () => killOrphanDeepSeekProcesses
23
25
  });
24
26
  module.exports = __toCommonJS(system_exports);
@@ -42,6 +44,45 @@ async function checkDeepSeekInstalled() {
42
44
  });
43
45
  });
44
46
  }
47
+ const MIN_DSH_VERSION = "0.1.2-rc.1";
48
+ function parseDshVersion(version) {
49
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(version.trim());
50
+ if (!match) return null;
51
+ return {
52
+ major: Number(match[1]),
53
+ minor: Number(match[2]),
54
+ patch: Number(match[3]),
55
+ pre: match[4]
56
+ };
57
+ }
58
+ function isDeepSeekVersionAtLeast(version, minimum = MIN_DSH_VERSION) {
59
+ const a = parseDshVersion(version);
60
+ const b = parseDshVersion(minimum);
61
+ if (!a || !b) return null;
62
+ for (const key of ["major", "minor", "patch"]) {
63
+ if (a[key] !== b[key]) return a[key] > b[key];
64
+ }
65
+ if (a.pre === void 0 && b.pre === void 0) return true;
66
+ if (a.pre === void 0) return true;
67
+ if (b.pre === void 0) return false;
68
+ const pa = a.pre.split(".");
69
+ const pb = b.pre.split(".");
70
+ const len = Math.max(pa.length, pb.length);
71
+ for (let i = 0; i < len; i++) {
72
+ const x = pa[i];
73
+ const y = pb[i];
74
+ if (x === void 0) return true;
75
+ if (y === void 0) return false;
76
+ const xn = /^\d+$/.test(x) ? Number(x) : NaN;
77
+ const yn = /^\d+$/.test(y) ? Number(y) : NaN;
78
+ if (!Number.isNaN(xn) && !Number.isNaN(yn)) {
79
+ if (xn !== yn) return xn > yn;
80
+ } else if (x !== y) {
81
+ return x > y;
82
+ }
83
+ }
84
+ return true;
85
+ }
45
86
  function getDeepSeekVersion() {
46
87
  return new Promise((resolve) => {
47
88
  const proc = (0, import_child_process.spawn)("dsh", ["--version"], { stdio: "pipe", shell: true });
@@ -189,7 +230,9 @@ function killOrphanProcessesOnUnix(resolve, timer) {
189
230
  }
190
231
  // Annotate the CommonJS export names for ESM import in node:
191
232
  0 && (module.exports = {
233
+ MIN_DSH_VERSION,
192
234
  checkDeepSeekInstalled,
193
235
  getDeepSeekVersion,
236
+ isDeepSeekVersionAtLeast,
194
237
  killOrphanDeepSeekProcesses
195
238
  });
package/lib/system.d.ts CHANGED
@@ -1,3 +1,10 @@
1
1
  export declare function checkDeepSeekInstalled(): Promise<boolean>;
2
+ /** 本 provider 要求的 dsh 最低版本(0.1.2 起:browser-session 认证 + {args} Remote RPC + remote.mux,协议不向下兼容) */
3
+ export declare const MIN_DSH_VERSION = "0.1.2-rc.1";
4
+ /**
5
+ * 判定 version 是否 >= minimum(semver 风格,含 pre-release 比较:0.1.2 > 0.1.2-rc.1)。
6
+ * @returns true/false;任一版本无法解析时返回 null(调用方按"无法确认"放行)。
7
+ */
8
+ export declare function isDeepSeekVersionAtLeast(version: string, minimum?: string): boolean | null;
2
9
  export declare function getDeepSeekVersion(): Promise<string | null>;
3
10
  export declare function killOrphanDeepSeekProcesses(): Promise<number>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/provider-deepseek",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "type": "module",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "es/index.js",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "execa": "^9.6.1",
25
- "@aipanel/core": "1.2.7"
25
+ "@aipanel/core": "1.2.9"
26
26
  },
27
27
  "devDependencies": {
28
28
  "esbuild": "^0.25.0"
@@ -1,13 +0,0 @@
1
- export interface BridgeScriptOptions {
2
- /** 主题模式 */
3
- theme?: "light" | "dark" | "auto";
4
- /** 诊断功能开关(provider option enableDiagnostics;写入 localStorage 供 dsh-client 决定是否注册诊断视图) */
5
- diagnosticsEnabled?: boolean;
6
- }
7
- /**
8
- * 生成 PostMessage Bridge 脚本。
9
- * dsh 无正式"切换会话"URL 钩子,选中态持久化在 localStorage(CURRENT_SESSION),
10
- * 且 SPA 启动时会据此恢复选中——因此桥接采用"写入选中 + 刷新 iframe"的策略。
11
- * 若 dsh 后续暴露正式切会话接口,可替换以下 FOCUS_SESSION 分支。
12
- */
13
- export declare function generateBridgeScript(options?: BridgeScriptOptions): string;
@@ -1,158 +0,0 @@
1
- import { WIDGET_MSG } from "@aipanel/core";
2
- import { DSH_STORAGE_KEYS } from "./constants.js";
3
- function generateBridgeScript(options = {}) {
4
- const { theme = "auto", diagnosticsEnabled = false } = options;
5
- return `
6
- (function() {
7
- const CURRENT_SESSION_KEY = ${JSON.stringify(DSH_STORAGE_KEYS.CURRENT_SESSION)};
8
- const SELECTION_KEY = ${JSON.stringify(DSH_STORAGE_KEYS.SELECTION)};
9
- const DIAGNOSTICS_KEY = ${JSON.stringify(DSH_STORAGE_KEYS.DIAGNOSTICS_ENABLED)};
10
- const DIAGNOSTICS_ENABLED = ${JSON.stringify(diagnosticsEnabled)};
11
- const THEME = ${JSON.stringify(theme)};
12
-
13
- // \u8BCA\u65AD\u529F\u80FD\u5F00\u5173\uFF1A\u540C\u6B65\u5199\u5165\uFF08\u4E0D\u4F9D\u8D56 DOM\uFF09\uFF0C\u4FDD\u8BC1 dsh-client apply \u65F6\u5373\u53EF\u8BFB\u5230\u6807\u8BB0\u3002
14
- // bridge \u811A\u672C\u6CE8\u5165\u4E8E <head>\uFF0Cdsh-client \u63D2\u4EF6\u5728\u9875\u9762\u811A\u672C/React \u521D\u59CB\u5316\u540E\u624D apply\uFF0C
15
- // \u82E5\u7B49 DOMContentLoaded \u518D\u5199\u5219\u5B58\u5728\u65F6\u5E8F\u7ADE\u4E89\uFF0C\u89C6\u56FE\u53EF\u80FD\u6F0F\u6CE8\u518C\u3002
16
- try {
17
- if (DIAGNOSTICS_ENABLED) {
18
- localStorage.setItem(DIAGNOSTICS_KEY, "1");
19
- } else {
20
- localStorage.removeItem(DIAGNOSTICS_KEY);
21
- }
22
- } catch (e) { /* ignore */ }
23
-
24
- // \u6865\u63A5\u5C42\u901A\u77E5 dsh-client \u7684\u9009\u4E2D\u5143\u7D20\u63D2\u5165\u4E8B\u4EF6\uFF08\u4E0E opencode \u4E00\u81F4\uFF1A\u9009\u4E2D\u5373\u8FFD\u52A0\u5230\u5BF9\u8BDD\u6846\uFF09
25
- const INSERT_ELEMENT_EVENT = "aipanel:insert-element";
26
-
27
- // === \u8BB0\u5F55\u6700\u8FD1\u9009\u4E2D\u5143\u7D20 ===
28
- // \u4F9B dsh-client \u7684 @aipanel source \u4F5C\u4E3A\u5019\u9009\u8BFB\u53D6\uFF08\u53EF\u591A\u9009\uFF0C\u6700\u591A\u4FDD\u7559 20 \u4E2A\uFF09\uFF0C\u5E76\u6D3E\u53D1
29
- // aipanel:insert-element \u8BA9 dsh-client \u7ACB\u5373\u628A\u5143\u7D20\u8FFD\u52A0\u5230\u5F53\u524D\u4F1A\u8BDD\u8F93\u5165\u6846\u3002
30
- function pushSelection(element) {
31
- if (!element) return;
32
- try {
33
- var list = [];
34
- var raw = localStorage.getItem(SELECTION_KEY);
35
- if (raw) list = JSON.parse(raw) || [];
36
- if (!Array.isArray(list)) list = [];
37
- var exists = list.some(function (e) {
38
- return e && e.filePath === element.filePath && e.line === element.line;
39
- });
40
- if (!exists) list.unshift(element);
41
- if (list.length > 20) list.length = 20;
42
- localStorage.setItem(SELECTION_KEY, JSON.stringify(list));
43
- // \u901A\u77E5 dsh-client \u8FFD\u52A0\u5230\u5BF9\u8BDD\u6846\uFF08\u9009\u4E2D\u5373\u63D2\u5165\uFF0C\u65E0\u9700\u518D\u8F93\u5165 @\uFF09
44
- window.dispatchEvent(new CustomEvent(INSERT_ELEMENT_EVENT, {
45
- detail: { element: element }
46
- }));
47
- } catch (e) { /* ignore */ }
48
- }
49
-
50
- // === \u4E3B\u9898\u540C\u6B65\uFF08UI \u5448\u73B0\uFF1B\u6301\u4E45\u5316\u4EA4\u7531 dsh settings\u300Cui-theme.preference\u300D\uFF0C\u4E0D\u5728\u6B64\u5199 localStorage\uFF09===
51
- // dsh \u7684\u6697\u8272\u7531 body[data-ds-dark-theme] + colorScheme \u5448\u73B0\u3002
52
- // \u6CE8\u610F\uFF1Abridge \u53EF\u80FD\u88AB\u6CE8\u5165\u5230 <head>\uFF0C\u6B64\u65F6 document.body \u5C1A\u4E0D\u5B58\u5728\uFF0C\u987B\u5728 DOM ready \u540E\u518D\u6267\u884C\u3002
53
- // theme \u53C2\u6570\uFF1A"light" | "dark" | "auto"\uFF08auto \u4E0D\u5E72\u9884\uFF0C\u4EA4\u7ED9 dsh \u539F\u751F\u4E3B\u9898\u5904\u7406\uFF09\u3002
54
- function applyTheme(theme) {
55
- if (!document.body) return;
56
- if (theme === "dark") {
57
- document.body.setAttribute("data-ds-dark-theme", "");
58
- document.documentElement.style.colorScheme = "dark";
59
- } else if (theme === "light") {
60
- document.body.removeAttribute("data-ds-dark-theme");
61
- document.documentElement.style.colorScheme = "light";
62
- }
63
- }
64
-
65
- // === \u5E03\u5C40\u8986\u76D6 ===
66
- // \u9690\u85CF dsh \u7684\u4FA7\u8FB9\u680F\u5217\uFF0C\u907F\u514D\u4E0E AIPanel \u81EA\u5E26\u4F1A\u8BDD\u5217\u8868\u91CD\u590D\u3002
67
- // \u7A33\u5B9A\u951A\u70B9\uFF1AAppFrame \u6839\u7F51\u683C\u5728\u4FA7\u8FB9\u680F\u6298\u53E0\u65F6\u5E26 data-sidebar-collapsed\uFF08AIPanel \u7A84 iframe \u4E0B\u6052\u5B58\u5728\uFF09\uFF0C
68
- // \u4FA7\u8FB9\u680F\u5217\u662F\u6839\u7F51\u683C\u7684\u9996\u4E2A\u5B50\u5143\u7D20\u3002
69
- // \u6CE8\u610F\u4E0D\u80FD\u53EA display:none \u5143\u7D20\uFF1A\u663E\u5F0F gridTemplateColumns\uFF08\u5185\u8054\u6837\u5F0F\uFF09\u8F68\u9053\u4E0D\u4F1A\u56E0\u5B50\u9879
70
- // \u9690\u85CF\u800C\u6D88\u5931\uFF0C\u4F1A\u7559\u4E00\u6761\u7A7A\u767D\u5217\uFF0C\u987B\u628A\u9996\u5217\u8F68\u9053\u6539\u6210 auto\uFF08\u5B50\u9879\u9690\u85CF\u540E\u574D\u7F29\u4E3A 0\uFF09\u3002
71
- function applyLayoutOverrides() {
72
- try {
73
- if (document.getElementById("aipanel-layout-overrides")) return;
74
- var style = document.createElement("style");
75
- style.id = "aipanel-layout-overrides";
76
- style.textContent = [
77
- "[data-sidebar-collapsed] {",
78
- " grid-template-columns: auto !important;",
79
- "}",
80
- "[data-sidebar-collapsed] > :first-child {",
81
- " display: none !important;",
82
- "}",
83
- '[aria-label="\\u9009\\u62E9\\u5DE5\\u4F5C\\u533A"] {',
84
- " display: none !important;",
85
- "}",
86
- ].join("\\n");
87
- document.head.appendChild(style);
88
- } catch (e) { /* ignore */ }
89
- }
90
-
91
- // === \u6D88\u606F\u76D1\u542C ===
92
- window.addEventListener("message", function(event) {
93
- if (!event.data) return;
94
-
95
- // \u6838\u5FC3\u5C42\u901A\u77E5\uFF1A\u5207\u6362\u4E3B\u9898\uFF08\u5DE5\u5177\u680F\u4E3B\u9898\u6309\u94AE/\u8DDF\u968F\u7CFB\u7EDF\u53D8\u5316\uFF09\u3002\u52A8\u6001\u5E94\u7528\uFF0C\u65E0\u9700\u91CD\u8F7D\u3002
96
- if (event.data.type === ${JSON.stringify(WIDGET_MSG.SET_THEME)}) {
97
- applyTheme(event.data.theme);
98
- }
99
-
100
- // \u6838\u5FC3\u5C42\u901A\u77E5\uFF1A\u805A\u7126\u6307\u5B9A\u4F1A\u8BDD\uFF08\u65E0 deepLink \u6A21\u5F0F\uFF09\u3002
101
- // dsh \u7684\u9009\u4E2D\u6001\u6301\u4E45\u5316\u4E3A JSON.stringify({ sessionId, subagentAddress? })\uFF0CSPA \u542F\u52A8\u65F6\u636E\u6B64\u6062\u590D\u3002
102
- if (event.data.type === ${JSON.stringify(WIDGET_MSG.FOCUS_SESSION)}) {
103
- const sessionId = event.data.sessionId;
104
- if (!sessionId) return;
105
- try {
106
- localStorage.setItem(CURRENT_SESSION_KEY, JSON.stringify({ sessionId }));
107
- } catch (e) {
108
- console.warn("dsh bridge: failed to persist session selection", e);
109
- }
110
- // dsh SPA \u4ECE\u6301\u4E45\u5316\u9009\u4E2D\u6062\u590D\uFF0C\u5237\u65B0\u4EE5\u5207\u6362\u5230\u76EE\u6807\u4F1A\u8BDD
111
- location.reload();
112
- }
113
-
114
- // \u6838\u5FC3\u5C42\u901A\u77E5\uFF1A\u9875\u9762\u9009\u4E2D\u5143\u7D20 \u2192 \u8BB0\u5F55\uFF0C\u4F9B @aipanel \u83DC\u5355\u7B5B\u9009\u540E\u4EE5 reference \u63D2\u5165
115
- if (event.data.type === ${JSON.stringify(WIDGET_MSG.INSERT_FILE_PART)}) {
116
- pushSelection(event.data.element);
117
- }
118
- });
119
-
120
- // === \u5C31\u7EEA\u901A\u77E5 ===
121
- // \u4E0D\u518D\u7528 MutationObserver \u6BCF\u5E27\u53D1 READY\uFF08\u90A3\u4F1A\u5728 dsh \u521A\u6E32\u67D3\u3001\u76EE\u6807\u4F1A\u8BDD\u5C1A\u672A\u6FC0\u6D3B\u65F6\u5C31
122
- // \u63D0\u524D\u653E\u884C loading\uFF09\u3002\u6539\u4E3A\u76D1\u542C dsh-client \u63D2\u4EF6\u5728"\u76EE\u6807\u4F1A\u8BDD\u6FC0\u6D3B\u4E14\u6E32\u67D3\u7A33\u5B9A"\u540E\u6D3E\u53D1\u7684
123
- // aipanel:session-ready \u4E8B\u4EF6\uFF0C\u6536\u5230\u540E\u4E0A\u62A5 SESSION_READY{sessionId}\u3002
124
- // \u53EA\u53D1 SESSION_READY \u800C\u4E0D\u53D1 READY\uFF1A\u5BA2\u6237\u7AEF\u5DF2\u80FD\u51ED sessionId \u5339\u914D\u5F53\u524D\u4F1A\u8BDD\u51B3\u5B9A\u4F55\u65F6
125
- // \u653E\u884C loading / \u8865\u53D1\u805A\u7126\uFF1B\u907F\u514D\u4E0E"FOCUS_SESSION \u2192 reload \u2192 \u518D\u5C31\u7EEA"\u6784\u6210\u5237\u65B0\u6B7B\u5FAA\u73AF\u3002
126
- const SESSION_READY_EVENT = "aipanel:session-ready";
127
-
128
- function sendSessionReady(sessionId) {
129
- if (window.parent !== window) {
130
- window.parent.postMessage({
131
- type: ${JSON.stringify(WIDGET_MSG.SESSION_READY)},
132
- sessionId
133
- }, "*");
134
- }
135
- }
136
-
137
- window.addEventListener(SESSION_READY_EVENT, function(e) {
138
- const sessionId = e && e.detail && e.detail.sessionId;
139
- if (!sessionId) return;
140
- sendSessionReady(sessionId);
141
- });
142
-
143
- // \u4E3B\u9898\u540C\u6B65/\u5E03\u5C40\u8986\u76D6\u4ECD\u987B\u5728\u6BCF\u6B21\u9875\u9762\u52A0\u8F7D\u65F6\u751F\u6548\uFF08\u4E0E\u5C31\u7EEA\u5224\u5B9A\u89E3\u8026\uFF0C\u4E0D\u53C2\u4E0E loading \u653E\u884C\uFF09
144
- function init() {
145
- applyTheme(THEME);
146
- applyLayoutOverrides();
147
- }
148
- if (document.readyState === "loading") {
149
- document.addEventListener("DOMContentLoaded", init);
150
- } else {
151
- init();
152
- }
153
- })();
154
- `;
155
- }
156
- export {
157
- generateBridgeScript
158
- };