@lmzhen/dsh-evolution-curator 0.3.74 → 0.3.77
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/README.md +2 -0
- package/lib/index.js +38 -8
- package/lib/types/index.d.ts +1 -1
- package/package.json +7 -13
- package/lib/invariant.js +0 -8
- package/lib/types/invariant.d.ts +0 -5
package/README.md
CHANGED
|
@@ -39,3 +39,5 @@ Independent of request-prefix construction. This package does not alter the asse
|
|
|
39
39
|
|
|
40
40
|
- `autoStart` (default true) arms an hourly interval check plus a deferred catch-up check `bootGraceSeconds` (default 10) after host boot. Both decide due-ness from the **persisted** `lastRunAt`, so a restart with an overdue schedule runs the first pass within the boot grace instead of waiting a full interval. `bootGraceSeconds: 0` disables the deferral (not recommended: the check may run against a half-mounted host). All scheduling gates — interval, idle, first-run deferral, and the reentrancy guard — remain inside `run()`.
|
|
41
41
|
- `autoStart: false` disables both automatic checks; `/evolution curator run` (manual, gate-skipping) still works.
|
|
42
|
+
|
|
43
|
+
**Runtime invariant:** No companion is published. The platform auto-assembles nothing and the family mounts no `<pkg>/invariant` cordis row, so a companion here would never execute (v37 S2.1 / I-3).
|
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_BOOT_GRACE_SECONDS, DEFAULT_CURATOR_INTERVAL_HOURS, DEFAULT_CURATOR_MODEL, DEFAULT_CURATOR_REVIEW_MAX_TOKENS, DEFAULT_HEALTH_THRESHOLDS, DEFAULT_MIN_IDLE_HOURS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, MAX_TIMER_DELAY_MS, SKILL_NAME_RE,
|
|
6
|
+
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_STALE_AFTER_DAYS, EvolutionGateSet, MAX_TIMER_DELAY_MS, SKILL_NAME_RE, buildCuratorRunReport, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, emptyRecord, evolutionHome, evolutionIoAdapter, foldCuratorFields, loadSuppressedNames, loadUsage, markerEntryName, mutateUsage, newSkillLibrary, parseCuratorNominations, parseFrontmatter, 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.
|
|
@@ -95,8 +95,10 @@ var EvolutionCurator = class extends Service {
|
|
|
95
95
|
constructor(ctx, config = {}) {
|
|
96
96
|
super(ctx, "evolutionCurator");
|
|
97
97
|
this.io = evolutionIoAdapter(() => ctx.evolutionIo.provider());
|
|
98
|
-
this.skills =
|
|
99
|
-
|
|
98
|
+
this.skills = newSkillLibrary({
|
|
99
|
+
config,
|
|
100
|
+
io: this.io,
|
|
101
|
+
ctx: this.ctx
|
|
100
102
|
});
|
|
101
103
|
this.enabled = config.enabled ?? true;
|
|
102
104
|
const clamped = [];
|
|
@@ -524,7 +526,7 @@ var EvolutionCurator = class extends Service {
|
|
|
524
526
|
suppressedNames,
|
|
525
527
|
referencedSkillNames: this.referencedSkillNames
|
|
526
528
|
}, /* @__PURE__ */ new Date(), gates, protectedNames);
|
|
527
|
-
const recommendPool = [...new Set([...result.markStale, ...dedupMembers])];
|
|
529
|
+
const recommendPool = [...new Set([...result.markStale, ...dedupMembers])].filter((name) => SKILL_NAME_RE.test(name));
|
|
528
530
|
const nominations = this.llmReview ? await this.recommend(recommendPool, { dryRun }) : {
|
|
529
531
|
prunings: [],
|
|
530
532
|
consolidations: [],
|
|
@@ -742,6 +744,7 @@ var EvolutionCurator = class extends Service {
|
|
|
742
744
|
consolidated: []
|
|
743
745
|
};
|
|
744
746
|
}
|
|
747
|
+
const alreadyArchived = /* @__PURE__ */ new Set();
|
|
745
748
|
for (const name of archiveCandidates) {
|
|
746
749
|
if (!treeNames.has(name)) {
|
|
747
750
|
const record = usage.get(name);
|
|
@@ -751,6 +754,10 @@ var EvolutionCurator = class extends Service {
|
|
|
751
754
|
stateOwned.add(name);
|
|
752
755
|
this.ctx.logger.warn(`evolution-curator: skill "${name}" left the tree without an archive move - its usage record was folded to archived; if the directory is still on disk, repair or remove it manually (it will not re-enter the lifecycle while the record is archived)`);
|
|
753
756
|
}
|
|
757
|
+
if (!SKILL_NAME_RE.test(name)) {
|
|
758
|
+
this.ctx.logger.warn(`evolution-curator: usage sidecar key "${name}" is not a valid skill name - skipped (no archive/marker probe, no suppression write)`);
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
754
761
|
let wasBundled = false;
|
|
755
762
|
try {
|
|
756
763
|
wasBundled = await this.io.exists(join(this.skills.root, ".archive", name, markerEntryName("bundled")));
|
|
@@ -802,6 +809,7 @@ var EvolutionCurator = class extends Service {
|
|
|
802
809
|
path: archived.path ?? "",
|
|
803
810
|
reason: "Lifecycle: reached archive threshold"
|
|
804
811
|
});
|
|
812
|
+
alreadyArchived.add(name);
|
|
805
813
|
if (bundledNames.has(name)) {
|
|
806
814
|
suppressedNames.add(name);
|
|
807
815
|
suppressedAdded.add(name);
|
|
@@ -809,7 +817,6 @@ var EvolutionCurator = class extends Service {
|
|
|
809
817
|
}
|
|
810
818
|
}
|
|
811
819
|
}
|
|
812
|
-
const alreadyArchived = new Set(archiveCandidates);
|
|
813
820
|
let consolidationDisposed = false;
|
|
814
821
|
if (this.isDisposed()) {
|
|
815
822
|
consolidationDisposed = true;
|
|
@@ -840,7 +847,8 @@ var EvolutionCurator = class extends Service {
|
|
|
840
847
|
alreadyArchived.add(nomination.from);
|
|
841
848
|
executedConsolidations.push({
|
|
842
849
|
from: nomination.from,
|
|
843
|
-
into: nomination.into
|
|
850
|
+
into: nomination.into,
|
|
851
|
+
...nomination.mode === void 0 ? {} : { mode: nomination.mode }
|
|
844
852
|
});
|
|
845
853
|
archivedSkills.push({
|
|
846
854
|
name: nomination.from,
|
|
@@ -905,6 +913,7 @@ var EvolutionCurator = class extends Service {
|
|
|
905
913
|
}
|
|
906
914
|
const real = [];
|
|
907
915
|
const errors = [];
|
|
916
|
+
let unorderableWarned = false;
|
|
908
917
|
for (const name of entries.filter((entry) => entry.startsWith("curator-") && entry.endsWith(".json"))) try {
|
|
909
918
|
const raw = await this.io.readText(join(reportsRoot, name));
|
|
910
919
|
if (raw === null) continue;
|
|
@@ -914,10 +923,15 @@ var EvolutionCurator = class extends Service {
|
|
|
914
923
|
const mtime = await this.io.mtime?.(join(reportsRoot, name)) ?? null;
|
|
915
924
|
if (mtime !== null) startedAt = mtime;
|
|
916
925
|
}
|
|
926
|
+
if (!Number.isFinite(startedAt) && typeof parsed.at === "string") startedAt = Date.parse(parsed.at);
|
|
917
927
|
if (Number.isFinite(startedAt)) (name.startsWith("curator-error-") ? errors : real).push({
|
|
918
928
|
name,
|
|
919
929
|
startedAt
|
|
920
930
|
});
|
|
931
|
+
else if (!unorderableWarned) {
|
|
932
|
+
unorderableWarned = true;
|
|
933
|
+
this.ctx.logger.warn(`evolution-curator: report "${name}" carries no usable timestamp and this backend has no mtime probe - it is kept outside the retention window`);
|
|
934
|
+
}
|
|
921
935
|
} catch {}
|
|
922
936
|
real.sort((a, b) => b.startedAt - a.startedAt);
|
|
923
937
|
errors.sort((a, b) => b.startedAt - a.startedAt);
|
|
@@ -938,10 +952,26 @@ var EvolutionCurator = class extends Service {
|
|
|
938
952
|
}
|
|
939
953
|
async latestReport() {
|
|
940
954
|
const reportsRoot = join(evolutionHome(), "reports");
|
|
941
|
-
|
|
955
|
+
let names;
|
|
956
|
+
try {
|
|
957
|
+
names = (await this.io.list(reportsRoot)).filter((name) => name.startsWith("curator-") && name.endsWith(".json") && !name.startsWith("curator-error-"));
|
|
958
|
+
} catch (error) {
|
|
959
|
+
this.ctx.logger.warn(`evolution-curator: latestReport could not list the reports directory (${error instanceof Error ? error.message : String(error)}) - answering "no report"`);
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
942
962
|
let latest = null;
|
|
963
|
+
let probeWarned = false;
|
|
943
964
|
for (const name of names) {
|
|
944
|
-
|
|
965
|
+
let mtime;
|
|
966
|
+
try {
|
|
967
|
+
mtime = await this.io.mtime?.(join(reportsRoot, name)) ?? null;
|
|
968
|
+
} catch (error) {
|
|
969
|
+
if (!probeWarned) {
|
|
970
|
+
probeWarned = true;
|
|
971
|
+
this.ctx.logger.warn(`evolution-curator: latestReport could not read a report mtime (${error instanceof Error ? error.message : String(error)}) - the affected report(s) are not eligible as the latest`);
|
|
972
|
+
}
|
|
973
|
+
continue;
|
|
974
|
+
}
|
|
945
975
|
if (mtime === null) continue;
|
|
946
976
|
if (latest === null || mtime > latest.mtime) latest = {
|
|
947
977
|
name,
|
package/lib/types/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
6
6
|
import type Schema from '@deepseek-ai/schemastery';
|
|
7
|
-
import { EvolutionGateSet, SkillLibrary } from '@lmzhen/dsh-evolution-core';
|
|
7
|
+
import { EvolutionGateSet, type SkillLibrary } from '@lmzhen/dsh-evolution-core';
|
|
8
8
|
import { type CuratorConsolidation, type CuratorNominations, type CuratorRunReport, type ScopeView, type SkillActionResult, type SkillHealthVerdict } from '@lmzhen/dsh-evolution-core';
|
|
9
9
|
import type { CuratorStateRecord } from '@lmzhen/dsh-evolution-state';
|
|
10
10
|
declare module '@deepseek-ai/cordis' {
|
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.
|
|
4
|
+
"version": "0.3.77",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"types": "./lib/types/index.d.ts",
|
|
19
19
|
"default": "./lib/index.js"
|
|
20
20
|
},
|
|
21
|
-
"./invariant": {
|
|
22
|
-
"types": "./lib/types/invariant.d.ts",
|
|
23
|
-
"default": "./lib/invariant.js"
|
|
24
|
-
},
|
|
25
21
|
"./package.json": "./package.json"
|
|
26
22
|
},
|
|
27
23
|
"files": [
|
|
@@ -31,22 +27,20 @@
|
|
|
31
27
|
"license": "MIT",
|
|
32
28
|
"dependencies": {
|
|
33
29
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
34
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
30
|
+
"@lmzhen/dsh-evolution-core": "^0.3.77"
|
|
35
31
|
},
|
|
36
32
|
"peerDependencies": {
|
|
37
33
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
38
|
-
"@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
|
|
39
34
|
"@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
|
|
40
35
|
"@deepseek-ai/dsh-session": "^0.1.5-rc.2",
|
|
41
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
42
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
36
|
+
"@lmzhen/dsh-evolution-io": "^0.3.77",
|
|
37
|
+
"@lmzhen/dsh-evolution-state": "^0.3.77"
|
|
43
38
|
},
|
|
44
39
|
"devDependencies": {
|
|
45
|
-
"@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
|
|
46
40
|
"@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
|
|
47
41
|
"@deepseek-ai/dsh-session": "^0.1.5-rc.2",
|
|
48
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
49
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
50
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
42
|
+
"@lmzhen/dsh-evolution-core": "^0.3.77",
|
|
43
|
+
"@lmzhen/dsh-evolution-io": "^0.3.77",
|
|
44
|
+
"@lmzhen/dsh-evolution-state": "^0.3.77"
|
|
51
45
|
}
|
|
52
46
|
}
|
package/lib/invariant.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
//#region lib/types/invariant.js
|
|
2
|
-
const PACKAGE_NAME = "@lmzhen/dsh-evolution-curator";
|
|
3
|
-
const name = "evolution-curator-invariant";
|
|
4
|
-
const inject = ["invariants"];
|
|
5
|
-
const install = () => {};
|
|
6
|
-
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
7
|
-
//#endregion
|
|
8
|
-
export { apply, inject, name };
|
package/lib/types/invariant.d.ts
DELETED