@fffangchenghao/dsh-autoupdater 0.6.2 → 0.6.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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/main.js +42 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -97,6 +97,7 @@ dsh plugin --profile web add github:fangchenghao/dsh-autoupdater
97
97
  - **`dsh.cmd` 调用**:PATH / sibling 找到的 `.cmd` 经 `cmd.exe` 执行并正确加引号;超时用 `taskkill /T /F` 结束整棵进程树,避免留下 pnpm 子进程。
98
98
  - **环境变量**:没有 `HOME` 时用 `homedir()`(Windows 的 `USERPROFILE`);PATH 兼容 `Path` 键,并额外查找 `%APPDATA%\npm` / `%LOCALAPPDATA%\pnpm`。
99
99
  - Windows 上不执行 DSH 本体更新(交给安装器/App 自带更新器),插件换版后同样只提示重启。
100
+ - **多 profile 选择**:优先使用桌面 App 注入的 `DSH_PROFILE_DIR` / `DSH_PROFILE`;桌面版在两者都缺失时默认 `desktop`,不会因为某个测试 profile 的 `node_modules` 更新时间更近而误选。
100
101
 
101
102
  开发机是 macOS;Windows 分支是按 Node/Electron 的跨平台语义改的,并做了逻辑测试,但**尚未在真实 Windows 机器上端到端跑过**。如果 Windows 上仍失败,请把面板日志和 `%USERPROFILE%\.dsh\autoupdater\history.jsonl` 发到 GitHub issue。
102
103
 
@@ -104,7 +105,7 @@ dsh plugin --profile web add github:fangchenghao/dsh-autoupdater
104
105
 
105
106
  - 上游项目:[niubi6668889595/dsh-autoupdater](https://github.com/niubi6668889595/dsh-autoupdater)(MIT)。
106
107
  - 本分支新增:桌面版 CLI 换版、npmmirror 优先、跳过 `link:`/git 来源、只有真正升级成功才算“已应用”、Windows 空闲判定/.cmd 调用适配;完整差异见 git log。
107
- - 发布渠道:npm `@fffangchenghao/dsh-autoupdater`,GitHub `fangchenghao/dsh-autoupdater`,tag `v0.6.2`。
108
+ - 发布渠道:npm `@fffangchenghao/dsh-autoupdater`,GitHub `fangchenghao/dsh-autoupdater`,tag `v0.6.3`。
108
109
  - 与上游同步:把上游加为 remote,rebase/merge 到本分支后重新发版即可。
109
110
 
110
111
  ## 安全模型
package/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFile, writeFile, mkdir, appendFile } from 'node:fs/promises';
2
2
  import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
3
3
  import { execFileSync, spawn } from 'node:child_process';
4
- import { basename, delimiter, dirname, join } from 'node:path';
4
+ import { basename, delimiter, dirname, join, resolve } from 'node:path';
5
5
  import { homedir } from 'node:os';
6
6
 
7
7
  /** 本插件的真实包名(上游名或发布用的 scoped 名),用于把自己排除在自动更新之外。 */
@@ -140,6 +140,20 @@ async function readJson(path) {
140
140
  try { return JSON.parse(await readFile(path, 'utf8')); } catch { return null; }
141
141
  }
142
142
 
143
+ /**
144
+ * 与 @deepseek-ai/dsh-home-paths 的 resolveDshHome 对齐:
145
+ * $DSH_HOME 优先(支持 ~ / ~\ 前缀,空/全空白视为未设置),否则 ~/.dsh。
146
+ * 这样 Windows 上没有 HOME、只设置 DSH_HOME 或 USERPROFILE 时都能落到同一目录。
147
+ */
148
+ function resolveDshHome(env = process.env) {
149
+ const raw = typeof env.DSH_HOME === 'string' ? env.DSH_HOME : '';
150
+ if (raw.trim().length === 0) return join(homedir(), '.dsh');
151
+ let expanded = raw;
152
+ if (raw === '~') expanded = homedir();
153
+ else if (raw.startsWith('~/') || raw.startsWith('~\\')) expanded = join(homedir(), raw.slice(2));
154
+ return resolve(expanded);
155
+ }
156
+
143
157
  /**
144
158
  * 递归找出目录里最新的文件 mtime(毫秒)。
145
159
  * 目录不存在 → 0(没有会话 = 空闲);根目录读不了 → 抛错(调用方保守当忙)。
@@ -244,7 +258,7 @@ export const inject = ['agents', 'pluginManager', 'webServer'];
244
258
 
245
259
  export function apply(ctx, rawConfig = {}) {
246
260
  // Windows 上通常没有 HOME,只有 USERPROFILE;homedir() 会选对。
247
- const home = process.env.DSH_HOME || join(homedir(), '.dsh');
261
+ const home = resolveDshHome();
248
262
  const stateDir = join(home, 'autoupdater');
249
263
  const statePath = join(stateDir, 'status.json');
250
264
  const historyPath = join(stateDir, 'history.jsonl');
@@ -262,28 +276,38 @@ export function apply(ctx, rawConfig = {}) {
262
276
  if (hot) config = normalizeConfig({ ...rawConfig, ...hot });
263
277
  }
264
278
 
279
+ /** 是否运行在 Electron 桌面 App 的进程里(macOS/Windows 安装包)。 */
280
+ const isDesktopApp = () => typeof process.versions?.electron === 'string';
281
+
265
282
  // ── profile 目录探测(磁盘版本回读用)──
266
- // DSH_PROFILE_DIR 优先;否则在 $DSH_HOME/profiles 下找含 node_modules 的目录,
267
- // 多个时取 node_modules 最近修改的。找不到 = 磁盘回读退化为仅信安装结果。
283
+ // 优先级与 DSH 自身一致:DSH_PROFILE_DIR → DSH_PROFILE → 扫描 profiles。
284
+ // 桌面版在 DSH_PROFILE 缺失时默认 desktop,避免多 profile 时误选最近修改的测试 profile。
268
285
  let profileDir = process.env.DSH_PROFILE_DIR || null;
286
+ if (profileDir && !existsSync(profileDir)) profileDir = null;
287
+ if (!profileDir) {
288
+ const configuredProfile = process.env.DSH_PROFILE || (isDesktopApp() ? 'desktop' : '');
289
+ if (configuredProfile) {
290
+ const candidate = join(home, 'profiles', configuredProfile);
291
+ if (existsSync(candidate)) profileDir = candidate;
292
+ }
293
+ }
269
294
  try {
270
- const base = join(home, 'profiles');
271
- const candidates = readdirSync(base)
272
- .map((name) => join(base, name))
273
- .filter((dir) => existsSync(join(dir, 'node_modules')));
274
- if (candidates.length === 1) {
275
- profileDir = candidates[0];
276
- } else if (candidates.length > 1) {
277
- profileDir = candidates
278
- .map((dir) => ({ dir, m: statSync(join(dir, 'node_modules')).mtimeMs }))
279
- .sort((a, b) => b.m - a.m)[0].dir;
295
+ if (!profileDir) {
296
+ const base = join(home, 'profiles');
297
+ const candidates = readdirSync(base)
298
+ .map((name) => join(base, name))
299
+ .filter((dir) => existsSync(join(dir, 'node_modules')));
300
+ if (candidates.length === 1) {
301
+ profileDir = candidates[0];
302
+ } else if (candidates.length > 1) {
303
+ profileDir = candidates
304
+ .map((dir) => ({ dir, m: statSync(join(dir, 'node_modules')).mtimeMs }))
305
+ .sort((a, b) => b.m - a.m)[0].dir;
306
+ }
280
307
  }
281
308
  if (profileDir && config.verbose) log('profileDir detected:', profileDir);
282
309
  } catch {}
283
310
 
284
- /** 是否运行在 Electron 桌面 App 的进程里(macOS/Windows 安装包)。 */
285
- const isDesktopApp = () => typeof process.versions?.electron === 'string';
286
-
287
311
  /**
288
312
  * 找一条能真正写 profile 的 `dsh plugin` 入口。
289
313
  *
@@ -476,7 +500,7 @@ export function apply(ctx, rawConfig = {}) {
476
500
  async function runPluginCliAdd(pkg, version) {
477
501
  const cli = resolvePluginCli();
478
502
  if (!cli) {
479
- const reason = '找不到可用的 dsh CLI(桌面 App 自带的 dsh-desktop-host 与 PATH 上的 dsh 都不可用)';
503
+ const reason = `找不到可用的 dsh CLI(platform=${process.platform}, resourcesPath=${process.resourcesPath ?? 'n/a'}, execPath=${process.execPath})`;
480
504
  log('CLI add:', reason);
481
505
  return { ok: false, code: -1, output: '', reason };
482
506
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fffangchenghao/dsh-autoupdater",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Maintained fork of dsh-autoupdater with macOS/Windows desktop fixes. Scheduled update checks for DSH itself and installed plugins, applied only in idle windows.",