@lmzhen/dsh-evolution-curator 0.3.64 → 0.3.66
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 +58 -12
- package/lib/types/index.d.ts +11 -0
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const DEFAULT_QUALITY_WARN_STALE_AFTER_DAYS = 7;
|
|
|
17
17
|
* 120s matches the review subagent default; the 32-bit ceiling is Node's
|
|
18
18
|
* timer-delay limit (`AbortSignal.timeout` throws above it). */
|
|
19
19
|
const DEFAULT_CURATOR_REVIEW_TIMEOUT_MS = 12e4;
|
|
20
|
-
const MAX_TIMER_DELAY_MS =
|
|
20
|
+
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
21
21
|
/**
|
|
22
22
|
* Block LLM-nominated consolidations that would touch a gate-protected name:
|
|
23
23
|
* exclude / referenced / suppressed skills must never merge (neither as the
|
|
@@ -401,6 +401,17 @@ var EvolutionCurator = class extends Service {
|
|
|
401
401
|
* increments `mutexDepth` synchronously (so run()'s skip check sees queued
|
|
402
402
|
* work), awaits the previous tail, and the returned release resolves the
|
|
403
403
|
* tail for the next entrant. Double-release is a no-op.
|
|
404
|
+
*
|
|
405
|
+
* v20 (C-3) cross-layer note: this chain serializes CURATOR operations
|
|
406
|
+
* only. The review subagent channel writes through its own SkillLibrary
|
|
407
|
+
* and shares NO mutex with this service; the cross-layer exclusion is
|
|
408
|
+
* skill-store's per-file write lock + the F-17 marker probe (a destructive
|
|
409
|
+
* mover refuses a directory whose writer lock is alive), so a collision
|
|
410
|
+
* degrades to a recorded failed op + snapshot rollback, never a torn
|
|
411
|
+
* write. Automatic passes are kept out of the session-active window by the
|
|
412
|
+
* min-idle gate; a manual run (`ignoreGates`) bypasses that gate and is
|
|
413
|
+
* the one realistic interleave window — documented, accepted (plan v20
|
|
414
|
+
* C-3①). The same statement lives on evolution-review's `reviewInFlight`.
|
|
404
415
|
*/
|
|
405
416
|
mutexDepth = 0;
|
|
406
417
|
mutexTail = Promise.resolve();
|
|
@@ -449,13 +460,17 @@ var EvolutionCurator = class extends Service {
|
|
|
449
460
|
skipped: "active-session"
|
|
450
461
|
};
|
|
451
462
|
if (!ignoreGates && persisted === null && (stateService !== void 0 || !this.statelessFirstRunDeferred)) {
|
|
452
|
-
if (stateService)
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
463
|
+
if (stateService) try {
|
|
464
|
+
await stateService.saveCuratorState({
|
|
465
|
+
schemaVersion: 1,
|
|
466
|
+
lastRunAt: Date.now(),
|
|
467
|
+
runCount: 0,
|
|
468
|
+
lastSummary: "first-run-deferred",
|
|
469
|
+
paused: false
|
|
470
|
+
});
|
|
471
|
+
} catch (error) {
|
|
472
|
+
this.ctx.logger.warn(`evolution-curator: failed to persist the first-run baseline: ${error instanceof Error ? error.message : String(error)}`);
|
|
473
|
+
}
|
|
459
474
|
else {
|
|
460
475
|
this.lastRun = Date.now();
|
|
461
476
|
this.statelessFirstRunDeferred = true;
|
|
@@ -472,6 +487,16 @@ var EvolutionCurator = class extends Service {
|
|
|
472
487
|
const rawUsage = await loadUsage(root, this.io);
|
|
473
488
|
const usage = dryRun ? new Map([...rawUsage].map(([name, record]) => [name, { ...record }])) : rawUsage;
|
|
474
489
|
const runStartStates = new Map([...usage].map(([name, record]) => [name, record.state]));
|
|
490
|
+
if (this.isDisposed()) {
|
|
491
|
+
this.ctx.logger.warn("evolution-curator: run aborted before the archive phase (plugin disposed mid-run)");
|
|
492
|
+
return {
|
|
493
|
+
stale: [],
|
|
494
|
+
archived: [],
|
|
495
|
+
errors: ["run aborted: evolution-curator was disposed mid-run"],
|
|
496
|
+
report: this.skippedReport(runId, startedAt),
|
|
497
|
+
skipped: "disposed"
|
|
498
|
+
};
|
|
499
|
+
}
|
|
475
500
|
const snapshotPath = dryRun ? void 0 : await this.snapshotFull("pre-curator-run");
|
|
476
501
|
const suppressedNames = new Set(await loadSuppressedNames(root, this.io));
|
|
477
502
|
const gates = new EvolutionGateSet({
|
|
@@ -658,6 +683,15 @@ var EvolutionCurator = class extends Service {
|
|
|
658
683
|
let suppressedChanged = false;
|
|
659
684
|
const suppressedAdded = /* @__PURE__ */ new Set();
|
|
660
685
|
const stateOwned = new Set(input.stateOwned ?? []);
|
|
686
|
+
if (this.isDisposed()) {
|
|
687
|
+
this.ctx.logger.warn("evolution-curator: run aborted at the archive gate (plugin disposed mid-run)");
|
|
688
|
+
return {
|
|
689
|
+
archivedSkills: [],
|
|
690
|
+
errors: ["run aborted: evolution-curator was disposed mid-run"],
|
|
691
|
+
suppressedChanged: false,
|
|
692
|
+
consolidated: []
|
|
693
|
+
};
|
|
694
|
+
}
|
|
661
695
|
for (const name of archiveCandidates) {
|
|
662
696
|
if (!treeNames.has(name)) {
|
|
663
697
|
const record = usage.get(name);
|
|
@@ -725,7 +759,13 @@ var EvolutionCurator = class extends Service {
|
|
|
725
759
|
}
|
|
726
760
|
}
|
|
727
761
|
const alreadyArchived = new Set(archiveCandidates);
|
|
728
|
-
|
|
762
|
+
let consolidationDisposed = false;
|
|
763
|
+
if (this.isDisposed()) {
|
|
764
|
+
consolidationDisposed = true;
|
|
765
|
+
errors.push("run aborted: evolution-curator was disposed mid-run — consolidation skipped; archives that landed above are still accounted");
|
|
766
|
+
this.ctx.logger.warn("evolution-curator: consolidation phase skipped (plugin disposed mid-run); archive accounts above are preserved");
|
|
767
|
+
}
|
|
768
|
+
for (const nomination of consolidationDisposed ? [] : nominations.consolidations) {
|
|
729
769
|
if (alreadyArchived.has(nomination.from)) continue;
|
|
730
770
|
if (!treeNames.has(nomination.from) || !treeNames.has(nomination.into)) {
|
|
731
771
|
errors.push(`${nomination.from}: consolidation target or source missing from the skill tree`);
|
|
@@ -768,7 +808,9 @@ var EvolutionCurator = class extends Service {
|
|
|
768
808
|
let skipped = [];
|
|
769
809
|
await mutateUsage(root, this.io, (disk) => {
|
|
770
810
|
skipped = foldCuratorFields(disk, usage, stateOwned, runStartStates);
|
|
771
|
-
})
|
|
811
|
+
}, { onQuarantine: (message) => {
|
|
812
|
+
this.ctx.logger.warn(`evolution-curator: ${message}`);
|
|
813
|
+
} });
|
|
772
814
|
if (skipped.length > 0) this.ctx.logger.warn(`evolution-curator: lifecycle fold skipped ${skipped.length} name(s) whose on-disk state moved during the run (a concurrent curator/tool won): ${skipped.join(", ")}`);
|
|
773
815
|
} catch {
|
|
774
816
|
this.ctx.logger.warn("evolution-curator: failed to persist usage sidecar");
|
|
@@ -974,7 +1016,9 @@ var EvolutionCurator = class extends Service {
|
|
|
974
1016
|
record.archived_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
975
1017
|
}
|
|
976
1018
|
}
|
|
977
|
-
})
|
|
1019
|
+
}, { onQuarantine: (message) => {
|
|
1020
|
+
this.ctx.logger.warn(`evolution-curator: ${message}`);
|
|
1021
|
+
} });
|
|
978
1022
|
} catch (error) {
|
|
979
1023
|
this.ctx.logger.warn(`evolution-curator: failed to persist consolidate usage state: ${error instanceof Error ? error.message : String(error)}`);
|
|
980
1024
|
}
|
|
@@ -1003,7 +1047,9 @@ var EvolutionCurator = class extends Service {
|
|
|
1003
1047
|
record.state = "active";
|
|
1004
1048
|
record.archived_at = null;
|
|
1005
1049
|
}
|
|
1006
|
-
})
|
|
1050
|
+
}, { onQuarantine: (message) => {
|
|
1051
|
+
this.ctx.logger.warn(`evolution-curator: ${message}`);
|
|
1052
|
+
} });
|
|
1007
1053
|
} catch (error) {
|
|
1008
1054
|
this.ctx.logger.warn(`evolution-curator: failed to persist restore usage state: ${error instanceof Error ? error.message : String(error)}`);
|
|
1009
1055
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -214,6 +214,17 @@ export declare class EvolutionCurator extends Service {
|
|
|
214
214
|
* increments `mutexDepth` synchronously (so run()'s skip check sees queued
|
|
215
215
|
* work), awaits the previous tail, and the returned release resolves the
|
|
216
216
|
* tail for the next entrant. Double-release is a no-op.
|
|
217
|
+
*
|
|
218
|
+
* v20 (C-3) cross-layer note: this chain serializes CURATOR operations
|
|
219
|
+
* only. The review subagent channel writes through its own SkillLibrary
|
|
220
|
+
* and shares NO mutex with this service; the cross-layer exclusion is
|
|
221
|
+
* skill-store's per-file write lock + the F-17 marker probe (a destructive
|
|
222
|
+
* mover refuses a directory whose writer lock is alive), so a collision
|
|
223
|
+
* degrades to a recorded failed op + snapshot rollback, never a torn
|
|
224
|
+
* write. Automatic passes are kept out of the session-active window by the
|
|
225
|
+
* min-idle gate; a manual run (`ignoreGates`) bypasses that gate and is
|
|
226
|
+
* the one realistic interleave window — documented, accepted (plan v20
|
|
227
|
+
* C-3①). The same statement lives on evolution-review's `reviewInFlight`.
|
|
217
228
|
*/
|
|
218
229
|
private mutexDepth;
|
|
219
230
|
private mutexTail;
|
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.66",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -31,20 +31,20 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
34
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
34
|
+
"@lmzhen/dsh-evolution-core": "^0.3.66"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
38
38
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
39
39
|
"@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
|
|
40
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
41
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
40
|
+
"@lmzhen/dsh-evolution-io": "^0.3.66",
|
|
41
|
+
"@lmzhen/dsh-evolution-state": "^0.3.66"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
45
45
|
"@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
|
|
46
|
-
"@lmzhen/dsh-evolution-core": "^0.3.
|
|
47
|
-
"@lmzhen/dsh-evolution-io": "^0.3.
|
|
48
|
-
"@lmzhen/dsh-evolution-state": "^0.3.
|
|
46
|
+
"@lmzhen/dsh-evolution-core": "^0.3.66",
|
|
47
|
+
"@lmzhen/dsh-evolution-io": "^0.3.66",
|
|
48
|
+
"@lmzhen/dsh-evolution-state": "^0.3.66"
|
|
49
49
|
}
|
|
50
50
|
}
|