ygc-dsh-sync 1.0.1 → 1.1.0

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/lib/plugins.js CHANGED
@@ -380,6 +380,42 @@ function bytesOf(file) {
380
380
  }
381
381
  }
382
382
 
383
+ /**
384
+ * 从 pnpm-lock.yaml 里读出某个包**实际装到的** commit。
385
+ *
386
+ * git 依赖的 lockfile 记录长这样:
387
+ * dsh-purge-community:
388
+ * specifier: github:owner/repo#v1.6.97
389
+ * version: https://codeload.github.com/owner/repo/tar.gz/<40 位 commit>
390
+ *
391
+ * 为什么记 commit 而不只记 tag:tag 可以移动,commit 不会。只写 tag 的话,
392
+ * 将来对方重打 tag,别人按清单装出来的就不是同一份代码。
393
+ *
394
+ * 读不到就返回 undefined(比如用 file:/registry 装的、或 lockfile 不在),
395
+ * 上层会退化成只写 ref,不编造。
396
+ *
397
+ * @param {string} name 包名
398
+ * @returns {string|undefined}
399
+ */
400
+ export function installedGitCommit(name) {
401
+ let text = '';
402
+ try {
403
+ text = fs.readFileSync(path.join(profileDir(), 'pnpm-lock.yaml'), 'utf8');
404
+ } catch {
405
+ return undefined;
406
+ }
407
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
408
+ const directRe = new RegExp(
409
+ escaped +
410
+ '@https:\\/\\/codeload\\.github\\.com\\/[^/]+\\/[^/]+\\/tar\\.gz\\/([0-9a-f]{40})',
411
+ );
412
+ const hit = directRe.exec(text);
413
+ if (hit) return hit[1];
414
+ const looseRe = new RegExp(escaped + ':[\\s\\S]{0,400}?tar\\.gz\\/([0-9a-f]{40})');
415
+ const m = looseRe.exec(text);
416
+ return m ? m[1] : undefined;
417
+ }
418
+
383
419
  /* ------------------------------------------------------------ 来源描述 */
384
420
 
385
421
  /**
@@ -428,6 +464,9 @@ export function describeSource(plugin) {
428
464
  repo: (parsed && parsed.repo) || undefined,
429
465
  // 原始写法照录:`github:o/r#v1` 与 `git+https://…` 归一后看不出区别
430
466
  raw: spec || undefined,
467
+ // 实际装到的 commit:ref 是 tag 时它可以被移动,commit 不会。
468
+ // 读不到就留空,不编造。
469
+ commit: installedGitCommit(name) || undefined,
431
470
  version,
432
471
  };
433
472
  }
@@ -785,7 +824,8 @@ export function writeAggregate({ config, machineId, publishedNames, log } = {})
785
824
  if (src.type === 'npm') return `npm · ${src.spec || src.package || ''}`;
786
825
  if (src.type === 'git') {
787
826
  const ref = src.ref ? `#${src.ref}` : '';
788
- return src.url ? `git · ${src.url}${ref}` : `git · ${src.raw || '-'}`;
827
+ const commit = src.commit ? ` @${String(src.commit).slice(0, 12)}` : '';
828
+ return src.url ? `git · ${src.url}${ref}${commit}` : `git · ${src.raw || '-'}`;
789
829
  }
790
830
  if (src.type === 'local') return `local · ${src.form || ''} ${src.path || ''}`.trim();
791
831
  if (src.type === 'installation') return '随桌面端安装';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ygc-dsh-sync",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "DSH 同步插件:会话按工作区落地、按机器隔离的跨机备份与拉取;技能本机↔母版双向同步(含记忆插件技能优化闭环);插件清单共享(只存清单与来源,不存源码,只能联网装)。",
6
6
  "icon": "icon.svg",
@@ -58,4 +58,4 @@
58
58
  ]
59
59
  }
60
60
  }
61
- }
61
+ }
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import fs from 'node:fs';
16
16
  import path from 'node:path';
17
+ import { fileURLToPath, pathToFileURL } from 'node:url';
17
18
 
18
19
  const args = process.argv.slice(2);
19
20
  const has = (f) => args.includes(f);
@@ -30,8 +31,11 @@ const REPLY = val('--reply');
30
31
  const LEDGER = path.join(process.env.USERPROFILE, '.mnemon', 'skills', 'ledger.json');
31
32
  const LOCAL = path.join(process.env.USERPROFILE, '.agents', 'skills');
32
33
 
34
+ // 优先用源码仓(YGC_SYNC_SRC),否则用已装副本里的同一份 —— 两边逐字一致。
35
+ const PKG_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
36
+ const SRC_ROOT = process.env.YGC_SYNC_SRC || PKG_ROOT;
33
37
  const P = await import(
34
- 'file:///C:/Users/DSH/Documents/deepseek-harness/default-workspace/projects/dsh-sync-backup/lib/mnemon-pipeline.js'
38
+ pathToFileURL(path.join(SRC_ROOT, 'lib', 'mnemon-pipeline.js')).href
35
39
  );
36
40
  const log = (m) => console.log(m);
37
41
 
@@ -11,10 +11,18 @@
11
11
  import fs from 'node:fs';
12
12
  import path from 'node:path';
13
13
  import crypto from 'node:crypto';
14
+ import os from 'node:os';
14
15
  import { execFileSync } from 'node:child_process';
15
16
 
16
- const ROOT = 'C:/Users/DSH/Documents/deepseek-harness/default-workspace/projects/dsh-sync-backup';
17
- const PROFILE = 'C:/Users/DSH/.dsh/profiles/desktop';
17
+ // 源码根与 profile 都不写死:换机器只改环境变量。
18
+ // ROOT 指向 ygc-dsh-sync 源码仓(有 package.json 的那层)。
19
+ const ROOT = process.env.YGC_SYNC_SRC || process.argv[2] || process.cwd();
20
+ const PROFILE = process.env.DSH_PROFILE_DIR
21
+ || path.join(process.env.DSH_HOME || path.join(os.homedir(), '.dsh'), 'profiles', process.env.DSH_PROFILE || 'desktop');
22
+ if (!fs.existsSync(path.join(ROOT, 'package.json'))) {
23
+ console.error('找不到源码根:' + ROOT + '(设 YGC_SYNC_SRC 或在仓库根运行)');
24
+ process.exit(2);
25
+ }
18
26
  const PKG = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
19
27
  const NAME = PKG.name;
20
28
 
@@ -10,9 +10,11 @@
10
10
  import fs from 'node:fs';
11
11
  import path from 'node:path';
12
12
  import crypto from 'node:crypto';
13
+ import os from 'node:os';
13
14
 
14
15
  const tgz = process.argv[2];
15
- const PROFILE = process.argv[3] || 'C:/Users/DSH/.dsh/profiles/desktop';
16
+ const PROFILE = process.argv[3] || process.env.DSH_PROFILE_DIR
17
+ || path.join(process.env.DSH_HOME || path.join(os.homedir(), '.dsh'), 'profiles', process.env.DSH_PROFILE || 'desktop');
16
18
  if (!tgz || !fs.existsSync(tgz)) {
17
19
  console.error('usage: node tools/sync-lock.mjs <tgz> [profile]');
18
20
  process.exit(2);
@@ -18,7 +18,8 @@ if (!HASH) {
18
18
  process.exit(2);
19
19
  }
20
20
  const NAME = 'ygc-dsh-sync-backup';
21
- const PROFILE = 'C:/Users/DSH/.dsh/profiles/desktop';
21
+ const PROFILE = process.env.DSH_PROFILE_DIR
22
+ || path.join(process.env.DSH_HOME || path.join(os.homedir(), '.dsh'), 'profiles', process.env.DSH_PROFILE || 'desktop');
22
23
 
23
24
  const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'dsb-verify-'));
24
25
  process.env.DSH_SYNC_SKILLS_ROOT = path.join(tmp, 'skills');