@lmzhen/dsh-evolution-review 0.3.61 → 0.3.63

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 CHANGED
@@ -28,12 +28,13 @@ Independent of request-prefix construction. This package does not alter the asse
28
28
  - The completion-channel counters (`cumulativeToolCalls` / `completionInjected`) are in-memory only. A process restart resets them, which is accepted behavior: the completion review is a one-per-session post-task adaptation and a restart is treated as a fresh conversation boundary. The cadence state (`turnsSinceMemory` / `turnsSinceSkill`) is persisted via `ReviewState` and survives restart.
29
29
  - `evolution/review-scheduled` and `evolution/review-error` are emitted for platform/user wiring only — this family has no in-repo production `ctx.on` consumer for them. They are declared externally owned (the platform side wires consumption), which matches the `EXEMPT_ORPHANS` set in `scripts/verify-event-pairing.mjs`.
30
30
  - When the `evolution-state` service is not mounted, the memory/skill cadence state is not persisted and every turn restarts from a clean `{ turnsSinceMemory: 0, turnsSinceSkill: 0 }` baseline — the review schedule is stateless and re-decided each turn rather than accumulating across the conversation. The loss is surfaced once per process as a logger warning at the first turn/end.
31
+ - Read-before-write can see the review subagent's own `skill` reads only when the subagent backend exposes `localAgent` (the in-process driver does; out-of-process backends such as ACP and the CLI providers set `localAgent: undefined`). With a remote backend the subagent's reads are invisible, so a plan item patching a skill the subagent itself loaded is dropped as "unread" — the review then falls back to the parent session's reads only. Documented rather than worked around: recovering the child read set needs a `SubagentLike` contract change (v14 P2-6).
31
32
 
32
33
  ## Configuration
33
34
 
34
35
  `reviewProvider` selects the LLM provider for review subagents. When omitted, the subagent inherits the deployment default route instead of a hardcoded provider name. Model selection stays on the policy (`memoryReviewModel` / `skillReviewModel`).
35
36
 
36
- `reviewTimeoutMs` bounds each review subagent run (an `AbortSignal.timeout`; `0` aborts immediately). `executionTimeoutMs` is a leftover declaration and is **not consumed** it is kept only as a code comment and has no effect; configure `reviewTimeoutMs` instead.
37
+ `reviewTimeoutMs` bounds each review subagent run (an `AbortSignal.timeout`; `0` aborts immediately). The former `executionTimeoutMs` declaration was removed in v14 (nothing read it, so it was configuration that did nothing); use `reviewTimeoutMs`.
37
38
 
38
39
  ### Review delivery contract (0.3.38-0.3.42)
39
40
 
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { createUserMessage } from "@deepseek-ai/dsh-llm";
4
- import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_USER_CHAR_LIMIT, PROMPT_BUNDLE, SkillLibrary, advanceReview, clampedNumber, evolutionIoAdapter, foldTurn, redactSecrets, resolveOrigins, resolveSkillsRoot, reviewPrompt, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
4
+ import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_REVIEW_CONTEXT_MESSAGES, DEFAULT_REVIEW_MEMORY_INTERVAL, DEFAULT_REVIEW_MESSAGE_CHARS, DEFAULT_REVIEW_SKILL_INTERVAL, DEFAULT_REVIEW_TIMEOUT_MS, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_USER_CHAR_LIMIT, PROMPT_BUNDLE, SkillLibrary, advanceReview, clampedNumber, evolutionIoAdapter, foldTurn, redactSecrets, resolveOrigins, resolveSkillsRoot, reviewPrompt, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
5
5
  import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
6
6
  //#region lib/types/index.js
7
7
  /**
@@ -16,10 +16,9 @@ const Config = z.object({
16
16
  memoryInterval: z.number().min(1).default(DEFAULT_REVIEW_MEMORY_INTERVAL),
17
17
  skillInterval: z.number().min(1).default(DEFAULT_REVIEW_SKILL_INTERVAL),
18
18
  reviewToolAllow: z.array(z.string()).default(["skill"]),
19
- reviewTimeoutMs: z.number().min(1).default(12e4),
20
- executionTimeoutMs: z.number().min(1).default(3e4),
21
- reviewContextMessages: z.number().min(1).default(60),
22
- reviewMessageChars: z.number().min(1).default(2e3),
19
+ reviewTimeoutMs: z.number().min(1).default(DEFAULT_REVIEW_TIMEOUT_MS),
20
+ reviewContextMessages: z.number().min(1).default(DEFAULT_REVIEW_CONTEXT_MESSAGES),
21
+ reviewMessageChars: z.number().min(1).default(DEFAULT_REVIEW_MESSAGE_CHARS),
23
22
  reviewMaxDepth: z.number().min(1).default(1),
24
23
  reviewProvider: z.string(),
25
24
  skillReviewTrigger: z.union([
@@ -49,7 +48,6 @@ const REVIEW_OUTPUT_SCHEMA = {
49
48
  summary: { type: "string" }
50
49
  }
51
50
  };
52
- let statelessReviewStateWarned = false;
53
51
  function clampReviewConfig(rawConfig, ctx) {
54
52
  const clamped = [];
55
53
  const field = (name, value, fallback, min) => {
@@ -60,9 +58,9 @@ function clampReviewConfig(rawConfig, ctx) {
60
58
  const config = Object.assign({}, rawConfig, {
61
59
  memoryInterval: field("memoryInterval", rawConfig.memoryInterval, DEFAULT_REVIEW_MEMORY_INTERVAL, 1),
62
60
  skillInterval: field("skillInterval", rawConfig.skillInterval, DEFAULT_REVIEW_SKILL_INTERVAL, 1),
63
- reviewTimeoutMs: field("reviewTimeoutMs", rawConfig.reviewTimeoutMs, 12e4, 1),
64
- reviewContextMessages: field("reviewContextMessages", rawConfig.reviewContextMessages, 60, 1),
65
- reviewMessageChars: field("reviewMessageChars", rawConfig.reviewMessageChars, 2e3, 1),
61
+ reviewTimeoutMs: field("reviewTimeoutMs", rawConfig.reviewTimeoutMs, DEFAULT_REVIEW_TIMEOUT_MS, 1),
62
+ reviewContextMessages: field("reviewContextMessages", rawConfig.reviewContextMessages, DEFAULT_REVIEW_CONTEXT_MESSAGES, 1),
63
+ reviewMessageChars: field("reviewMessageChars", rawConfig.reviewMessageChars, DEFAULT_REVIEW_MESSAGE_CHARS, 1),
66
64
  reviewMaxDepth: field("reviewMaxDepth", rawConfig.reviewMaxDepth, 1, 1),
67
65
  skillReviewCompletionMinToolCalls: field("skillReviewCompletionMinToolCalls", rawConfig.skillReviewCompletionMinToolCalls, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, 1)
68
66
  });
@@ -73,6 +71,7 @@ function apply(ctx, rawConfig) {
73
71
  if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to schedule review work");
74
72
  const config = clampReviewConfig(rawConfig, ctx);
75
73
  const turnStarts = /* @__PURE__ */ new Map();
74
+ let statelessReviewStateWarned = false;
76
75
  const cumulativeToolCalls = /* @__PURE__ */ new Map();
77
76
  const completionInjected = /* @__PURE__ */ new Set();
78
77
  const pendingCadenceReviews = /* @__PURE__ */ new Map();
@@ -349,7 +348,11 @@ function apply(ctx, rawConfig) {
349
348
  let ok = true;
350
349
  try {
351
350
  for (const op of plan.memoryOps ?? []) {
352
- if (!Array.isArray(op.evidence) || op.evidence.length === 0) continue;
351
+ if (!Array.isArray(op.evidence) || op.evidence.length === 0) {
352
+ ok = false;
353
+ failedOps.push(`memory ${op.action ?? "add"} ${op.target}: missing evidence (defense-in-depth rejection)`);
354
+ continue;
355
+ }
353
356
  const normalized = {
354
357
  target: op.target === "user" ? "user" : "memory",
355
358
  action: op.action ?? "add",
@@ -364,7 +367,11 @@ function apply(ctx, rawConfig) {
364
367
  }
365
368
  }
366
369
  for (const op of plan.skillOps ?? []) {
367
- if (!Array.isArray(op.evidence) || op.evidence.length === 0 || !op.name) continue;
370
+ if (!Array.isArray(op.evidence) || op.evidence.length === 0 || !op.name) {
371
+ ok = false;
372
+ failedOps.push(`skill ${op.action ?? "patch"} ${op.name ?? "<unnamed>"}: missing evidence or name (defense-in-depth rejection)`);
373
+ continue;
374
+ }
368
375
  const args = {
369
376
  ...op,
370
377
  evidence: op.evidence
@@ -472,7 +479,7 @@ function apply(ctx, rawConfig) {
472
479
  if (archived.ok) await ctx.get("skillUsage")?.markArchived?.(name);
473
480
  return archived;
474
481
  }
475
- if (op.action === "write_file") return await library.writeSupportFile(name, op.file_path ?? "", op.file_content ?? op.content ?? "", origin);
482
+ if (op.action === "write_file") return await library.writeSupportFile(name, op.file_path ?? "", op.file_content ?? "", origin);
476
483
  if (op.action === "remove_file") return await library.removeSupportFile(name, op.file_path ?? "", origin);
477
484
  if (op.action === "restructure") {
478
485
  const moves = (op.restructure ?? []).filter((move) => move !== null).map((move) => ({
@@ -18,7 +18,6 @@ export interface Config {
18
18
  */
19
19
  reviewToolAllow?: string[];
20
20
  reviewTimeoutMs?: number;
21
- executionTimeoutMs?: number;
22
21
  reviewContextMessages?: number;
23
22
  reviewMessageChars?: number;
24
23
  /** ABSOLUTE cap of the review subagent's own delegation depth (platform
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-review",
3
3
  "description": "Background review orchestration (community build)",
4
- "version": "0.3.61",
4
+ "version": "0.3.63",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,9 +31,9 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-approval": "^0.3.61",
35
- "@lmzhen/dsh-evolution-core": "^0.3.61",
36
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.61"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.63",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.63",
36
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.63"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@deepseek-ai/cordis": "^4.0.1",
@@ -42,8 +42,8 @@
42
42
  "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
43
43
  "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
44
44
  "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
45
- "@lmzhen/dsh-evolution-state": "^0.3.61",
46
- "@lmzhen/dsh-evolution-policy": "^0.3.61"
45
+ "@lmzhen/dsh-evolution-state": "^0.3.63",
46
+ "@lmzhen/dsh-evolution-policy": "^0.3.63"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
@@ -54,9 +54,9 @@
54
54
  "@deepseek-ai/dsh-session-persistence": "^0.1.1-rc.2",
55
55
  "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.1-rc.2",
56
56
  "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
57
- "@lmzhen/dsh-evolution-approval": "^0.3.61",
58
- "@lmzhen/dsh-evolution-core": "^0.3.61",
59
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.61",
60
- "@lmzhen/dsh-evolution-state": "^0.3.61"
57
+ "@lmzhen/dsh-evolution-approval": "^0.3.63",
58
+ "@lmzhen/dsh-evolution-core": "^0.3.63",
59
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.63",
60
+ "@lmzhen/dsh-evolution-state": "^0.3.63"
61
61
  }
62
62
  }