@lmzhen/dsh-evolution-merge 0.30.13 → 0.30.15

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
@@ -1801,6 +1801,7 @@ async function runScan(options) {
1801
1801
  runId: options.runId
1802
1802
  };
1803
1803
  const before = (await loadMergeState(options.io, options.home)).state.rows.find((item) => item.pairKey === row.pairKey);
1804
+ if (before?.state === "verify" && before.runId !== void 0 && before.runId !== options.runId && await options.isOwnerActive?.(before.runId) === true) continue;
1804
1805
  const placed = await upsertRow(options.io, options.home, options.now, row, "verify", before?.updatedAt ?? null);
1805
1806
  if (!placed.ok && before?.state === "skipped") {
1806
1807
  const restored = transition(before, {
@@ -2178,7 +2179,8 @@ async function runScanCommand(options) {
2178
2179
  startedAt: ctx.startedAt,
2179
2180
  runId: ctx.runId,
2180
2181
  ...options.timeoutMinutes === void 0 ? {} : { timeoutMinutes: options.timeoutMinutes },
2181
- ...options.notes === void 0 ? {} : { notes: options.notes }
2182
+ ...options.notes === void 0 ? {} : { notes: options.notes },
2183
+ ...options.isOwnerActive === void 0 ? {} : { isOwnerActive: options.isOwnerActive }
2182
2184
  });
2183
2185
  }
2184
2186
  });
@@ -2467,36 +2469,47 @@ async function runResumeCommand(options) {
2467
2469
  ok: false,
2468
2470
  message: "merge row not found: " + options.rowId
2469
2471
  };
2470
- if (row.state === "verify") return await runScanCommand({
2471
- io: options.io,
2472
- home: options.home,
2473
- registry: options.registry,
2474
- approval: true,
2475
- platformWrite: options.platformWrite,
2476
- now: options.now,
2477
- ...options.makePorts === void 0 ? { ports: {
2478
- ...options.ports,
2479
- screening: () => Promise.resolve([{
2480
- a: row.a,
2481
- b: row.b
2482
- }])
2483
- } } : { makePorts: (runId) => {
2484
- const makePorts = options.makePorts;
2485
- if (makePorts === void 0) throw new Error("resume makePorts disappeared");
2486
- return {
2487
- ...makePorts(runId),
2472
+ if (row.state === "verify") {
2473
+ if (row.runId !== void 0 && await options.isOwnerActive?.(row.runId) === true) return {
2474
+ ok: false,
2475
+ message: "merge run still owns this verify row: " + row.runId
2476
+ };
2477
+ return await runScanCommand({
2478
+ io: options.io,
2479
+ home: options.home,
2480
+ registry: options.registry,
2481
+ approval: true,
2482
+ platformWrite: options.platformWrite,
2483
+ now: options.now,
2484
+ ...options.makePorts === void 0 ? { ports: {
2485
+ ...options.ports,
2488
2486
  screening: () => Promise.resolve([{
2489
2487
  a: row.a,
2490
2488
  b: row.b
2491
2489
  }])
2492
- };
2493
- } },
2494
- ...options.timeoutMinutes === void 0 ? {} : { timeoutMinutes: options.timeoutMinutes }
2495
- });
2490
+ } } : { makePorts: (runId) => {
2491
+ const makePorts = options.makePorts;
2492
+ if (makePorts === void 0) throw new Error("resume makePorts disappeared");
2493
+ return {
2494
+ ...makePorts(runId),
2495
+ screening: () => Promise.resolve([{
2496
+ a: row.a,
2497
+ b: row.b
2498
+ }])
2499
+ };
2500
+ } },
2501
+ ...options.timeoutMinutes === void 0 ? {} : { timeoutMinutes: options.timeoutMinutes },
2502
+ ...options.isOwnerActive === void 0 ? {} : { isOwnerActive: options.isOwnerActive }
2503
+ });
2504
+ }
2496
2505
  if (row.state !== "fuse" && row.state !== "approved") return {
2497
2506
  ok: false,
2498
2507
  message: "row is not resumable from state " + row.state
2499
2508
  };
2509
+ if (row.runId !== void 0 && await options.isOwnerActive?.(row.runId) === true) return {
2510
+ ok: false,
2511
+ message: "merge run still owns this fuse row: " + row.runId
2512
+ };
2500
2513
  const decision = row.decision;
2501
2514
  if (decision === void 0) return {
2502
2515
  ok: false,
@@ -3774,6 +3787,7 @@ function createMergeRuntime(deps) {
3774
3787
  registry: deps.registry,
3775
3788
  platformWrite: deps.platformWrite,
3776
3789
  now: deps.now,
3790
+ ...deps.isOwnerActive === void 0 ? {} : { isOwnerActive: deps.isOwnerActive },
3777
3791
  ...timeout === void 0 ? {} : { timeoutMinutes: timeout }
3778
3792
  };
3779
3793
  const stage = deps.stage;
@@ -4062,7 +4076,13 @@ function createMergeRuntime(deps) {
4062
4076
  };
4063
4077
  }
4064
4078
  const loaded = await loadMergeState(deps.io, deps.home);
4065
- const row = command.id === void 0 ? loaded.state.rows.find((item) => item.state === "fuse" || item.state === "verify" || command.retry === true && item.state === "approved") : loaded.state.rows.find((item) => item.id === command.id);
4079
+ let row = command.id === void 0 ? void 0 : loaded.state.rows.find((item) => item.id === command.id);
4080
+ if (command.id === void 0) for (const item of loaded.state.rows) {
4081
+ if (item.state !== "fuse" && item.state !== "verify" && !(command.retry === true && item.state === "approved")) continue;
4082
+ if (item.runId !== void 0 && await deps.isOwnerActive?.(item.runId) === true) continue;
4083
+ row = item;
4084
+ break;
4085
+ }
4066
4086
  if (row === void 0) return {
4067
4087
  ok: false,
4068
4088
  text: "merge row not found: " + (command.id ?? "(auto)")
@@ -4092,6 +4112,7 @@ function createMergeRuntime(deps) {
4092
4112
  ...common,
4093
4113
  rowId: row.id,
4094
4114
  ports: basePorts,
4115
+ ...deps.isOwnerActive === void 0 ? {} : { isOwnerActive: deps.isOwnerActive },
4095
4116
  makePorts: (runId) => createChannelScanPorts({
4096
4117
  io: deps.io,
4097
4118
  home: deps.home,
@@ -4818,6 +4839,10 @@ function apply(ctx, rawConfig = {}) {
4818
4839
  isBlocked: async (name) => {
4819
4840
  return await ctx.get("evolutionCurator")?.isBlocked?.(name) === true;
4820
4841
  },
4842
+ isOwnerActive: (runId) => {
4843
+ const run = runs.find(runId);
4844
+ return run !== void 0 && run.state === "running";
4845
+ },
4821
4846
  async cards(signal) {
4822
4847
  const listed = await skills.list({ withContent: true });
4823
4848
  if (signal.aborted) return [];
@@ -222,6 +222,10 @@ export function apply(ctx, rawConfig = {}) {
222
222
  const curator = ctx.get('evolutionCurator');
223
223
  return (await curator?.isBlocked?.(name)) === true;
224
224
  },
225
+ isOwnerActive: (runId) => {
226
+ const run = runs.find(runId);
227
+ return run !== undefined && run.state === 'running';
228
+ },
225
229
  async cards(signal) {
226
230
  const listed = await skills.list({ withContent: true });
227
231
  if (signal.aborted)
@@ -19,6 +19,7 @@ export interface RunResumeCommandOptions {
19
19
  readonly platformWrite: boolean;
20
20
  readonly timeoutMinutes?: number;
21
21
  readonly now: () => number;
22
+ readonly isOwnerActive?: (runId: string) => boolean | Promise<boolean>;
22
23
  }
23
24
  export declare function runResumeCommand(options: RunResumeCommandOptions): Promise<WithMergeRunResult>;
24
25
  //# sourceMappingURL=resume-command.d.ts.map
@@ -8,6 +8,9 @@ export async function runResumeCommand(options) {
8
8
  if (row === undefined)
9
9
  return { ok: false, message: 'merge row not found: ' + options.rowId };
10
10
  if (row.state === 'verify') {
11
+ if (row.runId !== undefined && (await options.isOwnerActive?.(row.runId)) === true) {
12
+ return { ok: false, message: 'merge run still owns this verify row: ' + row.runId };
13
+ }
11
14
  return await runScanCommand({
12
15
  io: options.io, home: options.home, registry: options.registry,
13
16
  approval: true, platformWrite: options.platformWrite, now: options.now,
@@ -22,10 +25,14 @@ export async function runResumeCommand(options) {
22
25
  },
23
26
  }),
24
27
  ...(options.timeoutMinutes === undefined ? {} : { timeoutMinutes: options.timeoutMinutes }),
28
+ ...(options.isOwnerActive === undefined ? {} : { isOwnerActive: options.isOwnerActive }),
25
29
  });
26
30
  }
27
31
  if (row.state !== 'fuse' && row.state !== 'approved')
28
32
  return { ok: false, message: 'row is not resumable from state ' + row.state };
33
+ if (row.runId !== undefined && (await options.isOwnerActive?.(row.runId)) === true) {
34
+ return { ok: false, message: 'merge run still owns this fuse row: ' + row.runId };
35
+ }
29
36
  const decision = row.decision;
30
37
  if (decision === undefined)
31
38
  return { ok: false, message: 'fuse row has no decision' };
@@ -33,6 +33,7 @@ export interface MergeRuntimeDeps {
33
33
  readonly cards: (signal: AbortSignal) => Promise<readonly SkillCard[]>;
34
34
  /** Curator gate set: excluded/referenced/suppressed/protected builtins. */
35
35
  readonly isBlocked?: (name: string) => boolean | Promise<boolean>;
36
+ readonly isOwnerActive?: (runId: string) => boolean | Promise<boolean>;
36
37
  /** Run-scoped engine screening. */
37
38
  readonly screeningForRun: (cards: readonly SkillCard[], runId: string, signal: AbortSignal) => Promise<readonly MergeCandidate[]>;
38
39
  readonly stage?: MergeStageBindingPort;
@@ -34,6 +34,7 @@ export function createMergeRuntime(deps) {
34
34
  const common = {
35
35
  io: deps.io, home: deps.home, registry: deps.registry,
36
36
  platformWrite: deps.platformWrite, now: deps.now,
37
+ ...(deps.isOwnerActive === undefined ? {} : { isOwnerActive: deps.isOwnerActive }),
37
38
  ...(timeout === undefined ? {} : { timeoutMinutes: timeout }),
38
39
  };
39
40
  const stage = deps.stage;
@@ -231,9 +232,17 @@ export function createMergeRuntime(deps) {
231
232
  return { ok: true, text: '已清除合并行:' + cleared.id };
232
233
  }
233
234
  const loaded = await loadMergeState(deps.io, deps.home);
234
- const row = command.id === undefined
235
- ? loaded.state.rows.find(item => item.state === 'fuse' || item.state === 'verify' || (command.retry === true && item.state === 'approved'))
236
- : loaded.state.rows.find(item => item.id === command.id);
235
+ let row = command.id === undefined ? undefined : loaded.state.rows.find(item => item.id === command.id);
236
+ if (command.id === undefined) {
237
+ for (const item of loaded.state.rows) {
238
+ if (item.state !== 'fuse' && item.state !== 'verify' && !(command.retry === true && item.state === 'approved'))
239
+ continue;
240
+ if (item.runId !== undefined && (await deps.isOwnerActive?.(item.runId)) === true)
241
+ continue;
242
+ row = item;
243
+ break;
244
+ }
245
+ }
237
246
  if (row === undefined)
238
247
  return { ok: false, text: 'merge row not found: ' + (command.id ?? '(auto)') };
239
248
  const signal = new AbortController().signal;
@@ -250,6 +259,7 @@ export function createMergeRuntime(deps) {
250
259
  };
251
260
  const result = await runResumeCommand({
252
261
  ...common, rowId: row.id, ports: basePorts,
262
+ ...(deps.isOwnerActive === undefined ? {} : { isOwnerActive: deps.isOwnerActive }),
253
263
  makePorts: runId => createChannelScanPorts({
254
264
  io: deps.io, home: deps.home, runId, cards, screening: pair,
255
265
  channel: deps.channel, parent, allow: deps.allow,
@@ -18,6 +18,7 @@ export interface RunScanCommandOptions {
18
18
  readonly now: () => number;
19
19
  readonly detached?: boolean;
20
20
  readonly notes?: readonly string[];
21
+ readonly isOwnerActive?: (runId: string) => boolean | Promise<boolean>;
21
22
  }
22
23
  export declare function runScanCommand(options: RunScanCommandOptions): Promise<WithMergeRunResult>;
23
24
  //# sourceMappingURL=scan-command.d.ts.map
@@ -25,6 +25,7 @@ export async function runScanCommand(options) {
25
25
  runId: ctx.runId,
26
26
  ...(options.timeoutMinutes === undefined ? {} : { timeoutMinutes: options.timeoutMinutes }),
27
27
  ...(options.notes === undefined ? {} : { notes: options.notes }),
28
+ ...(options.isOwnerActive === undefined ? {} : { isOwnerActive: options.isOwnerActive }),
28
29
  });
29
30
  },
30
31
  });
@@ -45,6 +45,7 @@ export interface RunScanOptions {
45
45
  }) => Promise<void>;
46
46
  readonly notes?: readonly string[];
47
47
  readonly runId?: string;
48
+ readonly isOwnerActive?: (runId: string) => boolean | Promise<boolean>;
48
49
  }
49
50
  export declare function runScan(options: RunScanOptions): Promise<MergeRunReportDraft>;
50
51
  //# sourceMappingURL=scan-run.d.ts.map
@@ -66,6 +66,10 @@ export async function runScan(options) {
66
66
  throw new Error(created.ok ? 'candidate row missing' : created.message);
67
67
  row = options.runId === undefined ? created.row : { ...created.row, runId: options.runId };
68
68
  const before = (await loadMergeState(options.io, options.home)).state.rows.find(item => item.pairKey === row.pairKey);
69
+ if (before?.state === 'verify' && before.runId !== undefined && before.runId !== options.runId
70
+ && (await options.isOwnerActive?.(before.runId)) === true) {
71
+ continue;
72
+ }
69
73
  const placed = await upsertRow(options.io, options.home, options.now, row, 'verify', before?.updatedAt ?? null);
70
74
  if (!placed.ok && before?.state === 'skipped') {
71
75
  const restored = transition(before, { type: 'restore', at: at(options.now) });
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.13",
4
+ "version": "0.30.15",
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.13",
31
- "@lmzhen/dsh-evolution-merge-engine": "^0.30.13"
30
+ "@lmzhen/dsh-evolution-core": "^0.30.15",
31
+ "@lmzhen/dsh-evolution-merge-engine": "^0.30.15"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@deepseek-ai/cordis": "^4.0.5"