apteva 0.4.4 → 0.4.6
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.csbvbyak.js +227 -0
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/db.ts +98 -19
- package/src/integrations/agentdojo.ts +350 -0
- package/src/openapi.ts +195 -0
- package/src/providers.ts +78 -7
- package/src/routes/api/agent-utils.ts +638 -0
- package/src/routes/api/agents.ts +743 -0
- package/src/routes/api/helpers.ts +12 -0
- package/src/routes/api/integrations.ts +608 -0
- package/src/routes/api/mcp.ts +377 -0
- package/src/routes/api/meta-agent.ts +145 -0
- package/src/routes/api/projects.ts +95 -0
- package/src/routes/api/providers.ts +269 -0
- package/src/routes/api/skills.ts +538 -0
- package/src/routes/api/system.ts +215 -0
- package/src/routes/api/telemetry.ts +143 -0
- package/src/routes/api/users.ts +148 -0
- package/src/routes/api.ts +32 -3477
- package/src/server.ts +1 -1
- package/src/web/components/api/ApiDocsPage.tsx +259 -0
- package/src/web/components/dashboard/Dashboard.tsx +92 -3
- package/src/web/components/mcp/IntegrationsPanel.tsx +15 -8
- package/src/web/components/mcp/McpPage.tsx +458 -174
- package/src/web/components/settings/SettingsPage.tsx +275 -36
- package/src/web/components/skills/SkillsPage.tsx +330 -1
- package/src/web/components/tasks/TasksPage.tsx +187 -58
- package/src/web/context/TelemetryContext.tsx +14 -1
- package/src/web/hooks/useAgents.ts +9 -0
- package/src/web/types.ts +22 -4
- package/dist/App.mbp9atpm.js +0 -227
|
@@ -35,12 +35,20 @@ interface MarketplaceSkill {
|
|
|
35
35
|
repository: string | null;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
interface GitHubSkill {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
path: string;
|
|
42
|
+
size: number;
|
|
43
|
+
downloadUrl: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
export function SkillsPage() {
|
|
39
47
|
const { authFetch } = useAuth();
|
|
40
48
|
const { projects, currentProjectId } = useProjects();
|
|
41
49
|
const [skills, setSkills] = useState<Skill[]>([]);
|
|
42
50
|
const [loading, setLoading] = useState(true);
|
|
43
|
-
const [activeTab, setActiveTab] = useState<"installed" | "marketplace">("installed");
|
|
51
|
+
const [activeTab, setActiveTab] = useState<"installed" | "marketplace" | "github">("installed");
|
|
44
52
|
const [showCreate, setShowCreate] = useState(false);
|
|
45
53
|
const [showImport, setShowImport] = useState(false);
|
|
46
54
|
const [selectedSkill, setSelectedSkill] = useState<Skill | null>(null);
|
|
@@ -55,6 +63,17 @@ export function SkillsPage() {
|
|
|
55
63
|
const [marketplaceLoading, setMarketplaceLoading] = useState(false);
|
|
56
64
|
const [installing, setInstalling] = useState<string | null>(null);
|
|
57
65
|
|
|
66
|
+
// GitHub state
|
|
67
|
+
const [githubRepo, setGithubRepo] = useState("");
|
|
68
|
+
const [githubSkills, setGithubSkills] = useState<GitHubSkill[]>([]);
|
|
69
|
+
const [githubLoading, setGithubLoading] = useState(false);
|
|
70
|
+
const [githubError, setGithubError] = useState<string | null>(null);
|
|
71
|
+
const [githubRepoInfo, setGithubRepoInfo] = useState<{ owner: string; repo: string; url: string } | null>(null);
|
|
72
|
+
const [installingGithub, setInstallingGithub] = useState<string | null>(null);
|
|
73
|
+
const [githubProjectId, setGithubProjectId] = useState<string | null>(
|
|
74
|
+
currentProjectId && currentProjectId !== "unassigned" ? currentProjectId : null
|
|
75
|
+
);
|
|
76
|
+
|
|
58
77
|
// Filter skills based on global project selector
|
|
59
78
|
// When a project is selected, show global + that project's skills
|
|
60
79
|
const filteredSkills = skills.filter(skill => {
|
|
@@ -145,6 +164,125 @@ export function SkillsPage() {
|
|
|
145
164
|
|
|
146
165
|
const isInstalled = (name: string) => skills.some((s) => s.name === name);
|
|
147
166
|
|
|
167
|
+
// GitHub functions
|
|
168
|
+
const browseGitHubRepo = async (repoInput?: string) => {
|
|
169
|
+
const input = repoInput || githubRepo;
|
|
170
|
+
if (!input.trim()) return;
|
|
171
|
+
|
|
172
|
+
// Parse repo input: "owner/repo" or full URL
|
|
173
|
+
let owner = "";
|
|
174
|
+
let repo = "";
|
|
175
|
+
|
|
176
|
+
if (input.includes("github.com")) {
|
|
177
|
+
const match = input.match(/github\.com\/([^/]+)\/([^/]+)/);
|
|
178
|
+
if (match) {
|
|
179
|
+
owner = match[1];
|
|
180
|
+
repo = match[2].replace(/\.git$/, "");
|
|
181
|
+
}
|
|
182
|
+
} else if (input.includes("/")) {
|
|
183
|
+
const parts = input.split("/");
|
|
184
|
+
owner = parts[0];
|
|
185
|
+
repo = parts[1];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (!owner || !repo) {
|
|
189
|
+
setGithubError("Invalid repo format. Use 'owner/repo' or GitHub URL");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
setGithubLoading(true);
|
|
194
|
+
setGithubError(null);
|
|
195
|
+
setGithubSkills([]);
|
|
196
|
+
setGithubRepoInfo(null);
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const res = await authFetch(`/api/skills/github/${owner}/${repo}`);
|
|
200
|
+
const data = await res.json();
|
|
201
|
+
|
|
202
|
+
if (!res.ok) {
|
|
203
|
+
setGithubError(data.error || "Failed to fetch repository");
|
|
204
|
+
setGithubLoading(false);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
setGithubSkills(data.skills || []);
|
|
209
|
+
setGithubRepoInfo(data.repo || null);
|
|
210
|
+
} catch (e) {
|
|
211
|
+
setGithubError("Failed to fetch repository");
|
|
212
|
+
}
|
|
213
|
+
setGithubLoading(false);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const installFromGitHub = async (skill: GitHubSkill) => {
|
|
217
|
+
if (!githubRepoInfo) return;
|
|
218
|
+
|
|
219
|
+
setInstallingGithub(skill.name);
|
|
220
|
+
try {
|
|
221
|
+
const res = await authFetch("/api/skills/github/install", {
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers: { "Content-Type": "application/json" },
|
|
224
|
+
body: JSON.stringify({
|
|
225
|
+
owner: githubRepoInfo.owner,
|
|
226
|
+
repo: githubRepoInfo.repo,
|
|
227
|
+
skillName: skill.name,
|
|
228
|
+
downloadUrl: skill.downloadUrl,
|
|
229
|
+
projectId: githubProjectId,
|
|
230
|
+
}),
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const data = await res.json();
|
|
234
|
+
if (res.ok) {
|
|
235
|
+
await alert(`Installed "${skill.name}" successfully!`, { title: "Skill Installed" });
|
|
236
|
+
fetchSkills();
|
|
237
|
+
} else {
|
|
238
|
+
await alert(data.error || "Failed to install skill", { title: "Installation Failed", variant: "error" });
|
|
239
|
+
}
|
|
240
|
+
} catch (e) {
|
|
241
|
+
await alert("Failed to install skill", { title: "Error", variant: "error" });
|
|
242
|
+
}
|
|
243
|
+
setInstallingGithub(null);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const installAllFromGitHub = async () => {
|
|
247
|
+
if (!githubRepoInfo || githubSkills.length === 0) return;
|
|
248
|
+
|
|
249
|
+
const uninstalled = githubSkills.filter(s => !isInstalled(s.name));
|
|
250
|
+
if (uninstalled.length === 0) {
|
|
251
|
+
await alert("All skills are already installed", { title: "Info" });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const confirmed = await confirm(
|
|
256
|
+
`Install ${uninstalled.length} skill(s) from ${githubRepoInfo.owner}/${githubRepoInfo.repo}?`,
|
|
257
|
+
{ confirmText: "Install All", title: "Install Skills" }
|
|
258
|
+
);
|
|
259
|
+
if (!confirmed) return;
|
|
260
|
+
|
|
261
|
+
let installed = 0;
|
|
262
|
+
for (const skill of uninstalled) {
|
|
263
|
+
setInstallingGithub(skill.name);
|
|
264
|
+
try {
|
|
265
|
+
const res = await authFetch("/api/skills/github/install", {
|
|
266
|
+
method: "POST",
|
|
267
|
+
headers: { "Content-Type": "application/json" },
|
|
268
|
+
body: JSON.stringify({
|
|
269
|
+
owner: githubRepoInfo.owner,
|
|
270
|
+
repo: githubRepoInfo.repo,
|
|
271
|
+
skillName: skill.name,
|
|
272
|
+
downloadUrl: skill.downloadUrl,
|
|
273
|
+
projectId: githubProjectId,
|
|
274
|
+
}),
|
|
275
|
+
});
|
|
276
|
+
if (res.ok) installed++;
|
|
277
|
+
} catch (e) {
|
|
278
|
+
// Continue with others
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
setInstallingGithub(null);
|
|
282
|
+
fetchSkills();
|
|
283
|
+
await alert(`Installed ${installed} of ${uninstalled.length} skills`, { title: "Installation Complete" });
|
|
284
|
+
};
|
|
285
|
+
|
|
148
286
|
return (
|
|
149
287
|
<>
|
|
150
288
|
{ConfirmDialog}
|
|
@@ -189,6 +327,16 @@ export function SkillsPage() {
|
|
|
189
327
|
>
|
|
190
328
|
Installed ({skills.length})
|
|
191
329
|
</button>
|
|
330
|
+
<button
|
|
331
|
+
onClick={() => setActiveTab("github")}
|
|
332
|
+
className={`px-4 py-2 rounded text-sm font-medium transition ${
|
|
333
|
+
activeTab === "github"
|
|
334
|
+
? "bg-[#1a1a1a] text-white"
|
|
335
|
+
: "text-[#666] hover:text-[#888]"
|
|
336
|
+
}`}
|
|
337
|
+
>
|
|
338
|
+
Browse GitHub
|
|
339
|
+
</button>
|
|
192
340
|
<button
|
|
193
341
|
onClick={() => setActiveTab("marketplace")}
|
|
194
342
|
className={`px-4 py-2 rounded text-sm font-medium transition ${
|
|
@@ -243,6 +391,187 @@ export function SkillsPage() {
|
|
|
243
391
|
</>
|
|
244
392
|
)}
|
|
245
393
|
|
|
394
|
+
{/* GitHub Tab */}
|
|
395
|
+
{activeTab === "github" && (
|
|
396
|
+
<div className="space-y-6">
|
|
397
|
+
{/* Search */}
|
|
398
|
+
<form
|
|
399
|
+
onSubmit={(e) => {
|
|
400
|
+
e.preventDefault();
|
|
401
|
+
browseGitHubRepo();
|
|
402
|
+
}}
|
|
403
|
+
className="flex gap-2"
|
|
404
|
+
>
|
|
405
|
+
<input
|
|
406
|
+
type="text"
|
|
407
|
+
value={githubRepo}
|
|
408
|
+
onChange={(e) => setGithubRepo(e.target.value)}
|
|
409
|
+
placeholder="Enter GitHub repo (e.g., WordPress/agent-skills)"
|
|
410
|
+
className="flex-1 bg-[#111] border border-[#333] rounded-lg px-4 py-3 focus:outline-none focus:border-[#f97316]"
|
|
411
|
+
/>
|
|
412
|
+
<button
|
|
413
|
+
type="submit"
|
|
414
|
+
disabled={githubLoading}
|
|
415
|
+
className="bg-[#f97316] hover:bg-[#fb923c] disabled:opacity-50 text-black px-6 py-3 rounded-lg font-medium transition"
|
|
416
|
+
>
|
|
417
|
+
{githubLoading ? "..." : "Browse"}
|
|
418
|
+
</button>
|
|
419
|
+
</form>
|
|
420
|
+
|
|
421
|
+
{/* Project Scope Selector */}
|
|
422
|
+
{hasProjects && githubSkills.length > 0 && (
|
|
423
|
+
<div className="flex items-center gap-3 p-3 bg-[#0a0a0a] border border-[#222] rounded-lg">
|
|
424
|
+
<span className="text-sm text-[#666]">Install to:</span>
|
|
425
|
+
<Select
|
|
426
|
+
value={githubProjectId || ""}
|
|
427
|
+
onChange={(value) => setGithubProjectId(value || null)}
|
|
428
|
+
options={[
|
|
429
|
+
{ value: "", label: "Global (all projects)" },
|
|
430
|
+
...projects.map(p => ({ value: p.id, label: p.name }))
|
|
431
|
+
]}
|
|
432
|
+
placeholder="Select scope..."
|
|
433
|
+
/>
|
|
434
|
+
</div>
|
|
435
|
+
)}
|
|
436
|
+
|
|
437
|
+
{/* Error */}
|
|
438
|
+
{githubError && (
|
|
439
|
+
<div className="text-red-400 text-sm p-3 bg-red-500/10 border border-red-500/20 rounded-lg">
|
|
440
|
+
{githubError}
|
|
441
|
+
</div>
|
|
442
|
+
)}
|
|
443
|
+
|
|
444
|
+
{/* Repo Info Header */}
|
|
445
|
+
{githubRepoInfo && githubSkills.length > 0 && (
|
|
446
|
+
<div className="flex items-center justify-between">
|
|
447
|
+
<div className="flex items-center gap-3">
|
|
448
|
+
<a
|
|
449
|
+
href={githubRepoInfo.url}
|
|
450
|
+
target="_blank"
|
|
451
|
+
rel="noopener noreferrer"
|
|
452
|
+
className="text-[#f97316] hover:underline font-medium"
|
|
453
|
+
>
|
|
454
|
+
{githubRepoInfo.owner}/{githubRepoInfo.repo}
|
|
455
|
+
</a>
|
|
456
|
+
<span className="text-sm text-[#666]">
|
|
457
|
+
{githubSkills.length} skill{githubSkills.length !== 1 ? "s" : ""} found
|
|
458
|
+
</span>
|
|
459
|
+
</div>
|
|
460
|
+
{githubSkills.some(s => !isInstalled(s.name)) && (
|
|
461
|
+
<button
|
|
462
|
+
onClick={installAllFromGitHub}
|
|
463
|
+
disabled={!!installingGithub}
|
|
464
|
+
className="text-sm bg-[#1a1a1a] hover:bg-[#222] border border-[#333] hover:border-[#f97316] px-4 py-2 rounded transition disabled:opacity-50"
|
|
465
|
+
>
|
|
466
|
+
Install All
|
|
467
|
+
</button>
|
|
468
|
+
)}
|
|
469
|
+
</div>
|
|
470
|
+
)}
|
|
471
|
+
|
|
472
|
+
{/* Loading */}
|
|
473
|
+
{githubLoading && (
|
|
474
|
+
<div className="text-center py-8 text-[#666]">
|
|
475
|
+
Fetching skills from repository...
|
|
476
|
+
</div>
|
|
477
|
+
)}
|
|
478
|
+
|
|
479
|
+
{/* Empty State */}
|
|
480
|
+
{!githubLoading && !githubRepoInfo && !githubError && (
|
|
481
|
+
<div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-8 text-center">
|
|
482
|
+
<div className="text-4xl mb-4">📦</div>
|
|
483
|
+
<h3 className="text-lg font-medium mb-2">Browse Skills from GitHub</h3>
|
|
484
|
+
<p className="text-[#666] mb-6 max-w-md mx-auto">
|
|
485
|
+
Enter a GitHub repository to browse and install skills. Skills are markdown files with instructions that teach agents how to perform specific tasks.
|
|
486
|
+
</p>
|
|
487
|
+
<div className="flex flex-wrap gap-2 justify-center">
|
|
488
|
+
{[
|
|
489
|
+
{ label: "WordPress Skills", repo: "WordPress/agent-skills" },
|
|
490
|
+
].map(({ label, repo }) => (
|
|
491
|
+
<button
|
|
492
|
+
key={repo}
|
|
493
|
+
onClick={() => {
|
|
494
|
+
setGithubRepo(repo);
|
|
495
|
+
browseGitHubRepo(repo);
|
|
496
|
+
}}
|
|
497
|
+
className="text-sm bg-[#1a1a1a] hover:bg-[#222] border border-[#333] hover:border-[#f97316] px-3 py-1.5 rounded transition"
|
|
498
|
+
>
|
|
499
|
+
{label}
|
|
500
|
+
</button>
|
|
501
|
+
))}
|
|
502
|
+
</div>
|
|
503
|
+
</div>
|
|
504
|
+
)}
|
|
505
|
+
|
|
506
|
+
{/* No Skills Found */}
|
|
507
|
+
{!githubLoading && githubRepoInfo && githubSkills.length === 0 && (
|
|
508
|
+
<div className="text-center py-8 text-[#666]">
|
|
509
|
+
No skills found in this repository. Skills should be in subdirectories with a SKILL.md file.
|
|
510
|
+
</div>
|
|
511
|
+
)}
|
|
512
|
+
|
|
513
|
+
{/* Skills Grid */}
|
|
514
|
+
{githubSkills.length > 0 && (
|
|
515
|
+
<div className="grid gap-4 md:grid-cols-2">
|
|
516
|
+
{githubSkills.map((skill) => {
|
|
517
|
+
const installed = isInstalled(skill.name);
|
|
518
|
+
const isInstalling = installingGithub === skill.name;
|
|
519
|
+
|
|
520
|
+
return (
|
|
521
|
+
<div
|
|
522
|
+
key={skill.name}
|
|
523
|
+
className={`bg-[#111] border rounded-lg p-4 transition ${
|
|
524
|
+
installed ? "border-green-500/30" : "border-[#1a1a1a] hover:border-[#333]"
|
|
525
|
+
}`}
|
|
526
|
+
>
|
|
527
|
+
<div className="flex items-start justify-between gap-3">
|
|
528
|
+
<div className="flex-1 min-w-0">
|
|
529
|
+
<div className="flex items-center gap-2">
|
|
530
|
+
<h3 className="font-medium truncate">{skill.name}</h3>
|
|
531
|
+
{installed && (
|
|
532
|
+
<span className="text-xs text-green-400">✓ Installed</span>
|
|
533
|
+
)}
|
|
534
|
+
</div>
|
|
535
|
+
<p className="text-sm text-[#666] mt-1 line-clamp-2">
|
|
536
|
+
{skill.description || "No description"}
|
|
537
|
+
</p>
|
|
538
|
+
<div className="flex items-center gap-2 mt-2 text-xs text-[#555]">
|
|
539
|
+
<span>{(skill.size / 1024).toFixed(1)}KB</span>
|
|
540
|
+
<span className="px-1.5 py-0.5 rounded bg-blue-500/10 text-blue-400">
|
|
541
|
+
GitHub
|
|
542
|
+
</span>
|
|
543
|
+
</div>
|
|
544
|
+
</div>
|
|
545
|
+
<div className="flex-shrink-0">
|
|
546
|
+
{installed ? (
|
|
547
|
+
<span className="text-xs text-[#555] px-3 py-1.5">Added</span>
|
|
548
|
+
) : (
|
|
549
|
+
<button
|
|
550
|
+
onClick={() => installFromGitHub(skill)}
|
|
551
|
+
disabled={isInstalling}
|
|
552
|
+
className="text-sm bg-[#1a1a1a] hover:bg-[#222] border border-[#333] hover:border-[#f97316] px-3 py-1.5 rounded transition disabled:opacity-50"
|
|
553
|
+
>
|
|
554
|
+
{isInstalling ? "Installing..." : "Install"}
|
|
555
|
+
</button>
|
|
556
|
+
)}
|
|
557
|
+
</div>
|
|
558
|
+
</div>
|
|
559
|
+
</div>
|
|
560
|
+
);
|
|
561
|
+
})}
|
|
562
|
+
</div>
|
|
563
|
+
)}
|
|
564
|
+
|
|
565
|
+
{/* Info */}
|
|
566
|
+
<div className="p-4 bg-[#111] border border-[#1a1a1a] rounded-lg text-sm text-[#666]">
|
|
567
|
+
<p>
|
|
568
|
+
Skills are sourced from GitHub repositories. Each skill should be in its own directory with a{" "}
|
|
569
|
+
<code className="text-[#888] bg-[#0a0a0a] px-1 rounded">SKILL.md</code> file containing instructions.
|
|
570
|
+
</p>
|
|
571
|
+
</div>
|
|
572
|
+
</div>
|
|
573
|
+
)}
|
|
574
|
+
|
|
246
575
|
{/* Marketplace Tab */}
|
|
247
576
|
{activeTab === "marketplace" && (
|
|
248
577
|
<>
|