@lmzhen/dsh-evolution-maintenance 0.3.31 → 0.3.33

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 (2) hide show
  1. package/lib/index.js +17 -6
  2. package/package.json +2 -2
package/lib/index.js CHANGED
@@ -112,10 +112,13 @@ function validateAndNormalizeMaintainPlan(raw, report, validSignals) {
112
112
  const protectedNames = /* @__PURE__ */ new Set();
113
113
  const factNames = /* @__PURE__ */ new Set();
114
114
  const canonicalByName = /* @__PURE__ */ new Map();
115
+ const ambiguousNames = /* @__PURE__ */ new Set();
115
116
  for (const skill of report.skills) {
116
117
  const key = skill.name.trim().toLowerCase();
117
118
  factNames.add(key);
118
- canonicalByName.set(key, skill.name);
119
+ const existing = canonicalByName.get(key);
120
+ if (existing !== void 0 && existing !== skill.name) ambiguousNames.add(key);
121
+ else canonicalByName.set(key, skill.name);
119
122
  if (skill.protected) protectedNames.add(key);
120
123
  }
121
124
  if (!isRecord(raw)) return {
@@ -147,12 +150,20 @@ function validateAndNormalizeMaintainPlan(raw, report, validSignals) {
147
150
  let namesOut = [];
148
151
  if (rawNames.length === 0 || !rawNames.every(isNonEmptyString)) errors.push(`${path}.names: non-empty string array required`);
149
152
  else {
150
- namesOut = rawNames.map((nm) => canonicalByName.get(nm.trim().toLowerCase()) ?? nm.trim());
151
- const missing = namesOut.find((nm) => !factNames.has(nm.toLowerCase()));
152
- if (missing !== void 0) errors.push(`${path}.names: references skill "${missing}" not in the facts report — names must come from the scanned skill set`);
153
+ namesOut = rawNames.map((nm) => {
154
+ const key = nm.trim().toLowerCase();
155
+ if (ambiguousNames.has(key)) return nm.trim();
156
+ return canonicalByName.get(key) ?? nm.trim();
157
+ });
158
+ const ambiguousHit = namesOut.find((nm) => ambiguousNames.has(nm.trim().toLowerCase()));
159
+ if (ambiguousHit !== void 0) errors.push(`${path}.names: "${ambiguousHit}" matches multiple differently-cased skill names in the facts report — use the exact spelling`);
153
160
  else {
154
- const hit = namesOut.find((nm) => protectedNames.has(nm.toLowerCase()));
155
- if (hit !== void 0) errors.push(`${path}.names: references protected skill "${hit}" — §7 forbids recommendations for bundled/hub-installed/pinned skills`);
161
+ const missing = namesOut.find((nm) => !factNames.has(nm.toLowerCase()));
162
+ if (missing !== void 0) errors.push(`${path}.names: references skill "${missing}" not in the facts report names must come from the scanned skill set`);
163
+ else {
164
+ const hit = namesOut.find((nm) => protectedNames.has(nm.toLowerCase()));
165
+ if (hit !== void 0) errors.push(`${path}.names: references protected skill "${hit}" — §7 forbids recommendations for bundled/hub-installed/pinned skills`);
166
+ }
156
167
  }
157
168
  }
158
169
  if (!isNonEmptyString(item.rule)) errors.push(`${path}.rule: required`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-maintenance",
3
3
  "description": "Deterministic maintenance-scan surface: skill-library snapshot assembly, drift signals and mechanical-facts rendering (design 011) (community build)",
4
- "version": "0.3.31",
4
+ "version": "0.3.33",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -34,7 +34,7 @@
34
34
  ],
35
35
  "license": "MIT",
36
36
  "dependencies": {
37
- "@lmzhen/dsh-evolution-core": "^0.3.31"
37
+ "@lmzhen/dsh-evolution-core": "^0.3.33"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",