import { createServerFn } from "@tanstack/react-start"; import { z } from "zod"; import { requireViewer, viewerMiddleware } from "./middleware"; import { limitWrite } from "~/server/limits"; import { createAgent, deleteAgent, listAgents, MAX_AGENT_TOKEN_DAYS, mintAgentToken } from "~/server/mcp/agents"; import { TOKEN_AREAS } from "~/server/token-scope"; const areaAccess = z.enum(["read", "write"]).optional(); export const listAgentIdentities = createServerFn({ method: "GET" }) .middleware([viewerMiddleware]) .handler(async ({ context }) => listAgents(requireViewer(context.viewer).id)); export const createAgentIdentity = createServerFn({ method: "POST" }) .middleware([viewerMiddleware]) .validator(z.object({ name: z.string().trim().min(1).max(64), description: z.string().trim().max(500) })) .handler(async ({ data, context }) => { const viewer = requireViewer(context.viewer); await limitWrite(viewer); return createAgent(viewer, data.name, data.description || null); }); export const deleteAgentIdentity = createServerFn({ method: "POST" }) .middleware([viewerMiddleware]) .validator(z.object({ id: z.string() })) .handler(async ({ data, context }) => { const viewer = requireViewer(context.viewer); await limitWrite(viewer); await deleteAgent(viewer, data.id); return { ok: true }; }); export const createAgentToken = createServerFn({ method: "POST" }) .middleware([viewerMiddleware]) .validator( z.object({ id: z.string(), repos: z.array(z.string()).max(50), allRepos: z.boolean(), permissions: z.object(Object.fromEntries(TOKEN_AREAS.map((area) => [area, areaAccess]))), expiresInDays: z.number().int().min(1).max(MAX_AGENT_TOKEN_DAYS), forgeAccess: z.boolean(), }), ) .handler(async ({ data, context }) => { const viewer = requireViewer(context.viewer); await limitWrite(viewer); const minted = await mintAgentToken(viewer, data.id, data); return { token: minted.token }; });