@lmzhen/dsh-evolution-curator 0.1.0-rc.16 → 0.1.0-rc.18
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 +106 -70
- package/lib/types/index.d.ts +10 -0
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -197,81 +197,23 @@ var EvolutionCurator = class extends Service {
|
|
|
197
197
|
suppressedNames,
|
|
198
198
|
referencedSkillNames: this.referencedSkillNames
|
|
199
199
|
});
|
|
200
|
-
|
|
201
|
-
for (const name of treeNames) supportDirs.set(name, await this.skills.countSupportDirs(name));
|
|
202
|
-
const quality = computeQualityScores({
|
|
203
|
-
usage,
|
|
204
|
-
supportDirs
|
|
205
|
-
});
|
|
206
|
-
for (const [name, score] of quality) {
|
|
207
|
-
const record = usage.get(name);
|
|
208
|
-
if (record) {
|
|
209
|
-
record.quality_score = score.score;
|
|
210
|
-
record.quality_warn = score.warn;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
const errors = [];
|
|
214
|
-
const archivedSkills = [];
|
|
200
|
+
await this.scoreTree(usage, treeNames);
|
|
215
201
|
const nominations = this.llmReview ? await this.recommend(result.markStale, { dryRun }) : {
|
|
216
202
|
prunings: [],
|
|
217
203
|
consolidations: []
|
|
218
204
|
};
|
|
219
205
|
const llmNominations = nominations.prunings;
|
|
220
206
|
const archiveCandidates = [...new Set([...result.archive, ...llmNominations])];
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
errors.push(`${name}: ${archived.message}`);
|
|
232
|
-
} else {
|
|
233
|
-
archivedSkills.push({
|
|
234
|
-
name,
|
|
235
|
-
path: archived.path ?? "",
|
|
236
|
-
reason: "Lifecycle: reached archive threshold"
|
|
237
|
-
});
|
|
238
|
-
if (bundledNames.has(name)) {
|
|
239
|
-
suppressedNames.add(name);
|
|
240
|
-
suppressedChanged = true;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
const alreadyArchived = new Set(archiveCandidates);
|
|
245
|
-
for (const nomination of nominations.consolidations) {
|
|
246
|
-
if (alreadyArchived.has(nomination.from)) continue;
|
|
247
|
-
if (!treeNames.has(nomination.from) || !treeNames.has(nomination.into)) {
|
|
248
|
-
errors.push(`${nomination.from}: consolidation target or source missing from the skill tree`);
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
const consolidated = await this.skills.consolidate(nomination.into, [nomination.from], "background_review");
|
|
252
|
-
if (!consolidated.ok) {
|
|
253
|
-
errors.push(`${nomination.from}: ${consolidated.message}`);
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
const record = usage.get(nomination.from);
|
|
257
|
-
if (record) {
|
|
258
|
-
record.state = "archived";
|
|
259
|
-
record.archived_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
260
|
-
}
|
|
261
|
-
alreadyArchived.add(nomination.from);
|
|
262
|
-
archivedSkills.push({
|
|
263
|
-
name: nomination.from,
|
|
264
|
-
path: consolidated.path ?? "",
|
|
265
|
-
reason: `Consolidated into ${nomination.into}`
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
if (suppressedChanged) try {
|
|
269
|
-
await saveSuppressedNames(root, suppressedNames, this.io);
|
|
270
|
-
} catch {
|
|
271
|
-
this.ctx.logger.warn("evolution-curator: failed to persist suppressed names; archived built-ins may re-enter the lifecycle");
|
|
272
|
-
}
|
|
273
|
-
await saveUsage(root, usage, this.io);
|
|
274
|
-
}
|
|
207
|
+
const { archivedSkills, errors } = await this.applyMutations({
|
|
208
|
+
dryRun,
|
|
209
|
+
archiveCandidates,
|
|
210
|
+
nominations,
|
|
211
|
+
treeNames,
|
|
212
|
+
usage,
|
|
213
|
+
bundledNames,
|
|
214
|
+
suppressedNames,
|
|
215
|
+
root
|
|
216
|
+
});
|
|
275
217
|
if (!dryRun) this.lastRun = Date.now();
|
|
276
218
|
const report = buildCuratorRunReport({
|
|
277
219
|
runId,
|
|
@@ -281,7 +223,7 @@ var EvolutionCurator = class extends Service {
|
|
|
281
223
|
llmNominations,
|
|
282
224
|
archiveCandidates,
|
|
283
225
|
archived: archivedSkills,
|
|
284
|
-
failed: archiveCandidates.filter((name) => errors.some((error) => error.startsWith(`${name}:`))).map((name) => {
|
|
226
|
+
failed: [...new Set([...archiveCandidates, ...nominations.consolidations.map((item) => item.from)])].filter((name) => errors.some((error) => error.startsWith(`${name}:`))).map((name) => {
|
|
285
227
|
return {
|
|
286
228
|
name,
|
|
287
229
|
reason: errors.find((item) => item.startsWith(`${name}:`))?.slice(name.length + 2) ?? "unknown"
|
|
@@ -330,6 +272,100 @@ var EvolutionCurator = class extends Service {
|
|
|
330
272
|
treeNames
|
|
331
273
|
};
|
|
332
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* F13 six-factor quality scoring, persisted onto the usage records.
|
|
277
|
+
*/
|
|
278
|
+
async scoreTree(usage, treeNames) {
|
|
279
|
+
const supportDirs = /* @__PURE__ */ new Map();
|
|
280
|
+
for (const name of treeNames) supportDirs.set(name, await this.skills.countSupportDirs(name));
|
|
281
|
+
const quality = computeQualityScores({
|
|
282
|
+
usage,
|
|
283
|
+
supportDirs
|
|
284
|
+
});
|
|
285
|
+
for (const [name, score] of quality) {
|
|
286
|
+
const record = usage.get(name);
|
|
287
|
+
if (record) {
|
|
288
|
+
record.quality_score = score.score;
|
|
289
|
+
record.quality_warn = score.warn;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Execute lifecycle archives and consolidation nominations, then persist the
|
|
295
|
+
* suppression and usage sidecars best-effort. A dry-run short-circuits: no
|
|
296
|
+
* file moves and no state persistence — the caller still writes the report.
|
|
297
|
+
*/
|
|
298
|
+
async applyMutations(input) {
|
|
299
|
+
if (input.dryRun) return {
|
|
300
|
+
archivedSkills: [],
|
|
301
|
+
errors: [],
|
|
302
|
+
suppressedChanged: false
|
|
303
|
+
};
|
|
304
|
+
const { archiveCandidates, nominations, treeNames, usage, bundledNames, suppressedNames, root } = input;
|
|
305
|
+
const errors = [];
|
|
306
|
+
const archivedSkills = [];
|
|
307
|
+
let suppressedChanged = false;
|
|
308
|
+
for (const name of archiveCandidates) {
|
|
309
|
+
const archived = await this.skills.archive(name, {
|
|
310
|
+
reason: "Lifecycle: reached archive threshold",
|
|
311
|
+
allowBundled: this.pruneBuiltins
|
|
312
|
+
});
|
|
313
|
+
if (!archived.ok) {
|
|
314
|
+
const record = usage.get(name);
|
|
315
|
+
if (record) record.state = "active";
|
|
316
|
+
errors.push(`${name}: ${archived.message}`);
|
|
317
|
+
} else {
|
|
318
|
+
archivedSkills.push({
|
|
319
|
+
name,
|
|
320
|
+
path: archived.path ?? "",
|
|
321
|
+
reason: "Lifecycle: reached archive threshold"
|
|
322
|
+
});
|
|
323
|
+
if (bundledNames.has(name)) {
|
|
324
|
+
suppressedNames.add(name);
|
|
325
|
+
suppressedChanged = true;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const alreadyArchived = new Set(archiveCandidates);
|
|
330
|
+
for (const nomination of nominations.consolidations) {
|
|
331
|
+
if (alreadyArchived.has(nomination.from)) continue;
|
|
332
|
+
if (!treeNames.has(nomination.from) || !treeNames.has(nomination.into)) {
|
|
333
|
+
errors.push(`${nomination.from}: consolidation target or source missing from the skill tree`);
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const consolidated = await this.skills.consolidate(nomination.into, [nomination.from], "background_review");
|
|
337
|
+
if (!consolidated.ok) {
|
|
338
|
+
errors.push(`${nomination.from}: ${consolidated.message}`);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const record = usage.get(nomination.from);
|
|
342
|
+
if (record) {
|
|
343
|
+
record.state = "archived";
|
|
344
|
+
record.archived_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
345
|
+
}
|
|
346
|
+
alreadyArchived.add(nomination.from);
|
|
347
|
+
archivedSkills.push({
|
|
348
|
+
name: nomination.from,
|
|
349
|
+
path: consolidated.path ?? "",
|
|
350
|
+
reason: `Consolidated into ${nomination.into}`
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (suppressedChanged) try {
|
|
354
|
+
await saveSuppressedNames(root, suppressedNames, this.io);
|
|
355
|
+
} catch {
|
|
356
|
+
this.ctx.logger.warn("evolution-curator: failed to persist suppressed names; archived built-ins may re-enter the lifecycle");
|
|
357
|
+
}
|
|
358
|
+
try {
|
|
359
|
+
await saveUsage(root, usage, this.io);
|
|
360
|
+
} catch {
|
|
361
|
+
this.ctx.logger.warn("evolution-curator: failed to persist usage sidecar");
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
archivedSkills,
|
|
365
|
+
errors,
|
|
366
|
+
suppressedChanged
|
|
367
|
+
};
|
|
368
|
+
}
|
|
333
369
|
recentSessionActive() {
|
|
334
370
|
const agents = this.ctx.get("agents");
|
|
335
371
|
if (!agents) return false;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -97,6 +97,16 @@ export declare class EvolutionCurator extends Service {
|
|
|
97
97
|
* returns the full active tree names for nomination validation.
|
|
98
98
|
*/
|
|
99
99
|
private seedBaseline;
|
|
100
|
+
/**
|
|
101
|
+
* F13 six-factor quality scoring, persisted onto the usage records.
|
|
102
|
+
*/
|
|
103
|
+
private scoreTree;
|
|
104
|
+
/**
|
|
105
|
+
* Execute lifecycle archives and consolidation nominations, then persist the
|
|
106
|
+
* suppression and usage sidecars best-effort. A dry-run short-circuits: no
|
|
107
|
+
* file moves and no state persistence — the caller still writes the report.
|
|
108
|
+
*/
|
|
109
|
+
private applyMutations;
|
|
100
110
|
private recentSessionActive;
|
|
101
111
|
latestReport(): Promise<CuratorRunReport | null>;
|
|
102
112
|
/**
|
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.18",
|
|
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.18"
|
|
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.18",
|
|
43
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.18"
|
|
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.18",
|
|
49
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.18",
|
|
50
|
+
"@lmzhen/dsh-evolution-state": "^0.1.0-rc.18"
|
|
51
51
|
}
|
|
52
52
|
}
|