@anvilkit/contracts 0.1.18
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/LICENSE +21 -0
- package/dist/ai-section.cjs +18 -0
- package/dist/ai-section.d.cts +244 -0
- package/dist/ai-section.d.cts.map +1 -0
- package/dist/ai-section.d.ts +244 -0
- package/dist/ai-section.d.ts.map +1 -0
- package/dist/ai-section.js +1 -0
- package/dist/ai.cjs +18 -0
- package/dist/ai.d.cts +265 -0
- package/dist/ai.d.cts.map +1 -0
- package/dist/ai.d.ts +265 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +1 -0
- package/dist/assets.cjs +18 -0
- package/dist/assets.d.cts +32 -0
- package/dist/assets.d.cts.map +1 -0
- package/dist/assets.d.ts +32 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +1 -0
- package/dist/export.cjs +18 -0
- package/dist/export.d.cts +240 -0
- package/dist/export.d.cts.map +1 -0
- package/dist/export.d.ts +240 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +1 -0
- package/dist/index.cjs +18 -0
- package/dist/index.d.cts +45 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/ir.cjs +18 -0
- package/dist/ir.d.cts +269 -0
- package/dist/ir.d.cts.map +1 -0
- package/dist/ir.d.ts +269 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +1 -0
- package/dist/page.cjs +18 -0
- package/dist/page.d.cts +197 -0
- package/dist/page.d.cts.map +1 -0
- package/dist/page.d.ts +197 -0
- package/dist/page.d.ts.map +1 -0
- package/dist/page.js +1 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ancyloce
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.r = (exports1)=>{
|
|
5
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
6
|
+
value: 'Module'
|
|
7
|
+
});
|
|
8
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
9
|
+
value: true
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
})();
|
|
13
|
+
var __webpack_exports__ = {};
|
|
14
|
+
__webpack_require__.r(__webpack_exports__);
|
|
15
|
+
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
16
|
+
Object.defineProperty(exports, '__esModule', {
|
|
17
|
+
value: true
|
|
18
|
+
});
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Section-level AI editing contract — the types
|
|
3
|
+
* `@anvilkit/schema/section`, `@anvilkit/validator/section`, and the
|
|
4
|
+
* `regenerateSelection()` flow in `@anvilkit/plugin-ai-copilot` pass
|
|
5
|
+
* between each other when an author asks an LLM to rewrite a selected
|
|
6
|
+
* subtree of an existing page.
|
|
7
|
+
*
|
|
8
|
+
* Section-level AI is the Phase 6 / M9 sibling to Phase 3's whole-page
|
|
9
|
+
* AI flow ({@link AiGenerationContext} in `./ai.ts`). The page-level
|
|
10
|
+
* flow asks the LLM to emit a complete {@link PageIR}; the section-level
|
|
11
|
+
* flow asks it to emit a {@link AiSectionPatch} that atomically replaces
|
|
12
|
+
* just the selected nodes inside one Puck zone.
|
|
13
|
+
*
|
|
14
|
+
* ### Shape of the contract
|
|
15
|
+
*
|
|
16
|
+
* - {@link AiSectionSelection} is the editor's "what did the author
|
|
17
|
+
* click" payload. The plugin builds it from Puck's selection state +
|
|
18
|
+
* the surrounding zone metadata, then hands it to
|
|
19
|
+
* `configToAiSectionContext()`.
|
|
20
|
+
* - {@link AiSectionContext} is the LLM-shaped view of that selection —
|
|
21
|
+
* the available replacement components (already narrowed to whatever
|
|
22
|
+
* the zone allows), the current subtree snapshots, and optional
|
|
23
|
+
* environment hints. `@anvilkit/schema/section` owns the derivation;
|
|
24
|
+
* this package only owns the destination shape.
|
|
25
|
+
* - {@link AiSectionPatch} is the LLM's response shape. Validation
|
|
26
|
+
* lives in `@anvilkit/validator/section`; this package only owns
|
|
27
|
+
* the type.
|
|
28
|
+
*
|
|
29
|
+
* ### Design rules
|
|
30
|
+
*
|
|
31
|
+
* 1. **Types only.** No runtime code.
|
|
32
|
+
* 2. **Single-subtree per call.** Phase 6 ships a single contiguous
|
|
33
|
+
* subtree replacement per call. Batched multi-zone patches are
|
|
34
|
+
* deliberately out of scope — they would need a new contract and
|
|
35
|
+
* are reserved for `1.2` (plan §12 Q1).
|
|
36
|
+
* 3. **Round-trip safe with Phase 3 page-level AI.** The
|
|
37
|
+
* {@link AiSectionContext.availableComponents} reuses the
|
|
38
|
+
* {@link AiComponentSchema} shape so the validator can apply the
|
|
39
|
+
* same field-level rules at both granularities without forking.
|
|
40
|
+
*
|
|
41
|
+
* @see {@link https://github.com/anvilkit/studio/blob/main/docs/plans/phase-6-plan.md | Phase 6 plan §5.1 Section-level AI patch model}
|
|
42
|
+
*/
|
|
43
|
+
import type { AiComponentSchema, AiThemeHint } from "./ai.js";
|
|
44
|
+
import type { PageIRNode } from "./ir.js";
|
|
45
|
+
/**
|
|
46
|
+
* The editor's description of which nodes the author selected before
|
|
47
|
+
* asking for a section-level regeneration.
|
|
48
|
+
*
|
|
49
|
+
* Built by the AI copilot plugin from Puck's selection state plus the
|
|
50
|
+
* surrounding zone metadata. Passed verbatim into
|
|
51
|
+
* `configToAiSectionContext()` to derive an LLM-shaped
|
|
52
|
+
* {@link AiSectionContext}.
|
|
53
|
+
*
|
|
54
|
+
* Selection lives inside a single zone — root, a legacy `data.zones`
|
|
55
|
+
* entry, or a modern slot field. The {@link zoneId} discriminates;
|
|
56
|
+
* {@link allow} / {@link disallow} mirror the parent slot's allow-list
|
|
57
|
+
* if the selection is slot-scoped.
|
|
58
|
+
*/
|
|
59
|
+
export interface AiSectionSelection {
|
|
60
|
+
/**
|
|
61
|
+
* The Puck zone identifier containing the selection.
|
|
62
|
+
*
|
|
63
|
+
* - For root content: Puck's root zone id (typically `"root-zone"`
|
|
64
|
+
* or the empty string, depending on Puck version).
|
|
65
|
+
* - For legacy `data.zones` entries: the dotted key Puck uses
|
|
66
|
+
* (`${parentId}:${zoneName}`).
|
|
67
|
+
* - For modern slot fields: the slot field's path inside the parent
|
|
68
|
+
* component.
|
|
69
|
+
*
|
|
70
|
+
* Opaque to {@link AiSectionContext} consumers — only the validator
|
|
71
|
+
* compares it against incoming {@link AiSectionPatch.zoneId} values.
|
|
72
|
+
*/
|
|
73
|
+
readonly zoneId: string;
|
|
74
|
+
/**
|
|
75
|
+
* Selected node IDs, in author-visible order.
|
|
76
|
+
*
|
|
77
|
+
* Length must be ≥ 1 — selecting zero nodes is the page-level flow,
|
|
78
|
+
* not the section flow. The order is preserved into
|
|
79
|
+
* {@link AiSectionPatch.nodeIds} so the validator can match
|
|
80
|
+
* positions when {@link AiSectionContext.allowResize} is `false`.
|
|
81
|
+
*/
|
|
82
|
+
readonly nodeIds: readonly string[];
|
|
83
|
+
/**
|
|
84
|
+
* Optional snapshot of the current node subtrees being replaced.
|
|
85
|
+
*
|
|
86
|
+
* When provided, `configToAiSectionContext()` forwards this onto
|
|
87
|
+
* {@link AiSectionContext.currentNodes} so the prompt builder can
|
|
88
|
+
* include "before" content. Hosts that have already loaded a
|
|
89
|
+
* `PageIR` have this for free; hosts that drive Puck without a
|
|
90
|
+
* normalized IR may omit it.
|
|
91
|
+
*/
|
|
92
|
+
readonly currentNodes?: readonly PageIRNode[];
|
|
93
|
+
/**
|
|
94
|
+
* Optional zone-scoped allow-list, mirroring the
|
|
95
|
+
* `allow` array on Puck slot field definitions.
|
|
96
|
+
*
|
|
97
|
+
* When present, `configToAiSectionContext()` narrows
|
|
98
|
+
* {@link AiSectionContext.availableComponents} to this set. Absent
|
|
99
|
+
* means "every registered component is permitted in this zone"
|
|
100
|
+
* (the root-zone default).
|
|
101
|
+
*/
|
|
102
|
+
readonly allow?: readonly string[];
|
|
103
|
+
/**
|
|
104
|
+
* Optional zone-scoped disallow-list, mirroring the `disallow` array
|
|
105
|
+
* on Puck slot field definitions. Applied after {@link allow}.
|
|
106
|
+
*/
|
|
107
|
+
readonly disallow?: readonly string[];
|
|
108
|
+
/**
|
|
109
|
+
* Optional Puck zone hint — `"slot"` for modern slot fields,
|
|
110
|
+
* `"zone"` for legacy `data.zones` entries, omitted for the root
|
|
111
|
+
* zone. Forwarded to {@link AiSectionContext.zoneKind}; the
|
|
112
|
+
* validator uses it as a sanity check when {@link allow} is empty.
|
|
113
|
+
*/
|
|
114
|
+
readonly zoneKind?: "slot" | "zone";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Optional environment hints for `configToAiSectionContext()`.
|
|
118
|
+
*
|
|
119
|
+
* Mirrors the per-call hints on {@link AiGenerationContext} (theme,
|
|
120
|
+
* locale) so a host that already builds a page-level context can reuse
|
|
121
|
+
* the same hint object for both flows.
|
|
122
|
+
*/
|
|
123
|
+
export interface ConfigToAiSectionContextOptions {
|
|
124
|
+
/**
|
|
125
|
+
* Optional theme hint (`"light"` | `"dark"`) forwarded onto
|
|
126
|
+
* {@link AiSectionContext.theme}.
|
|
127
|
+
*/
|
|
128
|
+
readonly theme?: AiThemeHint;
|
|
129
|
+
/**
|
|
130
|
+
* Optional BCP 47 language tag forwarded onto
|
|
131
|
+
* {@link AiSectionContext.locale}.
|
|
132
|
+
*/
|
|
133
|
+
readonly locale?: string;
|
|
134
|
+
/**
|
|
135
|
+
* When `true`, the resulting context's {@link AiSectionContext.allowResize}
|
|
136
|
+
* is set so the LLM (and the validator) accepts a {@link AiSectionPatch}
|
|
137
|
+
* whose `replacement.length` ≠ {@link AiSectionSelection.nodeIds}.length.
|
|
138
|
+
*
|
|
139
|
+
* Defaults to `false` — Phase 6 / M9 ships size-preserving patches
|
|
140
|
+
* only. Hosts wanting "split this hero into three sections" must opt
|
|
141
|
+
* in explicitly.
|
|
142
|
+
*/
|
|
143
|
+
readonly allowResize?: boolean;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The LLM-shaped view of a section-level regeneration request.
|
|
147
|
+
*
|
|
148
|
+
* Produced by `@anvilkit/schema/section`'s `configToAiSectionContext()`
|
|
149
|
+
* from a Puck `Config` + an {@link AiSectionSelection}. Passed into the
|
|
150
|
+
* host-supplied `generateSection(ctx, prompt)` callback and again into
|
|
151
|
+
* `validateAiSectionPatch(patch, ctx)` after the LLM responds.
|
|
152
|
+
*
|
|
153
|
+
* Closed shape: every field is intentional. Hosts must not stuff
|
|
154
|
+
* arbitrary metadata onto this object — open extension is reserved for
|
|
155
|
+
* a Phase 7 major bump.
|
|
156
|
+
*/
|
|
157
|
+
export interface AiSectionContext {
|
|
158
|
+
/**
|
|
159
|
+
* The zone the selection lives inside. Forwarded from
|
|
160
|
+
* {@link AiSectionSelection.zoneId} so the validator can verify
|
|
161
|
+
* that the LLM's emitted {@link AiSectionPatch.zoneId} matches.
|
|
162
|
+
*/
|
|
163
|
+
readonly zoneId: string;
|
|
164
|
+
/**
|
|
165
|
+
* Optional Puck zone discriminator — `"slot"`, `"zone"`, or omitted
|
|
166
|
+
* for the root zone. Forwarded from
|
|
167
|
+
* {@link AiSectionSelection.zoneKind}.
|
|
168
|
+
*/
|
|
169
|
+
readonly zoneKind?: "slot" | "zone";
|
|
170
|
+
/**
|
|
171
|
+
* The selected node IDs in author-visible order. Forwarded from
|
|
172
|
+
* {@link AiSectionSelection.nodeIds}; an emitted patch must
|
|
173
|
+
* preserve this order (and length, when
|
|
174
|
+
* {@link allowResize} is `false`).
|
|
175
|
+
*/
|
|
176
|
+
readonly nodeIds: readonly string[];
|
|
177
|
+
/**
|
|
178
|
+
* The components the LLM may emit inside this zone, already
|
|
179
|
+
* narrowed by the zone's allow / disallow lists.
|
|
180
|
+
*
|
|
181
|
+
* Each entry has the same shape as
|
|
182
|
+
* {@link AiGenerationContext.availableComponents} so the validator
|
|
183
|
+
* applies identical field-level rules at section and page
|
|
184
|
+
* granularity.
|
|
185
|
+
*
|
|
186
|
+
* The list is sorted by {@link AiComponentSchema.componentName} for
|
|
187
|
+
* deterministic prompts.
|
|
188
|
+
*/
|
|
189
|
+
readonly availableComponents: readonly AiComponentSchema[];
|
|
190
|
+
/**
|
|
191
|
+
* Optional snapshot of the subtrees being replaced. Forwarded from
|
|
192
|
+
* {@link AiSectionSelection.currentNodes}. Lets the prompt builder
|
|
193
|
+
* include "rewrite THIS subtree" context.
|
|
194
|
+
*/
|
|
195
|
+
readonly currentNodes?: readonly PageIRNode[];
|
|
196
|
+
/**
|
|
197
|
+
* Whether a size-changing replacement is permitted. Driven by
|
|
198
|
+
* {@link ConfigToAiSectionContextOptions.allowResize}; defaults to
|
|
199
|
+
* `false` so single-subtree-replacement is the safe default.
|
|
200
|
+
*/
|
|
201
|
+
readonly allowResize: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Optional theme hint forwarded onto the prompt. Mirrors
|
|
204
|
+
* {@link AiGenerationContext.theme}.
|
|
205
|
+
*/
|
|
206
|
+
readonly theme?: AiThemeHint;
|
|
207
|
+
/**
|
|
208
|
+
* Optional BCP 47 locale hint. Mirrors
|
|
209
|
+
* {@link AiGenerationContext.locale}.
|
|
210
|
+
*/
|
|
211
|
+
readonly locale?: string;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The LLM's response to a section-level regeneration request.
|
|
215
|
+
*
|
|
216
|
+
* Replaces {@link nodeIds} inside {@link zoneId} with {@link replacement}
|
|
217
|
+
* via `puckApi.dispatch({ type: "setData", data: applyPatch(...) })`,
|
|
218
|
+
* preserving surrounding canvas (selection, sidebar, scroll).
|
|
219
|
+
*
|
|
220
|
+
* Validation lives in `@anvilkit/validator/section`'s
|
|
221
|
+
* `validateAiSectionPatch()`; this package only owns the type.
|
|
222
|
+
*/
|
|
223
|
+
export interface AiSectionPatch {
|
|
224
|
+
/**
|
|
225
|
+
* The zone the patch applies to. Must match
|
|
226
|
+
* {@link AiSectionContext.zoneId} — patches that target a different
|
|
227
|
+
* zone are rejected with code `PATCH_SHAPE`.
|
|
228
|
+
*/
|
|
229
|
+
readonly zoneId: string;
|
|
230
|
+
/**
|
|
231
|
+
* The node IDs being replaced. Must equal
|
|
232
|
+
* {@link AiSectionContext.nodeIds} (same order, same length unless
|
|
233
|
+
* {@link AiSectionContext.allowResize} is `true`).
|
|
234
|
+
*/
|
|
235
|
+
readonly nodeIds: readonly string[];
|
|
236
|
+
/**
|
|
237
|
+
* The new subtrees, in the order they should appear in the zone
|
|
238
|
+
* after the replacement is applied. Each node is fully formed
|
|
239
|
+
* `PageIRNode` shape — the validator runs the same per-node rules
|
|
240
|
+
* as `validateAiOutput`, scoped to this subtree only.
|
|
241
|
+
*/
|
|
242
|
+
readonly replacement: readonly PageIRNode[];
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=ai-section.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-section.d.cts","sourceRoot":"","sources":["../src/ai-section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC/C;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,mBAAmB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;CAC5C"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Section-level AI editing contract — the types
|
|
3
|
+
* `@anvilkit/schema/section`, `@anvilkit/validator/section`, and the
|
|
4
|
+
* `regenerateSelection()` flow in `@anvilkit/plugin-ai-copilot` pass
|
|
5
|
+
* between each other when an author asks an LLM to rewrite a selected
|
|
6
|
+
* subtree of an existing page.
|
|
7
|
+
*
|
|
8
|
+
* Section-level AI is the Phase 6 / M9 sibling to Phase 3's whole-page
|
|
9
|
+
* AI flow ({@link AiGenerationContext} in `./ai.ts`). The page-level
|
|
10
|
+
* flow asks the LLM to emit a complete {@link PageIR}; the section-level
|
|
11
|
+
* flow asks it to emit a {@link AiSectionPatch} that atomically replaces
|
|
12
|
+
* just the selected nodes inside one Puck zone.
|
|
13
|
+
*
|
|
14
|
+
* ### Shape of the contract
|
|
15
|
+
*
|
|
16
|
+
* - {@link AiSectionSelection} is the editor's "what did the author
|
|
17
|
+
* click" payload. The plugin builds it from Puck's selection state +
|
|
18
|
+
* the surrounding zone metadata, then hands it to
|
|
19
|
+
* `configToAiSectionContext()`.
|
|
20
|
+
* - {@link AiSectionContext} is the LLM-shaped view of that selection —
|
|
21
|
+
* the available replacement components (already narrowed to whatever
|
|
22
|
+
* the zone allows), the current subtree snapshots, and optional
|
|
23
|
+
* environment hints. `@anvilkit/schema/section` owns the derivation;
|
|
24
|
+
* this package only owns the destination shape.
|
|
25
|
+
* - {@link AiSectionPatch} is the LLM's response shape. Validation
|
|
26
|
+
* lives in `@anvilkit/validator/section`; this package only owns
|
|
27
|
+
* the type.
|
|
28
|
+
*
|
|
29
|
+
* ### Design rules
|
|
30
|
+
*
|
|
31
|
+
* 1. **Types only.** No runtime code.
|
|
32
|
+
* 2. **Single-subtree per call.** Phase 6 ships a single contiguous
|
|
33
|
+
* subtree replacement per call. Batched multi-zone patches are
|
|
34
|
+
* deliberately out of scope — they would need a new contract and
|
|
35
|
+
* are reserved for `1.2` (plan §12 Q1).
|
|
36
|
+
* 3. **Round-trip safe with Phase 3 page-level AI.** The
|
|
37
|
+
* {@link AiSectionContext.availableComponents} reuses the
|
|
38
|
+
* {@link AiComponentSchema} shape so the validator can apply the
|
|
39
|
+
* same field-level rules at both granularities without forking.
|
|
40
|
+
*
|
|
41
|
+
* @see {@link https://github.com/anvilkit/studio/blob/main/docs/plans/phase-6-plan.md | Phase 6 plan §5.1 Section-level AI patch model}
|
|
42
|
+
*/
|
|
43
|
+
import type { AiComponentSchema, AiThemeHint } from "./ai.js";
|
|
44
|
+
import type { PageIRNode } from "./ir.js";
|
|
45
|
+
/**
|
|
46
|
+
* The editor's description of which nodes the author selected before
|
|
47
|
+
* asking for a section-level regeneration.
|
|
48
|
+
*
|
|
49
|
+
* Built by the AI copilot plugin from Puck's selection state plus the
|
|
50
|
+
* surrounding zone metadata. Passed verbatim into
|
|
51
|
+
* `configToAiSectionContext()` to derive an LLM-shaped
|
|
52
|
+
* {@link AiSectionContext}.
|
|
53
|
+
*
|
|
54
|
+
* Selection lives inside a single zone — root, a legacy `data.zones`
|
|
55
|
+
* entry, or a modern slot field. The {@link zoneId} discriminates;
|
|
56
|
+
* {@link allow} / {@link disallow} mirror the parent slot's allow-list
|
|
57
|
+
* if the selection is slot-scoped.
|
|
58
|
+
*/
|
|
59
|
+
export interface AiSectionSelection {
|
|
60
|
+
/**
|
|
61
|
+
* The Puck zone identifier containing the selection.
|
|
62
|
+
*
|
|
63
|
+
* - For root content: Puck's root zone id (typically `"root-zone"`
|
|
64
|
+
* or the empty string, depending on Puck version).
|
|
65
|
+
* - For legacy `data.zones` entries: the dotted key Puck uses
|
|
66
|
+
* (`${parentId}:${zoneName}`).
|
|
67
|
+
* - For modern slot fields: the slot field's path inside the parent
|
|
68
|
+
* component.
|
|
69
|
+
*
|
|
70
|
+
* Opaque to {@link AiSectionContext} consumers — only the validator
|
|
71
|
+
* compares it against incoming {@link AiSectionPatch.zoneId} values.
|
|
72
|
+
*/
|
|
73
|
+
readonly zoneId: string;
|
|
74
|
+
/**
|
|
75
|
+
* Selected node IDs, in author-visible order.
|
|
76
|
+
*
|
|
77
|
+
* Length must be ≥ 1 — selecting zero nodes is the page-level flow,
|
|
78
|
+
* not the section flow. The order is preserved into
|
|
79
|
+
* {@link AiSectionPatch.nodeIds} so the validator can match
|
|
80
|
+
* positions when {@link AiSectionContext.allowResize} is `false`.
|
|
81
|
+
*/
|
|
82
|
+
readonly nodeIds: readonly string[];
|
|
83
|
+
/**
|
|
84
|
+
* Optional snapshot of the current node subtrees being replaced.
|
|
85
|
+
*
|
|
86
|
+
* When provided, `configToAiSectionContext()` forwards this onto
|
|
87
|
+
* {@link AiSectionContext.currentNodes} so the prompt builder can
|
|
88
|
+
* include "before" content. Hosts that have already loaded a
|
|
89
|
+
* `PageIR` have this for free; hosts that drive Puck without a
|
|
90
|
+
* normalized IR may omit it.
|
|
91
|
+
*/
|
|
92
|
+
readonly currentNodes?: readonly PageIRNode[];
|
|
93
|
+
/**
|
|
94
|
+
* Optional zone-scoped allow-list, mirroring the
|
|
95
|
+
* `allow` array on Puck slot field definitions.
|
|
96
|
+
*
|
|
97
|
+
* When present, `configToAiSectionContext()` narrows
|
|
98
|
+
* {@link AiSectionContext.availableComponents} to this set. Absent
|
|
99
|
+
* means "every registered component is permitted in this zone"
|
|
100
|
+
* (the root-zone default).
|
|
101
|
+
*/
|
|
102
|
+
readonly allow?: readonly string[];
|
|
103
|
+
/**
|
|
104
|
+
* Optional zone-scoped disallow-list, mirroring the `disallow` array
|
|
105
|
+
* on Puck slot field definitions. Applied after {@link allow}.
|
|
106
|
+
*/
|
|
107
|
+
readonly disallow?: readonly string[];
|
|
108
|
+
/**
|
|
109
|
+
* Optional Puck zone hint — `"slot"` for modern slot fields,
|
|
110
|
+
* `"zone"` for legacy `data.zones` entries, omitted for the root
|
|
111
|
+
* zone. Forwarded to {@link AiSectionContext.zoneKind}; the
|
|
112
|
+
* validator uses it as a sanity check when {@link allow} is empty.
|
|
113
|
+
*/
|
|
114
|
+
readonly zoneKind?: "slot" | "zone";
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Optional environment hints for `configToAiSectionContext()`.
|
|
118
|
+
*
|
|
119
|
+
* Mirrors the per-call hints on {@link AiGenerationContext} (theme,
|
|
120
|
+
* locale) so a host that already builds a page-level context can reuse
|
|
121
|
+
* the same hint object for both flows.
|
|
122
|
+
*/
|
|
123
|
+
export interface ConfigToAiSectionContextOptions {
|
|
124
|
+
/**
|
|
125
|
+
* Optional theme hint (`"light"` | `"dark"`) forwarded onto
|
|
126
|
+
* {@link AiSectionContext.theme}.
|
|
127
|
+
*/
|
|
128
|
+
readonly theme?: AiThemeHint;
|
|
129
|
+
/**
|
|
130
|
+
* Optional BCP 47 language tag forwarded onto
|
|
131
|
+
* {@link AiSectionContext.locale}.
|
|
132
|
+
*/
|
|
133
|
+
readonly locale?: string;
|
|
134
|
+
/**
|
|
135
|
+
* When `true`, the resulting context's {@link AiSectionContext.allowResize}
|
|
136
|
+
* is set so the LLM (and the validator) accepts a {@link AiSectionPatch}
|
|
137
|
+
* whose `replacement.length` ≠ {@link AiSectionSelection.nodeIds}.length.
|
|
138
|
+
*
|
|
139
|
+
* Defaults to `false` — Phase 6 / M9 ships size-preserving patches
|
|
140
|
+
* only. Hosts wanting "split this hero into three sections" must opt
|
|
141
|
+
* in explicitly.
|
|
142
|
+
*/
|
|
143
|
+
readonly allowResize?: boolean;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The LLM-shaped view of a section-level regeneration request.
|
|
147
|
+
*
|
|
148
|
+
* Produced by `@anvilkit/schema/section`'s `configToAiSectionContext()`
|
|
149
|
+
* from a Puck `Config` + an {@link AiSectionSelection}. Passed into the
|
|
150
|
+
* host-supplied `generateSection(ctx, prompt)` callback and again into
|
|
151
|
+
* `validateAiSectionPatch(patch, ctx)` after the LLM responds.
|
|
152
|
+
*
|
|
153
|
+
* Closed shape: every field is intentional. Hosts must not stuff
|
|
154
|
+
* arbitrary metadata onto this object — open extension is reserved for
|
|
155
|
+
* a Phase 7 major bump.
|
|
156
|
+
*/
|
|
157
|
+
export interface AiSectionContext {
|
|
158
|
+
/**
|
|
159
|
+
* The zone the selection lives inside. Forwarded from
|
|
160
|
+
* {@link AiSectionSelection.zoneId} so the validator can verify
|
|
161
|
+
* that the LLM's emitted {@link AiSectionPatch.zoneId} matches.
|
|
162
|
+
*/
|
|
163
|
+
readonly zoneId: string;
|
|
164
|
+
/**
|
|
165
|
+
* Optional Puck zone discriminator — `"slot"`, `"zone"`, or omitted
|
|
166
|
+
* for the root zone. Forwarded from
|
|
167
|
+
* {@link AiSectionSelection.zoneKind}.
|
|
168
|
+
*/
|
|
169
|
+
readonly zoneKind?: "slot" | "zone";
|
|
170
|
+
/**
|
|
171
|
+
* The selected node IDs in author-visible order. Forwarded from
|
|
172
|
+
* {@link AiSectionSelection.nodeIds}; an emitted patch must
|
|
173
|
+
* preserve this order (and length, when
|
|
174
|
+
* {@link allowResize} is `false`).
|
|
175
|
+
*/
|
|
176
|
+
readonly nodeIds: readonly string[];
|
|
177
|
+
/**
|
|
178
|
+
* The components the LLM may emit inside this zone, already
|
|
179
|
+
* narrowed by the zone's allow / disallow lists.
|
|
180
|
+
*
|
|
181
|
+
* Each entry has the same shape as
|
|
182
|
+
* {@link AiGenerationContext.availableComponents} so the validator
|
|
183
|
+
* applies identical field-level rules at section and page
|
|
184
|
+
* granularity.
|
|
185
|
+
*
|
|
186
|
+
* The list is sorted by {@link AiComponentSchema.componentName} for
|
|
187
|
+
* deterministic prompts.
|
|
188
|
+
*/
|
|
189
|
+
readonly availableComponents: readonly AiComponentSchema[];
|
|
190
|
+
/**
|
|
191
|
+
* Optional snapshot of the subtrees being replaced. Forwarded from
|
|
192
|
+
* {@link AiSectionSelection.currentNodes}. Lets the prompt builder
|
|
193
|
+
* include "rewrite THIS subtree" context.
|
|
194
|
+
*/
|
|
195
|
+
readonly currentNodes?: readonly PageIRNode[];
|
|
196
|
+
/**
|
|
197
|
+
* Whether a size-changing replacement is permitted. Driven by
|
|
198
|
+
* {@link ConfigToAiSectionContextOptions.allowResize}; defaults to
|
|
199
|
+
* `false` so single-subtree-replacement is the safe default.
|
|
200
|
+
*/
|
|
201
|
+
readonly allowResize: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Optional theme hint forwarded onto the prompt. Mirrors
|
|
204
|
+
* {@link AiGenerationContext.theme}.
|
|
205
|
+
*/
|
|
206
|
+
readonly theme?: AiThemeHint;
|
|
207
|
+
/**
|
|
208
|
+
* Optional BCP 47 locale hint. Mirrors
|
|
209
|
+
* {@link AiGenerationContext.locale}.
|
|
210
|
+
*/
|
|
211
|
+
readonly locale?: string;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The LLM's response to a section-level regeneration request.
|
|
215
|
+
*
|
|
216
|
+
* Replaces {@link nodeIds} inside {@link zoneId} with {@link replacement}
|
|
217
|
+
* via `puckApi.dispatch({ type: "setData", data: applyPatch(...) })`,
|
|
218
|
+
* preserving surrounding canvas (selection, sidebar, scroll).
|
|
219
|
+
*
|
|
220
|
+
* Validation lives in `@anvilkit/validator/section`'s
|
|
221
|
+
* `validateAiSectionPatch()`; this package only owns the type.
|
|
222
|
+
*/
|
|
223
|
+
export interface AiSectionPatch {
|
|
224
|
+
/**
|
|
225
|
+
* The zone the patch applies to. Must match
|
|
226
|
+
* {@link AiSectionContext.zoneId} — patches that target a different
|
|
227
|
+
* zone are rejected with code `PATCH_SHAPE`.
|
|
228
|
+
*/
|
|
229
|
+
readonly zoneId: string;
|
|
230
|
+
/**
|
|
231
|
+
* The node IDs being replaced. Must equal
|
|
232
|
+
* {@link AiSectionContext.nodeIds} (same order, same length unless
|
|
233
|
+
* {@link AiSectionContext.allowResize} is `true`).
|
|
234
|
+
*/
|
|
235
|
+
readonly nodeIds: readonly string[];
|
|
236
|
+
/**
|
|
237
|
+
* The new subtrees, in the order they should appear in the zone
|
|
238
|
+
* after the replacement is applied. Each node is fully formed
|
|
239
|
+
* `PageIRNode` shape — the validator runs the same per-node rules
|
|
240
|
+
* as `validateAiOutput`, scoped to this subtree only.
|
|
241
|
+
*/
|
|
242
|
+
readonly replacement: readonly PageIRNode[];
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=ai-section.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-section.d.ts","sourceRoot":"","sources":["../src/ai-section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC/C;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,mBAAmB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/ai.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.r = (exports1)=>{
|
|
5
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
6
|
+
value: 'Module'
|
|
7
|
+
});
|
|
8
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
9
|
+
value: true
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
})();
|
|
13
|
+
var __webpack_exports__ = {};
|
|
14
|
+
__webpack_require__.r(__webpack_exports__);
|
|
15
|
+
for(var __rspack_i in __webpack_exports__)exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
16
|
+
Object.defineProperty(exports, '__esModule', {
|
|
17
|
+
value: true
|
|
18
|
+
});
|