@almadar/skills 1.0.12 → 1.1.0
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.d.ts +86 -12
- package/dist/index.js +744 -392
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { generateBehaviorsDocs, getAllBehaviors, generateModulesDocs, getAllStdOperators } from '@almadar/std';
|
|
4
4
|
import { OPERATORS, UI_SLOTS, PATTERN_TYPES, ViewTypeSchema } from '@almadar/core/types';
|
|
5
|
-
import { getPatternPropsCompact, getPatternActionsRef, getAllPatternTypes
|
|
5
|
+
import { getPatternPropsCompact, getPatternActionsRef, getAllPatternTypes } from '@almadar/patterns';
|
|
6
6
|
|
|
7
7
|
// src/generators/utils.ts
|
|
8
8
|
function formatFrontmatter(fm) {
|
|
@@ -46,24 +46,6 @@ Writing ${skills.length} skills to ${baseDir}...`);
|
|
|
46
46
|
console.log(`
|
|
47
47
|
\u2713 Generated ${skills.length} skills`);
|
|
48
48
|
}
|
|
49
|
-
function getMinimalTypeReference() {
|
|
50
|
-
const patternsByCategory = getPatternsGroupedByCategory();
|
|
51
|
-
const categories = Object.keys(patternsByCategory);
|
|
52
|
-
return `## Type Reference
|
|
53
|
-
|
|
54
|
-
### Pattern Types
|
|
55
|
-
${categories.map((cat) => `- **${cat}**: ${patternsByCategory[cat].slice(0, 5).join(", ")}...`).join("\n")}
|
|
56
|
-
|
|
57
|
-
Total: ${PATTERN_TYPES.length} patterns
|
|
58
|
-
|
|
59
|
-
### Operators
|
|
60
|
-
Use S-expressions for guards and effects. See std library for full list.
|
|
61
|
-
|
|
62
|
-
**Math**: \`+\`, \`-\`, \`*\`, \`/\`, \`>\`, \`<\`, \`>=\`, \`<=\`, \`=\`, \`!=\`
|
|
63
|
-
**Logic**: \`and\`, \`or\`, \`not\`
|
|
64
|
-
**Effects**: \`set\`, \`++\`, \`--\`, \`persist\`, \`fetch\`, \`emit\`, \`render-ui\`
|
|
65
|
-
`;
|
|
66
|
-
}
|
|
67
49
|
function getSExprQuickRef() {
|
|
68
50
|
return `## S-Expression Syntax
|
|
69
51
|
|
|
@@ -134,20 +116,27 @@ ${mod.operators.map((op) => `- **${op.name}**: ${op.description}`).join("\n")}
|
|
|
134
116
|
}
|
|
135
117
|
function getStdBehaviorsWithStateMachines() {
|
|
136
118
|
const behaviors = getAllBehaviors();
|
|
137
|
-
const nonGameBehaviors = behaviors.filter(
|
|
138
|
-
|
|
139
|
-
|
|
119
|
+
const nonGameBehaviors = behaviors.filter((b) => {
|
|
120
|
+
const traits = b.orbitals?.[0]?.traits ?? [];
|
|
121
|
+
const hasGameCategory = traits.some((t) => t.category?.includes("game"));
|
|
122
|
+
const hasStateMachine = traits.some((t) => t.stateMachine);
|
|
123
|
+
return !hasGameCategory && hasStateMachine;
|
|
124
|
+
});
|
|
140
125
|
return `## Standard Behaviors
|
|
141
126
|
|
|
142
|
-
${nonGameBehaviors.map((behavior) =>
|
|
127
|
+
${nonGameBehaviors.map((behavior) => {
|
|
128
|
+
const trait = (behavior.orbitals?.[0]?.traits ?? []).find((t) => t.stateMachine);
|
|
129
|
+
const sm = trait?.stateMachine;
|
|
130
|
+
return `### ${behavior.name}
|
|
143
131
|
|
|
144
|
-
**States**: ${
|
|
145
|
-
**Events**: ${
|
|
132
|
+
**States**: ${sm?.states?.map((s) => s.name).join(", ") ?? "N/A"}
|
|
133
|
+
**Events**: ${sm?.events?.join(", ") ?? "N/A"}
|
|
146
134
|
|
|
147
135
|
\`\`\`json
|
|
148
136
|
${JSON.stringify(behavior, null, 2)}
|
|
149
137
|
\`\`\`
|
|
150
|
-
|
|
138
|
+
`;
|
|
139
|
+
}).join("\n\n")}
|
|
151
140
|
`;
|
|
152
141
|
}
|
|
153
142
|
function getKeyBehaviorsReference() {
|
|
@@ -273,35 +262,23 @@ function getValidViewTypes() {
|
|
|
273
262
|
const validTypes = ViewTypeSchema.options;
|
|
274
263
|
return validTypes.map((t) => `\`${t}\``).join(", ");
|
|
275
264
|
}
|
|
276
|
-
function getCommonErrorsSection() {
|
|
265
|
+
function getCommonErrorsSection(level = "full") {
|
|
266
|
+
const critical = getCriticalErrors();
|
|
267
|
+
if (level === "top6") return critical;
|
|
268
|
+
return critical + getEdgeCaseErrors();
|
|
269
|
+
}
|
|
270
|
+
function getCriticalErrors() {
|
|
277
271
|
return `## Critical Rules
|
|
278
272
|
|
|
279
|
-
###
|
|
280
|
-
|
|
281
|
-
The \`set\` effect modifies entity state. **@payload is READ-ONLY** - it contains event data.
|
|
282
|
-
|
|
283
|
-
\`\`\`json
|
|
284
|
-
// WRONG - @payload is read-only!
|
|
285
|
-
["set", "@payload.data.createdAt", "@now"]
|
|
286
|
-
["set", "@payload.data.status", "active"]
|
|
287
|
-
|
|
288
|
-
// CORRECT - Use @entity to modify state
|
|
289
|
-
["set", "@entity.createdAt", "@now"]
|
|
290
|
-
["set", "@entity.status", "active"]
|
|
291
|
-
\`\`\`
|
|
292
|
-
|
|
293
|
-
**Rule:** \`set\` target MUST start with \`@entity\`, never \`@payload\`.
|
|
294
|
-
|
|
295
|
-
### INIT Transition Required (CRITICAL)
|
|
273
|
+
### 1. INIT Transition Required (CRITICAL)
|
|
296
274
|
|
|
297
275
|
Every trait MUST have an INIT self-loop transition. The runtime fires \`INIT\` when page loads.
|
|
298
276
|
|
|
299
277
|
\`\`\`json
|
|
300
|
-
// REQUIRED in EVERY trait:
|
|
301
278
|
{
|
|
302
279
|
"from": "Browsing",
|
|
303
280
|
"to": "Browsing",
|
|
304
|
-
"event": "INIT",
|
|
281
|
+
"event": "INIT",
|
|
305
282
|
"effects": [
|
|
306
283
|
["render-ui", "main", { "type": "page-header", ... }],
|
|
307
284
|
["render-ui", "main", { "type": "entity-table", ... }]
|
|
@@ -311,43 +288,40 @@ Every trait MUST have an INIT self-loop transition. The runtime fires \`INIT\` w
|
|
|
311
288
|
|
|
312
289
|
Without INIT: Page loads blank, nothing renders, no UI appears.
|
|
313
290
|
|
|
314
|
-
###
|
|
291
|
+
### 2. NEVER Use @payload in set Effects
|
|
315
292
|
|
|
316
|
-
|
|
293
|
+
The \`set\` effect modifies entity state. **@payload is READ-ONLY**.
|
|
317
294
|
|
|
318
|
-
|
|
295
|
+
\`\`\`json
|
|
296
|
+
// WRONG
|
|
297
|
+
["set", "@payload.data.status", "active"]
|
|
319
298
|
|
|
320
|
-
|
|
299
|
+
// CORRECT
|
|
300
|
+
["set", "@entity.status", "active"]
|
|
301
|
+
\`\`\`
|
|
302
|
+
|
|
303
|
+
**Rule:** \`set\` target MUST start with \`@entity\`, never \`@payload\`.
|
|
321
304
|
|
|
322
|
-
### Valid
|
|
305
|
+
### 3. Valid Patterns ONLY
|
|
323
306
|
|
|
324
|
-
|
|
307
|
+
**DO NOT invent custom patterns!** Only these patterns exist:
|
|
325
308
|
|
|
326
|
-
|
|
309
|
+
${getPatternCategories()}
|
|
327
310
|
|
|
328
|
-
|
|
311
|
+
**NEVER use**: \`onboarding-welcome\`, \`category-selector\`, \`assessment-question\`, etc.
|
|
329
312
|
|
|
330
|
-
${
|
|
313
|
+
Valid viewType values: ${getValidViewTypes()}
|
|
331
314
|
|
|
332
|
-
### Page Structure Required
|
|
315
|
+
### 4. Page Structure Required
|
|
333
316
|
|
|
334
317
|
Every page MUST have \`path\` and \`traits\` properties:
|
|
335
318
|
|
|
336
319
|
\`\`\`json
|
|
337
|
-
// WRONG - missing path and traits:
|
|
338
320
|
{
|
|
339
321
|
"pages": [{
|
|
340
322
|
"name": "TasksPage",
|
|
341
|
-
"
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// CORRECT - complete page definition:
|
|
346
|
-
{
|
|
347
|
-
"pages": [{
|
|
348
|
-
"name": "TasksPage",
|
|
349
|
-
"path": "/tasks", // \u2190 REQUIRED: starts with /
|
|
350
|
-
"traits": [{ "ref": "TaskManagement" }] // \u2190 REQUIRED: trait-driven UI
|
|
323
|
+
"path": "/tasks",
|
|
324
|
+
"traits": [{ "ref": "TaskManagement" }]
|
|
351
325
|
}]
|
|
352
326
|
}
|
|
353
327
|
\`\`\`
|
|
@@ -355,232 +329,119 @@ Every page MUST have \`path\` and \`traits\` properties:
|
|
|
355
329
|
Without \`path\`: Validation error \`ORB_P_MISSING_PATH\`
|
|
356
330
|
Without \`traits\`: Validation error \`ORB_P_MISSING_TRAITS\`
|
|
357
331
|
|
|
358
|
-
### Valid Field Types ONLY
|
|
332
|
+
### 5. Valid Field Types ONLY
|
|
359
333
|
|
|
360
334
|
Field types MUST be one of: \`string\`, \`number\`, \`boolean\`, \`date\`, \`timestamp\`, \`datetime\`, \`array\`, \`object\`, \`enum\`, \`relation\`
|
|
361
335
|
|
|
362
336
|
\`\`\`json
|
|
363
337
|
// WRONG - using entity name as type:
|
|
364
|
-
{ "name": "author", "type": "User" }
|
|
365
|
-
{ "name": "post", "type": "BlogPost" } // \u274C Invalid!
|
|
338
|
+
{ "name": "author", "type": "User" }
|
|
366
339
|
|
|
367
|
-
// CORRECT - use relation type
|
|
340
|
+
// CORRECT - use relation type:
|
|
368
341
|
{ "name": "author", "type": "relation", "relation": { "entity": "User", "cardinality": "one" } }
|
|
369
|
-
{ "name": "post", "type": "relation", "relation": { "entity": "BlogPost", "cardinality": "one" } }
|
|
370
|
-
|
|
371
|
-
// CORRECT for arrays of primitives:
|
|
372
|
-
{ "name": "tags", "type": "array", "items": { "type": "string" } }
|
|
373
|
-
|
|
374
|
-
// CORRECT for enums:
|
|
375
|
-
{ "name": "status", "type": "enum", "values": ["pending", "active", "done"] }
|
|
376
342
|
\`\`\`
|
|
377
343
|
|
|
378
|
-
###
|
|
344
|
+
### 6. Modal State Machine Pattern
|
|
379
345
|
|
|
380
|
-
|
|
346
|
+
When a transition opens a modal/drawer, the target state MUST have CLOSE and CANCEL transitions:
|
|
381
347
|
|
|
382
348
|
\`\`\`json
|
|
383
|
-
|
|
384
|
-
{
|
|
385
|
-
|
|
386
|
-
"
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
"traits": [{
|
|
392
|
-
"name": "TaskInteraction",
|
|
393
|
-
"listens": [
|
|
394
|
-
{ "event": "USER_UPDATED", "handler": "REFRESH_LIST" } // \u2705 Object format
|
|
395
|
-
]
|
|
396
|
-
}]
|
|
397
|
-
}
|
|
349
|
+
{ "from": "Browsing", "to": "Creating", "event": "CREATE",
|
|
350
|
+
"effects": [["render-ui", "modal", { "type": "form-section", "cancelEvent": "CANCEL", ... }]] },
|
|
351
|
+
{ "from": "Creating", "to": "Browsing", "event": "CANCEL",
|
|
352
|
+
"effects": [["render-ui", "modal", null]] },
|
|
353
|
+
{ "from": "Creating", "to": "Browsing", "event": "CLOSE",
|
|
354
|
+
"effects": [["render-ui", "modal", null]] },
|
|
355
|
+
{ "from": "Creating", "to": "Browsing", "event": "SAVE",
|
|
356
|
+
"effects": [["persist", "create", "Entity", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]] }
|
|
398
357
|
\`\`\`
|
|
399
358
|
|
|
359
|
+
**CLOSE** = user clicks outside modal/presses Escape. **CANCEL** = form cancel button. Both needed.
|
|
360
|
+
`;
|
|
361
|
+
}
|
|
362
|
+
function getEdgeCaseErrors() {
|
|
363
|
+
return `
|
|
400
364
|
---
|
|
401
365
|
|
|
402
|
-
##
|
|
403
|
-
|
|
404
|
-
### 1. Missing INIT Transition
|
|
405
|
-
\`\`\`
|
|
406
|
-
WRONG: No INIT transition \u2192 Page loads blank
|
|
407
|
-
CORRECT: { "from": "browsing", "to": "browsing", "event": "INIT", "effects": [...render-ui...] }
|
|
408
|
-
\`\`\`
|
|
366
|
+
## Additional Errors (Edge Cases)
|
|
409
367
|
|
|
410
|
-
###
|
|
368
|
+
### 7. Over-Generating Pages
|
|
411
369
|
\`\`\`
|
|
412
370
|
WRONG: TaskListPage, TaskCreatePage, TaskEditPage, TaskViewPage (4 pages!)
|
|
413
371
|
CORRECT: TasksPage with EntityManagement trait (1 page)
|
|
414
372
|
\`\`\`
|
|
415
373
|
|
|
416
|
-
###
|
|
374
|
+
### 8. Duplicate Slot Rendering
|
|
417
375
|
\`\`\`
|
|
418
376
|
WRONG: Two traits both render to "main" on page load
|
|
419
377
|
CORRECT: ONE trait owns each slot
|
|
420
378
|
\`\`\`
|
|
421
379
|
|
|
422
|
-
###
|
|
380
|
+
### 9. Missing onSubmit in form-section
|
|
423
381
|
\`\`\`
|
|
424
382
|
WRONG: { "type": "form-section", "entity": "Task" }
|
|
425
383
|
CORRECT: { "type": "form-section", "entity": "Task", "onSubmit": "SAVE" }
|
|
426
384
|
\`\`\`
|
|
427
385
|
|
|
428
|
-
###
|
|
386
|
+
### 10. Duplicate Transitions (Same from+event)
|
|
429
387
|
\`\`\`
|
|
430
388
|
WRONG: Two transitions with same "from" and "event" without guards
|
|
431
389
|
CORRECT: Use GUARDS to differentiate transitions
|
|
432
390
|
\`\`\`
|
|
433
391
|
|
|
434
|
-
###
|
|
392
|
+
### 11. Using "render" Instead of "render-ui"
|
|
435
393
|
\`\`\`
|
|
436
394
|
WRONG: ["render", "main", {...}]
|
|
437
395
|
CORRECT: ["render-ui", "main", {...}]
|
|
438
396
|
\`\`\`
|
|
439
397
|
|
|
440
|
-
###
|
|
398
|
+
### 12. Generating Sections Array (Legacy)
|
|
441
399
|
\`\`\`
|
|
442
400
|
WRONG: { "pages": [{ "sections": [...] }] }
|
|
443
401
|
CORRECT: { "pages": [{ "traits": [...] }] } - UI comes from render-ui effects
|
|
444
402
|
\`\`\`
|
|
445
403
|
|
|
446
|
-
###
|
|
404
|
+
### 13. Using form-actions Pattern (DOES NOT EXIST!)
|
|
447
405
|
\`\`\`
|
|
448
406
|
WRONG: ["render-ui", "main", { "type": "form-actions", "actions": [...] }]
|
|
449
|
-
CORRECT: Use form-section with onSubmit/onCancel props
|
|
450
|
-
{ "type": "form-section", "entity": "Task", "fields": [...], "onSubmit": "SAVE", "onCancel": "CANCEL" }
|
|
407
|
+
CORRECT: Use form-section with onSubmit/onCancel props
|
|
451
408
|
\`\`\`
|
|
452
|
-
Actions are INSIDE patterns, not separate patterns.
|
|
409
|
+
Actions are INSIDE patterns, not separate patterns.
|
|
453
410
|
|
|
454
|
-
###
|
|
411
|
+
### 14. Forgetting itemActions in entity-table
|
|
455
412
|
\`\`\`
|
|
456
|
-
WRONG: { "type": "entity-table", "entity": "Task" }
|
|
457
|
-
CORRECT: { "type": "entity-table", "entity": "Task", "itemActions": [{"label": "Edit", "event": "EDIT"}
|
|
413
|
+
WRONG: { "type": "entity-table", "entity": "Task" }
|
|
414
|
+
CORRECT: { "type": "entity-table", "entity": "Task", "itemActions": [{"label": "Edit", "event": "EDIT"}] }
|
|
458
415
|
\`\`\`
|
|
459
416
|
|
|
460
|
-
###
|
|
417
|
+
### 15. Duplicate Trait Names Across Orbitals
|
|
461
418
|
\`\`\`
|
|
462
419
|
WRONG: UserOrbital uses "EntityManagement", TaskOrbital uses "EntityManagement"
|
|
463
420
|
CORRECT: UserOrbital uses "UserManagement", TaskOrbital uses "TaskManagement"
|
|
464
421
|
\`\`\`
|
|
465
422
|
Each trait name MUST be unique. Pattern: \`{Entity}{Purpose}\`
|
|
466
423
|
|
|
467
|
-
###
|
|
468
|
-
\`\`\`
|
|
469
|
-
WRONG: ["set", "@payload.acceptedAt", "@now"] // @payload is read-only!
|
|
470
|
-
CORRECT: ["set", "@entity.acceptedAt", "@now"] // set modifies entity state
|
|
471
|
-
\`\`\`
|
|
472
|
-
\`set\` effect MUST use \`@entity.field\` binding. \`@payload\` is read-only event data.
|
|
473
|
-
|
|
474
|
-
### 12. Hallucinated itemAction Properties
|
|
424
|
+
### 16. Hallucinated itemAction Properties
|
|
475
425
|
\`\`\`
|
|
476
|
-
WRONG: { "label": "View", "event": "VIEW", "condition": "
|
|
477
|
-
CORRECT: { "label": "View", "event": "VIEW"
|
|
426
|
+
WRONG: { "label": "View", "event": "VIEW", "condition": "..." }
|
|
427
|
+
CORRECT: { "label": "View", "event": "VIEW" }
|
|
478
428
|
\`\`\`
|
|
479
429
|
Valid itemAction props: \`label\`, \`event\`, \`navigatesTo\`, \`placement\`, \`variant\`, \`showWhen\`
|
|
480
|
-
Note: \`showWhen\` is defined but NOT yet implemented - actions always visible.
|
|
481
|
-
|
|
482
|
-
### 14. Missing Page Path
|
|
483
|
-
\`\`\`
|
|
484
|
-
WRONG: { "pages": [{ "name": "TasksPage", "entity": "Task" }] }
|
|
485
|
-
CORRECT: { "pages": [{ "name": "TasksPage", "path": "/tasks", "traits": [...] }] }
|
|
486
|
-
\`\`\`
|
|
487
430
|
|
|
488
|
-
###
|
|
489
|
-
|
|
490
|
-
WRONG: { "name": "author", "type": "User" }
|
|
491
|
-
CORRECT: { "name": "author", "type": "relation", "relation": { "entity": "User", "cardinality": "one" } }
|
|
492
|
-
\`\`\`
|
|
493
|
-
|
|
494
|
-
### 16. Missing Traits Array on Page
|
|
495
|
-
\`\`\`
|
|
496
|
-
WRONG: { "pages": [{ "name": "TasksPage", "path": "/tasks" }] }
|
|
497
|
-
CORRECT: { "pages": [{ "name": "TasksPage", "path": "/tasks", "traits": [{ "ref": "TaskManagement" }] }] }
|
|
498
|
-
\`\`\`
|
|
499
|
-
|
|
500
|
-
### 13. Modal State Machine Pattern (CRITICAL)
|
|
501
|
-
|
|
502
|
-
When a transition opens a modal (renders to \`modal\` or \`drawer\` slot), the target state MUST have:
|
|
503
|
-
1. A **CLOSE** transition to clear the modal and return to browsing state
|
|
504
|
-
2. A **CANCEL** transition (for forms with cancel buttons)
|
|
505
|
-
3. The CLOSE/CANCEL effects MUST include \`["render-ui", "modal", null]\` to clear the slot
|
|
506
|
-
|
|
507
|
-
\`\`\`json
|
|
508
|
-
// WRONG - Modal opens but no way to close it!
|
|
509
|
-
{
|
|
510
|
-
"from": "browsing", "to": "creating", "event": "CREATE",
|
|
511
|
-
"effects": [["render-ui", "modal", { "type": "form-section", ... }]]
|
|
512
|
-
}
|
|
513
|
-
// No CLOSE or CANCEL transition from "creating" \u2192 Page gets stuck!
|
|
514
|
-
|
|
515
|
-
// CORRECT - Full modal open/close cycle:
|
|
516
|
-
{
|
|
517
|
-
"from": "browsing", "to": "creating", "event": "CREATE",
|
|
518
|
-
"effects": [["render-ui", "modal", { "type": "form-section", "cancelEvent": "CANCEL", ... }]]
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
"from": "creating", "to": "browsing", "event": "CANCEL",
|
|
522
|
-
"effects": [["render-ui", "modal", null]]
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
"from": "creating", "to": "browsing", "event": "CLOSE",
|
|
526
|
-
"effects": [["render-ui", "modal", null]]
|
|
527
|
-
},
|
|
528
|
-
{
|
|
529
|
-
"from": "creating", "to": "browsing", "event": "SAVE",
|
|
530
|
-
"effects": [
|
|
531
|
-
["persist", "create", "Entity", "@payload.data"],
|
|
532
|
-
["render-ui", "modal", null], // \u2190 IMPORTANT: Clear modal on save too!
|
|
533
|
-
["fetch", "Entity", {}]
|
|
534
|
-
]
|
|
535
|
-
}
|
|
536
|
-
\`\`\`
|
|
537
|
-
|
|
538
|
-
**Why CLOSE is needed:** The UI sends \`CLOSE\` when user clicks outside the modal or presses Escape.
|
|
539
|
-
**Why CANCEL is needed:** Forms emit \`CANCEL\` when user clicks the Cancel button.
|
|
540
|
-
**Both are needed** for complete modal behavior. Without them, the modal cannot be dismissed and reopened.
|
|
541
|
-
|
|
542
|
-
### 14. Wrong Filtering Pattern (Use Query Singleton)
|
|
543
|
-
\`\`\`
|
|
544
|
-
WRONG: Individual filter buttons with manual FILTER events
|
|
545
|
-
{ "type": "button", "label": "Active", "action": "FILTER", "data": { "status": "active" } }
|
|
546
|
-
|
|
547
|
-
CORRECT: Use Query Singleton entity + filter-group pattern:
|
|
548
|
-
\`\`\`
|
|
549
|
-
|
|
550
|
-
**Query Singleton Pattern for Filtering:**
|
|
551
|
-
|
|
552
|
-
1. Define a singleton entity to hold filter state:
|
|
553
|
-
\`\`\`json
|
|
554
|
-
{
|
|
555
|
-
"name": "TaskQuery",
|
|
556
|
-
"entity": {
|
|
557
|
-
"name": "TaskQuery",
|
|
558
|
-
"singleton": true,
|
|
559
|
-
"runtime": true,
|
|
560
|
-
"fields": [
|
|
561
|
-
{ "name": "status", "type": "string" },
|
|
562
|
-
{ "name": "search", "type": "string" }
|
|
563
|
-
]
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
\`\`\`
|
|
567
|
-
|
|
568
|
-
2. Use \`set\` effects to update filter state:
|
|
431
|
+
### 17. Event Listeners Structure
|
|
432
|
+
Event listeners go INSIDE traits, not at orbital level:
|
|
569
433
|
\`\`\`json
|
|
570
|
-
{
|
|
571
|
-
"
|
|
572
|
-
"effects": [["set", "@TaskQuery.status", "@payload.status"]]
|
|
573
|
-
}
|
|
434
|
+
"traits": [{ "name": "TaskInteraction",
|
|
435
|
+
"listens": [{ "event": "USER_UPDATED", "handler": "REFRESH_LIST" }] }]
|
|
574
436
|
\`\`\`
|
|
575
437
|
|
|
576
|
-
|
|
438
|
+
### 18. Wrong Filtering Pattern (Use Query Singleton)
|
|
439
|
+
Use a singleton entity for filter state + \`query\` prop on entity-table:
|
|
577
440
|
\`\`\`json
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
"entity": "Task",
|
|
581
|
-
"query": "@TaskQuery"
|
|
582
|
-
}]
|
|
441
|
+
{ "name": "TaskQuery", "entity": { "name": "TaskQuery", "singleton": true, "runtime": true,
|
|
442
|
+
"fields": [{ "name": "status", "type": "string" }, { "name": "search", "type": "string" }] } }
|
|
583
443
|
\`\`\`
|
|
444
|
+
Reference: \`["render-ui", "main", { "type": "entity-table", "entity": "Task", "query": "@TaskQuery" }]\`
|
|
584
445
|
`;
|
|
585
446
|
}
|
|
586
447
|
function getValidationHintsSection() {
|
|
@@ -699,6 +560,78 @@ function getDecompositionChecklist() {
|
|
|
699
560
|
- [ ] emits/listens defined for cross-orbital events
|
|
700
561
|
`;
|
|
701
562
|
}
|
|
563
|
+
function getDecompositionCompact() {
|
|
564
|
+
return `## Orbital Decomposition Protocol
|
|
565
|
+
|
|
566
|
+
### Step 0: Classify Domain
|
|
567
|
+
| Domain | Keywords | Key Traits |
|
|
568
|
+
|--------|----------|------------|
|
|
569
|
+
| business | manage, track, workflow | EntityManagement, SearchAndFilter |
|
|
570
|
+
| game | play, score, level | Physics2D, Health, GameState |
|
|
571
|
+
| form | wizard, onboarding | Wizard, FormSubmission |
|
|
572
|
+
| dashboard | metrics, KPI | EntityManagement |
|
|
573
|
+
| content | blog, CMS | none (page navigation) |
|
|
574
|
+
|
|
575
|
+
### Step 1: Identify Entities (ONE Orbital Per Entity)
|
|
576
|
+
- What are the core data objects?
|
|
577
|
+
- persistent (DB), runtime (memory), or singleton (config)?
|
|
578
|
+
- **CRITICAL: Create exactly ONE orbital per entity**
|
|
579
|
+
|
|
580
|
+
### Step 2: Select Interaction Model
|
|
581
|
+
| Domain | Create | View | Edit | Delete |
|
|
582
|
+
|--------|--------|------|------|--------|
|
|
583
|
+
| business | modal | drawer | modal | confirm |
|
|
584
|
+
| game | none | none | none | none |
|
|
585
|
+
| form | wizard | drawer | page | confirm |
|
|
586
|
+
|
|
587
|
+
### Step 3: Choose Traits
|
|
588
|
+
- Business: EntityManagement (handles CRUD via render-ui)
|
|
589
|
+
- Game: Physics2D, Health, Score, Collision
|
|
590
|
+
- Form: Wizard (multi-step) or FormSubmission (single)
|
|
591
|
+
|
|
592
|
+
### Step 4: Define State Machine
|
|
593
|
+
\`\`\`
|
|
594
|
+
states: Identify user-facing modes (browsing, creating, editing, viewing)
|
|
595
|
+
events: Identify user actions (INIT, CREATE, VIEW, EDIT, SAVE, CLOSE)
|
|
596
|
+
transitions: Map (from, event) \u2192 (to, effects)
|
|
597
|
+
\`\`\`
|
|
598
|
+
|
|
599
|
+
### Step 5: Add INIT Transition (CRITICAL)
|
|
600
|
+
Every trait MUST have an INIT self-loop with render-ui effects. Without INIT, the page loads blank!
|
|
601
|
+
|
|
602
|
+
### Step 6: Define Pages
|
|
603
|
+
- ONE page per entity (business) or workflow (form)
|
|
604
|
+
- Attach traits to pages via \`traits\` array
|
|
605
|
+
- Add \`"guard"\` (singular) S-expressions on SAVE transitions for business rules
|
|
606
|
+
`;
|
|
607
|
+
}
|
|
608
|
+
function getConnectivityCompact() {
|
|
609
|
+
return `## Orbital Connectivity
|
|
610
|
+
|
|
611
|
+
For multi-entity apps, connect orbitals:
|
|
612
|
+
|
|
613
|
+
\`\`\`json
|
|
614
|
+
{
|
|
615
|
+
"entity": {
|
|
616
|
+
"fields": [
|
|
617
|
+
{ "name": "customerId", "type": "relation", "relation": { "entity": "Customer", "cardinality": "one" } }
|
|
618
|
+
]
|
|
619
|
+
},
|
|
620
|
+
"emits": ["ORDER_COMPLETED"],
|
|
621
|
+
"listens": [{ "event": "MENU_ITEM_UNAVAILABLE", "triggers": "DISABLE_ITEM" }],
|
|
622
|
+
"design": {
|
|
623
|
+
"uxHints": {
|
|
624
|
+
"relatedLinks": [{ "relation": "customerId", "label": "View Customer", "targetView": "detail" }]
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
\`\`\`
|
|
629
|
+
|
|
630
|
+
- **relation fields**: Link entities (Order \u2192 Customer)
|
|
631
|
+
- **emits/listens**: Cross-orbital event communication
|
|
632
|
+
- **relatedLinks**: Navigation between related records
|
|
633
|
+
`;
|
|
634
|
+
}
|
|
702
635
|
function getFlowPatternSection() {
|
|
703
636
|
return `## Flow Pattern Selection
|
|
704
637
|
|
|
@@ -804,6 +737,151 @@ Orbitals communicate via events:
|
|
|
804
737
|
- Add relatedLinks for navigation between related records
|
|
805
738
|
`;
|
|
806
739
|
}
|
|
740
|
+
function getRenderUIDesignGuide() {
|
|
741
|
+
return `## Render-UI Design Guide
|
|
742
|
+
|
|
743
|
+
### Syntax
|
|
744
|
+
\`["render-ui", slot, { "type": pattern, ...props }]\`
|
|
745
|
+
Clear slot: \`["render-ui", "modal", null]\`
|
|
746
|
+
|
|
747
|
+
### Slot Strategy
|
|
748
|
+
| Slot | Use For | Composable? |
|
|
749
|
+
|------|---------|-------------|
|
|
750
|
+
| \`main\` | Primary content | **YES** \u2014 stack multiple render-ui calls |
|
|
751
|
+
| \`modal\` | Forms (create/edit), confirmations | One at a time |
|
|
752
|
+
| \`drawer\` | Detail views, quick edits | One at a time |
|
|
753
|
+
| \`sidebar\` | Navigation, persistent filters | One at a time |
|
|
754
|
+
| \`overlay\` | Confirmations, alerts | One at a time |
|
|
755
|
+
|
|
756
|
+
### Pattern Selection by Intent
|
|
757
|
+
| Intent | Patterns | Key Props |
|
|
758
|
+
|--------|----------|-----------|
|
|
759
|
+
| List/browse data | \`entity-table\`, \`entity-cards\`, \`entity-list\` | columns, itemActions, searchable |
|
|
760
|
+
| Show metrics/KPIs | \`stats\` | metrics: [{label, value, icon, trend}] |
|
|
761
|
+
| Filter/search | \`filter-group\`, \`search-input\` | filters (from entity enum fields) |
|
|
762
|
+
| Create/edit form | \`form-section\` | fields, submitEvent, cancelEvent |
|
|
763
|
+
| View details | \`entity-detail\`, \`detail-panel\` | fields/fieldNames, actions |
|
|
764
|
+
| Organize content | \`tabs\` | tabs: [{label, content}] |
|
|
765
|
+
| Dashboard layout | \`dashboard-grid\` | columns (number) |
|
|
766
|
+
| Charts | \`chart\` | chartType, data, xAxis, yAxis |
|
|
767
|
+
| Progress | \`progress-bar\`, \`meter\` | value, max, label |
|
|
768
|
+
| Timeline | \`timeline\` | items: [{date, title, description}] |
|
|
769
|
+
| Page heading | \`page-header\` | title, subtitle, actions |
|
|
770
|
+
| Confirmation | \`confirmation\` | title, message, onConfirm, onCancel |
|
|
771
|
+
| Master/detail | \`master-detail\` | Split list + detail |
|
|
772
|
+
| Cards grid | \`entity-cards\` | columns, itemActions, layout |
|
|
773
|
+
|
|
774
|
+
### Composition Recipes
|
|
775
|
+
|
|
776
|
+
**CRUD Browsing INIT** (most common \u2014 compose ALL of these in main slot):
|
|
777
|
+
\`\`\`json
|
|
778
|
+
["render-ui", "main", { "type": "page-header", "title": "Tasks", "subtitle": "Manage your tasks", "actions": [{ "label": "New Task", "event": "CREATE", "variant": "primary" }] }],
|
|
779
|
+
["render-ui", "main", { "type": "stats", "entity": "Task", "metrics": [{ "label": "Total", "value": "@count", "icon": "clipboard" }, { "label": "Active", "value": "@count:status=active", "icon": "clock" }, { "label": "Done", "value": "@count:status=done", "icon": "check-circle" }] }],
|
|
780
|
+
["render-ui", "main", { "type": "entity-table", "entity": "Task", "columns": ["title", "status", "createdAt"], "searchable": true, "itemActions": [{ "label": "View", "event": "VIEW" }, { "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE" }] }]
|
|
781
|
+
\`\`\`
|
|
782
|
+
|
|
783
|
+
**Dashboard INIT**:
|
|
784
|
+
\`\`\`
|
|
785
|
+
main: page-header \u2192 title + date range actions
|
|
786
|
+
main: dashboard-grid \u2192 columns: 3
|
|
787
|
+
main: stats \u2192 computed KPIs from entity counts
|
|
788
|
+
main: chart \u2192 primary data visualization
|
|
789
|
+
main: entity-cards \u2192 recent items (limit: 6)
|
|
790
|
+
\`\`\`
|
|
791
|
+
|
|
792
|
+
**Detail View (drawer)**:
|
|
793
|
+
\`\`\`
|
|
794
|
+
drawer: entity-detail \u2192 all fields + [Edit, Delete] actions
|
|
795
|
+
drawer: tabs \u2192 related collections (if entity has relation fields)
|
|
796
|
+
\`\`\`
|
|
797
|
+
|
|
798
|
+
**Wizard Flow**:
|
|
799
|
+
\`\`\`
|
|
800
|
+
main: wizard-progress \u2192 steps array + currentStep
|
|
801
|
+
main: wizard-container \u2192 current step content
|
|
802
|
+
main: wizard-navigation \u2192 Back/Next/Submit buttons
|
|
803
|
+
\`\`\`
|
|
804
|
+
|
|
805
|
+
### Layout Composition (stack, box, grid)
|
|
806
|
+
|
|
807
|
+
Layout patterns wrap other patterns via \`children\` arrays for rich, structured views.
|
|
808
|
+
|
|
809
|
+
**VStack** (vertical stack): \`{ "type": "stack", "direction": "vertical", ... }\`
|
|
810
|
+
**HStack** (horizontal stack): \`{ "type": "stack", "direction": "horizontal", ... }\`
|
|
811
|
+
**Box** (styled container): \`{ "type": "box", ... }\`
|
|
812
|
+
|
|
813
|
+
#### Stack Props
|
|
814
|
+
| Prop | Values | Default |
|
|
815
|
+
|------|--------|---------|
|
|
816
|
+
| \`direction\` | \`"vertical"\`, \`"horizontal"\` | \`"vertical"\` |
|
|
817
|
+
| \`gap\` | \`"none"\`, \`"xs"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"xl"\` | \`"md"\` |
|
|
818
|
+
| \`align\` | \`"start"\`, \`"center"\`, \`"end"\`, \`"stretch"\` | \`"stretch"\` |
|
|
819
|
+
| \`justify\` | \`"start"\`, \`"center"\`, \`"end"\`, \`"between"\`, \`"around"\` | \`"start"\` |
|
|
820
|
+
| \`wrap\` | \`true\`, \`false\` | \`false\` |
|
|
821
|
+
|
|
822
|
+
#### Box Props
|
|
823
|
+
| Prop | Values |
|
|
824
|
+
|------|--------|
|
|
825
|
+
| \`padding\` / \`paddingX\` / \`paddingY\` | \`"none"\`, \`"xs"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"xl"\` |
|
|
826
|
+
| \`bg\` | \`"default"\`, \`"muted"\`, \`"card"\`, \`"primary"\`, \`"secondary"\`, \`"accent"\` |
|
|
827
|
+
| \`border\` | \`true\`, \`false\` |
|
|
828
|
+
| \`rounded\` | \`"none"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"full"\` |
|
|
829
|
+
| \`shadow\` | \`"none"\`, \`"sm"\`, \`"md"\`, \`"lg"\` |
|
|
830
|
+
|
|
831
|
+
#### Grid Props
|
|
832
|
+
| Prop | Values |
|
|
833
|
+
|------|--------|
|
|
834
|
+
| \`cols\` | \`1\`\u2013\`12\` or \`{ sm: 1, md: 2, lg: 3 }\` |
|
|
835
|
+
| \`gap\` | \`"none"\`, \`"xs"\`, \`"sm"\`, \`"md"\`, \`"lg"\`, \`"xl"\` |
|
|
836
|
+
|
|
837
|
+
#### Nesting Example \u2014 Page Header + Stats Row + Table
|
|
838
|
+
\`\`\`json
|
|
839
|
+
["render-ui", "main", {
|
|
840
|
+
"type": "stack", "direction": "vertical", "gap": "lg",
|
|
841
|
+
"children": [
|
|
842
|
+
{ "type": "stack", "direction": "horizontal", "justify": "between", "align": "center",
|
|
843
|
+
"children": [
|
|
844
|
+
{ "type": "typography", "variant": "h1", "text": "Orders" },
|
|
845
|
+
{ "type": "button", "label": "New Order", "event": "CREATE", "variant": "primary" }
|
|
846
|
+
]
|
|
847
|
+
},
|
|
848
|
+
{ "type": "stack", "direction": "horizontal", "gap": "md", "wrap": true,
|
|
849
|
+
"children": [
|
|
850
|
+
{ "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
|
|
851
|
+
"children": [{ "type": "stats", "metrics": [{ "label": "Total", "value": "@count" }] }]
|
|
852
|
+
},
|
|
853
|
+
{ "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
|
|
854
|
+
"children": [{ "type": "stats", "metrics": [{ "label": "Pending", "value": "@count:status=pending" }] }]
|
|
855
|
+
}
|
|
856
|
+
]
|
|
857
|
+
},
|
|
858
|
+
{ "type": "entity-table", "entity": "Order", "columns": ["customer", "total", "status"], "searchable": true }
|
|
859
|
+
]
|
|
860
|
+
}]
|
|
861
|
+
\`\`\`
|
|
862
|
+
|
|
863
|
+
#### When to Use Layout Patterns
|
|
864
|
+
- **VStack**: Default page layout \u2014 stack header, content sections, tables vertically
|
|
865
|
+
- **HStack**: Side-by-side elements \u2014 stat cards, action buttons, header with controls
|
|
866
|
+
- **Box**: Visual grouping \u2014 cards, panels, highlighted sections with borders/backgrounds
|
|
867
|
+
- **Grid**: Equal-width columns \u2014 dashboard cards, stat grids, gallery layouts
|
|
868
|
+
|
|
869
|
+
> **Tip**: A single \`render-ui\` call with a top-level \`stack\` containing nested children produces a more cohesive layout than multiple flat \`render-ui\` calls to the same slot.
|
|
870
|
+
|
|
871
|
+
### Domain-Aware Pattern Selection
|
|
872
|
+
| Domain | List Pattern | Extras |
|
|
873
|
+
|--------|-------------|--------|
|
|
874
|
+
| business/admin | \`entity-table\` (searchable) | \`stats\`, \`filter-group\` |
|
|
875
|
+
| e-commerce | \`entity-cards\` | \`stats\` (revenue), \`chart\` |
|
|
876
|
+
| content/CMS | \`entity-cards\` | \`tabs\`, \`media-gallery\` |
|
|
877
|
+
| dashboard | \`dashboard-grid\` | \`stats\`, \`chart\`, \`meter\`, \`timeline\` |
|
|
878
|
+
| workflow | \`entity-table\` | \`progress-bar\`, \`timeline\` |
|
|
879
|
+
|
|
880
|
+
${getPatternPropsCompact()}
|
|
881
|
+
|
|
882
|
+
${getPatternActionsRef()}
|
|
883
|
+
`;
|
|
884
|
+
}
|
|
807
885
|
|
|
808
886
|
// src/prompts/skill-sections/custom-traits.ts
|
|
809
887
|
function getCustomTraitSection() {
|
|
@@ -1889,13 +1967,16 @@ function generateLeanOrbitalSkill(options = {}) {
|
|
|
1889
1967
|
const {
|
|
1890
1968
|
includeExample = true,
|
|
1891
1969
|
includeToolWorkflow = true,
|
|
1892
|
-
includeStdLibrary =
|
|
1970
|
+
includeStdLibrary = false,
|
|
1893
1971
|
stdLibraryFull = false,
|
|
1894
|
-
includeStdStateMachines =
|
|
1895
|
-
includeSchemaUpdates =
|
|
1972
|
+
includeStdStateMachines = false,
|
|
1973
|
+
includeSchemaUpdates = false,
|
|
1974
|
+
includeCustomTraits = false,
|
|
1975
|
+
errorLevel = "top6",
|
|
1976
|
+
includeDesignGuide = true
|
|
1896
1977
|
} = options;
|
|
1897
1978
|
let stdSection = "";
|
|
1898
|
-
if (includeStdLibrary) {
|
|
1979
|
+
if (includeStdLibrary || includeStdStateMachines) {
|
|
1899
1980
|
if (includeStdStateMachines) {
|
|
1900
1981
|
stdSection = `---
|
|
1901
1982
|
|
|
@@ -1917,6 +1998,8 @@ ${getStdMinimalReference()}
|
|
|
1917
1998
|
`;
|
|
1918
1999
|
}
|
|
1919
2000
|
}
|
|
2001
|
+
const decompositionSection = includeStdStateMachines || includeCustomTraits ? getDecompositionSection() : getDecompositionCompact();
|
|
2002
|
+
const connectivitySection = includeStdStateMachines || includeCustomTraits ? getOrbitalConnectivitySection() : getConnectivityCompact();
|
|
1920
2003
|
return `# Orbital Generation Skill
|
|
1921
2004
|
|
|
1922
2005
|
> Generate Orbital applications using Orbital Units: Entity \xD7 Traits \xD7 Patterns
|
|
@@ -1925,15 +2008,11 @@ ${getArchitectureSection()}
|
|
|
1925
2008
|
|
|
1926
2009
|
---
|
|
1927
2010
|
|
|
1928
|
-
${getMinimalTypeReference()}
|
|
1929
|
-
|
|
1930
|
-
---
|
|
1931
|
-
|
|
1932
2011
|
${getSExprQuickRef()}
|
|
1933
2012
|
|
|
1934
2013
|
---
|
|
1935
2014
|
|
|
1936
|
-
${
|
|
2015
|
+
${includeDesignGuide ? getRenderUIDesignGuide() : ""}
|
|
1937
2016
|
|
|
1938
2017
|
${stdSection}
|
|
1939
2018
|
---
|
|
@@ -1942,7 +2021,7 @@ ${getFlowPatternSection()}
|
|
|
1942
2021
|
|
|
1943
2022
|
---
|
|
1944
2023
|
|
|
1945
|
-
${
|
|
2024
|
+
${decompositionSection}
|
|
1946
2025
|
|
|
1947
2026
|
---
|
|
1948
2027
|
|
|
@@ -1950,7 +2029,7 @@ ${getPortableOrbitalOutputSection()}
|
|
|
1950
2029
|
|
|
1951
2030
|
---
|
|
1952
2031
|
|
|
1953
|
-
${
|
|
2032
|
+
${connectivitySection}
|
|
1954
2033
|
|
|
1955
2034
|
---
|
|
1956
2035
|
|
|
@@ -1958,12 +2037,12 @@ ${getContextUsageCompact()}
|
|
|
1958
2037
|
|
|
1959
2038
|
---
|
|
1960
2039
|
|
|
1961
|
-
${getCommonErrorsSection()}
|
|
2040
|
+
${getCommonErrorsSection(errorLevel)}
|
|
1962
2041
|
|
|
1963
|
-
|
|
2042
|
+
${includeCustomTraits ? `---
|
|
1964
2043
|
|
|
1965
2044
|
${getCustomTraitSection()}
|
|
1966
|
-
|
|
2045
|
+
` : ""}
|
|
1967
2046
|
${includeToolWorkflow ? getToolWorkflowSection() : ""}
|
|
1968
2047
|
|
|
1969
2048
|
${includeSchemaUpdates ? `---
|
|
@@ -2024,17 +2103,67 @@ function getToolWorkflowSection() {
|
|
|
2024
2103
|
|
|
2025
2104
|
## Tool Workflow
|
|
2026
2105
|
|
|
2027
|
-
1
|
|
2028
|
-
|
|
2029
|
-
|
|
2106
|
+
### Phase 1: DECOMPOSE
|
|
2107
|
+
Break requirements into OrbitalUnits (pure reasoning, no tools).
|
|
2108
|
+
|
|
2109
|
+
### Phase 2: GENERATE
|
|
2110
|
+
Call \`generate_orbital\` for each orbital:
|
|
2030
2111
|
|
|
2031
2112
|
\`\`\`
|
|
2032
2113
|
generate_orbital({ orbital: {...}, orbitalIndex: 0, totalOrbitals: N })
|
|
2033
2114
|
generate_orbital({ orbital: {...}, orbitalIndex: 1, totalOrbitals: N })
|
|
2034
2115
|
...
|
|
2035
|
-
construct_combined_schema({ name: "App", description: "..." })
|
|
2036
|
-
# STOP HERE - job is done
|
|
2037
2116
|
\`\`\`
|
|
2117
|
+
|
|
2118
|
+
Each orbital is written to \`.orbitals/<name>.json\` with ALL effects (render-ui, persist, emit, set, etc.).
|
|
2119
|
+
|
|
2120
|
+
### Phase 3: COMBINE
|
|
2121
|
+
Call \`finish_task\` to auto-combine and validate:
|
|
2122
|
+
|
|
2123
|
+
\`\`\`
|
|
2124
|
+
finish_task({ appName: "App" })
|
|
2125
|
+
# Reads .orbitals/*.json \u2192 schema.json \u2192 orbital validate
|
|
2126
|
+
\`\`\`
|
|
2127
|
+
|
|
2128
|
+
### Phase 4: DESIGN REFINEMENT (optional but recommended)
|
|
2129
|
+
|
|
2130
|
+
After \`finish_task\` produces \`schema.json\`, enhance key transitions with \`design_transition\`.
|
|
2131
|
+
|
|
2132
|
+
**When to use**: INIT transitions (they benefit most from rich composition \u2014 header + stats + content), and CREATE/VIEW transitions for polished forms and detail views.
|
|
2133
|
+
|
|
2134
|
+
**Step-by-step:**
|
|
2135
|
+
|
|
2136
|
+
1. Call \`design_transition\` for the transition:
|
|
2137
|
+
\`\`\`json
|
|
2138
|
+
{
|
|
2139
|
+
"from": "Browsing", "to": "Browsing", "event": "INIT",
|
|
2140
|
+
"slot": "main", "entityName": "Task",
|
|
2141
|
+
"entityFields": [{"name": "title", "type": "string"}, {"name": "status", "type": "enum", "values": ["pending", "active", "done"]}],
|
|
2142
|
+
"domainCategory": "business"
|
|
2143
|
+
}
|
|
2144
|
+
\`\`\`
|
|
2145
|
+
Returns: \`{ "success": true, "effects": [["render-ui", "main", {...}], ...] }\`
|
|
2146
|
+
|
|
2147
|
+
2. Extract the orbital chunk:
|
|
2148
|
+
\`\`\`json
|
|
2149
|
+
{ "file": "schema.json", "type": "orbital", "name": "Task Management" }
|
|
2150
|
+
\`\`\`
|
|
2151
|
+
|
|
2152
|
+
3. Edit the chunk file: replace render-ui effects in the target transition with the designed effects. **Keep all non-render-ui effects** (persist, emit, set) \u2014 only replace the render-ui tuples.
|
|
2153
|
+
|
|
2154
|
+
4. Apply the chunk back:
|
|
2155
|
+
\`\`\`json
|
|
2156
|
+
{ "chunkId": "<id from extract_chunk>" }
|
|
2157
|
+
\`\`\`
|
|
2158
|
+
|
|
2159
|
+
**Splicing rule**: For a transition with mixed effects like:
|
|
2160
|
+
\`\`\`json
|
|
2161
|
+
[["persist", "create", "Task", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]]
|
|
2162
|
+
\`\`\`
|
|
2163
|
+
Keep \`persist\` and \`emit\`, replace \`render-ui\` with the designed effects.
|
|
2164
|
+
For INIT transitions (render-ui only), replace all effects.
|
|
2165
|
+
|
|
2166
|
+
**Skip design_transition for**: SAVE, CANCEL, CONFIRM_DELETE transitions (they have persist/emit effects with simple slot-clearing \u2014 no UI to design).
|
|
2038
2167
|
`;
|
|
2039
2168
|
}
|
|
2040
2169
|
function getMinimalExample() {
|
|
@@ -2072,8 +2201,9 @@ function getMinimalExample() {
|
|
|
2072
2201
|
{
|
|
2073
2202
|
"from": "Browsing", "to": "Browsing", "event": "INIT",
|
|
2074
2203
|
"effects": [
|
|
2075
|
-
["render-ui", "main", { "type": "page-header", "title": "Tasks", "actions": [{ "label": "New Task", "event": "CREATE", "variant": "primary" }] }],
|
|
2076
|
-
["render-ui", "main", { "type": "
|
|
2204
|
+
["render-ui", "main", { "type": "page-header", "title": "Tasks", "subtitle": "Manage your tasks", "actions": [{ "label": "New Task", "event": "CREATE", "variant": "primary" }] }],
|
|
2205
|
+
["render-ui", "main", { "type": "stats", "entity": "Task", "metrics": [{ "label": "Total", "value": "@count", "icon": "clipboard" }, { "label": "Active", "value": "@count:status=active", "icon": "clock" }, { "label": "Done", "value": "@count:status=done", "icon": "check-circle" }] }],
|
|
2206
|
+
["render-ui", "main", { "type": "entity-table", "entity": "Task", "columns": ["title", "status"], "searchable": true, "itemActions": [{ "label": "View", "event": "VIEW" }, { "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE" }] }]
|
|
2077
2207
|
]
|
|
2078
2208
|
},
|
|
2079
2209
|
{
|
|
@@ -2130,14 +2260,15 @@ function getMinimalExample() {
|
|
|
2130
2260
|
|
|
2131
2261
|
**Key points**:
|
|
2132
2262
|
- ONE page (TasksPage) not four (list/create/edit/view)
|
|
2133
|
-
- INIT transition
|
|
2263
|
+
- INIT transition composes **multiple patterns**: page-header + stats + entity-table
|
|
2134
2264
|
- States are OBJECTS with \`isInitial\` flag
|
|
2135
2265
|
- **Actions are INSIDE patterns (use unified props)**:
|
|
2136
2266
|
- \`page-header\` has \`actions: [{label, event, variant}]\`
|
|
2137
|
-
- \`entity-table\` has \`itemActions: [{label, event}]\`
|
|
2267
|
+
- \`entity-table\` has \`itemActions: [{label, event}]\` and \`searchable: true\`
|
|
2138
2268
|
- \`form-section\` has \`submitEvent\` and \`cancelEvent\` (NOT onSubmit/onCancel!)
|
|
2139
2269
|
- \`entity-detail\` has \`actions\` (NOT headerActions!)
|
|
2140
2270
|
- \`confirmation\` emits action events
|
|
2271
|
+
- \`stats\` has \`metrics: [{label, value, icon}]\`
|
|
2141
2272
|
- **NEVER use**: \`onSubmit\`, \`onCancel\`, \`headerActions\`, \`loading\` (use \`isLoading\`)
|
|
2142
2273
|
- NO separate "form-actions" pattern - it doesn't exist!
|
|
2143
2274
|
`;
|
|
@@ -2148,15 +2279,18 @@ function generateKflowOrbitalsSkill(compact = false) {
|
|
|
2148
2279
|
const frontmatter = {
|
|
2149
2280
|
name: "kflow-orbitals",
|
|
2150
2281
|
description: "Generate KFlow schemas using the Orbitals composition model. Decomposes applications into atomic Orbital Units (Entity x Traits x Patterns) with structural caching for efficiency.",
|
|
2151
|
-
allowedTools: ["Read", "Write", "Edit"],
|
|
2152
|
-
version: "
|
|
2153
|
-
//
|
|
2282
|
+
allowedTools: ["Read", "Write", "Edit", "generate_orbital", "design_transition", "finish_task", "query_schema_structure", "extract_chunk", "apply_chunk"],
|
|
2283
|
+
version: "4.1.0"
|
|
2284
|
+
// v4.1: design refinement workflow with design_transition
|
|
2154
2285
|
};
|
|
2155
2286
|
const content = generateLeanOrbitalSkill({
|
|
2156
2287
|
includeExample: true,
|
|
2157
2288
|
includeToolWorkflow: true,
|
|
2158
|
-
includeStdStateMachines:
|
|
2159
|
-
|
|
2289
|
+
includeStdStateMachines: false,
|
|
2290
|
+
includeSchemaUpdates: false,
|
|
2291
|
+
includeCustomTraits: false,
|
|
2292
|
+
errorLevel: "top6",
|
|
2293
|
+
includeDesignGuide: true
|
|
2160
2294
|
});
|
|
2161
2295
|
return {
|
|
2162
2296
|
name: "kflow-orbitals",
|
|
@@ -2201,10 +2335,6 @@ ${getArchitectureSection()}
|
|
|
2201
2335
|
|
|
2202
2336
|
---
|
|
2203
2337
|
|
|
2204
|
-
${getMinimalTypeReference()}
|
|
2205
|
-
|
|
2206
|
-
---
|
|
2207
|
-
|
|
2208
2338
|
${getSExprQuickRef()}
|
|
2209
2339
|
|
|
2210
2340
|
---
|
|
@@ -2225,7 +2355,11 @@ ${getOverGenerationSection()}` : ""}
|
|
|
2225
2355
|
|
|
2226
2356
|
---
|
|
2227
2357
|
|
|
2228
|
-
${getCommonErrorsSection()}
|
|
2358
|
+
${getCommonErrorsSection("full")}
|
|
2359
|
+
|
|
2360
|
+
---
|
|
2361
|
+
|
|
2362
|
+
${getCustomTraitSection()}
|
|
2229
2363
|
|
|
2230
2364
|
${includeSchemaUpdates ? `---
|
|
2231
2365
|
|
|
@@ -2476,9 +2610,356 @@ Output the complete updated domain language text.
|
|
|
2476
2610
|
content
|
|
2477
2611
|
};
|
|
2478
2612
|
}
|
|
2613
|
+
function getMinimalTypeReference() {
|
|
2614
|
+
return `
|
|
2615
|
+
## Orbital Schema Structure
|
|
2479
2616
|
|
|
2480
|
-
|
|
2481
|
-
|
|
2617
|
+
\`\`\`typescript
|
|
2618
|
+
interface OrbitalDefinition {
|
|
2619
|
+
name: string; // Entity name (PascalCase)
|
|
2620
|
+
entity: Entity; // Data model
|
|
2621
|
+
traits: TraitRef[]; // State machines (names or definitions)
|
|
2622
|
+
pages: Page[]; // Routes and views
|
|
2623
|
+
emits?: string[]; // Events this orbital emits
|
|
2624
|
+
listens?: EventListener[]; // Events this orbital listens to
|
|
2625
|
+
}
|
|
2626
|
+
\`\`\`
|
|
2627
|
+
|
|
2628
|
+
### Entity Fields
|
|
2629
|
+
|
|
2630
|
+
\`\`\`typescript
|
|
2631
|
+
{ name: "title", type: "string", required: true }
|
|
2632
|
+
{ name: "count", type: "number", default: 0 }
|
|
2633
|
+
{ name: "status", type: "enum", values: ["pending", "active", "done"] }
|
|
2634
|
+
{ name: "dueDate", type: "date" }
|
|
2635
|
+
\`\`\`
|
|
2636
|
+
|
|
2637
|
+
### Trait State Machine
|
|
2638
|
+
|
|
2639
|
+
\`\`\`typescript
|
|
2640
|
+
{
|
|
2641
|
+
states: [{ name: "Idle", isInitial: true }, { name: "Active" }],
|
|
2642
|
+
events: ["INIT", "ACTIVATE", "COMPLETE"],
|
|
2643
|
+
transitions: [
|
|
2644
|
+
{ from: "Idle", to: "Active", event: "ACTIVATE",
|
|
2645
|
+
guards: [["condition"]],
|
|
2646
|
+
effects: [["action"]] }
|
|
2647
|
+
]
|
|
2648
|
+
}
|
|
2649
|
+
\`\`\`
|
|
2650
|
+
`.trim();
|
|
2651
|
+
}
|
|
2652
|
+
function getPatternTypesCompact() {
|
|
2653
|
+
const patterns = getAllPatternTypes();
|
|
2654
|
+
return `
|
|
2655
|
+
## Available Pattern Types
|
|
2656
|
+
|
|
2657
|
+
${patterns.map((p) => `- \`${p}\``).join("\n")}
|
|
2658
|
+
|
|
2659
|
+
${getPatternPropsCompact()}
|
|
2660
|
+
`.trim();
|
|
2661
|
+
}
|
|
2662
|
+
function getSExprQuickRef2() {
|
|
2663
|
+
const operators = Object.keys(OPERATORS).slice(0, 15);
|
|
2664
|
+
return `
|
|
2665
|
+
## S-Expression Quick Reference
|
|
2666
|
+
|
|
2667
|
+
### Guard Expressions (Conditions)
|
|
2668
|
+
|
|
2669
|
+
\`\`\`typescript
|
|
2670
|
+
["=", "@entity.status", "active"] // Equality
|
|
2671
|
+
[">", "@entity.count", 0] // Greater than
|
|
2672
|
+
["and", ["cond1"], ["cond2"]] // Logical AND
|
|
2673
|
+
["or", ["cond1"], ["cond2"]] // Logical OR
|
|
2674
|
+
["not", ["condition"]] // Logical NOT
|
|
2675
|
+
\`\`\`
|
|
2676
|
+
|
|
2677
|
+
### Effect Expressions (Actions)
|
|
2678
|
+
|
|
2679
|
+
\`\`\`typescript
|
|
2680
|
+
["set", "@entity.field", value] // Update field
|
|
2681
|
+
["emit", "EVENT_NAME", payload] // Emit event
|
|
2682
|
+
["navigate", "/path"] // Navigate to route
|
|
2683
|
+
["render-ui", "main", { type, props }] // Render pattern
|
|
2684
|
+
["persist", "create", "Entity", data] // Database operation
|
|
2685
|
+
\`\`\`
|
|
2686
|
+
|
|
2687
|
+
### Available Operators
|
|
2688
|
+
|
|
2689
|
+
${operators.map((op) => `- \`${op}\``).join("\n")}
|
|
2690
|
+
`.trim();
|
|
2691
|
+
}
|
|
2692
|
+
function getRenderUIQuickRef2() {
|
|
2693
|
+
const slots = UI_SLOTS;
|
|
2694
|
+
return `
|
|
2695
|
+
## Render-UI Effect Reference
|
|
2696
|
+
|
|
2697
|
+
### Syntax
|
|
2698
|
+
|
|
2699
|
+
\`\`\`typescript
|
|
2700
|
+
["render-ui", slot, patternConfig | null]
|
|
2701
|
+
\`\`\`
|
|
2702
|
+
|
|
2703
|
+
### UI Slots
|
|
2704
|
+
|
|
2705
|
+
${slots.map((slot) => `- \`${slot}\``).join("\n")}
|
|
2706
|
+
|
|
2707
|
+
### Example
|
|
2708
|
+
|
|
2709
|
+
\`\`\`typescript
|
|
2710
|
+
["render-ui", "main", {
|
|
2711
|
+
type: "entity-table",
|
|
2712
|
+
entity: "Task",
|
|
2713
|
+
columns: ["title", "status"],
|
|
2714
|
+
itemActions: [{ label: "Edit", event: "EDIT" }]
|
|
2715
|
+
}]
|
|
2716
|
+
\`\`\`
|
|
2717
|
+
|
|
2718
|
+
Clear slot: \`["render-ui", "modal", null]\`
|
|
2719
|
+
`.trim();
|
|
2720
|
+
}
|
|
2721
|
+
function getFieldTypesCompact() {
|
|
2722
|
+
return `
|
|
2723
|
+
## Field Types
|
|
2724
|
+
|
|
2725
|
+
| Type | Example | Notes |
|
|
2726
|
+
|------|---------|-------|
|
|
2727
|
+
| \`string\` | \`{ name: "title", type: "string" }\` | Text |
|
|
2728
|
+
| \`number\` | \`{ name: "count", type: "number" }\` | Integer or float |
|
|
2729
|
+
| \`boolean\` | \`{ name: "active", type: "boolean" }\` | true/false |
|
|
2730
|
+
| \`date\` | \`{ name: "birthday", type: "date" }\` | Date only |
|
|
2731
|
+
| \`timestamp\` | \`{ name: "createdAt", type: "timestamp" }\` | Date + time |
|
|
2732
|
+
| \`enum\` | \`{ name: "status", type: "enum", values: ["a", "b"] }\` | Fixed options |
|
|
2733
|
+
| \`array\` | \`{ name: "tags", type: "array", items: "string" }\` | List |
|
|
2734
|
+
| \`relation\` | \`{ name: "user", type: "relation", relation: { entity: "User", cardinality: "one" } }\` | Foreign key |
|
|
2735
|
+
|
|
2736
|
+
### Field Properties
|
|
2737
|
+
|
|
2738
|
+
- \`required: true\` - Must have value
|
|
2739
|
+
- \`default: value\` - Default value
|
|
2740
|
+
- \`unique: true\` - Must be unique
|
|
2741
|
+
`.trim();
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
// src/generators/kflow-design.ts
|
|
2745
|
+
function getTransitionContextGuide() {
|
|
2746
|
+
return `## Transition Context
|
|
2747
|
+
|
|
2748
|
+
You receive a single transition to design. Use these inputs to make UI decisions:
|
|
2749
|
+
|
|
2750
|
+
### Input Fields
|
|
2751
|
+
| Field | What It Tells You |
|
|
2752
|
+
|-------|-------------------|
|
|
2753
|
+
| \`from\` | Current state (e.g., "Browsing", "Creating") |
|
|
2754
|
+
| \`to\` | Target state (e.g., "Browsing", "Viewing") |
|
|
2755
|
+
| \`event\` | What the user did (e.g., "INIT", "CREATE", "VIEW") |
|
|
2756
|
+
| \`currentSlot\` | Which slot to render into (\`main\`, \`modal\`, \`drawer\`) |
|
|
2757
|
+
| \`entity\` | Entity name + fields (drives column/field selection) |
|
|
2758
|
+
| \`designHints\` | Style + UX hints from decomposition |
|
|
2759
|
+
| \`domainContext\` | Category + vocabulary (drives pattern choice) |
|
|
2760
|
+
| \`existingEffects\` | Current render-ui effects (if enhancing) |
|
|
2761
|
+
|
|
2762
|
+
### Decision Flow
|
|
2763
|
+
|
|
2764
|
+
\`\`\`
|
|
2765
|
+
1. What EVENT is this?
|
|
2766
|
+
\u251C\u2500 INIT \u2192 Compose full page layout (header + content + data)
|
|
2767
|
+
\u251C\u2500 CREATE/EDIT \u2192 Form in modal or drawer
|
|
2768
|
+
\u251C\u2500 VIEW \u2192 Detail in drawer or inline
|
|
2769
|
+
\u251C\u2500 DELETE \u2192 Confirmation in overlay
|
|
2770
|
+
\u2514\u2500 SAVE/CANCEL \u2192 Clear slot (return null)
|
|
2771
|
+
|
|
2772
|
+
2. What SLOT?
|
|
2773
|
+
\u251C\u2500 main \u2192 Compose multiple patterns (stack them)
|
|
2774
|
+
\u251C\u2500 modal \u2192 Single form or confirmation
|
|
2775
|
+
\u251C\u2500 drawer \u2192 Detail view or quick edit form
|
|
2776
|
+
\u2514\u2500 overlay \u2192 Confirmation dialog
|
|
2777
|
+
|
|
2778
|
+
3. What DOMAIN?
|
|
2779
|
+
\u251C\u2500 business \u2192 entity-table + stats + filter-group
|
|
2780
|
+
\u251C\u2500 dashboard \u2192 dashboard-grid + chart + stats
|
|
2781
|
+
\u251C\u2500 e-commerce \u2192 entity-cards + stats (revenue)
|
|
2782
|
+
\u251C\u2500 content \u2192 entity-cards + tabs + media
|
|
2783
|
+
\u2514\u2500 workflow \u2192 timeline + progress-bar
|
|
2784
|
+
|
|
2785
|
+
4. What ENTITY FIELDS suggest?
|
|
2786
|
+
\u251C\u2500 enum fields \u2192 filter-group, badge columns
|
|
2787
|
+
\u251C\u2500 date fields \u2192 timeline, date columns
|
|
2788
|
+
\u251C\u2500 number fields \u2192 stats, chart, meter
|
|
2789
|
+
\u251C\u2500 relation fields \u2192 tabs for related collections
|
|
2790
|
+
\u2514\u2500 image/url fields \u2192 entity-cards (visual)
|
|
2791
|
+
\`\`\``;
|
|
2792
|
+
}
|
|
2793
|
+
function getLayoutCompositionGuide() {
|
|
2794
|
+
return `## Layout Composition
|
|
2795
|
+
|
|
2796
|
+
Use layout patterns to create structured, visually rich views.
|
|
2797
|
+
|
|
2798
|
+
### Stack (VStack / HStack)
|
|
2799
|
+
\`{ "type": "stack", "direction": "vertical"|"horizontal", "gap": "sm"|"md"|"lg", "children": [...] }\`
|
|
2800
|
+
|
|
2801
|
+
### Box (Styled Container)
|
|
2802
|
+
\`{ "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md", "children": [...] }\`
|
|
2803
|
+
|
|
2804
|
+
### Grid (Multi-Column)
|
|
2805
|
+
\`{ "type": "grid", "cols": 3, "gap": "md", "children": [...] }\`
|
|
2806
|
+
|
|
2807
|
+
### Composition Patterns
|
|
2808
|
+
|
|
2809
|
+
**Page Layout** \u2014 VStack wrapping all content:
|
|
2810
|
+
\`\`\`json
|
|
2811
|
+
["render-ui", "main", {
|
|
2812
|
+
"type": "stack", "direction": "vertical", "gap": "lg",
|
|
2813
|
+
"children": [
|
|
2814
|
+
{ "type": "page-header", "title": "...", "actions": [...] },
|
|
2815
|
+
{ "type": "stack", "direction": "horizontal", "gap": "md", "wrap": true,
|
|
2816
|
+
"children": [
|
|
2817
|
+
{ "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
|
|
2818
|
+
"children": [{ "type": "stats", "metrics": [...] }] },
|
|
2819
|
+
{ "type": "box", "padding": "md", "bg": "card", "border": true, "rounded": "md",
|
|
2820
|
+
"children": [{ "type": "stats", "metrics": [...] }] }
|
|
2821
|
+
]
|
|
2822
|
+
},
|
|
2823
|
+
{ "type": "entity-table", "entity": "...", "columns": [...], "searchable": true }
|
|
2824
|
+
]
|
|
2825
|
+
}]
|
|
2826
|
+
\`\`\`
|
|
2827
|
+
|
|
2828
|
+
**Dashboard Layout** \u2014 Grid of cards:
|
|
2829
|
+
\`\`\`json
|
|
2830
|
+
["render-ui", "main", {
|
|
2831
|
+
"type": "stack", "direction": "vertical", "gap": "lg",
|
|
2832
|
+
"children": [
|
|
2833
|
+
{ "type": "page-header", "title": "Dashboard" },
|
|
2834
|
+
{ "type": "grid", "cols": { "sm": 1, "md": 2, "lg": 3 }, "gap": "md",
|
|
2835
|
+
"children": [
|
|
2836
|
+
{ "type": "box", "padding": "lg", "bg": "card", "border": true, "rounded": "md",
|
|
2837
|
+
"children": [{ "type": "stats", "metrics": [...] }] },
|
|
2838
|
+
{ "type": "box", "padding": "lg", "bg": "card", "border": true, "rounded": "md",
|
|
2839
|
+
"children": [{ "type": "chart", "chartType": "line", "data": [...] }] },
|
|
2840
|
+
{ "type": "box", "padding": "lg", "bg": "card", "border": true, "rounded": "md",
|
|
2841
|
+
"children": [{ "type": "entity-cards", "entity": "...", "columns": 1 }] }
|
|
2842
|
+
]
|
|
2843
|
+
}
|
|
2844
|
+
]
|
|
2845
|
+
}]
|
|
2846
|
+
\`\`\`
|
|
2847
|
+
|
|
2848
|
+
**Detail Drawer** \u2014 Stacked sections:
|
|
2849
|
+
\`\`\`json
|
|
2850
|
+
["render-ui", "drawer", {
|
|
2851
|
+
"type": "stack", "direction": "vertical", "gap": "md",
|
|
2852
|
+
"children": [
|
|
2853
|
+
{ "type": "entity-detail", "entity": "...", "actions": [{ "label": "Edit", "event": "EDIT" }] },
|
|
2854
|
+
{ "type": "tabs", "tabs": [
|
|
2855
|
+
{ "label": "Related Items", "content": { "type": "entity-table", "entity": "..." } },
|
|
2856
|
+
{ "label": "Activity", "content": { "type": "timeline", "items": [...] } }
|
|
2857
|
+
]}
|
|
2858
|
+
]
|
|
2859
|
+
}]
|
|
2860
|
+
\`\`\`
|
|
2861
|
+
|
|
2862
|
+
### When to Use Layout vs Flat
|
|
2863
|
+
- **Flat** (multiple render-ui calls): Simple pages, 2-3 patterns stacked vertically
|
|
2864
|
+
- **Nested** (single render-ui with layout): Complex pages, side-by-side elements, cards with backgrounds, dashboard grids`;
|
|
2865
|
+
}
|
|
2866
|
+
function getOutputFormatSection() {
|
|
2867
|
+
return `## Output Format
|
|
2868
|
+
|
|
2869
|
+
Return ONLY a JSON array of render-ui effect tuples. No explanation, no markdown.
|
|
2870
|
+
|
|
2871
|
+
### Simple (multiple flat effects):
|
|
2872
|
+
\`\`\`json
|
|
2873
|
+
[
|
|
2874
|
+
["render-ui", "main", { "type": "page-header", "title": "...", "actions": [...] }],
|
|
2875
|
+
["render-ui", "main", { "type": "stats", "entity": "...", "metrics": [...] }],
|
|
2876
|
+
["render-ui", "main", { "type": "entity-table", "entity": "...", "columns": [...] }]
|
|
2877
|
+
]
|
|
2878
|
+
\`\`\`
|
|
2879
|
+
|
|
2880
|
+
### Composed (single effect with layout nesting):
|
|
2881
|
+
\`\`\`json
|
|
2882
|
+
[
|
|
2883
|
+
["render-ui", "main", { "type": "stack", "direction": "vertical", "gap": "lg", "children": [...] }]
|
|
2884
|
+
]
|
|
2885
|
+
\`\`\`
|
|
2886
|
+
|
|
2887
|
+
### Clear slot:
|
|
2888
|
+
\`\`\`json
|
|
2889
|
+
[
|
|
2890
|
+
["render-ui", "modal", null]
|
|
2891
|
+
]
|
|
2892
|
+
\`\`\`
|
|
2893
|
+
|
|
2894
|
+
### Rules
|
|
2895
|
+
1. Return valid JSON array \u2014 nothing else
|
|
2896
|
+
2. Every effect must be \`["render-ui", slot, config]\`
|
|
2897
|
+
3. Use entity fields from the input for columns, form fields, stats
|
|
2898
|
+
4. Match domain vocabulary for labels (e.g., "Place Order" not "Create")
|
|
2899
|
+
5. Include \`itemActions\` on tables/cards with appropriate events
|
|
2900
|
+
6. Use \`searchable: true\` on tables for business domains
|
|
2901
|
+
7. For INIT transitions, ALWAYS compose multiple patterns (never just a table)
|
|
2902
|
+
8. For CREATE/EDIT, always include \`submitEvent\` and \`cancelEvent\` on form-section`;
|
|
2903
|
+
}
|
|
2904
|
+
function generateKflowDesignSkill() {
|
|
2905
|
+
const frontmatter = {
|
|
2906
|
+
name: "kflow-design",
|
|
2907
|
+
description: "Design rich render-ui effects for orbital schema transitions. Focused on pattern selection, layout composition, and domain-aware UI authoring.",
|
|
2908
|
+
allowedTools: ["Read", "Write", "Edit"],
|
|
2909
|
+
version: "1.0.0"
|
|
2910
|
+
};
|
|
2911
|
+
const content = `# Render-UI Design Skill
|
|
2912
|
+
|
|
2913
|
+
> Design rich, polished render-ui effects for orbital schema transitions.
|
|
2914
|
+
|
|
2915
|
+
You are a UI design specialist for KFlow orbital schemas. Your job is to take a
|
|
2916
|
+
transition context (state, event, entity, domain) and produce the best possible
|
|
2917
|
+
render-ui effects using the full pattern catalog.
|
|
2918
|
+
|
|
2919
|
+
**Your goal**: Every transition should produce UI that is visually rich, functionally
|
|
2920
|
+
complete, and domain-appropriate. Never default to just "entity-table" \u2014 compose
|
|
2921
|
+
layouts with headers, stats, filters, and appropriate patterns.
|
|
2922
|
+
|
|
2923
|
+
---
|
|
2924
|
+
|
|
2925
|
+
${getTransitionContextGuide()}
|
|
2926
|
+
|
|
2927
|
+
---
|
|
2928
|
+
|
|
2929
|
+
${getRenderUIDesignGuide()}
|
|
2930
|
+
|
|
2931
|
+
---
|
|
2932
|
+
|
|
2933
|
+
${getLayoutCompositionGuide()}
|
|
2934
|
+
|
|
2935
|
+
---
|
|
2936
|
+
|
|
2937
|
+
${getSExprQuickRef2()}
|
|
2938
|
+
|
|
2939
|
+
---
|
|
2940
|
+
|
|
2941
|
+
${getCommonErrorsSection("top6")}
|
|
2942
|
+
|
|
2943
|
+
---
|
|
2944
|
+
|
|
2945
|
+
${getOutputFormatSection()}
|
|
2946
|
+
`;
|
|
2947
|
+
return {
|
|
2948
|
+
name: "kflow-design",
|
|
2949
|
+
frontmatter,
|
|
2950
|
+
content
|
|
2951
|
+
};
|
|
2952
|
+
}
|
|
2953
|
+
function getDesignSkillStats() {
|
|
2954
|
+
const skill = generateKflowDesignSkill();
|
|
2955
|
+
return {
|
|
2956
|
+
lines: skill.content.split("\n").length,
|
|
2957
|
+
chars: skill.content.length
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
// src/orbitals-skills-generators/lean/lean-orbital-generator.ts
|
|
2962
|
+
var LEAN_CORE_INSTRUCTIONS = `
|
|
2482
2963
|
## Core Instructions
|
|
2483
2964
|
|
|
2484
2965
|
Generate orbital schemas using **Domain Language** - a natural, readable format.
|
|
@@ -3072,139 +3553,10 @@ function generateAllBuilderSkills() {
|
|
|
3072
3553
|
},
|
|
3073
3554
|
content: generateLeanFixingSkill2()
|
|
3074
3555
|
},
|
|
3075
|
-
generateDomainLanguageSkill()
|
|
3556
|
+
generateDomainLanguageSkill(),
|
|
3557
|
+
generateKflowDesignSkill()
|
|
3076
3558
|
];
|
|
3077
3559
|
}
|
|
3078
|
-
function getMinimalTypeReference2() {
|
|
3079
|
-
return `
|
|
3080
|
-
## Orbital Schema Structure
|
|
3081
|
-
|
|
3082
|
-
\`\`\`typescript
|
|
3083
|
-
interface OrbitalDefinition {
|
|
3084
|
-
name: string; // Entity name (PascalCase)
|
|
3085
|
-
entity: Entity; // Data model
|
|
3086
|
-
traits: TraitRef[]; // State machines (names or definitions)
|
|
3087
|
-
pages: Page[]; // Routes and views
|
|
3088
|
-
emits?: string[]; // Events this orbital emits
|
|
3089
|
-
listens?: EventListener[]; // Events this orbital listens to
|
|
3090
|
-
}
|
|
3091
|
-
\`\`\`
|
|
3092
|
-
|
|
3093
|
-
### Entity Fields
|
|
3094
|
-
|
|
3095
|
-
\`\`\`typescript
|
|
3096
|
-
{ name: "title", type: "string", required: true }
|
|
3097
|
-
{ name: "count", type: "number", default: 0 }
|
|
3098
|
-
{ name: "status", type: "enum", values: ["pending", "active", "done"] }
|
|
3099
|
-
{ name: "dueDate", type: "date" }
|
|
3100
|
-
\`\`\`
|
|
3101
|
-
|
|
3102
|
-
### Trait State Machine
|
|
3103
|
-
|
|
3104
|
-
\`\`\`typescript
|
|
3105
|
-
{
|
|
3106
|
-
states: [{ name: "Idle", isInitial: true }, { name: "Active" }],
|
|
3107
|
-
events: ["INIT", "ACTIVATE", "COMPLETE"],
|
|
3108
|
-
transitions: [
|
|
3109
|
-
{ from: "Idle", to: "Active", event: "ACTIVATE",
|
|
3110
|
-
guards: [["condition"]],
|
|
3111
|
-
effects: [["action"]] }
|
|
3112
|
-
]
|
|
3113
|
-
}
|
|
3114
|
-
\`\`\`
|
|
3115
|
-
`.trim();
|
|
3116
|
-
}
|
|
3117
|
-
function getPatternTypesCompact() {
|
|
3118
|
-
const patterns = getAllPatternTypes();
|
|
3119
|
-
return `
|
|
3120
|
-
## Available Pattern Types
|
|
3121
|
-
|
|
3122
|
-
${patterns.map((p) => `- \`${p}\``).join("\n")}
|
|
3123
|
-
|
|
3124
|
-
${getPatternPropsCompact()}
|
|
3125
|
-
`.trim();
|
|
3126
|
-
}
|
|
3127
|
-
function getSExprQuickRef2() {
|
|
3128
|
-
const operators = Object.keys(OPERATORS).slice(0, 15);
|
|
3129
|
-
return `
|
|
3130
|
-
## S-Expression Quick Reference
|
|
3131
|
-
|
|
3132
|
-
### Guard Expressions (Conditions)
|
|
3133
|
-
|
|
3134
|
-
\`\`\`typescript
|
|
3135
|
-
["=", "@entity.status", "active"] // Equality
|
|
3136
|
-
[">", "@entity.count", 0] // Greater than
|
|
3137
|
-
["and", ["cond1"], ["cond2"]] // Logical AND
|
|
3138
|
-
["or", ["cond1"], ["cond2"]] // Logical OR
|
|
3139
|
-
["not", ["condition"]] // Logical NOT
|
|
3140
|
-
\`\`\`
|
|
3141
|
-
|
|
3142
|
-
### Effect Expressions (Actions)
|
|
3143
|
-
|
|
3144
|
-
\`\`\`typescript
|
|
3145
|
-
["set", "@entity.field", value] // Update field
|
|
3146
|
-
["emit", "EVENT_NAME", payload] // Emit event
|
|
3147
|
-
["navigate", "/path"] // Navigate to route
|
|
3148
|
-
["render-ui", "main", { type, props }] // Render pattern
|
|
3149
|
-
["persist", "create", "Entity", data] // Database operation
|
|
3150
|
-
\`\`\`
|
|
3151
|
-
|
|
3152
|
-
### Available Operators
|
|
3153
|
-
|
|
3154
|
-
${operators.map((op) => `- \`${op}\``).join("\n")}
|
|
3155
|
-
`.trim();
|
|
3156
|
-
}
|
|
3157
|
-
function getRenderUIQuickRef2() {
|
|
3158
|
-
const slots = UI_SLOTS;
|
|
3159
|
-
return `
|
|
3160
|
-
## Render-UI Effect Reference
|
|
3161
|
-
|
|
3162
|
-
### Syntax
|
|
3163
|
-
|
|
3164
|
-
\`\`\`typescript
|
|
3165
|
-
["render-ui", slot, patternConfig | null]
|
|
3166
|
-
\`\`\`
|
|
3167
|
-
|
|
3168
|
-
### UI Slots
|
|
3169
|
-
|
|
3170
|
-
${slots.map((slot) => `- \`${slot}\``).join("\n")}
|
|
3171
|
-
|
|
3172
|
-
### Example
|
|
3173
|
-
|
|
3174
|
-
\`\`\`typescript
|
|
3175
|
-
["render-ui", "main", {
|
|
3176
|
-
type: "entity-table",
|
|
3177
|
-
entity: "Task",
|
|
3178
|
-
columns: ["title", "status"],
|
|
3179
|
-
itemActions: [{ label: "Edit", event: "EDIT" }]
|
|
3180
|
-
}]
|
|
3181
|
-
\`\`\`
|
|
3182
|
-
|
|
3183
|
-
Clear slot: \`["render-ui", "modal", null]\`
|
|
3184
|
-
`.trim();
|
|
3185
|
-
}
|
|
3186
|
-
function getFieldTypesCompact() {
|
|
3187
|
-
return `
|
|
3188
|
-
## Field Types
|
|
3189
|
-
|
|
3190
|
-
| Type | Example | Notes |
|
|
3191
|
-
|------|---------|-------|
|
|
3192
|
-
| \`string\` | \`{ name: "title", type: "string" }\` | Text |
|
|
3193
|
-
| \`number\` | \`{ name: "count", type: "number" }\` | Integer or float |
|
|
3194
|
-
| \`boolean\` | \`{ name: "active", type: "boolean" }\` | true/false |
|
|
3195
|
-
| \`date\` | \`{ name: "birthday", type: "date" }\` | Date only |
|
|
3196
|
-
| \`timestamp\` | \`{ name: "createdAt", type: "timestamp" }\` | Date + time |
|
|
3197
|
-
| \`enum\` | \`{ name: "status", type: "enum", values: ["a", "b"] }\` | Fixed options |
|
|
3198
|
-
| \`array\` | \`{ name: "tags", type: "array", items: "string" }\` | List |
|
|
3199
|
-
| \`relation\` | \`{ name: "user", type: "relation", relation: { entity: "User", cardinality: "one" } }\` | Foreign key |
|
|
3200
|
-
|
|
3201
|
-
### Field Properties
|
|
3202
|
-
|
|
3203
|
-
- \`required: true\` - Must have value
|
|
3204
|
-
- \`default: value\` - Default value
|
|
3205
|
-
- \`unique: true\` - Must be unique
|
|
3206
|
-
`.trim();
|
|
3207
|
-
}
|
|
3208
3560
|
|
|
3209
3561
|
// src/prompts/generation-prompts.ts
|
|
3210
3562
|
function getOrbitalDecompositionPrompt() {
|
|
@@ -3244,7 +3596,7 @@ ${getArchitectureSection()}
|
|
|
3244
3596
|
|
|
3245
3597
|
---
|
|
3246
3598
|
|
|
3247
|
-
${
|
|
3599
|
+
${getMinimalTypeReference()}
|
|
3248
3600
|
|
|
3249
3601
|
---
|
|
3250
3602
|
|
|
@@ -3378,6 +3730,6 @@ Use with: \`uses: [{ from: "std/behaviors/crud", as: "CRUD" }]\`
|
|
|
3378
3730
|
`;
|
|
3379
3731
|
}
|
|
3380
3732
|
|
|
3381
|
-
export { formatFrontmatter, generateAllBuilderSkills, generateDomainLanguageSkill, generateKflowOrbitalFixingSkill, generateKflowOrbitalsSkill, generateLeanFixingSkill2 as generateLeanFixingSkill, generateLeanFixingSkill as generateLeanFixingSkillFull, generateLeanOrbitalSkill2 as generateLeanOrbitalSkill, generateLeanOrbitalSkill as generateLeanOrbitalSkillFull, getArchitectureSection, getAssetRefSection, getCommonErrorsSection, getCommonFixPatternsSection, getCompletionRulesSection, getContextUsageCompact, getContextUsageSection, getCustomTraitCompact, getCustomTraitSection, getDecompositionChecklist, getDecompositionSection, getDesignErrorsCompact, getDesignErrorsSection, getEfficiencySection, getFieldTypesCompact, getFixingWorkflowSection, getFlowPatternSection, getFullOrbitalPrompt, getGameAsOrbitalsSection, getGameEntityTemplatesSection, getGamePatternsSection, getGameTraitsSection, getGameTypesSection, getIconLibraryCompact, getIconLibrarySection, getKeyBehaviorsReference2 as getKeyBehaviorsReference,
|
|
3733
|
+
export { formatFrontmatter, generateAllBuilderSkills, generateDomainLanguageSkill, generateKflowDesignSkill, generateKflowOrbitalFixingSkill, generateKflowOrbitalsSkill, generateLeanFixingSkill2 as generateLeanFixingSkill, generateLeanFixingSkill as generateLeanFixingSkillFull, generateLeanOrbitalSkill2 as generateLeanOrbitalSkill, generateLeanOrbitalSkill as generateLeanOrbitalSkillFull, getArchitectureSection, getAssetRefSection, getCommonErrorsSection, getCommonFixPatternsSection, getCompletionRulesSection, getConnectivityCompact, getContextUsageCompact, getContextUsageSection, getCustomTraitCompact, getCustomTraitSection, getDecompositionChecklist, getDecompositionCompact, getDecompositionSection, getDesignErrorsCompact, getDesignErrorsSection, getDesignSkillStats, getEfficiencySection, getFieldTypesCompact, getFixingWorkflowSection, getFlowPatternSection, getFullOrbitalPrompt, getGameAsOrbitalsSection, getGameEntityTemplatesSection, getGamePatternsSection, getGameTraitsSection, getGameTypesSection, getIconLibraryCompact, getIconLibrarySection, getKeyBehaviorsReference2 as getKeyBehaviorsReference, getMinimalTypeReference, getMultiFileSection, getOrbitalConnectivitySection, getOrbitalDecompositionPrompt, getOverGenerationSection, getPatternTypesCompact, getPortableOrbitalOutputSection, getRenderUIDesignGuide, getRenderUIQuickRef2 as getRenderUIQuickRef, getRequirementsDecomposePrompt, getRequirementsTraitPrompt, getSExprQuickRef2 as getSExprQuickRef, getSchemaUpdateCompact, getSchemaUpdateSection, getUsesImportCompact, getUsesImportSection, getValidationHintsSection, writeAllSkills, writeSkill };
|
|
3382
3734
|
//# sourceMappingURL=index.js.map
|
|
3383
3735
|
//# sourceMappingURL=index.js.map
|