apteva 0.2.3 → 0.2.5

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 (36) hide show
  1. package/dist/App.ggy88vnx.js +213 -0
  2. package/dist/index.html +1 -1
  3. package/dist/styles.css +1 -1
  4. package/package.json +6 -6
  5. package/src/binary.ts +271 -1
  6. package/src/crypto.ts +53 -0
  7. package/src/db.ts +492 -3
  8. package/src/mcp-client.ts +599 -0
  9. package/src/providers.ts +31 -0
  10. package/src/routes/api.ts +786 -63
  11. package/src/server.ts +122 -5
  12. package/src/web/App.tsx +36 -1
  13. package/src/web/components/agents/AgentCard.tsx +22 -1
  14. package/src/web/components/agents/AgentPanel.tsx +381 -0
  15. package/src/web/components/agents/AgentsView.tsx +27 -10
  16. package/src/web/components/agents/CreateAgentModal.tsx +7 -7
  17. package/src/web/components/agents/index.ts +1 -1
  18. package/src/web/components/common/Icons.tsx +8 -0
  19. package/src/web/components/common/Modal.tsx +2 -2
  20. package/src/web/components/common/Select.tsx +1 -1
  21. package/src/web/components/common/index.ts +1 -0
  22. package/src/web/components/dashboard/Dashboard.tsx +74 -25
  23. package/src/web/components/index.ts +5 -2
  24. package/src/web/components/layout/Sidebar.tsx +22 -2
  25. package/src/web/components/mcp/McpPage.tsx +1144 -0
  26. package/src/web/components/mcp/index.ts +1 -0
  27. package/src/web/components/onboarding/OnboardingWizard.tsx +5 -1
  28. package/src/web/components/settings/SettingsPage.tsx +312 -82
  29. package/src/web/components/tasks/TasksPage.tsx +129 -0
  30. package/src/web/components/tasks/index.ts +1 -0
  31. package/src/web/components/telemetry/TelemetryPage.tsx +316 -0
  32. package/src/web/hooks/useAgents.ts +23 -0
  33. package/src/web/styles.css +18 -0
  34. package/src/web/types.ts +75 -1
  35. package/dist/App.wfhmfhx7.js +0 -213
  36. package/src/web/components/agents/ChatPanel.tsx +0 -63
@@ -1,38 +1,42 @@
1
1
  import React from "react";
2
2
  import { AgentCard } from "./AgentCard";
3
- import { ChatPanel } from "./ChatPanel";
3
+ import { AgentPanel } from "./AgentPanel";
4
4
  import { LoadingSpinner } from "../common/LoadingSpinner";
5
- import type { Agent } from "../../types";
5
+ import type { Agent, Provider } from "../../types";
6
6
 
7
7
  interface AgentsViewProps {
8
8
  agents: Agent[];
9
9
  loading: boolean;
10
10
  selectedAgent: Agent | null;
11
+ providers: Provider[];
11
12
  onSelectAgent: (agent: Agent) => void;
12
13
  onCloseAgent: () => void;
13
14
  onToggleAgent: (agent: Agent, e?: React.MouseEvent) => void;
14
15
  onDeleteAgent: (id: string, e?: React.MouseEvent) => void;
16
+ onUpdateAgent: (id: string, updates: Partial<Agent>) => Promise<{ error?: string }>;
15
17
  }
16
18
 
17
19
  export function AgentsView({
18
20
  agents,
19
21
  loading,
20
22
  selectedAgent,
23
+ providers,
21
24
  onSelectAgent,
22
25
  onCloseAgent,
23
26
  onToggleAgent,
24
27
  onDeleteAgent,
28
+ onUpdateAgent,
25
29
  }: AgentsViewProps) {
26
30
  return (
27
- <div className="flex-1 flex overflow-hidden">
31
+ <div className="flex-1 flex overflow-hidden relative">
28
32
  {/* Agents list */}
29
- <div className={`${selectedAgent ? 'w-1/2 border-r border-[#1a1a1a]' : 'flex-1'} overflow-auto p-6 transition-all`}>
33
+ <div className="flex-1 overflow-auto p-6">
30
34
  {loading ? (
31
35
  <LoadingSpinner message="Loading agents..." />
32
36
  ) : agents.length === 0 ? (
33
37
  <EmptyState />
34
38
  ) : (
35
- <div className={`grid gap-4 ${selectedAgent ? 'grid-cols-1 xl:grid-cols-2' : 'md:grid-cols-2 xl:grid-cols-3'}`}>
39
+ <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
36
40
  {agents.map((agent) => (
37
41
  <AgentCard
38
42
  key={agent.id}
@@ -47,14 +51,27 @@ export function AgentsView({
47
51
  )}
48
52
  </div>
49
53
 
50
- {/* Chat Panel */}
54
+ {/* Overlay backdrop */}
51
55
  {selectedAgent && (
52
- <ChatPanel
53
- agent={selectedAgent}
54
- onClose={onCloseAgent}
55
- onStartAgent={(e) => onToggleAgent(selectedAgent, e)}
56
+ <div
57
+ className="absolute inset-0 bg-black/40 backdrop-blur-[2px] z-10"
58
+ onClick={onCloseAgent}
56
59
  />
57
60
  )}
61
+
62
+ {/* Agent Panel - slides in from right */}
63
+ {selectedAgent && (
64
+ <div className="absolute right-0 top-0 bottom-0 w-[600px] z-20">
65
+ <AgentPanel
66
+ agent={selectedAgent}
67
+ providers={providers}
68
+ onClose={onCloseAgent}
69
+ onStartAgent={(e) => onToggleAgent(selectedAgent, e)}
70
+ onUpdateAgent={(updates) => onUpdateAgent(selectedAgent.id, updates)}
71
+ onDeleteAgent={() => onDeleteAgent(selectedAgent.id)}
72
+ />
73
+ </div>
74
+ )}
58
75
  </div>
59
76
  );
60
77
  }
@@ -16,11 +16,11 @@ interface CreateAgentModalProps {
16
16
  }
17
17
 
18
18
  const FEATURE_CONFIG = [
19
- { key: "memory" as keyof AgentFeatures, label: "Memory", description: "Remember information across conversations", icon: MemoryIcon },
20
- { key: "tasks" as keyof AgentFeatures, label: "Tasks", description: "Create and execute scheduled tasks", icon: TasksIcon },
19
+ { key: "memory" as keyof AgentFeatures, label: "Memory", description: "Persistent recall", icon: MemoryIcon },
20
+ { key: "tasks" as keyof AgentFeatures, label: "Tasks", description: "Schedule and execute tasks", icon: TasksIcon },
21
21
  { key: "vision" as keyof AgentFeatures, label: "Vision", description: "Process images and PDFs", icon: VisionIcon },
22
- { key: "operator" as keyof AgentFeatures, label: "Operator", description: "Browser automation (computer use)", icon: OperatorIcon },
23
- { key: "mcp" as keyof AgentFeatures, label: "MCP", description: "Connect to external tools and services", icon: McpIcon },
22
+ { key: "operator" as keyof AgentFeatures, label: "Operator", description: "Browser automation", icon: OperatorIcon },
23
+ { key: "mcp" as keyof AgentFeatures, label: "MCP", description: "External tools/services", icon: McpIcon },
24
24
  { key: "realtime" as keyof AgentFeatures, label: "Realtime", description: "Voice conversations", icon: RealtimeIcon },
25
25
  ];
26
26
 
@@ -103,7 +103,7 @@ export function CreateAgentModal({
103
103
  </FormField>
104
104
 
105
105
  <FormField label="Features">
106
- <div className="grid grid-cols-2 gap-2">
106
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
107
107
  {FEATURE_CONFIG.map(({ key, label, description, icon: Icon }) => (
108
108
  <button
109
109
  key={key}
@@ -115,12 +115,12 @@ export function CreateAgentModal({
115
115
  : "border-[#222] hover:border-[#333]"
116
116
  }`}
117
117
  >
118
- <Icon className={`w-5 h-5 ${form.features[key] ? "text-[#f97316]" : "text-[#666]"}`} />
118
+ <Icon className={`w-5 h-5 flex-shrink-0 ${form.features[key] ? "text-[#f97316]" : "text-[#666]"}`} />
119
119
  <div className="flex-1 min-w-0">
120
120
  <div className={`text-sm font-medium ${form.features[key] ? "text-[#f97316]" : ""}`}>
121
121
  {label}
122
122
  </div>
123
- <div className="text-xs text-[#666] truncate">{description}</div>
123
+ <div className="text-xs text-[#666]">{description}</div>
124
124
  </div>
125
125
  </button>
126
126
  ))}
@@ -1,4 +1,4 @@
1
1
  export { AgentCard } from "./AgentCard";
2
2
  export { CreateAgentModal } from "./CreateAgentModal";
3
- export { ChatPanel } from "./ChatPanel";
3
+ export { AgentPanel } from "./AgentPanel";
4
4
  export { AgentsView } from "./AgentsView";
@@ -109,3 +109,11 @@ export function RealtimeIcon({ className = "w-4 h-4" }: IconProps) {
109
109
  </svg>
110
110
  );
111
111
  }
112
+
113
+ export function TelemetryIcon({ className = "w-4 h-4" }: IconProps) {
114
+ return (
115
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
116
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
117
+ </svg>
118
+ );
119
+ }
@@ -7,8 +7,8 @@ interface ModalProps {
7
7
 
8
8
  export function Modal({ children, onClose }: ModalProps) {
9
9
  return (
10
- <div className="fixed inset-0 bg-black/70 flex items-center justify-center z-50">
11
- <div className="bg-[#111] rounded p-6 w-full max-w-md border border-[#1a1a1a]">
10
+ <div className="fixed inset-0 bg-black/70 flex items-center justify-center z-50 p-4">
11
+ <div className="bg-[#111] rounded p-6 w-full max-w-xl border border-[#1a1a1a] max-h-[90vh] overflow-y-auto">
12
12
  {children}
13
13
  </div>
14
14
  </div>
@@ -50,7 +50,7 @@ export function Select({ value, options, onChange, placeholder = "Select..." }:
50
50
  </button>
51
51
 
52
52
  {isOpen && (
53
- <div className="absolute z-50 w-full mt-1 bg-[#111] border border-[#222] rounded shadow-lg max-h-60 overflow-auto">
53
+ <div className="absolute z-50 w-full min-w-max mt-1 bg-[#111] border border-[#222] rounded shadow-lg max-h-60 overflow-y-auto scrollbar-hide">
54
54
  {options.map((option) => (
55
55
  <button
56
56
  key={option.value}
@@ -13,4 +13,5 @@ export {
13
13
  OperatorIcon,
14
14
  McpIcon,
15
15
  RealtimeIcon,
16
+ TelemetryIcon,
16
17
  } from "./Icons";
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import type { Agent, Provider, Route } from "../../types";
1
+ import React, { useState, useEffect } from "react";
2
+ import type { Agent, Provider, Route, DashboardStats, Task } from "../../types";
3
3
 
4
4
  interface DashboardProps {
5
5
  agents: Agent[];
@@ -18,16 +18,49 @@ export function Dashboard({
18
18
  onNavigate,
19
19
  onSelectAgent,
20
20
  }: DashboardProps) {
21
+ const [stats, setStats] = useState<DashboardStats | null>(null);
22
+ const [recentTasks, setRecentTasks] = useState<Task[]>([]);
23
+
24
+ useEffect(() => {
25
+ fetchDashboardData();
26
+ const interval = setInterval(fetchDashboardData, 10000);
27
+ return () => clearInterval(interval);
28
+ }, []);
29
+
30
+ const fetchDashboardData = async () => {
31
+ try {
32
+ const [dashRes, tasksRes] = await Promise.all([
33
+ fetch("/api/dashboard"),
34
+ fetch("/api/tasks?status=all"),
35
+ ]);
36
+
37
+ if (dashRes.ok) {
38
+ const data = await dashRes.json();
39
+ setStats(data);
40
+ }
41
+
42
+ if (tasksRes.ok) {
43
+ const data = await tasksRes.json();
44
+ setRecentTasks((data.tasks || []).slice(0, 5));
45
+ }
46
+ } catch (e) {
47
+ console.error("Failed to fetch dashboard data:", e);
48
+ }
49
+ };
50
+
51
+ const taskStats = stats?.tasks || { total: 0, pending: 0, running: 0, completed: 0 };
52
+
21
53
  return (
22
54
  <div className="flex-1 overflow-auto p-6">
23
55
  {/* Stats Cards */}
24
- <div className="grid grid-cols-3 gap-4 mb-6">
25
- <StatCard label="Total Agents" value={agents.length} />
26
- <StatCard label="Running" value={runningCount} color="text-[#3b82f6]" />
56
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-6">
57
+ <StatCard label="Agents" value={agents.length} subValue={`${runningCount} running`} />
58
+ <StatCard label="Tasks" value={taskStats.total} subValue={`${taskStats.pending} pending`} />
59
+ <StatCard label="Completed" value={taskStats.completed} color="text-green-400" />
27
60
  <StatCard label="Providers" value={configuredProviders.length} color="text-[#f97316]" />
28
61
  </div>
29
62
 
30
- <div className="grid grid-cols-2 gap-6">
63
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
31
64
  {/* Agents List */}
32
65
  <DashboardCard
33
66
  title="Agents"
@@ -61,31 +94,29 @@ export function Dashboard({
61
94
  )}
62
95
  </DashboardCard>
63
96
 
64
- {/* Configured Providers */}
97
+ {/* Recent Tasks */}
65
98
  <DashboardCard
66
- title="Providers"
67
- actionLabel="Manage"
68
- onAction={() => onNavigate("settings")}
99
+ title="Recent Tasks"
100
+ actionLabel="View All"
101
+ onAction={() => onNavigate("tasks")}
69
102
  >
70
- {configuredProviders.length === 0 ? (
103
+ {recentTasks.length === 0 ? (
71
104
  <div className="p-4 text-center text-[#666]">
72
- <p>No providers configured</p>
73
- <button
74
- onClick={() => onNavigate("settings")}
75
- className="text-[#f97316] hover:underline mt-1"
76
- >
77
- Add API Key
78
- </button>
105
+ <p>No tasks yet</p>
106
+ <p className="text-sm text-[#444] mt-1">Tasks will appear when agents create them</p>
79
107
  </div>
80
108
  ) : (
81
109
  <div className="divide-y divide-[#1a1a1a]">
82
- {configuredProviders.map((provider) => (
83
- <div key={provider.id} className="px-4 py-3 flex items-center justify-between">
84
- <div>
85
- <p className="font-medium">{provider.name}</p>
86
- <p className="text-sm text-[#666]">{provider.models.length} models</p>
110
+ {recentTasks.map((task) => (
111
+ <div
112
+ key={`${task.agentId}-${task.id}`}
113
+ className="px-4 py-3 flex items-center justify-between"
114
+ >
115
+ <div className="flex-1 min-w-0">
116
+ <p className="font-medium truncate">{task.title}</p>
117
+ <p className="text-sm text-[#666]">{task.agentName}</p>
87
118
  </div>
88
- <span className="text-green-400 text-sm">{provider.keyHint}</span>
119
+ <TaskStatusBadge status={task.status} />
89
120
  </div>
90
121
  ))}
91
122
  </div>
@@ -99,14 +130,16 @@ export function Dashboard({
99
130
  interface StatCardProps {
100
131
  label: string;
101
132
  value: number;
133
+ subValue?: string;
102
134
  color?: string;
103
135
  }
104
136
 
105
- function StatCard({ label, value, color }: StatCardProps) {
137
+ function StatCard({ label, value, subValue, color }: StatCardProps) {
106
138
  return (
107
139
  <div className="bg-[#111] rounded p-4 border border-[#1a1a1a]">
108
140
  <p className="text-sm text-[#666] mb-1">{label}</p>
109
141
  <p className={`text-2xl font-semibold ${color || ''}`}>{value}</p>
142
+ {subValue && <p className="text-xs text-[#555] mt-1">{subValue}</p>}
110
143
  </div>
111
144
  );
112
145
  }
@@ -134,3 +167,19 @@ function DashboardCard({ title, actionLabel, onAction, children }: DashboardCard
134
167
  </div>
135
168
  );
136
169
  }
170
+
171
+ function TaskStatusBadge({ status }: { status: Task["status"] }) {
172
+ const colors: Record<string, string> = {
173
+ pending: "bg-yellow-500/20 text-yellow-400",
174
+ running: "bg-blue-500/20 text-blue-400",
175
+ completed: "bg-green-500/20 text-green-400",
176
+ failed: "bg-red-500/20 text-red-400",
177
+ cancelled: "bg-gray-500/20 text-gray-400",
178
+ };
179
+
180
+ return (
181
+ <span className={`px-2 py-0.5 rounded text-xs font-medium ${colors[status] || colors.pending}`}>
182
+ {status}
183
+ </span>
184
+ );
185
+ }
@@ -1,5 +1,5 @@
1
1
  // Common components
2
- export { LoadingSpinner, Modal, Select, CheckIcon, CloseIcon, DashboardIcon, AgentsIcon, SettingsIcon } from "./common";
2
+ export { LoadingSpinner, Modal, Select, CheckIcon, CloseIcon, DashboardIcon, AgentsIcon, SettingsIcon, TasksIcon } from "./common";
3
3
 
4
4
  // Layout components
5
5
  export { Header, Sidebar, ErrorBanner } from "./layout";
@@ -7,5 +7,8 @@ export { Header, Sidebar, ErrorBanner } from "./layout";
7
7
  // Feature components
8
8
  export { OnboardingWizard } from "./onboarding";
9
9
  export { SettingsPage } from "./settings";
10
- export { AgentCard, CreateAgentModal, ChatPanel, AgentsView } from "./agents";
10
+ export { AgentCard, CreateAgentModal, AgentPanel, AgentsView } from "./agents";
11
11
  export { Dashboard } from "./dashboard";
12
+ export { TasksPage } from "./tasks";
13
+ export { McpPage } from "./mcp";
14
+ export { TelemetryPage } from "./telemetry/TelemetryPage";
@@ -1,14 +1,15 @@
1
1
  import React from "react";
2
- import { DashboardIcon, AgentsIcon, SettingsIcon } from "../common/Icons";
2
+ import { DashboardIcon, AgentsIcon, TasksIcon, McpIcon, TelemetryIcon, SettingsIcon } from "../common/Icons";
3
3
  import type { Route } from "../../types";
4
4
 
5
5
  interface SidebarProps {
6
6
  route: Route;
7
7
  agentCount: number;
8
+ taskCount?: number;
8
9
  onNavigate: (route: Route) => void;
9
10
  }
10
11
 
11
- export function Sidebar({ route, agentCount, onNavigate }: SidebarProps) {
12
+ export function Sidebar({ route, agentCount, taskCount, onNavigate }: SidebarProps) {
12
13
  return (
13
14
  <aside className="w-56 border-r border-[#1a1a1a] flex-shrink-0 p-4">
14
15
  <nav className="space-y-1">
@@ -25,6 +26,25 @@ export function Sidebar({ route, agentCount, onNavigate }: SidebarProps) {
25
26
  onClick={() => onNavigate("agents")}
26
27
  badge={agentCount > 0 ? String(agentCount) : undefined}
27
28
  />
29
+ <NavButton
30
+ icon={<TasksIcon />}
31
+ label="Tasks"
32
+ active={route === "tasks"}
33
+ onClick={() => onNavigate("tasks")}
34
+ badge={taskCount && taskCount > 0 ? String(taskCount) : undefined}
35
+ />
36
+ <NavButton
37
+ icon={<McpIcon />}
38
+ label="MCP"
39
+ active={route === "mcp"}
40
+ onClick={() => onNavigate("mcp")}
41
+ />
42
+ <NavButton
43
+ icon={<TelemetryIcon />}
44
+ label="Telemetry"
45
+ active={route === "telemetry"}
46
+ onClick={() => onNavigate("telemetry")}
47
+ />
28
48
  <NavButton
29
49
  icon={<SettingsIcon />}
30
50
  label="Settings"