@lmzhen/dsh-evolution-review 0.5.0 → 0.6.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/README.md +4 -0
- package/lib/index.js +54 -13
- package/lib/types/index.d.ts +29 -1
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -33,6 +33,10 @@ own, and the delivery mode lives on the `evolution-policy` row, not here.
|
|
|
33
33
|
- `reviewToolAllow`: the allow-list review subagents are spawned with (default `[skill]`).
|
|
34
34
|
- `reviewWakeInject` (default `true`): waking (`agent.followup`) delivery instead of the non-waking `agent.inject`.
|
|
35
35
|
- `skillReviewTrigger` (`'cadence'` default, or `'completion'` / `'both'`): gates only the completion channel.
|
|
36
|
+
- Deprecated names (G0/S0.3): `memoryInterval` and `skillInterval` are the legacy
|
|
37
|
+
spellings of the policy row's `reviewMemoryInterval` / `reviewSkillInterval`
|
|
38
|
+
(the snapshot shadows them in every shipped composition). Reading them still
|
|
39
|
+
works; writing them is refused, and both are removed in 0.7.0.
|
|
36
40
|
|
|
37
41
|
### Review delivery contract
|
|
38
42
|
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
4
4
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
5
|
-
import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, 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_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_USER_CHAR_LIMIT, MAX_TIMER_DELAY_MS, PROMPT_BUNDLE, advanceReview, assertSkillsRootAliasRetired, clampedNumber, clearReviewChannel, contentHash, evolutionIoAdapter, foldToolDispatches, foldTurn, markReviewChannel, newSkillLibrary, policyStageLimits, readDispatchSignal, redactSecrets, resolveOrigins, resolveRootConfig, reviewPrompt, sessionAudited, skillReadNameOf, sweepReviewChannelSessions, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
5
|
+
import { COMPLETION_SKILL_REVIEW_PROMPT, DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_MEMORY_REVIEW_MODEL, 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_LIMITS, DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS, DEFAULT_SKILL_REVIEW_MODEL, DEFAULT_SKILL_REVIEW_TRIGGER, DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS, DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS, DEFAULT_SUBSTANTIVE_MIN_USER_CHARS, DEFAULT_USER_CHAR_LIMIT, MAX_TIMER_DELAY_MS, PARAM_NAMESPACES, PROMPT_BUNDLE, advanceReview, assertSkillsRootAliasRetired, clampedNumber, clearReviewChannel, contentHash, evolutionIoAdapter, foldToolDispatches, foldTurn, installParamSection, markReviewChannel, newSkillLibrary, policyStageLimits, readDispatchSignal, readNumberParam, redactSecrets, resolveOrigins, resolveRootConfig, reviewPrompt, sessionAudited, skillReadNameOf, sweepReviewChannelSessions, verifyPromptBundle } from "@lmzhen/dsh-evolution-core";
|
|
6
6
|
import { validateEvolutionPlan } from "@lmzhen/dsh-evolution-plan-validator";
|
|
7
7
|
//#region lib/types/session-state.js
|
|
8
8
|
/**
|
|
@@ -138,8 +138,8 @@ function clampReviewConfig(rawConfig, ctx) {
|
|
|
138
138
|
return result;
|
|
139
139
|
};
|
|
140
140
|
const config = Object.assign({}, rawConfig, {
|
|
141
|
-
memoryInterval: field("memoryInterval", rawConfig
|
|
142
|
-
skillInterval: field("skillInterval", rawConfig
|
|
141
|
+
memoryInterval: field("memoryInterval", readNumberParam(rawConfig, "reviewMemoryInterval"), DEFAULT_REVIEW_MEMORY_INTERVAL, 1),
|
|
142
|
+
skillInterval: field("skillInterval", readNumberParam(rawConfig, "reviewSkillInterval"), DEFAULT_REVIEW_SKILL_INTERVAL, 1),
|
|
143
143
|
reviewTimeoutMs: field("reviewTimeoutMs", rawConfig.reviewTimeoutMs, DEFAULT_REVIEW_TIMEOUT_MS, 1, MAX_TIMER_DELAY_MS),
|
|
144
144
|
reviewContextMessages: field("reviewContextMessages", rawConfig.reviewContextMessages, DEFAULT_REVIEW_CONTEXT_MESSAGES, 1),
|
|
145
145
|
reviewMessageChars: field("reviewMessageChars", rawConfig.reviewMessageChars, DEFAULT_REVIEW_MESSAGE_CHARS, 1),
|
|
@@ -152,6 +152,23 @@ function clampReviewConfig(rawConfig, ctx) {
|
|
|
152
152
|
function policySnapshotOf(source) {
|
|
153
153
|
return source?.get?.();
|
|
154
154
|
}
|
|
155
|
+
/** Namespace the review group's user-writable knobs live in (core's PARAM_NAMESPACES). */
|
|
156
|
+
const REVIEW_SETTINGS_NAMESPACE = "evolution-review";
|
|
157
|
+
/** Schema the platform validates the user layer against; defaults mirror the
|
|
158
|
+
* core constants so an empty document resolves to today's behaviour. */
|
|
159
|
+
const REVIEW_SETTINGS_SCHEMA = z.object({
|
|
160
|
+
reviewSkillInterval: z.number().min(1).default(DEFAULT_REVIEW_SKILL_INTERVAL),
|
|
161
|
+
reviewMemoryInterval: z.number().min(1).default(DEFAULT_REVIEW_MEMORY_INTERVAL),
|
|
162
|
+
skillReviewTrigger: z.union([
|
|
163
|
+
z.const("cadence"),
|
|
164
|
+
z.const("completion"),
|
|
165
|
+
z.const("both")
|
|
166
|
+
]).default(DEFAULT_SKILL_REVIEW_TRIGGER),
|
|
167
|
+
skillReviewCompletionMinToolCalls: z.number().min(1).default(DEFAULT_SKILL_REVIEW_COMPLETION_MIN_TOOL_CALLS),
|
|
168
|
+
reviewEnabled: z.boolean().default(true),
|
|
169
|
+
reviewMode: z.union([z.const("subagent"), z.const("inject")]).default("inject"),
|
|
170
|
+
reviewWakeInject: z.boolean().default(true)
|
|
171
|
+
});
|
|
155
172
|
function apply(ctx, rawConfig = {}) {
|
|
156
173
|
if (!verifyPromptBundle(PROMPT_BUNDLE)) throw new Error("dsh-evolution prompt bundle integrity check failed; refusing to schedule review work");
|
|
157
174
|
const config = clampReviewConfig(rawConfig, ctx);
|
|
@@ -170,6 +187,30 @@ function apply(ctx, rawConfig = {}) {
|
|
|
170
187
|
const cadenceResetWarned = sessionState.add("cadenceResetWarned", /* @__PURE__ */ new Set());
|
|
171
188
|
let reviewInFlight = false;
|
|
172
189
|
const policy = () => ctx.get("evolutionPolicy")?.get();
|
|
190
|
+
const settingsBase = {
|
|
191
|
+
reviewSkillInterval: config.skillInterval,
|
|
192
|
+
reviewMemoryInterval: config.memoryInterval,
|
|
193
|
+
skillReviewTrigger: config.skillReviewTrigger ?? DEFAULT_SKILL_REVIEW_TRIGGER,
|
|
194
|
+
skillReviewCompletionMinToolCalls: config.skillReviewCompletionMinToolCalls,
|
|
195
|
+
reviewEnabled: config.reviewEnabled ?? true,
|
|
196
|
+
reviewMode: config.reviewMode ?? "inject",
|
|
197
|
+
reviewWakeInject: config.reviewWakeInject ?? true
|
|
198
|
+
};
|
|
199
|
+
const overrides = installParamSection(ctx, PARAM_NAMESPACES["evolution-review"] ?? "evolution-review", REVIEW_SETTINGS_SCHEMA, settingsBase, { warn: (message) => {
|
|
200
|
+
ctx.logger.warn("dsh-evolution-review: " + message);
|
|
201
|
+
} });
|
|
202
|
+
const params = () => {
|
|
203
|
+
const snapshot = policy();
|
|
204
|
+
return {
|
|
205
|
+
reviewSkillInterval: overrides.get("reviewSkillInterval") ?? snapshot?.reviewSkillInterval ?? config.skillInterval,
|
|
206
|
+
reviewMemoryInterval: overrides.get("reviewMemoryInterval") ?? snapshot?.reviewMemoryInterval ?? config.memoryInterval,
|
|
207
|
+
skillReviewTrigger: overrides.get("skillReviewTrigger") ?? config.skillReviewTrigger ?? DEFAULT_SKILL_REVIEW_TRIGGER,
|
|
208
|
+
skillReviewCompletionMinToolCalls: overrides.get("skillReviewCompletionMinToolCalls") ?? config.skillReviewCompletionMinToolCalls,
|
|
209
|
+
reviewEnabled: overrides.get("reviewEnabled") ?? config.reviewEnabled ?? true,
|
|
210
|
+
reviewMode: overrides.get("reviewMode") ?? snapshot?.reviewMode ?? config.reviewMode ?? "inject",
|
|
211
|
+
reviewWakeInject: overrides.get("reviewWakeInject") ?? config.reviewWakeInject ?? true
|
|
212
|
+
};
|
|
213
|
+
};
|
|
173
214
|
const schemaDefaults = Config["~standard"].validate({}).value;
|
|
174
215
|
const shadowedRowFields = [
|
|
175
216
|
"reviewMode",
|
|
@@ -188,7 +229,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
188
229
|
warnShadowed();
|
|
189
230
|
});
|
|
190
231
|
}
|
|
191
|
-
if ((
|
|
232
|
+
if (params().reviewMode === "inject") ctx.logger.warn("dsh-evolution-review: reviewMode \"inject\" (default) runs the review in the parent session and emits NO evolution/plan-applied ledger entry — evolution-activity and evolution-replay stay empty in this mode (see the evolution-review README, \"Known Limitations and Deferred Work\"). Set reviewMode: \"subagent\" on the evolution-policy row to keep the audited plan path.");
|
|
192
233
|
const reviewStateLocks = sessionState.add("reviewStateLocks", /* @__PURE__ */ new Map());
|
|
193
234
|
async function withReviewStateLock(id, task) {
|
|
194
235
|
const next = (reviewStateLocks.get(id) ?? Promise.resolve()).catch(() => {}).then(task);
|
|
@@ -237,7 +278,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
237
278
|
}
|
|
238
279
|
}
|
|
239
280
|
async function runOnTurnEnd(session, event) {
|
|
240
|
-
if (!
|
|
281
|
+
if (!params().reviewEnabled) return;
|
|
241
282
|
if (session.header.origin === "subagent") return;
|
|
242
283
|
const agent = ctx.agents.get(session.id);
|
|
243
284
|
if (!agent) return;
|
|
@@ -269,8 +310,8 @@ function apply(ctx, rawConfig = {}) {
|
|
|
269
310
|
lastTurn: -1
|
|
270
311
|
};
|
|
271
312
|
advanced.kind = advanceReview(state, event.data.turn, signal, {
|
|
272
|
-
memoryInterval:
|
|
273
|
-
skillInterval:
|
|
313
|
+
memoryInterval: params().reviewMemoryInterval,
|
|
314
|
+
skillInterval: params().reviewSkillInterval,
|
|
274
315
|
substantiveMinToolCalls: snapshot?.substantiveMinToolCalls ?? DEFAULT_SUBSTANTIVE_MIN_TOOL_CALLS,
|
|
275
316
|
substantiveMinUserChars: snapshot?.substantiveMinUserChars ?? DEFAULT_SUBSTANTIVE_MIN_USER_CHARS,
|
|
276
317
|
substantiveMinAgentChars: snapshot?.substantiveMinAgentChars ?? DEFAULT_SUBSTANTIVE_MIN_AGENT_CHARS,
|
|
@@ -285,7 +326,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
285
326
|
const pendingKind = kind ?? pendingCadenceReviews.get(session.id) ?? void 0;
|
|
286
327
|
if (pendingKind !== void 0) {
|
|
287
328
|
pendingCadenceReviews.delete(session.id);
|
|
288
|
-
if ((
|
|
329
|
+
if (params().reviewMode === "inject") {
|
|
289
330
|
if (!deliverMessage(agent, reviewPrompt(pendingKind), cadenceSummary(pendingKind), true)) {
|
|
290
331
|
pendingCadenceReviews.set(session.id, pendingKind);
|
|
291
332
|
return;
|
|
@@ -363,10 +404,10 @@ function apply(ctx, rawConfig = {}) {
|
|
|
363
404
|
return;
|
|
364
405
|
}
|
|
365
406
|
if (skipFire) return;
|
|
366
|
-
const trigger =
|
|
407
|
+
const trigger = params().skillReviewTrigger;
|
|
367
408
|
if (trigger !== "completion" && trigger !== "both") return;
|
|
368
409
|
if (completionInjected.has(session.id)) return;
|
|
369
|
-
if (!shouldCompletionReview(event.data.reason, cumulative,
|
|
410
|
+
if (!shouldCompletionReview(event.data.reason, cumulative, params().skillReviewCompletionMinToolCalls)) return;
|
|
370
411
|
completionInjected.add(session.id);
|
|
371
412
|
if (reviewInFlight) {
|
|
372
413
|
if (deferredFallbackReviews.length < DEFERRED_REVIEW_CAP) deferredFallbackReviews.push({
|
|
@@ -483,7 +524,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
483
524
|
ctx.logger.warn(`dsh-evolution-review: inbox coalescing failed (${error instanceof Error ? error.message : String(error)}) — delivering a fresh message instead`);
|
|
484
525
|
}
|
|
485
526
|
try {
|
|
486
|
-
if (
|
|
527
|
+
if (params().reviewWakeInject && typeof wake.followup === "function") {
|
|
487
528
|
wake.followup(message);
|
|
488
529
|
skipNextCadenceFire.set(agent.session.id, { afterTurn: lastTurnStart.get(agent.session.id) ?? -1 });
|
|
489
530
|
} else agent.inject(message);
|
|
@@ -557,7 +598,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
557
598
|
return hashes;
|
|
558
599
|
}
|
|
559
600
|
async function trySubagentReview(session, agent, kind, signal) {
|
|
560
|
-
if ((
|
|
601
|
+
if (params().reviewMode === "inject") return false;
|
|
561
602
|
const subagents = ctx.get("subagents");
|
|
562
603
|
if (!subagents) return false;
|
|
563
604
|
if (reviewInFlight) {
|
|
@@ -1232,4 +1273,4 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars)
|
|
|
1232
1273
|
].join("\n");
|
|
1233
1274
|
}
|
|
1234
1275
|
//#endregion
|
|
1235
|
-
export { Config, REVIEW_OUTPUT_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, renderToolResultLine, shouldCompletionReview, sweepDeadSessionEntries };
|
|
1276
|
+
export { Config, REVIEW_OUTPUT_SCHEMA, REVIEW_SETTINGS_NAMESPACE, REVIEW_SETTINGS_SCHEMA, apply, buildReviewRequest, clampReviewConfig, filterUnreadSkillOps, inject, name, renderToolResultLine, shouldCompletionReview, sweepDeadSessionEntries };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -24,8 +24,12 @@ export interface Config {
|
|
|
24
24
|
* row's value, which the plugin reports once at load (v37 P2-24). */
|
|
25
25
|
reviewMode?: 'subagent' | 'inject';
|
|
26
26
|
/** Shadowed by the policy snapshot in every shipped composition — configure
|
|
27
|
-
* `reviewMemoryInterval` on the `evolution-policy` row instead (v37 P2-24).
|
|
27
|
+
* `reviewMemoryInterval` on the `evolution-policy` row instead (v37 P2-24).
|
|
28
|
+
* Deprecated alias (G0/S0.3): still readable, refused by writes; removed 0.7.0. */
|
|
28
29
|
memoryInterval?: number;
|
|
30
|
+
/** Shadowed by the policy snapshot in every shipped composition — configure
|
|
31
|
+
* `reviewSkillInterval` on the `evolution-policy` row instead. Deprecated
|
|
32
|
+
* alias (G0/S0.3): still readable, refused by writes; removed 0.7.0. */
|
|
29
33
|
skillInterval?: number;
|
|
30
34
|
/**
|
|
31
35
|
* Tools the one-shot review subagent may use. Only actually-existing tools
|
|
@@ -125,6 +129,30 @@ type ClampedReviewConfig = Config & {
|
|
|
125
129
|
skillReviewCompletionMinToolCalls: number;
|
|
126
130
|
};
|
|
127
131
|
export declare function clampReviewConfig(rawConfig: Config, ctx: Context): ClampedReviewConfig;
|
|
132
|
+
/** Namespace the review group's user-writable knobs live in (core's PARAM_NAMESPACES). */
|
|
133
|
+
export declare const REVIEW_SETTINGS_NAMESPACE = "evolution-review";
|
|
134
|
+
/** Review behaviour a user may change (G3/S3.1). Field names are the CANONICAL
|
|
135
|
+
* parameter ids from the registry, so the settings document, the params output,
|
|
136
|
+
* the doctor report and the cards all spell one name. */
|
|
137
|
+
export interface ReviewSettings {
|
|
138
|
+
/** Activity units between skill-review injections. */
|
|
139
|
+
reviewSkillInterval: number;
|
|
140
|
+
/** Activity units between memory-review injections. */
|
|
141
|
+
reviewMemoryInterval: number;
|
|
142
|
+
/** Which channel may inject a skill review. */
|
|
143
|
+
skillReviewTrigger: 'cadence' | 'completion' | 'both';
|
|
144
|
+
/** Tool calls a task needs before the completion channel injects. */
|
|
145
|
+
skillReviewCompletionMinToolCalls: number;
|
|
146
|
+
/** Master switch for the review plugin. */
|
|
147
|
+
reviewEnabled: boolean;
|
|
148
|
+
/** Run the review in the parent session (inject) or on a subagent. */
|
|
149
|
+
reviewMode: 'subagent' | 'inject';
|
|
150
|
+
/** Deliver the deferred review as a waking follow-up message. */
|
|
151
|
+
reviewWakeInject: boolean;
|
|
152
|
+
}
|
|
153
|
+
/** Schema the platform validates the user layer against; defaults mirror the
|
|
154
|
+
* core constants so an empty document resolves to today's behaviour. */
|
|
155
|
+
export declare const REVIEW_SETTINGS_SCHEMA: z<ReviewSettings>;
|
|
128
156
|
export declare function apply(ctx: Context, rawConfig?: Config): void;
|
|
129
157
|
/** Completion-channel decision: task finished normally AND the session is proven long. */
|
|
130
158
|
export declare function shouldCompletionReview(reason: {
|
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.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
30
|
-
"@lmzhen/dsh-evolution-approval": "^0.
|
|
31
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
32
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.
|
|
30
|
+
"@lmzhen/dsh-evolution-approval": "^0.6.0",
|
|
31
|
+
"@lmzhen/dsh-evolution-core": "^0.6.0",
|
|
32
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.6.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
|
|
38
38
|
"@deepseek-ai/dsh-session": "^0.1.5-rc.2",
|
|
39
39
|
"@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
|
|
40
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
41
|
-
"@lmzhen/dsh-evolution-policy": "^0.
|
|
40
|
+
"@lmzhen/dsh-evolution-state": "^0.6.0",
|
|
41
|
+
"@lmzhen/dsh-evolution-policy": "^0.6.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.2",
|
|
49
49
|
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.5-rc.2",
|
|
50
50
|
"@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
|
|
51
|
-
"@lmzhen/dsh-evolution-approval": "^0.
|
|
52
|
-
"@lmzhen/dsh-evolution-core": "^0.
|
|
53
|
-
"@lmzhen/dsh-evolution-curator": "^0.
|
|
54
|
-
"@lmzhen/dsh-evolution-plan-validator": "^0.
|
|
55
|
-
"@lmzhen/dsh-evolution-state": "^0.
|
|
51
|
+
"@lmzhen/dsh-evolution-approval": "^0.6.0",
|
|
52
|
+
"@lmzhen/dsh-evolution-core": "^0.6.0",
|
|
53
|
+
"@lmzhen/dsh-evolution-curator": "^0.6.0",
|
|
54
|
+
"@lmzhen/dsh-evolution-plan-validator": "^0.6.0",
|
|
55
|
+
"@lmzhen/dsh-evolution-state": "^0.6.0"
|
|
56
56
|
}
|
|
57
57
|
}
|