166 lines · 5.2 KB · TypeScript
RawDownload
import { Effect, Layer, Stream } from "effect";import { describe, expect, it, vi } from "vitest";import type { OrchestrationReadModel } from "@t3tools/contracts"; import { OrchestrationEngineService } from "../../orchestration/Services/OrchestrationEngine.ts";import { TerminalManager } from "../../terminal/Services/Manager.ts";import { ProjectSetupScriptRunner } from "../Services/ProjectSetupScriptRunner.ts";import { ProjectSetupScriptRunnerLive } from "./ProjectSetupScriptRunner.ts"; const emptySnapshot = (  scripts: OrchestrationReadModel["projects"][number]["scripts"],): OrchestrationReadModel =>  ({    snapshotSequence: 1,    updatedAt: "2026-01-01T00:00:00.000Z",    projects: [      {        id: "project-1",        title: "Project",        workspaceRoot: "/repo/project",        defaultModelSelection: null,        scripts,        createdAt: "2026-01-01T00:00:00.000Z",        updatedAt: "2026-01-01T00:00:00.000Z",        deletedAt: null,      },    ],    threads: [],    providerSessions: [],    providerStatuses: [],    pendingApprovals: [],    latestTurnByThreadId: {},  }) as unknown as OrchestrationReadModel; describe("ProjectSetupScriptRunner", () => {  it("returns no-script when no setup script exists", async () => {    const open = vi.fn();    const write = vi.fn();    const runner = await Effect.runPromise(      Effect.service(ProjectSetupScriptRunner).pipe(        Effect.provide(          ProjectSetupScriptRunnerLive.pipe(            Layer.provideMerge(              Layer.succeed(OrchestrationEngineService, {                getReadModel: () => Effect.succeed(emptySnapshot([])),                readEvents: () => Stream.empty,                dispatch: () => Effect.die(new Error("unused")),                streamDomainEvents: Stream.empty,              }),            ),            Layer.provideMerge(              Layer.succeed(TerminalManager, {                open,                write,                resize: () => Effect.void,                clear: () => Effect.void,                restart: () => Effect.die(new Error("unused")),                close: () => Effect.void,                subscribe: () => Effect.succeed(() => undefined),              }),            ),          ),        ),      ),    );     const result = await Effect.runPromise(      runner.runForThread({        threadId: "thread-1",        projectId: "project-1",        worktreePath: "/repo/worktrees/a",      }),    );     expect(result).toEqual({ status: "no-script" });    expect(open).not.toHaveBeenCalled();    expect(write).not.toHaveBeenCalled();  });   it("opens the deterministic setup terminal with worktree env and writes the command", async () => {    const open = vi.fn(() =>      Effect.succeed({        threadId: "thread-1",        terminalId: "setup-setup",        cwd: "/repo/worktrees/a",        worktreePath: "/repo/worktrees/a",        status: "running" as const,        pid: 123,        history: "",        exitCode: null,        exitSignal: null,        updatedAt: "2026-01-01T00:00:00.000Z",      }),    );    const write = vi.fn(() => Effect.void);    const runner = await Effect.runPromise(      Effect.service(ProjectSetupScriptRunner).pipe(        Effect.provide(          ProjectSetupScriptRunnerLive.pipe(            Layer.provideMerge(              Layer.succeed(OrchestrationEngineService, {                getReadModel: () =>                  Effect.succeed(                    emptySnapshot([                      {                        id: "setup",                        name: "Setup",                        command: "bun install",                        icon: "configure",                        runOnWorktreeCreate: true,                      },                    ]),                  ),                readEvents: () => Stream.empty,                dispatch: () => Effect.die(new Error("unused")),                streamDomainEvents: Stream.empty,              }),            ),            Layer.provideMerge(              Layer.succeed(TerminalManager, {                open,                write,                resize: () => Effect.void,                clear: () => Effect.void,                restart: () => Effect.die(new Error("unused")),                close: () => Effect.void,                subscribe: () => Effect.succeed(() => undefined),              }),            ),          ),        ),      ),    );     const result = await Effect.runPromise(      runner.runForThread({        threadId: "thread-1",        projectCwd: "/repo/project",        worktreePath: "/repo/worktrees/a",      }),    );     expect(result).toEqual({      status: "started",      scriptId: "setup",      scriptName: "Setup",      terminalId: "setup-setup",      cwd: "/repo/worktrees/a",    });    expect(open).toHaveBeenCalledWith({      threadId: "thread-1",      terminalId: "setup-setup",      cwd: "/repo/worktrees/a",      worktreePath: "/repo/worktrees/a",      env: {        T3CODE_PROJECT_ROOT: "/repo/project",        T3CODE_WORKTREE_PATH: "/repo/worktrees/a",      },    });    expect(write).toHaveBeenCalledWith({      threadId: "thread-1",      terminalId: "setup-setup",      data: "bun install\r",    });  });});