@atoms-agent/skills 0.4.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/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/catalog.d.ts +12 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +406 -0
- package/dist/catalog.js.map +1 -0
- package/dist/frontmatter.d.ts +23 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +68 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +11 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +33 -0
- package/dist/limits.js.map +1 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +129 -0
- package/dist/paths.js.map +1 -0
- package/dist/tools.d.ts +32 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +132 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/utf8.d.ts +3 -0
- package/dist/utf8.d.ts.map +1 -0
- package/dist/utf8.js +13 -0
- package/dist/utf8.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 atoms_agent contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @atoms-agent/skills
|
|
2
|
+
|
|
3
|
+
Optional extension for `atoms_agent`: discover and lazily load local
|
|
4
|
+
Claude/Codex-style `SKILL.md` directories, then expose them through Core tools.
|
|
5
|
+
|
|
6
|
+
This package depends only on `@atoms-agent/core` public contracts. It does
|
|
7
|
+
**not** depend on `@atoms-agent/mcp`, does not execute skill scripts, and does
|
|
8
|
+
not implement marketplaces, plugin loaders, or sandboxes.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @atoms-agent/skills@0.4.0 @atoms-agent/core@0.4.0 @atoms-agent/llm@0.4.0
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { createAgent } from "@atoms-agent/core";
|
|
20
|
+
import type { ModelAdapter } from "@atoms-agent/llm";
|
|
21
|
+
import {
|
|
22
|
+
createSkillCatalog,
|
|
23
|
+
createSkillTools,
|
|
24
|
+
formatSkillCatalogPrompt,
|
|
25
|
+
} from "@atoms-agent/skills";
|
|
26
|
+
|
|
27
|
+
// Provide any ModelAdapter (OpenAI/Anthropic/ScriptedModel/etc).
|
|
28
|
+
declare const model: ModelAdapter;
|
|
29
|
+
|
|
30
|
+
const { catalog } = await createSkillCatalog({
|
|
31
|
+
roots: ["/absolute/path/to/skills-root"],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const skillTools = createSkillTools({ catalog });
|
|
35
|
+
const skillPrompt = formatSkillCatalogPrompt({ catalog });
|
|
36
|
+
|
|
37
|
+
const agent = createAgent({
|
|
38
|
+
model,
|
|
39
|
+
systemPrompt: `Use local skills when helpful.\n${skillPrompt}`,
|
|
40
|
+
tools: skillTools,
|
|
41
|
+
authorize: () => "allow",
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Host must pass explicit skill roots. `list_skills` / `load_skill` /
|
|
46
|
+
`read_skill_resource` are read-only and never execute `scripts/`.
|
|
47
|
+
|
|
48
|
+
For offline demos, install `@atoms-agent/testing` as a **dev** dependency and
|
|
49
|
+
pass `createScriptedModel(...)` as `model`.
|
|
50
|
+
|
|
51
|
+
Only import from the package root. Subpath / deep imports are not supported.
|
|
52
|
+
|
|
53
|
+
## Requirements
|
|
54
|
+
|
|
55
|
+
- Node.js >= 22.13
|
|
56
|
+
- ESM
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SkillCatalog, SkillCatalogDiagnostic, SkillRootConfig } from "./types.js";
|
|
2
|
+
export type CreateSkillCatalogResult = {
|
|
3
|
+
catalog: SkillCatalog;
|
|
4
|
+
diagnostics: readonly SkillCatalogDiagnostic[];
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* 从 Host 显式 Root 构建只读 Skill Catalog。
|
|
8
|
+
* 发现阶段只解析有界 Frontmatter;正文与资源按需加载。
|
|
9
|
+
* 永不执行 scripts/。
|
|
10
|
+
*/
|
|
11
|
+
export declare function createSkillCatalog(config: SkillRootConfig): Promise<CreateSkillCatalogResult>;
|
|
12
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAEV,YAAY,EACZ,sBAAsB,EAOtB,eAAe,EAEhB,MAAM,YAAY,CAAC;AAWpB,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChD,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,wBAAwB,CAAC,CAqMnC"}
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { open, readdir, stat } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { AtomsAgentError } from "@atoms-agent/core";
|
|
4
|
+
import { parseSkillMarkdown } from "./frontmatter.js";
|
|
5
|
+
import { resolveSkillLimits, estimateSkillTokens } from "./limits.js";
|
|
6
|
+
import { comparePathStable, resolvePathInsideRoot, resolveSkillRoot, toPosixPath, } from "./paths.js";
|
|
7
|
+
import { decodeUtf8Strict } from "./utf8.js";
|
|
8
|
+
/**
|
|
9
|
+
* 从 Host 显式 Root 构建只读 Skill Catalog。
|
|
10
|
+
* 发现阶段只解析有界 Frontmatter;正文与资源按需加载。
|
|
11
|
+
* 永不执行 scripts/。
|
|
12
|
+
*/
|
|
13
|
+
export async function createSkillCatalog(config) {
|
|
14
|
+
if (!Array.isArray(config.roots) || config.roots.length === 0) {
|
|
15
|
+
throw new AtomsAgentError("CONFIG_ERROR", "At least one skill root is required.");
|
|
16
|
+
}
|
|
17
|
+
const limits = resolveSkillLimits(config.limits);
|
|
18
|
+
if (config.roots.length > limits.maxRoots) {
|
|
19
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill roots exceed maxRoots (${limits.maxRoots}).`);
|
|
20
|
+
}
|
|
21
|
+
const duplicateNamePolicy = config.duplicateNamePolicy ?? "error";
|
|
22
|
+
if (duplicateNamePolicy !== "error" && duplicateNamePolicy !== "first-wins") {
|
|
23
|
+
throw new AtomsAgentError("CONFIG_ERROR", "duplicateNamePolicy must be error or first-wins.");
|
|
24
|
+
}
|
|
25
|
+
const diagnostics = [];
|
|
26
|
+
const entriesByName = new Map();
|
|
27
|
+
let totalBytes = 0;
|
|
28
|
+
for (const [rootIndex, rootPath] of config.roots.entries()) {
|
|
29
|
+
const rootReal = resolveSkillRoot(rootPath);
|
|
30
|
+
const skillDirs = await listSkillDirectories(rootReal, limits);
|
|
31
|
+
for (const skillDirReal of skillDirs) {
|
|
32
|
+
if (entriesByName.size >= limits.maxSkills) {
|
|
33
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill count exceeds maxSkills (${limits.maxSkills}).`);
|
|
34
|
+
}
|
|
35
|
+
const skillResolved = resolvePathInsideRoot(skillDirReal, "SKILL.md");
|
|
36
|
+
const sourceLabel = safeLocation(rootReal, skillDirReal);
|
|
37
|
+
// Catalog 阶段只读前缀:允许大正文文件存在,只要 Frontmatter 落在有界前缀内。
|
|
38
|
+
const frontmatterPrefix = await readFilePrefixBounded(skillResolved.real, limits.maxFrontmatterBytes + 64, "CONTEXT_LIMIT_ERROR", `Skill frontmatter exceeds maxFrontmatterBytes (${sourceLabel}).`);
|
|
39
|
+
totalBytes = addTotalBytes(totalBytes, frontmatterPrefix.byteLength, limits);
|
|
40
|
+
const parsed = parseSkillMarkdown(frontmatterPrefix.text, {
|
|
41
|
+
maxFrontmatterBytes: limits.maxFrontmatterBytes,
|
|
42
|
+
sourceLabel,
|
|
43
|
+
allowTruncatedBody: true,
|
|
44
|
+
});
|
|
45
|
+
const summary = Object.freeze({
|
|
46
|
+
name: parsed.name,
|
|
47
|
+
description: parsed.description,
|
|
48
|
+
location: sourceLabel,
|
|
49
|
+
rootIndex,
|
|
50
|
+
});
|
|
51
|
+
const existing = entriesByName.get(parsed.name);
|
|
52
|
+
if (existing !== undefined) {
|
|
53
|
+
if (duplicateNamePolicy === "error") {
|
|
54
|
+
throw new AtomsAgentError("CONFIG_ERROR", `Duplicate skill name "${parsed.name}" at ${existing.summary.location} and ${summary.location}.`);
|
|
55
|
+
}
|
|
56
|
+
diagnostics.push({
|
|
57
|
+
code: "DUPLICATE_SKILL_NAME",
|
|
58
|
+
skillName: parsed.name,
|
|
59
|
+
keptLocation: existing.summary.location,
|
|
60
|
+
skippedLocation: summary.location,
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
entriesByName.set(parsed.name, {
|
|
65
|
+
summary,
|
|
66
|
+
skillDirReal,
|
|
67
|
+
skillFileReal: skillResolved.real,
|
|
68
|
+
rootReal,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const ordered = [...entriesByName.values()].sort((a, b) => comparePathStable(a.summary.name, b.summary.name));
|
|
73
|
+
const summaries = Object.freeze(ordered.map((entry) => entry.summary));
|
|
74
|
+
const entries = new Map(ordered.map((entry) => [entry.summary.name, entry]));
|
|
75
|
+
const catalog = {
|
|
76
|
+
list() {
|
|
77
|
+
return summaries;
|
|
78
|
+
},
|
|
79
|
+
async loadSkill(name, options) {
|
|
80
|
+
throwIfAborted(options?.signal);
|
|
81
|
+
const entry = requireEntry(entries, name);
|
|
82
|
+
const sourceLabel = entry.summary.location;
|
|
83
|
+
// 再次校验 SKILL.md real path 仍在 skill 目录内(防 TOCTOU / 被替换为外链)。
|
|
84
|
+
const skillResolved = resolvePathInsideRoot(entry.skillDirReal, "SKILL.md");
|
|
85
|
+
const full = await readFileBounded(skillResolved.real, limits.maxFrontmatterBytes + limits.maxBodyBytes + 64, "CONTEXT_LIMIT_ERROR", `Skill document exceeds size limits (${sourceLabel}).`);
|
|
86
|
+
throwIfAborted(options?.signal);
|
|
87
|
+
const parsed = parseSkillMarkdown(full.text, {
|
|
88
|
+
maxFrontmatterBytes: limits.maxFrontmatterBytes,
|
|
89
|
+
sourceLabel,
|
|
90
|
+
});
|
|
91
|
+
const bodyBytes = Buffer.byteLength(parsed.body, "utf8");
|
|
92
|
+
if (bodyBytes > limits.maxBodyBytes) {
|
|
93
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill body exceeds maxBodyBytes (${sourceLabel}).`);
|
|
94
|
+
}
|
|
95
|
+
const tokenEstimate = estimateSkillTokens(parsed.body);
|
|
96
|
+
if (tokenEstimate > limits.maxEstimatedTokens) {
|
|
97
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill body exceeds maxEstimatedTokens (${sourceLabel}).`);
|
|
98
|
+
}
|
|
99
|
+
const resources = await listSkillResources(entry.skillDirReal, limits, options?.signal);
|
|
100
|
+
return Object.freeze({
|
|
101
|
+
summary: entry.summary,
|
|
102
|
+
body: parsed.body,
|
|
103
|
+
resources: Object.freeze(resources),
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
async readSkillResource(name, resourcePath, options) {
|
|
107
|
+
throwIfAborted(options?.signal);
|
|
108
|
+
const entry = requireEntry(entries, name);
|
|
109
|
+
const resolved = resolvePathInsideRoot(entry.skillDirReal, resourcePath);
|
|
110
|
+
let fileStat;
|
|
111
|
+
try {
|
|
112
|
+
fileStat = await stat(resolved.real);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
throw new AtomsAgentError("TOOL_EXECUTION_ERROR", "Skill resource does not exist.", {
|
|
116
|
+
cause: error,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
if (!fileStat.isFile()) {
|
|
120
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Skill resource must be a regular file.");
|
|
121
|
+
}
|
|
122
|
+
if (fileStat.size > limits.maxResourceBytes) {
|
|
123
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", "Skill resource exceeds maxResourceBytes.");
|
|
124
|
+
}
|
|
125
|
+
const content = await readFileBounded(resolved.real, limits.maxResourceBytes, "CONTEXT_LIMIT_ERROR", "Skill resource exceeds maxResourceBytes.");
|
|
126
|
+
throwIfAborted(options?.signal);
|
|
127
|
+
if (estimateSkillTokens(content.text) > limits.maxEstimatedTokens) {
|
|
128
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", "Skill resource exceeds maxEstimatedTokens.");
|
|
129
|
+
}
|
|
130
|
+
return Object.freeze({
|
|
131
|
+
path: resolved.relativePosix,
|
|
132
|
+
content: content.text,
|
|
133
|
+
byteLength: content.byteLength,
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
catalog,
|
|
139
|
+
diagnostics: Object.freeze(diagnostics),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function requireEntry(entries, name) {
|
|
143
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
144
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Skill name must be a non-empty string.");
|
|
145
|
+
}
|
|
146
|
+
const entry = entries.get(name.trim());
|
|
147
|
+
if (entry === undefined) {
|
|
148
|
+
throw new AtomsAgentError("TOOL_EXECUTION_ERROR", `Unknown skill "${name.trim()}".`);
|
|
149
|
+
}
|
|
150
|
+
return entry;
|
|
151
|
+
}
|
|
152
|
+
async function listSkillDirectories(rootReal, limits) {
|
|
153
|
+
const found = [];
|
|
154
|
+
const visitedDirs = new Set();
|
|
155
|
+
async function walk(dirReal) {
|
|
156
|
+
if (visitedDirs.has(dirReal)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
visitedDirs.add(dirReal);
|
|
160
|
+
let dirents;
|
|
161
|
+
try {
|
|
162
|
+
dirents = await readdir(dirReal, { withFileTypes: true });
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Failed to read skill root directory.", {
|
|
166
|
+
cause: error,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const names = dirents.map((d) => d.name).sort(comparePathStable);
|
|
170
|
+
for (const name of names) {
|
|
171
|
+
if (name === "." || name === "..") {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const childAbsolute = join(dirReal, name);
|
|
175
|
+
let childReal;
|
|
176
|
+
let isDirectory = false;
|
|
177
|
+
try {
|
|
178
|
+
const resolved = resolvePathInsideRoot(rootReal, toPosixPath(relative(rootReal, childAbsolute)));
|
|
179
|
+
childReal = resolved.real;
|
|
180
|
+
const st = await stat(childReal);
|
|
181
|
+
isDirectory = st.isDirectory();
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (error instanceof AtomsAgentError && error.code === "CONTEXT_LIMIT_ERROR") {
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
// 不可解析或逃逸的条目直接跳过。
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (!isDirectory) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (visitedDirs.has(childReal)) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// SKILL.md 必须经 realpath 校验仍在 skill 目录内;符号链接逃逸不得被当作合法入口。
|
|
197
|
+
let hasSkillMd = false;
|
|
198
|
+
try {
|
|
199
|
+
const skillResolved = resolvePathInsideRoot(childReal, "SKILL.md");
|
|
200
|
+
const st = await stat(skillResolved.real);
|
|
201
|
+
hasSkillMd = st.isFile();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (error instanceof AtomsAgentError && error.code === "CONTEXT_LIMIT_ERROR") {
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
hasSkillMd = false;
|
|
208
|
+
}
|
|
209
|
+
if (hasSkillMd) {
|
|
210
|
+
found.push(childReal);
|
|
211
|
+
if (found.length > limits.maxSkills) {
|
|
212
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill count exceeds maxSkills (${limits.maxSkills}).`);
|
|
213
|
+
}
|
|
214
|
+
// Skill 目录不再向下钻,但仍标记 visited,防止后续循环链回到此。
|
|
215
|
+
visitedDirs.add(childReal);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
await walk(childReal);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Root 自身若直接是 skill 目录也支持。
|
|
222
|
+
try {
|
|
223
|
+
const skillResolved = resolvePathInsideRoot(rootReal, "SKILL.md");
|
|
224
|
+
const st = await stat(skillResolved.real);
|
|
225
|
+
if (st.isFile()) {
|
|
226
|
+
return [rootReal];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// not a single-skill root
|
|
231
|
+
}
|
|
232
|
+
await walk(rootReal);
|
|
233
|
+
found.sort(comparePathStable);
|
|
234
|
+
return found;
|
|
235
|
+
}
|
|
236
|
+
async function listSkillResources(skillDirReal, limits, signal) {
|
|
237
|
+
const resources = [];
|
|
238
|
+
const visited = new Set();
|
|
239
|
+
async function walk(dirReal, relativeDirPosix) {
|
|
240
|
+
throwIfAborted(signal);
|
|
241
|
+
if (visited.has(dirReal)) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
visited.add(dirReal);
|
|
245
|
+
let dirents;
|
|
246
|
+
try {
|
|
247
|
+
dirents = await readdir(dirReal, { withFileTypes: true });
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const names = dirents.map((d) => d.name).sort(comparePathStable);
|
|
253
|
+
for (const name of names) {
|
|
254
|
+
if (name === "SKILL.md" || name === "." || name === "..") {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
const childRel = relativeDirPosix === "" ? name : `${relativeDirPosix}/${name}`;
|
|
258
|
+
let resolved;
|
|
259
|
+
try {
|
|
260
|
+
resolved = resolvePathInsideRoot(skillDirReal, childRel);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
if (error instanceof AtomsAgentError && error.code === "CONTEXT_LIMIT_ERROR") {
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
let st;
|
|
269
|
+
try {
|
|
270
|
+
st = await stat(resolved.real);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (st.isDirectory()) {
|
|
276
|
+
await walk(resolved.real, resolved.relativePosix);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (!st.isFile()) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (resources.length >= limits.maxResourcesPerSkill) {
|
|
283
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill resources exceed maxResourcesPerSkill (${limits.maxResourcesPerSkill}).`);
|
|
284
|
+
}
|
|
285
|
+
resources.push(Object.freeze({
|
|
286
|
+
path: resolved.relativePosix,
|
|
287
|
+
kind: classifyResourceKind(resolved.relativePosix),
|
|
288
|
+
byteLength: st.size,
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
await walk(skillDirReal, "");
|
|
293
|
+
resources.sort((a, b) => comparePathStable(a.path, b.path));
|
|
294
|
+
return resources;
|
|
295
|
+
}
|
|
296
|
+
function classifyResourceKind(relativePosix) {
|
|
297
|
+
if (relativePosix === "references" || relativePosix.startsWith("references/")) {
|
|
298
|
+
return "reference";
|
|
299
|
+
}
|
|
300
|
+
if (relativePosix === "assets" || relativePosix.startsWith("assets/")) {
|
|
301
|
+
return "asset";
|
|
302
|
+
}
|
|
303
|
+
if (relativePosix === "scripts" || relativePosix.startsWith("scripts/")) {
|
|
304
|
+
return "script";
|
|
305
|
+
}
|
|
306
|
+
return "other";
|
|
307
|
+
}
|
|
308
|
+
/** 读取完整文件,文件 size 不得超过 maxBytes。 */
|
|
309
|
+
async function readFileBounded(absolutePath, maxBytes, limitCode, limitMessage) {
|
|
310
|
+
let handle;
|
|
311
|
+
try {
|
|
312
|
+
handle = await open(absolutePath, "r");
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
throw new AtomsAgentError("TOOL_EXECUTION_ERROR", "Failed to open skill file.", {
|
|
316
|
+
cause: error,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
const st = await handle.stat();
|
|
321
|
+
if (!st.isFile()) {
|
|
322
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Skill path must be a regular file.");
|
|
323
|
+
}
|
|
324
|
+
if (st.size > maxBytes) {
|
|
325
|
+
throw new AtomsAgentError(limitCode, limitMessage);
|
|
326
|
+
}
|
|
327
|
+
const buffer = Buffer.alloc(Number(st.size));
|
|
328
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
|
|
329
|
+
if (bytesRead > maxBytes) {
|
|
330
|
+
throw new AtomsAgentError(limitCode, limitMessage);
|
|
331
|
+
}
|
|
332
|
+
const slice = buffer.subarray(0, bytesRead);
|
|
333
|
+
return { text: decodeUtf8Strict(slice), byteLength: bytesRead };
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
await handle.close();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* 只读文件前缀(最多 maxBytes)。用于 Catalog 阶段解析 Frontmatter,
|
|
341
|
+
* 不要求整个 SKILL.md 小于 Frontmatter 上限。
|
|
342
|
+
*/
|
|
343
|
+
async function readFilePrefixBounded(absolutePath, maxBytes, limitCode, limitMessage) {
|
|
344
|
+
let handle;
|
|
345
|
+
try {
|
|
346
|
+
handle = await open(absolutePath, "r");
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
throw new AtomsAgentError("TOOL_EXECUTION_ERROR", "Failed to open skill file.", {
|
|
350
|
+
cause: error,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
const st = await handle.stat();
|
|
355
|
+
if (!st.isFile()) {
|
|
356
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Skill path must be a regular file.");
|
|
357
|
+
}
|
|
358
|
+
const toRead = Math.min(Number(st.size), maxBytes);
|
|
359
|
+
const buffer = Buffer.alloc(toRead);
|
|
360
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
|
|
361
|
+
// 固定字节截断可能落在多字节字符中间;先回退到完整 UTF-8 前缀再严格解码。
|
|
362
|
+
const complete = completeUtf8Prefix(buffer.subarray(0, bytesRead));
|
|
363
|
+
void limitCode;
|
|
364
|
+
void limitMessage;
|
|
365
|
+
return {
|
|
366
|
+
text: decodeUtf8Strict(complete, "Skill frontmatter prefix"),
|
|
367
|
+
byteLength: complete.byteLength,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
finally {
|
|
371
|
+
await handle.close();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/** 去掉末尾不完整的 UTF-8 序列,避免前缀截断误伤合法正文。 */
|
|
375
|
+
function completeUtf8Prefix(bytes) {
|
|
376
|
+
let end = bytes.byteLength;
|
|
377
|
+
while (end > 0) {
|
|
378
|
+
try {
|
|
379
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, end));
|
|
380
|
+
return bytes.subarray(0, end);
|
|
381
|
+
}
|
|
382
|
+
catch {
|
|
383
|
+
end -= 1;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return bytes.subarray(0, 0);
|
|
387
|
+
}
|
|
388
|
+
function addTotalBytes(current, delta, limits) {
|
|
389
|
+
const next = current + delta;
|
|
390
|
+
if (next > limits.maxTotalBytes) {
|
|
391
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill catalog exceeds maxTotalBytes (${limits.maxTotalBytes}).`);
|
|
392
|
+
}
|
|
393
|
+
return next;
|
|
394
|
+
}
|
|
395
|
+
function safeLocation(rootReal, skillDirReal) {
|
|
396
|
+
const rel = toPosixPath(relative(rootReal, skillDirReal));
|
|
397
|
+
return rel === "" ? "." : rel;
|
|
398
|
+
}
|
|
399
|
+
function throwIfAborted(signal) {
|
|
400
|
+
if (signal?.aborted) {
|
|
401
|
+
throw new AtomsAgentError("CANCELLED", "Skill operation was cancelled.", {
|
|
402
|
+
cause: signal.reason,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ParsedSkillDocument = {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
/** Frontmatter 之外的其余字段(仅 JSON-safe 原始值,供诊断;不进入 Catalog 必需面)。 */
|
|
5
|
+
extra: Record<string, unknown>;
|
|
6
|
+
body: string;
|
|
7
|
+
frontmatterBytes: number;
|
|
8
|
+
/** Catalog 前缀读取时 body 可能不完整。 */
|
|
9
|
+
bodyComplete: boolean;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* 结构化解析 SKILL.md:必须是以 `---` 包裹的 YAML Frontmatter + 正文。
|
|
13
|
+
* 禁止用随意字符串切割代替 YAML 解析。
|
|
14
|
+
*
|
|
15
|
+
* allowTruncatedBody:Catalog 阶段只读前缀时,Frontmatter 闭合后允许正文被截断;
|
|
16
|
+
* 此时 body 不应被当作完整内容使用。
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseSkillMarkdown(raw: string, options: {
|
|
19
|
+
maxFrontmatterBytes: number;
|
|
20
|
+
sourceLabel: string;
|
|
21
|
+
allowTruncatedBody?: boolean;
|
|
22
|
+
}): ParsedSkillDocument;
|
|
23
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC;AAIF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IACP,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GACA,mBAAmB,CA2ErB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { AtomsAgentError } from "@atoms-agent/core";
|
|
2
|
+
import { parse as parseYaml } from "yaml";
|
|
3
|
+
const FRONTMATTER_OPEN = "---";
|
|
4
|
+
/**
|
|
5
|
+
* 结构化解析 SKILL.md:必须是以 `---` 包裹的 YAML Frontmatter + 正文。
|
|
6
|
+
* 禁止用随意字符串切割代替 YAML 解析。
|
|
7
|
+
*
|
|
8
|
+
* allowTruncatedBody:Catalog 阶段只读前缀时,Frontmatter 闭合后允许正文被截断;
|
|
9
|
+
* 此时 body 不应被当作完整内容使用。
|
|
10
|
+
*/
|
|
11
|
+
export function parseSkillMarkdown(raw, options) {
|
|
12
|
+
// Strip optional UTF-8 BOM without embedding irregular whitespace in source.
|
|
13
|
+
const normalized = raw.charCodeAt(0) === 0xfeff ? raw.slice(1) : raw;
|
|
14
|
+
if (!normalized.startsWith(`${FRONTMATTER_OPEN}\n`) &&
|
|
15
|
+
!normalized.startsWith(`${FRONTMATTER_OPEN}\r\n`)) {
|
|
16
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", `Skill document must start with YAML frontmatter (${options.sourceLabel}).`);
|
|
17
|
+
}
|
|
18
|
+
const afterOpen = normalized.startsWith(`${FRONTMATTER_OPEN}\r\n`)
|
|
19
|
+
? normalized.slice(FRONTMATTER_OPEN.length + 2)
|
|
20
|
+
: normalized.slice(FRONTMATTER_OPEN.length + 1);
|
|
21
|
+
const closeMatch = afterOpen.match(/\r?\n---(?:\r?\n|$)/);
|
|
22
|
+
if (closeMatch === null || closeMatch.index === undefined) {
|
|
23
|
+
throw new AtomsAgentError(options.allowTruncatedBody ? "CONTEXT_LIMIT_ERROR" : "TOOL_VALIDATION_ERROR", options.allowTruncatedBody
|
|
24
|
+
? `Skill frontmatter exceeds bounded prefix or is not closed (${options.sourceLabel}).`
|
|
25
|
+
: `Skill frontmatter is not closed (${options.sourceLabel}).`);
|
|
26
|
+
}
|
|
27
|
+
const frontmatterText = afterOpen.slice(0, closeMatch.index);
|
|
28
|
+
const frontmatterBytes = Buffer.byteLength(frontmatterText, "utf8");
|
|
29
|
+
if (frontmatterBytes > options.maxFrontmatterBytes) {
|
|
30
|
+
throw new AtomsAgentError("CONTEXT_LIMIT_ERROR", `Skill frontmatter exceeds maxFrontmatterBytes (${options.sourceLabel}).`);
|
|
31
|
+
}
|
|
32
|
+
const body = afterOpen.slice(closeMatch.index + closeMatch[0].length);
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
parsed = parseYaml(frontmatterText, { uniqueKeys: true });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", `Skill frontmatter YAML is invalid (${options.sourceLabel}).`, { cause: error });
|
|
39
|
+
}
|
|
40
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
41
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", `Skill frontmatter must be a YAML mapping (${options.sourceLabel}).`);
|
|
42
|
+
}
|
|
43
|
+
const record = parsed;
|
|
44
|
+
const name = requireNonEmptyString(record.name, "name", options.sourceLabel);
|
|
45
|
+
const description = requireNonEmptyString(record.description, "description", options.sourceLabel);
|
|
46
|
+
const extra = {};
|
|
47
|
+
for (const [key, value] of Object.entries(record)) {
|
|
48
|
+
if (key === "name" || key === "description") {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
extra[key] = value;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
name,
|
|
55
|
+
description,
|
|
56
|
+
extra,
|
|
57
|
+
body: options.allowTruncatedBody ? "" : body,
|
|
58
|
+
frontmatterBytes,
|
|
59
|
+
bodyComplete: !options.allowTruncatedBody,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function requireNonEmptyString(value, field, sourceLabel) {
|
|
63
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
64
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", `Skill frontmatter field "${field}" must be a non-empty string (${sourceLabel}).`);
|
|
65
|
+
}
|
|
66
|
+
return value.trim();
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @atoms-agent/skills 公共根入口。
|
|
3
|
+
*
|
|
4
|
+
* A401 冻结:类型、默认限制与纯配置辅助。
|
|
5
|
+
* Catalog 加载(S401)与 Core Tool 集成(S402)在后续任务导出。
|
|
6
|
+
*/
|
|
7
|
+
export type { LoadedSkill, SkillCatalog, SkillCatalogDiagnostic, SkillCatalogOptions, SkillDuplicateNamePolicy, SkillLimits, SkillResourceContent, SkillResourceDescriptor, SkillResourceKind, SkillRootConfig, SkillSummary, } from "./types.js";
|
|
8
|
+
export { DEFAULT_SKILL_LIMITS, estimateSkillTokens, resolveSkillLimits } from "./limits.js";
|
|
9
|
+
export { createSkillCatalog } from "./catalog.js";
|
|
10
|
+
export type { CreateSkillCatalogResult } from "./catalog.js";
|
|
11
|
+
export { parseSkillMarkdown } from "./frontmatter.js";
|
|
12
|
+
export type { ParsedSkillDocument } from "./frontmatter.js";
|
|
13
|
+
export { createSkillTools, formatSkillCatalogPrompt } from "./tools.js";
|
|
14
|
+
export type { CreateSkillToolsOptions, SkillCatalogPromptOptions, SkillToolName } from "./tools.js";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,WAAW,EACX,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @atoms-agent/skills 公共根入口。
|
|
3
|
+
*
|
|
4
|
+
* A401 冻结:类型、默认限制与纯配置辅助。
|
|
5
|
+
* Catalog 加载(S401)与 Core Tool 集成(S402)在后续任务导出。
|
|
6
|
+
*/
|
|
7
|
+
export { DEFAULT_SKILL_LIMITS, estimateSkillTokens, resolveSkillLimits } from "./limits.js";
|
|
8
|
+
export { createSkillCatalog } from "./catalog.js";
|
|
9
|
+
export { parseSkillMarkdown } from "./frontmatter.js";
|
|
10
|
+
export { createSkillTools, formatSkillCatalogPrompt } from "./tools.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/limits.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SkillLimits } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 默认有界限制(docs/V04-EXTENSIONS.md §3.2)。
|
|
4
|
+
* 数值可在后续任务微调,但字段集合与“超限先失败”语义已冻结。
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_SKILL_LIMITS: Readonly<SkillLimits>;
|
|
7
|
+
/** 合并 Host 覆盖项;非法数值在配置期失败。 */
|
|
8
|
+
export declare function resolveSkillLimits(partial?: Partial<SkillLimits>): SkillLimits;
|
|
9
|
+
/** 粗略估算 Token:UTF-8 字节 / 4,与 Core sliding window 同量级启发式。 */
|
|
10
|
+
export declare function estimateSkillTokens(text: string): number;
|
|
11
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,WAAW,CASrD,CAAC;AAEH,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAa9E;AAED,4DAA4D;AAC5D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD"}
|
package/dist/limits.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AtomsAgentError } from "@atoms-agent/core";
|
|
2
|
+
/**
|
|
3
|
+
* 默认有界限制(docs/V04-EXTENSIONS.md §3.2)。
|
|
4
|
+
* 数值可在后续任务微调,但字段集合与“超限先失败”语义已冻结。
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_SKILL_LIMITS = Object.freeze({
|
|
7
|
+
maxRoots: 16,
|
|
8
|
+
maxSkills: 128,
|
|
9
|
+
maxResourcesPerSkill: 64,
|
|
10
|
+
maxFrontmatterBytes: 8_192,
|
|
11
|
+
maxBodyBytes: 256_000,
|
|
12
|
+
maxResourceBytes: 256_000,
|
|
13
|
+
maxTotalBytes: 2_000_000,
|
|
14
|
+
maxEstimatedTokens: 32_000,
|
|
15
|
+
});
|
|
16
|
+
/** 合并 Host 覆盖项;非法数值在配置期失败。 */
|
|
17
|
+
export function resolveSkillLimits(partial) {
|
|
18
|
+
const merged = {
|
|
19
|
+
...DEFAULT_SKILL_LIMITS,
|
|
20
|
+
...partial,
|
|
21
|
+
};
|
|
22
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
23
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
24
|
+
throw new AtomsAgentError("CONFIG_ERROR", `Skill limit ${key} must be a positive integer.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return Object.freeze(merged);
|
|
28
|
+
}
|
|
29
|
+
/** 粗略估算 Token:UTF-8 字节 / 4,与 Core sliding window 同量级启发式。 */
|
|
30
|
+
export function estimateSkillTokens(text) {
|
|
31
|
+
return Math.ceil(new TextEncoder().encode(text).byteLength / 4);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA0B,MAAM,CAAC,MAAM,CAAC;IACvE,QAAQ,EAAE,EAAE;IACZ,SAAS,EAAE,GAAG;IACd,oBAAoB,EAAE,EAAE;IACxB,mBAAmB,EAAE,KAAK;IAC1B,YAAY,EAAE,OAAO;IACrB,gBAAgB,EAAE,OAAO;IACzB,aAAa,EAAE,SAAS;IACxB,kBAAkB,EAAE,MAAM;CAC3B,CAAC,CAAC;AAEH,8BAA8B;AAC9B,MAAM,UAAU,kBAAkB,CAAC,OAA8B;IAC/D,MAAM,MAAM,GAAgB;QAC1B,GAAG,oBAAoB;QACvB,GAAG,OAAO;KACX,CAAC;IAEF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAuC,EAAE,CAAC;QACxF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,eAAe,CAAC,cAAc,EAAE,eAAe,GAAG,8BAA8B,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;AAClE,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** 将路径段转为 POSIX 风格,用于稳定 location 与资源 path。 */
|
|
2
|
+
export declare function toPosixPath(pathValue: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* 解析并校验 Root:必须存在且为目录;返回 real path。
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveSkillRoot(rootPath: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* 在 skillDirReal 内解析相对资源路径。
|
|
9
|
+
* 拒绝绝对路径、空段、`..` 逃逸与符号链接逃逸。
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolvePathInsideRoot(rootReal: string, relativePath: string, options?: {
|
|
12
|
+
allowMissing?: boolean;
|
|
13
|
+
}): {
|
|
14
|
+
absolute: string;
|
|
15
|
+
real: string;
|
|
16
|
+
relativePosix: string;
|
|
17
|
+
};
|
|
18
|
+
/** 稳定的字典序比较(Unicode 码点 / 默认 localeCompare 确定性排序)。 */
|
|
19
|
+
export declare function comparePathStable(a: string, b: string): number;
|
|
20
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAqCzD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACnC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAwE3D;AAoCD,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9D"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { AtomsAgentError } from "@atoms-agent/core";
|
|
4
|
+
/** 将路径段转为 POSIX 风格,用于稳定 location 与资源 path。 */
|
|
5
|
+
export function toPosixPath(pathValue) {
|
|
6
|
+
return pathValue.split(sep).join("/");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 解析并校验 Root:必须存在且为目录;返回 real path。
|
|
10
|
+
*/
|
|
11
|
+
export function resolveSkillRoot(rootPath) {
|
|
12
|
+
if (typeof rootPath !== "string" || rootPath.trim().length === 0) {
|
|
13
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Skill root path must be a non-empty string.");
|
|
14
|
+
}
|
|
15
|
+
let absolute;
|
|
16
|
+
try {
|
|
17
|
+
absolute = resolve(rootPath);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Skill root path is invalid.", { cause: error });
|
|
21
|
+
}
|
|
22
|
+
let realRoot;
|
|
23
|
+
try {
|
|
24
|
+
realRoot = realpathSync(absolute);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Skill root path does not exist or is inaccessible.", {
|
|
28
|
+
cause: error,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
let stats;
|
|
32
|
+
try {
|
|
33
|
+
stats = statSync(realRoot);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Skill root path is not readable.", { cause: error });
|
|
37
|
+
}
|
|
38
|
+
if (!stats.isDirectory()) {
|
|
39
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Skill root path must be a directory.");
|
|
40
|
+
}
|
|
41
|
+
return realRoot;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 在 skillDirReal 内解析相对资源路径。
|
|
45
|
+
* 拒绝绝对路径、空段、`..` 逃逸与符号链接逃逸。
|
|
46
|
+
*/
|
|
47
|
+
export function resolvePathInsideRoot(rootReal, relativePath, options) {
|
|
48
|
+
if (typeof relativePath !== "string" || relativePath.trim().length === 0) {
|
|
49
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path must be a non-empty string.");
|
|
50
|
+
}
|
|
51
|
+
const trimmed = relativePath.trim();
|
|
52
|
+
if (isAbsolute(trimmed) || trimmed.includes("\0")) {
|
|
53
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path must be relative and safe.");
|
|
54
|
+
}
|
|
55
|
+
const posixCandidate = toPosixPath(trimmed);
|
|
56
|
+
if (posixCandidate === ".." ||
|
|
57
|
+
posixCandidate.startsWith("../") ||
|
|
58
|
+
posixCandidate.includes("/../") ||
|
|
59
|
+
posixCandidate.endsWith("/..") ||
|
|
60
|
+
posixCandidate.split("/").some((segment) => segment === ".." || segment === "")) {
|
|
61
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path must not contain empty segments or parent references.");
|
|
62
|
+
}
|
|
63
|
+
const absolute = normalize(join(rootReal, ...posixCandidate.split("/")));
|
|
64
|
+
const relativeCheck = relative(rootReal, absolute);
|
|
65
|
+
if (relativeCheck.startsWith("..") ||
|
|
66
|
+
isAbsolute(relativeCheck) ||
|
|
67
|
+
relativeCheck.split(sep).includes("..")) {
|
|
68
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path escapes the skill directory.");
|
|
69
|
+
}
|
|
70
|
+
let real;
|
|
71
|
+
try {
|
|
72
|
+
real = realpathSync(absolute);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (options?.allowMissing) {
|
|
76
|
+
// 目标不存在时,校验父目录 real path 仍在 root 内,防止通过 dangling symlink 探测。
|
|
77
|
+
ensureParentInsideRoot(rootReal, absolute);
|
|
78
|
+
return {
|
|
79
|
+
absolute,
|
|
80
|
+
real: absolute,
|
|
81
|
+
relativePosix: toPosixPath(relativeCheck),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
throw new AtomsAgentError("TOOL_EXECUTION_ERROR", "Resource path does not exist.", {
|
|
85
|
+
cause: error,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const realRelative = relative(rootReal, real);
|
|
89
|
+
if (realRelative.startsWith("..") ||
|
|
90
|
+
isAbsolute(realRelative) ||
|
|
91
|
+
realRelative.split(sep).includes("..")) {
|
|
92
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path resolves outside the skill directory.");
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
absolute,
|
|
96
|
+
real,
|
|
97
|
+
relativePosix: toPosixPath(relativeCheck),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function ensureParentInsideRoot(rootReal, absoluteTarget) {
|
|
101
|
+
let current = dirname(absoluteTarget);
|
|
102
|
+
// 向上找到第一个存在的祖先,验证其 real path 仍在 root 内。
|
|
103
|
+
for (let i = 0; i < 64; i += 1) {
|
|
104
|
+
try {
|
|
105
|
+
const realParent = realpathSync(current);
|
|
106
|
+
const rel = relative(rootReal, realParent);
|
|
107
|
+
if (rel.startsWith("..") || isAbsolute(rel) || rel.split(sep).includes("..")) {
|
|
108
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path resolves outside the skill directory.");
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (error instanceof AtomsAgentError) {
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
const parent = dirname(current);
|
|
117
|
+
if (parent === current) {
|
|
118
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path resolves outside the skill directory.");
|
|
119
|
+
}
|
|
120
|
+
current = parent;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", "Resource path resolves outside the skill directory.");
|
|
124
|
+
}
|
|
125
|
+
/** 稳定的字典序比较(Unicode 码点 / 默认 localeCompare 确定性排序)。 */
|
|
126
|
+
export function comparePathStable(a, b) {
|
|
127
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@atoms-agent/core";
|
|
2
|
+
import type { SkillCatalog } from "./types.js";
|
|
3
|
+
declare const SKILL_TOOL_NAMES: readonly ["list_skills", "load_skill", "read_skill_resource"];
|
|
4
|
+
export type SkillToolName = (typeof SKILL_TOOL_NAMES)[number];
|
|
5
|
+
export type CreateSkillToolsOptions = {
|
|
6
|
+
catalog: SkillCatalog;
|
|
7
|
+
/**
|
|
8
|
+
* 已存在的本地 Tool 名称;与 skill tool 冲突时在注册前失败。
|
|
9
|
+
*/
|
|
10
|
+
existingToolNames?: Iterable<string>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 生成 Core `ToolDefinition`:list_skills / load_skill / read_skill_resource。
|
|
14
|
+
* 全部 sideEffect: "none";永不执行 scripts/。
|
|
15
|
+
*/
|
|
16
|
+
export declare function createSkillTools(options: CreateSkillToolsOptions): ToolDefinition[];
|
|
17
|
+
export type SkillCatalogPromptOptions = {
|
|
18
|
+
catalog: SkillCatalog;
|
|
19
|
+
/** 最多列出的 skill 数;默认 32。 */
|
|
20
|
+
maxSkills?: number;
|
|
21
|
+
/** 单条 description 最大字符;默认 200。 */
|
|
22
|
+
maxDescriptionChars?: number;
|
|
23
|
+
/** 整段摘要最大字符;默认 4000。 */
|
|
24
|
+
maxTotalChars?: number;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* 有界 Catalog Prompt 摘要,供 Host 显式并入 systemPrompt。
|
|
28
|
+
* 不修改消息历史,不加载 skill 正文。
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatSkillCatalogPrompt(options: SkillCatalogPromptOptions): string;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAErF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,QAAA,MAAM,gBAAgB,+DAAgE,CAAC;AAEvF,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,YAAY,CAAC;IACtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,cAAc,EAAE,CAgGnF;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wBAAwB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAmCnF"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { AtomsAgentError, defineTool } from "@atoms-agent/core";
|
|
2
|
+
const SKILL_TOOL_NAMES = ["list_skills", "load_skill", "read_skill_resource"];
|
|
3
|
+
/**
|
|
4
|
+
* 生成 Core `ToolDefinition`:list_skills / load_skill / read_skill_resource。
|
|
5
|
+
* 全部 sideEffect: "none";永不执行 scripts/。
|
|
6
|
+
*/
|
|
7
|
+
export function createSkillTools(options) {
|
|
8
|
+
const existing = new Set(options.existingToolNames ?? []);
|
|
9
|
+
for (const name of SKILL_TOOL_NAMES) {
|
|
10
|
+
if (existing.has(name)) {
|
|
11
|
+
throw new AtomsAgentError("CONFIG_ERROR", `Skill tool name "${name}" conflicts with an existing tool.`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const catalog = options.catalog;
|
|
15
|
+
const listSkills = defineTool({
|
|
16
|
+
name: "list_skills",
|
|
17
|
+
description: "List available local skills (name, description, location). Does not load bodies.",
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {},
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
},
|
|
23
|
+
sideEffect: "none",
|
|
24
|
+
async execute(_input, context) {
|
|
25
|
+
throwIfAborted(context.signal);
|
|
26
|
+
return {
|
|
27
|
+
skills: catalog.list().map((skill) => ({
|
|
28
|
+
name: skill.name,
|
|
29
|
+
description: skill.description,
|
|
30
|
+
location: skill.location,
|
|
31
|
+
rootIndex: skill.rootIndex,
|
|
32
|
+
})),
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const loadSkill = defineTool({
|
|
37
|
+
name: "load_skill",
|
|
38
|
+
description: "Load a skill body and resource descriptors by name. Read-only; never executes scripts.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
name: { type: "string", minLength: 1 },
|
|
43
|
+
},
|
|
44
|
+
required: ["name"],
|
|
45
|
+
additionalProperties: false,
|
|
46
|
+
},
|
|
47
|
+
sideEffect: "none",
|
|
48
|
+
async execute(input, context) {
|
|
49
|
+
throwIfAborted(context.signal);
|
|
50
|
+
const name = String(input.name);
|
|
51
|
+
const loaded = await catalog.loadSkill(name, { signal: context.signal });
|
|
52
|
+
return {
|
|
53
|
+
name: loaded.summary.name,
|
|
54
|
+
description: loaded.summary.description,
|
|
55
|
+
location: loaded.summary.location,
|
|
56
|
+
body: loaded.body,
|
|
57
|
+
resources: loaded.resources.map((resource) => ({
|
|
58
|
+
path: resource.path,
|
|
59
|
+
kind: resource.kind,
|
|
60
|
+
byteLength: resource.byteLength,
|
|
61
|
+
})),
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const readSkillResource = defineTool({
|
|
66
|
+
name: "read_skill_resource",
|
|
67
|
+
description: "Read one skill resource file (including scripts/) as text. Read-only; never executes scripts.",
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: {
|
|
71
|
+
name: { type: "string", minLength: 1 },
|
|
72
|
+
path: { type: "string", minLength: 1 },
|
|
73
|
+
},
|
|
74
|
+
required: ["name", "path"],
|
|
75
|
+
additionalProperties: false,
|
|
76
|
+
},
|
|
77
|
+
sideEffect: "none",
|
|
78
|
+
async execute(input, context) {
|
|
79
|
+
throwIfAborted(context.signal);
|
|
80
|
+
const { name, path } = input;
|
|
81
|
+
const resource = await catalog.readSkillResource(String(name), String(path), {
|
|
82
|
+
signal: context.signal,
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
name: String(name),
|
|
86
|
+
path: resource.path,
|
|
87
|
+
content: resource.content,
|
|
88
|
+
byteLength: resource.byteLength,
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
return [listSkills, loadSkill, readSkillResource];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 有界 Catalog Prompt 摘要,供 Host 显式并入 systemPrompt。
|
|
96
|
+
* 不修改消息历史,不加载 skill 正文。
|
|
97
|
+
*/
|
|
98
|
+
export function formatSkillCatalogPrompt(options) {
|
|
99
|
+
const maxSkills = options.maxSkills ?? 32;
|
|
100
|
+
const maxDescriptionChars = options.maxDescriptionChars ?? 200;
|
|
101
|
+
const maxTotalChars = options.maxTotalChars ?? 4_000;
|
|
102
|
+
if (![maxSkills, maxDescriptionChars, maxTotalChars].every((n) => Number.isInteger(n) && n > 0)) {
|
|
103
|
+
throw new AtomsAgentError("CONFIG_ERROR", "Skill catalog prompt limits must be positive integers.");
|
|
104
|
+
}
|
|
105
|
+
const skills = options.catalog.list().slice(0, maxSkills);
|
|
106
|
+
const lines = [
|
|
107
|
+
"Available local skills (use list_skills / load_skill / read_skill_resource to fetch details).",
|
|
108
|
+
"Loading a skill never executes scripts; script execution requires a separate Host tool.",
|
|
109
|
+
];
|
|
110
|
+
for (const skill of skills) {
|
|
111
|
+
const description = skill.description.length > maxDescriptionChars
|
|
112
|
+
? `${skill.description.slice(0, maxDescriptionChars)}…`
|
|
113
|
+
: skill.description;
|
|
114
|
+
lines.push(`- ${skill.name}: ${description}`);
|
|
115
|
+
}
|
|
116
|
+
if (options.catalog.list().length > maxSkills) {
|
|
117
|
+
lines.push(`…and ${options.catalog.list().length - maxSkills} more (call list_skills).`);
|
|
118
|
+
}
|
|
119
|
+
let text = lines.join("\n");
|
|
120
|
+
if (text.length > maxTotalChars) {
|
|
121
|
+
text = `${text.slice(0, Math.max(0, maxTotalChars - 1))}…`;
|
|
122
|
+
}
|
|
123
|
+
return text;
|
|
124
|
+
}
|
|
125
|
+
function throwIfAborted(signal) {
|
|
126
|
+
if (signal.aborted) {
|
|
127
|
+
throw new AtomsAgentError("CANCELLED", "Skill tool operation was cancelled.", {
|
|
128
|
+
cause: signal.reason,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills 公共契约类型(docs/V04-EXTENSIONS.md §3)。
|
|
3
|
+
* Catalog 实现见 S401;Core Tool 集成见 S402。
|
|
4
|
+
*/
|
|
5
|
+
/** 发现/加载的有界限制;超限必须在分配无界缓冲前失败。 */
|
|
6
|
+
export type SkillLimits = {
|
|
7
|
+
maxRoots: number;
|
|
8
|
+
maxSkills: number;
|
|
9
|
+
maxResourcesPerSkill: number;
|
|
10
|
+
maxFrontmatterBytes: number;
|
|
11
|
+
maxBodyBytes: number;
|
|
12
|
+
maxResourceBytes: number;
|
|
13
|
+
maxTotalBytes: number;
|
|
14
|
+
maxEstimatedTokens: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* 重复 Skill name 策略(确定性,禁止静默覆盖):
|
|
18
|
+
* - error:任一重复即失败(默认)
|
|
19
|
+
* - first-wins:按稳定遍历顺序保留先出现者,并产生诊断
|
|
20
|
+
*/
|
|
21
|
+
export type SkillDuplicateNamePolicy = "error" | "first-wins";
|
|
22
|
+
/** Host 显式提供的 Skill Root 配置。不得默认扫描 Home/Workspace。 */
|
|
23
|
+
export type SkillRootConfig = {
|
|
24
|
+
roots: string[];
|
|
25
|
+
limits?: Partial<SkillLimits>;
|
|
26
|
+
duplicateNamePolicy?: SkillDuplicateNamePolicy;
|
|
27
|
+
};
|
|
28
|
+
/** Catalog 阶段的有界元数据。 */
|
|
29
|
+
export type SkillSummary = {
|
|
30
|
+
name: string;
|
|
31
|
+
description: string;
|
|
32
|
+
/** 稳定位置标识;默认不包含 Secret 或用户 Home 绝对路径。 */
|
|
33
|
+
location: string;
|
|
34
|
+
rootIndex: number;
|
|
35
|
+
};
|
|
36
|
+
export type SkillResourceKind = "reference" | "asset" | "script" | "other";
|
|
37
|
+
export type SkillResourceDescriptor = {
|
|
38
|
+
/** Skill 目录内相对 POSIX 路径,例如 references/api.md */
|
|
39
|
+
path: string;
|
|
40
|
+
kind: SkillResourceKind;
|
|
41
|
+
byteLength: number;
|
|
42
|
+
};
|
|
43
|
+
/** loadSkill 的按需结果:正文 + 资源描述(仍只读)。 */
|
|
44
|
+
export type LoadedSkill = {
|
|
45
|
+
summary: SkillSummary;
|
|
46
|
+
body: string;
|
|
47
|
+
resources: readonly SkillResourceDescriptor[];
|
|
48
|
+
};
|
|
49
|
+
export type SkillResourceContent = {
|
|
50
|
+
path: string;
|
|
51
|
+
content: string;
|
|
52
|
+
byteLength: number;
|
|
53
|
+
};
|
|
54
|
+
export type SkillCatalogOptions = {
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Skill Catalog 公共表面。
|
|
59
|
+
* list / load / read 均为只读,永不执行 scripts/。
|
|
60
|
+
*/
|
|
61
|
+
export type SkillCatalog = {
|
|
62
|
+
list(): readonly SkillSummary[];
|
|
63
|
+
loadSkill(name: string, options?: SkillCatalogOptions): Promise<LoadedSkill>;
|
|
64
|
+
readSkillResource(name: string, resourcePath: string, options?: SkillCatalogOptions): Promise<SkillResourceContent>;
|
|
65
|
+
};
|
|
66
|
+
/** first-wins 策略下的确定性诊断(不改变 list 结果的稳定性)。 */
|
|
67
|
+
export type SkillCatalogDiagnostic = {
|
|
68
|
+
code: "DUPLICATE_SKILL_NAME";
|
|
69
|
+
skillName: string;
|
|
70
|
+
keptLocation: string;
|
|
71
|
+
skippedLocation: string;
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iCAAiC;AACjC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,YAAY,CAAC;AAE9D,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9B,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;CAChD,CAAC;AAEF,wBAAwB;AACxB,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE3E,MAAM,MAAM,uBAAuB,GAAG;IACpC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,sCAAsC;AACtC,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,YAAY,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,IAAI,SAAS,YAAY,EAAE,CAAC;IAChC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7E,iBAAiB,CACf,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAClC,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/utf8.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utf8.d.ts","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":"AAEA,sCAAsC;AACtC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,SAAkB,GAAG,MAAM,CAQnF"}
|
package/dist/utf8.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AtomsAgentError } from "@atoms-agent/core";
|
|
2
|
+
/** 严格 UTF-8 解码:非法序列不得静默替换为 U+FFFD。 */
|
|
3
|
+
export function decodeUtf8Strict(bytes, label = "Skill content") {
|
|
4
|
+
try {
|
|
5
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
throw new AtomsAgentError("TOOL_VALIDATION_ERROR", `${label} is not valid UTF-8.`, {
|
|
9
|
+
cause: error,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=utf8.js.map
|
package/dist/utf8.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utf8.js","sourceRoot":"","sources":["../src/utf8.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,sCAAsC;AACtC,MAAM,UAAU,gBAAgB,CAAC,KAAiB,EAAE,KAAK,GAAG,eAAe;IACzE,IAAI,CAAC;QACH,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,eAAe,CAAC,uBAAuB,EAAE,GAAG,KAAK,sBAAsB,EAAE;YACjF,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atoms-agent/skills",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Local SKILL.md catalog, secure discovery, lazy loading and Core tool integration",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "atoms_agent contributors",
|
|
8
|
+
"homepage": "https://github.com/Fufu-0101/atoms_agent#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Fufu-0101/atoms_agent.git",
|
|
12
|
+
"directory": "packages/skills"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/Fufu-0101/atoms_agent/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"agent",
|
|
19
|
+
"skills",
|
|
20
|
+
"skill-md",
|
|
21
|
+
"catalog",
|
|
22
|
+
"typescript",
|
|
23
|
+
"sdk"
|
|
24
|
+
],
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"build": "tsc -b"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.13"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@atoms-agent/core": "workspace:0.4.0",
|
|
48
|
+
"yaml": "2.8.0"
|
|
49
|
+
}
|
|
50
|
+
}
|