@lmzhen/dsh-tool-skill-manage 0.3.68 → 0.3.70

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.
Files changed (2) hide show
  1. package/lib/index.js +57 -11
  2. package/package.json +15 -15
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { effectiveSessionPolicy } from "@lmzhen/dsh-evolution-approval";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { defineTool } from "@deepseek-ai/dsh-tools";
4
- import { DEFAULT_SKILL_LIMITS, DSH_AUTHORING_STANDARDS, SKILLS_GUIDANCE, SkillLibrary, authoringFeedback, clampedNumber, computeDedupGroups, contentHash, evolutionIoAdapter, parseFrontmatter, resolveOrigins, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
4
+ import { DEFAULT_SKILL_LIMITS, DSH_AUTHORING_STANDARDS, SKILLS_GUIDANCE, SKILLS_GUIDANCE_SECTION_ORDER, SkillLibrary, authoringFeedback, clampedNumber, computeDedupGroups, contentHash, evolutionIoAdapter, parseFrontmatter, resolveOrigins, resolveSkillsRoot } from "@lmzhen/dsh-evolution-core";
5
5
  //#region lib/types/index.js
6
6
  /**
7
7
  * Model-facing skill_manage tool over ctx.evolutionIo + ctx.skillUsage.
@@ -37,11 +37,17 @@ const Config = z.object({
37
37
  descriptionStrict: z.boolean().default(false),
38
38
  threatExemptLabels: z.array(z.string()).default([])
39
39
  });
40
+ /** v30 REV-02: read the protected-skill list off the (optional) policy
41
+ * snapshot through an `unknown` boundary — the Context augmentation types the
42
+ * getter non-optionally, but at runtime the row can be absent. */
43
+ function policySnapshotOf(source) {
44
+ return source?.get?.();
45
+ }
40
46
  function apply(ctx, rawConfig = {}) {
41
47
  const systemPrompt = ctx.get("systemPrompt");
42
48
  if (systemPrompt) ctx.effect(() => systemPrompt.section({
43
49
  name: "evolution-skills-guidance",
44
- order: 900,
50
+ order: SKILLS_GUIDANCE_SECTION_ORDER,
45
51
  text: SKILLS_GUIDANCE
46
52
  }), "tool-skill-manage.skills-guidance");
47
53
  const io = evolutionIoAdapter(() => ctx.evolutionIo.provider());
@@ -64,18 +70,32 @@ function apply(ctx, rawConfig = {}) {
64
70
  async function executeCore(args, origin = "foreground") {
65
71
  const action = args.action;
66
72
  const name = args.name ?? "";
67
- if (action === "review") return {
68
- ok: true,
69
- message: await buildSkillReviewText(),
70
- skills: []
71
- };
72
- if (action === "list") {
73
+ if (action === "review") try {
74
+ return {
75
+ ok: true,
76
+ message: await buildSkillReviewText(),
77
+ skills: []
78
+ };
79
+ } catch (error) {
80
+ return {
81
+ ok: false,
82
+ message: `skill_manage review: skill tree scan failed (${error instanceof Error ? error.message : String(error)}).`,
83
+ skills: []
84
+ };
85
+ }
86
+ if (action === "list") try {
73
87
  const list = await library.list();
74
88
  return {
75
89
  ok: true,
76
90
  message: `Listed ${list.length} skills.`,
77
91
  skills: list.map((s) => s.name)
78
92
  };
93
+ } catch (error) {
94
+ return {
95
+ ok: false,
96
+ message: `skill_manage list: skill tree scan failed (${error instanceof Error ? error.message : String(error)}).`,
97
+ skills: []
98
+ };
79
99
  }
80
100
  const scalarArgs = args;
81
101
  for (const field of [
@@ -94,7 +114,14 @@ function apply(ctx, rawConfig = {}) {
94
114
  skills: []
95
115
  };
96
116
  }
97
- const missing = (action === void 0 ? [] : {
117
+ if (origin !== "foreground") {
118
+ if ((policySnapshotOf(ctx.get("evolutionPolicy"))?.protectedSkillNames)?.includes(name)) return {
119
+ ok: false,
120
+ message: `skill_manage: "${name}" is protected by the current policy (protectedSkillNames); replayed/autonomous writes are refused.`,
121
+ skills: []
122
+ };
123
+ }
124
+ const REQUIRED_ARGS = {
98
125
  create: ["name", "content"],
99
126
  edit: ["name", "content"],
100
127
  update: ["name", "content"],
@@ -113,7 +140,8 @@ function apply(ctx, rawConfig = {}) {
113
140
  restructure: ["name"],
114
141
  pin: ["name"],
115
142
  unpin: ["name"]
116
- }[action] ?? []).filter((field) => scalarArgs[field] === void 0 || scalarArgs[field] === null);
143
+ };
144
+ const missing = (action === void 0 || typeof action !== "string" || !Object.hasOwn(REQUIRED_ARGS, action) ? [] : REQUIRED_ARGS[action] ?? []).filter((field) => scalarArgs[field] === void 0 || scalarArgs[field] === null);
117
145
  if (missing.length > 0) return {
118
146
  ok: false,
119
147
  message: `skill_manage ${action} requires ${missing.join(", ")}; the tool description lists the arguments per action.`,
@@ -129,6 +157,15 @@ function apply(ctx, rawConfig = {}) {
129
157
  skills: []
130
158
  };
131
159
  }
160
+ if ((action === "write_file" || action === "remove_file") && typeof args.staged_from_sha256 === "string" && args.staged_from_sha256 !== "") {
161
+ const currentBytes = await library.readSupportFile(name, args.file_path ?? "").catch(() => void 0);
162
+ const actual = currentBytes === void 0 || currentBytes === null ? "absent" : contentHash(currentBytes);
163
+ if (currentBytes === void 0 || actual !== args.staged_from_sha256) return {
164
+ ok: false,
165
+ message: `Support file "${args.file_path ?? ""}" of "${name}" changed after this write was staged (or its state could not be verified); refusing to replay the stale snapshot. Re-stage the file operation.`,
166
+ skills: []
167
+ };
168
+ }
132
169
  if ((action === "create" || action === "edit" || action === "update") && args.content) {
133
170
  const parsed = parseFrontmatter(args.content);
134
171
  if (parsed) {
@@ -194,7 +231,12 @@ function apply(ctx, rawConfig = {}) {
194
231
  const protection = summary.protectionUnknown ? " [protection:unknown]" : summary.protectedBy ? ` [${summary.protectedBy}]` : "";
195
232
  return `- ${summary.name} | ${record?.state ?? "active"} | use:${record?.use_count ?? 0} view:${record?.view_count ?? 0} patch:${record?.patch_count ?? 0}${quality}${protection}`;
196
233
  });
197
- const groups = computeDedupGroups({ contents: new Map(await Promise.all(list.map(async (summary) => [summary.name, await library.read(summary.name) ?? ""]))) });
234
+ const contents = /* @__PURE__ */ new Map();
235
+ for (let offset = 0; offset < list.length; offset += 16) await Promise.all(list.slice(offset, offset + 16).map(async (summary) => {
236
+ const body = await library.read(summary.name).catch(() => null);
237
+ contents.set(summary.name, body ?? "");
238
+ }));
239
+ const groups = computeDedupGroups({ contents });
198
240
  const dedupLines = groups.slice(0, MAX_DEDUP_GROUPS_IN_REVIEW).map((group) => `- ${group.join(" ~ ")}`);
199
241
  const warned = list.filter((summary) => warnedFlag(summary.name)).map((summary) => summary.name);
200
242
  const warningLine = warned.length === 0 ? "" : `\nWarning skills (${warned.length}): ${warned.join(", ")} — low quality; consider consolidating them before authoring new skills.`;
@@ -286,6 +328,10 @@ function apply(ctx, rawConfig = {}) {
286
328
  const stageCurrent = await library.read(args.name).catch(() => null);
287
329
  if (stageCurrent !== null) args.staged_from_sha256 = contentHash(stageCurrent);
288
330
  }
331
+ if ((args.action === "write_file" || args.action === "remove_file") && typeof args.name === "string" && args.name !== "" && typeof args.file_path === "string" && args.file_path !== "") {
332
+ const stageFile = await library.readSupportFile(args.name, args.file_path).catch(() => void 0);
333
+ if (stageFile !== void 0) args.staged_from_sha256 = stageFile === null ? "absent" : contentHash(stageFile);
334
+ }
289
335
  const decision = await approval.request({
290
336
  kind: "skill",
291
337
  summary: `skill ${args.action ?? "?"} ${args.name ?? ""}`.trim(),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-tool-skill-manage",
3
3
  "description": "Model-facing skill_manage tool (community build)",
4
- "version": "0.3.68",
4
+ "version": "0.3.70",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,24 +31,24 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
33
  "@deepseek-ai/schemastery": "^3.18.1",
34
- "@lmzhen/dsh-evolution-approval": "^0.3.68",
35
- "@lmzhen/dsh-evolution-core": "^0.3.68"
34
+ "@lmzhen/dsh-evolution-approval": "^0.3.70",
35
+ "@lmzhen/dsh-evolution-core": "^0.3.70"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@deepseek-ai/cordis": "^4.0.1",
39
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
40
- "@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.2",
41
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
42
- "@lmzhen/dsh-evolution-io": "^0.3.68",
43
- "@lmzhen/dsh-skill-usage": "^0.3.68"
39
+ "@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
40
+ "@deepseek-ai/dsh-system-prompt": "^0.1.5-rc.2",
41
+ "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
42
+ "@lmzhen/dsh-evolution-io": "^0.3.70",
43
+ "@lmzhen/dsh-skill-usage": "^0.3.70"
44
44
  },
45
45
  "devDependencies": {
46
- "@deepseek-ai/dsh-agent-loop-testkit": "^0.1.1-rc.2",
47
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
48
- "@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.2",
49
- "@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
50
- "@lmzhen/dsh-evolution-core": "^0.3.68",
51
- "@lmzhen/dsh-evolution-io": "^0.3.68",
52
- "@lmzhen/dsh-skill-usage": "^0.3.68"
46
+ "@deepseek-ai/dsh-agent-loop-testkit": "^0.1.5-rc.2",
47
+ "@deepseek-ai/dsh-invariants": "^0.1.5-rc.2",
48
+ "@deepseek-ai/dsh-system-prompt": "^0.1.5-rc.2",
49
+ "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
50
+ "@lmzhen/dsh-evolution-core": "^0.3.70",
51
+ "@lmzhen/dsh-evolution-io": "^0.3.70",
52
+ "@lmzhen/dsh-skill-usage": "^0.3.70"
53
53
  }
54
54
  }