dsh-llm-codebuddy 1.3.1 → 1.3.2

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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/cli.js +92 -3
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -27,6 +27,8 @@ DSH WebUI 中填写 API Key、获取模型、调整模型参数并使用 CodeBud
27
27
  - 已安装 DSH;
28
28
  - 已验证 DSH `0.1.0-rc.6`。
29
29
 
30
+ 安装器已自带 DSH 所需的 `pnpm`,无需全局安装。
31
+
30
32
  > DSH 仍处于预发布阶段。未来版本如果调整插件接口,本插件可能需要同步升级;
31
33
  > DSH 普通更新不会覆盖本插件。
32
34
 
package/cli.js CHANGED
@@ -2,12 +2,15 @@
2
2
 
3
3
  import { copyFileSync, existsSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { homedir, tmpdir } from "node:os";
5
- import { dirname, join, resolve } from "node:path";
5
+ import { createRequire } from "node:module";
6
+ import { delimiter, dirname, join, resolve } from "node:path";
6
7
  import { spawnSync } from "node:child_process";
7
8
  import { parseDocument } from "yaml";
8
9
 
9
10
  const PACKAGE = "dsh-llm-codebuddy";
10
11
  const PROVIDER_PATH = ["llm-pi-ai", "providers", "codebuddy-cn"];
12
+ const IGNORED_BUILDS = ["@google/genai", "protobufjs"];
13
+ const require = createRequire(import.meta.url);
11
14
 
12
15
  function dshHome() {
13
16
  return resolve(process.env.DSH_HOME || join(homedir(), ".dsh"));
@@ -20,15 +23,74 @@ function profileHasPlugin(home, profile) {
20
23
  return Boolean(json.dependencies?.[PACKAGE] || json.devDependencies?.[PACKAGE]);
21
24
  }
22
25
 
26
+ function dshEnv() {
27
+ const pnpmPackageDir = dirname(require.resolve("pnpm"));
28
+ const pnpmBinDir = join(dirname(pnpmPackageDir), ".bin");
29
+ const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path") || "PATH";
30
+ return {
31
+ ...process.env,
32
+ [pathKey]: `${pnpmBinDir}${delimiter}${process.env[pathKey] || ""}`,
33
+ npm_config_ignore_workspace_root_check: "true",
34
+ };
35
+ }
36
+
23
37
  function runDsh(args) {
24
38
  const result = spawnSync(process.platform === "win32" ? "dsh.cmd" : "dsh", args, {
25
39
  stdio: "inherit",
26
40
  shell: process.platform === "win32",
41
+ env: dshEnv(),
27
42
  });
28
43
  if (result.error) throw result.error;
29
44
  if (result.status !== 0) throw new Error(`dsh ${args.join(" ")} 执行失败(退出码 ${result.status})`);
30
45
  }
31
46
 
47
+ function writeYamlDocument(file, document) {
48
+ const temporary = join(dirname(file), `.codebuddy-${process.pid}.tmp`);
49
+ writeFileSync(temporary, String(document), "utf8");
50
+ renameSync(temporary, file);
51
+ }
52
+
53
+ function withPnpmBuildPolicy(file, action) {
54
+ const document = parseDocument(readFileSync(file, "utf8"));
55
+ if (document.errors.length) throw new Error(`无法解析 ${file}:${document.errors[0].message}`);
56
+ const changes = [];
57
+ for (const packageName of IGNORED_BUILDS) {
58
+ const path = ["allowBuilds", packageName];
59
+ if (typeof document.getIn(path) !== "boolean") {
60
+ changes.push({ packageName, existed: document.hasIn(path), value: document.getIn(path) });
61
+ document.setIn(path, false);
62
+ }
63
+ }
64
+ if (changes.length) writeYamlDocument(file, document);
65
+ try {
66
+ return action();
67
+ } finally {
68
+ if (changes.length) {
69
+ const current = parseDocument(readFileSync(file, "utf8"));
70
+ for (const change of changes) {
71
+ const path = ["allowBuilds", change.packageName];
72
+ if (change.existed) current.setIn(path, change.value);
73
+ else current.deleteIn(path);
74
+ }
75
+ if (current.getIn(["allowBuilds"])?.items?.length === 0) current.deleteIn(["allowBuilds"]);
76
+ writeYamlDocument(file, current);
77
+ }
78
+ }
79
+ }
80
+
81
+ function cleanPnpmWorkspace(file) {
82
+ if (!existsSync(file)) return;
83
+ const document = parseDocument(readFileSync(file, "utf8"));
84
+ if (document.errors.length) throw new Error(`无法解析 ${file}:${document.errors[0].message}`);
85
+ const entries = document.getIn(["minimumReleaseAgeExclude"])?.items;
86
+ if (!entries) return;
87
+ const remaining = entries.map((entry) => entry.value).filter((entry) => !String(entry).startsWith(`${PACKAGE}@`));
88
+ if (remaining.length === entries.length) return;
89
+ if (remaining.length) document.setIn(["minimumReleaseAgeExclude"], remaining);
90
+ else document.deleteIn(["minimumReleaseAgeExclude"]);
91
+ writeYamlDocument(file, document);
92
+ }
93
+
32
94
  function cleanSettings(file) {
33
95
  if (!existsSync(file)) return undefined;
34
96
  const source = readFileSync(file, "utf8");
@@ -48,7 +110,9 @@ function cleanSettings(file) {
48
110
 
49
111
  function install() {
50
112
  for (const profile of ["web", "headless"]) {
51
- runDsh(["plugin", "--profile", profile, "add", `${PACKAGE}@latest`]);
113
+ runDsh(["plugin", "--profile", profile, "list", "--depth", "0"]);
114
+ const workspace = join(dshHome(), "profiles", profile, "pnpm-workspace.yaml");
115
+ withPnpmBuildPolicy(workspace, () => runDsh(["plugin", "--profile", profile, "add", `${PACKAGE}@latest`]));
52
116
  }
53
117
  console.log("CodeBuddy Provider 已安装。请重启 DSH 后进行配置。");
54
118
  }
@@ -56,7 +120,11 @@ function install() {
56
120
  function uninstall(home = dshHome()) {
57
121
  const backup = cleanSettings(join(home, "settings.yaml"));
58
122
  for (const profile of ["web", "headless"]) {
59
- if (profileHasPlugin(home, profile)) runDsh(["plugin", "--profile", profile, "remove", PACKAGE]);
123
+ const workspace = join(home, "profiles", profile, "pnpm-workspace.yaml");
124
+ if (profileHasPlugin(home, profile)) {
125
+ withPnpmBuildPolicy(workspace, () => runDsh(["plugin", "--profile", profile, "remove", PACKAGE]));
126
+ }
127
+ cleanPnpmWorkspace(workspace);
60
128
  }
61
129
  console.log(backup ? `CodeBuddy 配置已清理,备份:${backup}` : "未发现 CodeBuddy Provider 配置。");
62
130
  console.log("插件已卸载,API Key 凭据保持不变。请重启 DSH。");
@@ -72,6 +140,27 @@ function selfTest() {
72
140
  if (!backup || !existsSync(backup) || result.hasIn(PROVIDER_PATH) || !result.hasIn(["llm-pi-ai", "providers", "opencode-go"])) {
73
141
  throw new Error("uninstall settings cleanup self-test failed");
74
142
  }
143
+ const workspace = join(root, "pnpm-workspace.yaml");
144
+ writeFileSync(workspace, "packages:\n - .\nallowBuilds:\n '@google/genai': true\n protobufjs: pending\n", "utf8");
145
+ withPnpmBuildPolicy(workspace, () => {
146
+ const active = parseDocument(readFileSync(workspace, "utf8"));
147
+ if (active.getIn(["allowBuilds", "@google/genai"]) !== true || active.getIn(["allowBuilds", "protobufjs"]) !== false) {
148
+ throw new Error("pnpm build policy activation self-test failed");
149
+ }
150
+ });
151
+ const restored = parseDocument(readFileSync(workspace, "utf8"));
152
+ if (restored.getIn(["allowBuilds", "@google/genai"]) !== true || restored.getIn(["allowBuilds", "protobufjs"]) !== "pending") {
153
+ throw new Error("pnpm build policy self-test failed");
154
+ }
155
+ restored.setIn(["minimumReleaseAgeExclude"], ["other@1.0.0", `${PACKAGE}@1.3.1`]);
156
+ writeYamlDocument(workspace, restored);
157
+ cleanPnpmWorkspace(workspace);
158
+ const cleaned = parseDocument(readFileSync(workspace, "utf8")).getIn(["minimumReleaseAgeExclude"])?.items?.map((entry) => entry.value);
159
+ if (cleaned?.join(",") !== "other@1.0.0") throw new Error("pnpm workspace cleanup self-test failed");
160
+ const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path") || "PATH";
161
+ if (!dshEnv()[pathKey].split(delimiter)[0].endsWith(join("node_modules", ".bin"))) {
162
+ throw new Error("bundled pnpm PATH self-test failed");
163
+ }
75
164
  console.log("CLI-SELF-TEST-OK");
76
165
  } finally {
77
166
  rmSync(root, { recursive: true, force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-llm-codebuddy",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "使用 WorkBuddy API Key 为 DeepSeek Harness 接入 CodeBuddy 模型",
5
5
  "author": "Axiaohungry",
6
6
  "keywords": [
@@ -49,7 +49,8 @@
49
49
  "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
50
50
  "@deepseek-ai/dsh-settings": "0.1.0-rc.6",
51
51
  "@earendil-works/pi-ai": "0.82.1",
52
- "yaml": "2.8.1"
52
+ "pnpm": "11.19.0",
53
+ "yaml": "2.9.0"
53
54
  },
54
55
  "engines": {
55
56
  "node": ">=22.19.0"