@lmzhen/dsh-evolution-curator 0.27.3 → 0.29.0
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 +46 -7
- package/lib/types/index.d.ts +2 -0
- package/package.json +7 -7
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
|
+
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, acquireTreeWriteLock, authorityFrom, blobPath, buildCuratorRunReport, claimInstance, clampOnce, clampedNumber, computeDedupGroups, computeLifecycleTransitions, computePrefixClusters, computeQualityScores, computeScopeView, contentHash, emptyRecord, entryTarget, evolutionHome, evolutionIoAdapter, executeUnitUndo, foldCuratorFields, historyIndexFile, isPresent, isUnknown, lintSkill, liveBool, loadSuppressedNames, loadUsage, markerEntryName, mutateUsage, newSkillLibrary, paramRowId, parseCuratorNominations, parseFrontmatter, parseHistoryIndex, pickWithPolicy, planUnitUndoAcross, 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";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
@@ -670,6 +670,19 @@ var EvolutionCurator = class extends Service {
|
|
|
670
670
|
runClaim = false;
|
|
671
671
|
mutexDepth = 0;
|
|
672
672
|
mutexTail = Promise.resolve();
|
|
673
|
+
/** Cross-process tree lock shared with merge runs; curator mutations take it only around apply. */
|
|
674
|
+
async withMergeTreeLock(body) {
|
|
675
|
+
const acquired = await acquireTreeWriteLock({
|
|
676
|
+
io: this.io,
|
|
677
|
+
home: evolutionHome()
|
|
678
|
+
});
|
|
679
|
+
if (!acquired.ok) throw new Error("evolution-curator: merge tree lock unavailable (" + acquired.reason + ")" + (acquired.holder === void 0 ? "" : "; holder pid " + String(acquired.holder.pid)));
|
|
680
|
+
try {
|
|
681
|
+
return await body();
|
|
682
|
+
} finally {
|
|
683
|
+
await acquired.lock.release();
|
|
684
|
+
}
|
|
685
|
+
}
|
|
673
686
|
acquireMutex() {
|
|
674
687
|
this.mutexDepth += 1;
|
|
675
688
|
const prev = this.mutexTail;
|
|
@@ -858,7 +871,7 @@ var EvolutionCurator = class extends Service {
|
|
|
858
871
|
note: (text) => {
|
|
859
872
|
this.ctx.logger.info("evolution-curator: " + text);
|
|
860
873
|
}
|
|
861
|
-
}, async () => apply({
|
|
874
|
+
}, async () => this.withMergeTreeLock(() => apply({
|
|
862
875
|
dryRun,
|
|
863
876
|
archiveCandidates,
|
|
864
877
|
nominations: gatedNominations,
|
|
@@ -875,7 +888,7 @@ var EvolutionCurator = class extends Service {
|
|
|
875
888
|
]),
|
|
876
889
|
runStartStates,
|
|
877
890
|
failedFrom: new Map(result.transitions.filter((t) => t.to === "archived").map((t) => [t.name, t.from]))
|
|
878
|
-
}));
|
|
891
|
+
})));
|
|
879
892
|
const runAborted = errors.some((error) => error.startsWith("run aborted"));
|
|
880
893
|
if (!dryRun && !runAborted) this.lastRun = Date.now();
|
|
881
894
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1632,10 +1645,36 @@ var EvolutionCurator = class extends Service {
|
|
|
1632
1645
|
message: "单元 " + unit + " 的成员没解析齐:" + missing + (conflicts === "" ? "" : ";冲突:" + conflicts) + " —— 拒绝用剩余片段拼一个撤销。"
|
|
1633
1646
|
};
|
|
1634
1647
|
}
|
|
1635
|
-
if (resolved.members.length > 1)
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1648
|
+
if (resolved.members.length > 1) {
|
|
1649
|
+
const crossMembers = [];
|
|
1650
|
+
for (const slice of resolved.members) {
|
|
1651
|
+
const live = await this.skills.read(slice.skill);
|
|
1652
|
+
crossMembers.push({
|
|
1653
|
+
skill: slice.skill,
|
|
1654
|
+
entries: slice.entries,
|
|
1655
|
+
status: live === null ? "archived" : "live",
|
|
1656
|
+
...live === null ? { archivedPath: "archive" } : {},
|
|
1657
|
+
...slice.skill === name && slice.entries.some((entry) => entry.action === "create") ? { createdInUnit: true } : {}
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
const result = await executeUnitUndo(planUnitUndoAcross(crossMembers), {
|
|
1661
|
+
readSkill: (skill) => this.skills.read(skill),
|
|
1662
|
+
readSupport: (skill, path) => this.skills.readSupportFile(skill, path),
|
|
1663
|
+
readBlob: async (hash) => {
|
|
1664
|
+
const probe = await probeText(this.io, blobPath(this.skills.root, hash));
|
|
1665
|
+
return isPresent(probe) ? probe.value : null;
|
|
1666
|
+
},
|
|
1667
|
+
restoreFromArchive: (skill) => this.skills.restoreFromArchive(skill, "foreground"),
|
|
1668
|
+
archive: (skill, reason) => this.skills.archive(skill, { reason }, "foreground"),
|
|
1669
|
+
updateSkill: (skill, body, anchor) => this.skills.update(skill, body, "foreground", anchor),
|
|
1670
|
+
writeSupportFile: (skill, path, body, anchor) => this.skills.writeSupportFile(skill, path, body, "foreground", anchor),
|
|
1671
|
+
removeSupportFile: (skill, path, anchor) => this.skills.removeSupportFile(skill, path, "foreground", anchor)
|
|
1672
|
+
});
|
|
1673
|
+
return {
|
|
1674
|
+
ok: result.ok,
|
|
1675
|
+
message: result.message
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1639
1678
|
}
|
|
1640
1679
|
const blobOf = async (hash) => {
|
|
1641
1680
|
if (hash === void 0) return null;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -415,6 +415,8 @@ export declare class EvolutionCurator extends Service {
|
|
|
415
415
|
private runClaim;
|
|
416
416
|
private mutexDepth;
|
|
417
417
|
private mutexTail;
|
|
418
|
+
/** Cross-process tree lock shared with merge runs; curator mutations take it only around apply. */
|
|
419
|
+
private withMergeTreeLock;
|
|
418
420
|
private acquireMutex;
|
|
419
421
|
/**
|
|
420
422
|
* PLAN S4.5 (2026-09-16) (audit P2-16): the manual control-plane entries
|
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.
|
|
4
|
+
"version": "0.29.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,21 +27,21 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
30
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
30
|
+
"@lmzhen/dsh-evolution-core": "^0.29.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@deepseek-ai/cordis": "^4.0.5",
|
|
34
34
|
"@deepseek-ai/dsh-llm": "^0.2.1-rc.1",
|
|
35
35
|
"@deepseek-ai/dsh-session": "^0.2.1-rc.1",
|
|
36
|
-
"@lmzhen/dsh-evolution-io": "^0.
|
|
37
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
36
|
+
"@lmzhen/dsh-evolution-io": "^0.29.0",
|
|
37
|
+
"@lmzhen/dsh-evolution-state": "^0.29.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@deepseek-ai/dsh-llm": "^0.2.1-rc.1",
|
|
41
41
|
"@deepseek-ai/dsh-session": "^0.2.1-rc.1",
|
|
42
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
43
|
-
"@lmzhen/dsh-evolution-io": "^0.
|
|
44
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
42
|
+
"@lmzhen/dsh-evolution-core": "^0.29.0",
|
|
43
|
+
"@lmzhen/dsh-evolution-io": "^0.29.0",
|
|
44
|
+
"@lmzhen/dsh-evolution-state": "^0.29.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"dsh": ">=0.2.1-rc.1 <0.2.2-0"
|