@lmzhen/dsh-evolution-merge 0.30.5 → 0.30.6
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
|
@@ -1527,24 +1527,28 @@ function mergeUsage() {
|
|
|
1527
1527
|
//#endregion
|
|
1528
1528
|
//#region lib/types/read-commands.js
|
|
1529
1529
|
async function handleReadOnlyMergeCommand(command, io, home) {
|
|
1530
|
+
const withNote = (text, note) => note === void 0 ? text : "note: " + note + "\n" + text;
|
|
1530
1531
|
if (command.verb === "status") {
|
|
1531
1532
|
const loaded = await loadMergeState(io, home);
|
|
1532
1533
|
if (command.id !== void 0) {
|
|
1533
1534
|
const row = loaded.state.rows.find((item) => item.id === command.id);
|
|
1534
|
-
return row === void 0 ? "merge row not found: " + command.id : formatStatus([row]);
|
|
1535
|
+
return withNote(row === void 0 ? "merge row not found: " + command.id : formatStatus([row]), loaded.note);
|
|
1535
1536
|
}
|
|
1536
|
-
return formatStatus(loaded.state.rows);
|
|
1537
|
+
return withNote(formatStatus(loaded.state.rows), loaded.note);
|
|
1537
1538
|
}
|
|
1538
1539
|
if (command.verb === "pending") {
|
|
1539
1540
|
const loaded = await loadMergeState(io, home);
|
|
1540
1541
|
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");
|
|
1542
|
+
return withNote(command.expired === true ? formatStatus(rows) : formatQueue(rows, "pending"), loaded.note);
|
|
1542
1543
|
}
|
|
1543
1544
|
if (command.verb === "candidates") {
|
|
1544
1545
|
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");
|
|
1546
|
+
return withNote(formatQueue(command.retry === true ? loaded.state.rows.filter((row) => row.state === "approved") : loaded.state.rows, command.retry === true ? "fuse" : "verify"), loaded.note);
|
|
1547
|
+
}
|
|
1548
|
+
if (command.verb === "skipped") {
|
|
1549
|
+
const loaded = await loadMergeState(io, home);
|
|
1550
|
+
return withNote(formatQueue(loaded.state.rows, "skipped"), loaded.note);
|
|
1546
1551
|
}
|
|
1547
|
-
if (command.verb === "skipped") return formatQueue((await loadMergeState(io, home)).state.rows, "skipped");
|
|
1548
1552
|
return null;
|
|
1549
1553
|
}
|
|
1550
1554
|
function mergeCommandHelp() {
|
|
@@ -1554,8 +1558,8 @@ function mergeCommandHelp() {
|
|
|
1554
1558
|
//#region lib/types/domain/errors.js
|
|
1555
1559
|
function formatMergeError(error) {
|
|
1556
1560
|
if (error.kind === "parameter") return "merge: " + error.message + " (" + error.code + ")";
|
|
1557
|
-
const
|
|
1558
|
-
return "merge failed: " + error.message + " (" + error.code + ")" +
|
|
1561
|
+
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(" ");
|
|
1562
|
+
return "merge failed: " + error.message + " (" + error.code + ")\n" + where + "\nnext: fix the target or rerun after the cause is gone";
|
|
1559
1563
|
}
|
|
1560
1564
|
//#endregion
|
|
1561
1565
|
//#region lib/types/merge-command.js
|
|
@@ -1767,7 +1771,16 @@ async function runScan(options) {
|
|
|
1767
1771
|
if (!created.ok || created.row === null) throw new Error(created.ok ? "candidate row missing" : created.message);
|
|
1768
1772
|
row = created.row;
|
|
1769
1773
|
const placed = await upsertRow(options.io, options.home, options.now, row, "verify");
|
|
1770
|
-
if (!placed.ok
|
|
1774
|
+
if (!placed.ok && placed.current.state === "skipped") {
|
|
1775
|
+
const restored = transition(placed.current, {
|
|
1776
|
+
type: "restore",
|
|
1777
|
+
at: at(options.now)
|
|
1778
|
+
});
|
|
1779
|
+
if (!restored.ok || restored.row === null) throw new Error("cannot restore skipped pair");
|
|
1780
|
+
row = restored.row;
|
|
1781
|
+
const retried = await upsertRow(options.io, options.home, options.now, row, "verify");
|
|
1782
|
+
if (!retried.ok) throw new Error("pair already in " + retried.current.state);
|
|
1783
|
+
} else if (!placed.ok) throw new Error("pair already in " + placed.current.state);
|
|
1771
1784
|
} catch (error) {
|
|
1772
1785
|
totals.failed += 1;
|
|
1773
1786
|
pairs.push({
|
|
@@ -3749,7 +3762,7 @@ function createMergeRuntime(deps) {
|
|
|
3749
3762
|
const managed = new Set(cards.filter((card) => card.managed === true && card.protectedBy == null).map((card) => card.name));
|
|
3750
3763
|
const loadedState = await loadMergeState(deps.io, deps.home);
|
|
3751
3764
|
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));
|
|
3765
|
+
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
3766
|
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
3767
|
const result = await runScanCommand({
|
|
3755
3768
|
...common,
|
|
@@ -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.6",
|
|
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.6",
|
|
31
|
+
"@lmzhen/dsh-evolution-merge-engine": "^0.30.6"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@deepseek-ai/cordis": "^4.0.5"
|