@stellisoft/stellify-mcp 0.1.26 → 0.1.28
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.
- package/dist/index.js +257 -158
- package/dist/stellify-client.d.ts +5 -0
- package/dist/stellify-client.js +18 -0
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ const STELLIFY_FRAMEWORK_API = {
|
|
|
26
26
|
List: ['create', 'from', 'range', 'add', 'remove', 'removeWhere', 'set', 'get', 'first', 'last', 'sort', 'sortBy', 'reverse', 'filter', 'find', 'findIndex', 'map', 'reduce', 'forEach', 'includes', 'indexOf', 'every', 'some', 'slice', 'take', 'skip', 'chunk', 'unique', 'uniqueBy', 'groupBy', 'flatten', 'concat', 'isEmpty', 'isNotEmpty', 'count', 'clear', 'toArray', 'toJSON', 'clone', 'sum', 'avg', 'min', 'max'],
|
|
27
27
|
Tree: ['create', 'setRoot', 'addChild', 'removeNode', 'getNode', 'getRoot', 'getChildren', 'getParent', 'getSiblings', 'getAncestors', 'getDescendants', 'getDepth', 'getPath', 'traverse', 'find', 'findAll', 'move', 'toArray', 'size'],
|
|
28
28
|
// Network
|
|
29
|
-
Http: ['create', 'get', 'post', 'put', 'patch', 'delete', 'withHeaders', 'withToken', 'withTimeout'],
|
|
29
|
+
Http: ['create', 'get', 'post', 'put', 'patch', 'delete', 'items', 'withHeaders', 'withToken', 'withTimeout'],
|
|
30
30
|
Socket: ['create', 'connect', 'disconnect', 'send', 'sendEvent', 'on', 'off', 'once', 'isConnected', 'getState'],
|
|
31
31
|
Auth: ['create', 'login', 'logout', 'fetchUser', 'getUser', 'getToken', 'isAuthenticated', 'setToken', 'setUser', 'refresh', 'onAuthChange', 'offAuthChange', 'getAuthHeader'],
|
|
32
32
|
Stream: ['create', 'headers', 'withToken', 'onChunk', 'onComplete', 'onError', 'get', 'post', 'abort', 'getBuffer', 'getChunks', 'isStreaming', 'clear'],
|
|
@@ -77,12 +77,8 @@ The npm package is "stellify-framework" (NOT @stellify/core).
|
|
|
77
77
|
Import like: import { Http, List, Form } from 'stellify-framework';
|
|
78
78
|
|
|
79
79
|
IMPORTANT - List class and Vue reactivity:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
When assigning to a Vue ref that will be used with v-for, call .toArray():
|
|
84
|
-
- CORRECT: notes.value = List.from(response.data).toArray();
|
|
85
|
-
- INCORRECT (v-for won't work): notes.value = List.from(response.data);
|
|
80
|
+
List is iterable and works directly with Vue's v-for directive.
|
|
81
|
+
Use List.from() to wrap arrays for chainable operations (filter, map, sort, etc.).
|
|
86
82
|
|
|
87
83
|
Example response:
|
|
88
84
|
{
|
|
@@ -138,13 +134,16 @@ LEGACY (still supported but prefer combined tools above):
|
|
|
138
134
|
|
|
139
135
|
For PHP: Use type='class', 'model', 'controller', or 'middleware'.
|
|
140
136
|
For Vue: Use type='js' and extension='vue'. Place in the 'js' directory.
|
|
137
|
+
- Auto-creates app.js (check response.appJs)
|
|
138
|
+
- Auto-creates template route for visual editor (check response.templateRoute.uuid)
|
|
141
139
|
|
|
142
140
|
DEPENDENCY RESOLUTION (automatic):
|
|
143
|
-
Pass 'includes' as an array of namespace strings (e.g., ["
|
|
144
|
-
The system resolves these to UUIDs automatically
|
|
145
|
-
- App\\* classes → creates stub file in your project (tenant DB)
|
|
141
|
+
Pass 'includes' as an array of namespace strings for FRAMEWORK classes (e.g., ["Illuminate\\Http\\Request", "Illuminate\\Support\\Facades\\Hash"]).
|
|
142
|
+
The system resolves these to UUIDs automatically:
|
|
146
143
|
- Illuminate\\*/Laravel\\* → fetches from Laravel API, creates in Application DB
|
|
147
|
-
- Vendor packages → fetches from vendor, creates in Application DB
|
|
144
|
+
- Vendor packages → fetches from vendor, creates in Application DB
|
|
145
|
+
|
|
146
|
+
NOTE: For controllers that use PROJECT models (Feedback, Vote, etc.), add those to the 'models' array in save_file instead. Do NOT put project models in includes - this causes duplicate use statement errors.`,
|
|
148
147
|
inputSchema: {
|
|
149
148
|
type: 'object',
|
|
150
149
|
properties: {
|
|
@@ -186,7 +185,9 @@ The system resolves these to UUIDs automatically, creating missing dependencies
|
|
|
186
185
|
name: 'create_method',
|
|
187
186
|
description: `Create a method in a file. Can optionally include the body and async flag in a single call.
|
|
188
187
|
|
|
189
|
-
**NEW: Combined creation** -
|
|
188
|
+
**NEW: Combined creation** - Pass 'body' to create the complete method in ONE call. Async is auto-detected when body contains \`await\`.
|
|
189
|
+
|
|
190
|
+
**Nested code is handled correctly.** The parser tracks brace/bracket/paren depth and only splits statements on semicolons at the top level. This means computed properties, arrow functions with block bodies, and other nested constructs work correctly as single statements.
|
|
190
191
|
|
|
191
192
|
Parameters are automatically created as clauses. The response includes the clause UUIDs for each parameter.
|
|
192
193
|
|
|
@@ -202,12 +203,11 @@ Example request (simple - signature only):
|
|
|
202
203
|
]
|
|
203
204
|
}
|
|
204
205
|
|
|
205
|
-
Example request (combined - with body
|
|
206
|
+
Example request (combined - with body, async auto-detected):
|
|
206
207
|
{
|
|
207
208
|
"file": "file-uuid",
|
|
208
209
|
"name": "fetchData",
|
|
209
|
-
"body": "const response = await Http.get('/api/data');\\nreturn response.data;"
|
|
210
|
-
"is_async": true
|
|
210
|
+
"body": "const response = await Http.get('/api/data');\\nreturn response.data;"
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
Example response includes:
|
|
@@ -289,6 +289,8 @@ Example response includes:
|
|
|
289
289
|
name: 'add_method_body',
|
|
290
290
|
description: `Parse and add PHP code to a method body. Provide the method implementation code (without the function declaration). Stellify will parse it into structured statements.
|
|
291
291
|
|
|
292
|
+
**Nested code is handled correctly.** The parser tracks brace/bracket/paren depth and only splits on semicolons at the top level. Arrow functions with block bodies, computed properties, and other nested constructs work as single statements.
|
|
293
|
+
|
|
292
294
|
IMPORTANT: This APPENDS to existing method statements. To REPLACE a method's code:
|
|
293
295
|
1. Create a NEW method with create_method
|
|
294
296
|
2. Add body with add_method_body
|
|
@@ -456,7 +458,9 @@ Example - Remove duplicate/unwanted statements:
|
|
|
456
458
|
},
|
|
457
459
|
{
|
|
458
460
|
name: 'create_route',
|
|
459
|
-
description: `Create a route/page. For API routes, pass controller
|
|
461
|
+
description: `Create a route/page. For API routes, you MUST pass BOTH controller AND controller_method UUIDs to wire execution.
|
|
462
|
+
|
|
463
|
+
IMPORTANT: Both 'controller' (file UUID) and 'controller_method' (method UUID) are required together for API routes to execute code. Without both, the route won't run any code.
|
|
460
464
|
|
|
461
465
|
Route params like {id} auto-inject into controller method parameters when names match.`,
|
|
462
466
|
inputSchema: {
|
|
@@ -488,11 +492,11 @@ Route params like {id} auto-inject into controller method parameters when names
|
|
|
488
492
|
},
|
|
489
493
|
controller: {
|
|
490
494
|
type: 'string',
|
|
491
|
-
description: 'UUID of the controller file
|
|
495
|
+
description: 'UUID of the controller file. MUST be provided together with controller_method for API routes to execute code.',
|
|
492
496
|
},
|
|
493
497
|
controller_method: {
|
|
494
498
|
type: 'string',
|
|
495
|
-
description: 'UUID of the method
|
|
499
|
+
description: 'UUID of the method to execute. MUST be provided together with controller for API routes to execute code.',
|
|
496
500
|
},
|
|
497
501
|
data: {
|
|
498
502
|
type: 'object',
|
|
@@ -527,6 +531,7 @@ Use this to look up a route you created or to find existing routes in the projec
|
|
|
527
531
|
description: `Update an existing route/page. Use this to wire a route to a controller method.
|
|
528
532
|
|
|
529
533
|
IMPORTANT: This is how you connect API routes to controller methods!
|
|
534
|
+
IMPORTANT: You MUST provide BOTH controller AND controller_method together - they are a pair.
|
|
530
535
|
|
|
531
536
|
Example - Wire an API route to a controller method:
|
|
532
537
|
{
|
|
@@ -536,8 +541,8 @@ Example - Wire an API route to a controller method:
|
|
|
536
541
|
}
|
|
537
542
|
|
|
538
543
|
Available fields:
|
|
539
|
-
- controller: UUID of the controller file
|
|
540
|
-
- controller_method: UUID of the method to execute
|
|
544
|
+
- controller: UUID of the controller file (MUST be paired with controller_method)
|
|
545
|
+
- controller_method: UUID of the method to execute (MUST be paired with controller)
|
|
541
546
|
- path: URL path
|
|
542
547
|
- name: Route name
|
|
543
548
|
- type: "web" or "api"
|
|
@@ -553,11 +558,11 @@ Available fields:
|
|
|
553
558
|
},
|
|
554
559
|
controller: {
|
|
555
560
|
type: 'string',
|
|
556
|
-
description: 'UUID of the controller file
|
|
561
|
+
description: 'UUID of the controller file. MUST be provided together with controller_method.',
|
|
557
562
|
},
|
|
558
563
|
controller_method: {
|
|
559
564
|
type: 'string',
|
|
560
|
-
description: 'UUID of the method
|
|
565
|
+
description: 'UUID of the method to execute. MUST be provided together with controller.',
|
|
561
566
|
},
|
|
562
567
|
path: {
|
|
563
568
|
type: 'string',
|
|
@@ -679,11 +684,22 @@ Generates: <div class="card p-4" v-for="note in notes" :key="note.id">`,
|
|
|
679
684
|
name: 'update_element',
|
|
680
685
|
description: `Update a UI element's attributes.
|
|
681
686
|
|
|
682
|
-
Pass data object with: tag, classes (array), text, variable (for v-model), and event handlers
|
|
687
|
+
Pass data object with: tag, classes (array), text, variable (for v-model), and event handlers.
|
|
683
688
|
|
|
684
689
|
Key fields: inputType (not 'type') for button/input HTML type. clickArgs for handler arguments in v-for loops.
|
|
685
690
|
|
|
686
|
-
|
|
691
|
+
EVENT HANDLERS - Use method UUIDs:
|
|
692
|
+
{ "click": "method-uuid" } → @click="methodName"
|
|
693
|
+
{ "click": "method-uuid", "clickArgs": "item" } → @click="methodName(item)"
|
|
694
|
+
|
|
695
|
+
Create methods for all handlers, including simple state changes like opening modals or toggling flags.
|
|
696
|
+
|
|
697
|
+
Event types: click, submit, change, input, focus, blur, keydown, keyup, mouseenter, mouseleave.
|
|
698
|
+
|
|
699
|
+
EFFICIENCY - Prefer updates over delete/recreate:
|
|
700
|
+
- Move between routes: change \`routeParent\` attribute
|
|
701
|
+
- Reparent elements: change \`parent\` attribute
|
|
702
|
+
- Reorder children: update parent's \`data\` array with new UUID order`,
|
|
687
703
|
inputSchema: {
|
|
688
704
|
type: 'object',
|
|
689
705
|
properties: {
|
|
@@ -776,6 +792,8 @@ Note: To reorder elements, use update_element to modify the parent element's 'da
|
|
|
776
792
|
|
|
777
793
|
Auto-detects Vue bindings ({{ var }}). For Vue components, omit 'page'. For pages, provide route UUID.
|
|
778
794
|
|
|
795
|
+
**@click auto-wiring:** Pass 'file' UUID to auto-resolve @click="methodName" handlers. Methods must exist in the file first.
|
|
796
|
+
|
|
779
797
|
Prefer SVG icons over emoji (encoding issues).`,
|
|
780
798
|
inputSchema: {
|
|
781
799
|
type: 'object',
|
|
@@ -792,6 +810,10 @@ Prefer SVG icons over emoji (encoding issues).`,
|
|
|
792
810
|
type: 'string',
|
|
793
811
|
description: 'Parent element UUID to attach to (alternative to page)',
|
|
794
812
|
},
|
|
813
|
+
file: {
|
|
814
|
+
type: 'string',
|
|
815
|
+
description: 'Vue component file UUID. Pass this to auto-wire @click handlers to method UUIDs.',
|
|
816
|
+
},
|
|
795
817
|
test: {
|
|
796
818
|
type: 'boolean',
|
|
797
819
|
description: 'If true, returns structure without creating elements',
|
|
@@ -852,11 +874,13 @@ For Vue components, include the returned statement UUID in save_file's 'statemen
|
|
|
852
874
|
|
|
853
875
|
**PREFERRED:** Use this instead of the two-step create_statement → add_statement_code process.
|
|
854
876
|
|
|
877
|
+
**Nested code is handled correctly.** The parser tracks brace/bracket/paren depth and only splits on top-level semicolons. Computed properties, arrow functions with block bodies, and other nested constructs are kept as single statements.
|
|
878
|
+
|
|
855
879
|
Examples:
|
|
856
880
|
- PHP: "use Illuminate\\Http\\Request;" or "private $items = [];"
|
|
857
881
|
- JS/Vue: "const count = ref(0);" or "import { ref } from 'vue';"
|
|
858
882
|
|
|
859
|
-
For Vue components, include the returned statement
|
|
883
|
+
For Vue components, include the returned statement UUIDs in save_file's 'statements' array (NOT 'data' - that's for methods).`,
|
|
860
884
|
inputSchema: {
|
|
861
885
|
type: 'object',
|
|
862
886
|
properties: {
|
|
@@ -880,7 +904,7 @@ For Vue components, include the returned statement UUID in save_file's 'statemen
|
|
|
880
904
|
name: 'add_statement_code',
|
|
881
905
|
description: `Add code to an existing statement. This is step 2 of 2 - call this AFTER create_statement.
|
|
882
906
|
|
|
883
|
-
**ALTERNATIVE:** Use create_statement_with_code for a single-call approach.
|
|
907
|
+
**ALTERNATIVE:** Use create_statement_with_code for a single-call approach that combines both steps.
|
|
884
908
|
|
|
885
909
|
The statement must already exist (created via create_statement). This parses and stores the code.
|
|
886
910
|
|
|
@@ -1018,12 +1042,12 @@ This works the same as create_file's dependency resolution.`,
|
|
|
1018
1042
|
includes: {
|
|
1019
1043
|
type: 'array',
|
|
1020
1044
|
items: { type: 'string' },
|
|
1021
|
-
description: 'Array of file UUIDs OR namespace strings
|
|
1045
|
+
description: 'Array of file UUIDs OR namespace strings for FRAMEWORK classes only (Request, JsonResponse, etc.). Do NOT put project models here - use the models array instead.',
|
|
1022
1046
|
},
|
|
1023
1047
|
models: {
|
|
1024
1048
|
type: 'array',
|
|
1025
1049
|
items: { type: 'string' },
|
|
1026
|
-
description: 'Array of model file UUIDs
|
|
1050
|
+
description: 'Array of model file UUIDs for PROJECT models (Feedback, Vote, etc.). These get sandbox namespace automatically. Do NOT also add these to includes or you will get duplicate use statement errors.',
|
|
1027
1051
|
},
|
|
1028
1052
|
},
|
|
1029
1053
|
required: ['uuid', 'name', 'type'],
|
|
@@ -1458,6 +1482,111 @@ The response includes actionable suggestions like:
|
|
|
1458
1482
|
},
|
|
1459
1483
|
},
|
|
1460
1484
|
},
|
|
1485
|
+
{
|
|
1486
|
+
name: 'get_setting',
|
|
1487
|
+
description: `Get a setting/config value from the tenant's settings table.
|
|
1488
|
+
|
|
1489
|
+
These settings are read by the config() function in sandbox code execution.
|
|
1490
|
+
Use this to check existing configuration values before modifying them.
|
|
1491
|
+
|
|
1492
|
+
EXAMPLE:
|
|
1493
|
+
{ "name": "app" }
|
|
1494
|
+
|
|
1495
|
+
Returns the setting data as key-value pairs, e.g.:
|
|
1496
|
+
{
|
|
1497
|
+
"name": "My App",
|
|
1498
|
+
"timezone": "UTC",
|
|
1499
|
+
"locale": "en"
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
Common setting profiles:
|
|
1503
|
+
- "app": Application settings (name, timezone, locale)
|
|
1504
|
+
- "database": Database connection settings
|
|
1505
|
+
- "mail": Mail configuration
|
|
1506
|
+
- "cache": Cache settings
|
|
1507
|
+
- Custom profiles for app-specific config`,
|
|
1508
|
+
inputSchema: {
|
|
1509
|
+
type: 'object',
|
|
1510
|
+
properties: {
|
|
1511
|
+
name: {
|
|
1512
|
+
type: 'string',
|
|
1513
|
+
description: 'Setting profile name (e.g., "app", "database", "mail", or custom names like "vote")',
|
|
1514
|
+
},
|
|
1515
|
+
},
|
|
1516
|
+
required: ['name'],
|
|
1517
|
+
},
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
name: 'save_setting',
|
|
1521
|
+
description: `Create or update a setting in the tenant's settings table.
|
|
1522
|
+
|
|
1523
|
+
These settings are accessible via config() in sandbox code execution.
|
|
1524
|
+
Use this to configure application behavior, API keys, feature flags, etc.
|
|
1525
|
+
|
|
1526
|
+
IMPORTANT: This creates or updates the setting profile with the provided key-value data.
|
|
1527
|
+
The data is merged with any existing values for that profile.
|
|
1528
|
+
|
|
1529
|
+
EXAMPLE - Create app settings:
|
|
1530
|
+
{
|
|
1531
|
+
"name": "app",
|
|
1532
|
+
"data": {
|
|
1533
|
+
"name": "My Feedback App",
|
|
1534
|
+
"timezone": "America/New_York",
|
|
1535
|
+
"locale": "en"
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
EXAMPLE - Create custom settings for voting:
|
|
1540
|
+
{
|
|
1541
|
+
"name": "vote",
|
|
1542
|
+
"data": {
|
|
1543
|
+
"salt": "my-secret-salt-for-ip-hashing",
|
|
1544
|
+
"allow_anonymous": true,
|
|
1545
|
+
"max_votes_per_day": 10
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
In your controller code, access these with:
|
|
1550
|
+
- config('app.name') returns "My Feedback App"
|
|
1551
|
+
- config('vote.salt') returns "my-secret-salt-for-ip-hashing"
|
|
1552
|
+
- config('vote.allow_anonymous') returns true`,
|
|
1553
|
+
inputSchema: {
|
|
1554
|
+
type: 'object',
|
|
1555
|
+
properties: {
|
|
1556
|
+
name: {
|
|
1557
|
+
type: 'string',
|
|
1558
|
+
description: 'Setting profile name (e.g., "app", "vote", "features")',
|
|
1559
|
+
},
|
|
1560
|
+
data: {
|
|
1561
|
+
type: 'object',
|
|
1562
|
+
description: 'Key-value pairs for the setting (e.g., { "salt": "secret", "enabled": true })',
|
|
1563
|
+
},
|
|
1564
|
+
},
|
|
1565
|
+
required: ['name', 'data'],
|
|
1566
|
+
},
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
name: 'delete_setting',
|
|
1570
|
+
description: `Delete a setting profile from the tenant's settings table.
|
|
1571
|
+
|
|
1572
|
+
WARNING: This permanently removes the entire setting profile and all its values.
|
|
1573
|
+
This cannot be undone.
|
|
1574
|
+
|
|
1575
|
+
EXAMPLE:
|
|
1576
|
+
{ "name": "vote" }
|
|
1577
|
+
|
|
1578
|
+
This removes the "vote" setting profile entirely.`,
|
|
1579
|
+
inputSchema: {
|
|
1580
|
+
type: 'object',
|
|
1581
|
+
properties: {
|
|
1582
|
+
name: {
|
|
1583
|
+
type: 'string',
|
|
1584
|
+
description: 'Setting profile name to delete',
|
|
1585
|
+
},
|
|
1586
|
+
},
|
|
1587
|
+
required: ['name'],
|
|
1588
|
+
},
|
|
1589
|
+
},
|
|
1461
1590
|
];
|
|
1462
1591
|
// Server instructions for tool discovery (used by MCP Tool Search)
|
|
1463
1592
|
const SERVER_INSTRUCTIONS = `Stellify is a coding platform where you code alongside AI on a codebase maintained and curated by AI. Build Laravel, stellify-framework, and Vue.js applications.
|
|
@@ -1486,114 +1615,76 @@ Key concepts:
|
|
|
1486
1615
|
|
|
1487
1616
|
1. get_project → find 'js' directory UUID (or create it)
|
|
1488
1617
|
2. create_file → type='js', extension='vue' for the component
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
- This route is NOT where the component displays - it's only for accessing the template in the Stellify visual editor
|
|
1492
|
-
- The actual display route (e.g., "/notes") will have just \`<div id="app"></div>\` where Vue mounts
|
|
1493
|
-
4. Create statements for imports using **create_statement_with_code** (ONE call each):
|
|
1618
|
+
- **Auto-creates app.js** and **template route** (check response for appJs and templateRoute fields)
|
|
1619
|
+
3. Create statements for imports using **create_statement_with_code** (ONE call each):
|
|
1494
1620
|
- create_statement_with_code(file, "import { ref, onMounted } from 'vue';")
|
|
1495
1621
|
- create_statement_with_code(file, "import { Http } from 'stellify-framework';")
|
|
1496
|
-
|
|
1497
|
-
5.
|
|
1498
|
-
6. **create_method with body and is_async** (ONE call instead of three). Example:
|
|
1622
|
+
4. Create statements for reactive data: create_statement_with_code(file, "const notes = ref([]);")
|
|
1623
|
+
5. **create_method with body** (async auto-detected from \`await\`). Example:
|
|
1499
1624
|
\`\`\`
|
|
1500
1625
|
create_method({
|
|
1501
1626
|
file: fileUuid,
|
|
1502
1627
|
name: "fetchNotes",
|
|
1503
|
-
body: "const response = await Http.get('/api/notes');\\nnotes.value = response.data || [];"
|
|
1504
|
-
is_async: true
|
|
1628
|
+
body: "const response = await Http.get('/api/notes');\\nnotes.value = response.data || [];"
|
|
1505
1629
|
})
|
|
1506
1630
|
\`\`\`
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
## CRITICAL: Http Response Handling (Most Common Error)
|
|
1525
|
-
|
|
1526
|
-
**This is the #1 cause of "notes not displaying" bugs.**
|
|
1527
|
-
|
|
1528
|
-
When fetching data from API endpoints, stellify-framework's Http class returns the JSON body DIRECTLY - it does NOT wrap responses like axios does.
|
|
1631
|
+
6. Create statement for onMounted: create_statement_with_code(file, "onMounted(fetchData);")
|
|
1632
|
+
7. **Create UI interaction methods** for any button that changes state:
|
|
1633
|
+
\`\`\`
|
|
1634
|
+
create_method({ file: fileUuid, name: "openModal", body: "showModal.value = true;" })
|
|
1635
|
+
create_method({ file: fileUuid, name: "closeModal", body: "showModal.value = false;" })
|
|
1636
|
+
\`\`\`
|
|
1637
|
+
8. html_to_elements with @click handlers auto-wired:
|
|
1638
|
+
\`\`\`
|
|
1639
|
+
html_to_elements({
|
|
1640
|
+
elements: '<button @click="openModal">Open</button>',
|
|
1641
|
+
page: templateRoute.uuid,
|
|
1642
|
+
file: fileUuid // Auto-wires @click="openModal" to the method UUID
|
|
1643
|
+
})
|
|
1644
|
+
\`\`\`
|
|
1645
|
+
9. save_file with: extension='vue', template=[elementUuid], data=[methodUuids], statements=[importUuids, refUuids, onMountedUuid]
|
|
1646
|
+
11. Create web route for the display page (e.g., "/notes")
|
|
1647
|
+
12. Add \`<div id="app"></div>\` to the display page: html_to_elements(page=routeUuid, elements='<div id="app"></div>')
|
|
1529
1648
|
|
|
1530
|
-
|
|
1649
|
+
## Fetching Paginated Data
|
|
1531
1650
|
|
|
1532
|
-
|
|
1651
|
+
Use \`Http.items()\` for paginated endpoints - it auto-extracts the array from Laravel responses:
|
|
1533
1652
|
|
|
1534
1653
|
\`\`\`javascript
|
|
1535
|
-
//
|
|
1536
|
-
|
|
1537
|
-
notes.value = response.data || [];
|
|
1654
|
+
// Recommended - auto-extracts .data from paginated response
|
|
1655
|
+
notes.value = await Http.items('/api/notes');
|
|
1538
1656
|
|
|
1539
|
-
//
|
|
1657
|
+
// Alternative - manual extraction
|
|
1540
1658
|
const response = await Http.get('/api/notes');
|
|
1541
|
-
notes.value = response.data
|
|
1659
|
+
notes.value = response.data || [];
|
|
1542
1660
|
\`\`\`
|
|
1543
1661
|
|
|
1544
|
-
|
|
1662
|
+
## Editing Existing Code
|
|
1545
1663
|
|
|
1546
|
-
**
|
|
1664
|
+
- **Edit at the right level:** To change code, edit the statement or clause - never delete an entire method just to change a line.
|
|
1547
1665
|
|
|
1548
1666
|
## Common Pitfalls
|
|
1549
1667
|
|
|
1550
|
-
-
|
|
1668
|
+
- **@click auto-wiring:** Pass the file UUID to html_to_elements to auto-wire @click handlers. Methods must be created BEFORE calling html_to_elements.
|
|
1551
1669
|
- **Stellify imports:** Use "stellify-framework" package (NOT @stellify/core)
|
|
1552
1670
|
CORRECT: import { Http, List, Form } from 'stellify-framework';
|
|
1553
1671
|
WRONG: import { Http } from '@stellify/core';
|
|
1554
1672
|
- v-model requires ref(), NOT Form class: const formData = ref({title: ''})
|
|
1555
|
-
- List
|
|
1673
|
+
- List is iterable and works directly with v-for (no .toArray() needed)
|
|
1556
1674
|
- add_method_body APPENDS, doesn't replace - create new method to replace
|
|
1557
1675
|
- 'data' array = method UUIDs, 'statements' array = import/variable UUIDs
|
|
1558
1676
|
- For buttons in forms, set inputType: "button" to prevent auto-submit
|
|
1559
|
-
- **Async methods:**
|
|
1677
|
+
- **Async methods:** Auto-detected when body contains \`await\`. Response includes \`is_async: true\` if detected.
|
|
1560
1678
|
- **onMounted:** Use direct method reference: "onMounted(fetchNotes);"
|
|
1561
1679
|
The assembler automatically outputs lifecycle hooks after method definitions.
|
|
1562
1680
|
|
|
1563
|
-
##
|
|
1564
|
-
|
|
1565
|
-
**This causes "Cannot read properties of null" errors.**
|
|
1566
|
-
|
|
1567
|
-
When using a nullable ref (e.g., \`const editingNote = ref(null)\`) with v-model or property access in templates, you MUST guard with an explicit v-if that checks the ref is not null.
|
|
1568
|
-
|
|
1569
|
-
**WRONG - v-else does NOT protect against null evaluation:**
|
|
1570
|
-
\`\`\`html
|
|
1571
|
-
<template v-if="!editingItem">
|
|
1572
|
-
<!-- view mode -->
|
|
1573
|
-
</template>
|
|
1574
|
-
<template v-else>
|
|
1575
|
-
<input v-model="editingItem.title" /> <!-- ERROR: editingItem could be null -->
|
|
1576
|
-
</template>
|
|
1577
|
-
\`\`\`
|
|
1578
|
-
|
|
1579
|
-
**CORRECT - explicit v-if with null check:**
|
|
1580
|
-
\`\`\`html
|
|
1581
|
-
<template v-if="!editingItem || editingItem.id !== item.id">
|
|
1582
|
-
<!-- view mode -->
|
|
1583
|
-
</template>
|
|
1584
|
-
<template v-if="editingItem && editingItem.id === item.id">
|
|
1585
|
-
<input v-model="editingItem.title" /> <!-- Safe: editingItem is guaranteed non-null -->
|
|
1586
|
-
</template>
|
|
1587
|
-
\`\`\`
|
|
1681
|
+
## Nullable Refs: Use explicit v-if, NOT v-else
|
|
1588
1682
|
|
|
1589
|
-
|
|
1683
|
+
When using nullable refs (e.g., \`const editingItem = ref(null)\`) with v-model, use explicit v-if guards:
|
|
1684
|
+
- WRONG: \`<template v-else><input v-model="editingItem.title"/></template>\`
|
|
1685
|
+
- CORRECT: \`<template v-if="editingItem && editingItem.id === item.id"><input v-model="editingItem.title"/></template>\`
|
|
1590
1686
|
|
|
1591
|
-
|
|
1592
|
-
1. Create ref: \`const editingItem = ref(null);\`
|
|
1593
|
-
2. View template: \`v-if="!editingItem || editingItem.id !== item.id"\`
|
|
1594
|
-
3. Edit template: \`v-if="editingItem && editingItem.id === item.id"\` (NOT v-else!)
|
|
1595
|
-
4. Start editing: \`editingItem.value = { ...item };\`
|
|
1596
|
-
5. Cancel/save: \`editingItem.value = null;\`
|
|
1687
|
+
Vue evaluates v-model bindings before v-else is applied, causing "Cannot read properties of null" errors.
|
|
1597
1688
|
|
|
1598
1689
|
## Stack and Business Logic
|
|
1599
1690
|
|
|
@@ -1601,65 +1692,18 @@ When using a nullable ref (e.g., \`const editingNote = ref(null)\`) with v-model
|
|
|
1601
1692
|
|
|
1602
1693
|
**All business logic** (controllers, models, middleware, etc.) goes in the tenant DB via MCP tools. If a required capability is not available, use \`request_capability\` to log it.
|
|
1603
1694
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
When building features, group related files by passing a "module" parameter.
|
|
1607
|
-
|
|
1608
|
-
- create_file(..., module: "blog-posts") - auto-groups file
|
|
1609
|
-
- create_route(..., module: "blog-posts") - auto-groups route
|
|
1610
|
-
|
|
1611
|
-
Modules are auto-created if they don't exist. This helps users see all code related to a feature grouped together.
|
|
1612
|
-
|
|
1613
|
-
## CRITICAL: JavaScript Entry File (app.js)
|
|
1614
|
-
|
|
1615
|
-
**You MUST have a JS entry file to register Vue components for use on pages.**
|
|
1616
|
-
|
|
1617
|
-
### First component in a project:
|
|
1618
|
-
1. Create app.js in the 'js' directory with the component in includes array:
|
|
1619
|
-
- create_file with type='js', extension='js', name='app', includes=[component-file-uuid]
|
|
1620
|
-
2. Add statements for NAMED imports only:
|
|
1621
|
-
- "import { createApp } from 'vue';"
|
|
1622
|
-
- "createApp(NotesApp).mount('#app');"
|
|
1623
|
-
NOTE: The component import (NotesApp) is handled by the includes array, NOT a statement!
|
|
1624
|
-
3. save_file with statement UUIDs
|
|
1625
|
-
|
|
1626
|
-
### Adding more components (app.js already exists):
|
|
1627
|
-
1. **search_files** for "app" to find existing app.js
|
|
1628
|
-
2. **get_file** to retrieve current includes and statements
|
|
1629
|
-
3. Add the new component UUID to the includes array via save_file
|
|
1630
|
-
4. Update the mount code to register the new component:
|
|
1631
|
-
- Create new statement: "app.component('Counter', Counter);"
|
|
1632
|
-
5. save_file with updated includes and statements arrays
|
|
1695
|
+
**Prefer Laravel methods:** When Laravel provides a helper (Str, Arr, Hash, Number, Collection), use it instead of native PHP functions.
|
|
1633
1696
|
|
|
1634
|
-
|
|
1635
|
-
**DO NOT use statements for file imports - use the includes array!**
|
|
1697
|
+
## JavaScript Entry File (app.js) - Auto-Generated
|
|
1636
1698
|
|
|
1637
|
-
|
|
1638
|
-
Each page that uses Vue components needs a \`<div id="app"></div>\`.
|
|
1699
|
+
When you create a Vue component, **app.js is automatically created/updated** with component registration. The create_file response will confirm this with an \`appJs\` field.
|
|
1639
1700
|
|
|
1640
|
-
|
|
1641
|
-
-
|
|
1642
|
-
|
|
1643
|
-
**Without app.js AND div#app, Vue components will NOT render!**
|
|
1644
|
-
|
|
1645
|
-
### Import types summary:
|
|
1646
|
-
- **File imports (components, classes):** Use \`includes\` array with file UUIDs
|
|
1647
|
-
- **Named imports (vue, stellify-framework):** Use statements with add_statement_code
|
|
1648
|
-
|
|
1649
|
-
Example app.js structure:
|
|
1650
|
-
- includes: [notesAppFileUuid, counterFileUuid]
|
|
1651
|
-
- statements: ["import { createApp } from 'vue';", "const app = createApp({});", "app.component('NotesApp', NotesApp);", "app.component('Counter', Counter);", "app.mount('#app');"]
|
|
1652
|
-
|
|
1653
|
-
## Efficiency Tips
|
|
1654
|
-
|
|
1655
|
-
- **Move elements between routes:** Use \`update_element\` to change \`routeParent\` - don't delete/recreate
|
|
1656
|
-
- **Reparent elements:** Update \`parent\` attribute instead of recreating
|
|
1657
|
-
- **Reorder children:** Update parent's \`data\` array with new UUID order
|
|
1658
|
-
- Always prefer updating over deleting and recreating`;
|
|
1701
|
+
**Page mount point:** Each page using Vue needs \`<div id="app"></div>\`:
|
|
1702
|
+
- html_to_elements(page=routeUuid, elements='<div id="app"></div>')`;
|
|
1659
1703
|
// Create MCP server
|
|
1660
1704
|
const server = new Server({
|
|
1661
1705
|
name: 'stellify-mcp',
|
|
1662
|
-
version: '0.1.
|
|
1706
|
+
version: '0.1.28',
|
|
1663
1707
|
}, {
|
|
1664
1708
|
capabilities: {
|
|
1665
1709
|
tools: {},
|
|
@@ -1722,14 +1766,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1722
1766
|
case 'create_file': {
|
|
1723
1767
|
const result = await stellify.createFile(args);
|
|
1724
1768
|
const fileData = result.data || result;
|
|
1769
|
+
const appJs = fileData.appJs || result.appJs;
|
|
1770
|
+
let message = `Created file "${args.name}" (UUID: ${fileData.uuid})`;
|
|
1771
|
+
if (appJs?.created) {
|
|
1772
|
+
message += `. Auto-created app.js (UUID: ${appJs.uuid}) with component registration.`;
|
|
1773
|
+
}
|
|
1774
|
+
else if (appJs?.updated) {
|
|
1775
|
+
message += `. Auto-updated app.js to include this component.`;
|
|
1776
|
+
}
|
|
1725
1777
|
return {
|
|
1726
1778
|
content: [
|
|
1727
1779
|
{
|
|
1728
1780
|
type: 'text',
|
|
1729
1781
|
text: JSON.stringify({
|
|
1730
1782
|
success: true,
|
|
1731
|
-
message
|
|
1783
|
+
message,
|
|
1732
1784
|
file: fileData,
|
|
1785
|
+
appJs: appJs || null,
|
|
1733
1786
|
}, null, 2),
|
|
1734
1787
|
},
|
|
1735
1788
|
],
|
|
@@ -2428,6 +2481,52 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2428
2481
|
],
|
|
2429
2482
|
};
|
|
2430
2483
|
}
|
|
2484
|
+
case 'get_setting': {
|
|
2485
|
+
const result = await stellify.getSetting(args.name);
|
|
2486
|
+
const data = result.data || result;
|
|
2487
|
+
return {
|
|
2488
|
+
content: [
|
|
2489
|
+
{
|
|
2490
|
+
type: 'text',
|
|
2491
|
+
text: JSON.stringify({
|
|
2492
|
+
success: true,
|
|
2493
|
+
message: `Retrieved setting "${args.name}"`,
|
|
2494
|
+
setting: data,
|
|
2495
|
+
}, null, 2),
|
|
2496
|
+
},
|
|
2497
|
+
],
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
case 'save_setting': {
|
|
2501
|
+
const { name, data } = args;
|
|
2502
|
+
await stellify.saveSetting(name, data);
|
|
2503
|
+
return {
|
|
2504
|
+
content: [
|
|
2505
|
+
{
|
|
2506
|
+
type: 'text',
|
|
2507
|
+
text: JSON.stringify({
|
|
2508
|
+
success: true,
|
|
2509
|
+
message: `Saved setting "${name}" with ${Object.keys(data).length} key(s)`,
|
|
2510
|
+
keys: Object.keys(data),
|
|
2511
|
+
}, null, 2),
|
|
2512
|
+
},
|
|
2513
|
+
],
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
case 'delete_setting': {
|
|
2517
|
+
await stellify.deleteSetting(args.name);
|
|
2518
|
+
return {
|
|
2519
|
+
content: [
|
|
2520
|
+
{
|
|
2521
|
+
type: 'text',
|
|
2522
|
+
text: JSON.stringify({
|
|
2523
|
+
success: true,
|
|
2524
|
+
message: `Deleted setting "${args.name}"`,
|
|
2525
|
+
}, null, 2),
|
|
2526
|
+
},
|
|
2527
|
+
],
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2431
2530
|
default:
|
|
2432
2531
|
throw new Error(`Unknown tool: ${name}`);
|
|
2433
2532
|
}
|
|
@@ -120,6 +120,7 @@ export declare class StellifyClient {
|
|
|
120
120
|
elements: string;
|
|
121
121
|
page?: string;
|
|
122
122
|
selection?: string;
|
|
123
|
+
file?: string;
|
|
123
124
|
test?: boolean;
|
|
124
125
|
}): Promise<any>;
|
|
125
126
|
getDirectory(uuid: string): Promise<any>;
|
|
@@ -183,4 +184,8 @@ export declare class StellifyClient {
|
|
|
183
184
|
analyzeQuality(params: {
|
|
184
185
|
type?: 'full' | 'relationships' | 'fillables' | 'casts' | 'routes';
|
|
185
186
|
}): Promise<any>;
|
|
187
|
+
getSetting(name: string): Promise<any>;
|
|
188
|
+
saveSetting(name: string, data: Record<string, any>): Promise<any>;
|
|
189
|
+
createSetting(name: string): Promise<any>;
|
|
190
|
+
deleteSetting(name: string): Promise<any>;
|
|
186
191
|
}
|
package/dist/stellify-client.js
CHANGED
|
@@ -207,4 +207,22 @@ export class StellifyClient {
|
|
|
207
207
|
const response = await this.client.get(endpoint);
|
|
208
208
|
return response.data;
|
|
209
209
|
}
|
|
210
|
+
// Settings/Config management - for tenant-specific configuration
|
|
211
|
+
// These settings are read by the config() override in sandbox code execution
|
|
212
|
+
async getSetting(name) {
|
|
213
|
+
const response = await this.client.get(`/config/${name}`);
|
|
214
|
+
return response.data;
|
|
215
|
+
}
|
|
216
|
+
async saveSetting(name, data) {
|
|
217
|
+
const response = await this.client.put(`/config/${name}`, { data });
|
|
218
|
+
return response.data;
|
|
219
|
+
}
|
|
220
|
+
async createSetting(name) {
|
|
221
|
+
const response = await this.client.post('/config', { name });
|
|
222
|
+
return response.data;
|
|
223
|
+
}
|
|
224
|
+
async deleteSetting(name) {
|
|
225
|
+
const response = await this.client.delete(`/config/${name}`);
|
|
226
|
+
return response.data;
|
|
227
|
+
}
|
|
210
228
|
}
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/Stellify-Software-Ltd/stellify-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.28",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@stellisoft/stellify-mcp",
|
|
14
|
-
"version": "0.1.
|
|
14
|
+
"version": "0.1.28",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|