@lmzhen/dsh-evolution-curator 0.26.15 → 0.26.26
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 +31 -14
- package/lib/types/index.d.ts +5 -0
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Service } from "@deepseek-ai/cordis";
|
|
2
|
+
import { BASELINE_ACTION, 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_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_LIMITS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, INSTANCE_KEYS, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, SKILL_NAME_RE, authorityFrom, blobPath, buildCuratorRunReport, claimInstance, clampOnce, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, emptyRecord, entryTarget, evolutionHome, evolutionIoAdapter, foldCuratorFields, historyIndexFile, isPresent, isUnknown, lintSkill, liveBool, loadSuppressedNames, loadUsage, markerEntryName, mutateUsage, newSkillLibrary, paramRowId, parseCuratorNominations, parseFrontmatter, parseHistoryIndex, pickWithPolicy, policyStageLimits, probeList, probeText, readNumberParam, relatedSkillNames, releaseInstance, renderCuratorReportMarkdown, reportTime, reportsSweepLockTarget, resolveUnitMembers, sessionLastEventTime, staleRouteStubs, sweepReports, transactIo, unitMembersAreComplete, unwrapLive, updateSuppressedNames, usageObserved, userSetKeys, verifyPromptBundle, withTreeWrite } from "@lmzhen/dsh-evolution-core";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
5
6
|
import z from "@deepseek-ai/schemastery";
|
|
6
|
-
import { preferProvider } from "@lmzhen/dsh-evolution-io";
|
|
7
|
-
import { BASELINE_ACTION, 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_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_LIMITS, DEFAULT_STALE_AFTER_DAYS, EvolutionGateSet, INSTANCE_KEYS, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, SKILL_NAME_RE, blobPath, buildCuratorRunReport, claimInstance, clampOnce, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, emptyRecord, entryTarget, evolutionHome, evolutionIoAdapter, foldCuratorFields, historyIndexFile, isPresent, isUnknown, lintSkill, liveBool, loadSuppressedNames, loadUsage, markerEntryName, mutateUsage, newSkillLibrary, paramRowId, parseCuratorNominations, parseFrontmatter, parseHistoryIndex, pickWithPolicy, policyStageLimits, probeList, probeText, readNumberParam, relatedSkillNames, releaseInstance, renderCuratorReportMarkdown, reportTime, reportsSweepLockTarget, resolveUnitMembers, sessionLastEventTime, staleRouteStubs, sweepReports, transactIo, unitMembersAreComplete, unwrapLive, updateSuppressedNames, usageObserved, userSetKeys, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
8
7
|
//#region lib/types/unit-undo-plan.js
|
|
9
8
|
/**
|
|
10
9
|
* G3a: the pure half of `undoUnit` — deciding WHAT to write back, with no io and no host.
|
|
@@ -206,8 +205,9 @@ var EvolutionCurator = class extends Service {
|
|
|
206
205
|
if (typeof disposer === "function") ctx.effect(() => disposer, "evolution-curator: settings presentation");
|
|
207
206
|
});
|
|
208
207
|
if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to run the curator");
|
|
209
|
-
this.io = evolutionIoAdapter(() =>
|
|
208
|
+
this.io = evolutionIoAdapter(() => ctx.evolutionIo.provider());
|
|
210
209
|
this.skills = newSkillLibrary({
|
|
210
|
+
authority: authorityFrom({ origin: "background_review" }),
|
|
211
211
|
config,
|
|
212
212
|
io: this.io,
|
|
213
213
|
ctx: this.ctx,
|
|
@@ -619,18 +619,18 @@ var EvolutionCurator = class extends Service {
|
|
|
619
619
|
report: this.skippedReport("instance-held", (/* @__PURE__ */ new Date()).toISOString()),
|
|
620
620
|
skipped: "instance-held"
|
|
621
621
|
};
|
|
622
|
-
if (this.mutexDepth > 0) return {
|
|
622
|
+
if (this.runClaim || this.mutexDepth > 0) return {
|
|
623
623
|
stale: [],
|
|
624
624
|
archived: [],
|
|
625
625
|
errors: [],
|
|
626
626
|
report: this.skippedReport("already-running", (/* @__PURE__ */ new Date()).toISOString()),
|
|
627
627
|
skipped: "already-running"
|
|
628
628
|
};
|
|
629
|
-
|
|
629
|
+
this.runClaim = true;
|
|
630
630
|
try {
|
|
631
631
|
return await this.runCore(options);
|
|
632
632
|
} finally {
|
|
633
|
-
|
|
633
|
+
this.runClaim = false;
|
|
634
634
|
try {
|
|
635
635
|
await this.retainReports();
|
|
636
636
|
} catch (error) {
|
|
@@ -663,6 +663,11 @@ var EvolutionCurator = class extends Service {
|
|
|
663
663
|
* the one realistic interleave window — documented, accepted (plan v20
|
|
664
664
|
* C-3①). The same statement lives on evolution-review's `reviewInFlight`.
|
|
665
665
|
*/
|
|
666
|
+
/** G1/1.5 (S7-09): the synchronous run claim. The mutex is taken later now (around the mutation only),
|
|
667
|
+
* so this is what makes the `already-running` answer atomic with respect to other entrants. It is a
|
|
668
|
+
* CLAIM, not a wait: no polling, so it cannot reintroduce the v15 micro-task starvation the promise
|
|
669
|
+
* chain replaced. */
|
|
670
|
+
runClaim = false;
|
|
666
671
|
mutexDepth = 0;
|
|
667
672
|
mutexTail = Promise.resolve();
|
|
668
673
|
acquireMutex() {
|
|
@@ -776,14 +781,13 @@ var EvolutionCurator = class extends Service {
|
|
|
776
781
|
suppressed: suppressedNames
|
|
777
782
|
});
|
|
778
783
|
const { bundledNames, treeNames, resetToActive } = await this.seedBaseline(usage);
|
|
784
|
+
const listed = await this.skills.list({ withContent: true });
|
|
779
785
|
const contents = /* @__PURE__ */ new Map();
|
|
780
|
-
for (const
|
|
781
|
-
const text = await this.skills.read(name);
|
|
782
|
-
if (text) contents.set(name, text);
|
|
783
|
-
}
|
|
786
|
+
for (const summary of listed) if (summary.content) contents.set(summary.name, summary.content);
|
|
784
787
|
const referencedBy = referencedSkillNames(contents);
|
|
785
788
|
const protectedNames = await this.protectedNameMap();
|
|
786
|
-
const
|
|
789
|
+
const dedupScan = computeDedupGroups({ contents });
|
|
790
|
+
const dedupMembers = [...new Set(dedupScan.groups.filter((group) => group.length >= 2).flat())].filter((name) => !protectedNames.has(name) && !referencedBy.has(name));
|
|
787
791
|
await this.scoreTree(usage, treeNames, contents);
|
|
788
792
|
const result = computeLifecycleTransitions(usage, {
|
|
789
793
|
staleAfterDays: lifecycle.staleAfterDays,
|
|
@@ -842,7 +846,19 @@ var EvolutionCurator = class extends Service {
|
|
|
842
846
|
skipped: "active-session"
|
|
843
847
|
};
|
|
844
848
|
}
|
|
845
|
-
const
|
|
849
|
+
const apply = this.applyMutations.bind(this);
|
|
850
|
+
const { archivedSkills, errors, consolidated } = await withTreeWrite(() => this.acquireMutex(), {
|
|
851
|
+
names: [...treeNames],
|
|
852
|
+
read: async (name) => {
|
|
853
|
+
return (await this.skills.list({ withContent: true })).find((entry) => entry.name === name)?.content;
|
|
854
|
+
},
|
|
855
|
+
writeSkill: async (name, content) => {
|
|
856
|
+
await this.skills.update(name, content, "background_review");
|
|
857
|
+
},
|
|
858
|
+
note: (text) => {
|
|
859
|
+
this.ctx.logger.info("evolution-curator: " + text);
|
|
860
|
+
}
|
|
861
|
+
}, async () => apply({
|
|
846
862
|
dryRun,
|
|
847
863
|
archiveCandidates,
|
|
848
864
|
nominations: gatedNominations,
|
|
@@ -859,7 +875,7 @@ var EvolutionCurator = class extends Service {
|
|
|
859
875
|
]),
|
|
860
876
|
runStartStates,
|
|
861
877
|
failedFrom: new Map(result.transitions.filter((t) => t.to === "archived").map((t) => [t.name, t.from]))
|
|
862
|
-
});
|
|
878
|
+
}));
|
|
863
879
|
const runAborted = errors.some((error) => error.startsWith("run aborted"));
|
|
864
880
|
if (!dryRun && !runAborted) this.lastRun = Date.now();
|
|
865
881
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -891,7 +907,8 @@ var EvolutionCurator = class extends Service {
|
|
|
891
907
|
consolidated,
|
|
892
908
|
...snapshotPath === void 0 ? {} : { snapshotPath },
|
|
893
909
|
llmReviewEnabled: settings.llmReview,
|
|
894
|
-
...gatedNominations.warnings.length > 0 ? { nominationsWarnings: gatedNominations.warnings } : {}
|
|
910
|
+
...gatedNominations.warnings.length > 0 ? { nominationsWarnings: gatedNominations.warnings } : {},
|
|
911
|
+
...dedupScan.truncated ? { scanWarnings: ["dedup scan truncated at the pair-comparison budget - the candidate pool is a PARTIAL result: the budget is spent in name order, so the tail was never examined"] } : {}
|
|
895
912
|
});
|
|
896
913
|
report.routeStubs = await (async () => {
|
|
897
914
|
const history = join(this.skills.root, ".history", "skills");
|
package/lib/types/index.d.ts
CHANGED
|
@@ -408,6 +408,11 @@ export declare class EvolutionCurator extends Service {
|
|
|
408
408
|
* the one realistic interleave window — documented, accepted (plan v20
|
|
409
409
|
* C-3①). The same statement lives on evolution-review's `reviewInFlight`.
|
|
410
410
|
*/
|
|
411
|
+
/** G1/1.5 (S7-09): the synchronous run claim. The mutex is taken later now (around the mutation only),
|
|
412
|
+
* so this is what makes the `already-running` answer atomic with respect to other entrants. It is a
|
|
413
|
+
* CLAIM, not a wait: no polling, so it cannot reintroduce the v15 micro-task starvation the promise
|
|
414
|
+
* chain replaced. */
|
|
415
|
+
private runClaim;
|
|
411
416
|
private mutexDepth;
|
|
412
417
|
private mutexTail;
|
|
413
418
|
private acquireMutex;
|
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.26.
|
|
4
|
+
"version": "0.26.26",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
30
|
-
"@lmzhen/dsh-evolution-core": "^0.26.
|
|
30
|
+
"@lmzhen/dsh-evolution-core": "^0.26.26"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
34
34
|
"@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
|
|
35
35
|
"@deepseek-ai/dsh-session": "^0.2.0-rc.1",
|
|
36
|
-
"@lmzhen/dsh-evolution-io": "^0.26.
|
|
37
|
-
"@lmzhen/dsh-evolution-state": "^0.26.
|
|
36
|
+
"@lmzhen/dsh-evolution-io": "^0.26.26",
|
|
37
|
+
"@lmzhen/dsh-evolution-state": "^0.26.26"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
|
|
41
41
|
"@deepseek-ai/dsh-session": "^0.2.0-rc.1",
|
|
42
|
-
"@lmzhen/dsh-evolution-core": "^0.26.
|
|
43
|
-
"@lmzhen/dsh-evolution-io": "^0.26.
|
|
44
|
-
"@lmzhen/dsh-evolution-state": "^0.26.
|
|
42
|
+
"@lmzhen/dsh-evolution-core": "^0.26.26",
|
|
43
|
+
"@lmzhen/dsh-evolution-io": "^0.26.26",
|
|
44
|
+
"@lmzhen/dsh-evolution-state": "^0.26.26"
|
|
45
45
|
}
|
|
46
46
|
}
|