apteva 0.4.32 → 0.4.44

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 (113) hide show
  1. package/dist/ActivityPage.c48n83h2.js +3 -0
  2. package/dist/ApiDocsPage.yzcxx5ax.js +4 -0
  3. package/dist/App.09yb8t0b.js +1 -0
  4. package/dist/App.152mbs1r.js +4 -0
  5. package/dist/App.3a67nx9w.js +4 -0
  6. package/dist/App.9epx6785.js +4 -0
  7. package/dist/App.d8955awp.js +4 -0
  8. package/dist/App.drwb57jq.js +4 -0
  9. package/dist/App.gssbmajb.js +4 -0
  10. package/dist/App.qw70pc29.js +53 -0
  11. package/dist/App.qzbx5wtj.js +4 -0
  12. package/dist/App.r5serxkt.js +8 -0
  13. package/dist/App.tpmp9020.js +20 -0
  14. package/dist/App.v2wb4d7d.js +61 -0
  15. package/dist/App.vxmaaj0m.js +13 -0
  16. package/dist/App.w4p2tda9.js +4 -0
  17. package/dist/App.wv2ng55q.js +221 -0
  18. package/dist/App.yncnrn0f.js +4 -0
  19. package/dist/ConnectionsPage.k6cspyqq.js +3 -0
  20. package/dist/McpPage.cdxm48xj.js +3 -0
  21. package/dist/SettingsPage.evpv7c2y.js +3 -0
  22. package/dist/SkillsPage.pvzp6c1a.js +3 -0
  23. package/dist/TasksPage.6jnvbpsy.js +3 -0
  24. package/dist/TelemetryPage.t7vk24zc.js +3 -0
  25. package/dist/TestsPage.5x6658aa.js +3 -0
  26. package/dist/ThreadsPage.3fvhtevh.js +3 -0
  27. package/dist/apteva-kit.css +1 -1
  28. package/dist/index.html +1 -1
  29. package/dist/styles.css +1 -1
  30. package/package.json +10 -9
  31. package/src/crypto.ts +4 -3
  32. package/src/db.ts +171 -36
  33. package/src/integrations/agentdojo.ts +95 -12
  34. package/src/integrations/index.ts +7 -0
  35. package/src/mcp-platform.ts +870 -142
  36. package/src/openapi.ts +96 -0
  37. package/src/providers.ts +60 -34
  38. package/src/routes/api/agent-utils.ts +59 -47
  39. package/src/routes/api/agents.ts +71 -2
  40. package/src/routes/api/integrations.ts +11 -5
  41. package/src/routes/api/mcp.ts +5 -4
  42. package/src/routes/api/meta-agent.ts +37 -1
  43. package/src/routes/api/projects.ts +3 -3
  44. package/src/routes/api/providers.ts +121 -30
  45. package/src/routes/api/skills.ts +2 -3
  46. package/src/routes/api/system.ts +98 -14
  47. package/src/routes/api/telemetry.ts +19 -1
  48. package/src/routes/share.ts +85 -0
  49. package/src/server.ts +43 -32
  50. package/src/triggers/agentdojo.ts +2 -2
  51. package/src/web/App.tsx +107 -21
  52. package/src/web/components/activity/ActivityPage.tsx +242 -389
  53. package/src/web/components/agents/AgentCard.tsx +19 -27
  54. package/src/web/components/agents/AgentPanel.tsx +358 -198
  55. package/src/web/components/agents/AgentsView.tsx +4 -4
  56. package/src/web/components/agents/CreateAgentModal.tsx +21 -79
  57. package/src/web/components/api/ApiDocsPage.tsx +66 -66
  58. package/src/web/components/auth/CreateAccountStep.tsx +16 -16
  59. package/src/web/components/auth/LoginPage.tsx +10 -10
  60. package/src/web/components/common/Icons.tsx +8 -0
  61. package/src/web/components/common/LoadingSpinner.tsx +2 -2
  62. package/src/web/components/common/Modal.tsx +8 -8
  63. package/src/web/components/common/Select.tsx +11 -10
  64. package/src/web/components/connections/ConnectionsPage.tsx +4 -4
  65. package/src/web/components/connections/IntegrationsTab.tsx +18 -18
  66. package/src/web/components/connections/OverviewTab.tsx +13 -13
  67. package/src/web/components/connections/TriggersTab.tsx +99 -99
  68. package/src/web/components/dashboard/Dashboard.tsx +177 -52
  69. package/src/web/components/index.ts +1 -1
  70. package/src/web/components/layout/Header.tsx +50 -34
  71. package/src/web/components/layout/Sidebar.tsx +41 -16
  72. package/src/web/components/mcp/IntegrationsPanel.tsx +160 -69
  73. package/src/web/components/mcp/McpPage.tsx +218 -209
  74. package/src/web/components/meta-agent/MetaAgent.tsx +15 -11
  75. package/src/web/components/onboarding/OnboardingWizard.tsx +25 -25
  76. package/src/web/components/settings/SettingsPage.tsx +389 -221
  77. package/src/web/components/skills/SkillsPage.tsx +88 -88
  78. package/src/web/components/tasks/TasksPage.tsx +385 -68
  79. package/src/web/components/telemetry/TelemetryPage.tsx +294 -39
  80. package/src/web/components/tests/TestsPage.tsx +50 -50
  81. package/src/web/components/threads/ThreadsPage.tsx +315 -0
  82. package/src/web/context/AuthContext.tsx +3 -3
  83. package/src/web/context/ProjectContext.tsx +8 -3
  84. package/src/web/context/TelemetryContext.tsx +24 -6
  85. package/src/web/context/ThemeContext.tsx +69 -0
  86. package/src/web/context/index.ts +3 -1
  87. package/src/web/styles.css +25 -7
  88. package/src/web/themes.ts +99 -0
  89. package/src/web/types.ts +4 -7
  90. package/dist/ActivityPage.41nbye4r.js +0 -3
  91. package/dist/ApiDocsPage.4smnt8m3.js +0 -4
  92. package/dist/App.0sbax9et.js +0 -4
  93. package/dist/App.0ws427h8.js +0 -4
  94. package/dist/App.6q6bar8b.js +0 -4
  95. package/dist/App.80301vdb.js +0 -4
  96. package/dist/App.af2wg84v.js +0 -267
  97. package/dist/App.ca1rz1ph.js +0 -4
  98. package/dist/App.ensa6z0r.js +0 -4
  99. package/dist/App.f8g7tych.js +0 -13
  100. package/dist/App.mvtqv6qc.js +0 -20
  101. package/dist/App.ncgc9cxy.js +0 -4
  102. package/dist/App.p02f4ret.js +0 -1
  103. package/dist/App.p0fb1pds.js +0 -4
  104. package/dist/App.pmaq48sj.js +0 -4
  105. package/dist/App.yv87t9m5.js +0 -4
  106. package/dist/App.zjmfm8p6.js +0 -4
  107. package/dist/ConnectionsPage.anb3rv9a.js +0 -3
  108. package/dist/McpPage.y396h6fy.js +0 -3
  109. package/dist/SettingsPage.p1hc60gk.js +0 -3
  110. package/dist/SkillsPage.yj3xdsay.js +0 -3
  111. package/dist/TasksPage.sjv0khtv.js +0 -3
  112. package/dist/TelemetryPage.2qm4w16r.js +0 -3
  113. package/dist/TestsPage.zzs4qfj8.js +0 -3
package/src/server.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { type Server, type Subprocess } from "bun";
2
2
  import { handleApiRequest } from "./routes/api";
3
3
  import { handleAuthRequest } from "./routes/auth";
4
+ import { handleShareRequest } from "./routes/share";
4
5
  import { serveStatic } from "./routes/static";
5
6
  import { join } from "path";
6
7
  import { homedir } from "os";
7
8
  import { mkdirSync, existsSync } from "fs";
8
- import { initDatabase, AgentDB, ProviderKeysDB, McpServerDB, ChannelDB, type McpServer, type Agent } from "./db";
9
+ import { initDatabase, AgentDB, ProviderKeysDB, McpServerDB, ChannelDB, TelemetryDB, type McpServer, type Agent } from "./db";
9
10
  import { authMiddleware, type AuthContext } from "./auth/middleware";
10
11
  import { startMcpProcess } from "./mcp-client";
11
12
  import {
@@ -103,6 +104,12 @@ if (await envFile.exists()) {
103
104
  // Initialize database (silently)
104
105
  initDatabase(DATA_DIR);
105
106
 
107
+ // Clean up old telemetry events (keep last 30 days)
108
+ try {
109
+ const deleted = TelemetryDB.deleteOlderThan(30);
110
+ if (deleted > 0) console.log(`[db] Cleaned up ${deleted} telemetry events older than 30 days`);
111
+ } catch { /* ignore */ }
112
+
106
113
  // Initialize version tracking
107
114
  initVersionTracking(DATA_DIR);
108
115
 
@@ -127,37 +134,31 @@ async function cleanupOrphanedProcesses(): Promise<void> {
127
134
 
128
135
  if (assignedPorts.length === 0) return;
129
136
 
130
- let cleaned = 0;
131
- for (const port of assignedPorts) {
137
+ // Check all ports in parallel
138
+ const results = await Promise.allSettled(assignedPorts.map(async (port) => {
132
139
  try {
133
140
  const res = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(200) });
134
- if (res.ok) {
135
- // Orphaned process on this port - shut it down gracefully first
136
- try {
137
- await fetch(`http://localhost:${port}/shutdown`, { method: "POST", signal: AbortSignal.timeout(500) });
138
- await new Promise(r => setTimeout(r, 500)); // Wait for graceful shutdown
139
- } catch {
140
- // Graceful shutdown failed
141
- }
142
-
143
- // Check if still running and force kill if needed
144
- try {
145
- const check = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(200) });
146
- if (check.ok) {
147
- // Still running - force kill via lsof
148
- const { execSync } = await import("child_process");
149
- execSync(`lsof -ti :${port} | xargs -r kill -9 2>/dev/null || true`, { stdio: "ignore" });
150
- }
151
- } catch {
152
- // Not responding anymore - good
141
+ if (!res.ok) return false;
142
+ // Orphaned process - shut it down gracefully
143
+ try {
144
+ await fetch(`http://localhost:${port}/shutdown`, { method: "POST", signal: AbortSignal.timeout(500) });
145
+ await new Promise(r => setTimeout(r, 500));
146
+ } catch {}
147
+ // Force kill if still running
148
+ try {
149
+ const check = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(200) });
150
+ if (check.ok) {
151
+ const { execSync } = await import("child_process");
152
+ execSync(`lsof -ti :${port} | xargs -r kill -9 2>/dev/null || true`, { stdio: "ignore" });
153
153
  }
154
- cleaned++;
155
- }
154
+ } catch {}
155
+ return true;
156
156
  } catch {
157
- // Port not in use - good
157
+ return false;
158
158
  }
159
- }
159
+ }));
160
160
 
161
+ const cleaned = results.filter(r => r.status === "fulfilled" && r.value).length;
161
162
  if (cleaned > 0) {
162
163
  console.log(` [cleanup] Stopped ${cleaned} orphaned agent process(es)`);
163
164
  }
@@ -421,6 +422,17 @@ const server = Bun.serve({
421
422
  return response;
422
423
  }
423
424
 
425
+ // Share routes (public, token-authenticated)
426
+ if (path.startsWith("/share/")) {
427
+ const shareResponse = await handleShareRequest(req, path);
428
+ if (shareResponse) {
429
+ Object.entries(corsHeaders).forEach(([key, value]) => {
430
+ shareResponse.headers.set(key, value);
431
+ });
432
+ return shareResponse;
433
+ }
434
+ }
435
+
424
436
  // Serve static files (React app)
425
437
  return serveStatic(req, path);
426
438
  },
@@ -490,14 +502,13 @@ if (hasRestarts) {
490
502
  }
491
503
  }
492
504
 
493
- // Then restart agents
505
+ // Then restart agents - in parallel
494
506
  if (agentsToRestart.length > 0) {
495
507
  console.log(` ${c.darkGray}Agents${c.reset} ${c.gray}Restarting ${agentsToRestart.length} agent(s)...${c.reset}`);
496
508
 
497
- for (const agent of agentsToRestart) {
509
+ await Promise.allSettled(agentsToRestart.map(async (agent) => {
498
510
  try {
499
511
  const result = await startAgentProcess(agent, { silent: true });
500
-
501
512
  if (result.success) {
502
513
  console.log(` ${c.gray} ✓ ${agent.name} on :${result.port}${c.reset}`);
503
514
  } else {
@@ -506,7 +517,7 @@ if (hasRestarts) {
506
517
  } catch (err) {
507
518
  console.log(` ${c.gray} ✗ ${agent.name}: ${err}${c.reset}`);
508
519
  }
509
- }
520
+ }));
510
521
  }
511
522
 
512
523
  // Restart channels (after agents, since channels depend on running agents)
@@ -514,7 +525,7 @@ if (hasRestarts) {
514
525
  const { startChannel } = await import("./channels");
515
526
  console.log(` ${c.darkGray}Channels${c.reset} ${c.gray}Restarting ${channelsToRestart.length} channel(s)...${c.reset}`);
516
527
 
517
- for (const channel of channelsToRestart) {
528
+ await Promise.allSettled(channelsToRestart.map(async (channel) => {
518
529
  try {
519
530
  const result = await startChannel(channel.id);
520
531
  if (result.success) {
@@ -525,7 +536,7 @@ if (hasRestarts) {
525
536
  } catch (err) {
526
537
  console.log(` ${c.gray} ✗ ${channel.name}: ${err}${c.reset}`);
527
538
  }
528
- }
539
+ }));
529
540
  }
530
541
  })();
531
542
  }
@@ -16,13 +16,13 @@ export const AgentDojoTriggerProvider: TriggerProvider = {
16
16
  name: "AgentDojo",
17
17
 
18
18
  async listTriggerTypes(apiKey: string, toolkitSlugs?: string[]): Promise<TriggerType[]> {
19
- const params = new URLSearchParams({ is_active: "true", limit: "200" });
19
+ const params = new URLSearchParams({ is_active: "true", limit: "500" });
20
20
  if (toolkitSlugs?.length) {
21
21
  // Filter by toolkit name(s) — API supports one at a time, so fetch each
22
22
  const allItems: any[] = [];
23
23
  for (const slug of toolkitSlugs) {
24
24
  const res = await fetch(
25
- `${AGENTDOJO_API_BASE}/triggers?${new URLSearchParams({ toolkit_name: slug, is_active: "true", limit: "200" })}`,
25
+ `${AGENTDOJO_API_BASE}/triggers?${new URLSearchParams({ toolkit_name: slug, is_active: "true", limit: "500" })}`,
26
26
  { headers: headers(apiKey) },
27
27
  );
28
28
  if (res.ok) {
package/src/web/App.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import React, { useState, useEffect, useMemo, lazy, Suspense } from "react";
2
2
  import { createRoot } from "react-dom/client";
3
+ import { Chat } from "@apteva/apteva-kit";
3
4
  import "@apteva/apteva-kit/styles.css";
4
5
 
5
6
  // Types
@@ -7,7 +8,7 @@ import type { Agent, Provider, Route, NewAgentForm } from "./types";
7
8
  import { DEFAULT_FEATURES } from "./types";
8
9
 
9
10
  // Context
10
- import { TelemetryProvider, AuthProvider, ProjectProvider, useAuth, useProjects, useAgentStatusChange, useTaskChange } from "./context";
11
+ import { TelemetryProvider, AuthProvider, ProjectProvider, ThemeProvider, useTheme, useAuth, useProjects, useAgentStatusChange, useTaskChange } from "./context";
11
12
 
12
13
  // Hooks
13
14
  import { useAgents, useProviders, useOnboarding } from "./hooks";
@@ -28,13 +29,14 @@ import { MetaAgentProvider, MetaAgentPanel } from "./components/meta-agent/MetaA
28
29
 
29
30
  // Lazy-loaded page components (only loaded when navigated to)
30
31
  const SettingsPage = lazy(() => import("./components/settings/SettingsPage").then(m => ({ default: m.SettingsPage })));
31
- const ActivityPage = lazy(() => import("./components/activity/ActivityPage").then(m => ({ default: m.ActivityPage })));
32
32
  const TasksPage = lazy(() => import("./components/tasks/TasksPage").then(m => ({ default: m.TasksPage })));
33
33
  const McpPage = lazy(() => import("./components/mcp/McpPage").then(m => ({ default: m.McpPage })));
34
34
  const SkillsPage = lazy(() => import("./components/skills/SkillsPage").then(m => ({ default: m.SkillsPage })));
35
35
  const TestsPage = lazy(() => import("./components/tests/TestsPage").then(m => ({ default: m.TestsPage })));
36
+ const ThreadsPage = lazy(() => import("./components/threads/ThreadsPage").then(m => ({ default: m.ThreadsPage })));
36
37
  const TelemetryPage = lazy(() => import("./components/telemetry/TelemetryPage").then(m => ({ default: m.TelemetryPage })));
37
38
  const ConnectionsPage = lazy(() => import("./components/connections/ConnectionsPage").then(m => ({ default: m.ConnectionsPage })));
39
+ const ActivityPage = lazy(() => import("./components/activity/ActivityPage").then(m => ({ default: m.ActivityPage })));
38
40
  const ApiDocsPage = lazy(() => import("./components/api/ApiDocsPage").then(m => ({ default: m.ApiDocsPage })));
39
41
 
40
42
  function AppContent() {
@@ -111,7 +113,7 @@ function AppContent() {
111
113
  };
112
114
 
113
115
  fetchTaskCount();
114
- }, [shouldFetchData, accessToken, currentProjectId, agents, statusChangeCounter, taskChangeCounter]);
116
+ }, [shouldFetchData, accessToken, currentProjectId, statusChangeCounter, taskChangeCounter]);
115
117
 
116
118
  // Form state
117
119
  const [newAgent, setNewAgent] = useState<NewAgentForm>({
@@ -239,7 +241,7 @@ function AppContent() {
239
241
  }
240
242
 
241
243
  return (
242
- <div className="h-screen bg-[#0a0a0a] text-[#e0e0e0] font-mono flex flex-col overflow-hidden">
244
+ <div className="h-screen font-mono flex flex-col overflow-hidden" style={{ backgroundColor: "var(--color-bg)", color: "var(--color-text)" }}>
243
245
  <Header onMenuClick={() => setMobileMenuOpen(true)} agents={agents} />
244
246
 
245
247
  {startError && (
@@ -260,14 +262,6 @@ function AppContent() {
260
262
  <Suspense fallback={<LoadingSpinner />}>
261
263
  {route === "settings" && <SettingsPage />}
262
264
 
263
- {route === "activity" && (
264
- <ActivityPage
265
- agents={agents}
266
- loading={loading}
267
- onNavigate={setRoute}
268
- />
269
- )}
270
-
271
265
  {route === "agents" && (
272
266
  <AgentsView
273
267
  agents={agents}
@@ -295,6 +289,21 @@ function AppContent() {
295
289
  />
296
290
  )}
297
291
 
292
+ {route === "threads" && (
293
+ <ThreadsPage
294
+ agents={agents}
295
+ onNavigate={setRoute}
296
+ />
297
+ )}
298
+
299
+ {route === "activity" && (
300
+ <ActivityPage
301
+ agents={agents}
302
+ loading={loading}
303
+ onNavigate={handleNavigate}
304
+ />
305
+ )}
306
+
298
307
  {route === "tasks" && <TasksPage />}
299
308
 
300
309
  {route === "connections" && <ConnectionsPage />}
@@ -334,18 +343,95 @@ function AppContent() {
334
343
  );
335
344
  }
336
345
 
346
+ // ==================== Share Page (public, no auth) ====================
347
+ function SharePage({ token }: { token: string }) {
348
+ const { theme } = useTheme();
349
+ const [status, setStatus] = useState<"checking" | "online" | "offline">("checking");
350
+ const [agentName, setAgentName] = useState("Agent");
351
+
352
+ useEffect(() => {
353
+ const check = async () => {
354
+ try {
355
+ const res = await fetch(`/share/${token}/info`);
356
+ if (res.ok) {
357
+ const data = await res.json();
358
+ setAgentName(data.name || "Agent");
359
+ setStatus(data.status === "running" ? "online" : "offline");
360
+ } else {
361
+ setStatus("offline");
362
+ }
363
+ } catch {
364
+ setStatus("offline");
365
+ }
366
+ };
367
+ check();
368
+ const interval = setInterval(check, 15000);
369
+ return () => clearInterval(interval);
370
+ }, [token]);
371
+
372
+ if (status === "checking") {
373
+ return (
374
+ <div className="min-h-[100dvh] flex items-center justify-center" style={{ backgroundColor: "var(--color-bg)" }}>
375
+ <div className="text-sm" style={{ color: "var(--color-text-muted)" }}>Connecting...</div>
376
+ </div>
377
+ );
378
+ }
379
+
380
+ if (status === "offline") {
381
+ return (
382
+ <div className="min-h-[100dvh] flex items-center justify-center" style={{ backgroundColor: "var(--color-bg)" }}>
383
+ <div className="text-center">
384
+ <div className="w-2.5 h-2.5 rounded-full mx-auto mb-3" style={{ backgroundColor: "var(--color-text-muted)" }} />
385
+ <div className="text-base font-semibold mb-1.5" style={{ color: "var(--color-text)" }}>{agentName}</div>
386
+ <div className="text-sm" style={{ color: "var(--color-text-muted)" }}>This agent is currently offline</div>
387
+ </div>
388
+ </div>
389
+ );
390
+ }
391
+
392
+ return (
393
+ <div className="min-h-[100dvh] flex items-center justify-center p-0 md:p-4" style={{ backgroundColor: "var(--color-bg)" }}>
394
+ <div className="w-full max-w-[640px] h-[100dvh] md:h-[calc(100dvh-32px)] md:max-h-[800px] md:rounded-xl overflow-hidden md:border flex flex-col" style={{ backgroundColor: "var(--color-bg)", borderColor: "var(--color-border)" }}>
395
+ <Chat
396
+ agentId="default"
397
+ apiUrl={`/share/${token}`}
398
+ placeholder="Type a message..."
399
+ variant="terminal"
400
+ theme={theme.id as "light" | "dark"}
401
+ headerTitle={agentName}
402
+ enableMarkdown
403
+ enableWidgets
404
+ availableWidgets={["form", "kpi"]}
405
+ />
406
+ </div>
407
+ </div>
408
+ );
409
+ }
410
+
337
411
  // Wrapper component that provides all contexts
338
412
  function App() {
413
+ // Check if this is a /share/:token URL — render public share page without auth
414
+ const shareMatch = window.location.pathname.match(/^\/share\/([a-f0-9]{32})$/);
415
+ if (shareMatch) {
416
+ return (
417
+ <ThemeProvider>
418
+ <SharePage token={shareMatch[1]} />
419
+ </ThemeProvider>
420
+ );
421
+ }
422
+
339
423
  return (
340
- <AuthProvider>
341
- <ProjectProvider>
342
- <MetaAgentProvider>
343
- <TelemetryProvider>
344
- <AppContent />
345
- </TelemetryProvider>
346
- </MetaAgentProvider>
347
- </ProjectProvider>
348
- </AuthProvider>
424
+ <ThemeProvider>
425
+ <AuthProvider>
426
+ <ProjectProvider>
427
+ <MetaAgentProvider>
428
+ <TelemetryProvider>
429
+ <AppContent />
430
+ </TelemetryProvider>
431
+ </MetaAgentProvider>
432
+ </ProjectProvider>
433
+ </AuthProvider>
434
+ </ThemeProvider>
349
435
  );
350
436
  }
351
437