Skip to content

Commit 141b9ab

Browse files
feat: auto-wire the DSH plugin on install
The Windows installer no longer asks users to run dsh plugin add. Post-install (and again when picking DeepSeek Harness) writes the Cordis insert into the existing web profile, or a home-level patch if DSH has not been initialized yet. Uninstall removes the wiring. beautiCode still never starts DSH.
1 parent 5bc1c96 commit 141b9ab

8 files changed

Lines changed: 359 additions & 2 deletions

File tree

apps/tray/start-tray.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,18 @@ foreach ($requiredRuntimeFile in @($HostScript, $coreDist, $adapterDist)) {
335335
}
336336
}
337337

338+
if ($script:targetHost -eq "dsh") {
339+
$pluginInstaller = Join-Path $RepoRoot "scripts\install-dsh-plugin.ps1"
340+
$pluginRoot = Join-Path $RepoRoot "integrations\deepseek-harness"
341+
if (Test-Path -LiteralPath $pluginInstaller -PathType Leaf) {
342+
try {
343+
& $pluginInstaller -PluginRoot $pluginRoot
344+
} catch {
345+
Write-BcTrayLog ("dsh plugin install failed: {0}" -f $_.Exception.Message)
346+
}
347+
}
348+
}
349+
338350
# Cryptographically strong token for the local control plane.
339351
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
340352
try {

docs/deepseek-harness.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ beautiCode 通过 DeepSeek Harness 的 Cordis 插件接口接入(`@beauticode/
1616

1717
## 安装插件
1818

19+
Windows 安装包会在安装结束时(以及选择 DeepSeek Harness 时)自动写入你的 DSH profile。没有 DSH 也不影响安装;第一次运行 `dsh web` 会走 home 层补丁。也可手动:
20+
1921
```sh
2022
# 源码目录
2123
dsh plugin --profile web add file:<beautiCode 路径>/integrations/deepseek-harness

docs/windows-installer.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010

1111
The package includes the compiled beautiCode runtime and a pinned Node.js x64
1212
runtime. The target machine does not need Node.js, npm, TypeScript, or a source
13-
checkout. DeepSeek Harness is **not** bundled — install the plugin from
14-
`{app}\integrations\deepseek-harness` into your DSH profile and run `dsh web`
13+
checkout. DeepSeek Harness is **not** bundled. The installer ships the plugin files and
14+
wires them into the user's DSH profile (`dsh plugin` is not required; if no
15+
profile exists yet, a home-level `cordis.patch.yml` is written). Run `dsh web`
1516
yourself. Codex Desktop is optional and remains a separate prerequisite if you
1617
choose that host; the tray still launches Codex as before.
1718

installer/windows/beauticode.iss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,8 @@ Name: "{autodesktop}\beautiCode"; Filename: "{sys}\WindowsPowerShell\v1.0\powers
5858
Name: "{userstartup}\beautiCode"; Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File ""{app}\scripts\start-beauticode-engine.ps1"" -NoLaunchCodex"; WorkingDir: "{app}"; IconFilename: "{app}\beauticode.ico"; Tasks: autostart
5959

6060
[Run]
61+
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\install-dsh-plugin.ps1"" -PluginRoot ""{app}\integrations\deepseek-harness"""; WorkingDir: "{app}"; StatusMsg: "正在把 beautiCode 插件写入 DeepSeek Harness…"; Flags: postinstall runhidden
6162
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File ""{app}\scripts\start-beauticode.ps1"""; WorkingDir: "{app}"; Description: "启动 beautiCode"; Flags: postinstall nowait skipifsilent
63+
64+
[UninstallRun]
65+
Filename: "{sys}\WindowsPowerShell\v1.0\powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\scripts\install-dsh-plugin.ps1"" -PluginRoot ""{app}\integrations\deepseek-harness"" -Remove"; WorkingDir: "{app}"; Flags: runhidden

packages/adapter-dsh/test/launcher-scripts.test.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from "node:assert/strict";
22
import { spawnSync } from "node:child_process";
33
import fs from "node:fs";
4+
import os from "node:os";
45
import path from "node:path";
56
import test from "node:test";
67
import { fileURLToPath } from "node:url";
@@ -12,6 +13,7 @@ const scripts = [
1213
"scripts/start-beauticode.ps1",
1314
"scripts/start-beauticode-engine.ps1",
1415
"scripts/codex-launch.ps1",
16+
"scripts/install-dsh-plugin.ps1",
1517
"apps/tray/start-tray.ps1",
1618
];
1719

@@ -100,3 +102,92 @@ test("picker DryRun routes DSH to the tray and Codex to its launcher", () => {
100102
assert.match(result.stdout, new RegExp(needle.replace(/[.]/g, "\\.")));
101103
}
102104
});
105+
106+
test("install-dsh-plugin wires a missing DSH home and can uninstall", () => {
107+
const script = path.join(repoRoot, "scripts/install-dsh-plugin.ps1");
108+
const pluginRoot = path.join(repoRoot, "integrations/deepseek-harness");
109+
const home = fs.mkdtempSync(path.join(os.tmpdir(), "bc-dsh-home-"));
110+
try {
111+
const add = spawnSync(
112+
"powershell.exe",
113+
[
114+
"-NoProfile",
115+
"-ExecutionPolicy",
116+
"Bypass",
117+
"-File",
118+
script,
119+
"-PluginRoot",
120+
pluginRoot,
121+
"-DshHome",
122+
home,
123+
],
124+
{ encoding: "utf8", windowsHide: true },
125+
);
126+
assert.equal(add.status, 0, add.stderr || add.stdout);
127+
const homePatch = fs.readFileSync(path.join(home, "cordis.patch.yml"), "utf8");
128+
assert.match(homePatch, /id: beauticode-bridge/);
129+
assert.match(homePatch, /file:\/\//);
130+
131+
const web = path.join(home, "profiles", "web");
132+
fs.mkdirSync(web, { recursive: true });
133+
fs.writeFileSync(
134+
path.join(web, "package.json"),
135+
JSON.stringify({
136+
name: "dsh-profile-web",
137+
private: true,
138+
dependencies: {},
139+
dsh: { profile: { bundles: ["@deepseek-ai/dsh-base"] } },
140+
}),
141+
"utf8",
142+
);
143+
fs.writeFileSync(path.join(web, "cordis.patch.yml"), "[]\n", "utf8");
144+
const migrate = spawnSync(
145+
"powershell.exe",
146+
[
147+
"-NoProfile",
148+
"-ExecutionPolicy",
149+
"Bypass",
150+
"-File",
151+
script,
152+
"-PluginRoot",
153+
pluginRoot,
154+
"-DshHome",
155+
home,
156+
],
157+
{ encoding: "utf8", windowsHide: true },
158+
);
159+
assert.equal(migrate.status, 0, migrate.stderr || migrate.stdout);
160+
const webPatch = fs.readFileSync(path.join(web, "cordis.patch.yml"), "utf8");
161+
assert.match(webPatch, /@beauticode\/dsh-plugin/);
162+
assert.equal(fs.existsSync(path.join(home, "cordis.patch.yml")), false);
163+
assert.ok(
164+
fs.existsSync(
165+
path.join(web, "node_modules", "@beauticode", "dsh-plugin", "index.mjs"),
166+
),
167+
);
168+
169+
const remove = spawnSync(
170+
"powershell.exe",
171+
[
172+
"-NoProfile",
173+
"-ExecutionPolicy",
174+
"Bypass",
175+
"-File",
176+
script,
177+
"-PluginRoot",
178+
pluginRoot,
179+
"-DshHome",
180+
home,
181+
"-Remove",
182+
],
183+
{ encoding: "utf8", windowsHide: true },
184+
);
185+
assert.equal(remove.status, 0, remove.stderr || remove.stdout);
186+
assert.equal(
187+
fs.existsSync(path.join(web, "node_modules", "@beauticode", "dsh-plugin")),
188+
false,
189+
);
190+
} finally {
191+
fs.rmSync(home, { recursive: true, force: true });
192+
}
193+
});

scripts/build-windows-installer.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ foreach ($relativeFile in @(
225225
"scripts\codex-launch.ps1",
226226
"scripts\start-beauticode.ps1",
227227
"scripts\start-beauticode-engine.ps1",
228+
"scripts\install-dsh-plugin.ps1",
228229
"packages\core\package.json",
229230
"packages\adapter-codex\package.json",
230231
"packages\adapter-dsh\package.json",

0 commit comments

Comments
 (0)