@amalgm/automations 0.2.6 → 0.3.1
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/AXIOMS.md +54 -9
- package/PURPOSE.md +47 -11
- package/README.md +119 -12
- package/dist/src/cli/arguments.d.ts +20 -0
- package/dist/src/cli/arguments.js +49 -0
- package/dist/src/cli/input.d.ts +6 -0
- package/dist/src/cli/input.js +48 -0
- package/dist/src/cli/main.d.ts +7 -0
- package/dist/src/cli/main.js +39 -0
- package/dist/src/cli/run.d.ts +13 -0
- package/dist/src/cli/run.js +51 -0
- package/dist/src/cli/shell-runtime.d.ts +9 -0
- package/dist/src/cli/shell-runtime.js +131 -0
- package/dist/src/cli-main.js +2 -20
- package/dist/src/cli.d.ts +3 -10
- package/dist/src/cli.js +3 -186
- package/dist/src/command-result.d.ts +8 -0
- package/dist/src/command-result.js +13 -0
- package/dist/src/command-surface.d.ts +25 -0
- package/dist/src/command-surface.js +125 -0
- package/dist/src/contract.d.ts +1 -1
- package/dist/src/execution-contract.d.ts +28 -0
- package/dist/src/execution-contract.js +1 -0
- package/dist/src/execution-errors.d.ts +6 -0
- package/dist/src/execution-errors.js +48 -0
- package/dist/src/execution-limits.d.ts +6 -0
- package/dist/src/execution-limits.js +6 -0
- package/dist/src/executor.d.ts +3 -16
- package/dist/src/executor.js +31 -36
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.js +7 -2
- package/dist/src/input-template.d.ts +2 -2
- package/dist/src/input-template.js +4 -4
- package/dist/src/mcp-main.js +0 -0
- package/dist/src/mcp.js +23 -80
- package/dist/src/node-process-host.d.ts +13 -0
- package/dist/src/node-process-host.js +116 -0
- package/dist/src/node-process-runner.d.ts +23 -0
- package/dist/src/node-process-runner.js +140 -0
- package/dist/src/plan.js +125 -9
- package/dist/src/run-contract.d.ts +41 -1
- package/dist/src/run-journal.d.ts +2 -2
- package/dist/src/run-journal.js +56 -1
- package/dist/src/schema.d.ts +4 -4
- package/package.json +3 -3
- package/skills/automations/SKILL.md +69 -6
- package/supabase/migrations/20260904010000_typed_workflow_admission.sql +272 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
-- Every delivery path admits the same declared workflow versions. The SDK owns
|
|
2
|
+
-- shape validation; this transaction-bound predicate prevents incomplete or
|
|
3
|
+
-- unsupported definitions from entering the durable execution ledger.
|
|
4
|
+
|
|
5
|
+
CREATE OR REPLACE FUNCTION public.amalgm_workflow_is_executable(p_compiled jsonb)
|
|
6
|
+
RETURNS boolean
|
|
7
|
+
LANGUAGE sql
|
|
8
|
+
IMMUTABLE
|
|
9
|
+
SET search_path = public
|
|
10
|
+
AS $$
|
|
11
|
+
SELECT jsonb_typeof(p_compiled) = 'object'
|
|
12
|
+
AND p_compiled->>'version' IN ('1', '2')
|
|
13
|
+
AND jsonb_typeof(p_compiled->'steps') = 'array'
|
|
14
|
+
AND jsonb_array_length(
|
|
15
|
+
CASE WHEN jsonb_typeof(p_compiled->'steps') = 'array'
|
|
16
|
+
THEN p_compiled->'steps' ELSE '[]'::jsonb END
|
|
17
|
+
) BETWEEN 1 AND 100;
|
|
18
|
+
$$;
|
|
19
|
+
|
|
20
|
+
CREATE OR REPLACE FUNCTION public.list_amalgm_event_triggers(p_user_id uuid, p_target_id text)
|
|
21
|
+
RETURNS TABLE (
|
|
22
|
+
user_id uuid,
|
|
23
|
+
automation_id text,
|
|
24
|
+
trigger_id text,
|
|
25
|
+
target_id text,
|
|
26
|
+
source text,
|
|
27
|
+
event text,
|
|
28
|
+
secret text
|
|
29
|
+
)
|
|
30
|
+
LANGUAGE sql
|
|
31
|
+
SECURITY DEFINER
|
|
32
|
+
SET search_path = public
|
|
33
|
+
AS $$
|
|
34
|
+
SELECT t.user_id, t.automation_id, t.id, a.target_id, t.source, t.event, t.secret
|
|
35
|
+
FROM public.amalgm_automation_triggers t
|
|
36
|
+
JOIN public.amalgm_automations a
|
|
37
|
+
ON a.user_id = t.user_id AND a.id = t.automation_id
|
|
38
|
+
JOIN public.amalgm_automation_workflows w
|
|
39
|
+
ON w.user_id = a.user_id AND w.automation_id = a.id
|
|
40
|
+
WHERE t.kind = 'webhook' AND t.user_id = p_user_id
|
|
41
|
+
AND a.target_id = p_target_id AND t.enabled AND a.enabled
|
|
42
|
+
AND public.amalgm_workflow_is_executable(w.compiled);
|
|
43
|
+
$$;
|
|
44
|
+
|
|
45
|
+
CREATE OR REPLACE FUNCTION public.list_due_amalgm_crons(p_now timestamptz)
|
|
46
|
+
RETURNS TABLE (
|
|
47
|
+
user_id uuid,
|
|
48
|
+
automation_id text,
|
|
49
|
+
trigger_id text,
|
|
50
|
+
target_id text,
|
|
51
|
+
cron text,
|
|
52
|
+
timezone text,
|
|
53
|
+
next_run_at timestamptz,
|
|
54
|
+
remaining_occurrences integer
|
|
55
|
+
)
|
|
56
|
+
LANGUAGE sql
|
|
57
|
+
SECURITY DEFINER
|
|
58
|
+
SET search_path = public
|
|
59
|
+
AS $$
|
|
60
|
+
SELECT t.user_id, t.automation_id, t.id, a.target_id,
|
|
61
|
+
t.cron, t.timezone, t.next_run_at, t.remaining_occurrences
|
|
62
|
+
FROM public.amalgm_automation_triggers t
|
|
63
|
+
JOIN public.amalgm_automations a
|
|
64
|
+
ON a.user_id = t.user_id AND a.id = t.automation_id
|
|
65
|
+
JOIN public.amalgm_automation_workflows w
|
|
66
|
+
ON w.user_id = a.user_id AND w.automation_id = a.id
|
|
67
|
+
WHERE t.kind = 'schedule' AND t.next_run_at <= p_now
|
|
68
|
+
AND (t.remaining_occurrences IS NULL OR t.remaining_occurrences > 0)
|
|
69
|
+
AND t.enabled AND a.enabled
|
|
70
|
+
AND public.amalgm_workflow_is_executable(w.compiled)
|
|
71
|
+
ORDER BY t.next_run_at, t.user_id, t.automation_id, t.id;
|
|
72
|
+
$$;
|
|
73
|
+
|
|
74
|
+
CREATE OR REPLACE FUNCTION public.resolve_amalgm_webhook(p_endpoint_id text)
|
|
75
|
+
RETURNS TABLE (
|
|
76
|
+
user_id uuid,
|
|
77
|
+
automation_id text,
|
|
78
|
+
trigger_id text,
|
|
79
|
+
target_id text,
|
|
80
|
+
endpoint_id text,
|
|
81
|
+
source text,
|
|
82
|
+
event text,
|
|
83
|
+
secret text
|
|
84
|
+
)
|
|
85
|
+
LANGUAGE sql
|
|
86
|
+
SECURITY DEFINER
|
|
87
|
+
SET search_path = public
|
|
88
|
+
AS $$
|
|
89
|
+
SELECT t.user_id, t.automation_id, t.id, a.target_id,
|
|
90
|
+
t.endpoint_id, t.source, t.event, t.secret
|
|
91
|
+
FROM public.amalgm_automation_triggers t
|
|
92
|
+
JOIN public.amalgm_automations a
|
|
93
|
+
ON a.user_id = t.user_id AND a.id = t.automation_id
|
|
94
|
+
JOIN public.amalgm_automation_workflows w
|
|
95
|
+
ON w.user_id = a.user_id AND w.automation_id = a.id
|
|
96
|
+
WHERE t.kind = 'webhook' AND t.endpoint_id = p_endpoint_id
|
|
97
|
+
AND t.enabled AND a.enabled
|
|
98
|
+
AND public.amalgm_workflow_is_executable(w.compiled);
|
|
99
|
+
$$;
|
|
100
|
+
|
|
101
|
+
CREATE OR REPLACE FUNCTION public.enqueue_amalgm_run(
|
|
102
|
+
p_kind text,
|
|
103
|
+
p_user_id uuid,
|
|
104
|
+
p_automation_id text,
|
|
105
|
+
p_trigger_id text,
|
|
106
|
+
p_target_id text,
|
|
107
|
+
p_endpoint_id text,
|
|
108
|
+
p_delivery_key text,
|
|
109
|
+
p_expected_next_run_at timestamptz,
|
|
110
|
+
p_next_run_at timestamptz,
|
|
111
|
+
p_input jsonb,
|
|
112
|
+
p_now timestamptz
|
|
113
|
+
) RETURNS SETOF public.amalgm_automation_runs
|
|
114
|
+
LANGUAGE plpgsql
|
|
115
|
+
SECURITY DEFINER
|
|
116
|
+
SET search_path = public
|
|
117
|
+
AS $$
|
|
118
|
+
DECLARE
|
|
119
|
+
v_inserted integer := 0;
|
|
120
|
+
BEGIN
|
|
121
|
+
IF p_kind = 'cron' THEN
|
|
122
|
+
IF p_endpoint_id IS NOT NULL OR p_delivery_key IS NOT NULL THEN
|
|
123
|
+
RAISE EXCEPTION 'Schedule admission cannot carry webhook identity';
|
|
124
|
+
END IF;
|
|
125
|
+
PERFORM 1
|
|
126
|
+
FROM public.amalgm_automation_triggers t
|
|
127
|
+
JOIN public.amalgm_automations a
|
|
128
|
+
ON a.user_id = t.user_id AND a.id = t.automation_id
|
|
129
|
+
WHERE t.user_id = p_user_id AND t.automation_id = p_automation_id
|
|
130
|
+
AND t.id = p_trigger_id AND a.target_id = p_target_id
|
|
131
|
+
AND t.kind = 'schedule' AND t.next_run_at = p_expected_next_run_at
|
|
132
|
+
AND (t.remaining_occurrences IS NULL OR t.remaining_occurrences > 0)
|
|
133
|
+
AND t.enabled AND a.enabled
|
|
134
|
+
FOR UPDATE OF t;
|
|
135
|
+
ELSIF p_kind = 'event' THEN
|
|
136
|
+
IF p_endpoint_id IS NULL THEN RAISE EXCEPTION 'Webhook endpoint is required'; END IF;
|
|
137
|
+
PERFORM 1
|
|
138
|
+
FROM public.amalgm_automation_triggers t
|
|
139
|
+
JOIN public.amalgm_automations a
|
|
140
|
+
ON a.user_id = t.user_id AND a.id = t.automation_id
|
|
141
|
+
WHERE t.user_id = p_user_id AND t.automation_id = p_automation_id
|
|
142
|
+
AND t.id = p_trigger_id AND a.target_id = p_target_id
|
|
143
|
+
AND t.kind = 'webhook' AND t.endpoint_id = p_endpoint_id
|
|
144
|
+
AND t.enabled AND a.enabled;
|
|
145
|
+
ELSE
|
|
146
|
+
RAISE EXCEPTION 'Invalid automation trigger kind';
|
|
147
|
+
END IF;
|
|
148
|
+
IF NOT FOUND THEN RETURN; END IF;
|
|
149
|
+
|
|
150
|
+
RETURN QUERY
|
|
151
|
+
INSERT INTO public.amalgm_automation_runs (
|
|
152
|
+
user_id, target_id, automation_id, trigger_id, workflow_id,
|
|
153
|
+
automation_payload, input, status, delivery_key, created_at
|
|
154
|
+
)
|
|
155
|
+
SELECT a.user_id, a.target_id, a.id, t.id, w.id,
|
|
156
|
+
jsonb_strip_nulls(jsonb_build_object(
|
|
157
|
+
'id', a.id, 'targetId', a.target_id, 'name', a.name,
|
|
158
|
+
'description', a.description, 'enabled', a.enabled,
|
|
159
|
+
'trigger', jsonb_strip_nulls(jsonb_build_object(
|
|
160
|
+
'id', t.id,
|
|
161
|
+
'kind', CASE WHEN t.kind = 'schedule' THEN 'cron' ELSE 'event' END,
|
|
162
|
+
'enabled', t.enabled, 'cron', t.cron, 'timezone', t.timezone,
|
|
163
|
+
'source', t.source, 'event', t.event
|
|
164
|
+
)),
|
|
165
|
+
'workflow', jsonb_strip_nulls(jsonb_build_object(
|
|
166
|
+
'id', w.id, 'name', w.name, 'script', w.script,
|
|
167
|
+
'compiled', w.compiled, 'allowlist', w.allowlist, 'limits', w.limits
|
|
168
|
+
))
|
|
169
|
+
)),
|
|
170
|
+
p_input, 'pending', p_delivery_key, p_now
|
|
171
|
+
FROM public.amalgm_automations a
|
|
172
|
+
JOIN public.amalgm_automation_triggers t
|
|
173
|
+
ON t.user_id = a.user_id AND t.automation_id = a.id
|
|
174
|
+
JOIN public.amalgm_automation_workflows w
|
|
175
|
+
ON w.user_id = a.user_id AND w.automation_id = a.id
|
|
176
|
+
WHERE a.user_id = p_user_id AND a.id = p_automation_id AND t.id = p_trigger_id
|
|
177
|
+
AND a.target_id = p_target_id AND t.enabled AND a.enabled
|
|
178
|
+
AND (p_kind = 'cron' OR (t.kind = 'webhook' AND t.endpoint_id = p_endpoint_id))
|
|
179
|
+
AND public.amalgm_workflow_is_executable(w.compiled)
|
|
180
|
+
ON CONFLICT (user_id, automation_id, trigger_id, delivery_key)
|
|
181
|
+
WHERE delivery_key IS NOT NULL
|
|
182
|
+
DO UPDATE SET delivery_key = EXCLUDED.delivery_key
|
|
183
|
+
RETURNING *;
|
|
184
|
+
GET DIAGNOSTICS v_inserted = ROW_COUNT;
|
|
185
|
+
|
|
186
|
+
IF p_kind = 'cron' AND v_inserted = 1 THEN
|
|
187
|
+
UPDATE public.amalgm_automation_triggers SET
|
|
188
|
+
next_run_at = p_next_run_at,
|
|
189
|
+
remaining_occurrences = CASE WHEN remaining_occurrences IS NULL
|
|
190
|
+
THEN NULL ELSE remaining_occurrences - 1 END,
|
|
191
|
+
enabled = CASE WHEN remaining_occurrences = 1 THEN false ELSE enabled END,
|
|
192
|
+
updated_at = p_now
|
|
193
|
+
WHERE user_id = p_user_id AND automation_id = p_automation_id
|
|
194
|
+
AND id = p_trigger_id AND kind = 'schedule'
|
|
195
|
+
AND next_run_at = p_expected_next_run_at;
|
|
196
|
+
END IF;
|
|
197
|
+
END;
|
|
198
|
+
$$;
|
|
199
|
+
|
|
200
|
+
CREATE OR REPLACE FUNCTION public.enqueue_amalgm_manual_run(
|
|
201
|
+
p_user_id uuid,
|
|
202
|
+
p_automation_id text,
|
|
203
|
+
p_input jsonb,
|
|
204
|
+
p_idempotency_key text,
|
|
205
|
+
p_now timestamptz
|
|
206
|
+
) RETURNS SETOF public.amalgm_automation_runs
|
|
207
|
+
LANGUAGE plpgsql
|
|
208
|
+
SECURITY DEFINER
|
|
209
|
+
SET search_path = public
|
|
210
|
+
AS $$
|
|
211
|
+
BEGIN
|
|
212
|
+
IF p_idempotency_key IS NOT NULL THEN
|
|
213
|
+
RETURN QUERY
|
|
214
|
+
SELECT r.*
|
|
215
|
+
FROM public.amalgm_automation_runs r
|
|
216
|
+
WHERE r.user_id = p_user_id
|
|
217
|
+
AND r.automation_id = p_automation_id
|
|
218
|
+
AND r.trigger_id = '@manual'
|
|
219
|
+
AND r.delivery_key = p_idempotency_key;
|
|
220
|
+
IF FOUND THEN RETURN; END IF;
|
|
221
|
+
END IF;
|
|
222
|
+
|
|
223
|
+
RETURN QUERY
|
|
224
|
+
INSERT INTO public.amalgm_automation_runs (
|
|
225
|
+
user_id, target_id, automation_id, trigger_id, workflow_id,
|
|
226
|
+
automation_payload, input, status, delivery_key, created_at
|
|
227
|
+
)
|
|
228
|
+
SELECT a.user_id, a.target_id, a.id, '@manual', w.id,
|
|
229
|
+
jsonb_strip_nulls(jsonb_build_object(
|
|
230
|
+
'id', a.id, 'targetId', a.target_id, 'name', a.name,
|
|
231
|
+
'description', a.description, 'enabled', a.enabled,
|
|
232
|
+
'trigger', jsonb_build_object(
|
|
233
|
+
'id', '@manual', 'kind', 'manual', 'enabled', true
|
|
234
|
+
),
|
|
235
|
+
'workflow', jsonb_strip_nulls(jsonb_build_object(
|
|
236
|
+
'id', w.id, 'name', w.name, 'script', w.script,
|
|
237
|
+
'compiled', w.compiled, 'allowlist', w.allowlist, 'limits', w.limits
|
|
238
|
+
))
|
|
239
|
+
)),
|
|
240
|
+
p_input, 'pending', p_idempotency_key, p_now
|
|
241
|
+
FROM public.amalgm_automations a
|
|
242
|
+
JOIN public.amalgm_automation_workflows w
|
|
243
|
+
ON w.user_id = a.user_id AND w.automation_id = a.id
|
|
244
|
+
WHERE a.user_id = p_user_id AND a.id = p_automation_id AND a.enabled
|
|
245
|
+
AND public.amalgm_workflow_is_executable(w.compiled)
|
|
246
|
+
ON CONFLICT (user_id, automation_id, trigger_id, delivery_key)
|
|
247
|
+
WHERE delivery_key IS NOT NULL
|
|
248
|
+
DO UPDATE SET delivery_key = EXCLUDED.delivery_key
|
|
249
|
+
RETURNING *;
|
|
250
|
+
END;
|
|
251
|
+
$$;
|
|
252
|
+
|
|
253
|
+
REVOKE ALL ON FUNCTION public.amalgm_workflow_is_executable(jsonb) FROM PUBLIC;
|
|
254
|
+
REVOKE ALL ON FUNCTION public.list_amalgm_event_triggers(uuid, text) FROM PUBLIC;
|
|
255
|
+
REVOKE ALL ON FUNCTION public.list_due_amalgm_crons(timestamptz) FROM PUBLIC;
|
|
256
|
+
REVOKE ALL ON FUNCTION public.resolve_amalgm_webhook(text) FROM PUBLIC;
|
|
257
|
+
REVOKE ALL ON FUNCTION public.enqueue_amalgm_run(
|
|
258
|
+
text, uuid, text, text, text, text, text, timestamptz, timestamptz, jsonb, timestamptz
|
|
259
|
+
) FROM PUBLIC;
|
|
260
|
+
REVOKE ALL ON FUNCTION public.enqueue_amalgm_manual_run(
|
|
261
|
+
uuid, text, jsonb, text, timestamptz
|
|
262
|
+
) FROM PUBLIC;
|
|
263
|
+
|
|
264
|
+
GRANT EXECUTE ON FUNCTION public.list_amalgm_event_triggers(uuid, text) TO service_role;
|
|
265
|
+
GRANT EXECUTE ON FUNCTION public.list_due_amalgm_crons(timestamptz) TO service_role;
|
|
266
|
+
GRANT EXECUTE ON FUNCTION public.resolve_amalgm_webhook(text) TO service_role;
|
|
267
|
+
GRANT EXECUTE ON FUNCTION public.enqueue_amalgm_run(
|
|
268
|
+
text, uuid, text, text, text, text, text, timestamptz, timestamptz, jsonb, timestamptz
|
|
269
|
+
) TO service_role;
|
|
270
|
+
GRANT EXECUTE ON FUNCTION public.enqueue_amalgm_manual_run(
|
|
271
|
+
uuid, text, jsonb, text, timestamptz
|
|
272
|
+
) TO service_role;
|