@lmzhen/dsh-evolution-merge 0.30.3 → 0.30.4
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 +125 -69
- package/lib/types/adapters/library.js +9 -2
- package/lib/types/commit-recovery.d.ts +1 -1
- package/lib/types/commit-recovery.js +25 -2
- package/lib/types/commit-snapshot.js +1 -1
- package/lib/types/domain/commit-journal.d.ts +1 -1
- package/lib/types/domain/commit-journal.js +1 -0
- package/lib/types/index.js +5 -1
- package/lib/types/runtime.js +3 -0
- package/package.json +3 -3
package/lib/index.js
CHANGED
|
@@ -588,6 +588,7 @@ function recoveryFor(journal) {
|
|
|
588
588
|
case "committed":
|
|
589
589
|
case "rolled-back":
|
|
590
590
|
case "failed": return "none";
|
|
591
|
+
default: return "refuse";
|
|
591
592
|
}
|
|
592
593
|
}
|
|
593
594
|
//#endregion
|
|
@@ -648,7 +649,7 @@ function isSafeSkillName(name) {
|
|
|
648
649
|
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) && name !== "." && name !== "..";
|
|
649
650
|
}
|
|
650
651
|
function skillFilePath(root, name, path) {
|
|
651
|
-
if (!isSafeSkillName(name) || path.startsWith("/") || path.includes("..")) throw new Error("unsafe skill file: " + name + "/" + path);
|
|
652
|
+
if (!isSafeSkillName(name) || path.startsWith("/") || path.split("/").includes("..")) throw new Error("unsafe skill file: " + name + "/" + path);
|
|
652
653
|
const base = resolve(root, name);
|
|
653
654
|
const file = resolve(base, path);
|
|
654
655
|
if (!file.startsWith(base + sep)) throw new Error("skill file escapes skill: " + name + "/" + path);
|
|
@@ -662,68 +663,6 @@ function skillBodyPath(root, name) {
|
|
|
662
663
|
return path;
|
|
663
664
|
}
|
|
664
665
|
//#endregion
|
|
665
|
-
//#region lib/types/commit-recovery.js
|
|
666
|
-
/** Startup replay for non-terminal commit journals. */
|
|
667
|
-
async function recoverCommitJournals(io, home, now, skillRoot, restoreSource) {
|
|
668
|
-
const dir = join(home, "merge", "journals");
|
|
669
|
-
if (!await io.exists(dir)) return [];
|
|
670
|
-
const files = (await io.list(dir)).filter((name) => name.endsWith(".json"));
|
|
671
|
-
const reports = [];
|
|
672
|
-
for (const file of files) {
|
|
673
|
-
let journal;
|
|
674
|
-
try {
|
|
675
|
-
journal = JSON.parse(await io.readText(join(dir, file)) ?? "");
|
|
676
|
-
} catch {
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
const recovery = recoveryFor(journal);
|
|
680
|
-
if (recovery === "none") continue;
|
|
681
|
-
const snapshot = await readCommitSnapshot(io, home, journal.runId);
|
|
682
|
-
let action = "report-only";
|
|
683
|
-
let ok = true;
|
|
684
|
-
if (recovery === "retry-commit") action = "no-host-write";
|
|
685
|
-
else if (snapshot === null) {
|
|
686
|
-
action = "snapshot-missing";
|
|
687
|
-
ok = false;
|
|
688
|
-
} else try {
|
|
689
|
-
if (recovery === "rollback-sources") {
|
|
690
|
-
let restoredArchived = restoreSource !== void 0;
|
|
691
|
-
if (restoreSource !== void 0) {
|
|
692
|
-
for (const source of snapshot.sourceBodies) if (!await restoreSource(source.name)) restoredArchived = false;
|
|
693
|
-
}
|
|
694
|
-
if (!restoredArchived) for (const source of snapshot.sourceBodies) await io.writeText(skillBodyPath(skillRoot, source.name), source.body);
|
|
695
|
-
}
|
|
696
|
-
if (snapshot.create && snapshot.targetBody === null) try {
|
|
697
|
-
await io.remove(skillBodyPath(skillRoot, snapshot.target));
|
|
698
|
-
} catch {}
|
|
699
|
-
else if (snapshot.targetBody !== null) await io.writeText(skillBodyPath(skillRoot, snapshot.target), snapshot.targetBody);
|
|
700
|
-
const oldPaths = new Set((snapshot.targetSupport ?? []).map((file) => file.path));
|
|
701
|
-
for (const file of snapshot.targetSupport ?? []) await io.writeText(skillFilePath(skillRoot, snapshot.target, file.path), file.content);
|
|
702
|
-
for (const file of snapshot.targetSupportAfter ?? []) if (!oldPaths.has(file.path)) try {
|
|
703
|
-
await io.remove(skillFilePath(skillRoot, snapshot.target, file.path));
|
|
704
|
-
} catch {}
|
|
705
|
-
for (const file of snapshot.sourceSupport ?? []) await io.writeText(skillFilePath(skillRoot, file.name, file.path), file.content);
|
|
706
|
-
action = recovery === "rollback-sources" ? "restored-sources-and-target" : "restored-target";
|
|
707
|
-
} catch (error) {
|
|
708
|
-
action = "restore-failed: " + (error instanceof Error ? error.message : String(error));
|
|
709
|
-
ok = false;
|
|
710
|
-
}
|
|
711
|
-
await writeJournal(io, home, {
|
|
712
|
-
...journal,
|
|
713
|
-
phase: ok ? "rolled-back" : "failed",
|
|
714
|
-
updatedAt: new Date(now).toISOString()
|
|
715
|
-
});
|
|
716
|
-
reports.push({
|
|
717
|
-
runId: journal.runId,
|
|
718
|
-
phase: journal.phase,
|
|
719
|
-
action,
|
|
720
|
-
ok
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
await io.writeText(join(home, "merge", "recovery.json"), JSON.stringify(reports, null, 2));
|
|
724
|
-
return reports;
|
|
725
|
-
}
|
|
726
|
-
//#endregion
|
|
727
666
|
//#region lib/types/commit-receipt.js
|
|
728
667
|
/**
|
|
729
668
|
* Commit receipt: <run>/commit.json, written immediately after a successful commit.
|
|
@@ -799,6 +738,113 @@ async function readCommitReceipt(io, home, runId, target) {
|
|
|
799
738
|
return null;
|
|
800
739
|
}
|
|
801
740
|
//#endregion
|
|
741
|
+
//#region lib/types/commit-recovery.js
|
|
742
|
+
/** Startup replay for non-terminal commit journals. */
|
|
743
|
+
async function recoverCommitJournals(io, home, now, skillRoot, restoreSource, isActive) {
|
|
744
|
+
const dir = join(home, "merge", "journals");
|
|
745
|
+
if (!await io.exists(dir)) return [];
|
|
746
|
+
const files = (await io.list(dir)).filter((name) => name.endsWith(".json"));
|
|
747
|
+
const reports = [];
|
|
748
|
+
for (const file of files) {
|
|
749
|
+
let journal;
|
|
750
|
+
try {
|
|
751
|
+
journal = JSON.parse(await io.readText(join(dir, file)) ?? "");
|
|
752
|
+
} catch {
|
|
753
|
+
continue;
|
|
754
|
+
}
|
|
755
|
+
if (isActive?.(journal.runId) === true) {
|
|
756
|
+
reports.push({
|
|
757
|
+
runId: journal.runId,
|
|
758
|
+
phase: journal.phase,
|
|
759
|
+
action: "skipped-active-run",
|
|
760
|
+
ok: true
|
|
761
|
+
});
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
const recovery = recoveryFor(journal);
|
|
765
|
+
if (recovery === "none") continue;
|
|
766
|
+
if (recovery === "refuse") {
|
|
767
|
+
reports.push({
|
|
768
|
+
runId: journal.runId,
|
|
769
|
+
phase: journal.phase,
|
|
770
|
+
action: "unknown-phase-refused",
|
|
771
|
+
ok: false
|
|
772
|
+
});
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
let receipt = null;
|
|
776
|
+
try {
|
|
777
|
+
receipt = await readCommitReceipt(io, home, journal.runId, journal.target);
|
|
778
|
+
} catch {
|
|
779
|
+
reports.push({
|
|
780
|
+
runId: journal.runId,
|
|
781
|
+
phase: journal.phase,
|
|
782
|
+
action: "receipt-read-failed",
|
|
783
|
+
ok: false
|
|
784
|
+
});
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
if (receipt !== null) {
|
|
788
|
+
await writeJournal(io, home, {
|
|
789
|
+
...journal,
|
|
790
|
+
phase: "committed",
|
|
791
|
+
unitId: receipt.unitId,
|
|
792
|
+
updatedAt: new Date(now).toISOString()
|
|
793
|
+
});
|
|
794
|
+
reports.push({
|
|
795
|
+
runId: journal.runId,
|
|
796
|
+
phase: journal.phase,
|
|
797
|
+
action: "receipt-committed",
|
|
798
|
+
ok: true
|
|
799
|
+
});
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
const snapshot = await readCommitSnapshot(io, home, journal.runId);
|
|
803
|
+
let action = "report-only";
|
|
804
|
+
let ok = true;
|
|
805
|
+
if (recovery === "retry-commit") action = "no-host-write";
|
|
806
|
+
else if (snapshot === null) {
|
|
807
|
+
action = "snapshot-missing";
|
|
808
|
+
ok = false;
|
|
809
|
+
} else try {
|
|
810
|
+
if (recovery === "rollback-sources") {
|
|
811
|
+
let restoredArchived = restoreSource !== void 0;
|
|
812
|
+
if (restoreSource !== void 0) {
|
|
813
|
+
for (const source of snapshot.sourceBodies) if (!await restoreSource(source.name)) restoredArchived = false;
|
|
814
|
+
}
|
|
815
|
+
if (!restoredArchived) for (const source of snapshot.sourceBodies) await io.writeText(skillBodyPath(skillRoot, source.name), source.body);
|
|
816
|
+
}
|
|
817
|
+
if (snapshot.create && snapshot.targetBody === null) try {
|
|
818
|
+
await io.remove(skillBodyPath(skillRoot, snapshot.target));
|
|
819
|
+
} catch {}
|
|
820
|
+
else if (snapshot.targetBody !== null) await io.writeText(skillBodyPath(skillRoot, snapshot.target), snapshot.targetBody);
|
|
821
|
+
const oldPaths = new Set((snapshot.targetSupport ?? []).map((file) => file.path));
|
|
822
|
+
for (const file of snapshot.targetSupport ?? []) await io.writeText(skillFilePath(skillRoot, snapshot.target, file.path), file.content);
|
|
823
|
+
for (const file of snapshot.targetSupportAfter ?? []) if (!oldPaths.has(file.path)) try {
|
|
824
|
+
await io.remove(skillFilePath(skillRoot, snapshot.target, file.path));
|
|
825
|
+
} catch {}
|
|
826
|
+
for (const file of snapshot.sourceSupport ?? []) await io.writeText(skillFilePath(skillRoot, file.name, file.path), file.content);
|
|
827
|
+
action = recovery === "rollback-sources" ? "restored-sources-and-target" : "restored-target";
|
|
828
|
+
} catch (error) {
|
|
829
|
+
action = "restore-failed: " + (error instanceof Error ? error.message : String(error));
|
|
830
|
+
ok = false;
|
|
831
|
+
}
|
|
832
|
+
if (ok) await writeJournal(io, home, {
|
|
833
|
+
...journal,
|
|
834
|
+
phase: "rolled-back",
|
|
835
|
+
updatedAt: new Date(now).toISOString()
|
|
836
|
+
});
|
|
837
|
+
reports.push({
|
|
838
|
+
runId: journal.runId,
|
|
839
|
+
phase: journal.phase,
|
|
840
|
+
action,
|
|
841
|
+
ok
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
await io.writeText(join(home, "merge", "recovery.json"), JSON.stringify(reports, null, 2));
|
|
845
|
+
return reports;
|
|
846
|
+
}
|
|
847
|
+
//#endregion
|
|
802
848
|
//#region lib/types/coordinator.js
|
|
803
849
|
/**
|
|
804
850
|
* Pure merge transition table. No io, no run shell, no subagents.
|
|
@@ -3552,11 +3598,16 @@ function skillLibraryPort(skills) {
|
|
|
3552
3598
|
async readSupportFiles(name) {
|
|
3553
3599
|
if (typeof skills.listSupportFiles !== "function") return [];
|
|
3554
3600
|
const probe = await skills.listSupportFiles(name);
|
|
3555
|
-
if (probe.kind
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
content
|
|
3559
|
-
|
|
3601
|
+
if (probe.kind === "unknown") throw new Error("support file list unknown: " + name);
|
|
3602
|
+
if (probe.kind === "absent") return [];
|
|
3603
|
+
return await Promise.all(probe.value.map(async (path) => {
|
|
3604
|
+
const content = await skills.readSupportFile(name, path);
|
|
3605
|
+
if (content === null) throw new Error("support file disappeared: " + name + "/" + path);
|
|
3606
|
+
return {
|
|
3607
|
+
path,
|
|
3608
|
+
content
|
|
3609
|
+
};
|
|
3610
|
+
}));
|
|
3560
3611
|
}
|
|
3561
3612
|
};
|
|
3562
3613
|
}
|
|
@@ -3614,6 +3665,7 @@ function createMergeRuntime(deps) {
|
|
|
3614
3665
|
b: command.b
|
|
3615
3666
|
}];
|
|
3616
3667
|
const existing = (await loadMergeState(deps.io, deps.home)).state.rows.find((row) => row.pairKey === pairKey(command.a, command.b));
|
|
3668
|
+
if (existing?.state === "skipped") await dropRow(deps.io, deps.home, deps.now, existing.id);
|
|
3617
3669
|
if (existing?.state === "pending") return {
|
|
3618
3670
|
ok: false,
|
|
3619
3671
|
text: "该 pair 已在待批准队列,先 approve/reject/discard: " + existing.id
|
|
@@ -4482,8 +4534,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
4482
4534
|
...policyStageLimits(policySnapshot?.get?.())
|
|
4483
4535
|
}
|
|
4484
4536
|
});
|
|
4485
|
-
|
|
4537
|
+
const mergeSkillsRoot = skills.root ?? skillsRoot();
|
|
4538
|
+
recoverCommitJournals(io, home, Date.now(), mergeSkillsRoot, async (name) => {
|
|
4486
4539
|
return (await skills.restoreFromArchive(name)).ok;
|
|
4540
|
+
}, (runId) => {
|
|
4541
|
+
const run = runs.find(runId);
|
|
4542
|
+
return run !== void 0 && run.state === "running";
|
|
4487
4543
|
}).then((reports) => {
|
|
4488
4544
|
if (reports.length > 0) ctx.logger.info("merge commit recovery: " + reports.map((report) => report.runId + "=" + report.action).join(", "));
|
|
4489
4545
|
}).catch((error) => {
|
|
@@ -13,9 +13,16 @@ export function skillLibraryPort(skills) {
|
|
|
13
13
|
if (typeof skills.listSupportFiles !== 'function')
|
|
14
14
|
return [];
|
|
15
15
|
const probe = await skills.listSupportFiles(name);
|
|
16
|
-
if (probe.kind
|
|
16
|
+
if (probe.kind === 'unknown')
|
|
17
|
+
throw new Error('support file list unknown: ' + name);
|
|
18
|
+
if (probe.kind === 'absent')
|
|
17
19
|
return [];
|
|
18
|
-
return await Promise.all(probe.value.map(async (path) =>
|
|
20
|
+
return await Promise.all(probe.value.map(async (path) => {
|
|
21
|
+
const content = await skills.readSupportFile(name, path);
|
|
22
|
+
if (content === null)
|
|
23
|
+
throw new Error('support file disappeared: ' + name + '/' + path);
|
|
24
|
+
return { path, content };
|
|
25
|
+
}));
|
|
19
26
|
},
|
|
20
27
|
};
|
|
21
28
|
}
|
|
@@ -6,5 +6,5 @@ export interface CommitRecoveryReport {
|
|
|
6
6
|
readonly action: string;
|
|
7
7
|
readonly ok: boolean;
|
|
8
8
|
}
|
|
9
|
-
export declare function recoverCommitJournals(io: EvolutionIoLike, home: string, now: number, skillRoot: string, restoreSource?: (name: string) => Promise<boolean
|
|
9
|
+
export declare function recoverCommitJournals(io: EvolutionIoLike, home: string, now: number, skillRoot: string, restoreSource?: (name: string) => Promise<boolean>, isActive?: (runId: string) => boolean): Promise<readonly CommitRecoveryReport[]>;
|
|
10
10
|
//# sourceMappingURL=commit-recovery.d.ts.map
|
|
@@ -3,7 +3,8 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { recoveryFor } from "./domain/commit-journal.js";
|
|
4
4
|
import { writeJournal } from "./domain/commit-journal-store.js";
|
|
5
5
|
import { readCommitSnapshot, skillBodyPath, skillFilePath } from "./commit-snapshot.js";
|
|
6
|
-
|
|
6
|
+
import { readCommitReceipt } from "./commit-receipt.js";
|
|
7
|
+
export async function recoverCommitJournals(io, home, now, skillRoot, restoreSource, isActive) {
|
|
7
8
|
const dir = join(home, 'merge', 'journals');
|
|
8
9
|
if (!(await io.exists(dir)))
|
|
9
10
|
return [];
|
|
@@ -17,9 +18,30 @@ export async function recoverCommitJournals(io, home, now, skillRoot, restoreSou
|
|
|
17
18
|
catch {
|
|
18
19
|
continue;
|
|
19
20
|
}
|
|
21
|
+
if (isActive?.(journal.runId) === true) {
|
|
22
|
+
reports.push({ runId: journal.runId, phase: journal.phase, action: 'skipped-active-run', ok: true });
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
20
25
|
const recovery = recoveryFor(journal);
|
|
21
26
|
if (recovery === 'none')
|
|
22
27
|
continue;
|
|
28
|
+
if (recovery === 'refuse') {
|
|
29
|
+
reports.push({ runId: journal.runId, phase: journal.phase, action: 'unknown-phase-refused', ok: false });
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
let receipt = null;
|
|
33
|
+
try {
|
|
34
|
+
receipt = await readCommitReceipt(io, home, journal.runId, journal.target);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
reports.push({ runId: journal.runId, phase: journal.phase, action: 'receipt-read-failed', ok: false });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (receipt !== null) {
|
|
41
|
+
await writeJournal(io, home, { ...journal, phase: 'committed', unitId: receipt.unitId, updatedAt: new Date(now).toISOString() });
|
|
42
|
+
reports.push({ runId: journal.runId, phase: journal.phase, action: 'receipt-committed', ok: true });
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
23
45
|
const snapshot = await readCommitSnapshot(io, home, journal.runId);
|
|
24
46
|
let action = 'report-only';
|
|
25
47
|
let ok = true;
|
|
@@ -75,7 +97,8 @@ export async function recoverCommitJournals(io, home, now, skillRoot, restoreSou
|
|
|
75
97
|
ok = false;
|
|
76
98
|
}
|
|
77
99
|
}
|
|
78
|
-
|
|
100
|
+
if (ok)
|
|
101
|
+
await writeJournal(io, home, { ...journal, phase: 'rolled-back', updatedAt: new Date(now).toISOString() });
|
|
79
102
|
reports.push({ runId: journal.runId, phase: journal.phase, action, ok });
|
|
80
103
|
}
|
|
81
104
|
await io.writeText(join(home, 'merge', 'recovery.json'), JSON.stringify(reports, null, 2));
|
|
@@ -45,7 +45,7 @@ export function isSafeSkillName(name) {
|
|
|
45
45
|
return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) && name !== '.' && name !== '..';
|
|
46
46
|
}
|
|
47
47
|
export function skillFilePath(root, name, path) {
|
|
48
|
-
if (!isSafeSkillName(name) || path.startsWith('/') || path.includes('..'))
|
|
48
|
+
if (!isSafeSkillName(name) || path.startsWith('/') || path.split('/').includes('..'))
|
|
49
49
|
throw new Error('unsafe skill file: ' + name + '/' + path);
|
|
50
50
|
const base = resolve(root, name);
|
|
51
51
|
const file = resolve(base, path);
|
|
@@ -10,7 +10,7 @@ export interface CommitJournal {
|
|
|
10
10
|
readonly updatedAt: string;
|
|
11
11
|
}
|
|
12
12
|
export declare function advanceJournal(journal: CommitJournal, phase: JournalPhase, at: string): CommitJournal;
|
|
13
|
-
export type JournalRecovery = 'none' | 'retry-commit' | 'rollback-target' | 'rollback-sources';
|
|
13
|
+
export type JournalRecovery = 'none' | 'retry-commit' | 'rollback-target' | 'rollback-sources' | 'refuse';
|
|
14
14
|
/** What a restart may do with the last durable phase. */
|
|
15
15
|
export declare function recoveryFor(journal: CommitJournal): JournalRecovery;
|
|
16
16
|
//# sourceMappingURL=commit-journal.d.ts.map
|
package/lib/types/index.js
CHANGED
|
@@ -138,9 +138,13 @@ export function apply(ctx, rawConfig = {}) {
|
|
|
138
138
|
io, ctx, authority: authorityFrom({ origin: 'subagent' }),
|
|
139
139
|
limits: { ...DEFAULT_SKILL_LIMITS, ...policyStageLimits(policySnapshot?.get?.()) },
|
|
140
140
|
});
|
|
141
|
-
|
|
141
|
+
const mergeSkillsRoot = skills.root ?? skillsRoot();
|
|
142
|
+
void recoverCommitJournals(io, home, Date.now(), mergeSkillsRoot, async (name) => {
|
|
142
143
|
const result = await skills.restoreFromArchive(name);
|
|
143
144
|
return result.ok;
|
|
145
|
+
}, (runId) => {
|
|
146
|
+
const run = runs.find(runId);
|
|
147
|
+
return run !== undefined && run.state === 'running';
|
|
144
148
|
}).then((reports) => { if (reports.length > 0)
|
|
145
149
|
ctx.logger.info('merge commit recovery: ' + reports.map(report => report.runId + '=' + report.action).join(', ')); }).catch((error) => { ctx.logger.warn('merge commit recovery failed: ' + (error instanceof Error ? error.message : String(error))); });
|
|
146
150
|
const channel = subagentChannelAdapter(createSubagentChannel(ctx));
|
package/lib/types/runtime.js
CHANGED
|
@@ -55,6 +55,9 @@ export function createMergeRuntime(deps) {
|
|
|
55
55
|
}
|
|
56
56
|
const pair = [{ a: command.a, b: command.b }];
|
|
57
57
|
const existing = (await loadMergeState(deps.io, deps.home)).state.rows.find(row => row.pairKey === pairKey(command.a, command.b));
|
|
58
|
+
if (existing?.state === 'skipped') {
|
|
59
|
+
await dropRow(deps.io, deps.home, deps.now, existing.id);
|
|
60
|
+
}
|
|
58
61
|
if (existing?.state === 'pending') {
|
|
59
62
|
return { ok: false, text: '该 pair 已在待批准队列,先 approve/reject/discard: ' + existing.id };
|
|
60
63
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-merge",
|
|
3
3
|
"description": "Skill auto-merge domain: screening, two-round authoring, queues and commit orchestration (community build)",
|
|
4
|
-
"version": "0.30.
|
|
4
|
+
"version": "0.30.4",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
30
|
-
"@lmzhen/dsh-evolution-core": "^0.30.
|
|
31
|
-
"@lmzhen/dsh-evolution-merge-engine": "^0.30.
|
|
30
|
+
"@lmzhen/dsh-evolution-core": "^0.30.4",
|
|
31
|
+
"@lmzhen/dsh-evolution-merge-engine": "^0.30.4"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@deepseek-ai/cordis": "^4.0.5"
|