@lmzhen/dsh-evolution-curator 0.1.0-rc.26 → 0.1.0-rc.28
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 +48 -7
- package/lib/types/index.d.ts +19 -1
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -3,12 +3,22 @@ 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, SKILL_NAME_RE, SkillLibrary, buildCuratorRunReport, computeLifecycleTransitions, computeQualityScores, emptyRecord, evolutionHome, evolutionIoAdapter, loadSuppressedNames, loadUsage, parseCuratorNominations, parseFrontmatter, 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, SKILL_NAME_RE, SkillLibrary, buildCuratorRunReport, computeLifecycleTransitions, computeQualityScores, computeScopeView, emptyRecord, evolutionHome, evolutionIoAdapter, loadSuppressedNames, loadUsage, parseCuratorNominations, parseFrontmatter, 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.
|
|
10
10
|
* @module @lmzhen/dsh-evolution-curator
|
|
11
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* Block LLM-nominated consolidations that would touch a gate-protected name:
|
|
14
|
+
* exclude / referenced / suppressed skills must never merge (neither as the
|
|
15
|
+
* source being archived nor as the umbrella being edited). Mirrors the control
|
|
16
|
+
* plane's `consolidate()` guard; automatic nominations must pass the same gate.
|
|
17
|
+
*/
|
|
18
|
+
function gateConsolidations(consolidations, gates) {
|
|
19
|
+
const blocked = (name) => gates.exclude?.has(name) === true || gates.referenced?.has(name) === true || gates.suppressed?.has(name) === true;
|
|
20
|
+
return consolidations.filter((n) => !blocked(n.from) && !blocked(n.into));
|
|
21
|
+
}
|
|
12
22
|
var EvolutionCurator = class extends Service {
|
|
13
23
|
static inject = ["evolutionIo"];
|
|
14
24
|
static Config = z.object({
|
|
@@ -219,12 +229,20 @@ var EvolutionCurator = class extends Service {
|
|
|
219
229
|
prunings: [],
|
|
220
230
|
consolidations: []
|
|
221
231
|
};
|
|
222
|
-
const
|
|
232
|
+
const gatedNominations = {
|
|
233
|
+
...nominations,
|
|
234
|
+
consolidations: gateConsolidations(nominations.consolidations, {
|
|
235
|
+
exclude: this.excludeSkillNames,
|
|
236
|
+
referenced: this.referencedSkillNames,
|
|
237
|
+
suppressed: suppressedNames
|
|
238
|
+
})
|
|
239
|
+
};
|
|
240
|
+
const llmNominations = gatedNominations.prunings;
|
|
223
241
|
const archiveCandidates = [...new Set([...result.archive, ...llmNominations])];
|
|
224
242
|
const { archivedSkills, errors } = await this.applyMutations({
|
|
225
243
|
dryRun,
|
|
226
244
|
archiveCandidates,
|
|
227
|
-
nominations,
|
|
245
|
+
nominations: gatedNominations,
|
|
228
246
|
treeNames,
|
|
229
247
|
usage,
|
|
230
248
|
bundledNames,
|
|
@@ -240,7 +258,7 @@ var EvolutionCurator = class extends Service {
|
|
|
240
258
|
llmNominations,
|
|
241
259
|
archiveCandidates,
|
|
242
260
|
archived: archivedSkills,
|
|
243
|
-
failed: [...new Set([...archiveCandidates, ...
|
|
261
|
+
failed: [...new Set([...archiveCandidates, ...gatedNominations.consolidations.map((item) => item.from)])].filter((name) => errors.some((error) => error.startsWith(`${name}:`))).map((name) => {
|
|
244
262
|
return {
|
|
245
263
|
name,
|
|
246
264
|
reason: errors.find((item) => item.startsWith(`${name}:`))?.slice(name.length + 2) ?? "unknown"
|
|
@@ -257,7 +275,7 @@ var EvolutionCurator = class extends Service {
|
|
|
257
275
|
this.ctx.logger.warn(error);
|
|
258
276
|
}
|
|
259
277
|
const llmHint = !this.llmReview && result.markStale.length > 0 ? " (llmReview: off - deterministic archive only; set llmReview: true for the LLM merge channel)" : "";
|
|
260
|
-
const summary = `${dryRun ? "dry-run" : "auto"}: stale:${result.markStale.length} archived:${archivedSkills.length} consolidated:${
|
|
278
|
+
const summary = `${dryRun ? "dry-run" : "auto"}: stale:${result.markStale.length} archived:${archivedSkills.length} consolidated:${gatedNominations.consolidations.length}${llmHint}`;
|
|
261
279
|
await stateService?.saveCuratorState({
|
|
262
280
|
schemaVersion: 1,
|
|
263
281
|
lastRunAt: dryRun ? persisted?.lastRunAt ?? this.lastRun : this.lastRun,
|
|
@@ -270,7 +288,7 @@ var EvolutionCurator = class extends Service {
|
|
|
270
288
|
archived: archivedSkills.map((item) => item.name),
|
|
271
289
|
errors,
|
|
272
290
|
report,
|
|
273
|
-
...this.llmReview ? { nominations } : {}
|
|
291
|
+
...this.llmReview ? { nominations: gatedNominations } : {}
|
|
274
292
|
};
|
|
275
293
|
}
|
|
276
294
|
/**
|
|
@@ -286,6 +304,8 @@ var EvolutionCurator = class extends Service {
|
|
|
286
304
|
treeNames.add(summary.name);
|
|
287
305
|
if (!usage.has(summary.name)) usage.set(summary.name, emptyRecord());
|
|
288
306
|
if (await this.skills.isBundled(summary.name)) bundledNames.add(summary.name);
|
|
307
|
+
const record = usage.get(summary.name);
|
|
308
|
+
if (record) record.pinned = await this.skills.isPinned(summary.name);
|
|
289
309
|
}
|
|
290
310
|
return {
|
|
291
311
|
bundledNames,
|
|
@@ -433,6 +453,27 @@ var EvolutionCurator = class extends Service {
|
|
|
433
453
|
}
|
|
434
454
|
}
|
|
435
455
|
/**
|
|
456
|
+
* Read-only lifecycle scope classification: which skills are in scope,
|
|
457
|
+
* watched (stale/quality-warned), exempted, or protected. Uses the same
|
|
458
|
+
* candidate gate as `run()` (`computeScopeView` / `lifecycleCandidate`),
|
|
459
|
+
* so the view always predicts what a curator pass may touch.
|
|
460
|
+
*/
|
|
461
|
+
async scopeView() {
|
|
462
|
+
const root = this.skills.root;
|
|
463
|
+
const usage = await loadUsage(root, this.io);
|
|
464
|
+
const { bundledNames } = await this.seedBaseline(usage);
|
|
465
|
+
return computeScopeView(usage, {
|
|
466
|
+
staleAfterDays: this.lifecycle().staleAfterDays,
|
|
467
|
+
archiveAfterDays: this.lifecycle().archiveAfterDays,
|
|
468
|
+
excludeSkillNames: this.excludeSkillNames,
|
|
469
|
+
referencedSkillNames: this.referencedSkillNames,
|
|
470
|
+
suppressedNames: new Set(await loadSuppressedNames(root, this.io)),
|
|
471
|
+
manageUnmanaged: this.manageUnmanaged,
|
|
472
|
+
pruneBuiltins: this.pruneBuiltins,
|
|
473
|
+
bundledNames
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
436
477
|
* Control-plane consolidation: merge source skill bodies into `target`,
|
|
437
478
|
* archive the sources with an absorbed-into marker, and fold their usage
|
|
438
479
|
* records into `archived` state. Snapshot-then-mutate, never a hard delete.
|
|
@@ -476,4 +517,4 @@ var EvolutionCurator = class extends Service {
|
|
|
476
517
|
}
|
|
477
518
|
};
|
|
478
519
|
//#endregion
|
|
479
|
-
export { EvolutionCurator, EvolutionCurator as default };
|
|
520
|
+
export { EvolutionCurator, EvolutionCurator as default, gateConsolidations };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
6
6
|
import type Schema from '@deepseek-ai/schemastery';
|
|
7
7
|
import { SkillLibrary } from '@deepseek-ai/dsh-evolution-core';
|
|
8
|
-
import { type CuratorNominations, type CuratorRunReport, type SkillActionResult } from '@deepseek-ai/dsh-evolution-core';
|
|
8
|
+
import { type CuratorConsolidation, type CuratorNominations, type CuratorRunReport, type ScopeView, type SkillActionResult } from '@deepseek-ai/dsh-evolution-core';
|
|
9
9
|
declare module '@deepseek-ai/cordis' {
|
|
10
10
|
interface Context {
|
|
11
11
|
evolutionCurator: EvolutionCurator;
|
|
@@ -54,6 +54,17 @@ export interface CuratorStateRecordShape {
|
|
|
54
54
|
lastSummary: string;
|
|
55
55
|
paused: boolean;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Block LLM-nominated consolidations that would touch a gate-protected name:
|
|
59
|
+
* exclude / referenced / suppressed skills must never merge (neither as the
|
|
60
|
+
* source being archived nor as the umbrella being edited). Mirrors the control
|
|
61
|
+
* plane's `consolidate()` guard; automatic nominations must pass the same gate.
|
|
62
|
+
*/
|
|
63
|
+
export declare function gateConsolidations(consolidations: CuratorConsolidation[], gates: {
|
|
64
|
+
exclude?: ReadonlySet<string>;
|
|
65
|
+
referenced?: ReadonlySet<string>;
|
|
66
|
+
suppressed?: ReadonlySet<string>;
|
|
67
|
+
}): CuratorConsolidation[];
|
|
57
68
|
export declare class EvolutionCurator extends Service {
|
|
58
69
|
static inject: string[];
|
|
59
70
|
static Config: Schema<Config>;
|
|
@@ -124,6 +135,13 @@ export declare class EvolutionCurator extends Service {
|
|
|
124
135
|
private applyMutations;
|
|
125
136
|
private recentSessionActive;
|
|
126
137
|
latestReport(): Promise<CuratorRunReport | null>;
|
|
138
|
+
/**
|
|
139
|
+
* Read-only lifecycle scope classification: which skills are in scope,
|
|
140
|
+
* watched (stale/quality-warned), exempted, or protected. Uses the same
|
|
141
|
+
* candidate gate as `run()` (`computeScopeView` / `lifecycleCandidate`),
|
|
142
|
+
* so the view always predicts what a curator pass may touch.
|
|
143
|
+
*/
|
|
144
|
+
scopeView(): Promise<ScopeView>;
|
|
127
145
|
/**
|
|
128
146
|
* Control-plane consolidation: merge source skill bodies into `target`,
|
|
129
147
|
* archive the sources with an absorbed-into marker, and fold their usage
|
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.
|
|
4
|
+
"version": "0.1.0-rc.28",
|
|
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.
|
|
36
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.28"
|
|
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.
|
|
43
|
-
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.
|
|
42
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.28",
|
|
43
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.28"
|
|
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.
|
|
49
|
-
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.
|
|
50
|
-
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.
|
|
48
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.28",
|
|
49
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.28",
|
|
50
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.28"
|
|
51
51
|
}
|
|
52
52
|
}
|