apteva 0.4.18 → 0.4.20

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 (84) hide show
  1. package/dist/ActivityPage.h769ek3a.js +3 -0
  2. package/dist/ApiDocsPage.kf6bbwkk.js +4 -0
  3. package/dist/{App.nps62kvt.js → App.039re6cf.js} +3 -3
  4. package/dist/App.2jmkqm8c.js +4 -0
  5. package/dist/{App.np463xvy.js → App.2yy66bnp.js} +3 -3
  6. package/dist/App.3515wsb4.js +4 -0
  7. package/dist/App.7v1w3ys9.js +4 -0
  8. package/dist/{App.nft7h9jt.js → App.c90t3dxg.js} +3 -3
  9. package/dist/App.edwahsvz.js +4 -0
  10. package/dist/App.jfx3der4.js +4 -0
  11. package/dist/App.n4jb3c22.js +13 -0
  12. package/dist/{App.mq6jqare.js → App.p02f4ret.js} +1 -1
  13. package/dist/App.q3bpx15d.js +20 -0
  14. package/dist/App.r0a2nmqs.js +267 -0
  15. package/dist/App.s2yrcz15.js +4 -0
  16. package/dist/App.s5j82a5j.js +4 -0
  17. package/dist/App.tg1b94tx.js +4 -0
  18. package/dist/ConnectionsPage.a67fjgbf.js +3 -0
  19. package/dist/McpPage.d4p3xvtk.js +3 -0
  20. package/dist/SettingsPage.46sqpe39.js +3 -0
  21. package/dist/SkillsPage.j9hkqm99.js +3 -0
  22. package/dist/TasksPage.6pvkb7s7.js +3 -0
  23. package/dist/TelemetryPage.5zq9msb5.js +3 -0
  24. package/dist/TestsPage.24432yqt.js +3 -0
  25. package/dist/apteva-kit.css +1 -1
  26. package/dist/index.html +1 -1
  27. package/dist/styles.css +1 -1
  28. package/package.json +9 -4
  29. package/src/channels/index.ts +40 -0
  30. package/src/channels/telegram.ts +306 -0
  31. package/src/db.ts +180 -0
  32. package/src/integrations/agentdojo.ts +1 -1
  33. package/src/mcp-handler.ts +31 -24
  34. package/src/mcp-platform.ts +353 -2
  35. package/src/providers.ts +22 -9
  36. package/src/routes/api/agents.ts +15 -2
  37. package/src/routes/api/channels.ts +182 -0
  38. package/src/routes/api/integrations.ts +13 -5
  39. package/src/routes/api/mcp.ts +27 -9
  40. package/src/routes/api/system.ts +12 -1
  41. package/src/routes/api/telemetry.ts +30 -0
  42. package/src/routes/api/triggers.ts +22 -2
  43. package/src/routes/api.ts +3 -1
  44. package/src/routes/auth.ts +11 -2
  45. package/src/server.ts +39 -4
  46. package/src/triggers/agentdojo.ts +23 -18
  47. package/src/tui/AgentList.tsx +145 -0
  48. package/src/tui/App.tsx +102 -0
  49. package/src/tui/Login.tsx +104 -0
  50. package/src/tui/api.ts +72 -0
  51. package/src/tui/index.tsx +7 -0
  52. package/src/web/App.tsx +2 -2
  53. package/src/web/components/agents/AgentPanel.tsx +4 -37
  54. package/src/web/components/common/Icons.tsx +8 -0
  55. package/src/web/components/connections/OverviewTab.tsx +22 -68
  56. package/src/web/components/connections/TriggersTab.tsx +549 -70
  57. package/src/web/components/dashboard/Dashboard.tsx +5 -4
  58. package/src/web/components/layout/Header.tsx +196 -4
  59. package/src/web/components/settings/SettingsPage.tsx +269 -1
  60. package/src/web/context/AuthContext.tsx +18 -11
  61. package/src/web/context/TelemetryContext.tsx +14 -1
  62. package/src/web/context/index.ts +1 -1
  63. package/src/web/hooks/useAgents.ts +7 -3
  64. package/src/web/hooks/useOnboarding.ts +9 -30
  65. package/dist/ActivityPage.yv28a2vj.js +0 -3
  66. package/dist/ApiDocsPage.4ccwjjbk.js +0 -4
  67. package/dist/App.155wke5v.js +0 -4
  68. package/dist/App.2e19nvn4.js +0 -13
  69. package/dist/App.2ye1b5n0.js +0 -4
  70. package/dist/App.4da4ycbe.js +0 -4
  71. package/dist/App.b6wtzd1j.js +0 -4
  72. package/dist/App.fjrh28tf.js +0 -4
  73. package/dist/App.htc36cy8.js +0 -4
  74. package/dist/App.me6reaa6.js +0 -4
  75. package/dist/App.n5q6p960.js +0 -4
  76. package/dist/App.q8ws33cc.js +0 -181
  77. package/dist/App.tb0y0jmt.js +0 -40
  78. package/dist/ConnectionsPage.52evzrp7.js +0 -3
  79. package/dist/McpPage.bjqrp0n2.js +0 -3
  80. package/dist/SettingsPage.es76hnj2.js +0 -3
  81. package/dist/SkillsPage.06h8yf0h.js +0 -3
  82. package/dist/TasksPage.99df66mk.js +0 -3
  83. package/dist/TelemetryPage.bmdnxhq7.js +0 -3
  84. package/dist/TestsPage.denxrg8c.js +0 -3
@@ -0,0 +1,102 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { Box, Text } from "ink";
3
+ import Spinner from "ink-spinner";
4
+ import { AptevaAPI, type User } from "./api.js";
5
+ import { Login } from "./Login.js";
6
+ import { AgentList } from "./AgentList.js";
7
+ import { spawn } from "child_process";
8
+ import { resolve, dirname } from "path";
9
+ import { fileURLToPath } from "url";
10
+
11
+ interface AppProps {
12
+ baseUrl: string;
13
+ }
14
+
15
+ export function App({ baseUrl }: AppProps) {
16
+ const [api] = useState(() => new AptevaAPI(baseUrl));
17
+ const [screen, setScreen] = useState<"connecting" | "login" | "agents">("connecting");
18
+ const [user, setUser] = useState<User | null>(null);
19
+ const [connectError, setConnectError] = useState("");
20
+
21
+ useEffect(() => {
22
+ let cancelled = false;
23
+
24
+ const tryConnect = async () => {
25
+ // First check if server is already running
26
+ const connected = await api.checkConnection();
27
+ if (cancelled) return;
28
+
29
+ if (connected) {
30
+ setScreen("login");
31
+ return;
32
+ }
33
+
34
+ // Server not running — try to start it
35
+ setConnectError("Server not running. Starting...");
36
+
37
+ try {
38
+ // Find the server entry point relative to this file
39
+ const serverPath = resolve(dirname(fileURLToPath(import.meta.url)), "../server.ts");
40
+ const child = spawn("bun", ["run", serverPath], {
41
+ stdio: "ignore",
42
+ detached: true,
43
+ env: { ...process.env, PORT: new URL(baseUrl).port || "4280" },
44
+ });
45
+ child.unref();
46
+
47
+ // Wait for server to come up (poll for up to 10 seconds)
48
+ for (let i = 0; i < 20; i++) {
49
+ if (cancelled) return;
50
+ await new Promise(r => setTimeout(r, 500));
51
+ const up = await api.checkConnection();
52
+ if (up) {
53
+ if (!cancelled) setScreen("login");
54
+ return;
55
+ }
56
+ }
57
+ } catch {
58
+ // Spawn failed
59
+ }
60
+
61
+ if (!cancelled) {
62
+ setConnectError(`Cannot connect to ${baseUrl}. Start the server with: bun run dev`);
63
+ }
64
+ };
65
+
66
+ tryConnect();
67
+ return () => { cancelled = true; };
68
+ }, []);
69
+
70
+ if (screen === "connecting") {
71
+ return (
72
+ <Box flexDirection="column" padding={1}>
73
+ <Box marginBottom={1}>
74
+ <Text color="hex('#f97316')" bold>{">"}_</Text>
75
+ <Text bold> apteva</Text>
76
+ </Box>
77
+ <Box>
78
+ <Text color="hex('#f97316')"><Spinner type="dots" /></Text>
79
+ <Text> {connectError || `Connecting to ${baseUrl}...`}</Text>
80
+ </Box>
81
+ </Box>
82
+ );
83
+ }
84
+
85
+ if (screen === "login") {
86
+ return (
87
+ <Login
88
+ api={api}
89
+ onSuccess={(u) => {
90
+ setUser(u);
91
+ setScreen("agents");
92
+ }}
93
+ />
94
+ );
95
+ }
96
+
97
+ if (screen === "agents" && user) {
98
+ return <AgentList api={api} user={user} />;
99
+ }
100
+
101
+ return null;
102
+ }
@@ -0,0 +1,104 @@
1
+ import React, { useState } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import TextInput from "ink-text-input";
4
+ import Spinner from "ink-spinner";
5
+ import type { AptevaAPI, User } from "./api.js";
6
+
7
+ interface LoginProps {
8
+ api: AptevaAPI;
9
+ onSuccess: (user: User) => void;
10
+ }
11
+
12
+ export function Login({ api, onSuccess }: LoginProps) {
13
+ const [field, setField] = useState<"username" | "password">("username");
14
+ const [username, setUsername] = useState("");
15
+ const [password, setPassword] = useState("");
16
+ const [error, setError] = useState("");
17
+ const [loading, setLoading] = useState(false);
18
+
19
+ useInput((input, key) => {
20
+ if (key.tab || (key.return && field === "username" && username)) {
21
+ setField(field === "username" ? "password" : "username");
22
+ }
23
+ });
24
+
25
+ const handleSubmit = async () => {
26
+ if (!username || !password) return;
27
+ setLoading(true);
28
+ setError("");
29
+ const result = await api.login(username, password);
30
+ setLoading(false);
31
+ if (result.success && result.user) {
32
+ onSuccess(result.user);
33
+ } else {
34
+ setError(result.error || "Login failed");
35
+ }
36
+ };
37
+
38
+ return (
39
+ <Box flexDirection="column" padding={1}>
40
+ <Box marginBottom={1}>
41
+ <Text color="hex('#f97316')" bold>
42
+ {">"}_
43
+ </Text>
44
+ <Text bold> apteva</Text>
45
+ </Box>
46
+
47
+ <Box marginBottom={1}>
48
+ <Text dimColor>Sign in to continue</Text>
49
+ </Box>
50
+
51
+ <Box>
52
+ <Text color={field === "username" ? "hex('#f97316')" : "white"}>
53
+ Username:{" "}
54
+ </Text>
55
+ {field === "username" ? (
56
+ <TextInput
57
+ value={username}
58
+ onChange={setUsername}
59
+ onSubmit={() => {
60
+ if (username) setField("password");
61
+ }}
62
+ />
63
+ ) : (
64
+ <Text>{username}</Text>
65
+ )}
66
+ </Box>
67
+
68
+ <Box>
69
+ <Text color={field === "password" ? "hex('#f97316')" : "white"}>
70
+ Password:{" "}
71
+ </Text>
72
+ {field === "password" ? (
73
+ <TextInput
74
+ value={password}
75
+ onChange={setPassword}
76
+ onSubmit={handleSubmit}
77
+ mask="*"
78
+ />
79
+ ) : (
80
+ <Text dimColor>{"*".repeat(password.length) || "..."}</Text>
81
+ )}
82
+ </Box>
83
+
84
+ {loading && (
85
+ <Box marginTop={1}>
86
+ <Text color="hex('#f97316')">
87
+ <Spinner type="dots" />
88
+ </Text>
89
+ <Text> Signing in...</Text>
90
+ </Box>
91
+ )}
92
+
93
+ {error && (
94
+ <Box marginTop={1}>
95
+ <Text color="red">{error}</Text>
96
+ </Box>
97
+ )}
98
+
99
+ <Box marginTop={1}>
100
+ <Text dimColor>Tab to switch fields · Enter to submit</Text>
101
+ </Box>
102
+ </Box>
103
+ );
104
+ }
package/src/tui/api.ts ADDED
@@ -0,0 +1,72 @@
1
+ export interface Agent {
2
+ id: string;
3
+ name: string;
4
+ model: string;
5
+ provider: string;
6
+ status: "running" | "stopped" | "error";
7
+ port: number | null;
8
+ projectId: string | null;
9
+ }
10
+
11
+ export interface User {
12
+ id: string;
13
+ username: string;
14
+ role: string;
15
+ }
16
+
17
+ export class AptevaAPI {
18
+ baseUrl: string;
19
+ private token: string | null = null;
20
+
21
+ constructor(baseUrl: string) {
22
+ this.baseUrl = baseUrl.replace(/\/$/, "");
23
+ }
24
+
25
+ async checkConnection(): Promise<boolean> {
26
+ try {
27
+ const res = await fetch(`${this.baseUrl}/api/auth/check`, { signal: AbortSignal.timeout(3000) });
28
+ return res.ok;
29
+ } catch {
30
+ return false;
31
+ }
32
+ }
33
+
34
+ private async fetch(path: string, opts: RequestInit = {}): Promise<Response> {
35
+ const headers: Record<string, string> = {
36
+ "Content-Type": "application/json",
37
+ ...(opts.headers as Record<string, string> || {}),
38
+ };
39
+ if (this.token) {
40
+ headers.Authorization = `Bearer ${this.token}`;
41
+ }
42
+ return fetch(`${this.baseUrl}${path}`, { ...opts, headers });
43
+ }
44
+
45
+ async login(username: string, password: string): Promise<{ success: boolean; user?: User; error?: string }> {
46
+ try {
47
+ const res = await this.fetch("/api/auth/login", {
48
+ method: "POST",
49
+ body: JSON.stringify({ username, password }),
50
+ });
51
+ const data = await res.json();
52
+ if (!res.ok) {
53
+ return { success: false, error: data.error || "Login failed" };
54
+ }
55
+ this.token = data.accessToken;
56
+ return { success: true, user: data.user };
57
+ } catch (err: any) {
58
+ return { success: false, error: err.message || "Connection failed" };
59
+ }
60
+ }
61
+
62
+ async getAgents(): Promise<Agent[]> {
63
+ try {
64
+ const res = await this.fetch("/api/agents");
65
+ if (!res.ok) return [];
66
+ const data = await res.json();
67
+ return data.agents || [];
68
+ } catch {
69
+ return [];
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { render } from "ink";
3
+ import { App } from "./App.js";
4
+
5
+ const baseUrl = process.argv[2] || "http://localhost:4280";
6
+
7
+ render(<App baseUrl={baseUrl} />);
package/src/web/App.tsx CHANGED
@@ -64,7 +64,7 @@ function AppContent() {
64
64
  updateAgent,
65
65
  deleteAgent,
66
66
  toggleAgent,
67
- } = useAgents(shouldFetchData);
67
+ } = useAgents(shouldFetchData, currentProjectId);
68
68
 
69
69
  const {
70
70
  providers,
@@ -240,7 +240,7 @@ function AppContent() {
240
240
 
241
241
  return (
242
242
  <div className="h-screen bg-[#0a0a0a] text-[#e0e0e0] font-mono flex flex-col overflow-hidden">
243
- <Header onMenuClick={() => setMobileMenuOpen(true)} />
243
+ <Header onMenuClick={() => setMobileMenuOpen(true)} agents={agents} />
244
244
 
245
245
  {startError && (
246
246
  <ErrorBanner message={startError} onDismiss={() => setStartError(null)} />
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect } from "react";
2
- import { Chat } from "@apteva/apteva-kit";
2
+ import { Chat, convertApiMessages } from "@apteva/apteva-kit";
3
3
  import { CloseIcon, MemoryIcon, TasksIcon, VisionIcon, OperatorIcon, McpIcon, RealtimeIcon, FilesIcon, MultiAgentIcon, RecurringIcon, ScheduledIcon, TaskOnceIcon } from "../common/Icons";
4
4
  import { formatCron, formatRelativeTime } from "../tasks/TasksPage";
5
5
  import { Select } from "../common/Select";
@@ -195,15 +195,7 @@ function ThreadsTab({ agent }: { agent: Agent }) {
195
195
  const res = await fetch(`/api/agents/${agent.id}/threads/${threadId}/messages`);
196
196
  if (res.ok) {
197
197
  const data = await res.json();
198
- const msgs = (data.messages || [])
199
- .filter((m: any) => typeof m.content === "string")
200
- .map((m: any) => ({
201
- id: m.id,
202
- role: m.role,
203
- content: m.content,
204
- timestamp: new Date(m.created_at),
205
- }));
206
- setInitialMessages(msgs);
198
+ setInitialMessages(convertApiMessages(data.messages || []));
207
199
  } else {
208
200
  setInitialMessages([]);
209
201
  }
@@ -255,36 +247,10 @@ function ThreadsTab({ agent }: { agent: Agent }) {
255
247
 
256
248
  // Show live chat for selected thread
257
249
  if (selectedThread) {
258
- const selectedThreadData = threads.find(t => t.id === selectedThread);
259
250
  return (
260
251
  <>
261
252
  {ConfirmDialog}
262
253
  <div className="flex-1 flex flex-col overflow-hidden">
263
- {/* Header with back button */}
264
- <div className="flex items-center gap-3 px-4 py-2 border-b border-[#1a1a1a] flex-shrink-0">
265
- <button
266
- onClick={() => { setSelectedThread(null); setInitialMessages([]); }}
267
- className="text-[#666] hover:text-[#e0e0e0] transition text-lg"
268
- >
269
-
270
- </button>
271
- <div className="flex-1 min-w-0">
272
- <p className="text-sm font-medium truncate">
273
- {selectedThreadData?.title || `Thread ${selectedThread.slice(0, 8)}`}
274
- </p>
275
- <p className="text-xs text-[#666]">
276
- {selectedThreadData && new Date(selectedThreadData.updated_at || selectedThreadData.created_at).toLocaleString()}
277
- </p>
278
- </div>
279
- <button
280
- onClick={(e) => deleteThread(selectedThread, e)}
281
- className="text-[#666] hover:text-red-400 text-sm px-2 py-1"
282
- >
283
- Delete
284
- </button>
285
- </div>
286
-
287
- {/* Live chat in this thread */}
288
254
  {loadingMessages ? (
289
255
  <div className="flex-1 flex items-center justify-center text-[#666]">Loading messages...</div>
290
256
  ) : (
@@ -297,7 +263,8 @@ function ThreadsTab({ agent }: { agent: Agent }) {
297
263
  placeholder="Continue this conversation..."
298
264
  context={agent.systemPrompt}
299
265
  variant="terminal"
300
- showHeader={false}
266
+ showHeader={true}
267
+ onHeaderBack={() => { setSelectedThread(null); setInitialMessages([]); }}
301
268
  />
302
269
  )}
303
270
  </div>
@@ -232,3 +232,11 @@ export function TaskOnceIcon({ className = "w-4 h-4" }: IconProps) {
232
232
  </svg>
233
233
  );
234
234
  }
235
+
236
+ export function BellIcon({ className = "w-5 h-5" }: IconProps) {
237
+ return (
238
+ <svg className={className} fill="none" stroke="currentColor" viewBox="0 0 24 24">
239
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
240
+ </svg>
241
+ );
242
+ }
@@ -12,15 +12,6 @@ interface Subscription {
12
12
  updated_at: string;
13
13
  }
14
14
 
15
- interface TriggerInstance {
16
- id: string;
17
- trigger_slug: string;
18
- connected_account_id: string | null;
19
- status: "active" | "disabled";
20
- config: Record<string, unknown>;
21
- created_at: string;
22
- }
23
-
24
15
  interface Agent {
25
16
  id: string;
26
17
  name: string;
@@ -32,7 +23,6 @@ export function OverviewTab() {
32
23
  const { currentProjectId } = useProjects();
33
24
 
34
25
  const [subscriptions, setSubscriptions] = useState<Subscription[]>([]);
35
- const [triggers, setTriggers] = useState<TriggerInstance[]>([]);
36
26
  const [agents, setAgents] = useState<Agent[]>([]);
37
27
  const [loading, setLoading] = useState(true);
38
28
 
@@ -42,9 +32,8 @@ export function OverviewTab() {
42
32
  const projectParam = currentProjectId && currentProjectId !== "unassigned" ? `?project_id=${currentProjectId}` : "";
43
33
 
44
34
  try {
45
- const [subsRes, triggersRes, agentsRes] = await Promise.all([
35
+ const [subsRes, agentsRes] = await Promise.all([
46
36
  authFetch(`/api/subscriptions${projectParam}`).catch(() => null),
47
- authFetch(`/api/triggers${projectParam}`).catch(() => null),
48
37
  authFetch(`/api/agents`).catch(() => null),
49
38
  ]);
50
39
 
@@ -52,10 +41,6 @@ export function OverviewTab() {
52
41
  const data = await subsRes.json();
53
42
  setSubscriptions(data.subscriptions || []);
54
43
  }
55
- if (triggersRes?.ok) {
56
- const data = await triggersRes.json();
57
- setTriggers(data.triggers || []);
58
- }
59
44
  if (agentsRes?.ok) {
60
45
  const data = await agentsRes.json();
61
46
  setAgents(data.agents || []);
@@ -73,40 +58,40 @@ export function OverviewTab() {
73
58
  return <div className="text-center py-12 text-[#666]">Loading...</div>;
74
59
  }
75
60
 
76
- const activeTriggers = triggers.filter(t => t.status === "active");
77
- const enabledSubscriptions = subscriptions.filter(s => s.enabled);
61
+ const enabledSubs = subscriptions.filter(s => s.enabled);
62
+ const disabledSubs = subscriptions.filter(s => !s.enabled);
78
63
  const agentMap = new Map(agents.map(a => [a.id, a]));
79
64
 
80
65
  return (
81
66
  <div className="space-y-6">
82
67
  {/* Stats */}
83
- <div className="grid grid-cols-2 md:grid-cols-3 gap-4">
84
- <StatCard label="Subscriptions" value={enabledSubscriptions.length} />
85
- <StatCard label="Active Triggers" value={activeTriggers.length} />
86
- <StatCard label="Total Triggers" value={triggers.length} />
68
+ <div className="grid grid-cols-3 gap-4">
69
+ <StatCard label="Active" value={enabledSubs.length} />
70
+ <StatCard label="Disabled" value={disabledSubs.length} />
71
+ <StatCard label="Total" value={subscriptions.length} />
87
72
  </div>
88
73
 
89
- {/* Active Subscriptions */}
74
+ {/* Subscriptions */}
90
75
  <section>
91
- <h3 className="text-sm font-medium text-[#888] mb-3">Active Subscriptions ({enabledSubscriptions.length})</h3>
92
- {enabledSubscriptions.length === 0 ? (
76
+ <h3 className="text-sm font-medium text-[#888] mb-3">Subscriptions ({subscriptions.length})</h3>
77
+ {subscriptions.length === 0 ? (
93
78
  <div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-6 text-center text-[#666] text-sm">
94
- No subscriptions. Go to the Triggers tab to route trigger events to agents.
79
+ No subscriptions yet. Go to the Triggers tab to create one.
95
80
  </div>
96
81
  ) : (
97
82
  <div className="space-y-2">
98
- {enabledSubscriptions.map(sub => {
83
+ {subscriptions.map(sub => {
99
84
  const agent = agentMap.get(sub.agent_id);
100
85
  return (
101
86
  <div key={sub.id} className="bg-[#111] border border-[#1a1a1a] rounded-lg p-3 flex items-center gap-3">
102
- <div className="w-2 h-2 rounded-full bg-green-400 flex-shrink-0" />
87
+ <div className={`w-2 h-2 rounded-full flex-shrink-0 ${sub.enabled ? "bg-green-400" : "bg-[#555]"}`} />
103
88
  <div className="flex-1 min-w-0">
104
89
  <div className="text-sm font-medium truncate">
105
- {sub.trigger_slug.replace(/_/g, " ")}
90
+ {sub.trigger_slug.replace(/_/g, " ").replace(/-/g, " ")}
106
91
  </div>
107
92
  <div className="text-xs text-[#666]">
108
93
  {sub.trigger_instance_id
109
- ? `Instance: ${sub.trigger_instance_id.slice(0, 12)}...`
94
+ ? `ID: ${sub.trigger_instance_id.slice(0, 12)}...`
110
95
  : "All instances"
111
96
  }
112
97
  </div>
@@ -115,50 +100,19 @@ export function OverviewTab() {
115
100
  <span className="text-[#555]">&rarr;</span>{" "}
116
101
  <span className="text-[#f97316]">{agent?.name || "Unknown Agent"}</span>
117
102
  </div>
118
- {agent && (
119
- <span className={`text-xs px-2 py-0.5 rounded flex-shrink-0 ${
120
- agent.status === "running"
121
- ? "bg-green-500/10 text-green-400"
122
- : "bg-yellow-500/10 text-yellow-400"
123
- }`}>
124
- {agent.status}
125
- </span>
126
- )}
103
+ <span className={`text-xs px-2 py-0.5 rounded flex-shrink-0 ${
104
+ sub.enabled
105
+ ? "bg-green-500/10 text-green-400"
106
+ : "bg-[#1a1a1a] text-[#555]"
107
+ }`}>
108
+ {sub.enabled ? "active" : "disabled"}
109
+ </span>
127
110
  </div>
128
111
  );
129
112
  })}
130
113
  </div>
131
114
  )}
132
115
  </section>
133
-
134
- {/* Active Triggers */}
135
- <section>
136
- <h3 className="text-sm font-medium text-[#888] mb-3">Active Triggers ({activeTriggers.length})</h3>
137
- {activeTriggers.length === 0 ? (
138
- <div className="bg-[#111] border border-[#1a1a1a] rounded-lg p-6 text-center text-[#666] text-sm">
139
- No active triggers on Composio.
140
- </div>
141
- ) : (
142
- <div className="space-y-2">
143
- {activeTriggers.map(trigger => (
144
- <div key={trigger.id} className="bg-[#111] border border-[#1a1a1a] rounded-lg p-3 flex items-center gap-3">
145
- <div className="w-2 h-2 rounded-full bg-green-400 flex-shrink-0" />
146
- <div className="flex-1 min-w-0">
147
- <div className="text-sm font-medium truncate">
148
- {trigger.trigger_slug.replace(/_/g, " ")}
149
- </div>
150
- <div className="text-xs text-[#666]">
151
- ID: {trigger.id.slice(0, 8)}...
152
- </div>
153
- </div>
154
- <span className="text-xs text-green-400 bg-green-500/10 px-2 py-0.5 rounded">
155
- active
156
- </span>
157
- </div>
158
- ))}
159
- </div>
160
- )}
161
- </section>
162
116
  </div>
163
117
  );
164
118
  }