@lmzhen/dsh-evolution-merge 0.30.5 → 0.30.7
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
CHANGED
|
@@ -814,10 +814,15 @@ async function recoverCommitJournals(io, home, now, skillRoot, restoreSource, is
|
|
|
814
814
|
}
|
|
815
815
|
if (!restoredArchived) for (const source of snapshot.sourceBodies) await io.writeText(skillBodyPath(skillRoot, source.name), source.body);
|
|
816
816
|
}
|
|
817
|
-
if (snapshot.create && snapshot.targetBody === null)
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
817
|
+
if (snapshot.create && snapshot.targetBody === null) {
|
|
818
|
+
try {
|
|
819
|
+
await io.remove(skillBodyPath(skillRoot, snapshot.target));
|
|
820
|
+
} catch {}
|
|
821
|
+
try {
|
|
822
|
+
const dir = join(skillRoot, snapshot.target);
|
|
823
|
+
if ((await io.list(dir)).length === 0) await io.remove(dir);
|
|
824
|
+
} catch {}
|
|
825
|
+
} else if (snapshot.targetBody !== null) await io.writeText(skillBodyPath(skillRoot, snapshot.target), snapshot.targetBody);
|
|
821
826
|
const oldPaths = new Set((snapshot.targetSupport ?? []).map((file) => file.path));
|
|
822
827
|
for (const file of snapshot.targetSupport ?? []) await io.writeText(skillFilePath(skillRoot, snapshot.target, file.path), file.content);
|
|
823
828
|
for (const file of snapshot.targetSupportAfter ?? []) if (!oldPaths.has(file.path)) try {
|
|
@@ -1527,24 +1532,28 @@ function mergeUsage() {
|
|
|
1527
1532
|
//#endregion
|
|
1528
1533
|
//#region lib/types/read-commands.js
|
|
1529
1534
|
async function handleReadOnlyMergeCommand(command, io, home) {
|
|
1535
|
+
const withNote = (text, note) => note === void 0 ? text : "note: " + note + "\n" + text;
|
|
1530
1536
|
if (command.verb === "status") {
|
|
1531
1537
|
const loaded = await loadMergeState(io, home);
|
|
1532
1538
|
if (command.id !== void 0) {
|
|
1533
1539
|
const row = loaded.state.rows.find((item) => item.id === command.id);
|
|
1534
|
-
return row === void 0 ? "merge row not found: " + command.id : formatStatus([row]);
|
|
1540
|
+
return withNote(row === void 0 ? "merge row not found: " + command.id : formatStatus([row]), loaded.note);
|
|
1535
1541
|
}
|
|
1536
|
-
return formatStatus(loaded.state.rows);
|
|
1542
|
+
return withNote(formatStatus(loaded.state.rows), loaded.note);
|
|
1537
1543
|
}
|
|
1538
1544
|
if (command.verb === "pending") {
|
|
1539
1545
|
const loaded = await loadMergeState(io, home);
|
|
1540
1546
|
const rows = command.expired === true ? loaded.state.rows.filter((row) => row.expired !== void 0) : loaded.state.rows;
|
|
1541
|
-
return command.expired === true ? formatStatus(rows) : formatQueue(rows, "pending");
|
|
1547
|
+
return withNote(command.expired === true ? formatStatus(rows) : formatQueue(rows, "pending"), loaded.note);
|
|
1542
1548
|
}
|
|
1543
1549
|
if (command.verb === "candidates") {
|
|
1544
1550
|
const loaded = await loadMergeState(io, home);
|
|
1545
|
-
return formatQueue(command.retry === true ? loaded.state.rows.filter((row) => row.state === "approved") : loaded.state.rows, command.retry === true ? "fuse" : "verify");
|
|
1551
|
+
return withNote(formatQueue(command.retry === true ? loaded.state.rows.filter((row) => row.state === "approved") : loaded.state.rows, command.retry === true ? "fuse" : "verify"), loaded.note);
|
|
1552
|
+
}
|
|
1553
|
+
if (command.verb === "skipped") {
|
|
1554
|
+
const loaded = await loadMergeState(io, home);
|
|
1555
|
+
return withNote(formatQueue(loaded.state.rows, "skipped"), loaded.note);
|
|
1546
1556
|
}
|
|
1547
|
-
if (command.verb === "skipped") return formatQueue((await loadMergeState(io, home)).state.rows, "skipped");
|
|
1548
1557
|
return null;
|
|
1549
1558
|
}
|
|
1550
1559
|
function mergeCommandHelp() {
|
|
@@ -1554,8 +1563,8 @@ function mergeCommandHelp() {
|
|
|
1554
1563
|
//#region lib/types/domain/errors.js
|
|
1555
1564
|
function formatMergeError(error) {
|
|
1556
1565
|
if (error.kind === "parameter") return "merge: " + error.message + " (" + error.code + ")";
|
|
1557
|
-
const
|
|
1558
|
-
return "merge failed: " + error.message + " (" + error.code + ")" +
|
|
1566
|
+
const where = error.stage === void 0 && error.runId === void 0 ? error.detail ?? "no additional detail" : [error.stage === void 0 ? void 0 : "stage=" + error.stage, error.runId === void 0 ? void 0 : "run=" + error.runId].filter(Boolean).join(" ");
|
|
1567
|
+
return "merge failed: " + error.message + " (" + error.code + ")\n" + where + "\nnext: fix the target or rerun after the cause is gone";
|
|
1559
1568
|
}
|
|
1560
1569
|
//#endregion
|
|
1561
1570
|
//#region lib/types/merge-command.js
|
|
@@ -1767,7 +1776,16 @@ async function runScan(options) {
|
|
|
1767
1776
|
if (!created.ok || created.row === null) throw new Error(created.ok ? "candidate row missing" : created.message);
|
|
1768
1777
|
row = created.row;
|
|
1769
1778
|
const placed = await upsertRow(options.io, options.home, options.now, row, "verify");
|
|
1770
|
-
if (!placed.ok
|
|
1779
|
+
if (!placed.ok && placed.current.state === "skipped") {
|
|
1780
|
+
const restored = transition(placed.current, {
|
|
1781
|
+
type: "restore",
|
|
1782
|
+
at: at(options.now)
|
|
1783
|
+
});
|
|
1784
|
+
if (!restored.ok || restored.row === null) throw new Error("cannot restore skipped pair");
|
|
1785
|
+
row = restored.row;
|
|
1786
|
+
const retried = await upsertRow(options.io, options.home, options.now, row, "verify");
|
|
1787
|
+
if (!retried.ok) throw new Error("pair already in " + retried.current.state);
|
|
1788
|
+
} else if (!placed.ok) throw new Error("pair already in " + placed.current.state);
|
|
1771
1789
|
} catch (error) {
|
|
1772
1790
|
totals.failed += 1;
|
|
1773
1791
|
pairs.push({
|
|
@@ -3749,7 +3767,7 @@ function createMergeRuntime(deps) {
|
|
|
3749
3767
|
const managed = new Set(cards.filter((card) => card.managed === true && card.protectedBy == null).map((card) => card.name));
|
|
3750
3768
|
const loadedState = await loadMergeState(deps.io, deps.home);
|
|
3751
3769
|
const skipped = skippedPairKeys(loadedState.state.rows, deps.params.mergeSkippedTtlDays, deps.now());
|
|
3752
|
-
const held = new Set(loadedState.state.rows.filter((row) => row.queue === "pending" || row.queue === "fuse" || !canRetry(row)).map((row) => row.pairKey));
|
|
3770
|
+
const held = new Set(loadedState.state.rows.filter((row) => row.queue === "pending" || row.queue === "fuse" || row.queue === "verify" && !canRetry(row)).map((row) => row.pairKey));
|
|
3753
3771
|
const conflictNotes = loadedState.state.rows.filter((row) => row.state === "pending" || row.state === "approved" || row.state === "fuse" || row.state === "skipped").map((row) => "conflict:" + row.state + ":" + row.pairKey + ":" + row.id);
|
|
3754
3772
|
const result = await runScanCommand({
|
|
3755
3773
|
...common,
|
|
@@ -72,6 +72,12 @@ export async function recoverCommitJournals(io, home, now, skillRoot, restoreSou
|
|
|
72
72
|
await io.remove(skillBodyPath(skillRoot, snapshot.target));
|
|
73
73
|
}
|
|
74
74
|
catch { /* already gone */ }
|
|
75
|
+
try {
|
|
76
|
+
const dir = join(skillRoot, snapshot.target);
|
|
77
|
+
if ((await io.list(dir)).length === 0)
|
|
78
|
+
await io.remove(dir);
|
|
79
|
+
}
|
|
80
|
+
catch { /* absent or non-empty */ }
|
|
75
81
|
}
|
|
76
82
|
else if (snapshot.targetBody !== null) {
|
|
77
83
|
await io.writeText(skillBodyPath(skillRoot, snapshot.target), snapshot.targetBody);
|
|
@@ -5,6 +5,8 @@ export interface MergeError {
|
|
|
5
5
|
readonly code: string;
|
|
6
6
|
readonly message: string;
|
|
7
7
|
readonly detail?: string;
|
|
8
|
+
readonly stage?: string;
|
|
9
|
+
readonly runId?: string;
|
|
8
10
|
}
|
|
9
11
|
export declare function formatMergeError(error: MergeError): string;
|
|
10
12
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export function formatMergeError(error) {
|
|
2
2
|
if (error.kind === 'parameter')
|
|
3
3
|
return 'merge: ' + error.message + ' (' + error.code + ')';
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const where = error.stage === undefined && error.runId === undefined
|
|
5
|
+
? (error.detail ?? 'no additional detail')
|
|
6
|
+
: [error.stage === undefined ? undefined : 'stage=' + error.stage, error.runId === undefined ? undefined : 'run=' + error.runId].filter(Boolean).join(' ');
|
|
7
|
+
return 'merge failed: ' + error.message + ' (' + error.code + ')\n' + where + '\nnext: fix the target or rerun after the cause is gone';
|
|
6
8
|
}
|
|
7
9
|
//# sourceMappingURL=errors.js.map
|
|
@@ -2,27 +2,28 @@ import { loadMergeState } from "./state.js";
|
|
|
2
2
|
import { formatQueue, formatStatus } from "./status.js";
|
|
3
3
|
import { mergeUsage } from "./commands.js";
|
|
4
4
|
export async function handleReadOnlyMergeCommand(command, io, home) {
|
|
5
|
+
const withNote = (text, note) => note === undefined ? text : 'note: ' + note + '\n' + text;
|
|
5
6
|
if (command.verb === 'status') {
|
|
6
7
|
const loaded = await loadMergeState(io, home);
|
|
7
8
|
if (command.id !== undefined) {
|
|
8
9
|
const row = loaded.state.rows.find(item => item.id === command.id);
|
|
9
|
-
return row === undefined ? 'merge row not found: ' + command.id : formatStatus([row]);
|
|
10
|
+
return withNote(row === undefined ? 'merge row not found: ' + command.id : formatStatus([row]), loaded.note);
|
|
10
11
|
}
|
|
11
|
-
return formatStatus(loaded.state.rows);
|
|
12
|
+
return withNote(formatStatus(loaded.state.rows), loaded.note);
|
|
12
13
|
}
|
|
13
14
|
if (command.verb === 'pending') {
|
|
14
15
|
const loaded = await loadMergeState(io, home);
|
|
15
16
|
const rows = command.expired === true ? loaded.state.rows.filter(row => row.expired !== undefined) : loaded.state.rows;
|
|
16
|
-
return command.expired === true ? formatStatus(rows) : formatQueue(rows, 'pending');
|
|
17
|
+
return withNote(command.expired === true ? formatStatus(rows) : formatQueue(rows, 'pending'), loaded.note);
|
|
17
18
|
}
|
|
18
19
|
if (command.verb === 'candidates') {
|
|
19
20
|
const loaded = await loadMergeState(io, home);
|
|
20
21
|
const rows = command.retry === true ? loaded.state.rows.filter(row => row.state === 'approved') : loaded.state.rows;
|
|
21
|
-
return formatQueue(rows, command.retry === true ? 'fuse' : 'verify');
|
|
22
|
+
return withNote(formatQueue(rows, command.retry === true ? 'fuse' : 'verify'), loaded.note);
|
|
22
23
|
}
|
|
23
24
|
if (command.verb === 'skipped') {
|
|
24
25
|
const loaded = await loadMergeState(io, home);
|
|
25
|
-
return formatQueue(loaded.state.rows, 'skipped');
|
|
26
|
+
return withNote(formatQueue(loaded.state.rows, 'skipped'), loaded.note);
|
|
26
27
|
}
|
|
27
28
|
return null;
|
|
28
29
|
}
|
package/lib/types/runtime.js
CHANGED
|
@@ -104,7 +104,7 @@ export function createMergeRuntime(deps) {
|
|
|
104
104
|
const managed = new Set(cards.filter(card => card.managed === true && card.protectedBy == null).map(card => card.name));
|
|
105
105
|
const loadedState = await loadMergeState(deps.io, deps.home);
|
|
106
106
|
const skipped = skippedPairKeys(loadedState.state.rows, deps.params.mergeSkippedTtlDays, deps.now());
|
|
107
|
-
const held = new Set(loadedState.state.rows.filter(row => row.queue === 'pending' || row.queue === 'fuse' || !canRetry(row)).map(row => row.pairKey));
|
|
107
|
+
const held = new Set(loadedState.state.rows.filter(row => row.queue === 'pending' || row.queue === 'fuse' || (row.queue === 'verify' && !canRetry(row))).map(row => row.pairKey));
|
|
108
108
|
const conflictNotes = loadedState.state.rows
|
|
109
109
|
.filter(row => row.state === 'pending' || row.state === 'approved' || row.state === 'fuse' || row.state === 'skipped')
|
|
110
110
|
.map(row => 'conflict:' + row.state + ':' + row.pairKey + ':' + row.id);
|
package/lib/types/scan-run.js
CHANGED
|
@@ -66,8 +66,18 @@ export async function runScan(options) {
|
|
|
66
66
|
throw new Error(created.ok ? 'candidate row missing' : created.message);
|
|
67
67
|
row = created.row;
|
|
68
68
|
const placed = await upsertRow(options.io, options.home, options.now, row, 'verify');
|
|
69
|
-
if (!placed.ok)
|
|
69
|
+
if (!placed.ok && placed.current.state === 'skipped') {
|
|
70
|
+
const restored = transition(placed.current, { type: 'restore', at: at(options.now) });
|
|
71
|
+
if (!restored.ok || restored.row === null)
|
|
72
|
+
throw new Error('cannot restore skipped pair');
|
|
73
|
+
row = restored.row;
|
|
74
|
+
const retried = await upsertRow(options.io, options.home, options.now, row, 'verify');
|
|
75
|
+
if (!retried.ok)
|
|
76
|
+
throw new Error('pair already in ' + retried.current.state);
|
|
77
|
+
}
|
|
78
|
+
else if (!placed.ok) {
|
|
70
79
|
throw new Error('pair already in ' + placed.current.state);
|
|
80
|
+
}
|
|
71
81
|
}
|
|
72
82
|
catch (error) {
|
|
73
83
|
totals.failed += 1;
|
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.7",
|
|
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.7",
|
|
31
|
+
"@lmzhen/dsh-evolution-merge-engine": "^0.30.7"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@deepseek-ai/cordis": "^4.0.5"
|