@jay-framework/jay-stack-cli 0.25.4 → 0.26.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.
@@ -0,0 +1,70 @@
1
+ # Source Editing — Plugin Contributor Guide
2
+
3
+ **Audience:** Plugin authors (and AI agents) making a plugin's contracts **editable at the source** (DL#219).
4
+
5
+ **Related:** [actions-guide.md](actions-guide.md) (`devOnly` actions), [plugin-routes.md](plugin-routes.md)
6
+ (`devOnly` routes), and the devops **source-editing** guide (the inspector protocol the AIditor uses).
7
+
8
+ ---
9
+
10
+ ## Why
11
+
12
+ When a page binds content to your contract — e.g. `<h1>{productPage.productName}</h1>` — the source-editing
13
+ inspector resolves that pixel to the contract, but it can't know **how** your data is edited: which record,
14
+ what the write path is, or where an editor UI lives. Only your plugin knows. So each contract declares its
15
+ **editing story**, and `jay-stack validate` warns when one is missing.
16
+
17
+ ## Declare the editing story (required for coverage)
18
+
19
+ In `plugin.yaml`, each contract declares **one** of:
20
+
21
+ ```yaml
22
+ contracts:
23
+ - name: product-page
24
+ contract: ./product-page.jay-contract
25
+ component: productPage
26
+ editingGuide: ./editing/product-page.md # how an agent edits this contract's bound data
27
+ - name: stock-badge
28
+ contract: ./stock-badge.jay-contract
29
+ component: stockBadge
30
+ readonly: true # this contract's data isn't editable in place
31
+ ```
32
+
33
+ - **`editingGuide`** — relative path to a markdown guide shipped by the plugin.
34
+ - **`readonly: true`** — the contract's data is derived/not editable in place (e.g. a computed badge).
35
+
36
+ `jay-stack validate` emits a `source-editing-coverage` warning for any contract that declares neither (and
37
+ checks the `editingGuide` file exists).
38
+
39
+ ## What the editing guide contains
40
+
41
+ The guide is the **single entry point** an agent follows to edit content bound to your contract. It should tell
42
+ the agent what to do with the identity the inspector provides:
43
+
44
+ - The inspector's `stack` gives the **record identity** — a `forEach` frame's `itemId` (trackBy), a `region`
45
+ frame's static `props`, plus the page's route params (`route`/`routePattern`).
46
+ - From that, instruct the agent to either:
47
+ - **Write the source** — call a `devOnly` action that persists the change (see actions-guide.md), or
48
+ - **Open an editor** — call a `devOnly` action that returns a URL and open it, or
49
+ - offer **several options** and let the agent choose.
50
+
51
+ Action names are ordinary (nothing is reserved). Example mapping for a stores plugin:
52
+
53
+ | Contract | Record key (from inspect result) | Guide instructs |
54
+ | ---------------- | -------------------------------- | ----------------------------------------- |
55
+ | `product-page` | `slug` (route param) | `getEditUrl(slug)` → fetch slug→productId |
56
+ | `product-search` | `productId` (`forEach` `itemId`) | `getEditUrl(productId)` |
57
+
58
+ ## Discovery
59
+
60
+ `plugin.yaml` is the source of truth: an agent that resolves a region to your contract reads `editingGuide`
61
+ from the plugin's `plugin.yaml` and then reads the guide file. Keep the guide concise and imperative — it is
62
+ read by an agent at edit time. (Surfacing `editingGuide` into `agent-kit/plugins-index.yaml` alongside the
63
+ contract entry, so it's one hop from the index, is a planned enhancement.)
64
+
65
+ ## Checklist
66
+
67
+ 1. Add `editingGuide:` (or `readonly: true`) to each contract in `plugin.yaml`.
68
+ 2. Write the guide at that path — the decision rule above: identity → write action / URL action.
69
+ 3. Expose the write/URL path as a `devOnly` action (actions-guide.md).
70
+ 4. Run `jay-stack validate` — resolve any `source-editing-coverage` warnings.
@@ -251,3 +251,39 @@ export const validate: JayHtmlValidatorFn = (ctx) => {
251
251
  return findings;
252
252
  };
253
253
  ```
254
+
255
+ ## Project-Level Validators (DL#232)
256
+
257
+ A per-file validator sees one jay-html file at a time. A **project-level validator** runs **once per
258
+ project** — for concerns that are not a single file: a config file, a `.well-known` file, a policy
259
+ file, cross-file consistency. Declare them under `projectValidators` (same `./tools` handler rules as
260
+ `validators`):
261
+
262
+ ```yaml
263
+ projectValidators:
264
+ - name: seo-site
265
+ handler: validateProject # export name from the ./tools entry
266
+ description: robots.txt, site identity, and ARD checks
267
+ ```
268
+
269
+ The handler receives only `{ projectRoot }` (and the plugin's own `settings`) — **not** parsed config
270
+ or parsed jay-html. A validator that needs `.jay` config reads it itself via `projectRoot`:
271
+
272
+ ```typescript
273
+ import type { ProjectValidatorFn, ProjectValidationFinding } from '@jay-framework/compiler-shared';
274
+
275
+ export const validateProject: ProjectValidatorFn = async (ctx) => {
276
+ const findings: ProjectValidationFinding[] = [];
277
+ // ctx.projectRoot — absolute project root path
278
+ // ctx.settings — the plugin's own settings (optional)
279
+ return findings;
280
+ };
281
+ ```
282
+
283
+ Each `ProjectValidationFinding` has `severity` (`'error'` | `'warning'`), `file` (project-relative,
284
+ or `.jay`), `message`, and optional `suggestion`. Project validators run **after** the per-file pass
285
+ and are **skipped under `--compile-only`**. Findings surface with `source: plugin:<plugin>/<name>`.
286
+
287
+ Built-in example: `@jay-framework/seo-validator` ships a `seo-site` project validator (robots.txt,
288
+ `site.baseUrl`, `site.name`, and ARD `/.well-known/ard.json`) — these moved out of core `validate`
289
+ into the plugin via this hook (DL#232), so a project only gets them when it installs seo-validator.
package/dist/index.d.ts CHANGED
@@ -25,6 +25,20 @@ interface JayConfig {
25
25
  componentsBase?: string;
26
26
  publicFolder?: string;
27
27
  configBase?: string;
28
+ /**
29
+ * Hosts the dev server's Vite host-check accepts, beyond localhost. Use Vite's host-suffix
30
+ * syntax (`.example.dev` matches any subdomain), or `true` to disable the check entirely
31
+ * (dev only — e.g. cloud preview sandboxes). Merged with the
32
+ * `__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS` env var. Absent → Vite's localhost-only default.
33
+ * (DL#220)
34
+ */
35
+ allowedHosts?: string[] | true;
36
+ /**
37
+ * Inject source-editing dev markers (`jay-dev-src` / `jay-dev-item`) so the source-editing
38
+ * inspector can map a rendered pixel back to its jay-html source (DL#219). Off by default —
39
+ * the markers change rendered output, so enable only for AIditor / source-editing sessions.
40
+ */
41
+ sourceEditing?: boolean;
28
42
  };
29
43
  site?: {
30
44
  baseUrl?: string;