@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/LICENSE +72 -0
- package/README.md +238 -0
- package/dist/index.d.ts +501 -0
- package/dist/index.js +3383 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -0
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
|