dsh-engram 0.3.6 → 0.4.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.
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * dsh-engram release-note helper.
4
+ *
5
+ * Prints the required "DSH 版本支持" markdown stanza for a release note by
6
+ * reading the single source of truth in package.json (engines.dsh + the
7
+ * @deepseek-ai/dsh-* peers), so the declared compatibility can never drift
8
+ * from what the package.json actually claims.
9
+ *
10
+ * Usage:
11
+ * node scripts/gen-release-notes.mjs # print the stanza
12
+ * node scripts/gen-release-notes.mjs --watch # also echo engines + peers
13
+ */
14
+
15
+ import { readFileSync } from "node:fs";
16
+ import { fileURLToPath } from "node:url";
17
+ import { dirname, resolve } from "node:path";
18
+
19
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
20
+ const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
21
+
22
+ const engines = pkg.engines ?? {};
23
+ const peers = pkg.peerDependencies ?? {};
24
+
25
+ const DSH_PEER_PREFIX = "@deepseek-ai/dsh-";
26
+ const dshPeers = Object.entries(peers)
27
+ .filter(([name]) => name.startsWith(DSH_PEER_PREFIX))
28
+ .sort(([a], [b]) => a.localeCompare(b));
29
+
30
+ const range = engines.dsh;
31
+ const legacyOld =
32
+ !range && dshPeers.every(([, r]) => r.includes("0.1.0-rc.7"));
33
+ const supportLine = legacyOld
34
+ ? "仅旧版 —— `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2`"
35
+ : range ?? "(package.json 未声明 engines.dsh —— 补注历史版本时按上一行规则填写)";
36
+
37
+ const peerLine = dshPeers.length
38
+ ? dshPeers.map(([n, r]) => ` - \`${n}\`: \`${r}\``).join("\n")
39
+ : " - (无 @deepseek-ai/dsh-* peer 声明)";
40
+
41
+ const body = `## DSH 版本支持
42
+
43
+ - **支持的 DSH 范围**:${supportLine}
44
+ - **peer 声明**:
45
+ ${peerLine}
46
+ ${
47
+ legacyOld
48
+ ? "- ⚠️ DSH `>=0.1.2-alpha.2` 与本版本**不兼容**(settings/client API 族在该版本断裂:`@deepseek-ai/dsh-settings` 移除 `settingsNamespace`/`installSettingsSection`,改 `settings.installSection`;client 注入集换到 `dsh-api-remotes` 等;cordis `^4.0.2`、schemastery `^3.18.2`)。如需新版 DSH,请升级插件到 `master` 的下一个发布。"
49
+ : range
50
+ ? `- **验证版本**:<如 dsh-v0.1.5-alpha.1>(本地 deepseek-harness checkout)
51
+ - **最后验证日期**:<YYYY-MM-DD>
52
+ - **安装方式已验证**:<如 dsh plugin --profile web add dsh-engram>`
53
+ : ""
54
+ }
55
+ `;
56
+
57
+ if (process.argv.includes("--watch")) {
58
+ console.log(`engines.dsh = ${range ?? "<未声明>"}`);
59
+ console.log(`engines.node = ${engines.node ?? "<未声明>"}`);
60
+ console.log(`@deepseek-ai/cordis peer = ${peers["@deepseek-ai/cordis"] ?? "<未声明>"}`);
61
+ console.log(`@deepseek-ai/schemastery peer = ${peers["@deepseek-ai/schemastery"] ?? "<未声明>"}`);
62
+ console.log("---");
63
+ }
64
+ process.stdout.write(body);
@@ -23,10 +23,10 @@ import { fileURLToPath, pathToFileURL } from "node:url";
23
23
  const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
24
24
  const tmp = mkdtempSync(join(tmpdir(), "dsh-engram-pack-"));
25
25
  const PEERS = [
26
- "@deepseek-ai/cordis@^4.0.1",
27
- "@deepseek-ai/dsh-settings@^0.1.0-rc.7",
28
- "@deepseek-ai/dsh-storage-domain@^0.1.0-rc.7",
29
- "@deepseek-ai/schemastery@^3.18.1",
26
+ "@deepseek-ai/cordis@^4.0.2",
27
+ "@deepseek-ai/dsh-settings@>=0.1.2-alpha.2 <0.2.0-0",
28
+ "@deepseek-ai/dsh-storage-domain@>=0.1.2-alpha.2 <0.2.0-0",
29
+ "@deepseek-ai/schemastery@^3.18.2",
30
30
  ];
31
31
 
32
32
  function sh(cmd, args, cwd) {
@@ -93,6 +93,11 @@ function findStoreZod(harness) {
93
93
  function buildPlan(harness) {
94
94
  const zodDir = findStoreZod(harness);
95
95
  const plan = [
96
+ {
97
+ label: "@deepseek-ai/cordis",
98
+ mount: join(SCOPE, "cordis"),
99
+ target: join(harness, "vendor", "cordis"),
100
+ },
96
101
  {
97
102
  label: "zod",
98
103
  mount: join(NODE_MODULES, "zod"),
@@ -141,7 +146,9 @@ function buildPlan(harness) {
141
146
  function isInstalled(mount, expected) {
142
147
  if (existsSync(mount)) {
143
148
  try {
144
- if (resolve(readlinkSync(mount)) === resolve(expected)) return true;
149
+ // readlinkSync() returns a relative target for pnpm-created links; resolve
150
+ // it from the mount's parent, rather than from the process cwd.
151
+ return resolve(dirname(mount), readlinkSync(mount)) === resolve(expected);
145
152
  } catch {
146
153
  /* not a symlink — fall through */
147
154
  }
@@ -185,24 +192,27 @@ function ensureLink(item) {
185
192
  return;
186
193
  }
187
194
  // 允许替换:符号链接直接 unlink;pnpm 预建的空目录用 rmdir 清掉。
195
+ let removed = false;
188
196
  try {
189
197
  unlinkSync(mount);
190
198
  console.log(` ~ ${label}: 替换旧链接`);
191
- return;
199
+ removed = true;
192
200
  } catch {
193
201
  /* not a symlink */
194
202
  }
195
- try {
196
- if (readdirSync(mount).length === 0) {
197
- rmdirSync(mount);
198
- console.log(` ~ ${label}: 移除空目录后重建`);
199
- } else {
200
- console.log(` ! ${label}: ${mount} 是含文件的真实目录,无法自动替换,请手动清理后重试`);
203
+ if (!removed) {
204
+ try {
205
+ if (readdirSync(mount).length === 0) {
206
+ rmdirSync(mount);
207
+ console.log(` ~ ${label}: 移除空目录后重建`);
208
+ } else {
209
+ console.log(` ! ${label}: ${mount} 是含文件的真实目录,无法自动替换,请手动清理后重试`);
210
+ return;
211
+ }
212
+ } catch {
213
+ console.log(` ! ${label}: ${mount} 无法自动替换,请手动清理后重试`);
201
214
  return;
202
215
  }
203
- } catch {
204
- console.log(` ! ${label}: ${mount} 无法自动替换,请手动清理后重试`);
205
- return;
206
216
  }
207
217
  }
208
218
  if (CHECK_ONLY) {