apteva 0.4.17 → 0.4.18

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 (59) hide show
  1. package/dist/ActivityPage.yv28a2vj.js +3 -0
  2. package/dist/ApiDocsPage.4ccwjjbk.js +4 -0
  3. package/dist/App.155wke5v.js +4 -0
  4. package/dist/App.2e19nvn4.js +13 -0
  5. package/dist/App.2ye1b5n0.js +4 -0
  6. package/dist/App.4da4ycbe.js +4 -0
  7. package/dist/App.b6wtzd1j.js +4 -0
  8. package/dist/App.fjrh28tf.js +4 -0
  9. package/dist/App.htc36cy8.js +4 -0
  10. package/dist/App.me6reaa6.js +4 -0
  11. package/dist/App.n5q6p960.js +4 -0
  12. package/dist/App.nft7h9jt.js +4 -0
  13. package/dist/App.np463xvy.js +4 -0
  14. package/dist/App.nps62kvt.js +4 -0
  15. package/dist/App.q8ws33cc.js +181 -0
  16. package/dist/App.tb0y0jmt.js +40 -0
  17. package/dist/ConnectionsPage.52evzrp7.js +3 -0
  18. package/dist/McpPage.bjqrp0n2.js +3 -0
  19. package/dist/SettingsPage.es76hnj2.js +3 -0
  20. package/dist/SkillsPage.06h8yf0h.js +3 -0
  21. package/dist/TasksPage.99df66mk.js +3 -0
  22. package/dist/TelemetryPage.bmdnxhq7.js +3 -0
  23. package/dist/TestsPage.denxrg8c.js +3 -0
  24. package/dist/index.html +1 -1
  25. package/dist/styles.css +1 -1
  26. package/package.json +1 -1
  27. package/src/auth/middleware.ts +2 -0
  28. package/src/db.ts +162 -11
  29. package/src/mcp-platform.ts +41 -1
  30. package/src/routes/api/agent-utils.ts +38 -2
  31. package/src/routes/api/agents.ts +65 -2
  32. package/src/routes/api/projects.ts +19 -2
  33. package/src/routes/api/system.ts +26 -12
  34. package/src/routes/api/triggers.ts +458 -0
  35. package/src/routes/api/webhooks.ts +171 -0
  36. package/src/routes/api.ts +4 -0
  37. package/src/routes/static.ts +12 -3
  38. package/src/server.ts +4 -2
  39. package/src/triggers/agentdojo.ts +248 -0
  40. package/src/triggers/composio.ts +264 -0
  41. package/src/triggers/index.ts +71 -0
  42. package/src/web/App.tsx +17 -10
  43. package/src/web/components/agents/AgentCard.tsx +14 -7
  44. package/src/web/components/agents/AgentPanel.tsx +105 -115
  45. package/src/web/components/common/Icons.tsx +8 -0
  46. package/src/web/components/common/index.ts +1 -0
  47. package/src/web/components/connections/ConnectionsPage.tsx +54 -0
  48. package/src/web/components/connections/IntegrationsTab.tsx +144 -0
  49. package/src/web/components/connections/OverviewTab.tsx +183 -0
  50. package/src/web/components/connections/TriggersTab.tsx +690 -0
  51. package/src/web/components/index.ts +1 -0
  52. package/src/web/components/layout/Sidebar.tsx +7 -1
  53. package/src/web/components/mcp/IntegrationsPanel.tsx +19 -3
  54. package/src/web/components/settings/SettingsPage.tsx +96 -2
  55. package/src/web/components/tasks/TasksPage.tsx +2 -2
  56. package/src/web/components/tests/TestsPage.tsx +1 -2
  57. package/src/web/hooks/useAgents.ts +15 -11
  58. package/src/web/types.ts +1 -1
  59. package/dist/App.fq4xbpcz.js +0 -228
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { DashboardIcon, ActivityIcon, AgentsIcon, TasksIcon, McpIcon, SkillsIcon, TestsIcon, TelemetryIcon, ApiIcon, SettingsIcon, CloseIcon } from "../common/Icons";
2
+ import { DashboardIcon, ActivityIcon, AgentsIcon, TasksIcon, ConnectionsIcon, McpIcon, SkillsIcon, TestsIcon, TelemetryIcon, ApiIcon, SettingsIcon, CloseIcon } from "../common/Icons";
3
3
  import type { Route } from "../../types";
4
4
 
5
5
  interface SidebarProps {
@@ -88,6 +88,12 @@ export function Sidebar({ route, agentCount, taskCount, onNavigate, isOpen, onCl
88
88
  active={route === "skills"}
89
89
  onClick={() => handleNavigate("skills")}
90
90
  />
91
+ <NavButton
92
+ icon={<ConnectionsIcon />}
93
+ label="Connections"
94
+ active={route === "connections"}
95
+ onClick={() => handleNavigate("connections")}
96
+ />
91
97
  <NavButton
92
98
  icon={<TestsIcon />}
93
99
  label="Tests"
@@ -46,10 +46,14 @@ export function IntegrationsPanel({
46
46
  providerId = "composio",
47
47
  projectId,
48
48
  onConnectionComplete,
49
+ onBrowseTriggers,
50
+ hideMcpConfig,
49
51
  }: {
50
52
  providerId?: string;
51
53
  projectId?: string | null;
52
54
  onConnectionComplete?: () => void;
55
+ onBrowseTriggers?: (toolkitSlug: string) => void;
56
+ hideMcpConfig?: boolean;
53
57
  }) {
54
58
  const { authFetch } = useAuth();
55
59
  const [apps, setApps] = useState<IntegrationApp[]>([]);
@@ -314,9 +318,10 @@ export function IntegrationsPanel({
314
318
  );
315
319
  };
316
320
 
317
- // Get connection for app
321
+ // Get connection for app (prefer active account)
318
322
  const getConnection = (appSlug: string) => {
319
- return connectedAccounts.find((a) => a.appId === appSlug);
323
+ return connectedAccounts.find((a) => a.appId === appSlug && a.status === "active")
324
+ || connectedAccounts.find((a) => a.appId === appSlug);
320
325
  };
321
326
 
322
327
  // Filter apps
@@ -590,7 +595,8 @@ export function IntegrationsPanel({
590
595
  const conn = getConnection(app.slug);
591
596
  if (conn) handleDisconnect(conn);
592
597
  }}
593
- onCreateMcpConfig={() => openMcpConfigModal(app)}
598
+ onCreateMcpConfig={hideMcpConfig ? undefined : () => openMcpConfigModal(app)}
599
+ onBrowseTriggers={onBrowseTriggers ? () => onBrowseTriggers(app.slug) : undefined}
594
600
  connecting={connecting === app.slug}
595
601
  />
596
602
  ))}
@@ -636,6 +642,7 @@ function AppCard({
636
642
  onConnect,
637
643
  onDisconnect,
638
644
  onCreateMcpConfig,
645
+ onBrowseTriggers,
639
646
  connecting,
640
647
  }: {
641
648
  app: IntegrationApp;
@@ -643,6 +650,7 @@ function AppCard({
643
650
  onConnect: () => void;
644
651
  onDisconnect?: () => void;
645
652
  onCreateMcpConfig?: () => void;
653
+ onBrowseTriggers?: () => void;
646
654
  connecting: boolean;
647
655
  }) {
648
656
  const isConnected = connection?.status === "active";
@@ -723,6 +731,14 @@ function AppCard({
723
731
  Create MCP Config
724
732
  </button>
725
733
  )}
734
+ {onBrowseTriggers && (
735
+ <button
736
+ onClick={onBrowseTriggers}
737
+ className="flex-1 text-xs bg-[#1a1a2a] hover:bg-[#1a1a3a] border border-blue-500/30 hover:border-blue-500/50 text-blue-400 px-3 py-1.5 rounded transition"
738
+ >
739
+ Browse Triggers
740
+ </button>
741
+ )}
726
742
  {onDisconnect && (
727
743
  <button
728
744
  onClick={onDisconnect}
@@ -5,13 +5,14 @@ import { Select } from "../common/Select";
5
5
  import { useProjects, useAuth, type Project } from "../../context";
6
6
  import type { Provider } from "../../types";
7
7
 
8
- type SettingsTab = "providers" | "projects" | "api-keys" | "account" | "updates" | "data";
8
+ type SettingsTab = "general" | "providers" | "projects" | "api-keys" | "account" | "updates" | "data";
9
9
 
10
10
  export function SettingsPage() {
11
11
  const { projectsEnabled } = useProjects();
12
- const [activeTab, setActiveTab] = useState<SettingsTab>("providers");
12
+ const [activeTab, setActiveTab] = useState<SettingsTab>("general");
13
13
 
14
14
  const tabs: { key: SettingsTab; label: string }[] = [
15
+ { key: "general", label: "General" },
15
16
  { key: "providers", label: "Providers" },
16
17
  ...(projectsEnabled ? [{ key: "projects" as SettingsTab, label: "Projects" }] : []),
17
18
  { key: "api-keys", label: "API Keys" },
@@ -58,6 +59,7 @@ export function SettingsPage() {
58
59
 
59
60
  {/* Settings Content */}
60
61
  <div className="flex-1 overflow-auto p-4 md:p-6">
62
+ {activeTab === "general" && <GeneralSettings />}
61
63
  {activeTab === "providers" && <ProvidersSettings />}
62
64
  {activeTab === "projects" && projectsEnabled && <ProjectsSettings />}
63
65
  {activeTab === "api-keys" && <ApiKeysSettings />}
@@ -92,6 +94,98 @@ function SettingsNavItem({
92
94
  );
93
95
  }
94
96
 
97
+ function GeneralSettings() {
98
+ const { authFetch } = useAuth();
99
+ const [instanceUrl, setInstanceUrl] = useState("");
100
+ const [loading, setLoading] = useState(true);
101
+ const [saving, setSaving] = useState(false);
102
+ const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null);
103
+
104
+ useEffect(() => {
105
+ const fetch = async () => {
106
+ try {
107
+ const res = await authFetch("/api/settings/instance-url");
108
+ const data = await res.json();
109
+ setInstanceUrl(data.instance_url || "");
110
+ } catch {
111
+ // ignore
112
+ }
113
+ setLoading(false);
114
+ };
115
+ fetch();
116
+ }, []);
117
+
118
+ const handleSave = async () => {
119
+ setSaving(true);
120
+ setMessage(null);
121
+ try {
122
+ const res = await authFetch("/api/settings/instance-url", {
123
+ method: "PUT",
124
+ headers: { "Content-Type": "application/json" },
125
+ body: JSON.stringify({ instance_url: instanceUrl }),
126
+ });
127
+ const data = await res.json();
128
+ if (res.ok) {
129
+ setInstanceUrl(data.instance_url || "");
130
+ setMessage({ type: "success", text: "Instance URL saved" });
131
+ } else {
132
+ setMessage({ type: "error", text: data.error || "Failed to save" });
133
+ }
134
+ } catch {
135
+ setMessage({ type: "error", text: "Failed to save" });
136
+ }
137
+ setSaving(false);
138
+ };
139
+
140
+ return (
141
+ <div className="max-w-4xl w-full">
142
+ <div className="mb-6">
143
+ <h1 className="text-2xl font-semibold mb-1">General</h1>
144
+ <p className="text-[#666]">Instance configuration.</p>
145
+ </div>
146
+
147
+ <div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-4">
148
+ <h3 className="font-medium mb-2">Instance URL</h3>
149
+ <p className="text-sm text-[#666] mb-4">
150
+ The public HTTPS URL for this instance. Used for webhook callbacks from external services like Composio.
151
+ </p>
152
+
153
+ {loading ? (
154
+ <div className="text-[#666] text-sm">Loading...</div>
155
+ ) : (
156
+ <div className="space-y-3 max-w-lg">
157
+ <input
158
+ type="text"
159
+ value={instanceUrl}
160
+ onChange={e => setInstanceUrl(e.target.value)}
161
+ placeholder="https://your-domain.com"
162
+ className="w-full bg-[#0a0a0a] border border-[#333] rounded px-3 py-2 focus:outline-none focus:border-[#f97316] font-mono text-sm"
163
+ />
164
+
165
+ {message && (
166
+ <div className={`p-3 rounded text-sm ${
167
+ message.type === "success"
168
+ ? "bg-green-500/10 text-green-400 border border-green-500/30"
169
+ : "bg-red-500/10 text-red-400 border border-red-500/30"
170
+ }`}>
171
+ {message.text}
172
+ </div>
173
+ )}
174
+
175
+ <button
176
+ onClick={handleSave}
177
+ disabled={saving}
178
+ className="px-4 py-2 bg-[#f97316] hover:bg-[#fb923c] disabled:opacity-50 text-black rounded text-sm font-medium transition"
179
+ >
180
+ {saving ? "Saving..." : "Save"}
181
+ </button>
182
+ </div>
183
+ )}
184
+ </div>
185
+ </div>
186
+ );
187
+ }
188
+
95
189
  function ProvidersSettings() {
96
190
  const { authFetch } = useAuth();
97
191
  const { projects, projectsEnabled } = useProjects();
@@ -500,7 +500,7 @@ function TrajectoryView({ trajectory }: { trajectory: TaskTrajectoryStep[] }) {
500
500
 
501
501
  const DAY_NAMES = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
502
502
 
503
- function formatCron(cron: string): string {
503
+ export function formatCron(cron: string): string {
504
504
  try {
505
505
  const parts = cron.trim().split(/\s+/);
506
506
  if (parts.length !== 5) return cron;
@@ -558,7 +558,7 @@ function formatCron(cron: string): string {
558
558
  }
559
559
  }
560
560
 
561
- function formatRelativeTime(dateStr: string): string {
561
+ export function formatRelativeTime(dateStr: string): string {
562
562
  const date = new Date(dateStr);
563
563
  const now = new Date();
564
564
  const diffMs = date.getTime() - now.getTime();
@@ -157,8 +157,7 @@ export function TestsPage() {
157
157
  };
158
158
 
159
159
  useEffect(() => {
160
- fetchTests();
161
- fetchAgents();
160
+ Promise.all([fetchTests(), fetchAgents()]);
162
161
  }, [currentProjectId]);
163
162
 
164
163
  const openCreate = () => {
@@ -23,19 +23,13 @@ export function useAgents(enabled: boolean) {
23
23
  setLoading(false);
24
24
  }, [getHeaders]);
25
25
 
26
- // Auto-refetch when agents start/stop/crash (via SSE telemetry)
26
+ // Fetch on mount + auto-refetch when agents start/stop/crash (via SSE telemetry)
27
27
  const statusChangeCounter = useAgentStatusChange();
28
- useEffect(() => {
29
- if (enabled && statusChangeCounter > 0) {
30
- fetchAgents();
31
- }
32
- }, [enabled, statusChangeCounter, fetchAgents]);
33
-
34
28
  useEffect(() => {
35
29
  if (enabled) {
36
30
  fetchAgents();
37
31
  }
38
- }, [enabled, fetchAgents]);
32
+ }, [enabled, statusChangeCounter, fetchAgents]);
39
33
 
40
34
  const createAgent = async (agent: {
41
35
  name: string;
@@ -83,10 +77,20 @@ export function useAgents(enabled: boolean) {
83
77
 
84
78
  const toggleAgent = async (agent: Agent): Promise<{ error?: string }> => {
85
79
  const action = agent.status === "running" ? "stop" : "start";
80
+
81
+ // Optimistic UI update — show transitioning state immediately
82
+ setAgents(prev => prev.map(a =>
83
+ a.id === agent.id ? { ...a, status: action === "start" ? "starting" as any : "stopping" as any } : a
84
+ ));
85
+
86
+ // Fire API call — telemetry SSE will trigger a refetch with the real status
86
87
  const res = await fetch(`/api/agents/${agent.id}/${action}`, { method: "POST", headers: getHeaders() });
87
- const data = await res.json();
88
- await fetchAgents();
89
- if (!res.ok && data.error) {
88
+ if (!res.ok) {
89
+ const data = await res.json();
90
+ // Revert on error
91
+ setAgents(prev => prev.map(a =>
92
+ a.id === agent.id ? { ...a, status: agent.status } : a
93
+ ));
90
94
  return { error: data.error };
91
95
  }
92
96
  return {};
package/src/web/types.ts CHANGED
@@ -143,7 +143,7 @@ export interface OnboardingStatus {
143
143
  has_any_keys: boolean;
144
144
  }
145
145
 
146
- export type Route = "dashboard" | "activity" | "agents" | "tasks" | "mcp" | "skills" | "tests" | "telemetry" | "settings" | "api";
146
+ export type Route = "dashboard" | "activity" | "agents" | "tasks" | "connections" | "mcp" | "skills" | "tests" | "telemetry" | "settings" | "api";
147
147
 
148
148
  // Tool use content block in trajectory
149
149
  export interface ToolUseBlock {