@lmzhen/dsh-evolution-merge 0.28.0 → 0.30.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/README.md +21 -18
- package/lib/index.js +1583 -1209
- package/lib/types/adapters/channel.js +29 -0
- package/lib/types/adapters/engine-screen.d.ts +55 -0
- package/lib/types/adapters/engine-screen.js +45 -0
- package/lib/types/adapters/library.js +14 -0
- package/lib/types/adapters/model-runner.d.ts +28 -0
- package/lib/types/adapters/model-runner.js +34 -0
- package/lib/types/adapters/select.d.ts +3 -0
- package/lib/types/adapters/select.js +35 -0
- package/lib/types/adapters/undo.js +35 -0
- package/lib/types/approve-command.js +42 -0
- package/lib/types/authoring-flow.d.ts +7 -2
- package/lib/types/authoring-flow.js +48 -0
- package/lib/types/channel-port.d.ts +2 -1
- package/lib/types/channel-port.js +74 -0
- package/lib/types/commands.d.ts +9 -0
- package/lib/types/commands.js +79 -0
- package/lib/types/commit-assembly.d.ts +2 -0
- package/lib/types/commit-assembly.js +48 -0
- package/lib/types/commit-execute.js +52 -0
- package/lib/types/commit-plan.js +56 -0
- package/lib/types/commit-receipt.d.ts +6 -1
- package/lib/types/commit-receipt.js +85 -0
- package/lib/types/contracts.d.ts +21 -7
- package/lib/types/contracts.js +57 -0
- package/lib/types/coordinator.d.ts +11 -0
- package/lib/types/coordinator.js +131 -0
- package/lib/types/decision.js +61 -0
- package/lib/types/doctor.d.ts +1 -1
- package/lib/types/doctor.js +50 -0
- package/lib/types/domain/claim.d.ts +10 -0
- package/lib/types/domain/claim.js +12 -0
- package/lib/types/domain/commit-journal-store.d.ts +6 -0
- package/lib/types/domain/commit-journal-store.js +22 -0
- package/lib/types/domain/commit-journal.d.ts +16 -0
- package/lib/types/domain/commit-journal.js +25 -0
- package/lib/types/domain/errors.d.ts +10 -0
- package/lib/types/domain/errors.js +7 -0
- package/lib/types/domain/failure-route.d.ts +25 -0
- package/lib/types/domain/failure-route.js +22 -0
- package/lib/types/domain/indexes.d.ts +21 -0
- package/lib/types/domain/indexes.js +15 -0
- package/lib/types/domain/ledger.d.ts +17 -0
- package/lib/types/domain/ledger.js +65 -0
- package/lib/types/domain/markdown.d.ts +2 -0
- package/lib/types/domain/markdown.js +57 -0
- package/lib/types/domain/migrate-v1.d.ts +41 -0
- package/lib/types/domain/migrate-v1.js +23 -0
- package/lib/types/domain/pair-index-store.d.ts +6 -0
- package/lib/types/domain/pair-index-store.js +25 -0
- package/lib/types/domain/pair-index.d.ts +9 -0
- package/lib/types/domain/pair-index.js +28 -0
- package/lib/types/domain/resolve-pair.d.ts +11 -0
- package/lib/types/domain/resolve-pair.js +17 -0
- package/lib/types/domain/row.d.ts +113 -0
- package/lib/types/domain/row.js +111 -0
- package/lib/types/domain/run-record.d.ts +45 -0
- package/lib/types/domain/run-record.js +24 -0
- package/lib/types/domain/state.d.ts +57 -0
- package/lib/types/domain/state.js +65 -0
- package/lib/types/gate-cache.js +36 -0
- package/lib/types/index.d.ts +6 -7
- package/lib/types/index.js +241 -0
- package/lib/types/ladder.js +162 -0
- package/lib/types/merge-command.d.ts +3 -0
- package/lib/types/merge-command.js +43 -0
- package/lib/types/merge-routes.d.ts +15 -4
- package/lib/types/merge-routes.js +99 -0
- package/lib/types/merge-tool.js +69 -0
- package/lib/types/new-child-authoring.d.ts +1 -1
- package/lib/types/new-child-authoring.js +83 -0
- package/lib/types/pair-command.js +18 -0
- package/lib/types/params.d.ts +1 -0
- package/lib/types/params.js +49 -0
- package/lib/types/pending-actions.js +28 -0
- package/lib/types/prompts.d.ts +7 -5
- package/lib/types/prompts.js +60 -0
- package/lib/types/read-commands.js +32 -0
- package/lib/types/report.js +70 -0
- package/lib/types/resume-command.js +57 -0
- package/lib/types/round2-outcome.js +50 -0
- package/lib/types/routes.d.ts +20 -2
- package/lib/types/routes.js +75 -0
- package/lib/types/rules.js +55 -0
- package/lib/types/run-shell.d.ts +7 -0
- package/lib/types/run-shell.js +69 -0
- package/lib/types/runtime.d.ts +5 -4
- package/lib/types/runtime.js +269 -0
- package/lib/types/scan-command.d.ts +1 -0
- package/lib/types/scan-command.js +30 -0
- package/lib/types/scan-ports.d.ts +1 -1
- package/lib/types/scan-ports.js +93 -0
- package/lib/types/scan-run.d.ts +4 -0
- package/lib/types/scan-run.js +186 -0
- package/lib/types/skill-card.d.ts +12 -0
- package/lib/types/skill-card.js +2 -0
- package/lib/types/skipped.js +24 -0
- package/lib/types/stage-tool-registry.js +32 -0
- package/lib/types/stage-tool.js +31 -0
- package/lib/types/staged-tree.js +75 -0
- package/lib/types/staging-files.js +86 -0
- package/lib/types/staging.d.ts +13 -0
- package/lib/types/staging.js +149 -0
- package/lib/types/state.js +103 -0
- package/lib/types/status.d.ts +2 -1
- package/lib/types/status.js +28 -0
- package/lib/types/supersede.js +14 -0
- package/lib/types/undo-merge.js +23 -0
- package/package.json +4 -7
- package/lib/types/adapters/model.d.ts +0 -31
- package/lib/types/gate-filter.d.ts +0 -31
- package/lib/types/propose.d.ts +0 -26
- package/lib/types/screening-port.d.ts +0 -47
- package/lib/types/screening.d.ts +0 -30
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { type MergeState } from './state.ts';
|
|
2
|
+
import type { MergeDecision, MergeFailure } from '../contracts.ts';
|
|
3
|
+
export interface MergeRowV2 {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly pairKey: string;
|
|
6
|
+
readonly a: string;
|
|
7
|
+
readonly b: string;
|
|
8
|
+
readonly state: MergeState;
|
|
9
|
+
readonly queue: 'verify' | 'pending' | 'fuse' | 'skipped';
|
|
10
|
+
readonly failure?: MergeFailure;
|
|
11
|
+
readonly decision?: MergeDecision;
|
|
12
|
+
readonly sourceRevision?: string;
|
|
13
|
+
readonly targetRevision?: string;
|
|
14
|
+
readonly runId?: string;
|
|
15
|
+
readonly unitId?: string;
|
|
16
|
+
readonly origin?: 'agent' | 'human' | 'system';
|
|
17
|
+
readonly attempts?: number;
|
|
18
|
+
readonly stagingRef?: string;
|
|
19
|
+
readonly stagingExpiresAt?: number;
|
|
20
|
+
readonly target?: {
|
|
21
|
+
readonly requested: string;
|
|
22
|
+
readonly actual?: string;
|
|
23
|
+
readonly created?: boolean;
|
|
24
|
+
};
|
|
25
|
+
readonly reason?: string;
|
|
26
|
+
readonly expired?: 'target-taken' | 'source-changed';
|
|
27
|
+
readonly createdAt: string;
|
|
28
|
+
readonly updatedAt: string;
|
|
29
|
+
}
|
|
30
|
+
export type MergeRowEvent = {
|
|
31
|
+
readonly type: 'candidate';
|
|
32
|
+
readonly a: string;
|
|
33
|
+
readonly b: string;
|
|
34
|
+
readonly at: string;
|
|
35
|
+
} | {
|
|
36
|
+
readonly type: 'round1-start';
|
|
37
|
+
readonly at: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly type: 'round1-keep';
|
|
40
|
+
readonly at: string;
|
|
41
|
+
} | {
|
|
42
|
+
readonly type: 'round1-merge';
|
|
43
|
+
readonly approval: 'on' | 'off';
|
|
44
|
+
readonly decision?: MergeDecision;
|
|
45
|
+
readonly stagingRef?: string;
|
|
46
|
+
readonly stagingExpiresAt?: number;
|
|
47
|
+
readonly at: string;
|
|
48
|
+
} | {
|
|
49
|
+
readonly type: 'round1-fail';
|
|
50
|
+
readonly failure: MergeFailure;
|
|
51
|
+
readonly at: string;
|
|
52
|
+
} | {
|
|
53
|
+
readonly type: 'approve';
|
|
54
|
+
readonly runId?: string;
|
|
55
|
+
readonly at: string;
|
|
56
|
+
} | {
|
|
57
|
+
readonly type: 'reject';
|
|
58
|
+
readonly at: string;
|
|
59
|
+
} | {
|
|
60
|
+
readonly type: 'round2-start';
|
|
61
|
+
readonly at: string;
|
|
62
|
+
} | {
|
|
63
|
+
readonly type: 'round2-fail';
|
|
64
|
+
readonly failure: MergeFailure;
|
|
65
|
+
readonly at: string;
|
|
66
|
+
} | {
|
|
67
|
+
readonly type: 'round2-success';
|
|
68
|
+
readonly unitId?: string;
|
|
69
|
+
readonly at: string;
|
|
70
|
+
} | {
|
|
71
|
+
readonly type: 'restore';
|
|
72
|
+
readonly at: string;
|
|
73
|
+
} | {
|
|
74
|
+
readonly type: 'discard';
|
|
75
|
+
readonly at: string;
|
|
76
|
+
} | {
|
|
77
|
+
readonly type: 'source-gone';
|
|
78
|
+
readonly at: string;
|
|
79
|
+
} | {
|
|
80
|
+
readonly type: 'target-taken';
|
|
81
|
+
readonly at: string;
|
|
82
|
+
} | {
|
|
83
|
+
readonly type: 'source-changed';
|
|
84
|
+
readonly at: string;
|
|
85
|
+
} | {
|
|
86
|
+
readonly type: 'staging-expired';
|
|
87
|
+
readonly at: string;
|
|
88
|
+
} | {
|
|
89
|
+
readonly type: 'round2-cancel';
|
|
90
|
+
readonly at: string;
|
|
91
|
+
} | {
|
|
92
|
+
readonly type: 'timeout';
|
|
93
|
+
readonly at: string;
|
|
94
|
+
} | {
|
|
95
|
+
readonly type: 'cancel';
|
|
96
|
+
readonly at: string;
|
|
97
|
+
} | {
|
|
98
|
+
readonly type: 'gate-keep';
|
|
99
|
+
readonly a: string;
|
|
100
|
+
readonly b: string;
|
|
101
|
+
readonly reason?: string;
|
|
102
|
+
readonly at: string;
|
|
103
|
+
};
|
|
104
|
+
export type RowTransitionResult = {
|
|
105
|
+
readonly ok: true;
|
|
106
|
+
readonly row: MergeRowV2 | null;
|
|
107
|
+
} | {
|
|
108
|
+
readonly ok: false;
|
|
109
|
+
readonly code: 'invalid-transition';
|
|
110
|
+
readonly message: string;
|
|
111
|
+
};
|
|
112
|
+
export declare function transitionRow(current: MergeRowV2 | undefined, event: MergeRowEvent): RowTransitionResult;
|
|
113
|
+
//# sourceMappingURL=row.d.ts.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** Pure v2 row transitions for G1 cutover. No IO. */
|
|
2
|
+
import { pairKey, rowIdOf } from "../contracts.js";
|
|
3
|
+
import { queueOf, transition as stateTransition } from "./state.js";
|
|
4
|
+
function base(row, at) {
|
|
5
|
+
return {
|
|
6
|
+
id: row.id, pairKey: row.pairKey, a: row.a, b: row.b,
|
|
7
|
+
state: row.state, queue: row.queue, createdAt: row.createdAt, updatedAt: at,
|
|
8
|
+
...(row.runId === undefined ? {} : { runId: row.runId }),
|
|
9
|
+
...(row.unitId === undefined ? {} : { unitId: row.unitId }),
|
|
10
|
+
...(row.origin === undefined ? {} : { origin: row.origin }),
|
|
11
|
+
...(row.decision === undefined ? {} : { decision: row.decision }),
|
|
12
|
+
...(row.sourceRevision === undefined ? {} : { sourceRevision: row.sourceRevision }),
|
|
13
|
+
...(row.targetRevision === undefined ? {} : { targetRevision: row.targetRevision }),
|
|
14
|
+
...(row.attempts === undefined ? {} : { attempts: row.attempts }),
|
|
15
|
+
...(row.stagingRef === undefined ? {} : { stagingRef: row.stagingRef }),
|
|
16
|
+
...(row.stagingExpiresAt === undefined ? {} : { stagingExpiresAt: row.stagingExpiresAt }),
|
|
17
|
+
...(row.expired === undefined ? {} : { expired: row.expired }),
|
|
18
|
+
...(row.target === undefined ? {} : { target: row.target }),
|
|
19
|
+
...(row.reason === undefined ? {} : { reason: row.reason }),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function next(row, at, state, patch = {}) {
|
|
23
|
+
return { ok: true, row: { ...base(row, at), state, queue: queueOf(state), ...patch } };
|
|
24
|
+
}
|
|
25
|
+
function invalid(event, state) {
|
|
26
|
+
return { ok: false, code: 'invalid-transition', message: 'cannot apply ' + event.type + ' to ' + (state ?? 'no row') };
|
|
27
|
+
}
|
|
28
|
+
export function transitionRow(current, event) {
|
|
29
|
+
if (event.type === 'candidate') {
|
|
30
|
+
if (current !== undefined)
|
|
31
|
+
return { ok: true, row: current };
|
|
32
|
+
const key = pairKey(event.a, event.b);
|
|
33
|
+
return { ok: true, row: { id: rowIdOf(key), pairKey: key, a: event.a, b: event.b, state: 'verify', queue: 'verify', createdAt: event.at, updatedAt: event.at } };
|
|
34
|
+
}
|
|
35
|
+
if (event.type === 'source-gone')
|
|
36
|
+
return { ok: true, row: null };
|
|
37
|
+
if (event.type === 'gate-keep') {
|
|
38
|
+
if (current !== undefined)
|
|
39
|
+
return { ok: true, row: current };
|
|
40
|
+
const key = pairKey(event.a, event.b);
|
|
41
|
+
return { ok: true, row: { id: rowIdOf(key), pairKey: key, a: event.a, b: event.b, state: 'skipped', queue: 'skipped', origin: 'agent', createdAt: event.at, updatedAt: event.at } };
|
|
42
|
+
}
|
|
43
|
+
if (current === undefined)
|
|
44
|
+
return invalid(event, undefined);
|
|
45
|
+
if (event.type === 'discard') {
|
|
46
|
+
return current.state === 'pending' || current.state === 'approved' || current.state === 'fuse'
|
|
47
|
+
? { ok: true, row: null }
|
|
48
|
+
: invalid(event, current.state);
|
|
49
|
+
}
|
|
50
|
+
if (event.type === 'restore') {
|
|
51
|
+
return current.state === 'skipped' ? next(current, event.at, 'verify') : invalid(event, current.state);
|
|
52
|
+
}
|
|
53
|
+
if (event.type === 'target-taken' || event.type === 'source-changed') {
|
|
54
|
+
return current.state === 'pending' || current.state === 'approved' || current.state === 'fuse'
|
|
55
|
+
? next(current, event.at, current.state, { expired: event.type })
|
|
56
|
+
: invalid(event, current.state);
|
|
57
|
+
}
|
|
58
|
+
if (event.type === 'staging-expired') {
|
|
59
|
+
return current.state === 'fuse' || current.state === 'approved'
|
|
60
|
+
? next(current, event.at, 'approved')
|
|
61
|
+
: invalid(event, current.state);
|
|
62
|
+
}
|
|
63
|
+
if (event.type === 'round2-cancel' || event.type === 'timeout' || event.type === 'cancel') {
|
|
64
|
+
return current.state === 'fuse' ? next(current, event.at, 'approved') : { ok: true, row: current };
|
|
65
|
+
}
|
|
66
|
+
const mapped = event.type === 'round2-success'
|
|
67
|
+
? { type: 'round2-merged' }
|
|
68
|
+
: event.type === 'round2-fail'
|
|
69
|
+
? { type: 'round2-fail' }
|
|
70
|
+
: event.type === 'round1-merge'
|
|
71
|
+
? { type: 'round1-merge', approval: event.approval === 'on' }
|
|
72
|
+
: event.type === 'round1-start'
|
|
73
|
+
? { type: 'round1-start' }
|
|
74
|
+
: event.type === 'round2-start'
|
|
75
|
+
? { type: 'round2-start' }
|
|
76
|
+
: event.type === 'round1-keep'
|
|
77
|
+
? { type: 'round1-keep' }
|
|
78
|
+
: event.type === 'round1-fail'
|
|
79
|
+
? { type: 'round1-fail' }
|
|
80
|
+
: event.type === 'approve'
|
|
81
|
+
? { type: 'approve' }
|
|
82
|
+
: { type: 'reject' };
|
|
83
|
+
const moved = stateTransition(current.state, mapped);
|
|
84
|
+
if (!moved.ok)
|
|
85
|
+
return invalid(event, current.state);
|
|
86
|
+
if (moved.state === null)
|
|
87
|
+
return { ok: true, row: null };
|
|
88
|
+
const patch = {};
|
|
89
|
+
if (event.type === 'round1-merge') {
|
|
90
|
+
if (event.decision !== undefined)
|
|
91
|
+
patch.decision = event.decision;
|
|
92
|
+
if (event.stagingRef !== undefined)
|
|
93
|
+
patch.stagingRef = event.stagingRef;
|
|
94
|
+
if (event.stagingExpiresAt !== undefined)
|
|
95
|
+
patch.stagingExpiresAt = event.stagingExpiresAt;
|
|
96
|
+
}
|
|
97
|
+
if (event.type === 'approve' && event.runId !== undefined)
|
|
98
|
+
patch.runId = event.runId;
|
|
99
|
+
if (event.type === 'round1-fail' || event.type === 'round2-fail') {
|
|
100
|
+
patch.failure = event.failure;
|
|
101
|
+
patch.attempts = (current.attempts ?? 0) + 1;
|
|
102
|
+
}
|
|
103
|
+
if (event.type === 'round1-keep')
|
|
104
|
+
patch.origin = 'agent';
|
|
105
|
+
if (event.type === 'reject')
|
|
106
|
+
patch.origin = 'human';
|
|
107
|
+
if (event.type === 'round2-success' && event.unitId !== undefined)
|
|
108
|
+
patch.unitId = event.unitId;
|
|
109
|
+
return next(current, event.at, moved.state, patch);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=row.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Pure RunRecord v2 types and derived 9-state projection. No IO. */
|
|
2
|
+
export type RunStatus = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'interrupted' | 'orphan';
|
|
3
|
+
export type MergeStatus = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'awaiting-approval' | 'undone' | 'superseded' | 'interrupted' | 'orphan';
|
|
4
|
+
export type PairResult = 'pending' | 'merged' | 'kept' | 'failed' | 'cancelled' | 'undone';
|
|
5
|
+
export interface PairRecord {
|
|
6
|
+
readonly pairKey: string;
|
|
7
|
+
readonly a: string;
|
|
8
|
+
readonly b: string;
|
|
9
|
+
readonly result: PairResult;
|
|
10
|
+
readonly target?: {
|
|
11
|
+
readonly requested: string;
|
|
12
|
+
readonly actual?: string;
|
|
13
|
+
readonly created?: boolean;
|
|
14
|
+
};
|
|
15
|
+
readonly stagingRef?: string;
|
|
16
|
+
readonly committed?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface PairIndexEntry {
|
|
19
|
+
readonly pairKey: string;
|
|
20
|
+
readonly runId: string;
|
|
21
|
+
readonly result: PairResult;
|
|
22
|
+
readonly target?: string;
|
|
23
|
+
readonly reportRef?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface RunRecordV2 {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly kind: 'merge';
|
|
28
|
+
readonly status: RunStatus;
|
|
29
|
+
readonly stage?: 'screening' | 'decide' | 'author' | 'commit' | 'settle';
|
|
30
|
+
readonly approval?: 'on' | 'off';
|
|
31
|
+
readonly parentRunId?: string;
|
|
32
|
+
readonly pairKey?: string;
|
|
33
|
+
readonly plane?: 'local' | 'foreign';
|
|
34
|
+
readonly startedAt: number;
|
|
35
|
+
readonly updatedAt: number;
|
|
36
|
+
readonly endedAt?: number;
|
|
37
|
+
readonly resultRef?: string;
|
|
38
|
+
readonly failure?: string;
|
|
39
|
+
readonly stagingRef?: string;
|
|
40
|
+
readonly pairs: readonly PairRecord[];
|
|
41
|
+
readonly supersededAt?: number;
|
|
42
|
+
}
|
|
43
|
+
export declare function deriveMergeStatus(record: RunRecordV2): MergeStatus;
|
|
44
|
+
export declare function allCommittedUndone(record: RunRecordV2): boolean;
|
|
45
|
+
//# sourceMappingURL=run-record.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function deriveMergeStatus(record) {
|
|
2
|
+
if (record.supersededAt !== undefined)
|
|
3
|
+
return 'superseded';
|
|
4
|
+
if (record.status === 'interrupted')
|
|
5
|
+
return 'interrupted';
|
|
6
|
+
if (record.status === 'orphan')
|
|
7
|
+
return 'orphan';
|
|
8
|
+
if (record.status === 'failed' || record.status === 'cancelled')
|
|
9
|
+
return record.status;
|
|
10
|
+
if (record.status === 'running') {
|
|
11
|
+
return record.approval === 'on' && record.pairs.some(pair => pair.result === 'pending')
|
|
12
|
+
? 'awaiting-approval'
|
|
13
|
+
: 'running';
|
|
14
|
+
}
|
|
15
|
+
const committed = record.pairs.filter(pair => pair.committed === true);
|
|
16
|
+
if (committed.length > 0 && committed.every(pair => pair.result === 'undone'))
|
|
17
|
+
return 'undone';
|
|
18
|
+
return 'succeeded';
|
|
19
|
+
}
|
|
20
|
+
export function allCommittedUndone(record) {
|
|
21
|
+
const committed = record.pairs.filter(pair => pair.committed === true);
|
|
22
|
+
return committed.length > 0 && committed.every(pair => pair.result === 'undone');
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=run-record.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Pure merge decision state machine. No IO, no host imports. */
|
|
2
|
+
export type MergeState = 'verify' | 'pending' | 'approved' | 'fuse' | 'skipped';
|
|
3
|
+
export type MergeQueue = 'verify' | 'pending' | 'fuse' | 'skipped';
|
|
4
|
+
export type MergeEvent = {
|
|
5
|
+
readonly type: 'candidate';
|
|
6
|
+
} | {
|
|
7
|
+
readonly type: 'round1-start';
|
|
8
|
+
} | {
|
|
9
|
+
readonly type: 'round1-keep';
|
|
10
|
+
} | {
|
|
11
|
+
readonly type: 'round1-merge';
|
|
12
|
+
readonly approval: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
readonly type: 'round1-fail';
|
|
15
|
+
} | {
|
|
16
|
+
readonly type: 'approve';
|
|
17
|
+
} | {
|
|
18
|
+
readonly type: 'reject';
|
|
19
|
+
} | {
|
|
20
|
+
readonly type: 'round2-start';
|
|
21
|
+
} | {
|
|
22
|
+
readonly type: 'round2-fail';
|
|
23
|
+
} | {
|
|
24
|
+
readonly type: 'round2-merged';
|
|
25
|
+
} | {
|
|
26
|
+
readonly type: 'round2-cancel';
|
|
27
|
+
} | {
|
|
28
|
+
readonly type: 'staging-expired';
|
|
29
|
+
} | {
|
|
30
|
+
readonly type: 'source-gone';
|
|
31
|
+
} | {
|
|
32
|
+
readonly type: 'target-taken';
|
|
33
|
+
} | {
|
|
34
|
+
readonly type: 'source-changed';
|
|
35
|
+
} | {
|
|
36
|
+
readonly type: 'cancel';
|
|
37
|
+
} | {
|
|
38
|
+
readonly type: 'timeout';
|
|
39
|
+
};
|
|
40
|
+
export type TransitionResult = {
|
|
41
|
+
readonly ok: true;
|
|
42
|
+
readonly state: MergeState;
|
|
43
|
+
} | {
|
|
44
|
+
readonly ok: true;
|
|
45
|
+
readonly state: null;
|
|
46
|
+
readonly removed: true;
|
|
47
|
+
} | {
|
|
48
|
+
readonly ok: false;
|
|
49
|
+
readonly code: 'invalid-transition';
|
|
50
|
+
readonly message: string;
|
|
51
|
+
};
|
|
52
|
+
export declare function queueOf(state: MergeState): MergeQueue;
|
|
53
|
+
export declare function isTerminal(state: MergeState): boolean;
|
|
54
|
+
/** Single transition point; callers must not mutate fields outside this function. */
|
|
55
|
+
export declare function transition(state: MergeState, event: MergeEvent): TransitionResult;
|
|
56
|
+
export declare function allowedEvents(state: MergeState): readonly MergeEvent['type'][];
|
|
57
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export function queueOf(state) {
|
|
2
|
+
switch (state) {
|
|
3
|
+
case 'verify': return 'verify';
|
|
4
|
+
case 'pending': return 'pending';
|
|
5
|
+
case 'approved':
|
|
6
|
+
case 'fuse': return 'fuse';
|
|
7
|
+
case 'skipped': return 'skipped';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function isTerminal(state) {
|
|
11
|
+
return state === 'skipped';
|
|
12
|
+
}
|
|
13
|
+
function fail(state, event) {
|
|
14
|
+
return { ok: false, code: 'invalid-transition', message: 'cannot apply ' + event.type + ' to ' + state };
|
|
15
|
+
}
|
|
16
|
+
/** Single transition point; callers must not mutate fields outside this function. */
|
|
17
|
+
export function transition(state, event) {
|
|
18
|
+
switch (event.type) {
|
|
19
|
+
case 'candidate':
|
|
20
|
+
return state === 'verify' ? { ok: true, state: 'verify' } : fail(state, event);
|
|
21
|
+
case 'round1-start':
|
|
22
|
+
return state === 'verify' ? { ok: true, state: 'verify' } : fail(state, event);
|
|
23
|
+
case 'round1-keep':
|
|
24
|
+
return state === 'verify' ? { ok: true, state: 'skipped' } : fail(state, event);
|
|
25
|
+
case 'round1-merge':
|
|
26
|
+
return state === 'verify'
|
|
27
|
+
? { ok: true, state: event.approval ? 'pending' : 'approved' }
|
|
28
|
+
: fail(state, event);
|
|
29
|
+
case 'round1-fail':
|
|
30
|
+
return state === 'verify' ? { ok: true, state: 'verify' } : fail(state, event);
|
|
31
|
+
case 'approve':
|
|
32
|
+
return state === 'pending' ? { ok: true, state: 'approved' } : fail(state, event);
|
|
33
|
+
case 'reject':
|
|
34
|
+
return state === 'pending' || state === 'approved' || state === 'fuse'
|
|
35
|
+
? { ok: true, state: 'skipped' }
|
|
36
|
+
: fail(state, event);
|
|
37
|
+
case 'round2-start':
|
|
38
|
+
return state === 'approved' ? { ok: true, state: 'fuse' } : fail(state, event);
|
|
39
|
+
case 'round2-fail':
|
|
40
|
+
case 'round2-cancel':
|
|
41
|
+
return state === 'fuse' || state === 'approved' ? { ok: true, state: 'approved' } : fail(state, event);
|
|
42
|
+
case 'round2-merged':
|
|
43
|
+
return state === 'fuse' || state === 'approved' ? { ok: true, state: null, removed: true } : fail(state, event);
|
|
44
|
+
case 'staging-expired':
|
|
45
|
+
return state === 'fuse' ? { ok: true, state: 'approved' } : fail(state, event);
|
|
46
|
+
case 'source-gone':
|
|
47
|
+
return { ok: true, state: null, removed: true };
|
|
48
|
+
case 'target-taken':
|
|
49
|
+
case 'source-changed':
|
|
50
|
+
return state === 'pending' ? { ok: true, state: 'pending' } : fail(state, event);
|
|
51
|
+
case 'cancel':
|
|
52
|
+
case 'timeout':
|
|
53
|
+
return state === 'verify' || state === 'approved' || state === 'fuse' ? { ok: true, state } : fail(state, event);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function allowedEvents(state) {
|
|
57
|
+
switch (state) {
|
|
58
|
+
case 'verify': return ['candidate', 'round1-start', 'round1-keep', 'round1-merge', 'round1-fail', 'source-gone', 'cancel', 'timeout'];
|
|
59
|
+
case 'pending': return ['approve', 'reject', 'target-taken', 'source-changed', 'source-gone'];
|
|
60
|
+
case 'approved': return ['round2-start', 'reject', 'staging-expired', 'source-gone', 'cancel', 'timeout'];
|
|
61
|
+
case 'fuse': return ['round2-fail', 'round2-merged', 'round2-cancel', 'staging-expired', 'reject', 'source-gone', 'cancel', 'timeout'];
|
|
62
|
+
case 'skipped': return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-backed gate cache: <home>/merge/gate-cache.json.
|
|
3
|
+
* Reads are three-state; a malformed file is reported, not overwritten. Writes are one
|
|
4
|
+
* transact so two runs cannot interleave a partial cache.
|
|
5
|
+
*/
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { probeText, transactIo } from '@lmzhen/dsh-evolution-core';
|
|
8
|
+
import { GateCache } from "./ladder.js";
|
|
9
|
+
export const GATE_CACHE_VERSION = 1;
|
|
10
|
+
export function gateCachePath(home) {
|
|
11
|
+
return join(home, 'merge', 'gate-cache.json');
|
|
12
|
+
}
|
|
13
|
+
export async function loadGateCache(io, home) {
|
|
14
|
+
const probe = await probeText(io, gateCachePath(home));
|
|
15
|
+
if (probe.kind === 'absent')
|
|
16
|
+
return { cache: new GateCache() };
|
|
17
|
+
if (probe.kind === 'unknown')
|
|
18
|
+
return { cache: new GateCache(), note: probe.reason };
|
|
19
|
+
try {
|
|
20
|
+
const parsed = JSON.parse(probe.value);
|
|
21
|
+
if (parsed.schemaVersion !== GATE_CACHE_VERSION || typeof parsed.entries !== 'object' || parsed.entries === null) {
|
|
22
|
+
return { cache: new GateCache(), note: 'gate cache has an unexpected shape' };
|
|
23
|
+
}
|
|
24
|
+
return { cache: GateCache.fromObject(parsed.entries) };
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return { cache: new GateCache(), note: 'gate cache is not JSON: ' + (error instanceof Error ? error.message : String(error)) };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function saveGateCache(io, home, cache) {
|
|
31
|
+
await transactIo(io, gateCachePath(home), () => JSON.stringify({ schemaVersion: GATE_CACHE_VERSION, entries: cache.toObject() }, null, 2) + '\n');
|
|
32
|
+
}
|
|
33
|
+
export function hasGateCache(cache) {
|
|
34
|
+
return cache.size > 0;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=gate-cache.js.map
|
package/lib/types/index.d.ts
CHANGED
|
@@ -6,11 +6,13 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
6
6
|
mergeSkippedTtlDays: z<number, number, "volatile-defined">;
|
|
7
7
|
mergeRunTimeoutMinutes: z<number, number, "volatile-defined">;
|
|
8
8
|
mergePairTimeoutMinutes: z<number, number, "defined">;
|
|
9
|
+
mergeModelsRoot: z<string, string, "defined">;
|
|
9
10
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
10
11
|
mergeApproval: z<boolean, boolean, "volatile-defined">;
|
|
11
12
|
mergeSkippedTtlDays: z<number, number, "volatile-defined">;
|
|
12
13
|
mergeRunTimeoutMinutes: z<number, number, "volatile-defined">;
|
|
13
14
|
mergePairTimeoutMinutes: z<number, number, "defined">;
|
|
15
|
+
mergeModelsRoot: z<string, string, "defined">;
|
|
14
16
|
}>>, "plain">;
|
|
15
17
|
export interface MergePresentationScope {
|
|
16
18
|
effect(run: () => () => void, label?: string): unknown;
|
|
@@ -20,6 +22,7 @@ export interface MergePresentationScope {
|
|
|
20
22
|
}, owner?: unknown) => unknown;
|
|
21
23
|
};
|
|
22
24
|
}
|
|
25
|
+
export declare function engineConfigFromEnv(configuredRoot?: string): Record<string, unknown> | undefined;
|
|
23
26
|
export interface MergePresentationContext {
|
|
24
27
|
inject(names: string[], run: (scope: MergePresentationScope) => void): void;
|
|
25
28
|
readonly fiber?: unknown;
|
|
@@ -27,6 +30,7 @@ export interface MergePresentationContext {
|
|
|
27
30
|
/** Suppress the platform auto form; the registry renders the merge card instead. */
|
|
28
31
|
export declare function configureMergePresentation(ctx: MergePresentationContext): void;
|
|
29
32
|
export * from './contracts.ts';
|
|
33
|
+
export * from './skill-card.ts';
|
|
30
34
|
export * from './state.ts';
|
|
31
35
|
export * from './coordinator.ts';
|
|
32
36
|
export * from './report.ts';
|
|
@@ -42,8 +46,9 @@ export * from './commit-receipt.ts';
|
|
|
42
46
|
export * from './commit-execute.ts';
|
|
43
47
|
export * from './undo-merge.ts';
|
|
44
48
|
export * from './adapters/library.ts';
|
|
45
|
-
export * from './adapters/model.ts';
|
|
49
|
+
export * from './adapters/model-runner.ts';
|
|
46
50
|
export * from './adapters/channel.ts';
|
|
51
|
+
export * from './adapters/engine-screen.ts';
|
|
47
52
|
export * from './adapters/undo.ts';
|
|
48
53
|
export * from './run-shell.ts';
|
|
49
54
|
export * from './scan-run.ts';
|
|
@@ -53,12 +58,6 @@ export * from './round2-outcome.ts';
|
|
|
53
58
|
export * from './approve-command.ts';
|
|
54
59
|
export * from './pair-command.ts';
|
|
55
60
|
export * from './resume-command.ts';
|
|
56
|
-
export * from './screening.ts';
|
|
57
|
-
export * from './propose.ts';
|
|
58
|
-
export * from './ladder.ts';
|
|
59
|
-
export * from './gate-cache.ts';
|
|
60
|
-
export * from './gate-filter.ts';
|
|
61
|
-
export * from './screening-port.ts';
|
|
62
61
|
export * from './decision.ts';
|
|
63
62
|
export * from './prompts.ts';
|
|
64
63
|
export * from './channel-port.ts';
|