@lmzhen/dsh-tool-skill-manage 0.1.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/README.md +24 -0
- package/lib/index.js +158 -0
- package/lib/invariant.js +8 -0
- package/lib/types/index.d.ts +24 -0
- package/lib/types/invariant.d.ts +5 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-tool-skill-manage
|
|
2
|
+
|
|
3
|
+
Model-facing skill_manage tool
|
|
4
|
+
|
|
5
|
+
## Model Experience
|
|
6
|
+
|
|
7
|
+
### skill_manage tool surface
|
|
8
|
+
|
|
9
|
+
#### What the model sees
|
|
10
|
+
|
|
11
|
+
The model sees the `skill_manage` tool schema and tool results containing success or validation messages.
|
|
12
|
+
|
|
13
|
+
#### Token effect
|
|
14
|
+
|
|
15
|
+
Adds the `skill_manage` tool schema to the request catalog; result tokens scale with returned messages.
|
|
16
|
+
|
|
17
|
+
#### KV Cache effect
|
|
18
|
+
|
|
19
|
+
Tool schema is prefix-stable. Skill writes do not alter the current request prompt; catalog invalidation affects the next request.
|
|
20
|
+
|
|
21
|
+
## Known Limitations and Deferred Work
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
- No known durable consumer gaps at this time. Runtime contracts are covered by package and boundary tests.
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
3
|
+
import { DEFAULT_SKILL_LIMITS, SkillLibrary, evolutionIoAdapter } from "@lmzhen/dsh-evolution-core";
|
|
4
|
+
//#region lib/types/index.js
|
|
5
|
+
/**
|
|
6
|
+
* Model-facing skill_manage tool over ctx.evolutionIo + ctx.skillUsage.
|
|
7
|
+
*
|
|
8
|
+
* Mutations pass through the evolution approval seam when it is mounted;
|
|
9
|
+
* approved/staged background writes are replayed by the registered runner.
|
|
10
|
+
* The skill library itself never hard-deletes: archive is the maximum
|
|
11
|
+
* destructive action and every curator mutation is snapshot-reversible.
|
|
12
|
+
* @module @lmzhen/dsh-tool-skill-manage
|
|
13
|
+
*/
|
|
14
|
+
const name = "tool-skill-manage";
|
|
15
|
+
const inject = [
|
|
16
|
+
"tools",
|
|
17
|
+
"skillUsage",
|
|
18
|
+
"evolutionIo"
|
|
19
|
+
];
|
|
20
|
+
const Config = z.object({
|
|
21
|
+
root: z.string().default(""),
|
|
22
|
+
maxSkillNameLength: z.number().default(DEFAULT_SKILL_LIMITS.maxNameLength),
|
|
23
|
+
maxDescriptionLength: z.number().default(DEFAULT_SKILL_LIMITS.maxDescriptionLength),
|
|
24
|
+
maxSkillContentChars: z.number().default(DEFAULT_SKILL_LIMITS.maxSkillContentChars),
|
|
25
|
+
maxSkillFileBytes: z.number().default(DEFAULT_SKILL_LIMITS.maxSkillFileBytes)
|
|
26
|
+
});
|
|
27
|
+
function apply(ctx, rawConfig = {}) {
|
|
28
|
+
const io = evolutionIoAdapter(() => ctx.evolutionIo.provider());
|
|
29
|
+
const library = new SkillLibrary(rawConfig.root || void 0, io, {
|
|
30
|
+
maxNameLength: rawConfig.maxSkillNameLength ?? DEFAULT_SKILL_LIMITS.maxNameLength,
|
|
31
|
+
maxDescriptionLength: rawConfig.maxDescriptionLength ?? DEFAULT_SKILL_LIMITS.maxDescriptionLength,
|
|
32
|
+
maxSkillContentChars: rawConfig.maxSkillContentChars ?? DEFAULT_SKILL_LIMITS.maxSkillContentChars,
|
|
33
|
+
maxSkillFileBytes: rawConfig.maxSkillFileBytes ?? DEFAULT_SKILL_LIMITS.maxSkillFileBytes
|
|
34
|
+
});
|
|
35
|
+
async function executeCore(args, origin = "foreground") {
|
|
36
|
+
const action = args.action;
|
|
37
|
+
const name = args.name ?? "";
|
|
38
|
+
if (action === "list") {
|
|
39
|
+
const list = await library.list();
|
|
40
|
+
return {
|
|
41
|
+
ok: true,
|
|
42
|
+
message: `Listed ${list.length} skills.`,
|
|
43
|
+
skills: list.map((s) => s.name)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
let result;
|
|
47
|
+
if (action === "create") result = await library.create(name, args.content ?? "", origin);
|
|
48
|
+
else if (action === "edit" || action === "update") result = await library.update(name, args.content ?? "");
|
|
49
|
+
else if (action === "patch") result = await library.patch(name, args.old_string ?? "", args.new_string ?? "", args.file_path ?? "", args.replace_all === true);
|
|
50
|
+
else if (action === "delete") result = await library.archive(name, args.absorbed_into ?? "");
|
|
51
|
+
else if (action === "write_file") result = await library.writeSupportFile(name, args.file_path ?? "", args.file_content ?? "");
|
|
52
|
+
else if (action === "remove_file") result = await library.removeSupportFile(name, args.file_path ?? "");
|
|
53
|
+
else result = {
|
|
54
|
+
ok: false,
|
|
55
|
+
message: `Unknown action "${action}".`
|
|
56
|
+
};
|
|
57
|
+
if (result.ok) {
|
|
58
|
+
if (name && action === "create" && origin === "background_review") await ctx.skillUsage.markAgentCreated(name);
|
|
59
|
+
if (name && action !== "list") await ctx.skillUsage.record(name, "patch");
|
|
60
|
+
ctx.emit("evolution/skill-mutated", {
|
|
61
|
+
action: action ?? "?",
|
|
62
|
+
name,
|
|
63
|
+
...result.path && action === "delete" ? { archivedPath: result.path } : result.path ? { filePath: result.path } : {}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
ok: result.ok,
|
|
68
|
+
message: result.message,
|
|
69
|
+
skills: []
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
ctx.tools.register(defineTool({
|
|
73
|
+
name: "skill_manage",
|
|
74
|
+
description: "Manage reusable skills. create/edit take full SKILL.md content; patch applies old_string -> new_string; delete archives to .archive. Protected bundled/hub skills reject mutation; pinned skills reject delete only. Prefer patching an umbrella over creating narrow skills.",
|
|
75
|
+
parameters: {
|
|
76
|
+
action: {
|
|
77
|
+
type: "string",
|
|
78
|
+
required: true,
|
|
79
|
+
enum: [
|
|
80
|
+
"create",
|
|
81
|
+
"edit",
|
|
82
|
+
"update",
|
|
83
|
+
"patch",
|
|
84
|
+
"delete",
|
|
85
|
+
"write_file",
|
|
86
|
+
"remove_file",
|
|
87
|
+
"list"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
name: { type: "string" },
|
|
91
|
+
content: { type: "string" },
|
|
92
|
+
old_string: { type: "string" },
|
|
93
|
+
new_string: { type: "string" },
|
|
94
|
+
replace_all: { type: "boolean" },
|
|
95
|
+
file_path: { type: "string" },
|
|
96
|
+
file_content: { type: "string" },
|
|
97
|
+
absorbed_into: { type: "string" }
|
|
98
|
+
},
|
|
99
|
+
output: {
|
|
100
|
+
schema: {
|
|
101
|
+
type: "object",
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
properties: {
|
|
104
|
+
ok: {
|
|
105
|
+
type: "boolean",
|
|
106
|
+
required: true
|
|
107
|
+
},
|
|
108
|
+
message: {
|
|
109
|
+
type: "string",
|
|
110
|
+
required: true
|
|
111
|
+
},
|
|
112
|
+
skills: {
|
|
113
|
+
type: "array",
|
|
114
|
+
required: true,
|
|
115
|
+
items: { type: "string" }
|
|
116
|
+
},
|
|
117
|
+
pending_id: { type: "string" }
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
render: (_args, value) => [{
|
|
121
|
+
type: "text",
|
|
122
|
+
text: `${value.ok ? "OK" : "Error"}: ${value.message}`
|
|
123
|
+
}]
|
|
124
|
+
},
|
|
125
|
+
isConcurrencySafe: () => false,
|
|
126
|
+
async execute(args, exec) {
|
|
127
|
+
const origin = exec.agent?.session.header.origin === "subagent" ? "background_review" : "foreground";
|
|
128
|
+
const approval = ctx.get("evolutionApproval");
|
|
129
|
+
if (approval && args.action !== "list") {
|
|
130
|
+
const decision = await approval.request({
|
|
131
|
+
kind: "skill",
|
|
132
|
+
summary: `skill ${args.action ?? "?"} ${args.name ?? ""}`.trim(),
|
|
133
|
+
args: {
|
|
134
|
+
operation: args,
|
|
135
|
+
origin
|
|
136
|
+
},
|
|
137
|
+
origin
|
|
138
|
+
});
|
|
139
|
+
if (decision.action === "staged") return {
|
|
140
|
+
ok: true,
|
|
141
|
+
message: decision.message,
|
|
142
|
+
skills: [],
|
|
143
|
+
pending_id: decision.pendingId ?? ""
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return await executeCore(args, origin);
|
|
147
|
+
}
|
|
148
|
+
}));
|
|
149
|
+
ctx.inject(["evolutionApproval"], (approvalCtx) => {
|
|
150
|
+
const dispose = approvalCtx.evolutionApproval.registerRunner("skill", (args) => {
|
|
151
|
+
const wrapped = args ?? {};
|
|
152
|
+
return executeCore(wrapped.operation ?? {}, wrapped.origin ?? "background_review");
|
|
153
|
+
});
|
|
154
|
+
approvalCtx.effect(() => dispose, "tool-skill-manage.approval-runner");
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
export { Config, apply, inject, name };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
const PACKAGE_NAME = "@deepseek-ai/dsh-tool-skill-manage";
|
|
3
|
+
const name = "tool-skill-manage-invariant";
|
|
4
|
+
const inject = ["invariants"];
|
|
5
|
+
const install = () => {};
|
|
6
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
7
|
+
//#endregion
|
|
8
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing skill_manage tool over ctx.evolutionIo + ctx.skillUsage.
|
|
3
|
+
*
|
|
4
|
+
* Mutations pass through the evolution approval seam when it is mounted;
|
|
5
|
+
* approved/staged background writes are replayed by the registered runner.
|
|
6
|
+
* The skill library itself never hard-deletes: archive is the maximum
|
|
7
|
+
* destructive action and every curator mutation is snapshot-reversible.
|
|
8
|
+
* @module @deepseek-ai/dsh-tool-skill-manage
|
|
9
|
+
*/
|
|
10
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import z from '@deepseek-ai/schemastery';
|
|
12
|
+
export declare const name = "tool-skill-manage";
|
|
13
|
+
export declare const inject: string[];
|
|
14
|
+
export interface Config {
|
|
15
|
+
/** Skill tree root; empty uses $DSH_HOME/skills. Align with skill-usage/catalog rows. */
|
|
16
|
+
root?: string;
|
|
17
|
+
maxSkillNameLength?: number;
|
|
18
|
+
maxDescriptionLength?: number;
|
|
19
|
+
maxSkillContentChars?: number;
|
|
20
|
+
maxSkillFileBytes?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare const Config: z<Config>;
|
|
23
|
+
export declare function apply(ctx: Context, rawConfig?: Config): void;
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lmzhen/dsh-tool-skill-manage",
|
|
3
|
+
"description": "Model-facing skill_manage tool (community build)",
|
|
4
|
+
"version": "0.1.0-rc.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/lmzhen/dsh-evolution.git",
|
|
11
|
+
"directory": "packages/dsh-tool-skill-manage"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"lib/index.js",
|
|
29
|
+
"lib/invariant.js",
|
|
30
|
+
"lib/types/**/*.d.ts",
|
|
31
|
+
"lib/types/invariant.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@deepseek-ai/schemastery": "^3.18.1",
|
|
36
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.1"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
40
|
+
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
|
|
41
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
42
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.1",
|
|
43
|
+
"@lmzhen/dsh-skill-usage": "^0.1.0-rc.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@deepseek-ai/dsh-agent-loop-testkit": "^0.1.0-rc.6",
|
|
47
|
+
"@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
|
|
48
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
49
|
+
"@lmzhen/dsh-evolution-core": "^0.1.0-rc.1",
|
|
50
|
+
"@lmzhen/dsh-evolution-io": "^0.1.0-rc.1",
|
|
51
|
+
"@lmzhen/dsh-skill-usage": "^0.1.0-rc.1"
|
|
52
|
+
}
|
|
53
|
+
}
|