@stellisoft/stellify-mcp 0.1.25 → 0.1.27
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 +199 -196
- package/dist/stellify-client.d.ts +12 -1
- package/dist/stellify-client.js +5 -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
|
{
|
|
@@ -127,20 +123,27 @@ This creates an EMPTY file shell - no methods, statements, or template yet. The
|
|
|
127
123
|
|
|
128
124
|
COMPLETE WORKFLOW:
|
|
129
125
|
1. create_file → creates empty shell, returns file UUID
|
|
130
|
-
2.
|
|
131
|
-
3. create_method
|
|
126
|
+
2. create_statement_with_code → add variables/imports in ONE call (returns statement UUIDs)
|
|
127
|
+
3. create_method with body param → add functions in ONE call (returns method UUIDs)
|
|
132
128
|
4. html_to_elements → create template elements (returns element UUIDs)
|
|
133
129
|
5. save_file → FINALIZE by wiring template/data arrays with all collected UUIDs
|
|
134
130
|
|
|
131
|
+
LEGACY (still supported but prefer combined tools above):
|
|
132
|
+
- create_statement + add_statement_code (2 calls instead of 1)
|
|
133
|
+
- create_method + add_method_body + save_method for is_async (3 calls instead of 1)
|
|
134
|
+
|
|
135
135
|
For PHP: Use type='class', 'model', 'controller', or 'middleware'.
|
|
136
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)
|
|
137
139
|
|
|
138
140
|
DEPENDENCY RESOLUTION (automatic):
|
|
139
|
-
Pass 'includes' as an array of namespace strings (e.g., ["
|
|
140
|
-
The system resolves these to UUIDs automatically
|
|
141
|
-
- 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:
|
|
142
143
|
- Illuminate\\*/Laravel\\* → fetches from Laravel API, creates in Application DB
|
|
143
|
-
- 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.`,
|
|
144
147
|
inputSchema: {
|
|
145
148
|
type: 'object',
|
|
146
149
|
properties: {
|
|
@@ -180,11 +183,13 @@ The system resolves these to UUIDs automatically, creating missing dependencies
|
|
|
180
183
|
},
|
|
181
184
|
{
|
|
182
185
|
name: 'create_method',
|
|
183
|
-
description: `Create a method
|
|
186
|
+
description: `Create a method in a file. Can optionally include the body and async flag in a single call.
|
|
187
|
+
|
|
188
|
+
**NEW: Combined creation** - Pass 'body' to create the complete method in ONE call. Async is auto-detected when body contains \`await\`.
|
|
184
189
|
|
|
185
190
|
Parameters are automatically created as clauses. The response includes the clause UUIDs for each parameter.
|
|
186
191
|
|
|
187
|
-
Example request:
|
|
192
|
+
Example request (simple - signature only):
|
|
188
193
|
{
|
|
189
194
|
"file": "file-uuid",
|
|
190
195
|
"name": "verify",
|
|
@@ -196,14 +201,21 @@ Example request:
|
|
|
196
201
|
]
|
|
197
202
|
}
|
|
198
203
|
|
|
204
|
+
Example request (combined - with body, async auto-detected):
|
|
205
|
+
{
|
|
206
|
+
"file": "file-uuid",
|
|
207
|
+
"name": "fetchData",
|
|
208
|
+
"body": "const response = await Http.get('/api/data');\\nreturn response.data;"
|
|
209
|
+
}
|
|
210
|
+
|
|
199
211
|
Example response includes:
|
|
200
212
|
{
|
|
201
213
|
"uuid": "method-uuid",
|
|
202
|
-
"name": "
|
|
203
|
-
"
|
|
204
|
-
"nullable": true,
|
|
214
|
+
"name": "fetchData",
|
|
215
|
+
"is_async": true,
|
|
205
216
|
"parameters": ["clause-uuid-for-credentials"],
|
|
206
|
-
...
|
|
217
|
+
"statements": {...}, // Only if body was provided
|
|
218
|
+
"clauses": {...} // Only if body was provided
|
|
207
219
|
}`,
|
|
208
220
|
inputSchema: {
|
|
209
221
|
type: 'object',
|
|
@@ -225,6 +237,10 @@ Example response includes:
|
|
|
225
237
|
type: 'boolean',
|
|
226
238
|
description: 'Whether the method is static (PHP only)',
|
|
227
239
|
},
|
|
240
|
+
is_async: {
|
|
241
|
+
type: 'boolean',
|
|
242
|
+
description: 'Whether the method is async (JavaScript/Vue only). Set to true for methods that use await.',
|
|
243
|
+
},
|
|
228
244
|
returnType: {
|
|
229
245
|
type: 'string',
|
|
230
246
|
description: 'Return type (e.g., "int", "string", "void", "object")',
|
|
@@ -259,6 +275,10 @@ Example response includes:
|
|
|
259
275
|
required: ['name'],
|
|
260
276
|
},
|
|
261
277
|
},
|
|
278
|
+
body: {
|
|
279
|
+
type: 'string',
|
|
280
|
+
description: 'Method body code (optional). If provided, automatically parses and adds the code. Example: "const response = await Http.get(\\"/api/data\\");\\nreturn response.data;"',
|
|
281
|
+
},
|
|
262
282
|
},
|
|
263
283
|
required: ['file', 'name'],
|
|
264
284
|
},
|
|
@@ -434,7 +454,9 @@ Example - Remove duplicate/unwanted statements:
|
|
|
434
454
|
},
|
|
435
455
|
{
|
|
436
456
|
name: 'create_route',
|
|
437
|
-
description: `Create a route/page. For API routes, pass controller
|
|
457
|
+
description: `Create a route/page. For API routes, you MUST pass BOTH controller AND controller_method UUIDs to wire execution.
|
|
458
|
+
|
|
459
|
+
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.
|
|
438
460
|
|
|
439
461
|
Route params like {id} auto-inject into controller method parameters when names match.`,
|
|
440
462
|
inputSchema: {
|
|
@@ -466,11 +488,11 @@ Route params like {id} auto-inject into controller method parameters when names
|
|
|
466
488
|
},
|
|
467
489
|
controller: {
|
|
468
490
|
type: 'string',
|
|
469
|
-
description: 'UUID of the controller file
|
|
491
|
+
description: 'UUID of the controller file. MUST be provided together with controller_method for API routes to execute code.',
|
|
470
492
|
},
|
|
471
493
|
controller_method: {
|
|
472
494
|
type: 'string',
|
|
473
|
-
description: 'UUID of the method
|
|
495
|
+
description: 'UUID of the method to execute. MUST be provided together with controller for API routes to execute code.',
|
|
474
496
|
},
|
|
475
497
|
data: {
|
|
476
498
|
type: 'object',
|
|
@@ -505,6 +527,7 @@ Use this to look up a route you created or to find existing routes in the projec
|
|
|
505
527
|
description: `Update an existing route/page. Use this to wire a route to a controller method.
|
|
506
528
|
|
|
507
529
|
IMPORTANT: This is how you connect API routes to controller methods!
|
|
530
|
+
IMPORTANT: You MUST provide BOTH controller AND controller_method together - they are a pair.
|
|
508
531
|
|
|
509
532
|
Example - Wire an API route to a controller method:
|
|
510
533
|
{
|
|
@@ -514,8 +537,8 @@ Example - Wire an API route to a controller method:
|
|
|
514
537
|
}
|
|
515
538
|
|
|
516
539
|
Available fields:
|
|
517
|
-
- controller: UUID of the controller file
|
|
518
|
-
- controller_method: UUID of the method to execute
|
|
540
|
+
- controller: UUID of the controller file (MUST be paired with controller_method)
|
|
541
|
+
- controller_method: UUID of the method to execute (MUST be paired with controller)
|
|
519
542
|
- path: URL path
|
|
520
543
|
- name: Route name
|
|
521
544
|
- type: "web" or "api"
|
|
@@ -531,11 +554,11 @@ Available fields:
|
|
|
531
554
|
},
|
|
532
555
|
controller: {
|
|
533
556
|
type: 'string',
|
|
534
|
-
description: 'UUID of the controller file
|
|
557
|
+
description: 'UUID of the controller file. MUST be provided together with controller_method.',
|
|
535
558
|
},
|
|
536
559
|
controller_method: {
|
|
537
560
|
type: 'string',
|
|
538
|
-
description: 'UUID of the method
|
|
561
|
+
description: 'UUID of the method to execute. MUST be provided together with controller.',
|
|
539
562
|
},
|
|
540
563
|
path: {
|
|
541
564
|
type: 'string',
|
|
@@ -657,11 +680,22 @@ Generates: <div class="card p-4" v-for="note in notes" :key="note.id">`,
|
|
|
657
680
|
name: 'update_element',
|
|
658
681
|
description: `Update a UI element's attributes.
|
|
659
682
|
|
|
660
|
-
Pass data object with: tag, classes (array), text, variable (for v-model), and event handlers
|
|
683
|
+
Pass data object with: tag, classes (array), text, variable (for v-model), and event handlers.
|
|
661
684
|
|
|
662
685
|
Key fields: inputType (not 'type') for button/input HTML type. clickArgs for handler arguments in v-for loops.
|
|
663
686
|
|
|
664
|
-
|
|
687
|
+
EVENT HANDLERS - Use method UUIDs:
|
|
688
|
+
{ "click": "method-uuid" } → @click="methodName"
|
|
689
|
+
{ "click": "method-uuid", "clickArgs": "item" } → @click="methodName(item)"
|
|
690
|
+
|
|
691
|
+
Create methods for all handlers, including simple state changes like opening modals or toggling flags.
|
|
692
|
+
|
|
693
|
+
Event types: click, submit, change, input, focus, blur, keydown, keyup, mouseenter, mouseleave.
|
|
694
|
+
|
|
695
|
+
EFFICIENCY - Prefer updates over delete/recreate:
|
|
696
|
+
- Move between routes: change \`routeParent\` attribute
|
|
697
|
+
- Reparent elements: change \`parent\` attribute
|
|
698
|
+
- Reorder children: update parent's \`data\` array with new UUID order`,
|
|
665
699
|
inputSchema: {
|
|
666
700
|
type: 'object',
|
|
667
701
|
properties: {
|
|
@@ -754,6 +788,8 @@ Note: To reorder elements, use update_element to modify the parent element's 'da
|
|
|
754
788
|
|
|
755
789
|
Auto-detects Vue bindings ({{ var }}). For Vue components, omit 'page'. For pages, provide route UUID.
|
|
756
790
|
|
|
791
|
+
**@click auto-wiring:** Pass 'file' UUID to auto-resolve @click="methodName" handlers. Methods must exist in the file first.
|
|
792
|
+
|
|
757
793
|
Prefer SVG icons over emoji (encoding issues).`,
|
|
758
794
|
inputSchema: {
|
|
759
795
|
type: 'object',
|
|
@@ -770,6 +806,10 @@ Prefer SVG icons over emoji (encoding issues).`,
|
|
|
770
806
|
type: 'string',
|
|
771
807
|
description: 'Parent element UUID to attach to (alternative to page)',
|
|
772
808
|
},
|
|
809
|
+
file: {
|
|
810
|
+
type: 'string',
|
|
811
|
+
description: 'Vue component file UUID. Pass this to auto-wire @click handlers to method UUIDs.',
|
|
812
|
+
},
|
|
773
813
|
test: {
|
|
774
814
|
type: 'boolean',
|
|
775
815
|
description: 'If true, returns structure without creating elements',
|
|
@@ -799,6 +839,8 @@ Prefer SVG icons over emoji (encoding issues).`,
|
|
|
799
839
|
name: 'create_statement',
|
|
800
840
|
description: `Create an empty statement in a file. This is step 1 of 2 - you MUST call add_statement_code next to add the actual code.
|
|
801
841
|
|
|
842
|
+
**ALTERNATIVE:** Use create_statement_with_code for a single-call approach that combines both steps.
|
|
843
|
+
|
|
802
844
|
IMPORTANT: This is a TWO-STEP process:
|
|
803
845
|
1. create_statement → returns statement UUID
|
|
804
846
|
2. add_statement_code → adds the actual code to that statement
|
|
@@ -822,10 +864,42 @@ For Vue components, include the returned statement UUID in save_file's 'statemen
|
|
|
822
864
|
},
|
|
823
865
|
},
|
|
824
866
|
},
|
|
867
|
+
{
|
|
868
|
+
name: 'create_statement_with_code',
|
|
869
|
+
description: `Create a statement with code in a SINGLE call. This combines create_statement and add_statement_code.
|
|
870
|
+
|
|
871
|
+
**PREFERRED:** Use this instead of the two-step create_statement → add_statement_code process.
|
|
872
|
+
|
|
873
|
+
Examples:
|
|
874
|
+
- PHP: "use Illuminate\\Http\\Request;" or "private $items = [];"
|
|
875
|
+
- JS/Vue: "const count = ref(0);" or "import { ref } from 'vue';"
|
|
876
|
+
|
|
877
|
+
For Vue components, include the returned statement UUID in save_file's 'statements' array (NOT 'data' - that's for methods).`,
|
|
878
|
+
inputSchema: {
|
|
879
|
+
type: 'object',
|
|
880
|
+
properties: {
|
|
881
|
+
file: {
|
|
882
|
+
type: 'string',
|
|
883
|
+
description: 'UUID of the file to add the statement to',
|
|
884
|
+
},
|
|
885
|
+
code: {
|
|
886
|
+
type: 'string',
|
|
887
|
+
description: 'The code for the statement (e.g., "const count = ref(0);")',
|
|
888
|
+
},
|
|
889
|
+
method: {
|
|
890
|
+
type: 'string',
|
|
891
|
+
description: 'UUID of the method to add the statement to (optional, for method body statements)',
|
|
892
|
+
},
|
|
893
|
+
},
|
|
894
|
+
required: ['file', 'code'],
|
|
895
|
+
},
|
|
896
|
+
},
|
|
825
897
|
{
|
|
826
898
|
name: 'add_statement_code',
|
|
827
899
|
description: `Add code to an existing statement. This is step 2 of 2 - call this AFTER create_statement.
|
|
828
900
|
|
|
901
|
+
**ALTERNATIVE:** Use create_statement_with_code for a single-call approach.
|
|
902
|
+
|
|
829
903
|
The statement must already exist (created via create_statement). This parses and stores the code.
|
|
830
904
|
|
|
831
905
|
Examples:
|
|
@@ -962,12 +1036,12 @@ This works the same as create_file's dependency resolution.`,
|
|
|
962
1036
|
includes: {
|
|
963
1037
|
type: 'array',
|
|
964
1038
|
items: { type: 'string' },
|
|
965
|
-
description: 'Array of file UUIDs OR namespace strings
|
|
1039
|
+
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.',
|
|
966
1040
|
},
|
|
967
1041
|
models: {
|
|
968
1042
|
type: 'array',
|
|
969
1043
|
items: { type: 'string' },
|
|
970
|
-
description: 'Array of model file UUIDs
|
|
1044
|
+
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.',
|
|
971
1045
|
},
|
|
972
1046
|
},
|
|
973
1047
|
required: ['uuid', 'name', 'type'],
|
|
@@ -1404,7 +1478,7 @@ The response includes actionable suggestions like:
|
|
|
1404
1478
|
},
|
|
1405
1479
|
];
|
|
1406
1480
|
// Server instructions for tool discovery (used by MCP Tool Search)
|
|
1407
|
-
const SERVER_INSTRUCTIONS = `Stellify is a coding platform where you code alongside AI on a codebase maintained and curated by AI. Build Laravel
|
|
1481
|
+
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.
|
|
1408
1482
|
|
|
1409
1483
|
Use Stellify tools when:
|
|
1410
1484
|
- Building PHP controllers, models, middleware, or classes
|
|
@@ -1430,198 +1504,89 @@ Key concepts:
|
|
|
1430
1504
|
|
|
1431
1505
|
1. get_project → find 'js' directory UUID (or create it)
|
|
1432
1506
|
2. create_file → type='js', extension='vue' for the component
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
-
|
|
1436
|
-
-
|
|
1437
|
-
4. Create statements for
|
|
1438
|
-
|
|
1439
|
-
- "import { Http } from 'stellify-framework';" (for API calls)
|
|
1440
|
-
NOTE: The npm package is "stellify-framework" (NOT @stellify/core)
|
|
1441
|
-
5. Create statements for reactive data: "const notes = ref([]);"
|
|
1442
|
-
6. create_method + add_method_body for functions. Example fetchNotes body:
|
|
1507
|
+
- **Auto-creates app.js** and **template route** (check response for appJs and templateRoute fields)
|
|
1508
|
+
3. Create statements for imports using **create_statement_with_code** (ONE call each):
|
|
1509
|
+
- create_statement_with_code(file, "import { ref, onMounted } from 'vue';")
|
|
1510
|
+
- create_statement_with_code(file, "import { Http } from 'stellify-framework';")
|
|
1511
|
+
4. Create statements for reactive data: create_statement_with_code(file, "const notes = ref([]);")
|
|
1512
|
+
5. **create_method with body** (async auto-detected from \`await\`). Example:
|
|
1443
1513
|
\`\`\`
|
|
1444
|
-
|
|
1445
|
-
|
|
1514
|
+
create_method({
|
|
1515
|
+
file: fileUuid,
|
|
1516
|
+
name: "fetchNotes",
|
|
1517
|
+
body: "const response = await Http.get('/api/notes');\\nnotes.value = response.data || [];"
|
|
1518
|
+
})
|
|
1446
1519
|
\`\`\`
|
|
1447
|
-
|
|
1448
|
-
7. Create
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
## CRITICAL: Http Response Handling (Most Common Error)
|
|
1466
|
-
|
|
1467
|
-
**This is the #1 cause of "notes not displaying" bugs.**
|
|
1468
|
-
|
|
1469
|
-
When fetching data from API endpoints, stellify-framework's Http class returns the JSON body DIRECTLY - it does NOT wrap responses like axios does.
|
|
1520
|
+
6. Create statement for onMounted: create_statement_with_code(file, "onMounted(fetchData);")
|
|
1521
|
+
7. **Create UI interaction methods** for any button that changes state:
|
|
1522
|
+
\`\`\`
|
|
1523
|
+
create_method({ file: fileUuid, name: "openModal", body: "showModal.value = true;" })
|
|
1524
|
+
create_method({ file: fileUuid, name: "closeModal", body: "showModal.value = false;" })
|
|
1525
|
+
\`\`\`
|
|
1526
|
+
8. html_to_elements with @click handlers auto-wired:
|
|
1527
|
+
\`\`\`
|
|
1528
|
+
html_to_elements({
|
|
1529
|
+
elements: '<button @click="openModal">Open</button>',
|
|
1530
|
+
page: templateRoute.uuid,
|
|
1531
|
+
file: fileUuid // Auto-wires @click="openModal" to the method UUID
|
|
1532
|
+
})
|
|
1533
|
+
\`\`\`
|
|
1534
|
+
9. save_file with: extension='vue', template=[elementUuid], data=[methodUuids], statements=[importUuids, refUuids, onMountedUuid]
|
|
1535
|
+
11. Create web route for the display page (e.g., "/notes")
|
|
1536
|
+
12. Add \`<div id="app"></div>\` to the display page: html_to_elements(page=routeUuid, elements='<div id="app"></div>')
|
|
1470
1537
|
|
|
1471
|
-
|
|
1538
|
+
## Fetching Paginated Data
|
|
1472
1539
|
|
|
1473
|
-
|
|
1540
|
+
Use \`Http.items()\` for paginated endpoints - it auto-extracts the array from Laravel responses:
|
|
1474
1541
|
|
|
1475
1542
|
\`\`\`javascript
|
|
1476
|
-
//
|
|
1477
|
-
|
|
1478
|
-
notes.value = response.data || [];
|
|
1543
|
+
// Recommended - auto-extracts .data from paginated response
|
|
1544
|
+
notes.value = await Http.items('/api/notes');
|
|
1479
1545
|
|
|
1480
|
-
//
|
|
1546
|
+
// Alternative - manual extraction
|
|
1481
1547
|
const response = await Http.get('/api/notes');
|
|
1482
|
-
notes.value = response.data
|
|
1548
|
+
notes.value = response.data || [];
|
|
1483
1549
|
\`\`\`
|
|
1484
1550
|
|
|
1485
|
-
**Why this mistake happens:** With axios, you write \`response.data.data\` because axios wraps the HTTP response (\`response.data\` unwraps axios, then \`.data\` gets the pagination array). Stellify's Http skips the wrapper, so you only need ONE \`.data\`.
|
|
1486
|
-
|
|
1487
|
-
**Symptom:** Notes exist in database, API returns them, but UI shows empty list or "No notes yet" message.
|
|
1488
|
-
|
|
1489
1551
|
## Common Pitfalls
|
|
1490
1552
|
|
|
1491
|
-
-
|
|
1553
|
+
- **@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.
|
|
1492
1554
|
- **Stellify imports:** Use "stellify-framework" package (NOT @stellify/core)
|
|
1493
1555
|
CORRECT: import { Http, List, Form } from 'stellify-framework';
|
|
1494
1556
|
WRONG: import { Http } from '@stellify/core';
|
|
1495
1557
|
- v-model requires ref(), NOT Form class: const formData = ref({title: ''})
|
|
1496
|
-
- List
|
|
1558
|
+
- List is iterable and works directly with v-for (no .toArray() needed)
|
|
1497
1559
|
- add_method_body APPENDS, doesn't replace - create new method to replace
|
|
1498
1560
|
- 'data' array = method UUIDs, 'statements' array = import/variable UUIDs
|
|
1499
1561
|
- For buttons in forms, set inputType: "button" to prevent auto-submit
|
|
1500
|
-
- **Async methods:**
|
|
1562
|
+
- **Async methods:** Auto-detected when body contains \`await\`. Response includes \`is_async: true\` if detected.
|
|
1501
1563
|
- **onMounted:** Use direct method reference: "onMounted(fetchNotes);"
|
|
1502
1564
|
The assembler automatically outputs lifecycle hooks after method definitions.
|
|
1503
1565
|
|
|
1504
|
-
##
|
|
1505
|
-
|
|
1506
|
-
**This causes "Cannot read properties of null" errors.**
|
|
1507
|
-
|
|
1508
|
-
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.
|
|
1509
|
-
|
|
1510
|
-
**WRONG - v-else does NOT protect against null evaluation:**
|
|
1511
|
-
\`\`\`html
|
|
1512
|
-
<template v-if="!editingItem">
|
|
1513
|
-
<!-- view mode -->
|
|
1514
|
-
</template>
|
|
1515
|
-
<template v-else>
|
|
1516
|
-
<input v-model="editingItem.title" /> <!-- ERROR: editingItem could be null -->
|
|
1517
|
-
</template>
|
|
1518
|
-
\`\`\`
|
|
1519
|
-
|
|
1520
|
-
**CORRECT - explicit v-if with null check:**
|
|
1521
|
-
\`\`\`html
|
|
1522
|
-
<template v-if="!editingItem || editingItem.id !== item.id">
|
|
1523
|
-
<!-- view mode -->
|
|
1524
|
-
</template>
|
|
1525
|
-
<template v-if="editingItem && editingItem.id === item.id">
|
|
1526
|
-
<input v-model="editingItem.title" /> <!-- Safe: editingItem is guaranteed non-null -->
|
|
1527
|
-
</template>
|
|
1528
|
-
\`\`\`
|
|
1529
|
-
|
|
1530
|
-
**Why v-else fails:** Vue evaluates v-model bindings during compilation/render setup, before the v-else condition is fully applied. The explicit v-if with \`editingItem &&\` ensures the binding is only evaluated when the ref exists.
|
|
1531
|
-
|
|
1532
|
-
**Inline editing pattern (CRUD apps):**
|
|
1533
|
-
1. Create ref: \`const editingItem = ref(null);\`
|
|
1534
|
-
2. View template: \`v-if="!editingItem || editingItem.id !== item.id"\`
|
|
1535
|
-
3. Edit template: \`v-if="editingItem && editingItem.id === item.id"\` (NOT v-else!)
|
|
1536
|
-
4. Start editing: \`editingItem.value = { ...item };\`
|
|
1537
|
-
5. Cancel/save: \`editingItem.value = null;\`
|
|
1538
|
-
|
|
1539
|
-
## Framework Capabilities (Libraries/Packages)
|
|
1540
|
-
|
|
1541
|
-
**CRITICAL: You write BUSINESS LOGIC only. Capabilities are installed packages/libraries (Sanctum, Stripe, AWS SDK, etc.) that Stellify provides. You CANNOT create these by writing code.**
|
|
1542
|
-
|
|
1543
|
-
Examples of capabilities (packages you cannot write):
|
|
1544
|
-
- Authentication: laravel/sanctum, laravel/socialite
|
|
1545
|
-
- Payments: stripe/stripe-php
|
|
1546
|
-
- Storage: aws/aws-sdk-php, league/flysystem-aws-s3-v3
|
|
1547
|
-
- Email: mailgun/mailgun-php, aws/aws-sdk-php (SES)
|
|
1548
|
-
- Search: meilisearch/meilisearch-php, algolia/algoliasearch-client-php
|
|
1549
|
-
- WebSocket: laravel/reverb
|
|
1550
|
-
|
|
1551
|
-
**WORKFLOW:**
|
|
1552
|
-
|
|
1553
|
-
1. When a user requests functionality that might need a package/library, check the capabilities list from get_project FIRST.
|
|
1554
|
-
|
|
1555
|
-
2. If status is "available" → package is installed, proceed with business logic.
|
|
1556
|
-
|
|
1557
|
-
3. If status is "needs_config" → package installed but needs API keys. INFORM THE USER to configure it in Project Settings.
|
|
1558
|
-
|
|
1559
|
-
4. If status is "not_available" or doesn't exist:
|
|
1560
|
-
- STOP IMMEDIATELY
|
|
1561
|
-
- Call request_capability() to log it
|
|
1562
|
-
- INFORM THE USER: "This feature requires the [X] package which isn't installed in Stellify yet. I've logged a request. This cannot be built until the package is added."
|
|
1563
|
-
|
|
1564
|
-
**NEVER write code that belongs in a package.** If you find yourself writing OAuth flows, payment processing, S3 clients, email transport, search indexing, or similar infrastructure - STOP. That's a capability request, not business logic.
|
|
1565
|
-
|
|
1566
|
-
## Project Modules (Code Organization)
|
|
1566
|
+
## Nullable Refs: Use explicit v-if, NOT v-else
|
|
1567
1567
|
|
|
1568
|
-
When
|
|
1568
|
+
When using nullable refs (e.g., \`const editingItem = ref(null)\`) with v-model, use explicit v-if guards:
|
|
1569
|
+
- WRONG: \`<template v-else><input v-model="editingItem.title"/></template>\`
|
|
1570
|
+
- CORRECT: \`<template v-if="editingItem && editingItem.id === item.id"><input v-model="editingItem.title"/></template>\`
|
|
1569
1571
|
|
|
1570
|
-
-
|
|
1571
|
-
- create_route(..., module: "blog-posts") - auto-groups route
|
|
1572
|
+
Vue evaluates v-model bindings before v-else is applied, causing "Cannot read properties of null" errors.
|
|
1572
1573
|
|
|
1573
|
-
|
|
1574
|
+
## Stack and Business Logic
|
|
1574
1575
|
|
|
1575
|
-
|
|
1576
|
+
**Default stack:** Laravel (PHP), stellify-framework (JS), and Vue.js. Available capabilities (optional packages/libraries) are returned by \`get_project\`. Use \`get_stellify_framework_api\` for the stellify-framework API reference.
|
|
1576
1577
|
|
|
1577
|
-
**
|
|
1578
|
+
**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.
|
|
1578
1579
|
|
|
1579
|
-
|
|
1580
|
-
1. Create app.js in the 'js' directory with the component in includes array:
|
|
1581
|
-
- create_file with type='js', extension='js', name='app', includes=[component-file-uuid]
|
|
1582
|
-
2. Add statements for NAMED imports only:
|
|
1583
|
-
- "import { createApp } from 'vue';"
|
|
1584
|
-
- "createApp(NotesApp).mount('#app');"
|
|
1585
|
-
NOTE: The component import (NotesApp) is handled by the includes array, NOT a statement!
|
|
1586
|
-
3. save_file with statement UUIDs
|
|
1580
|
+
## JavaScript Entry File (app.js) - Auto-Generated
|
|
1587
1581
|
|
|
1588
|
-
|
|
1589
|
-
1. **search_files** for "app" to find existing app.js
|
|
1590
|
-
2. **get_file** to retrieve current includes and statements
|
|
1591
|
-
3. Add the new component UUID to the includes array via save_file
|
|
1592
|
-
4. Update the mount code to register the new component:
|
|
1593
|
-
- Create new statement: "app.component('Counter', Counter);"
|
|
1594
|
-
5. save_file with updated includes and statements arrays
|
|
1582
|
+
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.
|
|
1595
1583
|
|
|
1596
|
-
**
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
### Page mount point (div#app):
|
|
1600
|
-
Each page that uses Vue components needs a \`<div id="app"></div>\`.
|
|
1601
|
-
|
|
1602
|
-
- **First time on a page:** html_to_elements(page=routeUuid, elements='<div id="app"></div>')
|
|
1603
|
-
- **Page already has it:** Do NOT add another one. Check with get_route first if unsure.
|
|
1604
|
-
|
|
1605
|
-
**Without app.js AND div#app, Vue components will NOT render!**
|
|
1606
|
-
|
|
1607
|
-
### Import types summary:
|
|
1608
|
-
- **File imports (components, classes):** Use \`includes\` array with file UUIDs
|
|
1609
|
-
- **Named imports (vue, stellify-framework):** Use statements with add_statement_code
|
|
1610
|
-
|
|
1611
|
-
Example app.js structure:
|
|
1612
|
-
- includes: [notesAppFileUuid, counterFileUuid]
|
|
1613
|
-
- statements: ["import { createApp } from 'vue';", "const app = createApp({});", "app.component('NotesApp', NotesApp);", "app.component('Counter', Counter);", "app.mount('#app');"]
|
|
1614
|
-
|
|
1615
|
-
## Efficiency Tips
|
|
1616
|
-
|
|
1617
|
-
- **Move elements between routes:** Use \`update_element\` to change \`routeParent\` - don't delete/recreate
|
|
1618
|
-
- **Reparent elements:** Update \`parent\` attribute instead of recreating
|
|
1619
|
-
- **Reorder children:** Update parent's \`data\` array with new UUID order
|
|
1620
|
-
- Always prefer updating over deleting and recreating`;
|
|
1584
|
+
**Page mount point:** Each page using Vue needs \`<div id="app"></div>\`:
|
|
1585
|
+
- html_to_elements(page=routeUuid, elements='<div id="app"></div>')`;
|
|
1621
1586
|
// Create MCP server
|
|
1622
1587
|
const server = new Server({
|
|
1623
1588
|
name: 'stellify-mcp',
|
|
1624
|
-
version: '0.1.
|
|
1589
|
+
version: '0.1.27',
|
|
1625
1590
|
}, {
|
|
1626
1591
|
capabilities: {
|
|
1627
1592
|
tools: {},
|
|
@@ -1684,14 +1649,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1684
1649
|
case 'create_file': {
|
|
1685
1650
|
const result = await stellify.createFile(args);
|
|
1686
1651
|
const fileData = result.data || result;
|
|
1652
|
+
const appJs = fileData.appJs || result.appJs;
|
|
1653
|
+
let message = `Created file "${args.name}" (UUID: ${fileData.uuid})`;
|
|
1654
|
+
if (appJs?.created) {
|
|
1655
|
+
message += `. Auto-created app.js (UUID: ${appJs.uuid}) with component registration.`;
|
|
1656
|
+
}
|
|
1657
|
+
else if (appJs?.updated) {
|
|
1658
|
+
message += `. Auto-updated app.js to include this component.`;
|
|
1659
|
+
}
|
|
1687
1660
|
return {
|
|
1688
1661
|
content: [
|
|
1689
1662
|
{
|
|
1690
1663
|
type: 'text',
|
|
1691
1664
|
text: JSON.stringify({
|
|
1692
1665
|
success: true,
|
|
1693
|
-
message
|
|
1666
|
+
message,
|
|
1694
1667
|
file: fileData,
|
|
1668
|
+
appJs: appJs || null,
|
|
1695
1669
|
}, null, 2),
|
|
1696
1670
|
},
|
|
1697
1671
|
],
|
|
@@ -1700,15 +1674,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1700
1674
|
case 'create_method': {
|
|
1701
1675
|
const result = await stellify.createMethod(args);
|
|
1702
1676
|
const methodData = result.data || result;
|
|
1677
|
+
const hasBody = !!args.body;
|
|
1678
|
+
const response = {
|
|
1679
|
+
success: true,
|
|
1680
|
+
message: hasBody
|
|
1681
|
+
? `Created method "${args.name}" with body (UUID: ${methodData.uuid})`
|
|
1682
|
+
: `Created method "${args.name}" (UUID: ${methodData.uuid})`,
|
|
1683
|
+
method: methodData,
|
|
1684
|
+
};
|
|
1685
|
+
// Include statements and clauses if body was provided
|
|
1686
|
+
if (result.statements) {
|
|
1687
|
+
response.statements = result.statements;
|
|
1688
|
+
}
|
|
1689
|
+
if (result.clauses) {
|
|
1690
|
+
response.clauses = result.clauses;
|
|
1691
|
+
}
|
|
1703
1692
|
return {
|
|
1704
1693
|
content: [
|
|
1705
1694
|
{
|
|
1706
1695
|
type: 'text',
|
|
1707
|
-
text: JSON.stringify(
|
|
1708
|
-
success: true,
|
|
1709
|
-
message: `Created method "${args.name}" (UUID: ${methodData.uuid})`,
|
|
1710
|
-
method: methodData,
|
|
1711
|
-
}, null, 2),
|
|
1696
|
+
text: JSON.stringify(response, null, 2),
|
|
1712
1697
|
},
|
|
1713
1698
|
],
|
|
1714
1699
|
};
|
|
@@ -2030,6 +2015,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2030
2015
|
],
|
|
2031
2016
|
};
|
|
2032
2017
|
}
|
|
2018
|
+
case 'create_statement_with_code': {
|
|
2019
|
+
const result = await stellify.createStatementWithCode(args);
|
|
2020
|
+
const statementData = result.data || result;
|
|
2021
|
+
return {
|
|
2022
|
+
content: [
|
|
2023
|
+
{
|
|
2024
|
+
type: 'text',
|
|
2025
|
+
text: JSON.stringify({
|
|
2026
|
+
success: true,
|
|
2027
|
+
message: `Created statement with code (UUID: ${statementData.uuid})`,
|
|
2028
|
+
statement: statementData.statement || statementData,
|
|
2029
|
+
statements: statementData.statements,
|
|
2030
|
+
clauses: statementData.clauses,
|
|
2031
|
+
}, null, 2),
|
|
2032
|
+
},
|
|
2033
|
+
],
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
2033
2036
|
case 'add_statement_code': {
|
|
2034
2037
|
const result = await stellify.addStatementCode(args);
|
|
2035
2038
|
return {
|
|
@@ -17,11 +17,16 @@ export interface CreateMethodParams {
|
|
|
17
17
|
name: string;
|
|
18
18
|
visibility?: 'public' | 'protected' | 'private';
|
|
19
19
|
is_static?: boolean;
|
|
20
|
+
is_async?: boolean;
|
|
20
21
|
returnType?: string;
|
|
22
|
+
nullable?: boolean;
|
|
21
23
|
parameters?: Array<{
|
|
22
24
|
name: string;
|
|
23
|
-
type
|
|
25
|
+
type?: string;
|
|
26
|
+
datatype?: string;
|
|
27
|
+
value?: string;
|
|
24
28
|
}>;
|
|
29
|
+
body?: string;
|
|
25
30
|
}
|
|
26
31
|
export interface AddMethodBodyParams {
|
|
27
32
|
file: string;
|
|
@@ -84,6 +89,11 @@ export declare class StellifyClient {
|
|
|
84
89
|
file?: string;
|
|
85
90
|
method?: string;
|
|
86
91
|
}): Promise<any>;
|
|
92
|
+
createStatementWithCode(params: {
|
|
93
|
+
file: string;
|
|
94
|
+
code: string;
|
|
95
|
+
method?: string;
|
|
96
|
+
}): Promise<any>;
|
|
87
97
|
getStatement(statement: string): Promise<any>;
|
|
88
98
|
deleteStatement(file: string, method: string, statement: string): Promise<any>;
|
|
89
99
|
saveStatement(statement: string, data: any): Promise<any>;
|
|
@@ -110,6 +120,7 @@ export declare class StellifyClient {
|
|
|
110
120
|
elements: string;
|
|
111
121
|
page?: string;
|
|
112
122
|
selection?: string;
|
|
123
|
+
file?: string;
|
|
113
124
|
test?: boolean;
|
|
114
125
|
}): Promise<any>;
|
|
115
126
|
getDirectory(uuid: string): Promise<any>;
|
package/dist/stellify-client.js
CHANGED
|
@@ -63,6 +63,11 @@ export class StellifyClient {
|
|
|
63
63
|
const response = await this.client.post('/statement', params);
|
|
64
64
|
return response.data;
|
|
65
65
|
}
|
|
66
|
+
// NEW: Combined create statement with code in a single call
|
|
67
|
+
async createStatementWithCode(params) {
|
|
68
|
+
const response = await this.client.post('/statement/with-code', params);
|
|
69
|
+
return response.data;
|
|
70
|
+
}
|
|
66
71
|
async getStatement(statement) {
|
|
67
72
|
const response = await this.client.get(`/statement/${statement}`);
|
|
68
73
|
return response.data;
|
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.27",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@stellisoft/stellify-mcp",
|
|
14
|
-
"version": "0.1.
|
|
14
|
+
"version": "0.1.27",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|