amalgm 0.1.51 → 0.1.53
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/lib/tunnel-events.js +48 -23
- package/package.json +2 -2
- package/runtime/lib/harnesses.js +12 -4
- package/runtime/scripts/amalgm-mcp/agents/store.js +5 -5
- package/runtime/scripts/amalgm-mcp/{artifacts → apps}/advertise.js +39 -24
- package/runtime/scripts/amalgm-mcp/apps/rest.js +144 -0
- package/runtime/scripts/amalgm-mcp/apps/store.js +171 -0
- package/runtime/scripts/amalgm-mcp/apps/supervisor.js +439 -0
- package/runtime/scripts/amalgm-mcp/apps/tools.js +176 -0
- package/runtime/scripts/amalgm-mcp/automations/cell-references.js +237 -0
- package/runtime/scripts/amalgm-mcp/automations/context.js +41 -0
- package/runtime/scripts/amalgm-mcp/automations/rest.js +148 -0
- package/runtime/scripts/amalgm-mcp/automations/runner.js +613 -0
- package/runtime/scripts/amalgm-mcp/automations/scheduler.js +90 -0
- package/runtime/scripts/amalgm-mcp/automations/store.js +1125 -0
- package/runtime/scripts/amalgm-mcp/automations/tool-actions.js +177 -0
- package/runtime/scripts/amalgm-mcp/automations/tools.js +418 -0
- package/runtime/scripts/amalgm-mcp/automations/validator.js +225 -0
- package/runtime/scripts/amalgm-mcp/browser/agent-browser.js +547 -0
- package/runtime/scripts/amalgm-mcp/browser/electron-bridge.js +222 -0
- package/runtime/scripts/amalgm-mcp/browser/page.js +13 -631
- package/runtime/scripts/amalgm-mcp/browser/tools.js +9 -7
- package/runtime/scripts/amalgm-mcp/config.js +33 -48
- package/runtime/scripts/amalgm-mcp/deps.js +1 -31
- package/runtime/scripts/amalgm-mcp/events/ingress.js +50 -42
- package/runtime/scripts/amalgm-mcp/events/internal-workflows.js +169 -0
- package/runtime/scripts/amalgm-mcp/events/matcher.js +45 -14
- package/runtime/scripts/amalgm-mcp/events/store.js +106 -57
- package/runtime/scripts/amalgm-mcp/index.js +12 -14
- package/runtime/scripts/amalgm-mcp/lib/prefs.js +229 -65
- package/runtime/scripts/amalgm-mcp/lib/tool-result.js +13 -27
- package/runtime/scripts/amalgm-mcp/server/core-tools.js +2 -3
- package/runtime/scripts/amalgm-mcp/server/http.js +106 -56
- package/runtime/scripts/amalgm-mcp/slack/inbound.js +1 -1
- package/runtime/scripts/amalgm-mcp/state/db.js +119 -0
- package/runtime/scripts/amalgm-mcp/state/snapshot.js +16 -3
- package/runtime/scripts/amalgm-mcp/tasks/executor.js +1 -1
- package/runtime/scripts/amalgm-mcp/tests/automations-store-runner.test.js +348 -0
- package/runtime/scripts/amalgm-mcp/tests/events-matcher.test.js +23 -0
- package/runtime/scripts/amalgm-mcp/tests/workflows-store-runner.test.js +67 -0
- package/runtime/scripts/amalgm-mcp/toolbox/tools.js +16 -3
- package/runtime/scripts/amalgm-mcp/workflows/compiler.js +222 -0
- package/runtime/scripts/amalgm-mcp/workflows/runner.js +593 -0
- package/runtime/scripts/amalgm-mcp/workflows/store.js +237 -0
- package/runtime/scripts/chat-core/adapters/claude.js +2 -1
- package/runtime/scripts/chat-core/auth.js +82 -12
- package/runtime/scripts/chat-core/contract.js +5 -1
- package/runtime/scripts/chat-core/engine.js +103 -62
- package/runtime/scripts/chat-core/event-schema.js +8 -0
- package/runtime/scripts/chat-core/events.js +5 -0
- package/runtime/scripts/chat-core/normalizers/codex.js +13 -1
- package/runtime/scripts/chat-core/parts.js +21 -6
- package/runtime/scripts/chat-core/sse.js +3 -0
- package/runtime/scripts/chat-core/tests/auth.test.js +84 -6
- package/runtime/scripts/chat-core/tests/engine.test.js +312 -0
- package/runtime/scripts/chat-core/tests/native-config.test.js +23 -0
- package/runtime/scripts/chat-core/tool-shape.js +4 -4
- package/runtime/scripts/chat-core/tooling/active-memory.js +5 -4
- package/runtime/scripts/chat-core/tooling/native-binaries.js +34 -9
- package/runtime/scripts/chat-core/tooling/native-config.js +34 -3
- package/runtime/scripts/local-gateway.js +34 -27
- package/runtime/scripts/platform-context.txt +76 -94
- package/runtime/scripts/amalgm-mcp/artifacts/rest.js +0 -103
- package/runtime/scripts/amalgm-mcp/artifacts/store.js +0 -157
- package/runtime/scripts/amalgm-mcp/artifacts/supervisor.js +0 -439
- package/runtime/scripts/amalgm-mcp/artifacts/tools.js +0 -176
- package/runtime/scripts/amalgm-mcp/events/executor.js +0 -258
- package/runtime/scripts/amalgm-mcp/events/rest.js +0 -214
- package/runtime/scripts/amalgm-mcp/events/tools.js +0 -323
- package/runtime/scripts/amalgm-mcp/tasks/rest.js +0 -110
- package/runtime/scripts/amalgm-mcp/tasks/tools.js +0 -416
|
@@ -32,32 +32,18 @@ function humanizeToolName(toolName) {
|
|
|
32
32
|
|
|
33
33
|
function buildActionDescriptor(toolName, args = {}) {
|
|
34
34
|
switch (toolName) {
|
|
35
|
-
case '
|
|
36
|
-
return `Create
|
|
37
|
-
case '
|
|
38
|
-
return args.enabled_only ? 'List enabled
|
|
39
|
-
case '
|
|
40
|
-
return `Get
|
|
41
|
-
case '
|
|
42
|
-
return `Update
|
|
43
|
-
case '
|
|
44
|
-
return `Delete
|
|
45
|
-
case '
|
|
46
|
-
return `Run
|
|
47
|
-
case 'scheduled_tasks_cancel':
|
|
48
|
-
return `Cancel scheduled task${quoteIfPresent(args.task_id)}`;
|
|
49
|
-
case 'scheduled_tasks_history':
|
|
50
|
-
return `Get scheduled task history${quoteIfPresent(args.task_id)}`;
|
|
51
|
-
case 'event_triggers_create':
|
|
52
|
-
return `Create event trigger${quoteIfPresent(args.name)}`;
|
|
53
|
-
case 'event_triggers_list':
|
|
54
|
-
return args.enabled_only ? 'List enabled event triggers' : 'List event triggers';
|
|
55
|
-
case 'event_triggers_get':
|
|
56
|
-
return `Get event trigger${quoteIfPresent(args.trigger_id)}`;
|
|
57
|
-
case 'event_triggers_update':
|
|
58
|
-
return `Update event trigger${quoteIfPresent(args.trigger_id || args.name)}`;
|
|
59
|
-
case 'event_triggers_delete':
|
|
60
|
-
return `Delete event trigger${quoteIfPresent(args.trigger_id)}`;
|
|
35
|
+
case 'automations_create':
|
|
36
|
+
return `Create automation${quoteIfPresent(args.name)}`;
|
|
37
|
+
case 'automations_list':
|
|
38
|
+
return args.enabled_only ? 'List enabled automations' : 'List automations';
|
|
39
|
+
case 'automations_get':
|
|
40
|
+
return `Get automation${quoteIfPresent(args.automation_id)}`;
|
|
41
|
+
case 'automations_update':
|
|
42
|
+
return `Update automation${quoteIfPresent(args.automation_id || args.name)}`;
|
|
43
|
+
case 'automations_delete':
|
|
44
|
+
return `Delete automation${quoteIfPresent(args.automation_id)}`;
|
|
45
|
+
case 'automations_run_now':
|
|
46
|
+
return `Run automation now${quoteIfPresent(args.automation_id)}`;
|
|
61
47
|
case 'notify_user':
|
|
62
48
|
return `Notify user${quoteIfPresent(args.subject || args.level || 'info')}`;
|
|
63
49
|
case 'agents_list':
|
|
@@ -126,7 +112,7 @@ function buildActionDescriptor(toolName, args = {}) {
|
|
|
126
112
|
case 'browser_cua_double_click':
|
|
127
113
|
return 'Double-click browser coordinates';
|
|
128
114
|
case 'browser_cua_move':
|
|
129
|
-
return 'Move browser
|
|
115
|
+
return 'Move browser mouse';
|
|
130
116
|
case 'browser_cua_scroll':
|
|
131
117
|
return 'Scroll browser';
|
|
132
118
|
case 'browser_cua_type':
|
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const CORE_TOOLS = [
|
|
12
|
-
...require('../
|
|
13
|
-
...require('../events/tools'),
|
|
12
|
+
...require('../automations/tools'),
|
|
14
13
|
...require('../notify'),
|
|
15
14
|
...require('../agents/tools'),
|
|
16
|
-
...require('../
|
|
15
|
+
...require('../apps/tools'),
|
|
17
16
|
...require('../browser/tools'),
|
|
18
17
|
];
|
|
19
18
|
|
|
@@ -4,15 +4,11 @@
|
|
|
4
4
|
* Route table:
|
|
5
5
|
* GET /healthz → stats snapshot
|
|
6
6
|
* * /mcp → MCP streamable-HTTP (delegated to SDK transport)
|
|
7
|
-
* POST /events → webhook ingress (signature match +
|
|
7
|
+
* POST /events → webhook ingress (signature match + workflow run)
|
|
8
8
|
* GET /events → recent events (in-memory ring buffer)
|
|
9
|
-
* GET /
|
|
10
|
-
* POST /
|
|
11
|
-
* POST /
|
|
12
|
-
* POST /tasks/delete → delete task
|
|
13
|
-
* POST /tasks/run-now → run task immediately
|
|
14
|
-
* GET /event-triggers/list → list triggers
|
|
15
|
-
* POST /event-triggers/{create,update,delete}
|
|
9
|
+
* GET /automations/list → list automations/triggers/workflows
|
|
10
|
+
* POST /automations/{get,create,update,delete,run-now,validate}
|
|
11
|
+
* POST /automations/triggers/{update,delete}
|
|
16
12
|
* GET /workspace/projects → list projects
|
|
17
13
|
* POST /workspace/import → copy a local folder into workspaces
|
|
18
14
|
* POST /github/clone → clone repository onto the computer
|
|
@@ -29,13 +25,19 @@
|
|
|
29
25
|
* POST /mcp-connections → save/update MCP connection
|
|
30
26
|
* DELETE /mcp-connections → remove MCP connection
|
|
31
27
|
* GET /toolbox → list local ToolboxDB tools/actions
|
|
28
|
+
* GET /toolbox/tools?id=... → get one toolbox tool
|
|
32
29
|
* POST /toolbox/tools → save/update a toolbox tool
|
|
30
|
+
* PATCH /toolbox/tools → partially update a toolbox tool
|
|
33
31
|
* DELETE /toolbox/tools → remove a toolbox tool
|
|
32
|
+
* GET /toolbox/actions?id=... → get one toolbox action
|
|
34
33
|
* POST /toolbox/actions → save/update a toolbox action
|
|
34
|
+
* PATCH /toolbox/actions → partially update a toolbox action
|
|
35
35
|
* DELETE /toolbox/actions → remove a toolbox action
|
|
36
36
|
* GET /state/snapshot → current Local Live Store snapshot
|
|
37
37
|
* GET /state/events → replay Local Live Store events
|
|
38
38
|
* GET /state/stream → SSE Local Live Store stream
|
|
39
|
+
* GET /user-preferences → current local user preferences
|
|
40
|
+
* PUT /user-preferences → update local user preferences
|
|
39
41
|
* POST /local/init → init local computer state
|
|
40
42
|
* GET /local/credentials → discover local agent auth
|
|
41
43
|
* POST /local/credentials/resolve → resolve spawn env for agent auth
|
|
@@ -46,9 +48,10 @@
|
|
|
46
48
|
* DELETE /credentials → remove local Amalgm credential profile
|
|
47
49
|
* POST /user-api-keys → legacy save BYOK credential file
|
|
48
50
|
* DELETE /user-api-keys → legacy remove BYOK credential file
|
|
49
|
-
* GET /
|
|
50
|
-
* GET /
|
|
51
|
-
* POST /
|
|
51
|
+
* GET /apps/list → list apps
|
|
52
|
+
* GET /apps/routes → app DNS routes for tunnel adverts
|
|
53
|
+
* POST /apps/{register,redeploy,start,stop,connect-dns,disconnect-dns}
|
|
54
|
+
* Legacy /artifacts/* aliases remain for older clients during the rename.
|
|
52
55
|
* GET /agents/list → list agents
|
|
53
56
|
* POST /agents/{get,create,update,delete}
|
|
54
57
|
*/
|
|
@@ -58,17 +61,17 @@ const { PORT, STORAGE_DIR } = require('../config');
|
|
|
58
61
|
const { hasSupabase } = require('../lib/supabase');
|
|
59
62
|
const { authorizeRuntimeHttp } = require('../../runtime-auth');
|
|
60
63
|
|
|
61
|
-
const { loadTasks } = require('../tasks/store');
|
|
62
64
|
const { loadAgents } = require('../agents/store');
|
|
63
|
-
const {
|
|
65
|
+
const { loadApps } = require('../apps/store');
|
|
64
66
|
const { activeAgentConversations } = require('../agents/talk');
|
|
65
|
-
const {
|
|
67
|
+
const { listAutomations } = require('../automations/store');
|
|
68
|
+
const { startAutomationScheduler, stopAutomationScheduler } = require('../automations/scheduler');
|
|
66
69
|
const { createTransport } = require('./mcp');
|
|
67
70
|
const { handleEventsPost } = require('../events/ingress');
|
|
68
71
|
const eventsRing = require('../events/ring-buffer');
|
|
69
|
-
const
|
|
72
|
+
const automationsRest = require('../automations/rest');
|
|
70
73
|
const agentsRest = require('../agents/rest');
|
|
71
|
-
const
|
|
74
|
+
const appsRest = require('../apps/rest');
|
|
72
75
|
const emailInbound = require('../email/inbound');
|
|
73
76
|
const slackInbound = require('../slack/inbound');
|
|
74
77
|
const fsRest = require('../fs/rest');
|
|
@@ -76,7 +79,7 @@ const localRest = require('../local/rest');
|
|
|
76
79
|
const mcpConnectionsRest = require('../mcp-connections/rest');
|
|
77
80
|
const toolboxRest = require('../toolbox/rest');
|
|
78
81
|
const stateRest = require('../state/rest');
|
|
79
|
-
const
|
|
82
|
+
const prefsStore = require('../lib/prefs');
|
|
80
83
|
const userApiKeysRest = require('../user-api-keys/rest');
|
|
81
84
|
const credentialsRest = require('../credentials/rest');
|
|
82
85
|
const workspaceRest = require('../workspace/rest');
|
|
@@ -112,14 +115,13 @@ function createServer() {
|
|
|
112
115
|
|
|
113
116
|
// ── Health ──────────────────────────────────────────────────────────────
|
|
114
117
|
if (req.url === '/healthz') {
|
|
115
|
-
const tasks = loadTasks();
|
|
116
118
|
const agents = loadAgents();
|
|
119
|
+
const automations = listAutomations();
|
|
117
120
|
return sendJson(200, {
|
|
118
121
|
status: 'ok',
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
artifacts: loadArtifacts().artifacts.length,
|
|
122
|
+
automations: automations.length,
|
|
123
|
+
enabledAutomations: automations.filter((automation) => automation.enabled !== false).length,
|
|
124
|
+
apps: loadApps().apps.length,
|
|
123
125
|
customAgents: agents.agents.length,
|
|
124
126
|
activeAgentConversations: activeAgentConversations.size,
|
|
125
127
|
});
|
|
@@ -136,6 +138,15 @@ function createServer() {
|
|
|
136
138
|
return stateRest.handleStream(req, res, getQuery());
|
|
137
139
|
}
|
|
138
140
|
|
|
141
|
+
// ── /user-preferences REST ───────────────────────────────────────────
|
|
142
|
+
if (req.url === '/user-preferences' && req.method === 'GET') {
|
|
143
|
+
return sendJson(200, prefsStore.readUserPreferences());
|
|
144
|
+
}
|
|
145
|
+
if (req.url === '/user-preferences' && req.method === 'PUT') {
|
|
146
|
+
const preferences = prefsStore.updateUserPreferences(await readJsonBody());
|
|
147
|
+
return sendJson(200, { success: true, preferences });
|
|
148
|
+
}
|
|
149
|
+
|
|
139
150
|
// ── /agents (REST, not MCP) ─────────────────────────────────────────────
|
|
140
151
|
if (req.url === '/agents/list' && req.method === 'GET') {
|
|
141
152
|
return agentsRest.handleList(sendJson);
|
|
@@ -161,35 +172,33 @@ function createServer() {
|
|
|
161
172
|
return sendJson(200, { events: eventsRing.recent(50) });
|
|
162
173
|
}
|
|
163
174
|
|
|
164
|
-
// ── /
|
|
165
|
-
if (req.url === '/
|
|
166
|
-
return
|
|
175
|
+
// ── /automations REST ─────────────────────────────────────────────────
|
|
176
|
+
if (req.url === '/automations/list' && req.method === 'GET') {
|
|
177
|
+
return automationsRest.handleList(req, sendJson);
|
|
167
178
|
}
|
|
168
|
-
if (req.url === '/
|
|
169
|
-
return
|
|
179
|
+
if (req.url === '/automations/get' && req.method === 'POST') {
|
|
180
|
+
return automationsRest.handleGet(await readJsonBody(), sendJson);
|
|
170
181
|
}
|
|
171
|
-
if (req.url === '/
|
|
172
|
-
return
|
|
182
|
+
if (req.url === '/automations/create' && req.method === 'POST') {
|
|
183
|
+
return automationsRest.handleCreate(await readJsonBody(), sendJson);
|
|
173
184
|
}
|
|
174
|
-
if (req.url === '/
|
|
175
|
-
return
|
|
185
|
+
if (req.url === '/automations/update' && req.method === 'POST') {
|
|
186
|
+
return automationsRest.handleUpdate(await readJsonBody(), sendJson);
|
|
176
187
|
}
|
|
177
|
-
if (req.url === '/
|
|
178
|
-
return
|
|
188
|
+
if (req.url === '/automations/delete' && req.method === 'POST') {
|
|
189
|
+
return automationsRest.handleDelete(await readJsonBody(), sendJson);
|
|
179
190
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (req.url === '/event-triggers/list' && req.method === 'GET') {
|
|
183
|
-
return eventsRest.handleList(req, sendJson);
|
|
191
|
+
if (req.url === '/automations/run-now' && req.method === 'POST') {
|
|
192
|
+
return automationsRest.handleRunNow(await readJsonBody(), sendJson);
|
|
184
193
|
}
|
|
185
|
-
if (req.url === '/
|
|
186
|
-
return
|
|
194
|
+
if (req.url === '/automations/validate' && req.method === 'POST') {
|
|
195
|
+
return automationsRest.handleValidate(await readJsonBody(), sendJson);
|
|
187
196
|
}
|
|
188
|
-
if (req.url === '/
|
|
189
|
-
return
|
|
197
|
+
if (req.url === '/automations/triggers/update' && req.method === 'POST') {
|
|
198
|
+
return automationsRest.handleTriggerUpdate(await readJsonBody(), sendJson);
|
|
190
199
|
}
|
|
191
|
-
if (req.url === '/
|
|
192
|
-
return
|
|
200
|
+
if (req.url === '/automations/triggers/delete' && req.method === 'POST') {
|
|
201
|
+
return automationsRest.handleTriggerDelete(await readJsonBody(), sendJson);
|
|
193
202
|
}
|
|
194
203
|
|
|
195
204
|
// ── /workspace REST ─────────────────────────────────────────────────────
|
|
@@ -265,15 +274,27 @@ function createServer() {
|
|
|
265
274
|
if (req.url === '/toolbox' && req.method === 'GET') {
|
|
266
275
|
return toolboxRest.handleList(sendJson);
|
|
267
276
|
}
|
|
277
|
+
if ((req.url === '/toolbox/tools' || req.url.startsWith('/toolbox/tools?')) && req.method === 'GET') {
|
|
278
|
+
return toolboxRest.handleGetTool(getQuery(), sendJson);
|
|
279
|
+
}
|
|
268
280
|
if (req.url === '/toolbox/tools' && req.method === 'POST') {
|
|
269
281
|
return toolboxRest.handleUpsertTool(await readJsonBody(), sendJson);
|
|
270
282
|
}
|
|
283
|
+
if (req.url === '/toolbox/tools' && req.method === 'PATCH') {
|
|
284
|
+
return toolboxRest.handleUpdateTool(await readJsonBody(), sendJson);
|
|
285
|
+
}
|
|
271
286
|
if (req.url === '/toolbox/tools' && req.method === 'DELETE') {
|
|
272
287
|
return toolboxRest.handleDeleteTool(await readJsonBody(), sendJson);
|
|
273
288
|
}
|
|
289
|
+
if ((req.url === '/toolbox/actions' || req.url.startsWith('/toolbox/actions?')) && req.method === 'GET') {
|
|
290
|
+
return toolboxRest.handleGetAction(getQuery(), sendJson);
|
|
291
|
+
}
|
|
274
292
|
if (req.url === '/toolbox/actions' && req.method === 'POST') {
|
|
275
293
|
return toolboxRest.handleUpsertAction(await readJsonBody(), sendJson);
|
|
276
294
|
}
|
|
295
|
+
if (req.url === '/toolbox/actions' && req.method === 'PATCH') {
|
|
296
|
+
return toolboxRest.handleUpdateAction(await readJsonBody(), sendJson);
|
|
297
|
+
}
|
|
277
298
|
if (req.url === '/toolbox/actions' && req.method === 'DELETE') {
|
|
278
299
|
return toolboxRest.handleDeleteAction(await readJsonBody(), sendJson);
|
|
279
300
|
}
|
|
@@ -316,33 +337,62 @@ function createServer() {
|
|
|
316
337
|
return userApiKeysRest.handleDelete(sendJson);
|
|
317
338
|
}
|
|
318
339
|
|
|
319
|
-
// ── /
|
|
340
|
+
// ── /apps REST ────────────────────────────────────────────────────
|
|
341
|
+
if (req.url === '/apps/list' && req.method === 'GET') {
|
|
342
|
+
return appsRest.handleList(sendJson);
|
|
343
|
+
}
|
|
344
|
+
if (req.url === '/apps/routes' && req.method === 'GET') {
|
|
345
|
+
return appsRest.handleRoutes(sendJson);
|
|
346
|
+
}
|
|
347
|
+
if (req.url === '/apps/register' && req.method === 'POST') {
|
|
348
|
+
return appsRest.handleRegister(await readJsonBody(), sendJson);
|
|
349
|
+
}
|
|
350
|
+
if (req.url === '/apps/redeploy' && req.method === 'POST') {
|
|
351
|
+
return appsRest.handleRedeploy(await readJsonBody(), sendJson);
|
|
352
|
+
}
|
|
353
|
+
if (req.url === '/apps/start' && req.method === 'POST') {
|
|
354
|
+
return appsRest.handleStart(await readJsonBody(), sendJson);
|
|
355
|
+
}
|
|
356
|
+
if (req.url === '/apps/stop' && req.method === 'POST') {
|
|
357
|
+
return appsRest.handleStop(await readJsonBody(), sendJson);
|
|
358
|
+
}
|
|
359
|
+
if (req.url === '/apps/delete' && req.method === 'POST') {
|
|
360
|
+
return appsRest.handleDelete(await readJsonBody(), sendJson);
|
|
361
|
+
}
|
|
362
|
+
if (req.url === '/apps/connect-dns' && req.method === 'POST') {
|
|
363
|
+
return appsRest.handleConnectDns(await readJsonBody(), sendJson);
|
|
364
|
+
}
|
|
365
|
+
if (req.url === '/apps/disconnect-dns' && req.method === 'POST') {
|
|
366
|
+
return appsRest.handleDisconnectDns(await readJsonBody(), sendJson);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// ── legacy /artifacts REST aliases ────────────────────────────────
|
|
320
370
|
if (req.url === '/artifacts/list' && req.method === 'GET') {
|
|
321
|
-
return
|
|
371
|
+
return appsRest.handleList(sendJson, { legacy: true });
|
|
322
372
|
}
|
|
323
373
|
if (req.url === '/artifacts/routes' && req.method === 'GET') {
|
|
324
|
-
return
|
|
374
|
+
return appsRest.handleRoutes(sendJson, { legacy: true });
|
|
325
375
|
}
|
|
326
376
|
if (req.url === '/artifacts/register' && req.method === 'POST') {
|
|
327
|
-
return
|
|
377
|
+
return appsRest.handleRegister(await readJsonBody(), sendJson, { legacy: true });
|
|
328
378
|
}
|
|
329
379
|
if (req.url === '/artifacts/redeploy' && req.method === 'POST') {
|
|
330
|
-
return
|
|
380
|
+
return appsRest.handleRedeploy(await readJsonBody(), sendJson, { legacy: true });
|
|
331
381
|
}
|
|
332
382
|
if (req.url === '/artifacts/start' && req.method === 'POST') {
|
|
333
|
-
return
|
|
383
|
+
return appsRest.handleStart(await readJsonBody(), sendJson, { legacy: true });
|
|
334
384
|
}
|
|
335
385
|
if (req.url === '/artifacts/stop' && req.method === 'POST') {
|
|
336
|
-
return
|
|
386
|
+
return appsRest.handleStop(await readJsonBody(), sendJson, { legacy: true });
|
|
337
387
|
}
|
|
338
388
|
if (req.url === '/artifacts/delete' && req.method === 'POST') {
|
|
339
|
-
return
|
|
389
|
+
return appsRest.handleDelete(await readJsonBody(), sendJson, { legacy: true });
|
|
340
390
|
}
|
|
341
391
|
if (req.url === '/artifacts/connect-dns' && req.method === 'POST') {
|
|
342
|
-
return
|
|
392
|
+
return appsRest.handleConnectDns(await readJsonBody(), sendJson, { legacy: true });
|
|
343
393
|
}
|
|
344
394
|
if (req.url === '/artifacts/disconnect-dns' && req.method === 'POST') {
|
|
345
|
-
return
|
|
395
|
+
return appsRest.handleDisconnectDns(await readJsonBody(), sendJson, { legacy: true });
|
|
346
396
|
}
|
|
347
397
|
|
|
348
398
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
@@ -363,9 +413,9 @@ async function listen() {
|
|
|
363
413
|
console.log(
|
|
364
414
|
`[AmalgmMCP] Supabase: ${hasSupabase() ? 'connected' : 'not configured (runs are local-only)'}`,
|
|
365
415
|
);
|
|
366
|
-
// Hydrate user model prefs non-blocking
|
|
416
|
+
// Hydrate user model prefs non-blocking from local SQLite.
|
|
367
417
|
require('../lib/prefs').hydrateModelPreferences().catch(() => {});
|
|
368
|
-
|
|
418
|
+
startAutomationScheduler();
|
|
369
419
|
});
|
|
370
420
|
|
|
371
421
|
// Graceful shutdown. Running tasks get aborted via SIGTERM → process exit;
|
|
@@ -373,7 +423,7 @@ async function listen() {
|
|
|
373
423
|
// runtime teardown paths.
|
|
374
424
|
function shutdown() {
|
|
375
425
|
console.log('[AmalgmMCP] Shutting down...');
|
|
376
|
-
|
|
426
|
+
stopAutomationScheduler();
|
|
377
427
|
httpServer.close(() => process.exit(0));
|
|
378
428
|
setTimeout(() => process.exit(0), 5000);
|
|
379
429
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The api-proxy verifies Slack, resolves/creates the Supabase session, then
|
|
5
5
|
* forwards a clean Slack payload here. This local route runs the agent through
|
|
6
|
-
* the same chat-server path as email/
|
|
6
|
+
* the same chat-server path as email/automations, then asks the proxy to send
|
|
7
7
|
* the Slack reply with the bot token that lives outside the local computer.
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -61,6 +61,125 @@ function migrate(database = openLocalDb()) {
|
|
|
61
61
|
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
+
CREATE TABLE IF NOT EXISTS automation_workflows (
|
|
65
|
+
id TEXT PRIMARY KEY,
|
|
66
|
+
name TEXT NOT NULL,
|
|
67
|
+
description TEXT,
|
|
68
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
69
|
+
project_path TEXT,
|
|
70
|
+
workflow_text TEXT NOT NULL,
|
|
71
|
+
workflow_ir_json TEXT,
|
|
72
|
+
compiler_errors_json TEXT,
|
|
73
|
+
allowlist_json TEXT NOT NULL DEFAULT '{}',
|
|
74
|
+
limits_json TEXT NOT NULL DEFAULT '{}',
|
|
75
|
+
created_at TEXT NOT NULL,
|
|
76
|
+
updated_at TEXT NOT NULL,
|
|
77
|
+
workflow_json TEXT NOT NULL
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
CREATE INDEX IF NOT EXISTS automation_workflows_enabled_idx
|
|
81
|
+
ON automation_workflows(enabled);
|
|
82
|
+
|
|
83
|
+
CREATE TABLE IF NOT EXISTS automation_definitions (
|
|
84
|
+
id TEXT PRIMARY KEY,
|
|
85
|
+
name TEXT NOT NULL,
|
|
86
|
+
description TEXT,
|
|
87
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
88
|
+
project_path TEXT,
|
|
89
|
+
workflow_id TEXT NOT NULL,
|
|
90
|
+
created_at TEXT NOT NULL,
|
|
91
|
+
updated_at TEXT NOT NULL,
|
|
92
|
+
automation_json TEXT NOT NULL,
|
|
93
|
+
FOREIGN KEY(workflow_id) REFERENCES automation_workflows(id) ON DELETE CASCADE
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
CREATE INDEX IF NOT EXISTS automation_definitions_workflow_idx
|
|
97
|
+
ON automation_definitions(workflow_id);
|
|
98
|
+
|
|
99
|
+
CREATE INDEX IF NOT EXISTS automation_definitions_enabled_idx
|
|
100
|
+
ON automation_definitions(enabled);
|
|
101
|
+
|
|
102
|
+
CREATE TABLE IF NOT EXISTS automation_triggers (
|
|
103
|
+
id TEXT PRIMARY KEY,
|
|
104
|
+
automation_id TEXT NOT NULL,
|
|
105
|
+
kind TEXT NOT NULL,
|
|
106
|
+
name TEXT NOT NULL,
|
|
107
|
+
description TEXT,
|
|
108
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
109
|
+
schedule_kind TEXT,
|
|
110
|
+
schedule_json TEXT,
|
|
111
|
+
next_run_at TEXT,
|
|
112
|
+
last_fired_at TEXT,
|
|
113
|
+
source TEXT,
|
|
114
|
+
event TEXT,
|
|
115
|
+
source_url TEXT,
|
|
116
|
+
webhook_url TEXT,
|
|
117
|
+
secret TEXT,
|
|
118
|
+
created_at TEXT NOT NULL,
|
|
119
|
+
updated_at TEXT NOT NULL,
|
|
120
|
+
trigger_json TEXT NOT NULL,
|
|
121
|
+
FOREIGN KEY(automation_id) REFERENCES automation_definitions(id) ON DELETE CASCADE
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
CREATE INDEX IF NOT EXISTS automation_triggers_automation_idx
|
|
125
|
+
ON automation_triggers(automation_id);
|
|
126
|
+
|
|
127
|
+
CREATE INDEX IF NOT EXISTS automation_triggers_kind_idx
|
|
128
|
+
ON automation_triggers(kind);
|
|
129
|
+
|
|
130
|
+
CREATE INDEX IF NOT EXISTS automation_triggers_due_idx
|
|
131
|
+
ON automation_triggers(kind, enabled, next_run_at);
|
|
132
|
+
|
|
133
|
+
CREATE TABLE IF NOT EXISTS automation_runs (
|
|
134
|
+
id TEXT PRIMARY KEY,
|
|
135
|
+
automation_id TEXT NOT NULL,
|
|
136
|
+
trigger_id TEXT,
|
|
137
|
+
workflow_id TEXT,
|
|
138
|
+
status TEXT NOT NULL,
|
|
139
|
+
started_at TEXT,
|
|
140
|
+
finished_at TEXT,
|
|
141
|
+
project_path TEXT,
|
|
142
|
+
error TEXT,
|
|
143
|
+
run_json TEXT NOT NULL,
|
|
144
|
+
created_at TEXT NOT NULL,
|
|
145
|
+
updated_at TEXT NOT NULL,
|
|
146
|
+
FOREIGN KEY(automation_id) REFERENCES automation_definitions(id) ON DELETE CASCADE,
|
|
147
|
+
FOREIGN KEY(trigger_id) REFERENCES automation_triggers(id) ON DELETE SET NULL,
|
|
148
|
+
FOREIGN KEY(workflow_id) REFERENCES automation_workflows(id) ON DELETE SET NULL
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
CREATE INDEX IF NOT EXISTS automation_runs_automation_updated_idx
|
|
152
|
+
ON automation_runs(automation_id, updated_at DESC);
|
|
153
|
+
|
|
154
|
+
CREATE INDEX IF NOT EXISTS automation_runs_trigger_updated_idx
|
|
155
|
+
ON automation_runs(trigger_id, updated_at DESC);
|
|
156
|
+
|
|
157
|
+
CREATE INDEX IF NOT EXISTS automation_runs_status_idx
|
|
158
|
+
ON automation_runs(status);
|
|
159
|
+
|
|
160
|
+
CREATE TABLE IF NOT EXISTS workflow_cell_runs (
|
|
161
|
+
id TEXT PRIMARY KEY,
|
|
162
|
+
run_id TEXT NOT NULL,
|
|
163
|
+
automation_id TEXT NOT NULL,
|
|
164
|
+
trigger_id TEXT,
|
|
165
|
+
workflow_id TEXT,
|
|
166
|
+
cell_name TEXT NOT NULL,
|
|
167
|
+
cell_kind TEXT NOT NULL,
|
|
168
|
+
status TEXT NOT NULL,
|
|
169
|
+
started_at TEXT,
|
|
170
|
+
finished_at TEXT,
|
|
171
|
+
output_json TEXT,
|
|
172
|
+
error TEXT,
|
|
173
|
+
cell_json TEXT NOT NULL,
|
|
174
|
+
created_at TEXT NOT NULL,
|
|
175
|
+
updated_at TEXT NOT NULL,
|
|
176
|
+
FOREIGN KEY(run_id) REFERENCES automation_runs(id) ON DELETE CASCADE,
|
|
177
|
+
FOREIGN KEY(automation_id) REFERENCES automation_definitions(id) ON DELETE CASCADE
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
CREATE INDEX IF NOT EXISTS workflow_cell_runs_run_idx
|
|
181
|
+
ON workflow_cell_runs(run_id);
|
|
182
|
+
|
|
64
183
|
CREATE TABLE IF NOT EXISTS scheduled_tasks (
|
|
65
184
|
id TEXT PRIMARY KEY,
|
|
66
185
|
name TEXT NOT NULL,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { currentSeq } = require('./events');
|
|
4
4
|
|
|
5
|
-
const DEFAULT_RESOURCES = ['
|
|
5
|
+
const DEFAULT_RESOURCES = ['automations', 'triggers', 'workflows', 'automation_runs', 'workflow_cell_runs', 'agents', 'apps', 'toolbox', 'tools', 'tool_actions', 'hooks', 'projects', 'workspaces', 'memories', 'mcp_connections'];
|
|
6
6
|
|
|
7
7
|
function normalizeResources(resources) {
|
|
8
8
|
const values = resources ? String(resources).split(',') : DEFAULT_RESOURCES;
|
|
@@ -12,6 +12,16 @@ function normalizeResources(resources) {
|
|
|
12
12
|
|
|
13
13
|
function readResource(resource, cache) {
|
|
14
14
|
switch (resource) {
|
|
15
|
+
case 'automations':
|
|
16
|
+
cache.automations ||= require('../automations/store').listAutomations();
|
|
17
|
+
return cache.automations;
|
|
18
|
+
case 'triggers':
|
|
19
|
+
cache.triggers ||= require('../automations/store').listTriggers();
|
|
20
|
+
return cache.triggers;
|
|
21
|
+
case 'automation_runs':
|
|
22
|
+
return require('../automations/store').listAutomationRuns({ limit: 100 });
|
|
23
|
+
case 'workflow_cell_runs':
|
|
24
|
+
return require('../automations/store').listWorkflowCellRuns({ limit: 100 });
|
|
15
25
|
case 'tasks':
|
|
16
26
|
return require('../tasks/store').loadTasks().tasks;
|
|
17
27
|
case 'task_runs':
|
|
@@ -20,10 +30,13 @@ function readResource(resource, cache) {
|
|
|
20
30
|
return require('../events/store').listEventRuns({ limit: 100 });
|
|
21
31
|
case 'event_triggers':
|
|
22
32
|
return require('../events/store').loadEventTriggers().triggers;
|
|
33
|
+
case 'workflows':
|
|
34
|
+
cache.workflows ||= require('../automations/store').listWorkflows();
|
|
35
|
+
return cache.workflows;
|
|
23
36
|
case 'agents':
|
|
24
37
|
return require('../agents/store').getAllAgentsWithBuiltins();
|
|
25
|
-
case '
|
|
26
|
-
return require('../
|
|
38
|
+
case 'apps':
|
|
39
|
+
return require('../apps/store').loadApps().apps;
|
|
27
40
|
case 'toolbox':
|
|
28
41
|
cache.toolbox ||= require('../toolbox/store').readToolbox();
|
|
29
42
|
return cache.toolbox;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* 4. Append a run-log JSONL entry and update task metadata.
|
|
9
9
|
*
|
|
10
10
|
* Held state (runningTasks) is purely in-process — it tracks abort controllers
|
|
11
|
-
* so
|
|
11
|
+
* so legacy compatibility callers can abort a live run.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const crypto = require('crypto');
|