From 19a41ab29778274a4f20ca8cf663d080abaf6ae1 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 27 Jan 2026 17:43:20 -0500 Subject: [PATCH] sync --- .../migration.sql | 5 +- .../snapshot.json | 138 ++++++++++++------ packages/opencode/src/session/session.sql.ts | 6 +- packages/opencode/src/session/todo.ts | 3 - .../opencode/src/storage/json-migration.ts | 5 +- .../test/storage/json-migration.test.ts | 43 +++++- 6 files changed, 143 insertions(+), 57 deletions(-) rename packages/opencode/migration/{20260127173238_melted_union_jack => 20260127222353_familiar_lady_ursula}/migration.sql (95%) rename packages/opencode/migration/{20260127173238_melted_union_jack => 20260127222353_familiar_lady_ursula}/snapshot.json (90%) diff --git a/packages/opencode/migration/20260127173238_melted_union_jack/migration.sql b/packages/opencode/migration/20260127222353_familiar_lady_ursula/migration.sql similarity index 95% rename from packages/opencode/migration/20260127173238_melted_union_jack/migration.sql rename to packages/opencode/migration/20260127222353_familiar_lady_ursula/migration.sql index db59eb0213..775c1a1173 100644 --- a/packages/opencode/migration/20260127173238_melted_union_jack/migration.sql +++ b/packages/opencode/migration/20260127222353_familiar_lady_ursula/migration.sql @@ -62,14 +62,13 @@ CREATE TABLE `session` ( --> statement-breakpoint CREATE TABLE `todo` ( `session_id` text NOT NULL, - `id` text NOT NULL, `content` text NOT NULL, `status` text NOT NULL, `priority` text NOT NULL, `position` integer NOT NULL, `time_created` integer NOT NULL, `time_updated` integer NOT NULL, - CONSTRAINT `todo_pk` PRIMARY KEY(`session_id`, `id`), + CONSTRAINT `todo_pk` PRIMARY KEY(`session_id`, `position`), CONSTRAINT `fk_todo_session_id_session_id_fk` FOREIGN KEY (`session_id`) REFERENCES `session`(`id`) ON DELETE CASCADE ); --> statement-breakpoint @@ -88,4 +87,4 @@ CREATE INDEX `part_message_idx` ON `part` (`message_id`);--> statement-breakpoin CREATE INDEX `part_session_idx` ON `part` (`session_id`);--> statement-breakpoint CREATE INDEX `session_project_idx` ON `session` (`project_id`);--> statement-breakpoint CREATE INDEX `session_parent_idx` ON `session` (`parent_id`);--> statement-breakpoint -CREATE INDEX `todo_session_idx` ON `todo` (`session_id`); +CREATE INDEX `todo_session_idx` ON `todo` (`session_id`); \ No newline at end of file diff --git a/packages/opencode/migration/20260127173238_melted_union_jack/snapshot.json b/packages/opencode/migration/20260127222353_familiar_lady_ursula/snapshot.json similarity index 90% rename from packages/opencode/migration/20260127173238_melted_union_jack/snapshot.json rename to packages/opencode/migration/20260127222353_familiar_lady_ursula/snapshot.json index 63943f49d3..1e297d3f8a 100644 --- a/packages/opencode/migration/20260127173238_melted_union_jack/snapshot.json +++ b/packages/opencode/migration/20260127222353_familiar_lady_ursula/snapshot.json @@ -1,7 +1,7 @@ { "version": "7", "dialect": "sqlite", - "id": "0e365b40-39c4-447f-9729-9714d865d8ff", + "id": "068758ed-a97a-46f6-8a59-6c639ae7c20c", "prevIds": [ "00000000-0000-0000-0000-000000000000" ], @@ -160,7 +160,17 @@ "autoincrement": false, "default": null, "generated": null, - "name": "created_at", + "name": "time_created", + "entityType": "columns", + "table": "message" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", "entityType": "columns", "table": "message" }, @@ -204,6 +214,26 @@ "entityType": "columns", "table": "part" }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "part" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "part" + }, { "type": "text", "notNull": true, @@ -224,6 +254,26 @@ "entityType": "columns", "table": "permission" }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "permission" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "permission" + }, { "type": "text", "notNull": true, @@ -360,37 +410,7 @@ "autoincrement": false, "default": null, "generated": null, - "name": "revert_message_id", - "entityType": "columns", - "table": "session" - }, - { - "type": "text", - "notNull": false, - "autoincrement": false, - "default": null, - "generated": null, - "name": "revert_part_id", - "entityType": "columns", - "table": "session" - }, - { - "type": "text", - "notNull": false, - "autoincrement": false, - "default": null, - "generated": null, - "name": "revert_snapshot", - "entityType": "columns", - "table": "session" - }, - { - "type": "text", - "notNull": false, - "autoincrement": false, - "default": null, - "generated": null, - "name": "revert_diff", + "name": "revert", "entityType": "columns", "table": "session" }, @@ -454,16 +474,6 @@ "entityType": "columns", "table": "todo" }, - { - "type": "text", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "id", - "entityType": "columns", - "table": "todo" - }, { "type": "text", "notNull": true, @@ -504,6 +514,26 @@ "entityType": "columns", "table": "todo" }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "todo" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "todo" + }, { "type": "text", "notNull": false, @@ -544,6 +574,26 @@ "entityType": "columns", "table": "session_share" }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_created", + "entityType": "columns", + "table": "session_share" + }, + { + "type": "integer", + "notNull": true, + "autoincrement": false, + "default": null, + "generated": null, + "name": "time_updated", + "entityType": "columns", + "table": "session_share" + }, { "columns": [ "session_id" @@ -637,7 +687,7 @@ { "columns": [ "session_id", - "id" + "position" ], "nameExplicit": false, "name": "todo_pk", diff --git a/packages/opencode/src/session/session.sql.ts b/packages/opencode/src/session/session.sql.ts index ea7c1e32a3..9c5c72c4c5 100644 --- a/packages/opencode/src/session/session.sql.ts +++ b/packages/opencode/src/session/session.sql.ts @@ -67,14 +67,16 @@ export const TodoTable = sqliteTable( session_id: text() .notNull() .references(() => SessionTable.id, { onDelete: "cascade" }), - id: text().notNull(), content: text().notNull(), status: text().notNull(), priority: text().notNull(), position: integer().notNull(), ...Timestamps, }, - (table) => [primaryKey({ columns: [table.session_id, table.id] }), index("todo_session_idx").on(table.session_id)], + (table) => [ + primaryKey({ columns: [table.session_id, table.position] }), + index("todo_session_idx").on(table.session_id), + ], ) export const PermissionTable = sqliteTable("permission", { diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts index 6ef7cbaaf5..ec2bcdda3c 100644 --- a/packages/opencode/src/session/todo.ts +++ b/packages/opencode/src/session/todo.ts @@ -10,7 +10,6 @@ export namespace Todo { content: z.string().describe("Brief description of the task"), status: z.string().describe("Current status of the task: pending, in_progress, completed, cancelled"), priority: z.string().describe("Priority level of the task: high, medium, low"), - id: z.string().describe("Unique identifier for the todo item"), }) .meta({ ref: "Todo" }) export type Info = z.infer @@ -33,7 +32,6 @@ export namespace Todo { .values( input.todos.map((todo, position) => ({ session_id: input.sessionID, - id: todo.id, content: todo.content, status: todo.status, priority: todo.priority, @@ -50,7 +48,6 @@ export namespace Todo { db.select().from(TodoTable).where(eq(TodoTable.session_id, sessionID)).orderBy(asc(TodoTable.position)).all(), ) return rows.map((row) => ({ - id: row.id, content: row.content, status: row.status, priority: row.priority, diff --git a/packages/opencode/src/storage/json-migration.ts b/packages/opencode/src/storage/json-migration.ts index c1236a0f76..0debe2e2e9 100644 --- a/packages/opencode/src/storage/json-migration.ts +++ b/packages/opencode/src/storage/json-migration.ts @@ -235,14 +235,15 @@ export namespace JsonMigration { } for (let position = 0; position < data.length; position++) { const todo = data[position] - if (!todo?.id || !todo?.content || !todo?.status || !todo?.priority) continue + if (!todo?.content || !todo?.status || !todo?.priority) continue values.push({ session_id: sessionID, - id: todo.id, content: todo.content, status: todo.status, priority: todo.priority, position, + time_created: Date.now(), + time_updated: Date.now(), }) } } diff --git a/packages/opencode/test/storage/json-migration.test.ts b/packages/opencode/test/storage/json-migration.test.ts index 09578ebe8c..f9be0d8041 100644 --- a/packages/opencode/test/storage/json-migration.test.ts +++ b/packages/opencode/test/storage/json-migration.test.ts @@ -282,17 +282,54 @@ describe("JSON to SQLite migration", () => { expect(stats?.todos).toBe(2) const db = drizzle({ client: sqlite }) - const todos = db.select().from(TodoTable).all() + const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all() expect(todos.length).toBe(2) - expect(todos[0].id).toBe("todo_1") expect(todos[0].content).toBe("First todo") expect(todos[0].status).toBe("pending") expect(todos[0].priority).toBe("high") expect(todos[0].position).toBe(0) - expect(todos[1].id).toBe("todo_2") + expect(todos[1].content).toBe("Second todo") expect(todos[1].position).toBe(1) }) + test("todos are ordered by position", async () => { + await Bun.write( + path.join(storageDir, "project", "proj_test123abc.json"), + JSON.stringify({ + id: "proj_test123abc", + worktree: "/", + time: { created: Date.now(), updated: Date.now() }, + sandboxes: [], + }), + ) + await Bun.write( + path.join(storageDir, "session", "proj_test123abc", "ses_test456def.json"), + JSON.stringify({ ...fixtures.session }), + ) + + await Bun.write( + path.join(storageDir, "todo", "ses_test456def.json"), + JSON.stringify([ + { content: "Third", status: "pending", priority: "low" }, + { content: "First", status: "pending", priority: "high" }, + { content: "Second", status: "in_progress", priority: "medium" }, + ]), + ) + + await JsonMigration.run(sqlite) + + const db = drizzle({ client: sqlite }) + const todos = db.select().from(TodoTable).orderBy(TodoTable.position).all() + + expect(todos.length).toBe(3) + expect(todos[0].content).toBe("Third") + expect(todos[0].position).toBe(0) + expect(todos[1].content).toBe("First") + expect(todos[1].position).toBe(1) + expect(todos[2].content).toBe("Second") + expect(todos[2].position).toBe(2) + }) + test("migrates permissions", async () => { // First create the project await Bun.write(