@jay-framework/jay-stack-cli 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-kit-template/designer/jay-html-components.md +42 -0
- package/agent-kit-template/designer/routing.md +19 -7
- package/agent-kit-template/developer/routing.md +19 -7
- package/agent-kit-template/plugin/INSTRUCTIONS.md +20 -3
- package/agent-kit-template/plugin/plugin-structure.md +20 -13
- package/agent-kit-template/plugin/setup-guide.md +180 -0
- package/agent-kit-template/plugin/validation.md +18 -4
- package/dist/index.js +1047 -82
- package/package.json +11 -11
|
@@ -71,6 +71,20 @@ Use `<jay:contract-name>` tags with props:
|
|
|
71
71
|
</jay:product-widget>
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
**With bindings from page data** (props from keyed components or page ViewState):
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<!-- p is a keyed headless component providing product data -->
|
|
78
|
+
<jay:category-products categorySlug="{p.categorySlug}" limit="4">
|
|
79
|
+
<div class="product-card">
|
|
80
|
+
<h3>{name}</h3>
|
|
81
|
+
<span>{price}</span>
|
|
82
|
+
</div>
|
|
83
|
+
</jay:category-products>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use `{path}` syntax to bind props to values from the page's ViewState. The binding is resolved at render time — works with both slow and fast phase data.
|
|
87
|
+
|
|
74
88
|
**With forEach** (dynamic props from parent data):
|
|
75
89
|
|
|
76
90
|
```html
|
|
@@ -85,6 +99,34 @@ Use `<jay:contract-name>` tags with props:
|
|
|
85
99
|
|
|
86
100
|
Inside `<jay:...>`, bindings resolve to **that instance's** contract tags (not the parent).
|
|
87
101
|
|
|
102
|
+
### Prop binding summary
|
|
103
|
+
|
|
104
|
+
| Syntax | Resolves to | Example |
|
|
105
|
+
| --------------------------------- | -------------------- | ------------------------- |
|
|
106
|
+
| `prop="literal"` | Literal string value | `productId="prod-1"` |
|
|
107
|
+
| `prop="{field}"` | Page ViewState field | `slug="{p.categorySlug}"` |
|
|
108
|
+
| `prop="{field}"` (inside forEach) | ForEach item field | `productId="{_id}"` |
|
|
109
|
+
|
|
110
|
+
### Prop phase constraints
|
|
111
|
+
|
|
112
|
+
Contract props can declare a `phase` (defaults to `slow`). The binding source must be available at that phase:
|
|
113
|
+
|
|
114
|
+
- A **slow** prop (default) must bind to a literal, a route param, or a slow-phase tag
|
|
115
|
+
- A **fast** prop can also bind to fast-phase tags
|
|
116
|
+
|
|
117
|
+
If a slow prop binds to a fast-phase field, `jay-stack validate` flags an error — the component's slow render would receive an empty value.
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
# In the component's contract:
|
|
121
|
+
props:
|
|
122
|
+
- name: categorySlug
|
|
123
|
+
type: string
|
|
124
|
+
phase: slow # Must be available at build time
|
|
125
|
+
- name: filter
|
|
126
|
+
type: string
|
|
127
|
+
phase: fast # Only needs to be available at request time
|
|
128
|
+
```
|
|
129
|
+
|
|
88
130
|
## Headfull Components
|
|
89
131
|
|
|
90
132
|
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.
|
|
@@ -51,23 +51,22 @@ src/pages/products/
|
|
|
51
51
|
|
|
52
52
|
The static `ceramic-flower-vase/` route takes priority over `[slug]/` for that URL, but all other product URLs still use the dynamic route.
|
|
53
53
|
|
|
54
|
-
### Static Override Params
|
|
54
|
+
### Static Override Params and Headless Component Props
|
|
55
55
|
|
|
56
|
-
Static override routes
|
|
56
|
+
Static override routes use the same headless component as the dynamic route they override. Since the static route has no dynamic directory segment, the params must be declared in the headless component's YAML body:
|
|
57
57
|
|
|
58
58
|
```html
|
|
59
59
|
<!-- src/pages/products/ceramic-flower-vase/page.jay-html -->
|
|
60
60
|
<html>
|
|
61
61
|
<head>
|
|
62
|
-
<script type="application/jay-params">
|
|
63
|
-
slug: ceramic-flower-vase
|
|
64
|
-
</script>
|
|
65
62
|
<script
|
|
66
63
|
type="application/jay-headless"
|
|
67
64
|
plugin="wix-stores"
|
|
68
65
|
contract="product-page"
|
|
69
66
|
key="product"
|
|
70
|
-
|
|
67
|
+
>
|
|
68
|
+
slug: ceramic-flower-vase
|
|
69
|
+
</script>
|
|
71
70
|
</head>
|
|
72
71
|
<body>
|
|
73
72
|
<h1>{product.productName}</h1>
|
|
@@ -75,7 +74,20 @@ Static override routes often use the same contract as the dynamic route they ove
|
|
|
75
74
|
</html>
|
|
76
75
|
```
|
|
77
76
|
|
|
78
|
-
The script body is YAML.
|
|
77
|
+
The script body is YAML. Values are passed to the component as props alongside route params. This same mechanism is used for any per-component configuration:
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<script
|
|
81
|
+
type="application/jay-headless"
|
|
82
|
+
plugin="@jay-framework/markdown"
|
|
83
|
+
contract="markdown-pages"
|
|
84
|
+
key="post"
|
|
85
|
+
>
|
|
86
|
+
contentDir: ./content
|
|
87
|
+
</script>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> **Note:** `<script type="application/jay-params">` is deprecated. Move param values into the headless component's script tag body.
|
|
79
91
|
|
|
80
92
|
## Page Files
|
|
81
93
|
|
|
@@ -51,23 +51,22 @@ src/pages/products/
|
|
|
51
51
|
|
|
52
52
|
The static `ceramic-flower-vase/` route takes priority over `[slug]/` for that URL, but all other product URLs still use the dynamic route.
|
|
53
53
|
|
|
54
|
-
### Static Override Params
|
|
54
|
+
### Static Override Params and Headless Component Props
|
|
55
55
|
|
|
56
|
-
Static override routes
|
|
56
|
+
Static override routes use the same headless component as the dynamic route they override. Since the static route has no dynamic directory segment, the params must be declared in the headless component's YAML body:
|
|
57
57
|
|
|
58
58
|
```html
|
|
59
59
|
<!-- src/pages/products/ceramic-flower-vase/page.jay-html -->
|
|
60
60
|
<html>
|
|
61
61
|
<head>
|
|
62
|
-
<script type="application/jay-params">
|
|
63
|
-
slug: ceramic-flower-vase
|
|
64
|
-
</script>
|
|
65
62
|
<script
|
|
66
63
|
type="application/jay-headless"
|
|
67
64
|
plugin="wix-stores"
|
|
68
65
|
contract="product-page"
|
|
69
66
|
key="product"
|
|
70
|
-
|
|
67
|
+
>
|
|
68
|
+
slug: ceramic-flower-vase
|
|
69
|
+
</script>
|
|
71
70
|
</head>
|
|
72
71
|
<body>
|
|
73
72
|
<h1>{product.productName}</h1>
|
|
@@ -75,7 +74,20 @@ Static override routes often use the same contract as the dynamic route they ove
|
|
|
75
74
|
</html>
|
|
76
75
|
```
|
|
77
76
|
|
|
78
|
-
The script body is YAML.
|
|
77
|
+
The script body is YAML. Values are passed to the component as props alongside route params. This same mechanism is used for any per-component configuration:
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<script
|
|
81
|
+
type="application/jay-headless"
|
|
82
|
+
plugin="@jay-framework/markdown"
|
|
83
|
+
contract="markdown-pages"
|
|
84
|
+
key="post"
|
|
85
|
+
>
|
|
86
|
+
contentDir: ./content
|
|
87
|
+
</script>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> **Note:** `<script type="application/jay-params">` is deprecated. Move param values into the headless component's script tag body.
|
|
79
91
|
|
|
80
92
|
## Page Files
|
|
81
93
|
|
|
@@ -12,9 +12,25 @@ A plugin provides headless components (data + interactions, no UI) that project
|
|
|
12
12
|
2. **Implement components** matching the contracts
|
|
13
13
|
3. **Define actions** with `.jay-action` metadata
|
|
14
14
|
4. **Optionally add routes** — pages for admin tools and dashboards
|
|
15
|
-
5. **
|
|
16
|
-
6. **
|
|
17
|
-
7. **
|
|
15
|
+
5. **Optionally add validators** — custom jay-html validation rules
|
|
16
|
+
6. **Optionally add setup/agentkit handlers** — config templating, add-menu generation
|
|
17
|
+
7. **Set up `plugin.yaml`** — list contracts, actions, services, contexts, routes, validators, setup, agentkit
|
|
18
|
+
8. **Configure build** — dual entry points (server + client), vite.config.ts, package.json exports
|
|
19
|
+
9. **Validate** with `jay-stack validate-plugin`
|
|
20
|
+
|
|
21
|
+
## Plugin Lifecycle — CLI Commands
|
|
22
|
+
|
|
23
|
+
The plugin participates in four CLI commands, each running different hooks:
|
|
24
|
+
|
|
25
|
+
| Command | When | What runs from your plugin |
|
|
26
|
+
| --------------------------- | ------------------ | ---------------------------------------------------------------------------------- |
|
|
27
|
+
| `jay-stack validate-plugin` | Plugin development | Checks plugin.yaml structure, contracts, exports, handler references |
|
|
28
|
+
| `jay-stack setup <plugin>` | Project setup | `setup` — creates config files, validates credentials |
|
|
29
|
+
| `jay-stack agent-kit` | Before development | `agentkit` — generates add-menu items, reference data, skills, thumbnails |
|
|
30
|
+
| `jay-stack validate` | During development | `validators[].handler` — runs your validation rules against project jay-html files |
|
|
31
|
+
|
|
32
|
+
**`validate-plugin`** validates YOUR plugin's structure. Run it during plugin development.
|
|
33
|
+
**`validate`** runs your plugin's validators against a PROJECT that uses your plugin. Run it from the project.
|
|
18
34
|
|
|
19
35
|
## Guides
|
|
20
36
|
|
|
@@ -36,6 +52,7 @@ A plugin provides headless components (data + interactions, no UI) that project
|
|
|
36
52
|
| [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
|
|
37
53
|
| [commands-guide.md](commands-guide.md) | makeCliCommand, .jay-command files, CONSOLE_CONTEXT, jay-stack run |
|
|
38
54
|
| [validation.md](validation.md) | jay-stack validate-plugin, writing custom jay-html validators |
|
|
55
|
+
| [setup-guide.md](setup-guide.md) | Setup handlers, references handlers, add-menu generation |
|
|
39
56
|
| [dev-server-service.md](dev-server-service.md) | Dev server service API: routes, params, freeze management |
|
|
40
57
|
| `../references/<plugin>/` | Plugin reference data |
|
|
41
58
|
|
|
@@ -63,15 +63,12 @@ commands:
|
|
|
63
63
|
|
|
64
64
|
validators:
|
|
65
65
|
- name: media-optimization
|
|
66
|
-
handler:
|
|
66
|
+
handler: validateMediaOptimization
|
|
67
67
|
description: Ensures media URLs use resize parameters
|
|
68
68
|
|
|
69
|
-
setup:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
configTemplate:
|
|
73
|
-
- source: templates/config.yaml
|
|
74
|
-
target: my-plugin.yaml
|
|
69
|
+
setup: setup-handler
|
|
70
|
+
agentkit: agentkit-handler
|
|
71
|
+
description: Configure My Plugin
|
|
75
72
|
```
|
|
76
73
|
|
|
77
74
|
### Contract Entry Fields
|
|
@@ -193,16 +190,26 @@ Commands are CLI operations run via `jay-stack run`. Use `makeCliCommand()` to c
|
|
|
193
190
|
### Validator Entry Fields
|
|
194
191
|
|
|
195
192
|
- `name` — Validator name (shown in validation output as `plugin-name/validator-name`)
|
|
196
|
-
- `handler` —
|
|
193
|
+
- `handler` — Export name (NPM plugins) or relative path (local plugins) to the validator function
|
|
197
194
|
- `description` — (optional) What this validator checks
|
|
198
195
|
|
|
199
|
-
|
|
196
|
+
**NPM plugins:** `handler` is the export name from the package entry point (e.g., `validateMediaOptimization`). The function must be exported from `lib/index.ts`.
|
|
197
|
+
**Local plugins:** `handler` is a relative path to the module (e.g., `./validators/media-validator`). The module must export a `validate` function.
|
|
200
198
|
|
|
201
|
-
|
|
199
|
+
Validators run during `jay-stack validate` against every parsed jay-html file in the project. See [validation.md](validation.md) for implementation details.
|
|
202
200
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- `
|
|
201
|
+
### Setup and agent-kit fields
|
|
202
|
+
|
|
203
|
+
- `setup` — Export name (NPM) or relative path (local) for `jay-stack setup <plugin>`. Creates config files, validates credentials and services.
|
|
204
|
+
- `agentkit` — Export name (NPM) or relative path (local) for `jay-stack agent-kit`. Generates discovery data: add-menu catalogs, reference files, skills, thumbnails.
|
|
205
|
+
- `description` — (optional, top-level) Human-readable description of what setup validates
|
|
206
|
+
|
|
207
|
+
**NPM plugins:** `setup` and `agentkit` are export names from the package entry point.
|
|
208
|
+
**Local plugins:** relative paths to the handler modules.
|
|
209
|
+
|
|
210
|
+
`jay-stack validate-plugin` checks that declared handlers exist and are correctly exported.
|
|
211
|
+
|
|
212
|
+
See [setup-guide.md](setup-guide.md) for implementation details.
|
|
206
213
|
|
|
207
214
|
## Package Layout
|
|
208
215
|
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Plugin Setup & Agent-Kit
|
|
2
|
+
|
|
3
|
+
Plugins can provide two hooks for project configuration and AI agent discovery:
|
|
4
|
+
|
|
5
|
+
- **Setup handler** (`setup` in `plugin.yaml`) — runs during `jay-stack setup <plugin>`. Creates config files, validates credentials.
|
|
6
|
+
- **Agent-kit handler** (`agentkit` in `plugin.yaml`) — runs during `jay-stack agent-kit`. Generates discovery data (add-menu catalogs, reference files, skills, thumbnails) using live services when needed.
|
|
7
|
+
|
|
8
|
+
## When Each Runs
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
jay-stack setup <plugin> → setup handler (config + credentials)
|
|
12
|
+
jay-stack agent-kit → agentkit handler (after contract materialization)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Setup runs when a project configures the plugin. Agent-kit runs whenever the developer regenerates the agent kit — it can use live services to produce fresh data.
|
|
16
|
+
|
|
17
|
+
## Declaring in plugin.yaml
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
name: my-plugin
|
|
21
|
+
setup: setupMyPlugin # export name (NPM) or ./path (local) — optional
|
|
22
|
+
agentkit: generateMyAgentKit # export name (NPM) or ./path (local) — optional
|
|
23
|
+
description: Validate credentials and install config # optional, top-level
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**NPM plugins:** `setup` and `agentkit` are export names from the package entry point (`lib/index.ts`).
|
|
27
|
+
**Local plugins:** relative paths to handler modules (e.g. `agentkit: ./agentkit` — export `agentkit` or `default` from that module).
|
|
28
|
+
|
|
29
|
+
`jay-stack validate-plugin` checks that declared handlers exist and are correctly exported.
|
|
30
|
+
|
|
31
|
+
## Writing a Setup Handler
|
|
32
|
+
|
|
33
|
+
The setup handler creates config files and validates services. It receives a `PluginSetupContext` and returns a `PluginSetupResult`.
|
|
34
|
+
|
|
35
|
+
**Do not** write add-menu catalogs in setup — use the agent-kit handler.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import type { PluginSetupContext, PluginSetupResult } from '@jay-framework/stack-server-runtime';
|
|
39
|
+
import fs from 'node:fs';
|
|
40
|
+
import path from 'node:path';
|
|
41
|
+
|
|
42
|
+
export async function setupMyPlugin(ctx: PluginSetupContext): Promise<PluginSetupResult> {
|
|
43
|
+
if (ctx.initError) {
|
|
44
|
+
return { status: 'error', message: `Init failed: ${ctx.initError.message}` };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const configCreated: string[] = [];
|
|
48
|
+
const configPath = path.join(ctx.configDir, '.my-plugin.yaml');
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(configPath) || ctx.force) {
|
|
51
|
+
fs.mkdirSync(ctx.configDir, { recursive: true });
|
|
52
|
+
fs.writeFileSync(configPath, '# My Plugin config\n', 'utf-8');
|
|
53
|
+
configCreated.push('config/.my-plugin.yaml');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
status: 'configured',
|
|
58
|
+
configCreated,
|
|
59
|
+
message:
|
|
60
|
+
configCreated.length > 0
|
|
61
|
+
? 'My Plugin config installed.'
|
|
62
|
+
: 'My Plugin config already present (use --force to rewrite).',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### PluginSetupContext
|
|
68
|
+
|
|
69
|
+
| Field | Type | Description |
|
|
70
|
+
| ------------- | --------- | ----------------------------------------------------------------- |
|
|
71
|
+
| `pluginName` | `string` | Plugin name from plugin.yaml |
|
|
72
|
+
| `projectRoot` | `string` | Absolute project root path |
|
|
73
|
+
| `configDir` | `string` | Config directory (from `.jay` configBase, defaults to `./config`) |
|
|
74
|
+
| `services` | `Map` | Registered services (may be empty if init failed) |
|
|
75
|
+
| `initError` | `Error?` | Present if plugin init failed — check this before using services |
|
|
76
|
+
| `force` | `boolean` | Whether `--force` flag was passed |
|
|
77
|
+
|
|
78
|
+
### PluginSetupResult
|
|
79
|
+
|
|
80
|
+
| Field | Type | Description |
|
|
81
|
+
| --------------- | ------------------------------------------- | ----------------------------------------------- |
|
|
82
|
+
| `status` | `'configured' \| 'needs-config' \| 'error'` | Overall result |
|
|
83
|
+
| `configCreated` | `string[]?` | Config files created (relative to project root) |
|
|
84
|
+
| `message` | `string?` | Human-readable status message |
|
|
85
|
+
|
|
86
|
+
## Writing an Agent-Kit Handler
|
|
87
|
+
|
|
88
|
+
The agent-kit handler generates discovery data at agent-kit time: add-menu catalogs, `agent-kit/references/<plugin>/` files, skills, thumbnails. It can use live services (database queries, API calls) to produce dynamic content.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import type {
|
|
92
|
+
PluginAgentKitContext,
|
|
93
|
+
PluginAgentKitResult,
|
|
94
|
+
} from '@jay-framework/stack-server-runtime';
|
|
95
|
+
import fs from 'node:fs';
|
|
96
|
+
import path from 'node:path';
|
|
97
|
+
import yaml from 'yaml';
|
|
98
|
+
|
|
99
|
+
export async function generateMyAgentKit(
|
|
100
|
+
ctx: PluginAgentKitContext,
|
|
101
|
+
): Promise<PluginAgentKitResult> {
|
|
102
|
+
if (ctx.initError) {
|
|
103
|
+
return { agentKitCreated: [], message: `Skipped: ${ctx.initError.message}` };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const outputPath = path.join(ctx.projectRoot, 'agent-kit/aiditor/add-menu/my-plugin.yaml');
|
|
107
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
108
|
+
|
|
109
|
+
const items = [
|
|
110
|
+
{ id: 'my-plugin:feature-1', title: 'Feature 1', category: 'My Plugin', prompt: '...' },
|
|
111
|
+
];
|
|
112
|
+
fs.writeFileSync(outputPath, yaml.stringify({ items }), 'utf-8');
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
agentKitCreated: ['agent-kit/aiditor/add-menu/my-plugin.yaml'],
|
|
116
|
+
message: `Generated ${items.length} add-menu items`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### PluginAgentKitContext
|
|
122
|
+
|
|
123
|
+
| Field | Type | Description |
|
|
124
|
+
| --------------- | --------- | --------------------------------------------------------------- |
|
|
125
|
+
| `pluginName` | `string` | Plugin name from plugin.yaml |
|
|
126
|
+
| `projectRoot` | `string` | Absolute project root path |
|
|
127
|
+
| `referencesDir` | `string` | Directory for reference data (`agent-kit/references/<plugin>/`) |
|
|
128
|
+
| `services` | `Map` | Registered services |
|
|
129
|
+
| `initError` | `Error?` | Present if plugin init failed |
|
|
130
|
+
| `force` | `boolean` | Whether `--force` flag was passed |
|
|
131
|
+
|
|
132
|
+
### PluginAgentKitResult
|
|
133
|
+
|
|
134
|
+
| Field | Type | Description |
|
|
135
|
+
| ----------------- | ---------- | ---------------------------------------- |
|
|
136
|
+
| `agentKitCreated` | `string[]` | Files created (relative to project root) |
|
|
137
|
+
| `message` | `string?` | Human-readable status message |
|
|
138
|
+
|
|
139
|
+
## Setup vs Agent-Kit — When to Use Which
|
|
140
|
+
|
|
141
|
+
| Use case | Hook | Why |
|
|
142
|
+
| -------------------------------------------------------------------- | ---------- | ----------------------------------------------------------- |
|
|
143
|
+
| Copy static add-menu template, skills, thumbnails | `agentkit` | Discovery data — regenerated on `jay-stack agent-kit` |
|
|
144
|
+
| Generate data from live services (product catalogs, CMS schemas) | `agentkit` | Needs services initialized; refreshed on each agent-kit run |
|
|
145
|
+
| Validate credentials / API keys | `setup` | Part of initial project configuration |
|
|
146
|
+
| Write AIditor add-menu from project-specific data (DESIGN.md tokens) | `agentkit` | Data comes from project files at agent-kit time |
|
|
147
|
+
|
|
148
|
+
## AIditor Add-Menu Items
|
|
149
|
+
|
|
150
|
+
The agent-kit handler writes to `agent-kit/aiditor/add-menu/<plugin-name>.yaml`. The AIditor discovers and loads all YAML files in this directory.
|
|
151
|
+
|
|
152
|
+
Each item:
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
items:
|
|
156
|
+
- id: my-plugin:feature-name # unique ID
|
|
157
|
+
title: Feature Name # shown in the add menu
|
|
158
|
+
category: My Plugin # grouping
|
|
159
|
+
subCategory: Components # sub-grouping
|
|
160
|
+
pluginName: my-plugin # optional: plugin attribution
|
|
161
|
+
packageName: '@my-org/my-plugin' # optional: npm package name
|
|
162
|
+
prompt: | # instructions for the AI agent
|
|
163
|
+
Use headless component @my-org/my-plugin / contract feature-name.
|
|
164
|
+
Read agent-kit/designer/feature-name.md for usage guide.
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
See `agent-kit/plugin/aiditor-add-menu.md` (installed by `jay-stack setup aiditor`) for the full contributor guide.
|
|
168
|
+
|
|
169
|
+
## Exporting Handlers
|
|
170
|
+
|
|
171
|
+
For NPM plugins, export handlers from the package entry point:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// lib/index.ts
|
|
175
|
+
export { setupMyPlugin } from './setup.js';
|
|
176
|
+
export { generateMyAgentKit } from './agentkit.js';
|
|
177
|
+
// ... other exports (components, actions, services)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
For local plugins, use relative paths in `plugin.yaml` and export `agentkit` or `default` from the handler module.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Plugin Validation
|
|
2
2
|
|
|
3
|
+
Two separate validation commands:
|
|
4
|
+
|
|
5
|
+
- **`jay-stack validate-plugin`** — validates your plugin's own structure (run during plugin development)
|
|
6
|
+
- **`jay-stack validate`** — validates a project's jay-html files, including running your plugin's custom validators (run from a project that uses your plugin)
|
|
7
|
+
|
|
8
|
+
## validate-plugin
|
|
9
|
+
|
|
3
10
|
Run `jay-stack validate-plugin` to check your plugin for errors.
|
|
4
11
|
|
|
5
12
|
## Usage
|
|
@@ -119,20 +126,27 @@ Values: `title`, `meta:<name>` (e.g., `meta:description`), `link:<rel>` (e.g., `
|
|
|
119
126
|
|
|
120
127
|
Validators access this via `ctx.headlessImports[].providedHeadTags`.
|
|
121
128
|
|
|
122
|
-
## Plugin Validators
|
|
129
|
+
## Plugin Validators (jay-stack validate)
|
|
123
130
|
|
|
124
|
-
Plugins can provide custom jay-html validation rules that run during `jay-stack validate
|
|
131
|
+
Plugins can provide custom jay-html validation rules that run during `jay-stack validate` in projects that use your plugin. Declare validators in `plugin.yaml`:
|
|
125
132
|
|
|
126
133
|
```yaml
|
|
127
134
|
validators:
|
|
128
135
|
- name: media-optimization
|
|
129
|
-
handler:
|
|
136
|
+
handler: validateMediaOptimization # export name from package entry point
|
|
130
137
|
description: Ensures media URLs use resize parameters
|
|
131
138
|
```
|
|
132
139
|
|
|
140
|
+
**Handler format:**
|
|
141
|
+
|
|
142
|
+
- **NPM plugins** — `handler` is an export name from the package entry point (e.g., `validateMediaOptimization`). The function must be exported from `lib/index.ts`.
|
|
143
|
+
- **Local plugins** (`src/plugins/`) — `handler` is a relative path to the module (e.g., `./validators/media-validator`). The module must export a `validate` function.
|
|
144
|
+
|
|
145
|
+
`jay-stack validate-plugin` checks that the handler exists and is correctly exported.
|
|
146
|
+
|
|
133
147
|
### Writing a Validator
|
|
134
148
|
|
|
135
|
-
|
|
149
|
+
Export the validator function from the package entry point (for NPM) or from the handler module (for local):
|
|
136
150
|
|
|
137
151
|
```typescript
|
|
138
152
|
import type { JayHtmlValidatorFn, JayHtmlValidationFinding } from '@jay-framework/compiler-shared';
|