Fix twenty cli (#15997)

As title

fixes "app add" and "app init" commands
adds tests
This commit is contained in:
martmull
2025-11-21 19:21:30 +01:00
committed by GitHub
parent 3b5949ec3c
commit aa5d30a911
22 changed files with 201 additions and 696 deletions
@@ -6,5 +6,3 @@ export const BASE_APPLICATION_PROJECT_PATH = join(
BASE_PATH,
'base-application-project',
);
export const BASE_SCHEMAS_PATH = join(BASE_PATH, 'schemas');
@@ -1,8 +0,0 @@
const SCHEMA_BASE_URL =
'https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas';
export const APP_MANIFEST_SCHEMA_URL = `${SCHEMA_BASE_URL}/appManifest.schema.json`;
export const AGENT_SCHEMA_URL = `${SCHEMA_BASE_URL}/agent.schema.json`;
export const OBJECT_SCHEMA_URL = `${SCHEMA_BASE_URL}/object.schema.json`;
export const TRIGGER_SCHEMA_URL = `${SCHEMA_BASE_URL}/trigger.schema.json`;
export const SERVERLESS_FUNCTION_SCHEMA_URL = `${SCHEMA_BASE_URL}/serverlessFunction.schema.json`;
@@ -1,109 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/agent.schema.json",
"title": "Twenty Agent Manifest",
"description": "Schema for Twenty AI agent configuration files",
"type": "object",
"required": ["standardId", "universalIdentifier", "name", "label", "prompt", "modelId"],
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema reference for validation and IDE support"
},
"universalIdentifier": {
"type": "string",
"description": "Unique identifier (UUID format recommended)",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"standardId": {
"const": { "$data": "1/universalIdentifier" },
"description": "Should be the same as universalIdentifier"
},
"name": {
"type": "string",
"description": "Internal name for the agent (camelCase, used in code)",
"pattern": "^[a-zA-Z][a-zA-Z0-9]*$",
"minLength": 1,
"maxLength": 100
},
"label": {
"type": "string",
"description": "Human-readable display name for the agent",
"minLength": 1,
"maxLength": 200
},
"description": {
"type": "string",
"description": "Brief description of what the agent does",
"maxLength": 500
},
"icon": {
"type": "string",
"description": "Icon for the agent (emoji or icon name)",
"maxLength": 50
},
"prompt": {
"type": "string",
"description": "System prompt that defines the agent's behavior and personality",
"minLength": 10,
"maxLength": 10000
},
"modelId": {
"type": "string",
"description": "AI model to use for this agent",
"default": "auto",
"enum": [
"auto",
"gpt-4o",
"gpt-4o-mini",
"gpt-4-turbo",
"claude-opus-4-20250514",
"claude-sonnet-4-20250514",
"claude-3-5-haiku-20241022",
"grok-3",
"grok-3-mini",
"grok-4"
]
},
"responseFormat": {
"type": "object",
"description": "Format specification for agent responses",
"required": ["type"],
"properties": {
"type": {
"type": "string",
"description": "Response format type",
"enum": ["text", "json"]
},
"schema": {
"type": "object",
"description": "JSON schema for structured responses (required when type is 'json')",
"additionalProperties": true
}
},
"if": {
"properties": {
"type": { "const": "json" }
}
},
"then": {
"required": ["schema"]
}
}
},
"additionalProperties": false,
"examples": [
{
"standardId": "550e8400-e29b-41d4-a716-446655440001",
"name": "customerSupportAgent",
"label": "Customer Support Assistant",
"description": "Helps customers with their inquiries and issues",
"icon": "🎧",
"prompt": "You are a helpful customer support agent. Always be polite, professional, and solution-oriented.",
"modelId": "auto",
"responseFormat": {
"type": "text"
}
}
]
}
@@ -1,129 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/appManifest.schema.json",
"title": "Twenty App Manifest",
"description": "Schema for Twenty application manifest files",
"type": "object",
"required": ["universalIdentifier", "name", "version", "license", "engines", "packageManager"],
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema reference for validation and IDE support"
},
"universalIdentifier": {
"type": "string",
"description": "Unique identifier (UUID format recommended)",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"name": {
"type": "string",
"description": "Human-readable display name for the application",
"minLength": 1,
"maxLength": 200
},
"description": {
"type": "string",
"description": "Brief description of what the application does",
"maxLength": 1000
},
"icon": {
"type": "string",
"description": "Icon for the application (emoji or icon name)",
"maxLength": 50
},
"license": {
"const": "MIT",
"title": "The application's license",
"description": "Currently only MIT is accepted, although more licenses will probably be available in the future."
},
"env": {
"type": "object",
"title": "Environment Variables",
"description": "Key-value pairs defining environment variables available to all serverless functions.",
"patternProperties": {
"^[A-Z_][A-Z0-9_]*$": {
"type": "object",
"title": "Environment Variable Definition",
"properties": {
"universalIdentifier": {
"type": "string",
"description": "Unique identifier (UUID format recommended)",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"description": {
"type": "string",
"description": "Description for this environment variable."
},
"value": {
"type": "string",
"description": "Default value for this environment variable"
},
"isSecret": {
"type": "boolean",
"description": "If true, the value will be treated as sensitive and hidden from logs or UI."
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"engines": {
"type": "object",
"title": "The application's engines",
"description": "Define engines here"
},
"packageManager": {
"const": "yarn@4.9.2",
"title": "Package manager of the application"
},
"version": {
"type": "string",
"description": "Semantic version of the application",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9-]+)?$"
},
"dependencies": {
"type": "object",
"title": "The extension's source dependencies",
"description": "Source dependencies following the npm package.json dependency format."
},
"devDependencies": {
"type": "object",
"title": "The extension's source devDependencies",
"description": "Dev dependencies following the npm package.json dependency format."
},
"agents": {
"type": "array",
"description": "Optional inline agent definitions (agents are typically discovered from the agents/ folder)",
"items": {
"type": "object",
"description": "Inline agent definition",
"$ref": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/agent.schema.json"
}
},
"objects": {
"type": "array",
"description": "Optional inline object definitions (objects are typically discovered from the objects/ folder)",
"items": {
"type": "object",
"description": "Inline object definition",
"$ref": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/object.schema.json"
}
}
},
"examples": [
{
"standardId": "550e8400-e29b-41d4-a716-446655440000",
"name": "Customer Support App",
"description": "Comprehensive customer support application with AI agents",
"icon": "🎧",
"version": "1.0.0",
"license": "MIT",
"engines": {
"node": "^24.5.0",
"npm": "please-use-yarn",
"yarn": ">=4.9.2"
}
}
]
}
@@ -1,78 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/object.schema.json",
"title": "Twenty Object Manifest",
"description": "Schema for Twenty AI object configuration files",
"type": "object",
"required": [
"standardId",
"universalIdentifier",
"nameSingular",
"namePlural",
"labelSingular",
"labelPlural"
],
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema reference for validation and IDE support"
},
"universalIdentifier": {
"type": "string",
"description": "Unique identifier (UUID format recommended)",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"standardId": {
"const": { "$data": "1/universalIdentifier" },
"description": "Should be the same as universalIdentifier"
},
"nameSingular": {
"type": "string",
"description": "Name singular for the object",
"pattern": "^[a-zA-Z][a-zA-Z0-9]*$",
"minLength": 1,
"maxLength": 100
},
"namePlural": {
"type": "string",
"description": "Name plural for the object",
"pattern": "^[a-zA-Z][a-zA-Z0-9]*$",
"minLength": 1,
"maxLength": 100
},
"labelSingular": {
"type": "string",
"description": "Human-readable display name singular for the object",
"minLength": 1,
"maxLength": 200
},
"labelPlural": {
"type": "string",
"description": "Human-readable display name singular for the object",
"minLength": 1,
"maxLength": 200
},
"description": {
"type": "string",
"description": "Brief description of the object",
"maxLength": 500
},
"icon": {
"type": "string",
"description": "Icon for the object (emoji or icon name)",
"maxLength": 50
}
},
"additionalProperties": false,
"examples": [
{
"standardId": "550e8400-e29b-41d4-a716-446655440001",
"nameSingular": "object",
"namePlural": "objects",
"labelSingular": "Object",
"labelPlural": "Objects",
"description": "Object description",
"icon": "🎧"
}
]
}
@@ -1,107 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/serverlessFunction.schema.json",
"title": "Twenty Serverless Function Manifest",
"description": "Schema for Twenty AI serverless function configuration files",
"type": "object",
"required": ["universalIdentifier"],
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema reference for validation and IDE support"
},
"universalIdentifier": {
"type": "string",
"description": "Unique identifier (UUID format recommended)",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"name": {
"type": "string",
"description": "Name singular for the serverless function (eg: my-serverless-function)",
"pattern": "^[a-z0-9-]+$",
"minLength": 1,
"maxLength": 100
},
"description": {
"type": "string",
"description": "Brief description of the serverless function",
"maxLength": 500
},
"timeoutSeconds": {
"type": "number",
"description": "Serverless function timeout in seconds, between 1 and 900",
"min": 1,
"max": 900
},
"triggers": {
"type": "array",
"description": "Serverless function's triggers",
"items": {
"anyOf": [
{ "$ref": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/trigger.schema.json" },
{
"type": "object",
"required": ["$ref"],
"properties": { "$ref": { "type": "string" } },
"additionalProperties": false
}
]
}
},
"code": {
"type": "object",
"description": "Serverless function's code",
"required": ["src"],
"properties": {
"src": {
"type": "object",
"description":"Serverless function source folder",
"required": ["index.ts"],
"properties": {
"index.ts": {
"type": "string",
"description":"Serverless function index.ts file"
},
"additionalProperties": true
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"examples": [
{
"standardId": "550e8400-e29b-41d4-a716-446655440001",
"universalIdentifier": "550e8400-e29b-41d4-a716-446655440001",
"name": "My serverless function",
"triggers": [
{
"standardId": "550e8400-e29b-41d4-a716-446655440002",
"universalIdentifier": "550e8400-e29b-41d4-a716-446655440002",
"type": "cron",
"schedule": "0 9 * * *"
},
{
"standardId": "550e8400-e29b-41d4-a716-446655440003",
"universalIdentifier": "550e8400-e29b-41d4-a716-446655440003",
"type": "databaseEvent",
"eventName": "company.created"
},
{
"standardId": "550e8400-e29b-41d4-a716-446655440004",
"universalIdentifier": "550e8400-e29b-41d4-a716-446655440004",
"type": "route",
"path": "test-route",
"httpMethod": "GET",
"isAuthRequired": false
}
],
"code": {
"src": {
"index.ts": "{\n \"code\": \"import axios from 'axios';\\n\\nexport const main = async (params) => {\\n const { a, b } = params;\\n const message = \\\"toto\\\";\\n return { message };\\n};\",\n \"params\": { \"a\": \"1\", \"b\": 2 }\n}\n"
}
}
}
]
}
@@ -1,43 +0,0 @@
{
"$id": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/src/constants/schemas/trigger.schema.json",
"type": "object",
"required": ["universalIdentifier", "type"],
"properties": {
"$schema": {
"type": "string",
"description": "JSON Schema reference for validation and IDE support"
},
"universalIdentifier": {
"type": "string",
"description": "Unique identifier (UUID format recommended)",
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
},
"type": { "enum": ["cron", "databaseEvent", "route"] },
"pattern": { "type": "string" },
"eventName": { "type": "string" },
"path": { "type": "string" },
"httpMethod": { "enum": ["GET", "POST", "PUT", "PATCH", "DELETE"] },
"isAuthRequired": { "type": "boolean" }
},
"allOf": [
{
"if": { "properties": { "type": { "const": "cron" } } },
"then": { "required": ["pattern"] }
},
{
"if": { "properties": { "type": { "const": "databaseEvent" } } },
"then": { "required": ["eventName"] }
},
{
"if": { "properties": { "type": { "const": "route" } } },
"then": { "required": ["path", "httpMethod", "isAuthRequired"] }
}
]
}