@jay-framework/jay-stack-cli 0.22.2 → 0.23.1
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/INSTRUCTIONS.md +4 -2
- package/agent-kit-template/designer/contracts-and-plugins.md +20 -0
- package/agent-kit-template/designer/jay-html-components.md +44 -6
- package/agent-kit-template/designer/jay-html-syntax.md +2 -0
- package/agent-kit-template/designer/jay-html-template-syntax.md +105 -1
- package/agent-kit-template/designer/navigation-patterns.md +73 -0
- package/agent-kit-template/designer/routing.md +56 -1
- package/agent-kit-template/designer/validation-guide.md +88 -0
- package/agent-kit-template/developer/routing.md +12 -1
- package/agent-kit-template/plugin/INSTRUCTIONS.md +25 -23
- package/agent-kit-template/plugin/add-menu-guide.md +114 -0
- package/agent-kit-template/plugin/aiditor-settings-guide.md +296 -0
- package/agent-kit-template/plugin/dev-server-service.md +2 -0
- package/agent-kit-template/plugin/plugin-routes.md +49 -0
- package/agent-kit-template/plugin/setup-guide.md +4 -16
- package/dist/index.d.ts +1 -88
- package/dist/index.js +388 -2662
- package/package.json +10 -11
- package/lib/vendors/README.md +0 -510
- package/lib/vendors/figma/README.md +0 -396
- package/test/vendors/figma/fixtures/README.md +0 -164
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# AIditor Add-Menu Items
|
|
2
|
+
|
|
3
|
+
Plugins contribute items to the AIditor's Add Menu via YAML catalog files generated by the agent-kit handler.
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
## Required and recommended fields
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
items:
|
|
11
|
+
- id: my-plugin:feature-name # required — unique, stable
|
|
12
|
+
title: Feature Name # required — shown in the add menu
|
|
13
|
+
category: My Plugin # required — top-level nav label
|
|
14
|
+
prompt: | # required — injected verbatim into agent task
|
|
15
|
+
Use headless component @my-org/my-plugin / contract feature-name.
|
|
16
|
+
Read agent-kit/designer/feature-name.md for usage guide.
|
|
17
|
+
pluginName: my-plugin # required — plugin attribution
|
|
18
|
+
packageName: '@my-org/my-plugin' # required — visibility filter
|
|
19
|
+
subCategory: Components # optional — second nav level
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`pluginName` and `packageName` must always be set and must match the plugin's `plugin.yaml` name and npm package name respectively. AIditor uses them to filter items — only items whose `packageName` or `pluginName` matches an installed plugin are visible.
|
|
23
|
+
|
|
24
|
+
## Interaction mode
|
|
25
|
+
|
|
26
|
+
Every item should declare how the user attaches it:
|
|
27
|
+
|
|
28
|
+
```yaml
|
|
29
|
+
interaction:
|
|
30
|
+
mode: reference # default — attach as context or @mention
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
interaction:
|
|
35
|
+
mode: stage-place # click/drag onto live preview
|
|
36
|
+
stagePromptTemplate: | # placed at the marker location
|
|
37
|
+
Add a product card at this location using wix-stores/product-widget.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `reference` for data sources (contracts, categories). Use `stage-place` for visual elements the user places on the page (components, design tokens, effects).
|
|
41
|
+
|
|
42
|
+
## Browse size
|
|
43
|
+
|
|
44
|
+
Controls card size in the browse grid:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
browse:
|
|
48
|
+
size: small # 4 per row — color swatches, small tokens
|
|
49
|
+
size: medium # 2 per row — default
|
|
50
|
+
size: large # 1 per row — full-width previews
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Presentation (preview)
|
|
54
|
+
|
|
55
|
+
Optional visual preview in the browse grid:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
# Static image
|
|
59
|
+
presentation:
|
|
60
|
+
type: image
|
|
61
|
+
src: thumbnails/my-plugin/feature.png
|
|
62
|
+
|
|
63
|
+
# HTML fragment — must use @scope for CSS isolation
|
|
64
|
+
presentation:
|
|
65
|
+
type: html-fragment
|
|
66
|
+
html: |
|
|
67
|
+
<div>
|
|
68
|
+
<style>@scope { .demo { color: blue; } }</style>
|
|
69
|
+
<div class="demo">Preview content</div>
|
|
70
|
+
</div>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Html-fragment rules:
|
|
74
|
+
|
|
75
|
+
- Single root `<div>`
|
|
76
|
+
- `<style>` with `@scope { }` (even if CSS is inline-only)
|
|
77
|
+
- No `<script>`, no `on*` handlers
|
|
78
|
+
- Keep under 8 KB
|
|
79
|
+
|
|
80
|
+
## TypeScript type
|
|
81
|
+
|
|
82
|
+
Import `AddMenuItem` from `@jay-framework/plugin-validator` for type-safe item construction:
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import type { AddMenuItem } from '@jay-framework/plugin-validator';
|
|
86
|
+
|
|
87
|
+
const items: AddMenuItem[] = [
|
|
88
|
+
{
|
|
89
|
+
id: 'my-plugin:feature',
|
|
90
|
+
title: 'Feature',
|
|
91
|
+
category: 'My Plugin',
|
|
92
|
+
pluginName: 'my-plugin',
|
|
93
|
+
packageName: '@my-org/my-plugin',
|
|
94
|
+
interaction: { mode: 'stage-place', stagePromptTemplate: 'Add feature here.' },
|
|
95
|
+
prompt: 'Use headless @my-org/my-plugin / contract feature.',
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## YAML serialization
|
|
101
|
+
|
|
102
|
+
When writing YAML with `js-yaml`, use `noRefs: true` to prevent anchor/alias syntax (`&ref_0` / `*ref_0`) which the AIditor does not support:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
fs.writeFileSync(outputPath, yaml.dump({ items }, { lineWidth: 120, noRefs: true }), 'utf-8');
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Project settings (separate surface)
|
|
109
|
+
|
|
110
|
+
Add Menu and **Project settings** are both materialized by the `agentkit` handler but use different paths and schemas. For a settings tab in AIditor, follow [aiditor-settings-guide.md](aiditor-settings-guide.md) — do not fold settings discovery into add-menu YAML.
|
|
111
|
+
|
|
112
|
+
## Full reference
|
|
113
|
+
|
|
114
|
+
See `agent-kit/plugin/aiditor-add-menu.md` (installed by `jay-stack setup aiditor`) for the full Add Menu contributor guide including validation rules, browse packing, and surface-specific behavior.
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# AIditor Project Settings — Plugin Contributor Guide
|
|
2
|
+
|
|
3
|
+
**Audience:** Plugin authors and AI agents adding a **Project settings** tab to a Jay Stack plugin.
|
|
4
|
+
|
|
5
|
+
**Related guides:** [setup-guide.md](setup-guide.md) (agent-kit handler), [plugin-routes.md](plugin-routes.md) (`devOnly` routes), [add-menu-guide.md](add-menu-guide.md) (Add Menu — orthogonal surface). After `jay-stack setup aiditor`, see also `agent-kit/plugin/aiditor-add-menu.md` for AIditor runtime behavior (iframe, postMessage).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is Project settings?
|
|
10
|
+
|
|
11
|
+
AIditor **Project settings** shows one tab per **installed** plugin that has a materialized discovery file under `agent-kit/aiditor/settings/`. Each tab embeds the plugin's settings **route** in an iframe (`?_jay_embed=true`).
|
|
12
|
+
|
|
13
|
+
This is separate from:
|
|
14
|
+
|
|
15
|
+
| Surface | Purpose | Plugin output |
|
|
16
|
+
| -------------------- | ------------------------------------------------ | ---------------------------------------------------- |
|
|
17
|
+
| **Add Menu** | Attach agent context to a change request | `agent-kit/aiditor/add-menu/*.yaml` |
|
|
18
|
+
| **Project settings** | Configure the project; run backend ops from a UI | `agent-kit/aiditor/settings/*.yaml` + dev-only route |
|
|
19
|
+
| **Headless on page** | Site runtime | contracts + components |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Contributor checklist
|
|
24
|
+
|
|
25
|
+
Follow these steps in order. Skipping a step is the most common reason a tab never appears.
|
|
26
|
+
|
|
27
|
+
1. **Ship template in the npm package** at `agent-kit/aiditor/settings.template.yaml` (exact path — validated by `jay-stack validate-plugin`).
|
|
28
|
+
2. **List `agent-kit/` in `package.json` `files`** so the template is included in the published npm tarball and available under `node_modules` after install.
|
|
29
|
+
3. **Declare `agentkit` in `plugin.yaml`** and materialize the template in the agent-kit handler to `agent-kit/aiditor/settings/<plugin-name>.yaml` in the **project** root (not inside the package).
|
|
30
|
+
4. **Declare a matching route** in `plugin.yaml` `routes[]` with **`devOnly: true`** (settings UIs are dev-server tooling).
|
|
31
|
+
5. **Implement the settings page** — `lib/pages/settings/page.jay-html` + page component; use plugin **actions** or **jay-commands** for mutations (never arbitrary shell).
|
|
32
|
+
6. **Run `jay-stack agent-kit`** in the consuming project and confirm the YAML file exists.
|
|
33
|
+
7. **Run `jay-stack validate-plugin`** — fix errors; heed warnings for missing `devOnly` or route mismatch.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Package layout
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
my-plugin/
|
|
41
|
+
├── agent-kit/
|
|
42
|
+
│ └── aiditor/
|
|
43
|
+
│ └── settings.template.yaml # shipped in package — source for copy/generate
|
|
44
|
+
├── lib/
|
|
45
|
+
│ ├── aiditor/
|
|
46
|
+
│ │ └── write-settings-contribution.ts # materialization helper
|
|
47
|
+
│ ├── pages/
|
|
48
|
+
│ │ └── settings/
|
|
49
|
+
│ │ ├── page.jay-html
|
|
50
|
+
│ │ └── page.ts
|
|
51
|
+
│ └── agentkit.ts # calls materialize + other agent-kit work
|
|
52
|
+
├── plugin.yaml
|
|
53
|
+
└── package.json # "files": [..., "agent-kit"]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Materialized output (project only, gitignored or committed per team policy):**
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
<project-root>/agent-kit/aiditor/settings/my-plugin.yaml
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use `<plugin>.generated.yaml` only for fixture/dogfood plugins that intentionally differ from the shipped template name.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Settings template schema
|
|
67
|
+
|
|
68
|
+
```yaml
|
|
69
|
+
# agent-kit/aiditor/settings.template.yaml
|
|
70
|
+
label: Media Manager # required — tab title in Project settings (text only in v1)
|
|
71
|
+
route: /my-plugin/settings # required — must match plugin.yaml routes[].path
|
|
72
|
+
pluginName: my-plugin # optional — defaults from output filename (my-plugin.yaml)
|
|
73
|
+
requires: # optional — tab blocked until dependency setup succeeds
|
|
74
|
+
- plugin: wix-server-client
|
|
75
|
+
status: configured # only "configured" is valid in v1
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Validate locally with types from `@jay-framework/plugin-validator`:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { validateAiditorSettingsFile } from '@jay-framework/plugin-validator';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## plugin.yaml route
|
|
87
|
+
|
|
88
|
+
Settings pages are **[dev-only plugin routes](plugin-routes.md#dev-only-routes)**. They are served on the dev server, hidden from page-navigation pickers that filter `devOnly`, and loaded by AIditor via explicit route URL.
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
name: my-plugin
|
|
92
|
+
agentkit: generateMyAgentKit
|
|
93
|
+
|
|
94
|
+
routes:
|
|
95
|
+
- path: /my-plugin/settings
|
|
96
|
+
jayHtml: ./lib/pages/settings/page.jay-html
|
|
97
|
+
component: myPluginSettingsPage
|
|
98
|
+
description: Project settings — configure my-plugin for this project
|
|
99
|
+
devOnly: true
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
See [plugin-routes.md](plugin-routes.md) for route authoring, project override precedence, and standalone URL behavior.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Materialize in the agent-kit handler
|
|
107
|
+
|
|
108
|
+
**Do not** write settings YAML in the `setup` handler. Settings discovery is regenerated on **`jay-stack agent-kit`**, same as Add Menu catalogs.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import type {
|
|
112
|
+
PluginAgentKitContext,
|
|
113
|
+
PluginAgentKitResult,
|
|
114
|
+
} from '@jay-framework/stack-server-runtime';
|
|
115
|
+
import { materializeMyPluginAiditorSettings } from './aiditor/write-settings-contribution.js';
|
|
116
|
+
|
|
117
|
+
export async function generateMyAgentKit(
|
|
118
|
+
ctx: PluginAgentKitContext,
|
|
119
|
+
): Promise<PluginAgentKitResult> {
|
|
120
|
+
const created: string[] = [];
|
|
121
|
+
|
|
122
|
+
const settingsPath = materializeMyPluginAiditorSettings(ctx.projectRoot, ctx.force);
|
|
123
|
+
if (settingsPath) created.push(settingsPath);
|
|
124
|
+
|
|
125
|
+
// ... add-menu, references, etc.
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
agentKitCreated: created,
|
|
129
|
+
message: created.length ? `Wrote ${created.join(', ')}` : 'Up to date',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Static copy vs generated YAML
|
|
135
|
+
|
|
136
|
+
| Case | Pattern |
|
|
137
|
+
| --------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
138
|
+
| Fixed label + route | Copy `settings.template.yaml` → `settings/<plugin>.yaml` |
|
|
139
|
+
| Label/route depends on live data | Build YAML object in handler; write with `yaml.stringify` |
|
|
140
|
+
| Add Menu rebuild from settings UI | Write `add-menu/<plugin>.generated.yaml` only — never overwrite hand-authored `add-menu/<plugin>.yaml` |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Resolving the packaged template path (required)
|
|
145
|
+
|
|
146
|
+
Agent-kit handlers run from **bundled** `dist/index.js` in published packages. A fixed `path.join(__dirname, '..')` hop count **breaks** when the module lives under `dist/` vs `lib/` (Vitest) vs nested bundles.
|
|
147
|
+
|
|
148
|
+
**Use a walk-up resolver** until `agent-kit/aiditor/settings.template.yaml` exists under a parent directory:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import * as fs from 'node:fs';
|
|
152
|
+
import * as path from 'node:path';
|
|
153
|
+
import { fileURLToPath } from 'node:url';
|
|
154
|
+
|
|
155
|
+
export const AIDITOR_SETTINGS_OUTPUT_REL = 'agent-kit/aiditor/settings/my-plugin.yaml';
|
|
156
|
+
const SETTINGS_TEMPLATE_REL = 'agent-kit/aiditor/settings.template.yaml';
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Resolve a file shipped inside the plugin package (agent-kit templates, etc.).
|
|
160
|
+
* Works from dist/index.js (production) and lib/aiditor/*.ts (Vitest).
|
|
161
|
+
*/
|
|
162
|
+
export function resolvePackagedAgentKitPath(
|
|
163
|
+
relativePath: string,
|
|
164
|
+
moduleUrl: string = import.meta.url,
|
|
165
|
+
): string | null {
|
|
166
|
+
let directory = path.dirname(fileURLToPath(moduleUrl));
|
|
167
|
+
for (let depth = 0; depth < 4; depth++) {
|
|
168
|
+
const candidate = path.join(directory, relativePath);
|
|
169
|
+
if (fs.existsSync(candidate)) {
|
|
170
|
+
return candidate;
|
|
171
|
+
}
|
|
172
|
+
const parent = path.dirname(directory);
|
|
173
|
+
if (parent === directory) break;
|
|
174
|
+
directory = parent;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function writeAiditorSettingsContribution(
|
|
180
|
+
projectRoot: string,
|
|
181
|
+
templatePath: string,
|
|
182
|
+
force = false,
|
|
183
|
+
): string | null {
|
|
184
|
+
const outputPath = path.join(projectRoot, AIDITOR_SETTINGS_OUTPUT_REL);
|
|
185
|
+
if (fs.existsSync(outputPath) && !force) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
189
|
+
fs.copyFileSync(templatePath, outputPath);
|
|
190
|
+
return AIDITOR_SETTINGS_OUTPUT_REL;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function materializeMyPluginAiditorSettings(
|
|
194
|
+
projectRoot: string,
|
|
195
|
+
force = false,
|
|
196
|
+
): string | null {
|
|
197
|
+
const templatePath = resolvePackagedAgentKitPath(SETTINGS_TEMPLATE_REL);
|
|
198
|
+
if (!templatePath) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
return writeAiditorSettingsContribution(projectRoot, templatePath, force);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Common mistakes
|
|
206
|
+
|
|
207
|
+
| Mistake | Symptom |
|
|
208
|
+
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
209
|
+
| `path.join(dirname(import.meta.url), '..', '..')` from bundled code | Walks to `node_modules/@jay-framework/` — template not found, **no settings YAML** |
|
|
210
|
+
| **No client bundle** (`index.client.ts` + `vite build` without `--ssr`) | Settings iframe SSR works; Vite errors on hydrate — `Failed to resolve import .../dist/index.client.js` |
|
|
211
|
+
| Writing YAML inside the package instead of `ctx.projectRoot` | Tab missing in consumer project |
|
|
212
|
+
| Route in template ≠ `plugin.yaml` `routes[].path` | `validate-plugin` warning `settings-route-missing`; iframe 404 |
|
|
213
|
+
| Missing `devOnly: true` | `settings-route-dev-only` warning; route may appear in page pickers |
|
|
214
|
+
| Template present but no `agentkit` handler | `settings-missing-agentkit-handler` warning |
|
|
215
|
+
| `agent-kit/` not in `package.json` `files` | Template missing after `yarn add` |
|
|
216
|
+
|
|
217
|
+
**Reference implementations:**
|
|
218
|
+
|
|
219
|
+
- `@jay-framework/design-system-validator` — `lib/aiditor/write-settings-contribution.ts` (walk-up resolver)
|
|
220
|
+
- `@jay-framework/wix-media` — same pattern (prefer walk-up over single `..` from `dist/`)
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Settings page responsibilities
|
|
225
|
+
|
|
226
|
+
The embedded settings route should:
|
|
227
|
+
|
|
228
|
+
1. **About / onboarding** — what the plugin does, which `config/` files matter, links to agent-kit docs.
|
|
229
|
+
2. **Run backend work** via plugin **actions** (`makeJayAction`) or **`jay-stack run <plugin>/<command>`** — not `child_process` shell.
|
|
230
|
+
3. **Write project-owned generated files only** — e.g. `agent-kit/aiditor/add-menu/<plugin>.generated.yaml`, reference data under `agent-kit/references/`.
|
|
231
|
+
4. **Never collect API keys or OAuth secrets** in settings forms — credentials belong in `setup` → `config/`.
|
|
232
|
+
|
|
233
|
+
### Notify AIditor when Add Menu catalog changes
|
|
234
|
+
|
|
235
|
+
After regenerating add-menu YAML from settings:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
window.parent.postMessage({ type: 'aiditor:addMenuCatalogChanged' }, window.location.origin);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Optional — submit an agent task (explicit user click only)
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
window.parent.postMessage(
|
|
245
|
+
{
|
|
246
|
+
type: 'aiditor:submitAgentTask',
|
|
247
|
+
prompt: '…',
|
|
248
|
+
context: { pageRoute: '/', renderedUrl: window.location.origin },
|
|
249
|
+
},
|
|
250
|
+
window.location.origin,
|
|
251
|
+
);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Full iframe and discovery behavior: `agent-kit/plugin/aiditor-add-menu.md` (installed by `jay-stack setup aiditor`).
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Validation (`jay-stack validate-plugin`)
|
|
259
|
+
|
|
260
|
+
When `agent-kit/aiditor/settings.template.yaml` exists, the validator:
|
|
261
|
+
|
|
262
|
+
- Parses schema (`label`, `route`, optional `requires`, `pluginName`)
|
|
263
|
+
- Warns if `route` is not in `plugin.yaml` `routes[]`
|
|
264
|
+
- Warns if matching route lacks `devOnly: true`
|
|
265
|
+
- Warns if template exists but `agentkit` is not declared
|
|
266
|
+
|
|
267
|
+
Fix all **errors** before publish; treat **warnings** as required for AIditor-facing plugins.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Verification
|
|
272
|
+
|
|
273
|
+
In a project that depends on your plugin:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
jay-stack agent-kit
|
|
277
|
+
ls agent-kit/aiditor/settings/my-plugin.yaml # must exist
|
|
278
|
+
jay-stack validate-plugin /path/to/my-plugin # or from package root
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
In AIditor: open **Project settings** — tab label matches `label`; iframe loads `route` with `?_jay_embed=true`. If `requires` is set, tab stays blocked until dependency `setup` reports `configured`.
|
|
282
|
+
|
|
283
|
+
**Dogfood fixture:** `jay-stack setup aiditor` on a starter project with the plugin-settings-fixture local plugin (see aiditor package examples).
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## AI agent quick reference
|
|
288
|
+
|
|
289
|
+
When asked to "add Project settings for plugin X":
|
|
290
|
+
|
|
291
|
+
1. Read this file and `plugin-routes.md` (`devOnly`).
|
|
292
|
+
2. Add `agent-kit/aiditor/settings.template.yaml` + ensure `package.json` ships `agent-kit/`.
|
|
293
|
+
3. Add `lib/aiditor/write-settings-contribution.ts` with **`resolvePackagedAgentKitPath`** — do not hard-code `..` depth.
|
|
294
|
+
4. Wire materialization into existing `agentkit` handler; return path in `agentKitCreated`.
|
|
295
|
+
5. Add `routes[]` entry with `devOnly: true` and implement settings page.
|
|
296
|
+
6. Do **not** duplicate Add Menu schema here — use [add-menu-guide.md](add-menu-guide.md) for catalog items.
|
|
@@ -135,3 +135,5 @@ The parent constructs the frozen page URL:
|
|
|
135
135
|
route + '?_jay_freeze=' + id // full page
|
|
136
136
|
route + '?_jay_freeze=' + id + '&format=fragment' // shadow DOM fragment
|
|
137
137
|
```
|
|
138
|
+
|
|
139
|
+
See also **Dev-only routes** in `plugin-routes.md` — settings pages loaded in AIditor Project settings use `_jay_embed` but are not blocked from direct URL access.
|
|
@@ -45,6 +45,8 @@ A plugin route is a **headless component + jay-html template + route path**. It
|
|
|
45
45
|
</html>
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
**Jay-html expression rules** — plugin route templates use the same binding syntax as project pages. `if` and `{…}` resolve **tag names only**; no `.length`, method calls, or bracket indexing. For empty lists, expose `hasItems: boolean` or `itemCount: number` in ViewState / the inline `application/jay-data` block. See [jay-html-template-syntax.md](../designer/jay-html-template-syntax.md#expression-limits-important).
|
|
49
|
+
|
|
48
50
|
### 2. Create the page component
|
|
49
51
|
|
|
50
52
|
```typescript
|
|
@@ -144,3 +146,50 @@ Each plugin should choose a recognizable route prefix to avoid collisions:
|
|
|
144
146
|
- `/cms/...` — content management
|
|
145
147
|
|
|
146
148
|
There is no enforced convention — just pick a prefix that's unique and descriptive.
|
|
149
|
+
|
|
150
|
+
## Dev-only routes
|
|
151
|
+
|
|
152
|
+
Some plugin pages are **dev-server tooling** — internal dashboards, QA fixtures, builder settings UIs. Mark them with `devOnly: true` so consumers of `listRoutes()` can distinguish them from public site pages. Production builds do not yet exclude `devOnly` routes — that is planned for a future framework release.
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
routes:
|
|
156
|
+
- path: /my-plugin/admin
|
|
157
|
+
jayHtml: ./lib/pages/admin/page.jay-html
|
|
158
|
+
component: adminPage
|
|
159
|
+
devOnly: true
|
|
160
|
+
description: Dev-server admin UI
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### What `devOnly` does (framework)
|
|
164
|
+
|
|
165
|
+
| Concern | Behavior |
|
|
166
|
+
| ------------------------------ | -------------------------------------------------------------------- |
|
|
167
|
+
| Dev server HTTP | **Served normally** — direct URL works |
|
|
168
|
+
| `listRoutes()` / `RouteInfo` | Includes route with `devOnly: true` |
|
|
169
|
+
| Page navigation UIs | **Consumer choice** — tools may filter `devOnly` routes from pickers |
|
|
170
|
+
| Routes loaded by explicit path | **Unaffected** — embed/host tools pass a known route URL |
|
|
171
|
+
| Production build | **Deferred** — future task excludes dev-only routes |
|
|
172
|
+
|
|
173
|
+
### Standalone access
|
|
174
|
+
|
|
175
|
+
Dev-only pages remain reachable at their URL on the dev server (new browser tab, bookmark). **This is intentional** — useful for debugging and optional standalone experiences.
|
|
176
|
+
|
|
177
|
+
Plugin authors decide how to handle visitors who open the URL outside an embedding host:
|
|
178
|
+
|
|
179
|
+
- **Redirect / gate** — explain the page is meant for a design tool
|
|
180
|
+
- **Standalone mode** — offer the same UI with appropriate copy
|
|
181
|
+
- **Hybrid** — embed in tool + "open in new tab" for power users
|
|
182
|
+
|
|
183
|
+
Example: detect iframe context (`?_jay_embed=true` or `window.parent !== window`) and adjust messaging.
|
|
184
|
+
|
|
185
|
+
### AIditor Project settings routes
|
|
186
|
+
|
|
187
|
+
Settings tabs embed a plugin route by URL. The usual pattern:
|
|
188
|
+
|
|
189
|
+
1. Ship `agent-kit/aiditor/settings.template.yaml` with `route` matching `routes[].path`
|
|
190
|
+
2. Materialize to `agent-kit/aiditor/settings/<plugin>.yaml` in the **project** via the `agentkit` handler
|
|
191
|
+
3. Set **`devOnly: true`** on that route entry
|
|
192
|
+
|
|
193
|
+
AIditor filters `devOnly` routes from the **Pages** dropdown but loads the settings iframe by explicit path — HTTP must remain available on the dev server.
|
|
194
|
+
|
|
195
|
+
Full contributor steps: [aiditor-settings-guide.md](aiditor-settings-guide.md). Runtime iframe protocol: `agent-kit/plugin/aiditor-add-menu.md` (after `jay-stack setup aiditor`).
|
|
@@ -254,27 +254,15 @@ export async function generateMyAgentKit(
|
|
|
254
254
|
| Generate data from live services (product catalogs, CMS schemas) | `agentkit` | Needs services initialized; refreshed on each agent-kit run |
|
|
255
255
|
| Validate credentials / API keys | `setup` | Part of initial project configuration |
|
|
256
256
|
| Write AIditor add-menu from project-specific data (DESIGN.md tokens) | `agentkit` | Data comes from project files at agent-kit time |
|
|
257
|
+
| Materialize AIditor Project settings tab discovery | `agentkit` | Copy/generate `agent-kit/aiditor/settings/<plugin>.yaml` |
|
|
257
258
|
|
|
258
259
|
## AIditor Add-Menu Items
|
|
259
260
|
|
|
260
|
-
|
|
261
|
+
See [add-menu-guide.md](add-menu-guide.md) for the complete add-menu item schema, interaction modes, browse sizes, presentation formats, and TypeScript types.
|
|
261
262
|
|
|
262
|
-
|
|
263
|
+
## AIditor Project Settings
|
|
263
264
|
|
|
264
|
-
|
|
265
|
-
items:
|
|
266
|
-
- id: my-plugin:feature-name # unique ID
|
|
267
|
-
title: Feature Name # shown in the add menu
|
|
268
|
-
category: My Plugin # grouping
|
|
269
|
-
subCategory: Components # sub-grouping
|
|
270
|
-
pluginName: my-plugin # optional: plugin attribution
|
|
271
|
-
packageName: '@my-org/my-plugin' # optional: npm package name
|
|
272
|
-
prompt: | # instructions for the AI agent
|
|
273
|
-
Use headless component @my-org/my-plugin / contract feature-name.
|
|
274
|
-
Read agent-kit/designer/feature-name.md for usage guide.
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
See `agent-kit/plugin/aiditor-add-menu.md` (installed by `jay-stack setup aiditor`) for the full contributor guide.
|
|
265
|
+
See [aiditor-settings-guide.md](aiditor-settings-guide.md) for the full checklist: `settings.template.yaml` in the package, walk-up path resolution from bundled `dist/`, `devOnly` route in `plugin.yaml`, and settings page responsibilities (actions, postMessage, no secrets in forms).
|
|
278
266
|
|
|
279
267
|
## Exporting Handlers
|
|
280
268
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { LogLevel } from '@jay-framework/logger';
|
|
2
|
-
import { PublishMessage, PublishResponse, SaveImageMessage, SaveImageResponse, HasImageMessage, HasImageResponse, GetProjectInfoMessage, GetProjectInfoResponse, ExportMessage, ExportResponse, ImportMessage, ImportResponse, ProjectPage, Plugin } from '@jay-framework/editor-protocol';
|
|
3
2
|
export { MaterializeContractsOptions, MaterializeResult, PluginContractEntry, PluginsIndex, PluginsIndexEntry, listContracts, materializeContracts } from '@jay-framework/stack-server-runtime';
|
|
4
3
|
|
|
5
4
|
interface StartDevServerOptions {
|
|
6
5
|
projectPath?: string;
|
|
7
|
-
/** Enable test endpoints (/_jay/health, /_jay/shutdown) */
|
|
8
6
|
testMode?: boolean;
|
|
9
|
-
/** Auto-shutdown after N seconds */
|
|
10
7
|
timeout?: number;
|
|
11
|
-
/** Log level for output */
|
|
12
8
|
logLevel?: LogLevel;
|
|
13
9
|
}
|
|
14
10
|
declare function startDevServer(options?: StartDevServerOptions): Promise<void>;
|
|
@@ -21,92 +17,9 @@ interface JayConfig {
|
|
|
21
17
|
publicFolder?: string;
|
|
22
18
|
configBase?: string;
|
|
23
19
|
};
|
|
24
|
-
editorServer?: {
|
|
25
|
-
portRange?: [number, number];
|
|
26
|
-
editorId?: string;
|
|
27
|
-
};
|
|
28
20
|
}
|
|
29
21
|
declare function loadConfig(): JayConfig;
|
|
30
22
|
declare function getConfigWithDefaults(config: JayConfig): Required<JayConfig>;
|
|
31
23
|
declare function updateConfig(updates: Partial<JayConfig>): void;
|
|
32
24
|
|
|
33
|
-
|
|
34
|
-
onPublish: (params: PublishMessage) => Promise<PublishResponse>;
|
|
35
|
-
onSaveImage: (params: SaveImageMessage) => Promise<SaveImageResponse>;
|
|
36
|
-
onHasImage: (params: HasImageMessage) => Promise<HasImageResponse>;
|
|
37
|
-
onGetProjectInfo: (params: GetProjectInfoMessage) => Promise<GetProjectInfoResponse>;
|
|
38
|
-
onExport: <TVendorDoc>(params: ExportMessage<TVendorDoc>) => Promise<ExportResponse>;
|
|
39
|
-
onImport: <TVendorDoc_1>(params: ImportMessage<TVendorDoc_1>) => Promise<ImportResponse<TVendorDoc_1>>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Vendor Interface
|
|
44
|
-
*
|
|
45
|
-
* Each vendor (e.g., Figma, Sketch, Adobe XD) implements this interface
|
|
46
|
-
* to provide conversion from their native format to Jay HTML format.
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Result of vendor conversion containing body HTML, fonts, and contract data
|
|
51
|
-
*/
|
|
52
|
-
interface VendorConversionResult {
|
|
53
|
-
/**
|
|
54
|
-
* The body HTML content (without <html>, <head>, or <body> tags)
|
|
55
|
-
*/
|
|
56
|
-
bodyHtml: string;
|
|
57
|
-
/**
|
|
58
|
-
* Set of font family names used in the document
|
|
59
|
-
*/
|
|
60
|
-
fontFamilies: Set<string>;
|
|
61
|
-
/**
|
|
62
|
-
* Optional contract data for the page
|
|
63
|
-
* If provided, will be used to generate the jay-data script tag
|
|
64
|
-
*/
|
|
65
|
-
contractData?: {
|
|
66
|
-
/**
|
|
67
|
-
* Contract name
|
|
68
|
-
*/
|
|
69
|
-
name: string;
|
|
70
|
-
/**
|
|
71
|
-
* Contract tags in YAML format
|
|
72
|
-
*/
|
|
73
|
-
tagsYaml: string;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
interface Vendor<TVendorDoc = any> {
|
|
77
|
-
/**
|
|
78
|
-
* The unique identifier for this vendor (e.g., 'figma', 'sketch', 'xd')
|
|
79
|
-
*/
|
|
80
|
-
vendorId: string;
|
|
81
|
-
/**
|
|
82
|
-
* Convert vendor document to body HTML with metadata
|
|
83
|
-
*
|
|
84
|
-
* @param vendorDoc - The vendor's native document format (e.g., Figma SectionNode)
|
|
85
|
-
* @param pageUrl - The page URL/route (e.g., '/home', '/products')
|
|
86
|
-
* @returns Conversion result with body HTML, fonts, and contract data
|
|
87
|
-
*/
|
|
88
|
-
convertToBodyHtml(vendorDoc: TVendorDoc, pageUrl: string, projectPage: ProjectPage, plugins: Plugin[]): Promise<VendorConversionResult>;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Get a vendor by ID
|
|
93
|
-
*
|
|
94
|
-
* @param vendorId - The vendor ID
|
|
95
|
-
* @returns The vendor or undefined if not found
|
|
96
|
-
*/
|
|
97
|
-
declare function getVendor(vendorId: string): Vendor | undefined;
|
|
98
|
-
/**
|
|
99
|
-
* Check if a vendor exists
|
|
100
|
-
*
|
|
101
|
-
* @param vendorId - The vendor ID
|
|
102
|
-
* @returns True if vendor exists
|
|
103
|
-
*/
|
|
104
|
-
declare function hasVendor(vendorId: string): boolean;
|
|
105
|
-
/**
|
|
106
|
-
* Get all registered vendor IDs
|
|
107
|
-
*
|
|
108
|
-
* @returns Array of vendor IDs
|
|
109
|
-
*/
|
|
110
|
-
declare function getRegisteredVendors(): string[];
|
|
111
|
-
|
|
112
|
-
export { type JayConfig, type StartDevServerOptions, type Vendor, createEditorHandlers, getConfigWithDefaults, getRegisteredVendors, getVendor, hasVendor, loadConfig, startDevServer, updateConfig };
|
|
25
|
+
export { type JayConfig, type StartDevServerOptions, getConfigWithDefaults, loadConfig, startDevServer, updateConfig };
|