@almadar/skills 1.0.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.js ADDED
@@ -0,0 +1,3383 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { generateBehaviorsDocs, getAllBehaviors, generateModulesDocs, getAllStdOperators } from '@almadar/std';
4
+ import { OPERATORS, UI_SLOTS, PATTERN_TYPES, ViewTypeSchema } from '@almadar/core/types';
5
+ import { getPatternPropsCompact, getPatternActionsRef, getAllPatternTypes, getPatternsGroupedByCategory } from '@almadar/patterns';
6
+
7
+ // src/generators/utils.ts
8
+ function formatFrontmatter(fm) {
9
+ const lines = ["---"];
10
+ lines.push(`name: ${fm.name}`);
11
+ lines.push(`description: ${fm.description}`);
12
+ if (fm.allowedTools?.length) {
13
+ lines.push(`allowed-tools: ${fm.allowedTools.join(", ")}`);
14
+ }
15
+ if (fm.version) {
16
+ lines.push(`version: ${fm.version}`);
17
+ }
18
+ lines.push("---");
19
+ return lines.join("\n");
20
+ }
21
+ function writeSkill(skill, baseDir) {
22
+ const skillDir = join(baseDir, skill.name);
23
+ if (!existsSync(skillDir)) {
24
+ mkdirSync(skillDir, { recursive: true });
25
+ }
26
+ const skillMd = formatFrontmatter(skill.frontmatter) + "\n\n" + skill.content;
27
+ writeFileSync(join(skillDir, "SKILL.md"), skillMd);
28
+ console.log(` \u2713 ${skill.name}/SKILL.md`);
29
+ if (skill.references) {
30
+ const refsDir = join(skillDir, "references");
31
+ if (!existsSync(refsDir)) {
32
+ mkdirSync(refsDir, { recursive: true });
33
+ }
34
+ for (const [filename, content] of Object.entries(skill.references)) {
35
+ writeFileSync(join(refsDir, filename), content);
36
+ console.log(` \u2713 ${skill.name}/references/${filename}`);
37
+ }
38
+ }
39
+ }
40
+ function writeAllSkills(skills, baseDir) {
41
+ console.log(`
42
+ Writing ${skills.length} skills to ${baseDir}...`);
43
+ for (const skill of skills) {
44
+ writeSkill(skill, baseDir);
45
+ }
46
+ console.log(`
47
+ \u2713 Generated ${skills.length} skills`);
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
+ function getSExprQuickRef() {
68
+ return `## S-Expression Syntax
69
+
70
+ **Bindings** (read data):
71
+ - \`@entity.field\` - Entity field value
72
+ - \`@payload.data\` - Event payload data
73
+ - \`@state\` - Current state name
74
+ - \`@now\` - Current timestamp
75
+
76
+ **Guards** (boolean expressions):
77
+ \`\`\`json
78
+ [">", "@entity.count", 0]
79
+ ["and", ["=", "@state", "Active"], ["<", "@entity.value", 100]]
80
+ \`\`\`
81
+
82
+ **Effects** (actions):
83
+ \`\`\`json
84
+ ["set", "@entity.count", ["+", "@entity.count", 1]]
85
+ ["persist", "update", "Task", "@entity.id", "@payload.data"]
86
+ ["emit", "TASK_COMPLETED", { "id": "@entity.id" }]
87
+ \`\`\`
88
+ `;
89
+ }
90
+ function getRenderUIQuickRef() {
91
+ return `## Render-UI Reference
92
+
93
+ **Syntax**: \`["render-ui", slot, config]\`
94
+
95
+ **Slots**: \`main\`, \`modal\`, \`drawer\`, \`sidebar\`, \`hud-top\`, \`hud-bottom\`
96
+
97
+ **Example**:
98
+ \`\`\`json
99
+ ["render-ui", "main", {
100
+ "type": "entity-table",
101
+ "entity": "Task",
102
+ "columns": ["title", "status"]
103
+ }]
104
+ \`\`\`
105
+
106
+ Clear a slot: \`["render-ui", "modal", null]\`
107
+ `;
108
+ }
109
+ function getStdMinimalReference() {
110
+ const operators = getAllStdOperators();
111
+ return `## Standard Library
112
+
113
+ **Operators**: ${operators.length} total
114
+
115
+ **Key Categories**:
116
+ - Math: \`clamp\`, \`lerp\`, \`random\`, \`abs\`, \`min\`, \`max\`
117
+ - String: \`concat\`, \`upper\`, \`lower\`, \`trim\`, \`split\`
118
+ - Array: \`filter\`, \`map\`, \`find\`, \`contains\`, \`length\`
119
+ - Time: \`now\`, \`format\`, \`diff\`, \`isPast\`, \`isFuture\`
120
+
121
+ Import with: \`uses: [{ from: "std/operators/math", as: "Math" }]\`
122
+ `;
123
+ }
124
+ function getStdFullReference() {
125
+ const modulesDocs = generateModulesDocs();
126
+ return `## Standard Library (Full Reference)
127
+
128
+ ${modulesDocs.modules.map((mod) => `### ${mod.name}
129
+ ${mod.description}
130
+
131
+ ${mod.operators.map((op) => `- **${op.name}**: ${op.description}`).join("\n")}
132
+ `).join("\n")}
133
+ `;
134
+ }
135
+ function getStdBehaviorsWithStateMachines() {
136
+ const behaviors = getAllBehaviors();
137
+ const nonGameBehaviors = behaviors.filter(
138
+ (b) => !b.category?.includes("game") && b.stateMachine
139
+ );
140
+ return `## Standard Behaviors
141
+
142
+ ${nonGameBehaviors.map((behavior) => `### ${behavior.name}
143
+
144
+ **States**: ${behavior.stateMachine.states.map((s) => s.name).join(", ")}
145
+ **Events**: ${behavior.stateMachine.events.join(", ")}
146
+
147
+ \`\`\`json
148
+ ${JSON.stringify(behavior, null, 2)}
149
+ \`\`\`
150
+ `).join("\n\n")}
151
+ `;
152
+ }
153
+ function getKeyBehaviorsReference() {
154
+ const behaviorsDocs = generateBehaviorsDocs();
155
+ return `## Key Standard Behaviors
156
+
157
+ ${behaviorsDocs.categories.map((cat) => `### ${cat.name}
158
+ ${cat.behaviors.map((b) => `- **${b.name}**: ${b.description}`).join("\n")}
159
+ `).join("\n")}
160
+
161
+ Use with: \`uses: [{ from: "std/behaviors/crud", as: "CRUD" }]\`
162
+ `;
163
+ }
164
+
165
+ // src/prompts/skill-sections/architecture.ts
166
+ function getArchitectureSection() {
167
+ return `## Orbital Architecture
168
+
169
+ ### Schema Format (IMPORTANT)
170
+
171
+ The correct schema format uses **orbitals** array at root:
172
+
173
+ \`\`\`json
174
+ {
175
+ "name": "MyApp",
176
+ "version": "1.0.0",
177
+ "orbitals": [ // \u2190 CORRECT: orbitals array
178
+ {
179
+ "name": "Task Management",
180
+ "entity": { ... },
181
+ "traits": [ ... ],
182
+ "pages": [ ... ]
183
+ }
184
+ ]
185
+ }
186
+ \`\`\`
187
+
188
+ **DO NOT** confuse with legacy format that had \`dataEntities\`, \`traits\`, \`pages\` at root level.
189
+ The \`orbitals[]\` format IS the standard format - do not "fix" it to something else.
190
+
191
+ **NOTE**: There is NO schema-level \`traits[]\` array. All traits belong inside orbitals.
192
+
193
+ ### Core Formula
194
+ \`\`\`
195
+ Orbital Unit = Entity \xD7 Traits \xD7 Patterns
196
+ Application = \u03A3(Orbital Units)
197
+ \`\`\`
198
+
199
+ ### The Closed Circuit Pattern
200
+ \`\`\`
201
+ Trait State Machine \u2192 render-ui \u2192 UI Component \u2192 User Action \u2192 Event \u2192 Trait
202
+ \u2191 |
203
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
204
+ \`\`\`
205
+
206
+ 1. **Trait** transitions to state, fires \`render-ui\` effect
207
+ 2. **UI Component** renders with actions (buttons, forms)
208
+ 3. **User clicks** \u2192 Component emits event (e.g., \`UI:CREATE\`)
209
+ 4. **Trait receives** event, transitions, cycle repeats
210
+
211
+ ### Key Principles
212
+
213
+ | Principle | Rule |
214
+ |-----------|------|
215
+ | **One trait per slot** | Each slot (main, modal, drawer) owned by ONE trait |
216
+ | **INIT renders UI** | Every trait needs INIT self-loop to render initial UI |
217
+ | **One page per entity** | Use trait's render-ui for create/edit/view, not separate pages |
218
+ | **form-section has onSubmit** | Connects form to trait events |
219
+ | **std/* are templates** | Guide LLM generation, not runtime code |
220
+
221
+ ### Slot Ownership
222
+ \`\`\`
223
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
224
+ \u2502 Page: /tasks \u2502
225
+ \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524
226
+ \u2502 TaskManagement trait OWNS: \u2502
227
+ \u2502 \u2022 main \u2192 entity-table, page-header \u2502
228
+ \u2502 \u2022 modal \u2192 form-section (create/edit) \u2502
229
+ \u2502 \u2022 drawer \u2192 entity-detail (view) \u2502
230
+ \u2502 \u2502
231
+ \u2502 NO other trait should render to these slots \u2502
232
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
233
+ \`\`\`
234
+ `;
235
+ }
236
+ function getPatternCategories() {
237
+ const categories = {
238
+ Header: PATTERN_TYPES.filter(
239
+ (p) => p.includes("header") || p === "title-only"
240
+ ),
241
+ Display: PATTERN_TYPES.filter(
242
+ (p) => p.startsWith("entity-") || p === "stats"
243
+ ),
244
+ Form: PATTERN_TYPES.filter((p) => p.startsWith("form-")),
245
+ Filter: PATTERN_TYPES.filter(
246
+ (p) => p.includes("search") || p.includes("filter")
247
+ ),
248
+ State: PATTERN_TYPES.filter((p) => p.includes("-state")),
249
+ Navigation: PATTERN_TYPES.filter((p) => ["tabs", "breadcrumb"].includes(p)),
250
+ Layout: PATTERN_TYPES.filter(
251
+ (p) => p.includes("layout") || p.includes("grid") || p === "master-detail"
252
+ ),
253
+ Interaction: PATTERN_TYPES.filter((p) => p === "confirmation" || typeof p === "string" && p.includes("confirmation")),
254
+ Game: PATTERN_TYPES.filter(
255
+ (p) => p.startsWith("game-") || [
256
+ "tilemap-renderer",
257
+ "inventory-panel",
258
+ "dialogue-box",
259
+ "level-select"
260
+ ].includes(p)
261
+ )
262
+ };
263
+ let table = "| Category | Valid Patterns |\n|----------|----------------|\n";
264
+ for (const [cat, patterns] of Object.entries(categories)) {
265
+ if (patterns.length > 0) {
266
+ table += `| ${cat} | ${patterns.map((p) => `\`${p}\``).join(", ")} |
267
+ `;
268
+ }
269
+ }
270
+ return table;
271
+ }
272
+ function getValidViewTypes() {
273
+ const validTypes = ViewTypeSchema.options;
274
+ return validTypes.map((t) => `\`${t}\``).join(", ");
275
+ }
276
+ function getCommonErrorsSection() {
277
+ return `## Critical Rules
278
+
279
+ ### NEVER Use @payload in set Effects (CRITICAL)
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)
296
+
297
+ Every trait MUST have an INIT self-loop transition. The runtime fires \`INIT\` when page loads.
298
+
299
+ \`\`\`json
300
+ // REQUIRED in EVERY trait:
301
+ {
302
+ "from": "Browsing",
303
+ "to": "Browsing",
304
+ "event": "INIT", // \u2190 Runtime fires this on page load
305
+ "effects": [
306
+ ["render-ui", "main", { "type": "page-header", ... }],
307
+ ["render-ui", "main", { "type": "entity-table", ... }]
308
+ ]
309
+ }
310
+ \`\`\`
311
+
312
+ Without INIT: Page loads blank, nothing renders, no UI appears.
313
+
314
+ ### Valid Patterns ONLY (CRITICAL)
315
+
316
+ **DO NOT invent custom patterns!** Only these patterns exist:
317
+
318
+ ${getPatternCategories()}
319
+
320
+ **NEVER use**: \`onboarding-welcome\`, \`category-selector\`, \`assessment-question\`, etc. - these DO NOT exist!
321
+
322
+ ### Valid viewType Values
323
+
324
+ Pages must use valid viewType values: ${getValidViewTypes()}
325
+
326
+ Invalid values like \`form\`, \`wizard\`, \`onboarding\` will cause validation errors.
327
+
328
+ ${getPatternPropsCompact()}
329
+
330
+ ${getPatternActionsRef()}
331
+
332
+ ### Page Structure Required (CRITICAL)
333
+
334
+ Every page MUST have \`path\` and \`traits\` properties:
335
+
336
+ \`\`\`json
337
+ // WRONG - missing path and traits:
338
+ {
339
+ "pages": [{
340
+ "name": "TasksPage",
341
+ "entity": "Task" // \u274C Missing path and traits!
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
351
+ }]
352
+ }
353
+ \`\`\`
354
+
355
+ Without \`path\`: Validation error \`ORB_P_MISSING_PATH\`
356
+ Without \`traits\`: Validation error \`ORB_P_MISSING_TRAITS\`
357
+
358
+ ### Valid Field Types ONLY (CRITICAL)
359
+
360
+ Field types MUST be one of: \`string\`, \`number\`, \`boolean\`, \`date\`, \`timestamp\`, \`datetime\`, \`array\`, \`object\`, \`enum\`, \`relation\`
361
+
362
+ \`\`\`json
363
+ // WRONG - using entity name as type:
364
+ { "name": "author", "type": "User" } // \u274C "User" is not a valid type!
365
+ { "name": "post", "type": "BlogPost" } // \u274C Invalid!
366
+
367
+ // CORRECT - use relation type with entity reference:
368
+ { "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
+ \`\`\`
377
+
378
+ ### Event Listeners Structure
379
+
380
+ Event listeners go INSIDE traits, not at orbital level:
381
+
382
+ \`\`\`json
383
+ // WRONG - at orbital level:
384
+ {
385
+ "name": "Task Management",
386
+ "listens": ["SOME_EVENT"] // \u274C Wrong location, wrong format
387
+ }
388
+
389
+ // CORRECT - inside trait:
390
+ {
391
+ "traits": [{
392
+ "name": "TaskInteraction",
393
+ "listens": [
394
+ { "event": "USER_UPDATED", "handler": "REFRESH_LIST" } // \u2705 Object format
395
+ ]
396
+ }]
397
+ }
398
+ \`\`\`
399
+
400
+ ---
401
+
402
+ ## Common Errors (AVOID)
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
+ \`\`\`
409
+
410
+ ### 2. Over-Generating Pages
411
+ \`\`\`
412
+ WRONG: TaskListPage, TaskCreatePage, TaskEditPage, TaskViewPage (4 pages!)
413
+ CORRECT: TasksPage with EntityManagement trait (1 page)
414
+ \`\`\`
415
+
416
+ ### 3. Duplicate Slot Rendering
417
+ \`\`\`
418
+ WRONG: Two traits both render to "main" on page load
419
+ CORRECT: ONE trait owns each slot
420
+ \`\`\`
421
+
422
+ ### 4. Missing onSubmit in form-section
423
+ \`\`\`
424
+ WRONG: { "type": "form-section", "entity": "Task" }
425
+ CORRECT: { "type": "form-section", "entity": "Task", "onSubmit": "SAVE" }
426
+ \`\`\`
427
+
428
+ ### 5. Duplicate Transitions (Same from+event)
429
+ \`\`\`
430
+ WRONG: Two transitions with same "from" and "event" without guards
431
+ CORRECT: Use GUARDS to differentiate transitions
432
+ \`\`\`
433
+
434
+ ### 6. Using "render" Instead of "render-ui"
435
+ \`\`\`
436
+ WRONG: ["render", "main", {...}]
437
+ CORRECT: ["render-ui", "main", {...}]
438
+ \`\`\`
439
+
440
+ ### 7. Generating Sections Array (Legacy)
441
+ \`\`\`
442
+ WRONG: { "pages": [{ "sections": [...] }] }
443
+ CORRECT: { "pages": [{ "traits": [...] }] } - UI comes from render-ui effects
444
+ \`\`\`
445
+
446
+ ### 8. Using form-actions Pattern (DOES NOT EXIST!)
447
+ \`\`\`
448
+ 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" }
451
+ \`\`\`
452
+ Actions are INSIDE patterns, not separate patterns. The form-section pattern includes submit/cancel buttons.
453
+
454
+ ### 9. Forgetting itemActions in entity-table
455
+ \`\`\`
456
+ WRONG: { "type": "entity-table", "entity": "Task" } // No row actions
457
+ CORRECT: { "type": "entity-table", "entity": "Task", "itemActions": [{"label": "Edit", "event": "EDIT"}, {"label": "Delete", "event": "DELETE"}] }
458
+ \`\`\`
459
+
460
+ ### 10. Duplicate Trait Names Across Orbitals
461
+ \`\`\`
462
+ WRONG: UserOrbital uses "EntityManagement", TaskOrbital uses "EntityManagement"
463
+ CORRECT: UserOrbital uses "UserManagement", TaskOrbital uses "TaskManagement"
464
+ \`\`\`
465
+ Each trait name MUST be unique. Pattern: \`{Entity}{Purpose}\`
466
+
467
+ ### 11. Using @payload in set Effect
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
475
+ \`\`\`
476
+ WRONG: { "label": "View", "event": "VIEW", "condition": "@entity.status === 'active'" }
477
+ CORRECT: { "label": "View", "event": "VIEW", "showWhen": ["=", "@entity.status", "active"] }
478
+ \`\`\`
479
+ 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
+
488
+ ### 15. Using Entity Name as Field Type
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:
569
+ \`\`\`json
570
+ {
571
+ "from": "Browsing", "to": "Browsing", "event": "FILTER",
572
+ "effects": [["set", "@TaskQuery.status", "@payload.status"]]
573
+ }
574
+ \`\`\`
575
+
576
+ 3. Reference query in patterns:
577
+ \`\`\`json
578
+ ["render-ui", "main", {
579
+ "type": "entity-table",
580
+ "entity": "Task",
581
+ "query": "@TaskQuery"
582
+ }]
583
+ \`\`\`
584
+ `;
585
+ }
586
+ function getValidationHintsSection() {
587
+ return `## Validation Error Quick Fixes
588
+
589
+ | Error | Fix |
590
+ |-------|-----|
591
+ | ORB_P_MISSING_PATH | Add \`path\` property starting with "/" to page (e.g., "/tasks") |
592
+ | ORB_P_MISSING_TRAITS | Add \`traits\` array to page with at least one trait ref |
593
+ | ORB_E_INVALID_FIELD_TYPE | Use valid type: string, number, boolean, date, enum, relation. NOT entity names! |
594
+ | ORB_INIT_MISSING | Add INIT self-loop transition with render-ui effects |
595
+ | ORB_FORM_SUBMIT | Add onSubmit event name to form-section pattern |
596
+ | ORB_DUPE_TRANS | Add guards to differentiate same-event transitions |
597
+ | ORB_SLOT_CONTENTION | Merge traits or use different slots |
598
+ | ORB_DUPE_PAGE_TRAITS | Remove duplicate trait references from page |
599
+ | ORB_T_DUPLICATE_NAME | Use unique trait names per entity: UserManagement, TaskManagement |
600
+ | ORB_EFF_SET_REQUIRES_ENTITY | Change @payload.field to @entity.field in set effects |
601
+ | ORB_RUI_UNKNOWN_ITEM_ACTION_PROP | Remove invalid props (like \`condition\`), use \`showWhen\` |
602
+ | ORB_MODAL_NO_CLOSE | Add CLOSE/CANCEL transitions from modal states with \`["render-ui", "modal", null]\` |
603
+ `;
604
+ }
605
+
606
+ // src/prompts/skill-sections/decomposition.ts
607
+ function getDecompositionSection() {
608
+ return `## Orbital Decomposition Protocol
609
+
610
+ ### Step 0: Classify Domain
611
+ | Domain | Keywords | Key Traits |
612
+ |--------|----------|------------|
613
+ | business | manage, track, workflow | EntityManagement, SearchAndFilter |
614
+ | game | play, score, level | Physics2D, Health, GameState |
615
+ | form | wizard, onboarding | Wizard, FormSubmission |
616
+ | dashboard | metrics, KPI | EntityManagement |
617
+ | content | blog, CMS | none (page navigation) |
618
+
619
+ ### Step 1: Identify Entities (ONE Orbital Per Entity)
620
+ - What are the core data objects?
621
+ - persistent (DB), runtime (memory), or singleton (config)?
622
+ - **CRITICAL: Create exactly ONE orbital per entity** - do NOT split CRUD operations into separate orbitals
623
+
624
+ ### Step 2: Select Interaction Model
625
+ | Domain | Create | View | Edit | Delete |
626
+ |--------|--------|------|------|--------|
627
+ | business | modal | drawer | modal | confirm |
628
+ | game | none | none | none | none |
629
+ | form | wizard | drawer | page | confirm |
630
+
631
+ ### Step 3: Choose Traits
632
+ - Business: EntityManagement (handles CRUD via render-ui)
633
+ - Game: Physics2D, Health, Score, Collision
634
+ - Form: Wizard (multi-step) or FormSubmission (single)
635
+
636
+ ### Step 4: Define State Machine
637
+ \`\`\`
638
+ states: Identify user-facing modes (browsing, creating, editing, viewing)
639
+ events: Identify user actions (INIT, CREATE, VIEW, EDIT, SAVE, CLOSE)
640
+ transitions: Map (from, event) \u2192 (to, effects)
641
+ \`\`\`
642
+
643
+ ### Step 5: Add INIT Transition (CRITICAL)
644
+ Every trait MUST have:
645
+ \`\`\`json
646
+ { "from": "initial", "to": "initial", "event": "INIT", "effects": [["render-ui", ...]] }
647
+ \`\`\`
648
+ Without INIT, the page loads blank!
649
+
650
+ ### Step 6: Define Pages
651
+ - ONE page per entity (business) or workflow (form)
652
+ - Attach traits to pages via \`traits\` array
653
+ - No \`sections\` array - UI comes from render-ui effects
654
+
655
+ ### Step 7: Add Guards (CRITICAL for Business Rules)
656
+
657
+ **Guards enforce business rules as S-expressions on transitions.**
658
+
659
+ #### When to use guards:
660
+ 1. **Business rule validation** - Enforce constraints on SAVE transitions
661
+ 2. **Conditional routing** - Same (from, event) leads to different states
662
+
663
+ #### Business Rule Guards (on SAVE):
664
+ \`\`\`json
665
+ {
666
+ "from": "Editing", "to": "Browsing", "event": "SAVE",
667
+ "guard": ["and",
668
+ ["<=", "@payload.data.age", 120],
669
+ [">=", "@payload.data.balance", 0]
670
+ ],
671
+ "effects": [["persist", "update", "Account", "@payload.data"], ...]
672
+ }
673
+ \`\`\`
674
+
675
+ #### Conditional Routing Guards:
676
+ \`\`\`json
677
+ { "from": "A", "to": "B", "event": "X", "guard": [">", "@entity.health", 0] }
678
+ { "from": "A", "to": "C", "event": "X", "guard": ["<=", "@entity.health", 0] }
679
+ \`\`\`
680
+
681
+ **IMPORTANT**:
682
+ - Use \`"guard"\` (singular) on transitions, NOT \`"guards"\` (plural)
683
+ - Business rules MUST be S-expression guards on the transition, NOT just UI messages!
684
+ `;
685
+ }
686
+ function getDecompositionChecklist() {
687
+ return `## Decomposition Checklist
688
+
689
+ - [ ] Domain classified (business/game/form/dashboard/content)
690
+ - [ ] Entities identified with persistence type
691
+ - [ ] **ONE orbital per entity** (not multiple orbitals for same entity!)
692
+ - [ ] Traits selected (EntityManagement for CRUD, domain-specific for others)
693
+ - [ ] State machine has states, events, transitions
694
+ - [ ] INIT transition exists with render-ui effects
695
+ - [ ] Pages defined (ONE per entity/workflow)
696
+ - [ ] Traits attached to pages
697
+ - [ ] **Business rule guards as S-expressions on SAVE transitions**
698
+ - [ ] Entity relations defined for cross-orbital links
699
+ - [ ] emits/listens defined for cross-orbital events
700
+ `;
701
+ }
702
+ function getFlowPatternSection() {
703
+ return `## Flow Pattern Selection
704
+
705
+ Select a flow pattern based on application type:
706
+
707
+ | App Type | Flow Pattern | Structure |
708
+ |----------|--------------|-----------|
709
+ | Dashboard/Admin | hub-spoke | Central hub \u2192 feature pages \u2192 back to hub |
710
+ | CRM/List-focused | master-detail | List with drill-down drawer or split view |
711
+ | CRUD App | crud-cycle | List \u2194 modal forms for create/edit |
712
+ | Onboarding/Checkout | linear | Step-by-step wizard flow |
713
+ | Multi-role | role-based | Role guards determine visible features |
714
+
715
+ **Flow \u2192 Orbital Structure:**
716
+ - hub-spoke: Dashboard orbital + feature orbitals with navigation
717
+ - master-detail: Entity orbital with detail drawer state
718
+ - crud-cycle: Entity orbital with modal form states
719
+ - linear: Step orbitals connected via navigation
720
+ - role-based: Shared orbitals with role-based guards
721
+ `;
722
+ }
723
+ function getPortableOrbitalOutputSection() {
724
+ return `## Orbital Output Format
725
+
726
+ Each orbital MUST include embedded context for portability:
727
+
728
+ \`\`\`json
729
+ {
730
+ "name": "Order Management",
731
+ "entity": {
732
+ "name": "Order",
733
+ "persistence": "persistent",
734
+ "fields": [
735
+ { "name": "customerId", "type": "relation", "relation": { "entity": "Customer", "cardinality": "one" } },
736
+ { "name": "items", "type": "relation", "relation": { "entity": "MenuItem", "cardinality": "many" } }
737
+ ]
738
+ },
739
+ "traits": ["EntityManagement"],
740
+ "domainContext": {
741
+ "request": "<full user request>",
742
+ "requestFragment": "<verbatim excerpt for THIS orbital>",
743
+ "category": "business",
744
+ "vocabulary": { "item": "Order", "create": "Place Order", "delete": "Cancel" }
745
+ },
746
+ "design": {
747
+ "style": "modern",
748
+ "uxHints": { "flowPattern": "crud-cycle", "listPattern": "entity-table", "formPattern": "modal" }
749
+ },
750
+ "emits": ["ORDER_READY", "ORDER_COMPLETED"],
751
+ "listens": [{ "event": "MENU_ITEM_UNAVAILABLE", "triggers": "DISABLE_ITEM" }],
752
+ "relations": [
753
+ { "entity": "Customer", "cardinality": "one" },
754
+ { "entity": "MenuItem", "cardinality": "many" }
755
+ ]
756
+ }
757
+ \`\`\`
758
+
759
+ **Required context fields:**
760
+ - \`domainContext.requestFragment\` - What user said that produced this orbital
761
+ - \`domainContext.category\` - Domain classification
762
+ - \`domainContext.vocabulary\` - Domain-specific naming
763
+ - \`design.uxHints\` - Pattern selection hints
764
+
765
+ **Cross-orbital connectivity (for multi-entity apps):**
766
+ - \`entity.fields[].relation\` - Link to related entities
767
+ - \`emits\` - Events this orbital emits when state changes
768
+ - \`listens\` - Events from other orbitals to handle
769
+ - \`relations\` - Summary of entity relationships
770
+ `;
771
+ }
772
+ function getOrbitalConnectivitySection() {
773
+ return `## Orbital Connectivity (CRITICAL)
774
+
775
+ Orbitals must NOT be discrete islands. For multi-entity apps, connect orbitals properly:
776
+
777
+ ### 1. Entity Relations (REQUIRED for related entities)
778
+ When Entity A references Entity B, add a relation field:
779
+ \`\`\`json
780
+ // In Order orbital's entity.fields:
781
+ { "name": "customerId", "type": "relation", "relation": { "entity": "Customer", "cardinality": "one" } }
782
+ { "name": "items", "type": "relation", "relation": { "entity": "MenuItem", "cardinality": "many" } }
783
+ \`\`\`
784
+
785
+ ### 2. Navigation Links (in design.uxHints.relatedLinks)
786
+ Enable drill-down from one orbital to another:
787
+ \`\`\`json
788
+ { "relatedLinks": [{ "relation": "customerId", "label": "View Customer", "targetView": "detail" }] }
789
+ \`\`\`
790
+
791
+ ### 3. Cross-Orbital Events (emits/listens)
792
+ Orbitals communicate via events:
793
+ \`\`\`json
794
+ // Order orbital emits when status changes:
795
+ { "emits": ["ORDER_READY", "ORDER_COMPLETED"] }
796
+
797
+ // Notification orbital listens:
798
+ { "listens": [{ "event": "ORDER_READY", "triggers": "NOTIFY_CUSTOMER" }] }
799
+ \`\`\`
800
+
801
+ **CRITICAL: For multi-entity apps:**
802
+ - Add relation fields to connect entities (e.g., Order \u2192 Customer, Order \u2192 MenuItem)
803
+ - Add emits/listens when one orbital's state change affects another
804
+ - Add relatedLinks for navigation between related records
805
+ `;
806
+ }
807
+
808
+ // src/prompts/skill-sections/custom-traits.ts
809
+ function getCustomTraitSection() {
810
+ return `## Custom Trait Guide
811
+
812
+ ### When to Create Custom Traits
813
+
814
+ | Scenario | Approach |
815
+ |----------|----------|
816
+ | Standard CRUD list/view/edit | Use \`std/List\` behavior pattern |
817
+ | Multi-step wizard | Custom trait with states = steps |
818
+ | Approval workflow | Custom trait (Drafting \u2192 InReview \u2192 Published) |
819
+ | Payment processing | Custom \`integration\` trait with call-service |
820
+ | Domain-specific workflow | Custom trait matching business states |
821
+
822
+ ### Trait Categories
823
+
824
+ | Category | Purpose | Requires render-ui? |
825
+ |----------|---------|---------------------|
826
+ | \`interaction\` | UI state machine | **YES** - must render UI |
827
+ | \`integration\` | Backend service calls | No |
828
+
829
+ ### Interaction Trait Requirements (CRITICAL)
830
+
831
+ Every \`interaction\` trait MUST have:
832
+ 1. **States as objects** with \`isInitial\` flag
833
+ 2. **INIT transition** (self-loop on initial state) that renders UI
834
+ 3. **render-ui effects** for every state transition
835
+ 4. **form-section with onSubmit** to connect forms to events
836
+
837
+ ### Example: Document Publishing Workflow
838
+
839
+ \`\`\`json
840
+ {
841
+ "name": "DocumentPublishing",
842
+ "category": "interaction",
843
+ "linkedEntity": "Document",
844
+ "stateMachine": {
845
+ "states": [
846
+ { "name": "Drafting", "isInitial": true },
847
+ { "name": "InReview" },
848
+ { "name": "Published" }
849
+ ],
850
+ "events": [
851
+ { "key": "INIT" },
852
+ { "key": "SUBMIT" },
853
+ { "key": "APPROVE" },
854
+ { "key": "REJECT" }
855
+ ],
856
+ "transitions": [
857
+ {
858
+ "from": "Drafting",
859
+ "to": "Drafting",
860
+ "event": "INIT",
861
+ "effects": [
862
+ ["render-ui", "main", {
863
+ "type": "page-header",
864
+ "title": "Edit Document",
865
+ "actions": [{ "label": "Submit", "event": "SUBMIT" }]
866
+ }],
867
+ ["render-ui", "main", {
868
+ "type": "form-section",
869
+ "entity": "Document",
870
+ "fields": ["title", "content"],
871
+ "onSubmit": "SUBMIT"
872
+ }]
873
+ ]
874
+ },
875
+ {
876
+ "from": "Drafting",
877
+ "to": "InReview",
878
+ "event": "SUBMIT",
879
+ "effects": [
880
+ ["set", "@entity.status", "review"],
881
+ ["persist", "update"],
882
+ ["render-ui", "main", {
883
+ "type": "page-header",
884
+ "title": "In Review"
885
+ }],
886
+ ["render-ui", "main", {
887
+ "type": "entity-detail",
888
+ "entity": "Document",
889
+ "fieldNames": ["title", "content"]
890
+ }],
891
+ ["render-ui", "main", {
892
+ "type": "form-section",
893
+ "submitLabel": "Approve",
894
+ "cancelLabel": "Reject",
895
+ "onSubmit": "APPROVE",
896
+ "onCancel": "REJECT"
897
+ }]
898
+ ]
899
+ },
900
+ {
901
+ "from": "InReview",
902
+ "to": "Drafting",
903
+ "event": "REJECT",
904
+ "effects": [
905
+ ["set", "@entity.status", "draft"],
906
+ ["persist", "update"],
907
+ ["emit", "INIT"]
908
+ ]
909
+ },
910
+ {
911
+ "from": "InReview",
912
+ "to": "Published",
913
+ "event": "APPROVE",
914
+ "effects": [
915
+ ["set", "@entity.status", "published"],
916
+ ["set", "@entity.publishedAt", "@now"],
917
+ ["persist", "update"],
918
+ ["render-ui", "main", {
919
+ "type": "page-header",
920
+ "title": "Published!"
921
+ }],
922
+ ["render-ui", "main", {
923
+ "type": "entity-detail",
924
+ "entity": "Document"
925
+ }]
926
+ ]
927
+ }
928
+ ]
929
+ }
930
+ }
931
+ \`\`\`
932
+
933
+ **Key Points:**
934
+ - INIT is a self-loop that renders the initial UI
935
+ - Every state transition has render-ui effects
936
+ - form-section always has onSubmit
937
+ - REJECT emits INIT to re-render Drafting state
938
+
939
+ ### Example: Integration Trait (Payment)
940
+
941
+ \`\`\`json
942
+ {
943
+ "name": "PaymentProcessing",
944
+ "category": "integration",
945
+ "linkedEntity": "Order",
946
+ "emits": [
947
+ {
948
+ "event": "ORDER_PAID",
949
+ "scope": "external",
950
+ "description": "Emitted when payment succeeds",
951
+ "payload": [
952
+ { "name": "orderId", "type": "string", "required": true, "description": "The paid order ID" },
953
+ { "name": "total", "type": "number", "required": true, "description": "Order total amount" }
954
+ ]
955
+ }
956
+ ],
957
+ "stateMachine": {
958
+ "states": [
959
+ { "name": "Pending", "isInitial": true },
960
+ { "name": "Processing" },
961
+ { "name": "Completed" },
962
+ { "name": "Failed" }
963
+ ],
964
+ "events": [
965
+ { "key": "PROCESS" },
966
+ { "key": "SUCCESS" },
967
+ { "key": "FAILURE" }
968
+ ],
969
+ "transitions": [
970
+ {
971
+ "from": "Pending",
972
+ "to": "Processing",
973
+ "event": "PROCESS",
974
+ "effects": [
975
+ ["call-service", "stripe", "charge", {
976
+ "amount": "@entity.total",
977
+ "onSuccess": "SUCCESS",
978
+ "onError": "FAILURE"
979
+ }]
980
+ ]
981
+ },
982
+ {
983
+ "from": "Processing",
984
+ "to": "Completed",
985
+ "event": "SUCCESS",
986
+ "effects": [
987
+ ["set", "@entity.paidAt", "@now"],
988
+ ["persist", "update"],
989
+ ["emit", "ORDER_PAID", { "orderId": "@entity.id", "total": "@entity.total" }]
990
+ ]
991
+ },
992
+ {
993
+ "from": "Processing",
994
+ "to": "Failed",
995
+ "event": "FAILURE",
996
+ "effects": [
997
+ ["notify", "Payment failed", "error"]
998
+ ]
999
+ }
1000
+ ]
1001
+ }
1002
+ }
1003
+ \`\`\`
1004
+
1005
+ **Note:** Integration traits don't need INIT or render-ui - they're triggered by events, not page load.
1006
+
1007
+ ### Cross-Orbital Communication (CRITICAL)
1008
+
1009
+ When traits need to communicate across orbitals, you MUST:
1010
+
1011
+ 1. **Declare emits with payload contract:**
1012
+ \`\`\`json
1013
+ "emits": [
1014
+ {
1015
+ "event": "ORDER_PAID",
1016
+ "scope": "external",
1017
+ "description": "Emitted when payment is confirmed",
1018
+ "payload": [
1019
+ { "name": "orderId", "type": "string", "required": true },
1020
+ { "name": "total", "type": "number", "required": true }
1021
+ ]
1022
+ }
1023
+ ]
1024
+ \`\`\`
1025
+
1026
+ 2. **Include payload data in emit effect:**
1027
+ \`\`\`json
1028
+ ["emit", "ORDER_PAID", { "orderId": "@entity.id", "total": "@entity.total" }]
1029
+ \`\`\`
1030
+
1031
+ 3. **Declare listeners with payloadMapping:**
1032
+ \`\`\`json
1033
+ "listens": [
1034
+ {
1035
+ "event": "PaymentProcessing.ORDER_PAID",
1036
+ "scope": "external",
1037
+ "triggers": "SEND_RECEIPT",
1038
+ "payloadMapping": {
1039
+ "orderId": "@payload.orderId",
1040
+ "amount": "@payload.total"
1041
+ }
1042
+ }
1043
+ ]
1044
+ \`\`\`
1045
+
1046
+ ### Anti-Patterns to Avoid
1047
+
1048
+ | Anti-Pattern | Problem | Fix |
1049
+ |--------------|---------|-----|
1050
+ | Missing INIT | Page is blank | Add self-loop with render-ui |
1051
+ | States as strings | Validation fails | Use \`{ "name": "...", "isInitial": true }\` |
1052
+ | No render-ui | UI doesn't update | Add render-ui to every transition |
1053
+ | form-section no onSubmit | Form does nothing | Add \`onSubmit: "EVENT"\` |
1054
+ | **Using form-actions** | **Pattern doesn't exist!** | **Use form-section with onSubmit/onCancel** |
1055
+ | Duplicate (from, event) | Second unreachable | Use guards or different events |
1056
+ | from: '*' | Non-deterministic | Use explicit from state |
1057
+ | **External emit no payload** | **Listeners have no data** | **Add payload array with typed fields** |
1058
+ | **emit effect no data** | **Payload is empty at runtime** | **Pass payload object: \`["emit", "EVT", {...}]\`** |
1059
+
1060
+ ### Pattern Action Props Quick Reference
1061
+
1062
+ | Pattern | Action Props | Purpose |
1063
+ |---------|--------------|---------|
1064
+ | \`page-header\` | \`actions: [{label, event}]\` | Top-right buttons (New, Export) |
1065
+ | \`form-section\` | \`onSubmit\`, \`onCancel\` | Form submit/cancel buttons |
1066
+ | \`entity-table\` | \`itemActions: [{label, event}]\` | Row action buttons (Edit, Delete) |
1067
+ | \`entity-detail\` | \`headerActions: [{label, event}]\` | Detail view header buttons |
1068
+ | \`confirmation\` | \`onConfirm\`, \`onCancel\` | Confirmation dialog buttons |
1069
+ `;
1070
+ }
1071
+ function getCustomTraitCompact() {
1072
+ return `## Custom Traits
1073
+
1074
+ **Interaction traits** (UI): MUST have INIT self-loop with render-ui
1075
+ **Integration traits** (backend): call-service, no render-ui needed
1076
+
1077
+ States = \`{ "name": "...", "isInitial": true }\` (objects, not strings)
1078
+ form-section = always include \`onSubmit: "EVENT"\`
1079
+ `;
1080
+ }
1081
+
1082
+ // src/prompts/skill-sections/schema-updates.ts
1083
+ function getSchemaUpdateSection() {
1084
+ return `## Updating Existing Schemas
1085
+
1086
+ When modifying an existing orbital schema, follow this systematic approach:
1087
+
1088
+ ### Step 1: Locate the Target
1089
+
1090
+ Use grep/search to find the right location:
1091
+
1092
+ \`\`\`bash
1093
+ # Find entity by name
1094
+ grep -n '"entity"' schema.orb -A 5 | grep "TaskEntity"
1095
+
1096
+ # Find trait by name
1097
+ grep -n '"traits"' schema.orb | head -10
1098
+
1099
+ # Find specific trait definition
1100
+ grep -n '"TaskInteraction"' schema.orb
1101
+
1102
+ # Find state machine transitions
1103
+ grep -n '"transitions"' schema.orb -A 30 | head -50
1104
+
1105
+ # Find all events
1106
+ grep -n '"events"' schema.orb
1107
+
1108
+ # Find all pages
1109
+ grep -n '"pages"' schema.orb -A 10
1110
+ \`\`\`
1111
+
1112
+ ### Step 2: Identify What to Modify
1113
+
1114
+ | Change Type | Location to Find | What to Modify |
1115
+ |-------------|------------------|----------------|
1116
+ | Add field | \`"fields": [\` | Add to entity.fields array |
1117
+ | Add event | \`"events": [\` | Add to stateMachine.events |
1118
+ | Add state | \`"states": [\` | Add to stateMachine.states |
1119
+ | Add transition | \`"transitions": [\` | Add to stateMachine.transitions |
1120
+ | Add action button | \`"page-header"\` or \`"itemActions"\` | Add to pattern props |
1121
+ | Add page | \`"pages": [\` | Add to orbital.pages array |
1122
+ | Modify UI | \`"render-ui"\` | Find transition with target slot |
1123
+
1124
+ ### Step 3: Common Modifications
1125
+
1126
+ **Add a new field to entity:**
1127
+ \`\`\`json
1128
+ // Find: "fields": [
1129
+ // Add before the closing bracket:
1130
+ { "name": "priority", "type": "enum", "values": ["low", "medium", "high"] }
1131
+ \`\`\`
1132
+
1133
+ **Add a new action button to page-header:**
1134
+ \`\`\`json
1135
+ // Find: INIT transition's page-header
1136
+ // Add to actions array:
1137
+ { "label": "Export", "event": "EXPORT", "variant": "secondary" }
1138
+ \`\`\`
1139
+
1140
+ **Add a new event:**
1141
+ \`\`\`json
1142
+ // Find: "events": [
1143
+ // Add the event:
1144
+ { "key": "EXPORT", "name": "Export Data" }
1145
+ \`\`\`
1146
+
1147
+ **Add a new transition:**
1148
+ \`\`\`json
1149
+ // Find: "transitions": [
1150
+ // Add after existing transitions:
1151
+ {
1152
+ "from": "Browsing",
1153
+ "to": "Exporting",
1154
+ "event": "EXPORT",
1155
+ "effects": [
1156
+ ["render-ui", "modal", { "type": "confirmation", "title": "Export?", "onConfirm": "CONFIRM_EXPORT", "onCancel": "CANCEL" }]
1157
+ ]
1158
+ }
1159
+ \`\`\`
1160
+
1161
+ **Add itemActions to entity-table:**
1162
+ \`\`\`json
1163
+ // Find: "entity-table" in INIT transition
1164
+ // Add itemActions prop:
1165
+ "itemActions": [
1166
+ { "label": "View", "event": "VIEW" },
1167
+ { "label": "Edit", "event": "EDIT" },
1168
+ { "label": "Delete", "event": "DELETE", "isDestructive": true }
1169
+ ]
1170
+ \`\`\`
1171
+
1172
+ ### Step 4: Ensure Completeness
1173
+
1174
+ After any modification, verify:
1175
+
1176
+ 1. **New events have matching transitions** - Every event must have at least one transition that uses it
1177
+ 2. **New states are reachable** - Every state must have a transition leading to it
1178
+ 3. **New states have exit transitions** - Every state (except browsing) needs a way back
1179
+ 4. **UI slots are cleared** - Modals/drawers opened must be closed with \`["render-ui", "modal", null]\`
1180
+
1181
+ ### Quick Reference: Finding Traits
1182
+
1183
+ Traits are defined in two places:
1184
+
1185
+ 1. **Inline in orbital** (most common):
1186
+ \`\`\`json
1187
+ "orbitals": [{
1188
+ "traits": [{
1189
+ "name": "TaskInteraction",
1190
+ "stateMachine": { ... } // <-- trait definition here
1191
+ }]
1192
+ }]
1193
+ \`\`\`
1194
+
1195
+ 2. **Referenced from library**:
1196
+ \`\`\`json
1197
+ "orbitals": [{
1198
+ "traits": [{
1199
+ "ref": "std/crud" // <-- references external trait
1200
+ }]
1201
+ }]
1202
+ \`\`\`
1203
+
1204
+ For inline traits, grep for the trait name. For library traits, find the library file.
1205
+
1206
+ ---
1207
+
1208
+ ## Large Schema Handling (40KB+)
1209
+
1210
+ For schemas exceeding 40KB, use the **chunking tools** instead of direct editing:
1211
+
1212
+ ### Available Tools
1213
+
1214
+ | Tool | Purpose |
1215
+ |------|---------|
1216
+ | \`query_schema_structure\` | Get lightweight map (~500 bytes): orbitals, traits, sizes |
1217
+ | \`extract_chunk\` | Extract orbital/trait to \`.chunks/chunk-{id}.json\` |
1218
+ | \`apply_chunk\` | Merge edited chunk back into schema |
1219
+
1220
+ **Note**: These tools work with both \`schema.json\` and \`schema.orb\` files. Changes are auto-persisted.
1221
+
1222
+ ### Chunking Workflow
1223
+
1224
+ \`\`\`
1225
+ 1. DISCOVER: query_schema_structure("schema.orb")
1226
+ \u2192 Returns structure map with orbital/trait names
1227
+
1228
+ 2. EXTRACT: extract_chunk({ file: "schema.orb", type: "orbital", name: "Task Management" })
1229
+ \u2192 Creates .chunks/chunk-{id}.json (2-5KB, easy to edit)
1230
+
1231
+ 3. EDIT: Use edit_file on chunk file (NOT full schema)
1232
+ \u2192 Much smaller = reliable edits
1233
+
1234
+ 4. APPLY: apply_chunk({ chunkId: "..." })
1235
+ \u2192 Merges changes back into schema.orb, auto-persists to database
1236
+ \`\`\`
1237
+
1238
+ ### Chunk Types
1239
+
1240
+ | Type | When to Use |
1241
+ |------|-------------|
1242
+ | \`orbital\` | Adding fields, modifying inline traits |
1243
+ | \`inline-trait\` | Editing trait inside an orbital (requires \`parentOrbital\`) |
1244
+
1245
+ **Note**: There is no schema-level \`traits[]\` array. All traits belong inside orbitals.
1246
+
1247
+ ### When to Use Chunking
1248
+
1249
+ | Schema Size | Strategy |
1250
+ |-------------|----------|
1251
+ | < 15KB | Direct edit (works fine) |
1252
+ | 15-40KB | Targeted edit_file |
1253
+ | > 40KB | **Use chunking tools** |`;
1254
+ }
1255
+ function getSchemaUpdateCompact() {
1256
+ return `## Schema Updates Quick Reference
1257
+
1258
+ **Find location:**
1259
+ \`\`\`bash
1260
+ grep -n '"entity"' schema.orb -A 5 # Find entities
1261
+ grep -n '"traits"' schema.orb # Find traits
1262
+ grep -n '"transitions"' schema.orb # Find transitions
1263
+ \`\`\`
1264
+
1265
+ **Common changes:**
1266
+ | Change | Find | Add to |
1267
+ |--------|------|--------|
1268
+ | Field | \`"fields": [\` | Entity fields array |
1269
+ | Event | \`"events": [\` | StateMachine events |
1270
+ | State | \`"states": [\` | StateMachine states |
1271
+ | Transition | \`"transitions": [\` | StateMachine transitions |
1272
+ | Button | \`"page-header"\` | actions array |
1273
+ | Row action | \`"entity-table"\` | itemActions array |
1274
+
1275
+ **After changes, verify:**
1276
+ - New events have transitions using them
1277
+ - New states are reachable and have exits
1278
+ - Modals/drawers are closed on completion`;
1279
+ }
1280
+
1281
+ // src/prompts/skill-sections/context-usage.ts
1282
+ function getContextUsageSection() {
1283
+ return `## Using Embedded Context
1284
+
1285
+ When generating, read context from the orbital:
1286
+
1287
+ | Context Field | Usage |
1288
+ |---------------|-------|
1289
+ | \`domainContext.requestFragment\` | Understand what user asked for |
1290
+ | \`domainContext.category\` | Influences pattern selection |
1291
+ | \`domainContext.vocabulary\` | Use for button labels, titles, messages |
1292
+ | \`design.style\` | Influences visual density and components |
1293
+ | \`design.uxHints.flowPattern\` | Determines overall navigation structure |
1294
+ | \`design.uxHints.listPattern\` | Use for entity display (table/cards/list) |
1295
+ | \`design.uxHints.formPattern\` | Use for create/edit (modal/drawer/page) |
1296
+ | \`design.uxHints.detailPattern\` | Use for detail view (drawer/page/split) |
1297
+ | \`design.uxHints.relatedLinks\` | Add navigation to related orbitals |
1298
+
1299
+ **Example usage in generation:**
1300
+ \`\`\`
1301
+ If domainContext.vocabulary.create = "Recruit"
1302
+ \u2192 Button label: "Recruit" instead of "Create"
1303
+
1304
+ If design.uxHints.listPattern = "entity-cards"
1305
+ \u2192 Use entity-cards pattern instead of entity-table
1306
+
1307
+ If design.uxHints.formPattern = "drawer"
1308
+ \u2192 Render create/edit forms in drawer slot
1309
+ \`\`\`
1310
+ `;
1311
+ }
1312
+ function getContextUsageCompact() {
1313
+ return `## Context Usage
1314
+ - \`domainContext.vocabulary\` \u2192 labels (item, create, delete)
1315
+ - \`design.uxHints.listPattern\` \u2192 entity-table | entity-cards | entity-list
1316
+ - \`design.uxHints.formPattern\` \u2192 modal | drawer | page
1317
+ - \`design.uxHints.relatedLinks\` \u2192 navigation to related orbitals
1318
+ `;
1319
+ }
1320
+
1321
+ // src/prompts/skill-sections/design-errors.ts
1322
+ function getDesignErrorsSection() {
1323
+ return `## \u274C Design-Specific Errors
1324
+
1325
+ | Error | Wrong | Correct |
1326
+ |-------|-------|---------|
1327
+ | Entity binding | \`@entity.task.title\` | \`@entity.title\` |
1328
+ | Toast effect | \`["toast", "success", "msg"]\` | \`["notify", "in_app", "msg"]\` |
1329
+ | Select missing options | \`{ "type": "select" }\` | Add \`"options": [{ "value": "x", "label": "X" }]\` |
1330
+ | Undefined trait | \`{ "ref": "NewTrait" }\` | Define trait in \`traits[]\` FIRST |
1331
+ | Missing action | \`{ "type": "button" }\` | \`{ "type": "button", "action": "SAVE" }\` |
1332
+
1333
+ ### Entity Bindings (CRITICAL)
1334
+
1335
+ \`@entity\` already knows the entity type. Access fields directly:
1336
+
1337
+ \`\`\`
1338
+ \u2705 @entity.title - Direct field access
1339
+ \u2705 @entity.address.city - Nested object field (address is an object)
1340
+ \u274C @entity.task.title - Wrong! "task" is the entity type, not a field
1341
+ \`\`\`
1342
+
1343
+ ### Notification Effects
1344
+
1345
+ Use \`notify\` effect, NOT \`toast\`:
1346
+
1347
+ \`\`\`json
1348
+ ["notify", "in_app", "Saved!", "success"] // \u2705 Correct
1349
+ ["toast", "success", "Saved!"] // \u274C Invalid effect
1350
+ \`\`\`
1351
+
1352
+ Variants: \`success\`, \`error\`, \`warning\`, \`info\`
1353
+
1354
+ ### Form Select Fields
1355
+
1356
+ Select fields REQUIRE options array:
1357
+
1358
+ \`\`\`json
1359
+ // \u274C Wrong - missing options
1360
+ { "name": "status", "type": "select" }
1361
+
1362
+ // \u2705 Correct - options provided
1363
+ {
1364
+ "name": "status",
1365
+ "type": "select",
1366
+ "options": [
1367
+ { "value": "todo", "label": "To Do" },
1368
+ { "value": "done", "label": "Done" }
1369
+ ]
1370
+ }
1371
+ \`\`\`
1372
+ `;
1373
+ }
1374
+ function getDesignErrorsCompact() {
1375
+ return `## \u274C Design Errors
1376
+
1377
+ | Wrong | Correct |
1378
+ |-------|---------|
1379
+ | \`@entity.task.title\` | \`@entity.title\` |
1380
+ | \`["toast", "success", "msg"]\` | \`["notify", "in_app", "msg"]\` |
1381
+ | \`{ "type": "select" }\` | Add \`options: [{value, label}]\` |
1382
+ | \`{ "ref": "NewTrait" }\` | Define in \`traits[]\` first |
1383
+ `;
1384
+ }
1385
+ function getIconLibrarySection() {
1386
+ return `### Icons (Lucide)
1387
+
1388
+ Use kebab-case icon names from Lucide:
1389
+
1390
+ | Category | Icons |
1391
+ |----------|-------|
1392
+ | Actions | \`plus\`, \`pencil\`, \`trash\`, \`eye\`, \`check\`, \`x\`, \`save\` |
1393
+ | Navigation | \`chevron-left\`, \`chevron-right\`, \`arrow-left\`, \`home\`, \`menu\` |
1394
+ | Status | \`check-circle\`, \`x-circle\`, \`alert-circle\`, \`clock\`, \`loader\` |
1395
+ | Content | \`file\`, \`folder\`, \`image\`, \`list\`, \`grid\`, \`clipboard\` |
1396
+ | UI | \`search\`, \`filter\`, \`settings\`, \`more-horizontal\`, \`bell\` |
1397
+
1398
+ \`\`\`json
1399
+ { "type": "button", "icon": "plus", "label": "Add" }
1400
+ { "label": "Delete", "icon": "trash", "event": "DELETE" }
1401
+ \`\`\`
1402
+ `;
1403
+ }
1404
+ function getIconLibraryCompact() {
1405
+ return `**Icons (Lucide)**: \`plus\`, \`pencil\`, \`trash\`, \`check-circle\`, \`x-circle\`, \`eye\`, \`settings\`, \`search\`, \`filter\``;
1406
+ }
1407
+
1408
+ // src/prompts/skill-sections/fixing-guidance.ts
1409
+ function getFixingWorkflowSection() {
1410
+ return `## Fixing Workflow
1411
+
1412
+ ### Step 1: Validate and Analyze
1413
+
1414
+ \`\`\`
1415
+ validate_schema()
1416
+ \`\`\`
1417
+
1418
+ Group errors by orbital component:
1419
+ - **Entity errors**: Field types, relations, collection names
1420
+ - **Trait errors**: State machine, events, transitions
1421
+ - **Page errors**: Missing traits, invalid references
1422
+ - **Pattern errors**: Missing required fields in render-ui
1423
+
1424
+ ### Step 2: Apply Batched Fixes
1425
+
1426
+ Fix ALL errors of the same type in one edit. Priority order:
1427
+
1428
+ 1. **Entity fixes** (field types, enums, relations)
1429
+ 2. **State machine fixes** (initial state, orphan states)
1430
+ 3. **Transition fixes** (missing INIT, unreachable states)
1431
+ 4. **Pattern fixes** (missing props in render-ui effects)
1432
+
1433
+ ### Step 3: Re-validate
1434
+
1435
+ \`\`\`
1436
+ validate_schema()
1437
+ \`\`\`
1438
+
1439
+ **STOP when "valid": true** - do not add more tasks or re-verify.`;
1440
+ }
1441
+ function getCommonFixPatternsSection() {
1442
+ return `## Common Fix Patterns
1443
+
1444
+ ### Entity Fixes
1445
+
1446
+ | Error | Before | After |
1447
+ |-------|--------|-------|
1448
+ | Wrong enum syntax | \`"enumValues": [...]\` | \`"values": [...]\` |
1449
+ | Wrong relation | \`"type": "many-to-one"\` | \`"relationType": "many-to-one"\` |
1450
+ | Missing collection | (none) | \`"collection": "tasks"\` |
1451
+
1452
+ ### State Machine Fixes
1453
+
1454
+ | Error | Before | After |
1455
+ |-------|--------|-------|
1456
+ | No initial state | \`{ "name": "Idle" }\` | \`{ "name": "Idle", "isInitial": true }\` |
1457
+ | String states | \`"states": ["Idle"]\` | \`"states": [{ "name": "Idle", "isInitial": true }]\` |
1458
+ | Missing event | (not in events) | Add to \`"events": [...]\` |
1459
+
1460
+ ### Transition Fixes
1461
+
1462
+ | Error | Fix |
1463
+ |-------|-----|
1464
+ | No INIT transition | Add self-loop: \`{ "from": "Browsing", "to": "Browsing", "event": "INIT", "effects": [...] }\` |
1465
+ | Orphan state | Add transition TO the state from initial |
1466
+ | No exit from state | Add transition FROM the state back to browsing |
1467
+
1468
+ ### Pattern Fixes (in render-ui effects)
1469
+
1470
+ | Pattern | Missing | Add |
1471
+ |---------|---------|-----|
1472
+ | \`entity-table\` | columns | \`"columns": ["field1", "field2"]\` |
1473
+ | \`entity-table\` | itemActions | \`"itemActions": [{ "label": "Edit", "event": "EDIT" }]\` |
1474
+ | \`form-section\` | onSubmit | \`"onSubmit": "SAVE"\` |
1475
+ | \`form-section\` | fields | \`"fields": ["field1", "field2"]\` |
1476
+ | \`entity-detail\` | fieldNames | \`"fieldNames": ["field1", "field2"]\` |
1477
+ | \`page-header\` | actions | \`"actions": [{ "label": "New", "event": "CREATE" }]\` |`;
1478
+ }
1479
+ function getOverGenerationSection() {
1480
+ return `## Over-Generation Detection
1481
+
1482
+ **Signs of over-generation:**
1483
+ - TaskListPage + TaskCreatePage + TaskEditPage + TaskViewPage (4 pages for 1 entity!)
1484
+ - Multiple pages for the same entity CRUD
1485
+
1486
+ **Fix:** Consolidate to ONE page with trait-driven UI:
1487
+
1488
+ \`\`\`json
1489
+ // KEEP only:
1490
+ {
1491
+ "pages": [{
1492
+ "name": "TasksPage",
1493
+ "path": "/tasks",
1494
+ "viewType": "list",
1495
+ "traits": [{ "ref": "TaskInteraction" }]
1496
+ }]
1497
+ }
1498
+
1499
+ // DELETE separate create/edit/view pages
1500
+ \`\`\`
1501
+
1502
+ The trait's render-ui effects handle all UI (modals for create/edit, drawers for view).`;
1503
+ }
1504
+ function getEfficiencySection() {
1505
+ return `## Efficiency Guidelines
1506
+
1507
+ Target: **30-50 tool calls** for most fixes.
1508
+
1509
+ **DO:**
1510
+ - Batch related changes (read once, edit all, write once)
1511
+ - Fix all same-type errors together
1512
+ - Run validation once after all changes
1513
+
1514
+ **DON'T:**
1515
+ - Read schema multiple times without changes
1516
+ - Make one small change per tool call
1517
+ - Re-verify after validation passes
1518
+ - Create documentation files`;
1519
+ }
1520
+ function getCompletionRulesSection() {
1521
+ return `## Completion Rules
1522
+
1523
+ **STOP IMMEDIATELY when:**
1524
+ - \`validate_schema()\` returns \`"valid": true\`
1525
+
1526
+ **After validation passes:**
1527
+ 1. Mark todos complete
1528
+ 2. STOP - do not add more tasks
1529
+ 3. Do NOT create documentation
1530
+ 4. Do NOT "verify" or "confirm"
1531
+ 5. Do NOT validate again
1532
+
1533
+ The validated schema.json IS your only deliverable.`;
1534
+ }
1535
+
1536
+ // src/prompts/skill-sections/game-guidance.ts
1537
+ function getGameAsOrbitalsSection() {
1538
+ return `## Games as Orbital Composition
1539
+
1540
+ A game is a **list of orbitals**, each representing a game element:
1541
+
1542
+ \`\`\`
1543
+ Game Application = \u03A3(Game Orbitals)
1544
+
1545
+ \u251C\u2500\u2500 Player Orbital (runtime entity + input/physics traits)
1546
+ \u251C\u2500\u2500 Enemy Orbital (runtime entity + AI/physics traits)
1547
+ \u251C\u2500\u2500 Item Orbital (runtime entity + collectible trait)
1548
+ \u251C\u2500\u2500 Level Orbital (singleton entity + level loader trait)
1549
+ \u2514\u2500\u2500 GameState Orbital (singleton + score/health traits)
1550
+ \`\`\`
1551
+
1552
+ ### Persistence Types for Games
1553
+
1554
+ | Type | Use Case | Example |
1555
+ |------|----------|---------|
1556
+ | \`runtime: true\` | Active game objects | Player, Enemy, Bullet |
1557
+ | \`singleton: true\` | Global state | GameConfig, LevelState |
1558
+ | \`collection: "..."\` | Saved data | HighScores, SavedGames |`;
1559
+ }
1560
+ function getGameEntityTemplatesSection() {
1561
+ return `## Game Entity Templates
1562
+
1563
+ ### Player Entity (runtime)
1564
+
1565
+ \`\`\`json
1566
+ {
1567
+ "name": "Player",
1568
+ "runtime": true,
1569
+ "fields": [
1570
+ { "name": "x", "type": "number", "default": 100 },
1571
+ { "name": "y", "type": "number", "default": 100 },
1572
+ { "name": "velocityX", "type": "number", "default": 0 },
1573
+ { "name": "velocityY", "type": "number", "default": 0 },
1574
+ { "name": "health", "type": "number", "default": 100 },
1575
+ { "name": "facing", "type": "enum", "values": ["left", "right"], "default": "right" }
1576
+ ]
1577
+ }
1578
+ \`\`\`
1579
+
1580
+ ### GameState Entity (singleton)
1581
+
1582
+ \`\`\`json
1583
+ {
1584
+ "name": "GameState",
1585
+ "singleton": true,
1586
+ "fields": [
1587
+ { "name": "score", "type": "number", "default": 0 },
1588
+ { "name": "level", "type": "number", "default": 1 },
1589
+ { "name": "lives", "type": "number", "default": 3 },
1590
+ { "name": "state", "type": "enum", "values": ["menu", "playing", "paused", "gameOver"] }
1591
+ ]
1592
+ }
1593
+ \`\`\`
1594
+
1595
+ ### Enemy Entity (runtime)
1596
+
1597
+ \`\`\`json
1598
+ {
1599
+ "name": "Enemy",
1600
+ "runtime": true,
1601
+ "fields": [
1602
+ { "name": "x", "type": "number" },
1603
+ { "name": "y", "type": "number" },
1604
+ { "name": "health", "type": "number", "default": 30 },
1605
+ { "name": "damage", "type": "number", "default": 10 },
1606
+ { "name": "patrolStart", "type": "number" },
1607
+ { "name": "patrolEnd", "type": "number" }
1608
+ ]
1609
+ }
1610
+ \`\`\``;
1611
+ }
1612
+ function getGameTraitsSection() {
1613
+ return `## Game Traits
1614
+
1615
+ ### Core Game Traits
1616
+
1617
+ | Trait | Purpose | Key States |
1618
+ |-------|---------|------------|
1619
+ | \`Physics2D\` | Gravity, velocity | grounded, airborne, falling |
1620
+ | \`PlatformerInput\` | Movement controls | idle, moving, jumping |
1621
+ | \`Health\` | Damage, death | alive, hurt, dead |
1622
+ | \`Score\` | Points tracking | (stateless - just effects) |
1623
+ | \`Collectible\` | Pickup items | available, collected |
1624
+ | \`Patrol\` | Enemy AI | patrolling, reversing |
1625
+ | \`GameState\` | Game flow | menu, playing, paused, gameOver |
1626
+
1627
+ ### Game Trait Example
1628
+
1629
+ \`\`\`json
1630
+ {
1631
+ "name": "Physics2D",
1632
+ "category": "interaction",
1633
+ "linkedEntity": "Player",
1634
+ "stateMachine": {
1635
+ "states": [
1636
+ { "name": "grounded", "isInitial": true },
1637
+ { "name": "airborne" }
1638
+ ],
1639
+ "events": [
1640
+ { "key": "JUMP", "name": "Jump" },
1641
+ { "key": "LAND", "name": "Land" }
1642
+ ],
1643
+ "transitions": [
1644
+ {
1645
+ "from": "grounded",
1646
+ "to": "airborne",
1647
+ "event": "JUMP",
1648
+ "effects": [
1649
+ ["set", "@entity.velocityY", -15],
1650
+ ["emit", "PLAYER_JUMPED", "@entity"]
1651
+ ]
1652
+ },
1653
+ {
1654
+ "from": "airborne",
1655
+ "to": "grounded",
1656
+ "event": "LAND",
1657
+ "effects": [
1658
+ ["set", "@entity.velocityY", 0],
1659
+ ["set", "@entity.isGrounded", true]
1660
+ ]
1661
+ }
1662
+ ]
1663
+ }
1664
+ }
1665
+ \`\`\``;
1666
+ }
1667
+ function getGamePatternsSection() {
1668
+ return `## Game UI Patterns
1669
+
1670
+ | Pattern | Slot | Purpose |
1671
+ |---------|------|---------|
1672
+ | \`game-canvas\` | main | Main game rendering |
1673
+ | \`game-hud\` | overlay | Score, health, lives |
1674
+ | \`game-controls\` | overlay | Touch/keyboard hints |
1675
+ | \`game-menu\` | modal | Pause, settings |
1676
+
1677
+ ### Game Canvas Effect
1678
+
1679
+ \`\`\`json
1680
+ ["render-ui", "main", {
1681
+ "type": "game-canvas",
1682
+ "entities": ["Player", "Enemy", "Coin", "Platform"],
1683
+ "camera": { "follow": "Player" },
1684
+ "physics": { "gravity": 980 }
1685
+ }]
1686
+ \`\`\`
1687
+
1688
+ ### Game HUD Effect
1689
+
1690
+ \`\`\`json
1691
+ ["render-ui", "overlay", {
1692
+ "type": "game-hud",
1693
+ "elements": [
1694
+ { "type": "health-bar", "entity": "Player", "field": "health" },
1695
+ { "type": "score-display", "entity": "GameState", "field": "score" },
1696
+ { "type": "lives-counter", "entity": "GameState", "field": "lives" }
1697
+ ]
1698
+ }]
1699
+ \`\`\``;
1700
+ }
1701
+ function getAssetRefSection() {
1702
+ return `## Asset References
1703
+
1704
+ **NEVER hardcode asset paths. Use assetRef:**
1705
+
1706
+ \`\`\`json
1707
+ {
1708
+ "entity": {
1709
+ "name": "Player",
1710
+ "assetRef": {
1711
+ "role": "player",
1712
+ "category": "hero",
1713
+ "animations": ["idle", "run", "jump", "fall", "hurt"],
1714
+ "style": "pixel"
1715
+ }
1716
+ }
1717
+ }
1718
+ \`\`\`
1719
+
1720
+ The compiler resolves \`assetRef\` to actual sprite paths at build time.
1721
+
1722
+ ### Animation Mapping
1723
+
1724
+ | State | Animation |
1725
+ |-------|-----------|
1726
+ | grounded + idle | \`idle\` |
1727
+ | grounded + moving | \`run\` |
1728
+ | airborne + velocityY < 0 | \`jump\` |
1729
+ | airborne + velocityY > 0 | \`fall\` |
1730
+ | taking damage | \`hurt\` |
1731
+ | health <= 0 | \`die\` |`;
1732
+ }
1733
+ function getMultiFileSection() {
1734
+ return `## Multi-File Composition
1735
+
1736
+ Split large games into multiple .orb files:
1737
+
1738
+ \`\`\`
1739
+ game/
1740
+ \u251C\u2500\u2500 game.orb # Main schema with Player, GameState
1741
+ \u251C\u2500\u2500 enemies.orb # Enemy orbital definitions
1742
+ \u251C\u2500\u2500 items.orb # Collectibles, powerups
1743
+ \u2514\u2500\u2500 tiles.orb # Platforms, terrain
1744
+ \`\`\`
1745
+
1746
+ ### External Reference Syntax
1747
+
1748
+ \`\`\`json
1749
+ {
1750
+ "name": "Level1Enemies",
1751
+ "ref": "./enemies.orb#Slime",
1752
+ "instances": [
1753
+ { "id": "slime-1", "position": { "x": 300, "y": 400 } },
1754
+ { "id": "slime-2", "position": { "x": 600, "y": 400 } }
1755
+ ]
1756
+ }
1757
+ \`\`\``;
1758
+ }
1759
+ function getGameTypesSection() {
1760
+ return `## Game Type Templates
1761
+
1762
+ ### Platformer
1763
+ - Player with Physics2D + PlatformerInput
1764
+ - Platform entities for level layout
1765
+ - Collectible coins/items
1766
+ - Enemies with Patrol trait
1767
+
1768
+ ### Puzzle (Match-3, Tetris)
1769
+ - Grid-based entity (runtime singleton)
1770
+ - Tile/Piece entities
1771
+ - Match detection logic in trait
1772
+ - Score tracking
1773
+
1774
+ ### Roguelike
1775
+ - Player with Health + Inventory
1776
+ - Dungeon/Room singleton for level gen
1777
+ - Enemy entities with AI traits
1778
+ - Turn-based or real-time movement
1779
+
1780
+ ### Endless Runner
1781
+ - Player at fixed X, jumping
1782
+ - Obstacles spawning and moving
1783
+ - Procedural difficulty scaling
1784
+ - Distance-based scoring`;
1785
+ }
1786
+
1787
+ // src/prompts/skill-sections/uses-imports.ts
1788
+ function getUsesImportSection() {
1789
+ return `## Orbital Import System (\`uses\`)
1790
+
1791
+ Orbitals can import other orbitals to reuse their components.
1792
+
1793
+ ### Basic Usage
1794
+
1795
+ \`\`\`json
1796
+ {
1797
+ "name": "Level1",
1798
+ "uses": [
1799
+ { "from": "./goblin.orb", "as": "Goblin" },
1800
+ { "from": "./health.orb", "as": "Health" }
1801
+ ],
1802
+ "entity": "Goblin.entity",
1803
+ "traits": [
1804
+ "Goblin.traits.Movement",
1805
+ "Health.traits.Health"
1806
+ ],
1807
+ "pages": []
1808
+ }
1809
+ \`\`\`
1810
+
1811
+ ### Component References
1812
+
1813
+ After importing with \`uses\`, access components via:
1814
+
1815
+ | Component | Reference Format | Example |
1816
+ |-----------|------------------|---------|
1817
+ | Entity | \`Alias.entity\` | \`"entity": "Goblin.entity"\` |
1818
+ | Trait | \`Alias.traits.TraitName\` | \`"traits": ["Health.traits.Health"]\` |
1819
+ | Page | \`Alias.pages.PageName\` | \`"pages": ["User.pages.Profile"]\` |
1820
+
1821
+ ### Page Path Override
1822
+
1823
+ When importing a page, you can override its URL path:
1824
+
1825
+ \`\`\`json
1826
+ {
1827
+ "pages": [
1828
+ { "ref": "User.pages.Profile", "path": "/my-profile" }
1829
+ ]
1830
+ }
1831
+ \`\`\`
1832
+
1833
+ ### Entity Persistence Semantics
1834
+
1835
+ When you reference an imported entity, the behavior depends on its persistence type:
1836
+
1837
+ | Persistence | Sharing Behavior | Use Case |
1838
+ |-------------|------------------|----------|
1839
+ | \`persistent\` | **Shared** - Same DB collection | Users, Products, Orders |
1840
+ | \`runtime\` | **Isolated** - Each orbital gets own instances | Game entities, UI state |
1841
+ | \`singleton\` | **Shared** - Single global instance | Config, Game state |
1842
+
1843
+ **Example**: Two orbitals importing a \`runtime\` entity each get separate instances:
1844
+ \`\`\`json
1845
+ // level1.orb
1846
+ { "entity": "Goblin.entity" } // Level1's goblins
1847
+
1848
+ // level2.orb
1849
+ { "entity": "Goblin.entity" } // Level2's goblins (separate!)
1850
+ \`\`\`
1851
+
1852
+ ### Import Sources
1853
+
1854
+ | Source Format | Description |
1855
+ |---------------|-------------|
1856
+ | \`"./path.orb"\` | Local relative path |
1857
+ | \`"../shared/health.orb"\` | Parent directory |
1858
+ | \`"std/behaviors/game-core"\` | Standard library |
1859
+ | \`"@game-lib/enemies.orb"\` | Scoped package |
1860
+
1861
+ ### Key Rules
1862
+
1863
+ 1. **Alias must be PascalCase** - e.g., \`"as": "Health"\`, NOT \`"as": "health"\`
1864
+ 2. **All traits belong in orbitals** - No schema-level \`traits[]\` array
1865
+ 3. **References must match imports** - \`Goblin.entity\` requires \`{ "as": "Goblin" }\` in \`uses\`
1866
+ 4. **Inline OR reference** - Each component slot accepts either form
1867
+ `;
1868
+ }
1869
+ function getUsesImportCompact() {
1870
+ return `## Orbital Imports (\`uses\`)
1871
+
1872
+ Import other orbitals and reference their components:
1873
+
1874
+ \`\`\`json
1875
+ {
1876
+ "uses": [{ "from": "./health.orb", "as": "Health" }],
1877
+ "entity": "Health.entity", // Reference entity
1878
+ "traits": ["Health.traits.Health"], // Reference trait
1879
+ "pages": ["Health.pages.Dashboard"] // Reference page
1880
+ }
1881
+ \`\`\`
1882
+
1883
+ **Alias must be PascalCase.** No schema-level \`traits[]\` array exists.
1884
+ `;
1885
+ }
1886
+
1887
+ // src/orbitals-skills-generators/lean-orbital-skill-generator.ts
1888
+ function generateLeanOrbitalSkill(options = {}) {
1889
+ const {
1890
+ includeExample = true,
1891
+ includeToolWorkflow = true,
1892
+ includeStdLibrary = true,
1893
+ stdLibraryFull = false,
1894
+ includeStdStateMachines = true,
1895
+ includeSchemaUpdates = true
1896
+ } = options;
1897
+ let stdSection = "";
1898
+ if (includeStdLibrary) {
1899
+ if (includeStdStateMachines) {
1900
+ stdSection = `---
1901
+
1902
+ ${getKeyBehaviorsReference()}
1903
+
1904
+ ---
1905
+
1906
+ ${getStdBehaviorsWithStateMachines()}
1907
+ `;
1908
+ } else if (stdLibraryFull) {
1909
+ stdSection = `---
1910
+
1911
+ ${getStdFullReference()}
1912
+ `;
1913
+ } else {
1914
+ stdSection = `---
1915
+
1916
+ ${getStdMinimalReference()}
1917
+ `;
1918
+ }
1919
+ }
1920
+ return `# Orbital Generation Skill
1921
+
1922
+ > Generate Orbital applications using Orbital Units: Entity \xD7 Traits \xD7 Patterns
1923
+
1924
+ ${getArchitectureSection()}
1925
+
1926
+ ---
1927
+
1928
+ ${getMinimalTypeReference()}
1929
+
1930
+ ---
1931
+
1932
+ ${getSExprQuickRef()}
1933
+
1934
+ ---
1935
+
1936
+ ${getRenderUIQuickRef()}
1937
+
1938
+ ${stdSection}
1939
+ ---
1940
+
1941
+ ${getFlowPatternSection()}
1942
+
1943
+ ---
1944
+
1945
+ ${getDecompositionSection()}
1946
+
1947
+ ---
1948
+
1949
+ ${getPortableOrbitalOutputSection()}
1950
+
1951
+ ---
1952
+
1953
+ ${getOrbitalConnectivitySection()}
1954
+
1955
+ ---
1956
+
1957
+ ${getContextUsageCompact()}
1958
+
1959
+ ---
1960
+
1961
+ ${getCommonErrorsSection()}
1962
+
1963
+ ---
1964
+
1965
+ ${getCustomTraitSection()}
1966
+
1967
+ ${includeToolWorkflow ? getToolWorkflowSection() : ""}
1968
+
1969
+ ${includeSchemaUpdates ? `---
1970
+
1971
+ ${getSchemaUpdateSection()}
1972
+ ` : ""}
1973
+ ${getCriticalOutputRequirements()}
1974
+
1975
+ ${includeExample ? getMinimalExample() : ""}
1976
+ `;
1977
+ }
1978
+ function getCriticalOutputRequirements() {
1979
+ return `---
1980
+
1981
+ ## CRITICAL: Output Requirements
1982
+
1983
+ Every orbital MUST include:
1984
+
1985
+ ### 1. domainContext (REQUIRED)
1986
+ \`\`\`json
1987
+ "domainContext": {
1988
+ "request": "<original user request>",
1989
+ "requestFragment": "<what part produced THIS orbital>",
1990
+ "category": "business",
1991
+ "vocabulary": { "item": "Task", "create": "Add", "delete": "Remove" }
1992
+ }
1993
+ \`\`\`
1994
+
1995
+ ### 2. design (REQUIRED)
1996
+ \`\`\`json
1997
+ "design": {
1998
+ "style": "modern",
1999
+ "uxHints": {
2000
+ "flowPattern": "crud-cycle",
2001
+ "listPattern": "entity-table",
2002
+ "formPattern": "modal"
2003
+ }
2004
+ }
2005
+ \`\`\`
2006
+
2007
+ ### 3. Business Rule Guards on SAVE (when rules exist)
2008
+ If the user specifies validation constraints, add S-expression guards on transitions:
2009
+ \`\`\`json
2010
+ {
2011
+ "from": "Creating", "to": "Browsing", "event": "SAVE",
2012
+ "guard": ["<=", "@payload.data.score", 100],
2013
+ "effects": [["persist", "create", "Entry", "@payload.data"], ...]
2014
+ }
2015
+ \`\`\`
2016
+
2017
+ ### 4. ONE Orbital Per Entity
2018
+ Do NOT create multiple orbitals for the same entity. All CRUD operations belong in ONE orbital.
2019
+
2020
+ **Missing context fields = validation warnings. Missing guards = unenforced business rules!**`;
2021
+ }
2022
+ function getToolWorkflowSection() {
2023
+ return `---
2024
+
2025
+ ## Tool Workflow
2026
+
2027
+ 1. **DECOMPOSE**: Break requirements into OrbitalUnits
2028
+ 2. **GENERATE**: Call \`generate_orbital\` for each orbital
2029
+ 3. **COMBINE**: Call \`construct_combined_schema\` (FINAL STEP)
2030
+
2031
+ \`\`\`
2032
+ generate_orbital({ orbital: {...}, orbitalIndex: 0, totalOrbitals: N })
2033
+ generate_orbital({ orbital: {...}, orbitalIndex: 1, totalOrbitals: N })
2034
+ ...
2035
+ construct_combined_schema({ name: "App", description: "..." })
2036
+ # STOP HERE - job is done
2037
+ \`\`\`
2038
+ `;
2039
+ }
2040
+ function getMinimalExample() {
2041
+ return `---
2042
+
2043
+ ## Example: Task Manager
2044
+
2045
+ \`\`\`json
2046
+ {
2047
+ "name": "Taskly",
2048
+ "orbitals": [{
2049
+ "name": "Task Management",
2050
+ "entity": {
2051
+ "name": "Task",
2052
+ "collection": "tasks",
2053
+ "fields": [
2054
+ { "name": "title", "type": "string", "required": true },
2055
+ { "name": "status", "type": "enum", "values": ["pending", "active", "done"] }
2056
+ ]
2057
+ },
2058
+ "traits": [{
2059
+ "name": "TaskInteraction",
2060
+ "category": "interaction",
2061
+ "linkedEntity": "Task",
2062
+ "stateMachine": {
2063
+ "states": [
2064
+ { "name": "Browsing", "isInitial": true },
2065
+ { "name": "Creating" },
2066
+ { "name": "Viewing" },
2067
+ { "name": "Editing" },
2068
+ { "name": "Deleting" }
2069
+ ],
2070
+ "events": ["INIT", "CREATE", "VIEW", "EDIT", "DELETE", "SAVE", "CANCEL", "CONFIRM_DELETE"],
2071
+ "transitions": [
2072
+ {
2073
+ "from": "Browsing", "to": "Browsing", "event": "INIT",
2074
+ "effects": [
2075
+ ["render-ui", "main", { "type": "page-header", "title": "Tasks", "actions": [{ "label": "New Task", "event": "CREATE", "variant": "primary" }] }],
2076
+ ["render-ui", "main", { "type": "entity-table", "entity": "Task", "columns": ["title", "status"], "itemActions": [{ "label": "View", "event": "VIEW" }, { "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE" }] }]
2077
+ ]
2078
+ },
2079
+ {
2080
+ "from": "Browsing", "to": "Creating", "event": "CREATE",
2081
+ "effects": [["render-ui", "modal", { "type": "form-section", "entity": "Task", "fields": ["title", "status"], "submitEvent": "SAVE", "cancelEvent": "CANCEL" }]]
2082
+ },
2083
+ {
2084
+ "from": "Browsing", "to": "Viewing", "event": "VIEW",
2085
+ "effects": [["render-ui", "drawer", { "type": "entity-detail", "entity": "Task", "actions": [{ "label": "Edit", "event": "EDIT" }, { "label": "Delete", "event": "DELETE", "variant": "danger" }] }]]
2086
+ },
2087
+ {
2088
+ "from": "Browsing", "to": "Editing", "event": "EDIT",
2089
+ "effects": [["render-ui", "modal", { "type": "form-section", "entity": "Task", "fields": ["title", "status"], "submitEvent": "SAVE", "cancelEvent": "CANCEL" }]]
2090
+ },
2091
+ {
2092
+ "from": "Browsing", "to": "Deleting", "event": "DELETE",
2093
+ "effects": [["render-ui", "overlay", { "type": "confirmation", "title": "Delete Task?", "message": "This action cannot be undone." }]]
2094
+ },
2095
+ {
2096
+ "from": "Creating", "to": "Browsing", "event": "SAVE",
2097
+ "effects": [["persist", "create", "Task", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]]
2098
+ },
2099
+ {
2100
+ "from": "Creating", "to": "Browsing", "event": "CANCEL",
2101
+ "effects": [["render-ui", "modal", null]]
2102
+ },
2103
+ {
2104
+ "from": "Viewing", "to": "Browsing", "event": "CANCEL",
2105
+ "effects": [["render-ui", "drawer", null]]
2106
+ },
2107
+ {
2108
+ "from": "Editing", "to": "Browsing", "event": "SAVE",
2109
+ "effects": [["persist", "update", "Task", "@payload.data"], ["render-ui", "modal", null], ["emit", "INIT"]]
2110
+ },
2111
+ {
2112
+ "from": "Editing", "to": "Browsing", "event": "CANCEL",
2113
+ "effects": [["render-ui", "modal", null]]
2114
+ },
2115
+ {
2116
+ "from": "Deleting", "to": "Browsing", "event": "CONFIRM_DELETE",
2117
+ "effects": [["persist", "delete", "Task"], ["render-ui", "overlay", null], ["emit", "INIT"]]
2118
+ },
2119
+ {
2120
+ "from": "Deleting", "to": "Browsing", "event": "CANCEL",
2121
+ "effects": [["render-ui", "overlay", null]]
2122
+ }
2123
+ ]
2124
+ }
2125
+ }],
2126
+ "pages": [{ "name": "TasksPage", "path": "/tasks", "traits": [{ "ref": "TaskInteraction" }] }]
2127
+ }]
2128
+ }
2129
+ \`\`\`
2130
+
2131
+ **Key points**:
2132
+ - ONE page (TasksPage) not four (list/create/edit/view)
2133
+ - INIT transition renders initial UI (page-header + entity-table)
2134
+ - States are OBJECTS with \`isInitial\` flag
2135
+ - **Actions are INSIDE patterns (use unified props)**:
2136
+ - \`page-header\` has \`actions: [{label, event, variant}]\`
2137
+ - \`entity-table\` has \`itemActions: [{label, event}]\`
2138
+ - \`form-section\` has \`submitEvent\` and \`cancelEvent\` (NOT onSubmit/onCancel!)
2139
+ - \`entity-detail\` has \`actions\` (NOT headerActions!)
2140
+ - \`confirmation\` emits action events
2141
+ - **NEVER use**: \`onSubmit\`, \`onCancel\`, \`headerActions\`, \`loading\` (use \`isLoading\`)
2142
+ - NO separate "form-actions" pattern - it doesn't exist!
2143
+ `;
2144
+ }
2145
+
2146
+ // src/generators/kflow-orbitals.ts
2147
+ function generateKflowOrbitalsSkill(compact = false) {
2148
+ const frontmatter = {
2149
+ name: "kflow-orbitals",
2150
+ 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: "3.1.0"
2153
+ // Bumped version for compact option
2154
+ };
2155
+ const content = generateLeanOrbitalSkill({
2156
+ includeExample: true,
2157
+ includeToolWorkflow: true,
2158
+ includeStdStateMachines: !compact
2159
+ // Full std/* examples (21K chars)
2160
+ });
2161
+ return {
2162
+ name: "kflow-orbitals",
2163
+ frontmatter,
2164
+ content
2165
+ };
2166
+ }
2167
+ function generateLeanFixingSkill(options = {}) {
2168
+ const {
2169
+ includeOverGeneration = true,
2170
+ includeSchemaUpdates = true,
2171
+ includeEfficiency = true
2172
+ } = options;
2173
+ return `# Orbital Fixing Skill
2174
+
2175
+ > Fix validation errors using orbital understanding: Entity \xD7 Traits \xD7 Patterns
2176
+
2177
+ ## Key Principle
2178
+
2179
+ \`\`\`
2180
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
2181
+ \u2502 When fixing errors: \u2502
2182
+ \u2502 1. Identify which ORBITAL the error belongs to \u2502
2183
+ \u2502 2. Identify which COMPONENT (entity/trait/page/pattern) \u2502
2184
+ \u2502 3. Apply targeted fix for that component \u2502
2185
+ \u2502 \u2502
2186
+ \u2502 This gives you CONTEXT that improves fix accuracy. \u2502
2187
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
2188
+ \`\`\`
2189
+
2190
+ ---
2191
+
2192
+ ${getFixingWorkflowSection()}
2193
+
2194
+ ${includeEfficiency ? `---
2195
+
2196
+ ${getEfficiencySection()}` : ""}
2197
+
2198
+ ---
2199
+
2200
+ ${getArchitectureSection()}
2201
+
2202
+ ---
2203
+
2204
+ ${getMinimalTypeReference()}
2205
+
2206
+ ---
2207
+
2208
+ ${getSExprQuickRef()}
2209
+
2210
+ ---
2211
+
2212
+ ${getRenderUIQuickRef()}
2213
+
2214
+ ---
2215
+
2216
+ ${getPatternActionsRef()}
2217
+
2218
+ ---
2219
+
2220
+ ${getCommonFixPatternsSection()}
2221
+
2222
+ ${includeOverGeneration ? `---
2223
+
2224
+ ${getOverGenerationSection()}` : ""}
2225
+
2226
+ ---
2227
+
2228
+ ${getCommonErrorsSection()}
2229
+
2230
+ ${includeSchemaUpdates ? `---
2231
+
2232
+ ${getSchemaUpdateSection()}` : ""}
2233
+
2234
+ ---
2235
+
2236
+ ${getCompletionRulesSection()}
2237
+
2238
+ ---
2239
+
2240
+ ## Schema File Rule
2241
+
2242
+ \`\`\`
2243
+ \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
2244
+ \u2502 ALWAYS write to: schema.json \u2502
2245
+ \u2502 \u2502
2246
+ \u2502 NEVER use other file names like: \u2502
2247
+ \u2502 - schema_with_fixes.json \u274C \u2502
2248
+ \u2502 - new_schema.json \u274C \u2502
2249
+ \u2502 - updated_schema.json \u274C \u2502
2250
+ \u2502 \u2502
2251
+ \u2502 The persistence system ONLY reads from schema.json \u2502
2252
+ \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
2253
+ \`\`\`
2254
+ `;
2255
+ }
2256
+ function getFixingSkillMetadata() {
2257
+ return {
2258
+ name: "kflow-orbital-fixing",
2259
+ description: "Fix validation errors using orbital understanding (lean version)",
2260
+ version: "2.0.0"
2261
+ };
2262
+ }
2263
+
2264
+ // src/generators/kflow-orbital-fixing.ts
2265
+ function generateKflowOrbitalFixingSkill() {
2266
+ const metadata = getFixingSkillMetadata();
2267
+ const frontmatter = {
2268
+ name: metadata.name,
2269
+ description: metadata.description,
2270
+ allowedTools: ["Read", "Edit", "Bash"],
2271
+ version: metadata.version
2272
+ };
2273
+ const content = generateLeanFixingSkill({
2274
+ includeOverGeneration: true,
2275
+ includeSchemaUpdates: true,
2276
+ includeEfficiency: true
2277
+ });
2278
+ return {
2279
+ name: metadata.name,
2280
+ frontmatter,
2281
+ content
2282
+ };
2283
+ }
2284
+
2285
+ // src/generators/domain-language.ts
2286
+ var ODL_SYNTAX_REFERENCE = `
2287
+ ## Domain Language Syntax
2288
+
2289
+ Entity: \`A [Name] is a [persistent] entity that: - has [field] as [type]\`
2290
+ Page: \`[PageName] at /[path]: - shows [Entity] using [Behavior]\`
2291
+ `;
2292
+ var ODL_EXAMPLES = `
2293
+ ## Examples
2294
+
2295
+ \`\`\`
2296
+ A Task is a persistent entity that:
2297
+ - has title as text (required)
2298
+ - has status as enum [pending, active, done]
2299
+
2300
+ TasksPage at /tasks:
2301
+ - shows Task using List behavior
2302
+ \`\`\`
2303
+ `;
2304
+ var ODL_PATTERNS = `
2305
+ ## Patterns
2306
+
2307
+ Use patterns like entity-table, form-section in domain language.
2308
+ `;
2309
+ var ODL_TO_SCHEMA_MAPPING = `
2310
+ ## Mapping
2311
+
2312
+ Domain language converts to OrbitalSchema JSON via compiler.
2313
+ `;
2314
+ function generateDomainLanguageSkill() {
2315
+ const frontmatter = {
2316
+ name: "domain-language",
2317
+ description: "Understand, generate, and summarize KFlow domain language. Convert natural language requirements to domain language and provide human-readable summaries.",
2318
+ allowedTools: ["Read", "Write", "Edit"],
2319
+ version: "1.0.0"
2320
+ };
2321
+ const content = `
2322
+ # KFlow Domain Language Skill
2323
+
2324
+ This skill enables you to understand, generate, and summarize KFlow domain language - a human-readable format for defining application schemas.
2325
+
2326
+ ## What is Domain Language?
2327
+
2328
+ Domain language is a structured text format that represents KFlow schemas in a readable way:
2329
+ - **Entities** - Data models with fields and relationships
2330
+ - **Pages** - UI views with patterns and traits
2331
+ - **Behaviors** - State machines and workflows
2332
+
2333
+ ## Capabilities
2334
+
2335
+ ### 1. Generate Domain Language from Requirements
2336
+
2337
+ Convert natural language requirements into domain language text.
2338
+
2339
+ ### 2. Summarize Domain Language
2340
+
2341
+ Create human-readable summaries of existing domain language definitions.
2342
+
2343
+ ### 3. Edit Domain Language
2344
+
2345
+ Make targeted edits to existing domain language text.
2346
+
2347
+ ## Domain Language Syntax Reference
2348
+
2349
+ ${ODL_SYNTAX_REFERENCE}
2350
+
2351
+ ## Patterns Reference
2352
+
2353
+ ${ODL_PATTERNS}
2354
+
2355
+ ## Full Examples
2356
+
2357
+ ${ODL_EXAMPLES}
2358
+
2359
+ ## Mapping to Schema
2360
+
2361
+ ${ODL_TO_SCHEMA_MAPPING}
2362
+
2363
+ ## Generation Workflow
2364
+
2365
+ ### Step 1: Analyze Requirements
2366
+
2367
+ Extract key concepts:
2368
+ - **Entities** - What data objects are needed?
2369
+ - **Fields** - What properties does each entity have?
2370
+ - **Pages** - What views are required?
2371
+ - **Behaviors** - What workflows or state machines are needed?
2372
+
2373
+ ### Step 2: Generate Domain Language
2374
+
2375
+ Use the syntax reference to create valid domain language:
2376
+
2377
+ \`\`\`
2378
+ ENTITY TaskEntity:
2379
+ - title: string (required)
2380
+ - description: text
2381
+ - status: enum [pending, in_progress, done]
2382
+ - dueDate: date
2383
+ - assignee: relation -> User
2384
+
2385
+ PAGE TaskListPage:
2386
+ path: /tasks
2387
+ entity: Task
2388
+ viewType: list
2389
+ sections:
2390
+ - header (page-header): title="Tasks"
2391
+ - taskList (entity-list): entity="Task", presentation="table"
2392
+ traits: []
2393
+
2394
+ PAGE TaskCreateForm:
2395
+ path: /tasks/new
2396
+ entity: Task
2397
+ viewType: create
2398
+ sections:
2399
+ - header (page-header): title="Create Task"
2400
+ - form (form-section): entity="Task", layout="vertical"
2401
+ - actions (form-actions): submitLabel="Create Task"
2402
+ traits: [FormSubmission, FormValidation]
2403
+ \`\`\`
2404
+
2405
+ ### Step 3: Validate Structure
2406
+
2407
+ Ensure:
2408
+ 1. All entities have required fields
2409
+ 2. Pages reference valid entities
2410
+ 3. Traits are from the library or properly defined
2411
+ 4. Section patterns are valid
2412
+
2413
+ ## Summarization Workflow
2414
+
2415
+ ### Step 1: Parse Domain Language
2416
+
2417
+ Identify:
2418
+ - Number of entities and their purposes
2419
+ - Number of pages and their types
2420
+ - Key behaviors and workflows
2421
+
2422
+ ### Step 2: Generate Summary
2423
+
2424
+ Create a concise summary:
2425
+
2426
+ **Format:**
2427
+ \`\`\`
2428
+ **{App Name}** - {one-line description}
2429
+
2430
+ **Entities:**
2431
+ - {Entity1} - {brief description}
2432
+ - {Entity2} - {brief description}
2433
+
2434
+ **Pages:**
2435
+ - {Page1} ({viewType}) - {purpose}
2436
+ - {Page2} ({viewType}) - {purpose}
2437
+
2438
+ **Features:**
2439
+ - {Key behavior 1}
2440
+ - {Key behavior 2}
2441
+ \`\`\`
2442
+
2443
+ ### Summary Requirements
2444
+
2445
+ 1. Keep it concise (200 words max)
2446
+ 2. Focus on business functionality
2447
+ 3. Use bullet points for clarity
2448
+ 4. Include entity count and page count
2449
+ 5. Highlight key workflows
2450
+
2451
+ ## Output Format
2452
+
2453
+ ### For Generation
2454
+
2455
+ Output ONLY the domain language text - no explanations or commentary.
2456
+
2457
+ ### For Summary
2458
+
2459
+ Output a structured summary following the format above.
2460
+
2461
+ ### For Edits
2462
+
2463
+ Output the complete updated domain language text.
2464
+
2465
+ ## Best Practices
2466
+
2467
+ 1. **Use library traits** - Prefer existing traits over custom behaviors
2468
+ 2. **Follow naming conventions** - PascalCase for entities/pages, camelCase for fields
2469
+ 3. **Include all required fields** - Every entity needs at least one field
2470
+ 4. **Define page paths** - Use RESTful URL patterns
2471
+ 5. **Match patterns to view types** - list\u2192entity-list, detail\u2192entity-detail, create/edit\u2192form-section
2472
+ `.trim();
2473
+ return {
2474
+ name: "domain-language",
2475
+ frontmatter,
2476
+ content
2477
+ };
2478
+ }
2479
+
2480
+ // src/orbitals-skills-generators/lean/lean-orbital-generator.ts
2481
+ var LEAN_CORE_INSTRUCTIONS = `
2482
+ ## Core Instructions
2483
+
2484
+ Generate orbital schemas using **Domain Language** - a natural, readable format.
2485
+
2486
+ **Output Format**: Domain Language text (NOT JSON)
2487
+ **Token Efficiency**: ~5x fewer tokens than JSON format
2488
+ `;
2489
+ var LEAN_OUTPUT_FORMAT = `
2490
+ ## Output Format
2491
+
2492
+ Output ONLY domain language text. No JSON, no code blocks, no explanations.
2493
+
2494
+ Example Output:
2495
+ \`\`\`
2496
+ A Task is a persistent entity that:
2497
+ - has title as text (required)
2498
+ - has status as enum [pending, active, done]
2499
+ - has dueDate as date
2500
+
2501
+ TasksPage at /tasks:
2502
+ - shows Task using List behavior
2503
+ - view type: list
2504
+ \`\`\`
2505
+ `;
2506
+ var LEAN_VALIDATION_RULES = `
2507
+ ## Validation
2508
+
2509
+ - Every entity needs at least one field
2510
+ - Pages must reference valid entities
2511
+ - Use standard behaviors from std library
2512
+ - S-expressions for guards/effects
2513
+ `;
2514
+ var LEAN_DECOMPOSITION_PROTOCOL = `
2515
+ ## Decomposition
2516
+
2517
+ 1. Identify entities from requirements
2518
+ 2. Define fields for each entity
2519
+ 3. Create pages for each entity (list, create, edit)
2520
+ 4. Apply std behaviors (List, Detail, Form)
2521
+ `;
2522
+ var ODL_SYNTAX_REFERENCE2 = `
2523
+ ## Domain Language Syntax
2524
+
2525
+ **Entity**:
2526
+ \`\`\`
2527
+ A [Name] is a [persistent/runtime/singleton] entity that:
2528
+ - has [field] as [type] (required)
2529
+ - belongs to [Related]
2530
+ - has many [Related]s
2531
+ \`\`\`
2532
+
2533
+ **Page**:
2534
+ \`\`\`
2535
+ [PageName] at /[path]:
2536
+ - shows [Entity] using [Behavior]
2537
+ - view type: [list|detail|create|edit]
2538
+ \`\`\`
2539
+ `;
2540
+ var LEAN_STD_LIST_BEHAVIOR = `
2541
+ ## List Behavior
2542
+
2543
+ Use std/behaviors/crud List behavior for entity browsing.
2544
+ `;
2545
+ var LEAN_EFFECT_GUARD_SYNTAX = `
2546
+ ## S-Expressions
2547
+
2548
+ Use S-expressions for guards and effects:
2549
+ - Guards: \`[">", "@entity.count", 0]\`
2550
+ - Effects: \`["set", "@entity.field", value]\`
2551
+ `;
2552
+ var LEAN_CRITICAL_RULES = `
2553
+ ## Critical Rules
2554
+
2555
+ 1. Use domain language format (NOT JSON)
2556
+ 2. One page per entity (list view)
2557
+ 3. Use std behaviors
2558
+ `;
2559
+ var LEAN_COMMON_ERRORS = `
2560
+ ## Common Errors
2561
+
2562
+ - Don't generate JSON
2563
+ - Don't create separate create/edit/view pages
2564
+ - Use std behaviors
2565
+ `;
2566
+ var ODL_PATTERNS2 = `
2567
+ ## Patterns
2568
+
2569
+ Entity patterns: entity-table, entity-list, entity-cards
2570
+ Form patterns: form-section
2571
+ `;
2572
+ var ODL_TO_SCHEMA_MAPPING2 = `
2573
+ ## Mapping
2574
+
2575
+ Domain language is converted to OrbitalSchema JSON by the compiler.
2576
+ `;
2577
+ var LEAN_ERROR_HANDLING = `
2578
+ ## Error Handling
2579
+
2580
+ Output corrected domain language when errors occur.
2581
+ `;
2582
+ function generateLeanOrbitalSkill2() {
2583
+ return `---
2584
+ name: kflow-lean-orbitals
2585
+ description: Generate OrbitalSchema applications using Domain Language with S-Expression effects.
2586
+ allowed-tools: Read, generate_orbital_domain
2587
+ version: 2.1.0
2588
+ ---
2589
+
2590
+ # kflow-lean-orbitals
2591
+
2592
+ > Generate OrbitalSchema applications using Domain Language
2593
+ >
2594
+ > **Output**: Domain Language text with S-Expression effects
2595
+ > **Tools**: \`generate_orbital_domain\` (per-orbital generation with auto-persist)
2596
+
2597
+ ---
2598
+
2599
+ ${LEAN_CORE_INSTRUCTIONS}
2600
+
2601
+ ---
2602
+
2603
+ ${LEAN_DECOMPOSITION_PROTOCOL}
2604
+
2605
+ ---
2606
+
2607
+ ${LEAN_STD_LIST_BEHAVIOR}
2608
+
2609
+ ---
2610
+
2611
+ ${LEAN_OUTPUT_FORMAT}
2612
+
2613
+ ---
2614
+
2615
+ ${ODL_SYNTAX_REFERENCE2}
2616
+
2617
+ ---
2618
+
2619
+ ${LEAN_EFFECT_GUARD_SYNTAX}
2620
+
2621
+ ---
2622
+
2623
+ ${LEAN_CRITICAL_RULES}
2624
+
2625
+ ---
2626
+
2627
+ ${LEAN_COMMON_ERRORS}
2628
+
2629
+ ---
2630
+
2631
+ ${ODL_PATTERNS2}
2632
+
2633
+ ---
2634
+
2635
+ ${ODL_TO_SCHEMA_MAPPING2}
2636
+
2637
+ ---
2638
+
2639
+ ${LEAN_VALIDATION_RULES}
2640
+
2641
+ ---
2642
+
2643
+ ${LEAN_ERROR_HANDLING}
2644
+
2645
+ ---
2646
+
2647
+ ## Workflow Summary (MANDATORY TOOL USAGE)
2648
+
2649
+ \u26A0\uFE0F **CRITICAL: You MUST use \`generate_orbital_domain\` for EACH orbital.**
2650
+ \u26A0\uFE0F **NEVER use Write/Edit to create domain language directly - always use the tools.**
2651
+
2652
+ The tools handle proper prompting, caching, and S-Expression syntax. Writing directly will fail.
2653
+
2654
+ ### Phase 1: Decomposition (CRITICAL - NO tool calls yet)
2655
+
2656
+ **You MUST decompose the application into orbitals BEFORE calling any tools.**
2657
+
2658
+ 1. **Classify domain** - business, game, form, dashboard, content
2659
+ 2. **Identify entities** - List ALL data objects with:
2660
+ - Fields (name, type, required, default)
2661
+ - Relationships (belongs_to, has_many)
2662
+ - Persistence type (persistent, runtime, singleton)
2663
+ 3. **Resolve cross-references** - Ensure every "belongs to X" has entity X planned
2664
+ 4. **Plan orbitals** - Create a spec for each:
2665
+
2666
+ \`\`\`json
2667
+ {
2668
+ "name": "Task Management",
2669
+ "entity": {
2670
+ "name": "Task",
2671
+ "persistence": "persistent",
2672
+ "fields": [
2673
+ { "name": "title", "type": "text", "required": true },
2674
+ { "name": "status", "type": "enum [todo, done]", "default": "todo" }
2675
+ ],
2676
+ "relations": [
2677
+ { "entity": "User", "type": "belongs_to" }
2678
+ ]
2679
+ },
2680
+ "pages": [
2681
+ { "name": "TasksPage", "path": "/tasks", "viewType": "list", "isInitial": true }
2682
+ ],
2683
+ "traits": ["TaskManager"],
2684
+ "patterns": ["page-header", "entity-table", "form-section", "entity-detail"]
2685
+ }
2686
+ \`\`\`
2687
+
2688
+ ### Phase 2: Chunked Generation (generate_orbital_domain)
2689
+
2690
+ For EACH orbital spec, call the \`generate_orbital_domain\` tool:
2691
+
2692
+ \`\`\`json
2693
+ {
2694
+ "sessionId": "my-app-session",
2695
+ "orbital": { ... orbital spec from Phase 1 ... },
2696
+ "orbitalIndex": 0,
2697
+ "totalOrbitals": 3
2698
+ }
2699
+ \`\`\`
2700
+
2701
+ This tool:
2702
+ - Uses LLM with proper prompts (S-Expression syntax, patterns, CRUD template)
2703
+ - Caches results by fingerprint
2704
+ - **Auto-persists**: Each orbital is immediately converted to OrbitalSchema and saved
2705
+
2706
+ ### Phase 3: Finish
2707
+
2708
+ After ALL orbitals are generated, call \`finish_task\` to complete the workflow.
2709
+
2710
+ No manual merging needed - the schema is built incrementally as each orbital is generated.
2711
+
2712
+ ---
2713
+
2714
+ ## Tool Reference
2715
+
2716
+ ### generate_orbital_domain
2717
+
2718
+ Generate domain language for ONE orbital using LLM with proper prompts.
2719
+
2720
+ **Input:**
2721
+ - \`sessionId\`: Unique session ID for this batch
2722
+ - \`orbital\`: Orbital spec (entity, pages, traits, patterns)
2723
+ - \`orbitalIndex\`: Position in batch (0-based)
2724
+ - \`totalOrbitals\`: Total orbitals being generated
2725
+
2726
+ **Output:**
2727
+ - \`success\`: Whether generation succeeded
2728
+ - \`domainText\`: Generated domain language
2729
+ - \`cached\`: Whether result was from cache
2730
+ - \`usage\`: Token usage
2731
+ - \`schema\`: The orbital converted to OrbitalSchema (auto-persisted)
2732
+
2733
+ ---
2734
+
2735
+ ## Complete Example
2736
+
2737
+ **User**: Create a task management app
2738
+
2739
+ **Assistant** writes domain.txt:
2740
+ \`\`\`
2741
+ # Entities
2742
+
2743
+ A Task is a persistent entity that:
2744
+ - has title as text (required)
2745
+ - has description as long text
2746
+ - has status as enum [todo, in_progress, done] with default "todo"
2747
+ - has priority as enum [low, medium, high] with default "medium"
2748
+ - has dueDate as date
2749
+
2750
+ # Pages
2751
+
2752
+ TasksPage at /tasks:
2753
+ - shows Task using TaskManager
2754
+ - view type: list
2755
+ - is initial page
2756
+
2757
+ # Behaviors
2758
+
2759
+ TaskManager behavior:
2760
+ Entity: Task
2761
+ States: Browsing, Creating, Viewing, Editing, Deleting
2762
+ Initial: Browsing
2763
+
2764
+ Transitions:
2765
+ - From Browsing to Browsing on INIT
2766
+ then ["render-ui", "main", {"type": "page-header", "title": "Tasks", "actions": [{"label": "New Task", "event": "CREATE", "variant": "primary"}]}]
2767
+ then ["render-ui", "center", {"type": "entity-table", "entity": "Task", "columns": ["title", "status", "priority", "dueDate"], "itemActions": [{"label": "View", "event": "VIEW"}, {"label": "Edit", "event": "EDIT"}, {"label": "Delete", "event": "DELETE", "variant": "danger"}]}]
2768
+
2769
+ - From Browsing to Creating on CREATE
2770
+ then ["render-ui", "modal", {"type": "form-section", "entity": "Task", "fields": ["title", "description", "status", "priority", "dueDate"], "submitEvent": "SAVE", "cancelEvent": "CANCEL"}]
2771
+
2772
+ - From Creating to Browsing on SAVE
2773
+ then ["persist", "create", "Task", "@payload.data"]
2774
+ then ["render-ui", "modal", null]
2775
+ then ["emit", "INIT"]
2776
+
2777
+ - From Creating to Browsing on CANCEL
2778
+ then ["render-ui", "modal", null]
2779
+
2780
+ - From Browsing to Viewing on VIEW
2781
+ then ["render-ui", "drawer", {"type": "entity-detail", "entity": "Task", "fieldNames": ["title", "description", "status", "priority", "dueDate"], "actions": [{"label": "Edit", "event": "EDIT"}, {"label": "Delete", "event": "DELETE", "variant": "danger"}]}]
2782
+
2783
+ - From Viewing to Editing on EDIT
2784
+ then ["render-ui", "drawer", null]
2785
+ then ["render-ui", "modal", {"type": "form-section", "entity": "Task", "submitEvent": "SAVE", "cancelEvent": "CANCEL"}]
2786
+
2787
+ - From Browsing to Editing on EDIT
2788
+ then ["render-ui", "modal", {"type": "form-section", "entity": "Task", "submitEvent": "SAVE", "cancelEvent": "CANCEL"}]
2789
+
2790
+ - From Editing to Browsing on SAVE
2791
+ then ["persist", "update", "Task", "@payload.data"]
2792
+ then ["render-ui", "modal", null]
2793
+ then ["emit", "INIT"]
2794
+
2795
+ - From Editing to Browsing on CANCEL
2796
+ then ["render-ui", "modal", null]
2797
+
2798
+ - From Viewing to Browsing on CANCEL
2799
+ then ["render-ui", "drawer", null]
2800
+
2801
+ - From Browsing to Deleting on DELETE
2802
+ then ["render-ui", "overlay", {"type": "confirmation", "title": "Delete Task?", "message": "This action cannot be undone."}]
2803
+
2804
+ - From Viewing to Deleting on DELETE
2805
+ then ["render-ui", "drawer", null]
2806
+ then ["render-ui", "overlay", {"type": "confirmation", "title": "Delete Task?", "message": "This action cannot be undone."}]
2807
+
2808
+ - From Deleting to Browsing on CONFIRM_DELETE
2809
+ then ["persist", "delete", "Task"]
2810
+ then ["render-ui", "overlay", null]
2811
+ then ["emit", "INIT"]
2812
+
2813
+ - From Deleting to Browsing on CANCEL
2814
+ then ["render-ui", "overlay", null]
2815
+ \`\`\`
2816
+
2817
+ **Key points in this example:**
2818
+ - **Entity: Task** explicitly links the behavior to the Task entity (REQUIRED)
2819
+ - INIT renders BOTH page-header (with "New Task" action) AND entity-table (with View/Edit/Delete itemActions)
2820
+ - All effects use S-Expression format
2821
+ - Modal for create/edit, drawer for view, overlay for delete confirmation
2822
+ - Each open slot is closed with \`null\` when done
2823
+ - SAVE emits INIT to refresh the list
2824
+ `;
2825
+ }
2826
+
2827
+ // src/orbitals-skills-generators/lean/lean-fixing-generator.ts
2828
+ var LEAN_CORE_INSTRUCTIONS2 = `
2829
+ ## Core Instructions
2830
+
2831
+ Fix validation errors by outputting corrected Domain Language text.
2832
+ `;
2833
+ var LEAN_ERROR_HANDLING2 = `
2834
+ ## Error Handling
2835
+
2836
+ 1. Read the error message carefully
2837
+ 2. Locate the problematic section
2838
+ 3. Output corrected domain language
2839
+ `;
2840
+ var LEAN_VALIDATION_RULES2 = `
2841
+ ## Validation Rules
2842
+
2843
+ - Required fields must be marked
2844
+ - Entity references must be valid
2845
+ - Page paths must be unique
2846
+ - Behaviors must be from std library
2847
+ `;
2848
+ var ODL_SYNTAX_REFERENCE3 = `
2849
+ ## Domain Language Syntax
2850
+
2851
+ See kflow-lean-orbitals skill for full syntax reference.
2852
+ `;
2853
+ var LEAN_EFFECT_GUARD_SYNTAX2 = `
2854
+ ## S-Expressions
2855
+
2856
+ Use S-expressions in domain language for guards and effects.
2857
+ `;
2858
+ var ODL_TO_SCHEMA_MAPPING3 = `
2859
+ ## Schema Mapping
2860
+
2861
+ Domain language maps to OrbitalSchema JSON structure.
2862
+ `;
2863
+ function generateLeanFixingSkill2() {
2864
+ return `---
2865
+ name: kflow-lean-fixing
2866
+ description: Fix OrbitalSchema validation errors using Domain Language format.
2867
+ allowed-tools: Read, Write, Edit
2868
+ version: 1.0.0
2869
+ ---
2870
+
2871
+ # kflow-lean-fixing
2872
+
2873
+ > Fix OrbitalSchema validation errors using Domain Language
2874
+ >
2875
+ > **Input**: Validation errors + current ODL
2876
+ > **Output**: Fixed Domain Language sections
2877
+
2878
+ ---
2879
+
2880
+ ${LEAN_CORE_INSTRUCTIONS2}
2881
+
2882
+ ---
2883
+
2884
+ ## Error Fixing Protocol
2885
+
2886
+ 1. **Parse error code** - Identify the error type (ORB_E_*, ORB_T_*, etc.)
2887
+ 2. **Locate section** - Find the corresponding ODL section
2888
+ 3. **Apply fix** - Correct the issue in ODL format
2889
+ 4. **Output fixed section only** - Don't re-output unchanged sections
2890
+
2891
+ ---
2892
+
2893
+ ${LEAN_ERROR_HANDLING2}
2894
+
2895
+ ---
2896
+
2897
+ ## Common Fixes
2898
+
2899
+ ### ORB_E_MISSING_NAME
2900
+ **Error**: Entity missing name
2901
+ **Fix**: Ensure entity definition starts with "A [Name] is..."
2902
+
2903
+ Before:
2904
+ \`\`\`
2905
+ is a persistent entity that:
2906
+ - has title as text
2907
+ \`\`\`
2908
+
2909
+ After:
2910
+ \`\`\`
2911
+ A Task is a persistent entity that:
2912
+ - has title as text
2913
+ \`\`\`
2914
+
2915
+ ### ORB_E_NO_FIELDS
2916
+ **Error**: Entity has no fields
2917
+ **Fix**: Add at least one field definition
2918
+
2919
+ Before:
2920
+ \`\`\`
2921
+ A Task is a persistent entity that:
2922
+ \`\`\`
2923
+
2924
+ After:
2925
+ \`\`\`
2926
+ A Task is a persistent entity that:
2927
+ - has title as text (required)
2928
+ \`\`\`
2929
+
2930
+ ### ORB_T_NO_INITIAL_STATE
2931
+ **Error**: Behavior has no initial state
2932
+ **Fix**: Add "Initial: [StateName]" line
2933
+
2934
+ Before:
2935
+ \`\`\`
2936
+ TaskManager behavior:
2937
+ States: Viewing, Editing
2938
+
2939
+ Transitions:
2940
+ ...
2941
+ \`\`\`
2942
+
2943
+ After:
2944
+ \`\`\`
2945
+ TaskManager behavior:
2946
+ States: Viewing, Editing
2947
+ Initial: Viewing
2948
+
2949
+ Transitions:
2950
+ ...
2951
+ \`\`\`
2952
+
2953
+ ### ORB_T_INVALID_TRANSITION
2954
+ **Error**: Transition references non-existent state
2955
+ **Fix**: Ensure From/To states exist in States list
2956
+
2957
+ Before:
2958
+ \`\`\`
2959
+ TaskManager behavior:
2960
+ States: Viewing, Editing
2961
+ Initial: Viewing
2962
+
2963
+ Transitions:
2964
+ - From Viewing to Creating on CREATE # 'Creating' not in States
2965
+ \`\`\`
2966
+
2967
+ After:
2968
+ \`\`\`
2969
+ TaskManager behavior:
2970
+ States: Viewing, Editing, Creating # Added Creating
2971
+ Initial: Viewing
2972
+
2973
+ Transitions:
2974
+ - From Viewing to Creating on CREATE
2975
+ \`\`\`
2976
+
2977
+ ### ORB_P_NO_PATH
2978
+ **Error**: Page has no path
2979
+ **Fix**: Add "at /[path]" to page definition
2980
+
2981
+ Before:
2982
+ \`\`\`
2983
+ TasksPage:
2984
+ - shows Task using TaskManager
2985
+ \`\`\`
2986
+
2987
+ After:
2988
+ \`\`\`
2989
+ TasksPage at /tasks:
2990
+ - shows Task using TaskManager
2991
+ \`\`\`
2992
+
2993
+ ### ORB_E_INVALID_RELATION
2994
+ **Error**: Relation references non-existent entity
2995
+ **Fix**: Ensure target entity is defined
2996
+
2997
+ Before:
2998
+ \`\`\`
2999
+ A Task is a persistent entity that:
3000
+ - belongs to Project # Project not defined
3001
+ \`\`\`
3002
+
3003
+ After (add missing entity):
3004
+ \`\`\`
3005
+ A Project is a persistent entity that:
3006
+ - has name as text (required)
3007
+
3008
+ A Task is a persistent entity that:
3009
+ - belongs to Project
3010
+ \`\`\`
3011
+
3012
+ ---
3013
+
3014
+ ${ODL_SYNTAX_REFERENCE3}
3015
+
3016
+ ---
3017
+
3018
+ ${LEAN_EFFECT_GUARD_SYNTAX2}
3019
+
3020
+ ---
3021
+
3022
+ ${LEAN_VALIDATION_RULES2}
3023
+
3024
+ ---
3025
+
3026
+ ${ODL_TO_SCHEMA_MAPPING3}
3027
+
3028
+ ---
3029
+
3030
+ ## Output Format
3031
+
3032
+ **IMPORTANT**: Always write your fixes to \`domain.txt\` using the Write or Edit tool.
3033
+
3034
+ 1. If \`domain.txt\` exists, use the Edit tool to modify it
3035
+ 2. If it doesn't exist, use the Write tool to create it
3036
+ 3. The file must contain the COMPLETE domain language with your fixes applied
3037
+ 4. Do NOT just output text to the chat - you must write to the file
3038
+
3039
+ When fixing errors:
3040
+ - Read the existing domain.txt (if present)
3041
+ - Apply fixes to the affected sections
3042
+ - Write the complete fixed content to domain.txt
3043
+ - Confirm the changes were applied
3044
+
3045
+ Example workflow:
3046
+ 1. Read domain.txt to understand current structure
3047
+ 2. Edit the specific section that has errors
3048
+ 3. Verify the fix by reading the file again
3049
+ `;
3050
+ }
3051
+
3052
+ // src/generators/index.ts
3053
+ function generateAllBuilderSkills() {
3054
+ return [
3055
+ generateKflowOrbitalsSkill(),
3056
+ generateKflowOrbitalFixingSkill(),
3057
+ {
3058
+ name: "kflow-lean-orbitals",
3059
+ frontmatter: {
3060
+ name: "kflow-lean-orbitals",
3061
+ description: "Generate schemas using Domain Language (~5x fewer tokens)",
3062
+ allowedTools: ["Read", "Write", "Edit"]
3063
+ },
3064
+ content: generateLeanOrbitalSkill2()
3065
+ },
3066
+ {
3067
+ name: "kflow-lean-fixing",
3068
+ frontmatter: {
3069
+ name: "kflow-lean-fixing",
3070
+ description: "Fix validation errors using Domain Language",
3071
+ allowedTools: ["Read", "Write", "Edit"]
3072
+ },
3073
+ content: generateLeanFixingSkill2()
3074
+ },
3075
+ generateDomainLanguageSkill()
3076
+ ];
3077
+ }
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
+
3209
+ // src/prompts/generation-prompts.ts
3210
+ function getOrbitalDecompositionPrompt() {
3211
+ return `
3212
+ ## Orbital Unit Decomposition Protocol
3213
+
3214
+ ${getArchitectureSection()}
3215
+
3216
+ ---
3217
+
3218
+ ${getDecompositionSection()}
3219
+
3220
+ ---
3221
+
3222
+ ${getDecompositionChecklist()}
3223
+
3224
+ ---
3225
+
3226
+ ## Pattern Selection
3227
+
3228
+ ${getPatternTypesCompact()}
3229
+
3230
+ ---
3231
+
3232
+ ${getValidationHintsSection()}
3233
+ `.trim();
3234
+ }
3235
+ function getFullOrbitalPrompt() {
3236
+ return `
3237
+ # Subagent: Expand Lightweight Orbital to Full Orbital
3238
+
3239
+ You receive a lightweight OrbitalDefinition and must expand it into a complete FullOrbitalUnit with traits, state machines, and UI.
3240
+
3241
+ ---
3242
+
3243
+ ${getArchitectureSection()}
3244
+
3245
+ ---
3246
+
3247
+ ${getMinimalTypeReference2()}
3248
+
3249
+ ---
3250
+
3251
+ ${getSExprQuickRef2()}
3252
+
3253
+ ---
3254
+
3255
+ ${getRenderUIQuickRef2()}
3256
+
3257
+ ---
3258
+
3259
+ ${getFieldTypesCompact()}
3260
+
3261
+ ---
3262
+
3263
+ ${getCustomTraitSection()}
3264
+
3265
+ ---
3266
+
3267
+ ${getUsesImportSection()}
3268
+
3269
+ ---
3270
+
3271
+ ${getCommonErrorsSection()}
3272
+
3273
+ ---
3274
+
3275
+ ## Output Format
3276
+
3277
+ Return ONLY valid JSON matching the FullOrbitalUnit structure. No markdown, no explanations.
3278
+
3279
+ \`\`\`json
3280
+ {
3281
+ "name": "EntityName",
3282
+ "entity": { ... },
3283
+ "traits": [ ... ],
3284
+ "pages": [ ... ]
3285
+ }
3286
+ \`\`\`
3287
+ `.trim();
3288
+ }
3289
+ function getRequirementsDecomposePrompt() {
3290
+ return `
3291
+ ## Requirements-Aware Decomposition
3292
+
3293
+ When decomposing with extracted requirements, use them to improve orbital identification:
3294
+
3295
+ ### Using Entity Requirements
3296
+
3297
+ For each entity in \`requirements.entities\`:
3298
+ - Create one OrbitalUnit per **primary** entity
3299
+ - Group related entities (e.g., Order + OrderItem in same orbital)
3300
+ - Consider entity relationships when grouping
3301
+
3302
+ ### Using State Requirements
3303
+
3304
+ For each state in \`requirements.states\`:
3305
+ - Identify which entity lifecycle it belongs to
3306
+ - Create states in that entity's trait state machine
3307
+
3308
+ ### Using Event Requirements
3309
+
3310
+ For each event in \`requirements.events\`:
3311
+ - Map to trait events (UPPERCASE)
3312
+ - Connect to appropriate transitions
3313
+
3314
+ ### Using Guard Requirements
3315
+
3316
+ For each guard in \`requirements.guards\`:
3317
+ - Identify which entity the guard applies to
3318
+ - Include guard description in that entity's orbital
3319
+ - The subagent will convert to guard expression
3320
+
3321
+ ### Using Effect Requirements
3322
+
3323
+ For each effect in \`requirements.effects\`:
3324
+ - Identify the trigger (e.g., "on confirmation")
3325
+ - Identify the action (e.g., "send email")
3326
+ - Include in relevant orbital's effects list
3327
+
3328
+ ${getValidationHintsSection()}
3329
+ `.trim();
3330
+ }
3331
+ function getRequirementsTraitPrompt() {
3332
+ return `
3333
+ ## Generating Traits from Requirements
3334
+
3335
+ When generating a FullOrbitalUnit, convert requirements to schema elements:
3336
+
3337
+ ### Guard Patterns
3338
+
3339
+ Common guard patterns to recognize:
3340
+
3341
+ | Requirement | Guard Expression |
3342
+ |-------------|-----------------|
3343
+ | "only managers can approve" | \`["=", "@context.user.role", "manager"]\` |
3344
+ | "amount must be positive" | \`[">", "@entity.amount", 0]\` |
3345
+ | "if status is pending" | \`["=", "@entity.status", "pending"]\` |
3346
+ | "user is authenticated" | \`["=", "@context.user.authenticated", true]\` |
3347
+
3348
+ ### Effect Patterns
3349
+
3350
+ Common effect patterns to recognize:
3351
+
3352
+ | Requirement | Effect Type | Template |
3353
+ |-------------|------------|----------|
3354
+ | "send email" | \`emit\` | \`["emit", "EMAIL_SEND", { "to": "...", "subject": "..." }]\` |
3355
+ | "update status" | \`set\` | \`["set", "@entity.status", "newValue"]\` |
3356
+ | "navigate to page" | \`navigate\` | \`["navigate", "/page"]\` |
3357
+ | "show notification" | \`emit\` | \`["emit", "NOTIFY", { "message": "..." }]\` |
3358
+
3359
+ ### State Machine Construction
3360
+
3361
+ 1. Extract states from requirements.states
3362
+ 2. Create events for state transitions (UPPERCASE)
3363
+ 3. Add transitions with appropriate guards
3364
+ 4. Include render-ui effects for each state
3365
+
3366
+ ${getCommonErrorsSection()}
3367
+ `.trim();
3368
+ }
3369
+ function getKeyBehaviorsReference2() {
3370
+ const behaviorsDocs = generateBehaviorsDocs();
3371
+ return `## Key Standard Behaviors
3372
+
3373
+ ${behaviorsDocs.categories.map((cat) => `### ${cat.name}
3374
+ ${cat.behaviors.map((b) => `- **${b.name}**: ${b.description}`).join("\n")}
3375
+ `).join("\n")}
3376
+
3377
+ Use with: \`uses: [{ from: "std/behaviors/crud", as: "CRUD" }]\`
3378
+ `;
3379
+ }
3380
+
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, getMinimalTypeReference2 as getMinimalTypeReference, getMultiFileSection, getOrbitalConnectivitySection, getOrbitalDecompositionPrompt, getOverGenerationSection, getPatternTypesCompact, getPortableOrbitalOutputSection, getRenderUIQuickRef2 as getRenderUIQuickRef, getRequirementsDecomposePrompt, getRequirementsTraitPrompt, getSExprQuickRef2 as getSExprQuickRef, getSchemaUpdateCompact, getSchemaUpdateSection, getUsesImportCompact, getUsesImportSection, getValidationHintsSection, writeAllSkills, writeSkill };
3382
+ //# sourceMappingURL=index.js.map
3383
+ //# sourceMappingURL=index.js.map