@amalgm/automations 0.1.2 → 0.2.0
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 +11 -0
- package/PURPOSE.md +10 -3
- package/README.md +60 -113
- package/dist/host/auth.d.ts +11 -0
- package/dist/host/auth.js +89 -0
- package/dist/host/config.d.ts +8 -0
- package/dist/host/config.js +29 -0
- package/dist/host/index.d.ts +3 -0
- package/dist/host/index.js +3 -0
- package/dist/host/main.d.ts +1 -0
- package/dist/host/main.js +47 -0
- package/dist/host/server.d.ts +11 -0
- package/dist/host/server.js +53 -0
- package/dist/src/automations.js +4 -1
- package/dist/src/client.d.ts +3 -1
- package/dist/src/client.js +6 -4
- package/dist/src/contract.d.ts +17 -1
- package/dist/src/crud/automations.d.ts +3 -0
- package/dist/src/crud/automations.js +55 -0
- package/dist/src/crud/context.d.ts +13 -0
- package/dist/src/crud/context.js +34 -0
- package/dist/src/crud/repository.d.ts +35 -0
- package/dist/src/crud/repository.js +1 -0
- package/dist/src/crud/runs.d.ts +3 -0
- package/dist/src/crud/runs.js +19 -0
- package/dist/src/crud/triggers.d.ts +3 -0
- package/dist/src/crud/triggers.js +118 -0
- package/dist/src/crud/workflow.d.ts +3 -0
- package/dist/src/crud/workflow.js +42 -0
- package/dist/src/crud.d.ts +3 -33
- package/dist/src/crud.js +10 -237
- package/dist/src/executor.d.ts +16 -0
- package/dist/src/executor.js +76 -0
- package/dist/src/index.d.ts +8 -2
- package/dist/src/index.js +5 -0
- package/dist/src/machine-client.d.ts +7 -0
- package/dist/src/machine-client.js +30 -0
- package/dist/src/machine-http.d.ts +5 -0
- package/dist/src/machine-http.js +40 -0
- package/dist/src/machine.d.ts +41 -0
- package/dist/src/machine.js +43 -0
- package/dist/src/mcp.js +2 -2
- package/dist/src/schema.d.ts +8 -0
- package/dist/src/schema.js +2 -0
- package/dist/src/supabase-crud/automations.d.ts +5 -0
- package/dist/src/supabase-crud/automations.js +36 -0
- package/dist/src/supabase-crud/mappers.d.ts +8 -0
- package/dist/src/supabase-crud/mappers.js +81 -0
- package/dist/src/supabase-crud/rows.d.ts +56 -0
- package/dist/src/supabase-crud/rows.js +1 -0
- package/dist/src/supabase-crud/rpc.d.ts +10 -0
- package/dist/src/supabase-crud/rpc.js +19 -0
- package/dist/src/supabase-crud/triggers.d.ts +5 -0
- package/dist/src/supabase-crud/triggers.js +46 -0
- package/dist/src/supabase-crud/workflow-runs.d.ts +5 -0
- package/dist/src/supabase-crud/workflow-runs.js +41 -0
- package/dist/src/supabase-crud.d.ts +5 -41
- package/dist/src/supabase-crud.js +4 -267
- package/dist/src/supabase-machine.d.ts +16 -0
- package/dist/src/supabase-machine.js +63 -0
- package/dist/src/supabase-store.js +1 -0
- package/dist/src/types.d.ts +1 -0
- package/package.json +11 -2
- package/skills/automations/SKILL.md +52 -0
- package/supabase/migrations/20260829010000_bounded_schedules_and_machine_claims.sql +311 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { paged, schedule, webhook } from './mappers.js';
|
|
2
|
+
import { call } from './rpc.js';
|
|
3
|
+
export function triggerRepository(client) {
|
|
4
|
+
const list = async (functionName, userId, automationId, query, mapper) => paged(await call(client, functionName, {
|
|
5
|
+
p_user_id: userId,
|
|
6
|
+
p_automation_id: automationId,
|
|
7
|
+
p_limit: query.limit,
|
|
8
|
+
p_offset: query.offset,
|
|
9
|
+
}), mapper, query);
|
|
10
|
+
return {
|
|
11
|
+
createScheduleTrigger: async (userId, automationId, input) => schedule(await call(client, 'create_amalgm_schedule_trigger', { p_user_id: userId, p_automation_id: automationId, p_trigger: input })),
|
|
12
|
+
listScheduleTriggers: (userId, automationId, query) => list('list_amalgm_schedule_triggers', userId, automationId, query, schedule),
|
|
13
|
+
getScheduleTrigger: async (userId, automationId, triggerId) => {
|
|
14
|
+
const row = await call(client, 'get_amalgm_schedule_trigger', {
|
|
15
|
+
p_user_id: userId, p_automation_id: automationId, p_trigger_id: triggerId,
|
|
16
|
+
});
|
|
17
|
+
return row ? schedule(row) : null;
|
|
18
|
+
},
|
|
19
|
+
updateScheduleTrigger: async (userId, automationId, triggerId, patch) => {
|
|
20
|
+
const row = await call(client, 'update_amalgm_schedule_trigger', {
|
|
21
|
+
p_user_id: userId, p_automation_id: automationId, p_trigger_id: triggerId, p_patch: patch,
|
|
22
|
+
});
|
|
23
|
+
return row ? schedule(row) : null;
|
|
24
|
+
},
|
|
25
|
+
deleteScheduleTrigger: (userId, automationId, triggerId) => call(client, 'delete_amalgm_schedule_trigger', { p_user_id: userId, p_automation_id: automationId, p_trigger_id: triggerId }),
|
|
26
|
+
createWebhookTrigger: async (userId, automationId, input) => webhook(await call(client, 'create_amalgm_webhook_trigger', { p_user_id: userId, p_automation_id: automationId, p_trigger: input })),
|
|
27
|
+
listWebhookTriggers: (userId, automationId, query) => list('list_amalgm_webhook_triggers', userId, automationId, query, webhook),
|
|
28
|
+
getWebhookTrigger: async (userId, automationId, triggerId) => {
|
|
29
|
+
const row = await call(client, 'get_amalgm_webhook_trigger', {
|
|
30
|
+
p_user_id: userId, p_automation_id: automationId, p_trigger_id: triggerId,
|
|
31
|
+
});
|
|
32
|
+
return row ? webhook(row) : null;
|
|
33
|
+
},
|
|
34
|
+
updateWebhookTrigger: async (userId, automationId, triggerId, patch) => {
|
|
35
|
+
const row = await call(client, 'update_amalgm_webhook_trigger', {
|
|
36
|
+
p_user_id: userId, p_automation_id: automationId, p_trigger_id: triggerId, p_patch: patch,
|
|
37
|
+
});
|
|
38
|
+
return row ? webhook(row) : null;
|
|
39
|
+
},
|
|
40
|
+
deleteWebhookTrigger: (userId, automationId, triggerId) => call(client, 'delete_amalgm_webhook_trigger', { p_user_id: userId, p_automation_id: automationId, p_trigger_id: triggerId }),
|
|
41
|
+
listTriggers: async (userId, automationId) => (await call(client, 'list_amalgm_triggers', {
|
|
42
|
+
p_user_id: userId,
|
|
43
|
+
p_automation_id: automationId,
|
|
44
|
+
})).map((row) => row.kind === 'schedule' ? schedule(row) : webhook(row)),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AutomationCrudRepository } from '../crud.js';
|
|
2
|
+
import { type SupabaseRpcClient } from './rpc.js';
|
|
3
|
+
type Operations = Pick<AutomationCrudRepository, 'createWorkflow' | 'getWorkflow' | 'updateWorkflow' | 'deleteWorkflow' | 'listRuns' | 'getRun'>;
|
|
4
|
+
export declare function workflowRunRepository(client: SupabaseRpcClient): Operations;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { paged, run, workflow } from './mappers.js';
|
|
2
|
+
import { call } from './rpc.js';
|
|
3
|
+
export function workflowRunRepository(client) {
|
|
4
|
+
return {
|
|
5
|
+
createWorkflow: async (userId, automationId, input) => workflow(await call(client, 'create_amalgm_workflow', { p_user_id: userId, p_automation_id: automationId, p_workflow: input })),
|
|
6
|
+
getWorkflow: async (userId, automationId) => {
|
|
7
|
+
const row = await call(client, 'get_amalgm_workflow', {
|
|
8
|
+
p_user_id: userId,
|
|
9
|
+
p_automation_id: automationId,
|
|
10
|
+
});
|
|
11
|
+
return row ? workflow(row) : null;
|
|
12
|
+
},
|
|
13
|
+
updateWorkflow: async (userId, automationId, patch) => {
|
|
14
|
+
const row = await call(client, 'update_amalgm_workflow', {
|
|
15
|
+
p_user_id: userId,
|
|
16
|
+
p_automation_id: automationId,
|
|
17
|
+
p_patch: patch,
|
|
18
|
+
});
|
|
19
|
+
return row ? workflow(row) : null;
|
|
20
|
+
},
|
|
21
|
+
deleteWorkflow: (userId, automationId) => call(client, 'delete_amalgm_workflow', {
|
|
22
|
+
p_user_id: userId,
|
|
23
|
+
p_automation_id: automationId,
|
|
24
|
+
}),
|
|
25
|
+
listRuns: async (userId, automationId, query) => paged(await call(client, 'list_amalgm_runs', {
|
|
26
|
+
p_user_id: userId,
|
|
27
|
+
p_automation_id: automationId,
|
|
28
|
+
p_status: query.status || null,
|
|
29
|
+
p_limit: query.limit,
|
|
30
|
+
p_offset: query.offset,
|
|
31
|
+
}), run, query),
|
|
32
|
+
getRun: async (userId, automationId, runId) => {
|
|
33
|
+
const row = await call(client, 'get_amalgm_run', {
|
|
34
|
+
p_user_id: userId,
|
|
35
|
+
p_automation_id: automationId,
|
|
36
|
+
p_run_id: runId,
|
|
37
|
+
});
|
|
38
|
+
return row ? run(row) : null;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -1,44 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
data: unknown;
|
|
6
|
-
error: {
|
|
7
|
-
code?: string;
|
|
8
|
-
message?: string;
|
|
9
|
-
} | null;
|
|
10
|
-
}>;
|
|
1
|
+
import type { AutomationCrudRepository } from './crud.js';
|
|
2
|
+
import type { SupabaseRpcClient } from './supabase-crud/rpc.js';
|
|
3
|
+
export type { SupabaseRpcClient } from './supabase-crud/rpc.js';
|
|
4
|
+
export interface SupabaseAutomationCrudRepository extends AutomationCrudRepository {
|
|
11
5
|
}
|
|
12
|
-
export declare class SupabaseAutomationCrudRepository
|
|
13
|
-
#private;
|
|
14
|
-
private readonly client;
|
|
6
|
+
export declare class SupabaseAutomationCrudRepository {
|
|
15
7
|
constructor(client: SupabaseRpcClient);
|
|
16
|
-
createAutomation(userId: string, input: Required<CreateAutomation>): Promise<Automation>;
|
|
17
|
-
listAutomations(userId: string, query: NormalizedListAutomations): Promise<Page<Automation>>;
|
|
18
|
-
getAutomation(userId: string, automationId: string): Promise<Automation | null>;
|
|
19
|
-
updateAutomation(userId: string, automationId: string, patch: UpdateAutomation): Promise<Automation | null>;
|
|
20
|
-
deleteAutomation(userId: string, automationId: string): Promise<boolean>;
|
|
21
|
-
createScheduleTrigger(userId: string, automationId: string, input: StoredScheduleCreate): Promise<ScheduleTrigger>;
|
|
22
|
-
listScheduleTriggers(userId: string, automationId: string, query: Required<{
|
|
23
|
-
limit?: number;
|
|
24
|
-
offset?: number;
|
|
25
|
-
}>): Promise<Page<ScheduleTrigger>>;
|
|
26
|
-
getScheduleTrigger(userId: string, automationId: string, triggerId: string): Promise<ScheduleTrigger | null>;
|
|
27
|
-
updateScheduleTrigger(userId: string, automationId: string, triggerId: string, patch: StoredScheduleUpdate): Promise<ScheduleTrigger | null>;
|
|
28
|
-
deleteScheduleTrigger(userId: string, automationId: string, triggerId: string): Promise<boolean>;
|
|
29
|
-
createWebhookTrigger(userId: string, automationId: string, input: Required<CreateWebhookTrigger>): Promise<WebhookTrigger>;
|
|
30
|
-
listWebhookTriggers(userId: string, automationId: string, query: Required<{
|
|
31
|
-
limit?: number;
|
|
32
|
-
offset?: number;
|
|
33
|
-
}>): Promise<Page<WebhookTrigger>>;
|
|
34
|
-
getWebhookTrigger(userId: string, automationId: string, triggerId: string): Promise<WebhookTrigger | null>;
|
|
35
|
-
updateWebhookTrigger(userId: string, automationId: string, triggerId: string, patch: UpdateWebhookTrigger): Promise<WebhookTrigger | null>;
|
|
36
|
-
deleteWebhookTrigger(userId: string, automationId: string, triggerId: string): Promise<boolean>;
|
|
37
|
-
listTriggers(userId: string, automationId: string): Promise<Trigger[]>;
|
|
38
|
-
createWorkflow(userId: string, automationId: string, input: Required<CreateWorkflow>): Promise<Workflow>;
|
|
39
|
-
getWorkflow(userId: string, automationId: string): Promise<Workflow | null>;
|
|
40
|
-
updateWorkflow(userId: string, automationId: string, patch: UpdateWorkflow): Promise<Workflow | null>;
|
|
41
|
-
deleteWorkflow(userId: string, automationId: string): Promise<boolean>;
|
|
42
|
-
listRuns(userId: string, automationId: string, query: NormalizedListRuns): Promise<Page<AutomationRun>>;
|
|
43
|
-
getRun(userId: string, automationId: string, runId: string): Promise<AutomationRun | null>;
|
|
44
8
|
}
|
|
@@ -1,271 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { automationRepository } from './supabase-crud/automations.js';
|
|
2
|
+
import { triggerRepository } from './supabase-crud/triggers.js';
|
|
3
|
+
import { workflowRunRepository } from './supabase-crud/workflow-runs.js';
|
|
2
4
|
export class SupabaseAutomationCrudRepository {
|
|
3
|
-
client;
|
|
4
5
|
constructor(client) {
|
|
5
|
-
this
|
|
6
|
+
Object.assign(this, automationRepository(client), triggerRepository(client), workflowRunRepository(client));
|
|
6
7
|
}
|
|
7
|
-
async createAutomation(userId, input) {
|
|
8
|
-
return automation(await this.#call('create_amalgm_automation', {
|
|
9
|
-
p_user_id: userId,
|
|
10
|
-
p_automation: input,
|
|
11
|
-
}));
|
|
12
|
-
}
|
|
13
|
-
async listAutomations(userId, query) {
|
|
14
|
-
const result = await this.#call('list_amalgm_automations', {
|
|
15
|
-
p_user_id: userId,
|
|
16
|
-
p_target_id: query.targetId || null,
|
|
17
|
-
p_enabled: query.enabled ?? null,
|
|
18
|
-
p_limit: query.limit,
|
|
19
|
-
p_offset: query.offset,
|
|
20
|
-
});
|
|
21
|
-
return paged(result, automation, query);
|
|
22
|
-
}
|
|
23
|
-
async getAutomation(userId, automationId) {
|
|
24
|
-
const row = await this.#call('get_amalgm_automation', {
|
|
25
|
-
p_user_id: userId,
|
|
26
|
-
p_automation_id: automationId,
|
|
27
|
-
});
|
|
28
|
-
return row ? automation(row) : null;
|
|
29
|
-
}
|
|
30
|
-
async updateAutomation(userId, automationId, patch) {
|
|
31
|
-
const row = await this.#call('update_amalgm_automation', {
|
|
32
|
-
p_user_id: userId,
|
|
33
|
-
p_automation_id: automationId,
|
|
34
|
-
p_patch: patch,
|
|
35
|
-
});
|
|
36
|
-
return row ? automation(row) : null;
|
|
37
|
-
}
|
|
38
|
-
deleteAutomation(userId, automationId) {
|
|
39
|
-
return this.#call('delete_amalgm_automation', {
|
|
40
|
-
p_user_id: userId,
|
|
41
|
-
p_automation_id: automationId,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
async createScheduleTrigger(userId, automationId, input) {
|
|
45
|
-
return schedule(await this.#call('create_amalgm_schedule_trigger', {
|
|
46
|
-
p_user_id: userId,
|
|
47
|
-
p_automation_id: automationId,
|
|
48
|
-
p_trigger: input,
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
51
|
-
async listScheduleTriggers(userId, automationId, query) {
|
|
52
|
-
return this.#listTriggers('list_amalgm_schedule_triggers', userId, automationId, query, schedule);
|
|
53
|
-
}
|
|
54
|
-
async getScheduleTrigger(userId, automationId, triggerId) {
|
|
55
|
-
const row = await this.#call('get_amalgm_schedule_trigger', {
|
|
56
|
-
p_user_id: userId,
|
|
57
|
-
p_automation_id: automationId,
|
|
58
|
-
p_trigger_id: triggerId,
|
|
59
|
-
});
|
|
60
|
-
return row ? schedule(row) : null;
|
|
61
|
-
}
|
|
62
|
-
async updateScheduleTrigger(userId, automationId, triggerId, patch) {
|
|
63
|
-
const row = await this.#call('update_amalgm_schedule_trigger', {
|
|
64
|
-
p_user_id: userId,
|
|
65
|
-
p_automation_id: automationId,
|
|
66
|
-
p_trigger_id: triggerId,
|
|
67
|
-
p_patch: patch,
|
|
68
|
-
});
|
|
69
|
-
return row ? schedule(row) : null;
|
|
70
|
-
}
|
|
71
|
-
deleteScheduleTrigger(userId, automationId, triggerId) {
|
|
72
|
-
return this.#call('delete_amalgm_schedule_trigger', {
|
|
73
|
-
p_user_id: userId,
|
|
74
|
-
p_automation_id: automationId,
|
|
75
|
-
p_trigger_id: triggerId,
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
async createWebhookTrigger(userId, automationId, input) {
|
|
79
|
-
return webhook(await this.#call('create_amalgm_webhook_trigger', {
|
|
80
|
-
p_user_id: userId,
|
|
81
|
-
p_automation_id: automationId,
|
|
82
|
-
p_trigger: input,
|
|
83
|
-
}));
|
|
84
|
-
}
|
|
85
|
-
async listWebhookTriggers(userId, automationId, query) {
|
|
86
|
-
return this.#listTriggers('list_amalgm_webhook_triggers', userId, automationId, query, webhook);
|
|
87
|
-
}
|
|
88
|
-
async getWebhookTrigger(userId, automationId, triggerId) {
|
|
89
|
-
const row = await this.#call('get_amalgm_webhook_trigger', {
|
|
90
|
-
p_user_id: userId,
|
|
91
|
-
p_automation_id: automationId,
|
|
92
|
-
p_trigger_id: triggerId,
|
|
93
|
-
});
|
|
94
|
-
return row ? webhook(row) : null;
|
|
95
|
-
}
|
|
96
|
-
async updateWebhookTrigger(userId, automationId, triggerId, patch) {
|
|
97
|
-
const row = await this.#call('update_amalgm_webhook_trigger', {
|
|
98
|
-
p_user_id: userId,
|
|
99
|
-
p_automation_id: automationId,
|
|
100
|
-
p_trigger_id: triggerId,
|
|
101
|
-
p_patch: patch,
|
|
102
|
-
});
|
|
103
|
-
return row ? webhook(row) : null;
|
|
104
|
-
}
|
|
105
|
-
deleteWebhookTrigger(userId, automationId, triggerId) {
|
|
106
|
-
return this.#call('delete_amalgm_webhook_trigger', {
|
|
107
|
-
p_user_id: userId,
|
|
108
|
-
p_automation_id: automationId,
|
|
109
|
-
p_trigger_id: triggerId,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
async listTriggers(userId, automationId) {
|
|
113
|
-
const rows = await this.#call('list_amalgm_triggers', {
|
|
114
|
-
p_user_id: userId,
|
|
115
|
-
p_automation_id: automationId,
|
|
116
|
-
});
|
|
117
|
-
return rows.map((row) => row.kind === 'schedule' ? schedule(row) : webhook(row));
|
|
118
|
-
}
|
|
119
|
-
async createWorkflow(userId, automationId, input) {
|
|
120
|
-
return workflow(await this.#call('create_amalgm_workflow', {
|
|
121
|
-
p_user_id: userId,
|
|
122
|
-
p_automation_id: automationId,
|
|
123
|
-
p_workflow: input,
|
|
124
|
-
}));
|
|
125
|
-
}
|
|
126
|
-
async getWorkflow(userId, automationId) {
|
|
127
|
-
const row = await this.#call('get_amalgm_workflow', {
|
|
128
|
-
p_user_id: userId,
|
|
129
|
-
p_automation_id: automationId,
|
|
130
|
-
});
|
|
131
|
-
return row ? workflow(row) : null;
|
|
132
|
-
}
|
|
133
|
-
async updateWorkflow(userId, automationId, patch) {
|
|
134
|
-
const row = await this.#call('update_amalgm_workflow', {
|
|
135
|
-
p_user_id: userId,
|
|
136
|
-
p_automation_id: automationId,
|
|
137
|
-
p_patch: patch,
|
|
138
|
-
});
|
|
139
|
-
return row ? workflow(row) : null;
|
|
140
|
-
}
|
|
141
|
-
deleteWorkflow(userId, automationId) {
|
|
142
|
-
return this.#call('delete_amalgm_workflow', {
|
|
143
|
-
p_user_id: userId,
|
|
144
|
-
p_automation_id: automationId,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
async listRuns(userId, automationId, query) {
|
|
148
|
-
const result = await this.#call('list_amalgm_runs', {
|
|
149
|
-
p_user_id: userId,
|
|
150
|
-
p_automation_id: automationId,
|
|
151
|
-
p_status: query.status || null,
|
|
152
|
-
p_limit: query.limit,
|
|
153
|
-
p_offset: query.offset,
|
|
154
|
-
});
|
|
155
|
-
return paged(result, run, query);
|
|
156
|
-
}
|
|
157
|
-
async getRun(userId, automationId, runId) {
|
|
158
|
-
const row = await this.#call('get_amalgm_run', {
|
|
159
|
-
p_user_id: userId,
|
|
160
|
-
p_automation_id: automationId,
|
|
161
|
-
p_run_id: runId,
|
|
162
|
-
});
|
|
163
|
-
return row ? run(row) : null;
|
|
164
|
-
}
|
|
165
|
-
async #listTriggers(functionName, userId, automationId, query, mapper) {
|
|
166
|
-
const result = await this.#call(functionName, {
|
|
167
|
-
p_user_id: userId,
|
|
168
|
-
p_automation_id: automationId,
|
|
169
|
-
p_limit: query.limit,
|
|
170
|
-
p_offset: query.offset,
|
|
171
|
-
});
|
|
172
|
-
return paged(result, mapper, query);
|
|
173
|
-
}
|
|
174
|
-
async #call(functionName, arguments_) {
|
|
175
|
-
const { data, error } = await this.client.rpc(functionName, arguments_);
|
|
176
|
-
if (error) {
|
|
177
|
-
if (error.code === '23505' || /duplicate key|unique constraint/i.test(error.message || '')) {
|
|
178
|
-
throw new ConflictError(resource(functionName));
|
|
179
|
-
}
|
|
180
|
-
throw new Error(error.message || `Supabase function ${functionName} failed`);
|
|
181
|
-
}
|
|
182
|
-
return data;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function resource(functionName) {
|
|
186
|
-
if (functionName.includes('workflow'))
|
|
187
|
-
return 'Workflow';
|
|
188
|
-
if (functionName.includes('trigger'))
|
|
189
|
-
return 'Trigger';
|
|
190
|
-
if (functionName.includes('automation'))
|
|
191
|
-
return 'Automation';
|
|
192
|
-
return 'Automation resource';
|
|
193
|
-
}
|
|
194
|
-
function automation(row) {
|
|
195
|
-
return {
|
|
196
|
-
id: row.id,
|
|
197
|
-
targetId: row.target_id,
|
|
198
|
-
...(row.name ? { name: row.name } : {}),
|
|
199
|
-
...(row.description ? { description: row.description } : {}),
|
|
200
|
-
enabled: row.enabled,
|
|
201
|
-
createdAt: timestamp(row.created_at),
|
|
202
|
-
updatedAt: timestamp(row.updated_at),
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
function schedule(row) {
|
|
206
|
-
return {
|
|
207
|
-
id: row.id,
|
|
208
|
-
automationId: row.automation_id,
|
|
209
|
-
kind: 'schedule',
|
|
210
|
-
enabled: row.enabled,
|
|
211
|
-
cron: row.cron,
|
|
212
|
-
timezone: row.timezone,
|
|
213
|
-
createdAt: timestamp(row.created_at),
|
|
214
|
-
updatedAt: timestamp(row.updated_at),
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
function webhook(row) {
|
|
218
|
-
return {
|
|
219
|
-
id: row.id,
|
|
220
|
-
automationId: row.automation_id,
|
|
221
|
-
kind: 'webhook',
|
|
222
|
-
enabled: row.enabled,
|
|
223
|
-
source: row.source,
|
|
224
|
-
event: row.event,
|
|
225
|
-
secretConfigured: row.secret_configured,
|
|
226
|
-
createdAt: timestamp(row.created_at),
|
|
227
|
-
updatedAt: timestamp(row.updated_at),
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
function workflow(row) {
|
|
231
|
-
return {
|
|
232
|
-
id: row.id,
|
|
233
|
-
automationId: row.automation_id,
|
|
234
|
-
...(row.name ? { name: row.name } : {}),
|
|
235
|
-
script: row.script,
|
|
236
|
-
...(row.compiled !== null ? { compiled: row.compiled } : {}),
|
|
237
|
-
...(row.allowlist !== null ? { allowlist: row.allowlist } : {}),
|
|
238
|
-
...(row.limits !== null ? { limits: row.limits } : {}),
|
|
239
|
-
createdAt: timestamp(row.created_at),
|
|
240
|
-
updatedAt: timestamp(row.updated_at),
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
function run(row) {
|
|
244
|
-
return {
|
|
245
|
-
id: row.id,
|
|
246
|
-
automationId: row.automation_id,
|
|
247
|
-
triggerId: row.trigger_id,
|
|
248
|
-
workflowId: row.workflow_id,
|
|
249
|
-
targetId: row.target_id,
|
|
250
|
-
status: row.status,
|
|
251
|
-
input: row.input,
|
|
252
|
-
createdAt: timestamp(row.created_at),
|
|
253
|
-
...(row.sent_at ? { sentAt: timestamp(row.sent_at) } : {}),
|
|
254
|
-
...(row.started_at ? { startedAt: timestamp(row.started_at) } : {}),
|
|
255
|
-
...(row.finished_at ? { finishedAt: timestamp(row.finished_at) } : {}),
|
|
256
|
-
...(row.output !== null ? { output: row.output } : {}),
|
|
257
|
-
...(row.error !== null ? { error: row.error } : {}),
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
function paged(result, mapper, query) {
|
|
261
|
-
return {
|
|
262
|
-
items: result.items.map(mapper),
|
|
263
|
-
total: result.total,
|
|
264
|
-
limit: query.limit,
|
|
265
|
-
offset: query.offset,
|
|
266
|
-
hasMore: query.offset + result.items.length < result.total,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
function timestamp(value) {
|
|
270
|
-
return new Date(value).toISOString();
|
|
271
8
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ClaimedAutomationRun, MachineRunRepository } from './machine.js';
|
|
2
|
+
export interface MachineRpcClient {
|
|
3
|
+
rpc(name: string, arguments_: Record<string, unknown>): PromiseLike<{
|
|
4
|
+
data: unknown;
|
|
5
|
+
error: {
|
|
6
|
+
message?: string;
|
|
7
|
+
} | null;
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
export declare class SupabaseMachineRunRepository implements MachineRunRepository {
|
|
11
|
+
#private;
|
|
12
|
+
private readonly client;
|
|
13
|
+
constructor(client: MachineRpcClient);
|
|
14
|
+
claim(input: Parameters<MachineRunRepository['claim']>[0]): Promise<ClaimedAutomationRun[]>;
|
|
15
|
+
update(input: Parameters<MachineRunRepository['update']>[0]): Promise<ClaimedAutomationRun | null>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { AutomationError } from './errors.js';
|
|
2
|
+
export class SupabaseMachineRunRepository {
|
|
3
|
+
client;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
async claim(input) {
|
|
8
|
+
const rows = await this.#call('claim_amalgm_machine_runs', {
|
|
9
|
+
p_user_id: input.userId,
|
|
10
|
+
p_target_id: input.targetId,
|
|
11
|
+
p_limit: input.limit,
|
|
12
|
+
p_lease_seconds: input.leaseSeconds,
|
|
13
|
+
});
|
|
14
|
+
return rows.map(run);
|
|
15
|
+
}
|
|
16
|
+
async update(input) {
|
|
17
|
+
const rows = await this.#call('update_amalgm_claimed_run', {
|
|
18
|
+
p_user_id: input.userId,
|
|
19
|
+
p_target_id: input.targetId,
|
|
20
|
+
p_run_id: input.runId,
|
|
21
|
+
p_lease_token: input.update.leaseToken,
|
|
22
|
+
p_update: update(input.update),
|
|
23
|
+
p_now: input.now.toISOString(),
|
|
24
|
+
});
|
|
25
|
+
return rows[0] ? run(rows[0]) : null;
|
|
26
|
+
}
|
|
27
|
+
async #call(name, arguments_) {
|
|
28
|
+
const { data, error } = await this.client.rpc(name, arguments_);
|
|
29
|
+
if (error)
|
|
30
|
+
throw new AutomationError('internal', error.message ?? `${name} failed`);
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function run(row) {
|
|
35
|
+
return {
|
|
36
|
+
id: row.id,
|
|
37
|
+
userId: row.user_id,
|
|
38
|
+
targetId: row.target_id,
|
|
39
|
+
automationId: row.automation_id,
|
|
40
|
+
triggerId: row.trigger_id,
|
|
41
|
+
workflowId: row.workflow_id,
|
|
42
|
+
automation: row.automation_payload,
|
|
43
|
+
input: row.input,
|
|
44
|
+
status: row.status,
|
|
45
|
+
attempts: row.attempts,
|
|
46
|
+
leaseToken: row.lease_token,
|
|
47
|
+
leaseExpiresAt: timestamp(row.lease_expires_at),
|
|
48
|
+
createdAt: timestamp(row.created_at),
|
|
49
|
+
...(row.sent_at ? { sentAt: timestamp(row.sent_at) } : {}),
|
|
50
|
+
...(row.started_at ? { startedAt: timestamp(row.started_at) } : {}),
|
|
51
|
+
...(row.finished_at ? { finishedAt: timestamp(row.finished_at) } : {}),
|
|
52
|
+
...(row.output === null ? {} : { output: row.output }),
|
|
53
|
+
...(row.error === null ? {} : { error: row.error }),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function update(value) {
|
|
57
|
+
return {
|
|
58
|
+
status: value.status,
|
|
59
|
+
...(value.output === undefined ? {} : { output: value.output }),
|
|
60
|
+
...(value.error === undefined ? {} : { error: value.error }),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const timestamp = (value) => new Date(value).toISOString();
|
|
@@ -49,6 +49,7 @@ export class SupabaseStore {
|
|
|
49
49
|
cron: row.cron,
|
|
50
50
|
timezone: row.timezone,
|
|
51
51
|
nextRunAt: new Date(row.next_run_at).toISOString(),
|
|
52
|
+
...(row.remaining_occurrences === null ? {} : { remainingOccurrences: row.remaining_occurrences }),
|
|
52
53
|
}));
|
|
53
54
|
}
|
|
54
55
|
enqueueEvent(trigger, input, now) {
|
package/dist/src/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amalgm/automations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Amalgm's cloud automation SDK: Supabase-backed configuration, trigger admission, and run delivery.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
"./mcp": {
|
|
27
27
|
"types": "./dist/src/mcp.d.ts",
|
|
28
28
|
"import": "./dist/src/mcp.js"
|
|
29
|
+
},
|
|
30
|
+
"./host": {
|
|
31
|
+
"types": "./dist/host/index.d.ts",
|
|
32
|
+
"import": "./dist/host/index.js"
|
|
29
33
|
}
|
|
30
34
|
},
|
|
31
35
|
"bin": {
|
|
@@ -34,6 +38,7 @@
|
|
|
34
38
|
},
|
|
35
39
|
"files": [
|
|
36
40
|
"dist",
|
|
41
|
+
"skills",
|
|
37
42
|
"supabase",
|
|
38
43
|
"AXIOMS.md",
|
|
39
44
|
"PURPOSE.md",
|
|
@@ -46,14 +51,18 @@
|
|
|
46
51
|
"test:supabase": "tsx --test test/integration/postgres.test.ts",
|
|
47
52
|
"verify": "npm run check && npm test && npm run build",
|
|
48
53
|
"release:check": "npm run verify && npm run test:supabase",
|
|
49
|
-
"prepack": "npm run build"
|
|
54
|
+
"prepack": "npm run build",
|
|
55
|
+
"start": "node dist/host/main.js"
|
|
50
56
|
},
|
|
51
57
|
"engines": {
|
|
52
58
|
"node": ">=20"
|
|
53
59
|
},
|
|
54
60
|
"dependencies": {
|
|
61
|
+
"@amalgm/core": "0.4.2",
|
|
55
62
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
63
|
+
"@supabase/supabase-js": "2.57.4",
|
|
56
64
|
"cron-parser": "^5.4.0",
|
|
65
|
+
"jose": "^6.1.0",
|
|
57
66
|
"zod": "^4.4.3"
|
|
58
67
|
},
|
|
59
68
|
"devDependencies": {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: automations
|
|
3
|
+
description: Create, inspect, change, or delete Amalgm automations, schedules, workflows, and run history through the Automations MCP tools.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Amalgm Automations
|
|
7
|
+
|
|
8
|
+
Use the Automations tools for scheduled or webhook-driven work. The tools are
|
|
9
|
+
the agent adapter over the same hosted SDK used by the UI.
|
|
10
|
+
|
|
11
|
+
## Create a scheduled notification
|
|
12
|
+
|
|
13
|
+
For a request such as “remind me to call my mom every minute for the next ten
|
|
14
|
+
minutes,” create three resources for the current machine:
|
|
15
|
+
|
|
16
|
+
1. `amalgm_automations_create` with a clear name and the current machine target.
|
|
17
|
+
2. `amalgm_workflow_create` with a readable script summary and this compiled
|
|
18
|
+
plan:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"version": 1,
|
|
23
|
+
"steps": [
|
|
24
|
+
{
|
|
25
|
+
"id": "notify",
|
|
26
|
+
"actionId": "channels.notify_user",
|
|
27
|
+
"input": { "title": "Reminder", "message": "Call Mom" }
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
3. `amalgm_schedule_triggers_create` with cron `* * * * *`, the user's
|
|
34
|
+
timezone, and `maxOccurrences: 10`.
|
|
35
|
+
|
|
36
|
+
Create the automation disabled, attach its workflow and trigger, then enable it
|
|
37
|
+
only after both exist. If setup fails, leave it disabled and explain which
|
|
38
|
+
resource failed. Never replace a bounded occurrence count with an unbounded
|
|
39
|
+
schedule plus a promise to clean it up later.
|
|
40
|
+
|
|
41
|
+
## Read and change
|
|
42
|
+
|
|
43
|
+
Use list/get before changing an existing automation. Schedule and webhook
|
|
44
|
+
triggers are separate resources. A workflow is zero-or-one per automation. Run
|
|
45
|
+
history is read-only and remains after configuration deletion.
|
|
46
|
+
|
|
47
|
+
`pending` means a run is durable and waiting for its selected machine. `sent`
|
|
48
|
+
or `running` means that machine holds a lease. `completed` and `failed` are
|
|
49
|
+
terminal. Do not infer delivery from the schedule alone; inspect runs when the
|
|
50
|
+
user asks whether it actually happened.
|
|
51
|
+
|
|
52
|
+
Webhook secrets are write-only. Never echo, log, or place them in a workflow.
|