@aipanel/provider-deepseek 1.2.0-beta.1 → 1.2.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,21 @@
1
1
  export declare const DSH_CLIENT_PACKAGE = "@aipanel/dsh-client";
2
+ export declare const DSH_PLUGIN_PACKAGE = "@aipanel/dsh-plugin";
2
3
  /**
3
- * 是否为 dev workspace dsh-client 产物就绪(存在 package.json 与 lib/client.js)。
4
- * 生产安装的 provider 在 node_modules/@aipanel/provider-deepseek/ 下,上一级不是 dsh-client,返回 null。
4
+ * 是否为 dev workspace 且某 dsh 包产物就绪(存在 package.json 与产物文件)。
5
+ * 生产安装的 provider 在 node_modules/@aipanel/provider-deepseek/ 下,上一级不是 dsh-*,返回 null。
6
+ * @param metaUrl 调用方 import.meta.url(provider 源码 es/lib 的上一级是 packages/providers/deepseek)
7
+ * @param subdir dev 子目录名("dsh-client" | "dsh-plugin")
8
+ * @param distRel 产物相对路径(client 为 "lib/client.js",plugin 为 "dist/index.js")
5
9
  */
6
- export declare function resolveDevDshClientSource(metaUrl: string): string | null;
10
+ export declare function resolveDevDshPackageSource(metaUrl: string, subdir: string, distRel: string): string | null;
7
11
  /** dsh web profile 目录(固定 --profile web);home 未指定时回退 $DSH_HOME / ~/.dsh */
8
12
  export declare function dshProfileDir(home?: string): string;
9
- /** @aipanel/dsh-client profile 的 node_modules 中是否可解析 */
10
- export declare function isDshClientInstalled(profileDir: string): boolean;
13
+ /** @aipanel/dsh-* 包在 profile 的 node_modules 中是否可解析 */
14
+ export declare function isDshPackageInstalled(profileDir: string, packageName: string): boolean;
11
15
  /**
12
- * 确保 @aipanel/dsh-client 已安装且为最新(官方命令 dsh plugin add)。
16
+ * 确保某 @aipanel/dsh-* 包已安装且为最新(官方命令 dsh plugin add)。
13
17
  * 每次启动都执行(不跳过已安装):dev 本地目录每次重装保证改代码生效,
14
- * 生产 npm 包每次检查 registry 拉取最新版本。安装失败返回 false(不阻塞启动,仅 chip 高亮不可用)。
18
+ * 生产 npm 包每次检查 registry 拉取最新版本。安装失败返回 false(不阻塞启动,
19
+ * 仅对应 overlay 行停用,如失去 chip 高亮 / 审查工具)。
15
20
  */
16
- export declare function ensureDshClient(profileDir: string, target: string, home?: string): Promise<boolean>;
21
+ export declare function ensureDshPackage(profileDir: string, packageName: string, target: string, home?: string): Promise<boolean>;
package/es/dsh-install.js CHANGED
@@ -6,10 +6,14 @@ import { fileURLToPath } from "node:url";
6
6
  import { createLogger } from "@aipanel/core/node";
7
7
  const log = createLogger("DshInstall");
8
8
  const DSH_CLIENT_PACKAGE = "@aipanel/dsh-client";
9
- function resolveDevDshClientSource(metaUrl) {
9
+ const DSH_PLUGIN_PACKAGE = "@aipanel/dsh-plugin";
10
+ function packageJsonIn(profileDir, packageName) {
11
+ return path.join(profileDir, "node_modules", ...packageName.split("/"), "package.json");
12
+ }
13
+ function resolveDevDshPackageSource(metaUrl, subdir, distRel) {
10
14
  const here = path.dirname(fileURLToPath(metaUrl));
11
- const devDir = path.resolve(here, "../dsh-client");
12
- if (fs.existsSync(path.join(devDir, "package.json")) && fs.existsSync(path.join(devDir, "lib/client.js"))) {
15
+ const devDir = path.resolve(here, `../${subdir}`);
16
+ if (fs.existsSync(path.join(devDir, "package.json")) && fs.existsSync(path.join(devDir, distRel))) {
13
17
  return devDir;
14
18
  }
15
19
  return null;
@@ -18,12 +22,10 @@ function dshProfileDir(home) {
18
22
  const resolved = home || process.env.DSH_HOME || path.join(os.homedir(), ".dsh");
19
23
  return path.join(resolved, "profiles", "web");
20
24
  }
21
- function isDshClientInstalled(profileDir) {
22
- return fs.existsSync(
23
- path.join(profileDir, "node_modules", "@aipanel", "dsh-client", "package.json")
24
- );
25
+ function isDshPackageInstalled(profileDir, packageName) {
26
+ return fs.existsSync(packageJsonIn(profileDir, packageName));
25
27
  }
26
- async function ensureDshClient(profileDir, target, home) {
28
+ async function ensureDshPackage(profileDir, packageName, target, home) {
27
29
  try {
28
30
  log.debug(`installing ${target} into dsh profile via dsh plugin add`);
29
31
  await execa("dsh", ["plugin", "--profile", "web", "add", target], {
@@ -34,15 +36,15 @@ async function ensureDshClient(profileDir, target, home) {
34
36
  ...home ? { DSH_HOME: home } : {}
35
37
  }
36
38
  });
37
- if (!isDshClientInstalled(profileDir)) {
38
- log.warn(`dsh plugin add finished but ${DSH_CLIENT_PACKAGE} is not resolvable`, {
39
+ if (!isDshPackageInstalled(profileDir, packageName)) {
40
+ log.warn(`dsh plugin add finished but ${packageName} is not resolvable`, {
39
41
  profileDir
40
42
  });
41
43
  return false;
42
44
  }
43
45
  return true;
44
46
  } catch (e) {
45
- log.warn(`failed to install ${DSH_CLIENT_PACKAGE} via dsh plugin add`, {
47
+ log.warn(`failed to install ${packageName} via dsh plugin add`, {
46
48
  target,
47
49
  error: e instanceof Error ? e.message : String(e)
48
50
  });
@@ -51,8 +53,9 @@ async function ensureDshClient(profileDir, target, home) {
51
53
  }
52
54
  export {
53
55
  DSH_CLIENT_PACKAGE,
56
+ DSH_PLUGIN_PACKAGE,
54
57
  dshProfileDir,
55
- ensureDshClient,
56
- isDshClientInstalled,
57
- resolveDevDshClientSource
58
+ ensureDshPackage,
59
+ isDshPackageInstalled,
60
+ resolveDevDshPackageSource
58
61
  };
package/es/profile.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  export declare function buildDshOverlay(options: {
3
3
  vitePort: number;
4
4
  cwd: string;
5
- pluginDistPath?: string;
6
- /** client 插件是否可被 dsh 解析(provider 已同步到 dsh profile);false 时停用该行,避免 fail-loud */
5
+ /** host 插件(@aipanel/dsh-plugin)是否已被同步到 dsh profile;false 时停用该行,避免 fail-loud */
6
+ pluginAvailable?: boolean;
7
+ /** client 插件(@aipanel/dsh-client)是否可被 dsh 解析(provider 已同步到 dsh profile);false 时停用该行,避免 fail-loud */
7
8
  clientAvailable?: boolean;
8
9
  }): string;
9
- /** 将 overlay 写入项目缓存目录(node_modules/.cache/aipanel,参照 opencode
10
- * node_modules/.cache/opencode 惯例),不污染用户项目根目录。 */
10
+ /** 将 overlay 写入项目缓存目录(AIPANEL_CACHE_DIR 下按 provider 分二级目录),不污染用户项目根目录。 */
11
11
  export declare function writeDshOverlay(workspaceCwd: string, overlay: string): string;
package/es/profile.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { pathToFileURL } from "url";
4
- import { MCP_API_PATH, createLogger } from "@aipanel/core/node";
3
+ import { AIPANEL_CACHE_DIR, MCP_API_PATH, createLogger } from "@aipanel/core/node";
5
4
  const log = createLogger("DeepSeekProfile");
6
5
  function buildDshOverlay(options) {
7
- const { vitePort, cwd, pluginDistPath, clientAvailable = true } = options;
6
+ const { vitePort, cwd, pluginAvailable = true, clientAvailable = true } = options;
8
7
  const mcpUrl = `http://127.0.0.1:${vitePort}${MCP_API_PATH}`;
9
8
  const rows = [];
10
9
  rows.push(
@@ -18,22 +17,17 @@ function buildDshOverlay(options) {
18
17
  " headers: {}"
19
18
  ].join("\n")
20
19
  );
21
- if (pluginDistPath && fs.existsSync(pluginDistPath)) {
22
- const pluginSpec = pathToFileURL(pluginDistPath).href;
23
- log.debug("injecting aipanel host plugin row", { pluginDistPath, pluginSpec });
24
- rows.push(
25
- [
26
- " - id: aipanel",
27
- ` name: '${pluginSpec}'`,
28
- " inject: [tools, subprocess]",
29
- " config:",
30
- ` cwd: ${JSON.stringify(cwd)}`,
31
- " autoDiagnose: true"
32
- ].join("\n")
33
- );
34
- } else {
35
- log.debug("aipanel dsh-plugin dist not found, skipping host plugin row", { pluginDistPath });
36
- }
20
+ rows.push(
21
+ [
22
+ " - id: aipanel",
23
+ " name: '@aipanel/dsh-plugin'",
24
+ ...pluginAvailable ? [] : [" disabled: true"],
25
+ " inject: [tools, subprocess]",
26
+ " config:",
27
+ ` cwd: ${JSON.stringify(cwd)}`,
28
+ " autoDiagnose: true"
29
+ ].join("\n")
30
+ );
37
31
  rows.push(
38
32
  [
39
33
  " - id: aipanel-client",
@@ -44,7 +38,7 @@ function buildDshOverlay(options) {
44
38
  return ["- insert:", rows.join("\n"), ""].join("\n");
45
39
  }
46
40
  function writeDshOverlay(workspaceCwd, overlay) {
47
- const dir = path.join(workspaceCwd, "node_modules", ".cache", "aipanel");
41
+ const dir = path.join(workspaceCwd, AIPANEL_CACHE_DIR, "dsh");
48
42
  fs.mkdirSync(dir, { recursive: true });
49
43
  const file = path.join(dir, "dsh-overlay.cordis.yml");
50
44
  fs.writeFileSync(file, overlay, "utf-8");
package/es/provider.d.ts CHANGED
@@ -36,9 +36,6 @@ export declare class DeepSeekWebProvider implements WebProvider {
36
36
  start(options: ProviderStartOptions): Promise<ProviderStartResult>;
37
37
  /** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
38
38
  private buildSettingsToApply;
39
- /** 解析 aipanel dsh-plugin 的构建产物路径(存在才在 overlay 里注入插件行)。
40
- * 注意用 fileURLToPath:URL.pathname 是 percent-encoded,中文路径下 existsSync 会误判不存在。 */
41
- private resolvePluginDist;
42
39
  stop(): Promise<void>;
43
40
  killOrphans(): Promise<number>;
44
41
  listSessions(projectDir: string): Promise<ChatSession[]>;
package/es/provider.js CHANGED
@@ -1,7 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- import { fileURLToPath } from "node:url";
5
4
  import { createLogger } from "@aipanel/core/node";
6
5
  import { DEFAULT_DEEPSEEK_PROVIDER_OPTIONS } from "./constants.js";
7
6
  import { DSH_LOOPBACK_HOST, DSH_MUX_EVENTS_PATH, DSH_HOST_EVENTS_PATH } from "./constants.js";
@@ -11,10 +10,11 @@ import { startDeepSeekWeb } from "./deepseek-web.js";
11
10
  import { buildDshOverlay, writeDshOverlay } from "./profile.js";
12
11
  import { checkDeepSeekInstalled, getDeepSeekVersion, killOrphanDeepSeekProcesses } from "./system.js";
13
12
  import {
13
+ DSH_CLIENT_PACKAGE,
14
+ DSH_PLUGIN_PACKAGE,
14
15
  dshProfileDir,
15
- ensureDshClient,
16
- resolveDevDshClientSource,
17
- DSH_CLIENT_PACKAGE
16
+ ensureDshPackage,
17
+ resolveDevDshPackageSource
18
18
  } from "./dsh-install.js";
19
19
  const log = createLogger("DeepSeekWebProvider");
20
20
  class DeepSeekWebProvider {
@@ -66,9 +66,11 @@ or run without installing:
66
66
  cwd: options.cwd,
67
67
  vitePort: options.vitePort
68
68
  });
69
- const devClientDir = resolveDevDshClientSource(import.meta.url);
70
- const clientAvailable = await ensureDshClient(
71
- dshProfileDir(this.opts.home),
69
+ const profileDir = dshProfileDir(this.opts.home);
70
+ const devClientDir = resolveDevDshPackageSource(import.meta.url, "dsh-client", "lib/client.js");
71
+ const clientAvailable = await ensureDshPackage(
72
+ profileDir,
73
+ DSH_CLIENT_PACKAGE,
72
74
  devClientDir ?? DSH_CLIENT_PACKAGE,
73
75
  this.opts.home
74
76
  );
@@ -77,10 +79,22 @@ or run without installing:
77
79
  metaUrl: import.meta.url
78
80
  });
79
81
  }
82
+ const devPluginDir = resolveDevDshPackageSource(import.meta.url, "dsh-plugin", "dist/index.js");
83
+ const pluginAvailable = await ensureDshPackage(
84
+ profileDir,
85
+ DSH_PLUGIN_PACKAGE,
86
+ devPluginDir ?? DSH_PLUGIN_PACKAGE,
87
+ this.opts.home
88
+ );
89
+ if (!pluginAvailable) {
90
+ log.warn("@aipanel/dsh-plugin unavailable; run_diagnostics & auto-diagnose disabled", {
91
+ metaUrl: import.meta.url
92
+ });
93
+ }
80
94
  const overlay = buildDshOverlay({
81
95
  vitePort: options.vitePort,
82
96
  cwd: options.cwd,
83
- pluginDistPath: this.resolvePluginDist(),
97
+ pluginAvailable,
84
98
  clientAvailable
85
99
  });
86
100
  const patchPath = writeDshOverlay(options.cwd, overlay);
@@ -124,12 +138,6 @@ or run without installing:
124
138
  }
125
139
  return sections;
126
140
  }
127
- /** 解析 aipanel dsh-plugin 的构建产物路径(存在才在 overlay 里注入插件行)。
128
- * 注意用 fileURLToPath:URL.pathname 是 percent-encoded,中文路径下 existsSync 会误判不存在。 */
129
- resolvePluginDist() {
130
- const fromHere = new URL("../dsh-plugin/dist/index.js", import.meta.url);
131
- return fileURLToPath(fromHere);
132
- }
133
141
  async stop() {
134
142
  if (this.process) {
135
143
  log.debug("Killing dsh web process", { pid: this.process.pid });
@@ -28,10 +28,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
28
28
  var dsh_install_exports = {};
29
29
  __export(dsh_install_exports, {
30
30
  DSH_CLIENT_PACKAGE: () => DSH_CLIENT_PACKAGE,
31
+ DSH_PLUGIN_PACKAGE: () => DSH_PLUGIN_PACKAGE,
31
32
  dshProfileDir: () => dshProfileDir,
32
- ensureDshClient: () => ensureDshClient,
33
- isDshClientInstalled: () => isDshClientInstalled,
34
- resolveDevDshClientSource: () => resolveDevDshClientSource
33
+ ensureDshPackage: () => ensureDshPackage,
34
+ isDshPackageInstalled: () => isDshPackageInstalled,
35
+ resolveDevDshPackageSource: () => resolveDevDshPackageSource
35
36
  });
36
37
  module.exports = __toCommonJS(dsh_install_exports);
37
38
  var import_node_fs = __toESM(require("node:fs"));
@@ -42,10 +43,14 @@ var import_node_url = require("node:url");
42
43
  var import_node = require("@aipanel/core/node");
43
44
  const log = (0, import_node.createLogger)("DshInstall");
44
45
  const DSH_CLIENT_PACKAGE = "@aipanel/dsh-client";
45
- function resolveDevDshClientSource(metaUrl) {
46
+ const DSH_PLUGIN_PACKAGE = "@aipanel/dsh-plugin";
47
+ function packageJsonIn(profileDir, packageName) {
48
+ return import_node_path.default.join(profileDir, "node_modules", ...packageName.split("/"), "package.json");
49
+ }
50
+ function resolveDevDshPackageSource(metaUrl, subdir, distRel) {
46
51
  const here = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(metaUrl));
47
- const devDir = import_node_path.default.resolve(here, "../dsh-client");
48
- if (import_node_fs.default.existsSync(import_node_path.default.join(devDir, "package.json")) && import_node_fs.default.existsSync(import_node_path.default.join(devDir, "lib/client.js"))) {
52
+ const devDir = import_node_path.default.resolve(here, `../${subdir}`);
53
+ if (import_node_fs.default.existsSync(import_node_path.default.join(devDir, "package.json")) && import_node_fs.default.existsSync(import_node_path.default.join(devDir, distRel))) {
49
54
  return devDir;
50
55
  }
51
56
  return null;
@@ -54,12 +59,10 @@ function dshProfileDir(home) {
54
59
  const resolved = home || process.env.DSH_HOME || import_node_path.default.join(import_node_os.default.homedir(), ".dsh");
55
60
  return import_node_path.default.join(resolved, "profiles", "web");
56
61
  }
57
- function isDshClientInstalled(profileDir) {
58
- return import_node_fs.default.existsSync(
59
- import_node_path.default.join(profileDir, "node_modules", "@aipanel", "dsh-client", "package.json")
60
- );
62
+ function isDshPackageInstalled(profileDir, packageName) {
63
+ return import_node_fs.default.existsSync(packageJsonIn(profileDir, packageName));
61
64
  }
62
- async function ensureDshClient(profileDir, target, home) {
65
+ async function ensureDshPackage(profileDir, packageName, target, home) {
63
66
  try {
64
67
  log.debug(`installing ${target} into dsh profile via dsh plugin add`);
65
68
  await (0, import_execa.execa)("dsh", ["plugin", "--profile", "web", "add", target], {
@@ -70,15 +73,15 @@ async function ensureDshClient(profileDir, target, home) {
70
73
  ...home ? { DSH_HOME: home } : {}
71
74
  }
72
75
  });
73
- if (!isDshClientInstalled(profileDir)) {
74
- log.warn(`dsh plugin add finished but ${DSH_CLIENT_PACKAGE} is not resolvable`, {
76
+ if (!isDshPackageInstalled(profileDir, packageName)) {
77
+ log.warn(`dsh plugin add finished but ${packageName} is not resolvable`, {
75
78
  profileDir
76
79
  });
77
80
  return false;
78
81
  }
79
82
  return true;
80
83
  } catch (e) {
81
- log.warn(`failed to install ${DSH_CLIENT_PACKAGE} via dsh plugin add`, {
84
+ log.warn(`failed to install ${packageName} via dsh plugin add`, {
82
85
  target,
83
86
  error: e instanceof Error ? e.message : String(e)
84
87
  });
@@ -88,8 +91,9 @@ async function ensureDshClient(profileDir, target, home) {
88
91
  // Annotate the CommonJS export names for ESM import in node:
89
92
  0 && (module.exports = {
90
93
  DSH_CLIENT_PACKAGE,
94
+ DSH_PLUGIN_PACKAGE,
91
95
  dshProfileDir,
92
- ensureDshClient,
93
- isDshClientInstalled,
94
- resolveDevDshClientSource
96
+ ensureDshPackage,
97
+ isDshPackageInstalled,
98
+ resolveDevDshPackageSource
95
99
  });
@@ -1,16 +1,21 @@
1
1
  export declare const DSH_CLIENT_PACKAGE = "@aipanel/dsh-client";
2
+ export declare const DSH_PLUGIN_PACKAGE = "@aipanel/dsh-plugin";
2
3
  /**
3
- * 是否为 dev workspace dsh-client 产物就绪(存在 package.json 与 lib/client.js)。
4
- * 生产安装的 provider 在 node_modules/@aipanel/provider-deepseek/ 下,上一级不是 dsh-client,返回 null。
4
+ * 是否为 dev workspace 且某 dsh 包产物就绪(存在 package.json 与产物文件)。
5
+ * 生产安装的 provider 在 node_modules/@aipanel/provider-deepseek/ 下,上一级不是 dsh-*,返回 null。
6
+ * @param metaUrl 调用方 import.meta.url(provider 源码 es/lib 的上一级是 packages/providers/deepseek)
7
+ * @param subdir dev 子目录名("dsh-client" | "dsh-plugin")
8
+ * @param distRel 产物相对路径(client 为 "lib/client.js",plugin 为 "dist/index.js")
5
9
  */
6
- export declare function resolveDevDshClientSource(metaUrl: string): string | null;
10
+ export declare function resolveDevDshPackageSource(metaUrl: string, subdir: string, distRel: string): string | null;
7
11
  /** dsh web profile 目录(固定 --profile web);home 未指定时回退 $DSH_HOME / ~/.dsh */
8
12
  export declare function dshProfileDir(home?: string): string;
9
- /** @aipanel/dsh-client profile 的 node_modules 中是否可解析 */
10
- export declare function isDshClientInstalled(profileDir: string): boolean;
13
+ /** @aipanel/dsh-* 包在 profile 的 node_modules 中是否可解析 */
14
+ export declare function isDshPackageInstalled(profileDir: string, packageName: string): boolean;
11
15
  /**
12
- * 确保 @aipanel/dsh-client 已安装且为最新(官方命令 dsh plugin add)。
16
+ * 确保某 @aipanel/dsh-* 包已安装且为最新(官方命令 dsh plugin add)。
13
17
  * 每次启动都执行(不跳过已安装):dev 本地目录每次重装保证改代码生效,
14
- * 生产 npm 包每次检查 registry 拉取最新版本。安装失败返回 false(不阻塞启动,仅 chip 高亮不可用)。
18
+ * 生产 npm 包每次检查 registry 拉取最新版本。安装失败返回 false(不阻塞启动,
19
+ * 仅对应 overlay 行停用,如失去 chip 高亮 / 审查工具)。
15
20
  */
16
- export declare function ensureDshClient(profileDir: string, target: string, home?: string): Promise<boolean>;
21
+ export declare function ensureDshPackage(profileDir: string, packageName: string, target: string, home?: string): Promise<boolean>;
package/lib/profile.cjs CHANGED
@@ -33,11 +33,10 @@ __export(profile_exports, {
33
33
  module.exports = __toCommonJS(profile_exports);
34
34
  var import_fs = __toESM(require("fs"));
35
35
  var import_path = __toESM(require("path"));
36
- var import_url = require("url");
37
36
  var import_node = require("@aipanel/core/node");
38
37
  const log = (0, import_node.createLogger)("DeepSeekProfile");
39
38
  function buildDshOverlay(options) {
40
- const { vitePort, cwd, pluginDistPath, clientAvailable = true } = options;
39
+ const { vitePort, cwd, pluginAvailable = true, clientAvailable = true } = options;
41
40
  const mcpUrl = `http://127.0.0.1:${vitePort}${import_node.MCP_API_PATH}`;
42
41
  const rows = [];
43
42
  rows.push(
@@ -51,22 +50,17 @@ function buildDshOverlay(options) {
51
50
  " headers: {}"
52
51
  ].join("\n")
53
52
  );
54
- if (pluginDistPath && import_fs.default.existsSync(pluginDistPath)) {
55
- const pluginSpec = (0, import_url.pathToFileURL)(pluginDistPath).href;
56
- log.debug("injecting aipanel host plugin row", { pluginDistPath, pluginSpec });
57
- rows.push(
58
- [
59
- " - id: aipanel",
60
- ` name: '${pluginSpec}'`,
61
- " inject: [tools, subprocess]",
62
- " config:",
63
- ` cwd: ${JSON.stringify(cwd)}`,
64
- " autoDiagnose: true"
65
- ].join("\n")
66
- );
67
- } else {
68
- log.debug("aipanel dsh-plugin dist not found, skipping host plugin row", { pluginDistPath });
69
- }
53
+ rows.push(
54
+ [
55
+ " - id: aipanel",
56
+ " name: '@aipanel/dsh-plugin'",
57
+ ...pluginAvailable ? [] : [" disabled: true"],
58
+ " inject: [tools, subprocess]",
59
+ " config:",
60
+ ` cwd: ${JSON.stringify(cwd)}`,
61
+ " autoDiagnose: true"
62
+ ].join("\n")
63
+ );
70
64
  rows.push(
71
65
  [
72
66
  " - id: aipanel-client",
@@ -77,7 +71,7 @@ function buildDshOverlay(options) {
77
71
  return ["- insert:", rows.join("\n"), ""].join("\n");
78
72
  }
79
73
  function writeDshOverlay(workspaceCwd, overlay) {
80
- const dir = import_path.default.join(workspaceCwd, "node_modules", ".cache", "aipanel");
74
+ const dir = import_path.default.join(workspaceCwd, import_node.AIPANEL_CACHE_DIR, "dsh");
81
75
  import_fs.default.mkdirSync(dir, { recursive: true });
82
76
  const file = import_path.default.join(dir, "dsh-overlay.cordis.yml");
83
77
  import_fs.default.writeFileSync(file, overlay, "utf-8");
package/lib/profile.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  export declare function buildDshOverlay(options: {
3
3
  vitePort: number;
4
4
  cwd: string;
5
- pluginDistPath?: string;
6
- /** client 插件是否可被 dsh 解析(provider 已同步到 dsh profile);false 时停用该行,避免 fail-loud */
5
+ /** host 插件(@aipanel/dsh-plugin)是否已被同步到 dsh profile;false 时停用该行,避免 fail-loud */
6
+ pluginAvailable?: boolean;
7
+ /** client 插件(@aipanel/dsh-client)是否可被 dsh 解析(provider 已同步到 dsh profile);false 时停用该行,避免 fail-loud */
7
8
  clientAvailable?: boolean;
8
9
  }): string;
9
- /** 将 overlay 写入项目缓存目录(node_modules/.cache/aipanel,参照 opencode
10
- * node_modules/.cache/opencode 惯例),不污染用户项目根目录。 */
10
+ /** 将 overlay 写入项目缓存目录(AIPANEL_CACHE_DIR 下按 provider 分二级目录),不污染用户项目根目录。 */
11
11
  export declare function writeDshOverlay(workspaceCwd: string, overlay: string): string;
package/lib/provider.cjs CHANGED
@@ -23,7 +23,6 @@ __export(provider_exports, {
23
23
  });
24
24
  module.exports = __toCommonJS(provider_exports);
25
25
  const import_meta = {};
26
- var import_node_url = require("node:url");
27
26
  var import_node = require("@aipanel/core/node");
28
27
  var import_constants = require("./constants.cjs");
29
28
  var import_constants2 = require("./constants.cjs");
@@ -83,9 +82,11 @@ or run without installing:
83
82
  cwd: options.cwd,
84
83
  vitePort: options.vitePort
85
84
  });
86
- const devClientDir = (0, import_dsh_install.resolveDevDshClientSource)(import_meta.url);
87
- const clientAvailable = await (0, import_dsh_install.ensureDshClient)(
88
- (0, import_dsh_install.dshProfileDir)(this.opts.home),
85
+ const profileDir = (0, import_dsh_install.dshProfileDir)(this.opts.home);
86
+ const devClientDir = (0, import_dsh_install.resolveDevDshPackageSource)(import_meta.url, "dsh-client", "lib/client.js");
87
+ const clientAvailable = await (0, import_dsh_install.ensureDshPackage)(
88
+ profileDir,
89
+ import_dsh_install.DSH_CLIENT_PACKAGE,
89
90
  devClientDir ?? import_dsh_install.DSH_CLIENT_PACKAGE,
90
91
  this.opts.home
91
92
  );
@@ -94,10 +95,22 @@ or run without installing:
94
95
  metaUrl: import_meta.url
95
96
  });
96
97
  }
98
+ const devPluginDir = (0, import_dsh_install.resolveDevDshPackageSource)(import_meta.url, "dsh-plugin", "dist/index.js");
99
+ const pluginAvailable = await (0, import_dsh_install.ensureDshPackage)(
100
+ profileDir,
101
+ import_dsh_install.DSH_PLUGIN_PACKAGE,
102
+ devPluginDir ?? import_dsh_install.DSH_PLUGIN_PACKAGE,
103
+ this.opts.home
104
+ );
105
+ if (!pluginAvailable) {
106
+ log.warn("@aipanel/dsh-plugin unavailable; run_diagnostics & auto-diagnose disabled", {
107
+ metaUrl: import_meta.url
108
+ });
109
+ }
97
110
  const overlay = (0, import_profile.buildDshOverlay)({
98
111
  vitePort: options.vitePort,
99
112
  cwd: options.cwd,
100
- pluginDistPath: this.resolvePluginDist(),
113
+ pluginAvailable,
101
114
  clientAvailable
102
115
  });
103
116
  const patchPath = (0, import_profile.writeDshOverlay)(options.cwd, overlay);
@@ -141,12 +154,6 @@ or run without installing:
141
154
  }
142
155
  return sections;
143
156
  }
144
- /** 解析 aipanel dsh-plugin 的构建产物路径(存在才在 overlay 里注入插件行)。
145
- * 注意用 fileURLToPath:URL.pathname 是 percent-encoded,中文路径下 existsSync 会误判不存在。 */
146
- resolvePluginDist() {
147
- const fromHere = new URL("../dsh-plugin/dist/index.js", import_meta.url);
148
- return (0, import_node_url.fileURLToPath)(fromHere);
149
- }
150
157
  async stop() {
151
158
  if (this.process) {
152
159
  log.debug("Killing dsh web process", { pid: this.process.pid });
package/lib/provider.d.ts CHANGED
@@ -36,9 +36,6 @@ export declare class DeepSeekWebProvider implements WebProvider {
36
36
  start(options: ProviderStartOptions): Promise<ProviderStartResult>;
37
37
  /** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
38
38
  private buildSettingsToApply;
39
- /** 解析 aipanel dsh-plugin 的构建产物路径(存在才在 overlay 里注入插件行)。
40
- * 注意用 fileURLToPath:URL.pathname 是 percent-encoded,中文路径下 existsSync 会误判不存在。 */
41
- private resolvePluginDist;
42
39
  stop(): Promise<void>;
43
40
  killOrphans(): Promise<number>;
44
41
  listSessions(projectDir: string): Promise<ChatSession[]>;
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@aipanel/provider-deepseek",
3
- "version": "1.2.0-beta.1",
3
+ "version": "1.2.0-beta.3",
4
4
  "type": "module",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "es/index.js",
7
7
  "types": "es/index.d.ts",
8
8
  "files": [
9
9
  "es",
10
- "lib",
11
- "dsh-plugin/dist"
10
+ "lib"
12
11
  ],
13
12
  "exports": {
14
13
  ".": {
@@ -23,7 +22,7 @@
23
22
  },
24
23
  "dependencies": {
25
24
  "execa": "^9.6.1",
26
- "@aipanel/core": "1.2.0-beta.1"
25
+ "@aipanel/core": "1.2.0-beta.3"
27
26
  },
28
27
  "devDependencies": {
29
28
  "esbuild": "^0.25.0"
@@ -1,110 +0,0 @@
1
- // dsh-plugin/src/index.ts
2
- import path from "node:path";
3
- import {
4
- defineTool
5
- } from "@deepseek-ai/dsh-tools";
6
- import { createUserMessage } from "@deepseek-ai/dsh-llm";
7
- var name = "aipanel";
8
- var inject = ["tools", "subprocess"];
9
- var JS_EXTENSIONS = /* @__PURE__ */ new Set([
10
- ".js",
11
- ".jsx",
12
- ".ts",
13
- ".tsx",
14
- ".mjs",
15
- ".cjs",
16
- ".mts",
17
- ".cts",
18
- ".vue"
19
- ]);
20
- var MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
21
- var STDOUT_MAX_BYTES = 2e5;
22
- var STDOUT_SPILL_MAX_BYTES = 2e6;
23
- var STDERR_MAX_BYTES = 1e5;
24
- var GRACE_MS = 3e4;
25
- function apply(ctx, config = {}) {
26
- const cwd = config.cwd ?? process.cwd();
27
- const autoDiagnose = config.autoDiagnose ?? true;
28
- const tools = ctx.tools;
29
- const subprocess = ctx.subprocess;
30
- async function collectOutput(argv, signal) {
31
- try {
32
- const exe = await subprocess.resolveExecutable("npx", void 0, signal);
33
- const proc = subprocess.spawn({
34
- argv: [exe, ...argv],
35
- cwd,
36
- stdio: {
37
- stdin: "ignore",
38
- stdout: { maxBytes: STDOUT_MAX_BYTES, spill: { maxBytes: STDOUT_SPILL_MAX_BYTES } },
39
- stderr: { maxBytes: STDERR_MAX_BYTES }
40
- },
41
- graceMs: GRACE_MS,
42
- signal
43
- });
44
- await proc.done;
45
- return { text: proc.collected.stdout?.readFrom(0)?.text ?? "" };
46
- } catch (e) {
47
- return { text: "", error: String(e) };
48
- }
49
- }
50
- async function runDiagnostics(filePath, signal) {
51
- const parts = [];
52
- const tsc = await collectOutput(["tsc", "--noEmit", "--pretty", "false"], signal);
53
- if (tsc.error) parts.push("## tsc\n\n(diagnostics skipped: " + tsc.error + ")");
54
- else if (tsc.text.trim()) parts.push("## tsc\n\n" + tsc.text.trim());
55
- const eslint = await collectOutput(["eslint", filePath, "--format", "compact"], signal);
56
- if (eslint.text.trim()) parts.push("## eslint\n\n" + eslint.text.trim());
57
- return parts.join("\n\n");
58
- }
59
- tools.register(
60
- defineTool({
61
- name: "run_diagnostics",
62
- description: "Run ESLint and TypeScript type checks on filePath and report problems. Use after editing code to verify no lint/type errors before proceeding.",
63
- parameters: {
64
- filePath: {
65
- type: "string",
66
- required: true,
67
- description: "Absolute or cwd-relative file path to diagnose"
68
- }
69
- },
70
- output: {
71
- schema: { type: "string" },
72
- render: (_args, value) => [{ type: "text", text: value }]
73
- },
74
- async execute(args, exec) {
75
- return runDiagnostics(path.resolve(cwd, args.filePath), exec.signal).catch(
76
- (e) => "diagnostics failed: " + String(e)
77
- );
78
- }
79
- })
80
- );
81
- ctx.on(
82
- "tools/post-execute",
83
- async (exec, result, next) => {
84
- const decision = await next();
85
- if (!autoDiagnose) return decision;
86
- if (!MUTATING_TOOLS.has(exec.name)) return decision;
87
- if (result.isError) return decision;
88
- if (decision.kind !== "accept") return decision;
89
- const filePath = exec.arguments?.filePath;
90
- if (typeof filePath !== "string" || !filePath) return decision;
91
- if (!JS_EXTENSIONS.has(path.extname(filePath))) return decision;
92
- const diag = await runDiagnostics(path.resolve(cwd, filePath), exec.signal).catch(
93
- () => "diagnostics unavailable"
94
- );
95
- const message = createUserMessage({
96
- content: [
97
- { type: "text", text: `Auto diagnostics after ${exec.name} (${filePath}):
98
- ${diag}` }
99
- ],
100
- source: { kind: "plugin", plugin: name }
101
- });
102
- return { kind: "accept", additionalContexts: [message] };
103
- }
104
- );
105
- }
106
- export {
107
- apply,
108
- inject,
109
- name
110
- };