@owlmeans/viable-common 0.0.34 → 0.0.36

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.
Files changed (52) hide show
  1. package/README.md +3 -3
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/agent-presentation/SKILL.md +1 -1
  4. package/agent-meta/skills/viable-common/SKILL.md +2 -2
  5. package/build/dev/schemas.d.ts.map +1 -1
  6. package/build/dev/schemas.js +5 -0
  7. package/build/dev/schemas.js.map +1 -1
  8. package/build/dev/types.d.ts +2 -0
  9. package/build/dev/types.d.ts.map +1 -1
  10. package/build/preview/types.d.ts +3 -0
  11. package/build/preview/types.d.ts.map +1 -1
  12. package/build/scaffold/consts.d.ts +14 -1
  13. package/build/scaffold/consts.d.ts.map +1 -1
  14. package/build/scaffold/consts.js +10 -0
  15. package/build/scaffold/consts.js.map +1 -1
  16. package/build/scaffold/schemas.d.ts +7 -0
  17. package/build/scaffold/schemas.d.ts.map +1 -1
  18. package/build/scaffold/schemas.js +119 -68
  19. package/build/scaffold/schemas.js.map +1 -1
  20. package/build/scaffold/types.d.ts +62 -24
  21. package/build/scaffold/types.d.ts.map +1 -1
  22. package/build/ux/schemas.js +2 -2
  23. package/build/ux/schemas.js.map +1 -1
  24. package/package.json +1 -1
  25. package/src/dev/schemas.ts +5 -0
  26. package/src/dev/types.ts +2 -0
  27. package/src/preview/types.ts +3 -1
  28. package/src/scaffold/consts.ts +14 -1
  29. package/src/scaffold/schemas.ts +125 -69
  30. package/src/scaffold/types.ts +64 -23
  31. package/src/ux/schemas.ts +2 -2
  32. package/tests/scaffold.spec.ts +73 -13
  33. package/build/ba/schemas.d.ts +0 -13
  34. package/build/ba/schemas.d.ts.map +0 -1
  35. package/build/ba/schemas.js +0 -181
  36. package/build/ba/schemas.js.map +0 -1
  37. package/build/blueprint/case.d.ts +0 -73
  38. package/build/blueprint/case.d.ts.map +0 -1
  39. package/build/blueprint/case.js +0 -286
  40. package/build/blueprint/case.js.map +0 -1
  41. package/build/blueprint/resolve.d.ts +0 -51
  42. package/build/blueprint/resolve.d.ts.map +0 -1
  43. package/build/blueprint/resolve.js +0 -111
  44. package/build/blueprint/resolve.js.map +0 -1
  45. package/build/blueprint/schemas.d.ts +0 -41
  46. package/build/blueprint/schemas.d.ts.map +0 -1
  47. package/build/blueprint/schemas.js +0 -27
  48. package/build/blueprint/schemas.js.map +0 -1
  49. package/build/skills/catalogue.d.ts +0 -47
  50. package/build/skills/catalogue.d.ts.map +0 -1
  51. package/build/skills/catalogue.js +0 -1811
  52. package/build/skills/catalogue.js.map +0 -1
@@ -127,50 +127,88 @@ export interface BentoFragment {
127
127
  value?: string;
128
128
  }[];
129
129
  }
130
+ /**
131
+ * What kind of control a landing-gate field is. A CLOSED set of the simplest native inputs: each
132
+ * value is one plain element, so there is nothing here a visitor has to learn, and nothing that
133
+ * can grow into a picker, a chip group or a preview.
134
+ */
135
+ export type LandingGateFieldKind = 'text' | 'select' | 'number' | 'date';
136
+ /** One simple, non-sensitive field of the landing gate. */
137
+ export interface LandingGateField {
138
+ /** The camelCase key the entered value travels under in the landing handoff: "dish". */
139
+ name: string;
140
+ /** The visible label, in the end user's words: "What are you baking?". */
141
+ label: string;
142
+ kind: LandingGateFieldKind;
143
+ /** An example value shown inside an empty text or number field — never a personal one. */
144
+ placeholder?: string;
145
+ /** `select` only: 2–6 plain options. */
146
+ options?: string[];
147
+ }
130
148
  /**
131
149
  * The landing gate — the working entry into the product's key END-USER workflow, drawn in the
132
150
  * hero where the call-to-action pills would otherwise be.
133
151
  *
134
- * A guest makes a few non-sensitive choices on the landing page, sees sample results ranked
135
- * against them, and signs in to continue on the story's full-scale screen with those choices
136
- * carried over. Every field is copy or sample data in the end user's own words; nothing here is
137
- * an address the model invented — `target` is filled by code.
152
+ * A guest fills in one to three simple non-sensitive fields on the landing page and signs in to
153
+ * continue on the story's full-scale screen with what they entered already in place. It is a small
154
+ * form and nothing more: no choices to browse, no sample results, no counts. Every text is copy in
155
+ * the end user's own words; nothing here is an address the model invented — `target` is filled by
156
+ * code.
157
+ *
158
+ * The keys after `note` are the shape a plan had before the gate became a form (chips, sample
159
+ * records, a live count). They stay so a plan STORED under the old shape still validates and
160
+ * still reads; nothing writes them and nothing draws from them, and a gate that carries no
161
+ * `fields` is drawn as no gate at all.
138
162
  */
139
163
  export interface LandingGatePlan {
140
164
  /** The key end-user story's code — never rendered. */
141
165
  story: string;
142
166
  /** Entrypoint ALIAS of the story's full-scale screen in the user area (filled by code, not the model). */
143
167
  target?: string;
144
- /** The question the gate asks, in the end user's words: "What's in your pantry?". */
168
+ /** The heading of the form, in the end user's words: "What are you baking?". */
145
169
  question: string;
146
- /** The reassurance beside it: "No account needed". */
147
- hint: string;
148
- /** The accessible name of the chip group: "Your pantry". */
149
- label: string;
150
- /** 5–8 chip labels the guest picks from. */
151
- inputs: string[];
152
- /** 4–5 of `inputs`, pre-selected so the first view already shows results. */
153
- selected: string[];
154
- /** 3–4 sample records; `needs` is the subset of `inputs` each one uses. */
155
- results: {
170
+ /** The fields, one to three — one whenever one is enough. Absent only on a plan stored under the old shape. */
171
+ fields?: LandingGateField[];
172
+ /** The one button's label: "Start my post →". */
173
+ cta: string;
174
+ /** The muted line under the form: "No account needed. What you enter comes with you.". */
175
+ note: string;
176
+ /** @deprecated Pre-form shape, kept for stored plans only. */
177
+ hint?: string;
178
+ /** @deprecated Pre-form shape, kept for stored plans only. */
179
+ label?: string;
180
+ /** @deprecated Pre-form shape, kept for stored plans only. */
181
+ inputs?: string[];
182
+ /** @deprecated Pre-form shape, kept for stored plans only. */
183
+ selected?: string[];
184
+ /** @deprecated Pre-form shape, kept for stored plans only. */
185
+ results?: {
156
186
  title: string;
157
187
  meta: string;
158
188
  needs: string[];
159
189
  }[];
160
- /** The live count label; `{n}` is replaced by the number ("{n} bakes match"). */
161
- count: {
190
+ /** @deprecated Pre-form shape, kept for stored plans only. */
191
+ count?: {
162
192
  one: string;
163
193
  many: string;
164
194
  none: string;
165
195
  };
166
- /** The line shown when nothing matches the picks. */
167
- empty: string;
168
- /** The line beside the CTA: "Sign in with your email. Your picks come with you.". */
169
- note: string;
170
- /** The CTA label: "Open recipes →". */
196
+ /** @deprecated Pre-form shape, kept for stored plans only. */
197
+ empty?: string;
198
+ /** @deprecated Pre-form shape, kept for stored plans only. */
199
+ lock?: string;
200
+ }
201
+ /**
202
+ * The gate as the planning MODEL answers it: the form, and none of the pre-form keys. Assignable
203
+ * to {@link LandingGatePlan}, which is what a plan stores.
204
+ */
205
+ export interface LandingGateAnswer {
206
+ story: string;
207
+ target?: string;
208
+ question: string;
209
+ fields: LandingGateField[];
171
210
  cta: string;
172
- /** The accessible name of a result row's lock icon: "Full method after sign-in". */
173
- lock: string;
211
+ note: string;
174
212
  }
175
213
  /** The guest area's landing page — the product's public face. */
176
214
  export interface GuestHomePlan {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scaffold/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAA;IACf,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,wEAAwE;IACxE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC3C,8BAA8B;IAC9B,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC3C;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,MAAM,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;IAChE,iEAAiE;IACjE,MAAM,EAAE,aAAa,CAAA;IACrB,wFAAwF;IACxF,IAAI,EAAE,OAAO,CAAA;IACb;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,mFAAmF;AACnF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAA;IACjB,yDAAyD;IACzD,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACtC,yDAAyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAA;IACZ,gFAAgF;IAChF,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,+FAA+F;AAC/F,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAEpE;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAA;IACvB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qGAAqG;IACrG,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC1C;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAA;IACb,0GAA0G;IAC1G,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,QAAQ,EAAE,MAAM,CAAA;IAChB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAA;IACZ,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAA;IACb,4CAA4C;IAC5C,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,2EAA2E;IAC3E,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;IAC3D,iFAAiF;IACjF,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAA;IACb,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAA;IACX,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAA;CACb;AAED,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAA;QAChB,GAAG,EAAE,MAAM,CAAA;QACX,6FAA6F;QAC7F,GAAG,EAAE,MAAM,CAAA;QACX;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,qEAAqE;QACrE,SAAS,CAAC,EAAE,QAAQ,CAAA;QACpB,yFAAyF;QACzF,MAAM,CAAC,EAAE,QAAQ,CAAA;KAClB,CAAA;IACD,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACzC,iGAAiG;IACjG,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,EAAE,CAAA;IACrE,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC7D,6DAA6D;IAC7D,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACzC,iGAAiG;IACjG,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,8EAA8E;IAC9E,OAAO,CAAC,EAAE;QACR,QAAQ,EAAE,MAAM,CAAA;QAChB,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;QACf,SAAS,CAAC,EAAE,QAAQ,CAAA;QACpB,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KACzD,CAAA;IACD;;;OAGG;IACH,IAAI,CAAC,EAAE,eAAe,CAAA;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,EAAE,aAAa,CAAA;IACxB,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;CACf"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scaffold/types.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@ export const UXScreenListSchema = {
8
8
  type: "array",
9
9
  items: {
10
10
  type: "string",
11
- description: "Technical screen name, no spaces, kebab-case notation with slashes allowed"
11
+ description: "Technical screen name, no spaces, kebab-case notation with slashes allowed; every part is one or two words"
12
12
  },
13
13
  description: "List of screens"
14
14
  },
@@ -25,7 +25,7 @@ export const UXComponentListSchema = {
25
25
  type: "array",
26
26
  items: {
27
27
  type: "string",
28
- description: "Technical component name, no spaces, kebab-case notation with slashes allowed"
28
+ description: "Technical component name, no spaces, kebab-case notation with slashes allowed; every part is one or two words"
29
29
  },
30
30
  description: "List of components"
31
31
  },
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/ux/schemas.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,yBAAyB;IACtC,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,4EAA4E;aAC1F;YACD,WAAW,EAAE,iBAAiB;SAC/B;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,CAAC;IACrB,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAoC;IACpE,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,iBAAiB;IACxB,WAAW,EAAE,4BAA4B;IACzC,UAAU,EAAE;QACV,UAAU,EAAE;YACV,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+EAA+E;aAC7F;YACD,WAAW,EAAE,oBAAoB;SAClC;KACF;IACD,QAAQ,EAAE,CAAC,YAAY,CAAC;IACxB,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAwC;IAC5E,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,EAAE;IACd,oBAAoB,EAAE;QACpB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;SACf;KACF;IACD,QAAQ,EAAE,EAAE;CACb,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,6DAA6D;IAC1E,UAAU,EAAE;QACV,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,6BAA6B;SAC3C;QACD,EAAE,EAAE;YACF,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,2BAA2B;SACzC;QACD,SAAS,EAAE;YACT,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,yCAAyC;SACvD;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,sCAAsC;SACpD;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;YACrC,WAAW,EAAE,uDAAuD;SACrE;KACF;IACD,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC;IACvD,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAqC;IACtE,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,6BAA6B;IAC1C,UAAU,EAAE;QACV,WAAW,EAAE;YACX,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,kBAAkB;YACzB,WAAW,EAAE,aAAa;SAC3B;KACF;IACD,QAAQ,EAAE,CAAC,aAAa,CAAC;IACzB,oBAAoB,EAAE,KAAK;CAC5B,CAAA"}
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/ux/schemas.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,yBAAyB;IACtC,UAAU,EAAE;QACV,OAAO,EAAE;YACP,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,4GAA4G;aAC1H;YACD,WAAW,EAAE,iBAAiB;SAC/B;KACF;IACD,QAAQ,EAAE,CAAC,SAAS,CAAC;IACrB,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAoC;IACpE,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,iBAAiB;IACxB,WAAW,EAAE,4BAA4B;IACzC,UAAU,EAAE;QACV,UAAU,EAAE;YACV,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+GAA+G;aAC7H;YACD,WAAW,EAAE,oBAAoB;SAClC;KACF;IACD,QAAQ,EAAE,CAAC,YAAY,CAAC;IACxB,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAwC;IAC5E,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,EAAE;IACd,oBAAoB,EAAE;QACpB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;SACf;KACF;IACD,QAAQ,EAAE,EAAE;CACb,CAAA;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,6DAA6D;IAC1E,UAAU,EAAE;QACV,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,6BAA6B;SAC3C;QACD,EAAE,EAAE;YACF,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,2BAA2B;SACzC;QACD,SAAS,EAAE;YACT,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,yCAAyC;SACvD;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,sCAAsC;SACpD;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;YACrC,WAAW,EAAE,uDAAuD;SACrE;KACF;IACD,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC;IACvD,oBAAoB,EAAE,KAAK;CAC5B,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAqC;IACtE,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,6BAA6B;IAC1C,UAAU,EAAE;QACV,WAAW,EAAE;YACX,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,kBAAkB;YACzB,WAAW,EAAE,aAAa;SAC3B;KACF;IACD,QAAQ,EAAE,CAAC,aAAa,CAAC;IACzB,oBAAoB,EAAE,KAAK;CAC5B,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/viable-common",
3
- "version": "0.0.34",
3
+ "version": "0.0.36",
4
4
  "license": "MIT",
5
5
  "description": "Runtime-free contracts of the OwlMeans Viable platform — the analysis, design and metadata shapes of a generated project, its target-shape manifest, the slot command vocabulary, the connector protocol and the conversion vocabulary, and the intent-first hand-off from the public site to the platform.",
6
6
  "type": "module",
@@ -109,6 +109,11 @@ export const AccessBlockSchema: JSONSchemaType<AccessBlock> = {
109
109
  - admin - means the project owner only: authenticated and holding the admin marker
110
110
  `
111
111
  },
112
+ defaultEnabledPermissions: {
113
+ type: 'array', nullable: true, items: { type: 'string' },
114
+ description: 'Subset of permissions safe to grant to every signed-in end user by default. '
115
+ + 'Only include a permission when all matching routes enforce the intended public or own-record visibility.',
116
+ },
112
117
  },
113
118
  required: ["permissions", "level"],
114
119
  additionalProperties: false
package/src/dev/types.ts CHANGED
@@ -31,6 +31,8 @@ export interface AccessBlock {
31
31
  */
32
32
  permissions: string[]
33
33
  level: AccessLevel
34
+ /** Gate params safe for every newly signed-in user; a subset of permissions. */
35
+ defaultEnabledPermissions?: string[]
34
36
  }
35
37
 
36
38
  /**
@@ -41,6 +41,9 @@ export interface OwlMeansFetchErrorPayload {
41
41
  status: number
42
42
  statusText: string
43
43
  body: string
44
+ /** Server-labelled auth/IAM refusal; absent for unrelated HTTP failures. */
45
+ denialKind?: string
46
+ incidentId?: string
44
47
  }
45
48
 
46
49
  /**
@@ -76,4 +79,3 @@ export type OwlMenasPreviewPayloads =
76
79
  | OwlMeansPromiseRejectionPayload
77
80
  | OwlMeansFetchErrorPayload
78
81
  | OwlMeansCaughtErrorPayload
79
-
@@ -1,4 +1,4 @@
1
- import type { BentoFragmentKind } from './types.js'
1
+ import type { BentoFragmentKind, LandingGateFieldKind } from './types.js'
2
2
 
3
3
  /**
4
4
  * The shapes a drawn widget can take.
@@ -34,3 +34,16 @@ export const AREA_SECTION_CAP = 6
34
34
  * value nothing can draw is a tile with an empty bottom.
35
35
  */
36
36
  export const BENTO_FRAGMENT_KINDS: BentoFragmentKind[] = ['list', 'note', 'people', 'steps']
37
+
38
+ /**
39
+ * The controls a landing-gate field can be — the simplest native inputs, and no picker of any
40
+ * kind. A closed set for the same reason as {@link BENTO_FRAGMENT_KINDS}: each value is one plain
41
+ * element the seed's gate knows how to draw.
42
+ */
43
+ export const LANDING_GATE_FIELD_KINDS: LandingGateFieldKind[] = ['text', 'select', 'number', 'date']
44
+
45
+ /** The most fields a landing gate carries. A form longer than this is a screen, not an entry. */
46
+ export const LANDING_GATE_MAX_FIELDS = 3
47
+
48
+ /** The options a `select` field carries: fewer is no choice, more is a list to browse. */
49
+ export const LANDING_GATE_OPTIONS = { min: 2, max: 6 } as const
@@ -1,9 +1,9 @@
1
1
  import type { JSONSchemaType } from 'ajv'
2
2
 
3
3
  import { ProjectArea } from '../areas/consts.js'
4
- import { BENTO_FRAGMENT_KINDS, WidgetKind } from './consts.js'
4
+ import { BENTO_FRAGMENT_KINDS, LANDING_GATE_FIELD_KINDS, WidgetKind } from './consts.js'
5
5
  import type {
6
- BentoFragment, GuestHomePlan, LandingGatePlan, ProductIdentity,
6
+ BentoFragment, GuestHomePlan, LandingGateAnswer, LandingGateField, LandingGatePlan, ProductIdentity,
7
7
  ScaffoldAreaPlan, ScaffoldPlan, ScaffoldStoryPlan, SketchContent,
8
8
  } from './types.js'
9
9
 
@@ -83,7 +83,8 @@ const ScaffoldStoryPlanSchema: JSONSchemaType<ScaffoldStoryPlan> = {
83
83
  screen: {
84
84
  type: 'string',
85
85
  description: 'The main screen this story will need, named "{section}/{purpose}" -'
86
- + ' e.g. "Requests/Submit a request". The section part must equal the section above'
86
+ + ' e.g. "Requests/Submit request". The purpose is one or two words, never a sentence.'
87
+ + ' The section part must equal the section above'
87
88
  },
88
89
  widget: {
89
90
  type: 'object',
@@ -225,99 +226,129 @@ const BentoFragmentSchema: JSONSchemaType<BentoFragment> = {
225
226
  additionalProperties: false,
226
227
  }
227
228
 
228
- const LandingGatePlanSchema: JSONSchemaType<LandingGatePlan> = {
229
+ const LandingGateFieldSchema: JSONSchemaType<LandingGateField> = {
229
230
  type: 'object',
230
- title: 'LandingGatePlan',
231
- description: 'The working entry into the key end-user workflow, drawn in the hero instead of the'
232
- + ' call-to-action buttons: a guest makes a few picks, sees sample results ranked against them,'
233
- + ' and signs in to continue with the picks carried over. Every text is in the end user\'s words',
231
+ title: 'LandingGateField',
232
+ description: 'One simple, non-sensitive field of the landing gate',
234
233
  properties: {
235
- story: {
234
+ name: {
236
235
  type: 'string',
237
- description: 'The code of the landing story, copied EXACTLY as given to you. Never shown'
236
+ description: 'The camelCase key its value travels under, one word - e.g. "dish"'
238
237
  },
239
- target: {
240
- type: 'string', nullable: true,
241
- description: 'Leave it out - the platform fills it'
242
- },
243
- question: {
238
+ label: {
244
239
  type: 'string',
245
- description: 'The question the gate asks, 3-6 words, in the end user\'s words - e.g. "What\'s'
246
- + ' in your pantry?"'
240
+ description: 'The visible label in the end user\'s words, 2-5 words - e.g. "What are you baking?"'
247
241
  },
248
- hint: { type: 'string', description: 'A short reassurance beside it, e.g. "No account needed"' },
249
- label: {
242
+ kind: {
250
243
  type: 'string',
251
- description: 'The accessible name of the group of choices, 2-3 words - e.g. "Your pantry"'
244
+ enum: LANDING_GATE_FIELD_KINDS,
245
+ description: 'text (a short line, the default), select (ONE choice out of 2-6 plain options),'
246
+ + ' number, or date. Nothing else exists: no chips, no toggles, no multiple choice'
252
247
  },
253
- inputs: {
254
- type: 'array',
255
- items: { type: 'string' },
256
- description: '5 to 8 things a guest can pick, 1-3 words each, from the story\'s own domain.'
257
- + ' Nothing personal, nothing sensitive, nothing that needs an account'
248
+ placeholder: {
249
+ type: 'string', nullable: true,
250
+ description: 'text or number only: an example value, e.g. "Rye sourdough". Never personal'
258
251
  },
259
- selected: {
260
- type: 'array',
252
+ options: {
253
+ type: 'array', nullable: true,
261
254
  items: { type: 'string' },
262
- description: '4 or 5 of the inputs above, copied exactly, pre-selected so the first view'
263
- + ' already shows results'
255
+ description: 'select only: 2 to 6 plain options, 1-3 words each'
264
256
  },
257
+ },
258
+ required: ['name', 'label', 'kind'],
259
+ additionalProperties: false,
260
+ }
261
+
262
+ /** What the gate's texts tell the planning model — one place, shared by the answer and stored schemas. */
263
+ const GATE_TEXT = {
264
+ description: 'The working entry into the key end-user workflow, drawn in the hero instead of the'
265
+ + ' call-to-action buttons: ONE SMALL FORM - a heading, one to three simple non-sensitive'
266
+ + ' fields, one button. A guest fills it in, signs in, and continues with what they entered.'
267
+ + ' No choices to browse, no sample results, no counts, no previews. Every text is in the end'
268
+ + ' user\'s words',
269
+ story: 'The code of the landing story, copied EXACTLY as given to you. Never shown',
270
+ target: 'Leave it out - the platform fills it',
271
+ question: 'The heading of the form, 3-6 words, in the end user\'s words - e.g. "What are you'
272
+ + ' baking?"',
273
+ fields: 'The fields, AS FEW AS POSSIBLE: one whenever one is enough, never more than three. They'
274
+ + ' are the first things the story\'s own screen asks for, in the same words',
275
+ cta: 'The button label, a verb first, 2-3 words and an arrow - e.g. "Start my post →"',
276
+ note: 'One short muted line under the form: no account is needed yet and what was entered comes'
277
+ + ' along - e.g. "No account needed. What you enter comes with you."',
278
+ }
279
+
280
+ /** The pre-form keys of a stored gate: optional, described as history, never offered to the model. */
281
+ const LEGACY_GATE_NOTE = 'Pre-form shape, never written'
282
+
283
+ /**
284
+ * What the planning MODEL answers for the gate: the form and nothing older. The stored schema below
285
+ * adds the pre-form keys as optional, so a plan written before the gate became a form still
286
+ * validates; the model is never offered them.
287
+ */
288
+ const LandingGateAnswerSchema: JSONSchemaType<LandingGateAnswer> = {
289
+ type: 'object',
290
+ title: 'LandingGatePlan',
291
+ description: GATE_TEXT.description,
292
+ properties: {
293
+ story: { type: 'string', description: GATE_TEXT.story },
294
+ target: { type: 'string', nullable: true, description: GATE_TEXT.target },
295
+ question: { type: 'string', description: GATE_TEXT.question },
296
+ fields: { type: 'array', items: LandingGateFieldSchema, description: GATE_TEXT.fields },
297
+ cta: { type: 'string', description: GATE_TEXT.cta },
298
+ note: { type: 'string', description: GATE_TEXT.note },
299
+ },
300
+ required: ['story', 'question', 'fields', 'cta', 'note'],
301
+ additionalProperties: false,
302
+ }
303
+
304
+ /**
305
+ * The gate as a plan may STORE it: the form, plus the pre-form keys (chips, sample records, a live
306
+ * count) as optional. A schema that validates a stored document only ever grows optional.
307
+ */
308
+ const LandingGatePlanSchema: JSONSchemaType<LandingGatePlan> = {
309
+ type: 'object',
310
+ title: 'LandingGatePlan',
311
+ description: GATE_TEXT.description,
312
+ properties: {
313
+ story: { type: 'string', description: GATE_TEXT.story },
314
+ target: { type: 'string', nullable: true, description: GATE_TEXT.target },
315
+ question: { type: 'string', description: GATE_TEXT.question },
316
+ fields: { type: 'array', nullable: true, items: LandingGateFieldSchema, description: GATE_TEXT.fields },
317
+ cta: { type: 'string', description: GATE_TEXT.cta },
318
+ note: { type: 'string', description: GATE_TEXT.note },
319
+ hint: { type: 'string', nullable: true, description: LEGACY_GATE_NOTE },
320
+ label: { type: 'string', nullable: true, description: LEGACY_GATE_NOTE },
321
+ inputs: { type: 'array', nullable: true, items: { type: 'string' }, description: LEGACY_GATE_NOTE },
322
+ selected: { type: 'array', nullable: true, items: { type: 'string' }, description: LEGACY_GATE_NOTE },
265
323
  results: {
266
- type: 'array',
324
+ type: 'array', nullable: true,
267
325
  items: {
268
326
  type: 'object',
269
327
  properties: {
270
- title: { type: 'string', description: 'A realistic record title, 2-4 words' },
271
- meta: {
272
- type: 'string',
273
- description: 'One short line: how well it fits and one fact, e.g. "Uses all 3 · 3 h 20 min"'
274
- },
275
- needs: {
276
- type: 'array',
277
- items: { type: 'string' },
278
- description: '2-4 of the inputs above, copied exactly, that this record uses'
279
- },
328
+ title: { type: 'string' },
329
+ meta: { type: 'string' },
330
+ needs: { type: 'array', items: { type: 'string' } },
280
331
  },
281
332
  required: ['title', 'meta', 'needs'],
282
333
  additionalProperties: false,
283
334
  },
284
- description: '3 or 4 sample records the picks are ranked against - illustrative, never real data'
335
+ description: LEGACY_GATE_NOTE
285
336
  },
286
337
  count: {
287
- type: 'object',
338
+ type: 'object', nullable: true,
288
339
  properties: {
289
- one: { type: 'string', description: 'The count for one match, with {n}: "{n} bake matches"' },
290
- many: { type: 'string', description: 'The count for several, with {n}: "{n} bakes match"' },
291
- none: { type: 'string', description: 'The count for none, e.g. "No matches yet"' },
340
+ one: { type: 'string' },
341
+ many: { type: 'string' },
342
+ none: { type: 'string' },
292
343
  },
293
344
  required: ['one', 'many', 'none'],
294
345
  additionalProperties: false,
295
- description: 'The live count label; write the literal token {n} where the number goes'
296
- },
297
- empty: {
298
- type: 'string',
299
- description: 'One line shown when nothing matches, saying what to pick - e.g. "Pick two or more'
300
- + ' ingredients to see what you can bake."'
301
- },
302
- note: {
303
- type: 'string',
304
- description: 'One short line beside the button: signing in is by email and the picks come'
305
- + ' along - e.g. "Sign in with your email. Your picks come with you."'
306
- },
307
- cta: {
308
- type: 'string',
309
- description: 'The button label, a verb first, 2-3 words and an arrow - e.g. "Open recipes →"'
310
- },
311
- lock: {
312
- type: 'string',
313
- description: 'What unlocks after sign-in, as the accessible name of a lock icon - e.g. "Full'
314
- + ' method after sign-in"'
346
+ description: LEGACY_GATE_NOTE
315
347
  },
348
+ empty: { type: 'string', nullable: true, description: LEGACY_GATE_NOTE },
349
+ lock: { type: 'string', nullable: true, description: LEGACY_GATE_NOTE },
316
350
  },
317
- required: [
318
- 'story', 'question', 'hint', 'label', 'inputs', 'selected', 'results', 'count', 'empty',
319
- 'note', 'cta', 'lock',
320
- ],
351
+ required: ['story', 'question', 'cta', 'note'],
321
352
  additionalProperties: false,
322
353
  }
323
354
 
@@ -535,3 +566,28 @@ export const ScaffoldPlanSchema: JSONSchemaType<ScaffoldPlan> = {
535
566
  required: ['identity', 'guestHome', 'areas', 'stories', 'motifs'],
536
567
  additionalProperties: false,
537
568
  }
569
+
570
+ /**
571
+ * The plan as the planning MODEL answers it — {@link ScaffoldPlanSchema} with the gate held to the
572
+ * form. The stored schema keeps the pre-form gate keys optional so an old plan still validates;
573
+ * offering them to the model would let it write a chip picker again. Typed as the stored plan
574
+ * because every answer is one: the answer's gate is a subset of the stored gate.
575
+ */
576
+ export const ScaffoldPlanAnswerSchema = {
577
+ ...ScaffoldPlanSchema,
578
+ properties: {
579
+ ...ScaffoldPlanSchema.properties,
580
+ guestHome: {
581
+ ...GuestHomePlanSchema,
582
+ properties: {
583
+ ...GuestHomePlanSchema.properties,
584
+ gate: {
585
+ ...LandingGateAnswerSchema,
586
+ nullable: true,
587
+ description: 'ONLY when you were given a landing story; omit it otherwise. '
588
+ + LandingGateAnswerSchema.description,
589
+ },
590
+ },
591
+ },
592
+ },
593
+ } as unknown as JSONSchemaType<ScaffoldPlan>
@@ -119,42 +119,83 @@ export interface BentoFragment {
119
119
  rows: { label: string, value?: string }[]
120
120
  }
121
121
 
122
+ /**
123
+ * What kind of control a landing-gate field is. A CLOSED set of the simplest native inputs: each
124
+ * value is one plain element, so there is nothing here a visitor has to learn, and nothing that
125
+ * can grow into a picker, a chip group or a preview.
126
+ */
127
+ export type LandingGateFieldKind = 'text' | 'select' | 'number' | 'date'
128
+
129
+ /** One simple, non-sensitive field of the landing gate. */
130
+ export interface LandingGateField {
131
+ /** The camelCase key the entered value travels under in the landing handoff: "dish". */
132
+ name: string
133
+ /** The visible label, in the end user's words: "What are you baking?". */
134
+ label: string
135
+ kind: LandingGateFieldKind
136
+ /** An example value shown inside an empty text or number field — never a personal one. */
137
+ placeholder?: string
138
+ /** `select` only: 2–6 plain options. */
139
+ options?: string[]
140
+ }
141
+
122
142
  /**
123
143
  * The landing gate — the working entry into the product's key END-USER workflow, drawn in the
124
144
  * hero where the call-to-action pills would otherwise be.
125
145
  *
126
- * A guest makes a few non-sensitive choices on the landing page, sees sample results ranked
127
- * against them, and signs in to continue on the story's full-scale screen with those choices
128
- * carried over. Every field is copy or sample data in the end user's own words; nothing here is
129
- * an address the model invented — `target` is filled by code.
146
+ * A guest fills in one to three simple non-sensitive fields on the landing page and signs in to
147
+ * continue on the story's full-scale screen with what they entered already in place. It is a small
148
+ * form and nothing more: no choices to browse, no sample results, no counts. Every text is copy in
149
+ * the end user's own words; nothing here is an address the model invented — `target` is filled by
150
+ * code.
151
+ *
152
+ * The keys after `note` are the shape a plan had before the gate became a form (chips, sample
153
+ * records, a live count). They stay so a plan STORED under the old shape still validates and
154
+ * still reads; nothing writes them and nothing draws from them, and a gate that carries no
155
+ * `fields` is drawn as no gate at all.
130
156
  */
131
157
  export interface LandingGatePlan {
132
158
  /** The key end-user story's code — never rendered. */
133
159
  story: string
134
160
  /** Entrypoint ALIAS of the story's full-scale screen in the user area (filled by code, not the model). */
135
161
  target?: string
136
- /** The question the gate asks, in the end user's words: "What's in your pantry?". */
162
+ /** The heading of the form, in the end user's words: "What are you baking?". */
137
163
  question: string
138
- /** The reassurance beside it: "No account needed". */
139
- hint: string
140
- /** The accessible name of the chip group: "Your pantry". */
141
- label: string
142
- /** 5–8 chip labels the guest picks from. */
143
- inputs: string[]
144
- /** 4–5 of `inputs`, pre-selected so the first view already shows results. */
145
- selected: string[]
146
- /** 3–4 sample records; `needs` is the subset of `inputs` each one uses. */
147
- results: { title: string, meta: string, needs: string[] }[]
148
- /** The live count label; `{n}` is replaced by the number ("{n} bakes match"). */
149
- count: { one: string, many: string, none: string }
150
- /** The line shown when nothing matches the picks. */
151
- empty: string
152
- /** The line beside the CTA: "Sign in with your email. Your picks come with you.". */
164
+ /** The fields, one to three — one whenever one is enough. Absent only on a plan stored under the old shape. */
165
+ fields?: LandingGateField[]
166
+ /** The one button's label: "Start my post →". */
167
+ cta: string
168
+ /** The muted line under the form: "No account needed. What you enter comes with you.". */
153
169
  note: string
154
- /** The CTA label: "Open recipes →". */
170
+ /** @deprecated Pre-form shape, kept for stored plans only. */
171
+ hint?: string
172
+ /** @deprecated Pre-form shape, kept for stored plans only. */
173
+ label?: string
174
+ /** @deprecated Pre-form shape, kept for stored plans only. */
175
+ inputs?: string[]
176
+ /** @deprecated Pre-form shape, kept for stored plans only. */
177
+ selected?: string[]
178
+ /** @deprecated Pre-form shape, kept for stored plans only. */
179
+ results?: { title: string, meta: string, needs: string[] }[]
180
+ /** @deprecated Pre-form shape, kept for stored plans only. */
181
+ count?: { one: string, many: string, none: string }
182
+ /** @deprecated Pre-form shape, kept for stored plans only. */
183
+ empty?: string
184
+ /** @deprecated Pre-form shape, kept for stored plans only. */
185
+ lock?: string
186
+ }
187
+
188
+ /**
189
+ * The gate as the planning MODEL answers it: the form, and none of the pre-form keys. Assignable
190
+ * to {@link LandingGatePlan}, which is what a plan stores.
191
+ */
192
+ export interface LandingGateAnswer {
193
+ story: string
194
+ target?: string
195
+ question: string
196
+ fields: LandingGateField[]
155
197
  cta: string
156
- /** The accessible name of a result row's lock icon: "Full method after sign-in". */
157
- lock: string
198
+ note: string
158
199
  }
159
200
 
160
201
  /** The guest area's landing page — the product's public face. */
package/src/ux/schemas.ts CHANGED
@@ -11,7 +11,7 @@ export const UXScreenListSchema: JSONSchemaType<UXScreenList> = {
11
11
  type: "array",
12
12
  items: {
13
13
  type: "string",
14
- description: "Technical screen name, no spaces, kebab-case notation with slashes allowed"
14
+ description: "Technical screen name, no spaces, kebab-case notation with slashes allowed; every part is one or two words"
15
15
  },
16
16
  description: "List of screens"
17
17
  },
@@ -29,7 +29,7 @@ export const UXComponentListSchema: JSONSchemaType<UXComponentList> = {
29
29
  type: "array",
30
30
  items: {
31
31
  type: "string",
32
- description: "Technical component name, no spaces, kebab-case notation with slashes allowed"
32
+ description: "Technical component name, no spaces, kebab-case notation with slashes allowed; every part is one or two words"
33
33
  },
34
34
  description: "List of components"
35
35
  },