@lmzhen/dsh-evolution-commands 0.3.67 → 0.3.68

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
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { effectiveSessionPolicy } from "@lmzhen/dsh-evolution-approval";
4
4
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
5
- import { SkillLibrary, appendEvolutionEvent, buildLearnPrompt, clampedNumber, composePresetComposition, eventsFile, evolutionRoot, resolveRootConfig, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
5
+ import { MAX_TIMER_DELAY_MS, SkillLibrary, appendEvolutionEvent, assertSkillsRootAliasRetired, buildLearnPrompt, clampedNumber, composePresetComposition, eventsFile, evolutionRoot, resolveRootConfig, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
6
6
  import { buildEnrichment, buildMaintainFacts, runMaintain, snapshotFromLibrary } from "@lmzhen/dsh-evolution-maintenance";
7
7
  import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
8
  import { dirname, join } from "node:path";
@@ -69,7 +69,7 @@ async function diagnose(ctx, options = {}) {
69
69
  if (full && host) conflicts.push("evolution-all and evolution-host are installed together — the infra rows double-mount and startup fails loud. Keep ONE: remove the other bundle.");
70
70
  if (full && preset) conflicts.push("evolution-all and evolution-preset are installed together — the infra rows double-mount. Keep ONE.");
71
71
  if (host && preset) conflicts.push("evolution-host and evolution-preset are installed together — the infra rows double-mount. Keep ONE.");
72
- if (full && layered) conflicts.push("evolution-all and the layered Evolution preset are both present — the model rows double-mount. Keep ONE (use layered without all, or drop the preset).");
72
+ if (full && presetDirInstalled) conflicts.push("evolution-all and the layered Evolution preset are both present — the model rows double-mount. Keep ONE (use layered without all, or drop the preset).");
73
73
  if (preset && presetDirInstalled) conflicts.push("evolution-preset and the layered Evolution preset are both present — the model rows double-mount (the preset bundle carries the same model rows as all). Keep ONE (drop the preset bundle, or remove the layered preset).");
74
74
  const services = {
75
75
  review: full || host || preset,
@@ -217,9 +217,8 @@ const Config = z.object({
217
217
  });
218
218
  function apply(ctx, rawConfig = {}) {
219
219
  const config = rawConfig;
220
- const rootConfig = resolveRootConfig(rawConfig);
221
- if (rootConfig.usedDeprecatedAlias) ctx.logger.warn("evolution-commands: config \"skillsRoot\" is deprecated (E-7); use \"root\" — the alias is honoured until 0.3.65");
222
- const skillsRootValue = rootConfig.root;
220
+ assertSkillsRootAliasRetired(rawConfig);
221
+ const skillsRootValue = resolveRootConfig(rawConfig).root;
223
222
  let lastMaintainAt = 0;
224
223
  let lastMaintainRunId = "";
225
224
  let maintainInFlightSince = 0;
@@ -231,7 +230,7 @@ function apply(ctx, rawConfig = {}) {
231
230
  recordInput: false,
232
231
  input: { hint: renderHint() },
233
232
  async handler(invocation) {
234
- const rawInputTrimmed = invocation.rawInput?.trim() ?? "";
233
+ const rawInputTrimmed = invocation.rawInput.trim();
235
234
  const input = rawInputTrimmed.replace(/\s+/g, " ");
236
235
  const ok = (text) => ({
237
236
  kind: "success",
@@ -385,7 +384,7 @@ function apply(ctx, rawConfig = {}) {
385
384
  }
386
385
  if (input === "learn" || input.startsWith("learn ")) {
387
386
  const request = rawInputTrimmed === "learn" ? "" : rawInputTrimmed.slice(6).trim();
388
- invocation.agent.inject(createUserMessage({
387
+ const message = createUserMessage({
389
388
  content: [{
390
389
  type: "text",
391
390
  text: buildLearnPrompt(request)
@@ -396,7 +395,11 @@ function apply(ctx, rawConfig = {}) {
396
395
  form: "notice",
397
396
  summary: "learn request"
398
397
  }
399
- }));
398
+ });
399
+ const followup = invocation.agent.followup;
400
+ const woke = typeof followup === "function";
401
+ if (woke) followup(message);
402
+ else invocation.agent.inject(message);
400
403
  const eventIo = ctx.get("evolutionIo")?.provider();
401
404
  if (eventIo) appendEvolutionEvent(eventIo, eventsFile(evolutionRoot()), {
402
405
  type: "learn",
@@ -405,7 +408,7 @@ function apply(ctx, rawConfig = {}) {
405
408
  }).catch((error) => {
406
409
  ctx.logger.warn(`evolution-commands: failed to record learn event: ${String(error)}`);
407
410
  });
408
- return ok("Learning request sent to this session. Follow it now.");
411
+ return woke ? ok("Learning request sent to this session. Follow it now.") : ok("Learning request queued for this session — this host exposes no wake-up channel, so it is read on your next message.");
409
412
  }
410
413
  if (input === "maintain --facts") {
411
414
  const ioRegistry = ctx.get("evolutionIo");
@@ -424,7 +427,7 @@ function apply(ctx, rawConfig = {}) {
424
427
  const maintainArgs = /^maintain(?:\s+--timeout[ =](\d+))?\s*$/.exec(input);
425
428
  if (maintainArgs) {
426
429
  const runTimeoutMs = maintainArgs[1] ? Number(maintainArgs[1]) : config.maintainTimeoutMs ?? 6e5;
427
- if (!Number.isSafeInteger(runTimeoutMs) || runTimeoutMs <= 0 || runTimeoutMs > 2147483647) return err(maintainArgs[1] ? "Invalid --timeout value: expected a positive integer number of milliseconds up to 2147483647 (e.g. /evolution maintain --timeout 600000)." : "The maintainTimeoutMs config is invalid: expected a positive integer number of milliseconds up to 2147483647. Fix the evolution-commands row config (maintainTimeoutMs), then retry.");
430
+ if (!Number.isSafeInteger(runTimeoutMs) || runTimeoutMs <= 0 || runTimeoutMs > MAX_TIMER_DELAY_MS) return err(maintainArgs[1] ? `Invalid --timeout value: expected a positive integer number of milliseconds up to ${MAX_TIMER_DELAY_MS} (e.g. /evolution maintain --timeout 600000).` : `The maintainTimeoutMs config is invalid: expected a positive integer number of milliseconds up to ${MAX_TIMER_DELAY_MS}. Fix the evolution-commands row config (maintainTimeoutMs), then retry.`);
428
431
  if (maintainInFlightSince > 0) return err(`Maintenance scan is already running (since ~${Math.max(1, Math.round((Date.now() - maintainInFlightSince) / 1e3))}s ago) — re-submitting now would cancel it. Wait for it to settle; the result appears when it finishes.`);
429
432
  const cooldownMs = clampedNumber(config.maintainCooldownMs, 3e4, { min: 0 });
430
433
  const sinceLast = Date.now() - lastMaintainAt;
@@ -445,7 +448,9 @@ function apply(ctx, rawConfig = {}) {
445
448
  tools: { get: (name) => ctx.get("tools")?.get(name) },
446
449
  logger: { warn: (message) => {
447
450
  ctx.logger.warn(message);
448
- } }
451
+ } },
452
+ rootExists: () => ioRegistry.provider().exists(skillsRootValue),
453
+ skillRoot: skillsRootValue
449
454
  }, {
450
455
  timeoutMs: runTimeoutMs,
451
456
  signal: invocation.signal,
@@ -533,8 +538,8 @@ function apply(ctx, rawConfig = {}) {
533
538
  libraryOrigin: "foreground"
534
539
  },
535
540
  origin: "foreground",
536
- ...session?.id ? { sessionId: session.id } : {},
537
- ...session ? { session } : {},
541
+ ...session.id ? { sessionId: session.id } : {},
542
+ session,
538
543
  ...sessionPolicy !== void 0 ? { sessionPolicy } : {}
539
544
  });
540
545
  if (decision.action === "staged") return ok(`${decision.message}${planRunId ? `\n[audit] plan=${planRunId}` : ""}`);
@@ -11,8 +11,9 @@ export interface Config {
11
11
  * resolved through resolveSkillsRoot() so an empty/whitespace value falls
12
12
  * back to the default instead of a CWD-relative root. */
13
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. */
14
+ /** V27 G2.4 (M-08): RETIRED alias of `root`. The field stays declared so the
15
+ * loader can hand it to the load-time gate (which rejects it loudly) instead
16
+ * of dropping it silently; the plugin never reads it as a root. */
16
17
  skillsRoot?: string | undefined;
17
18
  /** Cooldown window for scan commands (ms) — misclick/rapid-trigger guard;
18
19
  * secondary calls inside the window return the previous runId instead of
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.67",
4
+ "version": "0.3.68",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,19 +31,21 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-approval": "^0.3.67",
35
- "@lmzhen/dsh-evolution-core": "^0.3.67",
36
- "@lmzhen/dsh-evolution-maintenance": "^0.3.67"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.68",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.68",
36
+ "@lmzhen/dsh-evolution-maintenance": "^0.3.68"
37
37
  },
38
38
  "optionalDependencies": {
39
- "@lmzhen/dsh-evolution-agent-preset": "^0.3.67"
39
+ "@lmzhen/dsh-evolution-agent-preset": "^0.3.68"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@deepseek-ai/cordis": "^4.0.1",
43
+ "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
43
44
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
44
45
  "@deepseek-ai/dsh-llm": "^0.1.1-rc.2"
45
46
  },
46
47
  "devDependencies": {
48
+ "@deepseek-ai/dsh-commands": "^0.1.1-rc.2",
47
49
  "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2"
48
50
  }
49
51
  }