@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.
Files changed (47) hide show
  1. package/AXIOMS.md +54 -9
  2. package/PURPOSE.md +47 -11
  3. package/README.md +119 -12
  4. package/dist/src/cli/arguments.d.ts +20 -0
  5. package/dist/src/cli/arguments.js +49 -0
  6. package/dist/src/cli/input.d.ts +6 -0
  7. package/dist/src/cli/input.js +48 -0
  8. package/dist/src/cli/main.d.ts +7 -0
  9. package/dist/src/cli/main.js +39 -0
  10. package/dist/src/cli/run.d.ts +13 -0
  11. package/dist/src/cli/run.js +51 -0
  12. package/dist/src/cli/shell-runtime.d.ts +9 -0
  13. package/dist/src/cli/shell-runtime.js +131 -0
  14. package/dist/src/cli-main.js +2 -20
  15. package/dist/src/cli.d.ts +3 -10
  16. package/dist/src/cli.js +3 -186
  17. package/dist/src/command-result.d.ts +8 -0
  18. package/dist/src/command-result.js +13 -0
  19. package/dist/src/command-surface.d.ts +25 -0
  20. package/dist/src/command-surface.js +125 -0
  21. package/dist/src/contract.d.ts +1 -1
  22. package/dist/src/execution-contract.d.ts +28 -0
  23. package/dist/src/execution-contract.js +1 -0
  24. package/dist/src/execution-errors.d.ts +6 -0
  25. package/dist/src/execution-errors.js +48 -0
  26. package/dist/src/execution-limits.d.ts +6 -0
  27. package/dist/src/execution-limits.js +6 -0
  28. package/dist/src/executor.d.ts +3 -16
  29. package/dist/src/executor.js +31 -36
  30. package/dist/src/index.d.ts +8 -3
  31. package/dist/src/index.js +7 -2
  32. package/dist/src/input-template.d.ts +2 -2
  33. package/dist/src/input-template.js +4 -4
  34. package/dist/src/mcp-main.js +0 -0
  35. package/dist/src/mcp.js +23 -80
  36. package/dist/src/node-process-host.d.ts +13 -0
  37. package/dist/src/node-process-host.js +116 -0
  38. package/dist/src/node-process-runner.d.ts +23 -0
  39. package/dist/src/node-process-runner.js +140 -0
  40. package/dist/src/plan.js +125 -9
  41. package/dist/src/run-contract.d.ts +41 -1
  42. package/dist/src/run-journal.d.ts +2 -2
  43. package/dist/src/run-journal.js +56 -1
  44. package/dist/src/schema.d.ts +4 -4
  45. package/package.json +3 -3
  46. package/skills/automations/SKILL.md +69 -6
  47. 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;