apteva 0.4.20 → 0.4.29

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.
Files changed (67) hide show
  1. package/dist/ActivityPage.41nbye4r.js +3 -0
  2. package/dist/{ApiDocsPage.kf6bbwkk.js → ApiDocsPage.4smnt8m3.js} +2 -2
  3. package/dist/{App.jfx3der4.js → App.0sbax9et.js} +3 -3
  4. package/dist/App.0ws427h8.js +4 -0
  5. package/dist/App.4ehxpt48.js +4 -0
  6. package/dist/App.6q6bar8b.js +4 -0
  7. package/dist/App.ca1rz1ph.js +4 -0
  8. package/dist/{App.7v1w3ys9.js → App.ensa6z0r.js} +3 -3
  9. package/dist/{App.n4jb3c22.js → App.f8g7tych.js} +3 -3
  10. package/dist/App.kh7d2xj3.js +267 -0
  11. package/dist/App.mvtqv6qc.js +20 -0
  12. package/dist/{App.c90t3dxg.js → App.ncgc9cxy.js} +3 -3
  13. package/dist/{App.039re6cf.js → App.p0fb1pds.js} +3 -3
  14. package/dist/App.pmaq48sj.js +4 -0
  15. package/dist/{App.2yy66bnp.js → App.yv87t9m5.js} +3 -3
  16. package/dist/App.zjmfm8p6.js +4 -0
  17. package/dist/ConnectionsPage.anb3rv9a.js +3 -0
  18. package/dist/McpPage.y396h6fy.js +3 -0
  19. package/dist/SettingsPage.5k6vp396.js +3 -0
  20. package/dist/SkillsPage.yj3xdsay.js +3 -0
  21. package/dist/TasksPage.sjv0khtv.js +3 -0
  22. package/dist/TelemetryPage.2qm4w16r.js +3 -0
  23. package/dist/TestsPage.zzs4qfj8.js +3 -0
  24. package/dist/index.html +1 -1
  25. package/dist/styles.css +1 -1
  26. package/package.json +2 -2
  27. package/src/channels/telegram.ts +5 -0
  28. package/src/crypto.ts +13 -4
  29. package/src/db.ts +25 -2
  30. package/src/integrations/agentdojo.ts +1 -1
  31. package/src/providers.ts +46 -0
  32. package/src/routes/api/agent-utils.ts +64 -9
  33. package/src/routes/api/agents.ts +41 -13
  34. package/src/routes/api/integrations.ts +16 -6
  35. package/src/routes/api/mcp.ts +7 -0
  36. package/src/routes/api/triggers.ts +45 -5
  37. package/src/web/App.tsx +1 -0
  38. package/src/web/components/activity/ActivityPage.tsx +349 -214
  39. package/src/web/components/agents/AgentCard.tsx +37 -8
  40. package/src/web/components/agents/AgentPanel.tsx +268 -23
  41. package/src/web/components/connections/IntegrationsTab.tsx +57 -31
  42. package/src/web/components/connections/TriggersTab.tsx +336 -159
  43. package/src/web/components/dashboard/Dashboard.tsx +39 -7
  44. package/src/web/components/layout/Header.tsx +0 -34
  45. package/src/web/components/layout/Sidebar.tsx +43 -3
  46. package/src/web/components/mcp/McpPage.tsx +16 -5
  47. package/src/web/components/settings/SettingsPage.tsx +279 -30
  48. package/src/web/components/tasks/TasksPage.tsx +32 -6
  49. package/src/web/context/ProjectContext.tsx +5 -0
  50. package/src/web/context/TelemetryContext.tsx +14 -0
  51. package/src/web/types.ts +20 -2
  52. package/dist/ActivityPage.h769ek3a.js +0 -3
  53. package/dist/App.2jmkqm8c.js +0 -4
  54. package/dist/App.3515wsb4.js +0 -4
  55. package/dist/App.edwahsvz.js +0 -4
  56. package/dist/App.q3bpx15d.js +0 -20
  57. package/dist/App.r0a2nmqs.js +0 -267
  58. package/dist/App.s2yrcz15.js +0 -4
  59. package/dist/App.s5j82a5j.js +0 -4
  60. package/dist/App.tg1b94tx.js +0 -4
  61. package/dist/ConnectionsPage.a67fjgbf.js +0 -3
  62. package/dist/McpPage.d4p3xvtk.js +0 -3
  63. package/dist/SettingsPage.46sqpe39.js +0 -3
  64. package/dist/SkillsPage.j9hkqm99.js +0 -3
  65. package/dist/TasksPage.6pvkb7s7.js +0 -3
  66. package/dist/TelemetryPage.5zq9msb5.js +0 -3
  67. package/dist/TestsPage.24432yqt.js +0 -3
@@ -110,20 +110,47 @@ export async function handleAgentRoutes(
110
110
 
111
111
  const updated = AgentDB.update(agentMatch[1], updates);
112
112
 
113
- // If agent is running, push the new config and skills
113
+ // If agent is running, handle config update
114
114
  if (updated && updated.status === "running" && updated.port) {
115
- const providerKey = ProviderKeys.getDecrypted(updated.provider);
116
- if (providerKey) {
117
- const config = buildAgentConfig(updated, providerKey);
118
- const configResult = await pushConfigToAgent(updated.id, updated.port, config);
119
- if (!configResult.success) {
120
- console.error(`Failed to push config to running agent: ${configResult.error}`);
115
+ const providerChanged = body.provider !== undefined && body.provider !== agent.provider;
116
+
117
+ if (providerChanged) {
118
+ // Provider changed must restart to get new API key in env
119
+ console.log(`Provider changed for ${updated.name} (${agent.provider} -> ${updated.provider}), restarting...`);
120
+ const agentProc = agentProcesses.get(updated.id);
121
+ if (agentProc) {
122
+ // Graceful shutdown
123
+ try {
124
+ await fetch(`http://localhost:${updated.port}/shutdown`, {
125
+ method: "POST",
126
+ signal: AbortSignal.timeout(2000),
127
+ });
128
+ await new Promise(r => setTimeout(r, 500));
129
+ } catch {}
130
+ try { agentProc.proc.kill(); } catch {}
131
+ agentProcesses.delete(updated.id);
121
132
  }
122
- // Push skills via /skills endpoint
123
- if (config.skills?.definitions?.length > 0) {
124
- const skillsResult = await pushSkillsToAgent(updated.id, updated.port, config.skills.definitions);
125
- if (!skillsResult.success) {
126
- console.error(`Failed to push skills to running agent: ${skillsResult.error}`);
133
+ setAgentStatus(updated.id, "stopped", "provider_changed");
134
+ // Start with new provider
135
+ const startResult = await startAgentProcess(updated, { silent: true });
136
+ if (!startResult.success) {
137
+ console.error(`Failed to restart agent after provider change: ${startResult.error}`);
138
+ }
139
+ } else {
140
+ // Same provider — just push updated config
141
+ const providerKey = ProviderKeys.getDecrypted(updated.provider);
142
+ if (providerKey) {
143
+ const config = buildAgentConfig(updated, providerKey);
144
+ const configResult = await pushConfigToAgent(updated.id, updated.port, config);
145
+ if (!configResult.success) {
146
+ console.error(`Failed to push config to running agent: ${configResult.error}`);
147
+ }
148
+ // Push skills via /skills endpoint
149
+ if (config.skills?.definitions?.length > 0) {
150
+ const skillsResult = await pushSkillsToAgent(updated.id, updated.port, config.skills.definitions);
151
+ if (!skillsResult.success) {
152
+ console.error(`Failed to push skills to running agent: ${skillsResult.error}`);
153
+ }
127
154
  }
128
155
  }
129
156
  }
@@ -215,10 +242,11 @@ export async function handleAgentRoutes(
215
242
  return json({ error: "No API key found for this agent" }, 404);
216
243
  }
217
244
 
218
- // Return masked key (show only first 8 chars)
245
+ // Return masked key + full key (full key only shown on demand by frontend)
219
246
  const masked = apiKey.substring(0, 8) + "..." + apiKey.substring(apiKey.length - 4);
220
247
  return json({
221
248
  apiKey: masked,
249
+ fullKey: apiKey,
222
250
  hasKey: true,
223
251
  });
224
252
  }
@@ -518,20 +518,29 @@ export async function handleIntegrationRoutes(
518
518
  }
519
519
 
520
520
  try {
521
+ console.log(`[agentdojo:add] configId=${configId} projectId=${projectId}`);
521
522
  const server = await getAgentDojoServer(apiKey, configId);
522
523
  if (!server) {
524
+ console.log(`[agentdojo:add] server not found from AgentDojo API for configId=${configId}`);
523
525
  return json({ error: "Config not found" }, 404);
524
526
  }
525
-
526
- // Check if already exists
527
- const existing = McpServerDB.findAll().find(
528
- s => s.source === "agentdojo" && (s.url?.includes(server.slug) || s.url?.includes(configId))
527
+ console.log(`[agentdojo:add] fetched server: slug=${server.slug} name=${server.name} url=${server.url?.substring(0, 80)}`);
528
+
529
+ // Check if already exists — match by slug in URL, scoped to same project
530
+ const effectiveProjectId = projectId && projectId !== "unassigned" ? projectId : null;
531
+ const allServers = McpServerDB.findAll();
532
+ const agentdojoServers = allServers.filter(s => s.source === "agentdojo");
533
+ console.log(`[agentdojo:add] total servers=${allServers.length} agentdojo servers=${agentdojoServers.length}`);
534
+ const existing = agentdojoServers.find(
535
+ s => s.project_id === effectiveProjectId && s.url?.endsWith(`/${server.slug}`)
529
536
  );
530
537
  if (existing) {
538
+ console.log(`[agentdojo:add] ALREADY EXISTS: id=${existing.id} project_id=${existing.project_id} slug=${server.slug}`);
531
539
  return json({ server: existing, message: "Server already exists" });
532
540
  }
533
541
 
534
542
  // Create the MCP server entry
543
+ console.log(`[agentdojo:add] creating new server with effectiveProjectId=${effectiveProjectId}`);
535
544
  const mcpServer = McpServerDB.create({
536
545
  id: generateId(),
537
546
  name: server.name,
@@ -544,12 +553,13 @@ export async function handleIntegrationRoutes(
544
553
  url: server.url,
545
554
  headers: { "X-API-Key": apiKey },
546
555
  source: "agentdojo",
547
- project_id: projectId && projectId !== "unassigned" ? projectId : null,
556
+ project_id: effectiveProjectId,
548
557
  });
558
+ console.log(`[agentdojo:add] created server: id=${mcpServer.id} project_id=${mcpServer.project_id}`);
549
559
 
550
560
  return json({ server: mcpServer, message: "Server added successfully" });
551
561
  } catch (e) {
552
- console.error("Failed to add AgentDojo config:", e);
562
+ console.error("[agentdojo:add] Failed to add AgentDojo config:", e);
553
563
  return json({ error: "Failed to add AgentDojo config" }, 500);
554
564
  }
555
565
  }
@@ -25,16 +25,23 @@ export async function handleMcpRoutes(
25
25
  const forAgent = url.searchParams.get("forAgent"); // agent's project ID (shows global + project)
26
26
 
27
27
  let servers;
28
+ let queryMode: string;
28
29
  if (forAgent !== null) {
29
30
  // Get servers available for an agent (global + agent's project)
30
31
  servers = McpServerDB.findForAgent(forAgent || null);
32
+ queryMode = `forAgent=${forAgent}`;
31
33
  } else if (projectFilter === "global") {
32
34
  servers = McpServerDB.findGlobal();
35
+ queryMode = "global";
33
36
  } else if (projectFilter && projectFilter !== "all") {
34
37
  servers = McpServerDB.findByProject(projectFilter);
38
+ queryMode = `project=${projectFilter}`;
35
39
  } else {
36
40
  servers = McpServerDB.findAll();
41
+ queryMode = "all";
37
42
  }
43
+ const agentdojoCount = servers.filter(s => s.source === "agentdojo").length;
44
+ console.log(`[mcp:GET] mode=${queryMode} total=${servers.length} agentdojo=${agentdojoCount}`);
38
45
  return json({ servers });
39
46
  }
40
47
 
@@ -266,7 +266,19 @@ export async function handleTriggerRoutes(
266
266
 
267
267
  try {
268
268
  const success = await provider.deleteTrigger(apiKey, triggerId);
269
- return json({ success });
269
+
270
+ // Also clean up any local subscriptions referencing this trigger instance
271
+ const localSubs = SubscriptionDB.findByTriggerInstanceId(triggerId);
272
+ let localDeleted = 0;
273
+ for (const sub of localSubs) {
274
+ SubscriptionDB.delete(sub.id);
275
+ localDeleted++;
276
+ }
277
+ if (localDeleted > 0) {
278
+ console.log(`[triggers] Cleaned up ${localDeleted} local subscription(s) for trigger ${triggerId}`);
279
+ }
280
+
281
+ return json({ success, localSubscriptionsDeleted: localDeleted });
270
282
  } catch (e) {
271
283
  console.error(`Failed to delete trigger ${triggerId}:`, e);
272
284
  return json({ error: "Failed to delete trigger" }, 500);
@@ -446,14 +458,42 @@ export async function handleTriggerRoutes(
446
458
  }
447
459
  }
448
460
 
449
- // DELETE /api/subscriptions/:id
461
+ // DELETE /api/subscriptions/:id?provider=composio&project_id=xxx
450
462
  const subDeleteMatch = path.match(/^\/api\/subscriptions\/([^/]+)$/);
451
463
  if (subDeleteMatch && method === "DELETE") {
452
- const success = SubscriptionDB.delete(subDeleteMatch[1]);
453
- if (!success) {
464
+ const subId = subDeleteMatch[1];
465
+ const sub = SubscriptionDB.findById(subId);
466
+ if (!sub) {
454
467
  return json({ error: "Subscription not found" }, 404);
455
468
  }
456
- return json({ success: true });
469
+
470
+ // Also delete the remote trigger if it exists
471
+ let remoteDeleted = false;
472
+ if (sub.trigger_instance_id) {
473
+ const url = new URL(req.url);
474
+ const providerId = url.searchParams.get("provider") || null;
475
+ const projectId = url.searchParams.get("project_id") || sub.project_id || null;
476
+
477
+ // Try to determine provider — check query param, or try all registered providers
478
+ const providerIds = providerId ? [providerId] : getTriggerProviderIds();
479
+ for (const pid of providerIds) {
480
+ const provider = getTriggerProvider(pid);
481
+ const apiKey = provider ? ProviderKeys.getDecryptedForProject(pid, projectId) : null;
482
+ if (provider && apiKey) {
483
+ try {
484
+ await provider.deleteTrigger(apiKey, sub.trigger_instance_id);
485
+ remoteDeleted = true;
486
+ console.log(`[subscriptions] Deleted remote trigger ${sub.trigger_instance_id} via ${pid}`);
487
+ break;
488
+ } catch (e) {
489
+ console.warn(`[subscriptions] Failed to delete remote trigger ${sub.trigger_instance_id} via ${pid}:`, e);
490
+ }
491
+ }
492
+ }
493
+ }
494
+
495
+ const success = SubscriptionDB.delete(subId);
496
+ return json({ success, remoteDeleted });
457
497
  }
458
498
 
459
499
  // POST /api/subscriptions/:id/enable
package/src/web/App.tsx CHANGED
@@ -264,6 +264,7 @@ function AppContent() {
264
264
  <ActivityPage
265
265
  agents={agents}
266
266
  loading={loading}
267
+ onNavigate={setRoute}
267
268
  />
268
269
  )}
269
270