@lmzhen/dsh-evolution-commands 0.30.36 → 0.30.38
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 +45 -59
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { DEFAULT_SKILL_LIMITS, DIAGNOSTICS_FACT_KEYS, DIAGNOSTICS_RUNTIME_KEYS, DIAGNOSTICS_VIEW_SCHEMA_VERSION, EVOLUTION_PRESET_IDS, MAINTAINER_PRESET_ID, MAX_TIMER_DELAY_MS, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PLATFORM_LINE, REVIEWER_PRESET_ID, absentHostServices, appendEvolutionEvent, applyNamespaceMigration, asRecord, assertSkillsRootAliasRetired, atomicWriteFiles, authorityFrom, buildLearnPrompt, canonicalWriteId, clampedNumber, classifyNamespaceMigration, classifySessionEvent,
|
|
2
|
+
import { DEFAULT_SKILL_LIMITS, DIAGNOSTICS_FACT_KEYS, DIAGNOSTICS_RUNTIME_KEYS, DIAGNOSTICS_VIEW_SCHEMA_VERSION, EVOLUTION_PRESET_IDS, MAINTAINER_PRESET_ID, MAX_TIMER_DELAY_MS, PARAM_EXPOSURE, PARAM_GROUP_LABELS, PLATFORM_LINE, REVIEWER_PRESET_ID, absentHostServices, appendEvolutionEvent, applyNamespaceMigration, asRecord, assertSkillsRootAliasRetired, atomicWriteFiles, authorityFrom, buildExtractPlanFromLibrary, buildLearnPrompt, canonicalWriteId, clampedNumber, classifyNamespaceMigration, classifySessionEvent, createSubagentChannel, elapsedSince, errorText, eventsFile, evolutionHome, evolutionRoot, hostSurface, isDeprecatedParamId, isPresent, isRecord, isUnknown, liveBool, newRunRegistry, newSkillLibrary, paramSettingsId, partitionVersions, planNamespaceMigration, policyStageLimits, probeMtime, probeText, proposalFromPlan, reportsSweepLockTarget, resolveParamId, resolveRootConfig, scopedPackageName, scopedProbeReport, sweepReports, transactIo, writeProposalReport } from "@lmzhen/dsh-evolution-core";
|
|
3
3
|
import { HOST_ROUTES, json, methodNotAllowed, registerHostRoutes } from "@lmzhen/dsh-evolution-core/http-routes";
|
|
4
4
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
@@ -1996,6 +1996,11 @@ const COMMAND_ENTRIES = [
|
|
|
1996
1996
|
usage: "skill unpin <name>",
|
|
1997
1997
|
summary: "解钉一个技能:撤销上面的冻结(立即生效、不走审批)"
|
|
1998
1998
|
},
|
|
1999
|
+
{
|
|
2000
|
+
readonly: false,
|
|
2001
|
+
usage: "propose",
|
|
2002
|
+
summary: "为 body-oversize 技能写 keep 提议(不自动拆分;同一 reports store)"
|
|
2003
|
+
},
|
|
1999
2004
|
{
|
|
2000
2005
|
readonly: true,
|
|
2001
2006
|
usage: "skills health",
|
|
@@ -2063,8 +2068,8 @@ const COMMAND_ENTRIES = [
|
|
|
2063
2068
|
},
|
|
2064
2069
|
{
|
|
2065
2070
|
readonly: false,
|
|
2066
|
-
usage: "extract <source> <target> \"<heading>\" [--start <line>] [--end <line>] [--
|
|
2067
|
-
summary: "
|
|
2071
|
+
usage: "extract <source> <target> \"<heading>\" [--start <line>] [--end <line>] [--outcome extract|mixed] [--apply]",
|
|
2072
|
+
summary: "预览把源技能的可复用部分提取到已有类级 owner;默认 plan,--apply 才写(多根一次事务)"
|
|
2068
2073
|
},
|
|
2069
2074
|
{
|
|
2070
2075
|
readonly: true,
|
|
@@ -2114,7 +2119,8 @@ const VALUE_FLAGS = [
|
|
|
2114
2119
|
"timeout",
|
|
2115
2120
|
"plan",
|
|
2116
2121
|
"start",
|
|
2117
|
-
"end"
|
|
2122
|
+
"end",
|
|
2123
|
+
"outcome"
|
|
2118
2124
|
];
|
|
2119
2125
|
/**
|
|
2120
2126
|
* Narrow a parse result: true when it is the syntax failure rather than a command.
|
|
@@ -2711,21 +2717,25 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2711
2717
|
const versions = await curator.history(name);
|
|
2712
2718
|
if (versions.length === 0) return ok(`技能 "${name}" 还没有内容版本:下一次经 skill_manage 写入后才会出现。`);
|
|
2713
2719
|
const groups = partitionVersions(versions);
|
|
2714
|
-
const row = (entry) => `v${entry.v}\t${entry.at}\t${entry.action}\t${entry.chars} chars\t${entry.hash.slice(0, 12)}`;
|
|
2720
|
+
const row = (entry) => `v${entry.v}\t${entry.at}\t${entry.action}\t${entry.chars} chars\t${entry.hash.slice(0, 12)}${entry.unitId === void 0 ? "" : `\tunit:${entry.unitId}`}`;
|
|
2715
2721
|
const lines = [`技能 "${name}" 的内容版本(由旧到新,${groups.content.length} 条,最多保留这么多):`, ...groups.content.map(row)];
|
|
2716
2722
|
if (groups.support.length > 0) lines.push("支撑文件版本(仅在历史里 —— 撤销恢复的是 SKILL.md,不是这些字节):", ...groups.support.map(row));
|
|
2717
2723
|
return ok(lines.join("\n"));
|
|
2718
2724
|
}
|
|
2719
2725
|
if (input.startsWith("skill undo ")) {
|
|
2720
2726
|
const rest = input.slice(11).trim();
|
|
2721
|
-
const toMatch = /--to\s+v?(\d+)
|
|
2722
|
-
const
|
|
2723
|
-
|
|
2727
|
+
const toMatch = /--to\s+v?(\d+)/.exec(rest);
|
|
2728
|
+
const unitMatch = /--unit\s+(\S+)/.exec(rest);
|
|
2729
|
+
const marker = [toMatch?.index, unitMatch?.index].filter((index) => index !== void 0).sort((a, b) => a - b)[0];
|
|
2730
|
+
const name = (marker === void 0 ? rest : rest.slice(0, marker)).trim();
|
|
2731
|
+
if (!name) return err("用法:/evolution skill undo <name> [--to v<N> | --unit <id>]");
|
|
2732
|
+
if (toMatch !== null && unitMatch !== null) return err("--to 与 --unit 不能同时使用");
|
|
2724
2733
|
const skillUndoRefusal = unreplayableWriteRefusal("skill undo");
|
|
2725
2734
|
if (skillUndoRefusal) return skillUndoRefusal;
|
|
2726
2735
|
const curator = ctx.get("evolutionCurator");
|
|
2727
2736
|
const target = toMatch?.[1] === void 0 ? void 0 : Number(toMatch[1]);
|
|
2728
|
-
const
|
|
2737
|
+
const unitId = unitMatch?.[1];
|
|
2738
|
+
const result = curator ? unitId !== void 0 ? await curator.undoUnit(name, unitId) : target === void 0 ? await curator.undo(name) : await curator.undo(name, target) : {
|
|
2729
2739
|
ok: false,
|
|
2730
2740
|
message: errorText("e-302-curator-service-not-mounted")
|
|
2731
2741
|
};
|
|
@@ -2749,6 +2759,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2749
2759
|
}).setPinned(name, pinned);
|
|
2750
2760
|
return result.ok ? ok(result.message) : err(result.message);
|
|
2751
2761
|
}
|
|
2762
|
+
if (input === "propose") {
|
|
2763
|
+
const curator = ctx.get("evolutionCurator");
|
|
2764
|
+
if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
|
|
2765
|
+
const result = await curator.proposeKeeps();
|
|
2766
|
+
return result.ok ? ok(result.message) : err(result.message);
|
|
2767
|
+
}
|
|
2752
2768
|
if (input === "skills health") {
|
|
2753
2769
|
const curator = ctx.get("evolutionCurator");
|
|
2754
2770
|
if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
|
|
@@ -3161,13 +3177,15 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3161
3177
|
}
|
|
3162
3178
|
if (input.startsWith("extract ")) {
|
|
3163
3179
|
const extractParsed = parseSubcommand(rawInputTrimmed);
|
|
3164
|
-
if (isParseFailure(extractParsed) || extractParsed.name !== "extract") return err("用法:/evolution extract <source> <target> \"
|
|
3180
|
+
if (isParseFailure(extractParsed) || extractParsed.name !== "extract") return err("用法:/evolution extract <source> <target> \"<heading>\" [--start <line>] [--end <line>]");
|
|
3165
3181
|
const source = extractParsed.positionals[0] ?? "";
|
|
3166
3182
|
const target = extractParsed.positionals[1] ?? "";
|
|
3167
3183
|
const heading = extractParsed.positionals[2] ?? "";
|
|
3168
|
-
if (source === "" || target === "" || heading === "") return err("用法:/evolution extract <source> <target> \"
|
|
3184
|
+
if (source === "" || target === "" || heading === "") return err("用法:/evolution extract <source> <target> \"<heading>\" [--start <line>] [--end <line>]");
|
|
3169
3185
|
const startFlag = extractParsed.flags.get("start");
|
|
3170
3186
|
const endFlag = extractParsed.flags.get("end");
|
|
3187
|
+
const outcomeFlag = extractParsed.flags.get("outcome");
|
|
3188
|
+
if (outcomeFlag !== void 0 && outcomeFlag !== "extract" && outcomeFlag !== "mixed") return err("--outcome 只能是 extract 或 mixed。");
|
|
3171
3189
|
const start = typeof startFlag === "string" ? startFlag : void 0;
|
|
3172
3190
|
const end = typeof endFlag === "string" ? endFlag : void 0;
|
|
3173
3191
|
const ioRegistry = ctx.get("evolutionIo");
|
|
@@ -3183,56 +3201,24 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3183
3201
|
...policyStageLimits(ctx.get("evolutionPolicy")?.get?.())
|
|
3184
3202
|
}
|
|
3185
3203
|
});
|
|
3186
|
-
const
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
if (targetMd === null) return err("目标技能「" + target + "」不存在;owner-gap 不自动 create。");
|
|
3190
|
-
if (source === target) return err("source 与 target 不能相同。");
|
|
3191
|
-
const candidate = findOwnerCandidate(ownerCandidatesFromSummaries(source, await library.list({
|
|
3192
|
-
withContent: true,
|
|
3193
|
-
withFrontmatter: true
|
|
3194
|
-
})), target);
|
|
3195
|
-
if (candidate === void 0) return err("目标「" + target + "」不是可用的 owner candidate(描述为空或已排除);owner-gap,不自动 create。");
|
|
3196
|
-
if (candidate.protectionUnknown || candidate.protectedBy !== null) return err("目标「" + target + "」受保护(" + (candidate.protectedBy ?? "未知") + "),拒绝提取。");
|
|
3197
|
-
const sourceParsed = parseFrontmatter(sourceMd);
|
|
3198
|
-
if (sourceParsed === null) return err("技能「" + source + "」没有可读取的正文。");
|
|
3199
|
-
const sourceFiles = await library.listSupportFiles(source);
|
|
3200
|
-
const targetFiles = await library.listSupportFiles(target);
|
|
3201
|
-
if (!isPresent(sourceFiles) || !isPresent(targetFiles)) return err("支撑文件列表不可读;拒绝在不确定的闭包上提取。");
|
|
3202
|
-
const external = await readExternalSupport(sourceParsed.body, join(library.root, source), dirname(library.root), targetFiles.value);
|
|
3203
|
-
if (!external.ok) return err(external.message);
|
|
3204
|
-
const plan = planExtract({
|
|
3205
|
-
body: sourceParsed.body,
|
|
3206
|
-
sourceName: source,
|
|
3207
|
-
targetName: target,
|
|
3208
|
-
targetExists: true,
|
|
3209
|
-
outcome: start !== void 0 || end !== void 0 ? "mixed" : "extract",
|
|
3210
|
-
owner: {
|
|
3211
|
-
mode: "covered",
|
|
3212
|
-
name: target,
|
|
3213
|
-
triggerCovers: true,
|
|
3214
|
-
outcomeCovers: true,
|
|
3215
|
-
reason: "explicit target"
|
|
3216
|
-
},
|
|
3217
|
-
requests: [{
|
|
3204
|
+
const built = await buildExtractPlanFromLibrary(library, {
|
|
3205
|
+
source,
|
|
3206
|
+
items: [{
|
|
3218
3207
|
heading,
|
|
3219
3208
|
...start === void 0 ? {} : { start },
|
|
3220
|
-
...end === void 0 ? {} : { end }
|
|
3209
|
+
...end === void 0 ? {} : { end },
|
|
3210
|
+
to_skill: target
|
|
3221
3211
|
}],
|
|
3222
|
-
|
|
3223
|
-
targetFiles: targetFiles.value,
|
|
3224
|
-
external: external.files,
|
|
3225
|
-
anchors: {
|
|
3226
|
-
sourceMdSha256: contentHash(sourceMd),
|
|
3227
|
-
targetMdSha256: contentHash(targetMd)
|
|
3228
|
-
}
|
|
3212
|
+
...outcomeFlag === void 0 ? {} : { outcome: outcomeFlag }
|
|
3229
3213
|
});
|
|
3230
|
-
if (!
|
|
3231
|
-
|
|
3232
|
-
|
|
3214
|
+
if (!built.ok) return err(built.message);
|
|
3215
|
+
const plan = built.plan;
|
|
3216
|
+
const warnings = built.warnings === void 0 || built.warnings.length === 0 ? "" : "\n" + built.warnings.join("\n");
|
|
3217
|
+
if (!extractParsed.flags.has("apply")) {
|
|
3218
|
+
const proposal = proposalFromPlan(plan, { runId: "cli-" + Date.now().toString(36) });
|
|
3233
3219
|
const io = ctx.get("evolutionIo")?.provider();
|
|
3234
3220
|
if (io !== void 0) await writeProposalReport(io, proposal).catch(() => {});
|
|
3235
|
-
return ok("
|
|
3221
|
+
return ok("提取计划(未写入;默认 plan,--apply 才写):" + plan.parts.map((part) => "## " + part.heading).join(", ") + " -> " + target + "\n提取判定:outcome=" + plan.outcome + ";target=" + target + ";owner=covered by " + target + warnings);
|
|
3236
3222
|
}
|
|
3237
3223
|
if (approval) {
|
|
3238
3224
|
const session = invocationAgent?.session;
|
|
@@ -3266,17 +3252,17 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3266
3252
|
});
|
|
3267
3253
|
if (decision.action === "staged") return ok(decision.message);
|
|
3268
3254
|
}
|
|
3269
|
-
const result = await library.extract(plan
|
|
3255
|
+
const result = await library.extract(plan, "foreground");
|
|
3270
3256
|
if (!result.ok) return err(result.message);
|
|
3271
|
-
return ok(result.message);
|
|
3257
|
+
return ok(result.message + "\n提取判定:outcome=" + plan.outcome + ";target=" + target + warnings);
|
|
3272
3258
|
}
|
|
3273
3259
|
if (input.startsWith("restructure ")) {
|
|
3274
3260
|
const restParsed = parseSubcommand(rawInputTrimmed);
|
|
3275
|
-
if (isParseFailure(restParsed) || restParsed.name !== "restructure") return err("用法:/evolution restructure <name> \"
|
|
3261
|
+
if (isParseFailure(restParsed) || restParsed.name !== "restructure") return err("用法:/evolution restructure <name> \"<heading>\" <to_file>");
|
|
3276
3262
|
const name = restParsed.positionals[0] ?? "";
|
|
3277
3263
|
const heading = restParsed.positionals[1] ?? "";
|
|
3278
3264
|
const toFile = restParsed.positionals[2] ?? "";
|
|
3279
|
-
if (name === "" || heading === "" || toFile === "") return err("用法:/evolution restructure <name> \"
|
|
3265
|
+
if (name === "" || heading === "" || toFile === "") return err("用法:/evolution restructure <name> \"<heading>\" <to_file>");
|
|
3280
3266
|
const planFlag = restParsed.flags.get("plan");
|
|
3281
3267
|
const planRunId = typeof planFlag === "string" ? planFlag : void 0;
|
|
3282
3268
|
if (!toFile.startsWith("references/")) return err("to_file 必须位于 references/ 之下(日志或明细的落地位置)。");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-commands",
|
|
3
3
|
"description": "Human commands for the evolution family (/evolution pending|curator|maintain|doctor) (community build)",
|
|
4
|
-
"version": "0.30.
|
|
4
|
+
"version": "0.30.38",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.30.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.30.
|
|
32
|
-
"@lmzhen/dsh-evolution-maintenance": "^0.30.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.30.38",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.30.38",
|
|
32
|
+
"@lmzhen/dsh-evolution-maintenance": "^0.30.38"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@lmzhen/dsh-evolution-agent-preset": "^0.30.
|
|
35
|
+
"@lmzhen/dsh-evolution-agent-preset": "^0.30.38"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/cordis": "^4.0.5",
|