@lmzhen/dsh-evolution-commands 0.26.15 → 0.26.26
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 +60 -26
- package/lib/types/registry.d.ts +10 -1
- package/package.json +6 -7
package/lib/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import { DEFAULT_SKILL_LIMITS, MAX_TIMER_DELAY_MS, PARAM_EXPOSURE, PARAM_GROUP_LABELS, absentHostServices, appendEvolutionEvent, applyNamespaceMigration, asRecord, assertSkillsRootAliasRetired, atomicWriteFiles, authorityFrom, buildLearnPrompt, canonicalWriteId, clampedNumber, classifyNamespaceMigration, composePresetEntry, elapsedSince, errorText, eventsFile, evolutionHome, evolutionRoot, isDeprecatedParamId, isPresent, isRecord, isUnknown, liveBool, mergePresetRow, newRunRegistry, newSkillLibrary, paramSettingsId, partitionVersions, planNamespaceMigration, policyStageLimits, presetPatchText, presetRowBlock, presetRowBody, presetRowId, probeText, reportsSweepLockTarget, resolveBasePresetPatch, resolveParamId, resolveRootConfig, scopedPackageName, scopedProbeReport, sweepReports, transactIo } from "@lmzhen/dsh-evolution-core";
|
|
2
3
|
import z from "@deepseek-ai/schemastery";
|
|
3
4
|
import { effectiveSessionPolicy } from "@lmzhen/dsh-evolution-approval";
|
|
4
5
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
5
|
-
import { DEFAULT_SKILL_LIMITS, MAX_TIMER_DELAY_MS, PARAM_EXPOSURE, PARAM_GROUP_LABELS, absentHostServices, appendEvolutionEvent, applyNamespaceMigration, asRecord, assertSkillsRootAliasRetired, atomicWriteFiles, buildLearnPrompt, canonicalWriteId, clampedNumber, classifyNamespaceMigration, composePresetEntry, elapsedSince, errorText, eventsFile, evolutionHome, evolutionRoot, isDeprecatedParamId, isPresent, isRecord, isUnknown, liveBool, mergePresetRow, newRunRegistry, newSkillLibrary, paramSettingsId, partitionVersions, planNamespaceMigration, policyStageLimits, presetPatchText, presetRowBlock, presetRowBody, presetRowId, probeText, reportsSweepLockTarget, resolveBasePresetPatch, resolveParamId, resolveRootConfig, scopedProbeReport, sweepReports, transactIo } from "@lmzhen/dsh-evolution-core";
|
|
6
6
|
import { buildEnrichment, buildMaintainFacts, enrichmentSnapshotOptions, runMaintain, snapshotFromLibrary } from "@lmzhen/dsh-evolution-maintenance";
|
|
7
|
-
import { preferProvider } from "@lmzhen/dsh-evolution-io";
|
|
8
7
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
9
8
|
import { dirname, join } from "node:path";
|
|
10
9
|
import { fileURLToPath } from "node:url";
|
|
@@ -53,15 +52,18 @@ async function runNamespaceMigration(run) {
|
|
|
53
52
|
await settings.update(rowId, patch);
|
|
54
53
|
};
|
|
55
54
|
if (settings.describe === void 0 || settings.update === void 0) return NOTHING;
|
|
55
|
+
let seen;
|
|
56
56
|
for (const source of legacySettingsPaths(run.home)) {
|
|
57
57
|
const text = await run.io.readText(source);
|
|
58
58
|
if (text === null) continue;
|
|
59
59
|
const plan = planNamespaceMigration(text);
|
|
60
|
-
if (plan.entries.length === 0)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
if (plan.entries.length === 0) {
|
|
61
|
+
seen ??= {
|
|
62
|
+
source,
|
|
63
|
+
plan
|
|
64
|
+
};
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
65
67
|
return {
|
|
66
68
|
source,
|
|
67
69
|
plan,
|
|
@@ -72,7 +74,11 @@ async function runNamespaceMigration(run) {
|
|
|
72
74
|
})
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
|
-
return NOTHING
|
|
77
|
+
return seen === void 0 ? NOTHING : {
|
|
78
|
+
source: seen.source,
|
|
79
|
+
plan: seen.plan,
|
|
80
|
+
report: void 0
|
|
81
|
+
};
|
|
76
82
|
}
|
|
77
83
|
/**
|
|
78
84
|
* Read the legacy document and report what is still unmigrated.
|
|
@@ -86,11 +92,24 @@ async function runNamespaceMigration(run) {
|
|
|
86
92
|
async function readLegacyDocumentState(run) {
|
|
87
93
|
const settings = run.settings;
|
|
88
94
|
if (settings?.describe === void 0) return void 0;
|
|
95
|
+
let seen;
|
|
89
96
|
for (const source of legacySettingsPaths(run.home)) {
|
|
90
97
|
const text = await run.io.readText(source);
|
|
91
98
|
if (text === null) continue;
|
|
92
99
|
const plan = planNamespaceMigration(text);
|
|
93
|
-
|
|
100
|
+
if (plan.entries.length === 0) {
|
|
101
|
+
seen ??= {
|
|
102
|
+
source,
|
|
103
|
+
plan
|
|
104
|
+
};
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
return stateOf(source, plan);
|
|
108
|
+
}
|
|
109
|
+
return seen === void 0 ? void 0 : stateOf(seen.source, seen.plan);
|
|
110
|
+
/** The doctor-facing state of ONE document, judged against the seat. */
|
|
111
|
+
function stateOf(source, plan) {
|
|
112
|
+
const read = (rowId) => settings?.describe?.({ redactSecrets: false }).find((entry) => entry.ns === rowId);
|
|
94
113
|
const decided = classifyNamespaceMigration(plan, read);
|
|
95
114
|
return {
|
|
96
115
|
source,
|
|
@@ -657,7 +676,7 @@ function memoryInterpolationIssues(home) {
|
|
|
657
676
|
* "unknown" — the doctor never throws.
|
|
658
677
|
* Platform anchor: `packages/boot/app-boot/src/profile.ts` — a family preset is a ROW in the
|
|
659
678
|
* profile's own patch layer there (`PROFILE_PATCH_FILENAME`), never a preset directory. */
|
|
660
|
-
const AGENT_PRESET_PACKAGE = "
|
|
679
|
+
const AGENT_PRESET_PACKAGE = scopedPackageName("dsh-evolution-agent-preset", import.meta.url);
|
|
661
680
|
/** Resolve one asset the package declares in its exports map.
|
|
662
681
|
* @param asset - bases.json or agent.cordis.yml.
|
|
663
682
|
* @returns the file path, or null when the package is not installed. */
|
|
@@ -1368,10 +1387,20 @@ function flagsOf(name) {
|
|
|
1368
1387
|
const entry = COMMAND_ENTRIES.find((candidate) => entryName(candidate) === name);
|
|
1369
1388
|
return entry === void 0 ? [] : entryFlags(entry);
|
|
1370
1389
|
}
|
|
1371
|
-
/**
|
|
1390
|
+
/**
|
|
1391
|
+
* C7 shape, DERIVED: the entry IDENTITY key, and it is HIERARCHICAL (E-08).
|
|
1392
|
+
*
|
|
1393
|
+
* The key used to be the first token alone, and `flagsOf` finds an entry with `.find(...)` - the FIRST
|
|
1394
|
+
* match - so `maintain handoff` / `maintain cancel` and `skill restore` / `skill history` / `skill undo` /
|
|
1395
|
+
* `skill pin` all derived the SAME key as their parent and every flag lookup silently saw the parent entry
|
|
1396
|
+
* only (nine collisions). A bare parent (`maintain [--timeout]`) keeps its one-token key, so parent lookups
|
|
1397
|
+
* still resolve: the one call site that named an entry by a name the key no longer produced was the preset
|
|
1398
|
+
* dispatch branch, and it now asks for the entry own key (`preset install`).
|
|
1399
|
+
*/
|
|
1372
1400
|
function entryName(entry) {
|
|
1373
|
-
const [head = ""] = entry.usage.split(" ");
|
|
1374
|
-
|
|
1401
|
+
const [head = "", second = ""] = entry.usage.split(" ");
|
|
1402
|
+
const name = head.split("|")[0] ?? "";
|
|
1403
|
+
return /^[a-z][a-z-]*$/.test(second) && !second.startsWith("--") ? name + " " + second : name;
|
|
1375
1404
|
}
|
|
1376
1405
|
/** C7 shape, DERIVED: the flags a `usage` declares, in the form `--flag` (value flags keep their name). */
|
|
1377
1406
|
function entryFlags(entry) {
|
|
@@ -1841,7 +1870,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1841
1870
|
const ioRegistry = ioCtx.get("evolutionIo");
|
|
1842
1871
|
if (!ioRegistry) return;
|
|
1843
1872
|
const registry = newRunRegistry({
|
|
1844
|
-
io:
|
|
1873
|
+
io: ioRegistry.provider(),
|
|
1845
1874
|
home: evolutionHome(),
|
|
1846
1875
|
warn: (message) => {
|
|
1847
1876
|
ctx.logger.warn(message);
|
|
@@ -2072,8 +2101,9 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2072
2101
|
const ioRegistry = ctx.get("evolutionIo");
|
|
2073
2102
|
if (!ioRegistry) return err("未挂载 evolution-io 注册表:无法固定或取消固定技能。");
|
|
2074
2103
|
const result = await newSkillLibrary({
|
|
2104
|
+
authority: authorityFrom({ origin: "foreground" }),
|
|
2075
2105
|
config: { root: skillsRootValue },
|
|
2076
|
-
io:
|
|
2106
|
+
io: ioRegistry.provider(),
|
|
2077
2107
|
ctx,
|
|
2078
2108
|
limits: {
|
|
2079
2109
|
...DEFAULT_SKILL_LIMITS,
|
|
@@ -2149,8 +2179,9 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2149
2179
|
const ioRegistry = ctx.get("evolutionIo");
|
|
2150
2180
|
if (!ioRegistry) return err("未挂载 evolution-io 注册表:维护事实不可用。");
|
|
2151
2181
|
const library = newSkillLibrary({
|
|
2182
|
+
authority: authorityFrom({ origin: "foreground" }),
|
|
2152
2183
|
config: { root: skillsRootValue },
|
|
2153
|
-
io:
|
|
2184
|
+
io: ioRegistry.provider()
|
|
2154
2185
|
});
|
|
2155
2186
|
const enrichment = await buildEnrichment(ctx, library);
|
|
2156
2187
|
const readFailures = [];
|
|
@@ -2162,7 +2193,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2162
2193
|
}
|
|
2163
2194
|
});
|
|
2164
2195
|
if (snapshots.length === 0 && readFailures.length > 0) return err(`维护扫描读不出 ${readFailures.length} 个已登记技能(${readFailures.slice(0, 10).join(", ")}${readFailures.length > 10 ? ", …" : ""}),且一个技能都没读到:技能库未被审计。请修好读不出的技能(或它们的目录名)后重新扫描`);
|
|
2165
|
-
if (snapshots.length === 0 && skillsRootValue !== "" && !await
|
|
2196
|
+
if (snapshots.length === 0 && skillsRootValue !== "" && !await ioRegistry.provider().exists(skillsRootValue)) return err(`维护扫描发现技能库为空,但配置的技能根目录不存在(${skillsRootValue}):请把 skillsRoot 指向真实目录(字面量 \`~\` 不会被展开),然后重新扫描`);
|
|
2166
2197
|
if (snapshots.length === 0) return ok("维护扫描:技能库为空,无需处理。");
|
|
2167
2198
|
const { facts } = buildMaintainFacts(snapshots, enrichment.usageObservedValue, void 0);
|
|
2168
2199
|
return ok(`维护事实(零 token 预览):\n${facts}`);
|
|
@@ -2202,8 +2233,9 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2202
2233
|
(async () => {
|
|
2203
2234
|
try {
|
|
2204
2235
|
const library = newSkillLibrary({
|
|
2236
|
+
authority: authorityFrom({ origin: "foreground" }),
|
|
2205
2237
|
config: { root: skillsRootValue },
|
|
2206
|
-
io:
|
|
2238
|
+
io: ioRegistry.provider()
|
|
2207
2239
|
});
|
|
2208
2240
|
const enrichment = await buildEnrichment(ctx, library);
|
|
2209
2241
|
const outcome = await runMaintain({
|
|
@@ -2215,7 +2247,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2215
2247
|
logger: { warn: (message) => {
|
|
2216
2248
|
ctx.logger.warn(message);
|
|
2217
2249
|
} },
|
|
2218
|
-
rootExists: skillsRootValue === "" ? void 0 : () =>
|
|
2250
|
+
rootExists: skillsRootValue === "" ? void 0 : () => ioRegistry.provider().exists(skillsRootValue),
|
|
2219
2251
|
skillRoot: skillsRootValue
|
|
2220
2252
|
}, {
|
|
2221
2253
|
timeoutMs: runTimeoutMs,
|
|
@@ -2224,7 +2256,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2224
2256
|
enrichment: () => enrichment
|
|
2225
2257
|
});
|
|
2226
2258
|
const endedAt = Date.now();
|
|
2227
|
-
const resultRef = await writeMaintainReport(
|
|
2259
|
+
const resultRef = await writeMaintainReport(ioRegistry.provider(), {
|
|
2228
2260
|
runId: handle.id,
|
|
2229
2261
|
...outcome.ok ? {
|
|
2230
2262
|
verdict: outcome.verdict,
|
|
@@ -2248,7 +2280,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2248
2280
|
...outcome.ok ? {} : { failure: handle.signal.aborted ? "cancelled: the scan was stopped before it settled" : outcome.error ?? "Maintenance scan failed." }
|
|
2249
2281
|
});
|
|
2250
2282
|
if (outcome.ok) {
|
|
2251
|
-
appendEvolutionEvent(
|
|
2283
|
+
appendEvolutionEvent(ioRegistry.provider(), eventsFile(runRoot), {
|
|
2252
2284
|
type: "maintain",
|
|
2253
2285
|
source: "manual",
|
|
2254
2286
|
runId: handle.id,
|
|
@@ -2341,7 +2373,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2341
2373
|
if (wanted === void 0 && record.state === "running") return err(`最新一次运行 ${record.id} 仍在进行:它结束后才会出报告;用 /evolution maintain status ${record.id} 查看进度。`);
|
|
2342
2374
|
const ioRegistry = ctx.get("evolutionIo");
|
|
2343
2375
|
if (!ioRegistry) return err("未挂载 evolution-io 注册表:无法查看运行结果。");
|
|
2344
|
-
const probed = await readRunReport(
|
|
2376
|
+
const probed = await readRunReport(ioRegistry.provider(), record);
|
|
2345
2377
|
if (probed.kind === "missing") return err(`运行 ${record.id}(${record.state})没有结果:没有写出报告${record.failure === void 0 ? "" : `(${record.failure})`}。`);
|
|
2346
2378
|
if (probed.kind === "unknown") return err(`运行 ${record.id} 有报告但读不出来(${probed.reason}):这「不是」没有结果。`);
|
|
2347
2379
|
return ok(probed.text);
|
|
@@ -2386,7 +2418,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2386
2418
|
if (wanted === void 0 && record.state === "running") return err(`最新一次运行 ${record.id} 仍在进行:它结束后才会出报告;用 /evolution maintain status ${record.id} 查看进度。`);
|
|
2387
2419
|
const ioRegistry = ctx.get("evolutionIo");
|
|
2388
2420
|
if (!ioRegistry) return err("未挂载 evolution-io 注册表:无法交付报告。");
|
|
2389
|
-
const probed = await readRunReport(
|
|
2421
|
+
const probed = await readRunReport(ioRegistry.provider(), record);
|
|
2390
2422
|
if (probed.kind === "missing") return err(`运行 ${record.id}(${record.state})没有结果:没有写出报告${record.failure === void 0 ? "" : `(${record.failure})`}。`);
|
|
2391
2423
|
if (probed.kind === "unknown") return err(`运行 ${record.id} 有报告但读不出来(${probed.reason}):这「不是」没有结果。`);
|
|
2392
2424
|
const missingAgent = agentMissing("handoff");
|
|
@@ -2413,7 +2445,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2413
2445
|
}
|
|
2414
2446
|
if (/^maintain\b/.test(input)) return err("未知的 maintain 参数:应为 `maintain`、`maintain --timeout <ms>` / `maintain --timeout=<ms>`、`maintain status [<id>]`、`maintain report [<id>]`、`maintain handoff [<id>]` 或 `maintain cancel [<id>]`。实际收到:" + input);
|
|
2415
2447
|
const presetParsed = parseSubcommand(input);
|
|
2416
|
-
const presetInstall = isParseFailure(presetParsed) || presetParsed.name !== "preset" ? null : presetParsed.positionals[0] === "install" && presetParsed.positionals.length === 1 && [...presetParsed.flags.keys()].every((flag) => flagsOf("preset").includes("--" + flag)) ? presetParsed : false;
|
|
2448
|
+
const presetInstall = isParseFailure(presetParsed) || presetParsed.name !== "preset" ? null : presetParsed.positionals[0] === "install" && presetParsed.positionals.length === 1 && [...presetParsed.flags.keys()].every((flag) => flagsOf("preset install").includes("--" + flag)) ? presetParsed : false;
|
|
2417
2449
|
if (presetInstall !== null && presetInstall !== false) {
|
|
2418
2450
|
{
|
|
2419
2451
|
const mounted = presetProfileTarget(ctx);
|
|
@@ -2525,8 +2557,9 @@ function apply(ctx, rawConfig = {}) {
|
|
|
2525
2557
|
if (decision.action === "staged") return ok(`${decision.message}${planRunId ? `\n[audit] plan=${planRunId}` : ""}`);
|
|
2526
2558
|
}
|
|
2527
2559
|
const result = await newSkillLibrary({
|
|
2560
|
+
authority: authorityFrom({ origin: "foreground" }),
|
|
2528
2561
|
config: { root: skillsRootValue },
|
|
2529
|
-
io:
|
|
2562
|
+
io: ioRegistry.provider(),
|
|
2530
2563
|
ctx,
|
|
2531
2564
|
threatExemptLabels: config.threatExemptLabels,
|
|
2532
2565
|
limits: {
|
|
@@ -2783,7 +2816,8 @@ function resolveAgentPresetDir(importMetaUrl) {
|
|
|
2783
2816
|
const overlayCandidate = join(dirname(fileURLToPath(importMetaUrl)), "..", "..", "evolution-agent");
|
|
2784
2817
|
if (existsSync(join(overlayCandidate, "agent.cordis.yml")) && existsSync(join(overlayCandidate, "bases.json"))) return overlayCandidate;
|
|
2785
2818
|
try {
|
|
2786
|
-
|
|
2819
|
+
const agentPresetPackage = scopedPackageName("dsh-evolution-agent-preset", importMetaUrl);
|
|
2820
|
+
return dirname(createRequire(importMetaUrl).resolve(agentPresetPackage + "/package.json"));
|
|
2787
2821
|
} catch {
|
|
2788
2822
|
return overlayCandidate;
|
|
2789
2823
|
}
|
package/lib/types/registry.d.ts
CHANGED
|
@@ -19,7 +19,16 @@ export interface CommandEntry {
|
|
|
19
19
|
}
|
|
20
20
|
/** The flags the TABLE declares for one subcommand (name → `--flag`), DERIVED from its usage. */
|
|
21
21
|
export declare function flagsOf(name: string): string[];
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* C7 shape, DERIVED: the entry IDENTITY key, and it is HIERARCHICAL (E-08).
|
|
24
|
+
*
|
|
25
|
+
* The key used to be the first token alone, and `flagsOf` finds an entry with `.find(...)` - the FIRST
|
|
26
|
+
* match - so `maintain handoff` / `maintain cancel` and `skill restore` / `skill history` / `skill undo` /
|
|
27
|
+
* `skill pin` all derived the SAME key as their parent and every flag lookup silently saw the parent entry
|
|
28
|
+
* only (nine collisions). A bare parent (`maintain [--timeout]`) keeps its one-token key, so parent lookups
|
|
29
|
+
* still resolve: the one call site that named an entry by a name the key no longer produced was the preset
|
|
30
|
+
* dispatch branch, and it now asks for the entry own key (`preset install`).
|
|
31
|
+
*/
|
|
23
32
|
export declare function entryName(entry: CommandEntry): string;
|
|
24
33
|
/** C7 shape, DERIVED: the flags a `usage` declares, in the form `--flag` (value flags keep their name). */
|
|
25
34
|
export declare function entryFlags(entry: CommandEntry): string[];
|
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.26.
|
|
4
|
+
"version": "0.26.26",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,18 +27,17 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.26.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.26.
|
|
32
|
-
"@lmzhen/dsh-evolution-maintenance": "^0.26.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.26.26",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.26.26",
|
|
32
|
+
"@lmzhen/dsh-evolution-maintenance": "^0.26.26"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@lmzhen/dsh-evolution-agent-preset": "^0.26.
|
|
35
|
+
"@lmzhen/dsh-evolution-agent-preset": "^0.26.26"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
39
39
|
"@deepseek-ai/dsh-commands": "^0.2.0-rc.1",
|
|
40
|
-
"@deepseek-ai/dsh-llm": "^0.2.0-rc.1"
|
|
41
|
-
"@lmzhen/dsh-evolution-io": "^0.26.15"
|
|
40
|
+
"@deepseek-ai/dsh-llm": "^0.2.0-rc.1"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@deepseek-ai/dsh-commands": "^0.2.0-rc.1"
|