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.
- package/dist/ActivityPage.h769ek3a.js +3 -0
- package/dist/ApiDocsPage.kf6bbwkk.js +4 -0
- package/dist/{App.nps62kvt.js → App.039re6cf.js} +3 -3
- package/dist/App.2jmkqm8c.js +4 -0
- package/dist/{App.np463xvy.js → App.2yy66bnp.js} +3 -3
- package/dist/App.3515wsb4.js +4 -0
- package/dist/App.7v1w3ys9.js +4 -0
- package/dist/{App.nft7h9jt.js → App.c90t3dxg.js} +3 -3
- package/dist/App.edwahsvz.js +4 -0
- package/dist/App.jfx3der4.js +4 -0
- package/dist/App.n4jb3c22.js +13 -0
- package/dist/{App.mq6jqare.js → App.p02f4ret.js} +1 -1
- package/dist/App.q3bpx15d.js +20 -0
- package/dist/App.r0a2nmqs.js +267 -0
- package/dist/App.s2yrcz15.js +4 -0
- package/dist/App.s5j82a5j.js +4 -0
- package/dist/App.tg1b94tx.js +4 -0
- package/dist/ConnectionsPage.a67fjgbf.js +3 -0
- package/dist/McpPage.d4p3xvtk.js +3 -0
- package/dist/SettingsPage.46sqpe39.js +3 -0
- package/dist/SkillsPage.j9hkqm99.js +3 -0
- package/dist/TasksPage.6pvkb7s7.js +3 -0
- package/dist/TelemetryPage.5zq9msb5.js +3 -0
- package/dist/TestsPage.24432yqt.js +3 -0
- package/dist/apteva-kit.css +1 -1
- package/dist/index.html +1 -1
- package/dist/styles.css +1 -1
- package/package.json +9 -4
- package/src/channels/index.ts +40 -0
- package/src/channels/telegram.ts +306 -0
- package/src/db.ts +180 -0
- package/src/integrations/agentdojo.ts +1 -1
- package/src/mcp-handler.ts +31 -24
- package/src/mcp-platform.ts +353 -2
- package/src/providers.ts +22 -9
- package/src/routes/api/agents.ts +15 -2
- package/src/routes/api/channels.ts +182 -0
- package/src/routes/api/integrations.ts +13 -5
- package/src/routes/api/mcp.ts +27 -9
- package/src/routes/api/system.ts +12 -1
- package/src/routes/api/telemetry.ts +30 -0
- package/src/routes/api/triggers.ts +22 -2
- package/src/routes/api.ts +3 -1
- package/src/routes/auth.ts +11 -2
- package/src/server.ts +39 -4
- package/src/triggers/agentdojo.ts +23 -18
- package/src/tui/AgentList.tsx +145 -0
- package/src/tui/App.tsx +102 -0
- package/src/tui/Login.tsx +104 -0
- package/src/tui/api.ts +72 -0
- package/src/tui/index.tsx +7 -0
- package/src/web/App.tsx +2 -2
- package/src/web/components/agents/AgentPanel.tsx +4 -37
- package/src/web/components/common/Icons.tsx +8 -0
- package/src/web/components/connections/OverviewTab.tsx +22 -68
- package/src/web/components/connections/TriggersTab.tsx +549 -70
- package/src/web/components/dashboard/Dashboard.tsx +5 -4
- package/src/web/components/layout/Header.tsx +196 -4
- package/src/web/components/settings/SettingsPage.tsx +269 -1
- package/src/web/context/AuthContext.tsx +18 -11
- package/src/web/context/TelemetryContext.tsx +14 -1
- package/src/web/context/index.ts +1 -1
- package/src/web/hooks/useAgents.ts +7 -3
- package/src/web/hooks/useOnboarding.ts +9 -30
- package/dist/ActivityPage.yv28a2vj.js +0 -3
- package/dist/ApiDocsPage.4ccwjjbk.js +0 -4
- package/dist/App.155wke5v.js +0 -4
- package/dist/App.2e19nvn4.js +0 -13
- package/dist/App.2ye1b5n0.js +0 -4
- package/dist/App.4da4ycbe.js +0 -4
- package/dist/App.b6wtzd1j.js +0 -4
- package/dist/App.fjrh28tf.js +0 -4
- package/dist/App.htc36cy8.js +0 -4
- package/dist/App.me6reaa6.js +0 -4
- package/dist/App.n5q6p960.js +0 -4
- package/dist/App.q8ws33cc.js +0 -181
- package/dist/App.tb0y0jmt.js +0 -40
- package/dist/ConnectionsPage.52evzrp7.js +0 -3
- package/dist/McpPage.bjqrp0n2.js +0 -3
- package/dist/SettingsPage.es76hnj2.js +0 -3
- package/dist/SkillsPage.06h8yf0h.js +0 -3
- package/dist/TasksPage.99df66mk.js +0 -3
- package/dist/TelemetryPage.bmdnxhq7.js +0 -3
- package/dist/TestsPage.denxrg8c.js +0 -3
package/src/db.ts
CHANGED
|
@@ -217,6 +217,33 @@ export interface SubscriptionRow {
|
|
|
217
217
|
updated_at: string;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
// Channel: external messaging platform bound to an agent
|
|
221
|
+
export interface Channel {
|
|
222
|
+
id: string;
|
|
223
|
+
type: "telegram"; // future: "slack", "discord"
|
|
224
|
+
name: string;
|
|
225
|
+
agent_id: string;
|
|
226
|
+
config: string; // encrypted JSON
|
|
227
|
+
status: "stopped" | "running" | "error";
|
|
228
|
+
error: string | null;
|
|
229
|
+
project_id: string | null;
|
|
230
|
+
created_at: string;
|
|
231
|
+
updated_at: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface ChannelRow {
|
|
235
|
+
id: string;
|
|
236
|
+
type: string;
|
|
237
|
+
name: string;
|
|
238
|
+
agent_id: string;
|
|
239
|
+
config: string;
|
|
240
|
+
status: string;
|
|
241
|
+
error: string | null;
|
|
242
|
+
project_id: string | null;
|
|
243
|
+
created_at: string;
|
|
244
|
+
updated_at: string;
|
|
245
|
+
}
|
|
246
|
+
|
|
220
247
|
export interface McpServerRow {
|
|
221
248
|
id: string;
|
|
222
249
|
name: string;
|
|
@@ -737,6 +764,33 @@ function runMigrations() {
|
|
|
737
764
|
CREATE INDEX IF NOT EXISTS idx_subscriptions_trigger_instance ON subscriptions(trigger_instance_id);
|
|
738
765
|
`,
|
|
739
766
|
},
|
|
767
|
+
{
|
|
768
|
+
name: "032_create_channels",
|
|
769
|
+
sql: `
|
|
770
|
+
CREATE TABLE IF NOT EXISTS channels (
|
|
771
|
+
id TEXT PRIMARY KEY,
|
|
772
|
+
type TEXT NOT NULL,
|
|
773
|
+
name TEXT NOT NULL,
|
|
774
|
+
agent_id TEXT NOT NULL,
|
|
775
|
+
config TEXT NOT NULL,
|
|
776
|
+
status TEXT DEFAULT 'stopped',
|
|
777
|
+
error TEXT,
|
|
778
|
+
project_id TEXT,
|
|
779
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
780
|
+
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
781
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id) ON DELETE CASCADE
|
|
782
|
+
);
|
|
783
|
+
CREATE INDEX IF NOT EXISTS idx_channels_agent ON channels(agent_id);
|
|
784
|
+
CREATE INDEX IF NOT EXISTS idx_channels_status ON channels(status);
|
|
785
|
+
`,
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
name: "033_add_telemetry_seen",
|
|
789
|
+
sql: `
|
|
790
|
+
ALTER TABLE telemetry_events ADD COLUMN seen INTEGER DEFAULT 0;
|
|
791
|
+
CREATE INDEX IF NOT EXISTS idx_telemetry_seen ON telemetry_events(seen);
|
|
792
|
+
`,
|
|
793
|
+
},
|
|
740
794
|
{
|
|
741
795
|
name: "029_fix_provider_keys_unique_constraint",
|
|
742
796
|
sql: `
|
|
@@ -1768,6 +1822,7 @@ export interface TelemetryEvent {
|
|
|
1768
1822
|
duration_ms: number | null;
|
|
1769
1823
|
error: string | null;
|
|
1770
1824
|
received_at: string;
|
|
1825
|
+
seen?: boolean;
|
|
1771
1826
|
}
|
|
1772
1827
|
|
|
1773
1828
|
interface TelemetryEventRow {
|
|
@@ -1785,6 +1840,7 @@ interface TelemetryEventRow {
|
|
|
1785
1840
|
duration_ms: number | null;
|
|
1786
1841
|
error: string | null;
|
|
1787
1842
|
received_at: string;
|
|
1843
|
+
seen?: number;
|
|
1788
1844
|
}
|
|
1789
1845
|
|
|
1790
1846
|
// Telemetry operations
|
|
@@ -2066,6 +2122,45 @@ export const TelemetryDB = {
|
|
|
2066
2122
|
const row = db.query("SELECT COUNT(*) as count FROM telemetry_events").get() as { count: number };
|
|
2067
2123
|
return row.count;
|
|
2068
2124
|
},
|
|
2125
|
+
|
|
2126
|
+
// --- Notification helpers (piggyback on telemetry with `seen` flag) ---
|
|
2127
|
+
|
|
2128
|
+
// Notification-worthy filter: errors + agent crashes
|
|
2129
|
+
getNotifications(limit = 50): TelemetryEvent[] {
|
|
2130
|
+
const rows = db.query(`
|
|
2131
|
+
SELECT * FROM telemetry_events
|
|
2132
|
+
WHERE (level = 'error' OR (category = 'system' AND type = 'agent_stopped') OR category = 'ERROR')
|
|
2133
|
+
ORDER BY timestamp DESC
|
|
2134
|
+
LIMIT ?
|
|
2135
|
+
`).all(limit) as TelemetryEventRow[];
|
|
2136
|
+
return rows.map(rowToTelemetryEvent);
|
|
2137
|
+
},
|
|
2138
|
+
|
|
2139
|
+
getUnseenCount(): number {
|
|
2140
|
+
const row = db.query(`
|
|
2141
|
+
SELECT COUNT(*) as count FROM telemetry_events
|
|
2142
|
+
WHERE seen = 0
|
|
2143
|
+
AND (level = 'error' OR (category = 'system' AND type = 'agent_stopped') OR category = 'ERROR')
|
|
2144
|
+
`).get() as { count: number };
|
|
2145
|
+
return row.count;
|
|
2146
|
+
},
|
|
2147
|
+
|
|
2148
|
+
markSeen(ids: string[]): number {
|
|
2149
|
+
if (ids.length === 0) return 0;
|
|
2150
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
2151
|
+
const result = db.run(
|
|
2152
|
+
`UPDATE telemetry_events SET seen = 1 WHERE id IN (${placeholders})`,
|
|
2153
|
+
ids
|
|
2154
|
+
);
|
|
2155
|
+
return result.changes;
|
|
2156
|
+
},
|
|
2157
|
+
|
|
2158
|
+
markAllSeen(): number {
|
|
2159
|
+
const result = db.run(
|
|
2160
|
+
`UPDATE telemetry_events SET seen = 1 WHERE seen = 0 AND (level = 'error' OR (category = 'system' AND type = 'agent_stopped') OR category = 'ERROR')`
|
|
2161
|
+
);
|
|
2162
|
+
return result.changes;
|
|
2163
|
+
},
|
|
2069
2164
|
};
|
|
2070
2165
|
|
|
2071
2166
|
function rowToTelemetryEvent(row: TelemetryEventRow): TelemetryEvent {
|
|
@@ -2084,6 +2179,7 @@ function rowToTelemetryEvent(row: TelemetryEventRow): TelemetryEvent {
|
|
|
2084
2179
|
duration_ms: row.duration_ms,
|
|
2085
2180
|
error: row.error,
|
|
2086
2181
|
received_at: row.received_at,
|
|
2182
|
+
seen: row.seen === 1,
|
|
2087
2183
|
};
|
|
2088
2184
|
}
|
|
2089
2185
|
|
|
@@ -2726,6 +2822,90 @@ export const SubscriptionDB = {
|
|
|
2726
2822
|
},
|
|
2727
2823
|
};
|
|
2728
2824
|
|
|
2825
|
+
// --- Channel DB ---
|
|
2826
|
+
|
|
2827
|
+
function rowToChannel(row: ChannelRow): Channel {
|
|
2828
|
+
return {
|
|
2829
|
+
id: row.id,
|
|
2830
|
+
type: row.type as Channel["type"],
|
|
2831
|
+
name: row.name,
|
|
2832
|
+
agent_id: row.agent_id,
|
|
2833
|
+
config: row.config,
|
|
2834
|
+
status: row.status as Channel["status"],
|
|
2835
|
+
error: row.error,
|
|
2836
|
+
project_id: row.project_id,
|
|
2837
|
+
created_at: row.created_at,
|
|
2838
|
+
updated_at: row.updated_at,
|
|
2839
|
+
};
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
export const ChannelDB = {
|
|
2843
|
+
create(channel: { type: string; name: string; agent_id: string; config: string; project_id?: string | null }): Channel {
|
|
2844
|
+
const id = generateId();
|
|
2845
|
+
const now = new Date().toISOString();
|
|
2846
|
+
db.run(
|
|
2847
|
+
`INSERT INTO channels (id, type, name, agent_id, config, status, project_id, created_at, updated_at)
|
|
2848
|
+
VALUES (?, ?, ?, ?, ?, 'stopped', ?, ?, ?)`,
|
|
2849
|
+
[id, channel.type, channel.name, channel.agent_id, channel.config, channel.project_id || null, now, now]
|
|
2850
|
+
);
|
|
2851
|
+
return this.findById(id)!;
|
|
2852
|
+
},
|
|
2853
|
+
|
|
2854
|
+
findById(id: string): Channel | null {
|
|
2855
|
+
const row = db.query("SELECT * FROM channels WHERE id = ?").get(id) as ChannelRow | null;
|
|
2856
|
+
return row ? rowToChannel(row) : null;
|
|
2857
|
+
},
|
|
2858
|
+
|
|
2859
|
+
findAll(): Channel[] {
|
|
2860
|
+
const rows = db.query("SELECT * FROM channels ORDER BY created_at DESC").all() as ChannelRow[];
|
|
2861
|
+
return rows.map(rowToChannel);
|
|
2862
|
+
},
|
|
2863
|
+
|
|
2864
|
+
findByAgentId(agentId: string): Channel[] {
|
|
2865
|
+
const rows = db.query("SELECT * FROM channels WHERE agent_id = ?").all(agentId) as ChannelRow[];
|
|
2866
|
+
return rows.map(rowToChannel);
|
|
2867
|
+
},
|
|
2868
|
+
|
|
2869
|
+
findRunning(): Channel[] {
|
|
2870
|
+
const rows = db.query("SELECT * FROM channels WHERE status = 'running'").all() as ChannelRow[];
|
|
2871
|
+
return rows.map(rowToChannel);
|
|
2872
|
+
},
|
|
2873
|
+
|
|
2874
|
+
update(id: string, updates: { name?: string; agent_id?: string; config?: string; project_id?: string | null }): Channel | null {
|
|
2875
|
+
const channel = this.findById(id);
|
|
2876
|
+
if (!channel) return null;
|
|
2877
|
+
|
|
2878
|
+
const fields: string[] = [];
|
|
2879
|
+
const values: (string | null)[] = [];
|
|
2880
|
+
|
|
2881
|
+
if (updates.name !== undefined) { fields.push("name = ?"); values.push(updates.name); }
|
|
2882
|
+
if (updates.agent_id !== undefined) { fields.push("agent_id = ?"); values.push(updates.agent_id); }
|
|
2883
|
+
if (updates.config !== undefined) { fields.push("config = ?"); values.push(updates.config); }
|
|
2884
|
+
if (updates.project_id !== undefined) { fields.push("project_id = ?"); values.push(updates.project_id || null); }
|
|
2885
|
+
|
|
2886
|
+
if (fields.length === 0) return channel;
|
|
2887
|
+
|
|
2888
|
+
fields.push("updated_at = ?");
|
|
2889
|
+
values.push(new Date().toISOString());
|
|
2890
|
+
values.push(id);
|
|
2891
|
+
|
|
2892
|
+
db.run(`UPDATE channels SET ${fields.join(", ")} WHERE id = ?`, values);
|
|
2893
|
+
return this.findById(id);
|
|
2894
|
+
},
|
|
2895
|
+
|
|
2896
|
+
setStatus(id: string, status: Channel["status"], error?: string | null): void {
|
|
2897
|
+
db.run(
|
|
2898
|
+
"UPDATE channels SET status = ?, error = ?, updated_at = ? WHERE id = ?",
|
|
2899
|
+
[status, error || null, new Date().toISOString(), id]
|
|
2900
|
+
);
|
|
2901
|
+
},
|
|
2902
|
+
|
|
2903
|
+
delete(id: string): boolean {
|
|
2904
|
+
const result = db.run("DELETE FROM channels WHERE id = ?", [id]);
|
|
2905
|
+
return result.changes > 0;
|
|
2906
|
+
},
|
|
2907
|
+
};
|
|
2908
|
+
|
|
2729
2909
|
// Generate unique ID
|
|
2730
2910
|
export function generateId(): string {
|
|
2731
2911
|
return Math.random().toString(36).substring(2, 15);
|
|
@@ -127,7 +127,7 @@ export const AgentDojoProvider: IntegrationProvider = {
|
|
|
127
127
|
|
|
128
128
|
return credentials.map((cred: any) => ({
|
|
129
129
|
id: String(cred.id),
|
|
130
|
-
appId:
|
|
130
|
+
appId: cred.provider_name || cred.toolkit_name || String(cred.provider_id || cred.toolkit_id),
|
|
131
131
|
appName: cred.provider_name || cred.name || cred.toolkit_name || String(cred.provider_id),
|
|
132
132
|
status: (cred.status === "active" || cred.is_valid !== false) ? "active" as const : "failed" as const,
|
|
133
133
|
createdAt: cred.created_at || new Date().toISOString(),
|
package/src/mcp-handler.ts
CHANGED
|
@@ -73,34 +73,28 @@ function evaluateExpression(
|
|
|
73
73
|
args: Record<string, any>,
|
|
74
74
|
helpers: ReturnType<typeof templateHelpers>,
|
|
75
75
|
): any {
|
|
76
|
-
// Handle args.* references
|
|
76
|
+
// Handle args.* references (e.g. args.name, args.query)
|
|
77
77
|
if (expr.startsWith("args.")) {
|
|
78
78
|
const key = expr.slice(5);
|
|
79
79
|
return args[key] ?? null;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
// Handle helper
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
helpers.random_int,
|
|
99
|
-
helpers.random_float,
|
|
100
|
-
);
|
|
101
|
-
} catch {
|
|
102
|
-
return expr;
|
|
103
|
-
}
|
|
82
|
+
// Handle known helper values
|
|
83
|
+
if (expr === "now") return helpers.now;
|
|
84
|
+
if (expr === "timestamp") return helpers.timestamp;
|
|
85
|
+
|
|
86
|
+
// Handle known helper function calls
|
|
87
|
+
const uuidMatch = expr.match(/^uuid\(\)$/);
|
|
88
|
+
if (uuidMatch) return helpers.uuid();
|
|
89
|
+
|
|
90
|
+
const randIntMatch = expr.match(/^random_int\(\s*(\d+)\s*,\s*(\d+)\s*\)$/);
|
|
91
|
+
if (randIntMatch) return helpers.random_int(Number(randIntMatch[1]), Number(randIntMatch[2]));
|
|
92
|
+
|
|
93
|
+
const randFloatMatch = expr.match(/^random_float\(\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/);
|
|
94
|
+
if (randFloatMatch) return helpers.random_float(Number(randFloatMatch[1]), Number(randFloatMatch[2]));
|
|
95
|
+
|
|
96
|
+
// Return expression as-is if not recognized — never execute arbitrary code
|
|
97
|
+
return expr;
|
|
104
98
|
}
|
|
105
99
|
|
|
106
100
|
// Execute a mock handler — returns the rendered mock_response
|
|
@@ -197,7 +191,11 @@ async function executeHttp(
|
|
|
197
191
|
}
|
|
198
192
|
}
|
|
199
193
|
|
|
200
|
-
// Execute a JavaScript handler — runs code
|
|
194
|
+
// Execute a JavaScript handler — runs user-defined code in a restricted scope.
|
|
195
|
+
// SECURITY NOTE: This intentionally allows authenticated admins to define custom tool logic.
|
|
196
|
+
// The code runs in a restricted Function scope with only args, credentials, and helpers exposed.
|
|
197
|
+
// process, require, import, Bun, fetch etc. are NOT passed in — but note that new Function()
|
|
198
|
+
// still has access to globalThis. For full sandboxing, consider using a Worker or subprocess.
|
|
201
199
|
function executeJavascript(
|
|
202
200
|
tool: McpServerTool,
|
|
203
201
|
args: Record<string, any>,
|
|
@@ -210,6 +208,15 @@ function executeJavascript(
|
|
|
210
208
|
};
|
|
211
209
|
}
|
|
212
210
|
|
|
211
|
+
// Basic static checks — block obvious dangerous patterns
|
|
212
|
+
const dangerous = /\b(process|require|import|Bun|Deno|eval|Function|child_process|exec|spawn)\b/;
|
|
213
|
+
if (dangerous.test(tool.code)) {
|
|
214
|
+
return {
|
|
215
|
+
content: [{ type: "text", text: "Error: Tool code contains disallowed keywords (process, require, import, eval, exec, spawn)" }],
|
|
216
|
+
isError: true,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
213
220
|
try {
|
|
214
221
|
const helpers = templateHelpers();
|
|
215
222
|
const fn = new Function(
|