apteva 0.2.11 → 0.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/dist/App.mvbdnw89.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/auth/index.ts +11 -3
- package/src/auth/middleware.ts +1 -0
- package/src/crypto.ts +52 -7
- package/src/db.ts +437 -14
- package/src/integrations/skillsmp.ts +318 -0
- package/src/providers.ts +21 -0
- package/src/routes/api.ts +836 -16
- package/src/server.ts +58 -7
- package/src/web/App.tsx +24 -8
- package/src/web/components/agents/AgentCard.tsx +36 -11
- package/src/web/components/agents/AgentPanel.tsx +333 -24
- package/src/web/components/agents/AgentsView.tsx +1 -1
- package/src/web/components/agents/CreateAgentModal.tsx +169 -23
- package/src/web/components/common/Icons.tsx +8 -0
- package/src/web/components/common/index.ts +1 -0
- package/src/web/components/index.ts +1 -0
- package/src/web/components/layout/Header.tsx +4 -2
- package/src/web/components/layout/Sidebar.tsx +7 -1
- package/src/web/components/mcp/McpPage.tsx +602 -19
- package/src/web/components/meta-agent/MetaAgent.tsx +222 -0
- package/src/web/components/settings/SettingsPage.tsx +212 -150
- package/src/web/components/skills/SkillsPage.tsx +871 -0
- package/src/web/context/AuthContext.tsx +5 -0
- package/src/web/context/ProjectContext.tsx +26 -4
- package/src/web/types.ts +48 -3
- package/dist/App.44ge5b89.js +0 -218
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// Skills Integration Provider
|
|
2
|
+
// Fetches from public GitHub repositories
|
|
3
|
+
|
|
4
|
+
export interface MarketplaceSkill {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
content: string; // Full SKILL.md content
|
|
9
|
+
author: string;
|
|
10
|
+
version: string;
|
|
11
|
+
license: string | null;
|
|
12
|
+
compatibility: string | null;
|
|
13
|
+
tags: string[];
|
|
14
|
+
downloads: number;
|
|
15
|
+
rating: number;
|
|
16
|
+
repository: string | null;
|
|
17
|
+
created_at: string;
|
|
18
|
+
updated_at: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SkillsSearchResult {
|
|
22
|
+
skills: MarketplaceSkill[];
|
|
23
|
+
total: number;
|
|
24
|
+
page: number;
|
|
25
|
+
per_page: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// GitHub repo sources
|
|
29
|
+
// Add more repositories here as the skills ecosystem grows
|
|
30
|
+
// Each repo should have folders containing SKILL.md files with YAML frontmatter
|
|
31
|
+
const GITHUB_REPOS = [
|
|
32
|
+
{
|
|
33
|
+
owner: "anthropics",
|
|
34
|
+
repo: "skills",
|
|
35
|
+
path: "skills",
|
|
36
|
+
author: "Anthropic",
|
|
37
|
+
},
|
|
38
|
+
// Community repos can be added here, e.g.:
|
|
39
|
+
// { owner: "some-org", repo: "claude-skills", path: "skills", author: "Community" },
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
// Cache for fetched skills (TTL: 5 minutes)
|
|
43
|
+
let skillsCache: { skills: MarketplaceSkill[]; fetchedAt: number } | null = null;
|
|
44
|
+
const CACHE_TTL = 5 * 60 * 1000;
|
|
45
|
+
|
|
46
|
+
// Fetch all skills from GitHub repos
|
|
47
|
+
async function fetchAllSkills(): Promise<MarketplaceSkill[]> {
|
|
48
|
+
// Check cache
|
|
49
|
+
if (skillsCache && Date.now() - skillsCache.fetchedAt < CACHE_TTL) {
|
|
50
|
+
return skillsCache.skills;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const allSkills: MarketplaceSkill[] = [];
|
|
54
|
+
|
|
55
|
+
for (const repo of GITHUB_REPOS) {
|
|
56
|
+
try {
|
|
57
|
+
// Fetch directory listing
|
|
58
|
+
const listRes = await fetch(
|
|
59
|
+
`https://api.github.com/repos/${repo.owner}/${repo.repo}/contents/${repo.path}`,
|
|
60
|
+
{
|
|
61
|
+
headers: {
|
|
62
|
+
Accept: "application/vnd.github.v3+json",
|
|
63
|
+
"User-Agent": "Apteva-Skills-Fetcher",
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (!listRes.ok) {
|
|
69
|
+
console.error(`Failed to fetch ${repo.owner}/${repo.repo}: ${listRes.status}`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const items = (await listRes.json()) as Array<{
|
|
74
|
+
name: string;
|
|
75
|
+
type: string;
|
|
76
|
+
path: string;
|
|
77
|
+
}>;
|
|
78
|
+
|
|
79
|
+
// Filter directories only
|
|
80
|
+
const skillDirs = items.filter((item) => item.type === "dir");
|
|
81
|
+
|
|
82
|
+
// Fetch each skill's SKILL.md
|
|
83
|
+
const skillPromises = skillDirs.map(async (dir) => {
|
|
84
|
+
try {
|
|
85
|
+
const skillMdRes = await fetch(
|
|
86
|
+
`https://raw.githubusercontent.com/${repo.owner}/${repo.repo}/main/${dir.path}/SKILL.md`,
|
|
87
|
+
{
|
|
88
|
+
headers: { "User-Agent": "Apteva-Skills-Fetcher" },
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (!skillMdRes.ok) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const content = await skillMdRes.text();
|
|
97
|
+
const parsed = parseSkillMd(content);
|
|
98
|
+
|
|
99
|
+
if (!parsed) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
id: `${repo.owner}-${dir.name}`,
|
|
105
|
+
name: parsed.name,
|
|
106
|
+
description: parsed.description,
|
|
107
|
+
content,
|
|
108
|
+
author: repo.author,
|
|
109
|
+
version: parsed.metadata?.version || "1.0.0",
|
|
110
|
+
license: parsed.license || "MIT",
|
|
111
|
+
compatibility: parsed.compatibility || null,
|
|
112
|
+
tags: inferTags(dir.name, parsed.description),
|
|
113
|
+
downloads: 0, // Not available from GitHub
|
|
114
|
+
rating: 4.5, // Default rating
|
|
115
|
+
repository: `https://github.com/${repo.owner}/${repo.repo}/tree/main/${dir.path}`,
|
|
116
|
+
created_at: new Date().toISOString(),
|
|
117
|
+
updated_at: new Date().toISOString(),
|
|
118
|
+
} as MarketplaceSkill;
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.error(`Failed to fetch skill ${dir.name}:`, e);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const skills = (await Promise.all(skillPromises)).filter(
|
|
126
|
+
(s): s is MarketplaceSkill => s !== null
|
|
127
|
+
);
|
|
128
|
+
allSkills.push(...skills);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
console.error(`Failed to fetch from ${repo.owner}/${repo.repo}:`, e);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Update cache
|
|
135
|
+
skillsCache = { skills: allSkills, fetchedAt: Date.now() };
|
|
136
|
+
|
|
137
|
+
return allSkills;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Infer tags from skill name and description
|
|
141
|
+
function inferTags(name: string, description: string): string[] {
|
|
142
|
+
const tags: string[] = [];
|
|
143
|
+
const text = `${name} ${description}`.toLowerCase();
|
|
144
|
+
|
|
145
|
+
const tagKeywords: Record<string, string[]> = {
|
|
146
|
+
pdf: ["pdf"],
|
|
147
|
+
document: ["doc", "docx", "document", "word"],
|
|
148
|
+
spreadsheet: ["xlsx", "excel", "spreadsheet"],
|
|
149
|
+
presentation: ["pptx", "powerpoint", "slides", "presentation"],
|
|
150
|
+
design: ["design", "ui", "frontend", "canvas", "art"],
|
|
151
|
+
code: ["code", "programming", "developer", "builder"],
|
|
152
|
+
mcp: ["mcp"],
|
|
153
|
+
testing: ["test", "testing", "qa"],
|
|
154
|
+
communication: ["slack", "comms", "communication"],
|
|
155
|
+
brand: ["brand", "guidelines"],
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
for (const [tag, keywords] of Object.entries(tagKeywords)) {
|
|
159
|
+
if (keywords.some((kw) => text.includes(kw))) {
|
|
160
|
+
tags.push(tag);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return tags.length > 0 ? tags : ["general"];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Provider interface
|
|
168
|
+
export interface SkillsProvider {
|
|
169
|
+
id: string;
|
|
170
|
+
name: string;
|
|
171
|
+
search(query: string, page?: number): Promise<SkillsSearchResult>;
|
|
172
|
+
getSkill(skillId: string): Promise<MarketplaceSkill | null>;
|
|
173
|
+
getFeatured(): Promise<MarketplaceSkill[]>;
|
|
174
|
+
getCategories(): Promise<string[]>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export const GithubSkillsProvider: SkillsProvider = {
|
|
178
|
+
id: "github",
|
|
179
|
+
name: "GitHub Public Skills",
|
|
180
|
+
|
|
181
|
+
async search(query: string, page = 1): Promise<SkillsSearchResult> {
|
|
182
|
+
const allSkills = await fetchAllSkills();
|
|
183
|
+
|
|
184
|
+
if (!query.trim()) {
|
|
185
|
+
return {
|
|
186
|
+
skills: allSkills,
|
|
187
|
+
total: allSkills.length,
|
|
188
|
+
page: 1,
|
|
189
|
+
per_page: 50,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const lowerQuery = query.toLowerCase();
|
|
194
|
+
const filtered = allSkills.filter(
|
|
195
|
+
(s) =>
|
|
196
|
+
s.name.toLowerCase().includes(lowerQuery) ||
|
|
197
|
+
s.description.toLowerCase().includes(lowerQuery) ||
|
|
198
|
+
s.tags.some((t) => t.toLowerCase().includes(lowerQuery))
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
skills: filtered,
|
|
203
|
+
total: filtered.length,
|
|
204
|
+
page: 1,
|
|
205
|
+
per_page: 50,
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
async getSkill(skillId: string): Promise<MarketplaceSkill | null> {
|
|
210
|
+
const allSkills = await fetchAllSkills();
|
|
211
|
+
return allSkills.find((s) => s.id === skillId) || null;
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
async getFeatured(): Promise<MarketplaceSkill[]> {
|
|
215
|
+
const allSkills = await fetchAllSkills();
|
|
216
|
+
// Return all skills sorted by name
|
|
217
|
+
return [...allSkills].sort((a, b) => a.name.localeCompare(b.name));
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
async getCategories(): Promise<string[]> {
|
|
221
|
+
const allSkills = await fetchAllSkills();
|
|
222
|
+
const tags = new Set<string>();
|
|
223
|
+
allSkills.forEach((s) => s.tags.forEach((t) => tags.add(t)));
|
|
224
|
+
return Array.from(tags).sort();
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Legacy export for compatibility (uses GitHub provider now)
|
|
229
|
+
export const SkillsmpProvider = {
|
|
230
|
+
id: "skillsmp",
|
|
231
|
+
name: "SkillsMP",
|
|
232
|
+
|
|
233
|
+
async search(apiKey: string, query: string, page = 1): Promise<SkillsSearchResult> {
|
|
234
|
+
// Ignore API key, use GitHub provider
|
|
235
|
+
return GithubSkillsProvider.search(query, page);
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
async getSkill(apiKey: string, skillId: string): Promise<MarketplaceSkill | null> {
|
|
239
|
+
return GithubSkillsProvider.getSkill(skillId);
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
async getFeatured(apiKey: string): Promise<MarketplaceSkill[]> {
|
|
243
|
+
return GithubSkillsProvider.getFeatured();
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
async getCategories(apiKey: string): Promise<string[]> {
|
|
247
|
+
return GithubSkillsProvider.getCategories();
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// Parse SKILL.md content into structured data
|
|
252
|
+
export function parseSkillMd(content: string): {
|
|
253
|
+
name: string;
|
|
254
|
+
description: string;
|
|
255
|
+
body: string;
|
|
256
|
+
license?: string;
|
|
257
|
+
compatibility?: string;
|
|
258
|
+
metadata?: Record<string, string>;
|
|
259
|
+
allowedTools?: string[];
|
|
260
|
+
} | null {
|
|
261
|
+
// Check for YAML frontmatter
|
|
262
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
263
|
+
if (!frontmatterMatch) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const [, frontmatter, body] = frontmatterMatch;
|
|
268
|
+
|
|
269
|
+
// Parse YAML (simple parser for common fields)
|
|
270
|
+
const yaml: Record<string, any> = {};
|
|
271
|
+
const lines = frontmatter.split("\n");
|
|
272
|
+
let inMetadata = false;
|
|
273
|
+
|
|
274
|
+
for (const line of lines) {
|
|
275
|
+
if (line.startsWith("metadata:")) {
|
|
276
|
+
inMetadata = true;
|
|
277
|
+
yaml.metadata = {};
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (inMetadata) {
|
|
282
|
+
if (line.startsWith(" ")) {
|
|
283
|
+
const match = line.trim().match(/^(\w+):\s*["']?(.*)["']?$/);
|
|
284
|
+
if (match) {
|
|
285
|
+
yaml.metadata[match[1]] = match[2].replace(/["']$/, "");
|
|
286
|
+
}
|
|
287
|
+
} else {
|
|
288
|
+
inMetadata = false;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!inMetadata) {
|
|
293
|
+
const match = line.match(/^(\w[\w-]*):\s*(.*)$/);
|
|
294
|
+
if (match) {
|
|
295
|
+
const [, key, value] = match;
|
|
296
|
+
yaml[key] = value.replace(/^["']|["']$/g, "");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (!yaml.name || !yaml.description) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
name: yaml.name,
|
|
307
|
+
description: yaml.description,
|
|
308
|
+
body: body.trim(),
|
|
309
|
+
license: yaml.license,
|
|
310
|
+
compatibility: yaml.compatibility,
|
|
311
|
+
metadata: yaml.metadata,
|
|
312
|
+
allowedTools: yaml["allowed-tools"]?.split(/\s+/).filter(Boolean),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Re-export types for backwards compatibility
|
|
317
|
+
export type SkillsmpSkill = MarketplaceSkill;
|
|
318
|
+
export type SkillsmpSearchResult = SkillsSearchResult;
|
package/src/providers.ts
CHANGED
|
@@ -128,6 +128,27 @@ export const PROVIDERS = {
|
|
|
128
128
|
description: "MCP server registry and hosting",
|
|
129
129
|
models: [],
|
|
130
130
|
},
|
|
131
|
+
agentdojo: {
|
|
132
|
+
id: "agentdojo",
|
|
133
|
+
name: "AgentDojo",
|
|
134
|
+
displayName: "AgentDojo",
|
|
135
|
+
type: "integration" as const,
|
|
136
|
+
envVar: "AGENTDOJO_API_KEY",
|
|
137
|
+
docsUrl: "https://agentdojo.com/settings",
|
|
138
|
+
description: "Hosted MCP tools and agent capabilities",
|
|
139
|
+
models: [],
|
|
140
|
+
},
|
|
141
|
+
// Skills Integrations
|
|
142
|
+
skillsmp: {
|
|
143
|
+
id: "skillsmp",
|
|
144
|
+
name: "SkillsMP",
|
|
145
|
+
displayName: "SkillsMP",
|
|
146
|
+
type: "integration" as const,
|
|
147
|
+
envVar: "SKILLSMP_API_KEY",
|
|
148
|
+
docsUrl: "https://skillsmp.com/settings",
|
|
149
|
+
description: "Agent skills marketplace (optional - public registry available without key)",
|
|
150
|
+
models: [],
|
|
151
|
+
},
|
|
131
152
|
} as const;
|
|
132
153
|
|
|
133
154
|
export type ProviderId = keyof typeof PROVIDERS;
|