@lmzhen/dsh-evolution-commands 0.32.5 → 0.32.6
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 +5 -17
- package/lib/index.js +149 -3
- package/lib/types/command-fallback.d.ts +1 -1
- package/lib/types/settings-route.d.ts +27 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
# @lmzhen/dsh-evolution-commands
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Host command surface for the `/evolution` namespace: diagnostics, pending approvals, curator operations, maintenance, skill history, parameters, merge dispatch, migration, and preset installation.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The canonical user command reference is [docs/commands.md](../../docs/commands.md); the package map and preset-install spelling live in [packages/README.md](../README.md). Do not maintain a second command table here.
|
|
6
6
|
|
|
7
|
-
`/evolution
|
|
7
|
+
The command row ships with `all`, `host`, and `preset`. If the platform `commands` service is absent, the `/evolution` namespace is not registered.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Under a layered/variant installation, original-preset sessions still see the management commands even though they do not carry the family model rows. That accepted difference and the mutual-exclusion rules are single-sourced in [INSTALL.md](../INSTALL.md).
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## 默认 / 前提
|
|
14
|
-
|
|
15
|
-
随 all/host/preset 安装自动注册。
|
|
16
|
-
|
|
17
|
-
## 边界
|
|
18
|
-
|
|
19
|
-
没有 `commands` 服务时整条命令不存在。
|
|
20
|
-
|
|
21
|
-
分层/variant 的命令面差异单源在 [INSTALL.md](../INSTALL.md)。
|
|
22
|
-
|
|
23
|
-
> 旧的 consolidate 已从用户面退役;合并请用 `merge`。
|
|
11
|
+
The old `consolidate` command is retired; use `merge` for skill merging.
|
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, buildExtractPlanFromLibrary, buildLearnPrompt, canonicalWriteId, clampedNumber, classifyNamespaceMigration, classifySessionEvent, createSubagentChannel, elapsedSince, errorText, eventsFile, evolutionHome, evolutionRoot, hostSurface, isDeprecatedParamId, isPresent, isRecord, isUnknown, liveBool, newRunRegistry, newSkillLibrary, ownerDecisionText, paramSettingsId, partitionVersions, planNamespaceMigration, policyStageLimits, probeMtime, probeText, proposalFromPlan, reportsSweepLockTarget, resolveParamId, resolveRootConfig, scopedPackageName, scopedProbeReport, sweepReports, transactIo, writeProposalReport } from "@lmzhen/dsh-evolution-core";
|
|
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, PARAM_NAMESPACES, 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, ownerDecisionText, paramSettingsId, partitionVersions, planNamespaceMigration, policyStageLimits, probeMtime, probeText, proposalFromPlan, registerOwnerSettings, reportsSweepLockTarget, resolveParamId, resolveRootConfig, scopedPackageName, scopedProbeReport, sweepReports, transactIo, unwrapLive, 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";
|
|
@@ -29,9 +29,10 @@ import { processScopeViolations } from "@lmzhen/dsh-evolution-state-storage";
|
|
|
29
29
|
*/
|
|
30
30
|
const COMMAND_FALLBACKS = {
|
|
31
31
|
approval: { command: "/evolution pending … /evolution approve <id> … /evolution reject <id> … /evolution release <id>" },
|
|
32
|
-
"skill-history": { command: "/evolution
|
|
32
|
+
"skill-history": { command: "/evolution skill undo <name> [--to v<N>](查看:/evolution skill history <name>)" },
|
|
33
33
|
"skill-health": { command: "/evolution skills refresh(健康行:/evolution doctor)" },
|
|
34
34
|
merge: { command: "/evolution merge status / pending / approve <id> / report" },
|
|
35
|
+
settings: { command: "/evolution policy set <id> <value>(查看:/evolution policy)" },
|
|
35
36
|
diagnostics: {
|
|
36
37
|
command: "/evolution doctor",
|
|
37
38
|
platformCli: "dsh --json /evolution doctor"
|
|
@@ -486,6 +487,150 @@ function makeDiagnosticsRoutes(getInputs) {
|
|
|
486
487
|
}];
|
|
487
488
|
}
|
|
488
489
|
//#endregion
|
|
490
|
+
//#region lib/types/settings-route.js
|
|
491
|
+
/**
|
|
492
|
+
* Family settings data plane.
|
|
493
|
+
*
|
|
494
|
+
* The platform RPC only serves its own namespace allowlist, so the browser cannot
|
|
495
|
+
* reach family namespaces through /api/settings.* even though the underlying
|
|
496
|
+
* settings service has them registered. These exact routes reuse the SAME
|
|
497
|
+
* provider (describe/mutate), so storage, schema validation, revision conflicts
|
|
498
|
+
* and redaction stay platform-owned; only the transport is family-scoped.
|
|
499
|
+
* @module @lmzhen/dsh-evolution-commands/settings-route
|
|
500
|
+
*/
|
|
501
|
+
const FAMILY_NAMESPACES = new Set(Object.keys(PARAM_NAMESPACES));
|
|
502
|
+
function normaliseValue(value) {
|
|
503
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
|
|
504
|
+
const out = {};
|
|
505
|
+
for (const [key, field] of Object.entries(value)) {
|
|
506
|
+
const live = unwrapLive(field);
|
|
507
|
+
out[key] = live === void 0 ? field : live;
|
|
508
|
+
}
|
|
509
|
+
return out;
|
|
510
|
+
}
|
|
511
|
+
function snapshotOf(provider, descriptor) {
|
|
512
|
+
if (descriptor === void 0) return {
|
|
513
|
+
status: "unavailable",
|
|
514
|
+
writable: false,
|
|
515
|
+
value: void 0,
|
|
516
|
+
user: void 0,
|
|
517
|
+
base: void 0,
|
|
518
|
+
revision: void 0,
|
|
519
|
+
reason: "not-served"
|
|
520
|
+
};
|
|
521
|
+
return {
|
|
522
|
+
status: "ready",
|
|
523
|
+
writable: provider.writable,
|
|
524
|
+
value: normaliseValue(descriptor.value),
|
|
525
|
+
user: descriptor.user,
|
|
526
|
+
base: descriptor.base,
|
|
527
|
+
revision: descriptor.revision
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function providerOf(getProvider) {
|
|
531
|
+
return getProvider();
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* @param getProvider - resolves the live platform settings provider per request.
|
|
535
|
+
* @returns exact routes for family settings describe/mutate.
|
|
536
|
+
*/
|
|
537
|
+
function makeSettingsRoutes(getProvider) {
|
|
538
|
+
return [{
|
|
539
|
+
path: HOST_ROUTES.settings.describe,
|
|
540
|
+
methods: ["GET"],
|
|
541
|
+
requestBody: "buffered",
|
|
542
|
+
fetch: async (request) => {
|
|
543
|
+
if (request.method !== "GET") return methodNotAllowed(["GET"]);
|
|
544
|
+
const provider = providerOf(getProvider);
|
|
545
|
+
if (provider === void 0) return json(503, {
|
|
546
|
+
ok: false,
|
|
547
|
+
error: "settings-service-unavailable"
|
|
548
|
+
});
|
|
549
|
+
try {
|
|
550
|
+
const namespaces = provider.describe({ redactSecrets: true }).filter((item) => FAMILY_NAMESPACES.has(item.ns)).map((item) => ({
|
|
551
|
+
ns: item.ns,
|
|
552
|
+
...snapshotOf(provider, item)
|
|
553
|
+
}));
|
|
554
|
+
return json(200, {
|
|
555
|
+
ok: true,
|
|
556
|
+
data: {
|
|
557
|
+
writable: provider.writable,
|
|
558
|
+
namespaces
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
} catch (error) {
|
|
562
|
+
return json(500, {
|
|
563
|
+
ok: false,
|
|
564
|
+
error: error instanceof Error ? error.message : String(error)
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}, {
|
|
569
|
+
path: HOST_ROUTES.settings.mutate,
|
|
570
|
+
methods: ["POST"],
|
|
571
|
+
requestBody: "buffered",
|
|
572
|
+
fetch: async (request) => {
|
|
573
|
+
if (request.method !== "POST") return methodNotAllowed(["POST"]);
|
|
574
|
+
const provider = providerOf(getProvider);
|
|
575
|
+
if (provider === void 0) return json(503, {
|
|
576
|
+
ok: false,
|
|
577
|
+
error: "settings-service-unavailable"
|
|
578
|
+
});
|
|
579
|
+
let body;
|
|
580
|
+
try {
|
|
581
|
+
body = await request.json();
|
|
582
|
+
} catch {
|
|
583
|
+
return json(400, {
|
|
584
|
+
ok: false,
|
|
585
|
+
error: "invalid-json"
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
if (typeof body !== "object" || body === null) return json(400, {
|
|
589
|
+
ok: false,
|
|
590
|
+
error: "invalid-body"
|
|
591
|
+
});
|
|
592
|
+
const { ns, ops, expectedRevision } = body;
|
|
593
|
+
if (typeof ns !== "string" || !FAMILY_NAMESPACES.has(ns)) return json(400, {
|
|
594
|
+
ok: false,
|
|
595
|
+
error: "namespace-not-allowed"
|
|
596
|
+
});
|
|
597
|
+
if (!Array.isArray(ops) || ops.length === 0) return json(400, {
|
|
598
|
+
ok: false,
|
|
599
|
+
error: "ops-required"
|
|
600
|
+
});
|
|
601
|
+
if (expectedRevision !== void 0 && typeof expectedRevision !== "number") return json(400, {
|
|
602
|
+
ok: false,
|
|
603
|
+
error: "invalid-revision"
|
|
604
|
+
});
|
|
605
|
+
try {
|
|
606
|
+
await provider.mutate(ns, ops, expectedRevision);
|
|
607
|
+
const descriptor = provider.describe({ redactSecrets: true }).find((item) => item.ns === ns);
|
|
608
|
+
return json(200, {
|
|
609
|
+
ok: true,
|
|
610
|
+
data: {
|
|
611
|
+
writable: provider.writable,
|
|
612
|
+
namespaces: [{
|
|
613
|
+
ns,
|
|
614
|
+
...snapshotOf(provider, descriptor)
|
|
615
|
+
}]
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
} catch (error) {
|
|
619
|
+
if (error?.code === "SETTINGS_CONFLICT") return json(409, {
|
|
620
|
+
ok: false,
|
|
621
|
+
error: "settings-conflict",
|
|
622
|
+
actual: error.actual,
|
|
623
|
+
expected: error.expected
|
|
624
|
+
});
|
|
625
|
+
return json(400, {
|
|
626
|
+
ok: false,
|
|
627
|
+
error: error instanceof Error ? error.message : String(error)
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}];
|
|
632
|
+
}
|
|
633
|
+
//#endregion
|
|
489
634
|
//#region lib/types/migration.js
|
|
490
635
|
/**
|
|
491
636
|
* G3 (caller half): find the legacy settings document and run the namespace migration.
|
|
@@ -2512,6 +2657,7 @@ async function readRunReport(io, record) {
|
|
|
2512
2657
|
}
|
|
2513
2658
|
}
|
|
2514
2659
|
function apply(ctx, rawConfig = {}) {
|
|
2660
|
+
registerOwnerSettings(ctx, "evolution-commands", Config);
|
|
2515
2661
|
const config = rawConfig;
|
|
2516
2662
|
assertSkillsRootAliasRetired(rawConfig);
|
|
2517
2663
|
const skillsRootValue = resolveRootConfig(rawConfig).root;
|
|
@@ -3529,7 +3675,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3529
3675
|
ctx.inject(["settings"], () => {
|
|
3530
3676
|
runMigrationOnce();
|
|
3531
3677
|
});
|
|
3532
|
-
registerHostRoutes(ctx, () => makeDiagnosticsRoutes(() => assembleDoctorInputs(ctx, { runs: doctorRuns() })));
|
|
3678
|
+
registerHostRoutes(ctx, () => [...makeDiagnosticsRoutes(() => assembleDoctorInputs(ctx, { runs: doctorRuns() })), ...makeSettingsRoutes(() => ctx.get("settings"))]);
|
|
3533
3679
|
(async () => {
|
|
3534
3680
|
const loader = ctx.root.loader;
|
|
3535
3681
|
try {
|
|
@@ -16,7 +16,7 @@ export interface CommandFallbackHint {
|
|
|
16
16
|
readonly platformCli?: string;
|
|
17
17
|
}
|
|
18
18
|
/** The four Host surfaces (keyed exactly like the frozen `COMMAND_FALLBACK_SURFACES`). */
|
|
19
|
-
export type CommandFallbackSurface = 'approval' | 'skill-history' | 'skill-health' | 'merge' | 'diagnostics';
|
|
19
|
+
export type CommandFallbackSurface = 'approval' | 'skill-history' | 'skill-health' | 'merge' | 'diagnostics' | 'settings';
|
|
20
20
|
/**
|
|
21
21
|
* One entry per Host surface. The command column names the same service methods the routes call,
|
|
22
22
|
* so the answers (and refusal sentences) match the panel.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ConnectionFetchRouteLike } from '@lmzhen/dsh-evolution-core/http-routes';
|
|
2
|
+
interface SettingsDescriptorLike {
|
|
3
|
+
ns: string;
|
|
4
|
+
value?: unknown;
|
|
5
|
+
user?: Record<string, unknown>;
|
|
6
|
+
base?: unknown;
|
|
7
|
+
revision?: number;
|
|
8
|
+
applies?: 'live' | 'restart';
|
|
9
|
+
}
|
|
10
|
+
interface SettingsProviderLike {
|
|
11
|
+
readonly writable: boolean;
|
|
12
|
+
describe(options?: {
|
|
13
|
+
redactSecrets?: boolean;
|
|
14
|
+
}): SettingsDescriptorLike[];
|
|
15
|
+
mutate(ns: string, ops: readonly {
|
|
16
|
+
op: 'set' | 'unset';
|
|
17
|
+
path: readonly string[];
|
|
18
|
+
value?: unknown;
|
|
19
|
+
}[], expectedRevision?: number): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* @param getProvider - resolves the live platform settings provider per request.
|
|
23
|
+
* @returns exact routes for family settings describe/mutate.
|
|
24
|
+
*/
|
|
25
|
+
export declare function makeSettingsRoutes(getProvider: () => SettingsProviderLike | undefined): ConnectionFetchRouteLike[];
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=settings-route.d.ts.map
|
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.32.
|
|
4
|
+
"version": "0.32.6",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.5",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.32.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.32.
|
|
32
|
-
"@lmzhen/dsh-evolution-maintenance": "^0.32.
|
|
33
|
-
"@lmzhen/dsh-evolution-state-storage": "^0.32.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.32.6",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.32.6",
|
|
32
|
+
"@lmzhen/dsh-evolution-maintenance": "^0.32.6",
|
|
33
|
+
"@lmzhen/dsh-evolution-state-storage": "^0.32.6"
|
|
34
34
|
},
|
|
35
35
|
"optionalDependencies": {
|
|
36
|
-
"@lmzhen/dsh-evolution-agent-preset": "^0.32.
|
|
36
|
+
"@lmzhen/dsh-evolution-agent-preset": "^0.32.6"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@deepseek-ai/cordis": "^4.0.5",
|