@lmzhen/dsh-evolution-plan-validator 0.1.0-rc.9 → 0.2.0-rc.1
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 +18 -5
- package/lib/types/index.d.ts +7 -0
- package/package.json +5 -4
package/lib/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_MAX_OPS_PER_PLAN, DEFAULT_MEMORY_CHAR_LIMIT, DEFAULT_SKILL_CONTENT_CHARS, DEFAULT_USER_CHAR_LIMIT, MAX_RESTRUCTURE_MOVES, RESTRUCTURE_TARGET_RE } from "@lmzhen/dsh-evolution-core";
|
|
1
2
|
//#region lib/types/index.js
|
|
2
3
|
/**
|
|
3
4
|
* Deterministic validator for model-produced evolution plans.
|
|
@@ -16,7 +17,8 @@ const SKILL_ACTIONS = new Set([
|
|
|
16
17
|
"patch",
|
|
17
18
|
"delete",
|
|
18
19
|
"write_file",
|
|
19
|
-
"remove_file"
|
|
20
|
+
"remove_file",
|
|
21
|
+
"restructure"
|
|
20
22
|
]);
|
|
21
23
|
const FORBIDDEN_KEYS = [
|
|
22
24
|
"policy",
|
|
@@ -30,12 +32,12 @@ function hasValidEvidence(evidence, sessionSeq) {
|
|
|
30
32
|
return evidence.every((item) => {
|
|
31
33
|
if (!item || typeof item !== "object") return false;
|
|
32
34
|
const record = item;
|
|
33
|
-
const seq = typeof record.event_seq === "number" ? record.event_seq : typeof record.seq === "number" ? record.seq : Number(record.event_seq);
|
|
35
|
+
const seq = typeof record.event_seq === "number" ? record.event_seq : typeof record.seq === "number" ? record.seq : typeof record.event_seq === "string" && /^\d+$/.test(record.event_seq) ? Number(record.event_seq) : -1;
|
|
34
36
|
return Number.isInteger(seq) && seq >= 0 && seq <= sessionSeq;
|
|
35
37
|
});
|
|
36
38
|
}
|
|
37
39
|
function validateEvolutionPlan(plan, context) {
|
|
38
|
-
const maxOps = context.maxOpsPerPlan ??
|
|
40
|
+
const maxOps = context.maxOpsPerPlan ?? DEFAULT_MAX_OPS_PER_PLAN;
|
|
39
41
|
const rejected = [];
|
|
40
42
|
const memoryOps = [];
|
|
41
43
|
const skillOps = [];
|
|
@@ -102,7 +104,7 @@ function validateMemoryOp(op, context, index) {
|
|
|
102
104
|
const text = (op.facts ?? op.content ?? "").trim();
|
|
103
105
|
if (action !== "remove" && text.length === 0) return `memory op ${index}: ${action} requires facts/content`;
|
|
104
106
|
if (action !== "add" && !(op.old_text ?? "").trim()) return `memory op ${index}: ${action} requires old_text`;
|
|
105
|
-
const budget = op.target === "user" ? context.maxUserChars ??
|
|
107
|
+
const budget = op.target === "user" ? context.maxUserChars ?? DEFAULT_USER_CHAR_LIMIT : context.maxMemoryChars ?? DEFAULT_MEMORY_CHAR_LIMIT;
|
|
106
108
|
if (text.length > budget) return `memory op ${index}: content exceeds ${op.target === "user" ? "user" : "memory"} budget`;
|
|
107
109
|
return null;
|
|
108
110
|
}
|
|
@@ -116,7 +118,18 @@ function validateSkillOp(op, context, index) {
|
|
|
116
118
|
if (!SKILL_ACTIONS.has(action)) return `skill op ${index}: unknown action ${action}`;
|
|
117
119
|
if ((action === "create" || action === "edit" || action === "update") && !(op.content ?? "").trim()) return `skill op ${index}: ${action} requires content`;
|
|
118
120
|
if (action === "patch" && !(op.old_string ?? "")) return `skill op ${index}: patch requires old_string`;
|
|
119
|
-
if (
|
|
121
|
+
if (action === "delete" && !(op.absorbed_into ?? "").trim()) return `skill op ${index}: delete requires absorbed_into`;
|
|
122
|
+
const writeContent = op.file_content ?? op.content ?? "";
|
|
123
|
+
if (action === "write_file" && !writeContent.trim()) return `skill op ${index}: write_file requires file_content`;
|
|
124
|
+
if (writeContent.length > (context.maxSkillContentChars ?? DEFAULT_SKILL_CONTENT_CHARS)) return `skill op ${index}: content exceeds skill budget`;
|
|
125
|
+
if (action === "restructure") {
|
|
126
|
+
if (!Array.isArray(op.restructure) || op.restructure.length === 0) return `skill op ${index}: restructure requires a non-empty restructure list`;
|
|
127
|
+
if (op.restructure.length > MAX_RESTRUCTURE_MOVES) return `skill op ${index}: restructure exceeds ${MAX_RESTRUCTURE_MOVES} moves`;
|
|
128
|
+
for (const [moveIndex, move] of op.restructure.entries()) {
|
|
129
|
+
if (!move || typeof move.heading !== "string" || !move.heading.trim()) return `skill op ${index}: restructure[${moveIndex}] requires a non-empty heading`;
|
|
130
|
+
if (typeof move.to_file !== "string" || !RESTRUCTURE_TARGET_RE.test(move.to_file)) return `skill op ${index}: restructure[${moveIndex}] to_file must be references/<topic>.md`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
120
133
|
return null;
|
|
121
134
|
}
|
|
122
135
|
//#endregion
|
package/lib/types/index.d.ts
CHANGED
|
@@ -15,10 +15,17 @@ export interface SkillOp {
|
|
|
15
15
|
action?: string;
|
|
16
16
|
name?: string;
|
|
17
17
|
content?: string;
|
|
18
|
+
/** write_file payload (the tool reads `file_content`, not `content`). */
|
|
19
|
+
file_content?: string;
|
|
18
20
|
old_string?: string;
|
|
19
21
|
new_string?: string;
|
|
20
22
|
file_path?: string;
|
|
21
23
|
absorbed_into?: string;
|
|
24
|
+
/** restructure payload: body sections moved to references/ (008 batch B). */
|
|
25
|
+
restructure?: Array<{
|
|
26
|
+
heading?: string;
|
|
27
|
+
to_file?: string;
|
|
28
|
+
} | null>;
|
|
22
29
|
evidence?: unknown[];
|
|
23
30
|
}
|
|
24
31
|
export interface EvolutionPlan {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lmzhen/dsh-evolution-plan-validator",
|
|
3
3
|
"description": "Deterministic validator for model-produced evolution plans (community build)",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0-rc.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,13 +32,14 @@
|
|
|
32
32
|
],
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@deepseek-ai/schemastery": "^3.18.1"
|
|
35
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
36
|
+
"@lmzhen/dsh-evolution-core": "^0.2.0-rc.1"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
38
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
39
|
+
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
39
40
|
"@deepseek-ai/cordis": "^4.0.1"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
43
|
+
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2"
|
|
43
44
|
}
|
|
44
45
|
}
|