@lmzhen/dsh-evolution-commands 0.3.62 → 0.3.64

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
4
- import { SkillLibrary, appendEvolutionEvent, buildLearnPrompt, clampedNumber, composePresetComposition, eventsFile, evolutionRoot, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
4
+ import { SkillLibrary, appendEvolutionEvent, buildLearnPrompt, clampedNumber, composePresetComposition, eventsFile, evolutionRoot, resolveRootConfig, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
5
5
  import { buildEnrichment, buildMaintainFacts, runMaintain, snapshotFromLibrary } from "@lmzhen/dsh-evolution-maintenance";
6
6
  import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
7
7
  import { dirname, join } from "node:path";
@@ -16,6 +16,14 @@ import { fileURLToPath } from "node:url";
16
16
  * services are actually mounted in this runtime. Always ends with suggested
17
17
  * actions so any finding carries its next step.
18
18
  */
19
+ /** D-6 (v18): exact-segment tail match (the loose substring form matched a
20
+ * hypothetical `dsh-evolution-allowlist`). */
21
+ const tailOf = (name) => name.slice(name.lastIndexOf("/") + 1);
22
+ const EVOLUTION_BUNDLE_TAILS = new Set([
23
+ "dsh-evolution-all",
24
+ "dsh-evolution-host",
25
+ "dsh-evolution-preset"
26
+ ]);
19
27
  /** Profile bundle rows for evolution-family packages across all profiles. */
20
28
  function collectEvolutionBundles(home) {
21
29
  const profilesDir = join(home, "profiles");
@@ -25,7 +33,7 @@ function collectEvolutionBundles(home) {
25
33
  if (!profile.isDirectory()) continue;
26
34
  try {
27
35
  const manifest = JSON.parse(readFileSync(join(profilesDir, profile.name, "package.json"), "utf8"));
28
- for (const name of manifest.dsh?.profile?.bundles ?? []) if (/evolution-(all|host|preset)/.test(name)) bundles.push(name);
36
+ for (const name of manifest.dsh?.profile?.bundles ?? []) if (EVOLUTION_BUNDLE_TAILS.has(tailOf(name))) bundles.push(name);
29
37
  } catch {}
30
38
  }
31
39
  return bundles;
@@ -50,9 +58,9 @@ async function diagnose(ctx, options = {}) {
50
58
  const home = options.home ?? evolutionRoot();
51
59
  const bundles = collectEvolutionBundles(home);
52
60
  const has = (name) => ctx.get(name) !== void 0;
53
- const full = bundles.some((name) => /evolution-all/.test(name));
54
- const host = bundles.some((name) => /evolution-host/.test(name));
55
- const preset = bundles.some((name) => /evolution-preset/.test(name));
61
+ const full = bundles.some((name) => tailOf(name) === "dsh-evolution-all");
62
+ const host = bundles.some((name) => tailOf(name) === "dsh-evolution-host");
63
+ const preset = bundles.some((name) => tailOf(name) === "dsh-evolution-preset");
56
64
  const presetDir = join(home, ".agent-presets", "evolution");
57
65
  const layered = host && existsSync(presetDir);
58
66
  const conflicts = [];
@@ -122,8 +130,8 @@ const COMMAND_ENTRIES = [
122
130
  summary: "drop a staged write without running it"
123
131
  },
124
132
  {
125
- usage: "doctor",
126
- summary: "read-only self-check: install form, conflicts, env, services"
133
+ usage: "doctor [--json]",
134
+ summary: "read-only self-check: install form, conflicts, env, services (--json feeds scripts)"
127
135
  },
128
136
  {
129
137
  usage: "curator run|pause|resume|status|report|scope",
@@ -191,6 +199,7 @@ function renderHelpText() {
191
199
  /** Enrichment maps shared by the full scan and the `--facts` preview (v12). */
192
200
  const name = "evolution-commands";
193
201
  const Config = z.object({
202
+ root: z.string().default(""),
194
203
  skillsRoot: z.string().default(""),
195
204
  maintainCooldownMs: z.number().min(0).default(3e4),
196
205
  maintainTimeoutMs: z.number().min(1).default(6e5),
@@ -198,6 +207,9 @@ const Config = z.object({
198
207
  });
199
208
  function apply(ctx, rawConfig = {}) {
200
209
  const config = rawConfig;
210
+ const rootConfig = resolveRootConfig(rawConfig);
211
+ if (rootConfig.usedDeprecatedAlias) ctx.logger.warn("evolution-commands: config \"skillsRoot\" is deprecated (E-7); use \"root\" — the alias is honoured until 0.3.65");
212
+ const skillsRootValue = rootConfig.root;
201
213
  let lastMaintainAt = 0;
202
214
  let lastMaintainRunId = "";
203
215
  let maintainInFlightSince = 0;
@@ -251,6 +263,7 @@ function apply(ctx, rawConfig = {}) {
251
263
  const curator = ctx.get("evolutionCurator");
252
264
  if (!curator) return err("E-302: curator service not mounted. Next: mount the evolution-curator row (evolution-host/evolution-all) and run /evolution doctor.");
253
265
  const result = await curator.run({ ignoreGates: true });
266
+ if (result.skipped !== void 0) return ok(`Curator run skipped (${result.skipped}): no curation pass was executed.\nrunId=${result.report.runId}`);
254
267
  return ok(`Curator run complete: ${result.stale.length} stale, ${result.archived.length} archived, ${result.errors.length} failed.\nrunId=${result.report.runId}${result.report.snapshotPath ? `\nsnapshot=${result.report.snapshotPath}` : ""}`);
255
268
  }
256
269
  if (input === "curator pause" || input === "curator resume") {
@@ -384,7 +397,7 @@ function apply(ctx, rawConfig = {}) {
384
397
  if (input === "maintain --facts") {
385
398
  const ioRegistry = ctx.get("evolutionIo");
386
399
  if (!ioRegistry) return err("Evolution IO registry not mounted — maintenance facts unavailable.");
387
- const library = new SkillLibrary(resolveSkillsRoot({ root: config.skillsRoot }), ioRegistry.provider());
400
+ const library = new SkillLibrary(resolveSkillsRoot({ root: skillsRootValue }), ioRegistry.provider());
388
401
  const enrichment = await buildEnrichment(ctx, library);
389
402
  const { facts } = buildMaintainFacts(await snapshotFromLibrary(library, {
390
403
  descriptions: enrichment.descriptions,
@@ -409,7 +422,7 @@ function apply(ctx, rawConfig = {}) {
409
422
  if (!subagents) return err("Subagents service not mounted — maintenance scan unavailable.");
410
423
  try {
411
424
  maintainInFlightSince = Date.now();
412
- const library = new SkillLibrary(resolveSkillsRoot({ root: config.skillsRoot }), ioRegistry.provider());
425
+ const library = new SkillLibrary(resolveSkillsRoot({ root: skillsRootValue }), ioRegistry.provider());
413
426
  const enrichment = await buildEnrichment(ctx, library);
414
427
  const outcome = await runMaintain({
415
428
  library,
@@ -422,6 +435,7 @@ function apply(ctx, rawConfig = {}) {
422
435
  } }
423
436
  }, {
424
437
  timeoutMs: runTimeoutMs,
438
+ signal: invocation.signal,
425
439
  descriptions: () => enrichment.descriptions,
426
440
  supportFiles: () => enrichment.supportFiles,
427
441
  quality: () => enrichment.quality,
@@ -486,7 +500,7 @@ function apply(ctx, rawConfig = {}) {
486
500
  if (!toFile.startsWith("references/")) return err("to_file must live under references/ (log/detail destination).");
487
501
  const ioRegistry = ctx.get("evolutionIo");
488
502
  if (!ioRegistry) return err("Evolution IO registry not mounted — restructure unavailable.");
489
- const result = await new SkillLibrary(resolveSkillsRoot({ root: config.skillsRoot }), ioRegistry.provider(), void 0, (event) => {
503
+ const result = await new SkillLibrary(resolveSkillsRoot({ root: skillsRootValue }), ioRegistry.provider(), void 0, (event) => {
490
504
  ctx.emit("evolution/skill-mutated", event);
491
505
  }, void 0, config.threatExemptLabels ?? []).restructure(name, [{
492
506
  heading,
@@ -520,14 +534,12 @@ function apply(ctx, rawConfig = {}) {
520
534
  * dir≠name trap), so BOTH sibling shapes are probed.
521
535
  */
522
536
  function resolveAgentPresetDir(importMetaUrl) {
523
- const dir = dirname(fileURLToPath(importMetaUrl));
524
- const siblingCandidate = join(dir, "..", "dsh-evolution-agent-preset");
525
- const candidates = [siblingCandidate, join(dir, "..", "..", "evolution-agent")];
526
- for (const candidate of candidates) if (existsSync(join(candidate, "agent.cordis.yml")) && existsSync(join(candidate, "preset.yml"))) return candidate;
537
+ const overlayCandidate = join(dirname(fileURLToPath(importMetaUrl)), "..", "..", "evolution-agent");
538
+ if (existsSync(join(overlayCandidate, "agent.cordis.yml")) && existsSync(join(overlayCandidate, "preset.yml"))) return overlayCandidate;
527
539
  try {
528
540
  return dirname(createRequire(importMetaUrl).resolve("@lmzhen/dsh-evolution-agent-preset/package.json"));
529
541
  } catch {
530
- return siblingCandidate;
542
+ return overlayCandidate;
531
543
  }
532
544
  }
533
545
  const defaultFs = {
@@ -6,10 +6,13 @@ import type { Context } from '@deepseek-ai/cordis';
6
6
  import z from '@deepseek-ai/schemastery';
7
7
  export declare const name = "evolution-commands";
8
8
  export interface Config {
9
- /** Skill-tree root for maintain/restructure; empty uses skillsRoot().
10
- * Align with tool-skill-manage/skill-usage/evolution-skill-catalog rows (A7).
11
- * 0.3.22 (G3.2, F-342): resolved through resolveSkillsRoot() so an empty/
12
- * whitespace value falls back to the default instead of a CWD-relative root. */
9
+ /** Skill-tree root for maintain/restructure; empty uses the default tree.
10
+ * E-7 (v18): canonical key — the same `root` every other family row reads,
11
+ * resolved through resolveSkillsRoot() so an empty/whitespace value falls
12
+ * back to the default instead of a CWD-relative root. */
13
+ root?: string | undefined;
14
+ /** Deprecated alias of `root` (E-7, v18): honoured only while `root` is
15
+ * empty, with a warning; removed after 0.3.65. */
13
16
  skillsRoot?: string | undefined;
14
17
  /** Cooldown window for scan commands (ms) — misclick/rapid-trigger guard;
15
18
  * secondary calls inside the window return the previous runId instead of
@@ -34,11 +37,13 @@ export interface Config {
34
37
  threatExemptLabels?: string[] | undefined;
35
38
  }
36
39
  export declare const Config: z<Schemastery.ObjectS<{
40
+ root: z<string, string>;
37
41
  skillsRoot: z<string, string>;
38
42
  maintainCooldownMs: z<number, number>;
39
43
  maintainTimeoutMs: z<number, number>;
40
44
  threatExemptLabels: z<string[], string[]>;
41
45
  }>, Schemastery.ObjectT<{
46
+ root: z<string, string>;
42
47
  skillsRoot: z<string, string>;
43
48
  maintainCooldownMs: z<number, number>;
44
49
  maintainTimeoutMs: z<number, number>;
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.3.62",
4
+ "version": "0.3.64",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,12 +31,12 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-approval": "^0.3.62",
35
- "@lmzhen/dsh-evolution-core": "^0.3.62",
36
- "@lmzhen/dsh-evolution-maintenance": "^0.3.62"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.64",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.64",
36
+ "@lmzhen/dsh-evolution-maintenance": "^0.3.64"
37
37
  },
38
38
  "optionalDependencies": {
39
- "@lmzhen/dsh-evolution-agent-preset": "^0.3.62"
39
+ "@lmzhen/dsh-evolution-agent-preset": "^0.3.64"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@deepseek-ai/cordis": "^4.0.1",