@lmzhen/dsh-evolution-commands 0.2.1 → 0.3.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 +102 -6
- package/lib/types/index.d.ts +11 -1
- package/package.json +3 -2
package/lib/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
2
|
-
import { appendEvolutionEvent, buildLearnPrompt, eventsFile } from "@lmzhen/dsh-evolution-core";
|
|
2
|
+
import { SkillLibrary, appendEvolutionEvent, buildLearnPrompt, eventsFile, parseFrontmatter, usageObserved } from "@lmzhen/dsh-evolution-core";
|
|
3
|
+
import { buildMaintainFacts, runMaintain, snapshotFromLibrary } from "@lmzhen/dsh-evolution-maintenance";
|
|
3
4
|
import { homedir } from "node:os";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
//#region lib/types/index.js
|
|
@@ -8,13 +9,40 @@ import { join } from "node:path";
|
|
|
8
9
|
* @module @lmzhen/dsh-evolution-commands
|
|
9
10
|
*/
|
|
10
11
|
const name = "evolution-commands";
|
|
11
|
-
function
|
|
12
|
+
async function buildEnrichment(ctx, library) {
|
|
13
|
+
const skillUsage = ctx.get("skillUsage");
|
|
14
|
+
const usageMap = skillUsage?.report ? await skillUsage.report() : void 0;
|
|
15
|
+
const usageObservedValue = usageMap ? usageObserved(usageMap) : void 0;
|
|
16
|
+
const descriptions = /* @__PURE__ */ new Map();
|
|
17
|
+
const supportFiles = /* @__PURE__ */ new Map();
|
|
18
|
+
const quality = /* @__PURE__ */ new Map();
|
|
19
|
+
for (const entry of await library.list()) {
|
|
20
|
+
const body = await library.read(entry.name);
|
|
21
|
+
if (body === null) continue;
|
|
22
|
+
const description = parseFrontmatter(body)?.frontmatter.description;
|
|
23
|
+
if (typeof description === "string" && description.trim().length > 0) descriptions.set(entry.name, description);
|
|
24
|
+
const files = await library.listSupportFiles(entry.name);
|
|
25
|
+
if (files.length > 0) supportFiles.set(entry.name, files);
|
|
26
|
+
const record = usageMap?.get(entry.name);
|
|
27
|
+
if (typeof record?.quality_score === "number") quality.set(entry.name, record.quality_score);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
descriptions,
|
|
31
|
+
supportFiles,
|
|
32
|
+
quality,
|
|
33
|
+
usageObservedValue
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function apply(ctx, rawConfig = {}) {
|
|
37
|
+
const config = rawConfig;
|
|
38
|
+
let lastMaintainAt = 0;
|
|
39
|
+
let lastMaintainRunId = "";
|
|
12
40
|
ctx.inject(["commands"], (commandCtx) => {
|
|
13
41
|
commandCtx.commands.register({
|
|
14
42
|
name: "evolution",
|
|
15
43
|
description: "Self-evolution status and approval controls",
|
|
16
44
|
recordInput: false,
|
|
17
|
-
input: { hint: "pending | approve <id> | reject <id> | curator run|pause|resume|status|report|scope | restore | consolidate <target> <sources...> | skill restore <name> | skills health | learn [request] | replay" },
|
|
45
|
+
input: { hint: "pending | approve <id> | reject <id> | curator run|pause|resume|status|report|scope | restore | consolidate <target> <sources...> | skill restore <name> | skills health | learn [request] | maintain | restructure <name> \"<heading>\" <to_file> | replay" },
|
|
18
46
|
async handler(invocation) {
|
|
19
47
|
const input = invocation.rawInput?.trim() ?? "";
|
|
20
48
|
const ok = (text) => ({
|
|
@@ -115,14 +143,17 @@ function apply(ctx) {
|
|
|
115
143
|
return result.ok ? ok(result.message) : err(result.message);
|
|
116
144
|
}
|
|
117
145
|
if (input.startsWith("consolidate ")) {
|
|
118
|
-
const
|
|
146
|
+
const planTail = /\s--plan\s+(\S+)\s*$/.exec(input) ?? null;
|
|
147
|
+
const planRunId = planTail?.[1] ?? void 0;
|
|
148
|
+
const [target, ...sources] = (planTail ? input.slice(0, planTail.index) : input).slice(12).trim().split(/\s+/).filter(Boolean);
|
|
119
149
|
if (!target || sources.length === 0) return err("Usage: /evolution consolidate <target> <source...>");
|
|
120
150
|
const curator = ctx.get("evolutionCurator");
|
|
121
151
|
const result = curator ? await curator.consolidate(target, sources) : {
|
|
122
152
|
ok: false,
|
|
123
153
|
message: "Curator service not mounted."
|
|
124
154
|
};
|
|
125
|
-
|
|
155
|
+
if (!result.ok) return err(result.message);
|
|
156
|
+
return ok(planRunId ? `${result.message}\n[audit] plan=${planRunId}` : result.message);
|
|
126
157
|
}
|
|
127
158
|
if (input.startsWith("skill restore ")) {
|
|
128
159
|
const name = input.slice(14).trim();
|
|
@@ -167,12 +198,77 @@ function apply(ctx) {
|
|
|
167
198
|
});
|
|
168
199
|
return ok("Learning request sent to this session. Follow it now.");
|
|
169
200
|
}
|
|
201
|
+
if (input === "maintain --facts") {
|
|
202
|
+
const ioRegistry = ctx.get("evolutionIo");
|
|
203
|
+
if (!ioRegistry) return err("Evolution IO registry not mounted — maintenance facts unavailable.");
|
|
204
|
+
const library = new SkillLibrary(config.skillsRoot, ioRegistry.provider());
|
|
205
|
+
const enrichment = await buildEnrichment(ctx, library);
|
|
206
|
+
const { facts } = buildMaintainFacts(await snapshotFromLibrary(library, {
|
|
207
|
+
descriptions: enrichment.descriptions,
|
|
208
|
+
supportFiles: enrichment.supportFiles,
|
|
209
|
+
quality: enrichment.quality
|
|
210
|
+
}), enrichment.usageObservedValue, void 0);
|
|
211
|
+
return ok(`Maintenance facts (0-token preview):\n${facts}`);
|
|
212
|
+
}
|
|
213
|
+
if (input === "maintain") {
|
|
214
|
+
const cooldownMs = config.maintainCooldownMs ?? 13e4;
|
|
215
|
+
const sinceLast = Date.now() - lastMaintainAt;
|
|
216
|
+
if (cooldownMs > 0 && sinceLast < cooldownMs) return ok(`Maintenance cooldown active (${Math.ceil((cooldownMs - sinceLast) / 1e3)}s) — latest scan ${lastMaintainRunId}; re-running now would spend another model call.`);
|
|
217
|
+
const ioRegistry = ctx.get("evolutionIo");
|
|
218
|
+
const subagents = ctx.get("subagents");
|
|
219
|
+
if (!ioRegistry) return err("Evolution IO registry not mounted — maintenance scan unavailable.");
|
|
220
|
+
if (!subagents) return err("Subagents service not mounted — maintenance scan unavailable.");
|
|
221
|
+
const library = new SkillLibrary(config.skillsRoot, ioRegistry.provider());
|
|
222
|
+
const enrichment = await buildEnrichment(ctx, library);
|
|
223
|
+
const outcome = await runMaintain({
|
|
224
|
+
library,
|
|
225
|
+
subagents,
|
|
226
|
+
parent: invocation.agent
|
|
227
|
+
}, {
|
|
228
|
+
descriptions: () => enrichment.descriptions,
|
|
229
|
+
supportFiles: () => enrichment.supportFiles,
|
|
230
|
+
quality: () => enrichment.quality,
|
|
231
|
+
usageObserved: () => enrichment.usageObservedValue
|
|
232
|
+
});
|
|
233
|
+
lastMaintainAt = Date.now();
|
|
234
|
+
lastMaintainRunId = outcome.runId ?? "";
|
|
235
|
+
if (!outcome.ok) return err(outcome.error ?? "Maintenance scan failed.");
|
|
236
|
+
appendEvolutionEvent(ioRegistry.provider(), eventsFile(process.env.DSH_HOME ?? join(homedir(), ".dsh")), {
|
|
237
|
+
type: "maintain",
|
|
238
|
+
source: "manual",
|
|
239
|
+
runId: outcome.runId,
|
|
240
|
+
verdict: outcome.verdict,
|
|
241
|
+
recommendations: outcome.text?.split("\n").filter((line) => line.startsWith("- [")).length ?? 0
|
|
242
|
+
}).catch((error) => {
|
|
243
|
+
ctx.logger.warn(`evolution-commands: failed to record maintain event: ${String(error)}`);
|
|
244
|
+
});
|
|
245
|
+
return ok(`Maintenance scan ${outcome.runId}:\n${outcome.text ?? ""}`);
|
|
246
|
+
}
|
|
247
|
+
if (input.startsWith("restructure ")) {
|
|
248
|
+
const planTail = /\s--plan\s+(\S+)\s*$/.exec(input) ?? null;
|
|
249
|
+
const planRunId = planTail?.[1] ?? void 0;
|
|
250
|
+
const rest = planTail ? input.slice(0, planTail.index) : input;
|
|
251
|
+
const match = /^restructure\s+(\S+)\s+"([^"]+)"\s+(\S+)$/.exec(rest);
|
|
252
|
+
if (!match) return err("Usage: /evolution restructure <name> \"<## heading>\" <to_file>");
|
|
253
|
+
const name = match[1] ?? "";
|
|
254
|
+
const heading = match[2] ?? "";
|
|
255
|
+
const toFile = match[3] ?? "";
|
|
256
|
+
if (!toFile.startsWith("references/")) return err("to_file must live under references/ (log/detail destination).");
|
|
257
|
+
const ioRegistry = ctx.get("evolutionIo");
|
|
258
|
+
if (!ioRegistry) return err("Evolution IO registry not mounted — restructure unavailable.");
|
|
259
|
+
const result = await new SkillLibrary(config.skillsRoot, ioRegistry.provider()).restructure(name, [{
|
|
260
|
+
heading,
|
|
261
|
+
toFile
|
|
262
|
+
}], "foreground");
|
|
263
|
+
if (!result.ok) return err(result.message);
|
|
264
|
+
return ok(planRunId ? `${result.message}\n[audit] plan=${planRunId}` : result.message);
|
|
265
|
+
}
|
|
170
266
|
if (input === "replay") {
|
|
171
267
|
const replay = ctx.get("evolutionReplay");
|
|
172
268
|
if (!replay) return err("Replay service not mounted.");
|
|
173
269
|
return ok(replay.compare().report);
|
|
174
270
|
}
|
|
175
|
-
return ok("Evolution: memory, skills, review, curator. Use /evolution pending | approve <id> | reject <id> | curator run | curator status | curator pause | curator resume | curator report | curator scope | restore | consolidate <target> <source...> | skill restore <name> | skills health | learn [request] | replay.");
|
|
271
|
+
return ok("Evolution: memory, skills, review, curator. Use /evolution pending | approve <id> | reject <id> | curator run | curator status | curator pause | curator resume | curator report | curator scope | restore | consolidate <target> <source...> | skill restore <name> | skills health | learn [request] | maintain | restructure <name> \"<heading>\" <to_file> | replay.");
|
|
176
272
|
}
|
|
177
273
|
});
|
|
178
274
|
});
|
package/lib/types/index.d.ts
CHANGED
|
@@ -4,5 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { Context } from '@deepseek-ai/cordis';
|
|
6
6
|
export declare const name = "evolution-commands";
|
|
7
|
-
export
|
|
7
|
+
export interface Config {
|
|
8
|
+
/** Skill-tree root for maintain/restructure; empty uses skillsRoot().
|
|
9
|
+
* Align with tool-skill-manage/skill-usage/evolution-skill-catalog rows (A7). */
|
|
10
|
+
skillsRoot?: string | undefined;
|
|
11
|
+
/** Cooldown window for scan commands (ms) — misclick/rapid-trigger guard;
|
|
12
|
+
* secondary calls inside the window return the previous runId instead of
|
|
13
|
+
* spending another model call. Default 130s (>= maintain timeout 120s, so
|
|
14
|
+
* the window also covers in-flight runs); transient (per-process). */
|
|
15
|
+
maintainCooldownMs?: number | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare function apply(ctx: Context, rawConfig?: Config): void;
|
|
8
18
|
//# sourceMappingURL=index.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 (community build)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
36
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
36
|
+
"@lmzhen/dsh-evolution-core": "^0.3.0",
|
|
37
|
+
"@lmzhen/dsh-evolution-maintenance": "^0.3.0"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|
|
39
40
|
"@deepseek-ai/cordis": "^4.0.1",
|