@lmzhen/dsh-evolution-curator 0.1.0-rc.27 → 0.1.0-rc.29
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 +39 -11
- package/lib/types/index.d.ts +14 -1
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -9,6 +9,16 @@ import { CURATOR_DRY_RUN_BANNER, CURATOR_PROMPT, DEFAULT_ARCHIVE_AFTER_DAYS, DEF
|
|
|
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,17 +229,26 @@ 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,
|
|
231
249
|
suppressedNames,
|
|
232
|
-
root
|
|
250
|
+
root,
|
|
251
|
+
failedFrom: new Map(result.transitions.filter((t) => t.to === "archived").map((t) => [t.name, t.from]))
|
|
233
252
|
});
|
|
234
253
|
if (!dryRun) this.lastRun = Date.now();
|
|
235
254
|
const report = buildCuratorRunReport({
|
|
@@ -240,7 +259,7 @@ var EvolutionCurator = class extends Service {
|
|
|
240
259
|
llmNominations,
|
|
241
260
|
archiveCandidates,
|
|
242
261
|
archived: archivedSkills,
|
|
243
|
-
failed: [...new Set([...archiveCandidates, ...
|
|
262
|
+
failed: [...new Set([...archiveCandidates, ...gatedNominations.consolidations.map((item) => item.from)])].filter((name) => errors.some((error) => error.startsWith(`${name}:`))).map((name) => {
|
|
244
263
|
return {
|
|
245
264
|
name,
|
|
246
265
|
reason: errors.find((item) => item.startsWith(`${name}:`))?.slice(name.length + 2) ?? "unknown"
|
|
@@ -257,7 +276,7 @@ var EvolutionCurator = class extends Service {
|
|
|
257
276
|
this.ctx.logger.warn(error);
|
|
258
277
|
}
|
|
259
278
|
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:${
|
|
279
|
+
const summary = `${dryRun ? "dry-run" : "auto"}: stale:${result.markStale.length} archived:${archivedSkills.length} consolidated:${gatedNominations.consolidations.length}${llmHint}`;
|
|
261
280
|
await stateService?.saveCuratorState({
|
|
262
281
|
schemaVersion: 1,
|
|
263
282
|
lastRunAt: dryRun ? persisted?.lastRunAt ?? this.lastRun : this.lastRun,
|
|
@@ -270,7 +289,7 @@ var EvolutionCurator = class extends Service {
|
|
|
270
289
|
archived: archivedSkills.map((item) => item.name),
|
|
271
290
|
errors,
|
|
272
291
|
report,
|
|
273
|
-
...this.llmReview ? { nominations } : {}
|
|
292
|
+
...this.llmReview ? { nominations: gatedNominations } : {}
|
|
274
293
|
};
|
|
275
294
|
}
|
|
276
295
|
/**
|
|
@@ -346,7 +365,7 @@ var EvolutionCurator = class extends Service {
|
|
|
346
365
|
errors: [],
|
|
347
366
|
suppressedChanged: false
|
|
348
367
|
};
|
|
349
|
-
const { archiveCandidates, nominations, treeNames, usage, bundledNames, suppressedNames, root } = input;
|
|
368
|
+
const { archiveCandidates, nominations, treeNames, usage, bundledNames, suppressedNames, root, failedFrom } = input;
|
|
350
369
|
const errors = [];
|
|
351
370
|
const archivedSkills = [];
|
|
352
371
|
let suppressedChanged = false;
|
|
@@ -357,7 +376,8 @@ var EvolutionCurator = class extends Service {
|
|
|
357
376
|
});
|
|
358
377
|
if (!archived.ok) {
|
|
359
378
|
const record = usage.get(name);
|
|
360
|
-
|
|
379
|
+
const from = failedFrom?.get(name);
|
|
380
|
+
if (record && (from === "stale" || from === "active")) record.state = from;
|
|
361
381
|
errors.push(`${name}: ${archived.message}`);
|
|
362
382
|
} else {
|
|
363
383
|
archivedSkills.push({
|
|
@@ -391,7 +411,7 @@ var EvolutionCurator = class extends Service {
|
|
|
391
411
|
alreadyArchived.add(nomination.from);
|
|
392
412
|
archivedSkills.push({
|
|
393
413
|
name: nomination.from,
|
|
394
|
-
path:
|
|
414
|
+
path: join(this.skills.root, ".archive", nomination.from),
|
|
395
415
|
reason: `Consolidated into ${nomination.into}`
|
|
396
416
|
});
|
|
397
417
|
}
|
|
@@ -453,7 +473,13 @@ var EvolutionCurator = class extends Service {
|
|
|
453
473
|
manageUnmanaged: this.manageUnmanaged,
|
|
454
474
|
pruneBuiltins: this.pruneBuiltins,
|
|
455
475
|
bundledNames
|
|
456
|
-
});
|
|
476
|
+
}, await this.protectedNameMap());
|
|
477
|
+
}
|
|
478
|
+
/** marker info (pinned/bundled/hub-installed) per skill, from the library list. */
|
|
479
|
+
async protectedNameMap() {
|
|
480
|
+
const map = /* @__PURE__ */ new Map();
|
|
481
|
+
for (const summary of await this.skills.list()) if (summary.protectedBy !== null) map.set(summary.name, summary.protectedBy);
|
|
482
|
+
return map;
|
|
457
483
|
}
|
|
458
484
|
/**
|
|
459
485
|
* Control-plane consolidation: merge source skill bodies into `target`,
|
|
@@ -473,6 +499,7 @@ var EvolutionCurator = class extends Service {
|
|
|
473
499
|
for (const source of sources) {
|
|
474
500
|
const record = usage.get(source);
|
|
475
501
|
if (record) record.state = "archived";
|
|
502
|
+
if (record) record.archived_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
476
503
|
}
|
|
477
504
|
await saveUsage(this.skills.root, usage, this.io);
|
|
478
505
|
return result;
|
|
@@ -488,6 +515,7 @@ var EvolutionCurator = class extends Service {
|
|
|
488
515
|
const usage = await loadUsage(this.skills.root, this.io);
|
|
489
516
|
const record = usage.get(name);
|
|
490
517
|
if (record) record.state = "active";
|
|
518
|
+
if (record) record.archived_at = null;
|
|
491
519
|
await saveUsage(this.skills.root, usage, this.io);
|
|
492
520
|
const suppressed = new Set(await loadSuppressedNames(this.skills.root, this.io));
|
|
493
521
|
if (suppressed.delete(name)) try {
|
|
@@ -499,4 +527,4 @@ var EvolutionCurator = class extends Service {
|
|
|
499
527
|
}
|
|
500
528
|
};
|
|
501
529
|
//#endregion
|
|
502
|
-
export { EvolutionCurator, EvolutionCurator as default };
|
|
530
|
+
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 ScopeView, 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>;
|
|
@@ -131,6 +142,8 @@ export declare class EvolutionCurator extends Service {
|
|
|
131
142
|
* so the view always predicts what a curator pass may touch.
|
|
132
143
|
*/
|
|
133
144
|
scopeView(): Promise<ScopeView>;
|
|
145
|
+
/** marker info (pinned/bundled/hub-installed) per skill, from the library list. */
|
|
146
|
+
private protectedNameMap;
|
|
134
147
|
/**
|
|
135
148
|
* Control-plane consolidation: merge source skill bodies into `target`,
|
|
136
149
|
* 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.29",
|
|
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.29"
|
|
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.29",
|
|
43
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.29"
|
|
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.29",
|
|
49
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.29",
|
|
50
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.29"
|
|
51
51
|
}
|
|
52
52
|
}
|