@lmzhen/dsh-evolution-curator 0.3.24 → 0.3.25

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 +40 -23
  2. package/package.json +7 -7
package/lib/index.js CHANGED
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import { join } from "node:path";
4
4
  import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
5
5
  import z from "@deepseek-ai/schemastery";
6
- import { CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MIN_IDLE_HOURS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, SkillLibrary, buildCuratorRunReport, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, emptyRecord, evolutionHome, evolutionIoAdapter, foldCuratorFields, loadSuppressedNames, loadUsage, mutateUsage, parseCuratorNominations, relatedSkillNames, renderCuratorReportMarkdown, updateSuppressedNames, usageObserved } from "@lmzhen/dsh-evolution-core";
6
+ import { CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MIN_IDLE_HOURS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, SkillLibrary, buildCuratorRunReport, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, emptyRecord, evolutionHome, evolutionIoAdapter, foldCuratorFields, loadSuppressedNames, loadUsage, mutateUsage, parseCuratorNominations, relatedSkillNames, renderCuratorReportMarkdown, updateSuppressedNames, usageObserved } from "@lmzhen/dsh-evolution-core";
7
7
  //#region lib/types/index.js
8
8
  /**
9
9
  * Deterministic skill lifecycle curator with interval gate and archive.
@@ -25,24 +25,24 @@ var EvolutionCurator = class extends Service {
25
25
  static inject = ["evolutionIo"];
26
26
  static Config = z.object({
27
27
  enabled: z.boolean().default(true),
28
- intervalHours: z.number().default(DEFAULT_CURATOR_INTERVAL_HOURS),
29
- staleAfterDays: z.number().default(DEFAULT_STALE_AFTER_DAYS),
30
- archiveAfterDays: z.number().default(DEFAULT_ARCHIVE_AFTER_DAYS),
28
+ intervalHours: z.number().min(1).default(DEFAULT_CURATOR_INTERVAL_HOURS),
29
+ staleAfterDays: z.number().min(1).default(DEFAULT_STALE_AFTER_DAYS),
30
+ archiveAfterDays: z.number().min(1).default(DEFAULT_ARCHIVE_AFTER_DAYS),
31
31
  llmReview: z.boolean().default(false),
32
32
  curatorProvider: z.string().default("deepseek-official"),
33
- qualityWarnStaleAfterDays: z.number().default(DEFAULT_QUALITY_WARN_STALE_AFTER_DAYS),
34
- minIdleHours: z.number().default(DEFAULT_MIN_IDLE_HOURS),
33
+ qualityWarnStaleAfterDays: z.number().min(1).default(DEFAULT_QUALITY_WARN_STALE_AFTER_DAYS),
34
+ minIdleHours: z.number().min(0).default(DEFAULT_MIN_IDLE_HOURS),
35
35
  minIdleFailOpen: z.boolean().default(true),
36
36
  excludeSkillNames: z.array(z.string()).default([]),
37
37
  manageUnmanaged: z.boolean().default(false),
38
38
  pruneBuiltins: z.boolean().default(false),
39
39
  referencedSkillNames: z.array(z.string()).default([]),
40
40
  autoStart: z.boolean().default(true),
41
- bootGraceSeconds: z.number().default(10),
42
- curatorReviewMaxTokens: z.number().default(2048),
43
- healthSoftBodyChars: z.number().default(DEFAULT_HEALTH_THRESHOLDS.softBodyChars),
44
- healthStampDensityPerKb: z.number().default(DEFAULT_HEALTH_THRESHOLDS.stampDensityPerKb),
45
- healthChurnMinPatches: z.number().default(DEFAULT_HEALTH_THRESHOLDS.churnMinPatches)
41
+ bootGraceSeconds: z.number().min(0).default(10),
42
+ curatorReviewMaxTokens: z.number().min(1).default(2048),
43
+ healthSoftBodyChars: z.number().min(1).default(DEFAULT_HEALTH_THRESHOLDS.softBodyChars),
44
+ healthStampDensityPerKb: z.number().min(1).default(DEFAULT_HEALTH_THRESHOLDS.stampDensityPerKb),
45
+ healthChurnMinPatches: z.number().min(1).default(DEFAULT_HEALTH_THRESHOLDS.churnMinPatches)
46
46
  });
47
47
  skills;
48
48
  io;
@@ -79,23 +79,30 @@ var EvolutionCurator = class extends Service {
79
79
  this.ctx.emit("evolution/skill-mutated", event);
80
80
  });
81
81
  this.enabled = config.enabled ?? true;
82
- this.intervalHours = config.intervalHours ?? DEFAULT_CURATOR_INTERVAL_HOURS;
83
- this.staleAfterDays = config.staleAfterDays ?? DEFAULT_STALE_AFTER_DAYS;
84
- this.archiveAfterDays = config.archiveAfterDays ?? DEFAULT_ARCHIVE_AFTER_DAYS;
82
+ const clamped = [];
83
+ const field = (name, value, fallback, min) => {
84
+ const result = clampedNumber(value, fallback, { min });
85
+ if (value !== void 0 && result !== value) clamped.push(name);
86
+ return result;
87
+ };
88
+ this.intervalHours = field("intervalHours", config.intervalHours, DEFAULT_CURATOR_INTERVAL_HOURS, 1);
89
+ this.staleAfterDays = field("staleAfterDays", config.staleAfterDays, DEFAULT_STALE_AFTER_DAYS, 1);
90
+ this.archiveAfterDays = field("archiveAfterDays", config.archiveAfterDays, DEFAULT_ARCHIVE_AFTER_DAYS, 1);
85
91
  this.llmReview = config.llmReview ?? false;
86
92
  this.curatorProvider = config.curatorProvider ?? "deepseek-official";
87
- this.qualityWarnStaleAfterDays = config.qualityWarnStaleAfterDays ?? DEFAULT_QUALITY_WARN_STALE_AFTER_DAYS;
88
- this.minIdleHours = config.minIdleHours ?? DEFAULT_MIN_IDLE_HOURS;
93
+ this.qualityWarnStaleAfterDays = field("qualityWarnStaleAfterDays", config.qualityWarnStaleAfterDays, DEFAULT_QUALITY_WARN_STALE_AFTER_DAYS, 1);
94
+ this.minIdleHours = field("minIdleHours", config.minIdleHours, DEFAULT_MIN_IDLE_HOURS, 0);
89
95
  this.minIdleFailOpen = config.minIdleFailOpen ?? true;
90
96
  this.excludeSkillNames = new Set(config.excludeSkillNames ?? []);
91
97
  this.manageUnmanaged = config.manageUnmanaged ?? false;
92
98
  this.pruneBuiltins = config.pruneBuiltins ?? false;
93
99
  this.referencedSkillNames = new Set(config.referencedSkillNames ?? []);
94
- this.bootGraceSeconds = config.bootGraceSeconds ?? 10;
95
- this.curatorReviewMaxTokens = config.curatorReviewMaxTokens ?? 2048;
96
- this.healthSoftBodyChars = config.healthSoftBodyChars ?? DEFAULT_HEALTH_THRESHOLDS.softBodyChars;
97
- this.healthStampDensityPerKb = config.healthStampDensityPerKb ?? DEFAULT_HEALTH_THRESHOLDS.stampDensityPerKb;
98
- this.healthChurnMinPatches = config.healthChurnMinPatches ?? DEFAULT_HEALTH_THRESHOLDS.churnMinPatches;
100
+ this.bootGraceSeconds = field("bootGraceSeconds", config.bootGraceSeconds, 10, 0);
101
+ this.curatorReviewMaxTokens = field("curatorReviewMaxTokens", config.curatorReviewMaxTokens, 2048, 1);
102
+ this.healthSoftBodyChars = field("healthSoftBodyChars", config.healthSoftBodyChars, DEFAULT_HEALTH_THRESHOLDS.softBodyChars, 1);
103
+ this.healthStampDensityPerKb = field("healthStampDensityPerKb", config.healthStampDensityPerKb, DEFAULT_HEALTH_THRESHOLDS.stampDensityPerKb, 1);
104
+ this.healthChurnMinPatches = field("healthChurnMinPatches", config.healthChurnMinPatches, DEFAULT_HEALTH_THRESHOLDS.churnMinPatches, 1);
105
+ if (clamped.length > 0) this.ctx.logger.warn(`evolution-curator: ${clamped.join(", ")} provided an invalid value; falling back to the default`);
99
106
  this.lastRun = Date.now();
100
107
  this.ctx.effect(() => {
101
108
  return () => {
@@ -378,7 +385,8 @@ var EvolutionCurator = class extends Service {
378
385
  const text = await this.skills.read(name);
379
386
  if (text) contents.set(name, text);
380
387
  }
381
- const dedupMembers = [...new Set(computeDedupGroups({ contents }).filter((group) => group.length >= 2).flat())];
388
+ const protectedNames = await this.protectedNameMap();
389
+ const dedupMembers = [...new Set(computeDedupGroups({ contents }).filter((group) => group.length >= 2).flat())].filter((name) => !protectedNames.has(name));
382
390
  await this.scoreTree(usage, treeNames);
383
391
  const result = computeLifecycleTransitions(usage, {
384
392
  staleAfterDays: lifecycle.staleAfterDays,
@@ -546,6 +554,11 @@ var EvolutionCurator = class extends Service {
546
554
  record.archived_at = record.archived_at ?? (/* @__PURE__ */ new Date()).toISOString();
547
555
  stateOwned.add(name);
548
556
  }
557
+ if (bundledNames.has(name)) {
558
+ suppressedNames.add(name);
559
+ suppressedAdded.add(name);
560
+ suppressedChanged = true;
561
+ }
549
562
  continue;
550
563
  }
551
564
  const archived = await this.skills.archive(name, {
@@ -668,7 +681,11 @@ var EvolutionCurator = class extends Service {
668
681
  const raw = await this.io.readText(join(reportsRoot, name));
669
682
  if (raw === null) continue;
670
683
  const parsed = JSON.parse(raw);
671
- const startedAt = typeof parsed.startedAt === "string" ? Date.parse(parsed.startedAt) : NaN;
684
+ let startedAt = typeof parsed.startedAt === "string" ? Date.parse(parsed.startedAt) : NaN;
685
+ if (!Number.isFinite(startedAt)) {
686
+ const mtime = await this.io.mtime?.(join(reportsRoot, name)) ?? null;
687
+ if (mtime !== null) startedAt = mtime;
688
+ }
672
689
  if (Number.isFinite(startedAt)) dated.push({
673
690
  name,
674
691
  startedAt
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.3.24",
4
+ "version": "0.3.25",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,20 +31,20 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-core": "^0.3.24"
34
+ "@lmzhen/dsh-evolution-core": "^0.3.25"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "@deepseek-ai/cordis": "^4.0.1",
38
38
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
39
39
  "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
40
- "@lmzhen/dsh-evolution-io": "^0.3.24",
41
- "@lmzhen/dsh-evolution-state": "^0.3.24"
40
+ "@lmzhen/dsh-evolution-io": "^0.3.25",
41
+ "@lmzhen/dsh-evolution-state": "^0.3.25"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
45
45
  "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
46
- "@lmzhen/dsh-evolution-core": "^0.3.24",
47
- "@lmzhen/dsh-evolution-io": "^0.3.24",
48
- "@lmzhen/dsh-evolution-state": "^0.3.24"
46
+ "@lmzhen/dsh-evolution-core": "^0.3.25",
47
+ "@lmzhen/dsh-evolution-io": "^0.3.25",
48
+ "@lmzhen/dsh-evolution-state": "^0.3.25"
49
49
  }
50
50
  }