@agentforge-ai/cli 0.3.2 → 0.4.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/dist/default/.env.example +46 -6
- package/dist/default/README.md +89 -9
- package/dist/default/convex/schema.ts +248 -4
- package/dist/default/dashboard/app/components/DashboardLayout.tsx +245 -0
- package/dist/default/dashboard/app/components/ui/badge.tsx +26 -0
- package/dist/default/dashboard/app/components/ui/button.tsx +41 -0
- package/dist/default/dashboard/app/components/ui/card.tsx +44 -0
- package/dist/default/dashboard/app/components/ui/dialog.tsx +66 -0
- package/dist/default/dashboard/app/components/ui/input.tsx +21 -0
- package/dist/default/dashboard/app/components/ui/label.tsx +18 -0
- package/dist/default/dashboard/app/components/ui/select.tsx +75 -0
- package/dist/default/dashboard/app/components/ui/sheet.tsx +73 -0
- package/dist/default/dashboard/app/components/ui/switch.tsx +34 -0
- package/dist/default/dashboard/app/components/ui/table.tsx +60 -0
- package/dist/default/dashboard/app/components/ui/tabs.tsx +50 -0
- package/dist/default/dashboard/app/components/ui/tooltip.tsx +23 -0
- package/dist/default/dashboard/app/lib/utils.ts +6 -0
- package/dist/default/dashboard/app/main.tsx +35 -0
- package/dist/default/dashboard/app/routeTree.gen.ts +352 -0
- package/dist/default/dashboard/app/routes/__root.tsx +10 -0
- package/dist/default/dashboard/app/routes/agents.tsx +255 -0
- package/dist/default/dashboard/app/routes/chat.tsx +427 -0
- package/dist/default/dashboard/app/routes/connections.tsx +413 -0
- package/dist/default/dashboard/app/routes/cron.tsx +322 -0
- package/dist/default/dashboard/app/routes/files.tsx +203 -0
- package/dist/default/dashboard/app/routes/index.tsx +141 -0
- package/dist/default/dashboard/app/routes/projects.tsx +254 -0
- package/dist/default/dashboard/app/routes/sessions.tsx +272 -0
- package/dist/default/dashboard/app/routes/settings.tsx +583 -0
- package/dist/default/dashboard/app/routes/skills.tsx +252 -0
- package/dist/default/dashboard/app/routes/usage.tsx +181 -0
- package/dist/default/dashboard/app/styles/globals.css +93 -0
- package/dist/default/dashboard/index.html +13 -0
- package/dist/default/dashboard/package.json +36 -0
- package/dist/default/dashboard/postcss.config.js +6 -0
- package/dist/default/dashboard/tailwind.config.js +50 -0
- package/dist/default/dashboard/tsconfig.json +24 -0
- package/dist/default/dashboard/vite.config.ts +16 -0
- package/dist/default/package.json +8 -3
- package/dist/default/skills/skill-creator/SKILL.md +270 -0
- package/dist/default/skills/skill-creator/config.json +11 -0
- package/dist/default/skills/skill-creator/index.ts +392 -0
- package/dist/default/src/agent.ts +85 -5
- package/dist/index.js +1574 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/templates/default/.env.example +46 -6
- package/templates/default/README.md +89 -9
- package/templates/default/convex/schema.ts +248 -4
- package/templates/default/dashboard/app/components/DashboardLayout.tsx +245 -0
- package/templates/default/dashboard/app/components/ui/badge.tsx +26 -0
- package/templates/default/dashboard/app/components/ui/button.tsx +41 -0
- package/templates/default/dashboard/app/components/ui/card.tsx +44 -0
- package/templates/default/dashboard/app/components/ui/dialog.tsx +66 -0
- package/templates/default/dashboard/app/components/ui/input.tsx +21 -0
- package/templates/default/dashboard/app/components/ui/label.tsx +18 -0
- package/templates/default/dashboard/app/components/ui/select.tsx +75 -0
- package/templates/default/dashboard/app/components/ui/sheet.tsx +73 -0
- package/templates/default/dashboard/app/components/ui/switch.tsx +34 -0
- package/templates/default/dashboard/app/components/ui/table.tsx +60 -0
- package/templates/default/dashboard/app/components/ui/tabs.tsx +50 -0
- package/templates/default/dashboard/app/components/ui/tooltip.tsx +23 -0
- package/templates/default/dashboard/app/lib/utils.ts +6 -0
- package/templates/default/dashboard/app/main.tsx +35 -0
- package/templates/default/dashboard/app/routeTree.gen.ts +352 -0
- package/templates/default/dashboard/app/routes/__root.tsx +10 -0
- package/templates/default/dashboard/app/routes/agents.tsx +255 -0
- package/templates/default/dashboard/app/routes/chat.tsx +427 -0
- package/templates/default/dashboard/app/routes/connections.tsx +413 -0
- package/templates/default/dashboard/app/routes/cron.tsx +322 -0
- package/templates/default/dashboard/app/routes/files.tsx +203 -0
- package/templates/default/dashboard/app/routes/index.tsx +141 -0
- package/templates/default/dashboard/app/routes/projects.tsx +254 -0
- package/templates/default/dashboard/app/routes/sessions.tsx +272 -0
- package/templates/default/dashboard/app/routes/settings.tsx +583 -0
- package/templates/default/dashboard/app/routes/skills.tsx +252 -0
- package/templates/default/dashboard/app/routes/usage.tsx +181 -0
- package/templates/default/dashboard/app/styles/globals.css +93 -0
- package/templates/default/dashboard/index.html +13 -0
- package/templates/default/dashboard/package.json +36 -0
- package/templates/default/dashboard/postcss.config.js +6 -0
- package/templates/default/dashboard/tailwind.config.js +50 -0
- package/templates/default/dashboard/tsconfig.json +24 -0
- package/templates/default/dashboard/vite.config.ts +16 -0
- package/templates/default/package.json +8 -3
- package/templates/default/skills/skill-creator/SKILL.md +270 -0
- package/templates/default/skills/skill-creator/config.json +11 -0
- package/templates/default/skills/skill-creator/index.ts +392 -0
- package/templates/default/src/agent.ts +85 -5
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react(), tsconfigPaths()],
|
|
7
|
+
build: {
|
|
8
|
+
outDir: "dist",
|
|
9
|
+
sourcemap: true,
|
|
10
|
+
},
|
|
11
|
+
server: {
|
|
12
|
+
port: 3000,
|
|
13
|
+
host: "0.0.0.0",
|
|
14
|
+
allowedHosts: true,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -7,11 +7,16 @@
|
|
|
7
7
|
"dev": "agentforge run",
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"convex:dev": "npx convex dev",
|
|
10
|
-
"convex:deploy": "npx convex deploy"
|
|
10
|
+
"convex:deploy": "npx convex deploy",
|
|
11
|
+
"dashboard": "agentforge dashboard",
|
|
12
|
+
"dashboard:install": "cd dashboard && pnpm install",
|
|
13
|
+
"dashboard:dev": "cd dashboard && pnpm dev",
|
|
14
|
+
"dashboard:build": "cd dashboard && pnpm build"
|
|
11
15
|
},
|
|
12
16
|
"dependencies": {
|
|
13
|
-
"@agentforge-ai/core": "^0.
|
|
14
|
-
"convex": "^1.17.0"
|
|
17
|
+
"@agentforge-ai/core": "^0.4.0",
|
|
18
|
+
"convex": "^1.17.0",
|
|
19
|
+
"zod": "^3.23.0"
|
|
15
20
|
},
|
|
16
21
|
"devDependencies": {
|
|
17
22
|
"typescript": "^5.5.0"
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Skill Creator
|
|
2
|
+
|
|
3
|
+
**Built-in AgentForge Skill** — Create, manage, and discover skills for your agents.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Skill Creator is a default skill that ships with every AgentForge project. It allows you to:
|
|
8
|
+
|
|
9
|
+
1. **Create new skills** from natural language descriptions
|
|
10
|
+
2. **Browse example skills** to understand the skill format
|
|
11
|
+
3. **Validate skills** before installing them
|
|
12
|
+
4. **Generate skill code** using your connected LLM
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Via CLI
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Create a new skill interactively
|
|
20
|
+
agentforge skills create
|
|
21
|
+
|
|
22
|
+
# Ask the agent to create a skill
|
|
23
|
+
agentforge chat my-agent
|
|
24
|
+
> Create a skill that can fetch weather data for any city
|
|
25
|
+
|
|
26
|
+
# List available example skills
|
|
27
|
+
agentforge skills search examples
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Via Dashboard
|
|
31
|
+
|
|
32
|
+
Navigate to **Skills** in the sidebar, then click **"Create Skill"** to use the visual skill builder.
|
|
33
|
+
|
|
34
|
+
### Via Agent Chat
|
|
35
|
+
|
|
36
|
+
When chatting with an agent that has the Skill Creator tool enabled, simply ask:
|
|
37
|
+
|
|
38
|
+
> "Create a skill that can [description of what you want]"
|
|
39
|
+
|
|
40
|
+
The agent will generate the skill definition, validate it, and offer to install it.
|
|
41
|
+
|
|
42
|
+
## Skill Format
|
|
43
|
+
|
|
44
|
+
Every AgentForge skill is a directory with the following structure:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
skills/
|
|
48
|
+
my-skill/
|
|
49
|
+
SKILL.md # Documentation and instructions
|
|
50
|
+
index.ts # Main skill entry point
|
|
51
|
+
config.json # Skill metadata and configuration
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### config.json
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"name": "my-skill",
|
|
59
|
+
"version": "1.0.0",
|
|
60
|
+
"description": "What this skill does",
|
|
61
|
+
"category": "utility",
|
|
62
|
+
"author": "Your Name",
|
|
63
|
+
"tools": ["tool-name-1", "tool-name-2"],
|
|
64
|
+
"dependencies": [],
|
|
65
|
+
"agentInstructions": "Additional instructions for agents using this skill"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### index.ts
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { z } from 'zod';
|
|
73
|
+
|
|
74
|
+
export const tools = [
|
|
75
|
+
{
|
|
76
|
+
name: 'my-tool',
|
|
77
|
+
description: 'What this tool does',
|
|
78
|
+
inputSchema: z.object({
|
|
79
|
+
param1: z.string().describe('Description of param1'),
|
|
80
|
+
}),
|
|
81
|
+
outputSchema: z.object({
|
|
82
|
+
result: z.string(),
|
|
83
|
+
}),
|
|
84
|
+
handler: async (input: { param1: string }) => {
|
|
85
|
+
// Your tool logic here
|
|
86
|
+
return { result: `Processed: ${input.param1}` };
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
export default { tools };
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Example Skills
|
|
95
|
+
|
|
96
|
+
### 1. Web Search Skill
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// skills/web-search/index.ts
|
|
100
|
+
import { z } from 'zod';
|
|
101
|
+
|
|
102
|
+
export const tools = [
|
|
103
|
+
{
|
|
104
|
+
name: 'web-search',
|
|
105
|
+
description: 'Search the web for information',
|
|
106
|
+
inputSchema: z.object({
|
|
107
|
+
query: z.string().describe('Search query'),
|
|
108
|
+
maxResults: z.number().optional().default(5),
|
|
109
|
+
}),
|
|
110
|
+
outputSchema: z.object({
|
|
111
|
+
results: z.array(z.object({
|
|
112
|
+
title: z.string(),
|
|
113
|
+
url: z.string(),
|
|
114
|
+
snippet: z.string(),
|
|
115
|
+
})),
|
|
116
|
+
}),
|
|
117
|
+
handler: async (input) => {
|
|
118
|
+
// Implement with your preferred search API
|
|
119
|
+
const response = await fetch(
|
|
120
|
+
`https://api.search.example/search?q=${encodeURIComponent(input.query)}&limit=${input.maxResults}`
|
|
121
|
+
);
|
|
122
|
+
const data = await response.json();
|
|
123
|
+
return { results: data.results };
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 2. Calculator Skill
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// skills/calculator/index.ts
|
|
133
|
+
import { z } from 'zod';
|
|
134
|
+
|
|
135
|
+
export const tools = [
|
|
136
|
+
{
|
|
137
|
+
name: 'calculate',
|
|
138
|
+
description: 'Evaluate a mathematical expression',
|
|
139
|
+
inputSchema: z.object({
|
|
140
|
+
expression: z.string().describe('Math expression to evaluate (e.g., "2 + 2 * 3")'),
|
|
141
|
+
}),
|
|
142
|
+
outputSchema: z.object({
|
|
143
|
+
result: z.number(),
|
|
144
|
+
expression: z.string(),
|
|
145
|
+
}),
|
|
146
|
+
handler: async (input) => {
|
|
147
|
+
const result = Function('"use strict"; return (' + input.expression + ')')();
|
|
148
|
+
return { result: Number(result), expression: input.expression };
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
];
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 3. File Reader Skill
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// skills/file-reader/index.ts
|
|
158
|
+
import { z } from 'zod';
|
|
159
|
+
import { readFile } from 'fs/promises';
|
|
160
|
+
|
|
161
|
+
export const tools = [
|
|
162
|
+
{
|
|
163
|
+
name: 'read-file',
|
|
164
|
+
description: 'Read the contents of a file',
|
|
165
|
+
inputSchema: z.object({
|
|
166
|
+
path: z.string().describe('Path to the file'),
|
|
167
|
+
encoding: z.string().optional().default('utf-8'),
|
|
168
|
+
}),
|
|
169
|
+
outputSchema: z.object({
|
|
170
|
+
content: z.string(),
|
|
171
|
+
size: z.number(),
|
|
172
|
+
}),
|
|
173
|
+
handler: async (input) => {
|
|
174
|
+
const content = await readFile(input.path, input.encoding as BufferEncoding);
|
|
175
|
+
return { content, size: content.length };
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
];
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 4. JSON Transformer Skill
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// skills/json-transformer/index.ts
|
|
185
|
+
import { z } from 'zod';
|
|
186
|
+
|
|
187
|
+
export const tools = [
|
|
188
|
+
{
|
|
189
|
+
name: 'transform-json',
|
|
190
|
+
description: 'Transform JSON data using a jq-like expression',
|
|
191
|
+
inputSchema: z.object({
|
|
192
|
+
data: z.string().describe('JSON string to transform'),
|
|
193
|
+
path: z.string().describe('Dot-notation path to extract (e.g., "users.0.name")'),
|
|
194
|
+
}),
|
|
195
|
+
outputSchema: z.object({
|
|
196
|
+
result: z.any(),
|
|
197
|
+
}),
|
|
198
|
+
handler: async (input) => {
|
|
199
|
+
const obj = JSON.parse(input.data);
|
|
200
|
+
const parts = input.path.split('.');
|
|
201
|
+
let current: any = obj;
|
|
202
|
+
for (const part of parts) {
|
|
203
|
+
current = current?.[part] ?? current?.[Number(part)];
|
|
204
|
+
}
|
|
205
|
+
return { result: current };
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 5. HTTP Request Skill
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// skills/http-request/index.ts
|
|
215
|
+
import { z } from 'zod';
|
|
216
|
+
|
|
217
|
+
export const tools = [
|
|
218
|
+
{
|
|
219
|
+
name: 'http-request',
|
|
220
|
+
description: 'Make an HTTP request to any URL',
|
|
221
|
+
inputSchema: z.object({
|
|
222
|
+
url: z.string().url().describe('URL to request'),
|
|
223
|
+
method: z.enum(['GET', 'POST', 'PUT', 'DELETE']).default('GET'),
|
|
224
|
+
headers: z.record(z.string()).optional(),
|
|
225
|
+
body: z.string().optional(),
|
|
226
|
+
}),
|
|
227
|
+
outputSchema: z.object({
|
|
228
|
+
status: z.number(),
|
|
229
|
+
body: z.string(),
|
|
230
|
+
headers: z.record(z.string()),
|
|
231
|
+
}),
|
|
232
|
+
handler: async (input) => {
|
|
233
|
+
const response = await fetch(input.url, {
|
|
234
|
+
method: input.method,
|
|
235
|
+
headers: input.headers,
|
|
236
|
+
body: input.body,
|
|
237
|
+
});
|
|
238
|
+
const body = await response.text();
|
|
239
|
+
const headers: Record<string, string> = {};
|
|
240
|
+
response.headers.forEach((v, k) => { headers[k] = v; });
|
|
241
|
+
return { status: response.status, body, headers };
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Creating Skills with AI
|
|
248
|
+
|
|
249
|
+
When you ask an agent to create a skill, the Skill Creator tool will:
|
|
250
|
+
|
|
251
|
+
1. **Parse your request** — Understand what the skill should do
|
|
252
|
+
2. **Generate the code** — Create `index.ts` with proper Zod schemas
|
|
253
|
+
3. **Create metadata** — Generate `config.json` with name, description, category
|
|
254
|
+
4. **Write documentation** — Generate `SKILL.md` with usage instructions
|
|
255
|
+
5. **Validate** — Ensure the skill compiles and schemas are correct
|
|
256
|
+
6. **Install** — Save to your `skills/` directory and register with Convex
|
|
257
|
+
|
|
258
|
+
## Categories
|
|
259
|
+
|
|
260
|
+
Skills are organized by category:
|
|
261
|
+
|
|
262
|
+
| Category | Description | Examples |
|
|
263
|
+
|----------|-------------|---------|
|
|
264
|
+
| `utility` | General-purpose tools | Calculator, JSON transformer |
|
|
265
|
+
| `web` | Web interaction | HTTP requests, web search, scraping |
|
|
266
|
+
| `file` | File operations | Read, write, transform files |
|
|
267
|
+
| `data` | Data processing | CSV parsing, data analysis |
|
|
268
|
+
| `integration` | External services | Slack, GitHub, email |
|
|
269
|
+
| `ai` | AI-powered tools | Summarization, translation |
|
|
270
|
+
| `custom` | User-defined | Anything else |
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skill-creator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Built-in skill for creating, managing, and discovering AgentForge skills. Allows agents to generate new skills from natural language descriptions.",
|
|
5
|
+
"category": "utility",
|
|
6
|
+
"author": "AgentForge",
|
|
7
|
+
"isBuiltIn": true,
|
|
8
|
+
"tools": ["create-skill", "list-examples", "validate-skill"],
|
|
9
|
+
"dependencies": [],
|
|
10
|
+
"agentInstructions": "You have access to the Skill Creator tool. When a user asks you to create a skill, use the create-skill tool to generate the skill code, config, and documentation. You can also use list-examples to show available example skills, and validate-skill to check if a skill definition is valid."
|
|
11
|
+
}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Skill Creator — Built-in AgentForge Skill
|
|
5
|
+
*
|
|
6
|
+
* Provides tools for creating, discovering, and validating skills.
|
|
7
|
+
* This skill is automatically available in every AgentForge project.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ─── Example Skills Registry ───────────────────────────────────────────
|
|
11
|
+
const EXAMPLE_SKILLS = [
|
|
12
|
+
{
|
|
13
|
+
name: 'web-search',
|
|
14
|
+
description: 'Search the web for information using a search API',
|
|
15
|
+
category: 'web',
|
|
16
|
+
complexity: 'medium',
|
|
17
|
+
template: `import { z } from 'zod';
|
|
18
|
+
export const tools = [{
|
|
19
|
+
name: 'web-search',
|
|
20
|
+
description: 'Search the web for information',
|
|
21
|
+
inputSchema: z.object({ query: z.string(), maxResults: z.number().optional().default(5) }),
|
|
22
|
+
outputSchema: z.object({ results: z.array(z.object({ title: z.string(), url: z.string(), snippet: z.string() })) }),
|
|
23
|
+
handler: async (input) => {
|
|
24
|
+
const response = await fetch(\`https://api.search.example/search?q=\${encodeURIComponent(input.query)}&limit=\${input.maxResults}\`);
|
|
25
|
+
return { results: (await response.json()).results };
|
|
26
|
+
},
|
|
27
|
+
}];`,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'calculator',
|
|
31
|
+
description: 'Evaluate mathematical expressions safely',
|
|
32
|
+
category: 'utility',
|
|
33
|
+
complexity: 'simple',
|
|
34
|
+
template: `import { z } from 'zod';
|
|
35
|
+
export const tools = [{
|
|
36
|
+
name: 'calculate',
|
|
37
|
+
description: 'Evaluate a mathematical expression',
|
|
38
|
+
inputSchema: z.object({ expression: z.string().describe('Math expression, e.g. "2 + 2 * 3"') }),
|
|
39
|
+
outputSchema: z.object({ result: z.number(), expression: z.string() }),
|
|
40
|
+
handler: async (input) => {
|
|
41
|
+
const result = Function('"use strict"; return (' + input.expression + ')')();
|
|
42
|
+
return { result: Number(result), expression: input.expression };
|
|
43
|
+
},
|
|
44
|
+
}];`,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'file-reader',
|
|
48
|
+
description: 'Read file contents from the filesystem',
|
|
49
|
+
category: 'file',
|
|
50
|
+
complexity: 'simple',
|
|
51
|
+
template: `import { z } from 'zod';
|
|
52
|
+
import { readFile } from 'fs/promises';
|
|
53
|
+
export const tools = [{
|
|
54
|
+
name: 'read-file',
|
|
55
|
+
description: 'Read the contents of a file',
|
|
56
|
+
inputSchema: z.object({ path: z.string(), encoding: z.string().optional().default('utf-8') }),
|
|
57
|
+
outputSchema: z.object({ content: z.string(), size: z.number() }),
|
|
58
|
+
handler: async (input) => {
|
|
59
|
+
const content = await readFile(input.path, input.encoding as BufferEncoding);
|
|
60
|
+
return { content, size: content.length };
|
|
61
|
+
},
|
|
62
|
+
}];`,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'http-request',
|
|
66
|
+
description: 'Make HTTP requests to any URL',
|
|
67
|
+
category: 'web',
|
|
68
|
+
complexity: 'medium',
|
|
69
|
+
template: `import { z } from 'zod';
|
|
70
|
+
export const tools = [{
|
|
71
|
+
name: 'http-request',
|
|
72
|
+
description: 'Make an HTTP request to any URL',
|
|
73
|
+
inputSchema: z.object({
|
|
74
|
+
url: z.string().url(),
|
|
75
|
+
method: z.enum(['GET', 'POST', 'PUT', 'DELETE']).default('GET'),
|
|
76
|
+
headers: z.record(z.string()).optional(),
|
|
77
|
+
body: z.string().optional(),
|
|
78
|
+
}),
|
|
79
|
+
outputSchema: z.object({ status: z.number(), body: z.string() }),
|
|
80
|
+
handler: async (input) => {
|
|
81
|
+
const res = await fetch(input.url, { method: input.method, headers: input.headers, body: input.body });
|
|
82
|
+
return { status: res.status, body: await res.text() };
|
|
83
|
+
},
|
|
84
|
+
}];`,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'json-transformer',
|
|
88
|
+
description: 'Transform and extract data from JSON using dot-notation paths',
|
|
89
|
+
category: 'data',
|
|
90
|
+
complexity: 'simple',
|
|
91
|
+
template: `import { z } from 'zod';
|
|
92
|
+
export const tools = [{
|
|
93
|
+
name: 'transform-json',
|
|
94
|
+
description: 'Extract data from JSON using dot-notation path',
|
|
95
|
+
inputSchema: z.object({ data: z.string(), path: z.string() }),
|
|
96
|
+
outputSchema: z.object({ result: z.any() }),
|
|
97
|
+
handler: async (input) => {
|
|
98
|
+
const obj = JSON.parse(input.data);
|
|
99
|
+
let current = obj;
|
|
100
|
+
for (const part of input.path.split('.')) {
|
|
101
|
+
current = current?.[part] ?? current?.[Number(part)];
|
|
102
|
+
}
|
|
103
|
+
return { result: current };
|
|
104
|
+
},
|
|
105
|
+
}];`,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'text-summarizer',
|
|
109
|
+
description: 'Summarize long text into key points',
|
|
110
|
+
category: 'ai',
|
|
111
|
+
complexity: 'medium',
|
|
112
|
+
template: `import { z } from 'zod';
|
|
113
|
+
export const tools = [{
|
|
114
|
+
name: 'summarize',
|
|
115
|
+
description: 'Summarize text into key bullet points',
|
|
116
|
+
inputSchema: z.object({ text: z.string(), maxPoints: z.number().optional().default(5) }),
|
|
117
|
+
outputSchema: z.object({ summary: z.string(), keyPoints: z.array(z.string()) }),
|
|
118
|
+
handler: async (input) => {
|
|
119
|
+
const sentences = input.text.split(/[.!?]+/).filter(s => s.trim().length > 20);
|
|
120
|
+
const keyPoints = sentences.slice(0, input.maxPoints).map(s => s.trim());
|
|
121
|
+
return { summary: keyPoints.join('. ') + '.', keyPoints };
|
|
122
|
+
},
|
|
123
|
+
}];`,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'csv-parser',
|
|
127
|
+
description: 'Parse CSV data into structured JSON',
|
|
128
|
+
category: 'data',
|
|
129
|
+
complexity: 'medium',
|
|
130
|
+
template: `import { z } from 'zod';
|
|
131
|
+
export const tools = [{
|
|
132
|
+
name: 'parse-csv',
|
|
133
|
+
description: 'Parse CSV string into array of objects',
|
|
134
|
+
inputSchema: z.object({ csv: z.string(), delimiter: z.string().optional().default(',') }),
|
|
135
|
+
outputSchema: z.object({ rows: z.array(z.record(z.string())), count: z.number() }),
|
|
136
|
+
handler: async (input) => {
|
|
137
|
+
const lines = input.csv.trim().split('\\n');
|
|
138
|
+
const headers = lines[0].split(input.delimiter).map(h => h.trim());
|
|
139
|
+
const rows = lines.slice(1).map(line => {
|
|
140
|
+
const values = line.split(input.delimiter);
|
|
141
|
+
return Object.fromEntries(headers.map((h, i) => [h, values[i]?.trim() ?? '']));
|
|
142
|
+
});
|
|
143
|
+
return { rows, count: rows.length };
|
|
144
|
+
},
|
|
145
|
+
}];`,
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
// ─── Skill Creator Tools ───────────────────────────────────────────────
|
|
150
|
+
export const tools = [
|
|
151
|
+
{
|
|
152
|
+
name: 'create-skill',
|
|
153
|
+
description:
|
|
154
|
+
'Generate a new AgentForge skill from a natural language description. ' +
|
|
155
|
+
'Returns the complete skill code (index.ts), config (config.json), and documentation (SKILL.md). ' +
|
|
156
|
+
'The user can then review and install the skill.',
|
|
157
|
+
inputSchema: z.object({
|
|
158
|
+
name: z.string().describe('Skill name in kebab-case (e.g., "web-search")'),
|
|
159
|
+
description: z.string().describe('What the skill should do'),
|
|
160
|
+
category: z
|
|
161
|
+
.enum(['utility', 'web', 'file', 'data', 'integration', 'ai', 'custom'])
|
|
162
|
+
.default('custom')
|
|
163
|
+
.describe('Skill category'),
|
|
164
|
+
toolNames: z
|
|
165
|
+
.array(z.string())
|
|
166
|
+
.optional()
|
|
167
|
+
.describe('Names of tools to include (optional, will be auto-generated)'),
|
|
168
|
+
}),
|
|
169
|
+
outputSchema: z.object({
|
|
170
|
+
name: z.string(),
|
|
171
|
+
indexTs: z.string(),
|
|
172
|
+
configJson: z.string(),
|
|
173
|
+
skillMd: z.string(),
|
|
174
|
+
installCommand: z.string(),
|
|
175
|
+
}),
|
|
176
|
+
handler: async (input: {
|
|
177
|
+
name: string;
|
|
178
|
+
description: string;
|
|
179
|
+
category: string;
|
|
180
|
+
toolNames?: string[];
|
|
181
|
+
}) => {
|
|
182
|
+
const toolName = input.toolNames?.[0] ?? input.name;
|
|
183
|
+
|
|
184
|
+
// Generate index.ts
|
|
185
|
+
const indexTs = `import { z } from 'zod';
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* ${input.name} — AgentForge Skill
|
|
189
|
+
* ${input.description}
|
|
190
|
+
*/
|
|
191
|
+
export const tools = [
|
|
192
|
+
{
|
|
193
|
+
name: '${toolName}',
|
|
194
|
+
description: '${input.description}',
|
|
195
|
+
inputSchema: z.object({
|
|
196
|
+
input: z.string().describe('Input for ${toolName}'),
|
|
197
|
+
}),
|
|
198
|
+
outputSchema: z.object({
|
|
199
|
+
result: z.string(),
|
|
200
|
+
success: z.boolean(),
|
|
201
|
+
}),
|
|
202
|
+
handler: async (params: { input: string }) => {
|
|
203
|
+
// TODO: Implement your skill logic here
|
|
204
|
+
// This is a scaffold — replace with your actual implementation
|
|
205
|
+
return {
|
|
206
|
+
result: \`Processed: \${params.input}\`,
|
|
207
|
+
success: true,
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
export default { tools };
|
|
214
|
+
`;
|
|
215
|
+
|
|
216
|
+
// Generate config.json
|
|
217
|
+
const configJson = JSON.stringify(
|
|
218
|
+
{
|
|
219
|
+
name: input.name,
|
|
220
|
+
version: '1.0.0',
|
|
221
|
+
description: input.description,
|
|
222
|
+
category: input.category,
|
|
223
|
+
author: 'User',
|
|
224
|
+
tools: [toolName],
|
|
225
|
+
dependencies: [],
|
|
226
|
+
agentInstructions: `You have access to the ${input.name} skill. ${input.description}`,
|
|
227
|
+
},
|
|
228
|
+
null,
|
|
229
|
+
2
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Generate SKILL.md
|
|
233
|
+
const skillMd = `# ${input.name}
|
|
234
|
+
|
|
235
|
+
${input.description}
|
|
236
|
+
|
|
237
|
+
## Usage
|
|
238
|
+
|
|
239
|
+
### Via CLI
|
|
240
|
+
\`\`\`bash
|
|
241
|
+
agentforge skills install ${input.name}
|
|
242
|
+
\`\`\`
|
|
243
|
+
|
|
244
|
+
### Via Agent Chat
|
|
245
|
+
Ask your agent: "Use the ${toolName} tool to [your request]"
|
|
246
|
+
|
|
247
|
+
## Tools
|
|
248
|
+
|
|
249
|
+
### ${toolName}
|
|
250
|
+
${input.description}
|
|
251
|
+
|
|
252
|
+
**Input:**
|
|
253
|
+
- \`input\` (string) — Input for ${toolName}
|
|
254
|
+
|
|
255
|
+
**Output:**
|
|
256
|
+
- \`result\` (string) — The processed result
|
|
257
|
+
- \`success\` (boolean) — Whether the operation succeeded
|
|
258
|
+
|
|
259
|
+
## Configuration
|
|
260
|
+
|
|
261
|
+
Edit \`skills/${input.name}/config.json\` to customize behavior.
|
|
262
|
+
`;
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
name: input.name,
|
|
266
|
+
indexTs,
|
|
267
|
+
configJson,
|
|
268
|
+
skillMd,
|
|
269
|
+
installCommand: `agentforge skills install ${input.name}`,
|
|
270
|
+
};
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
{
|
|
275
|
+
name: 'list-examples',
|
|
276
|
+
description:
|
|
277
|
+
'List all available example skills with their descriptions, categories, and code templates. ' +
|
|
278
|
+
'Use this to show users what kinds of skills they can create.',
|
|
279
|
+
inputSchema: z.object({
|
|
280
|
+
category: z
|
|
281
|
+
.string()
|
|
282
|
+
.optional()
|
|
283
|
+
.describe('Filter by category (utility, web, file, data, ai)'),
|
|
284
|
+
showCode: z
|
|
285
|
+
.boolean()
|
|
286
|
+
.optional()
|
|
287
|
+
.default(false)
|
|
288
|
+
.describe('Include the full code template in the response'),
|
|
289
|
+
}),
|
|
290
|
+
outputSchema: z.object({
|
|
291
|
+
examples: z.array(
|
|
292
|
+
z.object({
|
|
293
|
+
name: z.string(),
|
|
294
|
+
description: z.string(),
|
|
295
|
+
category: z.string(),
|
|
296
|
+
complexity: z.string(),
|
|
297
|
+
template: z.string().optional(),
|
|
298
|
+
})
|
|
299
|
+
),
|
|
300
|
+
count: z.number(),
|
|
301
|
+
}),
|
|
302
|
+
handler: async (input: { category?: string; showCode?: boolean }) => {
|
|
303
|
+
let filtered = EXAMPLE_SKILLS;
|
|
304
|
+
if (input.category) {
|
|
305
|
+
filtered = filtered.filter((s) => s.category === input.category);
|
|
306
|
+
}
|
|
307
|
+
const examples = filtered.map((s) => ({
|
|
308
|
+
name: s.name,
|
|
309
|
+
description: s.description,
|
|
310
|
+
category: s.category,
|
|
311
|
+
complexity: s.complexity,
|
|
312
|
+
...(input.showCode ? { template: s.template } : {}),
|
|
313
|
+
}));
|
|
314
|
+
return { examples, count: examples.length };
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
{
|
|
319
|
+
name: 'validate-skill',
|
|
320
|
+
description:
|
|
321
|
+
'Validate a skill definition to ensure it has the correct structure, ' +
|
|
322
|
+
'required fields, and valid Zod schemas before installation.',
|
|
323
|
+
inputSchema: z.object({
|
|
324
|
+
name: z.string().describe('Skill name to validate'),
|
|
325
|
+
indexTs: z.string().describe('The index.ts file content'),
|
|
326
|
+
configJson: z.string().describe('The config.json file content'),
|
|
327
|
+
}),
|
|
328
|
+
outputSchema: z.object({
|
|
329
|
+
isValid: z.boolean(),
|
|
330
|
+
errors: z.array(z.string()),
|
|
331
|
+
warnings: z.array(z.string()),
|
|
332
|
+
}),
|
|
333
|
+
handler: async (input: {
|
|
334
|
+
name: string;
|
|
335
|
+
indexTs: string;
|
|
336
|
+
configJson: string;
|
|
337
|
+
}) => {
|
|
338
|
+
const errors: string[] = [];
|
|
339
|
+
const warnings: string[] = [];
|
|
340
|
+
|
|
341
|
+
// Validate name
|
|
342
|
+
if (!/^[a-z][a-z0-9-]*$/.test(input.name)) {
|
|
343
|
+
errors.push(
|
|
344
|
+
'Skill name must be kebab-case (lowercase letters, numbers, hyphens)'
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Validate index.ts
|
|
349
|
+
if (!input.indexTs.includes('export')) {
|
|
350
|
+
errors.push('index.ts must have at least one export');
|
|
351
|
+
}
|
|
352
|
+
if (!input.indexTs.includes('tools')) {
|
|
353
|
+
errors.push('index.ts must export a tools array');
|
|
354
|
+
}
|
|
355
|
+
if (!input.indexTs.includes('handler')) {
|
|
356
|
+
errors.push('Each tool must have a handler function');
|
|
357
|
+
}
|
|
358
|
+
if (!input.indexTs.includes('inputSchema')) {
|
|
359
|
+
warnings.push(
|
|
360
|
+
'Tools should define inputSchema for type safety'
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
if (!input.indexTs.includes('outputSchema')) {
|
|
364
|
+
warnings.push(
|
|
365
|
+
'Tools should define outputSchema for type safety'
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Validate config.json
|
|
370
|
+
try {
|
|
371
|
+
const config = JSON.parse(input.configJson);
|
|
372
|
+
if (!config.name) errors.push('config.json must have a "name" field');
|
|
373
|
+
if (!config.version)
|
|
374
|
+
errors.push('config.json must have a "version" field');
|
|
375
|
+
if (!config.description)
|
|
376
|
+
warnings.push('config.json should have a "description" field');
|
|
377
|
+
if (!config.category)
|
|
378
|
+
warnings.push('config.json should have a "category" field');
|
|
379
|
+
} catch {
|
|
380
|
+
errors.push('config.json is not valid JSON');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return {
|
|
384
|
+
isValid: errors.length === 0,
|
|
385
|
+
errors,
|
|
386
|
+
warnings,
|
|
387
|
+
};
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
];
|
|
391
|
+
|
|
392
|
+
export default { tools };
|