@lmzhen/dsh-evolution-curator 0.24.0 → 0.25.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/index.js CHANGED
@@ -4,7 +4,7 @@ import { join } from "node:path";
4
4
  import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
5
5
  import z from "@deepseek-ai/schemastery";
6
6
  import { preferProvider } from "@lmzhen/dsh-evolution-io";
7
- import { CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MIN_IDLE_HOURS, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_LIMITS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, INSTANCE_KEYS, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, SKILL_NAME_RE, buildCuratorRunReport, claimInstance, clampOnce, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, emptyRecord, entryTarget, evolutionHome, evolutionIoAdapter, foldCuratorFields, isPresent, isUnknown, liveBool, loadSuppressedNames, loadUsage, markerEntryName, mutateUsage, newSkillLibrary, paramRowId, parseCuratorNominations, parseFrontmatter, pickWithPolicy, policyStageLimits, probeList, probeText, readNumberParam, relatedSkillNames, releaseInstance, renderCuratorReportMarkdown, reportTime, reportsSweepLockTarget, sessionLastEventTime, sweepReports, transactIo, unwrapLive, updateSuppressedNames, usageObserved, userSetKeys, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
7
+ import { CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MIN_IDLE_HOURS, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_LIMITS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, INSTANCE_KEYS, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, SKILL_NAME_RE, buildCuratorRunReport, claimInstance, clampOnce, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, emptyRecord, entryTarget, evolutionHome, evolutionIoAdapter, foldCuratorFields, isPresent, isUnknown, lintSkill, liveBool, loadSuppressedNames, loadUsage, markerEntryName, mutateUsage, newSkillLibrary, paramRowId, parseCuratorNominations, parseFrontmatter, pickWithPolicy, policyStageLimits, probeList, probeText, readNumberParam, relatedSkillNames, releaseInstance, renderCuratorReportMarkdown, reportTime, reportsSweepLockTarget, sessionLastEventTime, sweepReports, transactIo, unwrapLive, updateSuppressedNames, usageObserved, userSetKeys, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
8
8
  //#region lib/types/index.js
9
9
  /**
10
10
  * Deterministic skill lifecycle curator with interval gate and archive.
@@ -33,6 +33,24 @@ function gateConsolidations(consolidations, gates) {
33
33
  const gateSet = gates instanceof EvolutionGateSet ? gates : new EvolutionGateSet(gates);
34
34
  return consolidations.filter((n) => !gateSet.isBlocked(n.from) && !gateSet.isBlocked(n.into));
35
35
  }
36
+ /**
37
+ * G5 (in-use protection): which skills are POINTED AT by others, and by whom.
38
+ *
39
+ * Pure: derived from the bodies already in hand, using `relatedSkillNames` — the single reader of
40
+ * that frontmatter field — so this map can never disagree with the catalog or the audit. The value
41
+ * is a Set of SOURCES, not a boolean, because a refusal has to be able to name the referrers.
42
+ * @param contents - skill name to its whole SKILL.md text.
43
+ * @returns target name to the set of skills naming it; targets nobody names are absent.
44
+ */
45
+ function referencedSkillNames(contents) {
46
+ const referencedBy = /* @__PURE__ */ new Map();
47
+ for (const [owner, text] of contents) for (const target of relatedSkillNames(text, owner)) {
48
+ const sources = referencedBy.get(target) ?? /* @__PURE__ */ new Set();
49
+ sources.add(owner);
50
+ referencedBy.set(target, sources);
51
+ }
52
+ return referencedBy;
53
+ }
36
54
  var EvolutionCurator = class extends Service {
37
55
  static inject = ["evolutionIo"];
38
56
  static Config = z.object({
@@ -691,8 +709,9 @@ var EvolutionCurator = class extends Service {
691
709
  const text = await this.skills.read(name);
692
710
  if (text) contents.set(name, text);
693
711
  }
712
+ const referencedBy = referencedSkillNames(contents);
694
713
  const protectedNames = await this.protectedNameMap();
695
- const dedupMembers = [...new Set(computeDedupGroups({ contents }).groups.filter((group) => group.length >= 2).flat())].filter((name) => !protectedNames.has(name));
714
+ const dedupMembers = [...new Set(computeDedupGroups({ contents }).groups.filter((group) => group.length >= 2).flat())].filter((name) => !protectedNames.has(name) && !referencedBy.has(name));
696
715
  await this.scoreTree(usage, treeNames, contents);
697
716
  const result = computeLifecycleTransitions(usage, {
698
717
  staleAfterDays: lifecycle.staleAfterDays,
@@ -1219,10 +1238,47 @@ var EvolutionCurator = class extends Service {
1219
1238
  patchCount: record.patch_count,
1220
1239
  readCount: record.view_count
1221
1240
  } : void 0);
1222
- if (assessment && assessment.verdict !== "healthy") rows.push({
1241
+ if (assessment !== null) {
1242
+ rows.push({
1243
+ name: summary.name,
1244
+ verdict: assessment.verdict,
1245
+ dims: assessment.dims,
1246
+ findings: assessment.findings
1247
+ });
1248
+ continue;
1249
+ }
1250
+ const findings = lintSkill({
1251
+ skillName: summary.name,
1252
+ dims: {
1253
+ bodyChars: null,
1254
+ bodyTokens: null,
1255
+ stampDensityPerKb: null,
1256
+ stampHits: null,
1257
+ supportGroups: 0,
1258
+ supportFiles: null,
1259
+ churnPatches: null,
1260
+ churnReads: null
1261
+ },
1262
+ softLineChars: thresholds.softBodyChars,
1263
+ overSoftLine: false,
1264
+ overTwiceSoftLine: false,
1265
+ stampLimitPerKb: thresholds.stampDensityPerKb,
1266
+ churnMinPatches: thresholds.churnMinPatches,
1267
+ readable: false
1268
+ });
1269
+ rows.push({
1223
1270
  name: summary.name,
1224
- verdict: assessment.verdict,
1225
- reasons: assessment.reasons
1271
+ verdict: "warn",
1272
+ dims: {
1273
+ bodyChars: null,
1274
+ bodyTokens: null,
1275
+ stampDensityPerKb: null,
1276
+ supportGroups: 0,
1277
+ supportFiles: null,
1278
+ churnPatches: null,
1279
+ churnReads: null
1280
+ },
1281
+ findings
1226
1282
  });
1227
1283
  }
1228
1284
  return rows;
@@ -1426,4 +1482,4 @@ var EvolutionCurator = class extends Service {
1426
1482
  }
1427
1483
  };
1428
1484
  //#endregion
1429
- export { EvolutionCurator, EvolutionCurator as default, gateConsolidations, validateCuratorSettings };
1485
+ export { EvolutionCurator, EvolutionCurator as default, gateConsolidations, referencedSkillNames, validateCuratorSettings };
@@ -148,6 +148,16 @@ export declare function gateConsolidations(consolidations: CuratorConsolidation[
148
148
  referenced?: ReadonlySet<string>;
149
149
  suppressed?: ReadonlySet<string>;
150
150
  }): CuratorConsolidation[];
151
+ /**
152
+ * G5 (in-use protection): which skills are POINTED AT by others, and by whom.
153
+ *
154
+ * Pure: derived from the bodies already in hand, using `relatedSkillNames` — the single reader of
155
+ * that frontmatter field — so this map can never disagree with the catalog or the audit. The value
156
+ * is a Set of SOURCES, not a boolean, because a refusal has to be able to name the referrers.
157
+ * @param contents - skill name to its whole SKILL.md text.
158
+ * @returns target name to the set of skills naming it; targets nobody names are absent.
159
+ */
160
+ export declare function referencedSkillNames(contents: ReadonlyMap<string, string>): Map<string, Set<string>>;
151
161
  export declare class EvolutionCurator extends Service {
152
162
  static inject: string[];
153
163
  static Config: z<Schemastery.ObjectS<NoInfer<{
@@ -495,7 +505,21 @@ export declare class EvolutionCurator extends Service {
495
505
  healthView(): Promise<Array<{
496
506
  name: string;
497
507
  verdict: SkillHealthVerdict;
498
- reasons: string[];
508
+ dims: {
509
+ bodyChars: number | null;
510
+ bodyTokens: number | null;
511
+ stampDensityPerKb: number | null;
512
+ supportGroups: number;
513
+ supportFiles: number | null;
514
+ churnPatches: number | null;
515
+ churnReads: number | null;
516
+ };
517
+ findings: Array<{
518
+ severity: 'warn' | 'error';
519
+ rule: string;
520
+ message: string;
521
+ count: number;
522
+ }>;
499
523
  }>>;
500
524
  /** Whether the library has ANY observed read evidence (C observation-window gate for churn signals). */
501
525
  usageObserved(): Promise<boolean>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-curator",
3
3
  "description": "Deterministic skill lifecycle and recovery (community build)",
4
- "version": "0.24.0",
4
+ "version": "0.25.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,20 +27,20 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.4",
30
- "@lmzhen/dsh-evolution-core": "^0.24.0"
30
+ "@lmzhen/dsh-evolution-core": "^0.25.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@deepseek-ai/cordis": "^4.0.1",
34
34
  "@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
35
35
  "@deepseek-ai/dsh-session": "^0.2.0-rc.1",
36
- "@lmzhen/dsh-evolution-io": "^0.24.0",
37
- "@lmzhen/dsh-evolution-state": "^0.24.0"
36
+ "@lmzhen/dsh-evolution-io": "^0.25.0",
37
+ "@lmzhen/dsh-evolution-state": "^0.25.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
41
41
  "@deepseek-ai/dsh-session": "^0.2.0-rc.1",
42
- "@lmzhen/dsh-evolution-core": "^0.24.0",
43
- "@lmzhen/dsh-evolution-io": "^0.24.0",
44
- "@lmzhen/dsh-evolution-state": "^0.24.0"
42
+ "@lmzhen/dsh-evolution-core": "^0.25.0",
43
+ "@lmzhen/dsh-evolution-io": "^0.25.0",
44
+ "@lmzhen/dsh-evolution-state": "^0.25.0"
45
45
  }
46
46
  }