From f95f1296a321c599739f0796ec64b3a6094a5c50 Mon Sep 17 00:00:00 2001 From: Dean Stratakos <29683763+dastratakos@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:10:05 +0000 Subject: [PATCH 1/3] feat(service,features,database): keep each member's read state on Inbox items An inbox item now carries `unread` for the member reading it, kept per member and item in `inbox_item_read`. An item is unread while it changed after the last change the member read through, or while they marked it unread. A member's own answer or message marks it read for them in the same write. `PUT`/`DELETE /api/inbox/:id/read` mark one item read or unread, and `PUT /api/inbox/read` marks every item the member's Inbox lists read, optionally in one workspace. The held reads' cursors digest the reader's unread state, so a marker moving wakes that member's reads. Items that stood before this ships read as read: the migration adds `inbox_item.read_through` with a `now()` default kept in the catalog, which stamps every standing row without rewriting it, and drops the default, so items posted after it start unread. No backfill. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com> --- apps/web/server/api-rewrites.json | 8 + apps/web/server/function-rewrites.ts | 12 +- apps/web/server/routes/inbox/read.ts | 9 + .../tests/inbox-item-read-migration.test.ts | 104 + .../migration.sql | 17 + .../snapshot.json | 13557 ++++++++++++++++ packages/database/package.json | 1 + .../database/src/schemas/inbox-item-read.ts | 41 + packages/database/src/schemas/inbox.ts | 11 + packages/database/src/schemas/index.ts | 1 + ...t-inbox-wire-accountInboxAnswerSchema.json | 6 + ...nt-inbox-wire-accountInboxEntrySchema.json | 3 + ...inbox-wire-accountTasklessEntrySchema.json | 3 + ...dingAgentAccountInboxAnswerViewSchema.json | 6 + ...view-codingAgentInboxAnswerViewSchema.json | 3 + ...ew-codingAgentInboxAnsweredViewSchema.json | 3 + ...ew-codingAgentInboxMessagedViewSchema.json | 3 + ...iew-codingAgentInboxReadAllViewSchema.json | 41 + ...w-codingAgentInboxReadStateViewSchema.json | 46 + .../inbox-wire-inboxAnswerSchema.json | 3 + .../inbox-wire-inboxAnsweredSchema.json | 3 + .../inbox-wire-inboxItemSchema.json | 3 + .../inbox-wire-inboxMessagedSchema.json | 3 + .../inbox-wire-inboxReadAllRequestSchema.json | 12 + .../inbox-wire-inboxReadAllSchema.json | 13 + .../inbox-wire-inboxReadStateSchema.json | 18 + packages/features/src/account-inbox-wire.ts | 4 + .../features/src/coding-agent-client.test.ts | 43 + packages/features/src/coding-agent-client.ts | 53 + packages/features/src/coding-agent-view.ts | 15 + .../features/src/hosted-wire-schemas.test.ts | 5 + packages/features/src/inbox-wire.ts | 35 +- packages/features/src/service-paths.ts | 11 + .../src/agents/coder-host/chat-waiting.ts | 4 +- .../src/agents/coder-host/inbox-page.ts | 3 +- .../src/agents/coder-host/inbox-store.test.ts | 252 +- .../src/agents/coding-agents-app.test.ts | 68 + .../service/src/agents/coding-agents-app.ts | 62 +- packages/service/src/http/held-read.ts | 20 +- packages/service/src/inbox/inbox-store.ts | 327 +- vercel.json | 8 + 41 files changed, 14785 insertions(+), 55 deletions(-) create mode 100644 apps/web/server/routes/inbox/read.ts create mode 100644 apps/web/tests/inbox-item-read-migration.test.ts create mode 100644 packages/database/migrations/20261018153718_inbox_item_read/migration.sql create mode 100644 packages/database/migrations/20261018153718_inbox_item_read/snapshot.json create mode 100644 packages/database/src/schemas/inbox-item-read.ts create mode 100644 packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadAllViewSchema.json create mode 100644 packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadStateViewSchema.json create mode 100644 packages/features/fixtures/json-schema/inbox-wire-inboxReadAllRequestSchema.json create mode 100644 packages/features/fixtures/json-schema/inbox-wire-inboxReadAllSchema.json create mode 100644 packages/features/fixtures/json-schema/inbox-wire-inboxReadStateSchema.json diff --git a/apps/web/server/api-rewrites.json b/apps/web/server/api-rewrites.json index 00f48b7bda..e2037d688f 100644 --- a/apps/web/server/api-rewrites.json +++ b/apps/web/server/api-rewrites.json @@ -195,6 +195,14 @@ "src": "/api/inbox/([^/]+)/messages", "dest": "/api/default.js?route=inbox/messages&id=$1" }, + { + "src": "/api/inbox/([^/]+)/read", + "dest": "/api/default.js?route=inbox/read&id=$1" + }, + { + "src": "/api/inbox/read", + "dest": "/api/default.js?route=inbox/read" + }, { "src": "/api/inbox/([^/]+)", "dest": "/api/default.js?route=inbox/item&id=$1" diff --git a/apps/web/server/function-rewrites.ts b/apps/web/server/function-rewrites.ts index 5cfc1c9621..259c509499 100644 --- a/apps/web/server/function-rewrites.ts +++ b/apps/web/server/function-rewrites.ts @@ -23,11 +23,16 @@ export interface Rewrite { readonly dest: string; } -/** Rewrites that read a path segment into the route's query, so a route sees `?id=` as it was written to. */ +/** + * Rewrites that read a path segment into the route's query, so a route sees + * `?id=` as it was written to, and the few exact paths that must stand ahead + * of a segment rewrite whose pattern would otherwise take them, which carry + * no query of their own. + */ interface SegmentRewrite { readonly src: string; readonly route: string; - readonly query: string; + readonly query?: string; } const SEGMENT_REWRITES: readonly SegmentRewrite[] = [ @@ -160,6 +165,9 @@ const SEGMENT_REWRITES: readonly SegmentRewrite[] = [ query: "id=$1&attachment=$2", }, { src: "/api/inbox/([^/]+)/messages", route: "inbox/messages", query: "id=$1" }, + { src: "/api/inbox/([^/]+)/read", route: "inbox/read", query: "id=$1" }, + // Every item of the Inbox marked read, ahead of the one item's rewrite that would read `read` as an id. + { src: "/api/inbox/read", route: "inbox/read" }, { src: "/api/inbox/([^/]+)", route: "inbox/item", query: "id=$1" }, { src: "/api/workspaces/([^/]+)/photo", route: "workspaces/photo", query: "id=$1" }, { src: "/api/automations/([^/]+)/webhook", route: "automations/webhook", query: "id=$1" }, diff --git a/apps/web/server/routes/inbox/read.ts b/apps/web/server/routes/inbox/read.ts new file mode 100644 index 0000000000..e497446cd5 --- /dev/null +++ b/apps/web/server/routes/inbox/read.ts @@ -0,0 +1,9 @@ +import { deploymentEveOrigin } from "@luke/service/agents/brain-host/eve-origin"; +import { codingAgentsApp } from "@luke/service/agents/coding-agents-app"; +import { resolveHostedUserId } from "@luke/service/auth/bearer"; +import { routeFromHttpRouter } from "../../route-effect.js"; + +/** A member's own read state on the Inbox: one item marked read (PUT) or unread (DELETE), or, where the path names none, every item their Inbox lists marked read (PUT). The logic lives in `packages/service/src/agents/coding-agents-app.ts`; this file only hands it the deployment's real seams. */ +export default routeFromHttpRouter( + codingAgentsApp({ resolveUserId: resolveHostedUserId, eveOrigin: deploymentEveOrigin }), +); diff --git a/apps/web/tests/inbox-item-read-migration.test.ts b/apps/web/tests/inbox-item-read-migration.test.ts new file mode 100644 index 0000000000..302439947b --- /dev/null +++ b/apps/web/tests/inbox-item-read-migration.test.ts @@ -0,0 +1,104 @@ +import assert from "node:assert/strict"; +import { randomUUID } from "node:crypto"; +import { NodeServices } from "@effect/platform-node"; +import { it } from "@effect/vitest"; +import { MIGRATIONS_FOLDER, runWebMigrations } from "@luke/database/core/migrator"; +import { Database } from "@luke/database/core/query"; +import { createCodingAgent } from "@luke/database/models/coding-agent-store"; +import { user } from "@luke/database/schemas/auth"; +import { joinWorkspace, startTask, unmigratedPgliteSqlClient } from "@luke/database/testing"; +import { INBOX_RESPONSE } from "@luke/features/inbox-wire"; +import { postInboxItem, readInboxItem } from "@luke/service/inbox/inbox-store"; +import { Effect, Layer, Option, Result } from "effect"; +import { FileSystem } from "effect/FileSystem"; +import { Path } from "effect/Path"; +import * as SqlClient from "effect/sql/SqlClient"; + +/** + * inbox-item-read-migration.test.ts -- the migration that keeps a member's read state on an inbox item, over items that stood before it. + * + * Over a database migrated up to it, holding an item an agent posted: once + * it runs, that item reads as read for its starter and a teammate alike, + * with no marker of theirs written, while an item posted after it reads + * unread for both; and a second run changes nothing. Synthetic accounts + * throughout. + */ + +const MIGRATION = "20261018153718_inbox_item_read"; + +/** A migrations folder holding every migration named before this one, and none after. */ +const foldersBefore = Effect.gen(function* () { + const fileSystem = yield* FileSystem; + const path = yield* Path; + const folder = yield* fileSystem.makeTempDirectoryScoped({ prefix: "luke-before-inbox-read-" }); + const names = (yield* fileSystem.readDirectory(MIGRATIONS_FOLDER)).filter( + (name) => name.localeCompare(MIGRATION) < 0, + ); + for (const name of names) { + yield* fileSystem.copy(path.join(MIGRATIONS_FOLDER, name), path.join(folder, name)); + } + return folder; +}); + +const openUser = (id: string) => + Database.use((db) => db.insert(user).values({ id, name: id, email: `${id}@luke.test` })); + +it.effect( + "an item that stood before unread was kept reads as read for every member, and one posted after it as unread", + () => + Effect.scoped( + Effect.gen(function* () { + const sql = yield* SqlClient.SqlClient; + yield* runWebMigrations(yield* foldersBefore); + yield* openUser("dean"); + yield* openUser("charles"); + const task = yield* startTask("dean", { name: "Teammate invitations" }); + yield* joinWorkspace(task.workspaceId, "charles"); + const started = Option.getOrThrow( + yield* createCodingAgent("dean", { + taskId: task.id, + idempotencyKey: randomUUID(), + model: "anthropic/claude-opus-5.5", + effort: "high", + repository: "acme/relay", + planSnapshot: "# Teammate invitations\n", + prompt: null, + }), + ); + const standing = randomUUID(); + yield* sql`insert into inbox_item (id, user_id, task_id, organization_id, agent_id, key, revision, version, title, blocks, response, needs_reply, status, posted_at, updated_at) + values (${standing}, 'dean', ${task.id}, ${task.workspaceId}, ${started.agent.id}, 'branch-protection', 1, 4, 'Require a review on main', '[]'::jsonb, '{"type":"task"}'::jsonb, false, 'open', '2026-10-17T09:00:00Z', '2026-10-17T09:00:00Z')`; + + yield* runWebMigrations(); + yield* sql`delete from __drizzle_migrations where name = ${MIGRATION}`; + yield* runWebMigrations(); + + const posted = yield* postInboxItem( + { userId: "dean", taskId: task.id, agentId: started.agent.id }, + { + key: "invite-copy", + title: "What should it say?", + response: { type: INBOX_RESPONSE.TEXT }, + }, + ); + assert.ok(Result.isSuccess(posted)); + const unread = (reader: string, itemId: string) => + Effect.map( + readInboxItem(reader, itemId), + (found) => Option.getOrThrow(found).item.unread, + ); + assert.deepEqual( + [yield* unread("dean", standing), yield* unread("charles", standing)], + [false, false], + ); + assert.deepEqual( + [yield* unread("dean", posted.success.id), yield* unread("charles", posted.success.id)], + [true, true], + ); + const markers = yield* sql<{ + readonly count: number; + }>`select count(*)::int as count from inbox_item_read`; + assert.deepEqual(markers, [{ count: 0 }], "no marker was written for the items standing"); + }), + ).pipe(Effect.provide(Layer.provideMerge(unmigratedPgliteSqlClient, NodeServices.layer))), +); diff --git a/packages/database/migrations/20261018153718_inbox_item_read/migration.sql b/packages/database/migrations/20261018153718_inbox_item_read/migration.sql new file mode 100644 index 0000000000..1372fbb0d9 --- /dev/null +++ b/packages/database/migrations/20261018153718_inbox_item_read/migration.sql @@ -0,0 +1,17 @@ +CREATE TABLE IF NOT EXISTS "inbox_item_read" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(), + "item_id" uuid NOT NULL, + "user_id" text NOT NULL, + "read_through" timestamp with time zone, + "marked_unread" boolean DEFAULT false NOT NULL +); +--> statement-breakpoint +-- No backfill: `now()` is stable, so this default is evaluated once and kept in the catalog as the value of every row standing, with no row of the table rewritten. Every item that stands when unread ships reads as read through that instant, for every member, until it changes again. +ALTER TABLE "inbox_item" ADD COLUMN IF NOT EXISTS "read_through" timestamp with time zone DEFAULT now();--> statement-breakpoint +-- The default is dropped in the same transaction, so an item posted from here on holds null and reads unread until a member reads it (`inbox-store.ts`). The standing rows keep the value the catalog stamped them with. +ALTER TABLE "inbox_item" ALTER COLUMN "read_through" DROP DEFAULT;--> statement-breakpoint +CREATE UNIQUE INDEX IF NOT EXISTS "inbox_item_read_item_user" ON "inbox_item_read" ("item_id","user_id");--> statement-breakpoint +ALTER TABLE "inbox_item_read" DROP CONSTRAINT IF EXISTS "inbox_item_read_item_id_inbox_item_id_fkey";--> statement-breakpoint +ALTER TABLE "inbox_item_read" ADD CONSTRAINT "inbox_item_read_item_id_inbox_item_id_fkey" FOREIGN KEY ("item_id") REFERENCES "inbox_item"("id") ON DELETE CASCADE;--> statement-breakpoint +ALTER TABLE "inbox_item_read" DROP CONSTRAINT IF EXISTS "inbox_item_read_user_id_user_id_fkey";--> statement-breakpoint +ALTER TABLE "inbox_item_read" ADD CONSTRAINT "inbox_item_read_user_id_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE CASCADE; diff --git a/packages/database/migrations/20261018153718_inbox_item_read/snapshot.json b/packages/database/migrations/20261018153718_inbox_item_read/snapshot.json new file mode 100644 index 0000000000..eb20731a63 --- /dev/null +++ b/packages/database/migrations/20261018153718_inbox_item_read/snapshot.json @@ -0,0 +1,13557 @@ +{ + "version": "8", + "dialect": "postgres", + "id": "9667e949-3c09-4312-b9bd-055bfc81177d", + "prevIds": ["5ff07ae7-ab3e-4f29-bb10-1f12135bee1c"], + "ddl": [ + { + "isRlsEnabled": false, + "name": "account_provider_key", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "agent_pin", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "invitation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "jwks", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "member", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_access_token", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_client", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_client_assertion", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_client_resource", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_consent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_refresh_token", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "oauth_resource", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "organization", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "session", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "user", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "verification", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "automation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "automation_run", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_channel", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_member", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_message", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "chat_read", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "workspace_chat", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "coding_agent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "coding_agent_delegation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "conversation_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "admin_favorite", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_connect_intent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_install_intent", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "github_installation", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_item", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_item_read", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "inbox_message", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "integration_connection", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "issue", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "mac_command", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "mac_command_listener", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "personal_workspace", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_attachment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_comment", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_comment_thread", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_page_version", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "plan_revision", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account_plan_template_revision", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "account_preference", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "repository_pin", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "sandbox_terminal_lease", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "session_sandbox_cleanup", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "asks", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "conversations", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "messages", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "turns", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_board", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_pin", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_section", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "task_section_entry", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "hosted_usage", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_session_usage", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_avatar_sessions", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_sessions", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "voice_transcript_segments", + "entityType": "tables", + "schema": "public" + }, + { + "isRlsEnabled": false, + "name": "workspace_integration_connection", + "entityType": "tables", + "schema": "public" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "key_version", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sealed_data_key", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sealed_key", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "hint", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status_at", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "fast_access", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account_provider_key" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_id", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "agent_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id_token", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token_expires_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token_expires_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "password", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "account" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'pending'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "inviter_id", + "entityType": "columns", + "schema": "public", + "table": "invitation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "public_key", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "private_key", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "alg", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "crv", + "entityType": "columns", + "schema": "public", + "table": "jwks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'member'", + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "authorization_code_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "resources", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "requested_user_info_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revoked", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "confirmation", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_access_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_secret", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_discovery_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "disabled", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "skip_consent", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "enable_end_session", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "subject_type", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": "'{}'", + "generated": null, + "identity": null, + "name": "client_credentials_scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "uri", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "icon", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "contacts", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tos", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "policy", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "software_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "software_version", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "software_statement", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "redirect_uris", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "post_logout_redirect_uris", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "backchannel_logout_uri", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "backchannel_logout_session_required", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token_endpoint_auth_method", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "application_type", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "jwks", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "jwks_uri", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "grant_types", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "response_types", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "public", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "type", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "require_pkce", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "dpop_bound_access_tokens", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "oauth_client" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_assertion" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_assertion" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "resource_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "resources", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "requested_user_info_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_consent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reference_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "authorization_code_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "resources", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "requested_user_info_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revoked", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rotated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rotation_replay_response", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "rotation_replay_expires_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "auth_time", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "confirmation", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "identifier", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "access_token_ttl", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "refresh_token_ttl", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "signing_algorithm", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "signing_key_id", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "allowed_scopes", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "custom_claims", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "dpop_bound_access_tokens_required", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "disabled", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "policy_version", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "oauth_resource" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "slug", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "logo", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "organization" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "token", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ip_address", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_agent", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "active_organization_id", + "entityType": "columns", + "schema": "public", + "table": "session" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "email", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "email_verified", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_login_method", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": "'user'", + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "user" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "identifier", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "value", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "verification" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'personal'", + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "enabled", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "trigger_kind", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "trigger", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "action", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "guards", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "next_run_at", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "webhook_secret_hash", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "repositories", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'new-agent'", + "generated": null, + "identity": null, + "name": "target_kind", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "target_agent_id", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "archive_successful", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "automation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "automation_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dedupe_key", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "firing", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "payload", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reason", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "fired_at", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "settled_at", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "claimed_agent_id", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archive_settled_at", + "entityType": "columns", + "schema": "public", + "table": "automation_run" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message_id", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "chat_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dm_a_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "dm_b_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_by_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "chat_channel" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "handle", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ordinal", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "read_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "notice_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "notice_channel_id", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "joined_at", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "left_at", + "entityType": "columns", + "schema": "public", + "table": "chat_member" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "channel_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "touched_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "parent_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "author_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "blocks", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 1, + "default": "'{}'", + "generated": null, + "identity": null, + "name": "mentions", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_key", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "touched_at", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_key", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_revision", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_status", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer_key", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answered_by_member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "closed_reason", + "entityType": "columns", + "schema": "public", + "table": "chat_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "member_id", + "entityType": "columns", + "schema": "public", + "table": "chat_read" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "channel_id", + "entityType": "columns", + "schema": "public", + "table": "chat_read" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "read_seq", + "entityType": "columns", + "schema": "public", + "table": "chat_read" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "workspace_chat" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "next_seq", + "entityType": "columns", + "schema": "public", + "table": "workspace_chat" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "automation_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "automation_origin", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_from", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "effort", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'long'", + "generated": null, + "identity": null, + "name": "context_window", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "plan_snapshot", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "prompt", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "repositories", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "branch", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "start_branch", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "last_step", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "compacted_at", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "published", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_by", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "disabled_servers", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "mentioned_servers", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "author", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "idempotency_key", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "coding_agent" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "child_conversation_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "call_id", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "effort", + "entityType": "columns", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sha256", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "width", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "height", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "conversation_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "admin_id", + "entityType": "columns", + "schema": "public", + "table": "admin_favorite" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "admin_favorite" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_connect_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state_hash", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "code_verifier", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "expires_at", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_install_intent" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "installation_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_id", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_login", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "account_type", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "github_installation" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "key", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "version", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "blocks", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "response", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "needs_reply", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answer_key", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "answered_by", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "closed_reason", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "posted_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "settled_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "read_through", + "entityType": "columns", + "schema": "public", + "table": "inbox_item" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "item_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "message_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'image'", + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item_read" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "item_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item_read" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_item_read" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "read_through", + "entityType": "columns", + "schema": "public", + "table": "inbox_item_read" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "marked_unread", + "entityType": "columns", + "schema": "public", + "table": "inbox_item_read" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "item_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "author", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "text", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_key", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "inbox_message" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connect_subject", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connection_name", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "label", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state_issued_at", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connect_verifier", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connected_at", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "integration_connection" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "number", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "''", + "generated": null, + "identity": null, + "name": "description", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'backlog'", + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'none'", + "generated": null, + "identity": null, + "name": "priority", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "creator_id", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "issue" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "command", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "timeout_seconds", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "queued_at", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "claimed_at", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "result", + "entityType": "columns", + "schema": "public", + "table": "mac_command" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "mac_command_listener" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seen_at", + "entityType": "columns", + "schema": "public", + "table": "mac_command_listener" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "personal_workspace" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "personal_workspace" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "personal_workspace" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "content_type", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "byte_count", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "bytea", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "bytes", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "saved_at", + "entityType": "columns", + "schema": "public", + "table": "plan_attachment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "thread_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "words", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "asked_actor", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "asked_agent_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_key", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "edited_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "scope", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "quote", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "anchor_from", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "anchor_to", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "section", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "page_id", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "version", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "html", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "shown_by", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "at", + "entityType": "columns", + "schema": "public", + "table": "plan_page_version" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "agent_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "live_session_id", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "document", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "changes", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "at", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "restored_from", + "entityType": "columns", + "schema": "public", + "table": "plan_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "actor", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "document", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "changes", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "at", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "restored_from", + "entityType": "columns", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_model", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_effort", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "coding_agent_context_window", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "plan_template", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "experiments", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "account_preference" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "repository_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository", + "entityType": "columns", + "schema": "public", + "table": "repository_pin" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "repository_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "held_until", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tried_at", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "credential_at", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "credential_session", + "entityType": "columns", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "queued_at", + "entityType": "columns", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tried_at", + "entityType": "columns", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "origin", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "delivery_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "turn_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cancel_requested_at", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice_session_id", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ask_revision", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "told_seq", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end_told_at", + "entityType": "columns", + "schema": "public", + "table": "asks" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "kind", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "parent_conversation_id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "runtime_session_id", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "last_activity_at", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "deleted_at", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "1", + "generated": null, + "identity": null, + "name": "next_message_seq", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "journal_revision", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "label", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "true", + "generated": null, + "identity": null, + "name": "expects_completion", + "entityType": "columns", + "schema": "public", + "table": "conversations" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "turn_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "client_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "parts", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "metadata", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "finished_at", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "revision", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "placed_at", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender_user_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender_name", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender_model", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "sender_agent_id", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "taken_after_step", + "entityType": "columns", + "schema": "public", + "table": "messages" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "origin", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "reasoning_effort", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "prompt_hash", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "tool_set_hash", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 1, + "default": null, + "generated": null, + "identity": null, + "name": "response_ids", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "usage", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "eve_turn_id", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "queued_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "settled_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "failure_detail", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cancel_requested_at", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "cancel_request_key", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "boolean", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "false", + "generated": null, + "identity": null, + "name": "fast_refused", + "entityType": "columns", + "schema": "public", + "table": "turns" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "name", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "agent_edits", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "document", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "repository", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "linear_issue", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "archived_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "conversation_id", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "task" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "'[]'", + "generated": null, + "identity": null, + "name": "elements", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "applied_drawing", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "drawing", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "drawing_number", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "image", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "task_board" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "pinned_at", + "entityType": "columns", + "schema": "public", + "table": "task_pin" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "title", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "icon", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "created_at", + "entityType": "columns", + "schema": "public", + "table": "task_section" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "section_id", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "position", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "added_at", + "entityType": "columns", + "schema": "public", + "table": "task_section_entry" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "day", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "calls", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "double precision", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "0", + "generated": null, + "identity": null, + "name": "dictation_seconds", + "entityType": "columns", + "schema": "public", + "table": "hosted_usage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "double precision", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seconds", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "bigint", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "recorded_at", + "entityType": "columns", + "schema": "public", + "table": "voice_session_usage" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice_session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "persona_id", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "ended_at", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seconds", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end_reason", + "entityType": "columns", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "gen_random_uuid()", + "generated": null, + "identity": null, + "name": "id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "user_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "device_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "task_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "live_session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "delegation_mode", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "started_at", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "closed_at", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "close_reason", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "jsonb", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "usage", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "model", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "detached_at", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "attach_id", + "entityType": "columns", + "schema": "public", + "table": "voice_sessions" + }, + { + "type": "uuid", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "voice_session_id", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "seq", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "role", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "text", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "start_ms", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "integer", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "end_ms", + "entityType": "columns", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "organization_id", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "provider", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "status", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "state_issued_at", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connect_verifier", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "text", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connected_by_user_id", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": false, + "dimensions": 0, + "default": null, + "generated": null, + "identity": null, + "name": "connected_at", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "type": "timestamp with time zone", + "typeSchema": null, + "notNull": true, + "dimensions": 0, + "default": "now()", + "generated": null, + "identity": null, + "name": "updated_at", + "entityType": "columns", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "coding_agent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "agent_pin_agent", + "entityType": "indexes", + "schema": "public", + "table": "agent_pin" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "account_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "invitation_organizationId_idx", + "entityType": "indexes", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "email", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "invitation_email_idx", + "entityType": "indexes", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "member_organizationId_idx", + "entityType": "indexes", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "member_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_sessionId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "authorization_code_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_authorizationCodeId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "refresh_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthAccessToken_refreshId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClient_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClientResource_clientId_resourceId_uidx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClientResource_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "resource_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthClientResource_resourceId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthConsent_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthConsent_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_clientId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_sessionId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "authorization_code_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "oauthRefreshToken_authorizationCodeId_idx", + "entityType": "indexes", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "session_userId_idx", + "entityType": "indexes", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "identifier", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "verification_identifier_idx", + "entityType": "indexes", + "schema": "public", + "table": "verification" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_user_created", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "next_run_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"next_run_at\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_next_run", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "trigger_kind", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_trigger_task", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "scope", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_org_scope_created", + "entityType": "indexes", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "automation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "dedupe_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_run_dedupe", + "entityType": "indexes", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "automation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "fired_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "automation_run_automation_fired", + "entityType": "indexes", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "message_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_attachment_message", + "entityType": "indexes", + "schema": "public", + "table": "chat_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "name", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"name\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_organization_name", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "dm_a_member_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "dm_b_member_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" = 'dm'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_organization_dm", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" = 'plan'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_task", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_channel_organization_created", + "entityType": "indexes", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "handle", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" <> 'planner'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_organization_handle", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "kind", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "ordinal", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_organization_kind_ordinal", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"user_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_organization_user", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "agent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"agent_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_agent", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"task_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_member_task", + "entityType": "indexes", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_organization_seq", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "channel_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_channel_client_key", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "channel_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_channel_seq", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "parent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"parent_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_parent_seq", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "touched_seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_organization_touched", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "author_member_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "ask_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"ask_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_author_ask_key", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "ask_status", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"ask_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_message_organization_ask_status", + "entityType": "indexes", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "channel_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "chat_read_channel", + "entityType": "indexes", + "schema": "public", + "table": "chat_read" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "idempotency_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_user_idempotency", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_task_created", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_org_created", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "(\"started_from\"->>'agentId')", + "isExpression": true, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "coding_agent_started_from_agent", + "entityType": "indexes", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "sha256", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversation_attachment_conversation_sha256", + "entityType": "indexes", + "schema": "public", + "table": "conversation_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_connect_intent_user_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_connect_intent" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "github_installation_organization_id_idx", + "entityType": "indexes", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "agent_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_agent_key", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_task_updated", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_org_updated", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "status", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_user_status_updated", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_attachment_item", + "entityType": "indexes", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "message_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_attachment_message", + "entityType": "indexes", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_item_read_item_user", + "entityType": "indexes", + "schema": "public", + "table": "inbox_item_read" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_message_item_created", + "entityType": "indexes", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "item_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"client_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "inbox_message_client_key", + "entityType": "indexes", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "connection_name", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_user_name_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "provider", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "connect_subject", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_provider_subject_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "state", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_state_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "provider", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "integration_connection_user_provider_idx", + "entityType": "indexes", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "number", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "issue_org_number", + "entityType": "indexes", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "updated_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "issue_org_updated", + "entityType": "indexes", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "claimed_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "mac_command_waiting", + "entityType": "indexes", + "schema": "public", + "table": "mac_command" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_attachment_task", + "entityType": "indexes", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"saved_at\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_attachment_unsaved", + "entityType": "indexes", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "thread_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "seq", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_thread_seq", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_task", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_key", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"client_key\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_client_key", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_comment_thread_task_created", + "entityType": "indexes", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "plan_page_version_task", + "entityType": "indexes", + "schema": "public", + "table": "plan_page_version" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "tried_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "held_until", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "sandbox_terminal_lease_next", + "entityType": "indexes", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "tried_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "queued_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "session_sandbox_cleanup_next", + "entityType": "indexes", + "schema": "public", + "table": "session_sandbox_cleanup" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "client_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_conversation_client", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_by_user", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "delivery_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_conversation_delivery", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "voice_session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"voice_session_id\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "asks_by_voice_session", + "entityType": "indexes", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": "\"kind\" = 'main' and \"deleted_at\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversations_standing_main", + "entityType": "indexes", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "deleted_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"deleted_at\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversations_deleted_at", + "entityType": "indexes", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "kind", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "conversations_user_kind", + "entityType": "indexes", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "revision", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"revision\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "messages_conversation_revision", + "entityType": "indexes", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "turns_by_user", + "entityType": "indexes", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "conversation_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "queued_at", + "isExpression": false, + "asc": false, + "nullsFirst": true, + "opclass": null + }, + { + "value": "id", + "isExpression": false, + "asc": false, + "nullsFirst": true, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "turns_conversation_queued", + "entityType": "indexes", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "started_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"status\" = 'running'", + "with": "", + "method": "btree", + "concurrently": false, + "name": "turns_running_started", + "entityType": "indexes", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_user_created", + "entityType": "indexes", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "created_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_organization_created", + "entityType": "indexes", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_pin_task", + "entityType": "indexes", + "schema": "public", + "table": "task_pin" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_user", + "entityType": "indexes", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "organization_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_organization", + "entityType": "indexes", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "task_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_entry_task", + "entityType": "indexes", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "section_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "task_section_entry_section", + "entityType": "indexes", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "voice_session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"ended_at\" is null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "voice_avatar_sessions_open", + "entityType": "indexes", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "user_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + }, + { + "value": "live_session_id", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "voice_sessions_by_owner", + "entityType": "indexes", + "schema": "public", + "table": "voice_sessions" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "detached_at", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": false, + "where": "\"closed_at\" is null and \"detached_at\" is not null", + "with": "", + "method": "btree", + "concurrently": false, + "name": "voice_sessions_detached", + "entityType": "indexes", + "schema": "public", + "table": "voice_sessions" + }, + { + "nameExplicit": true, + "columns": [ + { + "value": "state", + "isExpression": false, + "asc": true, + "nullsFirst": false, + "opclass": null + } + ], + "isUnique": true, + "where": null, + "with": "", + "method": "btree", + "concurrently": false, + "name": "workspace_integration_connection_state_idx", + "entityType": "indexes", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_provider_key_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account_provider_key" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "agent_pin_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "agent_pin" + }, + { + "nameExplicit": false, + "columns": ["coding_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "agent_pin_coding_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "agent_pin" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "invitation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": false, + "columns": ["inviter_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "invitation_inviter_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "invitation" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "member_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "member_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "member" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_access_token_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["session_id"], + "schemaTo": "public", + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "oauth_access_token_session_id_session_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_access_token_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["refresh_id"], + "schemaTo": "public", + "tableTo": "oauth_refresh_token", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_access_token_refresh_id_oauth_refresh_token_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_access_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_client_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_client" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_client_resource_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": false, + "columns": ["resource_id"], + "schemaTo": "public", + "tableTo": "oauth_resource", + "columnsTo": ["identifier"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_client_resource_resource_id_oauth_resource_identifier_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_client_resource" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_consent_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_consent_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_consent" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "schemaTo": "public", + "tableTo": "oauth_client", + "columnsTo": ["client_id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_refresh_token_client_id_oauth_client_client_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": false, + "columns": ["session_id"], + "schemaTo": "public", + "tableTo": "session", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "oauth_refresh_token_session_id_session_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "oauth_refresh_token_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "oauth_refresh_token" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "session_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "session" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["target_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "automation_target_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation" + }, + { + "nameExplicit": false, + "columns": ["automation_id"], + "schemaTo": "public", + "tableTo": "automation", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_run_automation_id_automation_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "automation_run_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["coding_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "automation_run_coding_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["claimed_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "automation_run_claimed_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "automation_run" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_attachment_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_attachment" + }, + { + "nameExplicit": false, + "columns": ["message_id"], + "schemaTo": "public", + "tableTo": "chat_message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_attachment_message_id_chat_message_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_attachment" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["dm_a_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_dm_a_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["dm_b_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_channel_dm_b_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["created_by_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_channel_created_by_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_channel" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_member_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_member_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_member_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_member_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["notice_channel_id"], + "schemaTo": "public", + "tableTo": "chat_channel", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_member_notice_channel_id_chat_channel_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_member" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_message_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["channel_id"], + "schemaTo": "public", + "tableTo": "chat_channel", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_message_channel_id_chat_channel_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["parent_id"], + "schemaTo": "public", + "tableTo": "chat_message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_message_parent_id_chat_message_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["author_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_message_author_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["answered_by_member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "chat_message_answered_by_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_message" + }, + { + "nameExplicit": false, + "columns": ["member_id"], + "schemaTo": "public", + "tableTo": "chat_member", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_read_member_id_chat_member_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_read" + }, + { + "nameExplicit": false, + "columns": ["channel_id"], + "schemaTo": "public", + "tableTo": "chat_channel", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "chat_read_channel_id_chat_channel_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "chat_read" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "workspace_chat_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "workspace_chat" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["automation_id"], + "schemaTo": "public", + "tableTo": "automation", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "coding_agent_automation_id_automation_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "coding_agent" + }, + { + "nameExplicit": true, + "columns": ["child_conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "coding_agent_delegation_child_conversation_id_conversations_id_", + "entityType": "fks", + "schema": "public", + "table": "coding_agent_delegation" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversation_attachment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "conversation_attachment" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversation_attachment_conversation_id_conversations_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "conversation_attachment" + }, + { + "nameExplicit": false, + "columns": ["admin_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "admin_favorite_admin_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "admin_favorite" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "admin_favorite_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "admin_favorite" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_connect_intent_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_connect_intent" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_install_intent_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_install_intent" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_install_intent_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_install_intent" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "github_installation_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "github_installation" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_agent_id_coding_agent_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["answered_by"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "inbox_item_answered_by_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_item" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["item_id"], + "schemaTo": "public", + "tableTo": "inbox_item", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_item_id_inbox_item_id_fk", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["message_id"], + "schemaTo": "public", + "tableTo": "inbox_message", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_attachment_message_id_inbox_message_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "nameExplicit": false, + "columns": ["item_id"], + "schemaTo": "public", + "tableTo": "inbox_item", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_read_item_id_inbox_item_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_item_read" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_item_read_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_item_read" + }, + { + "nameExplicit": false, + "columns": ["item_id"], + "schemaTo": "public", + "tableTo": "inbox_item", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "inbox_message_item_id_inbox_item_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "inbox_message_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "inbox_message" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "integration_connection_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "integration_connection" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "issue_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": false, + "columns": ["creator_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "issue_creator_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "issue" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "mac_command_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "mac_command" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "mac_command_listener_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "mac_command_listener" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "personal_workspace_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "personal_workspace" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "personal_workspace_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "personal_workspace" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_attachment_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_attachment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_attachment" + }, + { + "nameExplicit": false, + "columns": ["thread_id"], + "schemaTo": "public", + "tableTo": "plan_comment_thread", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_comment_thread_id_plan_comment_thread_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_comment_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_comment_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_comment_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["asked_agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_comment_asked_agent_id_coding_agent_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_comment_thread_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_comment_thread" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_page_version_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "plan_page_version" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_revision_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "plan_revision" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_revision_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "plan_revision" + }, + { + "nameExplicit": false, + "columns": ["agent_id"], + "schemaTo": "public", + "tableTo": "coding_agent", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_revision_agent_id_coding_agent_id_fk", + "entityType": "fks", + "schema": "public", + "table": "plan_revision" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_plan_template_revision_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "account_preference_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "account_preference" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "repository_pin_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "repository_pin" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "sandbox_terminal_lease_conversation_id_conversations_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "sandbox_terminal_lease" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "asks_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "asks_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "asks" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversations_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": false, + "columns": ["parent_conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "conversations_parent_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "conversations" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "messages_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "messages_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["turn_id"], + "schemaTo": "public", + "tableTo": "turns", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "NO ACTION", + "name": "messages_turn_id_turns_id_fk", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["sender_user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "messages_sender_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "turns_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "turns_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "turns" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": false, + "columns": ["conversation_id"], + "schemaTo": "public", + "tableTo": "conversations", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "plan_conversation_id_conversations_id_fk", + "entityType": "fks", + "schema": "public", + "table": "task" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_board_plan_id_plan_id_fk", + "entityType": "fks", + "schema": "public", + "table": "task_board" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_pin_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_pin" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "plan_pin_plan_id_plan_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_pin" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_organization_id_organization_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_entry_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": false, + "columns": ["task_id"], + "schemaTo": "public", + "tableTo": "task", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_entry_task_id_task_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": false, + "columns": ["section_id"], + "schemaTo": "public", + "tableTo": "task_section", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "task_section_entry_section_id_task_section_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "task_section_entry" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "hosted_usage_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "hosted_usage" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_session_usage_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "voice_session_usage" + }, + { + "nameExplicit": false, + "columns": ["voice_session_id"], + "schemaTo": "public", + "tableTo": "voice_sessions", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_avatar_sessions_voice_session_id_voice_sessions_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_avatar_sessions_user_id_user_id_fkey", + "entityType": "fks", + "schema": "public", + "table": "voice_avatar_sessions" + }, + { + "nameExplicit": false, + "columns": ["user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_sessions_user_id_user_id_fk", + "entityType": "fks", + "schema": "public", + "table": "voice_sessions" + }, + { + "nameExplicit": false, + "columns": ["voice_session_id"], + "schemaTo": "public", + "tableTo": "voice_sessions", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "voice_transcript_segments_voice_session_id_voice_sessions_id_fk", + "entityType": "fks", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "schemaTo": "public", + "tableTo": "organization", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "CASCADE", + "name": "workspace_integration_connection_HMbDsJWkK6TV_fkey", + "entityType": "fks", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "nameExplicit": false, + "columns": ["connected_by_user_id"], + "schemaTo": "public", + "tableTo": "user", + "columnsTo": ["id"], + "onUpdate": "NO ACTION", + "onDelete": "SET NULL", + "name": "workspace_integration_connection_3ggWlPzIKenx_fkey", + "entityType": "fks", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "columns": ["user_id", "provider"], + "nameExplicit": false, + "name": "account_provider_key_user_id_provider_pk", + "entityType": "pks", + "schema": "public", + "table": "account_provider_key" + }, + { + "columns": ["user_id", "coding_agent_id"], + "nameExplicit": false, + "name": "agent_pin_pkey", + "entityType": "pks", + "schema": "public", + "table": "agent_pin" + }, + { + "columns": ["member_id", "channel_id"], + "nameExplicit": false, + "name": "chat_read_pkey", + "entityType": "pks", + "schema": "public", + "table": "chat_read" + }, + { + "columns": ["admin_id", "user_id"], + "nameExplicit": false, + "name": "admin_favorite_admin_id_user_id_pk", + "entityType": "pks", + "schema": "public", + "table": "admin_favorite" + }, + { + "columns": ["task_id", "seq"], + "nameExplicit": false, + "name": "plan_revision_plan_id_seq_pk", + "entityType": "pks", + "schema": "public", + "table": "plan_revision" + }, + { + "columns": ["user_id", "seq"], + "nameExplicit": false, + "name": "account_plan_template_revision_user_id_seq_pk", + "entityType": "pks", + "schema": "public", + "table": "account_plan_template_revision" + }, + { + "columns": ["user_id", "repository"], + "nameExplicit": false, + "name": "repository_pin_user_id_repository_pk", + "entityType": "pks", + "schema": "public", + "table": "repository_pin" + }, + { + "columns": ["user_id", "task_id"], + "nameExplicit": false, + "name": "plan_pin_pkey", + "entityType": "pks", + "schema": "public", + "table": "task_pin" + }, + { + "columns": ["user_id", "task_id"], + "nameExplicit": false, + "name": "task_section_entry_pkey", + "entityType": "pks", + "schema": "public", + "table": "task_section_entry" + }, + { + "columns": ["user_id", "day"], + "nameExplicit": false, + "name": "hosted_usage_user_id_day_pk", + "entityType": "pks", + "schema": "public", + "table": "hosted_usage" + }, + { + "columns": ["voice_session_id", "seq"], + "nameExplicit": false, + "name": "voice_transcript_segments_voice_session_id_seq_pk", + "entityType": "pks", + "schema": "public", + "table": "voice_transcript_segments" + }, + { + "columns": ["organization_id", "provider"], + "nameExplicit": false, + "name": "workspace_integration_connection_pkey", + "entityType": "pks", + "schema": "public", + "table": "workspace_integration_connection" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "account_pkey", + "schema": "public", + "table": "account", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "invitation_pkey", + "schema": "public", + "table": "invitation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "jwks_pkey", + "schema": "public", + "table": "jwks", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "member_pkey", + "schema": "public", + "table": "member", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_access_token_pkey", + "schema": "public", + "table": "oauth_access_token", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_client_pkey", + "schema": "public", + "table": "oauth_client", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_client_assertion_pkey", + "schema": "public", + "table": "oauth_client_assertion", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_client_resource_pkey", + "schema": "public", + "table": "oauth_client_resource", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_consent_pkey", + "schema": "public", + "table": "oauth_consent", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_refresh_token_pkey", + "schema": "public", + "table": "oauth_refresh_token", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "oauth_resource_pkey", + "schema": "public", + "table": "oauth_resource", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "organization_pkey", + "schema": "public", + "table": "organization", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "session_pkey", + "schema": "public", + "table": "session", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "user_pkey", + "schema": "public", + "table": "user", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "verification_pkey", + "schema": "public", + "table": "verification", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "automation_pkey", + "schema": "public", + "table": "automation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "automation_run_pkey", + "schema": "public", + "table": "automation_run", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_attachment_pkey", + "schema": "public", + "table": "chat_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_channel_pkey", + "schema": "public", + "table": "chat_channel", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_member_pkey", + "schema": "public", + "table": "chat_member", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "chat_message_pkey", + "schema": "public", + "table": "chat_message", + "entityType": "pks" + }, + { + "columns": ["organization_id"], + "nameExplicit": false, + "name": "workspace_chat_pkey", + "schema": "public", + "table": "workspace_chat", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "coding_agent_pkey", + "schema": "public", + "table": "coding_agent", + "entityType": "pks" + }, + { + "columns": ["child_conversation_id"], + "nameExplicit": false, + "name": "coding_agent_delegation_pkey", + "schema": "public", + "table": "coding_agent_delegation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "conversation_attachment_pkey", + "schema": "public", + "table": "conversation_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "github_connect_intent_pkey", + "schema": "public", + "table": "github_connect_intent", + "entityType": "pks" + }, + { + "columns": ["state_hash"], + "nameExplicit": false, + "name": "github_install_intent_pkey", + "schema": "public", + "table": "github_install_intent", + "entityType": "pks" + }, + { + "columns": ["installation_id"], + "nameExplicit": false, + "name": "github_installation_pkey", + "schema": "public", + "table": "github_installation", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_item_pkey", + "schema": "public", + "table": "inbox_item", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_attachment_pkey", + "schema": "public", + "table": "inbox_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_item_read_pkey", + "schema": "public", + "table": "inbox_item_read", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "inbox_message_pkey", + "schema": "public", + "table": "inbox_message", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "integration_connection_pkey", + "schema": "public", + "table": "integration_connection", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "issue_pkey", + "schema": "public", + "table": "issue", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "mac_command_pkey", + "schema": "public", + "table": "mac_command", + "entityType": "pks" + }, + { + "columns": ["user_id"], + "nameExplicit": false, + "name": "mac_command_listener_pkey", + "schema": "public", + "table": "mac_command_listener", + "entityType": "pks" + }, + { + "columns": ["user_id"], + "nameExplicit": false, + "name": "personal_workspace_pkey", + "schema": "public", + "table": "personal_workspace", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_attachment_pkey", + "schema": "public", + "table": "plan_attachment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_comment_pkey", + "schema": "public", + "table": "plan_comment", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_comment_thread_pkey", + "schema": "public", + "table": "plan_comment_thread", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_page_version_pkey", + "schema": "public", + "table": "plan_page_version", + "entityType": "pks" + }, + { + "columns": ["user_id"], + "nameExplicit": false, + "name": "account_preference_pkey", + "schema": "public", + "table": "account_preference", + "entityType": "pks" + }, + { + "columns": ["conversation_id"], + "nameExplicit": false, + "name": "sandbox_terminal_lease_pkey", + "schema": "public", + "table": "sandbox_terminal_lease", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "session_sandbox_cleanup_pkey", + "schema": "public", + "table": "session_sandbox_cleanup", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "asks_pkey", + "schema": "public", + "table": "asks", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "conversations_pkey", + "schema": "public", + "table": "conversations", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "messages_pkey", + "schema": "public", + "table": "messages", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "turns_pkey", + "schema": "public", + "table": "turns", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "plan_pkey", + "schema": "public", + "table": "task", + "entityType": "pks" + }, + { + "columns": ["task_id"], + "nameExplicit": false, + "name": "plan_board_pkey", + "schema": "public", + "table": "task_board", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "task_section_pkey", + "schema": "public", + "table": "task_section", + "entityType": "pks" + }, + { + "columns": ["session_id"], + "nameExplicit": false, + "name": "voice_session_usage_pkey", + "schema": "public", + "table": "voice_session_usage", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "voice_avatar_sessions_pkey", + "schema": "public", + "table": "voice_avatar_sessions", + "entityType": "pks" + }, + { + "columns": ["id"], + "nameExplicit": false, + "name": "voice_sessions_pkey", + "schema": "public", + "table": "voice_sessions", + "entityType": "pks" + }, + { + "nameExplicit": true, + "columns": ["page_id", "version"], + "nullsNotDistinct": false, + "name": "plan_page_version_page_version", + "entityType": "uniques", + "schema": "public", + "table": "plan_page_version" + }, + { + "nameExplicit": true, + "columns": ["conversation_id", "client_id"], + "nullsNotDistinct": false, + "name": "messages_conversation_client", + "entityType": "uniques", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": true, + "columns": ["conversation_id", "seq"], + "nullsNotDistinct": false, + "name": "messages_conversation_seq", + "entityType": "uniques", + "schema": "public", + "table": "messages" + }, + { + "nameExplicit": false, + "columns": ["token"], + "nullsNotDistinct": false, + "name": "oauth_access_token_token_unique", + "schema": "public", + "table": "oauth_access_token", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["client_id"], + "nullsNotDistinct": false, + "name": "oauth_client_client_id_unique", + "schema": "public", + "table": "oauth_client", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["token"], + "nullsNotDistinct": false, + "name": "oauth_refresh_token_token_unique", + "schema": "public", + "table": "oauth_refresh_token", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["identifier"], + "nullsNotDistinct": false, + "name": "oauth_resource_identifier_unique", + "schema": "public", + "table": "oauth_resource", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["slug"], + "nullsNotDistinct": false, + "name": "organization_slug_key", + "schema": "public", + "table": "organization", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["token"], + "nullsNotDistinct": false, + "name": "session_token_unique", + "schema": "public", + "table": "session", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["email"], + "nullsNotDistinct": false, + "name": "user_email_unique", + "schema": "public", + "table": "user", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["account_id"], + "nullsNotDistinct": false, + "name": "github_installation_account_id_key", + "schema": "public", + "table": "github_installation", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["organization_id"], + "nullsNotDistinct": false, + "name": "personal_workspace_organization_id_key", + "schema": "public", + "table": "personal_workspace", + "entityType": "uniques" + }, + { + "nameExplicit": false, + "columns": ["live_session_id"], + "nullsNotDistinct": false, + "name": "voice_sessions_live_session_id_unique", + "schema": "public", + "table": "voice_sessions", + "entityType": "uniques" + }, + { + "value": "octet_length(\"bytes\") <= 1500000", + "name": "chat_attachment_bytes_bound", + "entityType": "checks", + "schema": "public", + "table": "chat_attachment" + }, + { + "value": "(\"kind\" = 'dm') = (\"name\" is null)\n and (\"kind\" = 'dm') = (\"dm_a_member_id\" is not null and \"dm_b_member_id\" is not null)\n and (\"dm_a_member_id\" is null or \"dm_a_member_id\" < \"dm_b_member_id\")", + "name": "chat_channel_shape_of_kind", + "entityType": "checks", + "schema": "public", + "table": "chat_channel" + }, + { + "value": "(\"kind\" = 'human') = (\"user_id\" is not null)\n and (\"agent_id\" is null or \"kind\" = 'agent')\n and (\"task_id\" is null or \"kind\" = 'planner')", + "name": "chat_member_id_of_kind", + "entityType": "checks", + "schema": "public", + "table": "chat_member" + }, + { + "value": "(\"ask_key\" is null) = (\"ask\" is null)\n and (\"ask_key\" is null) = (\"ask_revision\" is null)\n and (\"ask_key\" is null) = (\"ask_status\" is null)", + "name": "chat_message_ask_whole", + "entityType": "checks", + "schema": "public", + "table": "chat_message" + }, + { + "value": "octet_length(\"bytes\") <= 4000000", + "name": "conversation_attachment_bytes_bound", + "entityType": "checks", + "schema": "public", + "table": "conversation_attachment" + }, + { + "value": "(\"kind\" = 'image' and octet_length(\"bytes\") <= 1500000 and \"name\" is null and \"position\" is null and \"message_id\" is null) or (\"kind\" = 'answer' and octet_length(\"bytes\") <= 3000000 and \"name\" is not null and \"position\" is not null and \"message_id\" is null) or (\"kind\" = 'message' and octet_length(\"bytes\") <= 3000000 and \"name\" is not null and \"position\" is not null and \"message_id\" is not null)", + "name": "inbox_attachment_kind_bound", + "entityType": "checks", + "schema": "public", + "table": "inbox_attachment" + }, + { + "value": "octet_length(\"bytes\") <= 1500000", + "name": "plan_attachment_bytes_bound", + "entityType": "checks", + "schema": "public", + "table": "plan_attachment" + } + ], + "renames": [] +} diff --git a/packages/database/package.json b/packages/database/package.json index 2e4a2bc892..88ba7bdb86 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -66,6 +66,7 @@ "./schemas/inbox": "./src/schemas/inbox.js", "./schemas/conversation-attachment": "./src/schemas/conversation-attachment.js", "./schemas/inbox-attachment": "./src/schemas/inbox-attachment.js", + "./schemas/inbox-item-read": "./src/schemas/inbox-item-read.js", "./schemas/inbox-message": "./src/schemas/inbox-message.js", "./schemas/integration": "./src/schemas/integration.js", "./schemas/issue": "./src/schemas/issue.js", diff --git a/packages/database/src/schemas/inbox-item-read.ts b/packages/database/src/schemas/inbox-item-read.ts new file mode 100644 index 0000000000..d2bcb4a142 --- /dev/null +++ b/packages/database/src/schemas/inbox-item-read.ts @@ -0,0 +1,41 @@ +import { boolean, pgTable, text, uniqueIndex, uuid } from "drizzle-orm/pg-core"; +import { timestamptz } from "./_helpers.js"; +import { user } from "./auth.js"; +import { inboxItem } from "./inbox.js"; + +/** + * inbox-item-read.ts -- one member's read marker on one inbox item: how far they have read it, and whether they marked it unread. + * + * An item is unread for a member while it changed after the last change + * they read through, or while they marked it unread and have not read it + * since. Every member of the item's workspace keeps a marker of their own, + * so one member reading an item, answering it, or marking it unread never + * moves another's. A member with no marker reads the item by its own + * `read_through` (`inbox.ts`): read through the instant unread was first + * kept on an item that stood before it, and unread on one posted since. The + * marker goes with its item and with its member's account. + */ +export const inboxItemRead = pgTable( + "inbox_item_read", + { + id: uuid("id").primaryKey().defaultRandom(), + itemId: uuid("item_id") + .notNull() + .references(() => inboxItem.id, { onDelete: "cascade" }), + userId: text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + /** + * The item's last change the member has read through, its `updated_at` + * as it stood when they opened it, answered it, or wrote on its thread; + * null where they marked it unread before ever reading it. + */ + readThrough: timestamptz("read_through"), + /** Whether the member marked the item unread and has not read it since; any change leaves it standing. */ + markedUnread: boolean("marked_unread").notNull().default(false), + }, + (table) => [ + // One marker per member per item, which every read of an item's unread state looks up. + uniqueIndex("inbox_item_read_item_user").on(table.itemId, table.userId), + ], +); diff --git a/packages/database/src/schemas/inbox.ts b/packages/database/src/schemas/inbox.ts index c82e4a293e..9009f7612c 100644 --- a/packages/database/src/schemas/inbox.ts +++ b/packages/database/src/schemas/inbox.ts @@ -88,6 +88,17 @@ export const inboxItem = pgTable( settledAt: timestamptz("settled_at"), /** When the item last changed, by the agent, an answer, or a message on its thread. */ updatedAt: timestamptz("updated_at").notNull(), + /** + * The instant every member without a read marker of their own + * (`inbox-item-read.ts`) has read the item through: the instant unread + * was first kept, on an item that stood before it, so no item that stood + * then reads unread until it changes again; null on an item posted + * since, whose every change is unread until read. The migration that + * added it stamped the standing rows through the column's default, in + * the catalog rather than by a write of each row, and then dropped the + * default. + */ + readThrough: timestamptz("read_through"), }, (table) => [ // One item per key per agent: a post under a key it used is that item's write. diff --git a/packages/database/src/schemas/index.ts b/packages/database/src/schemas/index.ts index 16744e4562..6faf418bea 100644 --- a/packages/database/src/schemas/index.ts +++ b/packages/database/src/schemas/index.ts @@ -13,6 +13,7 @@ export * from "./github-install-intent.js"; export * from "./github-installation.js"; export * from "./inbox.js"; export * from "./inbox-attachment.js"; +export * from "./inbox-item-read.js"; export * from "./inbox-message.js"; export * from "./integration.js"; export * from "./issue.js"; diff --git a/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxAnswerSchema.json b/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxAnswerSchema.json index cd5424279a..853a90c271 100644 --- a/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxAnswerSchema.json +++ b/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxAnswerSchema.json @@ -51,6 +51,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ @@ -167,6 +170,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxEntrySchema.json b/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxEntrySchema.json index b5096b7af3..2739b1ff40 100644 --- a/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxEntrySchema.json +++ b/packages/features/fixtures/json-schema/account-inbox-wire-accountInboxEntrySchema.json @@ -46,6 +46,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/account-inbox-wire-accountTasklessEntrySchema.json b/packages/features/fixtures/json-schema/account-inbox-wire-accountTasklessEntrySchema.json index 83ad29a2b1..ad188de7a0 100644 --- a/packages/features/fixtures/json-schema/account-inbox-wire-accountTasklessEntrySchema.json +++ b/packages/features/fixtures/json-schema/account-inbox-wire-accountTasklessEntrySchema.json @@ -69,6 +69,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentAccountInboxAnswerViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentAccountInboxAnswerViewSchema.json index dfed1f5b24..7f001adf6e 100644 --- a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentAccountInboxAnswerViewSchema.json +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentAccountInboxAnswerViewSchema.json @@ -53,6 +53,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ @@ -169,6 +172,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json index 5b9e2775f4..4f32bde731 100644 --- a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnswerViewSchema.json @@ -573,6 +573,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json index 8133278e17..a91549e994 100644 --- a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxAnsweredViewSchema.json @@ -571,6 +571,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json index 03025a4038..16b82a79d2 100644 --- a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxMessagedViewSchema.json @@ -571,6 +571,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadAllViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadAllViewSchema.json new file mode 100644 index 0000000000..a440f93c39 --- /dev/null +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadAllViewSchema.json @@ -0,0 +1,41 @@ +{ + "anyOf": [ + { + "type": "object", + "properties": { + "marked": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "marked" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "failure": { + "type": "string", + "enum": [ + "unanswered", + "not-found", + "no-repository", + "repository-not-reachable", + "github-unanswered", + "invalid-choice", + "message-too-long", + "agent-not-ready", + "agent-retired", + "plan-archived" + ] + } + }, + "required": [ + "failure" + ], + "additionalProperties": false + } + ] +} diff --git a/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadStateViewSchema.json b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadStateViewSchema.json new file mode 100644 index 0000000000..6151a87d93 --- /dev/null +++ b/packages/features/fixtures/json-schema/coding-agent-view-codingAgentInboxReadStateViewSchema.json @@ -0,0 +1,46 @@ +{ + "anyOf": [ + { + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "unread": { + "type": "boolean" + } + }, + "required": [ + "id", + "unread" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "failure": { + "type": "string", + "enum": [ + "unanswered", + "not-found", + "no-repository", + "repository-not-reachable", + "github-unanswered", + "invalid-choice", + "message-too-long", + "agent-not-ready", + "agent-retired", + "plan-archived" + ] + } + }, + "required": [ + "failure" + ], + "additionalProperties": false + } + ] +} diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json index c7b20875c6..c3aede587c 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxAnswerSchema.json @@ -571,6 +571,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json index 87b7d2cdcc..8cebc5fa5e 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxAnsweredSchema.json @@ -569,6 +569,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json index ae05815cae..40fb551529 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxItemSchema.json @@ -566,6 +566,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json index 9395351016..28467c8ac2 100644 --- a/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxMessagedSchema.json @@ -569,6 +569,9 @@ "updatedAt": { "type": "number", "minimum": 0 + }, + "unread": { + "type": "boolean" } }, "required": [ diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxReadAllRequestSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxReadAllRequestSchema.json new file mode 100644 index 0000000000..d651bf2e98 --- /dev/null +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxReadAllRequestSchema.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "workspaceId": { + "type": "string", + "minLength": 1, + "maxLength": 200 + } + }, + "required": [], + "additionalProperties": false +} diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxReadAllSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxReadAllSchema.json new file mode 100644 index 0000000000..2c25aa49a3 --- /dev/null +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxReadAllSchema.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "properties": { + "marked": { + "type": "number", + "minimum": 0 + } + }, + "required": [ + "marked" + ], + "additionalProperties": false +} diff --git a/packages/features/fixtures/json-schema/inbox-wire-inboxReadStateSchema.json b/packages/features/fixtures/json-schema/inbox-wire-inboxReadStateSchema.json new file mode 100644 index 0000000000..b69b7a5ef9 --- /dev/null +++ b/packages/features/fixtures/json-schema/inbox-wire-inboxReadStateSchema.json @@ -0,0 +1,18 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "string", + "minLength": 1, + "maxLength": 36 + }, + "unread": { + "type": "boolean" + } + }, + "required": [ + "id", + "unread" + ], + "additionalProperties": false +} diff --git a/packages/features/src/account-inbox-wire.ts b/packages/features/src/account-inbox-wire.ts index 016e04d129..9c6c08eeb9 100644 --- a/packages/features/src/account-inbox-wire.ts +++ b/packages/features/src/account-inbox-wire.ts @@ -66,6 +66,8 @@ export const accountInboxEntrySchema = EffectSchema.Struct({ postedAt: countedNumber, /** When the item last changed. */ updatedAt: countedNumber, + /** Whether the item is unread for the reader, as a task's read says it (`inbox-wire.ts`); absent from a service before it, which the desktop reads as read. */ + unread: EffectSchema.optionalKey(EffectSchema.Boolean), }); export type AccountInboxEntry = typeof accountInboxEntrySchema.Type; @@ -105,6 +107,8 @@ export const accountTasklessEntrySchema = EffectSchema.Struct({ revision: countedNumber, postedAt: countedNumber, updatedAt: countedNumber, + /** Whether the item is unread for the reader, as a task's item says it. */ + unread: EffectSchema.optionalKey(EffectSchema.Boolean), }); export type AccountTasklessEntry = typeof accountTasklessEntrySchema.Type; diff --git a/packages/features/src/coding-agent-client.test.ts b/packages/features/src/coding-agent-client.test.ts index 23d3586187..3a7dc54096 100644 --- a/packages/features/src/coding-agent-client.test.ts +++ b/packages/features/src/coding-agent-client.test.ts @@ -293,6 +293,49 @@ it.effect( }), ); +it.effect( + "marks an inbox item read with a PUT and unread with a DELETE at the item's read path, every item read with a PUT naming the workspace, reads an item the account cannot reach as not found, and sends nothing for a workspace that is no id", + () => + Effect.gen(function* () { + const itemId = "5d2b8f0e-1a3c-4e6f-9b7d-2c4e6a8b0d1f"; + const api = fakeCloudApi({ + [`PUT /api/inbox/${itemId}/read`]: { answer: () => ({ id: itemId, unread: false }) }, + [`DELETE /api/inbox/${itemId}/read`]: { answer: () => ({ id: itemId, unread: true }) }, + "PUT /api/inbox/read": { answer: () => ({ marked: 3 }) }, + }); + const refusing = fakeCloudApi({ + [`PUT /api/inbox/${itemId}/read`]: { + answer: () => ({ error: HOSTED_API_ERROR.NOT_FOUND }), + status: HTTP_STATUS.NOT_FOUND, + }, + }); + + const read = yield* Effect.provide(client().markInboxItemRead(itemId), api.layer); + const unread = yield* Effect.provide(client().markInboxItemUnread(itemId), api.layer); + const all = yield* Effect.provide( + client().markInboxRead({ workspaceId: WORKSPACE_ID }), + api.layer, + ); + const everywhere = yield* Effect.provide(client().markInboxRead(), api.layer); + const missing = yield* Effect.provide(client().markInboxItemRead(itemId), refusing.layer); + const malformed = yield* Effect.provide( + client().markInboxRead({ workspaceId: "" }), + api.layer, + ); + + assert.deepEqual(read, { id: itemId, unread: false }); + assert.deepEqual(unread, { id: itemId, unread: true }); + assert.deepEqual([all, everywhere], [{ marked: 3 }, { marked: 3 }]); + assert.deepEqual( + api.requests().map((sent) => sent.body), + [undefined, undefined, JSON.stringify({ workspaceId: WORKSPACE_ID }), "{}"], + ); + assert.deepEqual(missing, { failure: CODING_AGENT_CALL_FAILURE.NOT_FOUND }); + assert.deepEqual(malformed, { failure: CODING_AGENT_CALL_FAILURE.UNANSWERED }); + assert.equal(api.requests().length, 4, "nothing is sent for a workspace that is no id"); + }), +); + it.effect( "lists a workspace's agents by its id and the repository named, and a workspace the account is not in as not found", () => diff --git a/packages/features/src/coding-agent-client.ts b/packages/features/src/coding-agent-client.ts index 13ad59440e..c7a01a7d90 100644 --- a/packages/features/src/coding-agent-client.ts +++ b/packages/features/src/coding-agent-client.ts @@ -37,6 +37,8 @@ import { type CodingAgentInboxAnswerView, type CodingAgentInboxAttachmentView, type CodingAgentInboxMessagedView, + type CodingAgentInboxReadAllView, + type CodingAgentInboxReadStateView, type CodingAgentListAnswer, type CodingAgentMessagesAnswerView, type CodingAgentModelsAnswer, @@ -91,12 +93,16 @@ import { imageBodyOf } from "./image-body.js"; import { type InboxAnswerRequest, type InboxMessageRequest, + type InboxReadAllRequest, inboxAnsweredSchema, inboxAnswerRequestSchema, inboxAnswerSchema, inboxImageTypeSchema, inboxMessagedSchema, inboxMessageRequestSchema, + inboxReadAllRequestSchema, + inboxReadAllSchema, + inboxReadStateSchema, } from "./inbox-wire.js"; import { codingAgentDefaultAnswerSchema, @@ -139,6 +145,7 @@ import { HOSTED_SERVICE_PATH, inboxAttachmentPath, inboxItemPath, + inboxItemReadPath, inboxMessagesPath, planTemplateRestorePath, planTemplateRevisionPath, @@ -983,4 +990,50 @@ export class HostedCodingAgentClient { (answer) => readAnswer(answer, inboxMessagedSchema, INBOX_ANSWER_REFUSALS), ); } + + /** + * One item marked read for the account, as opening it does: its id and + * its read state; not found where the item is not one the account + * reaches. Marking an item read that is read already changes nothing, so + * the window may ask on every open. + */ + markInboxItemRead( + itemId: string, + ): Effect.Effect { + return Effect.flatMap( + this.#call.send({ method: HTTP_METHOD.PUT, path: inboxItemReadPath(itemId) }), + (answer) => readAnswer(answer, inboxReadStateSchema, ROW_REFUSALS), + ); + } + + /** One item marked unread for the account until it reads the item again: its id and its read state; not found where the item is not one the account reaches. */ + markInboxItemUnread( + itemId: string, + ): Effect.Effect { + return Effect.flatMap( + this.#call.send({ method: HTTP_METHOD.DELETE, path: inboxItemReadPath(itemId) }), + (answer) => readAnswer(answer, inboxReadStateSchema, ROW_REFUSALS), + ); + } + + /** + * Every item the account's Inbox lists marked read for it, open or + * settled, in the one workspace the request names or in all of its + * workspaces: how many were unread. It clears the unread dots alone; an + * item still waiting on an answer still waits. + */ + markInboxRead( + request: InboxReadAllRequest = {}, + ): Effect.Effect { + const admitted = Result.getOrUndefined(readEither(inboxReadAllRequestSchema)(request)); + if (admitted === undefined) return Effect.succeed(UNANSWERED); + return Effect.flatMap( + this.#call.send({ + method: HTTP_METHOD.PUT, + path: HOSTED_SERVICE_PATH.INBOX_READ, + body: JSON.stringify(admitted), + }), + (answer) => readAnswer(answer, inboxReadAllSchema, {}), + ); + } } diff --git a/packages/features/src/coding-agent-view.ts b/packages/features/src/coding-agent-view.ts index ef2efdcc86..4e390120f3 100644 --- a/packages/features/src/coding-agent-view.ts +++ b/packages/features/src/coding-agent-view.ts @@ -28,6 +28,8 @@ import { inboxAnswerSchema, inboxMessagedSchema, inboxMessageRequestSchema, + inboxReadAllSchema, + inboxReadStateSchema, } from "./inbox-wire.js"; import { catalogModelSchema, modelChoiceSchema } from "./models-wire.js"; import { @@ -451,6 +453,19 @@ export const codingAgentInboxMessagedViewSchema = EffectSchema.Union([inboxMessa export type CodingAgentInboxMessagedView = typeof codingAgentInboxMessagedViewSchema.Type; +/** One item marked read or unread, as the window hears it: the item's id and its read state for the account, or why there is no answer. */ +export const codingAgentInboxReadStateViewSchema = EffectSchema.Union([ + inboxReadStateSchema, + failed, +]); + +export type CodingAgentInboxReadStateView = typeof codingAgentInboxReadStateViewSchema.Type; + +/** Every item of the Inbox marked read, as the window hears it: how many were unread, or why there is no answer. */ +export const codingAgentInboxReadAllViewSchema = EffectSchema.Union([inboxReadAllSchema, failed]); + +export type CodingAgentInboxReadAllView = typeof codingAgentInboxReadAllViewSchema.Type; + /** What waits across the account past a cursor, as main asks it: where it stands. */ export const codingAgentAccountInboxParamsSchema = EffectSchema.Struct({ after: EffectSchema.NonEmptyString, diff --git a/packages/features/src/hosted-wire-schemas.test.ts b/packages/features/src/hosted-wire-schemas.test.ts index d75ff861be..25df3d1bf3 100644 --- a/packages/features/src/hosted-wire-schemas.test.ts +++ b/packages/features/src/hosted-wire-schemas.test.ts @@ -175,6 +175,9 @@ const EFFECT_MODULE_SCHEMAS = { inboxAnsweredSchema: inboxWire.inboxAnsweredSchema, inboxMessageRequestSchema: inboxWire.inboxMessageRequestSchema, inboxMessagedSchema: inboxWire.inboxMessagedSchema, + inboxReadStateSchema: inboxWire.inboxReadStateSchema, + inboxReadAllRequestSchema: inboxWire.inboxReadAllRequestSchema, + inboxReadAllSchema: inboxWire.inboxReadAllSchema, } satisfies RecordedEffectJsonSchemas, "coding-agent-view": { codingAgentModelsAnswerSchema: codingAgentView.codingAgentModelsAnswerSchema, @@ -230,6 +233,8 @@ const EFFECT_MODULE_SCHEMAS = { codingAgentInboxAnsweredViewSchema: codingAgentView.codingAgentInboxAnsweredViewSchema, codingAgentInboxMessageParamsSchema: codingAgentView.codingAgentInboxMessageParamsSchema, codingAgentInboxMessagedViewSchema: codingAgentView.codingAgentInboxMessagedViewSchema, + codingAgentInboxReadStateViewSchema: codingAgentView.codingAgentInboxReadStateViewSchema, + codingAgentInboxReadAllViewSchema: codingAgentView.codingAgentInboxReadAllViewSchema, codingAgentAccountInboxParamsSchema: codingAgentView.codingAgentAccountInboxParamsSchema, codingAgentAccountInboxAnswerViewSchema: codingAgentView.codingAgentAccountInboxAnswerViewSchema, diff --git a/packages/features/src/inbox-wire.ts b/packages/features/src/inbox-wire.ts index 5bb322f11d..b5e667a005 100644 --- a/packages/features/src/inbox-wire.ts +++ b/packages/features/src/inbox-wire.ts @@ -9,7 +9,12 @@ import { } from "./coding-agent-wire.js"; import { githubRepositoryFullNameSchema } from "./github-repositories-wire.js"; import { countedNumber, memberRefSchema, wireUuidSchema } from "./service-wire.js"; -import { CODE_PATH_MAX_CHARS, codeLineSchema, commitShaSchema } from "./task-wire.js"; +import { + CODE_PATH_MAX_CHARS, + codeLineSchema, + commitShaSchema, + workspaceIdSchema, +} from "./task-wire.js"; /** * inbox-wire.ts -- the developer's inbox: what a task's coding agents need of the developer, posted by the agents and answered on the desktop. @@ -618,6 +623,14 @@ export const inboxItemSchema = EffectSchema.Struct({ settledAt: EffectSchema.optionalKey(countedNumber), /** When the item last changed, by the agent or the developer, a message on its thread included. */ updatedAt: countedNumber, + /** + * Whether the item is unread for the member reading it: it changed after + * the last change they read through, or they marked it unread and have + * not read it since. Their own answer or message leaves it read for them; + * another member's marker never moves it. Absent from a service before it, + * which the desktop reads as read. + */ + unread: EffectSchema.optionalKey(EffectSchema.Boolean), }); export type InboxItem = typeof inboxItemSchema.Type; @@ -676,6 +689,26 @@ export type InboxMessageRequest = typeof inboxMessageRequestSchema.Type; /** What a member's message comes back as: the item as it then stands, its thread with the message on it. */ export const inboxMessagedSchema = EffectSchema.Struct({ item: inboxItemSchema }); +/** One item's read state for the member who marked it, as marking it read or unread answers it. */ +export const inboxReadStateSchema = EffectSchema.Struct({ + id: wireUuidSchema, + unread: EffectSchema.Boolean, +}); + +/** + * Marking every item of the reader's Inbox read: every item it lists, in + * the one workspace named, or in every workspace of the account's where + * none is. + */ +export const inboxReadAllRequestSchema = EffectSchema.Struct({ + workspaceId: EffectSchema.optionalKey(workspaceIdSchema), +}); + +export type InboxReadAllRequest = typeof inboxReadAllRequestSchema.Type; + +/** What marking every item read answers: how many items it marked read that were unread. */ +export const inboxReadAllSchema = EffectSchema.Struct({ marked: countedNumber }); + /** How a member's message on an item's thread opens, in the message that hands it to the agent. */ export const INBOX_MESSAGE_LEAD = "Inbox message"; diff --git a/packages/features/src/service-paths.ts b/packages/features/src/service-paths.ts index ea82e45c53..9b70b5fb69 100644 --- a/packages/features/src/service-paths.ts +++ b/packages/features/src/service-paths.ts @@ -55,6 +55,12 @@ export const HOSTED_SERVICE_PATH = { * task's inbox is. `account-inbox-wire.ts` declares the answer. */ INBOX: "/api/inbox", + /** + * Every item the asking member's Inbox lists, marked read for them (PUT), + * in the one workspace the body names or in all of theirs. + * `inbox-wire.ts` declares the request and the answer. + */ + INBOX_READ: "/api/inbox/read", /** * A workspace's agents, on a task or with none, newest started first and * the archived ones left out unless the query asks for them, narrowed to @@ -533,6 +539,11 @@ export function inboxMessagesPath(itemId: string): string { return `${inboxItemPath(itemId)}/messages`; } +/** One item's read state for the asking member: marked read (PUT), as opening it does, or unread (DELETE); `inbox-wire.ts` declares the answer. */ +export function inboxItemReadPath(itemId: string): string { + return `${inboxItemPath(itemId)}/read`; +} + /** One workspace's photo, as its bytes under its own media type (GET), served to the workspace's members alone. */ export function workspacePhotoPath(workspaceId: string): string { return `${HOSTED_SERVICE_PATH.WORKSPACES}/${encodeURIComponent(workspaceId)}/photo`; diff --git a/packages/service/src/agents/coder-host/chat-waiting.ts b/packages/service/src/agents/coder-host/chat-waiting.ts index 66f3e51c5a..eddac86c99 100644 --- a/packages/service/src/agents/coder-host/chat-waiting.ts +++ b/packages/service/src/agents/coder-host/chat-waiting.ts @@ -13,7 +13,7 @@ import { listWorkspaces } from "@luke/database/models/workspace-store"; import { ACCOUNT_CHAT_REASON, type AccountChatEntry } from "@luke/features/account-inbox-wire"; import { ASK_STATUS, CHANNEL_KIND, MEMBER_KIND } from "@luke/features/chat-wire"; import { Effect, Option, type Schema } from "effect"; -import type { InboxStamp } from "../../inbox/inbox-store.js"; +import type { CursorStamp } from "../../http/held-read.js"; /** * chat-waiting.ts -- what waits on a person in their workspaces' chat, as the account's held read carries it beside the inbox: the asks open to them, and the message their member was last told of. @@ -70,7 +70,7 @@ function rostersOf(userId: string) { */ export function chatWaitingStamps( userId: string, -): Effect.Effect { +): Effect.Effect { return Effect.gen(function* () { // Chat is an experiment: an account with it off has nothing waiting in it. if (!(yield* chatEnabledFor(userId))) return []; diff --git a/packages/service/src/agents/coder-host/inbox-page.ts b/packages/service/src/agents/coder-host/inbox-page.ts index 2fd9ce9475..065974c7b5 100644 --- a/packages/service/src/agents/coder-host/inbox-page.ts +++ b/packages/service/src/agents/coder-host/inbox-page.ts @@ -55,9 +55,10 @@ import { chatWaitingEntries, chatWaitingStamps } from "./chat-waiting.js"; /** How far back a run that failed to start is still carried to its automation's owner. */ const FAILED_RUN_WINDOW = Duration.days(7); -/** What a cursor digests of one thing it covers, an item or a failed run. */ +/** What a cursor digests of one thing it covers, an item, whose stamp says whether it is unread for the reader, or a failed run. */ type InboxCursorStamp = Pick & { readonly status: string; + readonly unread?: boolean; }; /** Waits until the inbox moves past the reader's cursor, or a transcript read's hold ends. */ diff --git a/packages/service/src/agents/coder-host/inbox-store.test.ts b/packages/service/src/agents/coder-host/inbox-store.test.ts index 9482542e38..57059992e9 100644 --- a/packages/service/src/agents/coder-host/inbox-store.test.ts +++ b/packages/service/src/agents/coder-host/inbox-store.test.ts @@ -32,7 +32,7 @@ import { type InboxPost, } from "@luke/features/inbox-wire"; import { eq } from "drizzle-orm"; -import { Duration, Effect, Option, Result } from "effect"; +import { DateTime, Duration, Effect, Option, Result } from "effect"; import { TestClock } from "effect/testing"; import { accountInboxTasks, @@ -42,10 +42,14 @@ import { INBOX_MESSAGE_OUTCOME, type InboxAgent, type InboxFile, + markInboxItemRead, + markInboxItemUnread, + markInboxRead, postInboxItem, postInboxMessage, readInboxAttachment, readInboxItem, + replyInboxItem, taskInboxItems, withdrawInboxAnswer, withdrawInboxMessage, @@ -734,3 +738,249 @@ it.layer(getTestDB())("the inbox store", (it) => { }), ); }); + +/** Whether the item is unread for the reader, as their read of it says. */ +const unreadFor = (reader: string, itemId: string) => + Effect.map(readInboxItem(reader, itemId), (found) => Option.getOrThrow(found).item.unread); + +/** An agent's item posted under the key given, its id. */ +const postedId = (agent: InboxAgent, key: string) => + Effect.map(postInboxItem(agent, { ...SETTINGS, key }), (posted) => { + assert.ok(Result.isSuccess(posted)); + return posted.success.id; + }); + +it.layer(getTestDB())("an inbox item's read state", (it) => { + it.effect( + "a new item is unread for every member until each reads it, and unread again for a reader once anything happens on it after their read", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const id = yield* postedId(agent, SETTINGS.key); + + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [true, true], + ); + const listed = yield* taskInboxItems(teammate, agent.taskId ?? ""); + assert.deepEqual( + listed.map((item) => [item.id, item.unread]), + [[id, true]], + ); + const waiting = yield* accountWaitingItems(teammate); + assert.deepEqual( + waiting.map((entry) => [entry.id, entry.unread]), + [[id, true]], + ); + + assert.equal(yield* markInboxItemRead(agent.userId, id), true); + assert.equal(yield* markInboxItemRead(agent.userId, id), true, "reading it again is fine"); + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [false, true], + "one member's read leaves another's unread", + ); + + // Each change after the read makes it unread again: the agent's reply, a teammate's answer, a close, a post under its key. + const changes = [ + replyInboxItem(agent, SETTINGS.key, "Still needed."), + answerInboxItem(teammate, id, 1, DONE, randomUUID()), + postInboxItem(agent, SETTINGS), + closeInboxItem(agent, SETTINGS.key, "Done another way."), + ]; + for (const change of changes) { + yield* markInboxItemRead(agent.userId, id); + assert.equal(yield* unreadFor(agent.userId, id), false); + yield* TestClock.adjust(Duration.seconds(1)); + yield* change; + assert.equal(yield* unreadFor(agent.userId, id), true); + } + }), + ); + + it.effect( + "a member's own answer or message leaves the item read for them and unread for a teammate, as the write answers it and as later reads say", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const id = yield* postedId(agent, SETTINGS.key); + yield* markInboxItemRead(agent.userId, id); + yield* TestClock.adjust(Duration.seconds(1)); + + const answered = Option.getOrThrow( + yield* answerInboxItem(teammate, id, 1, DONE, randomUUID()), + ); + assert.equal(answered.unread, false, "the answer comes back read for its answerer"); + assert.deepEqual( + [yield* unreadFor(teammate, id), yield* unreadFor(agent.userId, id)], + [false, true], + ); + + yield* TestClock.adjust(Duration.seconds(1)); + const messaged = Option.getOrThrow( + yield* postInboxMessage(agent.userId, id, { text: "Thanks.", clientKey: randomUUID() }), + ); + assert.equal(messaged.item.unread, false, "the message comes back read for its writer"); + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [false, true], + ); + }), + ); + + it.effect( + "an item marked unread stays unread whatever changes until its member reads it again, and a teammate's marker never moves another's", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const outsider = yield* openUser; + yield* openWorkspace(outsider); + const id = yield* postedId(agent, SETTINGS.key); + yield* markInboxItemRead(agent.userId, id); + yield* markInboxItemRead(teammate, id); + + assert.equal(yield* markInboxItemUnread(agent.userId, id), true); + assert.equal( + yield* markInboxItemUnread(agent.userId, id), + true, + "marking it again is fine", + ); + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [true, false], + ); + yield* TestClock.adjust(Duration.seconds(1)); + yield* postInboxMessage(agent.userId, id, { text: "Later.", clientKey: randomUUID() }); + assert.equal(yield* unreadFor(teammate, id), true, "the message is news to the teammate"); + yield* markInboxItemRead(teammate, id); + assert.equal(yield* unreadFor(teammate, id), false); + assert.equal( + yield* unreadFor(agent.userId, id), + false, + "the member's own message is a read of the item they marked unread", + ); + + yield* markInboxItemUnread(agent.userId, id); + yield* markInboxItemUnread(teammate, id); + yield* markInboxItemRead(teammate, id); + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [true, false], + "the teammate's read leaves the item marked unread for the member who marked it", + ); + yield* markInboxItemRead(agent.userId, id); + assert.equal(yield* unreadFor(agent.userId, id), false); + + assert.equal(yield* markInboxItemRead(outsider, id), false, "an outsider reaches no item"); + assert.equal(yield* markInboxItemUnread(outsider, id), false); + assert.equal(yield* markInboxItemRead(agent.userId, randomUUID()), false); + }), + ); + + it.effect( + "marking every item read marks what the member's Inbox lists in the workspace named, settled items included, or in every workspace where none is, counts only what was unread, and leaves teammates' markers alone", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const elsewhere = yield* openTasklessAgent; + yield* joinWorkspace(elsewhere.workspaceId, agent.userId); + const open = yield* postedId(agent, "open"); + const settled = yield* postedId(agent, "settled"); + yield* answerInboxItem(teammate, settled, 1, DONE, randomUUID()); + const marked = yield* postedId(agent, "marked"); + yield* markInboxItemRead(agent.userId, marked); + yield* markInboxItemUnread(agent.userId, marked); + const read = yield* postedId(agent, "read"); + yield* markInboxItemRead(agent.userId, read); + const other = yield* postedId(elsewhere.agent, SETTINGS.key); + + assert.equal(yield* markInboxRead(agent.userId, workspaceId), 3); + for (const id of [open, settled, marked, read]) { + assert.equal(yield* unreadFor(agent.userId, id), false); + } + assert.equal(yield* unreadFor(agent.userId, other), true, "another workspace's is left"); + assert.deepEqual( + [yield* unreadFor(teammate, open), yield* unreadFor(teammate, settled)], + [true, false], + "the teammate's markers stand as they were", + ); + assert.equal(yield* markInboxRead(agent.userId, workspaceId), 0, "nothing is left unread"); + + assert.equal(yield* markInboxRead(agent.userId, undefined), 1); + assert.equal(yield* unreadFor(agent.userId, other), false); + }), + ); + + it.effect( + "an item that stood before unread was kept reads as read for every member until something happens on it", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const id = yield* postedId(agent, SETTINGS.key); + // As the migration that added the column stamped every item standing at the instant it ran. + yield* TestClock.adjust(Duration.seconds(1)); + const released = yield* DateTime.nowAsDate; + yield* Database.use((db) => + db.update(inboxItem).set({ readThrough: released }).where(eq(inboxItem.id, id)), + ); + + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [false, false], + ); + assert.equal(yield* markInboxRead(agent.userId, undefined), 0); + + yield* TestClock.adjust(Duration.seconds(1)); + yield* replyInboxItem(agent, SETTINGS.key, "One more thing."); + assert.deepEqual( + [yield* unreadFor(agent.userId, id), yield* unreadFor(teammate, id)], + [true, true], + ); + yield* markInboxItemRead(teammate, id); + assert.equal(yield* unreadFor(teammate, id), false); + }), + ); + + it.effect( + "a member's held reads move when their own marker moves, and a teammate's marker leaves them where they stand", + () => + Effect.gen(function* () { + const { agent, workspaceId } = yield* openAgentIn; + const teammate = yield* openUser; + yield* joinWorkspace(workspaceId, teammate); + const taskId = agent.taskId ?? ""; + const id = yield* postedId(agent, SETTINGS.key); + const task = yield* taskInboxPast(agent.userId, taskId, INBOX_CURSOR_START); + const account = yield* accountInboxPast(agent.userId, INBOX_CURSOR_START); + const theirs = yield* taskInboxPast(teammate, taskId, INBOX_CURSOR_START); + + yield* markInboxItemRead(agent.userId, id); + + // A held read past the old cursor answers at once, since the reader's own items moved. + const woken = yield* taskInboxPast(agent.userId, taskId, task.cursor); + assert.notEqual(woken.cursor, task.cursor); + assert.deepEqual( + woken.items.map((item) => item.unread), + [false], + ); + const accountWoken = yield* accountInboxPast(agent.userId, account.cursor); + assert.notEqual(accountWoken.cursor, account.cursor); + assert.deepEqual( + accountWoken.items.map((entry) => entry.unread), + [false], + ); + const unmoved = yield* taskInboxPast(teammate, taskId, INBOX_CURSOR_START); + assert.equal(unmoved.cursor, theirs.cursor, "the teammate's inbox stands where it stood"); + }), + ); +}); diff --git a/packages/service/src/agents/coding-agents-app.test.ts b/packages/service/src/agents/coding-agents-app.test.ts index 8ba4c5bc2d..4598e30aa4 100644 --- a/packages/service/src/agents/coding-agents-app.test.ts +++ b/packages/service/src/agents/coding-agents-app.test.ts @@ -131,6 +131,8 @@ import { inboxAnsweredSchema, inboxAnswerSchema, inboxMessagedSchema, + inboxReadAllSchema, + inboxReadStateSchema, } from "@luke/features/inbox-wire"; import { INTEGRATION_PROVIDER, type IntegrationProvider } from "@luke/features/integration-wire"; import { MENTION_KIND, mentionMarkdown } from "@luke/features/mention-link"; @@ -3105,6 +3107,7 @@ const INBOX_ITEM = "/api/inbox/item"; const ACCOUNT_INBOX = "/api/inbox"; const INBOX_ATTACHMENT = "/api/inbox/attachment"; const INBOX_MESSAGES = "/api/inbox/messages"; +const INBOX_READ = "/api/inbox/read"; /** The first bytes of a PNG, as a screenshot's file starts. */ const PNG = Uint8Array.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0, 0, 13]); @@ -3501,6 +3504,71 @@ it.layer(getTestDB())("the developer's inbox", (it) => { }), ); + it.effect( + "a member marks an item read and unread for themselves alone, or every item of a workspace's Inbox read, and an outsider, another method, and a malformed request are refused", + () => + Effect.gen(function* () { + const { owner, other, task, ask, post, read, waiting } = yield* openInbox(); + const asked = yield* post(QUESTION); + assert.ok(Result.isSuccess(asked)); + const { id } = asked.success; + const unread = () => + Effect.map(read(), (page) => page.items.find((item) => item.id === id)?.unread); + const mark = (method: string, bearer = owner) => + ask(request(INBOX_READ, bearer, { method, id })); + assert.equal(yield* unread(), true, "a new item is unread"); + assert.deepEqual( + (yield* waiting()).items.map((entry) => [entry.id, entry.unread]), + [[id, true]], + ); + + assert.deepEqual( + readAnswer(inboxReadStateSchema, HOSTED_HTTP_STATUS.OK, yield* mark("PUT")), + { id, unread: false }, + ); + assert.equal(yield* unread(), false); + assert.deepEqual( + readAnswer(inboxReadStateSchema, HOSTED_HTTP_STATUS.OK, yield* mark("DELETE")), + { id, unread: true }, + ); + assert.equal(yield* unread(), true); + + assert.deepEqual( + yield* mark("PUT", other), + refusal(HOSTED_HTTP_STATUS.NOT_FOUND, HOSTED_API_ERROR.NOT_FOUND), + "an account outside the workspace reaches no item", + ); + assert.deepEqual( + yield* mark("POST"), + refusal(HOSTED_HTTP_STATUS.METHOD_NOT_ALLOWED, HOSTED_API_ERROR.METHOD_NOT_ALLOWED), + ); + assert.deepEqual( + yield* ask(request(INBOX_READ, owner, { method: "DELETE", body: {} })), + refusal(HOSTED_HTTP_STATUS.METHOD_NOT_ALLOWED, HOSTED_API_ERROR.METHOD_NOT_ALLOWED), + "nothing marks every item unread", + ); + + const all = (body: WireBoundaryInput) => + ask(request(INBOX_READ, owner, { method: "PUT", body })); + assert.deepEqual( + yield* all({ workspaceId: "" }), + refusal(HOSTED_HTTP_STATUS.BAD_REQUEST, HOSTED_API_ERROR.INVALID_REQUEST), + ); + assert.deepEqual( + readAnswer( + inboxReadAllSchema, + HOSTED_HTTP_STATUS.OK, + yield* all({ workspaceId: task.workspaceId }), + ), + { marked: 1 }, + ); + assert.equal(yield* unread(), false); + assert.deepEqual(readAnswer(inboxReadAllSchema, HOSTED_HTTP_STATUS.OK, yield* all({})), { + marked: 0, + }); + }), + ); + it.effect( "a run of the account's own automation that failed to start rides the account's inbox read and moves its cursor, as no item, and another account's read carries none", () => diff --git a/packages/service/src/agents/coding-agents-app.ts b/packages/service/src/agents/coding-agents-app.ts index 2e2606e60d..54553156c1 100644 --- a/packages/service/src/agents/coding-agents-app.ts +++ b/packages/service/src/agents/coding-agents-app.ts @@ -53,6 +53,7 @@ import { inboxAnswerRequestSchema, inboxCursorSchema, inboxMessageRequestSchema, + inboxReadAllRequestSchema, inboxReplyRefusal, inboxThreadMessage, } from "@luke/features/inbox-wire"; @@ -106,6 +107,9 @@ import { logStoreFailure } from "../http/store-failure.js"; import { answerInboxItem, INBOX_MESSAGE_OUTCOME, + markInboxItemRead, + markInboxItemUnread, + markInboxRead, postInboxMessage, readInboxAttachment, readInboxItem, @@ -282,6 +286,8 @@ const AGENTS_PATH = { INBOX_ITEM: "/api/inbox/item", /** POST writes a member's message on one inbox item's thread; the rewrite moves the path's item id into the `id` query. */ INBOX_MESSAGES: "/api/inbox/messages", + /** PUT marks one inbox item read for the asking member and DELETE marks it unread, where the rewrite moves the path's item id into the `id` query; PUT with no `id` marks every item their Inbox lists read. */ + INBOX_READ: "/api/inbox/read", /** GET reads what waits on the developer across the account's tasks past `after`. */ INBOX: "/api/inbox", /** GET serves one attachment of an inbox item, an image block's picture; the rewrite moves the item id into the `id` query and the attachment id into `attachment`. */ @@ -295,7 +301,13 @@ const AGENTS_PATH = { /** The most agents a workspace's list answers: enough to choose one an automation's runs go to. */ const WORKSPACE_AGENTS_LIMIT = 50; -const HTTP_METHOD = { GET: "GET", POST: "POST", PATCH: "PATCH" } as const; +const HTTP_METHOD = { + GET: "GET", + POST: "POST", + PATCH: "PATCH", + PUT: "PUT", + DELETE: "DELETE", +} as const; const QUERY = { ID: "id", @@ -1414,6 +1426,49 @@ const inboxMessageEndpoint = /* @__PURE__ */ Effect.fn("web/inboxMessageEndpoint return hostedJsonResponse(HOSTED_HTTP_STATUS.OK, { item }); }); +/** A request to mark every item read names at most a workspace, so a few hundred bytes hold it. */ +const MAXIMUM_INBOX_READ_ALL_BODY_BYTES = 1_024; + +/** + * The member's own read state on the Inbox, which no other member's moves. + * Where the path names an item, PUT marks it read, which is what opening + * it does and writes nothing where it stands read already, and DELETE + * marks it unread until they read it again; each answers the item's id and + * its read state, and an item of a workspace the account is not in is not + * found. Where the path names none, PUT marks every item their Inbox lists + * read, in the workspace the body names or in all of theirs, and answers + * how many were unread. + */ +const inboxReadEndpoint = /* @__PURE__ */ Effect.fn("web/inboxReadEndpoint")(function* ( + seams: CodingAgentsAppSeams, +): Effect.fn.Return { + const incoming = yield* HttpServerRequest.HttpServerRequest; + const request = yield* Effect.orDie(HttpServerRequest.toWeb(incoming)); + const named = new URL(request.url).searchParams.has(QUERY.ID); + const method = incoming.method; + if (method !== HTTP_METHOD.PUT && !(named && method === HTTP_METHOD.DELETE)) { + return yield* Effect.fail(HOSTED_REFUSAL.METHOD_NOT_ALLOWED); + } + if (!named) { + const body = yield* readJsonBodyEffect(MAXIMUM_INBOX_READ_ALL_BODY_BYTES); + const asked = readEither(inboxReadAllRequestSchema)(body); + if (Result.isFailure(asked)) return yield* Effect.fail(HOSTED_REFUSAL.INVALID_REQUEST); + const userId = yield* resolvedUserId(seams, request); + const marked = yield* hostedStoreOrUnavailable( + markInboxRead(userId, asked.success.workspaceId), + ); + return hostedJsonResponse(HOSTED_HTTP_STATUS.OK, { marked }); + } + const itemId = yield* idOf(request); + const userId = yield* resolvedUserId(seams, request); + const unread = method === HTTP_METHOD.DELETE; + const found = yield* hostedStoreOrUnavailable( + unread ? markInboxItemUnread(userId, itemId) : markInboxItemRead(userId, itemId), + ); + if (!found) return yield* Effect.fail(HOSTED_REFUSAL.NOT_FOUND); + return hostedJsonResponse(HOSTED_HTTP_STATUS.OK, { id: itemId, unread }); +}); + /** * The item with the answer standing on it under the request's key: taken * now where the item is open at the revision named and takes the answer, @@ -1528,6 +1583,11 @@ export function codingAgentsApp(seams: CodingAgentsAppSeams): WebRoutes [stamp.id, stamp.revision, stamp.status, stamp.updatedAt] as const) + .map((stamp) => + stamp.unread === undefined + ? ([stamp.id, stamp.revision, stamp.status, stamp.updatedAt] as const) + : ([stamp.id, stamp.revision, stamp.status, stamp.updatedAt, stamp.unread] as const), + ) .toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)); return createHash("sha256").update(JSON.stringify(standing)).digest("hex").slice(0, CURSOR_CHARS); } diff --git a/packages/service/src/inbox/inbox-store.ts b/packages/service/src/inbox/inbox-store.ts index fbcb029c61..a4f83f1fa8 100644 --- a/packages/service/src/inbox/inbox-store.ts +++ b/packages/service/src/inbox/inbox-store.ts @@ -13,6 +13,7 @@ import { automation } from "@luke/database/schemas/automation"; import { codingAgent } from "@luke/database/schemas/coding-agent"; import { inboxItem } from "@luke/database/schemas/inbox"; import { inboxAttachment } from "@luke/database/schemas/inbox-attachment"; +import { inboxItemRead } from "@luke/database/schemas/inbox-item-read"; import { inboxMessage } from "@luke/database/schemas/inbox-message"; import { task } from "@luke/database/schemas/task"; import { INBOX_ATTACHMENT_KIND } from "@luke/database/storage-vocabulary"; @@ -101,6 +102,15 @@ import { SqlClient, SqlSchema } from "effect/sql"; * item's key leaves the thread and its files standing. What waits across * the account, every open item on a task it has not archived, is read on * its own index, so a desktop can hold that read whichever task is open. + * Every read of an item says whether it is unread for the member reading + * it, by that member's own marker (`@luke/database/schemas/inbox-item-read`): + * an item is unread while it changed after the last change they read + * through, or while they marked it unread and have not read it since. A + * member's own answer or message marks it read for them in the same write, + * and marking an item read, or every item their Inbox lists, writes only + * their own marker and only where it moves, so opening an item already + * read writes nothing. The stamps a held read compares carry the reader's + * unread state too, so a marker moved wakes that member's held reads. * Every function is an effect over the ambient `SqlClient` and names no * database of its own. */ @@ -133,6 +143,8 @@ export interface InboxStamp { readonly revision: number; readonly status: InboxItem["status"]; readonly updatedAt: number; + /** Whether the item is unread for the member the stamps were read for. */ + readonly unread: boolean; } /** An item as the service holds it, beyond what the wire carries: the key its answer was taken under. */ @@ -203,6 +215,30 @@ const MESSAGES = sql`(select coalesce(jsonb_agg(jsonb_build_object('id' /** Whether the item is settled: answered, or closed by its agent. */ const SETTLED = sql`${inboxItem.status} <> ${INBOX_STATUS.OPEN}`; +const ITEM_TABLE = sql.identifier(getTableName(inboxItem)); +const ITEM_UPDATED_AT = sql`${ITEM_TABLE}.${sql.identifier(inboxItem.updatedAt.name)}`; +const ITEM_READ_THROUGH = sql`${ITEM_TABLE}.${sql.identifier(inboxItem.readThrough.name)}`; + +const READ = { + itemId: qualified(inboxItemRead, inboxItemRead.itemId), + userId: qualified(inboxItemRead, inboxItemRead.userId), + readThrough: qualified(inboxItemRead, inboxItemRead.readThrough), + markedUnread: qualified(inboxItemRead, inboxItemRead.markedUnread), +}; + +/** + * Whether the item is unread for the reader: marked unread by them, or + * changed after the later of the change they read through and the instant + * the item itself is read through by everyone, which stands only on an item + * from before unread was kept. A reader with no marker reads it by the + * item's instant alone, so an item posted since is unread until they read + * it and one that stood before is read until it changes. + */ +function unreadFor(readerId: string): SQL { + const noMarker = sql`${ITEM_UPDATED_AT} > coalesce(${ITEM_READ_THROUGH}, '-infinity'::timestamptz)`; + return sql`coalesce((select ${READ.markedUnread} or ${ITEM_UPDATED_AT} > coalesce(greatest(${READ.readThrough}, ${ITEM_READ_THROUGH}), '-infinity'::timestamptz) from ${inboxItemRead} where ${READ.itemId} = ${ITEM_ID} and ${READ.userId} = ${readerId}), ${noMarker})`; +} + /** * When a settled item was settled, in epoch milliseconds: the instant kept, * or, on an item settled before it was kept, its last change, which no @@ -212,8 +248,16 @@ const SETTLED_AT = sql< number | null >`floor(extract(epoch from coalesce(${inboxItem.settledAt}, case when ${SETTLED} then ${inboxItem.updatedAt} end)) * 1000)::float8`; -/** The columns every read and every `returning` projects, so a row decodes one way whatever wrote it. */ -const INBOX_COLUMNS = { +/** The columns every read and every `returning` projects for the reader, so a row decodes one way whatever wrote it. */ +function inboxColumns(readerId: string) { + return { + ...INBOX_ITEM_COLUMNS, + unread: unreadFor(readerId), + }; +} + +/** What an item says whoever reads it. */ +const INBOX_ITEM_COLUMNS = { id: inboxItem.id, agentId: inboxItem.agentId, key: inboxItem.key, @@ -298,6 +342,7 @@ const InboxRowSchema = Schema.Struct({ postedAt: InstantColumnSchema, settledAt: Schema.NullOr(Schema.Number), updatedAt: InstantColumnSchema, + unread: Schema.Boolean, }); type InboxRow = typeof InboxRowSchema.Type; @@ -329,6 +374,7 @@ function storedItem(row: InboxRow): StoredInboxItem { postedAt: row.postedAt.getTime(), ...(row.settledAt === null ? undefined : { settledAt: row.settledAt }), updatedAt: row.updatedAt.getTime(), + unread: row.unread, }, answerKey: row.answerKey, }; @@ -632,7 +678,7 @@ const upsertItem = SqlSchema.findOne({ target: [inboxItem.agentId, inboxItem.key], set: { ...posted, revision: sql`${inboxItem.revision} + 1` }, }) - .returning(INBOX_COLUMNS), + .returning(inboxColumns(write.userId)), ); }, }); @@ -660,7 +706,7 @@ const closeItem = SqlSchema.findOneOption({ .where( and(eq(inboxItem.userId, userId), eq(inboxItem.agentId, agentId), eq(inboxItem.key, key)), ) - .returning(INBOX_COLUMNS), + .returning(inboxColumns(userId)), ), }); @@ -701,7 +747,7 @@ const findOpenItems = SqlSchema.findAll({ execute: (scope) => Database.use((db) => db - .select(INBOX_COLUMNS) + .select(inboxColumns(scope.userId)) .from(inboxItem) .where(and(inScope(scope), eq(inboxItem.status, INBOX_STATUS.OPEN))) .orderBy(...LATEST_FIRST), @@ -715,7 +761,7 @@ const findSettledItems = SqlSchema.findAll({ execute: ({ limit, ...scope }) => Database.use((db) => db - .select(INBOX_COLUMNS) + .select(inboxColumns(scope.userId)) .from(inboxItem) .where(and(inScope(scope), ne(inboxItem.status, INBOX_STATUS.OPEN))) .orderBy(...LATEST_FIRST) @@ -729,14 +775,19 @@ const StampRowSchema = Schema.Struct({ revision: Schema.Number, status: Schema.Literals(Object.values(INBOX_STATUS)), updatedAt: InstantColumnSchema, + unread: Schema.Boolean, }); -const STAMP_COLUMNS = { - id: inboxItem.id, - revision: inboxItem.revision, - status: inboxItem.status, - updatedAt: inboxItem.updatedAt, -}; +/** Where an item stands for the reader: its own stamp, and whether it is unread for them, so their marker moving wakes their held reads. */ +function stampColumns(readerId: string) { + return { + id: inboxItem.id, + revision: inboxItem.revision, + status: inboxItem.status, + updatedAt: inboxItem.updatedAt, + unread: unreadFor(readerId), + }; +} const findOpenStamps = SqlSchema.findAll({ Request: ScopeSchema, @@ -744,7 +795,7 @@ const findOpenStamps = SqlSchema.findAll({ execute: (scope) => Database.use((db) => db - .select(STAMP_COLUMNS) + .select(stampColumns(scope.userId)) .from(inboxItem) .where(and(inScope(scope), eq(inboxItem.status, INBOX_STATUS.OPEN))) .orderBy(...LATEST_FIRST), @@ -757,7 +808,7 @@ const findSettledStamps = SqlSchema.findAll({ execute: ({ limit, ...scope }) => Database.use((db) => db - .select(STAMP_COLUMNS) + .select(stampColumns(scope.userId)) .from(inboxItem) .where(and(inScope(scope), ne(inboxItem.status, INBOX_STATUS.OPEN))) .orderBy(...LATEST_FIRST) @@ -802,6 +853,7 @@ const WaitingRowSchema = Schema.Struct({ status: Schema.Literals(Object.values(INBOX_STATUS)), postedAt: InstantColumnSchema, updatedAt: InstantColumnSchema, + unread: Schema.Boolean, }); const findWaitingItems = SqlSchema.findAll({ @@ -822,6 +874,7 @@ const findWaitingItems = SqlSchema.findAll({ status: inboxItem.status, postedAt: inboxItem.postedAt, updatedAt: inboxItem.updatedAt, + unread: unreadFor(userId), }) .from(inboxItem) .innerJoin(task, eq(task.id, inboxItem.taskId)) @@ -847,6 +900,7 @@ const TasklessRowSchema = Schema.Struct({ status: Schema.Literals(Object.values(INBOX_STATUS)), postedAt: InstantColumnSchema, updatedAt: InstantColumnSchema, + unread: Schema.Boolean, }); const findTasklessWaitingItems = SqlSchema.findAll({ @@ -870,6 +924,7 @@ const findTasklessWaitingItems = SqlSchema.findAll({ status: inboxItem.status, postedAt: inboxItem.postedAt, updatedAt: inboxItem.updatedAt, + unread: unreadFor(userId), }) .from(inboxItem) .innerJoin(codingAgent, eq(codingAgent.id, inboxItem.agentId)) @@ -890,7 +945,7 @@ const findWaitingStamps = SqlSchema.findAll({ execute: ({ userId }) => Database.use((db) => db - .select(STAMP_COLUMNS) + .select(stampColumns(userId)) .from(inboxItem) .leftJoin(task, eq(task.id, inboxItem.taskId)) .where(or(accountWaiting(userId), tasklessWaiting(userId))) @@ -979,18 +1034,20 @@ const findItem = SqlSchema.findOneOption({ execute: ({ userId, itemId }) => Database.use((db) => db - .select(INBOX_COLUMNS) + .select(inboxColumns(userId)) .from(inboxItem) .where(and(eq(inboxItem.id, itemId), itemReachableBy(userId))), ), }); -/** The item by its id alone, read where the caller has reached it already. */ +/** The item by its id alone, read for the reader named where the caller has reached it already. */ const findItemOf = SqlSchema.findOneOption({ - Request: Schema.Struct({ itemId: Schema.String }), + Request: Schema.Struct({ readerId: Schema.String, itemId: Schema.String }), Result: InboxRowSchema, - execute: ({ itemId }) => - Database.use((db) => db.select(INBOX_COLUMNS).from(inboxItem).where(eq(inboxItem.id, itemId))), + execute: ({ readerId, itemId }) => + Database.use((db) => + db.select(inboxColumns(readerId)).from(inboxItem).where(eq(inboxItem.id, itemId)), + ), }); /** The account, task, and workspace an item stands under, which its attachments are written under too. */ @@ -1019,6 +1076,135 @@ function itemScope(request: { readonly itemId: string }) { return findItemScope(request).pipe(Effect.catchTag("NoSuchElementError", Effect.die)); } +/** A marker's column as the row an insert would have written, which an upsert's update takes. */ +function excluded(column: AnyPgColumn): SQL { + return sql`excluded.${sql.identifier(column.name)}`; +} + +const ReaderItemSchema = Schema.Struct({ userId: Schema.String, itemId: Schema.String }); + +const MarkedSchema = Schema.Struct({ itemId: Schema.String }); + +/** + * The member's marker on the item read through its last change, where the + * account reaches the item; nothing where the marker already read through + * that change and was not marked unread, so a read already standing writes + * no row. + */ +const upsertRead = SqlSchema.findOneOption({ + Request: ReaderItemSchema, + Result: MarkedSchema, + execute: ({ userId, itemId }) => + Database.use((db) => + db + .insert(inboxItemRead) + .select( + db + .select({ + itemId: inboxItem.id, + userId: sql`${userId}::text`.as(inboxItemRead.userId.name), + readThrough: inboxItem.updatedAt, + markedUnread: sql`false`.as(inboxItemRead.markedUnread.name), + }) + .from(inboxItem) + .where(and(eq(inboxItem.id, itemId), itemReachableBy(userId))), + ) + .onConflictDoUpdate({ + target: [inboxItemRead.itemId, inboxItemRead.userId], + set: { readThrough: excluded(inboxItemRead.readThrough), markedUnread: false }, + setWhere: sql`${inboxItemRead.markedUnread} or ${inboxItemRead.readThrough} is distinct from ${excluded(inboxItemRead.readThrough)}`, + }) + .returning({ itemId: inboxItemRead.itemId }), + ), +}); + +/** The member's marker on the item marked unread, where the account reaches the item; nothing where it stands marked already. */ +const upsertUnread = SqlSchema.findOneOption({ + Request: ReaderItemSchema, + Result: MarkedSchema, + execute: ({ userId, itemId }) => + Database.use((db) => + db + .insert(inboxItemRead) + .select( + db + .select({ + itemId: inboxItem.id, + userId: sql`${userId}::text`.as(inboxItemRead.userId.name), + markedUnread: sql`true`.as(inboxItemRead.markedUnread.name), + }) + .from(inboxItem) + .where(and(eq(inboxItem.id, itemId), itemReachableBy(userId))), + ) + .onConflictDoUpdate({ + target: [inboxItemRead.itemId, inboxItemRead.userId], + set: { markedUnread: true }, + setWhere: sql`not ${inboxItemRead.markedUnread}`, + }) + .returning({ itemId: inboxItemRead.itemId }), + ), +}); + +/** The item's id, where the account reaches it. */ +const findReachedItem = SqlSchema.findOneOption({ + Request: ReaderItemSchema, + Result: Schema.Struct({ id: Schema.String }), + execute: ({ userId, itemId }) => + Database.use((db) => + db + .select({ id: inboxItem.id }) + .from(inboxItem) + .where(and(eq(inboxItem.id, itemId), itemReachableBy(userId))), + ), +}); + +/** + * The items the account's Inbox lists, open or settled, whichever member's + * agent posted each: those on the tasks of its workspaces it has not + * archived, and those of agents with no task in its workspaces. Note that + * the task is joined on the left, because an item with no task has none. + */ +function inboxListed(userId: string) { + return or( + and(taskReachableBy(userId), isNull(task.archivedAt)), + and(isNull(inboxItem.taskId), itemReachableBy(userId)), + ); +} + +/** Every item the account's Inbox lists that is unread for it, in the one workspace named or in all of them, marked read through its last change: the markers moved. */ +const upsertAllRead = SqlSchema.findAll({ + Request: Schema.Struct({ userId: Schema.String, workspaceId: Schema.NullOr(Schema.String) }), + Result: MarkedSchema, + execute: ({ userId, workspaceId }) => + Database.use((db) => + db + .insert(inboxItemRead) + .select( + db + .select({ + itemId: inboxItem.id, + userId: sql`${userId}::text`.as(inboxItemRead.userId.name), + readThrough: inboxItem.updatedAt, + markedUnread: sql`false`.as(inboxItemRead.markedUnread.name), + }) + .from(inboxItem) + .leftJoin(task, eq(task.id, inboxItem.taskId)) + .where( + and( + inboxListed(userId), + workspaceId === null ? undefined : eq(inboxItem.organizationId, workspaceId), + unreadFor(userId), + ), + ), + ) + .onConflictDoUpdate({ + target: [inboxItemRead.itemId, inboxItemRead.userId], + set: { readThrough: excluded(inboxItemRead.readThrough), markedUnread: false }, + }) + .returning({ itemId: inboxItemRead.itemId }), + ), +}); + /** The answer written on the item where it is open at the revision named; nothing where it is not. */ const answerItem = SqlSchema.findOneOption({ Request: Schema.Struct({ @@ -1050,7 +1236,7 @@ const answerItem = SqlSchema.findOneOption({ eq(inboxItem.status, INBOX_STATUS.OPEN), ), ) - .returning(INBOX_COLUMNS), + .returning(inboxColumns(userId)), ), }); @@ -1221,6 +1407,48 @@ export function readInboxItem( return Effect.map(findItem({ userId, itemId }), Option.map(storedItem)); } +/** Whether the marker's write found the item: it moved the marker, or the account reaches an item whose marker stood as asked already. */ +function markerFound( + marked: Option.Option, + request: typeof ReaderItemSchema.Type, +): InboxStoreEffect { + if (Option.isSome(marked)) return Effect.succeed(true); + return Effect.map(findReachedItem(request), Option.isSome); +} + +/** + * The item marked read for the member, read through its last change and + * no longer marked unread, which is what opening it does; whether the + * account reaches the item. A read already standing writes nothing, so + * marking an item read again is one statement and one lookup. + */ +export function markInboxItemRead(userId: string, itemId: string): InboxStoreEffect { + const request = { userId, itemId }; + return Effect.flatMap(upsertRead(request), (marked) => markerFound(marked, request)); +} + +/** The item marked unread for the member, standing so until they read it again, whatever changes meanwhile; whether the account reaches the item. */ +export function markInboxItemUnread(userId: string, itemId: string): InboxStoreEffect { + const request = { userId, itemId }; + return Effect.flatMap(upsertUnread(request), (marked) => markerFound(marked, request)); +} + +/** + * Every item the member's Inbox lists marked read for them, open or + * settled, in the one workspace named or in every workspace of theirs + * where none is: how many were unread. An item already read is not + * written, and another member's markers are never touched. + */ +export function markInboxRead( + userId: string, + workspaceId: string | undefined, +): InboxStoreEffect { + return Effect.map( + upsertAllRead({ userId, workspaceId: workspaceId ?? null }), + (marked) => marked.length, + ); +} + /** The answer taken back off the item it was taken on under the key, opening it again; nothing where that answer no longer stands. */ const withdrawAnswer = SqlSchema.findOneOption({ Request: Schema.Struct({ @@ -1250,7 +1478,7 @@ const withdrawAnswer = SqlSchema.findOneOption({ eq(inboxItem.status, INBOX_STATUS.ANSWERED), ), ) - .returning(INBOX_COLUMNS), + .returning(inboxColumns(userId)), ), }); @@ -1267,7 +1495,9 @@ export function withdrawInboxAnswer( const withdrawn = yield* withdrawAnswer({ userId, itemId, answerKey, now }); if (Option.isNone(withdrawn)) return Option.none(); yield* deleteAnswerFiles({ itemId }); - // Note that the row is read again, because what `returning` projected still named the files. + // The answer taken back is the member's own, so it leaves the item read for them as the answer did. + yield* upsertRead({ userId, itemId }); + // Note that the row is read again, because what `returning` projected still named the files and was read before the marker moved. return Option.map(yield* findItem({ userId, itemId }), (row) => storedItem(row).item); }), ), @@ -1298,22 +1528,24 @@ export function answerInboxItem( Effect.gen(function* () { const now = yield* DateTime.nowAsDate; const answered = yield* answerItem({ userId, itemId, revision, answer, answerKey, now }); - if (Option.isNone(answered) || files.length === 0) { - return Option.map(answered, (row) => storedItem(row).item); + if (Option.isNone(answered)) return Option.none(); + // The member's own answer leaves the item read for them, and unread for every other member. + yield* upsertRead({ userId, itemId }); + if (files.length > 0) { + const scope = yield* itemScope({ itemId }); + yield* Effect.forEach(files, (file, position) => + insertAnswerFile({ + ...scope, + itemId, + name: file.name, + position, + contentType: file.mediaType, + bytes: bytesOf(file), + now, + }), + ); } - const scope = yield* itemScope({ itemId }); - yield* Effect.forEach(files, (file, position) => - insertAnswerFile({ - ...scope, - itemId, - name: file.name, - position, - contentType: file.mediaType, - bytes: bytesOf(file), - now, - }), - ); - // Note that the row is read again, because what `returning` projected was read before the files were written. + // Note that the row is read again, because what `returning` projected was read before the marker moved and the files were written. return Option.map(yield* findItem({ userId, itemId }), (row) => storedItem(row).item); }), ), @@ -1398,10 +1630,14 @@ function sameMessage( * its key is the one already written, which writes nothing and moves * nothing; another message under a key already taken, by another member or * with other words or files, is refused as the key reused, so the thread - * never names one message while the agent hears another. The caller has read the item as the writer may reach it, so the + * never names one message while the agent hears another. A member's + * message marks the item read for them in the same write. The item comes + * back as the reader named reads it: the member, or the agent's starter. + * The caller has read the item as the writer may reach it, so the * item named is one that stands. */ function writeInboxMessage( + readerId: string, itemId: string, writer: InboxMessageWriter, text: string, @@ -1433,11 +1669,13 @@ function writeInboxMessage( }), ); yield* touchItem({ itemId, now }); + // A member's own message leaves the item read for them, and unread for every other member. + if (member !== undefined) yield* upsertRead({ userId: member.userId, itemId }); } const outcome = Option.isSome(written) ? INBOX_MESSAGE_OUTCOME.WRITTEN : yield* repeatOutcome(itemId, member, text, files); - const found = yield* findItemOf({ itemId }); + const found = yield* findItemOf({ readerId, itemId }); return Option.map(found, (row) => ({ item: storedItem(row).item, outcome })); }), ), @@ -1477,6 +1715,7 @@ export function postInboxMessage( Option.isNone(found) ? Effect.succeed(Option.none()) : writeInboxMessage( + userId, itemId, { author: INBOX_MESSAGE_AUTHOR.MEMBER, userId, clientKey: message.clientKey }, message.text, @@ -1526,7 +1765,13 @@ export function replyInboxItem( Option.isNone(found) ? Effect.succeed(Option.none()) : Effect.map( - writeInboxMessage(found.value.id, { author: INBOX_MESSAGE_AUTHOR.AGENT }, text, pictures), + writeInboxMessage( + agent.userId, + found.value.id, + { author: INBOX_MESSAGE_AUTHOR.AGENT }, + text, + pictures, + ), Option.map((written) => written.item), ), ); diff --git a/vercel.json b/vercel.json index af0121fc76..77a3b326f3 100644 --- a/vercel.json +++ b/vercel.json @@ -209,6 +209,14 @@ "src": "/api/inbox/([^/]+)/messages", "dest": "/api/default.js?route=inbox/messages&id=$1" }, + { + "src": "/api/inbox/([^/]+)/read", + "dest": "/api/default.js?route=inbox/read&id=$1" + }, + { + "src": "/api/inbox/read", + "dest": "/api/default.js?route=inbox/read" + }, { "src": "/api/inbox/([^/]+)", "dest": "/api/default.js?route=inbox/item&id=$1" From 6abef0fbcadcbe4ffe239c6586123dded6c12372 Mon Sep 17 00:00:00 2001 From: Dean Stratakos <29683763+dastratakos@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:14:03 +0000 Subject: [PATCH 2/3] test(web): declare the inbox_item_read table among the schema's tables Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com> --- apps/web/tests/storage-schema.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/tests/storage-schema.test.ts b/apps/web/tests/storage-schema.test.ts index b4713cc069..9f16518bc5 100644 --- a/apps/web/tests/storage-schema.test.ts +++ b/apps/web/tests/storage-schema.test.ts @@ -63,6 +63,7 @@ const DECLARED_TABLES = [ "hosted_usage", "inbox_attachment", "inbox_item", + "inbox_item_read", "inbox_message", "integration_connection", "invitation", From 986b702d449e12d01fcd4b019913d3425a9b882d Mon Sep 17 00:00:00 2001 From: Dean Stratakos <29683763+dastratakos@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:18:38 +0000 Subject: [PATCH 3/3] fix(service): never move an inbox read marker back to an older change A read selects the item's last change before it takes the marker's lock, so a member's own answer recorded meanwhile could be overwritten by the older change, reading their answer as unread. Both read upserts now keep the later of the two and write only where the marker moves, so mark all counts only what it moved. Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com> --- .../src/agents/coder-host/inbox-store.test.ts | 35 +++++++++++++++++++ packages/service/src/inbox/inbox-store.ts | 28 +++++++++++---- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/service/src/agents/coder-host/inbox-store.test.ts b/packages/service/src/agents/coder-host/inbox-store.test.ts index 57059992e9..04236521f8 100644 --- a/packages/service/src/agents/coder-host/inbox-store.test.ts +++ b/packages/service/src/agents/coder-host/inbox-store.test.ts @@ -9,6 +9,7 @@ import { organization, user } from "@luke/database/schemas/auth"; import { automation as automationTable } from "@luke/database/schemas/automation"; import { codingAgent } from "@luke/database/schemas/coding-agent"; import { inboxItem } from "@luke/database/schemas/inbox"; +import { inboxItemRead } from "@luke/database/schemas/inbox-item-read"; import { getTestDB, joinWorkspace, openWorkspace, startTask } from "@luke/database/testing"; import { AUTOMATION_ACTION, @@ -919,6 +920,40 @@ it.layer(getTestDB())("an inbox item's read state", (it) => { }), ); + it.effect( + "a read never moves a member's marker back past a later change they read through, as their own write landing while a read waits leaves it", + () => + Effect.gen(function* () { + const { agent } = yield* openAgentIn; + const id = yield* postedId(agent, SETTINGS.key); + // As the member's own answer leaves the marker when it lands while a read that selected the older change waits on its lock. + yield* markInboxItemRead(agent.userId, id); + const ahead = new Date( + (yield* DateTime.nowAsDate).getTime() + Duration.toMillis("5 seconds"), + ); + yield* Database.use((db) => + db.update(inboxItemRead).set({ readThrough: ahead }).where(eq(inboxItemRead.itemId, id)), + ); + + yield* markInboxItemRead(agent.userId, id); + assert.equal( + yield* markInboxRead(agent.userId, undefined), + 0, + "nothing moved, so nothing counts", + ); + yield* markInboxItemUnread(agent.userId, id); + assert.equal(yield* markInboxRead(agent.userId, undefined), 1); + + yield* TestClock.adjust(Duration.seconds(2)); + yield* replyInboxItem(agent, SETTINGS.key, "Before the later change."); + assert.equal( + yield* unreadFor(agent.userId, id), + false, + "the marker still reads through the later change, so one before it is read", + ); + }), + ); + it.effect( "an item that stood before unread was kept reads as read for every member until something happens on it", () => diff --git a/packages/service/src/inbox/inbox-store.ts b/packages/service/src/inbox/inbox-store.ts index a4f83f1fa8..8d30d67918 100644 --- a/packages/service/src/inbox/inbox-store.ts +++ b/packages/service/src/inbox/inbox-store.ts @@ -1081,6 +1081,21 @@ function excluded(column: AnyPgColumn): SQL { return sql`excluded.${sql.identifier(column.name)}`; } +/** + * A read written over a marker that stands: read through the later of the + * two changes and no longer marked unread. Note that it never moves a + * marker back, because the change a read selected may be older than one a + * write of the member's own, such as their answer, recorded while the read + * waited on the marker's lock. + */ +const READ_ON = { + readThrough: sql`greatest(${inboxItemRead.readThrough}, ${excluded(inboxItemRead.readThrough)})`, + markedUnread: false, +}; + +/** Whether a read moves the marker that stands: it was marked unread, or the read reaches a later change than it had read through. */ +const READ_MOVES = sql`${inboxItemRead.markedUnread} or ${inboxItemRead.readThrough} is null or ${inboxItemRead.readThrough} < ${excluded(inboxItemRead.readThrough)}`; + const ReaderItemSchema = Schema.Struct({ userId: Schema.String, itemId: Schema.String }); const MarkedSchema = Schema.Struct({ itemId: Schema.String }); @@ -1088,8 +1103,8 @@ const MarkedSchema = Schema.Struct({ itemId: Schema.String }); /** * The member's marker on the item read through its last change, where the * account reaches the item; nothing where the marker already read through - * that change and was not marked unread, so a read already standing writes - * no row. + * that change or a later one and was not marked unread, so a read already + * standing writes no row. */ const upsertRead = SqlSchema.findOneOption({ Request: ReaderItemSchema, @@ -1111,8 +1126,8 @@ const upsertRead = SqlSchema.findOneOption({ ) .onConflictDoUpdate({ target: [inboxItemRead.itemId, inboxItemRead.userId], - set: { readThrough: excluded(inboxItemRead.readThrough), markedUnread: false }, - setWhere: sql`${inboxItemRead.markedUnread} or ${inboxItemRead.readThrough} is distinct from ${excluded(inboxItemRead.readThrough)}`, + set: READ_ON, + setWhere: READ_MOVES, }) .returning({ itemId: inboxItemRead.itemId }), ), @@ -1171,7 +1186,7 @@ function inboxListed(userId: string) { ); } -/** Every item the account's Inbox lists that is unread for it, in the one workspace named or in all of them, marked read through its last change: the markers moved. */ +/** Every item the account's Inbox lists that is unread for it, in the one workspace named or in all of them, marked read through its last change: the markers moved, which leaves out one a write of the member's own moved further meanwhile. */ const upsertAllRead = SqlSchema.findAll({ Request: Schema.Struct({ userId: Schema.String, workspaceId: Schema.NullOr(Schema.String) }), Result: MarkedSchema, @@ -1199,7 +1214,8 @@ const upsertAllRead = SqlSchema.findAll({ ) .onConflictDoUpdate({ target: [inboxItemRead.itemId, inboxItemRead.userId], - set: { readThrough: excluded(inboxItemRead.readThrough), markedUnread: false }, + set: READ_ON, + setWhere: READ_MOVES, }) .returning({ itemId: inboxItemRead.itemId }), ),