@lmzhen/dsh-evolution-merge 0.29.0 → 0.30.1

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.
Files changed (97) hide show
  1. package/lib/index.js +1125 -568
  2. package/lib/types/adapters/channel.js +29 -0
  3. package/lib/types/adapters/engine-screen.d.ts +1 -1
  4. package/lib/types/adapters/engine-screen.js +45 -0
  5. package/lib/types/adapters/library.js +14 -0
  6. package/lib/types/adapters/model-runner.js +34 -0
  7. package/lib/types/adapters/select.d.ts +3 -0
  8. package/lib/types/adapters/select.js +35 -0
  9. package/lib/types/adapters/undo.js +35 -0
  10. package/lib/types/approve-command.js +42 -0
  11. package/lib/types/authoring-flow.js +48 -0
  12. package/lib/types/channel-port.js +74 -0
  13. package/lib/types/commands.d.ts +9 -0
  14. package/lib/types/commands.js +79 -0
  15. package/lib/types/commit-assembly.js +48 -0
  16. package/lib/types/commit-execute.js +52 -0
  17. package/lib/types/commit-plan.js +56 -0
  18. package/lib/types/commit-receipt.d.ts +2 -0
  19. package/lib/types/commit-receipt.js +85 -0
  20. package/lib/types/contracts.d.ts +14 -5
  21. package/lib/types/contracts.js +57 -0
  22. package/lib/types/coordinator.d.ts +3 -0
  23. package/lib/types/coordinator.js +131 -0
  24. package/lib/types/decision.js +61 -0
  25. package/lib/types/doctor.js +50 -0
  26. package/lib/types/domain/claim.d.ts +10 -0
  27. package/lib/types/domain/claim.js +12 -0
  28. package/lib/types/domain/commit-journal-store.d.ts +6 -0
  29. package/lib/types/domain/commit-journal-store.js +22 -0
  30. package/lib/types/domain/commit-journal.d.ts +16 -0
  31. package/lib/types/domain/commit-journal.js +25 -0
  32. package/lib/types/domain/errors.d.ts +10 -0
  33. package/lib/types/domain/errors.js +7 -0
  34. package/lib/types/domain/failure-route.d.ts +25 -0
  35. package/lib/types/domain/failure-route.js +22 -0
  36. package/lib/types/domain/indexes.d.ts +21 -0
  37. package/lib/types/domain/indexes.js +15 -0
  38. package/lib/types/domain/ledger.d.ts +17 -0
  39. package/lib/types/domain/ledger.js +65 -0
  40. package/lib/types/domain/markdown.d.ts +2 -0
  41. package/lib/types/domain/markdown.js +57 -0
  42. package/lib/types/domain/migrate-v1.d.ts +41 -0
  43. package/lib/types/domain/migrate-v1.js +23 -0
  44. package/lib/types/domain/pair-index-store.d.ts +6 -0
  45. package/lib/types/domain/pair-index-store.js +25 -0
  46. package/lib/types/domain/pair-index.d.ts +9 -0
  47. package/lib/types/domain/pair-index.js +28 -0
  48. package/lib/types/domain/resolve-pair.d.ts +11 -0
  49. package/lib/types/domain/resolve-pair.js +17 -0
  50. package/lib/types/domain/row.d.ts +113 -0
  51. package/lib/types/domain/row.js +111 -0
  52. package/lib/types/domain/run-record.d.ts +45 -0
  53. package/lib/types/domain/run-record.js +24 -0
  54. package/lib/types/domain/state.d.ts +57 -0
  55. package/lib/types/domain/state.js +65 -0
  56. package/lib/types/gate-cache.js +36 -0
  57. package/lib/types/index.js +241 -0
  58. package/lib/types/ladder.js +162 -0
  59. package/lib/types/merge-command.js +43 -0
  60. package/lib/types/merge-routes.d.ts +14 -4
  61. package/lib/types/merge-routes.js +99 -0
  62. package/lib/types/merge-tool.js +69 -0
  63. package/lib/types/new-child-authoring.js +83 -0
  64. package/lib/types/pair-command.js +18 -0
  65. package/lib/types/params.js +49 -0
  66. package/lib/types/pending-actions.js +28 -0
  67. package/lib/types/prompts.js +60 -0
  68. package/lib/types/read-commands.js +32 -0
  69. package/lib/types/report.js +70 -0
  70. package/lib/types/resume-command.js +57 -0
  71. package/lib/types/round2-outcome.js +50 -0
  72. package/lib/types/routes.d.ts +5 -2
  73. package/lib/types/routes.js +75 -0
  74. package/lib/types/rules.js +55 -0
  75. package/lib/types/run-shell.d.ts +7 -0
  76. package/lib/types/run-shell.js +69 -0
  77. package/lib/types/runtime.d.ts +2 -0
  78. package/lib/types/runtime.js +269 -0
  79. package/lib/types/scan-command.d.ts +1 -0
  80. package/lib/types/scan-command.js +30 -0
  81. package/lib/types/scan-ports.js +93 -0
  82. package/lib/types/scan-run.d.ts +2 -0
  83. package/lib/types/scan-run.js +186 -0
  84. package/lib/types/skill-card.js +2 -0
  85. package/lib/types/skipped.js +24 -0
  86. package/lib/types/stage-tool-registry.js +32 -0
  87. package/lib/types/stage-tool.js +31 -0
  88. package/lib/types/staged-tree.js +75 -0
  89. package/lib/types/staging-files.js +86 -0
  90. package/lib/types/staging.d.ts +7 -0
  91. package/lib/types/staging.js +149 -0
  92. package/lib/types/state.js +103 -0
  93. package/lib/types/status.d.ts +2 -1
  94. package/lib/types/status.js +28 -0
  95. package/lib/types/supersede.js +14 -0
  96. package/lib/types/undo-merge.js +23 -0
  97. package/package.json +4 -4
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The one merge-state ledger: <home>/merge/merge-state.json.
3
+ *
4
+ * Reads are pure projections (no write, no reconciliation side effect). Every write goes
5
+ * through mutateMergeState and a single transactIo, so there is no second file and no
6
+ * incremental writer. A row's queue is always derived from its state on read; a hand-edited
7
+ * mismatch is repaired by the next write, never by a GET.
8
+ */
9
+ import { join } from 'node:path';
10
+ import { transactIo } from '@lmzhen/dsh-evolution-core';
11
+ import { MERGE_STATE_VERSION, queueOf, } from "./contracts.js";
12
+ import { parseLedger } from "./domain/ledger.js";
13
+ export function mergeStatePath(home) {
14
+ return join(home, 'merge', 'merge-state.json');
15
+ }
16
+ function parseState(raw) {
17
+ const parsed = parseLedger(raw);
18
+ if (!parsed.ok)
19
+ return { ok: false, rows: [] };
20
+ return {
21
+ ok: true,
22
+ rows: parsed.ledger.rows,
23
+ ...(parsed.note === undefined ? {} : { note: parsed.note }),
24
+ };
25
+ }
26
+ /** Pure read: never writes, never deletes a row. */
27
+ export async function loadMergeState(io, home) {
28
+ let raw = null;
29
+ try {
30
+ raw = await io.readText(mergeStatePath(home));
31
+ }
32
+ catch {
33
+ return { ok: false, state: { schemaVersion: MERGE_STATE_VERSION, rows: [] } };
34
+ }
35
+ const parsed = parseState(raw);
36
+ return {
37
+ ok: parsed.ok,
38
+ state: { schemaVersion: MERGE_STATE_VERSION, rows: parsed.rows },
39
+ ...(parsed.note === undefined ? {} : { note: parsed.note }),
40
+ };
41
+ }
42
+ /** The ONE write point. The callback returns the whole row set, not a delta. */
43
+ export async function mutateMergeState(io, home, now, fn) {
44
+ let result;
45
+ let ran = false;
46
+ await transactIo(io, mergeStatePath(home), (current) => {
47
+ ran = true;
48
+ const parsed = parseState(current);
49
+ const out = fn(parsed.rows);
50
+ result = out.result;
51
+ return JSON.stringify({ schemaVersion: MERGE_STATE_VERSION, rows: out.rows }, null, 2);
52
+ });
53
+ // transactIo only returns after fn ran; a skipped write is not a state outcome.
54
+ void ran;
55
+ void now;
56
+ return result;
57
+ }
58
+ export async function upsertRow(io, home, now, row) {
59
+ await mutateMergeState(io, home, now, (rows) => {
60
+ const index = rows.findIndex(item => item.pairKey === row.pairKey);
61
+ const normalized = { ...row, queue: queueOf(row.state) };
62
+ const next = [...rows];
63
+ if (index < 0)
64
+ next.push(normalized);
65
+ else
66
+ next[index] = { ...normalized, createdAt: rows[index]?.createdAt ?? normalized.createdAt };
67
+ return { rows: next, result: undefined };
68
+ });
69
+ }
70
+ export async function moveRow(io, home, now, id, patch) {
71
+ return await mutateMergeState(io, home, now, (rows) => {
72
+ const index = rows.findIndex(item => item.id === id);
73
+ if (index < 0)
74
+ return { rows, result: undefined };
75
+ const current = rows[index];
76
+ const state = patch.state ?? current.state;
77
+ const next = {
78
+ ...current,
79
+ state,
80
+ queue: queueOf(state),
81
+ updatedAt: new Date(now()).toISOString(),
82
+ ...(patch.failure === undefined ? {} : { failure: patch.failure }),
83
+ ...(patch.runId === undefined ? {} : { runId: patch.runId }),
84
+ ...(patch.unitId === undefined ? {} : { unitId: patch.unitId }),
85
+ ...(patch.origin === undefined ? {} : { origin: patch.origin }),
86
+ ...(patch.attempts === undefined ? {} : { attempts: patch.attempts }),
87
+ };
88
+ const copy = [...rows];
89
+ copy[index] = next;
90
+ return { rows: copy, result: next };
91
+ });
92
+ }
93
+ export async function dropRow(io, home, now, id) {
94
+ return await mutateMergeState(io, home, now, (rows) => {
95
+ const next = rows.filter(item => item.id !== id);
96
+ return { rows: next, result: next.length !== rows.length };
97
+ });
98
+ }
99
+ export async function rowsOf(io, home, queue) {
100
+ const loaded = await loadMergeState(io, home);
101
+ return queue === undefined ? loaded.state.rows : loaded.state.rows.filter(row => row.queue === queue);
102
+ }
103
+ //# sourceMappingURL=state.js.map
@@ -4,8 +4,9 @@
4
4
  */
5
5
  import type { MergeQueue, MergeRow } from './contracts.ts';
6
6
  export interface MergeCounts {
7
+ readonly verify: number;
7
8
  readonly pending: number;
8
- readonly retry: number;
9
+ readonly fuse: number;
9
10
  readonly skipped: number;
10
11
  }
11
12
  export declare function countRows(rows: readonly MergeRow[]): MergeCounts;
@@ -0,0 +1,28 @@
1
+ import { queueOf, stageOf } from "./contracts.js";
2
+ export function countRows(rows) {
3
+ const counts = { verify: 0, pending: 0, fuse: 0, skipped: 0 };
4
+ for (const row of rows)
5
+ counts[queueOf(row.state)] += 1;
6
+ return counts;
7
+ }
8
+ function describe(row) {
9
+ const stage = stageOf(row.state);
10
+ const target = row.decision?.shouldMerge === true ? ' → ' + row.decision.target : '';
11
+ return row.a + ' + ' + row.b + ' [' + row.state + (stage === null ? '' : '/' + stage) + ']' + target + (row.failure === undefined ? '' : ' — ' + row.failure.message);
12
+ }
13
+ export function formatStatus(rows) {
14
+ const counts = countRows(rows);
15
+ const lines = [
16
+ 'merge: verify ' + String(counts.verify) + ', pending ' + String(counts.pending) + ', fuse ' + String(counts.fuse) + ', skipped ' + String(counts.skipped),
17
+ ];
18
+ for (const row of rows)
19
+ lines.push('- ' + describe(row));
20
+ return lines.join('\n');
21
+ }
22
+ export function formatQueue(rows, queue) {
23
+ const selected = rows.filter(row => queueOf(row.state) === queue);
24
+ if (selected.length === 0)
25
+ return 'merge ' + queue + ': empty';
26
+ return ['merge ' + queue + ': ' + String(selected.length)].concat(selected.map(row => '- ' + describe(row))).join('\n');
27
+ }
28
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1,14 @@
1
+ export function mergeRunIdsToSupersede(runs) {
2
+ return runs.filter(run => run.kind === 'merge' && run.supersededAt === undefined).map(run => run.id);
3
+ }
4
+ export async function supersedeMergeRuns(registry) {
5
+ const shared = registry.supersedeKind;
6
+ if (typeof shared === 'function')
7
+ return await shared.call(registry, 'merge');
8
+ const ids = mergeRunIdsToSupersede(registry.runs());
9
+ if (ids.length === 0)
10
+ return 0;
11
+ await registry.supersede(ids);
12
+ return ids.length;
13
+ }
14
+ //# sourceMappingURL=supersede.js.map
@@ -0,0 +1,23 @@
1
+ import { executeUnitUndo, planUnitUndoAcross } from '@lmzhen/dsh-evolution-core';
2
+ export async function undoMergeReceipt(receipt, port) {
3
+ const targetVersions = (await port.listVersions(receipt.target)).filter(entry => entry.unitId === receipt.unitId);
4
+ if (targetVersions.length === 0) {
5
+ return { ok: false, message: 'unit ' + receipt.unitId + ' is not in the target history; refusing to guess', reverted: [] };
6
+ }
7
+ const members = [{ skill: receipt.target, entries: targetVersions, status: 'live', ...(receipt.create ? { createdInUnit: true } : {}) }];
8
+ for (const source of receipt.sources) {
9
+ const live = await port.readSkill(source);
10
+ members.push({
11
+ skill: source,
12
+ entries: (await port.listVersions(source)).filter(entry => entry.unitId === receipt.unitId),
13
+ status: live === null ? 'archived' : 'live',
14
+ ...(live === null ? { archivedPath: 'archive' } : {}),
15
+ });
16
+ }
17
+ const plan = planUnitUndoAcross(members);
18
+ if (plan.refusals.length > 0) {
19
+ return { ok: false, message: 'merge undo preflight refused: ' + plan.refusals.join('; '), reverted: [] };
20
+ }
21
+ return await executeUnitUndo(plan, port);
22
+ }
23
+ //# sourceMappingURL=undo-merge.js.map
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.29.0",
4
+ "version": "0.30.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -21,14 +21,14 @@
21
21
  "./package.json": "./package.json"
22
22
  },
23
23
  "files": [
24
- "lib/*.js",
24
+ "lib/**/*.js",
25
25
  "lib/types/**/*.d.ts"
26
26
  ],
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.5",
30
- "@lmzhen/dsh-evolution-core": "^0.29.0",
31
- "@lmzhen/dsh-evolution-merge-engine": "^0.29.0"
30
+ "@lmzhen/dsh-evolution-core": "^0.30.1",
31
+ "@lmzhen/dsh-evolution-merge-engine": "^0.30.1"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@deepseek-ai/cordis": "^4.0.5"