@lmzhen/dsh-evolution-commands 0.20.0 → 0.21.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/lib/index.js +63 -11
- package/lib/types/index.d.ts +10 -5
- package/package.json +5 -5
package/lib/index.js
CHANGED
|
@@ -380,8 +380,10 @@ function presetIssues(presets) {
|
|
|
380
380
|
* build-time guards cannot. Three classes, each with its own move:
|
|
381
381
|
* - a user override (the effective value is no longer the deployment's),
|
|
382
382
|
* - a deprecated alias still written in a user section (writes refuse it),
|
|
383
|
-
* - a declared user-writable parameter whose owner publishes no
|
|
384
|
-
*
|
|
383
|
+
* - a declared user-writable parameter whose owner publishes no settings namespace AT ALL
|
|
384
|
+
* (a registry fact: writes answer E-315), and
|
|
385
|
+
* - a declared user-writable parameter whose owning row this runtime does not mount
|
|
386
|
+
* (the registry promises a face this composition never carries).
|
|
385
387
|
* G5: the two layers and the live rows come from the platform (`configEditor.configuration()`,
|
|
386
388
|
* `pluginManager.listPlugins()`); the registry side (which spellings are deprecated, which rows
|
|
387
389
|
* declare an E3 parameter) stays the family's own table. A surface that is not mounted is
|
|
@@ -411,14 +413,20 @@ function paramDivergences(platform) {
|
|
|
411
413
|
return issues;
|
|
412
414
|
}
|
|
413
415
|
const live = liveRowTails(platform.plugins);
|
|
414
|
-
const
|
|
416
|
+
const noUserLayer = [];
|
|
417
|
+
const unmounted = [];
|
|
418
|
+
for (const entry of PARAM_EXPOSURE) {
|
|
419
|
+
if (entry.tier !== "E3") continue;
|
|
415
420
|
const namespace = paramSettingsId(entry.owner);
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
421
|
+
if (namespace === void 0) noUserLayer.push(entry.id);
|
|
422
|
+
else if (!live.has(namespace)) unmounted.push(entry.id);
|
|
423
|
+
}
|
|
424
|
+
for (const [ids, sentence] of [[noUserLayer, "declared user-writable but the owner publishes no settings namespace"], [unmounted, "declared user-writable but unreachable here"]]) {
|
|
425
|
+
if (ids.length === 0) continue;
|
|
426
|
+
const shown = ids.slice(0, 6).join(", ");
|
|
427
|
+
const more = ids.length > 6 ? ` (+${ids.length - 6} more)` : "";
|
|
428
|
+
const why = sentence.includes("no settings namespace") ? "those parameters have no user layer at all (writes answer E-315) — register the owner in PARAM_NAMESPACES or move its rows to E2" : "the owning row is not mounted in this runtime";
|
|
429
|
+
issues.push(`${sentence}: ${shown}${more} — ${why}`);
|
|
422
430
|
}
|
|
423
431
|
return issues;
|
|
424
432
|
}
|
|
@@ -1318,6 +1326,14 @@ const COMMAND_ENTRIES = [
|
|
|
1318
1326
|
usage: "skill undo <name> [--to v<N>]",
|
|
1319
1327
|
summary: "把某个技能的内容回退到某一版(默认上一版;只动内容,撤销本身也记为一版)"
|
|
1320
1328
|
},
|
|
1329
|
+
{
|
|
1330
|
+
usage: "skill pin <name>",
|
|
1331
|
+
summary: "钉住一个技能:免于删除、后台审查与生命周期整理(立即生效、随时可解钉;与 skill_manage 的 pin 动作同一语义,不走审批)"
|
|
1332
|
+
},
|
|
1333
|
+
{
|
|
1334
|
+
usage: "skill unpin <name>",
|
|
1335
|
+
summary: "解钉一个技能:撤销上面的冻结(立即生效、不走审批)"
|
|
1336
|
+
},
|
|
1321
1337
|
{
|
|
1322
1338
|
usage: "skills health",
|
|
1323
1339
|
summary: "技能库结构体检"
|
|
@@ -1400,7 +1416,7 @@ const Config = z.object({
|
|
|
1400
1416
|
skillsRoot: z.string().default(""),
|
|
1401
1417
|
maintainCooldownMs: z.number().min(0).default(3e4),
|
|
1402
1418
|
maintainTimeoutMs: z.number().min(1).default(6e5),
|
|
1403
|
-
maintainHandoffOnSettle: z.boolean().default(false),
|
|
1419
|
+
maintainHandoffOnSettle: z.boolean().default(false).volatile(),
|
|
1404
1420
|
threatExemptLabels: z.array(z.string()).default([])
|
|
1405
1421
|
});
|
|
1406
1422
|
/** How one run reads in `maintain status` output. */
|
|
@@ -1549,10 +1565,29 @@ async function readRunReport(io, record) {
|
|
|
1549
1565
|
};
|
|
1550
1566
|
}
|
|
1551
1567
|
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Read a switch that may be a live settings reference.
|
|
1570
|
+
*
|
|
1571
|
+
* The loader hands a `.volatile()` field as `{ get() }` and the value is read at USE time; a
|
|
1572
|
+
* directly constructed plugin passes a plain boolean (the schema is the loader's face — the same
|
|
1573
|
+
* split the numeric knobs document as their second clamp layer). A single-form read is wrong
|
|
1574
|
+
* either way: `=== true` is never true for a reference, and `?.get()` ignores the plain value.
|
|
1575
|
+
* @param value - the configured switch, in either form, or undefined.
|
|
1576
|
+
* @returns the switch; undefined reads as off.
|
|
1577
|
+
*/
|
|
1578
|
+
function liveFlag(value) {
|
|
1579
|
+
return typeof value === "boolean" ? value : value?.get() ?? false;
|
|
1580
|
+
}
|
|
1552
1581
|
function apply(ctx, rawConfig = {}) {
|
|
1553
1582
|
const config = rawConfig;
|
|
1554
1583
|
assertSkillsRootAliasRetired(rawConfig);
|
|
1555
1584
|
const skillsRootValue = resolveRootConfig(rawConfig).root;
|
|
1585
|
+
ctx.inject(["settings"], (scope) => {
|
|
1586
|
+
const settings = scope.settings;
|
|
1587
|
+
if (typeof settings?.configure !== "function") return;
|
|
1588
|
+
const disposer = settings.configure({ auto: false }, ctx.fiber);
|
|
1589
|
+
if (typeof disposer === "function") scope.effect(() => disposer, "evolution-commands: settings presentation");
|
|
1590
|
+
});
|
|
1556
1591
|
let runs;
|
|
1557
1592
|
ctx.inject(["evolutionIo"], (ioCtx) => {
|
|
1558
1593
|
const ioRegistry = ioCtx.get("evolutionIo");
|
|
@@ -1782,6 +1817,23 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1782
1817
|
};
|
|
1783
1818
|
return result.ok ? ok(result.message) : err(result.message);
|
|
1784
1819
|
}
|
|
1820
|
+
if (input === "skill pin" || input.startsWith("skill pin ") || input === "skill unpin" || input.startsWith("skill unpin ")) {
|
|
1821
|
+
const pinned = !input.startsWith("skill unpin");
|
|
1822
|
+
const name = input.slice(pinned ? 10 : 12).trim();
|
|
1823
|
+
if (!name) return err(`Usage: /evolution skill ${pinned ? "pin" : "unpin"} <name>`);
|
|
1824
|
+
const ioRegistry = ctx.get("evolutionIo");
|
|
1825
|
+
if (!ioRegistry) return err("Evolution IO registry not mounted — skill pinning unavailable.");
|
|
1826
|
+
const result = await newSkillLibrary({
|
|
1827
|
+
config: { root: skillsRootValue },
|
|
1828
|
+
io: ioRegistry.provider(),
|
|
1829
|
+
ctx,
|
|
1830
|
+
limits: {
|
|
1831
|
+
...DEFAULT_SKILL_LIMITS,
|
|
1832
|
+
...policyStageLimits(ctx.get("evolutionPolicy")?.get?.())
|
|
1833
|
+
}
|
|
1834
|
+
}).setPinned(name, pinned);
|
|
1835
|
+
return result.ok ? ok(result.message) : err(result.message);
|
|
1836
|
+
}
|
|
1785
1837
|
if (input === "skills health") {
|
|
1786
1838
|
const curator = ctx.get("evolutionCurator");
|
|
1787
1839
|
if (!curator) return err(errorText("e-302-curator-service-not-mounted"));
|
|
@@ -1937,7 +1989,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1937
1989
|
}).catch((error) => {
|
|
1938
1990
|
ctx.logger.warn(`evolution-commands: failed to record maintain event: ${String(error)}`);
|
|
1939
1991
|
});
|
|
1940
|
-
if (config.maintainHandoffOnSettle
|
|
1992
|
+
if (liveFlag(config.maintainHandoffOnSettle) && resultRef !== void 0 && runAgent !== void 0) try {
|
|
1941
1993
|
if (deliverHandoff(runAgent, createUserMessage({
|
|
1942
1994
|
content: [{
|
|
1943
1995
|
type: "text",
|
package/lib/types/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Human commands for the evolution family: /evolution learn|pending|curator|restore|consolidate|skills refresh.
|
|
3
3
|
* @module @lmzhen/dsh-evolution-commands
|
|
4
4
|
*/
|
|
5
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
5
|
+
import type { Context, Volatile } from '@deepseek-ai/cordis';
|
|
6
6
|
import z from '@deepseek-ai/schemastery';
|
|
7
7
|
import type { ContextFormed } from '@deepseek-ai/dsh-llm';
|
|
8
8
|
declare module '@deepseek-ai/dsh-llm' {
|
|
@@ -38,8 +38,13 @@ export interface Config {
|
|
|
38
38
|
maintainTimeoutMs?: number | undefined;
|
|
39
39
|
/** G2 (0.20.0): when a scan settles successfully, hand its report to the model
|
|
40
40
|
* automatically (the same pointer+protocol injection `maintain handoff` performs).
|
|
41
|
-
* Default false: the injection wakes a turn, which costs a model call.
|
|
42
|
-
|
|
41
|
+
* Default false: the injection wakes a turn, which costs a model call.
|
|
42
|
+
*
|
|
43
|
+
* `.volatile()` (0.21.0, G3): the field carries a USER LAYER, so the loader hands the live
|
|
44
|
+
* reference and the switch is read at every settle — a settings write turns it on or off without
|
|
45
|
+
* a reload. A directly constructed plugin still passes a plain boolean (the schema's default is
|
|
46
|
+
* the loader's face), so the reader accepts both. */
|
|
47
|
+
maintainHandoffOnSettle?: boolean | Volatile<boolean> | undefined;
|
|
43
48
|
/** Threat-scan exemption labels for WRITE-path skill mutations (P2-18).
|
|
44
49
|
* Threaded into the SkillLibrary this package constructs for `restructure`
|
|
45
50
|
* (its only write path); the core-side constructor option carries the same
|
|
@@ -55,14 +60,14 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
55
60
|
skillsRoot: z<string, string, "defined">;
|
|
56
61
|
maintainCooldownMs: z<number, number, "defined">;
|
|
57
62
|
maintainTimeoutMs: z<number, number, "defined">;
|
|
58
|
-
maintainHandoffOnSettle: z<boolean, boolean, "defined">;
|
|
63
|
+
maintainHandoffOnSettle: z<boolean, boolean, "volatile-defined">;
|
|
59
64
|
threatExemptLabels: z<string[], string[], "defined">;
|
|
60
65
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
61
66
|
root: z<string, string, "defined">;
|
|
62
67
|
skillsRoot: z<string, string, "defined">;
|
|
63
68
|
maintainCooldownMs: z<number, number, "defined">;
|
|
64
69
|
maintainTimeoutMs: z<number, number, "defined">;
|
|
65
|
-
maintainHandoffOnSettle: z<boolean, boolean, "defined">;
|
|
70
|
+
maintainHandoffOnSettle: z<boolean, boolean, "volatile-defined">;
|
|
66
71
|
threatExemptLabels: z<string[], string[], "defined">;
|
|
67
72
|
}>>, "plain">;
|
|
68
73
|
export declare function apply(ctx: Context, rawConfig?: Config): void;
|
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.
|
|
4
|
+
"version": "0.21.0",
|
|
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.4",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
32
|
-
"@lmzhen/dsh-evolution-maintenance": "^0.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.21.0",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.21.0",
|
|
32
|
+
"@lmzhen/dsh-evolution-maintenance": "^0.21.0"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@lmzhen/dsh-evolution-agent-preset": "^0.
|
|
35
|
+
"@lmzhen/dsh-evolution-agent-preset": "^0.21.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/cordis": "^4.0.1",
|