@lmzhen/dsh-evolution-merge 0.32.5 → 0.33.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 CHANGED
@@ -1,19 +1,21 @@
1
1
  # @lmzhen/dsh-evolution-merge
2
2
 
3
- > 技能合并:把重叠技能合成一个,可审批、可撤销。
3
+ Skill merge service with candidate screening, two-round authoring, pending/skipped queues, staged model work, commit orchestration, recovery, and undo.
4
4
 
5
- ## 你会看到
5
+ Use `/evolution merge …` for operations. `merge_stage` is the model-facing staging tool. The sidebar supplied by `evolution-merge-ui` is read-only and copies commands rather than executing a merge itself.
6
6
 
7
- `/evolution merge …` 命令与侧栏合并面板。
7
+ ## Control axes
8
8
 
9
- ## 什么时候会用到
9
+ | Setting | Default | Meaning |
10
+ |---|---|---|
11
+ | `mergeApproval` | `false` | Do not pause after round 1 for merge-specific approval. |
12
+ | `mergeSkippedTtlDays` | `0` | Skipped pairs never expire automatically. |
13
+ | `mergeRunTimeoutMinutes` | `0` | No overall run timeout. |
14
+ | `mergePairTimeoutMinutes` | `15` | Bound one pair round. |
15
+ | `mergeModelsRoot` | empty | Must be configured to the local model root for the shipped engine path. |
10
16
 
11
- 你主动合并,或后台提出合并建议时。
17
+ For scan, the model root contains `potion-multilingual-128M-int8` and `potion-multilingual-128M-pca64-int8`. Missing required models fail explicitly; this package does not silently provision them. Ordinary pair skips this local candidate-screening dependency, but its round 1 and authoring still require the child-session model channel rather than scan's stub fallback.
12
18
 
13
- ## 默认 / 前提
19
+ Merge approval is independent of the ordinary memory/skill approval queue. `platformWrite` is accepted as a fallback parameter, overridden by the host approval capability when available, and included in run reports and snapshots; it is not an admission check in this package. Actual write execution depends on host capability preparation and the merge state machine; neither that projected field nor `mergeApproval:false` proves that every environment permits writes.
14
20
 
15
- 需要本地合并模型;没有模型会明确报错。
16
-
17
- ## 边界
18
-
19
- 面板只读;合并结果可撤销。
21
+ Four read-only host routes expose view, rows, body, and history data. `merge/run` and `merge/runs` are declared but not implemented. Committed merges have durable receipts for undo; recovery and reconcile report blocked or interrupted state rather than hiding it.
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { dirname, join } from "node:path";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { pairKeyOf, screen, selectCandidates } from "@lmzhen/dsh-evolution-merge-engine";
4
- import { DEFAULT_SKILL_LIMITS, SkillLibrary, UnitTransactions, authorityFrom, contentHash, createSubagentChannel, errorText, evolutionHome, evolutionIoAdapter, executeUnitUndo, isPresent, isProcessAlive, newRunRegistry, newSkillLibrary, parseFrontmatter, planUnitUndoAcross, policyStageLimits, probeAbsent, probeList, probePresent, probeText, probeUnknown, readTreeLock, readUnitEvidence, readUnitJournal, reportsSweepLockTarget, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runsFile, scanContentThreats, skillLibraryUnitBackend, supportRefs, sweepReports, transactIo, validateFrontmatter, validateSupportPath } from "@lmzhen/dsh-evolution-core";
4
+ import { DEFAULT_SKILL_LIMITS, SkillLibrary, UnitTransactions, authorityFrom, contentHash, createSubagentChannel, errorText, evolutionHome, evolutionIoAdapter, executeUnitUndo, isPresent, isProcessAlive, newRunRegistry, newSkillLibrary, parseFrontmatter, planUnitUndoAcross, policyStageLimits, probeAbsent, probeList, probePresent, probeText, probeUnknown, readTreeLock, readUnitEvidence, readUnitJournal, registerOwnerSettings, reportsSweepLockTarget, revisionAnchorOf, revisionFingerprint, revisionSupportDigest, runsFile, scanContentThreats, skillLibraryUnitBackend, supportRefs, sweepReports, transactIo, validateFrontmatter, validateSupportPath } from "@lmzhen/dsh-evolution-core";
5
5
  import { HOST_ROUTES, json, methodNotAllowed, registerHostRoutes } from "@lmzhen/dsh-evolution-core/http-routes";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { chmod, mkdir, open, readFile, stat, unlink } from "node:fs/promises";
@@ -3700,6 +3700,10 @@ function runView(run, readAt, includeResultRef = false) {
3700
3700
  const record = run.record;
3701
3701
  const state = run.meta?.phase === "undone" ? "undone" : run.meta?.stopReason === "interrupted" ? "interrupted" : run.meta?.approval === "pending" ? "awaiting-approval" : record.state;
3702
3702
  const stopReason = run.meta?.stopReason ?? (record.state === "cancelled" ? "cancelled" : record.state === "failed" ? "failed" : record.state === "succeeded" ? "completed" : void 0);
3703
+ const progress = record.progress === void 0 ? null : {
3704
+ done: state === "succeeded" || state === "undone" ? Math.max(record.progress.done, run.pairs.length) : record.progress.done,
3705
+ total: record.progress.total
3706
+ };
3703
3707
  return {
3704
3708
  wireVersion: 1,
3705
3709
  readAt,
@@ -3707,10 +3711,7 @@ function runView(run, readAt, includeResultRef = false) {
3707
3711
  state,
3708
3712
  command: record.command ?? "scan",
3709
3713
  ...record.stage === void 0 ? {} : { stage: record.stage },
3710
- progress: record.progress === void 0 ? null : {
3711
- done: record.progress.done,
3712
- total: record.progress.total
3713
- },
3714
+ progress,
3714
3715
  startedAt: record.startedAt,
3715
3716
  ...record.endedAt === void 0 ? {} : { endedAt: record.endedAt },
3716
3717
  ...stopReason === void 0 ? {} : { stopReason },
@@ -10543,6 +10544,7 @@ function formatUnreadyError() {
10543
10544
  }
10544
10545
  const inject = [];
10545
10546
  function apply(ctx, rawConfig = {}) {
10547
+ registerOwnerSettings(ctx, "evolution-merge", Config);
10546
10548
  configureMergePresentation(ctx);
10547
10549
  let params = resolveMergeParams(rawConfig);
10548
10550
  let mergeRun;
@@ -5,6 +5,7 @@ import { selectWithErrors } from "./adapters/select.js";
5
5
  import { createEngineScreening } from "./adapters/engine-screen.js";
6
6
  import { createEngineRunner } from "./adapters/model-runner.js";
7
7
  import { authorityFrom, createSubagentChannel, evolutionHome, evolutionIoAdapter, newRunRegistry, newSkillLibrary, reportsSweepLockTarget, sweepReports, transactIo } from '@lmzhen/dsh-evolution-core';
8
+ import { registerOwnerSettings } from '@lmzhen/dsh-evolution-core';
8
9
  import { registerHostRoutes } from '@lmzhen/dsh-evolution-core/http-routes';
9
10
  import { loadMergeState } from "./state.js";
10
11
  import { pairLedger, normalizePairLedger } from "./domain/pair-ledger.js";
@@ -134,6 +135,7 @@ function formatUnreadyError() {
134
135
  }
135
136
  export const inject = [];
136
137
  export function apply(ctx, rawConfig = {}) {
138
+ registerOwnerSettings(ctx, 'evolution-merge', Config);
137
139
  configureMergePresentation(ctx);
138
140
  let params = resolveMergeParams(rawConfig);
139
141
  let mergeRun;
@@ -86,7 +86,13 @@ function runView(run, readAt, includeResultRef = false) {
86
86
  : run.meta?.approval === 'pending' ? 'awaiting-approval'
87
87
  : record.state;
88
88
  const stopReason = run.meta?.stopReason ?? (record.state === 'cancelled' ? 'cancelled' : record.state === 'failed' ? 'failed' : record.state === 'succeeded' ? 'completed' : undefined);
89
- return { wireVersion: 1, readAt, id: record.id, state, command: record.command ?? 'scan', ...(record.stage === undefined ? {} : { stage: record.stage }), progress: record.progress === undefined ? null : { done: record.progress.done, total: record.progress.total }, startedAt: record.startedAt, ...(record.endedAt === undefined ? {} : { endedAt: record.endedAt }), ...(stopReason === undefined ? {} : { stopReason }), ...(record.failure === undefined ? {} : { failure: { stage: 'settle', code: 'run-failed', retryable: false, retryFrom: 'none', detail: record.failure } }), ...(record.parentRunId === undefined ? {} : { parentRunId: record.parentRunId }), ...(run.pairs[0]?.pairKey === undefined ? {} : { currentPairKey: run.pairs[0].pairKey }), ...(record.resultRef === undefined ? {} : { resultRef: record.resultRef }), actions: [{ id: 'status', command: base + 'status ' + record.id, confirm: false, enabled: true }, { id: 'report', command: base + 'report ' + record.id, confirm: false, enabled: record.resultRef !== undefined }, { id: 'cancel', command: base + 'cancel ' + record.id, confirm: false, enabled: record.state === 'running' }] };
89
+ // The maker records progress while running; a terminal run that actually produced pairs
90
+ // must not keep the last in-flight 0/N. The UI shows what happened, not the last tick.
91
+ const progress = record.progress === undefined ? null : {
92
+ done: state === 'succeeded' || state === 'undone' ? Math.max(record.progress.done, run.pairs.length) : record.progress.done,
93
+ total: record.progress.total,
94
+ };
95
+ return { wireVersion: 1, readAt, id: record.id, state, command: record.command ?? 'scan', ...(record.stage === undefined ? {} : { stage: record.stage }), progress, startedAt: record.startedAt, ...(record.endedAt === undefined ? {} : { endedAt: record.endedAt }), ...(stopReason === undefined ? {} : { stopReason }), ...(record.failure === undefined ? {} : { failure: { stage: 'settle', code: 'run-failed', retryable: false, retryFrom: 'none', detail: record.failure } }), ...(record.parentRunId === undefined ? {} : { parentRunId: record.parentRunId }), ...(run.pairs[0]?.pairKey === undefined ? {} : { currentPairKey: run.pairs[0].pairKey }), ...(record.resultRef === undefined ? {} : { resultRef: record.resultRef }), actions: [{ id: 'status', command: base + 'status ' + record.id, confirm: false, enabled: true }, { id: 'report', command: base + 'report ' + record.id, confirm: false, enabled: record.resultRef !== undefined }, { id: 'cancel', command: base + 'cancel ' + record.id, confirm: false, enabled: record.state === 'running' }] };
90
96
  }
91
97
  export function buildFacts(snapshot) {
92
98
  const ordered = [...snapshot.runs].sort((a, b) => b.record.startedAt - a.record.startedAt);
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.32.5",
4
+ "version": "0.33.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,9 +32,9 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@deepseek-ai/schemastery": "^3.18.5",
35
- "@lmzhen/dsh-evolution-core": "^0.32.5",
36
- "@lmzhen/dsh-evolution-commands": "^0.32.5",
37
- "@lmzhen/dsh-evolution-merge-engine": "0.32.5"
35
+ "@lmzhen/dsh-evolution-core": "^0.33.0",
36
+ "@lmzhen/dsh-evolution-commands": "^0.33.0",
37
+ "@lmzhen/dsh-evolution-merge-engine": "0.33.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@deepseek-ai/cordis": "^4.0.5"