Ctrl K
ComunidadGuías…

tests/support/project-settings-fixture.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * Fake repos row behind the database boundary for the Control project
 * settings tool tests. Importing it installs the hooks that restore
 * supabaseAdmin.from after each test.
 */
import { isDeepStrictEqual } from "node:util";
import { afterEach, beforeAll } from "vitest";
import { presetForRole } from "@/lib/team-capabilities";
import { createProjectSettingsTools } from "@/lib/agents/tools/project-settings";

export const REPO_ID = "00000000-0000-4000-8000-000000000001";
export const USER_ID = "user-1";

type Row = Record<string, unknown>;
type Filter = { op: "eq" | "is"; column: string; value: unknown };

let supabaseAdmin: typeof import("@/lib/supabase/admin").supabaseAdmin;
let originalFrom: typeof supabaseAdmin.from;

beforeAll(async () => {
  process.env.NEXT_PUBLIC_SUPABASE_URL ??= "https://example.supabase.co";
  process.env.SUPABASE_SERVICE_ROLE_KEY ??= "test-service-role-key";
  ({ supabaseAdmin } = await import("@/lib/supabase/admin"));
  originalFrom = supabaseAdmin.from.bind(supabaseAdmin);
});

afterEach(() => {
  Object.defineProperty(supabaseAdmin, "from", {
    configurable: true,
    writable: true,
    value: originalFrom,
  });
});

const matches = (row: Row, filters: Filter[]) =>
  filters.every(({ op, column, value }) => {
    const actual = row[column] ?? null;
    if (op === "is") return actual === value;
    // jsonb equality ignores key order, so compare parsed maps.
    return column === "sandbox_env_vars" && typeof value === "string"
      ? isDeepStrictEqual(actual, JSON.parse(value))
      : actual === value;
  });

/**
 * One repos row behind the database boundary; records every write.
 * `beforeWrite` runs before each update and may return a database error;
 * `readError`, when set, fails every read with that error.
 */
export function installRepo(
  overrides: Row = {},
  beforeWrite: (row: Row) => unknown = () => null,
  readError: unknown = null
) {
  const row: Row = {
    id: REPO_ID,
    owner_type: "user",
    owner_user_id: USER_ID,
    product_team_id: null,
    runtime: "node22",
    root_directory: null,
    install_command: null,
    dev_command: null,
    dev_port: 3000,
    env_sync_mode: "sandbox-only",
    sandbox_env_vars: { DATABASE_URL: "postgres://owner@db/app" },
    ...overrides,
  };
  const writes: Row[] = [];
  const reads = { count: 0 };
  const query = () => {
    const filters: Filter[] = [];
    let patch: Row | null = null;
    const builder = {
      select: () => builder,
      update: (next: Row) => {
        patch = next;
        return builder;
      },
      eq: (column: string, value: unknown) => {
        filters.push({ op: "eq", column, value });
        return builder;
      },
      is: (column: string, value: unknown) => {
        filters.push({ op: "is", column, value });
        return builder;
      },
      maybeSingle: async () => {
        if (patch) {
          const error = beforeWrite(row);
          if (error) return { data: null, error };
        } else {
          reads.count += 1;
          if (readError) return { data: null, error: readError };
        }
        if (!matches(row, filters)) return { data: null, error: null };
        if (patch) {
          writes.push(patch);
          Object.assign(row, patch);
        }
        return { data: { ...row }, error: null };
      },
    };
    return builder;
  };
  Object.defineProperty(supabaseAdmin, "from", {
    configurable: true,
    writable: true,
    value: query,
  });
  return { row, writes, reads };
}

type ToolRecord = Record<
  string,
  {
    execute: (input: Record<string, unknown>) => Promise<Row>;
    inputSchema: {
      safeParse: (input: unknown) => { success: boolean; data?: Row };
    };
  }
>;

export function tools(
  teamId: string | null = null,
  role: "developer" | "viewer" | "lookup-failed" = "developer"
) {
  return createProjectSettingsTools(
    { userId: USER_ID, repoId: REPO_ID, teamId },
    {
      resolveTeam: async () =>
        role === "lookup-failed"
          ? { ok: false, status: 500, error: "Internal server error" }
          : {
              ok: true,
              teamId: teamId ?? "",
              capabilities: presetForRole(role),
            },
    }
  ) as unknown as ToolRecord;
}