amalgm 0.1.51 → 0.1.52
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 +505 -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-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
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Event-triggers MCP tools.
|
|
3
|
-
*
|
|
4
|
-
* 5 tools: create, list, get, update, delete. Create returns the webhook URL
|
|
5
|
-
* and secret that the user needs to configure in the external service.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const crypto = require('crypto');
|
|
9
|
-
const { textResult, errorResult } = require('../lib/tool-result');
|
|
10
|
-
const { loadEventTriggers, saveEventTriggers } = require('./store');
|
|
11
|
-
const { getWebhookUrl } = require('./webhook-url');
|
|
12
|
-
const {
|
|
13
|
-
chatInputToLegacyFields,
|
|
14
|
-
getChatInputText,
|
|
15
|
-
normalizeChatInput,
|
|
16
|
-
} = require('../../../lib/chatInput');
|
|
17
|
-
const {
|
|
18
|
-
DEFAULT_SELECTED_MODELS,
|
|
19
|
-
getSelectedModel,
|
|
20
|
-
hydrateModelPreferences,
|
|
21
|
-
} = require('../lib/prefs');
|
|
22
|
-
const credentialAdapter = require('../../credential-adapter');
|
|
23
|
-
const activeMemory = require('../../chat-core/tooling/active-memory');
|
|
24
|
-
|
|
25
|
-
function resolveEventHarness(harness, chatInput) {
|
|
26
|
-
return (
|
|
27
|
-
(chatInput && chatInput.agent && typeof chatInput.agent.harness === 'string' && chatInput.agent.harness)
|
|
28
|
-
|| (typeof harness === 'string' && harness)
|
|
29
|
-
|| 'claude_code'
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function resolveEventModel(harness, model) {
|
|
34
|
-
if (typeof model === 'string' && model) return model;
|
|
35
|
-
return getSelectedModel(harness) || DEFAULT_SELECTED_MODELS[harness] || null;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function resolveEventAuthMethod(harness, authMethod) {
|
|
39
|
-
if (typeof authMethod === 'string' && authMethod) return authMethod;
|
|
40
|
-
if (credentialAdapter.VALID_HARNESS_IDS.includes(harness)) {
|
|
41
|
-
return credentialAdapter.getPersistedAuthMode(harness);
|
|
42
|
-
}
|
|
43
|
-
return 'amalgm';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function buildEventChatInput(fields, existing = null) {
|
|
47
|
-
if (fields.chatInput) return fields.chatInput;
|
|
48
|
-
|
|
49
|
-
const existingNonTextParts =
|
|
50
|
-
existing && existing.chatInput && Array.isArray(existing.chatInput.parts)
|
|
51
|
-
? existing.chatInput.parts.filter((part) => part.type !== 'text')
|
|
52
|
-
: [];
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
...(existing && existing.chatInput ? existing.chatInput : {}),
|
|
56
|
-
parts: [
|
|
57
|
-
...existingNonTextParts,
|
|
58
|
-
...((typeof fields.agent_prompt === 'string' && fields.agent_prompt)
|
|
59
|
-
? [{ type: 'text', text: fields.agent_prompt }]
|
|
60
|
-
: []),
|
|
61
|
-
],
|
|
62
|
-
agent: {
|
|
63
|
-
...((existing && existing.chatInput && existing.chatInput.agent) || {}),
|
|
64
|
-
...(fields.harness ? { harness: fields.harness } : {}),
|
|
65
|
-
...(fields.model ? { model: fields.model } : {}),
|
|
66
|
-
...(fields.authMethod ? { authMethod: fields.authMethod } : {}),
|
|
67
|
-
},
|
|
68
|
-
tools: (existing && existing.chatInput && existing.chatInput.tools) || { mcpAppIds: [] },
|
|
69
|
-
execution: {
|
|
70
|
-
...((existing && existing.chatInput && existing.chatInput.execution) || {}),
|
|
71
|
-
...(fields.projectPath !== undefined ? { cwd: fields.projectPath || null } : {}),
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function normalizeEventTriggerRecord(triggerLike, existing = null) {
|
|
77
|
-
const rawChatInput = buildEventChatInput(triggerLike, existing);
|
|
78
|
-
const harness = resolveEventHarness(triggerLike.harness, rawChatInput);
|
|
79
|
-
const model = resolveEventModel(harness, triggerLike.model);
|
|
80
|
-
const authMethod = resolveEventAuthMethod(harness, triggerLike.authMethod);
|
|
81
|
-
const chatInput = normalizeChatInput(rawChatInput, {
|
|
82
|
-
prompt: triggerLike.agent_prompt,
|
|
83
|
-
harness,
|
|
84
|
-
modelId: model,
|
|
85
|
-
authMethod,
|
|
86
|
-
cwd: triggerLike.projectPath,
|
|
87
|
-
projectPath: triggerLike.projectPath,
|
|
88
|
-
});
|
|
89
|
-
const legacy = chatInputToLegacyFields(chatInput, {
|
|
90
|
-
prompt: triggerLike.agent_prompt,
|
|
91
|
-
harness,
|
|
92
|
-
modelId: model,
|
|
93
|
-
authMethod,
|
|
94
|
-
cwd: triggerLike.projectPath,
|
|
95
|
-
projectPath: triggerLike.projectPath,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
...triggerLike,
|
|
100
|
-
chatInput,
|
|
101
|
-
agent_prompt: getChatInputText(chatInput, triggerLike.agent_prompt) || legacy.prompt,
|
|
102
|
-
harness: legacy.harness || harness,
|
|
103
|
-
model: legacy.modelId || model,
|
|
104
|
-
authMethod: legacy.authMethod || authMethod,
|
|
105
|
-
projectPath: legacy.cwd || triggerLike.projectPath || null,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
module.exports = [
|
|
110
|
-
{
|
|
111
|
-
name: 'event_triggers_create',
|
|
112
|
-
description:
|
|
113
|
-
'Create a new event trigger that fires an agent run when a signed event is received (e.g. GitHub push, a first-party artifact event). Returns a webhook URL and secret to configure in the sender.',
|
|
114
|
-
inputSchema: {
|
|
115
|
-
type: 'object',
|
|
116
|
-
properties: {
|
|
117
|
-
name: {
|
|
118
|
-
type: 'string',
|
|
119
|
-
description: 'Human-readable trigger name (e.g. "PR merged", "Payment received")',
|
|
120
|
-
},
|
|
121
|
-
description: { type: 'string', description: 'Optional markdown description shown in the UI.' },
|
|
122
|
-
source: {
|
|
123
|
-
type: 'string',
|
|
124
|
-
description: 'Source label (e.g. "github", "stripe", "*" for any).',
|
|
125
|
-
},
|
|
126
|
-
event: { type: 'string', description: 'Event label (e.g. "push", "*" for any).' },
|
|
127
|
-
agent_prompt: {
|
|
128
|
-
type: 'string',
|
|
129
|
-
description: 'Prompt template for the agent run. Use {payload} to inject the body.',
|
|
130
|
-
},
|
|
131
|
-
projectPath: { type: 'string', description: 'Working directory path for the agent run.' },
|
|
132
|
-
harness: { type: 'string', description: 'Agent harness for the event run.' },
|
|
133
|
-
model: { type: 'string', description: 'Model ID for the event run.' },
|
|
134
|
-
modelSettings: { type: 'object', description: 'Advanced model settings such as effort and fastMode.' },
|
|
135
|
-
authMethod: { type: 'string', description: 'Auth method for the event run.' },
|
|
136
|
-
chatInput: { type: 'object', description: 'Shared chat input shape for the event run.' },
|
|
137
|
-
},
|
|
138
|
-
required: ['name', 'source', 'event'],
|
|
139
|
-
},
|
|
140
|
-
async handler({ name, description, source, event, agent_prompt, projectPath, harness, model, modelSettings, authMethod, chatInput }) {
|
|
141
|
-
if (!name || (!agent_prompt && !chatInput)) return errorResult('name and agent_prompt or chatInput are required');
|
|
142
|
-
await hydrateModelPreferences();
|
|
143
|
-
const data = loadEventTriggers();
|
|
144
|
-
const trigger = normalizeEventTriggerRecord({
|
|
145
|
-
id: crypto.randomUUID(),
|
|
146
|
-
name,
|
|
147
|
-
description: description || '',
|
|
148
|
-
source: source || '*',
|
|
149
|
-
event: event || '*',
|
|
150
|
-
agent_prompt: agent_prompt || null,
|
|
151
|
-
enabled: true,
|
|
152
|
-
webhookUrl: getWebhookUrl(),
|
|
153
|
-
secret: crypto.randomUUID().replace(/-/g, ''),
|
|
154
|
-
projectPath: projectPath || null,
|
|
155
|
-
harness: harness || null,
|
|
156
|
-
model: model || null,
|
|
157
|
-
modelSettings: modelSettings || null,
|
|
158
|
-
authMethod: authMethod || null,
|
|
159
|
-
chatInput: chatInput || null,
|
|
160
|
-
createdAt: new Date().toISOString(),
|
|
161
|
-
lastFiredAt: null,
|
|
162
|
-
});
|
|
163
|
-
data.triggers.push(trigger);
|
|
164
|
-
saveEventTriggers(data);
|
|
165
|
-
activeMemory.ensureConstructMemory({
|
|
166
|
-
type: 'event',
|
|
167
|
-
id: trigger.id,
|
|
168
|
-
name: trigger.name,
|
|
169
|
-
projectPath: trigger.projectPath,
|
|
170
|
-
}, { source: 'event:create' });
|
|
171
|
-
console.log(`[AmalgmMCP:Events] Created trigger via MCP: ${name} (${source}:${event})`);
|
|
172
|
-
return textResult(
|
|
173
|
-
`Event trigger created.\n\nWebhook URL: ${trigger.webhookUrl}\nSecret: ${trigger.secret}\n\nConfigure the sender to either sign each request with this secret or send it directly in a secret header, then POST JSON to the webhook URL.\n\n${JSON.stringify(trigger, null, 2)}`,
|
|
174
|
-
);
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: 'event_triggers_list',
|
|
179
|
-
description: 'List all event triggers with their webhook URLs, secrets, and status',
|
|
180
|
-
inputSchema: {
|
|
181
|
-
type: 'object',
|
|
182
|
-
properties: {
|
|
183
|
-
enabled_only: { type: 'boolean', description: 'If true, only return enabled triggers' },
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
async handler({ enabled_only }) {
|
|
187
|
-
const data = loadEventTriggers();
|
|
188
|
-
let triggers = data.triggers.map((trigger) => normalizeEventTriggerRecord(trigger));
|
|
189
|
-
if (enabled_only) triggers = triggers.filter((t) => t.enabled);
|
|
190
|
-
if (triggers.length === 0) return textResult('No event triggers found.');
|
|
191
|
-
const summary = triggers
|
|
192
|
-
.map(
|
|
193
|
-
(t) =>
|
|
194
|
-
`- ${t.name} (${t.id})\n ${t.enabled ? 'enabled' : 'disabled'} | source: ${t.source || '*'} | event: ${t.event || '*'}\n URL: ${t.webhookUrl}\n project: ${t.projectPath || '(default)'}\n last fired: ${t.lastFiredAt || 'never'}`,
|
|
195
|
-
)
|
|
196
|
-
.join('\n\n');
|
|
197
|
-
return textResult(`Event triggers:\n\n${summary}`);
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
name: 'event_triggers_get',
|
|
202
|
-
description: 'Get detailed information about a specific event trigger',
|
|
203
|
-
inputSchema: {
|
|
204
|
-
type: 'object',
|
|
205
|
-
properties: { trigger_id: { type: 'string' } },
|
|
206
|
-
required: ['trigger_id'],
|
|
207
|
-
},
|
|
208
|
-
async handler({ trigger_id }) {
|
|
209
|
-
const data = loadEventTriggers();
|
|
210
|
-
const trigger = data.triggers.find((t) => t.id === trigger_id);
|
|
211
|
-
if (!trigger) return errorResult(`Trigger not found: ${trigger_id}`);
|
|
212
|
-
return textResult(JSON.stringify(normalizeEventTriggerRecord(trigger), null, 2));
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
name: 'event_triggers_update',
|
|
217
|
-
description: 'Update properties of an existing event trigger',
|
|
218
|
-
inputSchema: {
|
|
219
|
-
type: 'object',
|
|
220
|
-
properties: {
|
|
221
|
-
trigger_id: { type: 'string' },
|
|
222
|
-
name: { type: 'string' },
|
|
223
|
-
description: { type: 'string' },
|
|
224
|
-
source: { type: 'string' },
|
|
225
|
-
event: { type: 'string' },
|
|
226
|
-
agent_prompt: { type: 'string' },
|
|
227
|
-
enabled: { type: 'boolean' },
|
|
228
|
-
projectPath: { type: 'string' },
|
|
229
|
-
harness: { type: 'string' },
|
|
230
|
-
model: { type: 'string' },
|
|
231
|
-
modelSettings: { type: 'object' },
|
|
232
|
-
authMethod: { type: 'string' },
|
|
233
|
-
chatInput: { type: 'object' },
|
|
234
|
-
},
|
|
235
|
-
required: ['trigger_id'],
|
|
236
|
-
},
|
|
237
|
-
async handler({ trigger_id, name, description, source, event, agent_prompt, enabled, projectPath, harness, model, modelSettings, authMethod, chatInput }) {
|
|
238
|
-
const data = loadEventTriggers();
|
|
239
|
-
const trigger = data.triggers.find((t) => t.id === trigger_id);
|
|
240
|
-
if (!trigger) return errorResult(`Trigger not found: ${trigger_id}`);
|
|
241
|
-
|
|
242
|
-
await hydrateModelPreferences();
|
|
243
|
-
|
|
244
|
-
if (name !== undefined) trigger.name = name;
|
|
245
|
-
if (description !== undefined) trigger.description = description || '';
|
|
246
|
-
if (source !== undefined) trigger.source = source;
|
|
247
|
-
if (event !== undefined) trigger.event = event;
|
|
248
|
-
if (agent_prompt !== undefined) trigger.agent_prompt = agent_prompt;
|
|
249
|
-
if (enabled !== undefined) trigger.enabled = enabled;
|
|
250
|
-
if (projectPath !== undefined) trigger.projectPath = projectPath || null;
|
|
251
|
-
if (harness !== undefined) trigger.harness = harness || null;
|
|
252
|
-
if (model !== undefined) trigger.model = model || null;
|
|
253
|
-
if (modelSettings !== undefined) trigger.modelSettings = modelSettings || null;
|
|
254
|
-
if (authMethod !== undefined) trigger.authMethod = authMethod || null;
|
|
255
|
-
if (chatInput !== undefined) trigger.chatInput = chatInput || null;
|
|
256
|
-
trigger.updatedAt = new Date().toISOString();
|
|
257
|
-
if (
|
|
258
|
-
chatInput === undefined
|
|
259
|
-
&& (
|
|
260
|
-
agent_prompt !== undefined
|
|
261
|
-
|| harness !== undefined
|
|
262
|
-
|| model !== undefined
|
|
263
|
-
|| authMethod !== undefined
|
|
264
|
-
|| projectPath !== undefined
|
|
265
|
-
)
|
|
266
|
-
) {
|
|
267
|
-
const existingNonTextParts = Array.isArray(trigger.chatInput?.parts)
|
|
268
|
-
? trigger.chatInput.parts.filter((part) => part.type !== 'text')
|
|
269
|
-
: [];
|
|
270
|
-
trigger.chatInput = {
|
|
271
|
-
...(trigger.chatInput || {}),
|
|
272
|
-
parts: [
|
|
273
|
-
...existingNonTextParts,
|
|
274
|
-
...((typeof trigger.agent_prompt === 'string' && trigger.agent_prompt)
|
|
275
|
-
? [{ type: 'text', text: trigger.agent_prompt }]
|
|
276
|
-
: []),
|
|
277
|
-
],
|
|
278
|
-
agent: {
|
|
279
|
-
...(trigger.chatInput?.agent || {}),
|
|
280
|
-
...(trigger.harness ? { harness: trigger.harness } : {}),
|
|
281
|
-
...(trigger.model ? { model: trigger.model } : {}),
|
|
282
|
-
...(trigger.authMethod ? { authMethod: trigger.authMethod } : {}),
|
|
283
|
-
},
|
|
284
|
-
tools: trigger.chatInput?.tools || { mcpAppIds: [] },
|
|
285
|
-
execution: {
|
|
286
|
-
...(trigger.chatInput?.execution || {}),
|
|
287
|
-
...(projectPath !== undefined ? { cwd: trigger.projectPath || null } : {}),
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
Object.assign(trigger, normalizeEventTriggerRecord(trigger, trigger));
|
|
293
|
-
|
|
294
|
-
saveEventTriggers(data);
|
|
295
|
-
activeMemory.ensureConstructMemory({
|
|
296
|
-
type: 'event',
|
|
297
|
-
id: trigger.id,
|
|
298
|
-
name: trigger.name,
|
|
299
|
-
projectPath: trigger.projectPath,
|
|
300
|
-
}, { source: 'event:update' });
|
|
301
|
-
console.log(`[AmalgmMCP:Events] Updated trigger via MCP: ${trigger_id}`);
|
|
302
|
-
return textResult(`Trigger updated.\n\n${JSON.stringify(trigger, null, 2)}`);
|
|
303
|
-
},
|
|
304
|
-
},
|
|
305
|
-
{
|
|
306
|
-
name: 'event_triggers_delete',
|
|
307
|
-
description: 'Delete an event trigger permanently. The webhook URL will stop working.',
|
|
308
|
-
inputSchema: {
|
|
309
|
-
type: 'object',
|
|
310
|
-
properties: { trigger_id: { type: 'string' } },
|
|
311
|
-
required: ['trigger_id'],
|
|
312
|
-
},
|
|
313
|
-
async handler({ trigger_id }) {
|
|
314
|
-
const data = loadEventTriggers();
|
|
315
|
-
const idx = data.triggers.findIndex((t) => t.id === trigger_id);
|
|
316
|
-
if (idx === -1) return errorResult(`Trigger not found: ${trigger_id}`);
|
|
317
|
-
const deleted = data.triggers.splice(idx, 1)[0];
|
|
318
|
-
saveEventTriggers(data);
|
|
319
|
-
console.log(`[AmalgmMCP:Events] Deleted trigger via MCP: ${trigger_id} (${deleted.name})`);
|
|
320
|
-
return textResult(`Trigger "${deleted.name}" deleted.`);
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
];
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* /tasks/* REST routes for the Next.js API to call.
|
|
3
|
-
* Not part of the MCP tool surface — used by the internal UI.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { loadTasks } = require('./store');
|
|
7
|
-
const taskTools = require('./tools');
|
|
8
|
-
|
|
9
|
-
const taskToolHandlers = new Map(taskTools.map((tool) => [tool.name, tool.handler]));
|
|
10
|
-
|
|
11
|
-
function extractText(result) {
|
|
12
|
-
const entry = Array.isArray(result?.content)
|
|
13
|
-
? result.content.find((item) => item && item.type === 'text' && typeof item.text === 'string')
|
|
14
|
-
: null;
|
|
15
|
-
return entry?.text || '';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function parseTaskFromText(text) {
|
|
19
|
-
const jsonStart = typeof text === 'string' ? text.indexOf('{') : -1;
|
|
20
|
-
if (jsonStart < 0) return null;
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(text.slice(jsonStart));
|
|
24
|
-
} catch {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function callTaskTool(name, args) {
|
|
30
|
-
const handler = taskToolHandlers.get(name);
|
|
31
|
-
if (!handler) {
|
|
32
|
-
throw new Error(`Unknown task tool: ${name}`);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const result = await handler(args);
|
|
36
|
-
const text = extractText(result);
|
|
37
|
-
return {
|
|
38
|
-
result,
|
|
39
|
-
text,
|
|
40
|
-
isError: Boolean(result?.isError),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function handleList(sendJson) {
|
|
45
|
-
const data = loadTasks();
|
|
46
|
-
sendJson(200, { tasks: data?.tasks || [] });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async function handleCreate(body, sendJson) {
|
|
50
|
-
const response = await callTaskTool('scheduled_tasks_create', body);
|
|
51
|
-
if (response.isError) {
|
|
52
|
-
return sendJson(400, { error: response.text || 'Failed to create task' });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
sendJson(200, {
|
|
56
|
-
ok: true,
|
|
57
|
-
task: parseTaskFromText(response.text),
|
|
58
|
-
output: response.result,
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function handleUpdate(body, sendJson) {
|
|
63
|
-
const response = await callTaskTool('scheduled_tasks_update', body);
|
|
64
|
-
if (response.isError) {
|
|
65
|
-
const status = response.text.startsWith('Task not found:') ? 404 : 400;
|
|
66
|
-
return sendJson(status, { error: response.text || 'Failed to update task' });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
sendJson(200, {
|
|
70
|
-
ok: true,
|
|
71
|
-
task: parseTaskFromText(response.text),
|
|
72
|
-
output: response.result,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function handleDelete(body, sendJson) {
|
|
77
|
-
const response = await callTaskTool('scheduled_tasks_delete', body);
|
|
78
|
-
if (response.isError) {
|
|
79
|
-
const status = response.text.startsWith('Task not found:') ? 404 : 400;
|
|
80
|
-
return sendJson(status, { error: response.text || 'Failed to delete task' });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
sendJson(200, {
|
|
84
|
-
ok: true,
|
|
85
|
-
message: response.text,
|
|
86
|
-
output: response.result,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async function handleRunNow(body, sendJson) {
|
|
91
|
-
const response = await callTaskTool('scheduled_tasks_run_now', body);
|
|
92
|
-
if (response.isError) {
|
|
93
|
-
const status = response.text.startsWith('Task not found:') ? 404 : 400;
|
|
94
|
-
return sendJson(status, { error: response.text || 'Failed to run task' });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
sendJson(200, {
|
|
98
|
-
ok: true,
|
|
99
|
-
message: response.text,
|
|
100
|
-
output: response.result,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
module.exports = {
|
|
105
|
-
handleList,
|
|
106
|
-
handleCreate,
|
|
107
|
-
handleUpdate,
|
|
108
|
-
handleDelete,
|
|
109
|
-
handleRunNow,
|
|
110
|
-
};
|