bash-tool 1.3.5 → 1.3.7
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 +68 -2
- package/dist/AGENTS.md +3 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/skill-tool.d.ts +36 -0
- package/dist/skill-tool.d.ts.map +1 -0
- package/dist/skill-tool.js +103 -0
- package/dist/skill-tool.js.map +1 -0
- package/dist/skills/parser.d.ts +33 -0
- package/dist/skills/parser.d.ts.map +1 -0
- package/dist/skills/parser.js +125 -0
- package/dist/skills/parser.js.map +1 -0
- package/dist/skills/types.d.ts +57 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/load-skill.d.ts +25 -0
- package/dist/tools/load-skill.d.ts.map +1 -0
- package/dist/tools/load-skill.js +74 -0
- package/dist/tools/load-skill.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -167,14 +167,80 @@ const customSandbox: Sandbox = {
|
|
|
167
167
|
// Your implementation here
|
|
168
168
|
return "";
|
|
169
169
|
},
|
|
170
|
-
async
|
|
171
|
-
// Your implementation here
|
|
170
|
+
async writeFiles(files) {
|
|
171
|
+
// Your implementation here - files is Array<{path, content}>
|
|
172
172
|
},
|
|
173
173
|
};
|
|
174
174
|
|
|
175
175
|
const { tools } = await createBashTool({ sandbox: customSandbox });
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
+
## Skills (Experimental)
|
|
179
|
+
|
|
180
|
+
Skills are modular capabilities that extend agent functionality. Each skill is a directory containing a `SKILL.md` file with instructions and optional scripts.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import {
|
|
184
|
+
experimental_createSkillTool as createSkillTool,
|
|
185
|
+
createBashTool,
|
|
186
|
+
} from "bash-tool";
|
|
187
|
+
import { ToolLoopAgent } from "ai";
|
|
188
|
+
|
|
189
|
+
// Discover skills and get files to upload
|
|
190
|
+
const { loadSkill, files, instructions } = await createSkillTool({
|
|
191
|
+
skillsDirectory: "./skills",
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Create bash tool with skill files
|
|
195
|
+
const { tools } = await createBashTool({
|
|
196
|
+
files,
|
|
197
|
+
extraInstructions: instructions,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Use both tools with an agent
|
|
201
|
+
const agent = new ToolLoopAgent({
|
|
202
|
+
model,
|
|
203
|
+
tools: { loadSkill, ...tools },
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Skill Directory Structure
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
skills/
|
|
211
|
+
├── csv/
|
|
212
|
+
│ ├── SKILL.md # Required: instructions with YAML frontmatter
|
|
213
|
+
│ ├── analyze.sh # Optional: scripts the agent can run
|
|
214
|
+
│ └── filter.sh
|
|
215
|
+
└── text/
|
|
216
|
+
├── SKILL.md
|
|
217
|
+
└── search.sh
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### SKILL.md Format
|
|
221
|
+
|
|
222
|
+
```markdown
|
|
223
|
+
---
|
|
224
|
+
name: csv
|
|
225
|
+
description: Analyze and transform CSV files
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
# CSV Processing
|
|
229
|
+
|
|
230
|
+
Use `./skills/csv/analyze.sh <file>` to analyze a CSV file.
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### How It Works
|
|
234
|
+
|
|
235
|
+
1. `createSkillTool` discovers skills and returns:
|
|
236
|
+
- `loadSkill` - Tool for the agent to load a skill's instructions on demand
|
|
237
|
+
- `files` - All skill files to pass to `createBashTool`
|
|
238
|
+
- `instructions` - Extra instructions listing available skills
|
|
239
|
+
|
|
240
|
+
2. The agent sees skill names in the `loadSkill` tool description
|
|
241
|
+
3. When the agent needs a skill, it calls `loadSkill("csv")` to get detailed instructions
|
|
242
|
+
4. The agent uses `bash` to run scripts from `./skills/csv/`
|
|
243
|
+
|
|
178
244
|
## AI Agent Instructions
|
|
179
245
|
|
|
180
246
|
For AI agents working with bash-tool, additional guidance is available in `AGENTS.md`:
|
package/dist/AGENTS.md
CHANGED
|
@@ -38,7 +38,7 @@ const result = await agent.generate({
|
|
|
38
38
|
## Key Behaviors
|
|
39
39
|
|
|
40
40
|
1. **Default sandbox is just-bash** - Install `just-bash` or provide your own sandbox
|
|
41
|
-
2. **Working directory defaults to
|
|
41
|
+
2. **Working directory defaults to `/workspace`** - All files written relative to `destination`
|
|
42
42
|
3. **Files are written before tools are returned** - Sandbox is pre-populated
|
|
43
43
|
4. **Tool descriptions include file list** - LLM sees available files in bash tool description
|
|
44
44
|
5. **No `stop()` method** - Sandbox lifecycle is managed externally
|
|
@@ -83,11 +83,11 @@ const { tools } = await createBashTool({ sandbox: existingSandbox });
|
|
|
83
83
|
const { tools } = await createBashTool({
|
|
84
84
|
onBeforeBashCall: ({ command }) => {
|
|
85
85
|
console.log("Running:", command);
|
|
86
|
-
//
|
|
86
|
+
return undefined; // Or return { command: modifiedCommand } to change it
|
|
87
87
|
},
|
|
88
88
|
onAfterBashCall: ({ command, result }) => {
|
|
89
89
|
console.log(`Exit: ${result.exitCode}`);
|
|
90
|
-
//
|
|
90
|
+
return undefined; // Or return { result: modifiedResult } to change it
|
|
91
91
|
},
|
|
92
92
|
});
|
|
93
93
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type { JustBashLike } from "./sandbox/just-bash.js";
|
|
2
|
+
export { experimental_createSkillTool } from "./skill-tool.js";
|
|
3
|
+
export type { CreateSkillToolOptions, DiscoveredSkill, Skill, SkillMetadata, SkillToolkit, } from "./skills/types.js";
|
|
2
4
|
export { createBashTool } from "./tool.js";
|
|
3
5
|
export { DEFAULT_MAX_OUTPUT_LENGTH } from "./tools/bash.js";
|
|
4
6
|
export type { BashToolCategory, BashToolInfo, FileFormat, ToolPromptOptions, } from "./tools-prompt.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,OAAO,EACP,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAC/D,YAAY,EACV,sBAAsB,EACtB,eAAe,EACf,KAAK,EACL,aAAa,EACb,YAAY,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,OAAO,EACP,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { experimental_createSkillTool } from "./skill-tool.js";
|
|
1
2
|
export { createBashTool } from "./tool.js";
|
|
2
3
|
export { DEFAULT_MAX_OUTPUT_LENGTH } from "./tools/bash.js";
|
|
3
4
|
export { bashTools, createToolPrompt, detectFormat, discoverAvailableTools, getToolsByCategory, getToolsForFormat, toolsByFormat, } from "./tools-prompt.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAO5D,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAQ/D,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAO5D,OAAO,EACL,SAAS,EACT,gBAAgB,EAChB,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CreateSkillToolOptions, SkillToolkit } from "./skills/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a skill toolkit for AI agents.
|
|
4
|
+
*
|
|
5
|
+
* Skills are modular capabilities that extend agent functionality.
|
|
6
|
+
* Each skill is a directory containing a SKILL.md file with instructions
|
|
7
|
+
* and optional scripts/resources.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import {
|
|
12
|
+
* experimental_createSkillTool as createSkillTool,
|
|
13
|
+
* createBashTool,
|
|
14
|
+
* } from "bash-tool";
|
|
15
|
+
*
|
|
16
|
+
* // Discover skills and get files
|
|
17
|
+
* const { loadSkill, skills, files, instructions } = await createSkillTool({
|
|
18
|
+
* skillsDirectory: "./skills",
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Create bash tool with skill files
|
|
22
|
+
* const { tools, sandbox } = await createBashTool({
|
|
23
|
+
* files,
|
|
24
|
+
* extraInstructions: instructions,
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Use with AI SDK
|
|
28
|
+
* const result = await generateText({
|
|
29
|
+
* model,
|
|
30
|
+
* tools: { loadSkill, ...tools },
|
|
31
|
+
* prompt: "Process this data using the csv skill",
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function experimental_createSkillTool(options: CreateSkillToolOptions): Promise<SkillToolkit>;
|
|
36
|
+
//# sourceMappingURL=skill-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-tool.d.ts","sourceRoot":"","sources":["../src/skill-tool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,sBAAsB,EAEtB,YAAY,EACb,MAAM,mBAAmB,CAAC;AAK3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,YAAY,CAAC,CAmDvB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { discoverSkills, listSkillFiles } from "./skills/parser.js";
|
|
4
|
+
import { createLoadSkillTool } from "./tools/load-skill.js";
|
|
5
|
+
const DEFAULT_DESTINATION = "skills";
|
|
6
|
+
/**
|
|
7
|
+
* Creates a skill toolkit for AI agents.
|
|
8
|
+
*
|
|
9
|
+
* Skills are modular capabilities that extend agent functionality.
|
|
10
|
+
* Each skill is a directory containing a SKILL.md file with instructions
|
|
11
|
+
* and optional scripts/resources.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import {
|
|
16
|
+
* experimental_createSkillTool as createSkillTool,
|
|
17
|
+
* createBashTool,
|
|
18
|
+
* } from "bash-tool";
|
|
19
|
+
*
|
|
20
|
+
* // Discover skills and get files
|
|
21
|
+
* const { loadSkill, skills, files, instructions } = await createSkillTool({
|
|
22
|
+
* skillsDirectory: "./skills",
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Create bash tool with skill files
|
|
26
|
+
* const { tools, sandbox } = await createBashTool({
|
|
27
|
+
* files,
|
|
28
|
+
* extraInstructions: instructions,
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Use with AI SDK
|
|
32
|
+
* const result = await generateText({
|
|
33
|
+
* model,
|
|
34
|
+
* tools: { loadSkill, ...tools },
|
|
35
|
+
* prompt: "Process this data using the csv skill",
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export async function experimental_createSkillTool(options) {
|
|
40
|
+
const { skillsDirectory, destination = DEFAULT_DESTINATION } = options;
|
|
41
|
+
// Discover all skills and collect their files
|
|
42
|
+
// sandboxDestination uses explicit relative path (e.g., "./skills") - works with any destination
|
|
43
|
+
const relativeDestination = `./${destination}`;
|
|
44
|
+
const discoveredSkills = await discoverSkills({
|
|
45
|
+
skillsDirectory,
|
|
46
|
+
sandboxDestination: relativeDestination,
|
|
47
|
+
});
|
|
48
|
+
// Enrich skills with file lists and collect all files
|
|
49
|
+
const skills = [];
|
|
50
|
+
const allFiles = {};
|
|
51
|
+
for (const skill of discoveredSkills) {
|
|
52
|
+
const skillFiles = await listSkillFiles(skill.localPath);
|
|
53
|
+
// Add to skills with file list
|
|
54
|
+
skills.push({
|
|
55
|
+
...skill,
|
|
56
|
+
files: skillFiles,
|
|
57
|
+
});
|
|
58
|
+
// Read and collect all files for this skill
|
|
59
|
+
const skillDirName = path.basename(skill.localPath);
|
|
60
|
+
for (const file of skillFiles) {
|
|
61
|
+
const localFilePath = path.join(skill.localPath, file);
|
|
62
|
+
const relativeFilePath = `./${path.posix.join(destination, skillDirName, file)}`;
|
|
63
|
+
try {
|
|
64
|
+
const content = await fs.readFile(localFilePath, "utf-8");
|
|
65
|
+
allFiles[relativeFilePath] = content;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Skip files that can't be read as text
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Create loadSkill tool
|
|
73
|
+
const loadSkill = createLoadSkillTool({ skills });
|
|
74
|
+
// Generate instructions for bash tool
|
|
75
|
+
const instructions = generateSkillInstructions(skills);
|
|
76
|
+
return {
|
|
77
|
+
loadSkill,
|
|
78
|
+
skills,
|
|
79
|
+
files: allFiles,
|
|
80
|
+
instructions,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate bash tool instructions that include skill paths.
|
|
85
|
+
*/
|
|
86
|
+
function generateSkillInstructions(skills) {
|
|
87
|
+
if (skills.length === 0) {
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
const lines = [
|
|
91
|
+
"SKILL DIRECTORIES:",
|
|
92
|
+
"Skills are available at the following paths:",
|
|
93
|
+
];
|
|
94
|
+
for (const skill of skills) {
|
|
95
|
+
lines.push(` ${skill.sandboxPath}/ - ${skill.name}: ${skill.description}`);
|
|
96
|
+
}
|
|
97
|
+
lines.push("");
|
|
98
|
+
lines.push("To use a skill:");
|
|
99
|
+
lines.push(" 1. Call loadSkill to get the skill's instructions");
|
|
100
|
+
lines.push(" 2. Run scripts from the skill directory with bash");
|
|
101
|
+
return lines.join("\n");
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=skill-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-tool.js","sourceRoot":"","sources":["../src/skill-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DiscoveredSkill, SkillMetadata } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse YAML frontmatter from SKILL.md content using gray-matter.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseFrontmatter(content: string): SkillMetadata | null;
|
|
6
|
+
/**
|
|
7
|
+
* Extract the body (instructions) from SKILL.md content.
|
|
8
|
+
* This is everything after the frontmatter.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractBody(content: string): string;
|
|
11
|
+
export interface DiscoverSkillsOptions {
|
|
12
|
+
/** Local directory containing skill subdirectories */
|
|
13
|
+
skillsDirectory: string;
|
|
14
|
+
/** Base path in sandbox where skills will be uploaded */
|
|
15
|
+
sandboxDestination: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Discover all skills in a directory.
|
|
19
|
+
* Looks for subdirectories containing SKILL.md files.
|
|
20
|
+
*/
|
|
21
|
+
export declare function discoverSkills(options: DiscoverSkillsOptions): Promise<DiscoveredSkill[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Read and parse a SKILL.md file, returning both metadata and body.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readSkillMd(skillMdPath: string): Promise<{
|
|
26
|
+
metadata: SkillMetadata;
|
|
27
|
+
body: string;
|
|
28
|
+
} | null>;
|
|
29
|
+
/**
|
|
30
|
+
* List files in a skill directory (for listing available scripts).
|
|
31
|
+
*/
|
|
32
|
+
export declare function listSkillFiles(skillPath: string): Promise<string[]>;
|
|
33
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/skills/parser.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjE;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAqBtE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,EAAE,CAAC,CA0C5B;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAgB3D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBzE"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
/**
|
|
5
|
+
* Parse YAML frontmatter from SKILL.md content using gray-matter.
|
|
6
|
+
*/
|
|
7
|
+
export function parseFrontmatter(content) {
|
|
8
|
+
try {
|
|
9
|
+
const { data } = matter(content);
|
|
10
|
+
// Validate required fields
|
|
11
|
+
if (typeof data.name !== "string" ||
|
|
12
|
+
typeof data.description !== "string" ||
|
|
13
|
+
!data.name ||
|
|
14
|
+
!data.description) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name: data.name,
|
|
19
|
+
description: data.description,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Extract the body (instructions) from SKILL.md content.
|
|
28
|
+
* This is everything after the frontmatter.
|
|
29
|
+
*/
|
|
30
|
+
export function extractBody(content) {
|
|
31
|
+
try {
|
|
32
|
+
const { content: body } = matter(content);
|
|
33
|
+
return body.trim();
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return content.trim();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Discover all skills in a directory.
|
|
41
|
+
* Looks for subdirectories containing SKILL.md files.
|
|
42
|
+
*/
|
|
43
|
+
export async function discoverSkills(options) {
|
|
44
|
+
const { skillsDirectory, sandboxDestination } = options;
|
|
45
|
+
const skills = [];
|
|
46
|
+
const absoluteDir = path.resolve(skillsDirectory);
|
|
47
|
+
let entries;
|
|
48
|
+
try {
|
|
49
|
+
entries = await fs.readdir(absoluteDir);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw new Error(`Failed to read skills directory: ${absoluteDir}. ${error instanceof Error ? error.message : String(error)}`);
|
|
53
|
+
}
|
|
54
|
+
for (const entryName of entries) {
|
|
55
|
+
const skillDir = path.join(absoluteDir, entryName);
|
|
56
|
+
// Check if it's a directory
|
|
57
|
+
try {
|
|
58
|
+
const stat = await fs.stat(skillDir);
|
|
59
|
+
if (!stat.isDirectory())
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const skillMdPath = path.join(skillDir, "SKILL.md");
|
|
66
|
+
try {
|
|
67
|
+
const content = await fs.readFile(skillMdPath, "utf-8");
|
|
68
|
+
const metadata = parseFrontmatter(content);
|
|
69
|
+
if (metadata) {
|
|
70
|
+
skills.push({
|
|
71
|
+
...metadata,
|
|
72
|
+
localPath: skillDir,
|
|
73
|
+
sandboxPath: `${sandboxDestination}/${entryName}`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch { }
|
|
78
|
+
}
|
|
79
|
+
return skills;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read and parse a SKILL.md file, returning both metadata and body.
|
|
83
|
+
*/
|
|
84
|
+
export async function readSkillMd(skillMdPath) {
|
|
85
|
+
try {
|
|
86
|
+
const content = await fs.readFile(skillMdPath, "utf-8");
|
|
87
|
+
const metadata = parseFrontmatter(content);
|
|
88
|
+
if (!metadata) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
metadata,
|
|
93
|
+
body: extractBody(content),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* List files in a skill directory (for listing available scripts).
|
|
102
|
+
*/
|
|
103
|
+
export async function listSkillFiles(skillPath) {
|
|
104
|
+
const files = [];
|
|
105
|
+
async function walkDir(dir, prefix = "") {
|
|
106
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
109
|
+
if (entry.isDirectory()) {
|
|
110
|
+
await walkDir(path.join(dir, entry.name), relativePath);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
files.push(relativePath);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
await walkDir(skillPath);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// Return empty if directory doesn't exist
|
|
122
|
+
}
|
|
123
|
+
return files;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/skills/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { createLoadSkillTool } from "../tools/load-skill.js";
|
|
2
|
+
/**
|
|
3
|
+
* Skill metadata parsed from SKILL.md frontmatter.
|
|
4
|
+
*/
|
|
5
|
+
export interface SkillMetadata {
|
|
6
|
+
/** Unique skill name (lowercase, hyphens allowed) */
|
|
7
|
+
name: string;
|
|
8
|
+
/** Description of what the skill does and when to use it */
|
|
9
|
+
description: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Base skill info from discovery (without file list).
|
|
13
|
+
*/
|
|
14
|
+
export interface DiscoveredSkill extends SkillMetadata {
|
|
15
|
+
/** Absolute path to the skill directory on disk */
|
|
16
|
+
localPath: string;
|
|
17
|
+
/** Path to the skill directory in the sandbox */
|
|
18
|
+
sandboxPath: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Full skill representation with file list.
|
|
22
|
+
*/
|
|
23
|
+
export interface Skill extends DiscoveredSkill {
|
|
24
|
+
/** List of files in the skill directory (relative paths) */
|
|
25
|
+
files: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for creating a skill toolkit.
|
|
29
|
+
*/
|
|
30
|
+
export interface CreateSkillToolOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Path to the directory containing skill subdirectories.
|
|
33
|
+
* Each subdirectory should contain a SKILL.md file.
|
|
34
|
+
* @example "./skills" or "/path/to/skills"
|
|
35
|
+
*/
|
|
36
|
+
skillsDirectory: string;
|
|
37
|
+
/**
|
|
38
|
+
* Relative path within the workspace where skills will be placed.
|
|
39
|
+
* @default "skills"
|
|
40
|
+
* @example "skills" -> files at ./skills/...
|
|
41
|
+
*/
|
|
42
|
+
destination?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Return type from createSkillTool.
|
|
46
|
+
*/
|
|
47
|
+
export interface SkillToolkit {
|
|
48
|
+
/** Tool to load a skill's instructions into context */
|
|
49
|
+
loadSkill: ReturnType<typeof createLoadSkillTool>;
|
|
50
|
+
/** Registry of discovered skills */
|
|
51
|
+
skills: Skill[];
|
|
52
|
+
/** Files to pass to createBashTool (path -> content) */
|
|
53
|
+
files: Record<string, string>;
|
|
54
|
+
/** Extra instructions to pass to createBashTool */
|
|
55
|
+
instructions: string;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/skills/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,KAAM,SAAQ,eAAe;IAC5C,4DAA4D;IAC5D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,SAAS,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;IAClD,oCAAoC;IACpC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,mDAAmD;IACnD,YAAY,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/skills/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Skill } from "../skills/types.js";
|
|
2
|
+
export interface CreateLoadSkillToolOptions {
|
|
3
|
+
/** Registry of discovered skills */
|
|
4
|
+
skills: Skill[];
|
|
5
|
+
}
|
|
6
|
+
export declare function createLoadSkillTool(options: CreateLoadSkillToolOptions): import("ai").Tool<{
|
|
7
|
+
skillName: string;
|
|
8
|
+
}, {
|
|
9
|
+
success: boolean;
|
|
10
|
+
error: string;
|
|
11
|
+
skill?: undefined;
|
|
12
|
+
instructions?: undefined;
|
|
13
|
+
files?: undefined;
|
|
14
|
+
} | {
|
|
15
|
+
success: boolean;
|
|
16
|
+
skill: {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
path: string;
|
|
20
|
+
};
|
|
21
|
+
instructions: string;
|
|
22
|
+
files: string[];
|
|
23
|
+
error?: undefined;
|
|
24
|
+
}>;
|
|
25
|
+
//# sourceMappingURL=load-skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-skill.d.ts","sourceRoot":"","sources":["../../src/tools/load-skill.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAMhD,MAAM,WAAW,0BAA0B;IACzC,oCAAoC;IACpC,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AA0BD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B;;;;;;;;;;;;;;;;;;GAmDtE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { tool } from "ai";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { extractBody } from "../skills/parser.js";
|
|
6
|
+
const loadSkillSchema = z.object({
|
|
7
|
+
skillName: z.string().describe("The name of the skill to load"),
|
|
8
|
+
});
|
|
9
|
+
function generateDescription(skills) {
|
|
10
|
+
const lines = [
|
|
11
|
+
"Load a skill's instructions to learn how to use it.",
|
|
12
|
+
"You can load multiple skills - each call returns that skill's instructions.",
|
|
13
|
+
"",
|
|
14
|
+
"Available skills:",
|
|
15
|
+
];
|
|
16
|
+
if (skills.length === 0) {
|
|
17
|
+
lines.push(" (no skills found)");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
for (const skill of skills) {
|
|
21
|
+
lines.push(` - ${skill.name}: ${skill.description}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
lines.push("");
|
|
25
|
+
lines.push("After loading a skill, use the bash tool to run its scripts from the skill's directory.");
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
28
|
+
export function createLoadSkillTool(options) {
|
|
29
|
+
const { skills } = options;
|
|
30
|
+
// Create a map for quick lookup
|
|
31
|
+
const skillMap = new Map();
|
|
32
|
+
for (const skill of skills) {
|
|
33
|
+
skillMap.set(skill.name, skill);
|
|
34
|
+
}
|
|
35
|
+
return tool({
|
|
36
|
+
description: generateDescription(skills),
|
|
37
|
+
inputSchema: loadSkillSchema,
|
|
38
|
+
execute: async ({ skillName }) => {
|
|
39
|
+
const skill = skillMap.get(skillName);
|
|
40
|
+
if (!skill) {
|
|
41
|
+
const availableNames = skills.map((s) => s.name).join(", ");
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
error: `Skill "${skillName}" not found. Available skills: ${availableNames || "none"}`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Read the SKILL.md from local filesystem
|
|
48
|
+
const skillMdPath = path.join(skill.localPath, "SKILL.md");
|
|
49
|
+
try {
|
|
50
|
+
const content = await fs.readFile(skillMdPath, "utf-8");
|
|
51
|
+
const body = extractBody(content);
|
|
52
|
+
// Get files list (excluding SKILL.md)
|
|
53
|
+
const files = skill.files.filter((f) => f !== "SKILL.md");
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
skill: {
|
|
57
|
+
name: skill.name,
|
|
58
|
+
description: skill.description,
|
|
59
|
+
path: skill.sandboxPath,
|
|
60
|
+
},
|
|
61
|
+
instructions: body,
|
|
62
|
+
files,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
error: `Failed to read skill "${skillName}": ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=load-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-skill.js","sourceRoot":"","sources":["../../src/tools/load-skill.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface BeforeBashCallInput {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Output from onBeforeBashCall callback.
|
|
25
|
-
* Return
|
|
25
|
+
* Return nothing to proceed unchanged.
|
|
26
26
|
*/
|
|
27
27
|
export interface BeforeBashCallOutput {
|
|
28
28
|
/** The (potentially modified) command to execute */
|
|
@@ -39,7 +39,7 @@ export interface AfterBashCallInput {
|
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
41
|
* Output from onAfterBashCall callback.
|
|
42
|
-
* Return
|
|
42
|
+
* Return nothing to proceed unchanged.
|
|
43
43
|
*/
|
|
44
44
|
export interface AfterBashCallOutput {
|
|
45
45
|
/** The (potentially modified) result */
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.3.
|
|
6
|
+
"version": "1.3.7",
|
|
7
7
|
"description": "Generic bash tool for AI agents, compatible with AI SDK",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "dist/index.js",
|
|
@@ -44,14 +44,15 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"fast-glob": "^3.3.2",
|
|
47
|
+
"gray-matter": "^4.0.3",
|
|
47
48
|
"zod": "^3.23.8"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@biomejs/biome": "^2.3.11",
|
|
51
52
|
"@types/node": "^22.10.0",
|
|
52
|
-
"@vercel/sandbox": "^1.
|
|
53
|
+
"@vercel/sandbox": "^1.2.0",
|
|
53
54
|
"ai": "^6.0.13",
|
|
54
|
-
"just-bash": "^2.5.
|
|
55
|
+
"just-bash": "^2.5.1",
|
|
55
56
|
"knip": "^5.80.0",
|
|
56
57
|
"typescript": "^5.7.0",
|
|
57
58
|
"vitest": "^2.1.0"
|
|
@@ -69,10 +70,9 @@
|
|
|
69
70
|
"optional": true
|
|
70
71
|
}
|
|
71
72
|
},
|
|
72
|
-
"packageManager": "pnpm@8.15.9+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81",
|
|
73
73
|
"scripts": {
|
|
74
74
|
"build": "tsc -p tsconfig.build.json && sed '1,/^-->/d' AGENTS.npm.md > dist/AGENTS.md",
|
|
75
|
-
"typecheck": "tsc --noEmit",
|
|
75
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.examples.json",
|
|
76
76
|
"test": "vitest --exclude 'src/tool.vercel.integration.test.ts'",
|
|
77
77
|
"test:run": "vitest run --exclude 'src/tool.vercel.integration.test.ts'",
|
|
78
78
|
"test:vercel": "vitest run src/tool.vercel.integration.test.ts --sequence.concurrent",
|
|
@@ -80,6 +80,6 @@
|
|
|
80
80
|
"lint:fix": "biome check --write .",
|
|
81
81
|
"format": "biome format --write .",
|
|
82
82
|
"knip": "knip",
|
|
83
|
-
"validate": "pnpm run lint && pnpm run knip && pnpm run typecheck && pnpm run test:run"
|
|
83
|
+
"validate": "pnpm run lint && pnpm run knip && pnpm run typecheck && pnpm run build && pnpm run test:run"
|
|
84
84
|
}
|
|
85
85
|
}
|