From 5c438f10d35731a79b58da85fc4c08a30829a800 Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Fri, 14 Aug 2026 20:04:21 +0000
Subject: [PATCH 1/7] feat: make goal mode visible in task history
---
.../tasks/__tests__/getTaskSummary.test.ts | 76 +++-
apps/api/src/handlers/tasks/getTaskSummary.ts | 17 +
apps/api/src/handlers/tasks/helpers.ts | 8 +
.../task/[taskId]/GoalStatusMessage.tsx | 75 ++++
.../task/[taskId]/Messages.client.test.tsx | 337 +++++++++++++++++-
.../app/(sandbox)/task/[taskId]/Messages.tsx | 118 +++++-
.../use-task-session.client.test.tsx | 26 ++
.../task/[taskId]/hooks/use-task-session.ts | 35 +-
.../[taskId]/messages/acp/AcpTextMessage.tsx | 78 ++--
.../__tests__/AcpTextMessage.client.test.tsx | 46 +++
.../task/[taskId]/messages/acp/goal-prompt.ts | 46 +++
.../prompt-input/PromptInput.client.test.tsx | 11 +
.../[taskId]/prompt-input/PromptInput.tsx | 1 +
.../prompt-input/optimistic-prompt.ts | 5 +
.../useOptimisticPromptSubmission.ts | 3 +
apps/web/src/types/task.ts | 5 +
.../__tests__/task-summary.test.ts | 75 ++++
.../mcp/roomote-mcp-server/task-summary.ts | 37 +-
.../src/mcp/roomote-mcp-server/types.ts | 11 +
.../lib/harnesses/opencode-server/harness.ts | 1 +
.../runtime-event-emitter.test.ts | 36 ++
.../opencode-server/runtime-event-emitter.ts | 10 +
22 files changed, 1011 insertions(+), 46 deletions(-)
create mode 100644 apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx
create mode 100644 apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
diff --git a/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts b/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts
index 7d993efe7..0df34b592 100644
--- a/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts
+++ b/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts
@@ -37,6 +37,14 @@ vi.mock('../helpers', () => ({
timestamp: 'tasks.timestamp',
activityAt: 'tasks.activityAt',
repositoryName: 'tasks.repository_name',
+ goalObjective: 'tasks.goalObjective',
+ goalStatus: 'tasks.goalStatus',
+ goalMaxContinuations: 'tasks.goalMaxContinuations',
+ goalContinuationsUsed: 'tasks.goalContinuationsUsed',
+ goalBlockedReason: 'tasks.goalBlockedReason',
+ goalCompletedAt: 'tasks.goalCompletedAt',
+ goalLastContinuationId: 'tasks.goalLastContinuationId',
+ goalGenerationIds: 'tasks.goalGenerationIds',
},
getLatestTaskRunsByTaskIds: mockGetLatestTaskRunsByTaskIds,
visibleTaskHistoryCondition,
@@ -97,11 +105,19 @@ describe('getTaskSummary', () => {
id: 'task-1',
title: 'Broken startup',
mode: 'standard',
- completed: false,
+ state: 'active',
repositoryName: 'owner/repo',
harness: 'opencode-server',
timestamp: 1,
activityAt: 2,
+ goalObjective: null,
+ goalStatus: null,
+ goalMaxContinuations: null,
+ goalContinuationsUsed: 0,
+ goalBlockedReason: null,
+ goalCompletedAt: null,
+ goalLastContinuationId: null,
+ goalGenerationIds: [],
},
]);
mockSelect.mockReturnValue({
@@ -140,6 +156,64 @@ describe('getTaskSummary', () => {
});
});
+ it.each([
+ ['active', null, null],
+ ['complete', null, new Date('2026-08-14T12:00:00Z')],
+ ['blocked', 'Waiting for approval', null],
+ ] as const)(
+ 'returns durable %s goal metadata without changing the legacy mode',
+ async (goalStatus, goalBlockedReason, goalCompletedAt) => {
+ selectLimitMock.mockResolvedValueOnce([
+ {
+ id: 'task-1',
+ title: 'Count to ten',
+ mode: null,
+ state: 'active',
+ repositoryName: 'owner/repo',
+ harness: 'opencode-server',
+ timestamp: 1,
+ activityAt: 2,
+ goalObjective: 'Count to ten',
+ goalStatus,
+ goalMaxContinuations: 5,
+ goalContinuationsUsed: 2,
+ goalBlockedReason,
+ goalCompletedAt,
+ goalLastContinuationId: 'goal-generation:1',
+ goalGenerationIds: ['goal-generation:1'],
+ },
+ ]);
+
+ const response = await createApp(authContext).request(
+ 'http://localhost/tasks/task-1/summary',
+ );
+
+ expect(response.status).toBe(200);
+ await expect(response.json()).resolves.toMatchObject({
+ mode: null,
+ hasUsedGoalMode: true,
+ goal: {
+ objective: 'Count to ten',
+ status: goalStatus,
+ blockedReason: goalBlockedReason,
+ generation: 'goal-generation:1',
+ },
+ });
+ },
+ );
+
+ it('explicitly reports that an ordinary task never used goal mode', async () => {
+ const response = await createApp(authContext).request(
+ 'http://localhost/tasks/task-1/summary',
+ );
+
+ expect(response.status).toBe(200);
+ await expect(response.json()).resolves.toMatchObject({
+ hasUsedGoalMode: false,
+ goal: null,
+ });
+ });
+
it('adds the hidden-task-history condition to the summary query', async () => {
const response = await createApp(authContext).request(
'http://localhost/tasks/task-1/summary',
diff --git a/apps/api/src/handlers/tasks/getTaskSummary.ts b/apps/api/src/handlers/tasks/getTaskSummary.ts
index b62ee78a5..389a35b57 100644
--- a/apps/api/src/handlers/tasks/getTaskSummary.ts
+++ b/apps/api/src/handlers/tasks/getTaskSummary.ts
@@ -49,6 +49,11 @@ export async function getTaskSummary(
columns: { id: true, name: true },
})
: null;
+ const hasUsedGoalMode =
+ typeof task.goalObjective === 'string' ||
+ task.goalStatus != null ||
+ (Array.isArray(task.goalGenerationIds) &&
+ task.goalGenerationIds.length > 0);
return c.json({
id: task.id,
@@ -65,6 +70,18 @@ export async function getTaskSummary(
environmentSetupState: latestRun?.environmentSetupState ?? null,
linkedEnvironmentId: linkedEnvironmentId ?? null,
linkedEnvironmentName: linkedEnvironment?.name ?? null,
+ hasUsedGoalMode,
+ goal: hasUsedGoalMode
+ ? {
+ objective: task.goalObjective ?? null,
+ status: task.goalStatus ?? null,
+ maxContinuations: task.goalMaxContinuations ?? null,
+ continuationsUsed: task.goalContinuationsUsed ?? 0,
+ blockedReason: task.goalBlockedReason ?? null,
+ completedAt: task.goalCompletedAt ?? null,
+ generation: task.goalLastContinuationId ?? null,
+ }
+ : null,
});
} catch (error) {
logHandlerError('getTaskSummary', error);
diff --git a/apps/api/src/handlers/tasks/helpers.ts b/apps/api/src/handlers/tasks/helpers.ts
index 4df043384..41b4d39a6 100644
--- a/apps/api/src/handlers/tasks/helpers.ts
+++ b/apps/api/src/handlers/tasks/helpers.ts
@@ -21,6 +21,14 @@ export const TASK_SELECT_COLUMNS = {
timestamp: tasks.timestamp,
activityAt: tasks.activityAt,
repositoryName: tasks.repositoryName,
+ goalObjective: tasks.goalObjective,
+ goalStatus: tasks.goalStatus,
+ goalMaxContinuations: tasks.goalMaxContinuations,
+ goalContinuationsUsed: tasks.goalContinuationsUsed,
+ goalBlockedReason: tasks.goalBlockedReason,
+ goalCompletedAt: tasks.goalCompletedAt,
+ goalLastContinuationId: tasks.goalLastContinuationId,
+ goalGenerationIds: tasks.goalGenerationIds,
};
interface LatestTaskRunSummary {
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx
new file mode 100644
index 000000000..6c20ff80d
--- /dev/null
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx
@@ -0,0 +1,75 @@
+import type { TaskGoalStatus } from '@roomote/types';
+
+import { CircleAlert, CircleCheck, LoaderCircle } from '@/components/system';
+import { Message, MessageContent } from '@/components/ai-elements';
+
+interface GoalStatusMessageProps {
+ objective: string;
+ status: TaskGoalStatus;
+ blockedReason?: string | null;
+}
+
+export function GoalStatusMessage({
+ objective,
+ status,
+ blockedReason,
+}: GoalStatusMessageProps) {
+ const presentation = (() => {
+ switch (status) {
+ case 'active':
+ return {
+ label: 'Pursuing goal',
+ Icon: LoaderCircle,
+ iconClassName: 'animate-spin text-primary',
+ };
+ case 'complete':
+ return {
+ label: 'Goal completed',
+ Icon: CircleCheck,
+ iconClassName: 'text-green-600 dark:text-green-500',
+ };
+ case 'blocked':
+ return {
+ label: 'Goal blocked',
+ Icon: CircleAlert,
+ iconClassName: 'text-amber-500',
+ };
+ case 'budget_limited':
+ return {
+ label: 'Goal continuation limit reached',
+ Icon: CircleAlert,
+ iconClassName: 'text-amber-500',
+ };
+ }
+ })();
+ const { Icon } = presentation;
+
+ return (
+
+
+
+
+
+
{presentation.label}
+
+ {objective}
+
+ {blockedReason ? (
+
+ {blockedReason}
+
+ ) : null}
+
+
+
+
+ );
+}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
index 9897af345..812531e71 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
@@ -21,6 +21,10 @@ const sandboxMessagesState = vi.hoisted(() => ({
messages: [] as unknown[],
}));
+const historyReadyState = vi.hoisted(() => ({
+ ready: true,
+}));
+
vi.mock('@/components/ai-elements', () => ({
Conversation: ({ children }: { children: ReactNode }) => (
{children}
@@ -61,7 +65,7 @@ vi.mock('./hooks', () => ({
useSandboxMessages: () => ({
messages: sandboxMessagesState.messages,
}),
- useSandboxHistoryReady: () => true,
+ useSandboxHistoryReady: () => historyReadyState.ready,
useSandboxTaskPhase: () => taskPhaseState.phase,
}));
@@ -88,7 +92,16 @@ vi.mock('./messages/index', () => ({
}));
vi.mock('./messages/acp', () => ({
- AcpMessageItem: ({ msg }: { msg: { id: string } }) => {msg.id}
,
+ AcpMessageItem: ({
+ msg,
+ }: {
+ msg: { id: string; data?: { goal?: unknown } };
+ }) => (
+
+ {msg.id}
+ {msg.data?.goal ? Sent as goal : null}
+
+ ),
AcpGroupedToolMessage: () => null,
AcpActivityGroupMessage: ({
group,
@@ -104,8 +117,15 @@ vi.mock('./messages/acp', () => ({
{children}
),
- AcpTextMessage: ({ msg }: { msg: { text?: string } }) => (
- {msg.text}
+ AcpTextMessage: ({
+ msg,
+ }: {
+ msg: { text?: string; data?: { goal?: unknown } };
+ }) => (
+
+ {msg.data?.goal ? Sent as goal : null}
+ {msg.text}
+
),
}));
@@ -130,7 +150,11 @@ vi.mock('./ScrollBridge', () => ({
}));
vi.mock('@/components/system', () => ({
+ CircleAlert: () => ,
+ CircleCheck: () => ,
Lightbulb: () => ,
+ LoaderCircle: () => ,
+ Skeleton: () => ,
}));
import { Messages } from './Messages';
@@ -143,6 +167,7 @@ describe('Messages', () => {
narrationModeState.enabled = false;
taskPhaseState.phase = null;
sandboxMessagesState.messages = [];
+ historyReadyState.ready = true;
mockBuildAcpRenderBlocks.mockReturnValue([]);
});
@@ -458,6 +483,310 @@ describe('Messages', () => {
);
});
+ it('shows the active goal objective without expanding tool traces', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Pursuing goal',
+ );
+ expect(screen.getByTestId('goal-status')).toHaveTextContent('Count to ten');
+ expect(screen.getByTestId('goal-status')).toHaveAttribute('role', 'status');
+ });
+
+ it.each([
+ ['complete', 'Goal completed'],
+ ['blocked', 'Goal blocked'],
+ ] as const)('shows the %s terminal goal marker', (goalStatus, label) => {
+ render(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(label);
+ expect(screen.getByTestId('goal-status')).toHaveTextContent('Count to ten');
+ if (goalStatus === 'blocked') {
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Waiting for a number',
+ );
+ }
+ });
+
+ it('keeps a completed goal visible after an ordinary follow-up message', () => {
+ mockBuildAcpRenderBlocks.mockReturnValue([
+ {
+ kind: 'message',
+ msg: {
+ id: 'ordinary-follow-up',
+ ts: 2_000,
+ role: 'user',
+ kind: 'text',
+ partial: false,
+ },
+ },
+ ] as never);
+
+ render(
+ ,
+ );
+
+ expect(screen.getByText('ordinary-follow-up')).toBeInTheDocument();
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Goal completed',
+ );
+ });
+
+ it('labels the matching historical goal turn when old envelopes lack provenance', () => {
+ const goalMessage = {
+ id: 'historical-goal-prompt',
+ ts: 1_000,
+ role: 'user',
+ kind: 'text',
+ partial: false,
+ sessionId: 'session-1',
+ updateType: 'roomote_runtime.user_prompt',
+ text: 'Count to ten',
+ data: {},
+ };
+ sandboxMessagesState.messages = [goalMessage];
+ mockBuildAcpRenderBlocks.mockReturnValue([
+ { kind: 'message', msg: goalMessage },
+ ] as never);
+
+ render(
+ ,
+ );
+
+ expect(screen.getByText('Sent as goal')).toBeVisible();
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Goal completed',
+ );
+ });
+
+ it('labels a legacy goal session prompt when no matching envelope exists', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByText('Sent as goal')).toBeVisible();
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Goal completed',
+ );
+ });
+
+ it('does not infer goal provenance when multiple legacy messages match', () => {
+ const matchingMessages = [
+ {
+ id: 'historical-goal-prompt',
+ ts: 1_000,
+ role: 'user',
+ kind: 'text',
+ partial: false,
+ sessionId: 'session-1',
+ updateType: 'roomote_runtime.user_prompt',
+ text: 'Count to ten',
+ data: {},
+ },
+ {
+ id: 'ordinary-duplicate-follow-up',
+ ts: 2_000,
+ role: 'user',
+ kind: 'text',
+ partial: false,
+ sessionId: 'session-1',
+ updateType: 'roomote_runtime.user_prompt',
+ text: 'Count to ten',
+ data: {},
+ },
+ ];
+ sandboxMessagesState.messages = matchingMessages;
+ mockBuildAcpRenderBlocks.mockReturnValue(
+ matchingMessages.map((msg) => ({ kind: 'message', msg })) as never,
+ );
+
+ render(
+ ,
+ );
+
+ expect(screen.queryByText('Sent as goal')).not.toBeInTheDocument();
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Goal completed',
+ );
+ });
+
+ it('does not infer legacy goal provenance before history finishes loading', () => {
+ const goalMessage = {
+ id: 'partial-goal-prompt',
+ ts: 1_000,
+ role: 'user',
+ kind: 'text',
+ partial: false,
+ sessionId: 'session-1',
+ updateType: 'roomote_runtime.user_prompt',
+ text: 'Count to ten',
+ data: {},
+ };
+ historyReadyState.ready = false;
+ sandboxMessagesState.messages = [goalMessage];
+ mockBuildAcpRenderBlocks.mockReturnValue([
+ { kind: 'message', msg: goalMessage },
+ ] as never);
+
+ render(
+ ,
+ );
+
+ expect(screen.queryByText('Sent as goal')).not.toBeInTheDocument();
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Pursuing goal',
+ );
+ });
+
+ it('leaves non-goal transcripts unchanged', () => {
+ render(
+ ,
+ );
+
+ expect(screen.queryByTestId('goal-status')).not.toBeInTheDocument();
+ });
+
it('collapses eligible background activity between text messages', () => {
mockBuildAcpRenderBlocks.mockReturnValue([
{
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
index e15f76dc6..0e4b01e66 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
@@ -57,6 +57,12 @@ import { messageAnchorId } from './messages/message-anchor';
import { LazyMessage } from './LazyMessage';
import { ScrollToHash } from './ScrollToHash';
import { ScrollBridge } from './ScrollBridge';
+import type { AcpUiMessage } from './types';
+import { GoalStatusMessage } from './GoalStatusMessage';
+import {
+ findLatestGoalPrompt,
+ getGoalPromptProvenance,
+} from './messages/acp/goal-prompt';
export interface MessagesHandle {
scrollToBottom: ScrollToBottom;
@@ -246,6 +252,90 @@ const MessagesBase = ({
Boolean(sessionPrompt);
const resolvedHideFirstAcpUserPrompt =
hideFirstAcpUserPrompt ?? shouldRenderSessionPrompt;
+ const latestGoalPrompt = useMemo(
+ () => findLatestGoalPrompt(messages),
+ [messages],
+ );
+ const inferredGoalPromptMessageId = useMemo(() => {
+ if (!historyReady) {
+ return null;
+ }
+
+ const objective = session.task?.goalObjective?.trim();
+ if (!objective) {
+ return null;
+ }
+
+ const matchingMessages = messages.filter(
+ (message) =>
+ message.role === 'user' && message.text?.trim() === objective,
+ );
+
+ return matchingMessages.length === 1 ? matchingMessages[0]!.id : null;
+ }, [historyReady, messages, session.task?.goalObjective]);
+ const taskGoalGenerations = session.task?.goalGenerationIds ?? [];
+ const taskHasLatestGoal = latestGoalPrompt
+ ? latestGoalPrompt.generation === null
+ ? session.task?.goalObjective === latestGoalPrompt.objective
+ : taskGoalGenerations.includes(latestGoalPrompt.generation)
+ : true;
+ const goalStatus =
+ session.task?.goalObjective && session.task.goalStatus && taskHasLatestGoal
+ ? {
+ objective: session.task.goalObjective,
+ status: session.task.goalStatus,
+ blockedReason: session.task.goalBlockedReason,
+ }
+ : latestGoalPrompt
+ ? {
+ objective: latestGoalPrompt.objective,
+ status: 'active' as const,
+ blockedReason: null,
+ }
+ : null;
+ const renderedSessionPrompt = useMemo(() => {
+ if (!sessionPrompt) {
+ return sessionPrompt;
+ }
+
+ const firstGoalMessage = messages.find(
+ (message) =>
+ message.role === 'user' &&
+ message.text === sessionPrompt.text &&
+ (getGoalPromptProvenance(message) !== null ||
+ message.id === inferredGoalPromptMessageId),
+ );
+
+ const shouldInferSessionPromptGoal =
+ historyReady &&
+ session.task?.goalObjective?.trim() === sessionPrompt.text?.trim() &&
+ !messages.some(
+ (message) =>
+ message.role === 'user' &&
+ message.text?.trim() === session.task?.goalObjective?.trim(),
+ );
+
+ return firstGoalMessage
+ ? ({
+ ...sessionPrompt,
+ data: withGoalProvenance(firstGoalMessage).data,
+ } as typeof sessionPrompt)
+ : shouldInferSessionPromptGoal
+ ? withGoalProvenance(sessionPrompt)
+ : sessionPrompt;
+ }, [
+ historyReady,
+ inferredGoalPromptMessageId,
+ messages,
+ session.task?.goalObjective,
+ sessionPrompt,
+ ]);
+
+ useEffect(() => {
+ if (latestGoalPrompt && !taskHasLatestGoal) {
+ void session.refreshTaskSession?.();
+ }
+ }, [latestGoalPrompt, session, taskHasLatestGoal]);
const renderBlocks = useMemo(() => {
const acpBlocks = buildAcpRenderBlocks(messages, {
@@ -380,9 +470,13 @@ const MessagesBase = ({
);
}
+ const message =
+ block.msg.id === inferredGoalPromptMessageId
+ ? withGoalProvenance(block.msg)
+ : block.msg;
const content = (
@@ -422,10 +516,11 @@ const MessagesBase = ({
className={cn('ph-no-capture', conversationClassName)}
>
{shouldRenderSessionPrompt && sessionPrompt && (
-
+
)}
{!historyReady && }
{renderBlocks.map((block) => renderRenderBlock(block, false))}
+ {goalStatus ? : null}
{session.taskRun && }
{shouldShowNarrationWorkingReasoning && (
@@ -465,6 +560,25 @@ function collectBlockAnchorIds(
return anchorIds;
}
+function withGoalProvenance(message: AcpUiMessage): AcpUiMessage {
+ if (getGoalPromptProvenance(message)) {
+ return message;
+ }
+
+ const objective = message.text?.trim();
+ if (!objective) {
+ return message;
+ }
+
+ return {
+ ...message,
+ data: {
+ ...message.data,
+ goal: { objective, generation: null },
+ },
+ } as AcpUiMessage;
+}
+
function collectBlockAnchorIdsInto(
blocks: AcpRenderBlock[],
pushAnchor: (anchorId: string) => void,
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/__tests__/use-task-session.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/__tests__/use-task-session.client.test.tsx
index e5535c61b..f6a1a9d80 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/__tests__/use-task-session.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/__tests__/use-task-session.client.test.tsx
@@ -166,6 +166,32 @@ describe('useTaskSession', () => {
);
});
+ it('polls durable task state quickly only while a goal is active', () => {
+ renderHook(() => useTaskSession('task-1', { refetchInterval: 30_000 }));
+
+ const options = sessionQueryOptionsMock.mock.calls[0]?.[1] as {
+ refetchInterval: (query: {
+ state: { data: { task: { goalStatus: string | null } } };
+ }) => number | false;
+ };
+
+ expect(
+ options.refetchInterval({
+ state: { data: { task: { goalStatus: 'active' } } },
+ }),
+ ).toBe(2_000);
+ expect(
+ options.refetchInterval({
+ state: { data: { task: { goalStatus: 'complete' } } },
+ }),
+ ).toBe(30_000);
+ expect(
+ options.refetchInterval({
+ state: { data: { task: { goalStatus: null } } },
+ }),
+ ).toBe(30_000);
+ });
+
it('splits session loading from token loading for interactive tasks', () => {
useQueryMock.mockReset();
useQueryMock
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/use-task-session.ts b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/use-task-session.ts
index 54c64a5db..37db052da 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/hooks/use-task-session.ts
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/hooks/use-task-session.ts
@@ -120,6 +120,9 @@ export interface TaskSession {
/** Refresh the live sandbox connection target after a connection error. */
refreshConnection: () => Promise;
+
+ /** Refresh durable task state after a live event announces an external change. */
+ refreshTaskSession?: () => Promise;
}
interface UseTaskSessionOptions {
@@ -134,10 +137,23 @@ export function useTaskSession(
const queryClient = useQueryClient();
const [isSnapshotting, setIsSnapshotting] = useState(false);
const effectiveRefetchInterval = (query?: {
- state?: { data?: { refetchInterval?: number } };
- }) =>
- query?.state?.data?.refetchInterval ??
- (isSnapshotting ? 2_000 : (refetchInterval ?? false));
+ state?: {
+ data?: {
+ refetchInterval?: number;
+ task?: { goalStatus?: string | null } | null;
+ };
+ };
+ }) => {
+ const data = query?.state?.data;
+ if (data?.task?.goalStatus === 'active') {
+ return 2_000;
+ }
+
+ return (
+ data?.refetchInterval ??
+ (isSnapshotting ? 2_000 : (refetchInterval ?? false))
+ );
+ };
const sessionQuery = useQuery(
trpc.sandboxSession.byTaskId.queryOptions(
{ taskId },
@@ -147,8 +163,10 @@ export function useTaskSession(
),
);
const sessionRefetchInterval =
- sessionQuery.data?.refetchInterval ??
- (isSnapshotting ? 2_000 : (refetchInterval ?? false));
+ sessionQuery.data?.task?.goalStatus === 'active'
+ ? 2_000
+ : (sessionQuery.data?.refetchInterval ??
+ (isSnapshotting ? 2_000 : (refetchInterval ?? false)));
// Switch to fast-poll (2s) while a snapshot is in progress so the UI
// picks up snapshotCreatedAt promptly and shows the "Going to sleep" state.
@@ -306,6 +324,9 @@ export function useTaskSession(
token: nextToken,
};
}, [queryClient]);
+ const refreshTaskSession = useCallback(async () => {
+ await sessionRefetchRef.current();
+ }, []);
return useMemo(
() => ({
@@ -326,6 +347,7 @@ export function useTaskSession(
transportErrorCategory,
isLoading: isSessionLoading || isTokenLoading,
refreshConnection,
+ refreshTaskSession,
}),
[
taskId,
@@ -343,6 +365,7 @@ export function useTaskSession(
hasTransportError,
transportErrorCategory,
refreshConnection,
+ refreshTaskSession,
],
);
}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/AcpTextMessage.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/AcpTextMessage.tsx
index 5caebd639..a6d6e1b0b 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/AcpTextMessage.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/AcpTextMessage.tsx
@@ -17,6 +17,7 @@ import {
ChevronDownIcon,
MediaViewerDialog,
MediaViewerImage,
+ Sparkles,
} from '@/components/system';
import {
type CollapsibleToggleRenderProps,
@@ -38,6 +39,7 @@ import { getTaskToolByInvocation } from '../../task-tools';
import { useInternalTranscriptRowsVisible } from '../../useInternalTranscriptRowsVisible';
import { messageAnchorId } from '../message-anchor';
import type { AcpUiMessage } from './types';
+import { getGoalPromptProvenance } from './goal-prompt';
import { ProviderRetryNoticeMessage } from './ProviderRetryNoticeMessage';
import { TerminalProviderErrorMessage } from './TerminalProviderErrorMessage';
@@ -163,6 +165,7 @@ export function AcpTextMessage({ msg }: AcpTextMessageProps) {
: stripLlmCitationArtifacts(msg.text ?? '');
const anchorId = messageAnchorId(msg.ts);
const taskTool = isUser ? getTaskToolByInvocation(baseContent) : undefined;
+ const goalPrompt = getGoalPromptProvenance(msg);
const linkedReviewResult = isUser
? parseLinkedReviewResults(baseContent)
: null;
@@ -298,38 +301,49 @@ export function AcpTextMessage({ msg }: AcpTextMessageProps) {
data={msg.data as Record}
/>
) : isUser ? (
-
-
- {requestUserInputResponse ? (
- <>
- {requestUserInputResponse.title ? (
-
- {requestUserInputResponse.title}
-
- ) : null}
- {requestUserInputResponse.questionTexts.map(
- (questionText, index) => (
-
- {questionText}
-
- ),
- )}
- {baseContent}
- >
- ) : (
- baseContent
- )}
-
-
+
+ {goalPrompt ? (
+
+
+ Sent as goal
+
+ ) : null}
+
+
+ {requestUserInputResponse ? (
+ <>
+ {requestUserInputResponse.title ? (
+
+ {requestUserInputResponse.title}
+
+ ) : null}
+ {requestUserInputResponse.questionTexts.map(
+ (questionText, index) => (
+
+ {questionText}
+
+ ),
+ )}
+ {baseContent}
+ >
+ ) : (
+ baseContent
+ )}
+
+
+
) : (
{content}
)}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx
index 0983429ec..5b53f1045 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx
@@ -328,6 +328,52 @@ describe('AcpTextMessage', () => {
).toBeVisible();
});
+ it('labels a user prompt that was sent as a goal', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-origin')).toHaveTextContent('Sent as goal');
+ expect(screen.getByText('Count to ten')).toBeVisible();
+ });
+
+ it('does not label an ordinary user prompt as a goal', () => {
+ render(
+ ,
+ );
+
+ expect(screen.queryByTestId('goal-origin')).not.toBeInTheDocument();
+ });
+
it('renders user text as plain text instead of markdown', () => {
render(
;
+ if (message.role !== 'user' || !data.goal) {
+ return null;
+ }
+
+ const goal = data.goal;
+ if (!goal || typeof goal !== 'object') {
+ return null;
+ }
+
+ const objective = Reflect.get(goal, 'objective');
+ const generation = Reflect.get(goal, 'generation');
+
+ if (
+ typeof objective !== 'string' ||
+ objective.trim().length === 0 ||
+ (generation !== null && typeof generation !== 'string')
+ ) {
+ return null;
+ }
+
+ return { objective, generation };
+}
+
+export function findLatestGoalPrompt(
+ messages: AcpUiMessage[],
+): GoalPromptProvenance | null {
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
+ const goal = getGoalPromptProvenance(messages[index]!);
+ if (goal) {
+ return goal;
+ }
+ }
+
+ return null;
+}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx
index 175a4280d..8a14ac0ee 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx
@@ -898,6 +898,17 @@ describe('PromptInput', () => {
});
});
expect(sandboxSendPromptMutateMock).not.toHaveBeenCalled();
+ expect(appendOptimisticAcpEventMock).toHaveBeenCalledWith(
+ expect.objectContaining({
+ text: 'ship the release',
+ payload: expect.objectContaining({
+ goal: {
+ objective: 'ship the release',
+ generation: null,
+ },
+ }),
+ }),
+ );
expect(toastSuccessMock).toHaveBeenCalledWith('Goal Mode enabled');
});
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx
index 7b82df226..fb040f457 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx
@@ -473,6 +473,7 @@ export const PromptInput = forwardRef(
taskId: taskRun.taskId,
prompt: preparedPrompt.text,
images: preparedPrompt.images,
+ ...(goalObjective ? { goalObjective } : {}),
location: optimisticLocation,
});
optimisticClientMessageId = clientMessageId;
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts
index a503c86e1..3c7341545 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts
@@ -20,6 +20,7 @@ type OptimisticPromptInput = {
taskId: string;
prompt: string;
images?: string[];
+ goalObjective?: string;
clientMessageId: string;
currentUserInfo: OptimisticPromptUserInfo | null;
};
@@ -38,6 +39,7 @@ export function createOptimisticPromptArtifacts({
taskId,
prompt,
images,
+ goalObjective,
clientMessageId,
currentUserInfo,
}: OptimisticPromptInput): OptimisticPromptArtifacts {
@@ -60,6 +62,9 @@ export function createOptimisticPromptArtifacts({
prompt: contentBlocks,
content,
...(images ? { images } : {}),
+ ...(goalObjective
+ ? { goal: { objective: goalObjective, generation: null } }
+ : {}),
...(currentUserInfo?.userId ? { userId: currentUserInfo.userId } : {}),
...(currentUserInfo?.userName
? { userName: currentUserInfo.userName }
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts
index 08e14b054..35386751e 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts
@@ -27,6 +27,7 @@ type StartOptimisticPromptSubmissionInput = {
taskId: string;
prompt: string;
images?: string[];
+ goalObjective?: string;
location: OptimisticPromptLocation;
};
@@ -67,6 +68,7 @@ export function useOptimisticPromptSubmission() {
taskId,
prompt,
images,
+ goalObjective,
location,
}: StartOptimisticPromptSubmissionInput) => {
const clientMessageId = generateClientUuid();
@@ -74,6 +76,7 @@ export function useOptimisticPromptSubmission() {
taskId,
prompt,
images,
+ goalObjective,
clientMessageId,
currentUserInfo,
});
diff --git a/apps/web/src/types/task.ts b/apps/web/src/types/task.ts
index 0fd76097e..0e1d6f63e 100644
--- a/apps/web/src/types/task.ts
+++ b/apps/web/src/types/task.ts
@@ -2,6 +2,7 @@ import { z } from 'zod';
import type { TaskArtifactType } from '@roomote/types';
import {
TASK_INITIATOR_KINDS,
+ TASK_GOAL_STATUSES,
TASK_STATES,
TASK_SURFACES,
TASK_WORKFLOWS,
@@ -47,6 +48,10 @@ export const taskSchema = z.object({
// the by-id command; absent from trimmed list rows).
prompt: z.string().nullable().optional(),
draftPrompt: z.string().nullable().optional(),
+ goalObjective: z.string().nullable().optional(),
+ goalStatus: z.enum(TASK_GOAL_STATUSES).nullable().optional(),
+ goalBlockedReason: z.string().nullable().optional(),
+ goalGenerationIds: z.array(z.string()).optional(),
slackChannelId: z.string().nullable().optional(),
slackThreadTs: z.string().nullable().optional(),
linearSessionId: z.string().nullable().optional(),
diff --git a/apps/worker/src/mcp/roomote-mcp-server/__tests__/task-summary.test.ts b/apps/worker/src/mcp/roomote-mcp-server/__tests__/task-summary.test.ts
index 5ab2cb484..cbc2a3080 100644
--- a/apps/worker/src/mcp/roomote-mcp-server/__tests__/task-summary.test.ts
+++ b/apps/worker/src/mcp/roomote-mcp-server/__tests__/task-summary.test.ts
@@ -93,6 +93,81 @@ describe('handleGetTaskSummary', () => {
expect(result.content[0]?.text).toContain('Status: Completed');
});
+ it.each([
+ ['active', 'Goal Mode: Active', null],
+ ['complete', 'Goal Mode: Completed', null],
+ ['blocked', 'Goal Mode: Blocked', 'Waiting for approval'],
+ ] as const)(
+ 'surfaces %s goal history even when legacy mode is null',
+ async (status, expectedStatus, blockedReason) => {
+ vi.mocked(tasksApiClient.getTaskSummary).mockResolvedValueOnce({
+ id: 'task-goal',
+ title: 'Count to ten',
+ mode: null,
+ completed: status === 'complete',
+ repositoryName: null,
+ harness: 'opencode-server',
+ createdAt: 1700000000,
+ taskRunStatus: 'running',
+ taskPhase: 'executing',
+ taskRunError: null,
+ environmentSetupState: null,
+ linkedEnvironmentId: null,
+ linkedEnvironmentName: null,
+ hasUsedGoalMode: true,
+ goal: {
+ objective: 'Count to ten',
+ status,
+ maxContinuations: 5,
+ continuationsUsed: 1,
+ blockedReason,
+ completedAt: status === 'complete' ? '2026-08-14T12:00:00Z' : null,
+ generation: 'goal-generation:1',
+ },
+ });
+
+ const result = await handleGetTaskSummary(
+ { taskId: 'task-goal' },
+ config,
+ );
+ const text = result.content[0]?.text ?? '';
+
+ expect(text).toContain(expectedStatus);
+ expect(text).toContain('Goal Objective: Count to ten');
+ expect(text).not.toMatch(/(^|\n)Mode:/);
+ if (blockedReason) {
+ expect(text).toContain(`Goal Blocker: ${blockedReason}`);
+ }
+ },
+ );
+
+ it('does not add goal output for a non-goal task', async () => {
+ vi.mocked(tasksApiClient.getTaskSummary).mockResolvedValueOnce({
+ id: 'task-ordinary',
+ title: 'Ordinary task',
+ mode: null,
+ completed: false,
+ repositoryName: null,
+ harness: 'opencode-server',
+ createdAt: 1700000000,
+ taskRunStatus: 'running',
+ taskPhase: 'executing',
+ taskRunError: null,
+ environmentSetupState: null,
+ linkedEnvironmentId: null,
+ linkedEnvironmentName: null,
+ hasUsedGoalMode: false,
+ goal: null,
+ });
+
+ const result = await handleGetTaskSummary(
+ { taskId: 'task-ordinary' },
+ config,
+ );
+
+ expect(result.content[0]?.text).not.toContain('Goal');
+ });
+
it('includes the latest task run error when present', async () => {
vi.mocked(tasksApiClient.getTaskSummary).mockResolvedValueOnce({
id: 'task-3',
diff --git a/apps/worker/src/mcp/roomote-mcp-server/task-summary.ts b/apps/worker/src/mcp/roomote-mcp-server/task-summary.ts
index fd427ac2a..ec9002f3f 100644
--- a/apps/worker/src/mcp/roomote-mcp-server/task-summary.ts
+++ b/apps/worker/src/mcp/roomote-mcp-server/task-summary.ts
@@ -1,7 +1,11 @@
import { getTaskSummary } from './tasks-api-client.js';
import { getHarnessLabel, getTaskStatusLabel } from './task-display.js';
import { textResult, catchError } from './tool-result.js';
-import type { RoomoteConfig, ToolResult } from './types.js';
+import type {
+ RoomoteConfig,
+ TaskSummaryResponse,
+ ToolResult,
+} from './types.js';
/**
* Lifecycle of the task's environment setup (repository setup commands and
@@ -26,6 +30,36 @@ function getEnvironmentSetupLine(state: string | null): string | null {
}
}
+function getGoalLines(
+ goal: TaskSummaryResponse['goal'],
+ hasUsedGoalMode: boolean | undefined,
+): string[] {
+ if (!goal) {
+ return hasUsedGoalMode ? ['Goal Mode: used previously'] : [];
+ }
+
+ const status = (() => {
+ switch (goal.status) {
+ case 'active':
+ return 'Active';
+ case 'complete':
+ return 'Completed';
+ case 'blocked':
+ return 'Blocked';
+ case 'budget_limited':
+ return 'Continuation limit reached';
+ default:
+ return 'Used';
+ }
+ })();
+
+ return [
+ `Goal Mode: ${status}`,
+ goal.objective ? `Goal Objective: ${goal.objective}` : null,
+ goal.blockedReason ? `Goal Blocker: ${goal.blockedReason}` : null,
+ ].filter((line): line is string => line !== null);
+}
+
export async function handleGetTaskSummary(
params: { taskId: string },
config: RoomoteConfig,
@@ -39,6 +73,7 @@ export async function handleGetTaskSummary(
`ID: ${result.id}`,
`Status: ${getTaskStatusLabel(result)}`,
result.mode ? `Mode: ${result.mode}` : null,
+ ...getGoalLines(result.goal, result.hasUsedGoalMode),
harnessLabel ? `Harness: ${harnessLabel}` : null,
result.repositoryName ? `Repository: ${result.repositoryName}` : null,
result.linkedEnvironmentName
diff --git a/apps/worker/src/mcp/roomote-mcp-server/types.ts b/apps/worker/src/mcp/roomote-mcp-server/types.ts
index a43650c6c..05c15bac2 100644
--- a/apps/worker/src/mcp/roomote-mcp-server/types.ts
+++ b/apps/worker/src/mcp/roomote-mcp-server/types.ts
@@ -67,6 +67,17 @@ export interface TaskSummaryResponse {
environmentSetupState: string | null;
linkedEnvironmentId: string | null;
linkedEnvironmentName: string | null;
+ /** Additive goal history fields; optional while older API servers remain supported. */
+ hasUsedGoalMode?: boolean;
+ goal?: {
+ objective: string | null;
+ status: 'active' | 'complete' | 'blocked' | 'budget_limited' | null;
+ maxContinuations: number | null;
+ continuationsUsed: number;
+ blockedReason: string | null;
+ completedAt: string | null;
+ generation: string | null;
+ } | null;
}
export interface TaskComputeLog {
diff --git a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts
index cca5396c0..4e0b6af35 100644
--- a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts
+++ b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/harness.ts
@@ -5242,6 +5242,7 @@ export class OpenCodeServerHarness
userName: next.userName,
userImageUrl: next.userImageUrl,
clientMessageId: next.clientMessageId,
+ goalContext: next.goalContext,
});
await this.submitPrompt({
text: next.text,
diff --git a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.test.ts b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.test.ts
index bde07fe81..19c6cc7e8 100644
--- a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.test.ts
+++ b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.test.ts
@@ -86,6 +86,42 @@ describe('OpenCodeRuntimeEventEmitter', () => {
});
});
+ it('persists goal provenance on the originating user prompt', () => {
+ const { emitter, runtimeOutput, runtimePersistedEnvelope } =
+ createEmitter();
+
+ emitter.userPrompt({
+ sessionId: 'session-1',
+ text: 'Count to ten',
+ goalContext: {
+ objective: 'Count to ten',
+ generation: 'goal-generation:1',
+ status: 'active',
+ maxContinuations: 5,
+ continuationsUsed: 0,
+ blockedReason: null,
+ completedAt: null,
+ },
+ });
+
+ expect(runtimeOutput.mock.calls[0]?.[0]).toMatchObject({
+ payload: {
+ goal: {
+ objective: 'Count to ten',
+ generation: 'goal-generation:1',
+ },
+ },
+ });
+ expect(runtimePersistedEnvelope.mock.calls[0]?.[0]).toMatchObject({
+ payload: {
+ goal: {
+ objective: 'Count to ten',
+ generation: 'goal-generation:1',
+ },
+ },
+ });
+ });
+
it('stamps stable logical ids on paired live and persisted tool call events', () => {
const { emitter, runtimeOutput, runtimePersistedEnvelope } =
createEmitter();
diff --git a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.ts b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.ts
index cae080881..78ff7cb00 100644
--- a/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.ts
+++ b/apps/worker/src/sandbox-server/lib/harnesses/opencode-server/runtime-event-emitter.ts
@@ -11,6 +11,7 @@ import {
type AcpRequestUserInputAnswers,
type AcpRequestUserInputPayload,
type AcpRequestUserInputResponsePayload,
+ type TaskGoal,
type TaskCompletionMetadata,
type TaskMessageContentBlock,
} from '@roomote/types';
@@ -100,6 +101,7 @@ export class OpenCodeRuntimeEventEmitter extends RuntimeEnvelopeBuilder {
userName?: string;
userImageUrl?: string;
clientMessageId?: string;
+ goalContext?: TaskGoal;
}): void {
const { sessionId } = options;
@@ -142,6 +144,14 @@ export class OpenCodeRuntimeEventEmitter extends RuntimeEnvelopeBuilder {
...(options.clientMessageId
? { clientMessageId: options.clientMessageId }
: {}),
+ ...(options.goalContext
+ ? {
+ goal: {
+ objective: options.goalContext.objective,
+ generation: options.goalContext.generation,
+ },
+ }
+ : {}),
},
visibleInTranscript: options.visibleInTranscript,
},
From fc64d6f7ff6c39aa20fa790f91839b156c9cfd4a Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Fri, 14 Aug 2026 20:05:18 +0000
Subject: [PATCH 2/7] fix: keep goal provenance type internal
---
.../src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
index 102f68e46..705343ebf 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
@@ -1,6 +1,6 @@
import type { AcpUiMessage } from './types';
-export interface GoalPromptProvenance {
+interface GoalPromptProvenance {
objective: string;
generation: string | null;
}
From 3bab689957e0bc74b3f79162cc53c0a2d1567b42 Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Fri, 14 Aug 2026 23:15:38 +0000
Subject: [PATCH 3/7] fix: reset status for optimistic goal retries
---
.../task/[taskId]/Messages.client.test.tsx | 69 +++++++++++++++++++
.../app/(sandbox)/task/[taskId]/Messages.tsx | 19 ++++-
2 files changed, 85 insertions(+), 3 deletions(-)
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
index 812531e71..33ae60bfa 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
@@ -583,6 +583,75 @@ describe('Messages', () => {
);
});
+ it.each([
+ ['complete', 'Goal completed', null],
+ ['blocked', 'Goal blocked', 'Waiting for a number'],
+ ['budget_limited', 'Goal continuation limit reached', null],
+ ] as const)(
+ 'keeps the prior %s marker while an optimistic retried goal is active',
+ (priorStatus, priorLabel, blockedReason) => {
+ const refreshTaskSession = vi.fn();
+ const previousGoal = {
+ id: 'previous-goal',
+ ts: 1_000,
+ role: 'user',
+ kind: 'text',
+ partial: false,
+ sessionId: 'session-1',
+ updateType: 'roomote_runtime.user_prompt',
+ text: 'Count to ten',
+ data: {
+ goal: {
+ objective: 'Count to ten',
+ generation: 'goal-generation:1',
+ },
+ },
+ };
+ const optimisticRetry = {
+ ...previousGoal,
+ id: 'optimistic-retry',
+ ts: 2_000,
+ data: {
+ goal: { objective: 'Count to ten', generation: null },
+ },
+ };
+ const session = {
+ taskId: `task-goal-retry-${priorStatus}`,
+ prompt: null,
+ task: {
+ goalObjective: 'Count to ten',
+ goalStatus: priorStatus,
+ goalBlockedReason: blockedReason,
+ goalGenerationIds: ['goal-generation:1'],
+ },
+ taskRun: null,
+ artifacts: [],
+ refreshTaskSession,
+ };
+
+ sandboxMessagesState.messages = [previousGoal];
+ mockBuildAcpRenderBlocks.mockReturnValue([
+ { kind: 'message', msg: previousGoal },
+ ] as never);
+ const { rerender } = render();
+
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(priorLabel);
+
+ sandboxMessagesState.messages = [previousGoal, optimisticRetry];
+ mockBuildAcpRenderBlocks.mockReturnValue([
+ { kind: 'message', msg: previousGoal },
+ { kind: 'message', msg: optimisticRetry },
+ ] as never);
+ rerender();
+
+ expect(screen.getAllByText('Sent as goal')).toHaveLength(2);
+ expect(screen.getByText(priorLabel)).toBeVisible();
+ expect(screen.getByText('Pursuing goal')).toBeVisible();
+ expect(screen.getAllByText('Count to ten')).toHaveLength(2);
+ expect(refreshTaskSession).toHaveBeenCalled();
+ },
+ );
+
it('labels the matching historical goal turn when old envelopes lack provenance', () => {
const goalMessage = {
id: 'historical-goal-prompt',
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
index 0e4b01e66..beb2484d7 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
@@ -275,10 +275,20 @@ const MessagesBase = ({
}, [historyReady, messages, session.task?.goalObjective]);
const taskGoalGenerations = session.task?.goalGenerationIds ?? [];
const taskHasLatestGoal = latestGoalPrompt
- ? latestGoalPrompt.generation === null
- ? session.task?.goalObjective === latestGoalPrompt.objective
- : taskGoalGenerations.includes(latestGoalPrompt.generation)
+ ? latestGoalPrompt.generation !== null &&
+ taskGoalGenerations.includes(latestGoalPrompt.generation)
: true;
+ const historicalGoalStatus =
+ latestGoalPrompt?.generation === null &&
+ session.task?.goalObjective &&
+ session.task.goalStatus &&
+ session.task.goalStatus !== 'active'
+ ? {
+ objective: session.task.goalObjective,
+ status: session.task.goalStatus,
+ blockedReason: session.task.goalBlockedReason,
+ }
+ : null;
const goalStatus =
session.task?.goalObjective && session.task.goalStatus && taskHasLatestGoal
? {
@@ -520,6 +530,9 @@ const MessagesBase = ({
)}
{!historyReady && }
{renderBlocks.map((block) => renderRenderBlock(block, false))}
+ {historicalGoalStatus ? (
+
+ ) : null}
{goalStatus ? : null}
{session.taskRun && }
{shouldShowNarrationWorkingReasoning && (
From 8413493ab04c4df95316a5e3fc4f3a7e774d04aa Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Fri, 14 Aug 2026 23:57:27 +0000
Subject: [PATCH 4/7] feat: show durable goal status above composer
---
.../tasks/__tests__/getTaskSummary.test.ts | 17 +-
apps/api/src/handlers/tasks/getTaskSummary.ts | 2 +
apps/api/src/handlers/tasks/helpers.ts | 2 +
.../task/[taskId]/GoalPanel.client.test.tsx | 151 +
.../app/(sandbox)/task/[taskId]/GoalPanel.tsx | 162 +
.../task/[taskId]/GoalStatusMessage.tsx | 75 -
.../task/[taskId]/LiveContent.client.test.tsx | 73 +
.../task/[taskId]/Messages.client.test.tsx | 374 +-
.../app/(sandbox)/task/[taskId]/Messages.tsx | 131 +-
.../task/[taskId]/TaskInputStack.tsx | 2 +
.../[taskId]/messages/acp/AcpTextMessage.tsx | 78 +-
.../__tests__/AcpTextMessage.client.test.tsx | 23 +-
.../task/[taskId]/messages/acp/goal-prompt.ts | 46 -
apps/web/src/types/task.ts | 2 +
.../src/mcp/roomote-mcp-server/types.ts | 2 +
.../src/server/__tests__/enqueue-task.test.ts | 2 +
.../cloud-agents/src/server/task-run-queue.ts | 1 +
.../db/drizzle/0038_perfect_madame_hydra.sql | 2 +
packages/db/drizzle/meta/0038_snapshot.json | 10922 ++++++++++++++++
packages/db/drizzle/meta/_journal.json | 7 +
packages/db/src/lib/task-goals.test.ts | 92 +-
packages/db/src/lib/task-goals.ts | 17 +-
packages/db/src/schema.ts | 2 +
23 files changed, 11503 insertions(+), 682 deletions(-)
create mode 100644 apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
create mode 100644 apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
delete mode 100644 apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx
delete mode 100644 apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
create mode 100644 packages/db/drizzle/0038_perfect_madame_hydra.sql
create mode 100644 packages/db/drizzle/meta/0038_snapshot.json
diff --git a/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts b/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts
index 0df34b592..80aa723af 100644
--- a/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts
+++ b/apps/api/src/handlers/tasks/__tests__/getTaskSummary.test.ts
@@ -42,6 +42,8 @@ vi.mock('../helpers', () => ({
goalMaxContinuations: 'tasks.goalMaxContinuations',
goalContinuationsUsed: 'tasks.goalContinuationsUsed',
goalBlockedReason: 'tasks.goalBlockedReason',
+ goalStartedAt: 'tasks.goalStartedAt',
+ goalEndedAt: 'tasks.goalEndedAt',
goalCompletedAt: 'tasks.goalCompletedAt',
goalLastContinuationId: 'tasks.goalLastContinuationId',
goalGenerationIds: 'tasks.goalGenerationIds',
@@ -115,6 +117,8 @@ describe('getTaskSummary', () => {
goalMaxContinuations: null,
goalContinuationsUsed: 0,
goalBlockedReason: null,
+ goalStartedAt: null,
+ goalEndedAt: null,
goalCompletedAt: null,
goalLastContinuationId: null,
goalGenerationIds: [],
@@ -158,11 +162,14 @@ describe('getTaskSummary', () => {
it.each([
['active', null, null],
- ['complete', null, new Date('2026-08-14T12:00:00Z')],
- ['blocked', 'Waiting for approval', null],
+ ['complete', null, new Date('2026-08-14T12:05:00Z')],
+ ['blocked', 'Waiting for approval', new Date('2026-08-14T12:05:00Z')],
+ ['budget_limited', null, new Date('2026-08-14T12:05:00Z')],
] as const)(
'returns durable %s goal metadata without changing the legacy mode',
- async (goalStatus, goalBlockedReason, goalCompletedAt) => {
+ async (goalStatus, goalBlockedReason, goalEndedAt) => {
+ const goalStartedAt = new Date('2026-08-14T12:00:00Z');
+ const goalCompletedAt = goalStatus === 'complete' ? goalEndedAt : null;
selectLimitMock.mockResolvedValueOnce([
{
id: 'task-1',
@@ -178,6 +185,8 @@ describe('getTaskSummary', () => {
goalMaxContinuations: 5,
goalContinuationsUsed: 2,
goalBlockedReason,
+ goalStartedAt,
+ goalEndedAt,
goalCompletedAt,
goalLastContinuationId: 'goal-generation:1',
goalGenerationIds: ['goal-generation:1'],
@@ -196,6 +205,8 @@ describe('getTaskSummary', () => {
objective: 'Count to ten',
status: goalStatus,
blockedReason: goalBlockedReason,
+ startedAt: goalStartedAt.toISOString(),
+ endedAt: goalEndedAt?.toISOString() ?? null,
generation: 'goal-generation:1',
},
});
diff --git a/apps/api/src/handlers/tasks/getTaskSummary.ts b/apps/api/src/handlers/tasks/getTaskSummary.ts
index 389a35b57..dd4ae56e9 100644
--- a/apps/api/src/handlers/tasks/getTaskSummary.ts
+++ b/apps/api/src/handlers/tasks/getTaskSummary.ts
@@ -78,6 +78,8 @@ export async function getTaskSummary(
maxContinuations: task.goalMaxContinuations ?? null,
continuationsUsed: task.goalContinuationsUsed ?? 0,
blockedReason: task.goalBlockedReason ?? null,
+ startedAt: task.goalStartedAt ?? null,
+ endedAt: task.goalEndedAt ?? null,
completedAt: task.goalCompletedAt ?? null,
generation: task.goalLastContinuationId ?? null,
}
diff --git a/apps/api/src/handlers/tasks/helpers.ts b/apps/api/src/handlers/tasks/helpers.ts
index 41b4d39a6..e1abc495e 100644
--- a/apps/api/src/handlers/tasks/helpers.ts
+++ b/apps/api/src/handlers/tasks/helpers.ts
@@ -26,6 +26,8 @@ export const TASK_SELECT_COLUMNS = {
goalMaxContinuations: tasks.goalMaxContinuations,
goalContinuationsUsed: tasks.goalContinuationsUsed,
goalBlockedReason: tasks.goalBlockedReason,
+ goalStartedAt: tasks.goalStartedAt,
+ goalEndedAt: tasks.goalEndedAt,
goalCompletedAt: tasks.goalCompletedAt,
goalLastContinuationId: tasks.goalLastContinuationId,
goalGenerationIds: tasks.goalGenerationIds,
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
new file mode 100644
index 000000000..f325de542
--- /dev/null
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
@@ -0,0 +1,151 @@
+import { act, render, screen } from '@testing-library/react';
+
+import { GoalPanel } from './GoalPanel';
+
+const startedAt = new Date('2026-08-14T12:00:00.000Z');
+
+function createTask(
+ overrides: Record = {},
+): Parameters[0]['task'] {
+ return {
+ goalObjective: 'Ship the durable goal panel',
+ goalStatus: 'active',
+ goalBlockedReason: null,
+ goalStartedAt: startedAt,
+ goalEndedAt: null,
+ ...overrides,
+ } as never;
+}
+
+describe('GoalPanel', () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ vi.setSystemTime(new Date('2026-08-14T12:01:05.000Z'));
+ });
+
+ afterEach(() => {
+ vi.useRealTimers();
+ });
+
+ it('stays hidden for tasks without a durable goal', () => {
+ const { rerender } = render();
+
+ expect(screen.queryByTestId('goal-panel')).not.toBeInTheDocument();
+
+ rerender(
+ ,
+ );
+ expect(screen.queryByTestId('goal-panel')).not.toBeInTheDocument();
+ });
+
+ it('shows an active goal and advances elapsed time from its durable start', () => {
+ render();
+
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent('Current goal');
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent('Active');
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent(
+ 'Ship the durable goal panel',
+ );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Active for 1m 5s',
+ );
+
+ act(() => vi.advanceTimersByTime(5_000));
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Active for 1m 10s',
+ );
+ });
+
+ it.each([
+ ['complete', 'Complete', 'Completed after'],
+ ['blocked', 'Blocked', 'Blocked after'],
+ ['budget_limited', 'Continuation limit reached', 'Limit reached after'],
+ ] as const)(
+ 'shows a stable duration for a %s goal',
+ (status, label, durationPrefix) => {
+ render(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent(label);
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ `${durationPrefix} 2m 5s`,
+ );
+ if (status === 'blocked') {
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent(
+ 'Waiting for approval',
+ );
+ }
+
+ act(() => vi.advanceTimersByTime(10_000));
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ `${durationPrefix} 2m 5s`,
+ );
+ },
+ );
+
+ it('resets objective and elapsed time when a replacement goal starts', () => {
+ const { rerender } = render();
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Active for 1m 5s',
+ );
+
+ rerender(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent(
+ 'Ship the replacement goal',
+ );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Active for 5s',
+ );
+ });
+
+ it('renders a durable goal again after remounting', () => {
+ const task = createTask({
+ goalStatus: 'complete',
+ goalEndedAt: new Date('2026-08-14T12:00:45.000Z'),
+ });
+ const first = render();
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Completed after 45s',
+ );
+ first.unmount();
+ render();
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Completed after 45s',
+ );
+ });
+
+ it('does not infer a terminal duration when durable timing is incomplete', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ 'Duration unavailable',
+ );
+ });
+});
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
new file mode 100644
index 000000000..dbe9f968a
--- /dev/null
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
@@ -0,0 +1,162 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import type { TaskGoalStatus } from '@roomote/types';
+
+import { TodoList as TodoListPrimitive } from '@/components/ai-elements';
+import {
+ Badge,
+ CircleAlert,
+ CircleCheck,
+ LoaderCircle,
+ Sparkles,
+} from '@/components/system';
+
+import type { TaskSession } from './hooks/use-task-session';
+
+const SECOND_MS = 1_000;
+const MINUTE_SECONDS = 60;
+const HOUR_SECONDS = 60 * MINUTE_SECONDS;
+const DAY_SECONDS = 24 * HOUR_SECONDS;
+
+function formatDurationPart(value: number, suffix: string): string {
+ return value > 0 ? `${value}${suffix}` : '';
+}
+
+function formatGoalDuration(
+ startedAt: Date | null | undefined,
+ endedAt: Date | null | undefined,
+ now: number,
+): string | null {
+ if (!startedAt) {
+ return null;
+ }
+
+ const elapsedSeconds = Math.max(
+ 0,
+ Math.floor(((endedAt?.getTime() ?? now) - startedAt.getTime()) / SECOND_MS),
+ );
+ const days = Math.floor(elapsedSeconds / DAY_SECONDS);
+ const hours = Math.floor((elapsedSeconds % DAY_SECONDS) / HOUR_SECONDS);
+ const minutes = Math.floor((elapsedSeconds % HOUR_SECONDS) / MINUTE_SECONDS);
+ const seconds = elapsedSeconds % MINUTE_SECONDS;
+
+ if (days > 0) {
+ return [formatDurationPart(days, 'd'), formatDurationPart(hours, 'h')]
+ .filter(Boolean)
+ .join(' ');
+ }
+
+ if (hours > 0) {
+ return [formatDurationPart(hours, 'h'), formatDurationPart(minutes, 'm')]
+ .filter(Boolean)
+ .join(' ');
+ }
+
+ if (minutes > 0) {
+ return `${minutes}m ${seconds}s`;
+ }
+
+ return `${seconds}s`;
+}
+
+function getGoalPresentation(status: TaskGoalStatus) {
+ switch (status) {
+ case 'active':
+ return {
+ label: 'Active',
+ durationPrefix: 'Active for',
+ badgeVariant: 'default' as const,
+ Icon: LoaderCircle,
+ };
+ case 'complete':
+ return {
+ label: 'Complete',
+ durationPrefix: 'Completed after',
+ badgeVariant: 'success' as const,
+ Icon: CircleCheck,
+ };
+ case 'blocked':
+ return {
+ label: 'Blocked',
+ durationPrefix: 'Blocked after',
+ badgeVariant: 'warning' as const,
+ Icon: CircleAlert,
+ };
+ case 'budget_limited':
+ return {
+ label: 'Continuation limit reached',
+ durationPrefix: 'Limit reached after',
+ badgeVariant: 'warning' as const,
+ Icon: CircleAlert,
+ };
+ }
+}
+
+export function GoalPanel({ task }: { task: TaskSession['task'] }) {
+ const objective = task?.goalObjective?.trim();
+ const status = task?.goalStatus;
+ const startedAtMs = task?.goalStartedAt?.getTime() ?? null;
+ const [, setTick] = useState(0);
+
+ useEffect(() => {
+ if (status !== 'active' || startedAtMs === null) {
+ return;
+ }
+
+ const intervalId = window.setInterval(
+ () => setTick((current) => current + 1),
+ SECOND_MS,
+ );
+ return () => window.clearInterval(intervalId);
+ }, [startedAtMs, status]);
+
+ if (!objective || !status) {
+ return null;
+ }
+
+ const presentation = getGoalPresentation(status);
+ const endedAt = status === 'active' ? null : task.goalEndedAt;
+ const duration =
+ status !== 'active' && !endedAt
+ ? null
+ : formatGoalDuration(task.goalStartedAt, endedAt, Date.now());
+ const { Icon } = presentation;
+
+ return (
+
+
+
+
+
+
+ Current goal
+
+
+
+ {presentation.label}
+
+
+ {duration
+ ? `${presentation.durationPrefix} ${duration}`
+ : 'Duration unavailable'}
+
+
+
+ {objective}
+
+ {status === 'blocked' && task.goalBlockedReason ? (
+
+ {task.goalBlockedReason}
+
+ ) : null}
+
+
+
+ );
+}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx
deleted file mode 100644
index 6c20ff80d..000000000
--- a/apps/web/src/app/(sandbox)/task/[taskId]/GoalStatusMessage.tsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import type { TaskGoalStatus } from '@roomote/types';
-
-import { CircleAlert, CircleCheck, LoaderCircle } from '@/components/system';
-import { Message, MessageContent } from '@/components/ai-elements';
-
-interface GoalStatusMessageProps {
- objective: string;
- status: TaskGoalStatus;
- blockedReason?: string | null;
-}
-
-export function GoalStatusMessage({
- objective,
- status,
- blockedReason,
-}: GoalStatusMessageProps) {
- const presentation = (() => {
- switch (status) {
- case 'active':
- return {
- label: 'Pursuing goal',
- Icon: LoaderCircle,
- iconClassName: 'animate-spin text-primary',
- };
- case 'complete':
- return {
- label: 'Goal completed',
- Icon: CircleCheck,
- iconClassName: 'text-green-600 dark:text-green-500',
- };
- case 'blocked':
- return {
- label: 'Goal blocked',
- Icon: CircleAlert,
- iconClassName: 'text-amber-500',
- };
- case 'budget_limited':
- return {
- label: 'Goal continuation limit reached',
- Icon: CircleAlert,
- iconClassName: 'text-amber-500',
- };
- }
- })();
- const { Icon } = presentation;
-
- return (
-
-
-
-
-
-
{presentation.label}
-
- {objective}
-
- {blockedReason ? (
-
- {blockedReason}
-
- ) : null}
-
-
-
-
- );
-}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx
index 5b0505f75..74a040022 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx
@@ -96,4 +96,77 @@ describe('TaskInputStack', () => {
expect(screen.getByTestId('prompt-input')).toBeInTheDocument();
});
+
+ it('places the durable goal panel immediately above the composer', () => {
+ render(
+ {}}
+ onCommandSearchOpen={() => {}}
+ scrollToBottom={() => {}}
+ />,
+ );
+
+ const panel = screen.getByTestId('goal-panel');
+ const composer = screen.getByTestId('prompt-input');
+ expect(panel.compareDocumentPosition(composer)).toBe(
+ Node.DOCUMENT_POSITION_FOLLOWING,
+ );
+ });
+
+ it('keeps the durable goal panel after an ordinary follow-up update', () => {
+ const task = {
+ goalObjective: 'Finish the current objective',
+ goalStatus: 'complete',
+ goalStartedAt: new Date('2026-08-14T12:00:00Z'),
+ goalEndedAt: new Date('2026-08-14T12:01:00Z'),
+ } as never;
+ const { rerender } = render(
+ {}}
+ onCommandSearchOpen={() => {}}
+ scrollToBottom={() => {}}
+ />,
+ );
+
+ rerender(
+ {}}
+ onCommandSearchOpen={() => {}}
+ scrollToBottom={() => {}}
+ />,
+ );
+
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent('Complete');
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent(
+ 'Finish the current objective',
+ );
+ });
+
+ it('does not add goal UI for a non-goal task', () => {
+ render(
+ {}}
+ onCommandSearchOpen={() => {}}
+ scrollToBottom={() => {}}
+ />,
+ );
+
+ expect(screen.queryByTestId('goal-panel')).not.toBeInTheDocument();
+ });
});
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
index 33ae60bfa..d05b3a1da 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.client.test.tsx
@@ -92,16 +92,7 @@ vi.mock('./messages/index', () => ({
}));
vi.mock('./messages/acp', () => ({
- AcpMessageItem: ({
- msg,
- }: {
- msg: { id: string; data?: { goal?: unknown } };
- }) => (
-
- {msg.id}
- {msg.data?.goal ? Sent as goal : null}
-
- ),
+ AcpMessageItem: ({ msg }: { msg: { id: string } }) => {msg.id}
,
AcpGroupedToolMessage: () => null,
AcpActivityGroupMessage: ({
group,
@@ -117,15 +108,8 @@ vi.mock('./messages/acp', () => ({
{children}
),
- AcpTextMessage: ({
- msg,
- }: {
- msg: { text?: string; data?: { goal?: unknown } };
- }) => (
-
- {msg.data?.goal ? Sent as goal : null}
- {msg.text}
-
+ AcpTextMessage: ({ msg }: { msg: { text?: string } }) => (
+ {msg.text}
),
}));
@@ -483,178 +467,9 @@ describe('Messages', () => {
);
});
- it('shows the active goal objective without expanding tool traces', () => {
- render(
- ,
- );
-
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Pursuing goal',
- );
- expect(screen.getByTestId('goal-status')).toHaveTextContent('Count to ten');
- expect(screen.getByTestId('goal-status')).toHaveAttribute('role', 'status');
- });
-
- it.each([
- ['complete', 'Goal completed'],
- ['blocked', 'Goal blocked'],
- ] as const)('shows the %s terminal goal marker', (goalStatus, label) => {
- render(
- ,
- );
-
- expect(screen.getByTestId('goal-status')).toHaveTextContent(label);
- expect(screen.getByTestId('goal-status')).toHaveTextContent('Count to ten');
- if (goalStatus === 'blocked') {
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Waiting for a number',
- );
- }
- });
-
- it('keeps a completed goal visible after an ordinary follow-up message', () => {
- mockBuildAcpRenderBlocks.mockReturnValue([
- {
- kind: 'message',
- msg: {
- id: 'ordinary-follow-up',
- ts: 2_000,
- role: 'user',
- kind: 'text',
- partial: false,
- },
- },
- ] as never);
-
- render(
- ,
- );
-
- expect(screen.getByText('ordinary-follow-up')).toBeInTheDocument();
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Goal completed',
- );
- });
-
- it.each([
- ['complete', 'Goal completed', null],
- ['blocked', 'Goal blocked', 'Waiting for a number'],
- ['budget_limited', 'Goal continuation limit reached', null],
- ] as const)(
- 'keeps the prior %s marker while an optimistic retried goal is active',
- (priorStatus, priorLabel, blockedReason) => {
- const refreshTaskSession = vi.fn();
- const previousGoal = {
- id: 'previous-goal',
- ts: 1_000,
- role: 'user',
- kind: 'text',
- partial: false,
- sessionId: 'session-1',
- updateType: 'roomote_runtime.user_prompt',
- text: 'Count to ten',
- data: {
- goal: {
- objective: 'Count to ten',
- generation: 'goal-generation:1',
- },
- },
- };
- const optimisticRetry = {
- ...previousGoal,
- id: 'optimistic-retry',
- ts: 2_000,
- data: {
- goal: { objective: 'Count to ten', generation: null },
- },
- };
- const session = {
- taskId: `task-goal-retry-${priorStatus}`,
- prompt: null,
- task: {
- goalObjective: 'Count to ten',
- goalStatus: priorStatus,
- goalBlockedReason: blockedReason,
- goalGenerationIds: ['goal-generation:1'],
- },
- taskRun: null,
- artifacts: [],
- refreshTaskSession,
- };
-
- sandboxMessagesState.messages = [previousGoal];
- mockBuildAcpRenderBlocks.mockReturnValue([
- { kind: 'message', msg: previousGoal },
- ] as never);
- const { rerender } = render();
-
- expect(screen.getByTestId('goal-status')).toHaveTextContent(priorLabel);
-
- sandboxMessagesState.messages = [previousGoal, optimisticRetry];
- mockBuildAcpRenderBlocks.mockReturnValue([
- { kind: 'message', msg: previousGoal },
- { kind: 'message', msg: optimisticRetry },
- ] as never);
- rerender();
-
- expect(screen.getAllByText('Sent as goal')).toHaveLength(2);
- expect(screen.getByText(priorLabel)).toBeVisible();
- expect(screen.getByText('Pursuing goal')).toBeVisible();
- expect(screen.getAllByText('Count to ten')).toHaveLength(2);
- expect(refreshTaskSession).toHaveBeenCalled();
- },
- );
-
- it('labels the matching historical goal turn when old envelopes lack provenance', () => {
- const goalMessage = {
- id: 'historical-goal-prompt',
+ it('never decorates the transcript from goal data or matching text', () => {
+ const matchingGoalMessage = {
+ id: 'matching-goal-message',
ts: 1_000,
role: 'user',
kind: 'text',
@@ -662,54 +477,27 @@ describe('Messages', () => {
sessionId: 'session-1',
updateType: 'roomote_runtime.user_prompt',
text: 'Count to ten',
- data: {},
+ data: {
+ goal: {
+ objective: 'Count to ten',
+ generation: 'goal-generation:1',
+ },
+ },
};
- sandboxMessagesState.messages = [goalMessage];
+ sandboxMessagesState.messages = [matchingGoalMessage];
mockBuildAcpRenderBlocks.mockReturnValue([
- { kind: 'message', msg: goalMessage },
+ { kind: 'message', msg: matchingGoalMessage },
] as never);
render(
,
- );
-
- expect(screen.getByText('Sent as goal')).toBeVisible();
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Goal completed',
- );
- });
-
- it('labels a legacy goal session prompt when no matching envelope exists', () => {
- render(
- {
},
taskRun: null,
artifacts: [],
- refreshTaskSession: vi.fn(),
- } as never
- }
- />,
- );
-
- expect(screen.getByText('Sent as goal')).toBeVisible();
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Goal completed',
- );
- });
-
- it('does not infer goal provenance when multiple legacy messages match', () => {
- const matchingMessages = [
- {
- id: 'historical-goal-prompt',
- ts: 1_000,
- role: 'user',
- kind: 'text',
- partial: false,
- sessionId: 'session-1',
- updateType: 'roomote_runtime.user_prompt',
- text: 'Count to ten',
- data: {},
- },
- {
- id: 'ordinary-duplicate-follow-up',
- ts: 2_000,
- role: 'user',
- kind: 'text',
- partial: false,
- sessionId: 'session-1',
- updateType: 'roomote_runtime.user_prompt',
- text: 'Count to ten',
- data: {},
- },
- ];
- sandboxMessagesState.messages = matchingMessages;
- mockBuildAcpRenderBlocks.mockReturnValue(
- matchingMessages.map((msg) => ({ kind: 'message', msg })) as never,
- );
-
- render(
- ,
- );
-
- expect(screen.queryByText('Sent as goal')).not.toBeInTheDocument();
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Goal completed',
- );
- });
-
- it('does not infer legacy goal provenance before history finishes loading', () => {
- const goalMessage = {
- id: 'partial-goal-prompt',
- ts: 1_000,
- role: 'user',
- kind: 'text',
- partial: false,
- sessionId: 'session-1',
- updateType: 'roomote_runtime.user_prompt',
- text: 'Count to ten',
- data: {},
- };
- historyReadyState.ready = false;
- sandboxMessagesState.messages = [goalMessage];
- mockBuildAcpRenderBlocks.mockReturnValue([
- { kind: 'message', msg: goalMessage },
- ] as never);
-
- render(
- ,
- );
-
- expect(screen.queryByText('Sent as goal')).not.toBeInTheDocument();
- expect(screen.getByTestId('goal-status')).toHaveTextContent(
- 'Pursuing goal',
- );
- });
-
- it('leaves non-goal transcripts unchanged', () => {
- render(
- ,
);
+ expect(screen.getByText('matching-goal-message')).toBeVisible();
expect(screen.queryByTestId('goal-status')).not.toBeInTheDocument();
+ expect(screen.queryByText('Sent as goal')).not.toBeInTheDocument();
+ expect(screen.queryByText('Goal completed')).not.toBeInTheDocument();
});
it('collapses eligible background activity between text messages', () => {
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
index beb2484d7..e15f76dc6 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/Messages.tsx
@@ -57,12 +57,6 @@ import { messageAnchorId } from './messages/message-anchor';
import { LazyMessage } from './LazyMessage';
import { ScrollToHash } from './ScrollToHash';
import { ScrollBridge } from './ScrollBridge';
-import type { AcpUiMessage } from './types';
-import { GoalStatusMessage } from './GoalStatusMessage';
-import {
- findLatestGoalPrompt,
- getGoalPromptProvenance,
-} from './messages/acp/goal-prompt';
export interface MessagesHandle {
scrollToBottom: ScrollToBottom;
@@ -252,100 +246,6 @@ const MessagesBase = ({
Boolean(sessionPrompt);
const resolvedHideFirstAcpUserPrompt =
hideFirstAcpUserPrompt ?? shouldRenderSessionPrompt;
- const latestGoalPrompt = useMemo(
- () => findLatestGoalPrompt(messages),
- [messages],
- );
- const inferredGoalPromptMessageId = useMemo(() => {
- if (!historyReady) {
- return null;
- }
-
- const objective = session.task?.goalObjective?.trim();
- if (!objective) {
- return null;
- }
-
- const matchingMessages = messages.filter(
- (message) =>
- message.role === 'user' && message.text?.trim() === objective,
- );
-
- return matchingMessages.length === 1 ? matchingMessages[0]!.id : null;
- }, [historyReady, messages, session.task?.goalObjective]);
- const taskGoalGenerations = session.task?.goalGenerationIds ?? [];
- const taskHasLatestGoal = latestGoalPrompt
- ? latestGoalPrompt.generation !== null &&
- taskGoalGenerations.includes(latestGoalPrompt.generation)
- : true;
- const historicalGoalStatus =
- latestGoalPrompt?.generation === null &&
- session.task?.goalObjective &&
- session.task.goalStatus &&
- session.task.goalStatus !== 'active'
- ? {
- objective: session.task.goalObjective,
- status: session.task.goalStatus,
- blockedReason: session.task.goalBlockedReason,
- }
- : null;
- const goalStatus =
- session.task?.goalObjective && session.task.goalStatus && taskHasLatestGoal
- ? {
- objective: session.task.goalObjective,
- status: session.task.goalStatus,
- blockedReason: session.task.goalBlockedReason,
- }
- : latestGoalPrompt
- ? {
- objective: latestGoalPrompt.objective,
- status: 'active' as const,
- blockedReason: null,
- }
- : null;
- const renderedSessionPrompt = useMemo(() => {
- if (!sessionPrompt) {
- return sessionPrompt;
- }
-
- const firstGoalMessage = messages.find(
- (message) =>
- message.role === 'user' &&
- message.text === sessionPrompt.text &&
- (getGoalPromptProvenance(message) !== null ||
- message.id === inferredGoalPromptMessageId),
- );
-
- const shouldInferSessionPromptGoal =
- historyReady &&
- session.task?.goalObjective?.trim() === sessionPrompt.text?.trim() &&
- !messages.some(
- (message) =>
- message.role === 'user' &&
- message.text?.trim() === session.task?.goalObjective?.trim(),
- );
-
- return firstGoalMessage
- ? ({
- ...sessionPrompt,
- data: withGoalProvenance(firstGoalMessage).data,
- } as typeof sessionPrompt)
- : shouldInferSessionPromptGoal
- ? withGoalProvenance(sessionPrompt)
- : sessionPrompt;
- }, [
- historyReady,
- inferredGoalPromptMessageId,
- messages,
- session.task?.goalObjective,
- sessionPrompt,
- ]);
-
- useEffect(() => {
- if (latestGoalPrompt && !taskHasLatestGoal) {
- void session.refreshTaskSession?.();
- }
- }, [latestGoalPrompt, session, taskHasLatestGoal]);
const renderBlocks = useMemo(() => {
const acpBlocks = buildAcpRenderBlocks(messages, {
@@ -480,13 +380,9 @@ const MessagesBase = ({
);
}
- const message =
- block.msg.id === inferredGoalPromptMessageId
- ? withGoalProvenance(block.msg)
- : block.msg;
const content = (
@@ -526,14 +422,10 @@ const MessagesBase = ({
className={cn('ph-no-capture', conversationClassName)}
>
{shouldRenderSessionPrompt && sessionPrompt && (
-
+
)}
{!historyReady && }
{renderBlocks.map((block) => renderRenderBlock(block, false))}
- {historicalGoalStatus ? (
-
- ) : null}
- {goalStatus ? : null}
{session.taskRun && }
{shouldShowNarrationWorkingReasoning && (
@@ -573,25 +465,6 @@ function collectBlockAnchorIds(
return anchorIds;
}
-function withGoalProvenance(message: AcpUiMessage): AcpUiMessage {
- if (getGoalPromptProvenance(message)) {
- return message;
- }
-
- const objective = message.text?.trim();
- if (!objective) {
- return message;
- }
-
- return {
- ...message,
- data: {
- ...message.data,
- goal: { objective, generation: null },
- },
- } as AcpUiMessage;
-}
-
function collectBlockAnchorIdsInto(
blocks: AcpRenderBlock[],
pushAnchor: (anchorId: string) => void,
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/TaskInputStack.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/TaskInputStack.tsx
index fb9f1e11a..94ea989c7 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/TaskInputStack.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/TaskInputStack.tsx
@@ -12,6 +12,7 @@ import { PromptInput, type PromptInputHandle } from './prompt-input';
import { QueuedMessages } from './QueuedMessages';
import { ActiveSubtasksList } from './ActiveSubtasksList';
import { TodoList } from './TodoList';
+import { GoalPanel } from './GoalPanel';
export function TaskInputStack({
session,
@@ -49,6 +50,7 @@ export function TaskInputStack({
onVisibleRequestKeyChange={setVisibleEnvVarRequestKey}
/>
+
{!isBooting && (
}
/>
) : isUser ? (
-
- {goalPrompt ? (
-
-
- Sent as goal
-
- ) : null}
-
-
- {requestUserInputResponse ? (
- <>
- {requestUserInputResponse.title ? (
-
- {requestUserInputResponse.title}
-
- ) : null}
- {requestUserInputResponse.questionTexts.map(
- (questionText, index) => (
-
- {questionText}
-
- ),
- )}
- {baseContent}
- >
- ) : (
- baseContent
- )}
-
-
-
+
+
+ {requestUserInputResponse ? (
+ <>
+ {requestUserInputResponse.title ? (
+
+ {requestUserInputResponse.title}
+
+ ) : null}
+ {requestUserInputResponse.questionTexts.map(
+ (questionText, index) => (
+
+ {questionText}
+
+ ),
+ )}
+ {baseContent}
+ >
+ ) : (
+ baseContent
+ )}
+
+
) : (
{content}
)}
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx
index 5b53f1045..db6c9db6b 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/__tests__/AcpTextMessage.client.test.tsx
@@ -328,7 +328,7 @@ describe('AcpTextMessage', () => {
).toBeVisible();
});
- it('labels a user prompt that was sent as a goal', () => {
+ it('does not decorate a user prompt with persisted goal provenance', () => {
render(
{
/>,
);
- expect(screen.getByTestId('goal-origin')).toHaveTextContent('Sent as goal');
expect(screen.getByText('Count to ten')).toBeVisible();
- });
-
- it('does not label an ordinary user prompt as a goal', () => {
- render(
- ,
- );
-
expect(screen.queryByTestId('goal-origin')).not.toBeInTheDocument();
+ expect(screen.queryByText('Sent as goal')).not.toBeInTheDocument();
});
it('renders user text as plain text instead of markdown', () => {
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts b/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
deleted file mode 100644
index 705343ebf..000000000
--- a/apps/web/src/app/(sandbox)/task/[taskId]/messages/acp/goal-prompt.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import type { AcpUiMessage } from './types';
-
-interface GoalPromptProvenance {
- objective: string;
- generation: string | null;
-}
-
-export function getGoalPromptProvenance(
- message: AcpUiMessage,
-): GoalPromptProvenance | null {
- const data = message.data as Record;
- if (message.role !== 'user' || !data.goal) {
- return null;
- }
-
- const goal = data.goal;
- if (!goal || typeof goal !== 'object') {
- return null;
- }
-
- const objective = Reflect.get(goal, 'objective');
- const generation = Reflect.get(goal, 'generation');
-
- if (
- typeof objective !== 'string' ||
- objective.trim().length === 0 ||
- (generation !== null && typeof generation !== 'string')
- ) {
- return null;
- }
-
- return { objective, generation };
-}
-
-export function findLatestGoalPrompt(
- messages: AcpUiMessage[],
-): GoalPromptProvenance | null {
- for (let index = messages.length - 1; index >= 0; index -= 1) {
- const goal = getGoalPromptProvenance(messages[index]!);
- if (goal) {
- return goal;
- }
- }
-
- return null;
-}
diff --git a/apps/web/src/types/task.ts b/apps/web/src/types/task.ts
index 0e1d6f63e..df4d325c5 100644
--- a/apps/web/src/types/task.ts
+++ b/apps/web/src/types/task.ts
@@ -51,6 +51,8 @@ export const taskSchema = z.object({
goalObjective: z.string().nullable().optional(),
goalStatus: z.enum(TASK_GOAL_STATUSES).nullable().optional(),
goalBlockedReason: z.string().nullable().optional(),
+ goalStartedAt: z.coerce.date().nullable().optional(),
+ goalEndedAt: z.coerce.date().nullable().optional(),
goalGenerationIds: z.array(z.string()).optional(),
slackChannelId: z.string().nullable().optional(),
slackThreadTs: z.string().nullable().optional(),
diff --git a/apps/worker/src/mcp/roomote-mcp-server/types.ts b/apps/worker/src/mcp/roomote-mcp-server/types.ts
index 05c15bac2..2d244ee1c 100644
--- a/apps/worker/src/mcp/roomote-mcp-server/types.ts
+++ b/apps/worker/src/mcp/roomote-mcp-server/types.ts
@@ -75,6 +75,8 @@ export interface TaskSummaryResponse {
maxContinuations: number | null;
continuationsUsed: number;
blockedReason: string | null;
+ startedAt?: string | null;
+ endedAt?: string | null;
completedAt: string | null;
generation: string | null;
} | null;
diff --git a/packages/cloud-agents/src/server/__tests__/enqueue-task.test.ts b/packages/cloud-agents/src/server/__tests__/enqueue-task.test.ts
index 716034dc5..641c7655f 100644
--- a/packages/cloud-agents/src/server/__tests__/enqueue-task.test.ts
+++ b/packages/cloud-agents/src/server/__tests__/enqueue-task.test.ts
@@ -231,6 +231,8 @@ describe('enqueueTask initiator stamping', () => {
goalLastContinuationId: expect.stringMatching(/^goal-generation:/),
goalGenerationIds: [expect.stringMatching(/^goal-generation:/)],
goalStatus: 'active',
+ goalStartedAt: expect.any(Date),
+ goalEndedAt: null,
goalMaxContinuations: 4,
goalContinuationsUsed: 0,
});
diff --git a/packages/cloud-agents/src/server/task-run-queue.ts b/packages/cloud-agents/src/server/task-run-queue.ts
index 6baa2b5cb..a4fbb2b60 100644
--- a/packages/cloud-agents/src/server/task-run-queue.ts
+++ b/packages/cloud-agents/src/server/task-run-queue.ts
@@ -1539,6 +1539,7 @@ async function enqueueFreshLaunch(
prompt: initialPrompt,
goalObjective: input.goal?.objective ?? null,
goalStatus: input.goal ? 'active' : null,
+ goalStartedAt: input.goal ? new Date() : null,
goalMaxContinuations: input.goal?.maxContinuations ?? null,
goalLastContinuationId: initialGoalGeneration,
goalGenerationIds: initialGoalGeneration ? [initialGoalGeneration] : [],
diff --git a/packages/db/drizzle/0038_perfect_madame_hydra.sql b/packages/db/drizzle/0038_perfect_madame_hydra.sql
new file mode 100644
index 000000000..7ed2242b0
--- /dev/null
+++ b/packages/db/drizzle/0038_perfect_madame_hydra.sql
@@ -0,0 +1,2 @@
+ALTER TABLE "tasks" ADD COLUMN "goal_started_at" timestamp;--> statement-breakpoint
+ALTER TABLE "tasks" ADD COLUMN "goal_ended_at" timestamp;
\ No newline at end of file
diff --git a/packages/db/drizzle/meta/0038_snapshot.json b/packages/db/drizzle/meta/0038_snapshot.json
new file mode 100644
index 000000000..b095234b7
--- /dev/null
+++ b/packages/db/drizzle/meta/0038_snapshot.json
@@ -0,0 +1,10922 @@
+{
+ "id": "b590e8c9-c722-4bff-9855-0b9cf48bb2f9",
+ "prevId": "7f03804c-75a9-46f1-8b6e-0b50270b72cc",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.auth_accounts": {
+ "name": "auth_accounts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "password": {
+ "name": "password",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "auth_accounts_user_id_idx": {
+ "name": "auth_accounts_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "auth_accounts_provider_account_unique": {
+ "name": "auth_accounts_provider_account_unique",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "account_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "auth_accounts_user_id_auth_users_id_fk": {
+ "name": "auth_accounts_user_id_auth_users_id_fk",
+ "tableFrom": "auth_accounts",
+ "tableTo": "auth_users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.auth_sessions": {
+ "name": "auth_sessions",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "ip_address": {
+ "name": "ip_address",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "auth_sessions_token_unique": {
+ "name": "auth_sessions_token_unique",
+ "columns": [
+ {
+ "expression": "token",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "auth_sessions_user_id_idx": {
+ "name": "auth_sessions_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "auth_sessions_user_id_auth_users_id_fk": {
+ "name": "auth_sessions_user_id_auth_users_id_fk",
+ "tableFrom": "auth_sessions",
+ "tableTo": "auth_users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.auth_users": {
+ "name": "auth_users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email_verified": {
+ "name": "email_verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "auth_users_email_unique": {
+ "name": "auth_users_email_unique",
+ "columns": [
+ {
+ "expression": "email",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "auth_users_created_at_idx": {
+ "name": "auth_users_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.auth_verifications": {
+ "name": "auth_verifications",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "auth_verifications_identifier_idx": {
+ "name": "auth_verifications_identifier_idx",
+ "columns": [
+ {
+ "expression": "identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.automations": {
+ "name": "automations",
+ "schema": "",
+ "columns": {
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "internal": {
+ "name": "internal",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "schedule": {
+ "name": "schedule",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "instructions": {
+ "name": "instructions",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "settings": {
+ "name": "settings",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "targets": {
+ "name": "targets",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "last_run_at": {
+ "name": "last_run_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_succeeded_at": {
+ "name": "last_succeeded_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_failed_at": {
+ "name": "last_failed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error": {
+ "name": "last_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scan_cursor": {
+ "name": "scan_cursor",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.compute_provider_usage": {
+ "name": "compute_provider_usage",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_usage_id": {
+ "name": "provider_usage_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "auth_kind": {
+ "name": "auth_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instance_id": {
+ "name": "instance_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "launch_mode": {
+ "name": "launch_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lifecycle_action": {
+ "name": "lifecycle_action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "measurement_source": {
+ "name": "measurement_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "configured_vcpus": {
+ "name": "configured_vcpus",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "configured_cpu_cores": {
+ "name": "configured_cpu_cores",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "configured_memory_mib": {
+ "name": "configured_memory_mib",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "wall_clock_duration_ms": {
+ "name": "wall_clock_duration_ms",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "active_cpu_duration_ms": {
+ "name": "active_cpu_duration_ms",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "observed_memory_mib_milliseconds": {
+ "name": "observed_memory_mib_milliseconds",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "network_ingress_bytes": {
+ "name": "network_ingress_bytes",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "network_egress_bytes": {
+ "name": "network_egress_bytes",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "details": {
+ "name": "details",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "compute_provider_usage_provider_usage_id_unique": {
+ "name": "compute_provider_usage_provider_usage_id_unique",
+ "columns": [
+ {
+ "expression": "provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_usage_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compute_provider_usage_run_id_idx": {
+ "name": "compute_provider_usage_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compute_provider_usage_task_id_idx": {
+ "name": "compute_provider_usage_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compute_provider_usage_created_at_idx": {
+ "name": "compute_provider_usage_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "compute_provider_usage_run_id_task_runs_id_fk": {
+ "name": "compute_provider_usage_run_id_task_runs_id_fk",
+ "tableFrom": "compute_provider_usage",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "compute_provider_usage_task_id_tasks_id_fk": {
+ "name": "compute_provider_usage_task_id_tasks_id_fk",
+ "tableFrom": "compute_provider_usage",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.compute_provider_usage_samples": {
+ "name": "compute_provider_usage_samples",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_usage_id": {
+ "name": "provider_usage_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instance_id": {
+ "name": "instance_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sampled_at": {
+ "name": "sampled_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "cpu_usage_ns_total": {
+ "name": "cpu_usage_ns_total",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "memory_usage_bytes": {
+ "name": "memory_usage_bytes",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "memory_peak_usage_bytes": {
+ "name": "memory_peak_usage_bytes",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "details": {
+ "name": "details",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "compute_provider_usage_samples_provider_usage_sampled_at_unique": {
+ "name": "compute_provider_usage_samples_provider_usage_sampled_at_unique",
+ "columns": [
+ {
+ "expression": "provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider_usage_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "sampled_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compute_provider_usage_samples_run_id_idx": {
+ "name": "compute_provider_usage_samples_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compute_provider_usage_samples_task_id_idx": {
+ "name": "compute_provider_usage_samples_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "compute_provider_usage_samples_created_at_idx": {
+ "name": "compute_provider_usage_samples_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "compute_provider_usage_samples_run_id_task_runs_id_fk": {
+ "name": "compute_provider_usage_samples_run_id_task_runs_id_fk",
+ "tableFrom": "compute_provider_usage_samples",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "compute_provider_usage_samples_task_id_tasks_id_fk": {
+ "name": "compute_provider_usage_samples_task_id_tasks_id_fk",
+ "tableFrom": "compute_provider_usage_samples",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.custom_automations": {
+ "name": "custom_automations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "prompt": {
+ "name": "prompt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "schedule_mode": {
+ "name": "schedule_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'off'"
+ },
+ "cron_expression": {
+ "name": "cron_expression",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "model": {
+ "name": "model",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "all_repositories": {
+ "name": "all_repositories",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "target": {
+ "name": "target",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "created_by_user_id": {
+ "name": "created_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_run_at": {
+ "name": "last_run_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_succeeded_at": {
+ "name": "last_succeeded_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_failed_at": {
+ "name": "last_failed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error": {
+ "name": "last_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_launched_task_id": {
+ "name": "last_launched_task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "launch_claimed_at": {
+ "name": "launch_claimed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "custom_automations_name_unique_idx": {
+ "name": "custom_automations_name_unique_idx",
+ "columns": [
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "custom_automations_enabled_idx": {
+ "name": "custom_automations_enabled_idx",
+ "columns": [
+ {
+ "expression": "enabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "custom_automations_environment_id_idx": {
+ "name": "custom_automations_environment_id_idx",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "custom_automations_environment_id_environments_id_fk": {
+ "name": "custom_automations_environment_id_environments_id_fk",
+ "tableFrom": "custom_automations",
+ "tableTo": "environments",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "custom_automations_created_by_user_id_users_id_fk": {
+ "name": "custom_automations_created_by_user_id_users_id_fk",
+ "tableFrom": "custom_automations",
+ "tableTo": "users",
+ "columnsFrom": ["created_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "custom_automations_last_launched_task_id_tasks_id_fk": {
+ "name": "custom_automations_last_launched_task_id_tasks_id_fk",
+ "tableFrom": "custom_automations",
+ "tableTo": "tasks",
+ "columnsFrom": ["last_launched_task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.custom_mcp_servers": {
+ "name": "custom_mcp_servers",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "auth_type": {
+ "name": "auth_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'none'"
+ },
+ "headers": {
+ "name": "headers",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "stdio": {
+ "name": "stdio",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "disabled_tools": {
+ "name": "disabled_tools",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "manual_client_id": {
+ "name": "manual_client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "manual_client_secret": {
+ "name": "manual_client_secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_server_metadata": {
+ "name": "oauth_server_metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_server_metadata_fetched_at": {
+ "name": "oauth_server_metadata_fetched_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_resource_indicator_disabled": {
+ "name": "oauth_resource_indicator_disabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "created_by_user_id": {
+ "name": "created_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "custom_mcp_servers_created_by_user_id_users_id_fk": {
+ "name": "custom_mcp_servers_created_by_user_id_users_id_fk",
+ "tableFrom": "custom_mcp_servers",
+ "tableTo": "users",
+ "columnsFrom": ["created_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "custom_mcp_servers_name_unique": {
+ "name": "custom_mcp_servers_name_unique",
+ "nullsNotDistinct": false,
+ "columns": ["name"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.deployment_mcp_enablements": {
+ "name": "deployment_mcp_enablements",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "mcp_id": {
+ "name": "mcp_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "enabled_by_user_id": {
+ "name": "enabled_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "disabled_tools": {
+ "name": "disabled_tools",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "deployment_mcp_enablements_enabled_by_user_id_users_id_fk": {
+ "name": "deployment_mcp_enablements_enabled_by_user_id_users_id_fk",
+ "tableFrom": "deployment_mcp_enablements",
+ "tableTo": "users",
+ "columnsFrom": ["enabled_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "deployment_mcp_enablements_mcp_unique": {
+ "name": "deployment_mcp_enablements_mcp_unique",
+ "nullsNotDistinct": false,
+ "columns": ["mcp_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.deployment_secrets": {
+ "name": "deployment_secrets",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "deployment_secrets_name_unique": {
+ "name": "deployment_secrets_name_unique",
+ "columns": [
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.deployment_settings": {
+ "name": "deployment_settings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "'default'"
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "task_model_settings": {
+ "name": "task_model_settings",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "workspace_routing_settings": {
+ "name": "workspace_routing_settings",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "router_debug_provider": {
+ "name": "router_debug_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "router_debug_channel_id": {
+ "name": "router_debug_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "router_debug_disabled": {
+ "name": "router_debug_disabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "router_debug_slack_channel_id": {
+ "name": "router_debug_slack_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "runtime_model_config": {
+ "name": "runtime_model_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "runtime_compute_config": {
+ "name": "runtime_compute_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_policy": {
+ "name": "access_policy",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "license_key": {
+ "name": "license_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "license_cloud_state": {
+ "name": "license_cloud_state",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "instance_analytics_id": {
+ "name": "instance_analytics_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "latest_known_version": {
+ "name": "latest_known_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "latest_version_checked_at": {
+ "name": "latest_version_checked_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "setup_completed_at": {
+ "name": "setup_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "setup_new_state": {
+ "name": "setup_new_state",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_onboarding_stage": {
+ "name": "slack_onboarding_stage",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "manager_slack_channel_id": {
+ "name": "manager_slack_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "manager_discord_channel_id": {
+ "name": "manager_discord_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "global_agent_instructions": {
+ "name": "global_agent_instructions",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "time_zone": {
+ "name": "time_zone",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "time_zone_updated_at": {
+ "name": "time_zone_updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "authorship_instructions": {
+ "name": "authorship_instructions",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "compiled_authorship_rules": {
+ "name": "compiled_authorship_rules",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "compiled_authorship_issues": {
+ "name": "compiled_authorship_issues",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "compiled_authorship_at": {
+ "name": "compiled_authorship_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "style_guidance": {
+ "name": "style_guidance",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_summon_emoji": {
+ "name": "slack_summon_emoji",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_ack_emoji": {
+ "name": "slack_ack_emoji",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'eyes'"
+ },
+ "slack_completion_emoji": {
+ "name": "slack_completion_emoji",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'white_check_mark'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.discord_gateway_sessions": {
+ "name": "discord_gateway_sessions",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "session_id": {
+ "name": "session_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "resume_gateway_url": {
+ "name": "resume_gateway_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sequence": {
+ "name": "sequence",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "shard_count": {
+ "name": "shard_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_connected_at": {
+ "name": "last_connected_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_heartbeat_ack_at": {
+ "name": "last_heartbeat_ack_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "disconnected_at": {
+ "name": "disconnected_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error": {
+ "name": "last_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.discord_installation_channels": {
+ "name": "discord_installation_channels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "discord_installation_id": {
+ "name": "discord_installation_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel_id": {
+ "name": "channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel_name": {
+ "name": "channel_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "channel_type": {
+ "name": "channel_type",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "position": {
+ "name": "position",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "permissions": {
+ "name": "permissions",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_available": {
+ "name": "is_available",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "discord_installation_channels_installation_id_idx": {
+ "name": "discord_installation_channels_installation_id_idx",
+ "columns": [
+ {
+ "expression": "discord_installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "discord_installation_channels_unique": {
+ "name": "discord_installation_channels_unique",
+ "columns": [
+ {
+ "expression": "discord_installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "discord_installation_channels_discord_installation_id_discord_installations_id_fk": {
+ "name": "discord_installation_channels_discord_installation_id_discord_installations_id_fk",
+ "tableFrom": "discord_installation_channels",
+ "tableTo": "discord_installations",
+ "columnsFrom": ["discord_installation_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.discord_installations": {
+ "name": "discord_installations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "guild_id": {
+ "name": "guild_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "guild_name": {
+ "name": "guild_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "application_id": {
+ "name": "application_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bot_user_id": {
+ "name": "bot_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "installed_by_user_id": {
+ "name": "installed_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "default_channel_id": {
+ "name": "default_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "default_channel_name": {
+ "name": "default_channel_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "default_channel_type": {
+ "name": "default_channel_type",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_active": {
+ "name": "is_active",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "last_seen_at": {
+ "name": "last_seen_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_used_at": {
+ "name": "last_used_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "discord_installations_guild_id_unique": {
+ "name": "discord_installations_guild_id_unique",
+ "columns": [
+ {
+ "expression": "guild_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "discord_installations_active_idx": {
+ "name": "discord_installations_active_idx",
+ "columns": [
+ {
+ "expression": "is_active",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "discord_installations_default_channel_idx": {
+ "name": "discord_installations_default_channel_idx",
+ "columns": [
+ {
+ "expression": "default_channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "discord_installations_installed_by_user_id_users_id_fk": {
+ "name": "discord_installations_installed_by_user_id_users_id_fk",
+ "tableFrom": "discord_installations",
+ "tableTo": "users",
+ "columnsFrom": ["installed_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.discord_user_mappings": {
+ "name": "discord_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "discord_user_id": {
+ "name": "discord_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "discord_username": {
+ "name": "discord_username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "discord_global_name": {
+ "name": "discord_global_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "discord_dm_channel_id": {
+ "name": "discord_dm_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "discord_user_mappings_user_id_idx": {
+ "name": "discord_user_mappings_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "discord_user_mappings_discord_user_id_unique": {
+ "name": "discord_user_mappings_discord_user_id_unique",
+ "columns": [
+ {
+ "expression": "discord_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "discord_user_mappings_user_id_users_id_fk": {
+ "name": "discord_user_mappings_user_id_users_id_fk",
+ "tableFrom": "discord_user_mappings",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.environment_config_versions": {
+ "name": "environment_config_versions",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "config": {
+ "name": "config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_by_user_id": {
+ "name": "created_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "environment_config_versions_environment_id_idx": {
+ "name": "environment_config_versions_environment_id_idx",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environment_config_versions_environment_version_unique": {
+ "name": "environment_config_versions_environment_version_unique",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "version",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_config_versions_environment_id_environments_id_fk": {
+ "name": "environment_config_versions_environment_id_environments_id_fk",
+ "tableFrom": "environment_config_versions",
+ "tableTo": "environments",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_config_versions_created_by_user_id_users_id_fk": {
+ "name": "environment_config_versions_created_by_user_id_users_id_fk",
+ "tableFrom": "environment_config_versions",
+ "tableTo": "users",
+ "columnsFrom": ["created_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.environment_repository_mappings": {
+ "name": "environment_repository_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "repository_id": {
+ "name": "repository_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "env_repo_mappings_env_id_idx": {
+ "name": "env_repo_mappings_env_id_idx",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "env_repo_mappings_repo_id_idx": {
+ "name": "env_repo_mappings_repo_id_idx",
+ "columns": [
+ {
+ "expression": "repository_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_repository_mappings_environment_id_environments_id_fk": {
+ "name": "environment_repository_mappings_environment_id_environments_id_fk",
+ "tableFrom": "environment_repository_mappings",
+ "tableTo": "environments",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_repository_mappings_repository_id_repositories_id_fk": {
+ "name": "environment_repository_mappings_repository_id_repositories_id_fk",
+ "tableFrom": "environment_repository_mappings",
+ "tableTo": "repositories",
+ "columnsFrom": ["repository_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "env_repo_mappings_unique": {
+ "name": "env_repo_mappings_unique",
+ "nullsNotDistinct": false,
+ "columns": ["environment_id", "repository_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.environment_snapshots": {
+ "name": "environment_snapshots",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "snapshot_id": {
+ "name": "snapshot_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_created_at": {
+ "name": "snapshot_created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_expires_at": {
+ "name": "snapshot_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_status": {
+ "name": "snapshot_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "environment_snapshots_environment_id_idx": {
+ "name": "environment_snapshots_environment_id_idx",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environment_snapshots_env_provider_unique": {
+ "name": "environment_snapshots_env_provider_unique",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "where": "\"environment_snapshots\".\"deleted_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_snapshots_environment_id_environments_id_fk": {
+ "name": "environment_snapshots_environment_id_environments_id_fk",
+ "tableFrom": "environment_snapshots",
+ "tableTo": "environments",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.environment_variables": {
+ "name": "environment_variables",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_by_user_id": {
+ "name": "created_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_updated_by_user_id": {
+ "name": "last_updated_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "environment_variables_user_id_idx": {
+ "name": "environment_variables_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environment_variables_name_unique": {
+ "name": "environment_variables_name_unique",
+ "columns": [
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environment_variables_user_id_users_id_fk": {
+ "name": "environment_variables_user_id_users_id_fk",
+ "tableFrom": "environment_variables",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environment_variables_created_by_user_id_users_id_fk": {
+ "name": "environment_variables_created_by_user_id_users_id_fk",
+ "tableFrom": "environment_variables",
+ "tableTo": "users",
+ "columnsFrom": ["created_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "environment_variables_last_updated_by_user_id_users_id_fk": {
+ "name": "environment_variables_last_updated_by_user_id_users_id_fk",
+ "tableFrom": "environment_variables",
+ "tableTo": "users",
+ "columnsFrom": ["last_updated_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.environments": {
+ "name": "environments",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_user_id": {
+ "name": "created_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "config": {
+ "name": "config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "is_eval": {
+ "name": "is_eval",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "declarative_source": {
+ "name": "declarative_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_verified": {
+ "name": "is_verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "verification_task_id": {
+ "name": "verification_task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "verified_at": {
+ "name": "verified_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "verification_error": {
+ "name": "verification_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_id": {
+ "name": "snapshot_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_created_at": {
+ "name": "snapshot_created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_expires_at": {
+ "name": "snapshot_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_status": {
+ "name": "snapshot_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "environments_user_id_idx": {
+ "name": "environments_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environments_created_by_user_id_idx": {
+ "name": "environments_created_by_user_id_idx",
+ "columns": [
+ {
+ "expression": "created_by_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environments_snapshot_expires_at_idx": {
+ "name": "environments_snapshot_expires_at_idx",
+ "columns": [
+ {
+ "expression": "snapshot_expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "environments_name_unique": {
+ "name": "environments_name_unique",
+ "columns": [
+ {
+ "expression": "name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "environments_user_id_users_id_fk": {
+ "name": "environments_user_id_users_id_fk",
+ "tableFrom": "environments",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "environments_created_by_user_id_users_id_fk": {
+ "name": "environments_created_by_user_id_users_id_fk",
+ "tableFrom": "environments",
+ "tableTo": "users",
+ "columnsFrom": ["created_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.github_installations": {
+ "name": "github_installations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "app_id": {
+ "name": "app_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "account_login": {
+ "name": "account_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "account_type": {
+ "name": "account_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "permissions": {
+ "name": "permissions",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "installed_by_user_id": {
+ "name": "installed_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "members_count": {
+ "name": "members_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "suspended_at": {
+ "name": "suspended_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "github_installations_account_login_idx": {
+ "name": "github_installations_account_login_idx",
+ "columns": [
+ {
+ "expression": "account_login",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "github_installations_deployment_installation_unique": {
+ "name": "github_installations_deployment_installation_unique",
+ "columns": [
+ {
+ "expression": "installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "github_installations_user_id_users_id_fk": {
+ "name": "github_installations_user_id_users_id_fk",
+ "tableFrom": "github_installations",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "github_installations_installed_by_user_id_users_id_fk": {
+ "name": "github_installations_installed_by_user_id_users_id_fk",
+ "tableFrom": "github_installations",
+ "tableTo": "users",
+ "columnsFrom": ["installed_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.github_pending_installations": {
+ "name": "github_pending_installations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "requested_by_user_id": {
+ "name": "requested_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "app_id": {
+ "name": "app_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "github_pending_installations_requested_by_user_id_idx": {
+ "name": "github_pending_installations_requested_by_user_id_idx",
+ "columns": [
+ {
+ "expression": "requested_by_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "github_pending_installations_user_id_users_id_fk": {
+ "name": "github_pending_installations_user_id_users_id_fk",
+ "tableFrom": "github_pending_installations",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "github_pending_installations_requested_by_user_id_users_id_fk": {
+ "name": "github_pending_installations_requested_by_user_id_users_id_fk",
+ "tableFrom": "github_pending_installations",
+ "tableTo": "users",
+ "columnsFrom": ["requested_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.github_user_mappings": {
+ "name": "github_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "github_login": {
+ "name": "github_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "github_user_id": {
+ "name": "github_user_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "token_expires_at": {
+ "name": "token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "github_user_mappings_github_login_idx": {
+ "name": "github_user_mappings_github_login_idx",
+ "columns": [
+ {
+ "expression": "github_login",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "github_user_mappings_user_id_idx": {
+ "name": "github_user_mappings_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "github_user_mappings_user_id_users_id_fk": {
+ "name": "github_user_mappings_user_id_users_id_fk",
+ "tableFrom": "github_user_mappings",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "github_user_mappings_unique": {
+ "name": "github_user_mappings_unique",
+ "nullsNotDistinct": false,
+ "columns": ["github_user_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.invites": {
+ "name": "invites",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "invited_by_user_id": {
+ "name": "invited_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'member'"
+ },
+ "max_uses": {
+ "name": "max_uses",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "used_count": {
+ "name": "used_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "revoked_at": {
+ "name": "revoked_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "invites_token_hash_unique": {
+ "name": "invites_token_hash_unique",
+ "columns": [
+ {
+ "expression": "token_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "invites_created_at_idx": {
+ "name": "invites_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "invites_invited_by_user_id_users_id_fk": {
+ "name": "invites_invited_by_user_id_users_id_fk",
+ "tableFrom": "invites",
+ "tableTo": "users",
+ "columnsFrom": ["invited_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.license_usage_observations": {
+ "name": "license_usage_observations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "observed_at": {
+ "name": "observed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "active_users": {
+ "name": "active_users",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "delivered_at": {
+ "name": "delivered_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "attempts": {
+ "name": "attempts",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "last_attempted_at": {
+ "name": "last_attempted_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "license_usage_observations_pending_idx": {
+ "name": "license_usage_observations_pending_idx",
+ "columns": [
+ {
+ "expression": "delivered_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "observed_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.linear_pending_selections": {
+ "name": "linear_pending_selections",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "session_id": {
+ "name": "session_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "linear_organization_id": {
+ "name": "linear_organization_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "step": {
+ "name": "step",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'awaiting_workspace'"
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "selected_repo": {
+ "name": "selected_repo",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "workspace_options": {
+ "name": "workspace_options",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "linear_pending_selections_expires_at_idx": {
+ "name": "linear_pending_selections_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "linear_pending_selections_step_idx": {
+ "name": "linear_pending_selections_step_idx",
+ "columns": [
+ {
+ "expression": "step",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "linear_pending_selections_user_id_users_id_fk": {
+ "name": "linear_pending_selections_user_id_users_id_fk",
+ "tableFrom": "linear_pending_selections",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "linear_pending_selections_session_id_unique": {
+ "name": "linear_pending_selections_session_id_unique",
+ "nullsNotDistinct": false,
+ "columns": ["session_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_inference_usage_events": {
+ "name": "task_inference_usage_events",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'opencode'"
+ },
+ "usage_type": {
+ "name": "usage_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'inference'"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "event_key": {
+ "name": "event_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "harness_session_id": {
+ "name": "harness_session_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "message_id": {
+ "name": "message_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "model_id": {
+ "name": "model_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "agent": {
+ "name": "agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "input_tokens": {
+ "name": "input_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "output_tokens": {
+ "name": "output_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "reasoning_tokens": {
+ "name": "reasoning_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "cache_read_tokens": {
+ "name": "cache_read_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "cache_write_tokens": {
+ "name": "cache_write_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "total_tokens": {
+ "name": "total_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "context_tokens": {
+ "name": "context_tokens",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "cost_micro_usd": {
+ "name": "cost_micro_usd",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "cost_source": {
+ "name": "cost_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pricing_metadata": {
+ "name": "pricing_metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "message_created_at": {
+ "name": "message_created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "message_completed_at": {
+ "name": "message_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "details": {
+ "name": "details",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_inference_usage_events_session_message_unique": {
+ "name": "task_inference_usage_events_session_message_unique",
+ "columns": [
+ {
+ "expression": "harness_session_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "message_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_event_key_unique": {
+ "name": "task_inference_usage_events_event_key_unique",
+ "columns": [
+ {
+ "expression": "event_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_task_id_idx": {
+ "name": "task_inference_usage_events_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_run_id_idx": {
+ "name": "task_inference_usage_events_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_user_id_idx": {
+ "name": "task_inference_usage_events_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_environment_id_idx": {
+ "name": "task_inference_usage_events_environment_id_idx",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_provider_model_idx": {
+ "name": "task_inference_usage_events_provider_model_idx",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "model_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_inference_usage_events_created_at_idx": {
+ "name": "task_inference_usage_events_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_inference_usage_events_task_id_tasks_id_fk": {
+ "name": "task_inference_usage_events_task_id_tasks_id_fk",
+ "tableFrom": "task_inference_usage_events",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_inference_usage_events_run_id_task_runs_id_fk": {
+ "name": "task_inference_usage_events_run_id_task_runs_id_fk",
+ "tableFrom": "task_inference_usage_events",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "task_inference_usage_events_user_id_users_id_fk": {
+ "name": "task_inference_usage_events_user_id_users_id_fk",
+ "tableFrom": "task_inference_usage_events",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "task_inference_usage_events_environment_id_environments_id_fk": {
+ "name": "task_inference_usage_events_environment_id_environments_id_fk",
+ "tableFrom": "task_inference_usage_events",
+ "tableTo": "environments",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mcp_connections": {
+ "name": "mcp_connections",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mcp_id": {
+ "name": "mcp_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_role": {
+ "name": "connection_role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'default'"
+ },
+ "auth_config": {
+ "name": "auth_config",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "auth_status": {
+ "name": "auth_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "token_expires_at": {
+ "name": "token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scopes": {
+ "name": "scopes",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "mcp_connections_user_id_idx": {
+ "name": "mcp_connections_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "mcp_connections_role_idx": {
+ "name": "mcp_connections_role_idx",
+ "columns": [
+ {
+ "expression": "mcp_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "connection_role",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mcp_connections_user_id_users_id_fk": {
+ "name": "mcp_connections_user_id_users_id_fk",
+ "tableFrom": "mcp_connections",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mcp_connections_user_mcp_id_unique": {
+ "name": "mcp_connections_user_mcp_id_unique",
+ "nullsNotDistinct": true,
+ "columns": ["user_id", "mcp_id", "connection_role"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mcp_oauth_replays": {
+ "name": "mcp_oauth_replays",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mcp_id": {
+ "name": "mcp_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_role": {
+ "name": "connection_role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'default'"
+ },
+ "session_id": {
+ "name": "session_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "redirect_to": {
+ "name": "redirect_to",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "mcp_oauth_replays_connection_id_idx": {
+ "name": "mcp_oauth_replays_connection_id_idx",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "mcp_oauth_replays_user_id_idx": {
+ "name": "mcp_oauth_replays_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "mcp_oauth_replays_expires_at_idx": {
+ "name": "mcp_oauth_replays_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mcp_oauth_replays_connection_id_mcp_connections_id_fk": {
+ "name": "mcp_oauth_replays_connection_id_mcp_connections_id_fk",
+ "tableFrom": "mcp_oauth_replays",
+ "tableTo": "mcp_connections",
+ "columnsFrom": ["connection_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "mcp_oauth_replays_user_id_users_id_fk": {
+ "name": "mcp_oauth_replays_user_id_users_id_fk",
+ "tableFrom": "mcp_oauth_replays",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mcp_oauth_replays_token_unique": {
+ "name": "mcp_oauth_replays_token_unique",
+ "nullsNotDistinct": false,
+ "columns": ["token"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.microsoft_auth_user_mappings": {
+ "name": "microsoft_auth_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "auth_account_id": {
+ "name": "auth_account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "microsoft_tenant_id": {
+ "name": "microsoft_tenant_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "microsoft_aad_object_id": {
+ "name": "microsoft_aad_object_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "microsoft_auth_user_mappings_user_id_idx": {
+ "name": "microsoft_auth_user_mappings_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "microsoft_auth_user_mappings_account_id_idx": {
+ "name": "microsoft_auth_user_mappings_account_id_idx",
+ "columns": [
+ {
+ "expression": "account_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "microsoft_auth_user_mappings_auth_account_idx": {
+ "name": "microsoft_auth_user_mappings_auth_account_idx",
+ "columns": [
+ {
+ "expression": "auth_account_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "microsoft_auth_user_mappings_aad_object_unique": {
+ "name": "microsoft_auth_user_mappings_aad_object_unique",
+ "columns": [
+ {
+ "expression": "microsoft_tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "microsoft_aad_object_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "microsoft_auth_user_mappings_auth_account_id_auth_accounts_id_fk": {
+ "name": "microsoft_auth_user_mappings_auth_account_id_auth_accounts_id_fk",
+ "tableFrom": "microsoft_auth_user_mappings",
+ "tableTo": "auth_accounts",
+ "columnsFrom": ["auth_account_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "microsoft_auth_user_mappings_user_id_auth_users_id_fk": {
+ "name": "microsoft_auth_user_mappings_user_id_auth_users_id_fk",
+ "tableFrom": "microsoft_auth_user_mappings",
+ "tableTo": "auth_users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.oauth_state": {
+ "name": "oauth_state",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "code_verifier": {
+ "name": "code_verifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "replay_token": {
+ "name": "replay_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "oauth_state_connection_id_idx": {
+ "name": "oauth_state_connection_id_idx",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_state_replay_token_idx": {
+ "name": "oauth_state_replay_token_idx",
+ "columns": [
+ {
+ "expression": "replay_token",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_state_expires_at_idx": {
+ "name": "oauth_state_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "oauth_state_connection_id_mcp_connections_id_fk": {
+ "name": "oauth_state_connection_id_mcp_connections_id_fk",
+ "tableFrom": "oauth_state",
+ "tableTo": "mcp_connections",
+ "columnsFrom": ["connection_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.pr_review_cycles": {
+ "name": "pr_review_cycles",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "source_control_provider": {
+ "name": "source_control_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "repository": {
+ "name": "repository",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pr_number": {
+ "name": "pr_number",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "review_head_sha": {
+ "name": "review_head_sha",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "cycle_id": {
+ "name": "cycle_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "pr_review_cycles_source_unique": {
+ "name": "pr_review_cycles_source_unique",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "repository",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "pr_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "review_head_sha",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "cycle_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.pr_review_event_deliveries": {
+ "name": "pr_review_event_deliveries",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "event_id": {
+ "name": "event_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'pending'"
+ },
+ "due_at": {
+ "name": "due_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deferrals": {
+ "name": "deferrals",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "lease_token": {
+ "name": "lease_token",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lease_expires_at": {
+ "name": "lease_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "pr_review_event_deliveries_event_task_unique": {
+ "name": "pr_review_event_deliveries_event_task_unique",
+ "columns": [
+ {
+ "expression": "event_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pr_review_event_deliveries_due_idx": {
+ "name": "pr_review_event_deliveries_due_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "due_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "lease_expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "pr_review_event_deliveries_event_id_pr_review_events_id_fk": {
+ "name": "pr_review_event_deliveries_event_id_pr_review_events_id_fk",
+ "tableFrom": "pr_review_event_deliveries",
+ "tableTo": "pr_review_events",
+ "columnsFrom": ["event_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "pr_review_event_deliveries_task_id_tasks_id_fk": {
+ "name": "pr_review_event_deliveries_task_id_tasks_id_fk",
+ "tableFrom": "pr_review_event_deliveries",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "pr_review_event_deliveries_status_check": {
+ "name": "pr_review_event_deliveries_status_check",
+ "value": "\"pr_review_event_deliveries\".\"status\" in ('pending', 'processing', 'delivered', 'suppressed')"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.pr_review_events": {
+ "name": "pr_review_events",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "event_key": {
+ "name": "event_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_control_provider": {
+ "name": "source_control_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "repository": {
+ "name": "repository",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pr_number": {
+ "name": "pr_number",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pr_url": {
+ "name": "pr_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "event": {
+ "name": "event",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "batch_kind": {
+ "name": "batch_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "batch_id": {
+ "name": "batch_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "review_head_sha": {
+ "name": "review_head_sha",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sealed_at": {
+ "name": "sealed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "superseded": {
+ "name": "superseded",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "available_at": {
+ "name": "available_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "observed_at": {
+ "name": "observed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "pr_review_events_source_unique": {
+ "name": "pr_review_events_source_unique",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "repository",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "pr_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "event_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pr_review_events_pr_idx": {
+ "name": "pr_review_events_pr_idx",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "repository",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "pr_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "pr_review_events_batch_kind_check": {
+ "name": "pr_review_events_batch_kind_check",
+ "value": "\"pr_review_events\".\"batch_kind\" in ('human', 'roomote')"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.pull_request_facts": {
+ "name": "pull_request_facts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "repository_id": {
+ "name": "repository_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "repository_full_name": {
+ "name": "repository_full_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_control_provider": {
+ "name": "source_control_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'github'"
+ },
+ "external_pull_request_id": {
+ "name": "external_pull_request_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pr_number": {
+ "name": "pr_number",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "html_url": {
+ "name": "html_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "author_login": {
+ "name": "author_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "state": {
+ "name": "state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at_remote": {
+ "name": "created_at_remote",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at_remote": {
+ "name": "updated_at_remote",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "closed_at_remote": {
+ "name": "closed_at_remote",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "merged_at_remote": {
+ "name": "merged_at_remote",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "first_seen_at": {
+ "name": "first_seen_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "synced_at": {
+ "name": "synced_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "pull_request_facts_deployment_repo_pr_unique": {
+ "name": "pull_request_facts_deployment_repo_pr_unique",
+ "columns": [
+ {
+ "expression": "repository_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "pr_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_facts_deployment_created_idx": {
+ "name": "pull_request_facts_deployment_created_idx",
+ "columns": [
+ {
+ "expression": "created_at_remote",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_facts_deployment_repo_created_idx": {
+ "name": "pull_request_facts_deployment_repo_created_idx",
+ "columns": [
+ {
+ "expression": "repository_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at_remote",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_facts_deployment_state_created_idx": {
+ "name": "pull_request_facts_deployment_state_created_idx",
+ "columns": [
+ {
+ "expression": "state",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at_remote",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_facts_deployment_author_created_idx": {
+ "name": "pull_request_facts_deployment_author_created_idx",
+ "columns": [
+ {
+ "expression": "author_login",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at_remote",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_facts_deployment_updated_idx": {
+ "name": "pull_request_facts_deployment_updated_idx",
+ "columns": [
+ {
+ "expression": "updated_at_remote",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "pull_request_facts_repository_id_repositories_id_fk": {
+ "name": "pull_request_facts_repository_id_repositories_id_fk",
+ "tableFrom": "pull_request_facts",
+ "tableTo": "repositories",
+ "columnsFrom": ["repository_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "pull_request_facts_source_control_provider_check": {
+ "name": "pull_request_facts_source_control_provider_check",
+ "value": "\"pull_request_facts\".\"source_control_provider\" in ('github', 'gitlab', 'gitea', 'ado', 'bitbucket')"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.pull_request_sync_states": {
+ "name": "pull_request_sync_states",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "repository_id": {
+ "name": "repository_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_incremental_updated_at": {
+ "name": "last_incremental_updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "backfill_completed_at": {
+ "name": "backfill_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cooldown_until": {
+ "name": "cooldown_until",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_successful_sync_at": {
+ "name": "last_successful_sync_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_attempted_sync_at": {
+ "name": "last_attempted_sync_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error_at": {
+ "name": "last_error_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error_message": {
+ "name": "last_error_message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "pull_request_sync_states_repo_unique": {
+ "name": "pull_request_sync_states_repo_unique",
+ "columns": [
+ {
+ "expression": "repository_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_sync_states_deployment_updated_idx": {
+ "name": "pull_request_sync_states_deployment_updated_idx",
+ "columns": [
+ {
+ "expression": "last_successful_sync_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "pull_request_sync_states_cooldown_idx": {
+ "name": "pull_request_sync_states_cooldown_idx",
+ "columns": [
+ {
+ "expression": "cooldown_until",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "pull_request_sync_states_repository_id_repositories_id_fk": {
+ "name": "pull_request_sync_states_repository_id_repositories_id_fk",
+ "tableFrom": "pull_request_sync_states",
+ "tableTo": "repositories",
+ "columnsFrom": ["repository_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.repositories": {
+ "name": "repositories",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "source_control_provider": {
+ "name": "source_control_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'github'"
+ },
+ "installation_id": {
+ "name": "installation_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "github_repo_id": {
+ "name": "github_repo_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "external_repo_id": {
+ "name": "external_repo_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "host": {
+ "name": "host",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "full_name": {
+ "name": "full_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "private": {
+ "name": "private",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "default_branch": {
+ "name": "default_branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'main'"
+ },
+ "clone_url": {
+ "name": "clone_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "html_url": {
+ "name": "html_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "permissions": {
+ "name": "permissions",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "is_active": {
+ "name": "is_active",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "linked_by_user_id": {
+ "name": "linked_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "repositories_source_control_provider_idx": {
+ "name": "repositories_source_control_provider_idx",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_installation_id_idx": {
+ "name": "repositories_installation_id_idx",
+ "columns": [
+ {
+ "expression": "installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_full_name_idx": {
+ "name": "repositories_full_name_idx",
+ "columns": [
+ {
+ "expression": "full_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_provider_host_full_name_idx": {
+ "name": "repositories_provider_host_full_name_idx",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "host",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "full_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_deployment_active_installation_idx": {
+ "name": "repositories_deployment_active_installation_idx",
+ "columns": [
+ {
+ "expression": "is_active",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_deployment_github_repo_unique": {
+ "name": "repositories_deployment_github_repo_unique",
+ "columns": [
+ {
+ "expression": "github_repo_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_provider_host_external_repo_unique": {
+ "name": "repositories_provider_host_external_repo_unique",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "coalesce(\"host\", '')",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "external_repo_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "repositories_provider_host_full_name_unique": {
+ "name": "repositories_provider_host_full_name_unique",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "coalesce(\"host\", '')",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "full_name",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "repositories_installation_id_github_installations_id_fk": {
+ "name": "repositories_installation_id_github_installations_id_fk",
+ "tableFrom": "repositories",
+ "tableTo": "github_installations",
+ "columnsFrom": ["installation_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "repositories_user_id_users_id_fk": {
+ "name": "repositories_user_id_users_id_fk",
+ "tableFrom": "repositories",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "repositories_linked_by_user_id_users_id_fk": {
+ "name": "repositories_linked_by_user_id_users_id_fk",
+ "tableFrom": "repositories",
+ "tableTo": "users",
+ "columnsFrom": ["linked_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "repositories_source_control_provider_check": {
+ "name": "repositories_source_control_provider_check",
+ "value": "\"repositories\".\"source_control_provider\" in ('github', 'gitlab', 'gitea', 'ado', 'bitbucket')"
+ },
+ "repositories_github_shape_check": {
+ "name": "repositories_github_shape_check",
+ "value": "\"repositories\".\"source_control_provider\" != 'github' OR (\"repositories\".\"installation_id\" IS NOT NULL AND \"repositories\".\"github_repo_id\" IS NOT NULL)"
+ },
+ "repositories_gitlab_shape_check": {
+ "name": "repositories_gitlab_shape_check",
+ "value": "\"repositories\".\"source_control_provider\" != 'gitlab' OR \"repositories\".\"external_repo_id\" IS NOT NULL"
+ },
+ "repositories_gitea_shape_check": {
+ "name": "repositories_gitea_shape_check",
+ "value": "\"repositories\".\"source_control_provider\" != 'gitea' OR \"repositories\".\"external_repo_id\" IS NOT NULL"
+ },
+ "repositories_ado_shape_check": {
+ "name": "repositories_ado_shape_check",
+ "value": "\"repositories\".\"source_control_provider\" != 'ado' OR \"repositories\".\"external_repo_id\" IS NOT NULL"
+ },
+ "repositories_bitbucket_shape_check": {
+ "name": "repositories_bitbucket_shape_check",
+ "value": "\"repositories\".\"source_control_provider\" != 'bitbucket' OR \"repositories\".\"external_repo_id\" IS NOT NULL"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.repository_automation_signals": {
+ "name": "repository_automation_signals",
+ "schema": "",
+ "columns": {
+ "repository_id": {
+ "name": "repository_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "signals_version": {
+ "name": "signals_version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "collected_at": {
+ "name": "collected_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "partial": {
+ "name": "partial",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ }
+ },
+ "indexes": {
+ "repository_automation_signals_collected_idx": {
+ "name": "repository_automation_signals_collected_idx",
+ "columns": [
+ {
+ "expression": "collected_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "repository_automation_signals_repository_id_repositories_id_fk": {
+ "name": "repository_automation_signals_repository_id_repositories_id_fk",
+ "tableFrom": "repository_automation_signals",
+ "tableTo": "repositories",
+ "columnsFrom": ["repository_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "repository_automation_signals_repository_id_signals_version_pk": {
+ "name": "repository_automation_signals_repository_id_signals_version_pk",
+ "columns": ["repository_id", "signals_version"]
+ }
+ },
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.sandbox_oidc_targets": {
+ "name": "sandbox_oidc_targets",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "environment_id": {
+ "name": "environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "compute_provider": {
+ "name": "compute_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "compute_provider_id": {
+ "name": "compute_provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "target_kind": {
+ "name": "target_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "audience": {
+ "name": "audience",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token_file": {
+ "name": "token_file",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "aws_role_arn": {
+ "name": "aws_role_arn",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "aws_region": {
+ "name": "aws_region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_at": {
+ "name": "refresh_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "sandbox_oidc_targets_environment_id_idx": {
+ "name": "sandbox_oidc_targets_environment_id_idx",
+ "columns": [
+ {
+ "expression": "environment_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "sandbox_oidc_targets_run_id_idx": {
+ "name": "sandbox_oidc_targets_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "sandbox_oidc_targets_refresh_at_idx": {
+ "name": "sandbox_oidc_targets_refresh_at_idx",
+ "columns": [
+ {
+ "expression": "refresh_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "sandbox_oidc_targets_provider_target_file_unique": {
+ "name": "sandbox_oidc_targets_provider_target_file_unique",
+ "columns": [
+ {
+ "expression": "compute_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "compute_provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "token_file",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "sandbox_oidc_targets_environment_id_environments_id_fk": {
+ "name": "sandbox_oidc_targets_environment_id_environments_id_fk",
+ "tableFrom": "sandbox_oidc_targets",
+ "tableTo": "environments",
+ "columnsFrom": ["environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "sandbox_oidc_targets_run_id_task_runs_id_fk": {
+ "name": "sandbox_oidc_targets_run_id_task_runs_id_fk",
+ "tableFrom": "sandbox_oidc_targets",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "sandbox_oidc_targets_owner_required": {
+ "name": "sandbox_oidc_targets_owner_required",
+ "value": "run_id IS NOT NULL"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.setup_qualification_blocks": {
+ "name": "setup_qualification_blocks",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reason": {
+ "name": "reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'blocked'"
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "email_domain": {
+ "name": "email_domain",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "github_account_login": {
+ "name": "github_account_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "github_account_type": {
+ "name": "github_account_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "first_blocked_at": {
+ "name": "first_blocked_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "last_blocked_at": {
+ "name": "last_blocked_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lifted_by_admin_user_id": {
+ "name": "lifted_by_admin_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lifted_by_admin_email": {
+ "name": "lifted_by_admin_email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "setup_qualification_blocks_deployment_user_reason_unique": {
+ "name": "setup_qualification_blocks_deployment_user_reason_unique",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "reason",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "setup_qualification_blocks_deployment_status_idx": {
+ "name": "setup_qualification_blocks_deployment_status_idx",
+ "columns": [
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "setup_qualification_blocks_user_status_idx": {
+ "name": "setup_qualification_blocks_user_status_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "setup_qualification_blocks_user_id_users_id_fk": {
+ "name": "setup_qualification_blocks_user_id_users_id_fk",
+ "tableFrom": "setup_qualification_blocks",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.slack_auth_tokens": {
+ "name": "slack_auth_tokens",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slack_user_id": {
+ "name": "slack_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slack_team_id": {
+ "name": "slack_team_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel": {
+ "name": "channel",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "thread_ts": {
+ "name": "thread_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "original_text": {
+ "name": "original_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slack_auth_tokens_expires_at_idx": {
+ "name": "slack_auth_tokens_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "slack_auth_tokens_token_unique": {
+ "name": "slack_auth_tokens_token_unique",
+ "nullsNotDistinct": false,
+ "columns": ["token"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.slack_conversation_messages": {
+ "name": "slack_conversation_messages",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "subject_user_id": {
+ "name": "subject_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_team_id": {
+ "name": "slack_team_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "subject_slack_user_id": {
+ "name": "subject_slack_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "sender_user_id": {
+ "name": "sender_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sender_slack_user_id": {
+ "name": "sender_slack_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_channel_id": {
+ "name": "slack_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "conversation_kind": {
+ "name": "conversation_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "thread_ts": {
+ "name": "thread_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "message_ts": {
+ "name": "message_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "message_at": {
+ "name": "message_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "direction": {
+ "name": "direction",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "author_kind": {
+ "name": "author_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "text": {
+ "name": "text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "''"
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_quick_answer_id": {
+ "name": "slack_quick_answer_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slack_conversation_messages_deployment_user_message_at_idx": {
+ "name": "slack_conversation_messages_deployment_user_message_at_idx",
+ "columns": [
+ {
+ "expression": "subject_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "message_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "slack_conversation_messages_deployment_user_thread_idx": {
+ "name": "slack_conversation_messages_deployment_user_thread_idx",
+ "columns": [
+ {
+ "expression": "subject_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "slack_channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "thread_ts",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "message_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "slack_conversation_messages_task_id_idx": {
+ "name": "slack_conversation_messages_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "slack_conversation_messages_run_id_idx": {
+ "name": "slack_conversation_messages_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "slack_conversation_messages_team_channel_message_unique": {
+ "name": "slack_conversation_messages_team_channel_message_unique",
+ "columns": [
+ {
+ "expression": "slack_team_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "slack_channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "message_ts",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "slack_conversation_messages_subject_user_id_users_id_fk": {
+ "name": "slack_conversation_messages_subject_user_id_users_id_fk",
+ "tableFrom": "slack_conversation_messages",
+ "tableTo": "users",
+ "columnsFrom": ["subject_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "slack_conversation_messages_sender_user_id_users_id_fk": {
+ "name": "slack_conversation_messages_sender_user_id_users_id_fk",
+ "tableFrom": "slack_conversation_messages",
+ "tableTo": "users",
+ "columnsFrom": ["sender_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "slack_conversation_messages_task_id_tasks_id_fk": {
+ "name": "slack_conversation_messages_task_id_tasks_id_fk",
+ "tableFrom": "slack_conversation_messages",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "slack_conversation_messages_run_id_task_runs_id_fk": {
+ "name": "slack_conversation_messages_run_id_task_runs_id_fk",
+ "tableFrom": "slack_conversation_messages",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "slack_conversation_messages_slack_quick_answer_id_slack_quick_answers_id_fk": {
+ "name": "slack_conversation_messages_slack_quick_answer_id_slack_quick_answers_id_fk",
+ "tableFrom": "slack_conversation_messages",
+ "tableTo": "slack_quick_answers",
+ "columnsFrom": ["slack_quick_answer_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.slack_installation_channels": {
+ "name": "slack_installation_channels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "slack_installation_id": {
+ "name": "slack_installation_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel_id": {
+ "name": "channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slack_installation_channels_installation_id_idx": {
+ "name": "slack_installation_channels_installation_id_idx",
+ "columns": [
+ {
+ "expression": "slack_installation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "slack_installation_channels_slack_installation_id_slack_installations_id_fk": {
+ "name": "slack_installation_channels_slack_installation_id_slack_installations_id_fk",
+ "tableFrom": "slack_installation_channels",
+ "tableTo": "slack_installations",
+ "columnsFrom": ["slack_installation_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "slack_installation_channels_unique": {
+ "name": "slack_installation_channels_unique",
+ "nullsNotDistinct": false,
+ "columns": ["slack_installation_id", "channel_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.slack_installations": {
+ "name": "slack_installations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "team_id": {
+ "name": "team_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "team_name": {
+ "name": "team_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "team_domain": {
+ "name": "team_domain",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enterprise_id": {
+ "name": "enterprise_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "enterprise_name": {
+ "name": "enterprise_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "app_id": {
+ "name": "app_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bot_user_id": {
+ "name": "bot_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bot_name": {
+ "name": "bot_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "app_name": {
+ "name": "app_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "bot_access_token": {
+ "name": "bot_access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_access_token": {
+ "name": "user_access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scopes": {
+ "name": "scopes",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token_type": {
+ "name": "token_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'bot'"
+ },
+ "installed_by_user_id": {
+ "name": "installed_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "member_count_snapshot": {
+ "name": "member_count_snapshot",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "member_count_snapshot_at": {
+ "name": "member_count_snapshot_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_active": {
+ "name": "is_active",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "last_used_at": {
+ "name": "last_used_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slack_installations_bot_user_id_idx": {
+ "name": "slack_installations_bot_user_id_idx",
+ "columns": [
+ {
+ "expression": "bot_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "slack_installations_active_idx": {
+ "name": "slack_installations_active_idx",
+ "columns": [
+ {
+ "expression": "is_active",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "slack_installations_installed_by_user_id_users_id_fk": {
+ "name": "slack_installations_installed_by_user_id_users_id_fk",
+ "tableFrom": "slack_installations",
+ "tableTo": "users",
+ "columnsFrom": ["installed_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "slack_installations_team_id_unique": {
+ "name": "slack_installations_team_id_unique",
+ "nullsNotDistinct": false,
+ "columns": ["team_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.slack_quick_answers": {
+ "name": "slack_quick_answers",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slack_channel": {
+ "name": "slack_channel",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slack_thread_ts": {
+ "name": "slack_thread_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "messages": {
+ "name": "messages",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slack_quick_answers_deployment_channel_thread_unique": {
+ "name": "slack_quick_answers_deployment_channel_thread_unique",
+ "columns": [
+ {
+ "expression": "slack_channel",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "slack_thread_ts",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "slack_quick_answers_deployment_user_idx": {
+ "name": "slack_quick_answers_deployment_user_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "slack_quick_answers_user_id_users_id_fk": {
+ "name": "slack_quick_answers_user_id_users_id_fk",
+ "tableFrom": "slack_quick_answers",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.slack_user_mappings": {
+ "name": "slack_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "slack_user_id": {
+ "name": "slack_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slack_team_id": {
+ "name": "slack_team_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slack_user_mappings_user_id_idx": {
+ "name": "slack_user_mappings_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "slack_user_mappings_user_id_users_id_fk": {
+ "name": "slack_user_mappings_user_id_users_id_fk",
+ "tableFrom": "slack_user_mappings",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "slack_user_mappings_unique": {
+ "name": "slack_user_mappings_unique",
+ "nullsNotDistinct": false,
+ "columns": ["slack_user_id", "slack_team_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.source_control_user_mappings": {
+ "name": "source_control_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "auth_account_id": {
+ "name": "auth_account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_control_provider": {
+ "name": "source_control_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "host": {
+ "name": "host",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "external_account_id": {
+ "name": "external_account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "username": {
+ "name": "username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "display_name": {
+ "name": "display_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "source_control_user_mappings_auth_account_unique": {
+ "name": "source_control_user_mappings_auth_account_unique",
+ "columns": [
+ {
+ "expression": "auth_account_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "source_control_user_mappings_user_provider_host_idx": {
+ "name": "source_control_user_mappings_user_provider_host_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "host",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "source_control_user_mappings_provider_identity_unique": {
+ "name": "source_control_user_mappings_provider_identity_unique",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "host",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "external_account_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "source_control_user_mappings_auth_account_id_auth_accounts_id_fk": {
+ "name": "source_control_user_mappings_auth_account_id_auth_accounts_id_fk",
+ "tableFrom": "source_control_user_mappings",
+ "tableTo": "auth_accounts",
+ "columnsFrom": ["auth_account_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "source_control_user_mappings_user_id_auth_users_id_fk": {
+ "name": "source_control_user_mappings_user_id_auth_users_id_fk",
+ "tableFrom": "source_control_user_mappings",
+ "tableTo": "auth_users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_artifacts": {
+ "name": "task_artifacts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "artifact_type": {
+ "name": "artifact_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'general'"
+ },
+ "content_type": {
+ "name": "content_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version": {
+ "name": "version",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "size": {
+ "name": "size",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "uploaded": {
+ "name": "uploaded",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_artifacts_task_id_idx": {
+ "name": "task_artifacts_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_artifacts_run_id_idx": {
+ "name": "task_artifacts_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_artifacts_uploaded_idx": {
+ "name": "task_artifacts_uploaded_idx",
+ "columns": [
+ {
+ "expression": "uploaded",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_artifacts_created_at_idx": {
+ "name": "task_artifacts_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_artifacts_path_idx": {
+ "name": "task_artifacts_path_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "path",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_artifacts_task_id_tasks_id_fk": {
+ "name": "task_artifacts_task_id_tasks_id_fk",
+ "tableFrom": "task_artifacts",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_artifacts_run_id_task_runs_id_fk": {
+ "name": "task_artifacts_run_id_task_runs_id_fk",
+ "tableFrom": "task_artifacts",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "task_artifacts_task_id_path_version_unique": {
+ "name": "task_artifacts_task_id_path_version_unique",
+ "nullsNotDistinct": false,
+ "columns": ["task_id", "path", "version"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_messages": {
+ "name": "task_messages",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "ts": {
+ "name": "ts",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "protocol": {
+ "name": "protocol",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "content_blocks": {
+ "name": "content_blocks",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_messages_task_id_ts_idx": {
+ "name": "task_messages_task_id_ts_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "ts",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_messages_run_id_idx": {
+ "name": "task_messages_run_id_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_messages_created_at_idx": {
+ "name": "task_messages_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_messages_run_id_task_runs_id_fk": {
+ "name": "task_messages_run_id_task_runs_id_fk",
+ "tableFrom": "task_messages",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_messages_task_id_tasks_id_fk": {
+ "name": "task_messages_task_id_tasks_id_fk",
+ "tableFrom": "task_messages",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_messages_user_id_users_id_fk": {
+ "name": "task_messages_user_id_users_id_fk",
+ "tableFrom": "task_messages",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "task_messages_task_protocol_ts_event_type_unique": {
+ "name": "task_messages_task_protocol_ts_event_type_unique",
+ "nullsNotDistinct": false,
+ "columns": ["task_id", "protocol", "ts", "event_type"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_pins": {
+ "name": "task_pins",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_pins_deployment_user_task_unique": {
+ "name": "task_pins_deployment_user_task_unique",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_pins_deployment_user_updated_at_idx": {
+ "name": "task_pins_deployment_user_updated_at_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "updated_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_pins_task_id_idx": {
+ "name": "task_pins_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_pins_task_id_tasks_id_fk": {
+ "name": "task_pins_task_id_tasks_id_fk",
+ "tableFrom": "task_pins",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_pins_user_id_users_id_fk": {
+ "name": "task_pins_user_id_users_id_fk",
+ "tableFrom": "task_pins",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_platform_issue_reports": {
+ "name": "task_platform_issue_reports",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_message_id": {
+ "name": "task_message_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "report": {
+ "name": "report",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slack_posted_at": {
+ "name": "slack_posted_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_platform_issue_reports_created_at_idx": {
+ "name": "task_platform_issue_reports_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_platform_issue_reports_task_id_created_at_idx": {
+ "name": "task_platform_issue_reports_task_id_created_at_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_platform_issue_reports_run_id_created_at_idx": {
+ "name": "task_platform_issue_reports_run_id_created_at_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_platform_issue_reports_task_message_id_unique": {
+ "name": "task_platform_issue_reports_task_message_id_unique",
+ "columns": [
+ {
+ "expression": "task_message_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_platform_issue_reports_task_id_tasks_id_fk": {
+ "name": "task_platform_issue_reports_task_id_tasks_id_fk",
+ "tableFrom": "task_platform_issue_reports",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_platform_issue_reports_run_id_task_runs_id_fk": {
+ "name": "task_platform_issue_reports_run_id_task_runs_id_fk",
+ "tableFrom": "task_platform_issue_reports",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_platform_issue_reports_task_message_id_task_messages_id_fk": {
+ "name": "task_platform_issue_reports_task_message_id_task_messages_id_fk",
+ "tableFrom": "task_platform_issue_reports",
+ "tableTo": "task_messages",
+ "columnsFrom": ["task_message_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_pull_requests": {
+ "name": "task_pull_requests",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source_control_provider": {
+ "name": "source_control_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'github'"
+ },
+ "host": {
+ "name": "host",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "repository_id": {
+ "name": "repository_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pr_url": {
+ "name": "pr_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "pr_number": {
+ "name": "pr_number",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pr_title": {
+ "name": "pr_title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "repository": {
+ "name": "repository",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pr_sha": {
+ "name": "pr_sha",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pr_base_ref": {
+ "name": "pr_base_ref",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pr_base_sha": {
+ "name": "pr_base_sha",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "github_reaction_id": {
+ "name": "github_reaction_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "github_check_run_id": {
+ "name": "github_check_run_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "github_review_comment_id": {
+ "name": "github_review_comment_id",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_roomote": {
+ "name": "created_by_roomote",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "auto_handle_feedback_by_user_id": {
+ "name": "auto_handle_feedback_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "detected_at": {
+ "name": "detected_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_pull_requests_task_id_idx": {
+ "name": "task_pull_requests_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_pull_requests_repository_id_idx": {
+ "name": "task_pull_requests_repository_id_idx",
+ "columns": [
+ {
+ "expression": "repository_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_pull_requests_provider_repository_pr_number_idx": {
+ "name": "task_pull_requests_provider_repository_pr_number_idx",
+ "columns": [
+ {
+ "expression": "source_control_provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "repository",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "pr_number",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_pull_requests_task_id_tasks_id_fk": {
+ "name": "task_pull_requests_task_id_tasks_id_fk",
+ "tableFrom": "task_pull_requests",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_pull_requests_repository_id_repositories_id_fk": {
+ "name": "task_pull_requests_repository_id_repositories_id_fk",
+ "tableFrom": "task_pull_requests",
+ "tableTo": "repositories",
+ "columnsFrom": ["repository_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "task_pull_requests_auto_handle_feedback_by_user_id_users_id_fk": {
+ "name": "task_pull_requests_auto_handle_feedback_by_user_id_users_id_fk",
+ "tableFrom": "task_pull_requests",
+ "tableTo": "users",
+ "columnsFrom": ["auto_handle_feedback_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "task_pull_requests_task_pr_unique": {
+ "name": "task_pull_requests_task_pr_unique",
+ "nullsNotDistinct": false,
+ "columns": ["task_id", "pr_url"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {
+ "task_pull_requests_source_control_provider_check": {
+ "name": "task_pull_requests_source_control_provider_check",
+ "value": "\"task_pull_requests\".\"source_control_provider\" in ('github', 'gitlab', 'gitea', 'ado', 'bitbucket')"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.task_run_events": {
+ "name": "task_run_events",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "event_type": {
+ "name": "event_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "message": {
+ "name": "message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "details": {
+ "name": "details",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_run_events_run_id_created_at_idx": {
+ "name": "task_run_events_run_id_created_at_idx",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_run_events_task_id_created_at_idx": {
+ "name": "task_run_events_task_id_created_at_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_run_events_created_at_idx": {
+ "name": "task_run_events_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_run_events_source_created_at_idx": {
+ "name": "task_run_events_source_created_at_idx",
+ "columns": [
+ {
+ "expression": "source",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_run_events_run_id_task_runs_id_fk": {
+ "name": "task_run_events_run_id_task_runs_id_fk",
+ "tableFrom": "task_run_events",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_run_events_task_id_tasks_id_fk": {
+ "name": "task_run_events_task_id_tasks_id_fk",
+ "tableFrom": "task_run_events",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_runs": {
+ "name": "task_runs",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "integer",
+ "primaryKey": true,
+ "notNull": true,
+ "identity": {
+ "type": "always",
+ "name": "task_runs_id_seq",
+ "schema": "public",
+ "increment": "1",
+ "startWith": "1",
+ "minValue": "1",
+ "maxValue": "2147483647",
+ "cache": "1",
+ "cycle": false
+ }
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'fresh'"
+ },
+ "source_run_id": {
+ "name": "source_run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "acting_user_id": {
+ "name": "acting_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "payload_kind": {
+ "name": "payload_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "harness": {
+ "name": "harness",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'opencode-server'"
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'pending'"
+ },
+ "queue_scope": {
+ "name": "queue_scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "task_phase": {
+ "name": "task_phase",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "prompt": {
+ "name": "prompt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "log": {
+ "name": "log",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "artifacts": {
+ "name": "artifacts",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "result": {
+ "name": "result",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error": {
+ "name": "error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error_code": {
+ "name": "error_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "machine_id": {
+ "name": "machine_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sandbox_cmd_id": {
+ "name": "sandbox_cmd_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "machine_domain": {
+ "name": "machine_domain",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "machine_domains": {
+ "name": "machine_domains",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "initial_paths": {
+ "name": "initial_paths",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "primary_port_name": {
+ "name": "primary_port_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sandbox_server_url": {
+ "name": "sandbox_server_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "proxy_ports": {
+ "name": "proxy_ports",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "worker_release_tag": {
+ "name": "worker_release_tag",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "worker_version": {
+ "name": "worker_version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "worker_commit": {
+ "name": "worker_commit",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "vendor": {
+ "name": "vendor",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "port": {
+ "name": "port",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "configured_vcpus": {
+ "name": "configured_vcpus",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "configured_cpu_cores": {
+ "name": "configured_cpu_cores",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "configured_memory_mib": {
+ "name": "configured_memory_mib",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_id": {
+ "name": "snapshot_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_requested_at": {
+ "name": "snapshot_requested_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_created_at": {
+ "name": "snapshot_created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "snapshot_failed_at": {
+ "name": "snapshot_failed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "keepalive_ms": {
+ "name": "keepalive_ms",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sleep_at": {
+ "name": "sleep_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sleep_requested_at": {
+ "name": "sleep_requested_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "worker_heartbeat_at": {
+ "name": "worker_heartbeat_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source_snapshot_id": {
+ "name": "source_snapshot_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "auth_bypass_value": {
+ "name": "auth_bypass_value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "auth_bypass_header_name": {
+ "name": "auth_bypass_header_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "dequeued_at": {
+ "name": "dequeued_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provision_started_at": {
+ "name": "provision_started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provision_ready_at": {
+ "name": "provision_ready_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "setup_completed_at": {
+ "name": "setup_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "environment_setup_state": {
+ "name": "environment_setup_state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "environment_setup_completed_at": {
+ "name": "environment_setup_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "harness_started_at": {
+ "name": "harness_started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "runtime_task_started_at": {
+ "name": "runtime_task_started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "first_assistant_output_at": {
+ "name": "first_assistant_output_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "completed_at": {
+ "name": "completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cancel_requested_at": {
+ "name": "cancel_requested_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "canceled_at": {
+ "name": "canceled_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "launch_mode": {
+ "name": "launch_mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "task_runs_task_id_idx": {
+ "name": "task_runs_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_queue_scope_idx": {
+ "name": "task_runs_queue_scope_idx",
+ "columns": [
+ {
+ "expression": "queue_scope",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_acting_user_id_idx": {
+ "name": "task_runs_acting_user_id_idx",
+ "columns": [
+ {
+ "expression": "acting_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_snapshot_id_idx": {
+ "name": "task_runs_snapshot_id_idx",
+ "columns": [
+ {
+ "expression": "snapshot_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_sleep_at_idx": {
+ "name": "task_runs_sleep_at_idx",
+ "columns": [
+ {
+ "expression": "sleep_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_worker_heartbeat_at_idx": {
+ "name": "task_runs_worker_heartbeat_at_idx",
+ "columns": [
+ {
+ "expression": "worker_heartbeat_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_sleep_check_due_v2_idx": {
+ "name": "task_runs_sleep_check_due_v2_idx",
+ "columns": [
+ {
+ "expression": "sleep_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "vendor",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"task_runs\".\"status\" IN ('running', 'idle') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"sleep_at\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_sleep_check_stale_worker_v2_idx": {
+ "name": "task_runs_sleep_check_stale_worker_v2_idx",
+ "columns": [
+ {
+ "expression": "worker_heartbeat_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "vendor",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"task_runs\".\"status\" IN ('running', 'idle') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"worker_heartbeat_at\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_sleep_check_active_v2_idx": {
+ "name": "task_runs_sleep_check_active_v2_idx",
+ "columns": [
+ {
+ "expression": "vendor",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "where": "\"task_runs\".\"status\" IN ('running', 'idle') AND \"task_runs\".\"machine_id\" IS NOT NULL AND \"task_runs\".\"sleep_requested_at\" IS NULL AND \"task_runs\".\"snapshot_id\" IS NULL AND \"task_runs\".\"snapshot_requested_at\" IS NULL AND \"task_runs\".\"vendor\" IN ('modal', 'daytona', 'e2b', 'docker', 'blaxel', 'box', 'roomote', 'azure')",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_source_snapshot_id_idx": {
+ "name": "task_runs_source_snapshot_id_idx",
+ "columns": [
+ {
+ "expression": "source_snapshot_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_source_run_id_idx": {
+ "name": "task_runs_source_run_id_idx",
+ "columns": [
+ {
+ "expression": "source_run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_discord_source_event_unique": {
+ "name": "task_runs_discord_source_event_unique",
+ "columns": [
+ {
+ "expression": "(\"payload\"->>'communicationSourceEventId')",
+ "asc": true,
+ "isExpression": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "where": "\"task_runs\".\"payload\"->>'communicationProvider' = 'discord' AND \"task_runs\".\"payload\"->>'communicationSourceEventId' IS NOT NULL AND \"task_runs\".\"canceled_at\" IS NULL",
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_runs_first_assistant_output_at_idx": {
+ "name": "task_runs_first_assistant_output_at_idx",
+ "columns": [
+ {
+ "expression": "first_assistant_output_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_runs_task_id_tasks_id_fk": {
+ "name": "task_runs_task_id_tasks_id_fk",
+ "tableFrom": "task_runs",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_runs_source_run_id_task_runs_id_fk": {
+ "name": "task_runs_source_run_id_task_runs_id_fk",
+ "tableFrom": "task_runs",
+ "tableTo": "task_runs",
+ "columnsFrom": ["source_run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "task_runs_acting_user_id_users_id_fk": {
+ "name": "task_runs_acting_user_id_users_id_fk",
+ "tableFrom": "task_runs",
+ "tableTo": "users",
+ "columnsFrom": ["acting_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "task_runs_kind_check": {
+ "name": "task_runs_kind_check",
+ "value": "\"task_runs\".\"kind\" in ('fresh', 'resume')"
+ },
+ "task_runs_harness_check": {
+ "name": "task_runs_harness_check",
+ "value": "\"task_runs\".\"harness\" in ('opencode-server')"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.task_slack_reply_details": {
+ "name": "task_slack_reply_details",
+ "schema": "",
+ "columns": {
+ "detail_id": {
+ "name": "detail_id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "summary": {
+ "name": "summary",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "findings": {
+ "name": "findings",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_slack_reply_details_task_id_idx": {
+ "name": "task_slack_reply_details_task_id_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_slack_reply_details_deployment_task_detail_unique": {
+ "name": "task_slack_reply_details_deployment_task_detail_unique",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "detail_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_slack_reply_details_task_id_tasks_id_fk": {
+ "name": "task_slack_reply_details_task_id_tasks_id_fk",
+ "tableFrom": "task_slack_reply_details",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.task_start_parallel_counts": {
+ "name": "task_start_parallel_counts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "task_id": {
+ "name": "task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "run_id": {
+ "name": "run_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload_kind": {
+ "name": "payload_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parallel_count": {
+ "name": "parallel_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "activity_window_seconds": {
+ "name": "activity_window_seconds",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "ended_at": {
+ "name": "ended_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "task_start_parallel_counts_run_id_unique": {
+ "name": "task_start_parallel_counts_run_id_unique",
+ "columns": [
+ {
+ "expression": "run_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_start_parallel_counts_task_id_started_at_idx": {
+ "name": "task_start_parallel_counts_task_id_started_at_idx",
+ "columns": [
+ {
+ "expression": "task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "started_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "task_start_parallel_counts_started_at_idx": {
+ "name": "task_start_parallel_counts_started_at_idx",
+ "columns": [
+ {
+ "expression": "started_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "task_start_parallel_counts_task_id_tasks_id_fk": {
+ "name": "task_start_parallel_counts_task_id_tasks_id_fk",
+ "tableFrom": "task_start_parallel_counts",
+ "tableTo": "tasks",
+ "columnsFrom": ["task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "task_start_parallel_counts_run_id_task_runs_id_fk": {
+ "name": "task_start_parallel_counts_run_id_task_runs_id_fk",
+ "tableFrom": "task_start_parallel_counts",
+ "tableTo": "task_runs",
+ "columnsFrom": ["run_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.tasks": {
+ "name": "tasks",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workflow": {
+ "name": "workflow",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "surface": {
+ "name": "surface",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "trigger": {
+ "name": "trigger",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "visibility": {
+ "name": "visibility",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'visible'"
+ },
+ "state": {
+ "name": "state",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'active'"
+ },
+ "initiator_kind": {
+ "name": "initiator_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "initiator_user_id": {
+ "name": "initiator_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "initiator_automation": {
+ "name": "initiator_automation",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "actor_external_id": {
+ "name": "actor_external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "actor_display_name": {
+ "name": "actor_display_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "commit_author_kind": {
+ "name": "commit_author_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "commit_author_user_id": {
+ "name": "commit_author_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "commit_author_login": {
+ "name": "commit_author_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "commit_author_external_id": {
+ "name": "commit_author_external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "pr_assignee_login": {
+ "name": "pr_assignee_login",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_channel_id": {
+ "name": "slack_channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slack_thread_ts": {
+ "name": "slack_thread_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "linear_session_id": {
+ "name": "linear_session_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "linear_issue_id": {
+ "name": "linear_issue_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "linear_organization_id": {
+ "name": "linear_organization_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "harness": {
+ "name": "harness",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'opencode-server'"
+ },
+ "harness_session_id": {
+ "name": "harness_session_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "model_provider": {
+ "name": "model_provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "title_edited_by_user_at": {
+ "name": "title_edited_by_user_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "llm_title_checkpoint": {
+ "name": "llm_title_checkpoint",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "mode": {
+ "name": "mode",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "model": {
+ "name": "model",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "prompt": {
+ "name": "prompt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_objective": {
+ "name": "goal_objective",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_status": {
+ "name": "goal_status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_max_continuations": {
+ "name": "goal_max_continuations",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_continuations_used": {
+ "name": "goal_continuations_used",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "goal_blocked_reason": {
+ "name": "goal_blocked_reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_started_at": {
+ "name": "goal_started_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_ended_at": {
+ "name": "goal_ended_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_completed_at": {
+ "name": "goal_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_last_continuation_id": {
+ "name": "goal_last_continuation_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_continuation_ids": {
+ "name": "goal_continuation_ids",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::text[]"
+ },
+ "goal_generation_ids": {
+ "name": "goal_generation_ids",
+ "type": "text[]",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::text[]"
+ },
+ "goal_blocker_candidate_reason": {
+ "name": "goal_blocker_candidate_reason",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "goal_blocker_candidate_count": {
+ "name": "goal_blocker_candidate_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "goal_blocker_last_continuation_used": {
+ "name": "goal_blocker_last_continuation_used",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "draft_prompt": {
+ "name": "draft_prompt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "requested_work_kind": {
+ "name": "requested_work_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'unknown'"
+ },
+ "requested_work_kind_source": {
+ "name": "requested_work_kind_source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'system_default'"
+ },
+ "requested_work_kind_confidence": {
+ "name": "requested_work_kind_confidence",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "harness_instructions": {
+ "name": "harness_instructions",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "compute_duration_ms": {
+ "name": "compute_duration_ms",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "activity_at": {
+ "name": "activity_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "repository_url": {
+ "name": "repository_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "repository_name": {
+ "name": "repository_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "default_branch": {
+ "name": "default_branch",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "tasks_initiator_user_id_idx": {
+ "name": "tasks_initiator_user_id_idx",
+ "columns": [
+ {
+ "expression": "initiator_user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_initiator_automation_idx": {
+ "name": "tasks_initiator_automation_idx",
+ "columns": [
+ {
+ "expression": "initiator_automation",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_workflow_idx": {
+ "name": "tasks_workflow_idx",
+ "columns": [
+ {
+ "expression": "workflow",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_visibility_activity_at_idx": {
+ "name": "tasks_visibility_activity_at_idx",
+ "columns": [
+ {
+ "expression": "visibility",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "activity_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_harness_session_id_idx": {
+ "name": "tasks_harness_session_id_idx",
+ "columns": [
+ {
+ "expression": "harness_session_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_timestamp_idx": {
+ "name": "tasks_timestamp_idx",
+ "columns": [
+ {
+ "expression": "timestamp",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_deployment_activity_at_idx": {
+ "name": "tasks_deployment_activity_at_idx",
+ "columns": [
+ {
+ "expression": "activity_at",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ },
+ {
+ "expression": "id",
+ "isExpression": false,
+ "asc": false,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tasks_created_at_idx": {
+ "name": "tasks_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "tasks_initiator_user_id_users_id_fk": {
+ "name": "tasks_initiator_user_id_users_id_fk",
+ "tableFrom": "tasks",
+ "tableTo": "users",
+ "columnsFrom": ["initiator_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "tasks_initiator_automation_automations_key_fk": {
+ "name": "tasks_initiator_automation_automations_key_fk",
+ "tableFrom": "tasks",
+ "tableTo": "automations",
+ "columnsFrom": ["initiator_automation"],
+ "columnsTo": ["key"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "tasks_commit_author_user_id_users_id_fk": {
+ "name": "tasks_commit_author_user_id_users_id_fk",
+ "tableFrom": "tasks",
+ "tableTo": "users",
+ "columnsFrom": ["commit_author_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "tasks_initiator_shape_check": {
+ "name": "tasks_initiator_shape_check",
+ "value": "(\"tasks\".\"initiator_kind\" = 'user' AND \"tasks\".\"initiator_automation\" IS NULL AND (\"tasks\".\"initiator_user_id\" IS NOT NULL OR \"tasks\".\"actor_external_id\" IS NOT NULL)) OR (\"tasks\".\"initiator_kind\" = 'automation' AND \"tasks\".\"initiator_automation\" IS NOT NULL AND \"tasks\".\"initiator_user_id\" IS NULL)"
+ },
+ "tasks_workflow_check": {
+ "name": "tasks_workflow_check",
+ "value": "\"tasks\".\"workflow\" in ('standard', 'pr_review', 'pr_conflict_resolve', 'scan', 'mcp_recommendations', 'setup_onboarding', 'env_snapshot', 'eval')"
+ },
+ "tasks_surface_check": {
+ "name": "tasks_surface_check",
+ "value": "\"tasks\".\"surface\" in ('web', 'api', 'slack', 'teams', 'telegram', 'discord', 'linear', 'github', 'gitlab', 'gitea', 'ado', 'bitbucket', 'system')"
+ },
+ "tasks_trigger_check": {
+ "name": "tasks_trigger_check",
+ "value": "\"tasks\".\"trigger\" in ('message', 'webhook', 'schedule', 'manual')"
+ },
+ "tasks_visibility_check": {
+ "name": "tasks_visibility_check",
+ "value": "\"tasks\".\"visibility\" in ('visible', 'hidden')"
+ },
+ "tasks_state_check": {
+ "name": "tasks_state_check",
+ "value": "\"tasks\".\"state\" in ('active', 'completed', 'failed', 'canceled')"
+ },
+ "tasks_goal_status_check": {
+ "name": "tasks_goal_status_check",
+ "value": "\"tasks\".\"goal_status\" IS NULL OR \"tasks\".\"goal_status\" in ('active', 'complete', 'blocked', 'budget_limited')"
+ },
+ "tasks_goal_continuations_check": {
+ "name": "tasks_goal_continuations_check",
+ "value": "\"tasks\".\"goal_continuations_used\" >= 0 AND (\"tasks\".\"goal_max_continuations\" IS NULL OR \"tasks\".\"goal_max_continuations\" > 0)"
+ },
+ "tasks_goal_blocker_candidate_count_check": {
+ "name": "tasks_goal_blocker_candidate_count_check",
+ "value": "\"tasks\".\"goal_blocker_candidate_count\" >= 0"
+ },
+ "tasks_harness_check": {
+ "name": "tasks_harness_check",
+ "value": "\"tasks\".\"harness\" in ('opencode-server')"
+ },
+ "tasks_requested_work_kind_check": {
+ "name": "tasks_requested_work_kind_check",
+ "value": "\"tasks\".\"requested_work_kind\" in ('question', 'plan', 'implement', 'unknown')"
+ },
+ "tasks_requested_work_kind_source_check": {
+ "name": "tasks_requested_work_kind_source_check",
+ "value": "\"tasks\".\"requested_work_kind_source\" in ('explicit_bootstrap', 'task_tool', 'llm_classifier', 'inherited', 'system_default')"
+ },
+ "tasks_commit_author_kind_check": {
+ "name": "tasks_commit_author_kind_check",
+ "value": "\"tasks\".\"commit_author_kind\" IS NULL OR \"tasks\".\"commit_author_kind\" in ('roomote', 'user', 'external')"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.teams_installations": {
+ "name": "teams_installations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "installation_key": {
+ "name": "installation_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tenant_id": {
+ "name": "tenant_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "team_id": {
+ "name": "team_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "team_name": {
+ "name": "team_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "channel_id": {
+ "name": "channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "channel_name": {
+ "name": "channel_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "conversation_id": {
+ "name": "conversation_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "conversation_type": {
+ "name": "conversation_type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "bot_app_id": {
+ "name": "bot_app_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bot_user_id": {
+ "name": "bot_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "bot_name": {
+ "name": "bot_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "service_url": {
+ "name": "service_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "is_active": {
+ "name": "is_active",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "last_activity_at": {
+ "name": "last_activity_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "teams_installations_tenant_id_idx": {
+ "name": "teams_installations_tenant_id_idx",
+ "columns": [
+ {
+ "expression": "tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "teams_installations_team_id_idx": {
+ "name": "teams_installations_team_id_idx",
+ "columns": [
+ {
+ "expression": "team_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "teams_installations_conversation_id_idx": {
+ "name": "teams_installations_conversation_id_idx",
+ "columns": [
+ {
+ "expression": "conversation_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "teams_installations_active_idx": {
+ "name": "teams_installations_active_idx",
+ "columns": [
+ {
+ "expression": "is_active",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "teams_installations_installation_key_unique": {
+ "name": "teams_installations_installation_key_unique",
+ "nullsNotDistinct": false,
+ "columns": ["installation_key"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.teams_user_mappings": {
+ "name": "teams_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "teams_user_id": {
+ "name": "teams_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "teams_tenant_id": {
+ "name": "teams_tenant_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "teams_aad_object_id": {
+ "name": "teams_aad_object_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "teams_user_mappings_aad_object_idx": {
+ "name": "teams_user_mappings_aad_object_idx",
+ "columns": [
+ {
+ "expression": "teams_aad_object_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "teams_tenant_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "teams_user_mappings_user_id_idx": {
+ "name": "teams_user_mappings_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "teams_user_mappings_user_id_users_id_fk": {
+ "name": "teams_user_mappings_user_id_users_id_fk",
+ "tableFrom": "teams_user_mappings",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "teams_user_mappings_unique": {
+ "name": "teams_user_mappings_unique",
+ "nullsNotDistinct": false,
+ "columns": ["teams_user_id", "teams_tenant_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.telegram_user_mappings": {
+ "name": "telegram_user_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "telegram_user_id": {
+ "name": "telegram_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "telegram_chat_id": {
+ "name": "telegram_chat_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "telegram_username": {
+ "name": "telegram_username",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "telegram_user_mappings_user_id_idx": {
+ "name": "telegram_user_mappings_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "telegram_user_mappings_user_id_users_id_fk": {
+ "name": "telegram_user_mappings_user_id_users_id_fk",
+ "tableFrom": "telegram_user_mappings",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "telegram_user_mappings_unique": {
+ "name": "telegram_user_mappings_unique",
+ "nullsNotDistinct": false,
+ "columns": ["telegram_user_id"]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.tracked_messages": {
+ "name": "tracked_messages",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "surface": {
+ "name": "surface",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "dedupe_key": {
+ "name": "dedupe_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "channel_id": {
+ "name": "channel_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "message_ts": {
+ "name": "message_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "thread_ts": {
+ "name": "thread_ts",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "work_item_id": {
+ "name": "work_item_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "automation_key": {
+ "name": "automation_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_by_user_id": {
+ "name": "created_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "summary_text": {
+ "name": "summary_text",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "''"
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "posted_at": {
+ "name": "posted_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "dismissed_at": {
+ "name": "dismissed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "tracked_messages_kind_dedupe_key_unique": {
+ "name": "tracked_messages_kind_dedupe_key_unique",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "dedupe_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tracked_messages_work_item_id_idx": {
+ "name": "tracked_messages_work_item_id_idx",
+ "columns": [
+ {
+ "expression": "work_item_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tracked_messages_channel_message_idx": {
+ "name": "tracked_messages_channel_message_idx",
+ "columns": [
+ {
+ "expression": "channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "message_ts",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "tracked_messages_automation_channel_posted_idx": {
+ "name": "tracked_messages_automation_channel_posted_idx",
+ "columns": [
+ {
+ "expression": "automation_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "channel_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "posted_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "tracked_messages_work_item_id_work_items_id_fk": {
+ "name": "tracked_messages_work_item_id_work_items_id_fk",
+ "tableFrom": "tracked_messages",
+ "tableTo": "work_items",
+ "columnsFrom": ["work_item_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "tracked_messages_automation_key_automations_key_fk": {
+ "name": "tracked_messages_automation_key_automations_key_fk",
+ "tableFrom": "tracked_messages",
+ "tableTo": "automations",
+ "columnsFrom": ["automation_key"],
+ "columnsTo": ["key"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "tracked_messages_created_by_user_id_users_id_fk": {
+ "name": "tracked_messages_created_by_user_id_users_id_fk",
+ "tableFrom": "tracked_messages",
+ "tableTo": "users",
+ "columnsFrom": ["created_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.user_api_keys": {
+ "name": "user_api_keys",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "api_key": {
+ "name": "api_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "user_api_keys_user_id_idx": {
+ "name": "user_api_keys_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "user_api_keys_user_deployment_provider_unique": {
+ "name": "user_api_keys_user_deployment_provider_unique",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "user_api_keys_user_id_users_id_fk": {
+ "name": "user_api_keys_user_id_users_id_fk",
+ "tableFrom": "user_api_keys",
+ "tableTo": "users",
+ "columnsFrom": ["user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image_url": {
+ "name": "image_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "entity": {
+ "name": "entity",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{}'::jsonb"
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'member'"
+ },
+ "analytics_id": {
+ "name": "analytics_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cookie_consented_at": {
+ "name": "cookie_consented_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "onboarding_completed_at": {
+ "name": "onboarding_completed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "invited_by_invite_id": {
+ "name": "invited_by_invite_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_sync_at": {
+ "name": "last_sync_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "deleted_at": {
+ "name": "deleted_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "users_email_idx": {
+ "name": "users_email_idx",
+ "columns": [
+ {
+ "expression": "email",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "users_created_at_idx": {
+ "name": "users_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "users_analytics_id_unique_idx": {
+ "name": "users_analytics_id_unique_idx",
+ "columns": [
+ {
+ "expression": "analytics_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.webhooks": {
+ "name": "webhooks",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "delivery_id": {
+ "name": "delivery_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "event": {
+ "name": "event",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload": {
+ "name": "payload",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "succeeded_at": {
+ "name": "succeeded_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "failed_at": {
+ "name": "failed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "error": {
+ "name": "error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "webhooks_provider_delivery_id_unique": {
+ "name": "webhooks_provider_delivery_id_unique",
+ "columns": [
+ {
+ "expression": "provider",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "delivery_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "webhooks_event_idx": {
+ "name": "webhooks_event_idx",
+ "columns": [
+ {
+ "expression": "event",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "webhooks_created_at_idx": {
+ "name": "webhooks_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {
+ "webhooks_status_exclusive": {
+ "name": "webhooks_status_exclusive",
+ "value": "(\n (succeeded_at IS NOT NULL)::int +\n (failed_at IS NOT NULL)::int\n ) <= 1"
+ }
+ },
+ "isRLSEnabled": false
+ },
+ "public.work_items": {
+ "name": "work_items",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "uuid",
+ "primaryKey": true,
+ "notNull": true,
+ "default": "gen_random_uuid()"
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "automation_key": {
+ "name": "automation_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source_task_id": {
+ "name": "source_task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "selected_by_user_id": {
+ "name": "selected_by_user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source_work_item_id": {
+ "name": "source_work_item_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "brief": {
+ "name": "brief",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "execution_prompt": {
+ "name": "execution_prompt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "investigation_context": {
+ "name": "investigation_context",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "priority": {
+ "name": "priority",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action_kind": {
+ "name": "action_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "disposition": {
+ "name": "disposition",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sort_order": {
+ "name": "sort_order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "repository_ids": {
+ "name": "repository_ids",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'[]'::jsonb"
+ },
+ "target_repository_full_name": {
+ "name": "target_repository_full_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "target_environment_id": {
+ "name": "target_environment_id",
+ "type": "uuid",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "workspace_readiness": {
+ "name": "workspace_readiness",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "readiness_message": {
+ "name": "readiness_message",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "fingerprint": {
+ "name": "fingerprint",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'open'"
+ },
+ "launch_claimed_at": {
+ "name": "launch_claimed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "launched_task_id": {
+ "name": "launched_task_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "launched_at": {
+ "name": "launched_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "failed_at": {
+ "name": "failed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "launch_error": {
+ "name": "launch_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "dismissed_at": {
+ "name": "dismissed_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "work_items_source_task_idx": {
+ "name": "work_items_source_task_idx",
+ "columns": [
+ {
+ "expression": "source_task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "work_items_kind_status_idx": {
+ "name": "work_items_kind_status_idx",
+ "columns": [
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "status",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "work_items_automation_key_fingerprint_idx": {
+ "name": "work_items_automation_key_fingerprint_idx",
+ "columns": [
+ {
+ "expression": "automation_key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "fingerprint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "work_items_fingerprint_idx": {
+ "name": "work_items_fingerprint_idx",
+ "columns": [
+ {
+ "expression": "fingerprint",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "work_items_launched_task_id_idx": {
+ "name": "work_items_launched_task_id_idx",
+ "columns": [
+ {
+ "expression": "launched_task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "work_items_source_task_kind_sort_order_unique": {
+ "name": "work_items_source_task_kind_sort_order_unique",
+ "columns": [
+ {
+ "expression": "source_task_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "kind",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "sort_order",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "work_items_automation_key_automations_key_fk": {
+ "name": "work_items_automation_key_automations_key_fk",
+ "tableFrom": "work_items",
+ "tableTo": "automations",
+ "columnsFrom": ["automation_key"],
+ "columnsTo": ["key"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "work_items_source_task_id_tasks_id_fk": {
+ "name": "work_items_source_task_id_tasks_id_fk",
+ "tableFrom": "work_items",
+ "tableTo": "tasks",
+ "columnsFrom": ["source_task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "work_items_selected_by_user_id_users_id_fk": {
+ "name": "work_items_selected_by_user_id_users_id_fk",
+ "tableFrom": "work_items",
+ "tableTo": "users",
+ "columnsFrom": ["selected_by_user_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "work_items_source_work_item_id_work_items_id_fk": {
+ "name": "work_items_source_work_item_id_work_items_id_fk",
+ "tableFrom": "work_items",
+ "tableTo": "work_items",
+ "columnsFrom": ["source_work_item_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "work_items_target_environment_id_environments_id_fk": {
+ "name": "work_items_target_environment_id_environments_id_fk",
+ "tableFrom": "work_items",
+ "tableTo": "environments",
+ "columnsFrom": ["target_environment_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ },
+ "work_items_launched_task_id_tasks_id_fk": {
+ "name": "work_items_launched_task_id_tasks_id_fk",
+ "tableFrom": "work_items",
+ "tableTo": "tasks",
+ "columnsFrom": ["launched_task_id"],
+ "columnsTo": ["id"],
+ "onDelete": "set null",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {},
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
diff --git a/packages/db/drizzle/meta/_journal.json b/packages/db/drizzle/meta/_journal.json
index 4312fbcbd..c83283c59 100644
--- a/packages/db/drizzle/meta/_journal.json
+++ b/packages/db/drizzle/meta/_journal.json
@@ -267,6 +267,13 @@
"when": 1786706349543,
"tag": "0037_youthful_fixer",
"breakpoints": true
+ },
+ {
+ "idx": 38,
+ "version": "7",
+ "when": 1786750533379,
+ "tag": "0038_perfect_madame_hydra",
+ "breakpoints": true
}
]
}
diff --git a/packages/db/src/lib/task-goals.test.ts b/packages/db/src/lib/task-goals.test.ts
index 676fc4e90..3e1c2c01b 100644
--- a/packages/db/src/lib/task-goals.test.ts
+++ b/packages/db/src/lib/task-goals.test.ts
@@ -13,6 +13,19 @@ import {
type TaskGoalMutationResult,
} from './task-goals';
+async function getStoredGoalTiming(taskId: string) {
+ const [stored] = await db
+ .select({
+ startedAt: tasks.goalStartedAt,
+ endedAt: tasks.goalEndedAt,
+ completedAt: tasks.goalCompletedAt,
+ })
+ .from(tasks)
+ .where(eq(tasks.id, taskId));
+
+ return stored;
+}
+
describe('task goals', () => {
it('holds a fast completion until goal delivery is committed', async () => {
const task = await taskFactory.create({
@@ -71,11 +84,15 @@ describe('task goals', () => {
});
it('restores the previous goal when delivery fails', async () => {
+ const previousStartedAt = new Date('2020-01-01T10:00:00Z');
+ const previousEndedAt = new Date('2020-01-01T10:05:00Z');
const task = await taskFactory.create({
goalObjective: 'Keep the existing objective',
- goalStatus: 'active',
+ goalStatus: 'blocked',
goalMaxContinuations: 3,
goalContinuationsUsed: 1,
+ goalStartedAt: previousStartedAt,
+ goalEndedAt: previousEndedAt,
goalContinuationIds: ['existing-turn'],
});
const run = await runFactory.create({ taskId: task.id });
@@ -90,10 +107,53 @@ describe('task goals', () => {
await expect(activation!.rollback()).resolves.toBe(true);
await expect(getTaskGoalForRun(run.id)).resolves.toMatchObject({
objective: 'Keep the existing objective',
- status: 'active',
+ status: 'blocked',
maxContinuations: 3,
continuationsUsed: 1,
});
+ await expect(getStoredGoalTiming(task.id)).resolves.toEqual({
+ startedAt: previousStartedAt,
+ endedAt: previousEndedAt,
+ completedAt: null,
+ });
+ });
+
+ it('resets lifecycle timing when a replacement goal begins', async () => {
+ const previousStartedAt = new Date('2020-01-01T10:00:00Z');
+ const previousEndedAt = new Date('2020-01-01T10:05:00Z');
+ const task = await taskFactory.create({
+ goalObjective: 'Old objective',
+ goalStatus: 'complete',
+ goalMaxContinuations: 3,
+ goalStartedAt: previousStartedAt,
+ goalEndedAt: previousEndedAt,
+ goalCompletedAt: previousEndedAt,
+ });
+ const run = await runFactory.create({ taskId: task.id });
+
+ const activation = await prepareTaskGoalActivation({
+ taskId: task.id,
+ goal: { objective: 'Replacement objective', maxContinuations: 5 },
+ });
+ const replacement = await activation!.commit();
+
+ expect(replacement).toMatchObject({
+ objective: 'Replacement objective',
+ status: 'active',
+ completedAt: null,
+ });
+ const replacementTiming = await getStoredGoalTiming(task.id);
+ expect(replacementTiming?.startedAt?.getTime()).toBeGreaterThan(
+ previousEndedAt.getTime(),
+ );
+ expect(replacementTiming).toMatchObject({
+ endedAt: null,
+ completedAt: null,
+ });
+ await expect(getTaskGoalForRun(run.id)).resolves.toMatchObject({
+ objective: 'Replacement objective',
+ status: 'active',
+ });
});
it('stops a waiting completion when first-time goal delivery fails', async () => {
@@ -383,7 +443,14 @@ describe('task goals', () => {
expect(exhausted).toMatchObject({
updated: false,
reason: 'budget_exhausted',
- goal: { status: 'budget_limited', continuationsUsed: 2 },
+ goal: {
+ status: 'budget_limited',
+ continuationsUsed: 2,
+ },
+ });
+ await expect(getStoredGoalTiming(task.id)).resolves.toMatchObject({
+ endedAt: expect.any(Date),
+ completedAt: null,
});
});
@@ -416,6 +483,9 @@ describe('task goals', () => {
status: 'active',
continuationsUsed: 0,
});
+ await expect(getStoredGoalTiming(task.id)).resolves.toMatchObject({
+ endedAt: null,
+ });
});
it('keeps claimed and released generations assigned after another continuation advances', async () => {
@@ -570,7 +640,14 @@ describe('task goals', () => {
await continueTurn('blocker-turn-4');
await expect(observe('Missing credential')).resolves.toMatchObject({
updated: true,
- goal: { status: 'blocked', blockedReason: 'Missing credential' },
+ goal: {
+ status: 'blocked',
+ blockedReason: 'Missing credential',
+ },
+ });
+ await expect(getStoredGoalTiming(task.id)).resolves.toMatchObject({
+ endedAt: expect.any(Date),
+ completedAt: null,
});
});
@@ -633,8 +710,13 @@ describe('task goals', () => {
expect(completed).toMatchObject({
updated: true,
- goal: { status: 'complete' },
+ goal: {
+ status: 'complete',
+ completedAt: expect.any(Date),
+ },
});
+ const completedTiming = await getStoredGoalTiming(task.id);
+ expect(completedTiming?.endedAt).toEqual(completedTiming?.completedAt);
expect(duplicate).toMatchObject({
updated: false,
reason: 'not_active',
diff --git a/packages/db/src/lib/task-goals.ts b/packages/db/src/lib/task-goals.ts
index 7f909bafa..6643d8af8 100644
--- a/packages/db/src/lib/task-goals.ts
+++ b/packages/db/src/lib/task-goals.ts
@@ -134,6 +134,7 @@ export async function prepareTaskGoalActivation(input: {
const activationUuid = randomUUID();
const activationId = `${GOAL_ACTIVATION_PREFIX}${activationUuid}`;
const generationId = `${GOAL_GENERATION_PREFIX}${activationUuid}`;
+ const startedAt = new Date();
const previous = await db.transaction(async (tx) => {
const [task] = await tx
.select()
@@ -153,6 +154,8 @@ export async function prepareTaskGoalActivation(input: {
goalMaxContinuations: input.goal.maxContinuations,
goalContinuationsUsed: 0,
goalBlockedReason: null,
+ goalStartedAt: startedAt,
+ goalEndedAt: null,
goalCompletedAt: null,
goalLastContinuationId: activationId,
goalContinuationIds: [],
@@ -202,6 +205,8 @@ export async function prepareTaskGoalActivation(input: {
goalMaxContinuations: previous.goalMaxContinuations,
goalContinuationsUsed: previous.goalContinuationsUsed,
goalBlockedReason: previous.goalBlockedReason,
+ goalStartedAt: previous.goalStartedAt,
+ goalEndedAt: previous.goalEndedAt,
goalCompletedAt: previous.goalCompletedAt,
goalLastContinuationId: previous.goalLastContinuationId,
goalContinuationIds: previous.goalContinuationIds,
@@ -285,6 +290,7 @@ export async function markTaskGoalForRun(
? {
goalStatus: 'blocked',
goalBlockedReason: reason,
+ goalEndedAt: new Date(),
goalBlockerCandidateReason: null,
goalBlockerCandidateCount: 0,
goalBlockerLastContinuationUsed: null,
@@ -344,12 +350,14 @@ export async function markTaskGoalForRun(
};
}
+ const completedAt = new Date();
const [updated] = await db
.update(tasks)
.set({
goalStatus: input.status,
goalBlockedReason: null,
- goalCompletedAt: new Date(),
+ goalEndedAt: completedAt,
+ goalCompletedAt: completedAt,
goalBlockerCandidateReason: null,
goalBlockerCandidateCount: 0,
goalBlockerLastContinuationUsed: null,
@@ -457,7 +465,11 @@ export async function claimTaskGoalContinuationForRun(input: {
const [limited] = await db
.update(tasks)
- .set({ goalStatus: 'budget_limited', updatedAt: new Date() })
+ .set({
+ goalStatus: 'budget_limited',
+ goalEndedAt: new Date(),
+ updatedAt: new Date(),
+ })
.where(
and(
eq(tasks.id, current.id),
@@ -499,6 +511,7 @@ export async function releaseTaskGoalContinuationForRun(input: {
.update(tasks)
.set({
goalStatus: 'active',
+ goalEndedAt: null,
goalContinuationsUsed: sql`GREATEST(${tasks.goalContinuationsUsed} - 1, 0)`,
goalLastContinuationId: releasedGeneration,
goalContinuationIds: sql`array_remove(${tasks.goalContinuationIds}, ${input.continuationId})`,
diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts
index 0acce2e2f..259978d88 100644
--- a/packages/db/src/schema.ts
+++ b/packages/db/src/schema.ts
@@ -702,6 +702,8 @@ export const tasks = pgTable(
.notNull()
.default(0),
goalBlockedReason: text('goal_blocked_reason'),
+ goalStartedAt: timestamp('goal_started_at'),
+ goalEndedAt: timestamp('goal_ended_at'),
goalCompletedAt: timestamp('goal_completed_at'),
goalLastContinuationId: text('goal_last_continuation_id'),
goalContinuationIds: text('goal_continuation_ids')
From f15736acc35a88f580bc2d587ba33e533549ddc0 Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Sat, 15 Aug 2026 00:08:30 +0000
Subject: [PATCH 5/7] fix: refresh goal panel after activation
---
.../prompt-input/PromptInput.client.test.tsx | 21 +++++++++++++------
.../[taskId]/prompt-input/PromptInput.tsx | 12 +++++++++--
.../prompt-input/optimistic-prompt.ts | 5 -----
.../useOptimisticPromptSubmission.ts | 3 ---
4 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx
index 8a14ac0ee..7af2a40f5 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.client.test.tsx
@@ -21,6 +21,7 @@ const {
appendAcpEventMock,
mutateMock,
preparePromptAttachmentsMock,
+ queryClientInvalidateQueriesMock,
queryClientSetQueryDataMock,
removeOptimisticMessageMock,
removeOptimisticQueuedMessageMock,
@@ -58,6 +59,7 @@ const {
appendAcpEventMock: vi.fn(),
mutateMock: vi.fn(),
preparePromptAttachmentsMock: vi.fn(),
+ queryClientInvalidateQueriesMock: vi.fn(),
queryClientSetQueryDataMock: vi.fn(),
removeOptimisticMessageMock: vi.fn(),
removeOptimisticQueuedMessageMock: vi.fn(),
@@ -94,6 +96,7 @@ const submittedFilesRef: {
vi.mock('@tanstack/react-query', () => ({
useMutation: useMutationMock,
useQueryClient: () => ({
+ invalidateQueries: queryClientInvalidateQueriesMock,
setQueryData: queryClientSetQueryDataMock,
}),
}));
@@ -322,6 +325,12 @@ describe('PromptInput', () => {
useTRPCMock.mockReturnValue({
sandboxSession: {
+ byTaskId: {
+ queryKey: vi.fn(({ taskId }: { taskId: string }) => [
+ 'sandboxSession.byTaskId',
+ taskId,
+ ]),
+ },
saveDraftPrompt: {
mutationOptions: vi.fn((options) => options ?? {}),
},
@@ -901,14 +910,14 @@ describe('PromptInput', () => {
expect(appendOptimisticAcpEventMock).toHaveBeenCalledWith(
expect.objectContaining({
text: 'ship the release',
- payload: expect.objectContaining({
- goal: {
- objective: 'ship the release',
- generation: null,
- },
- }),
+ payload: expect.not.objectContaining({ goal: expect.anything() }),
}),
);
+ await waitFor(() => {
+ expect(queryClientInvalidateQueriesMock).toHaveBeenCalledWith({
+ queryKey: ['sandboxSession.byTaskId', 'task-goal'],
+ });
+ });
expect(toastSuccessMock).toHaveBeenCalledWith('Goal Mode enabled');
});
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx
index fb040f457..9ec652b5e 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/PromptInput.tsx
@@ -8,7 +8,7 @@ import {
useRef,
useState,
} from 'react';
-import { useMutation } from '@tanstack/react-query';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import {
@@ -103,6 +103,7 @@ export const PromptInput = forwardRef(
) {
const trpc = useTRPC();
const trpcClient = useTRPCClient();
+ const queryClient = useQueryClient();
const client = useSandboxClient();
const {
rollbackOptimisticPromptSubmission,
@@ -473,7 +474,6 @@ export const PromptInput = forwardRef(
taskId: taskRun.taskId,
prompt: preparedPrompt.text,
images: preparedPrompt.images,
- ...(goalObjective ? { goalObjective } : {}),
location: optimisticLocation,
});
optimisticClientMessageId = clientMessageId;
@@ -489,6 +489,12 @@ export const PromptInput = forwardRef(
if (!started.success) {
throw new Error(started.error);
}
+
+ await queryClient.invalidateQueries({
+ queryKey: trpc.sandboxSession.byTaskId.queryKey({
+ taskId: taskRun.taskId,
+ }),
+ });
} else {
await trpcClient.sandboxSession.sendPrompt.mutate({
taskId: taskRun.taskId,
@@ -531,9 +537,11 @@ export const PromptInput = forwardRef(
pendingUserInputState,
sending,
handlePromptChange,
+ queryClient,
scrollToBottom,
handleMessageSent,
taskRun,
+ trpc,
trpcClient,
rollbackOptimisticPromptSubmission,
startOptimisticPromptSubmission,
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts
index 3c7341545..a503c86e1 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/optimistic-prompt.ts
@@ -20,7 +20,6 @@ type OptimisticPromptInput = {
taskId: string;
prompt: string;
images?: string[];
- goalObjective?: string;
clientMessageId: string;
currentUserInfo: OptimisticPromptUserInfo | null;
};
@@ -39,7 +38,6 @@ export function createOptimisticPromptArtifacts({
taskId,
prompt,
images,
- goalObjective,
clientMessageId,
currentUserInfo,
}: OptimisticPromptInput): OptimisticPromptArtifacts {
@@ -62,9 +60,6 @@ export function createOptimisticPromptArtifacts({
prompt: contentBlocks,
content,
...(images ? { images } : {}),
- ...(goalObjective
- ? { goal: { objective: goalObjective, generation: null } }
- : {}),
...(currentUserInfo?.userId ? { userId: currentUserInfo.userId } : {}),
...(currentUserInfo?.userName
? { userName: currentUserInfo.userName }
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts
index 35386751e..08e14b054 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/prompt-input/useOptimisticPromptSubmission.ts
@@ -27,7 +27,6 @@ type StartOptimisticPromptSubmissionInput = {
taskId: string;
prompt: string;
images?: string[];
- goalObjective?: string;
location: OptimisticPromptLocation;
};
@@ -68,7 +67,6 @@ export function useOptimisticPromptSubmission() {
taskId,
prompt,
images,
- goalObjective,
location,
}: StartOptimisticPromptSubmissionInput) => {
const clientMessageId = generateClientUuid();
@@ -76,7 +74,6 @@ export function useOptimisticPromptSubmission() {
taskId,
prompt,
images,
- goalObjective,
clientMessageId,
currentUserInfo,
});
From ddc60966efe41bcafe4df4f4baf332be90a91cc8 Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Sat, 15 Aug 2026 06:19:57 +0000
Subject: [PATCH 6/7] fix: compact goal status panel
---
.../task/[taskId]/GoalPanel.client.test.tsx | 108 +++++++++---------
.../app/(sandbox)/task/[taskId]/GoalPanel.tsx | 79 ++++++-------
.../task/[taskId]/LiveContent.client.test.tsx | 2 +-
3 files changed, 93 insertions(+), 96 deletions(-)
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
index f325de542..1429769bc 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
@@ -43,64 +43,54 @@ describe('GoalPanel', () => {
it('shows an active goal and advances elapsed time from its durable start', () => {
render();
- expect(screen.getByTestId('goal-panel')).toHaveTextContent('Current goal');
- expect(screen.getByTestId('goal-panel')).toHaveTextContent('Active');
- expect(screen.getByTestId('goal-panel')).toHaveTextContent(
- 'Ship the durable goal panel',
+ const panel = screen.getByTestId('goal-panel');
+ expect(panel).toHaveClass('flex', 'items-center', 'py-2');
+ expect(panel).not.toHaveClass('flex-wrap');
+ expect(panel.children).toHaveLength(5);
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Pursuing goal',
);
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- 'Active for 1m 5s',
+ expect(screen.getByTestId('goal-objective')).toHaveTextContent(
+ 'Ship the durable goal panel',
);
+ expect(screen.getByTestId('goal-separator')).toHaveTextContent('·');
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('1m 5s');
+ expect(screen.getByTestId('goal-duration')).not.toHaveClass('ml-auto');
act(() => vi.advanceTimersByTime(5_000));
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- 'Active for 1m 10s',
- );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('1m 10s');
});
it.each([
- ['complete', 'Complete', 'Completed after'],
- ['blocked', 'Blocked', 'Blocked after'],
- ['budget_limited', 'Continuation limit reached', 'Limit reached after'],
- ] as const)(
- 'shows a stable duration for a %s goal',
- (status, label, durationPrefix) => {
- render(
- ,
- );
-
- expect(screen.getByTestId('goal-panel')).toHaveTextContent(label);
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- `${durationPrefix} 2m 5s`,
- );
- if (status === 'blocked') {
- expect(screen.getByTestId('goal-panel')).toHaveTextContent(
- 'Waiting for approval',
- );
- }
-
- act(() => vi.advanceTimersByTime(10_000));
-
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- `${durationPrefix} 2m 5s`,
- );
- },
- );
+ ['complete', 'Goal complete'],
+ ['blocked', 'Goal blocked'],
+ ['budget_limited', 'Continuation limit reached'],
+ ] as const)('shows a stable duration for a %s goal', (status, label) => {
+ render(
+ ,
+ );
+
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(label);
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('2m 5s');
+ expect(screen.getByTestId('goal-panel').children).toHaveLength(5);
+
+ act(() => vi.advanceTimersByTime(10_000));
+
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('2m 5s');
+ });
it('resets objective and elapsed time when a replacement goal starts', () => {
const { rerender } = render();
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- 'Active for 1m 5s',
- );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('1m 5s');
rerender(
{
/>,
);
- expect(screen.getByTestId('goal-panel')).toHaveTextContent(
+ expect(screen.getByTestId('goal-objective')).toHaveTextContent(
'Ship the replacement goal',
);
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- 'Active for 5s',
- );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('5s');
});
it('renders a durable goal again after remounting', () => {
@@ -126,15 +114,23 @@ describe('GoalPanel', () => {
});
const first = render();
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- 'Completed after 45s',
- );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('45s');
first.unmount();
render();
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
- 'Completed after 45s',
- );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('45s');
+ });
+
+ it('keeps long objectives on one truncating line with full text available', () => {
+ const objective =
+ 'Ship a very long durable goal objective without expanding the compact composer status row';
+ render();
+
+ const objectiveElement = screen.getByTestId('goal-objective');
+ expect(objectiveElement).toHaveClass('min-w-0', 'truncate');
+ expect(objectiveElement).toHaveAttribute('title', objective);
+ expect(objectiveElement.tagName).toBe('SPAN');
+ expect(screen.getByTestId('goal-panel').querySelector('p')).toBeNull();
});
it('does not infer a terminal duration when durable timing is incomplete', () => {
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
index dbe9f968a..602d04c4b 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
@@ -5,11 +5,10 @@ import type { TaskGoalStatus } from '@roomote/types';
import { TodoList as TodoListPrimitive } from '@/components/ai-elements';
import {
- Badge,
+ BasicTooltip,
CircleAlert,
CircleCheck,
LoaderCircle,
- Sparkles,
} from '@/components/system';
import type { TaskSession } from './hooks/use-task-session';
@@ -64,30 +63,22 @@ function getGoalPresentation(status: TaskGoalStatus) {
switch (status) {
case 'active':
return {
- label: 'Active',
- durationPrefix: 'Active for',
- badgeVariant: 'default' as const,
+ label: 'Pursuing goal',
Icon: LoaderCircle,
};
case 'complete':
return {
- label: 'Complete',
- durationPrefix: 'Completed after',
- badgeVariant: 'success' as const,
+ label: 'Goal complete',
Icon: CircleCheck,
};
case 'blocked':
return {
- label: 'Blocked',
- durationPrefix: 'Blocked after',
- badgeVariant: 'warning' as const,
+ label: 'Goal blocked',
Icon: CircleAlert,
};
case 'budget_limited':
return {
label: 'Continuation limit reached',
- durationPrefix: 'Limit reached after',
- badgeVariant: 'warning' as const,
Icon: CircleAlert,
};
}
@@ -126,35 +117,45 @@ export function GoalPanel({ task }: { task: TaskSession['task'] }) {
return (
-
-
-
-
- Current goal
-
-
-
- {presentation.label}
-
+
+
+
+ {presentation.label}
+
+
- {duration
- ? `${presentation.durationPrefix} ${duration}`
- : 'Duration unavailable'}
+ {objective}
-
-
- {objective}
-
- {status === 'blocked' && task.goalBlockedReason ? (
-
- {task.goalBlockedReason}
-
- ) : null}
+
+
+ ·
+
+
+ {duration ?? 'Duration unavailable'}
+
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx
index 74a040022..c59b65b01 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/LiveContent.client.test.tsx
@@ -150,7 +150,7 @@ describe('TaskInputStack', () => {
/>,
);
- expect(screen.getByTestId('goal-panel')).toHaveTextContent('Complete');
+ expect(screen.getByTestId('goal-panel')).toHaveTextContent('Goal complete');
expect(screen.getByTestId('goal-panel')).toHaveTextContent(
'Finish the current objective',
);
From a1aba1ed0ff25903537b6156ad67fb6cabac1a01 Mon Sep 17 00:00:00 2001
From: "@daniel-lxs" <57051444+daniel-lxs@users.noreply.github.com>
Date: Sat, 15 Aug 2026 06:32:24 +0000
Subject: [PATCH 7/7] fix: keep compact goal status visible
---
.../task/[taskId]/GoalPanel.client.test.tsx | 20 ++++++++++++++++---
.../app/(sandbox)/task/[taskId]/GoalPanel.tsx | 4 +++-
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
index 1429769bc..bbb4edb9f 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.client.test.tsx
@@ -133,15 +133,29 @@ describe('GoalPanel', () => {
expect(screen.getByTestId('goal-panel').querySelector('p')).toBeNull();
});
- it('does not infer a terminal duration when durable timing is incomplete', () => {
+ it('uses a compact accessible fallback when durable timing is incomplete', () => {
render(
,
);
- expect(screen.getByTestId('goal-duration')).toHaveTextContent(
+ expect(screen.getByTestId('goal-status')).toHaveTextContent(
+ 'Continuation limit reached',
+ );
+ expect(screen.getByTestId('goal-duration')).toHaveTextContent('N/A');
+ expect(screen.getByTestId('goal-duration')).toHaveAttribute(
+ 'aria-label',
+ 'Duration unavailable',
+ );
+ expect(screen.getByTestId('goal-duration')).toHaveAttribute(
+ 'title',
'Duration unavailable',
);
+ expect(screen.getByTestId('goal-panel')).not.toHaveClass('flex-wrap');
});
});
diff --git a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
index 602d04c4b..9f7259701 100644
--- a/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
+++ b/apps/web/src/app/(sandbox)/task/[taskId]/GoalPanel.tsx
@@ -153,8 +153,10 @@ export function GoalPanel({ task }: { task: TaskSession['task'] }) {
- {duration ?? 'Duration unavailable'}
+ {duration ?? 'N/A'}