@jay-framework/jay-stack-cli 0.21.0 → 0.22.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/cli-commands.md +11 -13
- package/agent-kit-template/designer/routing.md +19 -7
- package/agent-kit-template/developer/cli-commands.md +17 -11
- package/agent-kit-template/developer/routing.md +19 -7
- package/agent-kit-template/devops/INSTRUCTIONS.md +50 -0
- package/agent-kit-template/plugin/INSTRUCTIONS.md +4 -4
- package/agent-kit-template/plugin/plugin-structure.md +9 -12
- package/agent-kit-template/plugin/setup-guide.md +171 -58
- package/dist/index.js +952 -73
- package/package.json +12 -11
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
# CLI Commands Reference
|
|
2
2
|
|
|
3
|
-
## jay-stack setup
|
|
3
|
+
## jay-stack-cli setup
|
|
4
4
|
|
|
5
|
-
Run plugin setup. Plugins
|
|
5
|
+
Run plugin setup. Plugins create configuration files, prompt for credentials, and validate services.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
# Run setup for all installed plugins
|
|
9
|
-
jay-stack setup
|
|
8
|
+
# Run setup for all installed plugins (interactive — may prompt for input)
|
|
9
|
+
jay-stack-cli setup
|
|
10
10
|
|
|
11
11
|
# Run setup for a specific plugin
|
|
12
|
-
jay-stack setup wix-stores
|
|
12
|
+
jay-stack-cli setup wix-stores
|
|
13
13
|
|
|
14
14
|
# Re-run setup (e.g., after config change)
|
|
15
|
-
jay-stack setup
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Plugins declare their setup handler in `plugin.yaml`. Setup does two things:
|
|
15
|
+
jay-stack-cli setup --force
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
# Non-interactive mode (creates config templates without prompting)
|
|
18
|
+
jay-stack-cli setup --no-interactive
|
|
19
|
+
```
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
Setup is **interactive by default** — plugins may prompt for API keys and credentials. Use `--no-interactive` in CI/scripts.
|
|
24
22
|
|
|
25
|
-
Run this after installing new plugins, before `jay-stack agent-kit`.
|
|
23
|
+
Run this after installing new plugins, before `jay-stack-cli agent-kit`.
|
|
26
24
|
|
|
27
25
|
## jay-stack agent-kit
|
|
28
26
|
|
|
@@ -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
|
|
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
# CLI Commands Reference
|
|
2
2
|
|
|
3
|
-
## jay-stack setup
|
|
3
|
+
## jay-stack-cli setup
|
|
4
4
|
|
|
5
|
-
Run plugin setup. Plugins can create configuration files,
|
|
5
|
+
Run plugin setup. Plugins can create configuration files, prompt for credentials, and validate their prerequisites.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
# Run setup for all installed plugins
|
|
9
|
-
jay-stack setup
|
|
8
|
+
# Run setup for all installed plugins (interactive — may prompt for input)
|
|
9
|
+
jay-stack-cli setup
|
|
10
10
|
|
|
11
11
|
# Run setup for a specific plugin
|
|
12
|
-
jay-stack setup wix-stores
|
|
12
|
+
jay-stack-cli setup wix-stores
|
|
13
13
|
|
|
14
14
|
# Re-run setup (e.g., after config change)
|
|
15
|
-
jay-stack setup wix-data --force
|
|
15
|
+
jay-stack-cli setup wix-data --force
|
|
16
|
+
|
|
17
|
+
# Non-interactive mode (CI/scripts — creates config templates without prompting)
|
|
18
|
+
jay-stack-cli setup --no-interactive
|
|
16
19
|
```
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
Setup is **interactive by default** — plugins can prompt for API keys, credentials, and configuration choices. In non-interactive mode (`--no-interactive`), prompts are skipped and plugins create config templates with placeholders instead.
|
|
22
|
+
|
|
23
|
+
Plugins declare their setup handler in `plugin.yaml`. Setup does three things:
|
|
19
24
|
|
|
20
|
-
1. **Config templates**: Creates `config/<plugin>.yaml` with
|
|
21
|
-
2. **Credential
|
|
25
|
+
1. **Config templates**: Creates `config/<plugin>.yaml` with credentials (interactive) or placeholders (non-interactive)
|
|
26
|
+
2. **Credential prompts**: Asks for API keys and configuration when running interactively
|
|
27
|
+
3. **Service validation**: Attempts to initialize services, reports success or failure
|
|
22
28
|
|
|
23
|
-
Reference data (product catalogs, collection schemas) is generated by `jay-stack agent-kit`, not by setup.
|
|
29
|
+
Reference data (product catalogs, collection schemas) is generated by `jay-stack-cli agent-kit`, not by setup.
|
|
24
30
|
|
|
25
|
-
Run this after installing new plugins, before `jay-stack agent-kit`.
|
|
31
|
+
Run this after installing new plugins, before `jay-stack-cli agent-kit`.
|
|
26
32
|
|
|
27
33
|
## jay-stack agent-kit
|
|
28
34
|
|
|
@@ -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
|
|
|
@@ -14,6 +14,56 @@ The devops role handles the production lifecycle: building artifacts, configurin
|
|
|
14
14
|
4. **Invalidate** — rebuild specific pages when data changes
|
|
15
15
|
5. **Admin** — run plugin CLI commands via `jay-stack run <plugin>/<command>` (media upload, data sync, cache purge)
|
|
16
16
|
|
|
17
|
+
## Plugin Setup
|
|
18
|
+
|
|
19
|
+
Plugins may need credentials or configuration before they can run. The setup command handles this.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Default (non-interactive) — exits with structured output if input is needed
|
|
23
|
+
jay-stack-cli setup
|
|
24
|
+
|
|
25
|
+
# Interactive — prompts for credentials via terminal
|
|
26
|
+
jay-stack-cli setup --interactive
|
|
27
|
+
|
|
28
|
+
# With pre-provided answers (for automation)
|
|
29
|
+
jay-stack-cli setup --answers answers.yaml
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Automated setup (CI / agents)
|
|
33
|
+
|
|
34
|
+
When running `jay-stack-cli setup` without `--interactive`, plugins that need user input will exit with structured YAML output:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
setup-needs-answer:
|
|
38
|
+
plugin: wix-server-client
|
|
39
|
+
key: api-key
|
|
40
|
+
type: input
|
|
41
|
+
message: 'Enter your API key'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
To provide the answer, create a YAML file and re-run:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
# answers.yaml
|
|
48
|
+
api-key: 'IST.abc123...'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
jay-stack-cli setup --answers answers.yaml
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Repeat until all plugins report `configured`. The flow is iterative — each run may reveal the next question.
|
|
56
|
+
|
|
57
|
+
### Setup order
|
|
58
|
+
|
|
59
|
+
Run setup **before** agent-kit and build:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
jay-stack-cli setup # 1. Configure plugins
|
|
63
|
+
jay-stack-cli agent-kit # 2. Generate contracts and discovery data
|
|
64
|
+
jay-stack-cli build # 3. Production build
|
|
65
|
+
```
|
|
66
|
+
|
|
17
67
|
## Guides
|
|
18
68
|
|
|
19
69
|
| File | Topic |
|
|
@@ -13,8 +13,8 @@ A plugin provides headless components (data + interactions, no UI) that project
|
|
|
13
13
|
3. **Define actions** with `.jay-action` metadata
|
|
14
14
|
4. **Optionally add routes** — pages for admin tools and dashboards
|
|
15
15
|
5. **Optionally add validators** — custom jay-html validation rules
|
|
16
|
-
6. **Optionally add setup/
|
|
17
|
-
7. **Set up `plugin.yaml`** — list contracts, actions, services, contexts, routes, validators, setup
|
|
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
18
|
8. **Configure build** — dual entry points (server + client), vite.config.ts, package.json exports
|
|
19
19
|
9. **Validate** with `jay-stack validate-plugin`
|
|
20
20
|
|
|
@@ -25,8 +25,8 @@ The plugin participates in four CLI commands, each running different hooks:
|
|
|
25
25
|
| Command | When | What runs from your plugin |
|
|
26
26
|
| --------------------------- | ------------------ | ---------------------------------------------------------------------------------- |
|
|
27
27
|
| `jay-stack validate-plugin` | Plugin development | Checks plugin.yaml structure, contracts, exports, handler references |
|
|
28
|
-
| `jay-stack setup <plugin>` | Project setup | `setup
|
|
29
|
-
| `jay-stack agent-kit` | Before development | `
|
|
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
30
|
| `jay-stack validate` | During development | `validators[].handler` — runs your validation rules against project jay-html files |
|
|
31
31
|
|
|
32
32
|
**`validate-plugin`** validates YOUR plugin's structure. Run it during plugin development.
|
|
@@ -66,12 +66,9 @@ validators:
|
|
|
66
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
|
|
@@ -201,16 +198,16 @@ Commands are CLI operations run via `jay-stack run`. Use `makeCliCommand()` to c
|
|
|
201
198
|
|
|
202
199
|
Validators run during `jay-stack validate` against every parsed jay-html file in the project. See [validation.md](validation.md) for implementation details.
|
|
203
200
|
|
|
204
|
-
### Setup
|
|
201
|
+
### Setup and agent-kit fields
|
|
205
202
|
|
|
206
|
-
- `
|
|
207
|
-
- `
|
|
208
|
-
- `description` — (optional)
|
|
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
|
|
209
206
|
|
|
210
|
-
**NPM plugins:** `
|
|
207
|
+
**NPM plugins:** `setup` and `agentkit` are export names from the package entry point.
|
|
211
208
|
**Local plugins:** relative paths to the handler modules.
|
|
212
209
|
|
|
213
|
-
`jay-stack validate-plugin` checks that
|
|
210
|
+
`jay-stack validate-plugin` checks that declared handlers exist and are correctly exported.
|
|
214
211
|
|
|
215
212
|
See [setup-guide.md](setup-guide.md) for implementation details.
|
|
216
213
|
|
|
@@ -1,36 +1,40 @@
|
|
|
1
|
-
# Plugin Setup &
|
|
1
|
+
# Plugin Setup & Agent-Kit
|
|
2
2
|
|
|
3
3
|
Plugins can provide two hooks for project configuration and AI agent discovery:
|
|
4
4
|
|
|
5
|
-
- **Setup handler** — runs during `jay-stack setup <plugin>`. Creates config files, validates credentials
|
|
6
|
-
- **
|
|
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
7
|
|
|
8
8
|
## When Each Runs
|
|
9
9
|
|
|
10
10
|
```
|
|
11
|
-
jay-stack setup <plugin> → setup
|
|
12
|
-
jay-stack agent-kit →
|
|
11
|
+
jay-stack setup <plugin> → setup handler (config + credentials)
|
|
12
|
+
jay-stack agent-kit → agentkit handler (after contract materialization)
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
Setup runs
|
|
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
16
|
|
|
17
17
|
## Declaring in plugin.yaml
|
|
18
18
|
|
|
19
19
|
```yaml
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
24
|
```
|
|
25
25
|
|
|
26
|
-
**NPM plugins:**
|
|
27
|
-
**Local plugins:** relative paths to
|
|
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
28
|
|
|
29
|
-
`jay-stack validate-plugin` checks that
|
|
29
|
+
`jay-stack validate-plugin` checks that declared handlers exist and are correctly exported.
|
|
30
30
|
|
|
31
31
|
## Writing a Setup Handler
|
|
32
32
|
|
|
33
|
-
The setup handler creates config files and
|
|
33
|
+
The setup handler creates config files, validates services, and can prompt the user for credentials. 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
|
+
### Basic setup (non-interactive)
|
|
34
38
|
|
|
35
39
|
```typescript
|
|
36
40
|
import type { PluginSetupContext, PluginSetupResult } from '@jay-framework/stack-server-runtime';
|
|
@@ -43,13 +47,12 @@ export async function setupMyPlugin(ctx: PluginSetupContext): Promise<PluginSetu
|
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
const configCreated: string[] = [];
|
|
50
|
+
const configPath = path.join(ctx.configDir, '.my-plugin.yaml');
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
fs.writeFileSync(addMenuPath, templateContent, 'utf-8');
|
|
52
|
-
configCreated.push('agent-kit/aiditor/add-menu/my-plugin.yaml');
|
|
52
|
+
if (!fs.existsSync(configPath) || ctx.force) {
|
|
53
|
+
fs.mkdirSync(ctx.configDir, { recursive: true });
|
|
54
|
+
fs.writeFileSync(configPath, '# My Plugin config\napiKey: "<your-api-key>"\n', 'utf-8');
|
|
55
|
+
configCreated.push('config/.my-plugin.yaml');
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
return {
|
|
@@ -57,22 +60,130 @@ export async function setupMyPlugin(ctx: PluginSetupContext): Promise<PluginSetu
|
|
|
57
60
|
configCreated,
|
|
58
61
|
message:
|
|
59
62
|
configCreated.length > 0
|
|
60
|
-
? 'My Plugin
|
|
61
|
-
: 'My Plugin
|
|
63
|
+
? 'My Plugin config installed.'
|
|
64
|
+
: 'My Plugin config already present (use --force to rewrite).',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Interactive setup (with prompts)
|
|
70
|
+
|
|
71
|
+
When the setup handler needs user input (API keys, credentials, configuration choices), use `ctx.prompt`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
export async function setupMyPlugin(ctx: PluginSetupContext): Promise<PluginSetupResult> {
|
|
75
|
+
const configPath = path.join(ctx.configDir, '.my-plugin.yaml');
|
|
76
|
+
|
|
77
|
+
// Already configured — skip unless --force
|
|
78
|
+
if (fs.existsSync(configPath) && !ctx.force) {
|
|
79
|
+
return { status: 'configured', message: 'Already configured' };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// In non-interactive mode, create a template and ask the user to fill it in later
|
|
83
|
+
if (!ctx.interactive) {
|
|
84
|
+
fs.mkdirSync(ctx.configDir, { recursive: true });
|
|
85
|
+
fs.writeFileSync(configPath, 'apiKey: "<your-api-key>"\n', 'utf-8');
|
|
86
|
+
return {
|
|
87
|
+
status: 'needs-config',
|
|
88
|
+
configCreated: ['config/.my-plugin.yaml'],
|
|
89
|
+
message: 'Run `jay-stack-cli setup` interactively to enter your API key',
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Interactive mode — prompt the user
|
|
94
|
+
const apiKey = await ctx.prompt.input({
|
|
95
|
+
message: 'Enter your API key (create one at https://example.com/api-keys):',
|
|
96
|
+
validate: (v) => (v.trim() ? true : 'API key is required'),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const region = await ctx.prompt.select({
|
|
100
|
+
message: 'Select your region:',
|
|
101
|
+
choices: [
|
|
102
|
+
{ name: 'US East', value: 'us-east' },
|
|
103
|
+
{ name: 'EU West', value: 'eu-west' },
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
fs.mkdirSync(ctx.configDir, { recursive: true });
|
|
108
|
+
fs.writeFileSync(configPath, `apiKey: "${apiKey.trim()}"\nregion: ${region}\n`, 'utf-8');
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
status: 'configured',
|
|
112
|
+
configCreated: ['config/.my-plugin.yaml'],
|
|
113
|
+
message: 'Credentials configured successfully',
|
|
62
114
|
};
|
|
63
115
|
}
|
|
64
116
|
```
|
|
65
117
|
|
|
118
|
+
### Setup modes
|
|
119
|
+
|
|
120
|
+
Setup runs in three modes:
|
|
121
|
+
|
|
122
|
+
| Mode | Command | `ctx.interactive` | `ctx.prompt` behavior |
|
|
123
|
+
| ----------------------------- | ----------------------------------------- | ----------------- | ----------------------------------------------------- |
|
|
124
|
+
| **Default** (agents, CI) | `jay-stack-cli setup` | `false` | Throws `SetupNeedsAnswerError` with structured output |
|
|
125
|
+
| **Interactive** (humans) | `jay-stack-cli setup --interactive` | `true` | Prompts via terminal |
|
|
126
|
+
| **Answers file** (automation) | `jay-stack-cli setup --answers file.yaml` | `false` | Reads from file, throws if missing |
|
|
127
|
+
|
|
128
|
+
In default mode, when a prompt has no answer, the CLI exits with structured YAML telling the caller what's needed. Agents can then provide the answer via `--answers` and re-run.
|
|
129
|
+
|
|
130
|
+
### Idempotency requirement
|
|
131
|
+
|
|
132
|
+
Setup handlers **must be idempotent** — re-running with the same answers must produce the same result without side effects. This is critical because:
|
|
133
|
+
|
|
134
|
+
- Agents re-run setup iteratively as they provide answers one at a time
|
|
135
|
+
- Users re-run setup after fixing credentials
|
|
136
|
+
- CI pipelines may run setup on every deploy
|
|
137
|
+
|
|
138
|
+
**Rules:**
|
|
139
|
+
|
|
140
|
+
1. Check if config already exists before creating it — skip if present (unless `ctx.force`)
|
|
141
|
+
2. Check if credentials are already valid before prompting — skip if configured
|
|
142
|
+
3. Never append to files — write the complete content each time
|
|
143
|
+
4. Use `ctx.force` to allow explicit re-creation when the user asks for it
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
export async function setupMyPlugin(ctx: PluginSetupContext): Promise<PluginSetupResult> {
|
|
147
|
+
const configPath = path.join(ctx.configDir, '.my-plugin.yaml');
|
|
148
|
+
|
|
149
|
+
// Idempotent: skip if already configured (unless --force)
|
|
150
|
+
if (fs.existsSync(configPath) && !ctx.force) {
|
|
151
|
+
// Optionally validate the existing config
|
|
152
|
+
return { status: 'configured', message: 'Already configured' };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Prompt only when needed
|
|
156
|
+
const apiKey = await ctx.prompt.input({
|
|
157
|
+
key: 'api-key',
|
|
158
|
+
message: 'Enter your API key:',
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Write complete config (not append)
|
|
162
|
+
fs.writeFileSync(configPath, `apiKey: "${apiKey}"\n`);
|
|
163
|
+
return { status: 'configured', configCreated: ['config/.my-plugin.yaml'] };
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
66
167
|
### PluginSetupContext
|
|
67
168
|
|
|
68
|
-
| Field | Type
|
|
69
|
-
| ------------- |
|
|
70
|
-
| `pluginName` | `string`
|
|
71
|
-
| `projectRoot` | `string`
|
|
72
|
-
| `configDir` | `string`
|
|
73
|
-
| `services` | `Map`
|
|
74
|
-
| `initError` | `Error?`
|
|
75
|
-
| `force` | `boolean`
|
|
169
|
+
| Field | Type | Description |
|
|
170
|
+
| ------------- | ------------------- | ----------------------------------------------------------------- |
|
|
171
|
+
| `pluginName` | `string` | Plugin name from plugin.yaml |
|
|
172
|
+
| `projectRoot` | `string` | Absolute project root path |
|
|
173
|
+
| `configDir` | `string` | Config directory (from `.jay` configBase, defaults to `./config`) |
|
|
174
|
+
| `services` | `Map` | Registered services (may be empty if init failed) |
|
|
175
|
+
| `initError` | `Error?` | Present if plugin init failed — check this before using services |
|
|
176
|
+
| `force` | `boolean` | Whether `--force` flag was passed |
|
|
177
|
+
| `interactive` | `boolean` | Whether running in interactive mode (can prompt user) |
|
|
178
|
+
| `prompt` | `PluginSetupPrompt` | Prompt functions for user input (see below) |
|
|
179
|
+
|
|
180
|
+
### PluginSetupPrompt
|
|
181
|
+
|
|
182
|
+
| Method | Signature | Description |
|
|
183
|
+
| --------- | -------------------------------------------------- | ---------------------------------------------------------- |
|
|
184
|
+
| `input` | `(opts: { message, validate? }) → Promise<string>` | Text input. Non-interactive: returns `""` |
|
|
185
|
+
| `confirm` | `(opts: { message, default? }) → Promise<boolean>` | Yes/no. Non-interactive: returns `default` or `false` |
|
|
186
|
+
| `select` | `(opts: { message, choices }) → Promise<string>` | Single choice. Non-interactive: returns first choice value |
|
|
76
187
|
|
|
77
188
|
### PluginSetupResult
|
|
78
189
|
|
|
@@ -82,42 +193,42 @@ export async function setupMyPlugin(ctx: PluginSetupContext): Promise<PluginSetu
|
|
|
82
193
|
| `configCreated` | `string[]?` | Config files created (relative to project root) |
|
|
83
194
|
| `message` | `string?` | Human-readable status message |
|
|
84
195
|
|
|
85
|
-
## Writing
|
|
196
|
+
## Writing an Agent-Kit Handler
|
|
86
197
|
|
|
87
|
-
The
|
|
198
|
+
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.
|
|
88
199
|
|
|
89
200
|
```typescript
|
|
90
201
|
import type {
|
|
91
|
-
|
|
92
|
-
|
|
202
|
+
PluginAgentKitContext,
|
|
203
|
+
PluginAgentKitResult,
|
|
93
204
|
} from '@jay-framework/stack-server-runtime';
|
|
94
205
|
import fs from 'node:fs';
|
|
95
206
|
import path from 'node:path';
|
|
207
|
+
import yaml from 'yaml';
|
|
96
208
|
|
|
97
|
-
export async function
|
|
98
|
-
ctx:
|
|
99
|
-
): Promise<
|
|
209
|
+
export async function generateMyAgentKit(
|
|
210
|
+
ctx: PluginAgentKitContext,
|
|
211
|
+
): Promise<PluginAgentKitResult> {
|
|
100
212
|
if (ctx.initError) {
|
|
101
|
-
return {
|
|
213
|
+
return { agentKitCreated: [], message: `Skipped: ${ctx.initError.message}` };
|
|
102
214
|
}
|
|
103
215
|
|
|
104
|
-
// Example: generate add-menu items from live data
|
|
105
216
|
const outputPath = path.join(ctx.projectRoot, 'agent-kit/aiditor/add-menu/my-plugin.yaml');
|
|
106
217
|
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
107
218
|
|
|
108
219
|
const items = [
|
|
109
220
|
{ id: 'my-plugin:feature-1', title: 'Feature 1', category: 'My Plugin', prompt: '...' },
|
|
110
221
|
];
|
|
111
|
-
fs.writeFileSync(outputPath, yaml.
|
|
222
|
+
fs.writeFileSync(outputPath, yaml.stringify({ items }), 'utf-8');
|
|
112
223
|
|
|
113
224
|
return {
|
|
114
|
-
|
|
225
|
+
agentKitCreated: ['agent-kit/aiditor/add-menu/my-plugin.yaml'],
|
|
115
226
|
message: `Generated ${items.length} add-menu items`,
|
|
116
227
|
};
|
|
117
228
|
}
|
|
118
229
|
```
|
|
119
230
|
|
|
120
|
-
###
|
|
231
|
+
### PluginAgentKitContext
|
|
121
232
|
|
|
122
233
|
| Field | Type | Description |
|
|
123
234
|
| --------------- | --------- | --------------------------------------------------------------- |
|
|
@@ -128,25 +239,25 @@ export async function generateMyReferences(
|
|
|
128
239
|
| `initError` | `Error?` | Present if plugin init failed |
|
|
129
240
|
| `force` | `boolean` | Whether `--force` flag was passed |
|
|
130
241
|
|
|
131
|
-
###
|
|
242
|
+
### PluginAgentKitResult
|
|
132
243
|
|
|
133
|
-
| Field
|
|
134
|
-
|
|
|
135
|
-
| `
|
|
136
|
-
| `message`
|
|
244
|
+
| Field | Type | Description |
|
|
245
|
+
| ----------------- | ---------- | ---------------------------------------- |
|
|
246
|
+
| `agentKitCreated` | `string[]` | Files created (relative to project root) |
|
|
247
|
+
| `message` | `string?` | Human-readable status message |
|
|
137
248
|
|
|
138
|
-
## Setup vs
|
|
249
|
+
## Setup vs Agent-Kit — When to Use Which
|
|
139
250
|
|
|
140
|
-
| Use case |
|
|
141
|
-
| -------------------------------------------------------------------- |
|
|
142
|
-
| Copy static
|
|
143
|
-
| Generate data from live services (product catalogs, CMS schemas) | `
|
|
144
|
-
| Validate credentials / API keys | `setup
|
|
145
|
-
| Write AIditor add-menu from project-specific data (DESIGN.md tokens) | `
|
|
251
|
+
| Use case | Hook | Why |
|
|
252
|
+
| -------------------------------------------------------------------- | ---------- | ----------------------------------------------------------- |
|
|
253
|
+
| Copy static add-menu template, skills, thumbnails | `agentkit` | Discovery data — regenerated on `jay-stack agent-kit` |
|
|
254
|
+
| Generate data from live services (product catalogs, CMS schemas) | `agentkit` | Needs services initialized; refreshed on each agent-kit run |
|
|
255
|
+
| Validate credentials / API keys | `setup` | Part of initial project configuration |
|
|
256
|
+
| Write AIditor add-menu from project-specific data (DESIGN.md tokens) | `agentkit` | Data comes from project files at agent-kit time |
|
|
146
257
|
|
|
147
258
|
## AIditor Add-Menu Items
|
|
148
259
|
|
|
149
|
-
|
|
260
|
+
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.
|
|
150
261
|
|
|
151
262
|
Each item:
|
|
152
263
|
|
|
@@ -163,15 +274,17 @@ items:
|
|
|
163
274
|
Read agent-kit/designer/feature-name.md for usage guide.
|
|
164
275
|
```
|
|
165
276
|
|
|
277
|
+
See `agent-kit/plugin/aiditor-add-menu.md` (installed by `jay-stack setup aiditor`) for the full contributor guide.
|
|
278
|
+
|
|
166
279
|
## Exporting Handlers
|
|
167
280
|
|
|
168
|
-
For NPM plugins, export
|
|
281
|
+
For NPM plugins, export handlers from the package entry point:
|
|
169
282
|
|
|
170
283
|
```typescript
|
|
171
284
|
// lib/index.ts
|
|
172
285
|
export { setupMyPlugin } from './setup.js';
|
|
173
|
-
export {
|
|
286
|
+
export { generateMyAgentKit } from './agentkit.js';
|
|
174
287
|
// ... other exports (components, actions, services)
|
|
175
288
|
```
|
|
176
289
|
|
|
177
|
-
For local plugins, use relative paths in plugin.yaml
|
|
290
|
+
For local plugins, use relative paths in `plugin.yaml` and export `agentkit` or `default` from the handler module.
|