@lmzhen/dsh-evolution-curator 0.1.0-rc.48 → 0.1.0-rc.49

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
@@ -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_MIN_IDLE_HOURS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, SkillLibrary, buildCuratorRunReport, computeLifecycleTransitions, computeQualityScores, computeScopeView, emptyRecord, evolutionHome, evolutionIoAdapter, loadSuppressedNames, loadUsage, parseCuratorNominations, relatedSkillNames, saveSuppressedNames, saveUsage } from "@lmzhen/dsh-evolution-core";
6
+ import { CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_MIN_IDLE_HOURS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, SkillLibrary, buildCuratorRunReport, computeLifecycleTransitions, computeQualityScores, computeScopeView, emptyRecord, evolutionHome, evolutionIoAdapter, loadSuppressedNames, loadUsage, parseCuratorNominations, relatedSkillNames, renderCuratorReportMarkdown, saveSuppressedNames, saveUsage } 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.
@@ -63,7 +63,9 @@ var EvolutionCurator = class extends Service {
63
63
  constructor(ctx, config = {}) {
64
64
  super(ctx, "evolutionCurator");
65
65
  this.io = evolutionIoAdapter(() => ctx.evolutionIo.provider());
66
- this.skills = new SkillLibrary(void 0, this.io);
66
+ this.skills = new SkillLibrary(void 0, this.io, void 0, (event) => {
67
+ this.ctx.emit("evolution/skill-mutated", event);
68
+ });
67
69
  this.enabled = config.enabled ?? true;
68
70
  this.intervalHours = config.intervalHours ?? DEFAULT_CURATOR_INTERVAL_HOURS;
69
71
  this.staleAfterDays = config.staleAfterDays ?? DEFAULT_STALE_AFTER_DAYS;
@@ -386,6 +388,8 @@ var EvolutionCurator = class extends Service {
386
388
  const reportsRoot = join(evolutionHome(), "reports");
387
389
  try {
388
390
  await this.io.writeText(join(reportsRoot, `curator-${runId}.json`), JSON.stringify(report, null, 2));
391
+ await this.io.writeText(join(reportsRoot, `curator-${runId}.md`), renderCuratorReportMarkdown(report));
392
+ await this.retainReports(20);
389
393
  } catch (error) {
390
394
  this.ctx.logger.warn(`evolution-curator: failed to persist report ${runId}`);
391
395
  this.ctx.logger.warn(error);
@@ -560,6 +564,42 @@ var EvolutionCurator = class extends Service {
560
564
  }
561
565
  return latest > 0 && Date.now() - latest < this.minIdleHours * 36e5;
562
566
  }
567
+ /**
568
+ * Keep only the newest N curator reports, ordered by the report's own
569
+ * `startedAt` (the runId is a UUID and cannot order history). Best-effort
570
+ * like `retainSnapshots`: a failed removal must not fail the run that just
571
+ * persisted its report. The paired `.md` digest is pruned with its JSON.
572
+ */
573
+ async retainReports(keep) {
574
+ const reportsRoot = join(evolutionHome(), "reports");
575
+ let entries;
576
+ try {
577
+ entries = await this.io.list(reportsRoot);
578
+ } catch {
579
+ return;
580
+ }
581
+ const dated = [];
582
+ for (const name of entries.filter((entry) => entry.startsWith("curator-") && entry.endsWith(".json"))) try {
583
+ const raw = await this.io.readText(join(reportsRoot, name));
584
+ if (raw === null) continue;
585
+ const parsed = JSON.parse(raw);
586
+ const startedAt = typeof parsed.startedAt === "string" ? Date.parse(parsed.startedAt) : NaN;
587
+ if (Number.isFinite(startedAt)) dated.push({
588
+ name,
589
+ startedAt
590
+ });
591
+ } catch {}
592
+ dated.sort((a, b) => b.startedAt - a.startedAt);
593
+ for (const oldReport of dated.slice(keep)) {
594
+ const stem = oldReport.name.replace(/\.json$/, "");
595
+ try {
596
+ await this.io.remove(join(reportsRoot, oldReport.name));
597
+ } catch {}
598
+ try {
599
+ await this.io.remove(join(reportsRoot, `${stem}.md`));
600
+ } catch {}
601
+ }
602
+ }
563
603
  async latestReport() {
564
604
  const reportsRoot = join(evolutionHome(), "reports");
565
605
  const latest = (await this.io.list(reportsRoot)).filter((name) => name.startsWith("curator-") && name.endsWith(".json")).sort().reverse()[0];
@@ -186,6 +186,13 @@ export declare class EvolutionCurator extends Service {
186
186
  */
187
187
  private applyMutations;
188
188
  private recentSessionActive;
189
+ /**
190
+ * Keep only the newest N curator reports, ordered by the report's own
191
+ * `startedAt` (the runId is a UUID and cannot order history). Best-effort
192
+ * like `retainSnapshots`: a failed removal must not fail the run that just
193
+ * persisted its report. The paired `.md` digest is pruned with its JSON.
194
+ */
195
+ private retainReports;
189
196
  latestReport(): Promise<CuratorRunReport | null>;
190
197
  /**
191
198
  * Read-only lifecycle scope classification: which skills are in scope,
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.1.0-rc.48",
4
+ "version": "0.1.0-rc.49",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -33,20 +33,20 @@
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
35
  "@deepseek-ai/schemastery": "^3.18.1",
36
- "@lmzhen/dsh-evolution-core": "^0.1.0-rc.48"
36
+ "@lmzhen/dsh-evolution-core": "^0.1.0-rc.49"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.1",
40
40
  "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
41
41
  "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
42
- "@lmzhen/dsh-evolution-io": "^0.1.0-rc.48",
43
- "@lmzhen/dsh-evolution-state": "^0.1.0-rc.48"
42
+ "@lmzhen/dsh-evolution-io": "^0.1.0-rc.49",
43
+ "@lmzhen/dsh-evolution-state": "^0.1.0-rc.49"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
47
47
  "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
48
- "@lmzhen/dsh-evolution-core": "^0.1.0-rc.48",
49
- "@lmzhen/dsh-evolution-io": "^0.1.0-rc.48",
50
- "@lmzhen/dsh-evolution-state": "^0.1.0-rc.48"
48
+ "@lmzhen/dsh-evolution-core": "^0.1.0-rc.49",
49
+ "@lmzhen/dsh-evolution-io": "^0.1.0-rc.49",
50
+ "@lmzhen/dsh-evolution-state": "^0.1.0-rc.49"
51
51
  }
52
52
  }