import { defineAction } from "@agent-native/core"; import { getWorkspaceAppIdValidationError, normalizeWorkspaceAppId, } from "@agent-native/core/shared"; import { z } from "zod"; import { startWorkspaceAppCreation } from "../server/lib/app-creation-store.js"; export default defineAction({ description: 'Start creating a new workspace app from Dispatch when the request truly needs its own app. For Claude Web, ChatGPT Web, or either host\'s web Project, this action is the Builder handoff: call it after forming a bounded source brief and do not scaffold or edit files in the host sandbox. This handoff is autonomous once the brief exists: do not ask the user for non-blocking product or UX choices; choose recommended defaults and let Builder record assumptions while it implements. Callers should include a concise generated description by default; Dispatch generates one from the prompt when omitted. In local dev this returns a code-agent prompt; in production it reuses the connected Agent-Native workspace project or, for an organization owner/admin, provisions it through the Builder Projects API before starting the Builder Cloud Agent branch. If no project is configured, organization members must ask an owner/admin to configure it first. The result must be a separate workspace app under apps/, not a new route or file in apps/chat. If chat is used as the source template, the finished app must be branded as the requested app and must not leave visible "Chat", "Starter", "Blank app", or "New app" UI behind. If the request needs Mail, Calendar, Analytics, Brain, Assets, or another first-party app, use the existing hosted/connected app via links or A2A; do not wrap or nest those apps inside the new app unless the user explicitly asks for a customized app from that template.', schema: z.object({ prompt: z.string().min(1).describe("The user's app creation request"), appId: z .string() .max(64) .transform(normalizeWorkspaceAppId) .refine((appId) => !getWorkspaceAppIdValidationError(appId), { message: "Use a non-reserved app id with lowercase letters, numbers, and hyphens.", }) .optional() .nullable() .describe( "Desired workspace app id/path or human-friendly name. Names are converted to lowercase, hyphenated ids.", ), template: z .string() .optional() .nullable() .describe("Template to start from"), description: z .string() .max(500) .optional() .nullable() .describe( "Concise AI-generated description of the app based on the user's prompt. Dispatch saves this while the app is being created.", ), secretIds: z .array(z.string()) .max(100) .optional() .describe("Dispatch vault secret IDs to grant to the app"), resourceIds: z .array(z.string()) .max(100) .optional() .describe( "Dispatch workspace resource IDs or knowledge packs to grant to the app", ), }), run: async (args) => startWorkspaceAppCreation(args), });