@olonjs/cli 3.0.87 → 3.0.89

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.
@@ -3,555 +3,1600 @@ set -e
3
3
 
4
4
  echo "Starting project reconstruction..."
5
5
 
6
- mkdir -p "docs"
7
- echo "Creating docs/01-Onboarding_Client_completo_aggiornato.md..."
8
- cat << 'END_OF_FILE_CONTENT' > "docs/01-Onboarding_Client_completo_aggiornato.md"
9
- # Onboarding — Percorso Client (senza CMS) — Versione completa
6
+ mkdir -p ".cursor"
7
+ mkdir -p ".cursor/skills-cursor"
8
+ mkdir -p ".cursor/skills-cursor/create-rule"
9
+ echo "Creating .cursor/skills-cursor/create-rule/SKILL.md..."
10
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/create-rule/SKILL.md"
11
+ ---
12
+ name: create-rule
13
+ description: >-
14
+ Create Cursor rules for persistent AI guidance. Use when you want to create a
15
+ rule, add coding standards, set up project conventions, configure
16
+ file-specific patterns, create RULE.md files, or asks about .cursor/rules/ or
17
+ AGENTS.md.
18
+ ---
19
+ # Creating Cursor Rules
10
20
 
11
- **Per chi:** Sviluppo grafico e dati quando **non** usi il CMS (Studio/ICE). Il sito è un **client**: i dati arrivano da JSON locali, da API o da un CMS esterno; tu ti occupi di layout, design e rendering.
21
+ Create project rules in `.cursor/rules/` to provide persistent context for the AI agent.
12
22
 
13
- **Riferimento spec:** OlonJS Architecture v1.2 (legacy alias: JSONPAGES) — solo le parti che riguardano struttura sito, componenti e dati. Ignori: Studio, ICE, Form Factory, IDAC, TOCC, AddSectionConfig, schema obbligatori per l'editor.
23
+ ## Gather Requirements
14
24
 
15
- ---
25
+ Before creating a rule, determine:
26
+
27
+ 1. **Purpose**: What should this rule enforce or teach?
28
+ 2. **Scope**: Should it always apply, or only for specific files?
29
+ 3. **File patterns**: If file-specific, which glob patterns?
30
+
31
+ ### Inferring from Context
32
+
33
+ If you have previous conversation context, infer rules from what was discussed. You can create multiple rules if the conversation covers distinct topics or patterns. Don't ask redundant questions if the context already provides the answers.
16
34
 
17
- ## 1. Cosa fai tu (in sintesi)
35
+ ### Required Questions
18
36
 
19
- - **Grafico:** Layout e stili delle section (View + CSS / design tokens se vuoi).
20
- - **Dati:** Da dove prendono i dati le pagine (file JSON, API, altro CMS) e come vengono passati al motore (config + pages).
37
+ If the user hasn't specified scope, ask:
38
+ - "Should this rule always apply, or only when working with specific files?"
21
39
 
22
- Non devi: tipizzare tutto per l'editor, esporre schema Zod al Form Factory, gestire overlay Studio, Add Section, ecc. Puoi usare tipi minimi o anche `unknown`/`any` sui dati se non ti serve type-safety forte.
40
+ If they mentioned specific files and haven't provided concrete patterns, ask:
41
+ - "Which file patterns should this rule apply to?" (e.g., `**/*.ts`, `backend/**/*.py`)
42
+
43
+ It's very important that we get clarity on the file patterns.
44
+
45
+ Use the AskQuestion tool when available to gather this efficiently.
23
46
 
24
47
  ---
25
48
 
26
- ## 2. Struttura progetto (minima)
49
+ ## Rule File Format
27
50
 
28
- - **`src/data/config/site.json`** Identità, header, footer (blocchi con `id`, `type`, `data`, `settings`).
29
- - **`src/data/config/menu.json`** — Menu (es. `{ main: [{ label, href }] }`).
30
- - **`src/data/config/theme.json`** — (Opzionale) Token tema (colori, font, radius).
31
- - **`src/data/pages/<slug>.json`** — Una pagina = `slug`, `meta`, `sections[]` (array di blocchi `id`, `type`, `data`, `settings`). **Per creare una nuova pagina** basta aggiungere un file `<slug>.json` in `src/data/pages/`; lo slug del nome file diventa il path della pagina (es. `chi-siamo.json` → `/chi-siamo`).
32
- - **`src/components/<sectionType>/`** — Una cartella per tipo di blocco (hero, header, footer, feature-grid, …).
33
- - **`src/App.tsx`** — Carica site, menu, theme, pages; costruisce la config; renderizza **`<JsonPagesEngine config={config} />` *(from `@olonjs/core`, legacy alias: `@jsonpages/core`)***.
51
+ Rules are `.mdc` files in `.cursor/rules/` with YAML frontmatter:
34
52
 
35
- Il motore (Core) si aspetta comunque un **registry** (mappa tipo → componente) e le **pagine** nel formato previsto (slug → page con `sections`). Come popoli i JSON (a mano, da script, da altro CMS) è fuori dall'editor.
53
+ ```
54
+ .cursor/rules/
55
+ typescript-standards.mdc
56
+ react-patterns.mdc
57
+ api-conventions.mdc
58
+ ```
36
59
 
37
- **Perché servono (struttura):** Path e forma (site, menu, theme, pages con sections) sono il contratto minimo che il Core usa per routing e rendering; rispettarli permette di cambiare in seguito fonte dati (JSON → API) senza riscrivere la logica. Vedi spec §2 (JSP), Appendix A.4.
60
+ ### File Structure
38
61
 
62
+ ```markdown
63
+ ---
64
+ description: Brief description of what this rule does
65
+ globs: **/*.ts # File pattern for file-specific rules
66
+ alwaysApply: false # Set to true if rule should always apply
39
67
  ---
40
68
 
41
- ## 3. Componenti (solo View)
69
+ # Rule Title
42
70
 
43
- - Ogni **section type** ha almeno una **View**: riceve `data` e, se serve, `settings`. L'header riceve anche `menu` (array di `{ label, href }`).
44
- - **Niente obbligo di capsule "piene":** puoi avere solo `View.tsx` (e magari un `index.ts` che esporta la View). Schema Zod e types servono solo se vuoi type-safety in sviluppo o se in futuro attivi il CMS.
45
- - **Stili:** Puoi usare classi Tailwind "libere" o un set di variabili CSS (es. `--local-bg`, `--local-text`) per coerenza. Le spec CIP (solo variabili, niente utility nude) sono per il percorso governance; qui puoi adattare alle tue convenzioni.
46
- - **Asset:** Se il Core espone `resolveAssetUrl(path, tenantId)`, usalo per le immagini; altrimenti path relativi o URL assoluti.
71
+ Your rule content here...
72
+ ```
47
73
 
48
- **Perché servono (componenti):** Il registry deve avere un componente per ogni `type` usato nei JSON; la View deve ricevere `data` (e `settings`/`menu` dove previsto) così il Core può renderizzare senza conoscere i dettagli. Senza registry coerente con i dati, il motore non saprebbe cosa montare. Vedi spec §3 (TBP), §4 (CIP) per il percorso completo.
74
+ ### Frontmatter Fields
75
+
76
+ | Field | Type | Description |
77
+ |-------|------|-------------|
78
+ | `description` | string | What the rule does (shown in rule picker) |
79
+ | `globs` | string | File pattern - rule applies when matching files are open |
80
+ | `alwaysApply` | boolean | If true, applies to every session |
49
81
 
50
82
  ---
51
83
 
52
- ## 3.1 Image e campi immagine (se usi schema in seguito)
84
+ ## Rule Configurations
85
+
86
+ ### Always Apply
87
+
88
+ For universal standards that should apply to every conversation:
53
89
 
54
- Se più avanti aggiungi schema Zod per type-safety o per attivare Studio, i **campi immagine** vanno modellati così:
90
+ ```yaml
91
+ ---
92
+ description: Core coding standards for the project
93
+ alwaysApply: true
94
+ ---
95
+ ```
55
96
 
56
- - **Schema:** Il campo immagine è un **oggetto** (non una stringa) con almeno `url` e opzionalmente `alt`. Lo schema di questo oggetto va marcato con **`.describe('ui:image-picker')`** così il Form Factory (Inspector) mostra il widget Image Picker. Esempio: uno sub-schema `ImageSelectionSchema = z.object({ url: z.string(), alt: z.string().optional() }).describe('ui:image-picker')` usato come `image: ImageSelectionSchema.default({ url: '', alt: '' })`.
57
- - **View:** Per il `src` dell'immagine usa **`resolveAssetUrl(data.image.url, tenantId)`**; sul nodo che rappresenta l'immagine imposta **`data-jp-field="image"`** (così l'Inspector lega correttamente il campo).
97
+ ### Apply to Specific Files
58
98
 
59
- **Riferimento:** componente `image-break` in `apps/tenant-alpha/src/components/image-break/` (schema.ts, View.tsx) come esempio completo.
99
+ For rules that apply when working with certain file types:
60
100
 
101
+ ```yaml
61
102
  ---
103
+ description: TypeScript conventions for this project
104
+ globs: **/*.ts
105
+ alwaysApply: false
106
+ ---
107
+ ```
62
108
 
63
- ## 4. Dati: da dove arrivano
109
+ ---
64
110
 
65
- - **Solo JSON locali:** Leggi `site.json`, `menu.json`, `theme.json`, `pages/*.json` e li passi in `config` (siteConfig, menuConfig, themeConfig, pages). Nessun CMS.
66
- - **CMS esterno / API:** Invece di importare i JSON, fai fetch (o SSR) e costruisci gli stessi oggetti (siteConfig, menuConfig, pages) e li passi a `JsonPagesEngine`. La forma delle pagine resta: `{ slug, meta?, sections[] }`; ogni section: `{ id, type, data, settings? }`.
67
- - **Ibrido:** Header/footer da `site.json`, body da API o da altro CMS: costruisci un unico `pages[slug]` con `sections` che rispettano i tipi di blocco che hai nel registry.
111
+ ## Best Practices
68
112
 
69
- Non devi registrare schema o AddSectionConfig a meno che non attivi Studio.
113
+ ### Keep Rules Concise
70
114
 
71
- **Perché servono (dati):** La forma `sections[]` con `id`, `type`, `data`, `settings?` è ciò che il SectionRenderer e il Core si aspettano; mantenere quella forma anche quando i dati arrivano da API o altro CMS evita adattatori fragili e permette di attivare Studio in seguito senza rifare i dati. Vedi spec Appendix A.2 (PageConfig, SiteConfig, MenuConfig).
115
+ - **Under 50 lines**: Rules should be concise and to the point
116
+ - **One concern per rule**: Split large rules into focused pieces
117
+ - **Actionable**: Write like clear internal docs
118
+ - **Concrete examples**: Ideally provide concrete examples of how to fix issues
72
119
 
73
120
  ---
74
121
 
75
- ## 5. Registry e config (minimo)
122
+ ## Example Rules
76
123
 
77
- - **Registry:** Un oggetto che mappa ogni `sectionType` (stringa) al componente React che renderizza quel tipo. Es.: `{ header: Header, footer: Footer, hero: Hero, ... }`. Se non usi Studio, puoi tipizzare in modo lasco (es. `Record<string, React.FC<any>>` o comunque compatibile con quanto si aspetta `JsonPagesConfig['registry']` from `@olonjs/core`).
78
- - **Config da passare a JsonPagesEngine:**
79
- `tenantId`, `registry`, `pages`, `siteConfig`, `menuConfig`, `themeConfig` (o oggetto vuoto), `themeCss: { tenant: cssString }`.
80
- Se **non** usi Studio, **schemas** e **addSection** possono essere placeholder (oggetto vuoto / no-op) se il Core lo permette; altrimenti fornisci il minimo (es. schemas = `{}`, addSection = `{ addableSectionTypes: [], sectionTypeLabels: {}, getDefaultSectionData: () => ({}) }`) per non rompere l'engine.
124
+ ### TypeScript Standards
81
125
 
82
- Verifica nella doc o nel tipo `JsonPagesConfig` se `schemas` e `addSection` sono opzionali quando Studio non è in uso.
126
+ ```markdown
127
+ ---
128
+ description: TypeScript coding standards
129
+ globs: **/*.ts
130
+ alwaysApply: false
131
+ ---
83
132
 
84
- **Perché servono (registry e config):** Il Core deve risolvere ogni section a un componente (registry) e avere pagine, site, menu, theme e CSS tenant per renderizzare e, se serve, iniettare lo Stage in iframe; i campi obbligatori di config sono il minimo per far funzionare l'engine. Placeholder per schemas/addSection evitano errori quando Studio non è usato. Vedi spec §10 (JEB), Appendix A.
133
+ # Error Handling
85
134
 
135
+ \`\`\`typescript
136
+ // ❌ BAD
137
+ try {
138
+ await fetchData();
139
+ } catch (e) {}
140
+
141
+ // ✅ GOOD
142
+ try {
143
+ await fetchData();
144
+ } catch (e) {
145
+ logger.error('Failed to fetch', { error: e });
146
+ throw new DataFetchError('Unable to retrieve data', { cause: e });
147
+ }
148
+ \`\`\`
149
+ ```
150
+
151
+ ### React Patterns
152
+
153
+ ```markdown
154
+ ---
155
+ description: React component patterns
156
+ globs: **/*.tsx
157
+ alwaysApply: false
86
158
  ---
87
159
 
88
- ## 6. Checklist rapida (sviluppo grafico e dati, senza CMS)
160
+ # React Patterns
89
161
 
90
- | Cosa | Azione |
91
- |------|--------|
92
- | **Layout / grafico** | Implementare le View (una per section type) e gli stili (CSS / Tailwind / variabili). |
93
- | **Dati** | Decidere fonte (JSON locali, API, altro CMS); costruire `siteConfig`, `menuConfig`, `pages` nella forma attesa e passarli in `config`. |
94
- | **Registry** | Mappare ogni tipo di blocco usato nei JSON al componente corrispondente. |
95
- | **Header / menu** | Header component riceve `data`, `settings`, `menu`; `menu` viene da `menuConfig` (es. `menuConfig.main`). |
96
- | **Pagine** | Ogni pagina = un entry in `pages` con `sections[]`; ogni section ha `id`, `type`, `data`, `settings?`. |
97
- | **Nuova pagina** | Aggiungere un file `<slug>.json` in `src/data/pages/` (lo slug diventa il path della pagina). |
98
- | **Image (se schema)** | Campo immagine = oggetto `{ url, alt? }` con schema `.describe('ui:image-picker')`; View usa `resolveAssetUrl` e `data-jp-field="image"`. |
99
- | **Studio / ICE** | Non usati: niente schema obbligatori, niente data-jp-*, niente overlay CSS, niente Add Section. |
162
+ - Use functional components
163
+ - Extract custom hooks for reusable logic
164
+ - Colocate styles with components
165
+ ```
100
166
 
101
167
  ---
102
168
 
103
- ## 7. Quando passi al percorso "Governance"
169
+ ## Checklist
104
170
 
105
- Se più avanti vuoi l'editor (Studio) e la governance (tipi, schema, Add Section, overlay): usa l'onboarding **02-Onboarding_Governance_completo.md** e allinea il progetto a tipi, capsule piene (View + schema + types), IDAC, TOCC, AddSectionConfig e Appendix A delle spec v1.2.
171
+ - [ ] File is `.mdc` format in `.cursor/rules/`
172
+ - [ ] Frontmatter configured correctly
173
+ - [ ] Content under 500 lines
174
+ - [ ] Includes concrete examples
106
175
 
107
176
  END_OF_FILE_CONTENT
108
- echo "Creating docs/01-Onboarding_Governance_naked.md..."
109
- cat << 'END_OF_FILE_CONTENT' > "docs/01-Onboarding_Governance_naked.md"
110
- ### 📄 File 1: Client Path (No CMS)
177
+ mkdir -p ".cursor/skills-cursor/create-skill"
178
+ echo "Creating .cursor/skills-cursor/create-skill/SKILL.md..."
179
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/create-skill/SKILL.md"
180
+ ---
181
+ name: create-skill
182
+ description: >-
183
+ Guides users through creating effective Agent Skills for Cursor. Use when you
184
+ want to create, write, or author a new skill, or asks about skill structure,
185
+ best practices, or SKILL.md format.
186
+ ---
187
+ # Creating Skills in Cursor
111
188
 
189
+ This skill guides you through creating effective Agent Skills for Cursor. Skills are markdown files that teach the agent how to perform specific tasks: reviewing PRs using team standards, generating commit messages in a preferred format, querying database schemas, or any specialized workflow.
112
190
 
191
+ ## Before You Begin: Gather Requirements
113
192
 
114
- # Onboarding Client Path (No CMS) Complete Version
193
+ Before creating a skill, gather essential information from the user about:
115
194
 
116
- **Target:** Frontend Developers & Data Entry staff who **do not** use the CMS (Studio/ICE). The site acts as a **client**: data comes from local JSON, APIs, or an external CMS; you are responsible for layout, design, and rendering.
195
+ 1. **Purpose and scope**: What specific task or workflow should this skill help with?
196
+ 2. **Target location**: Should this be a personal skill (~/.cursor/skills/) or project skill (.cursor/skills/)?
197
+ 3. **Trigger scenarios**: When should the agent automatically apply this skill?
198
+ 4. **Key domain knowledge**: What specialized information does the agent need that it wouldn't already know?
199
+ 5. **Output format preferences**: Are there specific templates, formats, or styles required?
200
+ 6. **Existing patterns**: Are there existing examples or conventions to follow?
117
201
 
118
- **Spec Reference:** JSONPAGES Architecture v1.2 — only the parts regarding site structure, components, and data. You ignore: Studio, ICE, Form Factory, IDAC, TOCC, AddSectionConfig, and mandatory schemas for the editor.
202
+ ### Inferring from Context
119
203
 
120
- ---
204
+ If you have previous conversation context, infer the skill from what was discussed. You can create skills based on workflows, patterns, or domain knowledge that emerged in the conversation.
205
+
206
+ ### Gathering Additional Information
121
207
 
122
- ## 1. Your Role (Summary)
208
+ If you need clarification, use the AskQuestion tool when available:
123
209
 
124
- - **Visuals:** Layout and styling of sections (View + CSS / design tokens).
125
- - **Data:** Where pages get their data (JSON files, API, external CMS) and how they are passed to the engine (config + pages).
210
+ ```
211
+ Example AskQuestion usage:
212
+ - "Where should this skill be stored?" with options like ["Personal (~/.cursor/skills/)", "Project (.cursor/skills/)"]
213
+ - "Should this skill include executable scripts?" with options like ["Yes", "No"]
214
+ ```
126
215
 
127
- You **do not** need to: type everything for the editor, expose Zod schemas to the Form Factory, handle Studio overlays, Add Section logic, etc. You can use minimal types or even `unknown`/`any` on data if strong type-safety is not required.
216
+ If the AskQuestion tool is not available, ask these questions conversationally.
128
217
 
129
218
  ---
130
219
 
131
- ## 2. Project Structure (Minimal)
220
+ ## Skill File Structure
221
+
222
+ ### Directory Layout
132
223
 
133
- - **`src/data/config/site.json`** Identity, header, footer (blocks with `id`, `type`, `data`, `settings`).
134
- - **`src/data/config/menu.json`** — Menu (e.g., `{ main: [{ label, href }] }`).
135
- - **`src/data/config/theme.json`** — (Optional) Theme tokens (colors, fonts, radius).
136
- - **`src/data/pages/<slug>.json`** — One page = `slug`, `meta`, `sections[]` (array of blocks `id`, `type`, `data`, `settings`). **To create a new page**, simply add a `<slug>.json` file in `src/data/pages/`; the filename slug becomes the page path (e.g., `about-us.json` → `/about-us`).
137
- - **`src/components/<sectionType>/`** — One folder per block type (hero, header, footer, feature-grid, …).
138
- - **`src/App.tsx`** — Loads site, menu, theme, pages; builds the config; renders **`<JsonPagesEngine config={config} />`**.
224
+ Skills are stored as directories containing a `SKILL.md` file:
139
225
 
140
- The Engine (Core) still expects a **registry** (type → component map) and **pages** in the expected format (slug → page with `sections`). How you populate the JSONs (manually, via script, from another CMS) is outside the editor's scope.
226
+ ```
227
+ skill-name/
228
+ ├── SKILL.md # Required - main instructions
229
+ ├── reference.md # Optional - detailed documentation
230
+ ├── examples.md # Optional - usage examples
231
+ └── scripts/ # Optional - utility scripts
232
+ ├── validate.py
233
+ └── helper.sh
234
+ ```
141
235
 
142
- **Why this matters (Structure):** Paths and shape (site, menu, theme, pages with sections) are the minimal contract the Core uses for routing and rendering; respecting them allows you to switch data sources (JSON → API) later without rewriting logic. See Spec §2 (JSP), Appendix A.4.
236
+ ### Storage Locations
143
237
 
144
- ---
238
+ | Type | Path | Scope |
239
+ |------|------|-------|
240
+ | Personal | ~/.cursor/skills/skill-name/ | Available across all your projects |
241
+ | Project | .cursor/skills/skill-name/ | Shared with anyone using the repository |
145
242
 
146
- ## 3. Components (View Only)
243
+ **IMPORTANT**: Never create skills in `~/.cursor/skills-cursor/`. This directory is reserved for Cursor's internal built-in skills and is managed automatically by the system.
147
244
 
148
- - Every **section type** has at least one **View**: it receives `data` and, if needed, `settings`. The header also receives `menu` (array of `{ label, href }`).
149
- - **No "Full Capsule" requirement:** you can have just `View.tsx` (and maybe an `index.ts` exporting the View). Zod schemas and types are only needed if you want dev-time type-safety or plan to activate the CMS later.
150
- - **Styles:** You can use "free" Tailwind classes or a set of CSS variables (e.g., `--local-bg`, `--local-text`) for consistency. CIP specs (variables only, no naked utilities) are for the Governance path; here you can adapt to your conventions.
151
- - **Assets:** If the Core exposes `resolveAssetUrl(path, tenantId)`, use it for images; otherwise, use relative paths or absolute URLs.
245
+ ### SKILL.md Structure
152
246
 
153
- **Why this matters (Components):** The registry must have a component for every `type` used in the JSONs; the View must receive `data` (and `settings`/`menu` where expected) so the Core can render without knowing details. Without a registry consistent with data, the engine wouldn't know what to mount. See Spec §3 (TBP), §4 (CIP) for the full path.
247
+ Every skill requires a `SKILL.md` file with YAML frontmatter and markdown body:
154
248
 
249
+ ```markdown
155
250
  ---
251
+ name: your-skill-name
252
+ description: Brief description of what this skill does and when to use it
253
+ ---
254
+
255
+ # Your Skill Name
156
256
 
157
- ## 3.1 Images and Image Fields (If using Schema later)
257
+ ## Instructions
258
+ Clear, step-by-step guidance for the agent.
158
259
 
159
- If you later add Zod schemas for type-safety or to activate Studio, **image fields** must be modeled as follows:
260
+ ## Examples
261
+ Concrete examples of using this skill.
262
+ ```
160
263
 
161
- - **Schema:** The image field is an **object** (not a string) with at least `url` and optionally `alt`. This object's schema must be marked with **`.describe('ui:image-picker')`** so the Form Factory (Inspector) shows the Image Picker widget. Example: a sub-schema `ImageSelectionSchema = z.object({ url: z.string(), alt: z.string().optional() }).describe('ui:image-picker')` used as `image: ImageSelectionSchema.default({ url: '', alt: '' })`.
162
- - **View:** For the image `src`, use **`resolveAssetUrl(data.image.url, tenantId)`**; on the node representing the image, set **`data-jp-field="image"`** (so the Inspector binds the field correctly).
264
+ ### Required Metadata Fields
163
265
 
164
- **Reference:** See the `image-break` component in `apps/tenant-alpha/src/components/image-break/` (schema.ts, View.tsx) for a complete example.
266
+ | Field | Requirements | Purpose |
267
+ |-------|--------------|---------|
268
+ | `name` | Max 64 chars, lowercase letters/numbers/hyphens only | Unique identifier for the skill |
269
+ | `description` | Max 1024 chars, non-empty | Helps agent decide when to apply the skill |
165
270
 
166
271
  ---
167
272
 
168
- ## 4. Data: Where it comes from
273
+ ## Writing Effective Descriptions
169
274
 
170
- - **Local JSONs only:** Read `site.json`, `menu.json`, `theme.json`, `pages/*.json` and pass them into `config` (siteConfig, menuConfig, themeConfig, pages). No CMS.
171
- - **External CMS / API:** Instead of importing JSONs, fetch (or SSR) and build the same objects (siteConfig, menuConfig, pages) and pass them to `JsonPagesEngine`. The page shape remains: `{ slug, meta?, sections[] }`; each section: `{ id, type, data, settings? }`.
172
- - **Hybrid:** Header/footer from `site.json`, body from API or another CMS: build a single `pages[slug]` with `sections` that respect the block types you have in the registry.
275
+ The description is **critical** for skill discovery. The agent uses it to decide when to apply your skill.
173
276
 
174
- You do not need to register schemas or AddSectionConfig unless you activate Studio.
277
+ ### Description Best Practices
175
278
 
176
- **Why this matters (Data):** The `sections[]` shape with `id`, `type`, `data`, `settings?` is what the SectionRenderer and Core expect; maintaining this shape even when data comes from an API or another CMS avoids fragile adapters and allows activating Studio later without redoing data. See Spec Appendix A.2 (PageConfig, SiteConfig, MenuConfig).
279
+ 1. **Write in third person** (the description is injected into the system prompt):
280
+ - ✅ Good: "Processes Excel files and generates reports"
281
+ - ❌ Avoid: "I can help you process Excel files"
282
+ - ❌ Avoid: "You can use this to process Excel files"
177
283
 
178
- ---
284
+ 2. **Be specific and include trigger terms**:
285
+ - ✅ Good: "Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction."
286
+ - ❌ Vague: "Helps with documents"
287
+
288
+ 3. **Include both WHAT and WHEN**:
289
+ - WHAT: What the skill does (specific capabilities)
290
+ - WHEN: When the agent should use it (trigger scenarios)
179
291
 
180
- ## 5. Registry and Config (Minimal)
292
+ ### Description Examples
181
293
 
182
- - **Registry:** An object mapping every `sectionType` (string) to the React component rendering that type. E.g.: `{ header: Header, footer: Footer, hero: Hero, ... }`. If not using Studio, you can type loosely (e.g., `Record<string, React.FC<any>>` or whatever is compatible with `JsonPagesConfig['registry']`).
183
- - **Config passed to JsonPagesEngine:**
184
- `tenantId`, `registry`, `pages`, `siteConfig`, `menuConfig`, `themeConfig` (or empty object), `themeCss: { tenant: cssString }`.
185
- If you are **not** using Studio, **schemas** and **addSection** can be placeholders (empty object / no-op) if the Core allows it; otherwise, provide the minimum (e.g., schemas = `{}`, addSection = `{ addableSectionTypes: [], sectionTypeLabels: {}, getDefaultSectionData: () => ({}) }`) to prevent engine errors.
294
+ ```yaml
295
+ # PDF Processing
296
+ description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.
186
297
 
187
- Check docs or `JsonPagesConfig` type to see if `schemas` and `addSection` are optional when Studio is unused.
298
+ # Excel Analysis
299
+ description: Analyze Excel spreadsheets, create pivot tables, generate charts. Use when analyzing Excel files, spreadsheets, tabular data, or .xlsx files.
188
300
 
189
- **Why this matters (Registry & Config):** The Core must resolve every section to a component (registry) and have pages, site, menu, theme, and tenant CSS to render and, if needed, inject the Stage iframe; mandatory config fields are the minimum to make the engine work. Placeholders for schemas/addSection avoid errors when Studio is not used. See Spec §10 (JEB), Appendix A.
301
+ # Git Commit Helper
302
+ description: Generate descriptive commit messages by analyzing git diffs. Use when the user asks for help writing commit messages or reviewing staged changes.
303
+
304
+ # Code Review
305
+ description: Review code for quality, security, and best practices following team standards. Use when reviewing pull requests, code changes, or when the user asks for a code review.
306
+ ```
190
307
 
191
308
  ---
192
309
 
193
- ## 6. Quick Checklist (Visual Dev & Data, No CMS)
310
+ ## Core Authoring Principles
311
+
312
+ ### 1. Concise is Key
313
+
314
+ The context window is shared with conversation history, other skills, and requests. Every token competes for space.
315
+
316
+ **Default assumption**: The agent is already very smart. Only add context it doesn't already have.
317
+
318
+ Challenge each piece of information:
319
+ - "Does the agent really need this explanation?"
320
+ - "Can I assume the agent knows this?"
321
+ - "Does this paragraph justify its token cost?"
322
+
323
+ **Good (concise)**:
324
+ ```markdown
325
+ ## Extract PDF text
326
+
327
+ Use pdfplumber for text extraction:
328
+
329
+ \`\`\`python
330
+ import pdfplumber
331
+
332
+ with pdfplumber.open("file.pdf") as pdf:
333
+ text = pdf.pages[0].extract_text()
334
+ \`\`\`
335
+ ```
336
+
337
+ **Bad (verbose)**:
338
+ ```markdown
339
+ ## Extract PDF text
340
+
341
+ PDF (Portable Document Format) files are a common file format that contains
342
+ text, images, and other content. To extract text from a PDF, you'll need to
343
+ use a library. There are many libraries available for PDF processing, but we
344
+ recommend pdfplumber because it's easy to use and handles most cases well...
345
+ ```
346
+
347
+ ### 2. Keep SKILL.md Under 500 Lines
348
+
349
+ For optimal performance, the main SKILL.md file should be concise. Use progressive disclosure for detailed content.
350
+
351
+ ### 3. Progressive Disclosure
352
+
353
+ Put essential information in SKILL.md; detailed reference material in separate files that the agent reads only when needed.
354
+
355
+ ```markdown
356
+ # PDF Processing
357
+
358
+ ## Quick start
359
+ [Essential instructions here]
360
+
361
+ ## Additional resources
362
+ - For complete API details, see [reference.md](reference.md)
363
+ - For usage examples, see [examples.md](examples.md)
364
+ ```
365
+
366
+ **Keep references one level deep** - link directly from SKILL.md to reference files. Deeply nested references may result in partial reads.
367
+
368
+ ### 4. Set Appropriate Degrees of Freedom
369
+
370
+ Match specificity to the task's fragility:
194
371
 
195
- | Item | Action |
196
- |------|--------|
197
- | **Layout / Visuals** | Implement Views (one per section type) and styles (CSS / Tailwind / variables). |
198
- | **Data** | Decide source (Local JSON, API, other CMS); build `siteConfig`, `menuConfig`, `pages` in the expected shape and pass to `config`. |
199
- | **Registry** | Map every block type used in JSONs to the corresponding component. |
200
- | **Header / Menu** | Header component receives `data`, `settings`, `menu`; `menu` comes from `menuConfig` (e.g., `menuConfig.main`). |
201
- | **Pages** | Each page = one entry in `pages` with `sections[]`; each section has `id`, `type`, `data`, `settings?`. |
202
- | **New Page** | Add a `<slug>.json` file in `src/data/pages/` (slug becomes page path). |
203
- | **Image (if schema)** | Image field = object `{ url, alt? }` with schema `.describe('ui:image-picker')`; View uses `resolveAssetUrl` and `data-jp-field="image"`. |
204
- | **Studio / ICE** | Not used: no mandatory schemas, no data-jp-*, no overlay CSS, no Add Section. |
372
+ | Freedom Level | When to Use | Example |
373
+ |---------------|-------------|---------|
374
+ | **High** (text instructions) | Multiple valid approaches, context-dependent | Code review guidelines |
375
+ | **Medium** (pseudocode/templates) | Preferred pattern with acceptable variation | Report generation |
376
+ | **Low** (specific scripts) | Fragile operations, consistency critical | Database migrations |
205
377
 
206
378
  ---
207
379
 
208
- ## 7. Switching to the "Governance" Path
380
+ ## Common Patterns
209
381
 
210
- If you later want the editor (Studio) and governance (types, schema, Add Section, overlay): use the onboarding guide **02-Onboarding_Governance.md** and align the project with types, full capsules (View + schema + types), IDAC, TOCC, AddSectionConfig, and Appendix A of Spec v1.2.
382
+ ### Template Pattern
211
383
 
384
+ Provide output format templates:
212
385
 
213
- END_OF_FILE_CONTENT
214
- echo "Creating docs/02-Onboarding_Governance_CMS.md..."
215
- cat << 'END_OF_FILE_CONTENT' > "docs/02-Onboarding_Governance_CMS.md"
386
+ ```markdown
387
+ ## Report structure
388
+
389
+ Use this template:
390
+
391
+ \`\`\`markdown
392
+ # [Analysis Title]
393
+
394
+ ## Executive summary
395
+ [One-paragraph overview of key findings]
396
+
397
+ ## Key findings
398
+ - Finding 1 with supporting data
399
+ - Finding 2 with supporting data
400
+
401
+ ## Recommendations
402
+ 1. Specific actionable recommendation
403
+ 2. Specific actionable recommendation
404
+ \`\`\`
405
+ ```
406
+
407
+ ### Examples Pattern
408
+
409
+ For skills where output quality depends on seeing examples:
410
+
411
+ ```markdown
412
+ ## Commit message format
413
+
414
+ **Example 1:**
415
+ Input: Added user authentication with JWT tokens
416
+ Output:
417
+ \`\`\`
418
+ feat(auth): implement JWT-based authentication
419
+
420
+ Add login endpoint and token validation middleware
421
+ \`\`\`
422
+
423
+ **Example 2:**
424
+ Input: Fixed bug where dates displayed incorrectly
425
+ Output:
426
+ \`\`\`
427
+ fix(reports): correct date formatting in timezone conversion
428
+
429
+ Use UTC timestamps consistently across report generation
430
+ \`\`\`
431
+ ```
432
+
433
+ ### Workflow Pattern
434
+
435
+ Break complex operations into clear steps with checklists:
436
+
437
+ ```markdown
438
+ ## Form filling workflow
439
+
440
+ Copy this checklist and track progress:
216
441
 
217
- # Onboarding — Governance Path (With CMS) — Complete Version
442
+ \`\`\`
443
+ Task Progress:
444
+ - [ ] Step 1: Analyze the form
445
+ - [ ] Step 2: Create field mapping
446
+ - [ ] Step 3: Validate mapping
447
+ - [ ] Step 4: Fill the form
448
+ - [ ] Step 5: Verify output
449
+ \`\`\`
218
450
 
219
- **Target:** Lead Developers & Architects setting up the **CMS** (Studio, ICE, Form Factory): in-app authoring, strong typing, content and component governance.
451
+ **Step 1: Analyze the form**
452
+ Run: \`python scripts/analyze_form.py input.pdf\`
453
+ ...
454
+ ```
455
+
456
+ ### Conditional Workflow Pattern
457
+
458
+ Guide through decision points:
459
+
460
+ ```markdown
461
+ ## Document modification workflow
462
+
463
+ 1. Determine the modification type:
464
+
465
+ **Creating new content?** → Follow "Creation workflow" below
466
+ **Editing existing content?** → Follow "Editing workflow" below
220
467
 
221
- **Spec Reference:** OlonJS Architecture Specifications v1.2 (legacy alias: JSONPAGES) + Appendix A — Tenant Type & Code-Generation Annex.
468
+ 2. Creation workflow:
469
+ - Use docx-js library
470
+ - Build document from scratch
471
+ ...
472
+ ```
473
+
474
+ ### Feedback Loop Pattern
475
+
476
+ For quality-critical tasks, implement validation loops:
477
+
478
+ ```markdown
479
+ ## Document editing process
480
+
481
+ 1. Make your edits
482
+ 2. **Validate immediately**: \`python scripts/validate.py output/\`
483
+ 3. If validation fails:
484
+ - Review the error message
485
+ - Fix the issues
486
+ - Run validation again
487
+ 4. **Only proceed when validation passes**
488
+ ```
222
489
 
223
490
  ---
224
491
 
225
- ## 1. What "Governance" Implies
492
+ ## Utility Scripts
226
493
 
227
- - **Types:** Every section type is declared in `SectionDataRegistry` / `SectionSettingsRegistry` (module augmentation) and in `SectionComponentPropsMap`. Registry and config are strictly typed.
228
- - **Schema:** Every section type has a Zod schema (data, and optionally settings) used by the Form Factory to generate the editor in the Inspector. Schemas are aggregated in `SECTION_SCHEMAS`.
229
- - **Studio/ICE:** The editor (Inspector) hooks into the DOM via **data-jp-field** and **data-jp-item-id** / **data-jp-item-field**. The selection overlay in the iframe requires the **tenant** to provide the CSS (TOCC).
230
- - **Add Section:** The tenant exposes **AddSectionConfig** (addable types, labels, default data) so the user can add sections from the library in Studio.
231
- - **Design Tokens:** Views use CSS variables (`--local-*`) and no "naked" utilities (CIP) for consistency and compatibility with themes and overlays.
494
+ Pre-made scripts offer advantages over generated code:
495
+ - More reliable than generated code
496
+ - Save tokens (no code in context)
497
+ - Save time (no code generation)
498
+ - Ensure consistency across uses
232
499
 
233
- **Why this matters (Summary):** Types and schemas allow the Core and Form Factory to operate without knowing Tenant details; IDAC allows the Inspector to link Stage clicks to the active row in the sidebar (including active/inactive opacity); TOCC makes the overlay visible; AddSectionConfig defines the "Add Section" library; tokens and z-index avoid conflicts with the editing UI. Detailed "Whys" for each spec: see Spec v1.2 (§1–§10, JAP, Appendix A).
500
+ ```markdown
501
+ ## Utility scripts
502
+
503
+ **analyze_form.py**: Extract all form fields from PDF
504
+ \`\`\`bash
505
+ python scripts/analyze_form.py input.pdf > fields.json
506
+ \`\`\`
507
+
508
+ **validate.py**: Check for errors
509
+ \`\`\`bash
510
+ python scripts/validate.py fields.json
511
+ # Returns: "OK" or lists conflicts
512
+ \`\`\`
513
+ ```
514
+
515
+ Make clear whether the agent should **execute** the script (most common) or **read** it as reference.
234
516
 
235
517
  ---
236
518
 
237
- ## 1.1 The Value of Typing: Governance vs. CMS UX
519
+ ## Anti-Patterns to Avoid
520
+
521
+ ### 1. Windows-Style Paths
522
+ - ✅ Use: `scripts/helper.py`
523
+ - ❌ Avoid: `scripts\helper.py`
524
+
525
+ ### 2. Too Many Options
526
+ ```markdown
527
+ # Bad - confusing
528
+ "You can use pypdf, or pdfplumber, or PyMuPDF, or..."
238
529
 
239
- Typing (TypeScript types + Zod schema) serves **two levels**: Governance (Developer/Architecture) and **CMS UX** (Author using Studio).
530
+ # Good - provide a default with escape hatch
531
+ "Use pdfplumber for text extraction.
532
+ For scanned PDFs requiring OCR, use pdf2image with pytesseract instead."
533
+ ```
534
+
535
+ ### 3. Time-Sensitive Information
536
+ ```markdown
537
+ # Bad - will become outdated
538
+ "If you're doing this before August 2025, use the old API."
539
+
540
+ # Good - use an "old patterns" section
541
+ ## Current method
542
+ Use the v2 API endpoint.
543
+
544
+ ## Old patterns (deprecated)
545
+ <details>
546
+ <summary>Legacy v1 API</summary>
547
+ ...
548
+ </details>
549
+ ```
240
550
 
241
- **Governance:** Typed registry, SectionComponentPropsMap, SiteConfig/PageConfig shape, audits, code-generation → consistency across tenants, no drift, safe refactoring, spec-based tooling.
551
+ ### 4. Inconsistent Terminology
552
+ Choose one term and use it throughout:
553
+ - ✅ Always "API endpoint" (not mixing "URL", "route", "path")
554
+ - ✅ Always "field" (not mixing "box", "element", "control")
242
555
 
243
- **CMS UX:** The Zod schema drives the **Form Factory** (which widget for which field: text, textarea, select, list, icon-picker, **image-picker**); **data-jp-field** and **data-jp-item-id/field** bind Stage clicks to Inspector forms; **AddSectionConfig** provides addable types, labels, and defaults. Result for the author: consistent forms, "Add Section" with sensible names and initial data, correct selection (click → right form), validation with clear errors. Without schema and typed contracts, the Inspector wouldn't know which fields to show or how to validate. Thus: for governance, typing guarantees **contracts**; for CMS UX, it defines the **editing experience**. Both must be specified.
556
+ ### 5. Vague Skill Names
557
+ - ✅ Good: `processing-pdfs`, `analyzing-spreadsheets`
558
+ - ❌ Avoid: `helper`, `utils`, `tools`
244
559
 
245
560
  ---
246
561
 
247
- ## 2. Project Structure (Complete)
248
-
249
- - **`src/data/config/site.json`** SiteConfig (identity, pages[], header block, footer block).
250
- - **`src/data/config/menu.json`** — MenuConfig (e.g., `main: MenuItem[]`).
251
- - **`src/data/config/theme.json`** ThemeConfig (tokens).
252
- - **`src/data/pages/<slug>.json`** — PageConfig (slug, meta, sections[]). **To create a new page**, simply add a `<slug>.json` file in `src/data/pages/`; the filename slug becomes the page path (e.g., `about-us.json` → `/about-us`).
253
- - **`src/components/<sectionType>/`** **Full Capsule:** View.tsx, schema.ts, types.ts, index.ts.
254
- - **`src/lib/base-schemas.ts`** BaseSectionData, BaseArrayItem, BaseSectionSettingsSchema.
255
- - **`src/lib/schemas.ts`** SECTION_SCHEMAS (aggregate of data schemas per type) + export SectionType.
256
- - **`src/lib/ComponentRegistry.tsx`** Typed Registry: `{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }`.
257
- - **`src/lib/addSectionConfig.ts`** AddSectionConfig (addableSectionTypes, sectionTypeLabels, getDefaultSectionData).
258
- - **`src/types.ts`** SectionComponentPropsMap, PageConfig, SiteConfig, MenuConfig, ThemeConfig; **module augmentation** for SectionDataRegistry and SectionSettingsRegistry; re-export from `@olonjs/core`.
259
- - **`src/App.tsx`** — Bootstrap: config (tenantId, registry, schemas, pages, siteConfig, themeConfig, menuConfig, themeCss, addSection); `<JsonPagesEngine config={config} />`.
260
- - **Global CSS** Includes TOCC selectors for overlay (hover/selected/type label).
562
+ ## Skill Creation Workflow
563
+
564
+ When helping a user create a skill, follow this process:
565
+
566
+ ### Phase 1: Discovery
567
+
568
+ Gather information about:
569
+ 1. The skill's purpose and primary use case
570
+ 2. Storage location (personal vs project)
571
+ 3. Trigger scenarios
572
+ 4. Any specific requirements or constraints
573
+ 5. Existing examples or patterns to follow
574
+
575
+ If you have access to the AskQuestion tool, use it for efficient structured gathering. Otherwise, ask conversationally.
576
+
577
+ ### Phase 2: Design
578
+
579
+ 1. Draft the skill name (lowercase, hyphens, max 64 chars)
580
+ 2. Write a specific, third-person description
581
+ 3. Outline the main sections needed
582
+ 4. Identify if supporting files or scripts are needed
583
+
584
+ ### Phase 3: Implementation
585
+
586
+ 1. Create the directory structure
587
+ 2. Write the SKILL.md file with frontmatter
588
+ 3. Create any supporting reference files
589
+ 4. Create any utility scripts if needed
590
+
591
+ ### Phase 4: Verification
592
+
593
+ 1. Verify the SKILL.md is under 500 lines
594
+ 2. Check that the description is specific and includes trigger terms
595
+ 3. Ensure consistent terminology throughout
596
+ 4. Verify all file references are one level deep
597
+ 5. Test that the skill can be discovered and applied
261
598
 
262
599
  ---
263
600
 
264
- ## 3. Components (Capsules + IDAC + Tokens)
601
+ ## Complete Example
265
602
 
266
- - **Capsule:** Every section type has View, schema (Zod), types (inferred), index. The **data** schema extends BaseSectionData; array items extend BaseArrayItem.
267
- - **View:** Receives `data` and `settings` (and `menu` for header). Does not import Zod. Uses **only** CSS variables for colors/radii (e.g., `bg-[var(--local-bg)]`), root section with `z-index` ≤ 1.
268
- - **IDAC (ICE):** On every editable scalar field: **`data-jp-field="<fieldKey>"`**. On every editable array item: **`data-jp-item-id="<stableId>"`** and **`data-jp-item-field="<arrayKey>"`**. This allows the Inspector to bind selection and forms to the correct paths.
269
- - **Schema:** Use UI vocabulary (ECIP): `.describe('ui:text')`, `ui:textarea`, `ui:select`, `ui:number`, `ui:list`, `ui:icon-picker`, **`ui:image-picker`** (see §3.1). Editable object arrays: every object must have an `id` (BaseArrayItem).
603
+ Here's a complete example of a well-structured skill:
270
604
 
271
- **Why this matters (Components):** **data-jp-field** and **data-jp-item-*** are needed because the Stage is in an iframe, and the Core needs to know which field/item corresponds to a click without knowing the Tenant's DOM: this allows the sidebar to highlight the active row (even with active/inactive opacity), open the form on the right field, and handle lists (reorder, delete). Without IDAC, clicks on the canvas are not reflected in the sidebar. Schema with `ui:*` and BaseArrayItem are needed for the Form Factory to generate the right widgets and maintain stable keys (reorder/delete). Tokens and z-index prevent content from covering the overlay. See Spec §6 (IDAC), §5 (ECIP), §4 (CIP).
605
+ **Directory structure:**
606
+ ```
607
+ code-review/
608
+ ├── SKILL.md
609
+ ├── STANDARDS.md
610
+ └── examples.md
611
+ ```
272
612
 
613
+ **SKILL.md:**
614
+ ```markdown
615
+ ---
616
+ name: code-review
617
+ description: Review code for quality, security, and maintainability following team standards. Use when reviewing pull requests, examining code changes, or when the user asks for a code review.
273
618
  ---
274
619
 
275
- ## 3.1 Image Picker: Correct Usage in Schema (Example `image-break`)
620
+ # Code Review
276
621
 
277
- For **image fields**, the Form Factory exposes the **Image Picker** widget only if the schema is modeled correctly.
622
+ ## Quick Start
278
623
 
279
- ### Rule
624
+ When reviewing code:
280
625
 
281
- - The image field is not a **string** (`z.string()`), but an **object** with at least `url` and, optionally, `alt`.
282
- - The **schema of this object** (the sub-schema) must be marked with **`.describe('ui:image-picker')`**. The Form Factory recognizes `ui:image-picker` only on **ZodObject** (object schema), not on string fields.
626
+ 1. Check for correctness and potential bugs
627
+ 2. Verify security best practices
628
+ 3. Assess code readability and maintainability
629
+ 4. Ensure tests are adequate
283
630
 
284
- ### Example (`image-break` capsule)
631
+ ## Review Checklist
285
632
 
286
- **Schema (`schema.ts`):**
633
+ - [ ] Logic is correct and handles edge cases
634
+ - [ ] No security vulnerabilities (SQL injection, XSS, etc.)
635
+ - [ ] Code follows project style conventions
636
+ - [ ] Functions are appropriately sized and focused
637
+ - [ ] Error handling is comprehensive
638
+ - [ ] Tests cover the changes
287
639
 
288
- ```ts
289
- import { z } from 'zod';
290
- import { BaseSectionData } from '@/lib/base-schemas';
640
+ ## Providing Feedback
291
641
 
292
- const ImageSelectionSchema = z
293
- .object({
294
- url: z.string(),
295
- alt: z.string().optional(),
296
- })
297
- .describe('ui:image-picker');
642
+ Format feedback as:
643
+ - 🔴 **Critical**: Must fix before merge
644
+ - 🟡 **Suggestion**: Consider improving
645
+ - 🟢 **Nice to have**: Optional enhancement
298
646
 
299
- export const ImageBreakSchema = BaseSectionData.extend({
300
- label: z.string().optional().describe('ui:text'),
301
- image: ImageSelectionSchema.default({ url: '', alt: '' }),
302
- caption: z.string().optional().describe('ui:textarea'),
303
- });
647
+ ## Additional Resources
648
+
649
+ - For detailed coding standards, see [STANDARDS.md](STANDARDS.md)
650
+ - For example reviews, see [examples.md](examples.md)
304
651
  ```
305
652
 
306
- - **ImageSelectionSchema** is a `z.object({ url, alt })` with **`.describe('ui:image-picker')`** on the object.
307
- - The **`image`** field in the section data uses that schema (with default), so the Inspector shows the Image Picker widget for `image`.
653
+ ---
308
654
 
309
- **View (`View.tsx`):**
655
+ ## Summary Checklist
310
656
 
311
- - For the image `src`: **`resolveAssetUrl(data.image.url, tenantId)`** (multi-tenant and relative paths).
312
- - On the node representing the image (e.g., the `<img>` or a wrapper): **`data-jp-field="image"`** so the Stage click binds the Inspector to the `image` field.
313
- - Other editable fields (caption, label) with **`data-jp-field="caption"`** and **`data-jp-field="label"`** where appropriate.
657
+ Before finalizing a skill, verify:
314
658
 
315
- **Full Reference:** `apps/tenant-alpha/src/components/image-break/` (schema.ts, types.ts, View.tsx, index.ts).
659
+ ### Core Quality
660
+ - [ ] Description is specific and includes key terms
661
+ - [ ] Description includes both WHAT and WHEN
662
+ - [ ] Written in third person
663
+ - [ ] SKILL.md body is under 500 lines
664
+ - [ ] Consistent terminology throughout
665
+ - [ ] Examples are concrete, not abstract
316
666
 
317
- ### What to Avoid
667
+ ### Structure
668
+ - [ ] File references are one level deep
669
+ - [ ] Progressive disclosure used appropriately
670
+ - [ ] Workflows have clear steps
671
+ - [ ] No time-sensitive information
318
672
 
319
- - **Do not** use `.describe('ui:image-picker')` on a **string** field (e.g., `imageUrl: z.string().describe('ui:image-picker')`): the Image Picker widget expects an object `{ url, alt? }`.
320
- - **Do not** forget `data-jp-field="image"` on the corresponding DOM node, otherwise Inspector ↔ Stage binding won't work for that field.
673
+ ### If Including Scripts
674
+ - [ ] Scripts solve problems rather than punt
675
+ - [ ] Required packages are documented
676
+ - [ ] Error handling is explicit and helpful
677
+ - [ ] No Windows-style paths
321
678
 
679
+ END_OF_FILE_CONTENT
680
+ mkdir -p ".cursor/skills-cursor/create-subagent"
681
+ echo "Creating .cursor/skills-cursor/create-subagent/SKILL.md..."
682
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/create-subagent/SKILL.md"
322
683
  ---
684
+ name: create-subagent
685
+ description: >-
686
+ Create custom subagents for specialized AI tasks. Use when you want to create
687
+ a new type of subagent, set up task-specific agents, configure code reviewers,
688
+ debuggers, or domain-specific assistants with custom prompts.
689
+ disable-model-invocation: true
690
+ ---
691
+ # Creating Custom Subagents
323
692
 
324
- ## 4. Data: Shape and Responsibility
693
+ This skill guides you through creating custom subagents for Cursor. Subagents are specialized AI assistants that run in isolated contexts with custom system prompts.
325
694
 
326
- - **site.json / menu.json / theme.json / pages/*.json** — Exact shape as in Appendix A (SiteConfig, MenuConfig, ThemeConfig, PageConfig). These are the Source of Truth when the user saves from Studio (Working Draft → persist to these files or API generating them).
327
- - **Studio** updates the Working Draft; sync with the iframe and "Bake" use the same structure. Therefore, data passed to JsonPagesEngine (siteConfig, menuConfig, pages) must be compatible with what the editor modifies.
695
+ ## When to Use Subagents
328
696
 
329
- If data comes from an external CMS, you must synchronize: e.g., export from Studio → push to CMS, or CMS as source and Studio in read-only; in any case, the **shape** of pages (sections with id, type, data, settings) remains that of the spec.
697
+ Subagents help you:
698
+ - **Preserve context** by isolating exploration from your main conversation
699
+ - **Specialize behavior** with focused system prompts for specific domains
700
+ - **Reuse configurations** across projects with user-level subagents
330
701
 
331
- ---
702
+ ### Inferring from Context
703
+
704
+ If you have previous conversation context, infer the subagent's purpose and behavior from what was discussed. Create the subagent based on specialized tasks or workflows that emerged in the conversation.
332
705
 
333
- ## 5. Registry, Schemas, Types, AddSection
706
+ ## Subagent Locations
334
707
 
335
- - **types.ts:** Single point of **module augmentation** and definition of SectionComponentPropsMap, PageConfig, SiteConfig, MenuConfig, ThemeConfig. Header: `{ data, settings?, menu: MenuItem[] }`; all others: `{ data, settings? }`.
336
- - **ComponentRegistry:** Every SectionType key has the corresponding component; type: `{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }`.
337
- - **SECTION_SCHEMAS:** Every SectionType key has the **data Zod schema** (same order as registry). Base schemas re-exported from base-schemas.ts.
338
- - **addSectionConfig:** addableSectionTypes (only types the user can add from the library), sectionTypeLabels, getDefaultSectionData(type) returning valid `data` for that schema.
708
+ | Location | Scope | Priority |
709
+ |----------|-------|----------|
710
+ | `.cursor/agents/` | Current project | Higher |
711
+ | `~/.cursor/agents/` | All your projects | Lower |
339
712
 
340
- **Why this matters (registry, schemas, types, addSection):** A single augmentation point (types.ts) and a single SECTION_SCHEMAS avoid duplication and ensure registry, Form Factory, and config use the same types. AddSectionConfig is the single source of truth for "which sections can be added" and "with what defaults"; without it, the "Add Section" modal wouldn't have valid names or initial data. See Spec §9 (ASC), Appendix A.2–A.3.
713
+ When multiple subagents share the same name, the higher-priority location wins.
341
714
 
715
+ **Project subagents** (`.cursor/agents/`): Ideal for codebase-specific agents. Check into version control to share with your team.
716
+
717
+ **User subagents** (`~/.cursor/agents/`): Personal agents available across all your projects.
718
+
719
+ ## Subagent File Format
720
+
721
+ Create a `.md` file with YAML frontmatter and a markdown body (the system prompt):
722
+
723
+ ```markdown
724
+ ---
725
+ name: code-reviewer
726
+ description: Reviews code for quality and best practices
342
727
  ---
343
728
 
344
- ## 6. Overlay and CSS (TOCC)
729
+ You are a code reviewer. When invoked, analyze the code and provide
730
+ specific, actionable feedback on quality, security, and best practices.
731
+ ```
732
+
733
+ ### Required Fields
734
+
735
+ | Field | Description |
736
+ |-------|-------------|
737
+ | `name` | Unique identifier (lowercase letters and hyphens only) |
738
+ | `description` | When to delegate to this subagent (be specific!) |
739
+
740
+ ## Writing Effective Descriptions
741
+
742
+ The description is **critical** - the AI uses it to decide when to delegate.
743
+
744
+ ```yaml
745
+ # ❌ Too vague
746
+ description: Helps with code
747
+
748
+ # ✅ Specific and actionable
749
+ description: Expert code review specialist. Proactively reviews code for quality, security, and maintainability. Use immediately after writing or modifying code.
750
+ ```
751
+
752
+ Include "use proactively" to encourage automatic delegation.
753
+
754
+ ## Example Subagents
755
+
756
+ ### Code Reviewer
345
757
 
346
- - The Core injects the overlay markup (wrapper with `data-section-id`, sibling with `data-jp-section-overlay`). The **tenant** must provide the CSS so that:
347
- - `[data-jp-section-overlay]` covers the section, `pointer-events: none`, high z-index (e.g., 9999).
348
- - Hover and selected states are visible (dashed/solid border, optional tint).
349
- - The type label (e.g., `[data-jp-section-overlay] > div`) is positioned and visible on hover/selected.
758
+ ```markdown
759
+ ---
760
+ name: code-reviewer
761
+ description: Expert code review specialist. Proactively reviews code for quality, security, and maintainability. Use immediately after writing or modifying code.
762
+ ---
350
763
 
351
- Without this, the overlay is invisible in the Studio iframe.
764
+ You are a senior code reviewer ensuring high standards of code quality and security.
765
+
766
+ When invoked:
767
+ 1. Run git diff to see recent changes
768
+ 2. Focus on modified files
769
+ 3. Begin review immediately
770
+
771
+ Review checklist:
772
+ - Code is clear and readable
773
+ - Functions and variables are well-named
774
+ - No duplicated code
775
+ - Proper error handling
776
+ - No exposed secrets or API keys
777
+ - Input validation implemented
778
+ - Good test coverage
779
+ - Performance considerations addressed
780
+
781
+ Provide feedback organized by priority:
782
+ - Critical issues (must fix)
783
+ - Warnings (should fix)
784
+ - Suggestions (consider improving)
785
+
786
+ Include specific examples of how to fix issues.
787
+ ```
352
788
 
353
- **Why this matters (TOCC):** The Stage iframe loads only Tenant CSS; the Core injects overlay markup but not styles. Without TOCC selectors in Tenant CSS, hover/selected borders and type labels are invisible: the author cannot see which section is selected. See Spec §7 (TOCC).
789
+ ### Debugger
354
790
 
791
+ ```markdown
355
792
  ---
793
+ name: debugger
794
+ description: Debugging specialist for errors, test failures, and unexpected behavior. Use proactively when encountering any issues.
795
+ ---
796
+
797
+ You are an expert debugger specializing in root cause analysis.
798
+
799
+ When invoked:
800
+ 1. Capture error message and stack trace
801
+ 2. Identify reproduction steps
802
+ 3. Isolate the failure location
803
+ 4. Implement minimal fix
804
+ 5. Verify solution works
805
+
806
+ Debugging process:
807
+ - Analyze error messages and logs
808
+ - Check recent code changes
809
+ - Form and test hypotheses
810
+ - Add strategic debug logging
811
+ - Inspect variable states
812
+
813
+ For each issue, provide:
814
+ - Root cause explanation
815
+ - Evidence supporting the diagnosis
816
+ - Specific code fix
817
+ - Testing approach
818
+ - Prevention recommendations
819
+
820
+ Focus on fixing the underlying issue, not the symptoms.
821
+ ```
356
822
 
357
- ## 7. Quick Checklist (Visual Dev & Data, With CMS)
358
-
359
- | Item | Action |
360
- |------|--------|
361
- | **Layout / Visuals** | View with `--local-*` variables, z-index ≤ 1, no naked utilities. |
362
- | **Data (Shape)** | SiteConfig, MenuConfig, ThemeConfig, PageConfig as in Appendix A; JSON in `data/config` and `data/pages`. |
363
- | **Capsules** | View + schema (with `ui:*`) + types + index; data schema extends BaseSectionData; array item with id. |
364
- | **IDAC** | `data-jp-field` on editable scalar fields; `data-jp-item-id` and `data-jp-item-field` on array items. |
365
- | **types.ts** | SectionComponentPropsMap (header with menu), augmentation, PageConfig, SiteConfig, MenuConfig, ThemeConfig. |
366
- | **Registry** | All types mapped to component; registry type as in Appendix A. |
367
- | **SECTION_SCHEMAS** | One entry per type (data schema); re-export base schemas. |
368
- | **addSectionConfig** | addableSectionTypes, sectionTypeLabels, getDefaultSectionData. |
369
- | **Config** | tenantId, registry, schemas, pages, siteConfig, themeConfig, menuConfig, themeCss, addSection. |
370
- | **TOCC** | CSS overlay for `[data-jp-section-overlay]`, hover, selected, type label. |
823
+ ### Data Scientist
371
824
 
825
+ ```markdown
826
+ ---
827
+ name: data-scientist
828
+ description: Data analysis expert for SQL queries, BigQuery operations, and data insights. Use proactively for data analysis tasks and queries.
372
829
  ---
373
830
 
374
- ## 8. Spec References
831
+ You are a data scientist specializing in SQL and BigQuery analysis.
832
+
833
+ When invoked:
834
+ 1. Understand the data analysis requirement
835
+ 2. Write efficient SQL queries
836
+ 3. Use BigQuery command line tools (bq) when appropriate
837
+ 4. Analyze and summarize results
838
+ 5. Present findings clearly
839
+
840
+ Key practices:
841
+ - Write optimized SQL queries with proper filters
842
+ - Use appropriate aggregations and joins
843
+ - Include comments explaining complex logic
844
+ - Format results for readability
845
+ - Provide data-driven recommendations
846
+
847
+ For each analysis:
848
+ - Explain the query approach
849
+ - Document any assumptions
850
+ - Highlight key findings
851
+ - Suggest next steps based on data
852
+
853
+ Always ensure queries are efficient and cost-effective.
854
+ ```
375
855
 
376
- - **Architecture and ICE:** §1–§10 (MTRP, JSP, TBP, CIP, ECIP, IDAC, TOCC, BSDS, ASC, JEB).
377
- - **Types and Code-Generation:** Appendix A (Core types, Tenant types, Schema contract, File paths, Integration checklist).
378
- - **Admin:** JAP (Studio topology, Working Draft, Bake, overlay, Green Build).
856
+ ## Subagent Creation Workflow
379
857
 
380
- Using this path gives you full **governance**: types, schema, editor, Add Section, and overlay aligned with Spec v1.2. For versions with all "Why this matters" explanations, use the file **JSONPAGES_Specs_v1.2_completo.md**.
858
+ ### Step 1: Decide the Scope
381
859
 
382
- --- END OF FILE docs/02-Onboarding_Governance.md ---
383
- END_OF_FILE_CONTENT
384
- echo "Creating docs/02-Onboarding_Governance_completo_aggiornato.md..."
385
- cat << 'END_OF_FILE_CONTENT' > "docs/02-Onboarding_Governance_completo_aggiornato.md"
386
- # Onboarding — Percorso Governance (con CMS) — Versione completa
860
+ - **Project-level** (`.cursor/agents/`): For codebase-specific agents shared with team
861
+ - **User-level** (`~/.cursor/agents/`): For personal agents across all projects
862
+
863
+ ### Step 2: Create the File
864
+
865
+ ```bash
866
+ # For project-level
867
+ mkdir -p .cursor/agents
868
+ touch .cursor/agents/my-agent.md
869
+
870
+ # For user-level
871
+ mkdir -p ~/.cursor/agents
872
+ touch ~/.cursor/agents/my-agent.md
873
+ ```
874
+
875
+ ### Step 3: Define Configuration
876
+
877
+ Write the frontmatter with the required fields (`name` and `description`).
878
+
879
+ ### Step 4: Write the System Prompt
880
+
881
+ The body becomes the system prompt. Be specific about:
882
+ - What the agent should do when invoked
883
+ - The workflow or process to follow
884
+ - Output format and structure
885
+ - Any constraints or guidelines
886
+
887
+ ### Step 5: Test the Agent
888
+
889
+ Ask the AI to use your new agent:
890
+
891
+ ```
892
+ Use the my-agent subagent to [task description]
893
+ ```
387
894
 
388
- **Per chi:** Sviluppo grafico e dati quando vuoi il **CMS** (Studio, ICE, Form Factory): authoring in-app, tipizzazione forte, governance dei contenuti e dei componenti.
895
+ ## Best Practices
389
896
 
390
- **Riferimento spec:** OlonJS Architecture Specifications v1.2 (legacy alias: JSONPAGES) + Appendix A Tenant Type & Code-Generation Annex.
897
+ 1. **Design focused subagents**: Each should excel at one specific task
898
+ 2. **Write detailed descriptions**: Include trigger terms so the AI knows when to delegate
899
+ 3. **Check into version control**: Share project subagents with your team
900
+ 4. **Use proactive language**: Include "use proactively" in descriptions
391
901
 
902
+ ## Troubleshooting
903
+
904
+ ### Subagent Not Found
905
+ - Ensure file is in `.cursor/agents/` or `~/.cursor/agents/`
906
+ - Check file has `.md` extension
907
+ - Verify YAML frontmatter syntax is valid
908
+
909
+ END_OF_FILE_CONTENT
910
+ mkdir -p ".cursor/skills-cursor/jsonpages-tenant"
911
+ echo "Creating .cursor/skills-cursor/jsonpages-tenant/SKILL.md..."
912
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/jsonpages-tenant/SKILL.md"
392
913
  ---
914
+ name: jsonpages-tenant
915
+ description: Use when working on a JsonPages tenant, transforming the base tenant DNA into a branded tenant, adding or modifying tenant sections, maintaining schema-driven editability, or reasoning about what belongs to @jsonpages/core versus the tenant.
916
+ ---
917
+
918
+ # JsonPages Tenant
919
+
920
+ Use this skill for work on the JsonPages ecosystem when the task involves:
921
+
922
+ - a tenant generated from the JsonPages CLI
923
+ - `@jsonpages/core`
924
+ - tenant sections/capsules
925
+ - `src/data/pages/**/*.json` or `src/data/config/*.json`
926
+ - schema-driven editing and inspector compatibility
927
+ - generator scripts that turn a base tenant into a branded tenant
928
+
929
+ Read code first. Treat documents as secondary unless they help interpret code that is otherwise ambiguous.
930
+
931
+ ## Core Model
932
+
933
+ JsonPages has a hard split between `core` and `tenant`.
934
+
935
+ - `@jsonpages/core` owns routing, `/admin`, `/admin/preview`, preview stage, studio state, inspector/form factory, and shared engine behavior.
936
+ - The tenant owns sections, schemas, type augmentation, page/config JSON, theme/design layer, and local workflow scripts.
937
+ - The tenant does not implement the CMS. It implements the tenant protocol consumed by the engine.
938
+
939
+ In this ecosystem, code is the source of truth.
940
+
941
+ Compliance priority:
942
+
943
+ 1. Data is bound correctly.
944
+ 2. Schemas describe fields correctly.
945
+ 3. Content is editable without breaking the inspector.
946
+ 4. Tenant structure stays standardized.
947
+ 5. Context-aware focus/highlight in the legacy admin is desirable but secondary.
948
+
949
+ ## Canonical References
950
+
951
+ Use these local references when available:
952
+
953
+ - Base tenant DNA: `\\wsl.localhost\Ubuntu\home\dev\temp\alpha`
954
+ - Custom tenant reference: `\\wsl.localhost\Ubuntu\home\dev\temp\gptgiorgio`
955
+ - Core engine: `\\wsl.localhost\Ubuntu\home\dev\npm-jpcore\packages\core`
956
+ - Generator example: `\\wsl.localhost\Ubuntu\home\dev\temp\clonark\generate_olon.sh`
957
+
958
+ If these paths are missing, infer the same roles from the current workspace:
959
+
960
+ - base CLI-generated tenant
961
+ - branded tenant
962
+ - core package
963
+ - generator script
964
+
965
+ ## Tenant Anatomy
966
+
967
+ Expect these files to move together:
968
+
969
+ - `src/components/<section>/View.tsx`
970
+ - `src/components/<section>/schema.ts`
971
+ - `src/components/<section>/types.ts`
972
+ - `src/components/<section>/index.ts`
973
+ - `src/lib/ComponentRegistry.tsx`
974
+ - `src/lib/schemas.ts`
975
+ - `src/lib/addSectionConfig.ts`
976
+ - `src/types.ts`
977
+ - `src/data/pages/**/*.json`
978
+ - `src/data/config/site.json`
979
+ - `src/data/config/theme.json`
980
+ - `src/data/config/menu.json`
981
+
982
+ Useful rule: if a section type changes, check all of the files above before concluding the task is done.
983
+
984
+ ## What Good Work Looks Like
985
+
986
+ A good tenant change:
987
+
988
+ - stays inside tenant boundaries unless the issue is truly in `@jsonpages/core`
989
+ - keeps schema, defaults, registry, and type augmentation aligned
990
+ - preserves editability for strings, lists, nested objects, CTAs, and image fields
991
+ - uses `ImageSelectionSchema`-style image fields when the content is image-driven
992
+ - keeps page content JSON-first
993
+
994
+ A suspicious tenant change:
995
+
996
+ - patches the core to fix a tenant modeling problem
997
+ - adds visual complexity without data bindings
998
+ - introduces fields into JSON that are not represented in schema
999
+ - changes a section view without updating defaults or types
1000
+ - optimizes legacy context awareness at the expense of simpler, reliable editability
1001
+
1002
+ ## Workflow 1: Base Tenant -> Branded Tenant
1003
+
1004
+ This is the primary workflow.
1005
+
1006
+ Goal:
1007
+
1008
+ - transform a CLI-generated base tenant into a branded tenant through a single generator script
1009
+
1010
+ Treat the generator script as procedural source of truth for the green build workflow.
1011
+
1012
+ When maintaining or authoring a generator:
1013
+
1014
+ 1. Separate non-deterministic bootstrap from deterministic sync.
1015
+ 2. Make explicit which files are managed output.
1016
+ 3. Keep the script aligned with the current tenant code, not with stale docs.
1017
+ 4. Preserve tenant protocol files: sections, schemas, registries, type augmentation, config JSON, assets, shims.
1018
+ 5. Prefer deterministic local writes after any remote/bootstrap step.
1019
+
1020
+ Typical structure of a good generator:
1021
+
1022
+ - preflight checks
1023
+ - remote/bootstrap steps such as `shadcn` or external registries
1024
+ - deterministic creation/sync of tenant files
1025
+ - compatibility patches for known unstable upstream payloads
1026
+ - final validation commands
1027
+
1028
+ When asked to update a branded tenant generator:
1029
+
1030
+ 1. Diff base tenant against branded tenant.
1031
+ 2. Classify differences into:
1032
+ - intended branded output
1033
+ - reusable generator logic
1034
+ - accidental drift
1035
+ 3. Encode only the reusable intended differences into the script.
1036
+ 4. Keep the output reproducible from a fresh base tenant.
1037
+
1038
+ ## Workflow 2: Add Or Change A Section
1039
+
1040
+ When adding a new section type:
1041
+
1042
+ 1. Create `View.tsx`, `schema.ts`, `types.ts`, `index.ts`.
1043
+ 2. Register the section in `src/lib/ComponentRegistry.tsx`.
1044
+ 3. Register the schema in `src/lib/schemas.ts`.
1045
+ 4. Add defaults and label in `src/lib/addSectionConfig.ts`.
1046
+ 5. Extend `SectionComponentPropsMap` and module augmentation in `src/types.ts`.
1047
+ 6. Add or update page JSON using the new section type.
1048
+
1049
+ When changing an existing section:
1050
+
1051
+ 1. Read the section schema first.
1052
+ 2. Read the page JSON using it.
1053
+ 3. Check the view for `data-jp-field` usage and binding shape.
1054
+ 4. Update defaults if the data shape changed.
1055
+ 5. Verify the inspector still has a path to edit the content.
1056
+
1057
+ ## Workflow 3: Images, Rich Content, Nested Routes
393
1058
 
394
- ## 1. Cosa implica "governance"
1059
+ Images:
395
1060
 
396
- - **Tipi:** Ogni section type è dichiarato in `SectionDataRegistry` / `SectionSettingsRegistry` (module augmentation) e in `SectionComponentPropsMap`. Registry e config sono tipizzati.
397
- - **Schema:** Ogni section type ha uno schema Zod (data, e opzionalmente settings) usato dal Form Factory per generare l'editor nell'Inspector. Gli schema sono aggregati in `SECTION_SCHEMAS`.
398
- - **Studio/ICE:** L'editor (Inspector) si aggancia al DOM tramite **data-jp-field** e **data-jp-item-id** / **data-jp-item-field**. L'overlay di selezione in iframe richiede che il **tenant** fornisca il CSS (TOCC).
399
- - **Add Section:** Il tenant espone **AddSectionConfig** (tipi addabili, label, default data) così in Studio l'utente può aggiungere section dalla libreria.
400
- - **Design tokens:** Le View usano variabili CSS (`--local-*`) e nessuna utility "nuda" (CIP) per coerenza e compatibilità con tema e overlay.
1061
+ - Prefer structured image objects compatible with tenant base schemas.
1062
+ - Assume the core supports image picking and upload flows.
1063
+ - The tenant is responsible for declaring image fields in schema and rendering them coherently.
401
1064
 
402
- **Perché servono (in sintesi):** Tipi e schema permettono al Core e al Form Factory di operare senza conoscere i dettagli del Tenant; IDAC permette all'Inspector di legare click in Stage e riga attiva nella sidebar (inclusa opacità attivo/inattivo); TOCC rende visibile l'overlay; AddSectionConfig definisce la libreria "Aggiungi sezione"; token e z-index evitano conflitti con l'UI di editing. Dettaglio sui "perché" per ogni specifica: spec v1.2 (§1–§10, JAP, Appendix A), dove ogni sezione ha un paragrafo **Perché servono**.
1065
+ Rich editorial content:
403
1066
 
1067
+ - Tiptap-style sections are tenant-level integrations.
1068
+ - Treat page JSON using `type: "tiptap"` as runtime usage examples, and section code as the real source of truth.
1069
+
1070
+ Nested routes:
1071
+
1072
+ - Files under `src/data/pages/**/*.json` may represent nested slugs.
1073
+ - Preserve slug/path consistency and do not replace file-based routing with manual lists.
1074
+
1075
+ ## Decision Rules
1076
+
1077
+ Use `alpha` patterns when the task is about:
1078
+
1079
+ - tenant DNA
1080
+ - capability reference
1081
+ - baseline protocol shape
1082
+ - proving what the base system already supports
1083
+
1084
+ Use `gptgiorgio` patterns when the task is about:
1085
+
1086
+ - stronger branded frontend customization
1087
+ - richer domain-specific sections
1088
+ - image-heavy schema design
1089
+ - proving how far customization can go without changing the bootstrap
1090
+
1091
+ Do not treat `gptgiorgio` as canonical for legacy admin context awareness.
1092
+
1093
+ ## Default Operating Procedure
1094
+
1095
+ When you receive a JsonPages tenant task:
1096
+
1097
+ 1. Identify whether the problem belongs to `core`, tenant, or generator.
1098
+ 2. Read the smallest code surface that proves it.
1099
+ 3. Prefer fixing the tenant contract before touching visual polish.
1100
+ 4. Keep generated and deterministic workflows reproducible.
1101
+ 5. State assumptions when inferring intended branded output from examples.
1102
+
1103
+ END_OF_FILE_CONTENT
1104
+ mkdir -p ".cursor/skills-cursor/migrate-to-skills"
1105
+ echo "Creating .cursor/skills-cursor/migrate-to-skills/SKILL.md..."
1106
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/migrate-to-skills/SKILL.md"
1107
+ ---
1108
+ name: migrate-to-skills
1109
+ description: >-
1110
+ Convert 'Applied intelligently' Cursor rules (.cursor/rules/*.mdc) and slash
1111
+ commands (.cursor/commands/*.md) to Agent Skills format (.cursor/skills/). Use
1112
+ when you want to migrate rules or commands to skills, convert .mdc rules to
1113
+ SKILL.md format, or consolidate commands into the skills directory.
1114
+ disable-model-invocation: true
404
1115
  ---
1116
+ # Migrate Rules and Slash Commands to Skills
1117
+
1118
+ Convert Cursor rules ("Applied intelligently") and slash commands to Agent Skills format.
1119
+
1120
+ **CRITICAL: Preserve the exact body content. Do not modify, reformat, or "improve" it - copy verbatim.**
1121
+
1122
+ ## Locations
405
1123
 
406
- ## 1.1 Valore della tipizzazione: governance e CMS UX
1124
+ | Level | Source | Destination |
1125
+ |-------|--------|-------------|
1126
+ | Project | `{workspaceFolder}/**/.cursor/rules/*.mdc`, `{workspaceFolder}/.cursor/commands/*.md` |
1127
+ | User | `~/.cursor/commands/*.md` |
407
1128
 
408
- La tipizzazione (tipi TypeScript + schema Zod) serve a **due livelli**: governance (sviluppatore/architettura) e **UX del CMS** (autore che usa Studio). Spesso si menziona solo il primo.
1129
+ Notes:
1130
+ - Cursor rules inside the project can live in nested directories. Be thorough in your search and use glob patterns to find them.
1131
+ - Ignore anything in ~/.cursor/worktrees
1132
+ - Ignore anything in ~/.cursor/skills-cursor. This is reserved for Cursor's internal built-in skills and is managed automatically by the system.
409
1133
 
410
- **Governance:** registry tipizzato, SectionComponentPropsMap, forma di SiteConfig/PageConfig, audit, code-generation → coerenza tra tenant, niente drift, refactor sicuro, tooling basato su spec.
1134
+ ## Finding Files to Migrate
411
1135
 
412
- **CMS UX:** lo schema Zod guida il **Form Factory** (quali widget per ogni campo: text, textarea, select, list, icon-picker, **image-picker**); **data-jp-field** e **data-jp-item-id/field** legano click in Stage e form nell'Inspector; **AddSectionConfig** dà tipi addabili, label e default. Risultato per l'autore: form coerenti, "Aggiungi sezione" con nomi e dati iniziali sensati, selezione corretta (click → form giusto), validazione con errori chiari. Senza schema e contratto tipizzato l'Inspector non saprebbe quali campi mostrare né come validare. Quindi: per la governance la tipizzazione garantisce contratti; per la **CMS UX** definisce l'**esperienza di editing** (controlli, label, default, binding). Va specificato entrambi.
1136
+ **Rules**: Migrate if rule has a `description` but NO `globs` and NO `alwaysApply: true`.
1137
+
1138
+ **Commands**: Migrate all - they're plain markdown without frontmatter.
1139
+
1140
+ ## Conversion Format
1141
+
1142
+ ### Rules: .mdc → SKILL.md
1143
+
1144
+ ```markdown
1145
+ # Before: .cursor/rules/my-rule.mdc
1146
+ ---
1147
+ description: What this rule does
1148
+ globs:
1149
+ alwaysApply: false
1150
+ ---
1151
+ # Title
1152
+ Body content...
1153
+ ```
413
1154
 
1155
+ ```markdown
1156
+ # After: .cursor/skills/my-rule/SKILL.md
1157
+ ---
1158
+ name: my-rule
1159
+ description: What this rule does
414
1160
  ---
1161
+ # Title
1162
+ Body content...
1163
+ ```
1164
+
1165
+ Changes: Add `name` field, remove `globs`/`alwaysApply`, keep body exactly.
415
1166
 
416
- ## 2. Struttura progetto (completa)
417
-
418
- - **`src/data/config/site.json`** — SiteConfig (identity, pages[], header block, footer block).
419
- - **`src/data/config/menu.json`** — MenuConfig (es. `main: MenuItem[]`).
420
- - **`src/data/config/theme.json`** — ThemeConfig (tokens).
421
- - **`src/data/pages/<slug>.json`** — PageConfig (slug, meta, sections[]). **Per creare una nuova pagina** basta aggiungere un file `<slug>.json` in `src/data/pages/`; lo slug del nome file diventa il path della pagina (es. `chi-siamo.json` → `/chi-siamo`).
422
- - **`src/components/<sectionType>/`** — **Capsula piena:** View.tsx, schema.ts, types.ts, index.ts.
423
- - **`src/lib/base-schemas.ts`** — BaseSectionData, BaseArrayItem, BaseSectionSettingsSchema.
424
- - **`src/lib/schemas.ts`** — SECTION_SCHEMAS (aggregato degli schema data per tipo) + export SectionType.
425
- - **`src/lib/ComponentRegistry.tsx`** — Registry tipizzato: `{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }`.
426
- - **`src/lib/addSectionConfig.ts`** — AddSectionConfig (addableSectionTypes, sectionTypeLabels, getDefaultSectionData).
427
- - **`src/types.ts`** — SectionComponentPropsMap, PageConfig, SiteConfig, MenuConfig, ThemeConfig; **module augmentation** per SectionDataRegistry e SectionSettingsRegistry; re-export da `@olonjs/core`.
428
- - **`src/App.tsx`** — Bootstrap: config (tenantId, registry, schemas, pages, siteConfig, themeConfig, menuConfig, themeCss, addSection); `<JsonPagesEngine config={config} />`.
429
- - **CSS globale** — Include i selettori TOCC per overlay (hover/selected/type label).
1167
+ ### Commands: .md SKILL.md
430
1168
 
1169
+ ```markdown
1170
+ # Before: .cursor/commands/commit.md
1171
+ # Commit current work
1172
+ Instructions here...
1173
+ ```
1174
+
1175
+ ```markdown
1176
+ # After: .cursor/skills/commit/SKILL.md
1177
+ ---
1178
+ name: commit
1179
+ description: Commit current work with standardized message format
1180
+ disable-model-invocation: true
431
1181
  ---
1182
+ # Commit current work
1183
+ Instructions here...
1184
+ ```
1185
+
1186
+ Changes: Add frontmatter with `name` (from filename), `description` (infer from content), and `disable-model-invocation: true`, keep body exactly.
1187
+
1188
+ **Note:** The `disable-model-invocation: true` field prevents the model from automatically invoking this skill. Slash commands are designed to be explicitly triggered by the user via the `/` menu, not automatically suggested by the model.
432
1189
 
433
- ## 3. Componenti (capsule + IDAC + token)
1190
+ ## Notes
1191
+
1192
+ - `name` must be lowercase with hyphens only
1193
+ - `description` is critical for skill discovery
1194
+ - Optionally delete originals after verifying migration works
1195
+
1196
+ ### Migrate a Rule (.mdc → SKILL.md)
1197
+
1198
+ 1. Read the rule file
1199
+ 2. Extract the `description` from the frontmatter
1200
+ 3. Extract the body content (everything after the closing `---` of the frontmatter)
1201
+ 4. Create the skill directory: `.cursor/skills/{skill-name}/` (skill name = filename without .mdc)
1202
+ 5. Write `SKILL.md` with new frontmatter (`name` and `description`) + the EXACT original body content (preserve all whitespace, formatting, code blocks verbatim)
1203
+ 6. Delete the original rule file
1204
+
1205
+ ### Migrate a Command (.md → SKILL.md)
1206
+
1207
+ 1. Read the command file
1208
+ 2. Extract description from the first heading (remove `#` prefix)
1209
+ 3. Create the skill directory: `.cursor/skills/{skill-name}/` (skill name = filename without .md)
1210
+ 4. Write `SKILL.md` with new frontmatter (`name`, `description`, and `disable-model-invocation: true`) + blank line + the EXACT original file content (preserve all whitespace, formatting, code blocks verbatim)
1211
+ 5. Delete the original command file
434
1212
 
435
- - **Capsula:** Ogni section type ha View, schema (Zod), types (inferiti), index. Lo schema **data** estende BaseSectionData; gli item degli array estendono BaseArrayItem.
436
- - **View:** Riceve `data` e `settings` (e `menu` per header). Non importa Zod. Usa **solo** variabili CSS per colori/raggi (es. `bg-[var(--local-bg)]`), sezione root con `z-index` ≤ 1.
437
- - **IDAC (ICE):** Su ogni campo editabile in modo scalare: **`data-jp-field="<fieldKey>"`**. Su ogni item di array editabile: **`data-jp-item-id="<stableId>"`** e **`data-jp-item-field="<arrayKey>"`**. Così l'Inspector può legare selezione e form ai path corretti.
438
- - **Schema:** Usa il vocabolario UI (ECIP): `.describe('ui:text')`, `ui:textarea`, `ui:select`, `ui:number`, `ui:list`, `ui:icon-picker`, **`ui:image-picker`** (vedi §3.1). Array di oggetti editabili: ogni oggetto con `id` (BaseArrayItem).
1213
+ **CRITICAL: Copy the body content character-for-character. Do not reformat, fix typos, or "improve" anything.**
439
1214
 
440
- **Perché servono (componenti):** **data-jp-field** e **data-jp-item-*** servono perché lo Stage è in un iframe e il Core deve sapere quale campo/item corrisponde al click senza conoscere il DOM del Tenant: così la sidebar può evidenziare la riga attiva (anche con opacità diversa per attivo/inattivo), aprire il form sul campo giusto e gestire liste (reorder, delete). Senza IDAC, click sul canvas non si riflette nella sidebar. Schema con `ui:*` e BaseArrayItem servono al Form Factory per generare i widget giusti e mantenere chiavi stabili (reorder/delete). Token e z-index evitano che il contenuto copra l'overlay. Vedi spec §6 (IDAC), §5 (ECIP), §4 (CIP).
1215
+ ## Workflow
441
1216
 
1217
+ If you have the Task tool available:
1218
+ DO NOT start to read all of the files yourself. That function should be delegated to the subagents. Your job is to dispatch the subagents for each category of files and wait for the results.
1219
+
1220
+ 1. [ ] Create the skills directories if they don't exist (`.cursor/skills/` for project, `~/.cursor/skills/` for user)
1221
+ 2. Dispatch three fast general purpose subagents (NOT explore) in parallel to do the following steps for project rules (pattern: `{workspaceFolder}/**/.cursor/rules/*.mdc`), user commands (pattern: `~/.cursor/commands/*.md`), and project commands (pattern: `{workspaceFolder}/**/.cursor/commands/*.md`):
1222
+ I. [ ] Find files to migrate in the given pattern
1223
+ II. [ ] For rules, check if it's an "applied intelligently" rule (has `description`, no `globs`, no `alwaysApply: true`). Commands are always migrated. DO NOT use the terminal to read files. Use the read tool.
1224
+ III. [ ] Make a list of files to migrate. If empty, done.
1225
+ IV. [ ] For each file, read it, then write the new skill file preserving the body content EXACTLY. DO NOT use the terminal to write these files. Use the edit tool.
1226
+ V. [ ] Delete the original file. DO NOT use the terminal to delete these files. Use the delete tool.
1227
+ VI. [ ] Return a list of all the skill files that were migrated along with the original file paths.
1228
+ 3. [ ] Wait for all subagents to complete and summarize the results to the user. IMPORTANT: Make sure to let them know if they want to undo the migration, to ask you to.
1229
+ 4. [ ] If the user asks you to undo the migration, do the opposite of the above steps to restore the original files.
1230
+
1231
+
1232
+ If you don't have the Task tool available:
1233
+ 1. [ ] Create the skills directories if they don't exist (`.cursor/skills/` for project, `~/.cursor/skills/` for user)
1234
+ 2. [ ] Find files to migrate in both project (`.cursor/`) and user (`~/.cursor/`) directories
1235
+ 3. [ ] For rules, check if it's an "applied intelligently" rule (has `description`, no `globs`, no `alwaysApply: true`). Commands are always migrated. DO NOT use the terminal to read files. Use the read tool.
1236
+ 4. [ ] Make a list of files to migrate. If empty, done.
1237
+ 5. [ ] For each file, read it, then write the new skill file preserving the body content EXACTLY. DO NOT use the terminal to write these files. Use the edit tool.
1238
+ 6. [ ] Delete the original file. DO NOT use the terminal to delete these files. Use the delete tool.
1239
+ 7. [ ] Summarize the results to the user. IMPORTANT: Make sure to let them know if they want to undo the migration, to ask you to.
1240
+ 8. [ ] If the user asks you to undo the migration, do the opposite of the above steps to restore the original files.
1241
+
1242
+ END_OF_FILE_CONTENT
1243
+ mkdir -p ".cursor/skills-cursor/olonjs"
1244
+ echo "Creating .cursor/skills-cursor/olonjs/SKILL.md..."
1245
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/olonjs/SKILL.md"
1246
+ ---
1247
+ name: olonjs-tenant
1248
+ description: Use when working on a OlonJS tenant, transforming the base tenant DNA into a branded tenant, adding or modifying tenant sections, maintaining schema-driven editability, or reasoning about what belongs to @olonjs/core versus the tenant.
442
1249
  ---
443
1250
 
444
- ## 3.1 Image Picker: uso corretto nello schema (esempio `image-break`)
1251
+ # OlonJS Tenant
445
1252
 
446
- Per i **campi immagine** il Form Factory espone il widget **Image Picker** solo se lo schema è modellato correttamente.
1253
+ Use this skill for work on the OlonJS ecosystem when the task involves:
447
1254
 
448
- ### Regola
1255
+ - a tenant generated from the OlonJS CLI
1256
+ - `@olonjs/core`
1257
+ - tenant sections/capsules
1258
+ - `src/data/pages/**/*.json` or `src/data/config/*.json`
1259
+ - schema-driven editing and inspector compatibility
1260
+ - generator scripts that turn a base tenant into a branded tenant
449
1261
 
450
- - Il campo immagine non è una **stringa** (`z.string()`), ma un **oggetto** con almeno `url` e, opzionalmente, `alt`.
451
- - Lo **schema di questo oggetto** (il sub-schema) va marcato con **`.describe('ui:image-picker')`**. Il Form Factory riconosce `ui:image-picker` solo su **ZodObject** (schema oggetto), non su campi stringa.
1262
+ Read code first. Treat documents as secondary unless they help interpret code that is otherwise ambiguous.
452
1263
 
453
- ### Esempio (capsula `image-break`)
1264
+ ## Architecture Specifications
454
1265
 
455
- **Schema (`schema.ts`):**
1266
+ Use this document as the architectural laws for each tenant, compliancy will be tested against these specs:
456
1267
 
457
- ```ts
458
- import { z } from 'zod';
459
- import { BaseSectionData } from '@/lib/base-schemas';
1268
+ - `\\wsl.localhost\Ubuntu\home\dev\npm-jpcore\specs\olonjsSpecs_V.1.3.md`
460
1269
 
461
- const ImageSelectionSchema = z
462
- .object({
463
- url: z.string(),
464
- alt: z.string().optional(),
465
- })
466
- .describe('ui:image-picker');
467
1270
 
468
- export const ImageBreakSchema = BaseSectionData.extend({
469
- label: z.string().optional().describe('ui:text'),
470
- image: ImageSelectionSchema.default({ url: '', alt: '' }),
471
- caption: z.string().optional().describe('ui:textarea'),
472
- });
473
- ```
474
1271
 
475
- - **ImageSelectionSchema** è un `z.object({ url, alt })` con **`.describe('ui:image-picker')`** sull'oggetto.
476
- - Il campo **`image`** nella section data usa quel schema (con default) così l'Inspector mostra il widget Image Picker per `image`.
477
1272
 
478
- **View (`View.tsx`):**
1273
+ ## Core Model
1274
+
1275
+ OlonJS has a hard split between `core` and `tenant`.
1276
+
1277
+ - `@olonjs/core` owns routing, `/admin`, `/admin/preview`, preview stage, studio state, inspector/form factory, and shared engine behavior.
1278
+ - The tenant owns sections, schemas, type augmentation, page/config JSON, theme/design layer, and local workflow scripts.
1279
+ - The tenant does not implement the CMS. It implements the tenant protocol consumed by the engine.
1280
+
1281
+ In this ecosystem, code is the source of truth.
1282
+
1283
+ Compliance priority:
1284
+
1285
+ 1. Data is bound correctly.
1286
+ 2. Schemas describe fields correctly.
1287
+ 3. Content is editable without breaking the inspector.
1288
+ 4. Tenant structure stays standardized.
1289
+ 5. Context-aware focus/highlight in the legacy admin is desirable but secondary.
1290
+
1291
+ ## Canonical References
1292
+
1293
+ Use these local references when available:
1294
+
1295
+ - Base tenant DNA: `\\wsl.localhost\Ubuntu\home\dev\temp\alpha`
1296
+ - Custom tenant reference: `\\wsl.localhost\Ubuntu\home\dev\temp\gptgiorgio`
1297
+ - Core engine: `\\wsl.localhost\Ubuntu\home\dev\npm-jpcore\packages\core`
1298
+ - Generator example: `\\wsl.localhost\Ubuntu\home\dev\temp\clonark\generate_olon.sh`
1299
+
1300
+ If these paths are missing, infer the same roles from the current workspace:
1301
+
1302
+ - base CLI-generated tenant
1303
+ - branded tenant
1304
+ - core package
1305
+ - generator script
1306
+
1307
+ ## Tenant Anatomy
1308
+
1309
+ Expect these files to move together:
1310
+
1311
+ - `src/components/<section>/View.tsx`
1312
+ - `src/components/<section>/schema.ts`
1313
+ - `src/components/<section>/types.ts`
1314
+ - `src/components/<section>/index.ts`
1315
+ - `src/lib/ComponentRegistry.tsx`
1316
+ - `src/lib/schemas.ts`
1317
+ - `src/lib/addSectionConfig.ts`
1318
+ - `src/types.ts`
1319
+ - `src/data/pages/**/*.json`
1320
+ - `src/data/config/site.json`
1321
+ - `src/data/config/theme.json`
1322
+ - `src/data/config/menu.json`
1323
+
1324
+ Useful rule: if a section type changes, check all of the files above before concluding the task is done.
1325
+
1326
+ ## What Good Work Looks Like
1327
+
1328
+ A good tenant change:
1329
+
1330
+ - stays inside tenant boundaries unless the issue is truly in `@olonjs/core`
1331
+ - keeps schema, defaults, registry, and type augmentation aligned
1332
+ - preserves editability for strings, lists, nested objects, CTAs, and image fields
1333
+ - uses `ImageSelectionSchema`-style image fields when the content is image-driven
1334
+ - keeps page content JSON-first
1335
+
1336
+ A suspicious tenant change:
1337
+
1338
+ - patches the core to fix a tenant modeling problem
1339
+ - adds visual complexity without data bindings
1340
+ - introduces fields into JSON that are not represented in schema
1341
+ - changes a section view without updating defaults or types
1342
+ - optimizes legacy context awareness at the expense of simpler, reliable editability
1343
+
1344
+ ## Workflow 1: Base Tenant -> Branded Tenant
1345
+
1346
+ This is the primary workflow.
1347
+
1348
+ Goal:
1349
+
1350
+ - transform a CLI-generated base tenant into a branded tenant through a single generator script
1351
+
1352
+ Treat the generator script as procedural source of truth for the green build workflow.
1353
+
1354
+ When maintaining or authoring a generator:
1355
+
1356
+ 1. Separate non-deterministic bootstrap from deterministic sync.
1357
+ 2. Make explicit which files are managed output.
1358
+ 3. Keep the script aligned with the current tenant code, not with stale docs.
1359
+ 4. Preserve tenant protocol files: sections, schemas, registries, type augmentation, config JSON, assets, shims.
1360
+ 5. Prefer deterministic local writes after any remote/bootstrap step.
1361
+
1362
+ Typical structure of a good generator:
1363
+
1364
+ - preflight checks
1365
+ - remote/bootstrap steps such as `shadcn` or external registries
1366
+ - deterministic creation/sync of tenant files
1367
+ - compatibility patches for known unstable upstream payloads
1368
+ - final validation commands
1369
+
1370
+ When asked to update a branded tenant generator:
1371
+
1372
+ 1. Diff base tenant against branded tenant.
1373
+ 2. Classify differences into:
1374
+ - intended branded output
1375
+ - reusable generator logic
1376
+ - accidental drift
1377
+ 3. Encode only the reusable intended differences into the script.
1378
+ 4. Keep the output reproducible from a fresh base tenant.
1379
+
1380
+ ## Workflow 2: Add Or Change A Section
1381
+
1382
+ When adding a new section type:
1383
+
1384
+ 1. Create `View.tsx`, `schema.ts`, `types.ts`, `index.ts`.
1385
+ 2. Register the section in `src/lib/ComponentRegistry.tsx`.
1386
+ 3. Register the schema in `src/lib/schemas.ts`.
1387
+ 4. Add defaults and label in `src/lib/addSectionConfig.ts`.
1388
+ 5. Extend `SectionComponentPropsMap` and module augmentation in `src/types.ts`.
1389
+ 6. Add or update page JSON using the new section type.
479
1390
 
480
- - Per il `src` dell'immagine: **`resolveAssetUrl(data.image.url, tenantId)`** (multi-tenant e path relativi).
481
- - Sul nodo che rappresenta l'immagine (es. il `<img>` o un wrapper): **`data-jp-field="image"`** così il click in Stage lega l'Inspector al campo `image`.
482
- - Altri campi editabili (caption, label) con **`data-jp-field="caption"`** e **`data-jp-field="label"`** dove appropriato.
1391
+ When changing an existing section:
483
1392
 
484
- **Riferimento completo:** `apps/tenant-alpha/src/components/image-break/` (schema.ts, types.ts, View.tsx, index.ts).
1393
+ 1. Read the section schema first.
1394
+ 2. Read the page JSON using it.
1395
+ 3. Check the view for `data-jp-field` usage and binding shape.
1396
+ 4. Update defaults if the data shape changed.
1397
+ 5. Verify the inspector still has a path to edit the content.
485
1398
 
486
- ### Cosa evitare
1399
+ ## Workflow 3: Images, Rich Content, Nested Routes
487
1400
 
488
- - **Non** usare `.describe('ui:image-picker')` su un campo **stringa** (es. `imageUrl: z.string().describe('ui:image-picker')`): il widget Image Picker si aspetta un oggetto `{ url, alt? }`.
489
- - **Non** dimenticare `data-jp-field="image"` sul nodo corrispondente nel DOM, altrimenti il binding Inspector ↔ Stage non funziona per quel campo.
1401
+ Images:
490
1402
 
1403
+ - Prefer structured image objects compatible with tenant base schemas.
1404
+ - Assume the core supports image picking and upload flows.
1405
+ - The tenant is responsible for declaring image fields in schema and rendering them coherently.
1406
+
1407
+ Rich editorial content:
1408
+
1409
+ - Tiptap-style sections are tenant-level integrations.
1410
+ - Treat page JSON using `type: "tiptap"` as runtime usage examples, and section code as the real source of truth.
1411
+
1412
+ Nested routes:
1413
+
1414
+ - Files under `src/data/pages/**/*.json` may represent nested slugs.
1415
+ - Preserve slug/path consistency and do not replace file-based routing with manual lists.
1416
+
1417
+ ## Decision Rules
1418
+
1419
+ Use `alpha` patterns when the task is about:
1420
+
1421
+ - tenant DNA
1422
+ - capability reference
1423
+ - baseline protocol shape
1424
+ - proving what the base system already supports
1425
+
1426
+ Use `gptgiorgio` patterns when the task is about:
1427
+
1428
+ - stronger branded frontend customization
1429
+ - richer domain-specific sections
1430
+ - image-heavy schema design
1431
+ - proving how far customization can go without changing the bootstrap
1432
+
1433
+ Do not treat `gptgiorgio` as canonical for legacy admin context awareness.
1434
+
1435
+ ## Default Operating Procedure
1436
+
1437
+ When you receive a OlonJS tenant task:
1438
+
1439
+ 1. Identify whether the problem belongs to `core`, tenant, or generator.
1440
+ 2. Read the smallest code surface that proves it.
1441
+ 3. Prefer fixing the tenant contract before touching visual polish.
1442
+ 4. Keep generated and deterministic workflows reproducible.
1443
+ 5. State assumptions when inferring intended branded output from examples.
1444
+
1445
+ END_OF_FILE_CONTENT
1446
+ # SKIP: .cursor/skills-cursor/olonjs/SKILL.md:Zone.Identifier is binary and cannot be embedded as text.
1447
+ mkdir -p ".cursor/skills-cursor/shell"
1448
+ echo "Creating .cursor/skills-cursor/shell/SKILL.md..."
1449
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/shell/SKILL.md"
1450
+ ---
1451
+ name: shell
1452
+ description: >-
1453
+ Runs the rest of a /shell request as a literal shell command. Use only when
1454
+ the user explicitly invokes /shell and wants the following text executed
1455
+ directly in the terminal.
1456
+ disable-model-invocation: true
491
1457
  ---
1458
+ # Run Shell Commands
1459
+
1460
+ Use this skill only when the user explicitly invokes `/shell`.
492
1461
 
493
- ## 4. Dati: forma e responsabilità
1462
+ ## Behavior
494
1463
 
495
- - **site.json / menu.json / theme.json / pages/*.json** Forma esatta come in Appendix A (SiteConfig, MenuConfig, ThemeConfig, PageConfig). Sono la source of truth quando l'utente salva da Studio (Working Draft → persist su questi file o su API che li generano).
496
- - **Studio** aggiorna il Working Draft; il sync con l'iframe e il "Bake" usano la stessa struttura. Quindi i dati che passi a JsonPagesEngine (siteConfig, menuConfig, pages) devono essere compatibili con ciò che l'editor modifica.
1464
+ 1. Treat all user text after the `/shell` invocation as the literal shell command to run.
1465
+ 2. Execute that command immediately with the terminal tool.
1466
+ 3. Do not rewrite, explain, or "improve" the command before running it.
1467
+ 4. Do not inspect the repository first unless the command itself requires repository context.
1468
+ 5. If the user invokes `/shell` without any following text, ask them which command to run.
497
1469
 
498
- Se i dati arrivano da un CMS esterno, tocca a te sincronizzare: es. export da Studio → push su CMS, oppure CMS come source e Studio in read-only; in ogni caso la **forma** delle pagine (sections con id, type, data, settings) resta quella della spec.
1470
+ ## Response
499
1471
 
1472
+ - Run the command first.
1473
+ - Then briefly report the exit status and any important stdout or stderr.
1474
+
1475
+ END_OF_FILE_CONTENT
1476
+ mkdir -p ".cursor/skills-cursor/update-cursor-settings"
1477
+ echo "Creating .cursor/skills-cursor/update-cursor-settings/SKILL.md..."
1478
+ cat << 'END_OF_FILE_CONTENT' > ".cursor/skills-cursor/update-cursor-settings/SKILL.md"
1479
+ ---
1480
+ name: update-cursor-settings
1481
+ description: >-
1482
+ Modify Cursor/VSCode user settings in settings.json. Use when you want to
1483
+ change editor settings, preferences, configuration, themes, font size, tab
1484
+ size, format on save, auto save, keybindings, or any settings.json values.
500
1485
  ---
1486
+ # Updating Cursor Settings
1487
+
1488
+ This skill guides you through modifying Cursor/VSCode user settings. Use this when you want to change editor settings, preferences, configuration, themes, keybindings, or any `settings.json` values.
1489
+
1490
+ ## Settings File Location
501
1491
 
502
- ## 5. Registry, schemas, types, addSection
1492
+ | OS | Path |
1493
+ |----|------|
1494
+ | macOS | ~/Library/Application Support/Cursor/User/settings.json |
1495
+ | Linux | ~/.config/Cursor/User/settings.json |
1496
+ | Windows | %APPDATA%\Cursor\User\settings.json |
1497
+
1498
+ ## Before Modifying Settings
1499
+
1500
+ 1. **Read the existing settings file** to understand current configuration
1501
+ 2. **Preserve existing settings** - only add/modify what the user requested
1502
+ 3. **Validate JSON syntax** before writing to avoid breaking the editor
1503
+
1504
+ ## Modifying Settings
1505
+
1506
+ ### Step 1: Read Current Settings
1507
+
1508
+ ```typescript
1509
+ // Read the settings file first
1510
+ const settingsPath = "~/Library/Application Support/Cursor/User/settings.json";
1511
+ // Use the Read tool to get current contents
1512
+ ```
1513
+
1514
+ ### Step 2: Identify the Setting to Change
1515
+
1516
+ Common setting categories:
1517
+ - **Editor**: `editor.fontSize`, `editor.tabSize`, `editor.wordWrap`, `editor.formatOnSave`
1518
+ - **Workbench**: `workbench.colorTheme`, `workbench.iconTheme`, `workbench.sideBar.location`
1519
+ - **Files**: `files.autoSave`, `files.exclude`, `files.associations`
1520
+ - **Terminal**: `terminal.integrated.fontSize`, `terminal.integrated.shell.*`
1521
+ - **Cursor-specific**: Settings prefixed with `cursor.` or `aipopup.`
1522
+
1523
+ ### Step 3: Update the Setting
1524
+
1525
+ When modifying settings.json:
1526
+ 1. Parse the existing JSON (handle comments - VSCode settings support JSON with comments)
1527
+ 2. Add or update the requested setting
1528
+ 3. Preserve all other existing settings
1529
+ 4. Write back with proper formatting (2-space indentation)
1530
+
1531
+ ### Example: Changing Font Size
1532
+
1533
+ If user says "make the font bigger":
1534
+
1535
+ ```json
1536
+ {
1537
+ "editor.fontSize": 16
1538
+ }
1539
+ ```
1540
+
1541
+ ### Example: Enabling Format on Save
1542
+
1543
+ If user says "format my code when I save":
1544
+
1545
+ ```json
1546
+ {
1547
+ "editor.formatOnSave": true
1548
+ }
1549
+ ```
503
1550
 
504
- - **types.ts:** Unico punto di **module augmentation** e definizione di SectionComponentPropsMap, PageConfig, SiteConfig, MenuConfig, ThemeConfig. Header: `{ data, settings?, menu: MenuItem[] }`; tutti gli altri: `{ data, settings? }`.
505
- - **ComponentRegistry:** Ogni chiave di SectionType ha il componente corrispondente; tipo: `{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }`.
506
- - **SECTION_SCHEMAS:** Ogni chiave di SectionType ha lo **schema Zod della data** (stesso ordine del registry). Base schemas re-exportati da base-schemas.ts.
507
- - **addSectionConfig:** addableSectionTypes (solo i tipi che l'utente può aggiungere dalla libreria), sectionTypeLabels, getDefaultSectionData(type) che restituisce `data` valido per quello schema.
1551
+ ### Example: Changing Theme
508
1552
 
509
- **Perché servono (registry, schemas, types, addSection):** Un solo punto di augmentation (types.ts) e un solo SECTION_SCHEMAS evita duplicazioni e garantisce che registry, Form Factory e config usino gli stessi tipi. AddSectionConfig è l'unica fonte di verità per "quali section si possono aggiungere" e "con quali default"; senza, il modal "Aggiungi sezione" non avrebbe nomi né dati iniziali validi. Vedi spec §9 (ASC), Appendix A.2–A.3.
1553
+ If user says "use dark theme" or "change my theme":
510
1554
 
511
- ---
1555
+ ```json
1556
+ {
1557
+ "workbench.colorTheme": "Default Dark Modern"
1558
+ }
1559
+ ```
512
1560
 
513
- ## 6. Overlay e CSS (TOCC)
1561
+ ## Important Notes
514
1562
 
515
- - Il Core inietta il markup dell'overlay (wrapper con `data-section-id`, sibling con `data-jp-section-overlay`). Il **tenant** deve fornire il CSS in modo che:
516
- - `[data-jp-section-overlay]` copra la section, `pointer-events: none`, z-index alto (es. 9999).
517
- - Hover e selected siano visibili (bordo tratteggiato / pieno, eventuale tint).
518
- - Il type label (es. `[data-jp-section-overlay] > div`) sia posizionato e visibile su hover/selected.
1563
+ 1. **JSON with Comments**: VSCode/Cursor settings.json supports comments (`//` and `/* */`). When reading, be aware comments may exist. When writing, preserve comments if possible.
519
1564
 
520
- Senza questo, in Studio l'overlay non si vede nell'iframe.
1565
+ 2. **Restart May Be Required**: Some settings take effect immediately, others require reloading the window or restarting Cursor. Inform the user if a restart is needed.
521
1566
 
522
- **Perché servono (TOCC):** L'iframe dello Stage carica solo il CSS del Tenant; il Core inietta il markup dell'overlay ma non gli stili. Senza i selettori TOCC nel CSS tenant, bordo hover/selected e type label non sono visibili: l'autore non vede quale section è selezionata. Vedi spec §7 (TOCC).
1567
+ 3. **Backup**: For significant changes, consider mentioning the user can undo via Ctrl/Cmd+Z in the settings file or by reverting git changes if tracked.
523
1568
 
524
- ---
1569
+ 4. **Workspace vs User Settings**:
1570
+ - User settings (what this skill covers): Apply globally to all projects
1571
+ - Workspace settings (`.vscode/settings.json`): Apply only to the current project
525
1572
 
526
- ## 7. Checklist rapida (sviluppo grafico e dati, con CMS)
527
-
528
- | Cosa | Azione |
529
- |------|--------|
530
- | **Layout / grafico** | View con variabili `--local-*`, z-index ≤ 1, nessuna utility naked. |
531
- | **Dati (forma)** | SiteConfig, MenuConfig, ThemeConfig, PageConfig come in Appendix A; JSON in `data/config` e `data/pages`. |
532
- | **Nuova pagina** | Aggiungere un file `<slug>.json` in `src/data/pages/` (lo slug diventa il path della pagina). |
533
- | **Capsule** | View + schema (con ui:*) + types + index; data schema estende BaseSectionData; array item con id. |
534
- | **IDAC** | data-jp-field su campi scalari editabili; data-jp-item-id e data-jp-item-field su item di array. |
535
- | **Image Picker** | Campo immagine = oggetto `{ url, alt? }` con sub-schema `.describe('ui:image-picker')`; View con `resolveAssetUrl` e `data-jp-field="image"`. Esempio: `image-break`. |
536
- | **types.ts** | SectionComponentPropsMap (header con menu), augmentation, PageConfig, SiteConfig, MenuConfig, ThemeConfig. |
537
- | **Registry** | Tutti i tipi mappati al componente; tipo registry come in Appendix A. |
538
- | **SECTION_SCHEMAS** | Un entry per tipo (schema data); re-export base schemas. |
539
- | **addSectionConfig** | addableSectionTypes, sectionTypeLabels, getDefaultSectionData. |
540
- | **Config** | tenantId, registry, schemas, pages, siteConfig, themeConfig, menuConfig, themeCss, addSection. |
541
- | **TOCC** | CSS overlay per [data-jp-section-overlay], hover, selected, type label. |
1573
+ 5. **Commit Attribution**: When the user asks about commit attribution, clarify whether they want to edit the **CLI agent** or the **IDE agent**. For the CLI agent, modify `~/.cursor/cli-config.json`. For the IDE agent, it is controlled from the UI at **Cursor Settings > Agent > Attribution** (not settings.json).
542
1574
 
543
- ---
1575
+ ## Common User Requests → Settings
544
1576
 
545
- ## 8. Riferimenti spec
1577
+ | User Request | Setting |
1578
+ |--------------|---------|
1579
+ | "bigger/smaller font" | `editor.fontSize` |
1580
+ | "change tab size" | `editor.tabSize` |
1581
+ | "format on save" | `editor.formatOnSave` |
1582
+ | "word wrap" | `editor.wordWrap` |
1583
+ | "change theme" | `workbench.colorTheme` |
1584
+ | "hide minimap" | `editor.minimap.enabled` |
1585
+ | "auto save" | `files.autoSave` |
1586
+ | "line numbers" | `editor.lineNumbers` |
1587
+ | "bracket matching" | `editor.bracketPairColorization.enabled` |
1588
+ | "cursor style" | `editor.cursorStyle` |
1589
+ | "smooth scrolling" | `editor.smoothScrolling` |
546
1590
 
547
- - **Architettura e ICE:** §1–§10 (MTRP, JSP, TBP, CIP, ECIP, IDAC, TOCC, BSDS, ASC, JEB).
548
- - **Tipi e code-generation:** Appendix A (Core types, Tenant types, Schema contract, File paths, Integration checklist).
549
- - **Admin:** JAP (Studio topology, Working Draft, Bake, overlay, Green Build).
1591
+ ## Workflow
550
1592
 
551
- Usando questo percorso hai **governance** piena: tipi, schema, editor, Add Section e overlay allineati alle spec v1.2. Per le versioni con tutti i "Perché servono" usa il file **JSONPAGES_Specs_v1.2_completo.md**.
1593
+ 1. Read ~/Library/Application Support/Cursor/User/settings.json
1594
+ 2. Parse the JSON content
1595
+ 3. Add/modify the requested setting(s)
1596
+ 4. Write the updated JSON back to the file
1597
+ 5. Inform the user the setting has been changed and whether a reload is needed
552
1598
 
553
1599
  END_OF_FILE_CONTENT
554
- mkdir -p "docs/ver"
555
1600
  echo "Creating index.html..."
556
1601
  cat << 'END_OF_FILE_CONTENT' > "index.html"
557
1602
  <!DOCTYPE html>
@@ -585,7 +1630,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
585
1630
  "dev:clean": "vite --force",
586
1631
  "prebuild": "node scripts/sync-pages-to-public.mjs",
587
1632
  "build": "tsc && vite build",
588
- "dist": "bash ./src2Code.sh --template alpha src vercel.json index.html vite.config.ts scripts docs package.json",
1633
+ "dist": "bash ./src2Code.sh --template alpha src .cursor vercel.json index.html vite.config.ts scripts specs package.json",
589
1634
  "preview": "vite preview",
590
1635
  "bake:email": "tsx scripts/bake-email.tsx",
591
1636
  "bakemail": "npm run bake:email --",
@@ -596,7 +1641,7 @@ cat << 'END_OF_FILE_CONTENT' > "package.json"
596
1641
  "@tiptap/extension-link": "^2.11.5",
597
1642
  "@tiptap/react": "^2.11.5",
598
1643
  "@tiptap/starter-kit": "^2.11.5",
599
- "@olonjs/core": "^1.0.75",
1644
+ "@olonjs/core": "^1.0.77",
600
1645
  "clsx": "^2.1.1",
601
1646
  "lucide-react": "^0.474.0",
602
1647
  "react": "^19.0.0",
@@ -916,6 +1961,615 @@ fs.cpSync(sourceDir, targetDir, { recursive: true });
916
1961
 
917
1962
  console.log('[sync-pages-to-public] Synced pages to public/pages');
918
1963
 
1964
+ END_OF_FILE_CONTENT
1965
+ mkdir -p "specs"
1966
+ echo "Creating specs/olonjsSpecs_V.1.3.md..."
1967
+ cat << 'END_OF_FILE_CONTENT' > "specs/olonjsSpecs_V.1.3.md"
1968
+ # 📐 OlonJS Architecture Specifications v1.3
1969
+
1970
+ **Status:** Mandatory Standard
1971
+ **Version:** 1.3.0 (Sovereign Core Edition — Architecture + Studio/ICE UX, Path-Deterministic Nested Editing)
1972
+ **Target:** Senior Architects / AI Agents / Enterprise Governance
1973
+
1974
+ **Scope v1.3:** This edition preserves the complete v1.2 architecture (MTRP, JSP, TBP, CIP, ECIP, JAP + Studio/ICE UX contract: IDAC, TOCC, BSDS, ASC, JEB + Tenant Type & Code-Generation Annex) as a **faithful superset**, and adds strict path-based/nested-array behavior for Studio selection and Inspector expansion.
1975
+ **Scope note (breaking):** In strict v1.3 Studio semantics, the legacy flat protocol (`itemField` / `itemId`) is removed in favor of `itemPath` (root-to-leaf path segments).
1976
+
1977
+ ---
1978
+
1979
+ ## 1. 📐 Modular Type Registry Pattern (MTRP) v1.2
1980
+
1981
+ **Objective:** Establish a strictly typed, open-ended protocol for extending content data structures where the **Core Engine** is the orchestrator and the **Tenant** is the provider.
1982
+
1983
+ ### 1.1 The Sovereign Dependency Inversion
1984
+ The **Core** defines the empty `SectionDataRegistry`. The **Tenant** "injects" its specific definitions using **Module Augmentation**. This allows the Core to be distributed as a compiled NPM package while remaining aware of Tenant-specific types at compile-time.
1985
+
1986
+ ### 1.2 Technical Implementation (`@olonjs/core/kernel`)
1987
+ ```typescript
1988
+ export interface SectionDataRegistry {} // Augmented by Tenant
1989
+ export interface SectionSettingsRegistry {} // Augmented by Tenant
1990
+
1991
+ export interface BaseSection<K extends keyof SectionDataRegistry> {
1992
+ id: string;
1993
+ type: K;
1994
+ data: SectionDataRegistry[K];
1995
+ settings?: K extends keyof SectionSettingsRegistry
1996
+ ? SectionSettingsRegistry[K]
1997
+ : BaseSectionSettings;
1998
+ }
1999
+
2000
+ export type Section = {
2001
+ [K in keyof SectionDataRegistry]: BaseSection<K>
2002
+ }[keyof SectionDataRegistry];
2003
+ ```
2004
+
2005
+ **SectionType:** Core exports (or Tenant infers) **`SectionType`** as **`keyof SectionDataRegistry`**. After Tenant module augmentation, this is the union of all section type keys (e.g. `'header' | 'footer' | 'hero' | ...`). The Tenant uses this type for the ComponentRegistry and SECTION_SCHEMAS keys.
2006
+
2007
+ **Perché servono:** Il Core deve poter renderizzare section senza conoscere i tipi concreti a compile-time; il Tenant deve poter aggiungere nuovi tipi senza modificare il Core. I registry vuoti + module augmentation permettono di distribuire Core come pacchetto NPM e mantenere type-safety end-to-end (Section, registry, config). Senza MTRP, ogni nuovo tipo richiederebbe cambi nel Core o tipi deboli (`any`).
2008
+
2009
+ ---
2010
+
2011
+ ## 2. 📐 JsonPages Site Protocol (JSP) v1.8
2012
+
2013
+ **Objective:** Define the deterministic file system and the **Sovereign Projection Engine** (CLI).
2014
+
2015
+ ### 2.1 The File System Ontology (The Silo Contract)
2016
+ Every site must reside in an isolated directory. Global Governance is physically separated from Local Content.
2017
+ * **`/config/site.json`** — Global Identity & Reserved System Blocks (Header/Footer). See Appendix A for typed shape.
2018
+ * **`/config/menu.json`** — Navigation Tree (SSOT for System Header). See Appendix A.
2019
+ * **`/config/theme.json`** — Theme tokens (optional but recommended). See Appendix A.
2020
+ * **`/pages/[slug].json`** — Local Body Content per page. See Appendix A (PageConfig).
2021
+
2022
+ **Application path convention:** The runtime app typically imports these via an alias (e.g. **`@/data/config/`** and **`@/data/pages/`**). The physical silo may be `src/data/config/` and `src/data/pages/` so that `site.json`, `menu.json`, `theme.json` live under `src/data/config/`, and page JSONs under `src/data/pages/`. The CLI or projection script may use `/config/` and `/pages/` at repo root; the **contract** is that the app receives **siteConfig**, **menuConfig**, **themeConfig**, and **pages** as defined in JEB (§10) and Appendix A.
2023
+
2024
+ ### 2.2 Deterministic Projection (CLI Workflow)
2025
+ The CLI (`@olonjs/cli`) creates new tenants by:
2026
+ 1. **Infra Projection:** Generating `package.json`, `tsconfig.json`, and `vite.config.ts` (The Shell).
2027
+ 2. **Source Projection:** Executing a deterministic script (`src_tenant_alpha.sh`) to reconstruct the `src` folder (The DNA).
2028
+ 3. **Dependency Resolution:** Enforcing specific versions of React, Radix, and Tailwind v4.
2029
+
2030
+ **Perché servono:** Una struttura file deterministica (config vs pages) separa governance globale (site, menu, theme) dal contenuto per pagina; il CLI può rigenerare tenant e tooling può trovare dati e schemi sempre negli stessi path. Senza JSP, ogni tenant sarebbe una struttura ad hoc e ingestione/export/Bake sarebbero fragili.
2031
+
2032
+ ---
2033
+
2034
+ ## 3. 🧱 Tenant Block Protocol (TBP) v1.0
2035
+
2036
+ **Objective:** Standardize the "Capsule" structure for components to enable automated ingestion (Pull) by the SaaS.
2037
+
2038
+ ### 3.1 The Atomic Capsule Structure
2039
+ Components are self-contained directories under **`src/components/<sectionType>/`**:
2040
+ * **`View.tsx`** — The pure React component (Dumb View). Props: see Appendix A (SectionComponentPropsMap).
2041
+ * **`schema.ts`** — Zod schema(s) for the **data** contract (and optionally **settings**). Exports at least one schema (e.g. `HeroSchema`) used as the **data** schema for that type. Must extend BaseSectionData (§8) for data; array items must extend BaseArrayItem (§8).
2042
+ * **`types.ts`** — TypeScript interfaces inferred from the schema (e.g. `HeroData`, `HeroSettings`). Export types with names **`<SectionType>Data`** and **`<SectionType>Settings`** (or equivalent) so the Tenant can aggregate them in a single types module.
2043
+ * **`index.ts`** — Public API: re-exports View, schema(s), and types.
2044
+
2045
+ ### 3.2 Reserved System Types
2046
+ * **`type: 'header'`** — Reserved for `site.json`. Receives **`menu: MenuItem[]`** in addition to `data` and `settings`. Menu is sourced from `menu.json` (see Appendix A). The Tenant **must** type `SectionComponentPropsMap['header']` as `{ data: HeaderData; settings?: HeaderSettings; menu: MenuItem[] }`.
2047
+ * **`type: 'footer'`** — Reserved for `site.json`. Props: `{ data: FooterData; settings?: FooterSettings }` only (no `menu`).
2048
+ * **`type: 'sectionHeader'`** — A standard local block. Must define its own `links` array in its local schema if used.
2049
+
2050
+ **Perché servono:** La capsula (View + schema + types + index) è l’unità di estensione: il Core e il Form Factory possono scoprire tipi e contratti per tipo senza convenzioni ad hoc. Header/footer riservati evitano conflitti tra globale e locale. Senza TBP, aggregazione di SECTION_SCHEMAS e registry sarebbe incoerente e l’ingestion da SaaS non sarebbe automatizzabile.
2051
+
2052
+ ---
2053
+
2054
+ ## 4. 🧱 Component Implementation Protocol (CIP) v1.5
2055
+
2056
+ **Objective:** Ensure system-wide stability and Admin UI integrity.
2057
+
2058
+ 1. **The "Sovereign View" Law:** Components receive `data` and `settings` (and `menu` for header only) and return JSX. They are metadata-blind (never import Zod schemas).
2059
+ 2. **Z-Index Neutrality:** Components must not use `z-index > 1`. Layout delegation (sticky/fixed) is managed by the `SectionRenderer`.
2060
+ 3. **Agnostic Asset Protocol:** Use `resolveAssetUrl(path, tenantId)` for all media. Resolved URLs are under **`/assets/...`** with no tenantId segment in the path (e.g. relative `img/hero.jpg` → `/assets/img/hero.jpg`).
2061
+
2062
+ ### 4.4 Local Design Tokens (v1.2)
2063
+ Section Views that control their own background, text, borders, or radii **shall** define a **local scope** via an inline `style` object on the section root: e.g. `--local-bg`, `--local-text`, `--local-text-muted`, `--local-surface`, `--local-border`, `--local-radius-lg`, `--local-accent`, mapped to theme variables. All Tailwind classes that affect color or radius in that section **must** use these variables (e.g. `bg-[var(--local-bg)]`, `text-[var(--local-text)]`). No naked utilities (e.g. `bg-blue-500`). An optional **`label`** in section data may be rendered with class **`jp-section-label`** for overlay type labels.
2064
+
2065
+ ### 4.5 Z-Index & Overlay Governance (v1.2)
2066
+ Section content root **must** stay at **`z-index` ≤ 1** (prefer `z-0`) so the Sovereign Overlay can sit above with high z-index in Tenant CSS (§7). Header/footer may use a higher z-index (e.g. 50) only as a documented exception for global chrome.
2067
+
2068
+ **Perché servono (CIP):** View “dumb” (solo data/settings) e senza import di Zod evita accoppiamento e permette al Form Factory di essere l’unica fonte di verità sugli schemi. Z-index basso evita che il contenuto copra l’overlay di selezione in Studio. Asset via `resolveAssetUrl`: i path relativi vengono risolti in `/assets/...` (senza segmento tenantId nel path). Token locali (`--local-*`) rendono le section temabili e coerenti con overlay e tema; senza, stili “nudi” creano drift visivo e conflitti con l’UI di editing.
2069
+
2070
+ ---
2071
+
2072
+ ## 5. 🛠️ Editor Component Implementation Protocol (ECIP) v1.5
2073
+
2074
+ **Objective:** Standardize the Polymorphic ICE engine.
2075
+
2076
+ 1. **Recursive Form Factory:** The Admin UI builds forms by traversing the Zod ontology.
2077
+ 2. **UI Metadata:** Use `.describe('ui:[widget]')` in schemas to pass instructions to the Form Factory.
2078
+ 3. **Deterministic IDs:** Every object in a `ZodArray` must extend `BaseArrayItem` (containing an `id`) to ensure React reconciliation stability during reordering.
2079
+
2080
+ ### 5.4 UI Metadata Vocabulary (v1.2)
2081
+ Standard keys for the Form Factory:
2082
+
2083
+ | Key | Use case |
2084
+ |-----|----------|
2085
+ | `ui:text` | Single-line text input. |
2086
+ | `ui:textarea` | Multi-line text. |
2087
+ | `ui:select` | Enum / single choice. |
2088
+ | `ui:number` | Numeric input. |
2089
+ | `ui:list` | Array of items; list editor (add/remove/reorder). |
2090
+ | `ui:icon-picker` | Icon selection. |
2091
+
2092
+ Unknown keys may be treated as `ui:text`. Array fields must use `BaseArrayItem` for items.
2093
+
2094
+ ### 5.5 Path-Only Nested Selection & Expansion (v1.3, breaking)
2095
+ In strict v1.3 Studio/Inspector behavior, nested editing targets are represented by **path segments from root to leaf**.
2096
+
2097
+ ```typescript
2098
+ export type SelectionPathSegment = { fieldKey: string; itemId?: string };
2099
+ export type SelectionPath = SelectionPathSegment[];
2100
+ ```
2101
+
2102
+ Rules:
2103
+ * Expansion and focus for nested arrays **must** be computed from `SelectionPath` (root → leaf), not from a single flat pair.
2104
+ * Matching by `fieldKey` alone is non-compliant for nested structures.
2105
+ * Legacy flat payload fields **`itemField`** and **`itemId`** are removed from strict v1.3 selection protocol.
2106
+
2107
+ **Perché servono (ECIP):** Il Form Factory deve sapere quale widget usare (text, textarea, select, list, …) senza hardcodare per tipo; `.describe('ui:...')` è il contratto. BaseArrayItem con `id` su ogni item di array garantisce chiavi stabili in React e reorder/delete corretti nell’Inspector. In v1.3 la selezione/espansione path-only elimina ambiguità su array annidati: senza path completo root→leaf, la sidebar può aprire il ramo sbagliato o non aprire il target.
2108
+
2109
+ ---
2110
+
2111
+ ## 6. 🎯 ICE Data Attribute Contract (IDAC) v1.1
2112
+
2113
+ **Objective:** Mandatory data attributes so the Stage (iframe) and Inspector can bind selection and field/item editing without coupling to Tenant DOM.
2114
+
2115
+ ### 6.1 Section-Level Markup (Core-Provided)
2116
+ **SectionRenderer** (Core) wraps each section root with:
2117
+ * **`data-section-id`** — Section instance ID (e.g. UUID). On the wrapper that contains content + overlay.
2118
+ * Sibling overlay element **`data-jp-section-overlay`** — Selection ring and type label. **Tenant does not add this;** Core injects it.
2119
+
2120
+ Tenant Views render the **content** root only (e.g. `<section>` or `<div>`), placed **inside** the Core wrapper.
2121
+
2122
+ ### 6.2 Field-Level Binding (Tenant-Provided)
2123
+ For every **editable scalar field** the View **must** attach **`data-jp-field="<fieldKey>"`** (key matches schema path: e.g. `title`, `description`, `sectionTitle`, `label`).
2124
+
2125
+ ### 6.3 Array-Item Binding (Tenant-Provided)
2126
+ For every **editable array item** the View **must** attach:
2127
+ * **`data-jp-item-id="<stableId>"`** — Prefer `item.id`; fallback e.g. `legacy-${index}` only outside strict mode.
2128
+ * **`data-jp-item-field="<arrayKey>"`** — e.g. `cards`, `layers`, `products`, `paragraphs`.
2129
+
2130
+ ### 6.4 Compliance
2131
+ **Reserved types** (`header`, `footer`): ICE attributes optional unless Studio edits them. **All other section types** in the Stage and in `SECTION_SCHEMAS` **must** implement §6.2 and §6.3 for every editable field and array item.
2132
+
2133
+ ### 6.5 Strict Path Extraction for Nested Arrays (v1.3, breaking)
2134
+ For nested array targets, the Core/Inspector contract is path-based:
2135
+ * The runtime selection target is expressed as `itemPath: SelectionPath` (root → leaf).
2136
+ * Flat identity (`itemField` + `itemId`) is not sufficient for nested structures and is removed in strict v1.3 payloads.
2137
+ * In strict mode, index-based identity fallback is non-compliant for editable object arrays.
2138
+
2139
+ **Perché servono (IDAC):** Lo Stage è in un iframe e l’Inspector deve sapere **quale campo o item** corrisponde al click (o alla selezione) senza conoscere la struttura DOM del Tenant. **`data-jp-field`** associa un nodo DOM al path dello schema (es. `title`, `description`): così il Core può evidenziare la riga giusta nella sidebar, applicare opacità attivo/inattivo e aprire il form sul campo corretto. **`data-jp-item-id`** e **`data-jp-item-field`** fanno lo stesso per gli item di array (liste, reorder, delete). In v1.3, `itemPath` rende deterministico anche il caso nested (array dentro array), eliminando mismatch tra selezione canvas e ramo aperto in sidebar.
2140
+
2141
+ ---
2142
+
2143
+ ## 7. 🎨 Tenant Overlay CSS Contract (TOCC) v1.0
2144
+
2145
+ **Objective:** The Stage iframe loads only Tenant HTML/CSS. Core injects overlay **markup** but does **not** ship overlay styles. The Tenant **must** supply CSS so overlay is visible.
2146
+
2147
+ ### 7.1 Required Selectors (Tenant global CSS)
2148
+ 1. **`[data-jp-section-overlay]`** — `position: absolute; inset: 0`; `pointer-events: none`; base state transparent.
2149
+ 2. **`[data-section-id]:hover [data-jp-section-overlay]`** — Hover: e.g. dashed border, subtle tint.
2150
+ 3. **`[data-section-id][data-jp-selected] [data-jp-section-overlay]`** — Selected: solid border, optional tint.
2151
+ 4. **`[data-jp-section-overlay] > div`** (type label) — Position and visibility (e.g. visible on hover/selected).
2152
+
2153
+ ### 7.2 Z-Index
2154
+ Overlay **z-index** high (e.g. 9999). Section content at or below CIP limit (§4.5).
2155
+
2156
+ ### 7.3 Responsibility
2157
+ **Core:** Injects wrapper and overlay DOM; sets `data-jp-selected`. **Tenant:** All overlay **visual** rules.
2158
+
2159
+ **Perché servono (TOCC):** L’iframe dello Stage carica solo HTML/CSS del Tenant; il Core inietta il markup dell’overlay ma non gli stili. Senza CSS Tenant per i selettori TOCC, bordo hover/selected e type label non sarebbero visibili: l’autore non vedrebbe quale section è selezionata né il label del tipo. TOCC chiarisce la responsabilità (Core = markup, Tenant = aspetto) e garantisce UX uniforme tra tenant.
2160
+
2161
+ ---
2162
+
2163
+ ## 8. 📦 Base Section Data & Settings (BSDS) v1.0
2164
+
2165
+ **Objective:** Standardize base schema fragments for anchors, array items, and section settings.
2166
+
2167
+ ### 8.1 BaseSectionData
2168
+ Every section data schema **must** extend a base with at least **`anchorId`** (optional string). Canonical Zod (Tenant `lib/base-schemas.ts` or equivalent):
2169
+
2170
+ ```typescript
2171
+ export const BaseSectionData = z.object({
2172
+ anchorId: z.string().optional().describe('ui:text'),
2173
+ });
2174
+ ```
2175
+
2176
+ ### 8.2 BaseArrayItem
2177
+ Every array item schema editable in the Inspector **must** include **`id`** (optional string minimum). Canonical Zod:
2178
+
2179
+ ```typescript
2180
+ export const BaseArrayItem = z.object({
2181
+ id: z.string().optional(),
2182
+ });
2183
+ ```
2184
+
2185
+ Recommended: required UUID for new items. Used by `data-jp-item-id` and React reconciliation.
2186
+
2187
+ ### 8.3 BaseSectionSettings (Optional)
2188
+ Common section-level settings. Canonical Zod (name **BaseSectionSettingsSchema** or as exported by Core):
2189
+
2190
+ ```typescript
2191
+ export const BaseSectionSettingsSchema = z.object({
2192
+ paddingTop: z.enum(['none', 'sm', 'md', 'lg', 'xl', '2xl']).default('md').describe('ui:select'),
2193
+ paddingBottom: z.enum(['none', 'sm', 'md', 'lg', 'xl', '2xl']).default('md').describe('ui:select'),
2194
+ theme: z.enum(['dark', 'light', 'accent']).default('dark').describe('ui:select'),
2195
+ container: z.enum(['boxed', 'fluid']).default('boxed').describe('ui:select'),
2196
+ });
2197
+ ```
2198
+
2199
+ Capsules may extend this for type-specific settings. Core may export **BaseSectionSettings** as the TypeScript type inferred from this or a superset.
2200
+
2201
+ **Perché servono (BSDS):** anchorId permette deep-link e navigazione in-page; id sugli array item è necessario per `data-jp-item-id`, reorder e React reconciliation. BaseSectionSettings comuni (padding, theme, container) evitano ripetizione e allineano il Form Factory tra capsule. Senza base condivisi, ogni capsule inventa convenzioni e validazione/add-section diventano fragili.
2202
+
2203
+ ---
2204
+
2205
+ ## 9. 📌 AddSectionConfig (ASC) v1.0
2206
+
2207
+ **Objective:** Formalize the "Add Section" contract used by the Studio.
2208
+
2209
+ **Type (Core exports `AddSectionConfig`):**
2210
+ ```typescript
2211
+ interface AddSectionConfig {
2212
+ addableSectionTypes: readonly string[];
2213
+ sectionTypeLabels: Record<string, string>;
2214
+ getDefaultSectionData(sectionType: string): Record<string, unknown>;
2215
+ }
2216
+ ```
2217
+
2218
+ **Shape:** Tenant provides one object (e.g. `addSectionConfig`) with:
2219
+ * **`addableSectionTypes`** — Readonly array of section type keys. Only these types appear in the Add Section Library. Must be a subset of (or equal to) the keys in SectionDataRegistry.
2220
+ * **`sectionTypeLabels`** — Map type key → display string (e.g. `{ hero: 'Hero', 'cta-banner': 'CTA Banner' }`).
2221
+ * **`getDefaultSectionData(sectionType: string): Record<string, unknown>`** — Returns default `data` for a new section. Must conform to the capsule’s data schema so the new section validates.
2222
+
2223
+ Core creates a new section with deterministic UUID, `type`, and `data` from `getDefaultSectionData(type)`.
2224
+
2225
+ **Perché servono (ASC):** Lo Studio deve mostrare una libreria “Aggiungi sezione” con nomi leggibili e, alla scelta, creare una section con dati iniziali validi. addableSectionTypes, sectionTypeLabels e getDefaultSectionData sono il contratto: il Tenant è l’unica fonte di verità su quali tipi sono addabili e con quali default. Senza ASC, il Core non saprebbe cosa mostrare in modal né come popolare i dati della nuova section.
2226
+
2227
+ ---
2228
+
2229
+ ## 10. ⚙️ JsonPagesConfig & Engine Bootstrap (JEB) v1.1
2230
+
2231
+ **Objective:** Bootstrap contract between Tenant app and `@olonjs/core`.
2232
+
2233
+ ### 10.1 JsonPagesConfig (required fields)
2234
+ The Tenant passes a single **config** object to **JsonPagesEngine**. Required fields:
2235
+
2236
+ | Field | Type | Description |
2237
+ |-------|------|-------------|
2238
+ | **tenantId** | string | Passed to `resolveAssetUrl(path, tenantId)`; resolved asset URLs are **`/assets/...`** with no tenantId segment in the path. |
2239
+ | **registry** | `{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }` | Component registry. Must match MTRP keys. See Appendix A. |
2240
+ | **schemas** | `Record<SectionType, ZodType>` or equivalent | SECTION_SCHEMAS: type → **data** Zod schema. Form Factory uses this. See Appendix A. |
2241
+ | **pages** | `Record<string, PageConfig>` | Slug → page config. See Appendix A. |
2242
+ | **siteConfig** | SiteConfig | Global site (identity, header/footer blocks). See Appendix A. |
2243
+ | **themeConfig** | ThemeConfig | Theme tokens. See Appendix A. |
2244
+ | **menuConfig** | MenuConfig | Navigation tree (SSOT for header menu). See Appendix A. |
2245
+ | **themeCss** | `{ tenant: string }` | At least **tenant**: string (inline CSS or URL) for Stage iframe injection. |
2246
+ | **addSection** | AddSectionConfig | Add-section config (§9). |
2247
+
2248
+ Core may define optional fields. The Tenant must not omit required fields.
2249
+
2250
+ ### 10.2 JsonPagesEngine
2251
+ Root component: **`<JsonPagesEngine config={config} />`**. Responsibilities: route → page, SectionRenderer per section; in Studio mode Sovereign Shell (Inspector, Control Bar, postMessage); section wrappers and overlay per IDAC and JAP. Tenant does not implement the Shell.
2252
+
2253
+ ### 10.3 Studio Selection Event Contract (v1.3, breaking)
2254
+ In strict v1.3 Studio, section selection payload for nested targets is path-based:
2255
+
2256
+ ```typescript
2257
+ type SectionSelectMessage = {
2258
+ type: 'SECTION_SELECT';
2259
+ section: { id: string; type: string; scope: 'global' | 'local' };
2260
+ itemPath?: SelectionPath; // root -> leaf
2261
+ };
2262
+ ```
2263
+
2264
+ Removed from strict protocol:
2265
+ * `itemField`
2266
+ * `itemId`
2267
+
2268
+ **Perché servono (JEB):** Un unico punto di bootstrap (config + Engine) evita che il Tenant replichi logica di routing, Shell e overlay. I campi obbligatori in JsonPagesConfig (tenantId, registry, schemas, pages, siteConfig, themeConfig, menuConfig, themeCss, addSection) sono il minimo per far funzionare rendering, Studio e Form Factory; omissioni causano errori a runtime. In v1.3, il payload `itemPath` sincronizza in modo non ambiguo Stage e Inspector su nested arrays.
2269
+
2270
+ ---
2271
+
2272
+ # 🏛️ OlonJS_ADMIN_PROTOCOL (JAP) v1.2
2273
+
2274
+ **Status:** Mandatory Standard
2275
+ **Version:** 1.2.0 (Sovereign Shell Edition — Path/Nested Strictness)
2276
+ **Objective:** Deterministic orchestration of the "Studio" environment (ICE Level 1).
2277
+
2278
+ ---
2279
+
2280
+ ## 1. The Sovereign Shell Topology
2281
+ The Admin interface is a **Sovereign Shell** from `@olonjs/core`.
2282
+ 1. **The Stage (Canvas):** Isolated Iframe; postMessage for data updates and selection mirroring. Section markup follows **IDAC** (§6); overlay styling follows **TOCC** (§7).
2283
+ 2. **The Inspector (Sidebar):** Consumes Tenant Zod schemas to generate editors; binding via `data-jp-field` and `data-jp-item-*`.
2284
+ 3. **The Control Bar:** Save, Export, Add Section.
2285
+
2286
+ ## 2. State Orchestration & Persistence
2287
+ * **Working Draft:** Reactive local state for unsaved changes.
2288
+ * **Sync Law:** Inspector changes → Working Draft → Stage via `STUDIO_EVENTS.UPDATE_DRAFTS`.
2289
+ * **Bake Protocol:** "Bake HTML" requests snapshot from Iframe, injects `ProjectState` as JSON, triggers download.
2290
+
2291
+ ## 3. Context Switching (Global vs. Local)
2292
+ * **Header/Footer** selection → Global Mode, `site.json`.
2293
+ * Any other section → Page Mode, current `[slug].json`.
2294
+
2295
+ ## 4. Section Lifecycle Management
2296
+ 1. **Add Section:** Modal from Tenant `SECTION_SCHEMAS`; UUID + default data via **AddSectionConfig** (§9).
2297
+ 2. **Reorder:** Inspector or Stage Overlay; array mutation in Working Draft.
2298
+ 3. **Delete:** Confirmation; remove from array, clear selection.
2299
+
2300
+ ## 5. Stage Isolation & Overlay
2301
+ * **CSS Shielding:** Stage in Iframe; Tenant CSS does not leak into Admin.
2302
+ * **Sovereign Overlay:** Selection ring and type labels injected per **IDAC** (§6); Tenant styles them per **TOCC** (§7).
2303
+
2304
+ ## 6. "Green Build" Validation
2305
+ Studio enforces `tsc && vite build`. No export with TypeScript errors.
2306
+
2307
+ ## 7. Path-Deterministic Selection & Sidebar Expansion (v1.3, breaking)
2308
+ * Section/item focus synchronization uses `itemPath` (root → leaf), not flat `itemField/itemId`.
2309
+ * Sidebar expansion state for nested arrays must be derived from all path segments.
2310
+ * Flat-only matching may open/close wrong branches and is non-compliant in strict mode.
2311
+
2312
+ **Perché servono (JAP):** Stage in iframe + Inspector + Control Bar separano il contesto di editing dal sito; postMessage e Working Draft permettono modifiche senza toccare subito i file. Bake ed Export richiedono uno stato coerente. Global vs Page mode evita confusione su dove si sta editando (site.json vs [slug].json). Add/Reorder/Delete sono gestiti in un solo modo (Working Draft + ASC). Green Build garantisce che ciò che si esporta compili. In v1.3, il path completo elimina ambiguità nella sincronizzazione Stage↔Sidebar su strutture annidate.
2313
+
2314
+ ---
2315
+
2316
+ ## Compliance: Legacy vs Full UX (v1.3)
2317
+
2318
+ | Dimension | Legacy / Less UX | Full UX (Core-aligned) |
2319
+ |-----------|-------------------|-------------------------|
2320
+ | **ICE binding** | No `data-jp-*`; Inspector cannot bind. | IDAC (§6) on every editable section/field/item. |
2321
+ | **Section wrapper** | Plain `<section>`; no overlay contract. | Core wrapper + overlay; Tenant CSS per TOCC (§7). |
2322
+ | **Design tokens** | Raw BEM / fixed classes. | Local tokens (§4.4); `var(--local-*)` only. |
2323
+ | **Base schemas** | Ad hoc. | BSDS (§8): BaseSectionData, BaseArrayItem, BaseSectionSettings. |
2324
+ | **Add Section** | Ad hoc defaults. | ASC (§9): addableSectionTypes, labels, getDefaultSectionData. |
2325
+ | **Bootstrap** | Implicit. | JEB (§10): JsonPagesConfig + JsonPagesEngine. |
2326
+ | **Selection payload** | Flat `itemField/itemId`. | Path-only `itemPath: SelectionPath` (JEB §10.3). |
2327
+ | **Nested array expansion** | Single-segment or field-only heuristics. | Root-to-leaf path expansion (ECIP §5.5, JAP §7). |
2328
+ | **Array item identity (strict)** | Index fallback tolerated. | Stable `id` required for editable object arrays. |
2329
+
2330
+ **Rule:** Every page section (non-header/footer) that appears in the Stage and in `SECTION_SCHEMAS` must comply with §6, §7, §4.4, §8, §9, §10 for full Studio UX.
2331
+
2332
+ ---
2333
+
2334
+ ## Summary of v1.3 Additions
2335
+
2336
+ | § | Title | Purpose |
2337
+ |---|--------|--------|
2338
+ | 5.5 | Path-Only Nested Selection & Expansion | ECIP: root→leaf `SelectionPath`; remove flat matching in strict mode. |
2339
+ | 6.5 | Strict Path Extraction for Nested Arrays | IDAC: path-based nested targeting; no strict flat fallback. |
2340
+ | 10.3 | Studio Selection Event Contract | JEB: `SECTION_SELECT` uses `itemPath`; remove `itemField/itemId`. |
2341
+ | JAP §7 | Path-Deterministic Selection & Sidebar Expansion | Studio state synchronization for nested arrays. |
2342
+ | Compliance | Legacy vs Full UX (v1.3) | Explicit breaking delta for flat protocol removal and strict IDs. |
2343
+ | **Appendix A.6** | **v1.3 Path/Nested Strictness Addendum** | Type/export and migration checklist for path-only protocol. |
2344
+
2345
+ ---
2346
+
2347
+ # Appendix A — Tenant Type & Code-Generation Annex
2348
+
2349
+ **Objective:** Make the specification **sufficient** to generate or audit a full tenant (new site, new components, new data) without a reference codebase. Defines TypeScript types, JSON shapes, schema contract, file paths, and integration pattern.
2350
+
2351
+ **Status:** Mandatory for code-generation and governance. Compliance ensures generated tenants are typed and wired like the reference implementation.
2352
+
2353
+ ---
2354
+
2355
+ ## A.1 Core-Provided Types (from `@olonjs/core`)
2356
+
2357
+ The following are assumed to be exported by Core. The Tenant augments **SectionDataRegistry** and **SectionSettingsRegistry**; all other types are consumed as-is.
2358
+
2359
+ | Type | Description |
2360
+ |------|-------------|
2361
+ | **SectionType** | `keyof SectionDataRegistry` (after Tenant augmentation). Union of all section type keys. |
2362
+ | **Section** | Union of `BaseSection<K>` for all K in SectionDataRegistry. See MTRP §1.2. |
2363
+ | **BaseSectionSettings** | Optional base type for section settings (may align with BSDS §8.3). |
2364
+ | **MenuItem** | Navigation item. **Minimum shape:** `{ label: string; href: string }`. Core may extend (e.g. `children?: MenuItem[]`). |
2365
+ | **AddSectionConfig** | See §9. |
2366
+ | **JsonPagesConfig** | See §10.1. |
2367
+
2368
+ **Perché servono (A.1):** Il Tenant deve conoscere i tipi esportati dal Core (SectionType, MenuItem, AddSectionConfig, JsonPagesConfig) per tipizzare registry, config e augmentation senza dipendere da implementazioni interne.
2369
+
2370
+ ---
2371
+
2372
+ ## A.2 Tenant-Provided Types (single source: `src/types.ts` or equivalent)
2373
+
2374
+ The Tenant **must** define the following in one module (e.g. **`src/types.ts`**). This module **must** perform the **module augmentation** of `@olonjs/core` for **SectionDataRegistry** and **SectionSettingsRegistry**, and **must** export **SectionComponentPropsMap** and re-export from `@olonjs/core` so that **SectionType** is available after augmentation.
2375
+
2376
+ ### A.2.1 SectionComponentPropsMap
2377
+
2378
+ Maps each section type to the props of its React component. **Header** is the only type that receives **menu**.
2379
+
2380
+ **Option A — Explicit (recommended for clarity and tooling):** For each section type K, add one entry. Header receives **menu**.
2381
+
2382
+ ```typescript
2383
+ import type { MenuItem } from '@olonjs/core';
2384
+ // Import Data/Settings from each capsule.
2385
+
2386
+ export type SectionComponentPropsMap = {
2387
+ 'header': { data: HeaderData; settings?: HeaderSettings; menu: MenuItem[] };
2388
+ 'footer': { data: FooterData; settings?: FooterSettings };
2389
+ 'hero': { data: HeroData; settings?: HeroSettings };
2390
+ // ... one entry per SectionType, e.g. 'feature-grid', 'cta-banner', etc.
2391
+ };
2392
+ ```
2393
+
2394
+ **Option B — Mapped type (DRY, requires SectionDataRegistry/SectionSettingsRegistry in scope):**
2395
+
2396
+ ```typescript
2397
+ import type { MenuItem } from '@olonjs/core';
2398
+
2399
+ export type SectionComponentPropsMap = {
2400
+ [K in SectionType]: K extends 'header'
2401
+ ? { data: SectionDataRegistry[K]; settings?: SectionSettingsRegistry[K]; menu: MenuItem[] }
2402
+ : { data: SectionDataRegistry[K]; settings?: K extends keyof SectionSettingsRegistry ? SectionSettingsRegistry[K] : BaseSectionSettings };
2403
+ };
2404
+ ```
2405
+
2406
+ SectionType is imported from Core (after Tenant augmentation). In practice Option A is the reference pattern; Option B is valid if the Tenant prefers a single derived definition.
2407
+
2408
+ **Perché servono (A.2):** SectionComponentPropsMap e i tipi di config (PageConfig, SiteConfig, MenuConfig, ThemeConfig) definiscono il contratto tra dati (JSON, API) e componente; l’augmentation è l’unico modo per estendere i registry del Core senza fork. Senza questi tipi, generazione tenant e refactor sarebbero senza guida e il type-check fallirebbe.
2409
+
2410
+ ### A.2.2 ComponentRegistry type
2411
+
2412
+ The registry object **must** be typed as:
2413
+
2414
+ ```typescript
2415
+ import type { SectionType } from '@olonjs/core';
2416
+ import type { SectionComponentPropsMap } from '@/types';
2417
+
2418
+ export const ComponentRegistry: {
2419
+ [K in SectionType]: React.FC<SectionComponentPropsMap[K]>;
2420
+ } = { /* ... */ };
2421
+ ```
2422
+
2423
+ File: **`src/lib/ComponentRegistry.tsx`** (or equivalent). Imports one View per section type and assigns it to the corresponding key.
2424
+
2425
+ ### A.2.3 PageConfig
2426
+
2427
+ Minimum shape for a single page (used in **pages** and in each **`[slug].json`**):
2428
+
2429
+ ```typescript
2430
+ export interface PageConfig {
2431
+ id?: string;
2432
+ slug: string;
2433
+ meta?: {
2434
+ title?: string;
2435
+ description?: string;
2436
+ };
2437
+ sections: Section[];
2438
+ }
2439
+ ```
2440
+
2441
+ **Section** is the union type from MTRP (§1.2). Each element of **sections** has **id**, **type**, **data**, **settings** and conforms to the capsule schemas.
2442
+
2443
+ ### A.2.4 SiteConfig
2444
+
2445
+ Minimum shape for **site.json** (and for **siteConfig** in JsonPagesConfig):
2446
+
2447
+ ```typescript
2448
+ export interface SiteConfigIdentity {
2449
+ title?: string;
2450
+ logoUrl?: string;
2451
+ }
2452
+
2453
+ export interface SiteConfig {
2454
+ identity?: SiteConfigIdentity;
2455
+ pages?: Array<{ slug: string; label: string }>;
2456
+ header: {
2457
+ id: string;
2458
+ type: 'header';
2459
+ data: HeaderData;
2460
+ settings?: HeaderSettings;
2461
+ };
2462
+ footer: {
2463
+ id: string;
2464
+ type: 'footer';
2465
+ data: FooterData;
2466
+ settings?: FooterSettings;
2467
+ };
2468
+ }
2469
+ ```
2470
+
2471
+ **HeaderData**, **FooterData**, **HeaderSettings**, **FooterSettings** are the types exported from the header and footer capsules.
2472
+
2473
+ ### A.2.5 MenuConfig
2474
+
2475
+ Minimum shape for **menu.json** (and for **menuConfig** in JsonPagesConfig). Structure is tenant-defined; Core expects the header to receive **MenuItem[]**. Common pattern: an object with a key (e.g. **main**) whose value is **MenuItem[]**.
2476
+
2477
+ ```typescript
2478
+ export interface MenuConfig {
2479
+ main?: MenuItem[];
2480
+ [key: string]: MenuItem[] | undefined;
2481
+ }
2482
+ ```
2483
+
2484
+ Or simply **`MenuItem[]`** if the app uses a single flat list. The Tenant must ensure that the value passed to the header component as **menu** conforms to **MenuItem[]** (e.g. `menuConfig.main` or `menuConfig` if it is the array).
2485
+
2486
+ ### A.2.6 ThemeConfig
2487
+
2488
+ Minimum shape for **theme.json** (and for **themeConfig** in JsonPagesConfig). Tenant-defined; typically tokens for colors, typography, radius.
2489
+
2490
+ ```typescript
2491
+ export interface ThemeConfig {
2492
+ name?: string;
2493
+ tokens?: {
2494
+ colors?: Record<string, string>;
2495
+ typography?: Record<string, string | Record<string, string>>;
2496
+ borderRadius?: Record<string, string>;
2497
+ };
2498
+ [key: string]: unknown;
2499
+ }
2500
+ ```
2501
+
2502
+ ---
2503
+
2504
+ ## A.3 Schema Contract (SECTION_SCHEMAS)
2505
+
2506
+ **Location:** **`src/lib/schemas.ts`** (or equivalent).
2507
+
2508
+ **Contract:**
2509
+ * **SECTION_SCHEMAS** is a **single object** whose keys are **SectionType** and whose values are **Zod schemas for the section data** (not settings, unless the Form Factory contract expects a combined or per-type settings schema; then each value may be the data schema only, and settings may be defined per capsule and aggregated elsewhere if needed).
2510
+ * The Tenant **must** re-export **BaseSectionData**, **BaseArrayItem**, and optionally **BaseSectionSettingsSchema** from **`src/lib/base-schemas.ts`** (or equivalent). Each capsule’s data schema **must** extend BaseSectionData; each array item schema **must** extend or include BaseArrayItem.
2511
+ * **SECTION_SCHEMAS** is typed as **`Record<SectionType, ZodType>`** or **`{ [K in SectionType]: ZodType }`** so that keys match the registry and SectionDataRegistry.
2512
+
2513
+ **Export:** The app imports **SECTION_SCHEMAS** and passes it as **config.schemas** to JsonPagesEngine. The Form Factory traverses these schemas to build editors.
2514
+
2515
+ **Perché servono (A.3):** Un unico oggetto SECTION_SCHEMAS con chiavi = SectionType e valori = schema data permette al Form Factory di costruire form per tipo senza convenzioni ad hoc; i base schema garantiscono anchorId e id su item. Senza questo contratto, l’Inspector non saprebbe quali campi mostrare né come validare.
2516
+
2517
+ ---
2518
+
2519
+ ## A.4 File Paths & Data Layout
2520
+
2521
+ | Purpose | Path (conventional) | Description |
2522
+ |---------|---------------------|-------------|
2523
+ | Site config | **`src/data/config/site.json`** | SiteConfig (identity, header, footer, pages list). |
2524
+ | Menu config | **`src/data/config/menu.json`** | MenuConfig (e.g. main nav). |
2525
+ | Theme config | **`src/data/config/theme.json`** | ThemeConfig (tokens). |
2526
+ | Page data | **`src/data/pages/<slug>.json`** | One file per page; content is PageConfig (slug, meta, sections). |
2527
+ | Base schemas | **`src/lib/base-schemas.ts`** | BaseSectionData, BaseArrayItem, BaseSectionSettingsSchema. |
2528
+ | Schema aggregate | **`src/lib/schemas.ts`** | SECTION_SCHEMAS; re-exports base schemas. |
2529
+ | Registry | **`src/lib/ComponentRegistry.tsx`** | ComponentRegistry object. |
2530
+ | Add-section config | **`src/lib/addSectionConfig.ts`** | addSectionConfig (AddSectionConfig). |
2531
+ | Tenant types & augmentation | **`src/types.ts`** | SectionComponentPropsMap, PageConfig, SiteConfig, MenuConfig, ThemeConfig; **declare module '@olonjs/core'** for SectionDataRegistry and SectionSettingsRegistry; re-export from Core. |
2532
+ | Bootstrap | **`src/App.tsx`** | Imports config (site, theme, menu, pages), registry, schemas, addSection, themeCss; builds JsonPagesConfig; renders **<JsonPagesEngine config={config} />**. |
2533
+
2534
+ The app entry (e.g. **main.tsx**) renders **App**. No other bootstrap contract is specified; the Tenant may use Vite aliases (e.g. **@/**) for the paths above.
2535
+
2536
+ **Perché servono (A.4):** Path fissi (data/config, data/pages, lib/schemas, types.ts, App.tsx) permettono a CLI, tooling e agenti di trovare sempre gli stessi file; l’onboarding e la generazione da spec sono deterministici. Senza convenzione, ogni tenant sarebbe una struttura diversa.
2537
+
2538
+ ---
2539
+
2540
+ ## A.5 Integration Checklist (Code-Generation)
2541
+
2542
+ When generating or auditing a tenant, ensure the following in order:
2543
+
2544
+ 1. **Capsules** — For each section type, create **`src/components/<type>/`** with View.tsx, schema.ts, types.ts, index.ts. Data schema extends BaseSectionData; array items extend BaseArrayItem; View complies with CIP and IDAC (§6.2–6.3 for non-reserved types).
2545
+ 2. **Base schemas** — **src/lib/base-schemas.ts** exports BaseSectionData, BaseArrayItem, BaseSectionSettingsSchema (and optional CtaSchema or similar shared fragments).
2546
+ 3. **types.ts** — Define SectionComponentPropsMap (header with **menu**), PageConfig, SiteConfig, MenuConfig, ThemeConfig; **declare module '@olonjs/core'** and augment SectionDataRegistry and SectionSettingsRegistry; re-export from `@olonjs/core`.
2547
+ 4. **ComponentRegistry** — Import every View; build object **{ [K in SectionType]: ViewComponent }**; type as **{ [K in SectionType]: React.FC<SectionComponentPropsMap[K]> }**.
2548
+ 5. **schemas.ts** — Import base schemas and each capsule’s data schema; export SECTION_SCHEMAS as **{ [K in SectionType]: SchemaK }**; export SectionType as **keyof typeof SECTION_SCHEMAS** if not using Core’s SectionType.
2549
+ 6. **addSectionConfig** — addableSectionTypes, sectionTypeLabels, getDefaultSectionData; export as AddSectionConfig.
2550
+ 7. **App.tsx** — Import site, theme, menu, pages from data paths; build config (tenantId, registry, schemas, pages, siteConfig, themeConfig, menuConfig, themeCss: { tenant }, addSection); render JsonPagesEngine.
2551
+ 8. **Data files** — Create or update site.json, menu.json, theme.json, and one or more **<slug>.json** under the paths in A.4. Ensure JSON shapes match SiteConfig, MenuConfig, ThemeConfig, PageConfig.
2552
+ 9. **Tenant CSS** — Include TOCC (§7) selectors in global CSS so the Stage overlay is visible.
2553
+ 10. **Reserved types** — Header and footer capsules receive props per SectionComponentPropsMap; menu is populated from menuConfig (e.g. menuConfig.main) when building the config or inside Core when rendering the header.
2554
+
2555
+ **Perché servono (A.5):** La checklist in ordine evita di dimenticare passi (es. augmentation prima del registry, TOCC dopo le View) e rende la spec sufficiente per generare o verificare un tenant senza codebase di riferimento.
2556
+
2557
+ ---
2558
+
2559
+ ## A.6 v1.3 Path/Nested Strictness Addendum (breaking)
2560
+
2561
+ This addendum extends Appendix A without removing prior v1.2 obligations:
2562
+
2563
+ 1. **Type exports** — Core and/or shared types module should expose `SelectionPathSegment` and `SelectionPath` for Studio messaging and Inspector expansion logic.
2564
+ 2. **Protocol migration** — Replace flat payload fields `itemField` / `itemId` with `itemPath?: SelectionPath` in strict v1.3 channels.
2565
+ 3. **Nested array compliance** — For editable object arrays, item identity must be stable (`id`) and propagated to DOM attributes (`data-jp-item-id`), schema items (BaseArrayItem), and selection path segments (`itemId` when segment targets array item).
2566
+ 4. **Backward compatibility policy** — Legacy flat fields may exist only in transitional adapters outside strict mode; normative v1.3 contract is path-only.
2567
+
2568
+ ---
2569
+
2570
+ **Validation:** Align with current `@olonjs/core` exports (SectionType, MenuItem, AddSectionConfig, JsonPagesConfig, and in v1.3 path types for Studio selection).
2571
+ **Distribution:** Core via `.yalc`; tenant projections via `@olonjs/cli`. This annex makes the spec **necessary and sufficient** for tenant code-generation and governance at enterprise grade.
2572
+
919
2573
  END_OF_FILE_CONTENT
920
2574
  mkdir -p "src"
921
2575
  echo "Creating src/App.tsx..."
@@ -6089,19 +7743,19 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/menu.json"
6089
7743
  {
6090
7744
  "main": [
6091
7745
  {
6092
- "label": "Architecture",
6093
- "href": "#architecture"
7746
+ "label": "The Problem",
7747
+ "href": "#problem"
6094
7748
  },
6095
7749
  {
6096
- "label": "CMS",
6097
- "href": "#cms"
7750
+ "label": "Architecture",
7751
+ "href": "#architecture"
6098
7752
  },
6099
7753
  {
6100
- "label": "Versioning",
6101
- "href": "#git"
7754
+ "label": "Why",
7755
+ "href": "#why"
6102
7756
  },
6103
7757
  {
6104
- "label": "Developer",
7758
+ "label": "DX",
6105
7759
  "href": "#devex"
6106
7760
  }
6107
7761
  ]
@@ -6142,19 +7796,19 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/config/site.json"
6142
7796
  "badge": "v1.4.0",
6143
7797
  "links": [
6144
7798
  {
6145
- "label": "Architecture",
6146
- "href": "#architecture"
7799
+ "label": "The Problem",
7800
+ "href": "#problem"
6147
7801
  },
6148
7802
  {
6149
- "label": "CMS",
6150
- "href": "#cms"
7803
+ "label": "Architecture",
7804
+ "href": "#architecture"
6151
7805
  },
6152
7806
  {
6153
- "label": "Versioning",
6154
- "href": "#git"
7807
+ "label": "Why",
7808
+ "href": "#why"
6155
7809
  },
6156
7810
  {
6157
- "label": "Developer",
7811
+ "label": "DX",
6158
7812
  "href": "#devex"
6159
7813
  }
6160
7814
  ]
@@ -6263,8 +7917,18 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
6263
7917
  "titleHighlight": "Agentic Web",
6264
7918
  "description": "AI agents are becoming operational actors in commerce, marketing, and support. OlonJS introduces a deterministic machine contract for websites — so agents can reliably read and operate any site, without custom glue.",
6265
7919
  "ctas": [
6266
- { "id": "cta-1", "label": "Read the Spec", "href": "/docs", "variant": "primary" },
6267
- { "id": "cta-2", "label": "View on GitHub", "href": "https://github.com/olonjs/npm-jpcore", "variant": "secondary" }
7920
+ {
7921
+ "id": "cta-1",
7922
+ "label": "Read the Spec",
7923
+ "href": "/docs",
7924
+ "variant": "primary"
7925
+ },
7926
+ {
7927
+ "id": "cta-2",
7928
+ "label": "View on GitHub",
7929
+ "href": "https://github.com/olonjs/npm-jpcore",
7930
+ "variant": "secondary"
7931
+ }
6268
7932
  ],
6269
7933
  "metrics": []
6270
7934
  },
@@ -6279,16 +7943,35 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
6279
7943
  "problemTag": "The problem",
6280
7944
  "problemTitle": "Websites aren't built for agents",
6281
7945
  "problemItems": [
6282
- { "id": "pi-1", "text": "Agentic workflows are growing, but integration is mostly custom glue — rebuilt tenant by tenant" },
6283
- { "id": "pi-2", "text": "Every site has a different content structure, routing assumptions, and edge cases" },
6284
- { "id": "pi-3", "text": "HTML-heavy, CMS-fragmented, inconsistent across propertiesslow, brittle, expensive" }
7946
+ {
7947
+ "id": "pi-1",
7948
+ "text": "Agentic workflows are growing, but integration is mostly custom glue rebuilt tenant by tenant"
7949
+ },
7950
+ {
7951
+ "id": "pi-2",
7952
+ "text": "Every site has a different content structure, routing assumptions, and edge cases"
7953
+ },
7954
+ {
7955
+ "id": "pi-3",
7956
+ "text": "HTML-heavy, CMS-fragmented, inconsistent across properties — slow, brittle, expensive"
7957
+ }
6285
7958
  ],
6286
7959
  "solutionTag": "Our solution",
6287
7960
  "solutionTitle": "A standard machine contract across tenants",
6288
7961
  "solutionItems": [
6289
- { "id": "si-1", "text": "Predictable page endpoints for agents —", "code": "/{slug}.json" },
6290
- { "id": "si-2", "text": "Typed, schema-driven content contracts — validated, versioned, auditable" },
6291
- { "id": "si-3", "text": "Repeatable governance and deployment patterns across every tenant" }
7962
+ {
7963
+ "id": "si-1",
7964
+ "text": "Predictable page endpoints for agents ",
7965
+ "code": "/{slug}.json"
7966
+ },
7967
+ {
7968
+ "id": "si-2",
7969
+ "text": "Typed, schema-driven content contracts — validated, versioned, auditable"
7970
+ },
7971
+ {
7972
+ "id": "si-3",
7973
+ "text": "Repeatable governance and deployment patterns across every tenant"
7974
+ }
6292
7975
  ]
6293
7976
  },
6294
7977
  "settings": {}
@@ -6302,15 +7985,47 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
6302
7985
  "sectionTitle": "Built for enterprise scale",
6303
7986
  "sectionLead": "Every layer is designed for determinism — from file system layout to component contracts to Studio UX.",
6304
7987
  "cards": [
6305
- { "id": "fc-1", "emoji": "📐", "title": "Modular Type Registry", "description": "Core defines empty registries; tenants inject types via module augmentation. Full TypeScript safety, zero Core changes." },
6306
- { "id": "fc-2", "emoji": "🧱", "title": "Tenant Block Protocol", "description": "Self-contained capsules (View + schema + types) enable automated ingestion and consistent editor generation." },
6307
- { "id": "fc-3", "emoji": "⚙️", "title": "Deterministic CLI", "description": "@olonjs/cli projects new tenants from a canonical script — reproducible across every environment." },
6308
- { "id": "fc-4", "emoji": "🎯", "title": "ICE Data Contract", "description": "Mandatory DOM attributes bind the Studio canvas to Inspector fields without coupling to tenant DOM structure." },
6309
- { "id": "fc-5", "emoji": "📦", "title": "Base Schema Fragments", "description": "Shared BaseSectionData and BaseArrayItem enforce anchor IDs and stable React keys across all capsules." },
6310
- { "id": "fc-6", "emoji": "🔗", "title": "Path-Based Selection", "description": "v1.4 strict path semantics eliminate nested array ambiguity. Studio selection is root-to-leaf, always deterministic." }
7988
+ {
7989
+ "id": "fc-1",
7990
+ "emoji": "📐",
7991
+ "title": "Modular Type Registry",
7992
+ "description": "Core defines empty registries; tenants inject types via module augmentation. Full TypeScript safety, zero Core changes."
7993
+ },
7994
+ {
7995
+ "id": "fc-2",
7996
+ "emoji": "🧱",
7997
+ "title": "Tenant Block Protocol",
7998
+ "description": "Self-contained capsules (View + schema + types) enable automated ingestion and consistent editor generation."
7999
+ },
8000
+ {
8001
+ "id": "fc-3",
8002
+ "emoji": "⚙️",
8003
+ "title": "Deterministic CLI",
8004
+ "description": "@olonjs/cli projects new tenants from a canonical script — reproducible across every environment."
8005
+ },
8006
+ {
8007
+ "id": "fc-4",
8008
+ "emoji": "🎯",
8009
+ "title": "ICE Data Contract",
8010
+ "description": "Mandatory DOM attributes bind the Studio canvas to Inspector fields without coupling to tenant DOM structure."
8011
+ },
8012
+ {
8013
+ "id": "fc-5",
8014
+ "emoji": "📦",
8015
+ "title": "Base Schema Fragments",
8016
+ "description": "Shared BaseSectionData and BaseArrayItem enforce anchor IDs and stable React keys across all capsules."
8017
+ },
8018
+ {
8019
+ "id": "fc-6",
8020
+ "emoji": "🔗",
8021
+ "title": "Path-Based Selection",
8022
+ "description": "v1.4 strict path semantics eliminate nested array ambiguity. Studio selection is root-to-leaf, always deterministic."
8023
+ }
6311
8024
  ]
6312
8025
  },
6313
- "settings": { "columns": 3 }
8026
+ "settings": {
8027
+ "columns": 3
8028
+ }
6314
8029
  },
6315
8030
  {
6316
8031
  "id": "why-now",
@@ -6321,10 +8036,26 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
6321
8036
  "title": "Why this matters",
6322
8037
  "titleAccent": "now",
6323
8038
  "cards": [
6324
- { "id": "wc-1", "title": "Agentic commerce is live", "description": "Operational standards are missing. Without a contract layer, teams face high integration cost and low reliability." },
6325
- { "id": "wc-2", "title": "Enterprises need governance", "description": "A contract layer you can audit, version, and scale — not a one-off adapter for every new agent workflow." },
6326
- { "id": "wc-3", "title": "AI tooling is ready", "description": "Deterministic structure means AI can scaffold, validate, and evolve tenants with less prompt ambiguity." },
6327
- { "id": "wc-4", "title": "Speed compounds", "description": "Teams that standardize now ship new experiences in hours while others rebuild integration logic repeatedly." }
8039
+ {
8040
+ "id": "wc-1",
8041
+ "title": "Agentic commerce is live",
8042
+ "description": "Operational standards are missing. Without a contract layer, teams face high integration cost and low reliability."
8043
+ },
8044
+ {
8045
+ "id": "wc-2",
8046
+ "title": "Enterprises need governance",
8047
+ "description": "A contract layer you can audit, version, and scale — not a one-off adapter for every new agent workflow."
8048
+ },
8049
+ {
8050
+ "id": "wc-3",
8051
+ "title": "AI tooling is ready",
8052
+ "description": "Deterministic structure means AI can scaffold, validate, and evolve tenants with less prompt ambiguity."
8053
+ },
8054
+ {
8055
+ "id": "wc-4",
8056
+ "title": "Speed compounds",
8057
+ "description": "Teams that standardize now ship new experiences in hours while others rebuild integration logic repeatedly."
8058
+ }
6328
8059
  ]
6329
8060
  },
6330
8061
  "settings": {}
@@ -6333,19 +8064,40 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
6333
8064
  "id": "dx-section",
6334
8065
  "type": "devex",
6335
8066
  "data": {
6336
- "anchorId": "developer-velocity",
8067
+ "anchorId": "devex",
6337
8068
  "label": "Developer Velocity",
6338
8069
  "title": "AI-native advantage,\nfrom day one",
6339
8070
  "description": "OlonJS dramatically increases AI-assisted development speed. Because structure is deterministic, agents scaffold and evolve tenants faster — with lower regression risk.",
6340
8071
  "features": [
6341
- { "id": "df-1", "text": "AI scaffolds and evolves tenants faster because structure is deterministic" },
6342
- { "id": "df-2", "text": "Shared conventions reduce prompt ambiguity and implementation drift" },
6343
- { "id": "df-3", "text": "Ship new tenant experiences in hours, not weeks" }
8072
+ {
8073
+ "id": "df-1",
8074
+ "text": "AI scaffolds and evolves tenants faster because structure is deterministic"
8075
+ },
8076
+ {
8077
+ "id": "df-2",
8078
+ "text": "Shared conventions reduce prompt ambiguity and implementation drift"
8079
+ },
8080
+ {
8081
+ "id": "df-3",
8082
+ "text": "Ship new tenant experiences in hours, not weeks"
8083
+ }
6344
8084
  ],
6345
8085
  "stats": [
6346
- { "id": "ds-1", "value": "10×", "label": "Faster scaffolding" },
6347
- { "id": "ds-2", "value": "∅", "label": "Glue per tenant" },
6348
- { "id": "ds-3", "value": "100%", "label": "Type-safe contracts" }
8086
+ {
8087
+ "id": "ds-1",
8088
+ "value": "10×",
8089
+ "label": "Faster scaffolding"
8090
+ },
8091
+ {
8092
+ "id": "ds-2",
8093
+ "value": "∅",
8094
+ "label": "Glue per tenant"
8095
+ },
8096
+ {
8097
+ "id": "ds-3",
8098
+ "value": "100%",
8099
+ "label": "Type-safe contracts"
8100
+ }
6349
8101
  ]
6350
8102
  },
6351
8103
  "settings": {}
@@ -6359,15 +8111,24 @@ cat << 'END_OF_FILE_CONTENT' > "src/data/pages/home.json"
6359
8111
  "description": "Read the full specification or explore the source on GitHub. Zero dependencies to start — one JSON endpoint per page.",
6360
8112
  "cliCommand": "npx @olonjs/cli@latest new tenant",
6361
8113
  "ctas": [
6362
- { "id": "cta-docs", "label": "Read the Specification", "href": "/docs", "variant": "primary" },
6363
- { "id": "cta-gh", "label": "View on GitHub", "href": "https://github.com/olonjs/npm-jpcore", "variant": "secondary" }
8114
+ {
8115
+ "id": "cta-docs",
8116
+ "label": "Read the Specification",
8117
+ "href": "/docs",
8118
+ "variant": "primary"
8119
+ },
8120
+ {
8121
+ "id": "cta-gh",
8122
+ "label": "View on GitHub",
8123
+ "href": "https://github.com/olonjs/npm-jpcore",
8124
+ "variant": "secondary"
8125
+ }
6364
8126
  ]
6365
8127
  },
6366
8128
  "settings": {}
6367
8129
  }
6368
8130
  ]
6369
8131
  }
6370
-
6371
8132
  END_OF_FILE_CONTENT
6372
8133
  echo "Creating src/data/pages/post.json..."
6373
8134
  cat << 'END_OF_FILE_CONTENT' > "src/data/pages/post.json"