@aipanel/provider-deepseek 1.2.8 → 1.2.10

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/system.js CHANGED
@@ -1,22 +1,12 @@
1
- import { spawn } from "child_process";
2
- import { createLogger } from "@aipanel/core/node";
3
- const log = createLogger("DeepSeekSystem");
4
- async function checkDeepSeekInstalled() {
5
- const timer = log.timer("checkDeepSeekInstalled");
6
- return new Promise((resolve) => {
7
- log.debug("Checking if dsh is installed...");
8
- const proc = spawn("dsh", ["--version"], { stdio: "ignore", shell: true });
9
- proc.on("close", (code) => {
10
- const installed = code === 0;
11
- timer.end(installed ? "\u2713 dsh is installed" : "\u274C dsh not found");
12
- resolve(installed);
13
- });
14
- proc.on("error", (err) => {
15
- log.debug("Failed to check dsh installation", { error: err.message });
16
- timer.end("\u274C Check failed");
17
- resolve(false);
18
- });
19
- });
1
+ import { checkCliInstalled, getCliVersion, killOrphanCliProcesses } from "@aipanel/core/node";
2
+ function checkDeepSeekInstalled() {
3
+ return checkCliInstalled("dsh");
4
+ }
5
+ function getDeepSeekVersion() {
6
+ return getCliVersion("dsh");
7
+ }
8
+ function killOrphanDeepSeekProcesses() {
9
+ return killOrphanCliProcesses("dsh", { match: "dsh", winName: "node.exe", label: "dsh" });
20
10
  }
21
11
  const MIN_DSH_VERSION = "0.1.2-rc.1";
22
12
  function parseDshVersion(version) {
@@ -57,151 +47,6 @@ function isDeepSeekVersionAtLeast(version, minimum = MIN_DSH_VERSION) {
57
47
  }
58
48
  return true;
59
49
  }
60
- function getDeepSeekVersion() {
61
- return new Promise((resolve) => {
62
- const proc = spawn("dsh", ["--version"], { stdio: "pipe", shell: true });
63
- let output = "";
64
- proc.stdout?.on("data", (data) => {
65
- output += data.toString();
66
- });
67
- proc.on("close", (code) => {
68
- if (code === 0 && output.trim()) {
69
- resolve(output.trim());
70
- } else {
71
- resolve(null);
72
- }
73
- });
74
- proc.on("error", () => {
75
- resolve(null);
76
- });
77
- });
78
- }
79
- const KILL_ORPHAN_TIMEOUT = 5e3;
80
- async function killOrphanDeepSeekProcesses() {
81
- const timer = log.timer("killOrphanDeepSeekProcesses");
82
- log.debug("Looking for orphan dsh processes (PPID=1)");
83
- return new Promise((resolve) => {
84
- let settled = false;
85
- const done = (count) => {
86
- if (settled) return;
87
- settled = true;
88
- resolve(count);
89
- };
90
- const timeout = setTimeout(() => {
91
- log.warn("Kill orphan processes timed out, skipping");
92
- timer.end("\u26A0 Timeout, skipped");
93
- done(0);
94
- }, KILL_ORPHAN_TIMEOUT);
95
- const wrappedResolve = (count) => {
96
- clearTimeout(timeout);
97
- done(count);
98
- };
99
- if (process.platform === "win32") {
100
- killOrphanProcessesOnWindows(wrappedResolve, timer);
101
- } else {
102
- killOrphanProcessesOnUnix(wrappedResolve, timer);
103
- }
104
- });
105
- }
106
- function killOrphanProcessesOnWindows(resolve, timer) {
107
- log.debug("Using Windows method to find orphan processes");
108
- const proc = spawn(
109
- "wmic",
110
- ["process", "where", 'name="node.exe"', "get", "processid,parentprocessid,commandline"],
111
- { stdio: "pipe" }
112
- );
113
- let output = "";
114
- proc.stdout?.on("data", (data) => {
115
- output += data.toString();
116
- });
117
- proc.on("close", () => {
118
- const pidsToKill = [];
119
- output.split("\n").forEach((rawLine) => {
120
- const line = rawLine.trim();
121
- if (!line.includes("dsh")) return;
122
- const parts = line.trim().split(/\s+/);
123
- if (parts.length >= 2) {
124
- const ppid = parts[0];
125
- const pid = parts[1];
126
- if (ppid === "1" && pid && !isNaN(Number(pid))) {
127
- pidsToKill.push(pid);
128
- }
129
- }
130
- });
131
- if (pidsToKill.length > 0) {
132
- log.debug(`Found ${pidsToKill.length} orphan processes`, { pids: pidsToKill });
133
- let killedCount = 0;
134
- let completedCount = 0;
135
- pidsToKill.forEach((pid) => {
136
- const killProc = spawn("taskkill", ["/F", "/PID", pid], { stdio: "ignore" });
137
- killProc.on("close", (code) => {
138
- completedCount++;
139
- if (code === 0) killedCount++;
140
- if (completedCount === pidsToKill.length) {
141
- timer.end(`\u2713 Killed ${killedCount} orphan processes`);
142
- resolve(killedCount);
143
- }
144
- });
145
- });
146
- } else {
147
- log.debug("No orphan processes found");
148
- timer.end("No orphan processes found");
149
- resolve(0);
150
- }
151
- });
152
- proc.on("error", (err) => {
153
- log.debug("Failed to find orphan processes", { error: err.message });
154
- timer.end("\u274C Failed to find orphan processes");
155
- resolve(0);
156
- });
157
- }
158
- function killOrphanProcessesOnUnix(resolve, timer) {
159
- log.debug("Using Unix method to find orphan processes");
160
- const proc = spawn("ps", ["-e", "-o", "pid,ppid,args"], { stdio: "pipe" });
161
- let output = "";
162
- proc.stdout?.on("data", (data) => {
163
- output += data.toString();
164
- });
165
- proc.on("close", () => {
166
- const lines = output.split("\n");
167
- const pidsToKill = [];
168
- lines.forEach((line) => {
169
- if (!line.includes("dsh")) return;
170
- const parts = line.trim().split(/\s+/);
171
- if (parts.length >= 3) {
172
- const pid = parts[0];
173
- const ppid = parts[1];
174
- if (ppid === "1") {
175
- pidsToKill.push(pid);
176
- }
177
- }
178
- });
179
- if (pidsToKill.length > 0) {
180
- log.debug(`Found ${pidsToKill.length} orphan processes`, { pids: pidsToKill });
181
- const killProc = spawn("kill", ["-9", ...pidsToKill], { stdio: "ignore" });
182
- killProc.on("close", (code) => {
183
- const killedCount = code === 0 ? pidsToKill.length : 0;
184
- timer.end(
185
- killedCount > 0 ? `\u2713 Killed ${killedCount} orphan processes` : "\u274C Failed to kill processes"
186
- );
187
- resolve(killedCount);
188
- });
189
- killProc.on("error", () => {
190
- timer.end("\u274C Failed to kill processes");
191
- resolve(0);
192
- });
193
- } else {
194
- log.debug("No orphan processes found");
195
- timer.end("No orphan processes found");
196
- resolve(0);
197
- }
198
- });
199
- proc.on("error", (err) => {
200
- log.debug("Failed to find orphan processes", { error: err.message });
201
- timer.end("\u274C Failed to find orphan processes");
202
- resolve(0);
203
- });
204
- }
205
50
  export {
206
51
  MIN_DSH_VERSION,
207
52
  checkDeepSeekInstalled,
package/lib/api.cjs CHANGED
@@ -180,11 +180,9 @@ class DeepSeekAPI {
180
180
  * sessionId === activeSessionId(当前选中会话,对应 UI 的 New Session 占位行)时展示。
181
181
  */
182
182
  async listSessions(projectDir, activeSessionId, retries = import_core.DEFAULT_RETRIES) {
183
- const timer = log.timer("listSessions", { projectDir, activeSessionId, retries });
184
- let lastError = null;
185
- for (let i = 0; i < retries; i++) {
186
- try {
187
- log.debug(`Attempt ${i + 1}/${retries}`, { method: "session/list", projectDir });
183
+ return (0, import_core.withRetries)(
184
+ async (attempt) => {
185
+ log.debug(`Attempt ${attempt + 1}/${retries}`, { method: "listSessions" });
188
186
  const workspaces = await this.fetchWorkspaceBaseline();
189
187
  const matchedWorkspace = workspaces.items.find((w) => w.path === projectDir);
190
188
  const ownedByWorkspace = new Set(matchedWorkspace?.sessionIds ?? []);
@@ -200,105 +198,54 @@ class DeepSeekAPI {
200
198
  return false;
201
199
  });
202
200
  const result = filtered.sort((a, b) => b.updatedAt - a.updatedAt);
203
- timer.end(`Found ${result.length} sessions`);
204
201
  return result;
205
- } catch (e) {
206
- lastError = e instanceof Error ? e : new Error(String(e));
207
- log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, { method: "listSessions" });
208
- if (i < retries - 1) {
209
- await (0, import_core.sleep)(import_core.RETRY_DELAY);
210
- }
202
+ },
203
+ {
204
+ attempts: retries,
205
+ onRetry: (n, e) => log.debug(`Attempt ${n} failed: ${e instanceof Error ? e.message : String(e)}`, {
206
+ method: "listSessions"
207
+ })
211
208
  }
212
- }
213
- timer.end("\u274C All retries exhausted");
214
- throw lastError;
209
+ );
215
210
  }
216
211
  /** 在当前目录下创建会话(dsh 仅返回 { sessionId, agentPreset? },非完整 SessionSummary)。
217
212
  * 与旧逻辑一致:先确保 projectDir 对应的 workspace 存在(workspace/create 幂等 get-or-create),
218
213
  * 再用 workspaceId 调 session/create,让新会话挂到该 workspace。 */
219
214
  async createSession(projectDir, retries = import_core.DEFAULT_RETRIES) {
220
- const timer = log.timer("createSession", { projectDir, retries });
221
- let lastError = null;
222
- for (let i = 0; i < retries; i++) {
223
- try {
224
- log.debug(`Attempt ${i + 1}/${retries}`, {
225
- method: "session/create",
226
- projectDir
227
- });
215
+ return (0, import_core.withRetries)(
216
+ async (attempt) => {
217
+ log.debug(`Attempt ${attempt + 1}/${retries}`, { method: "createSession" });
228
218
  const { workspace } = await this.call("workspace/create", {
229
219
  request: { path: projectDir }
230
220
  });
231
221
  const session = await this.call("session/create", {
232
222
  request: { workspaceId: workspace.workspaceId }
233
223
  });
234
- timer.end(`Created session: ${session.sessionId}`);
235
224
  return session;
236
- } catch (e) {
237
- lastError = e instanceof Error ? e : new Error(String(e));
238
- log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, { method: "createSession" });
239
- if (i < retries - 1) {
240
- await (0, import_core.sleep)(import_core.RETRY_DELAY);
241
- }
242
- }
243
- }
244
- timer.end("\u274C All retries exhausted");
245
- throw lastError;
246
- }
247
- /**
248
- * 通过 dsh settings/mutate 应用 providerOptions 指定的用户设置(逐命名空间幂等 patch)。
249
- * dsh 启动初期 API 未就绪,整体带重试;单个命名空间不存在会导致该次调用失败重试。
250
- */
251
- async applySettings(sections, retries = import_core.DEFAULT_RETRIES) {
252
- const namespaces = Object.keys(sections);
253
- if (namespaces.length === 0) return;
254
- const timer = log.timer("applySettings", { namespaces });
255
- let lastError = null;
256
- for (let i = 0; i < retries; i++) {
257
- try {
258
- log.debug(`Attempt ${i + 1}/${retries}`, { method: "settings/mutate", namespaces });
259
- for (const [ns, patch] of Object.entries(sections)) {
260
- const ops = Object.entries(patch).map(([key, value]) => ({
261
- op: "set",
262
- path: [key],
263
- value
264
- }));
265
- await this.call("settings/mutate", { ns, ops });
266
- }
267
- timer.end(`Applied settings: ${namespaces.join(", ")}`);
268
- return;
269
- } catch (e) {
270
- lastError = e instanceof Error ? e : new Error(String(e));
271
- log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, { method: "applySettings" });
272
- if (i < retries - 1) {
273
- await (0, import_core.sleep)(import_core.RETRY_DELAY);
274
- }
225
+ },
226
+ {
227
+ attempts: retries,
228
+ onRetry: (n, e) => log.debug(`Attempt ${n} failed: ${e instanceof Error ? e.message : String(e)}`, {
229
+ method: "createSession"
230
+ })
275
231
  }
276
- }
277
- timer.end("\u274C All retries exhausted");
278
- throw lastError;
232
+ );
279
233
  }
280
234
  /** 归档会话(dsh 无硬删除,仅归档;幂等) */
281
235
  async archiveSession(sessionId, retries = import_core.DEFAULT_RETRIES) {
282
- const timer = log.timer("archiveSession", { sessionId, retries });
283
- let lastError = null;
284
- for (let i = 0; i < retries; i++) {
285
- try {
286
- log.debug(`Attempt ${i + 1}/${retries}`, { method: "workspace/archiveSession" });
236
+ return (0, import_core.withRetries)(
237
+ async (attempt) => {
238
+ log.debug(`Attempt ${attempt + 1}/${retries}`, { method: "archiveSession" });
287
239
  await this.call("workspace/archiveSession", { request: { sessionId } });
288
- timer.end(`Archived session: ${sessionId}`);
289
240
  return;
290
- } catch (e) {
291
- lastError = e instanceof Error ? e : new Error(String(e));
292
- log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
241
+ },
242
+ {
243
+ attempts: retries,
244
+ onRetry: (n, e) => log.debug(`Attempt ${n} failed: ${e instanceof Error ? e.message : String(e)}`, {
293
245
  method: "archiveSession"
294
- });
295
- if (i < retries - 1) {
296
- await (0, import_core.sleep)(import_core.RETRY_DELAY);
297
- }
246
+ })
298
247
  }
299
- }
300
- timer.end("\u274C All retries exhausted");
301
- throw lastError;
248
+ );
302
249
  }
303
250
  /**
304
251
  * 取 workspace/follow 流的 baseline(等价旧 workspace.list 的快照:{ items, archivedSessionIds })。
package/lib/api.d.ts CHANGED
@@ -56,11 +56,6 @@ export declare class DeepSeekAPI {
56
56
  createSession(projectDir: string, retries?: number): Promise<{
57
57
  sessionId: string;
58
58
  }>;
59
- /**
60
- * 通过 dsh settings/mutate 应用 providerOptions 指定的用户设置(逐命名空间幂等 patch)。
61
- * dsh 启动初期 API 未就绪,整体带重试;单个命名空间不存在会导致该次调用失败重试。
62
- */
63
- applySettings(sections: Record<string, Record<string, unknown>>, retries?: number): Promise<void>;
64
59
  /** 归档会话(dsh 无硬删除,仅归档;幂等) */
65
60
  archiveSession(sessionId: string, retries?: number): Promise<void>;
66
61
  /**
package/lib/constants.cjs CHANGED
@@ -21,22 +21,13 @@ __export(constants_exports, {
21
21
  DSH_API_BASE: () => DSH_API_BASE,
22
22
  DSH_DEFAULT_PORT: () => DSH_DEFAULT_PORT,
23
23
  DSH_LOOPBACK_HOST: () => DSH_LOOPBACK_HOST,
24
- DSH_REMOTE_MUX_PATH: () => DSH_REMOTE_MUX_PATH,
25
- DSH_STORAGE_KEYS: () => DSH_STORAGE_KEYS
24
+ DSH_REMOTE_MUX_PATH: () => DSH_REMOTE_MUX_PATH
26
25
  });
27
26
  module.exports = __toCommonJS(constants_exports);
28
27
  const DSH_API_BASE = "/api";
29
28
  const DSH_REMOTE_MUX_PATH = "/api/remote.mux";
30
29
  const DSH_LOOPBACK_HOST = "127.0.0.1";
31
30
  const DSH_DEFAULT_PORT = 3080;
32
- const DSH_STORAGE_KEYS = {
33
- /** 当前选中会话(SPA 启动时据此恢复选中,无 URL 深链) */
34
- CURRENT_SESSION: "dsh.sessions.current",
35
- /** 选中的页面元素(bridge 写入,dsh-client 的 @aipanel source 读取) */
36
- SELECTION: "dsh.bridge.selection",
37
- /** 诊断功能开关标记(bridge 按 provider 配置写入,dsh-client 据此决定是否注册诊断视图) */
38
- DIAGNOSTICS_ENABLED: "dsh.bridge.diagnostics.enabled"
39
- };
40
31
  const DEFAULT_DEEPSEEK_PROVIDER_OPTIONS = {
41
32
  // 对齐 opencode 的 enableLsp(默认 true):诊断功能默认开启
42
33
  enableDiagnostics: true,
@@ -49,6 +40,5 @@ const DEFAULT_DEEPSEEK_PROVIDER_OPTIONS = {
49
40
  DSH_API_BASE,
50
41
  DSH_DEFAULT_PORT,
51
42
  DSH_LOOPBACK_HOST,
52
- DSH_REMOTE_MUX_PATH,
53
- DSH_STORAGE_KEYS
43
+ DSH_REMOTE_MUX_PATH
54
44
  });
@@ -17,14 +17,5 @@ export declare const DSH_REMOTE_MUX_PATH = "/api/remote.mux";
17
17
  export declare const DSH_LOOPBACK_HOST = "127.0.0.1";
18
18
  /** dsh web 默认端口(未显式指定时) */
19
19
  export declare const DSH_DEFAULT_PORT = 3080;
20
- /** ==================== dsh localStorage 键 ==================== */
21
- export declare const DSH_STORAGE_KEYS: {
22
- /** 当前选中会话(SPA 启动时据此恢复选中,无 URL 深链) */
23
- readonly CURRENT_SESSION: "dsh.sessions.current";
24
- /** 选中的页面元素(bridge 写入,dsh-client 的 @aipanel source 读取) */
25
- readonly SELECTION: "dsh.bridge.selection";
26
- /** 诊断功能开关标记(bridge 按 provider 配置写入,dsh-client 据此决定是否注册诊断视图) */
27
- readonly DIAGNOSTICS_ENABLED: "dsh.bridge.diagnostics.enabled";
28
- };
29
20
  /** ==================== Provider 专属配置默认值 ==================== */
30
21
  export declare const DEFAULT_DEEPSEEK_PROVIDER_OPTIONS: DeepSeekProviderOptions;
package/lib/index.cjs CHANGED
@@ -24,7 +24,6 @@ __export(lib_exports, {
24
24
  buildDshOverlay: () => import_profile.buildDshOverlay,
25
25
  checkDeepSeekInstalled: () => import_system.checkDeepSeekInstalled,
26
26
  createProvider: () => createProvider,
27
- generateBridgeScript: () => import_bridge_script.generateBridgeScript,
28
27
  getDeepSeekVersion: () => import_system.getDeepSeekVersion,
29
28
  killOrphanDeepSeekProcesses: () => import_system.killOrphanDeepSeekProcesses,
30
29
  startDeepSeekWeb: () => import_deepseek_web.startDeepSeekWeb,
@@ -36,7 +35,6 @@ var import_constants = require("./constants.cjs");
36
35
  var import_api = require("./api.cjs");
37
36
  var import_deepseek_web = require("./deepseek-web.cjs");
38
37
  var import_profile = require("./profile.cjs");
39
- var import_bridge_script = require("./bridge-script.cjs");
40
38
  var import_system = require("./system.cjs");
41
39
  var import_constants2 = require("./constants.cjs");
42
40
  function createProvider(ctx) {
@@ -55,7 +53,6 @@ function createProvider(ctx) {
55
53
  buildDshOverlay,
56
54
  checkDeepSeekInstalled,
57
55
  createProvider,
58
- generateBridgeScript,
59
56
  getDeepSeekVersion,
60
57
  killOrphanDeepSeekProcesses,
61
58
  startDeepSeekWeb,
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * DeepSeek Harness Web Provider
3
- * 实现 WebProvider 契约:进程管理、RPC 会话 API、桥接脚本、CLI 环境检查。
3
+ * 实现 WebProvider 契约:进程管理、RPC 会话 API、dsh 侧插件编排、CLI 环境检查。
4
4
  * 所有 dsh 专属类型与常量自包含于此包。
5
5
  */
6
6
  import type { ProviderInitContext, WebProvider } from "@aipanel/core";
@@ -10,7 +10,6 @@ export { DeepSeekAPI } from "./api";
10
10
  export type { DeepSeekWebProviderConfig, DeepSeekWebProviderDeps } from "./provider";
11
11
  export { startDeepSeekWeb, type DeepSeekWebOptions } from "./deepseek-web";
12
12
  export { buildDshOverlay, writeDshOverlay } from "./profile";
13
- export { generateBridgeScript, type BridgeScriptOptions } from "./bridge-script";
14
13
  export { checkDeepSeekInstalled, getDeepSeekVersion, killOrphanDeepSeekProcesses } from "./system";
15
14
  export { DEFAULT_DEEPSEEK_PROVIDER_OPTIONS, DSH_LOOPBACK_HOST, DSH_DEFAULT_PORT } from "./constants";
16
15
  export type { DeepSeekProviderOptions, DeepSeekPermissionPreset, DeepSeekBusyEnter, SessionSummary, WorkspaceView, SessionStreamEvent, ServerRequest, ServerResponse, ClientRequest, } from "./types";
package/lib/profile.cjs CHANGED
@@ -34,6 +34,8 @@ module.exports = __toCommonJS(profile_exports);
34
34
  var import_fs = __toESM(require("fs"));
35
35
  var import_path = __toESM(require("path"));
36
36
  var import_node = require("@aipanel/core/node");
37
+ var import_constants = require("./constants.cjs");
38
+ var import_dsh_install = require("./dsh-install.cjs");
37
39
  const log = (0, import_node.createLogger)("DeepSeekProfile");
38
40
  function buildDshOverlay(options) {
39
41
  const {
@@ -43,9 +45,13 @@ function buildDshOverlay(options) {
43
45
  clientAvailable = true,
44
46
  autoDiagnose,
45
47
  enableDiagnostics = true,
46
- eventsToken
48
+ eventsToken,
49
+ agentPreset,
50
+ permissionPreset,
51
+ busyEnter,
52
+ theme = "auto"
47
53
  } = options;
48
- const mcpUrl = `http://127.0.0.1:${vitePort}${import_node.MCP_API_PATH}`;
54
+ const mcpUrl = `http://${import_constants.DSH_LOOPBACK_HOST}:${vitePort}${import_node.MCP_API_PATH}`;
49
55
  const rows = [];
50
56
  rows.push(
51
57
  [
@@ -61,7 +67,7 @@ function buildDshOverlay(options) {
61
67
  rows.push(
62
68
  [
63
69
  " - id: aipanel",
64
- " name: '@aipanel/dsh-plugin'",
70
+ ` name: ${JSON.stringify(import_dsh_install.DSH_PLUGIN_PACKAGE)}`,
65
71
  ...pluginAvailable ? [] : [" disabled: true"],
66
72
  " inject: [tools]",
67
73
  " config:",
@@ -73,14 +79,21 @@ function buildDshOverlay(options) {
73
79
  ...eventsToken ? [
74
80
  ` eventsToken: ${JSON.stringify(eventsToken)}`,
75
81
  ` eventsPath: ${JSON.stringify(import_node.HOST_EVENTS_API_PATH)}`
76
- ] : []
82
+ ] : [],
83
+ // providerOptions → 启动期设置(dsh-plugin/applyProviderSettings 经 ctx.settings 写入)
84
+ ...agentPreset !== void 0 ? [` agentPreset: ${JSON.stringify(agentPreset)}`] : [],
85
+ ...permissionPreset !== void 0 ? [` permissionPreset: ${JSON.stringify(permissionPreset)}`] : [],
86
+ ...busyEnter !== void 0 ? [` busyEnter: ${JSON.stringify(busyEnter)}`] : []
77
87
  ].join("\n")
78
88
  );
79
89
  rows.push(
80
90
  [
81
91
  " - id: aipanel-client",
82
- " name: '@aipanel/dsh-client'",
83
- ...clientAvailable ? [] : [" disabled: true"]
92
+ ` name: ${JSON.stringify(import_dsh_install.DSH_CLIENT_PACKAGE)}`,
93
+ ...clientAvailable ? [] : [" disabled: true"],
94
+ " config:",
95
+ ` enableDiagnostics: ${enableDiagnostics ? "true" : "false"}`,
96
+ ...theme !== "auto" ? [` theme: ${JSON.stringify(theme)}`] : []
84
97
  ].join("\n")
85
98
  );
86
99
  return ["- insert:", rows.join("\n"), ""].join("\n");
package/lib/profile.d.ts CHANGED
@@ -1,10 +1,12 @@
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)。
@@ -14,14 +16,22 @@ export declare function buildDshOverlay(options: {
14
16
  /**
15
17
  * 宿主事件推送令牌(core 每轮启动随机):随 plugin config 注入 dsh-plugin,
16
18
  * 使其把归一化 ProviderEvent POST 到 core 的 HOST_EVENTS_API_PATH。
17
- * 缺省(undefined)时不写该配置行,事件中继不启用(兼容未升级的 dsh-plugin)。
18
19
  */
19
20
  eventsToken?: string;
20
21
  /**
21
22
  * 诊断功能总开关(provider option enableDiagnostics)。
22
- * true(默认,对齐 opencode enableLsp)时 host 插件注册 run_diagnostics 工具与自动诊断逻辑。
23
+ * true(默认,对齐 opencode enableLsp)时 host 插件注册 run_diagnostics 工具与自动诊断逻辑,
24
+ * client 插件注册诊断卡片视图。
23
25
  */
24
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;
25
35
  }): string;
26
36
  /** 将 overlay 写入项目缓存目录(AIPANEL_CACHE_DIR 下按 provider 分二级目录),不污染用户项目根目录。 */
27
37
  export declare function writeDshOverlay(workspaceCwd: string, overlay: string): string;
package/lib/provider.cjs CHANGED
@@ -28,7 +28,6 @@ var import_node = require("@aipanel/core/node");
28
28
  var import_constants = require("./constants.cjs");
29
29
  var import_constants2 = require("./constants.cjs");
30
30
  var import_api = require("./api.cjs");
31
- var import_bridge_script = require("./bridge-script.cjs");
32
31
  var import_deepseek_web = require("./deepseek-web.cjs");
33
32
  var import_profile = require("./profile.cjs");
34
33
  var import_system = require("./system.cjs");
@@ -43,22 +42,17 @@ class DeepSeekWebProvider {
43
42
  __publicField(this, "api");
44
43
  __publicField(this, "deps");
45
44
  __publicField(this, "process", null);
46
- __publicField(this, "bridgeOptions", {});
45
+ /** AIPanel 侧下发的主题偏好(AIPanelWidgetTheme,default auto):随 client 插件 config 注入,作为启动初值 */
46
+ __publicField(this, "uiTheme", "auto");
47
47
  __publicField(this, "opts");
48
48
  this.deps = deps;
49
49
  this.opts = resolveDeepSeekOptions(options);
50
50
  this.api = new import_api.DeepSeekAPI(import_constants2.DSH_LOOPBACK_HOST, deps.getWebPort);
51
51
  }
52
- /** 代理注入到 HTML 的桥接脚本(Provider 资产) */
53
- get bridgeScript() {
54
- return (0, import_bridge_script.generateBridgeScript)(this.bridgeOptions);
55
- }
56
- /** 初始化桥接配置(主题、诊断开关等) */
52
+ /** 记录 AIPanel 侧主题偏好(applyConfig start 前调用;start 时随 client 插件 config 下发) */
57
53
  applyConfig(config) {
58
- this.bridgeOptions = {
59
- theme: config.theme ?? "auto",
60
- diagnosticsEnabled: this.opts.enableDiagnostics ?? false
61
- };
54
+ const t = config.theme;
55
+ this.uiTheme = t === "light" || t === "dark" || t === "auto" ? t : "auto";
62
56
  }
63
57
  async checkEnvironment() {
64
58
  if (!await (0, import_system.checkDeepSeekInstalled)()) {
@@ -119,7 +113,7 @@ Please upgrade:
119
113
  this.opts.home
120
114
  );
121
115
  if (!pluginAvailable) {
122
- log.warn("@aipanel/dsh-plugin unavailable; run_diagnostics & auto-diagnose disabled", {
116
+ log.warn("@aipanel/dsh-plugin unavailable; run_diagnostics & settings application disabled", {
123
117
  metaUrl: import_meta.url
124
118
  });
125
119
  }
@@ -131,7 +125,11 @@ Please upgrade:
131
125
  autoDiagnose: this.opts.autoDiagnose,
132
126
  enableDiagnostics: this.opts.enableDiagnostics,
133
127
  // 宿主事件推送令牌(core 每轮启动随机):随 plugin config 注入 dsh-plugin 用于回推鉴权
134
- eventsToken: options.eventsToken
128
+ eventsToken: options.eventsToken,
129
+ agentPreset: this.opts.agentPreset,
130
+ permissionPreset: this.opts.permissionPreset,
131
+ busyEnter: this.opts.busyEnter,
132
+ theme: this.uiTheme
135
133
  });
136
134
  const patchPath = (0, import_profile.writeDshOverlay)(options.cwd, overlay);
137
135
  const launchToken = new import_deepseek_web.LaunchToken();
@@ -173,37 +171,8 @@ Please upgrade:
173
171
  }
174
172
  );
175
173
  }
176
- const settings = this.buildSettingsToApply();
177
- if (Object.keys(settings).length > 0) {
178
- void this.api.applySettings(settings).catch((e) => {
179
- log.warn("failed to apply provider settings to dsh", {
180
- settings,
181
- error: e instanceof Error ? e.message : String(e)
182
- });
183
- });
184
- }
185
174
  return { url: this.api.shellUrl, processHandle: proc, webAuthCookie };
186
175
  }
187
- /** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
188
- buildSettingsToApply() {
189
- const sections = {};
190
- if (this.opts.agentPreset !== void 0) {
191
- sections["agent-presets"] = { ...sections["agent-presets"], default: this.opts.agentPreset };
192
- }
193
- if (this.opts.permissionPreset !== void 0) {
194
- sections.permission = {
195
- ...sections.permission,
196
- defaultPreset: this.opts.permissionPreset
197
- };
198
- }
199
- if (this.opts.busyEnter !== void 0) {
200
- sections["ui-conversation"] = {
201
- ...sections["ui-conversation"],
202
- busyEnter: this.opts.busyEnter
203
- };
204
- }
205
- return sections;
206
- }
207
176
  async stop() {
208
177
  if (this.process) {
209
178
  log.debug("Killing dsh web process", { pid: this.process.pid });
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,17 +27,14 @@ 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
40
  listSessions(projectDir: string, activeSessionId?: string): Promise<ChatSession[]>;