feat: finish the automations plugin (B17)

This commit is contained in:
LukeGus committed 2026-09-24 13:05:44 -05:00
1 parent 993a91c899
commit 6b4d1432ab
96 files changed
+25106 -5077

No files matched your search

@@ -0,0 +1,86 @@
-- automations 0001: adopt_automations
-- Generated by termix-plugin migrations. Review before committing.
-- Hand-edited: keeps the legacy foreign keys the SDK cannot declare
-- (links between these tables, and a channel link to notification_channels).
CREATE TABLE IF NOT EXISTS `automations` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`user_id` varchar(255) NOT NULL,
`name` text NOT NULL,
`description` text,
`enabled` boolean NOT NULL DEFAULT true,
`definition` text NOT NULL,
`definition_version` int NOT NULL DEFAULT 1,
`concurrency_policy` text NOT NULL DEFAULT ('skip'),
`max_run_seconds` int NOT NULL DEFAULT 300,
`dry_run` boolean NOT NULL DEFAULT false,
`last_run_at` text,
`last_run_status` text,
`created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
);
RENAME TABLE `automations` TO `p_automations_automations`;
CREATE TABLE IF NOT EXISTS `automation_trigger_state` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`automation_id` int NOT NULL,
`state_key` varchar(255) NOT NULL,
`breach_started_at` text,
`last_fired_at` text,
`last_value` double,
`last_observed_state` text,
`updated_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
FOREIGN KEY (`automation_id`) REFERENCES `p_automations_automations` (`id`) ON DELETE CASCADE
);
RENAME TABLE `automation_trigger_state` TO `p_automations_trigger_state`;
CREATE TABLE IF NOT EXISTS `automation_schedules` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`automation_id` int NOT NULL,
`cron` text,
`interval_seconds` int,
`timezone` text,
`next_due_at` varchar(255),
`last_tick_at` text,
FOREIGN KEY (`automation_id`) REFERENCES `p_automations_automations` (`id`) ON DELETE CASCADE
);
RENAME TABLE `automation_schedules` TO `p_automations_schedules`;
CREATE TABLE IF NOT EXISTS `automation_runs` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`automation_id` int NOT NULL,
`user_id` varchar(255) NOT NULL,
`trigger_type` text NOT NULL,
`trigger_context` text,
`status` text NOT NULL,
`started_at` varchar(255) NOT NULL DEFAULT (CURRENT_TIMESTAMP),
`finished_at` text,
`duration_ms` int,
`error` text,
`dry_run` boolean NOT NULL DEFAULT false,
`parent_run_id` int,
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`automation_id`) REFERENCES `p_automations_automations` (`id`) ON DELETE CASCADE
);
RENAME TABLE `automation_runs` TO `p_automations_runs`;
CREATE TABLE IF NOT EXISTS `automation_run_steps` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`run_id` int NOT NULL,
`step_index` int NOT NULL,
`step_id` text NOT NULL,
`step_type` text NOT NULL,
`status` text NOT NULL,
`started_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP),
`finished_at` text,
`output` text,
`error` text,
`truncated` boolean NOT NULL DEFAULT false,
FOREIGN KEY (`run_id`) REFERENCES `p_automations_runs` (`id`) ON DELETE CASCADE
);
RENAME TABLE `automation_run_steps` TO `p_automations_run_steps`;
CREATE TABLE IF NOT EXISTS `automation_channels` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`automation_id` int NOT NULL,
`channel_id` int NOT NULL,
FOREIGN KEY (`automation_id`) REFERENCES `p_automations_automations` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`channel_id`) REFERENCES `notification_channels` (`id`) ON DELETE CASCADE
);
RENAME TABLE `automation_channels` TO `p_automations_channels`;
@@ -0,0 +1,94 @@
-- automations 0001: adopt_automations
-- Generated by termix-plugin migrations. Review before committing.
-- Hand-edited: keeps the legacy foreign keys the SDK cannot declare
-- (links between these tables, and a channel link to notification_channels).
CREATE TABLE IF NOT EXISTS "automations" (
"id" serial PRIMARY KEY,
"user_id" varchar(255) NOT NULL,
"name" text NOT NULL,
"description" text,
"enabled" boolean NOT NULL DEFAULT true,
"definition" text NOT NULL,
"definition_version" integer NOT NULL DEFAULT 1,
"concurrency_policy" text NOT NULL DEFAULT 'skip',
"max_run_seconds" integer NOT NULL DEFAULT 300,
"dry_run" boolean NOT NULL DEFAULT false,
"last_run_at" text,
"last_run_status" text,
"created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_automations_user" ON "automations" ("user_id", "enabled");
ALTER TABLE "automations" RENAME TO "p_automations_automations";
CREATE TABLE IF NOT EXISTS "automation_trigger_state" (
"id" serial PRIMARY KEY,
"automation_id" integer NOT NULL,
"state_key" varchar(255) NOT NULL,
"breach_started_at" text,
"last_fired_at" text,
"last_value" double precision,
"last_observed_state" text,
"updated_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "idx_automation_trigger_state_key" ON "automation_trigger_state" ("automation_id", "state_key");
ALTER TABLE "automation_trigger_state" RENAME TO "p_automations_trigger_state";
CREATE TABLE IF NOT EXISTS "automation_schedules" (
"id" serial PRIMARY KEY,
"automation_id" integer NOT NULL,
"cron" text,
"interval_seconds" integer,
"timezone" text,
"next_due_at" varchar(255),
"last_tick_at" text,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "idx_automation_schedules_automation" ON "automation_schedules" ("automation_id");
CREATE INDEX IF NOT EXISTS "idx_automation_schedules_due" ON "automation_schedules" ("next_due_at");
ALTER TABLE "automation_schedules" RENAME TO "p_automations_schedules";
CREATE TABLE IF NOT EXISTS "automation_runs" (
"id" serial PRIMARY KEY,
"automation_id" integer NOT NULL,
"user_id" varchar(255) NOT NULL,
"trigger_type" text NOT NULL,
"trigger_context" text,
"status" text NOT NULL,
"started_at" varchar(255) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"finished_at" text,
"duration_ms" integer,
"error" text,
"dry_run" boolean NOT NULL DEFAULT false,
"parent_run_id" integer,
FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_automation_runs_automation" ON "automation_runs" ("automation_id", "started_at");
CREATE INDEX IF NOT EXISTS "idx_automation_runs_user" ON "automation_runs" ("user_id", "started_at");
ALTER TABLE "automation_runs" RENAME TO "p_automations_runs";
CREATE TABLE IF NOT EXISTS "automation_run_steps" (
"id" serial PRIMARY KEY,
"run_id" integer NOT NULL,
"step_index" integer NOT NULL,
"step_id" text NOT NULL,
"step_type" text NOT NULL,
"status" text NOT NULL,
"started_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
"finished_at" text,
"output" text,
"error" text,
"truncated" boolean NOT NULL DEFAULT false,
FOREIGN KEY ("run_id") REFERENCES "p_automations_runs" ("id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_automation_run_steps_run" ON "automation_run_steps" ("run_id", "step_index");
ALTER TABLE "automation_run_steps" RENAME TO "p_automations_run_steps";
CREATE TABLE IF NOT EXISTS "automation_channels" (
"id" serial PRIMARY KEY,
"automation_id" integer NOT NULL,
"channel_id" integer NOT NULL,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE,
FOREIGN KEY ("channel_id") REFERENCES "notification_channels" ("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "idx_automation_channels_pair" ON "automation_channels" ("automation_id", "channel_id");
ALTER TABLE "automation_channels" RENAME TO "p_automations_channels";
@@ -0,0 +1,303 @@
{
"version": 1,
"tables": {
"automations": {
"columns": {
"id": {
"type": "id",
"primaryKey": true,
"notNull": true
},
"userId": {
"type": "refUser",
"length": 255,
"notNull": true
},
"name": {
"type": "text",
"notNull": true
},
"description": {
"type": "text"
},
"enabled": {
"type": "boolean",
"notNull": true,
"defaultValue": true
},
"definition": {
"type": "text",
"notNull": true
},
"definitionVersion": {
"type": "integer",
"notNull": true,
"defaultValue": 1
},
"concurrencyPolicy": {
"type": "text",
"notNull": true,
"defaultValue": "skip"
},
"maxRunSeconds": {
"type": "integer",
"notNull": true,
"defaultValue": 300
},
"dryRun": {
"type": "boolean",
"notNull": true,
"defaultValue": false
},
"lastRunAt": {
"type": "text"
},
"lastRunStatus": {
"type": "text"
},
"createdAt": {
"type": "timestamp",
"notNull": true,
"defaultNow": true
},
"updatedAt": {
"type": "timestamp",
"notNull": true,
"defaultNow": true
}
},
"indexes": [
{
"name": "idx_automations_user",
"columns": ["userId", "enabled"]
}
],
"adopts": "automations"
},
"trigger_state": {
"columns": {
"id": {
"type": "id",
"primaryKey": true,
"notNull": true
},
"automationId": {
"type": "integer",
"notNull": true
},
"stateKey": {
"type": "varchar",
"length": 255,
"notNull": true
},
"breachStartedAt": {
"type": "text"
},
"lastFiredAt": {
"type": "text"
},
"lastValue": {
"type": "real"
},
"lastObservedState": {
"type": "text"
},
"updatedAt": {
"type": "timestamp",
"notNull": true,
"defaultNow": true
}
},
"indexes": [
{
"name": "idx_automation_trigger_state_key",
"columns": ["automationId", "stateKey"],
"unique": true
}
],
"adopts": "automation_trigger_state"
},
"schedules": {
"columns": {
"id": {
"type": "id",
"primaryKey": true,
"notNull": true
},
"automationId": {
"type": "integer",
"notNull": true
},
"cron": {
"type": "text"
},
"intervalSeconds": {
"type": "integer"
},
"timezone": {
"type": "text"
},
"nextDueAt": {
"type": "timestamp"
},
"lastTickAt": {
"type": "text"
}
},
"indexes": [
{
"name": "idx_automation_schedules_automation",
"columns": ["automationId"],
"unique": true
},
{
"name": "idx_automation_schedules_due",
"columns": ["nextDueAt"]
}
],
"adopts": "automation_schedules"
},
"runs": {
"columns": {
"id": {
"type": "id",
"primaryKey": true,
"notNull": true
},
"automationId": {
"type": "integer",
"notNull": true
},
"userId": {
"type": "refUser",
"length": 255,
"notNull": true
},
"triggerType": {
"type": "text",
"notNull": true
},
"triggerContext": {
"type": "text"
},
"status": {
"type": "text",
"notNull": true
},
"startedAt": {
"type": "timestamp",
"notNull": true,
"defaultNow": true
},
"finishedAt": {
"type": "text"
},
"durationMs": {
"type": "integer"
},
"error": {
"type": "text"
},
"dryRun": {
"type": "boolean",
"notNull": true,
"defaultValue": false
},
"parentRunId": {
"type": "integer"
}
},
"indexes": [
{
"name": "idx_automation_runs_automation",
"columns": ["automationId", "startedAt"]
},
{
"name": "idx_automation_runs_user",
"columns": ["userId", "startedAt"]
}
],
"adopts": "automation_runs"
},
"run_steps": {
"columns": {
"id": {
"type": "id",
"primaryKey": true,
"notNull": true
},
"runId": {
"type": "integer",
"notNull": true
},
"stepIndex": {
"type": "integer",
"notNull": true
},
"stepId": {
"type": "text",
"notNull": true
},
"stepType": {
"type": "text",
"notNull": true
},
"status": {
"type": "text",
"notNull": true
},
"startedAt": {
"type": "timestamp",
"notNull": true,
"defaultNow": true
},
"finishedAt": {
"type": "text"
},
"output": {
"type": "text"
},
"error": {
"type": "text"
},
"truncated": {
"type": "boolean",
"notNull": true,
"defaultValue": false
}
},
"indexes": [
{
"name": "idx_automation_run_steps_run",
"columns": ["runId", "stepIndex"]
}
],
"adopts": "automation_run_steps"
},
"channels": {
"columns": {
"id": {
"type": "id",
"primaryKey": true,
"notNull": true
},
"automationId": {
"type": "integer",
"notNull": true
},
"channelId": {
"type": "integer",
"notNull": true
}
},
"indexes": [
{
"name": "idx_automation_channels_pair",
"columns": ["automationId", "channelId"],
"unique": true
}
],
"adopts": "automation_channels"
}
}
}
@@ -0,0 +1,94 @@
-- automations 0001: adopt_automations
-- Generated by termix-plugin migrations. Review before committing.
-- Hand-edited: keeps the legacy foreign keys the SDK cannot declare
-- (links between these tables, and a channel link to notification_channels).
CREATE TABLE IF NOT EXISTS "automations" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"user_id" text NOT NULL,
"name" text NOT NULL,
"description" text,
"enabled" integer NOT NULL DEFAULT 1,
"definition" text NOT NULL,
"definition_version" integer NOT NULL DEFAULT 1,
"concurrency_policy" text NOT NULL DEFAULT 'skip',
"max_run_seconds" integer NOT NULL DEFAULT 300,
"dry_run" integer NOT NULL DEFAULT 0,
"last_run_at" text,
"last_run_status" text,
"created_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_automations_user" ON "automations" ("user_id", "enabled");
ALTER TABLE "automations" RENAME TO "p_automations_automations";
CREATE TABLE IF NOT EXISTS "automation_trigger_state" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"automation_id" integer NOT NULL,
"state_key" text NOT NULL,
"breach_started_at" text,
"last_fired_at" text,
"last_value" real,
"last_observed_state" text,
"updated_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "idx_automation_trigger_state_key" ON "automation_trigger_state" ("automation_id", "state_key");
ALTER TABLE "automation_trigger_state" RENAME TO "p_automations_trigger_state";
CREATE TABLE IF NOT EXISTS "automation_schedules" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"automation_id" integer NOT NULL,
"cron" text,
"interval_seconds" integer,
"timezone" text,
"next_due_at" text,
"last_tick_at" text,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "idx_automation_schedules_automation" ON "automation_schedules" ("automation_id");
CREATE INDEX IF NOT EXISTS "idx_automation_schedules_due" ON "automation_schedules" ("next_due_at");
ALTER TABLE "automation_schedules" RENAME TO "p_automations_schedules";
CREATE TABLE IF NOT EXISTS "automation_runs" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"automation_id" integer NOT NULL,
"user_id" text NOT NULL,
"trigger_type" text NOT NULL,
"trigger_context" text,
"status" text NOT NULL,
"started_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
"finished_at" text,
"duration_ms" integer,
"error" text,
"dry_run" integer NOT NULL DEFAULT 0,
"parent_run_id" integer,
FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_automation_runs_automation" ON "automation_runs" ("automation_id", "started_at");
CREATE INDEX IF NOT EXISTS "idx_automation_runs_user" ON "automation_runs" ("user_id", "started_at");
ALTER TABLE "automation_runs" RENAME TO "p_automations_runs";
CREATE TABLE IF NOT EXISTS "automation_run_steps" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"run_id" integer NOT NULL,
"step_index" integer NOT NULL,
"step_id" text NOT NULL,
"step_type" text NOT NULL,
"status" text NOT NULL,
"started_at" text NOT NULL DEFAULT CURRENT_TIMESTAMP,
"finished_at" text,
"output" text,
"error" text,
"truncated" integer NOT NULL DEFAULT 0,
FOREIGN KEY ("run_id") REFERENCES "p_automations_runs" ("id") ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS "idx_automation_run_steps_run" ON "automation_run_steps" ("run_id", "step_index");
ALTER TABLE "automation_run_steps" RENAME TO "p_automations_run_steps";
CREATE TABLE IF NOT EXISTS "automation_channels" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"automation_id" integer NOT NULL,
"channel_id" integer NOT NULL,
FOREIGN KEY ("automation_id") REFERENCES "p_automations_automations" ("id") ON DELETE CASCADE,
FOREIGN KEY ("channel_id") REFERENCES "notification_channels" ("id") ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS "idx_automation_channels_pair" ON "automation_channels" ("automation_id", "channel_id");
ALTER TABLE "automation_channels" RENAME TO "p_automations_channels";