@lmzhen/dsh-evolution-review 0.3.38 → 0.3.40

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
@@ -23,6 +23,7 @@ const Config = z.object({
23
23
  reviewMaxDepth: z.number().min(1).default(1),
24
24
  reviewProvider: z.string(),
25
25
  skillReviewTrigger: z.string().default(DEFAULT_SKILL_REVIEW_TRIGGER),
26
+ reviewWakeInject: z.boolean().default(true),
26
27
  skillReviewCompletionMinToolCalls: z.number().min(1).default(DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS)
27
28
  });
28
29
  let statelessReviewStateWarned = false;
@@ -114,45 +115,17 @@ function apply(ctx, rawConfig) {
114
115
  skillInterval: snapshot?.reviewSkillInterval ?? config.skillInterval,
115
116
  substantiveMinToolCalls: snapshot?.substantiveMinToolCalls ?? 3,
116
117
  substantiveMinUserChars: snapshot?.substantiveMinUserChars ?? 200,
117
- substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ?? 500
118
+ substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ?? 500,
119
+ resetOnFire: false
118
120
  });
119
121
  await stateService?.saveReviewState(session.id, state);
120
122
  const cumulative = (cumulativeToolCalls.get(session.id) ?? 0) + signal.toolCalls;
121
123
  cumulativeToolCalls.set(session.id, cumulative);
122
- if (event.data.reason.kind === "completed") {
123
- const pendingKind = pendingCadenceReviews.get(session.id);
124
- if (pendingKind !== void 0) {
125
- pendingCadenceReviews.delete(session.id);
126
- try {
127
- agent.inject(createUserMessage({
128
- content: [{
129
- type: "text",
130
- text: reviewPrompt(pendingKind)
131
- }],
132
- source: {
133
- kind: "plugin",
134
- plugin: "dsh-evolution-review",
135
- form: "notice",
136
- summary: "auto-review"
137
- }
138
- }));
139
- } catch (injectError) {
140
- ctx.logger.warn(`dsh-evolution-review: deferred review inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
141
- }
142
- }
143
- }
144
- if (kind) {
145
- if (await trySubagentReview(session, agent, kind, signal)) ctx.emit("evolution/review-scheduled", {
146
- sessionId: session.id,
147
- kind,
148
- toolCalls: signal.toolCalls,
149
- userChars: signal.userChars,
150
- assistantChars: signal.assistantChars
151
- });
152
- else if ((policy()?.reviewMode ?? config.reviewMode) === "inject") agent.inject(createUserMessage({
124
+ const deliverReview = (text) => {
125
+ const message = createUserMessage({
153
126
  content: [{
154
127
  type: "text",
155
- text: reviewPrompt(kind)
128
+ text
156
129
  }],
157
130
  source: {
158
131
  kind: "plugin",
@@ -160,13 +133,42 @@ function apply(ctx, rawConfig) {
160
133
  form: "notice",
161
134
  summary: "auto-review"
162
135
  }
163
- }));
164
- else {
165
- pendingCadenceReviews.set(session.id, kind);
166
- if (!pendingCadenceWarned.has(session.id)) {
167
- pendingCadenceWarned.add(session.id);
168
- ctx.logger.warn(`dsh-evolution-review: ${kind} review could not run on a subagent this turn; deferred to the end of the conversation (no mid-task injection)`);
136
+ });
137
+ const followup = agent.followup;
138
+ if (config.reviewWakeInject && typeof followup === "function") followup(message);
139
+ else agent.inject(message);
140
+ };
141
+ if (event.data.reason.kind === "completed") {
142
+ const pendingKind = pendingCadenceReviews.get(session.id) ?? kind ?? void 0;
143
+ if (pendingKind !== void 0) {
144
+ pendingCadenceReviews.delete(session.id);
145
+ if ((policy()?.reviewMode ?? config.reviewMode) === "inject") try {
146
+ deliverReview(reviewPrompt(pendingKind));
147
+ } catch (injectError) {
148
+ ctx.logger.warn(`dsh-evolution-review: deferred review inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
149
+ }
150
+ else if (await trySubagentReview(session, agent, pendingKind, signal)) ctx.emit("evolution/review-scheduled", {
151
+ sessionId: session.id,
152
+ kind: pendingKind,
153
+ toolCalls: signal.toolCalls,
154
+ userChars: signal.userChars,
155
+ assistantChars: signal.assistantChars
156
+ });
157
+ else try {
158
+ deliverReview(reviewPrompt(pendingKind));
159
+ } catch (injectError) {
160
+ ctx.logger.warn(`dsh-evolution-review: deferred review inject failed: ${injectError instanceof Error ? injectError.message : String(injectError)}`);
169
161
  }
162
+ state.turnsSinceMemory = 0;
163
+ state.turnsSinceSkill = 0;
164
+ await stateService?.saveReviewState(session.id, state);
165
+ }
166
+ }
167
+ if (kind && event.data.reason.kind !== "completed") {
168
+ pendingCadenceReviews.set(session.id, kind);
169
+ if (!pendingCadenceWarned.has(session.id)) {
170
+ pendingCadenceWarned.add(session.id);
171
+ ctx.logger.warn(`dsh-evolution-review: ${kind} review threshold reached; the review runs at the end of the conversation (no mid-task execution)`);
170
172
  }
171
173
  return;
172
174
  }
@@ -265,7 +267,7 @@ function apply(ctx, rawConfig) {
265
267
  });
266
268
  const acceptedSkillOps = validation.accepted.skillOps ?? [];
267
269
  const skippedUnread = filterUnreadSkillOps(acceptedSkillOps, new Set([...collectReadSkillNames(session), ...childReads]));
268
- const executed = await executePlan(validation.accepted, session.id);
270
+ const executed = await executePlan(validation.accepted, session);
269
271
  const actions = executed.actions;
270
272
  const evidenceQuotes = [...validation.accepted.memoryOps ?? [], ...acceptedSkillOps].reduce((total, op) => total + (Array.isArray(op.evidence) ? op.evidence.length : 0), 0);
271
273
  if (actions.length > 0) {
@@ -343,7 +345,8 @@ function apply(ctx, rawConfig) {
343
345
  reviewInFlight = false;
344
346
  }
345
347
  }
346
- async function executePlan(plan, sessionId) {
348
+ async function executePlan(plan, session) {
349
+ const sessionId = session?.id;
347
350
  const memory = ctx.get("memory");
348
351
  const approval = ctx.get("evolutionApproval");
349
352
  const origins = resolveOrigins(void 0, true);
@@ -359,7 +362,7 @@ function apply(ctx, rawConfig) {
359
362
  facts: op.facts ?? op.content,
360
363
  old_text: op.old_text
361
364
  };
362
- const result = approval ? await runApproved("memory", `memory ${normalized.target} ${normalized.action}`, normalized, normalized) : await memory?.applyBatch(normalized.target, [normalized]);
365
+ const result = approval ? await runApproved("memory", `memory ${normalized.target} ${normalized.action}`, normalized, normalized, session) : await memory?.applyBatch(normalized.target, [normalized]);
363
366
  if (result?.ok) actions.push("Memory updated");
364
367
  else {
365
368
  ok = false;
@@ -376,7 +379,7 @@ function apply(ctx, rawConfig) {
376
379
  operation: args,
377
380
  origin: origins.library
378
381
  };
379
- const result = approval ? await runApproved("skill", `skill ${op.action ?? "patch"} ${op.name}`, runnerArgs, runnerArgs) : await executeSkillDirect(args);
382
+ const result = approval ? await runApproved("skill", `skill ${op.action ?? "patch"} ${op.name}`, runnerArgs, runnerArgs, session) : await executeSkillDirect(args);
380
383
  if (result?.ok) actions.push(`Skill ${op.name} ${op.action ?? "patch"}`);
381
384
  else {
382
385
  ok = false;
@@ -399,7 +402,7 @@ function apply(ctx, rawConfig) {
399
402
  aborted: reason
400
403
  };
401
404
  }
402
- async function runApproved(kind, summary, stored, runnerArgs) {
405
+ async function runApproved(kind, summary, stored, runnerArgs, approvalSession) {
403
406
  if (!approval) return void 0;
404
407
  if (approval.isEnabled === true && !approval.hasRunner(kind)) {
405
408
  ctx.logger.warn(`dsh-evolution-review: approval enabled but no replay runner registered for kind "${kind}" - skipping write (${summary})`);
@@ -413,7 +416,8 @@ function apply(ctx, rawConfig) {
413
416
  summary,
414
417
  args: stored,
415
418
  origin: origins.approval,
416
- ...sessionId ? { sessionId } : {}
419
+ ...sessionId ? { sessionId } : {},
420
+ ...approvalSession ? { session: approvalSession } : {}
417
421
  });
418
422
  if (decision.action === "staged") return {
419
423
  ok: false,
@@ -32,6 +32,11 @@ export interface Config {
32
32
  skillReviewTrigger?: string;
33
33
  /** Cumulative session tool calls before a session counts as proven-long for the completion channel. */
34
34
  skillReviewCompletionMinToolCalls?: number;
35
+ /** 0.3.40: deliver the deferred review with a WAKING inject for a summary the
36
+ * model starts immediately (agent.followup — same send() queue, wakeup bit
37
+ * differs). Default true; false degrades to the non-waking inject (the
38
+ * summary then waits for the next driver wake). */
39
+ reviewWakeInject?: boolean;
35
40
  }
36
41
  export declare const Config: z<Config>;
37
42
  /**
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.38",
4
+ "version": "0.3.40",
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.38",
35
- "@lmzhen/dsh-evolution-core": "^0.3.38",
36
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.38"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.40",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.40",
36
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.40"
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.38",
46
- "@lmzhen/dsh-evolution-policy": "^0.3.38"
45
+ "@lmzhen/dsh-evolution-state": "^0.3.40",
46
+ "@lmzhen/dsh-evolution-policy": "^0.3.40"
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.38",
58
- "@lmzhen/dsh-evolution-core": "^0.3.38",
59
- "@lmzhen/dsh-evolution-plan-validator": "^0.3.38",
60
- "@lmzhen/dsh-evolution-state": "^0.3.38"
57
+ "@lmzhen/dsh-evolution-approval": "^0.3.40",
58
+ "@lmzhen/dsh-evolution-core": "^0.3.40",
59
+ "@lmzhen/dsh-evolution-plan-validator": "^0.3.40",
60
+ "@lmzhen/dsh-evolution-state": "^0.3.40"
61
61
  }
62
62
  }