3390 lines · 113.9 KB · TypeScript
RawDownload
import {  type AgentSessionImportSource,  ChatAttachment,  CheckpointRef,  EventId,  MessageId,  ProjectId,  ThreadId,  type ThreadPullRequestLink,  ThreadLinkedPullRequest,  TurnId,  ProviderInstanceId,} from "@t3tools/contracts";import { assert, it } from "@effect/vitest";import * as NodeServices from "@effect/platform-node/NodeServices";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Schema from "effect/Schema";import * as SqlClient from "effect/unstable/sql/SqlClient"; import { SqlitePersistenceMemory } from "../../persistence/Layers/Sqlite.ts";import * as RepositoryIdentityResolver from "../../project/RepositoryIdentityResolver.ts";import { ORCHESTRATION_PROJECTOR_NAMES } from "./ProjectionPipeline.ts";import { OrchestrationProjectionSnapshotQueryLive } from "./ProjectionSnapshotQuery.ts";import * as ThreadBackgroundLiveness from "../ThreadBackgroundLiveness.ts";import * as ThreadPlanProgress from "../ThreadPlanProgress.ts";import { ProjectionSnapshotQuery } from "../Services/ProjectionSnapshotQuery.ts";import { encodeThreadDetailPageCursor } from "../threadDetailCursor.ts";import { projectThreadDetailSnapshot } from "../ActivityPayloadProjection.ts";import { makeSqlStatementCounter } from "../../../integration/SqlStatementCounter.integration.ts"; const asProjectId = (value: string): ProjectId => ProjectId.make(value);const asTurnId = (value: string): TurnId => TurnId.make(value);const asMessageId = (value: string): MessageId => MessageId.make(value);const asEventId = (value: string): EventId => EventId.make(value);const asCheckpointRef = (value: string): CheckpointRef => CheckpointRef.make(value);const encodeChatAttachments = Schema.encodeEffect(  Schema.fromJsonString(Schema.Array(ChatAttachment)),);const encodeThreadLinkedPullRequest = Schema.encodeSync(  Schema.fromJsonString(ThreadLinkedPullRequest),); const projectionSnapshotLayer = it.layer(  OrchestrationProjectionSnapshotQueryLive.pipe(    Layer.provide(ThreadBackgroundLiveness.layer),    Layer.provide(ThreadPlanProgress.layer),    Layer.provideMerge(RepositoryIdentityResolver.layer),    Layer.provideMerge(SqlitePersistenceMemory),    Layer.provideMerge(NodeServices.layer),  ),); projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => {  it.effect("hydrates read model from projection tables and computes snapshot sequence", () =>    Effect.gen(function* () {      const snapshotQuery = yield* ProjectionSnapshotQuery;      const sql = yield* SqlClient.SqlClient;      const branchPullRequest = {        projectId: asProjectId("project-1"),        repository: "pingdotgg/t3code",        number: 43,        url: "https://github.com/pingdotgg/t3code/pull/43",      };       yield* sql`DELETE FROM projection_projects`;      yield* sql`DELETE FROM projection_state`;      yield* sql`DELETE FROM projection_thread_proposed_plans`;      yield* sql`DELETE FROM projection_thread_pull_requests`;      yield* sql`DELETE FROM projection_turns`;       yield* sql`        INSERT INTO projection_projects (          project_id,          title,          workspace_root,          default_model_selection_json,          scripts_json,          created_at,          updated_at,          deleted_at        )        VALUES (          'project-1',          'Project 1',          '/tmp/project-1',          '{"provider":"codex","model":"gpt-5-codex"}',          '[{"id":"script-1","name":"Build","command":"bun run build","icon":"build","runOnWorktreeCreate":false}]',          '2026-02-24T00:00:00.000Z',          '2026-02-24T00:00:01.000Z',          NULL        )      `;       // A merged link plus a newer open one: the multi-link projection must      // resolve to the open pull request, not the stale JSON column below.      yield* sql`        INSERT INTO projection_thread_pull_requests (          thread_id,          host,          repository,          number,          url,          source,          linked_at,          snapshot_json,          stack_json        )        VALUES          (            'thread-1',            'github.com',            'pingdotgg/t3code',            41,            'https://github.com/pingdotgg/t3code/pull/41',            'created',            '2026-02-24T00:00:02.500Z',            '{"state":"merged","title":"Groundwork","headBranch":"feat/groundwork","baseBranch":"main","isDraft":false,"updatedAt":"2026-02-24T00:00:02.600Z","syncedAt":"2026-02-24T00:00:02.700Z"}',            NULL          ),          (            'thread-1',            'github.com',            'pingdotgg/t3code',            42,            'https://github.com/pingdotgg/t3code/pull/42',            'manual',            '2026-02-24T00:00:03.000Z',            NULL,            NULL          )      `;       yield* sql`        INSERT INTO projection_threads (          thread_id,          project_id,          title,          model_selection_json,          runtime_mode,          interaction_mode,          branch,          worktree_path,          linked_pull_request_json,          branch_pull_request_json,          latest_turn_id,          latest_user_message_at,          pending_approval_count,          pending_user_input_count,          has_actionable_proposed_plan,          pinned_at,          pin_order_key,          active_order_key,          created_at,          updated_at,          deleted_at        )        VALUES (          'thread-1',          'project-1',          'Thread 1',          '{"provider":"codex","model":"gpt-5-codex"}',          'full-access',          'default',          NULL,          NULL,          '{"projectId":"project-1","repository":"pingdotgg/t3code","number":41,"url":"https://github.com/pingdotgg/t3code/pull/41"}',          ${encodeThreadLinkedPullRequest(branchPullRequest)},          'turn-1',          '2026-02-24T00:00:04.000Z',          1,          0,          0,          '2026-02-24T00:00:01.000Z',          'gm',          'hq',          '2026-02-24T00:00:02.000Z',          '2026-02-24T00:00:03.000Z',          NULL        )      `;       yield* sql`        INSERT INTO projection_thread_messages (          message_id,          thread_id,          turn_id,          role,          text,          is_streaming,          created_at,          updated_at        )        VALUES (          'message-1',          'thread-1',          'turn-1',          'assistant',          'hello from projection',          0,          '2026-02-24T00:00:04.000Z',          '2026-02-24T00:00:05.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',          '# Ship it',          '2026-02-24T00:00:05.500Z',          'thread-2',          '2026-02-24T00:00:05.000Z',          '2026-02-24T00:00:05.500Z'        )      `;       yield* sql`        INSERT INTO projection_thread_activities (          activity_id,          thread_id,          turn_id,          tone,          kind,          summary,          payload_json,          created_at        )        VALUES (          'activity-1',          'thread-1',          'turn-1',          'info',          'runtime.note',          'provider started',          '{"stage":"start"}',          '2026-02-24T00:00:06.000Z'        )      `;       yield* sql`        INSERT INTO projection_thread_sessions (          thread_id,          status,          provider_name,          provider_session_id,          provider_thread_id,          runtime_mode,          active_turn_id,          last_error,          updated_at        )        VALUES (          'thread-1',          'running',          'codex',          'provider-session-1',          'provider-thread-1',          'approval-required',          'turn-1',          NULL,          '2026-02-24T00:00:07.000Z'        )      `;       yield* sql`        INSERT INTO projection_turns (          thread_id,          turn_id,          pending_message_id,          source_proposed_plan_thread_id,          source_proposed_plan_id,          assistant_message_id,          state,          requested_at,          started_at,          completed_at,          checkpoint_turn_count,          checkpoint_ref,          checkpoint_status,          checkpoint_files_json        )        VALUES (          'thread-1',          'turn-1',          NULL,          'thread-1',          'plan-1',          'message-1',          'completed',          '2026-02-24T00:00:08.000Z',          '2026-02-24T00:00:08.000Z',          '2026-02-24T00:00:08.000Z',          1,          'checkpoint-1',          'ready',          '[{"path":"README.md","kind":"modified","additions":2,"deletions":1}]'        )      `;       let sequence = 5;      for (const projector of Object.values(ORCHESTRATION_PROJECTOR_NAMES)) {        yield* sql`          INSERT INTO projection_state (            projector,            last_applied_sequence,            updated_at          )          VALUES (            ${projector},            ${sequence},            '2026-02-24T00:00:09.000Z'          )        `;        sequence += 1;      }       const expectedPullRequests: ReadonlyArray<ThreadPullRequestLink> = [        {          host: "github.com",          repository: "pingdotgg/t3code",          number: 41,          url: "https://github.com/pingdotgg/t3code/pull/41",          source: "created",          linkedAt: "2026-02-24T00:00:02.500Z",          snapshot: {            state: "merged",            title: "Groundwork",            headBranch: "feat/groundwork",            baseBranch: "main",            isDraft: false,            updatedAt: "2026-02-24T00:00:02.600Z",            syncedAt: "2026-02-24T00:00:02.700Z",          },          stack: null,        },        {          host: "github.com",          repository: "pingdotgg/t3code",          number: 42,          url: "https://github.com/pingdotgg/t3code/pull/42",          source: "manual",          linkedAt: "2026-02-24T00:00:03.000Z",          snapshot: null,          stack: null,        },      ];       const snapshot = yield* snapshotQuery.getSnapshot();       assert.equal(snapshot.snapshotSequence, 5);      assert.equal(snapshot.updatedAt, "2026-02-24T00:00:09.000Z");      assert.deepEqual(snapshot.projects, [        {          id: asProjectId("project-1"),          title: "Project 1",          workspaceRoot: "/tmp/project-1",          repositoryIdentity: null,          defaultModelSelection: {            instanceId: ProviderInstanceId.make("codex"),            model: "gpt-5-codex",          },          autoPull: false,          faviconPath: null,          projectIcon: null,          scripts: [            {              id: "script-1",              name: "Build",              command: "bun run build",              icon: "build",              runOnWorktreeCreate: false,            },          ],          defaultThreadEnvMode: null,          createdAt: "2026-02-24T00:00:00.000Z",          updatedAt: "2026-02-24T00:00:01.000Z",          deletedAt: null,        },      ]);      assert.deepEqual(snapshot.threads, [        {          id: ThreadId.make("thread-1"),          projectId: asProjectId("project-1"),          title: "Thread 1",          modelSelection: {            instanceId: ProviderInstanceId.make("codex"),            model: "gpt-5-codex",          },          interactionMode: "default",          runtimeMode: "full-access",          branch: null,          worktreePath: null,          pullRequests: expectedPullRequests,          branchPullRequest,          latestTurn: {            turnId: asTurnId("turn-1"),            state: "completed",            requestedAt: "2026-02-24T00:00:08.000Z",            startedAt: "2026-02-24T00:00:08.000Z",            completedAt: "2026-02-24T00:00:08.000Z",            assistantMessageId: asMessageId("message-1"),            sourceProposedPlan: {              threadId: ThreadId.make("thread-1"),              planId: "plan-1",            },          },          createdAt: "2026-02-24T00:00:02.000Z",          updatedAt: "2026-02-24T00:00:03.000Z",          archivedAt: null,          settledOverride: null,          settledAt: null,          unsettledAt: null,          snoozedUntil: null,          snoozedAt: null,          pinnedAt: "2026-02-24T00:00:01.000Z",          pinOrderKey: "gm",          activeOrderKey: "hq",          titleRegeneration: null,          deletedAt: null,          messages: [            {              id: asMessageId("message-1"),              role: "assistant",              text: "hello from projection",              turnId: asTurnId("turn-1"),              streaming: false,              createdAt: "2026-02-24T00:00:04.000Z",              updatedAt: "2026-02-24T00:00:05.000Z",            },          ],          proposedPlans: [            {              id: "plan-1",              turnId: asTurnId("turn-1"),              planMarkdown: "# Ship it",              implementedAt: "2026-02-24T00:00:05.500Z",              implementationThreadId: ThreadId.make("thread-2"),              createdAt: "2026-02-24T00:00:05.000Z",              updatedAt: "2026-02-24T00:00:05.500Z",            },          ],          activities: [            {              id: asEventId("activity-1"),              tone: "info",              kind: "runtime.note",              summary: "provider started",              payload: { stage: "start" },              turnId: asTurnId("turn-1"),              createdAt: "2026-02-24T00:00:06.000Z",            },          ],          checkpoints: [            {              turnId: asTurnId("turn-1"),              checkpointTurnCount: 1,              checkpointRef: asCheckpointRef("checkpoint-1"),              status: "ready",              files: [{ path: "README.md", kind: "modified", additions: 2, deletions: 1 }],              assistantMessageId: asMessageId("message-1"),              completedAt: "2026-02-24T00:00:08.000Z",            },          ],          session: {            threadId: ThreadId.make("thread-1"),            status: "running",            providerName: "codex",            runtimeMode: "approval-required",            activeTurnId: asTurnId("turn-1"),            lastError: null,            updatedAt: "2026-02-24T00:00:07.000Z",          },        },      ]);       const shellSnapshot = yield* snapshotQuery.getShellSnapshot();      assert.equal(shellSnapshot.snapshotSequence, 5);      assert.deepEqual(shellSnapshot.projects, [        {          id: asProjectId("project-1"),          title: "Project 1",          workspaceRoot: "/tmp/project-1",          repositoryIdentity: null,          defaultModelSelection: {            instanceId: ProviderInstanceId.make("codex"),            model: "gpt-5-codex",          },

Lines 1–500 of 3390.