@jay-framework/jay-stack-cli 0.19.6 → 0.19.7

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.
@@ -0,0 +1,75 @@
1
+ # Linked and Composed Contracts
2
+
3
+ Contracts can reference other contract files using `link:` syntax. This lets you build reusable pieces and compose them into larger contracts.
4
+
5
+ ## When to Extract a Sub-Contract
6
+
7
+ Extract a sub-contract into its own file when:
8
+
9
+ - The same data shape is used by multiple contracts (e.g., a product card used in search results and related products)
10
+ - The sub-contract is complex enough to warrant its own file for readability
11
+ - You want to share the structure between static and dynamic contracts
12
+
13
+ Keep a sub-contract inline when:
14
+
15
+ - It's only used in one place
16
+ - It's small (< 10 tags)
17
+ - Extracting it would make the parent harder to read
18
+
19
+ ## Link Syntax
20
+
21
+ Reference another contract file with a relative path:
22
+
23
+ ```yaml
24
+ - tag: mediaGallery
25
+ type: sub-contract
26
+ link: ./media-gallery # resolves to media-gallery.jay-contract in same directory
27
+ ```
28
+
29
+ For cross-package references (e.g., dynamic contracts linking to static ones):
30
+
31
+ ```yaml
32
+ - tag: gallery
33
+ type: sub-contract
34
+ link: '@my-org/my-plugin/media-gallery' # package path
35
+ ```
36
+
37
+ ## Composition Pattern
38
+
39
+ Build contracts from small pieces up to complex pages:
40
+
41
+ ```
42
+ media.jay-contract (trivial: url + mediaType)
43
+ ^
44
+ media-gallery.jay-contract (links to media, adds thumbnail navigation)
45
+ ^
46
+ product-page.jay-contract (links to media-gallery, adds options, pricing, etc.)
47
+ ```
48
+
49
+ ```
50
+ product-options.jay-contract (reusable option/choice structure)
51
+ ^
52
+ product-card.jay-contract (links to product-options for quick-add)
53
+ ^
54
+ product-search.jay-contract (links to product-card for search results)
55
+ ```
56
+
57
+ Each level adds its own tags around the linked sub-contracts. The linked contracts stay focused on their single responsibility.
58
+
59
+ ## Linked Repeated Sub-Contracts
60
+
61
+ A linked sub-contract can also be repeated:
62
+
63
+ ```yaml
64
+ - tag: searchResults
65
+ type: sub-contract
66
+ repeated: true
67
+ trackBy: _id
68
+ link: ./product-card
69
+ ```
70
+
71
+ The linked contract must have a tag matching the `trackBy` field.
72
+
73
+ ## See Also
74
+
75
+ - [composing-contracts example](examples/composing-contracts.md) — Real-world composition hierarchy from wix-stores
@@ -0,0 +1,73 @@
1
+ # Page Contracts
2
+
3
+ A page contract (`page.jay-contract`) defines page-level data for a route, alongside any headless plugin contracts the page imports.
4
+
5
+ ## When to Use
6
+
7
+ - The page has its own data that isn't provided by a plugin
8
+ - The page component (`page.ts`) renders data into ViewState
9
+ - You want type-safe bindings between the page component and its jay-html template
10
+
11
+ If the page only uses plugin headless components and has no page-level data, a page contract is optional.
12
+
13
+ ## File Placement
14
+
15
+ ```
16
+ src/pages/
17
+ page.jay-html
18
+ page.jay-contract
19
+ page.ts
20
+ ```
21
+
22
+ For dynamic routes:
23
+
24
+ ```
25
+ src/pages/products/[slug]/
26
+ page.jay-html
27
+ page.jay-contract
28
+ page.ts
29
+ ```
30
+
31
+ ## Params for Dynamic Routes
32
+
33
+ Declare `params` matching the route's dynamic segments:
34
+
35
+ ```yaml
36
+ name: product-page
37
+ params:
38
+ slug: string # required — from [slug]
39
+ prefix: string? # optional — from [[prefix]]
40
+ category: string? # optional
41
+ tags:
42
+ - tag: title
43
+ type: data
44
+ dataType: string
45
+ phase: slow
46
+ - tag: price
47
+ type: data
48
+ dataType: number
49
+ phase: fast+interactive
50
+ ```
51
+
52
+ ## Combining with Plugin Contracts
53
+
54
+ A page can have both a page contract and headless plugin contracts. The page contract covers page-owned data; plugins cover their own domains:
55
+
56
+ ```html
57
+ <html>
58
+ <head>
59
+ <script type="application/jay-data" contract="./page.jay-contract"></script>
60
+ <script
61
+ type="application/jay-headless"
62
+ plugin="wix-stores"
63
+ contract="product-page"
64
+ key="product"
65
+ ></script>
66
+ </head>
67
+ <body>
68
+ <h1>{heroTitle}</h1>
69
+ <div>{product.name}</div>
70
+ <div>{product.price}</div>
71
+ </body>
72
+ </html>
73
+ ```
@@ -0,0 +1,190 @@
1
+ # Contract Syntax Reference
2
+
3
+ ## Basic Structure
4
+
5
+ ```yaml
6
+ name: ProductCard
7
+ description: What this contract does and when to use it.
8
+ props:
9
+ - name: productId
10
+ type: string
11
+ required: true
12
+ description: The product to display
13
+ params:
14
+ slug: string
15
+ tags:
16
+ - tag: name
17
+ type: data
18
+ dataType: string
19
+ phase: slow
20
+ ```
21
+
22
+ ## Tag Types
23
+
24
+ ### `data` — Read-only values
25
+
26
+ ```yaml
27
+ - tag: productName
28
+ type: data
29
+ dataType: string
30
+ required: true
31
+ phase: slow
32
+ description: Display name
33
+ ```
34
+
35
+ Data types: `string` (default), `html-string`, `number`, `boolean`, `date`.
36
+
37
+ ### `variant` — Conditionals (enum or boolean)
38
+
39
+ ```yaml
40
+ - tag: status
41
+ type: variant
42
+ dataType: enum (AVAILABLE | OUT_OF_STOCK | PREORDER)
43
+ phase: fast+interactive
44
+ ```
45
+
46
+ Use in jay-html: `if="status===AVAILABLE"` or `if="isActive"` for booleans.
47
+
48
+ ### `interactive` — Element refs for user interaction
49
+
50
+ ```yaml
51
+ - tag: addToCart
52
+ type: interactive
53
+ elementType: HTMLButtonElement
54
+ ```
55
+
56
+ Element types: `HTMLButtonElement`, `HTMLAnchorElement`, `HTMLInputElement`, `HTMLSelectElement`, `HTMLElement`, etc.
57
+
58
+ Interactive tags are always `fast+interactive` — do not specify a phase.
59
+
60
+ ### Dual-type tags — Both data and interactive
61
+
62
+ ```yaml
63
+ - tag: quantityInput
64
+ type: [data, interactive]
65
+ dataType: number
66
+ elementType: HTMLInputElement
67
+ ```
68
+
69
+ Use when an element both displays a value and accepts user input.
70
+
71
+ ### `sub-contract` — Nested objects
72
+
73
+ Inline:
74
+
75
+ ```yaml
76
+ - tag: pricing
77
+ type: sub-contract
78
+ tags:
79
+ - tag: amount
80
+ type: data
81
+ dataType: number
82
+ - tag: currency
83
+ type: data
84
+ dataType: string
85
+ ```
86
+
87
+ Linked (reference another contract file):
88
+
89
+ ```yaml
90
+ - tag: author
91
+ type: sub-contract
92
+ link: ./author # relative path, resolves to author.jay-contract
93
+ ```
94
+
95
+ ### `sub-contract` with `repeated: true` — Arrays
96
+
97
+ ```yaml
98
+ - tag: items
99
+ type: sub-contract
100
+ repeated: true
101
+ trackBy: id
102
+ phase: fast
103
+ tags:
104
+ - tag: id
105
+ type: data
106
+ dataType: string
107
+ - tag: name
108
+ type: data
109
+ dataType: string
110
+ ```
111
+
112
+ `trackBy` must reference a `data` tag with `string` or `number` type within the sub-contract.
113
+
114
+ ## Rendering Phases
115
+
116
+ | Phase | When | Use for |
117
+ | ------------------ | ------------------ | -------------------------------------------- |
118
+ | `slow` | Build time (SSG) | Static content, SEO data, product names |
119
+ | `fast` | Request time (SSR) | Per-request data, live pricing, stock status |
120
+ | `fast+interactive` | Request + client | Data that also updates on the client |
121
+ | _(no phase)_ | All phases | Available everywhere |
122
+
123
+ **How to choose:**
124
+
125
+ - Known at build time? Use `slow`
126
+ - Changes per request (user, time, session)? Use `fast`
127
+ - Also updates on client after interaction? Use `fast+interactive`
128
+ - Interactive tags (refs) are always `fast+interactive`
129
+
130
+ **Phase rule for arrays:** Child phases must be >= parent phase.
131
+
132
+ ## Props — Component configuration
133
+
134
+ Props are passed by the parent. Use for component inputs like IDs, configuration flags, display options.
135
+
136
+ ```yaml
137
+ props:
138
+ - name: productId
139
+ type: string
140
+ required: true
141
+ description: The product to display
142
+ - name: showPricing
143
+ type: boolean
144
+ default: 'true'
145
+ ```
146
+
147
+ ## Params — URL route segments
148
+
149
+ Params come from dynamic route segments. Use for page-level routing.
150
+
151
+ ```yaml
152
+ params:
153
+ slug: string # required — from [slug]
154
+ lang: string? # optional — from [[lang]]
155
+ path: string[] # catch-all — from [...path]
156
+ ```
157
+
158
+ ## Async Data
159
+
160
+ Wrap any tag in `Promise<T>` with `async: true`:
161
+
162
+ ```yaml
163
+ - tag: reviews
164
+ type: data
165
+ async: true
166
+ dataType: string
167
+ ```
168
+
169
+ ## Tag Metadata
170
+
171
+ Free-form key-value map for plugin validators. The framework ignores `meta`; only validators read it.
172
+
173
+ ```yaml
174
+ - tag: heroImage
175
+ type: data
176
+ dataType: string
177
+ meta:
178
+ vendor: wix-image
179
+ defaultTransform: w_800,h_400,q_80
180
+ ```
181
+
182
+ ## Validation Rules
183
+
184
+ - Tag names must be unique at each level
185
+ - `repeated: true` requires `trackBy`
186
+ - `trackBy` must reference a `data` tag with `string` or `number` type
187
+ - Interactive tags cannot have an explicit `phase`
188
+ - Sub-contracts must have either `tags` (inline) or `link` (external), not both
189
+ - Array children must have phase >= parent phase
190
+ - Prop names must be unique
@@ -46,9 +46,19 @@ There is no standalone "interactive" phase. Any tag with `type: interactive` (re
46
46
  | [jay-html-styling.md](jay-html-styling.md) | Styling: inline, external, dynamic style bindings, class bindings |
47
47
  | [routing.md](routing.md) | Directory-based routing: page structure, dynamic routes, route priority |
48
48
  | [contracts-and-plugins.md](contracts-and-plugins.md) | Reading contracts, plugin.yaml, .jay-action files, and the materialized indexes |
49
+ | [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
50
+ | [script-tags.md](script-tags.md) | Script tag policy: use page.ts for behavior, jay-script="allow" for third-party scripts |
49
51
  | [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, params, action, dev server |
50
52
  | `../references/<plugin>/` | Pre-generated discovery data: product catalogs, collection schemas (from `jay-stack agent-kit`) |
51
53
 
54
+ ## When to Use Headfull Components
55
+
56
+ Use headfull full-stack components for **shared UI sections that should look the same across pages** — headers, navigation menus, footers, sidebars. These are placed in `src/components/` and imported into any page that needs them. This keeps the shared layout in one place: update the component once and every page reflects the change.
57
+
58
+ If a section is **unique to a single page**, write it directly in the page's `.jay-html` — no component needed.
59
+
60
+ See [jay-html-components.md](jay-html-components.md) for import syntax and component structure.
61
+
52
62
  ## Quick Start
53
63
 
54
64
  ### 1. Discover plugins and contracts
@@ -85,11 +85,13 @@ Use `<jay:contract-name>` tags with props:
85
85
 
86
86
  Inside `<jay:...>`, bindings resolve to **that instance's** contract tags (not the parent).
87
87
 
88
- ## Headfull Full-Stack Components
88
+ ## Headfull Components
89
89
 
90
- Headfull components own their UI and can be made full-stack by adding a `contract` attribute.
90
+ In Jay Stack, headfull components are full-stack. They must have a `.jay-contract` file and are created using `makeJayStackComponent` in their `.ts` file. They support server rendering (slow/fast/interactive phases) and must include a `contract` attribute in the import.
91
91
 
92
- Headfull FS components must be placed in `src/components/` each component in its own subdirectory with `.ts`, `.jay-html`, and `.jay-contract` files. The production build only discovers server-side component modules from `src/components/` and `src/plugins/`. Placing them inside page directories will work in dev mode but fail in production.
92
+ Each headfull component lives in its own subdirectory under `src/components/` with three files: `.ts`, `.jay-html`, and `.jay-contract`. The production build only discovers server-side component modules from `src/components/` and `src/plugins/`. Placing them inside page directories will work in dev mode but fail in production.
93
+
94
+ > **Note:** In Jay (without Jay Stack), headfull components use `makeJayComponent` and do not require a contract. However, `makeJayComponent` components should not be used in Jay Stack because they do not support server rendering.
93
95
 
94
96
  ### Import Declaration
95
97
 
@@ -97,7 +99,7 @@ Headfull FS components must be placed in `src/components/` — each component in
97
99
  <head>
98
100
  <script
99
101
  type="application/jay-headfull"
100
- src="../components/shared-header"
102
+ src="../components/shared-header/shared-header"
101
103
  names="SharedHeader"
102
104
  contract="../components/shared-header/shared-header.jay-contract"
103
105
  ></script>
@@ -106,23 +108,19 @@ Headfull FS components must be placed in `src/components/` — each component in
106
108
 
107
109
  **Attributes:**
108
110
 
109
- - `src` — Path to the component module
111
+ - `src` — Path to the component file (must include the filename, not just the directory)
110
112
  - `names` — Component name to import
111
- - `contract` — Path to the contract file (makes the component full-stack with SSR)
113
+ - `contract` — Path to the component's `.jay-contract` file (required in Jay Stack)
112
114
 
113
115
  ### Usage
114
116
 
115
- Same as client-only headfull, with props:
116
-
117
117
  ```html
118
118
  <jay:SharedHeader logoUrl="/logo.png" />
119
119
  ```
120
120
 
121
- Without `contract`, the component is client-only. With `contract`, it participates in slow/fast/interactive phases and is server-side rendered. Use headfull full-stack components for reusable UI with fixed layout that needs SSR (headers, footers, sidebars).
122
-
123
- ### Headfull FS Component Structure
121
+ ### Component Structure
124
122
 
125
- A headfull FS component has its own `.jay-html` file with the same structure as a page:
123
+ A headfull component has its own `.jay-html` file with the same structure as a page:
126
124
 
127
125
  ```html
128
126
  <!-- components/header/header.jay-html -->
@@ -227,7 +225,7 @@ A homepage with key-based, instance-based, and headfull components:
227
225
  ></script>
228
226
  <script
229
227
  type="application/jay-headfull"
230
- src="../components/shared-header"
228
+ src="../components/shared-header/shared-header"
231
229
  names="SharedHeader"
232
230
  contract="../components/shared-header/shared-header.jay-contract"
233
231
  ></script>
@@ -165,6 +165,7 @@ Iterate over repeated sub-contracts:
165
165
  - `forEach` — the repeated tag name from the contract
166
166
  - `trackBy` — stable unique key for each item (must match contract's trackBy)
167
167
  - Inside the loop, bindings resolve to the **current item's** tags
168
+ - **Do not combine `if` and `forEach` on the same element.** Use a wrapper: `<div if="..."><div forEach="...">...</div></div>`
168
169
 
169
170
  **Nested loops:**
170
171
 
@@ -0,0 +1,83 @@
1
+ # Script Tags in Jay-HTML
2
+
3
+ ## Default Rule
4
+
5
+ Use `page.ts` with `makeJayStackComponent` for all page behavior — animations, interactions, data fetching, DOM manipulation. Do not write inline `<script>` tags for page logic.
6
+
7
+ ## When Scripts Are Needed
8
+
9
+ Some third-party tools provide script snippets that must be included as-is:
10
+
11
+ - **Analytics**: Google Analytics, Google Tag Manager, Meta Pixel
12
+ - **Tag managers**: GTM containers, consent management platforms
13
+ - **Chat widgets**: Intercom, Drift, Zendesk
14
+ - **A/B testing**: Optimizely, VWO
15
+
16
+ These scripts cannot be rewritten as `page.ts` components — they are third-party code meant to run as provided.
17
+
18
+ ## How to Include Scripts
19
+
20
+ Add `jay-script="allow"` to mark a script for inclusion:
21
+
22
+ ```html
23
+ <!-- External script -->
24
+ <script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX" async jay-script="allow"></script>
25
+
26
+ <!-- Inline bootstrap snippet (e.g., GTM configuration) -->
27
+ <script jay-script="allow">
28
+ window.dataLayer = window.dataLayer || [];
29
+ function gtag() {
30
+ dataLayer.push(arguments);
31
+ }
32
+ gtag('js', new Date());
33
+ gtag('config', 'G-XXXXX');
34
+ </script>
35
+ ```
36
+
37
+ Without `jay-script="allow"`:
38
+
39
+ - Inline scripts produce an **error**
40
+ - External scripts produce a **warning**
41
+
42
+ ## What Is Not Supported
43
+
44
+ **Local script imports** are never allowed, even with `jay-script="allow"`:
45
+
46
+ ```html
47
+ <!-- Error: always rejected -->
48
+ <script src="./my-script.js"></script>
49
+ <script src="../lib/utils.js" jay-script="allow"></script>
50
+ ```
51
+
52
+ Move local script logic into `page.ts`.
53
+
54
+ ## Placement and Performance
55
+
56
+ Scripts can be placed in `<head>` or `<body>`. Choose based on loading priority:
57
+
58
+ | Placement | When to use |
59
+ | -------------------------------- | ------------------------------------------------------- |
60
+ | `<head>` with `async` | Script should load early without blocking (analytics) |
61
+ | `<head>` with `defer` | Script needs the DOM but should start downloading early |
62
+ | End of `<body>` | Non-critical scripts that should not delay page render |
63
+ | `<head>` without `async`/`defer` | Avoid — blocks page rendering |
64
+
65
+ ```html
66
+ <head>
67
+ <!-- Good: async loading, doesn't block render -->
68
+ <script
69
+ src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"
70
+ async
71
+ jay-script="allow"
72
+ ></script>
73
+ </head>
74
+ <body>
75
+ <main>...</main>
76
+ <!-- Good: loads after page content -->
77
+ <script src="https://cdn.example.com/chat-widget.js" defer jay-script="allow"></script>
78
+ </body>
79
+ ```
80
+
81
+ ## Per-Route Consideration
82
+
83
+ Not every page needs every script. Consider whether a third-party script is needed on all pages or only specific routes. Place scripts only on the pages that need them to avoid unnecessary loading.
@@ -18,17 +18,18 @@ The developer sets up the project, configures plugins, creates page-level compon
18
18
 
19
19
  ## Guides
20
20
 
21
- | File | Topic |
22
- | -------------------------------------------- | ---------------------------------------------------------- |
23
- | [project-structure.md](project-structure.md) | Directory layout, configuration files |
24
- | [routing.md](routing.md) | Directory-based routing, dynamic routes |
25
- | [configuration.md](configuration.md) | .jay file, plugin config, init.ts |
26
- | [page-contracts.md](page-contracts.md) | Page-level contracts (page.jay-contract) |
27
- | [page-components.md](page-components.md) | page.ts: makeJayStackComponent for pages |
28
- | [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray |
29
- | [component-refs.md](component-refs.md) | Refs, collection refs, element types |
30
- | [component-data.md](component-data.md) | Immutable data, JSON Patch, patching |
31
- | [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
32
- | [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
33
- | [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, dev, agent-kit |
34
- | `../references/<plugin>/` | Plugin reference data |
21
+ | File | Topic |
22
+ | ------------------------------------------------- | -------------------------------------------------------------------- |
23
+ | [project-structure.md](project-structure.md) | Directory layout, configuration files |
24
+ | [routing.md](routing.md) | Directory-based routing, dynamic routes |
25
+ | [configuration.md](configuration.md) | .jay file, plugin config, init.ts |
26
+ | [page-contracts.md](page-contracts.md) | Page-level contracts (page.jay-contract) |
27
+ | [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
28
+ | [page-components.md](page-components.md) | page.ts: makeJayStackComponent for pages |
29
+ | [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray |
30
+ | [component-refs.md](component-refs.md) | Refs, collection refs, element types |
31
+ | [component-data.md](component-data.md) | Immutable data, JSON Patch, patching |
32
+ | [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
33
+ | [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
34
+ | [cli-commands.md](cli-commands.md) | CLI commands: setup, validate, dev, agent-kit |
35
+ | `../references/<plugin>/` | Plugin reference data |
@@ -111,4 +111,4 @@ A page can have both a page contract and headless plugin contracts. The page con
111
111
 
112
112
  ## Contract Format Reference
113
113
 
114
- See the plugin [contracts-guide.md](../plugin/contracts-guide.md) for the full contract format: tag types, phases, sub-contracts, async data, and validation rules.
114
+ See the shared [Contract Authoring Guide](../contracts/GUIDE.md) for the full contract format, decision tree, and examples.
@@ -18,25 +18,26 @@ A plugin provides headless components (data + interactions, no UI) that project
18
18
 
19
19
  ## Guides
20
20
 
21
- | File | Topic |
22
- | ------------------------------------------------ | ----------------------------------------------------------------------- |
23
- | [contracts-guide.md](contracts-guide.md) | Contract format: tags, types, phases, props, params, sub-contracts |
24
- | [plugin-structure.md](plugin-structure.md) | plugin.yaml, package layout, exports |
25
- | [component-structure.md](component-structure.md) | makeJayStackComponent, builder API, three-phase rendering |
26
- | [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray, createEvent |
27
- | [component-refs.md](component-refs.md) | Refs, collection refs, element types |
28
- | [component-data.md](component-data.md) | Immutable data, JSON Patch, createPatchableSignal |
29
- | [component-context.md](component-context.md) | Context hooks: provide, reactive, global |
30
- | [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
31
- | [actions-guide.md](actions-guide.md) | makeJayAction, makeJayQuery, .jay-action files |
32
- | [webhooks-guide.md](webhooks-guide.md) | makeWebhook, data change invalidation, renderer server |
33
- | [services-guide.md](services-guide.md) | createJayService, makeJayInit |
34
- | [plugin-routes.md](plugin-routes.md) | Plugin-provided pages: routes, jay-html templates, page components |
35
- | [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
36
- | [commands-guide.md](commands-guide.md) | makeCliCommand, .jay-command files, CONSOLE_CONTEXT, jay-stack run |
37
- | [validation.md](validation.md) | jay-stack validate-plugin, writing custom jay-html validators |
38
- | [dev-server-service.md](dev-server-service.md) | Dev server service API: routes, params, freeze management |
39
- | `../references/<plugin>/` | Plugin reference data |
21
+ | File | Topic |
22
+ | ------------------------------------------------- | ----------------------------------------------------------------------- |
23
+ | [Contract Authoring Guide](../contracts/GUIDE.md) | Writing contracts: syntax, page/component/linked contracts, examples |
24
+ | [contracts-guide.md](contracts-guide.md) | Plugin-specific contract concerns |
25
+ | [plugin-structure.md](plugin-structure.md) | plugin.yaml, package layout, exports |
26
+ | [component-structure.md](component-structure.md) | makeJayStackComponent, builder API, three-phase rendering |
27
+ | [component-state.md](component-state.md) | createSignal, createMemo, createEffect, createDerivedArray, createEvent |
28
+ | [component-refs.md](component-refs.md) | Refs, collection refs, element types |
29
+ | [component-data.md](component-data.md) | Immutable data, JSON Patch, createPatchableSignal |
30
+ | [component-context.md](component-context.md) | Context hooks: provide, reactive, global |
31
+ | [render-results.md](render-results.md) | phaseOutput, RenderPipeline, errors, redirects |
32
+ | [actions-guide.md](actions-guide.md) | makeJayAction, makeJayQuery, .jay-action files |
33
+ | [webhooks-guide.md](webhooks-guide.md) | makeWebhook, data change invalidation, renderer server |
34
+ | [services-guide.md](services-guide.md) | createJayService, makeJayInit |
35
+ | [plugin-routes.md](plugin-routes.md) | Plugin-provided pages: routes, jay-html templates, page components |
36
+ | [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
37
+ | [commands-guide.md](commands-guide.md) | makeCliCommand, .jay-command files, CONSOLE_CONTEXT, jay-stack run |
38
+ | [validation.md](validation.md) | jay-stack validate-plugin, writing custom jay-html validators |
39
+ | [dev-server-service.md](dev-server-service.md) | Dev server service API: routes, params, freeze management |
40
+ | `../references/<plugin>/` | Plugin reference data |
40
41
 
41
42
  ## Key Principles
42
43
 
@@ -1,6 +1,8 @@
1
- # Contract Authoring Guide
1
+ # Plugin Contract Guide
2
2
 
3
- Contracts (`.jay-contract` files) are the source of truth for a component's data shape. Define the contract before implementing the component.
3
+ For the full contract syntax, decision tree, and examples, see the shared [Contract Authoring Guide](../contracts/GUIDE.md).
4
+
5
+ This file covers plugin-specific contract concerns. Contracts (`.jay-contract` files) are the source of truth for a component's data shape. Define the contract before implementing the component.
4
6
 
5
7
  ## Basic Structure
6
8
 
package/dist/index.js CHANGED
@@ -4824,9 +4824,35 @@ async function ensureAgentKitDocs(projectRoot, _force, mode) {
4824
4824
  getLogger().info(chalk.gray(` Created agent-kit/${role}/${filename}`));
4825
4825
  }
4826
4826
  }
4827
+ const topLevelFiles = (await fs$1.readdir(templateDir)).filter((f) => f.endsWith(".md"));
4828
+ for (const filename of topLevelFiles) {
4829
+ await fs$1.copyFile(path$1.join(templateDir, filename), path$1.join(agentKitDir, filename));
4830
+ getLogger().info(chalk.gray(` Created agent-kit/${filename}`));
4831
+ }
4832
+ const sharedDirs = ["contracts"];
4833
+ for (const dir of sharedDirs) {
4834
+ const srcDir = path$1.join(templateDir, dir);
4835
+ if (!fsSync.existsSync(srcDir))
4836
+ continue;
4837
+ await copyDirRecursive(srcDir, path$1.join(agentKitDir, dir));
4838
+ getLogger().info(chalk.gray(` Created agent-kit/${dir}/`));
4839
+ }
4840
+ }
4841
+ async function copyDirRecursive(src, dest) {
4842
+ await fs$1.mkdir(dest, { recursive: true });
4843
+ const entries = await fs$1.readdir(src, { withFileTypes: true });
4844
+ for (const entry of entries) {
4845
+ const srcPath = path$1.join(src, entry.name);
4846
+ const destPath = path$1.join(dest, entry.name);
4847
+ if (entry.isDirectory()) {
4848
+ await copyDirRecursive(srcPath, destPath);
4849
+ } else if (entry.name.endsWith(".md")) {
4850
+ await fs$1.copyFile(srcPath, destPath);
4851
+ }
4852
+ }
4827
4853
  }
4828
4854
  async function mergePluginAgentKitGuides(projectRoot, mode) {
4829
- const plugins = await scanPlugins$1({ projectRoot });
4855
+ const plugins = await scanPlugins$1({ projectRoot, includeDevDeps: true });
4830
4856
  const agentKitDir = path$1.join(projectRoot, "agent-kit");
4831
4857
  const roles = mode && ALL_ROLES.includes(mode) ? [mode] : ALL_ROLES;
4832
4858
  const copiedPerRole = /* @__PURE__ */ new Map();