@stellisoft/stellify-mcp 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import { AxiosInstance } from 'axios';
1
2
  export interface StellifyConfig {
2
3
  apiUrl: string;
3
4
  apiToken: string;
@@ -5,8 +6,11 @@ export interface StellifyConfig {
5
6
  export interface CreateFileParams {
6
7
  directory?: string;
7
8
  name: string;
8
- type: 'class' | 'model' | 'controller' | 'middleware';
9
+ type: 'class' | 'model' | 'controller' | 'middleware' | 'js';
9
10
  namespace?: string;
11
+ extension?: string;
12
+ code?: string;
13
+ auto_create_dependencies?: boolean;
10
14
  }
11
15
  export interface CreateMethodParams {
12
16
  file: string;
@@ -20,13 +24,13 @@ export interface CreateMethodParams {
20
24
  }>;
21
25
  }
22
26
  export interface AddMethodBodyParams {
23
- file_uuid: string;
24
- method_uuid: string;
27
+ file: string;
28
+ method: string;
25
29
  code: string;
26
30
  }
27
31
  export interface SearchMethodsParams {
28
32
  name?: string;
29
- file_uuid?: string;
33
+ file?: string;
30
34
  }
31
35
  export interface SearchFilesParams {
32
36
  query: string;
@@ -42,14 +46,106 @@ export interface SearchFilesParams {
42
46
  sort?: 'created_at' | 'name' | 'type' | 'ai_rating' | 'usage_rating' | 'system_rating' | 'user_name';
43
47
  direction?: 'asc' | 'desc';
44
48
  }
49
+ export interface CreateRouteParams {
50
+ project_id: string;
51
+ name: string;
52
+ path: string;
53
+ method: string;
54
+ type?: string;
55
+ data?: any;
56
+ }
57
+ export interface CreateElementParams {
58
+ type: string;
59
+ page?: string;
60
+ parent?: string;
61
+ }
45
62
  export declare class StellifyClient {
46
- private client;
63
+ client: AxiosInstance;
47
64
  constructor(config: StellifyConfig);
48
65
  createFile(params: CreateFileParams): Promise<any>;
49
66
  createMethod(params: CreateMethodParams): Promise<any>;
50
67
  addMethodBody(params: AddMethodBodyParams): Promise<any>;
68
+ addStatementCode(params: {
69
+ file: string;
70
+ statement: string;
71
+ code: string;
72
+ }): Promise<any>;
51
73
  searchMethods(params: SearchMethodsParams): Promise<any>;
52
74
  searchFiles(params: SearchFilesParams): Promise<any>;
53
- getFile(uuid: string): Promise<any>;
54
- getMethod(uuid: string): Promise<any>;
75
+ getFile(file: string): Promise<any>;
76
+ saveFile(file: string, data: any): Promise<any>;
77
+ getMethod(method: string): Promise<any>;
78
+ saveMethod(method: string, data: any): Promise<any>;
79
+ createStatement(params: {
80
+ file?: string;
81
+ method?: string;
82
+ }): Promise<any>;
83
+ getStatement(statement: string): Promise<any>;
84
+ saveStatement(statement: string, data: any): Promise<any>;
85
+ createRoute(params: CreateRouteParams): Promise<any>;
86
+ getRoute(route: string): Promise<any>;
87
+ searchRoutes(params: {
88
+ search?: string;
89
+ type?: string;
90
+ }): Promise<any>;
91
+ createElement(params: CreateElementParams): Promise<any>;
92
+ updateElement(element: string, data: any): Promise<any>;
93
+ getElement(element: string): Promise<any>;
94
+ getElementTree(element: string): Promise<any>;
95
+ deleteElement(route: string, current?: string, element?: string): Promise<any>;
96
+ searchElements(params: {
97
+ search?: string;
98
+ type?: string;
99
+ include_metadata?: boolean;
100
+ per_page?: number;
101
+ }): Promise<any>;
102
+ htmlToElements(params: {
103
+ elements: string;
104
+ page?: string;
105
+ selection?: string;
106
+ test?: boolean;
107
+ }): Promise<any>;
108
+ listGlobals(): Promise<any>;
109
+ getGlobal(uuid: string): Promise<any>;
110
+ installGlobal(params: {
111
+ file_uuid: string;
112
+ directory_uuid: string;
113
+ }): Promise<any>;
114
+ searchGlobalMethods(params: {
115
+ query: string;
116
+ }): Promise<any>;
117
+ listModules(): Promise<any>;
118
+ getModule(module: string): Promise<any>;
119
+ createModule(params: {
120
+ name: string;
121
+ description?: string;
122
+ version?: string;
123
+ tags?: string[];
124
+ }): Promise<any>;
125
+ addFileToModule(params: {
126
+ module: string;
127
+ file: string;
128
+ order?: number;
129
+ }): Promise<any>;
130
+ removeFileFromModule(module: string, file: string): Promise<any>;
131
+ installModule(params: {
132
+ module: string;
133
+ directory: string;
134
+ }): Promise<any>;
135
+ deleteModule(uuid: string): Promise<any>;
136
+ getDirectory(uuid: string): Promise<any>;
137
+ createDirectory(params: {
138
+ name: string;
139
+ }): Promise<any>;
140
+ saveDirectory(uuid: string, data: any): Promise<any>;
141
+ getProject(): Promise<any>;
142
+ broadcastElementCommand(params: {
143
+ action: 'update' | 'batch' | 'delete' | 'create';
144
+ element?: string;
145
+ changes?: Record<string, any>;
146
+ updates?: Array<{
147
+ element: string;
148
+ changes: Record<string, any>;
149
+ }>;
150
+ }): Promise<any>;
55
151
  }
@@ -23,6 +23,10 @@ export class StellifyClient {
23
23
  const response = await this.client.post('/code', params);
24
24
  return response.data;
25
25
  }
26
+ async addStatementCode(params) {
27
+ const response = await this.client.post('/code', params);
28
+ return response.data;
29
+ }
26
30
  async searchMethods(params) {
27
31
  const response = await this.client.get('/method/search', { params });
28
32
  return response.data;
@@ -31,12 +35,143 @@ export class StellifyClient {
31
35
  const response = await this.client.get('/file/search', { params });
32
36
  return response.data;
33
37
  }
34
- async getFile(uuid) {
35
- const response = await this.client.get(`/file/${uuid}`);
38
+ async getFile(file) {
39
+ const response = await this.client.get(`/file/${file}`);
40
+ return response.data;
41
+ }
42
+ async saveFile(file, data) {
43
+ const response = await this.client.put(`/file/${file}`, data);
44
+ return response.data;
45
+ }
46
+ async getMethod(method) {
47
+ const response = await this.client.get(`/method/${method}`);
48
+ return response.data;
49
+ }
50
+ async saveMethod(method, data) {
51
+ const response = await this.client.put(`/method/${method}`, data);
52
+ return response.data;
53
+ }
54
+ async createStatement(params) {
55
+ const response = await this.client.post('/statement', params);
56
+ return response.data;
57
+ }
58
+ async getStatement(statement) {
59
+ const response = await this.client.get(`/statement/${statement}`);
60
+ return response.data;
61
+ }
62
+ async saveStatement(statement, data) {
63
+ const response = await this.client.put(`/statement/${statement}`, data);
64
+ return response.data;
65
+ }
66
+ async createRoute(params) {
67
+ const response = await this.client.post('/route', params);
68
+ return response.data;
69
+ }
70
+ async getRoute(route) {
71
+ const response = await this.client.get(`/route/${route}`);
72
+ return response.data;
73
+ }
74
+ async searchRoutes(params) {
75
+ const response = await this.client.get('/route/search', { params });
76
+ return response.data;
77
+ }
78
+ async createElement(params) {
79
+ const response = await this.client.post('/element', params);
80
+ return response.data;
81
+ }
82
+ async updateElement(element, data) {
83
+ const response = await this.client.put(`/element/${element}`, data);
84
+ return response.data;
85
+ }
86
+ async getElement(element) {
87
+ const response = await this.client.get(`/element/${element}`);
88
+ return response.data;
89
+ }
90
+ async getElementTree(element) {
91
+ const response = await this.client.get(`/element/${element}/tree`);
92
+ return response.data;
93
+ }
94
+ async deleteElement(route, current, element) {
95
+ const routeParam = route || 'null';
96
+ const currentParam = current || 'null';
97
+ const response = await this.client.delete(`/element/${routeParam}/${currentParam}/${element}`);
98
+ return response.data;
99
+ }
100
+ async searchElements(params) {
101
+ const response = await this.client.get('/element/search', { params });
102
+ return response.data;
103
+ }
104
+ async htmlToElements(params) {
105
+ const response = await this.client.post('/html/elements', params);
106
+ return response.data;
107
+ }
108
+ // Global methods (Application DB)
109
+ async listGlobals() {
110
+ const response = await this.client.get('/globals/');
111
+ return response.data;
112
+ }
113
+ async getGlobal(uuid) {
114
+ const response = await this.client.get(`/globals/file/${uuid}`);
115
+ return response.data;
116
+ }
117
+ async installGlobal(params) {
118
+ const response = await this.client.post('/globals/install', params);
119
+ return response.data;
120
+ }
121
+ async searchGlobalMethods(params) {
122
+ const response = await this.client.post('/method/search-global', params);
123
+ return response.data;
124
+ }
125
+ // Module methods (groups of globals)
126
+ async listModules() {
127
+ const response = await this.client.get('/modules/');
128
+ return response.data;
129
+ }
130
+ async getModule(module) {
131
+ const response = await this.client.get(`/modules/${module}`);
132
+ return response.data;
133
+ }
134
+ async createModule(params) {
135
+ const response = await this.client.post('/modules/', params);
136
+ return response.data;
137
+ }
138
+ async addFileToModule(params) {
139
+ const response = await this.client.post('/modules/add-file', params);
140
+ return response.data;
141
+ }
142
+ async removeFileFromModule(module, file) {
143
+ const response = await this.client.delete(`/modules/${module}/file/${file}`);
144
+ return response.data;
145
+ }
146
+ async installModule(params) {
147
+ const response = await this.client.post('/modules/install', params);
148
+ return response.data;
149
+ }
150
+ async deleteModule(uuid) {
151
+ const response = await this.client.delete(`/modules/${module}`);
152
+ return response.data;
153
+ }
154
+ // Directory methods
155
+ async getDirectory(uuid) {
156
+ const response = await this.client.get(`/directory/${uuid}`);
157
+ return response.data;
158
+ }
159
+ async createDirectory(params) {
160
+ const response = await this.client.post('/directory', params);
161
+ return response.data;
162
+ }
163
+ async saveDirectory(uuid, data) {
164
+ const response = await this.client.put(`/directory/${uuid}`, { uuid, data });
165
+ return response.data;
166
+ }
167
+ // Project methods
168
+ async getProject() {
169
+ const response = await this.client.get('/getProject');
36
170
  return response.data;
37
171
  }
38
- async getMethod(uuid) {
39
- const response = await this.client.get(`/method/${uuid}`);
172
+ // Element command broadcast (real-time UI updates via WebSocket)
173
+ async broadcastElementCommand(params) {
174
+ const response = await this.client.post('/elements/command', params);
40
175
  return response.data;
41
176
  }
42
177
  }
package/manifest.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "manifest_version": "0.3",
3
+ "name": "stellify-mcp",
4
+ "display_name": "Stellify MCP",
5
+ "version": "0.1.2",
6
+ "description": "Build Laravel and Vue.js apps through conversation with AI-native structured code editing",
7
+ "long_description": "Stellify MCP bridges Claude with Stellify - an AI-native code generation platform. Unlike traditional file-based code, Stellify stores code as structured JSON in a database, enabling:\n\n- **Surgical, statement-level edits** - AI can modify specific code statements without risk of breaking surrounding code\n- **Queryable code** - Find all methods using a specific class, trace dependencies instantly\n- **34 specialized tools** for project management, file/method creation, Vue component building, UI elements, and a reusable code library\n- **Incremental development workflow** - Build applications step-by-step with full type safety\n\nSupports Laravel/PHP (controllers, models, middleware) and Vue.js (reactive components, event handlers, templates).",
8
+ "author": {
9
+ "name": "Stellisoft",
10
+ "email": "stellifysoftware@gmail.com",
11
+ "url": "https://stellisoft.com"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/Stellify-Software-Ltd/stellify-mcp.git"
16
+ },
17
+ "homepage": "https://stellisoft.com",
18
+ "documentation": "https://github.com/Stellify-Software-Ltd/stellify-mcp#readme",
19
+ "support": "https://github.com/Stellify-Software-Ltd/stellify-mcp/issues",
20
+ "keywords": ["laravel", "vue", "php", "code-generation", "ai-native", "structured-code"],
21
+ "license": "MIT",
22
+ "server": {
23
+ "type": "node",
24
+ "entry_point": "dist/index.js",
25
+ "mcp_config": {
26
+ "command": "node",
27
+ "args": ["${__dirname}/dist/index.js"],
28
+ "env": {
29
+ "STELLIFY_API_URL": "${user_config.api_url}",
30
+ "STELLIFY_API_TOKEN": "${user_config.api_token}"
31
+ }
32
+ }
33
+ },
34
+ "tools": [
35
+ {"name": "get_project", "description": "Get the active project and directory structure"},
36
+ {"name": "create_file", "description": "Create a new file (class, model, controller, middleware, or Vue.js)"},
37
+ {"name": "get_file", "description": "Retrieve a file with all methods and statements"},
38
+ {"name": "save_file", "description": "Finalize file configuration"},
39
+ {"name": "get_directory", "description": "List directory contents"},
40
+ {"name": "create_directory", "description": "Create a new directory"},
41
+ {"name": "search_files", "description": "Find files by name or type"},
42
+ {"name": "create_method", "description": "Create method signatures with type hints"},
43
+ {"name": "add_method_body", "description": "Add implementation code to methods"},
44
+ {"name": "search_methods", "description": "Find methods by name or file"},
45
+ {"name": "create_statement", "description": "Create statements (non-method code)"},
46
+ {"name": "add_statement_code", "description": "Add code to statements"},
47
+ {"name": "get_statement", "description": "Retrieve statement with clauses"},
48
+ {"name": "create_route", "description": "Create new routes (web pages or API endpoints)"},
49
+ {"name": "get_route", "description": "Retrieve route details"},
50
+ {"name": "search_routes", "description": "Search for existing routes"},
51
+ {"name": "create_element", "description": "Create UI elements on pages"},
52
+ {"name": "update_element", "description": "Update elements with attributes and event handlers"},
53
+ {"name": "get_element", "description": "Retrieve a single element"},
54
+ {"name": "get_element_tree", "description": "Get element with full hierarchical structure"},
55
+ {"name": "delete_element", "description": "Delete element and children"},
56
+ {"name": "search_elements", "description": "Search elements by name, type, or content"},
57
+ {"name": "html_to_elements", "description": "Convert HTML to Stellify elements in one operation"},
58
+ {"name": "list_globals", "description": "List reusable code in application database"},
59
+ {"name": "get_global", "description": "Get full global file structure"},
60
+ {"name": "install_global", "description": "Install global file into project"},
61
+ {"name": "search_global_methods", "description": "Search framework/global methods"},
62
+ {"name": "list_modules", "description": "List available module packages"},
63
+ {"name": "get_module", "description": "Get module with all files"},
64
+ {"name": "create_module", "description": "Create new module for grouping globals"},
65
+ {"name": "add_file_to_module", "description": "Add file to module"},
66
+ {"name": "install_module", "description": "Install entire module into project"}
67
+ ],
68
+ "tools_generated": false,
69
+ "compatibility": {
70
+ "claude_desktop": ">=1.0.0",
71
+ "platforms": ["darwin", "win32", "linux"],
72
+ "runtimes": {
73
+ "node": ">=18.0.0"
74
+ }
75
+ },
76
+ "user_config": {
77
+ "api_token": {
78
+ "type": "string",
79
+ "title": "Stellify API Token",
80
+ "description": "Your Stellify API token (get from stellisoft.com/settings/tokens)",
81
+ "sensitive": true,
82
+ "required": true
83
+ },
84
+ "api_url": {
85
+ "type": "string",
86
+ "title": "Stellify API URL",
87
+ "description": "Stellify API endpoint URL",
88
+ "required": false,
89
+ "default": "https://stellisoft.com/api/v1"
90
+ }
91
+ }
92
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stellisoft/stellify-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "mcpName": "io.github.MattStellisoft/stellify-mcp",
5
5
  "description": "MCP server for Stellify - AI-native code generation platform",
6
6
  "main": "dist/index.js",
Binary file
@@ -0,0 +1,96 @@
1
+ import { StellifyClient } from './dist/stellify-client.js';
2
+ import dotenv from 'dotenv';
3
+
4
+ dotenv.config();
5
+
6
+ const client = new StellifyClient({
7
+ apiUrl: process.env.STELLIFY_API_URL,
8
+ apiToken: process.env.STELLIFY_API_TOKEN,
9
+ });
10
+
11
+ const PROJECT_ID = 'b11ba1ac-ad5e-45c7-8285-57f0b7aa0196';
12
+
13
+ async function testElements() {
14
+ console.log('Testing Stellify Element Creation with UUID...\n');
15
+
16
+ try {
17
+ // Test 1: Create a test route first
18
+ console.log('1. Creating test route...');
19
+ const timestamp = Date.now();
20
+ const route = await client.createRoute({
21
+ project_id: PROJECT_ID,
22
+ name: `Test Page ${timestamp}`,
23
+ path: `/test-elements-${timestamp}`,
24
+ method: 'GET',
25
+ type: 'web',
26
+ });
27
+ console.log('✅ Route created:', route.data.uuid);
28
+ console.log('');
29
+
30
+ // Test 2: Create an element on that route
31
+ console.log('2. Creating element (s-wrapper)...');
32
+ const element = await client.createElement({
33
+ page: route.data.uuid,
34
+ type: 's-wrapper',
35
+ });
36
+ console.log('✅ Element created:', JSON.stringify(element, null, 2));
37
+ console.log('');
38
+
39
+ // Test 3: Verify UUID is in the element data
40
+ console.log('3. Verifying UUID in element data...');
41
+ if (element.data && element.data.uuid) {
42
+ console.log('✅ UUID found at root level:', element.data.uuid);
43
+ console.log(' Matches element UUID:', element.uuid === element.data.uuid ? '✅ YES' : '❌ NO');
44
+ } else {
45
+ console.log('❌ UUID NOT found in element.data');
46
+ console.log(' Element data structure:', JSON.stringify(element.data, null, 2));
47
+ }
48
+ console.log('');
49
+
50
+ // Test 3b: Verify route's data array contains the element UUID
51
+ console.log('3b. Verifying route contains element UUID...');
52
+ const routeCheck = await client.client.get(`/route/${route.data.uuid}`);
53
+ const routeData = routeCheck.data.data;
54
+ if (routeData.data && Array.isArray(routeData.data) && routeData.data.includes(element.data.uuid)) {
55
+ console.log('✅ Route data array contains element UUID');
56
+ console.log(' Route data array:', routeData.data);
57
+ } else {
58
+ console.log('❌ Route data array does NOT contain element UUID');
59
+ console.log(' Route data:', JSON.stringify(routeData, null, 2));
60
+ }
61
+ console.log('');
62
+
63
+ // Test 4: Create a child element
64
+ console.log('4. Creating child element (s-input)...');
65
+ const childElement = await client.createElement({
66
+ type: 's-input',
67
+ parent: element.data.uuid,
68
+ });
69
+ console.log('✅ Child element created:', childElement.data.uuid);
70
+
71
+ // Verify child UUID
72
+ if (childElement.data && childElement.data.uuid) {
73
+ console.log('✅ UUID found in child element.data:', childElement.data.uuid);
74
+ console.log(' Has parent reference:', childElement.data.parent ? '✅ YES (' + childElement.data.parent + ')' : '❌ NO');
75
+ } else {
76
+ console.log('❌ UUID NOT found in child element.data');
77
+ }
78
+ console.log('');
79
+
80
+ console.log('🎉 Element creation test complete!');
81
+ console.log('\nCreated Resources:');
82
+ console.log(` Route: ${route.data.uuid} (${route.data.path})`);
83
+ console.log(` Parent Element: ${element.data.uuid}`);
84
+ console.log(` Child Element: ${childElement.data.uuid}`);
85
+
86
+ } catch (error) {
87
+ console.error('❌ Test failed:', error.message);
88
+ if (error.response) {
89
+ console.error('Response data:', JSON.stringify(error.response.data, null, 2));
90
+ console.error('Response status:', error.response.status);
91
+ }
92
+ process.exit(1);
93
+ }
94
+ }
95
+
96
+ testElements();
@@ -0,0 +1,118 @@
1
+ import { StellifyClient } from './dist/stellify-client.js';
2
+ import dotenv from 'dotenv';
3
+
4
+ dotenv.config();
5
+
6
+ const client = new StellifyClient({
7
+ apiUrl: process.env.STELLIFY_API_URL,
8
+ apiToken: process.env.STELLIFY_API_TOKEN,
9
+ });
10
+
11
+ const PROJECT_ID = 'b11ba1ac-ad5e-45c7-8285-57f0b7aa0196';
12
+
13
+ async function testFullWorkflow() {
14
+ console.log('Testing Full Element Workflow: Create → Update with Attributes\n');
15
+
16
+ try {
17
+ // Step 1: Create route
18
+ console.log('1. Creating test route...');
19
+ const timestamp = Date.now();
20
+ const route = await client.createRoute({
21
+ project_id: PROJECT_ID,
22
+ name: `Contact Form ${timestamp}`,
23
+ path: `/contact-${timestamp}`,
24
+ method: 'GET',
25
+ type: 'web',
26
+ });
27
+ console.log('✅ Route created:', route.data.uuid);
28
+ console.log('');
29
+
30
+ // Step 2: Create form wrapper
31
+ console.log('2. Creating form wrapper (s-form)...');
32
+ const form = await client.createElement({
33
+ page: route.data.uuid,
34
+ type: 's-form',
35
+ });
36
+ console.log('✅ Form created:', form.data.uuid);
37
+ console.log('');
38
+
39
+ // Step 3: Update form with attributes
40
+ console.log('3. Updating form with HTML attributes...');
41
+ const updatedForm = await client.updateElement(form.data.uuid, {
42
+ name: 'Contact Form',
43
+ tag: 'form',
44
+ method: 'POST',
45
+ action: '/api/contact',
46
+ classes: ['space-y-4', 'max-w-md', 'mx-auto'],
47
+ });
48
+ console.log('✅ Form updated with attributes');
49
+ console.log(' Form data:', JSON.stringify(updatedForm.data, null, 2));
50
+ console.log('');
51
+
52
+ // Step 4: Create email input
53
+ console.log('4. Creating email input (s-input)...');
54
+ const emailInput = await client.createElement({
55
+ parent: form.data.uuid,
56
+ type: 's-input',
57
+ });
58
+ console.log('✅ Email input created:', emailInput.data.uuid);
59
+ console.log('');
60
+
61
+ // Step 5: Update email input with full attributes
62
+ console.log('5. Configuring email input with HTML attributes...');
63
+ const updatedEmail = await client.updateElement(emailInput.data.uuid, {
64
+ name: 'Email Field',
65
+ tag: 'input',
66
+ type: 'email',
67
+ placeholder: 'Enter your email',
68
+ required: true,
69
+ classes: ['form-input', 'w-full', 'px-4', 'py-2', 'border', 'rounded'],
70
+ });
71
+ console.log('✅ Email input configured');
72
+ console.log(' Input data:', JSON.stringify(updatedEmail.data, null, 2));
73
+ console.log('');
74
+
75
+ // Step 6: Create submit button
76
+ console.log('6. Creating submit button (s-wrapper)...');
77
+ const button = await client.createElement({
78
+ parent: form.data.uuid,
79
+ type: 's-wrapper',
80
+ });
81
+ console.log('✅ Button created:', button.data.uuid);
82
+ console.log('');
83
+
84
+ // Step 7: Update button with attributes
85
+ console.log('7. Configuring button with HTML attributes...');
86
+ const updatedButton = await client.updateElement(button.data.uuid, {
87
+ name: 'Submit Button',
88
+ tag: 'button',
89
+ type: 'submit',
90
+ text: 'Send Message',
91
+ classes: ['bg-blue-500', 'text-white', 'px-6', 'py-2', 'rounded', 'hover:bg-blue-600'],
92
+ });
93
+ console.log('✅ Button configured');
94
+ console.log(' Button data:', JSON.stringify(updatedButton.data, null, 2));
95
+ console.log('');
96
+
97
+ console.log('🎉 Full workflow test complete!');
98
+ console.log('\n📋 Summary:');
99
+ console.log(` Route: ${route.data.uuid} (${route.data.path})`);
100
+ console.log(` Form: ${form.data.uuid}`);
101
+ console.log(` Email Input: ${emailInput.data.uuid}`);
102
+ console.log(` Submit Button: ${button.data.uuid}`);
103
+ console.log('\n✨ Successfully built a complete contact form with:');
104
+ console.log(' - Form wrapper with POST action');
105
+ console.log(' - Email input with validation');
106
+ console.log(' - Submit button with styling');
107
+
108
+ } catch (error) {
109
+ console.error('❌ Test failed:', error.message);
110
+ if (error.response) {
111
+ console.error('Response data:', JSON.stringify(error.response.data, null, 2));
112
+ console.error('Response status:', error.response.status);
113
+ }
114
+ process.exit(1);
115
+ }
116
+ }
117
+
118
+ testFullWorkflow();