219 lines · 5.7 KB · TypeScript
RawDownload
import { assert, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as SqlClient from "effect/unstable/sql/SqlClient"; import { runMigrations } from "../Migrations.ts";import * as NodeSqliteClient from "@t3tools/shared/nodeSqliteClient"; const layer = it.layer(Layer.mergeAll(NodeSqliteClient.layerMemory())); layer("024_BackfillProjectionThreadShellSummary", (it) => {  it.effect("backfills thread shell summary fields and clears stale projected approvals", () =>    Effect.gen(function* () {      const sql = yield* SqlClient.SqlClient;       yield* runMigrations({ toMigrationInclusive: 23 });       yield* sql`        INSERT INTO projection_threads (          thread_id,          project_id,          title,          model_selection_json,          runtime_mode,          interaction_mode,          branch,          worktree_path,          latest_turn_id,          created_at,          updated_at,          archived_at,          latest_user_message_at,          pending_approval_count,          pending_user_input_count,          has_actionable_proposed_plan,          deleted_at        )        VALUES (          'thread-1',          'project-1',          'Thread 1',          '{"provider":"codex","model":"gpt-5-codex"}',          'approval-required',          'plan',          NULL,          NULL,          'turn-1',          '2026-02-24T00:00:00.000Z',          '2026-02-24T00:00:00.000Z',          NULL,          NULL,          0,          0,          0,          NULL        )      `;       yield* sql`        INSERT INTO projection_thread_messages (          message_id,          thread_id,          turn_id,          role,          text,          attachments_json,          is_streaming,          created_at,          updated_at        )        VALUES (          'message-user-1',          'thread-1',          'turn-1',          'user',          'Need help',          NULL,          0,          '2026-02-24T00:01:00.000Z',          '2026-02-24T00:01:00.000Z'        )      `;       yield* sql`        INSERT INTO projection_thread_activities (          activity_id,          thread_id,          turn_id,          tone,          kind,          summary,          payload_json,          sequence,          created_at        )        VALUES          (            'activity-approval-requested',            'thread-1',            'turn-1',            'approval',            'approval.requested',            'Command approval requested',            '{"requestId":"approval-1","requestKind":"command"}',            NULL,            '2026-02-24T00:02:00.000Z'          ),          (            'activity-approval-stale',            'thread-1',            'turn-1',            'error',            'provider.approval.respond.failed',            'Provider approval response failed',            '{"requestId":"approval-1","detail":"Unknown pending permission request: approval-1"}',            NULL,            '2026-02-24T00:03:00.000Z'          ),          (            'activity-user-input-requested',            'thread-1',            'turn-1',            'info',            'user-input.requested',            'User input requested',            '{"requestId":"input-1","questions":[{"id":"area","header":"Area","question":"Which repo area should I inspect next?","options":[{"label":"Server","description":"Server orchestration."}]}]}',            NULL,            '2026-02-24T00:04:00.000Z'          )      `;       yield* sql`        INSERT INTO projection_thread_proposed_plans (          plan_id,          thread_id,          turn_id,          plan_markdown,          implemented_at,          implementation_thread_id,          created_at,          updated_at        )        VALUES (          'plan-1',          'thread-1',          'turn-1',          '# Do the thing',          NULL,          NULL,          '2026-02-24T00:05:00.000Z',          '2026-02-24T00:05:00.000Z'        )      `;       yield* sql`        INSERT INTO projection_pending_approvals (          request_id,          thread_id,          turn_id,          status,          decision,          created_at,          resolved_at        )        VALUES (          'approval-1',          'thread-1',          'turn-1',          'pending',          NULL,          '2026-02-24T00:02:00.000Z',          NULL        )      `;       yield* runMigrations({ toMigrationInclusive: 24 });       const threadRows = yield* sql<{        readonly latestUserMessageAt: string | null;        readonly pendingApprovalCount: number;        readonly pendingUserInputCount: number;        readonly hasActionableProposedPlan: number;      }>`        SELECT          latest_user_message_at AS "latestUserMessageAt",          pending_approval_count AS "pendingApprovalCount",          pending_user_input_count AS "pendingUserInputCount",          has_actionable_proposed_plan AS "hasActionableProposedPlan"        FROM projection_threads        WHERE thread_id = 'thread-1'      `;      assert.deepStrictEqual(threadRows, [        {          latestUserMessageAt: "2026-02-24T00:01:00.000Z",          pendingApprovalCount: 0,          pendingUserInputCount: 1,          hasActionableProposedPlan: 1,        },      ]);       const approvalRows = yield* sql<{        readonly status: string;        readonly resolvedAt: string | null;      }>`        SELECT          status,          resolved_at AS "resolvedAt"        FROM projection_pending_approvals        WHERE request_id = 'approval-1'      `;      assert.deepStrictEqual(approvalRows, [        {          status: "resolved",          resolvedAt: "2026-02-24T00:03:00.000Z",        },      ]);    }),  );});