import { z } from "zod/v4"; import type { ColineAppManifestV2Input } from "../manifest/manifest"; import type { AppToolMetadata } from "../manifest/tool"; import type { AnyColineToolDefinitionV2, ColineAppConfigV2, } from "./types"; /** * The extraction step of the two-artifact model (plan §6.1). * * From one definition source, extraction produces the serializable * manifest artifact — names, schemas, effects, permissions, surfaces — * while the executable implementations stay behind in the runtime * artifact. Extraction is deterministic: no IO, no clocks, no randomness; * the platform re-runs it at publish time and rejects on mismatch. */ export function extractToolMetadata(tool: AnyColineToolDefinitionV2): AppToolMetadata { const inputSchema = z.toJSONSchema(tool.input, { unrepresentable: "throw" }); return { name: tool.name, description: tool.description, inputSchema: inputSchema as Record, effect: tool.effect, }; } function isCommandDefinition( command: ColineAppConfigV2["commands"] extends Array | undefined ? T : never, ): command is Extract { return "kind" in command && command.kind === "command"; } export function extractManifestInput(config: ColineAppConfigV2): ColineAppManifestV2Input { const { files, tools, commands, handlers, ...rest } = config; void handlers; return { ...rest, files: (files ?? []).map((fileType) => fileType.metadata), tools: (tools ?? []).map(extractToolMetadata), commands: (commands ?? []).map((command) => isCommandDefinition(command) ? command.command : command, ), }; }