Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0215bff
feat: persist automation definitions and runs
Astro-Han May 30, 2026
9c31dab
feat: add durable automation scheduling guards
Astro-Han May 30, 2026
ed085e9
fix: harden automation scheduler edge cases
Astro-Han May 30, 2026
6de4ebc
fix: restore persisted automations on access
Astro-Han May 30, 2026
c3847d7
fix: harden automation scheduler rescan
Astro-Han May 30, 2026
63444ec
fix: avoid repeated expensive cron scans
Astro-Han May 30, 2026
7a3ddb3
fix: preserve due automation fires during rescan
Astro-Han May 30, 2026
8a05940
fix: address automation review comments
Astro-Han May 30, 2026
882cdf4
fix: handle missed one-shot restart scans
Astro-Han May 30, 2026
a0c28e8
test: cover missed one-shot startup scan
Astro-Han May 30, 2026
c022b18
perf: query automation run guards in sql
Astro-Han May 30, 2026
144808a
fix: protect live automation runs during reconcile
Astro-Han May 30, 2026
34b18e9
fix: close automation run lease startup race
Astro-Han May 30, 2026
f666ea3
fix: release automation run lease on startup errors
Astro-Han May 30, 2026
eb12a26
fix: guard automation durable writes
Astro-Han May 30, 2026
73a54d2
fix: harden automation conflict follow-ups
Astro-Han May 30, 2026
d01c1b6
fix: reject deleting live automation runs
Astro-Han May 30, 2026
93f2493
fix: reconcile stale automation writers while owner lives
Astro-Han May 30, 2026
35ff10a
fix: reconcile stale automation writers before manual runs
Astro-Han May 30, 2026
f3c9300
fix: avoid publishing missing automation runs
Astro-Han May 30, 2026
7fbabc0
fix: record missed cron automation fires
Astro-Han May 30, 2026
9ee6b6c
fix: skip missed cron records after stop limit
Astro-Han May 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
CREATE TABLE `automation_definition` (
`id` text PRIMARY KEY,
`project_id` text NOT NULL,
`owner_directory` text NOT NULL,
`time_created` integer NOT NULL,
`time_updated` integer NOT NULL,
`data` text NOT NULL,
CONSTRAINT `fk_automation_definition_project_id_project_id_fk` FOREIGN KEY (`project_id`) REFERENCES `project`(`id`) ON DELETE CASCADE
);
--> statement-breakpoint
CREATE INDEX `automation_definition_project_owner_updated_idx` ON `automation_definition` (`project_id`,`owner_directory`,`time_updated`,`id`);--> statement-breakpoint
CREATE TABLE `automation_run` (
`id` text PRIMARY KEY,
`automation_id` text NOT NULL,
`project_id` text NOT NULL,
`owner_directory` text NOT NULL,
`triggered_at` integer NOT NULL,
`data` text NOT NULL,
`time_created` integer NOT NULL,
`time_updated` integer NOT NULL,
CONSTRAINT `fk_automation_run_automation_id_automation_definition_id_fk` FOREIGN KEY (`automation_id`) REFERENCES `automation_definition`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_automation_run_project_id_project_id_fk` FOREIGN KEY (`project_id`) REFERENCES `project`(`id`) ON DELETE CASCADE
);
--> statement-breakpoint
CREATE INDEX `automation_run_automation_triggered_idx` ON `automation_run` (`automation_id`,`triggered_at`,`id`);--> statement-breakpoint
CREATE INDEX `automation_run_project_owner_idx` ON `automation_run` (`project_id`,`owner_directory`);
2 changes: 2 additions & 0 deletions packages/opencode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@types/babel__core": "7.20.5",
"@types/bun": "catalog:",
"@types/cross-spawn": "catalog:",
"@types/luxon": "catalog:",
"@types/mime-types": "3.0.1",
"@types/npm-package-arg": "6.1.4",
"@types/npmcli__arborist": "6.3.3",
Expand Down Expand Up @@ -143,6 +144,7 @@
"hono-openapi": "catalog:",
"ignore": "7.0.5",
"jsonc-parser": "3.3.1",
"luxon": "catalog:",
"mime-types": "3.0.2",
"minimatch": "10.2.3",
"npm-package-arg": "13.0.2",
Expand Down
45 changes: 45 additions & 0 deletions packages/opencode/src/automation/automation.sql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core"
import type { Automation } from "."
import { ProjectTable } from "@/project/project.sql"
import type { ProjectID } from "@/project/schema"
import { Timestamps } from "@/storage/schema.sql"

export const AutomationDefinitionTable = sqliteTable(
"automation_definition",
{
id: text().primaryKey().$type<Automation.Definition["id"]>(),
project_id: text()
.$type<ProjectID>()
.notNull()
.references(() => ProjectTable.id, { onDelete: "cascade" }),
owner_directory: text().notNull(),
time_created: integer().notNull(),
time_updated: integer().notNull(),
data: text({ mode: "json" }).notNull().$type<Automation.Definition>(),
},
(table) => [
index("automation_definition_project_owner_updated_idx").on(table.project_id, table.owner_directory, table.time_updated, table.id),
],
)

export const AutomationRunTable = sqliteTable(
"automation_run",
{
id: text().primaryKey().$type<Automation.Run["id"]>(),
automation_id: text()
.notNull()
.references(() => AutomationDefinitionTable.id, { onDelete: "cascade" }),
project_id: text()
.$type<ProjectID>()
.notNull()
.references(() => ProjectTable.id, { onDelete: "cascade" }),
owner_directory: text().notNull(),
triggered_at: integer().notNull(),
data: text({ mode: "json" }).notNull().$type<Automation.Run>(),
...Timestamps,
},
(table) => [
index("automation_run_automation_triggered_idx").on(table.automation_id, table.triggered_at, table.id),
index("automation_run_project_owner_idx").on(table.project_id, table.owner_directory),
],
)
Loading