@vcp-dev/contracts 0.3.14
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/README.md +48 -0
- package/dist/cms-collection-binding.d.ts +34 -0
- package/dist/cms-public-url.d.ts +6 -0
- package/dist/colorway-distinctness.d.ts +24 -0
- package/dist/colorway-distinctness.js +1 -0
- package/dist/connect-dynamic-collection.d.ts +175 -0
- package/dist/connect-form.d.ts +134 -0
- package/dist/deployment-runtime.d.ts +8 -0
- package/dist/design-tokens.d.ts +54 -0
- package/dist/design-tokens.js +1 -0
- package/dist/font-catalog.d.ts +85 -0
- package/dist/index.d.ts +11979 -0
- package/dist/index.js +1 -0
- package/dist/page-slug.d.ts +54 -0
- package/dist/site-edit-capability.d.ts +116 -0
- package/dist/site-edit-class-name-source.d.ts +264 -0
- package/dist/site-edit-command-result.d.ts +50 -0
- package/dist/site-edit-element-property.d.ts +10 -0
- package/dist/site-edit-event.d.ts +79 -0
- package/dist/site-edit-identity.d.ts +10 -0
- package/dist/site-edit-operation.d.ts +593 -0
- package/dist/site-edit-patch-plan.d.ts +35 -0
- package/dist/site-edit-render-document.d.ts +987 -0
- package/dist/site-edit-repeat-instance-key.d.ts +11 -0
- package/dist/site-edit-runtime-capability.d.ts +21 -0
- package/dist/site-edit-runtime-capability.js +1 -0
- package/dist/site-edit-version.d.ts +23 -0
- package/dist/site-locale.d.ts +94 -0
- package/dist/theme-presets.d.ts +16 -0
- package/dist/user-facing-copy.d.ts +75 -0
- package/dist/workspace-design-apply.d.ts +19 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# `@vcp-dev/contracts`
|
|
2
|
+
|
|
3
|
+
VCP 对外共享的 TypeScript 合同包,承载站点编辑、render document、patch
|
|
4
|
+
plan、Agent / Workspace 相关 schema 与事件类型。
|
|
5
|
+
|
|
6
|
+
## 环境要求
|
|
7
|
+
|
|
8
|
+
- Node.js `>=24`
|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @vcp-dev/contracts
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 适用场景
|
|
17
|
+
|
|
18
|
+
- 校验 site edit operation / patch plan 输入输出
|
|
19
|
+
- 复用 site edit runtime fallback 标签集合与能力 fallback helper
|
|
20
|
+
- 复用 `site_id`、`snapshot_id`、`tenant_id` 等稳定边界字段
|
|
21
|
+
- 在服务端、工具链或外部集成中共享 Zod schema 与推导类型
|
|
22
|
+
|
|
23
|
+
## 示例
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import {
|
|
27
|
+
SiteEditOperationRequestSchema,
|
|
28
|
+
type SiteEditOperationRequest,
|
|
29
|
+
} from "@vcp-dev/contracts";
|
|
30
|
+
|
|
31
|
+
const request: SiteEditOperationRequest = SiteEditOperationRequestSchema.parse({
|
|
32
|
+
id: "op_123",
|
|
33
|
+
siteId: "site_123",
|
|
34
|
+
baseSnapshotId: "snapshot_123",
|
|
35
|
+
kind: "update-text",
|
|
36
|
+
target: { kind: "object", key: "hero-title" },
|
|
37
|
+
payload: { text: "Hello VCP" },
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 非目标
|
|
42
|
+
|
|
43
|
+
`@vcp-dev/contracts` 只提供合同、schema 与共享类型,不负责:
|
|
44
|
+
|
|
45
|
+
- 执行源码编辑
|
|
46
|
+
- 管理 snapshot 持久化
|
|
47
|
+
- 启动 preview / sandbox
|
|
48
|
+
- 触发站点发布
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* V1b binding-state 状态机(计划决策 2):connect_dynamic_collection provision
|
|
4
|
+
* 是多步外部写(cms 建应用 → 建分类 → 灌数据 → 生成页面),run 间靠
|
|
5
|
+
* cms_collection_bindings 行防 orphan。合法推进:
|
|
6
|
+
* provisioning → cms_app_created → seeded → ready;任一步失败落 failed。
|
|
7
|
+
*/
|
|
8
|
+
export declare const BINDING_STATUSES: readonly ["provisioning", "cms_app_created", "seeded", "ready", "failed"];
|
|
9
|
+
export type BindingStatus = (typeof BINDING_STATUSES)[number];
|
|
10
|
+
/**
|
|
11
|
+
* apps/api `/internal/cms/bindings` 内网面与 agent client 之间交换的 binding
|
|
12
|
+
* 行契约,字段对齐 `cms_collection_bindings` 表(uuid 代理主键不进契约——
|
|
13
|
+
* binding 身份是 (tenant_id, site_id, collection_slug) 三元组)。
|
|
14
|
+
* created_at / updated_at 是服务端时间戳的 ISO 字符串形态。
|
|
15
|
+
*/
|
|
16
|
+
export declare const CmsCollectionBindingSchema: z.ZodObject<{
|
|
17
|
+
tenant_id: z.ZodString;
|
|
18
|
+
site_id: z.ZodString;
|
|
19
|
+
collection_slug: z.ZodString;
|
|
20
|
+
cms_collection_id: z.ZodNullable<z.ZodString>;
|
|
21
|
+
status: z.ZodEnum<{
|
|
22
|
+
provisioning: "provisioning";
|
|
23
|
+
cms_app_created: "cms_app_created";
|
|
24
|
+
seeded: "seeded";
|
|
25
|
+
ready: "ready";
|
|
26
|
+
failed: "failed";
|
|
27
|
+
}>;
|
|
28
|
+
owned_by_vcp: z.ZodBoolean;
|
|
29
|
+
run_id: z.ZodNullable<z.ZodString>;
|
|
30
|
+
last_error: z.ZodNullable<z.ZodString>;
|
|
31
|
+
created_at: z.ZodString;
|
|
32
|
+
updated_at: z.ZodString;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
export type CmsCollectionBinding = z.infer<typeof CmsCollectionBindingSchema>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type DesignColorSeeds, type DesignSurfaceMode } from "./design-tokens.js";
|
|
2
|
+
/**
|
|
3
|
+
* 视觉调性 3 张配色卡的"是否肉眼可分"度量,仅供 clarify C2 telemetry(不重生成、
|
|
4
|
+
* 不阻断)。关键:用户感知的"同背景"来自派生 `deriveDesignColors(...)["--background"]`,
|
|
5
|
+
* 而 light 分支把 background 钉成 `oklch(0.98, 0.01, hue)`(L/C 常量、只 hue 微变),
|
|
6
|
+
* 所以**不能比 raw `colorSeeds.primary`**(那量的是色块差异,不是背景差异)。这里对每个
|
|
7
|
+
* colorway 走共享派生后,在派生结果上判可分:surfaceMode 多样性 + 背景 ciede2000 deltaE +
|
|
8
|
+
* primary/accent 的**色相**间距(用色相而非整体 deltaE,避免同色系不同明度被误判可分)。
|
|
9
|
+
* 命名色(cream/amber/slate)经 deriveDesignColors 内部的 SEMANTIC_SEED_ALIASES + hash
|
|
10
|
+
* 一律可解析,无需自写颜色解析、无需跳过。
|
|
11
|
+
*/
|
|
12
|
+
export interface ColorwayInput {
|
|
13
|
+
colorSeeds?: DesignColorSeeds;
|
|
14
|
+
surfaceMode?: DesignSurfaceMode;
|
|
15
|
+
}
|
|
16
|
+
export interface ColorwayDistinctnessResult {
|
|
17
|
+
/** 派生卡片背景两两 ciede2000 deltaE 的最小值;insufficient 时为 null。 */
|
|
18
|
+
minBackgroundDeltaE: number | null;
|
|
19
|
+
/** true = 三张配色肉眼不可分(同色系微变体、同 surface、同色相)。 */
|
|
20
|
+
tooSimilar: boolean;
|
|
21
|
+
/** 可解析的 colorway < 2,无法判定。 */
|
|
22
|
+
insufficient: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function measureColorwayDistinctness(colorways: ColorwayInput[]): ColorwayDistinctnessResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{converter as K,differenceCiede2000 as W}from"culori";import{converter as P,parse as k,wcagContrast as v}from"culori";var f=P("oklch"),M=4.5,$={paper:"oklch(0.92 0.008 250)",cream:"oklch(0.90 0.035 85)",sand:"oklch(0.75 0.05 78)",stone:"oklch(0.60 0.02 75)",ash:"oklch(0.60 0.012 250)",slate:"oklch(0.45 0.025 250)",charcoal:"oklch(0.30 0.015 255)",ink:"oklch(0.25 0.04 260)",sky:"oklch(0.72 0.12 230)",blue:"oklch(0.58 0.17 250)","medical blue":"oklch(0.58 0.12 235)",indigo:"oklch(0.50 0.18 280)",navy:"oklch(0.40 0.10 258)",ocean:"oklch(0.55 0.13 220)","slate blue":"oklch(0.46 0.06 245)",teal:"oklch(0.60 0.12 195)","soft aqua":"oklch(0.78 0.07 190)",mint:"oklch(0.78 0.10 165)",sage:"oklch(0.65 0.05 145)",green:"oklch(0.58 0.15 145)","clinical green":"oklch(0.62 0.12 155)",emerald:"oklch(0.60 0.16 155)",forest:"oklch(0.45 0.10 145)",olive:"oklch(0.58 0.08 115)",lime:"oklch(0.72 0.17 130)",yellow:"oklch(0.82 0.15 100)",gold:"oklch(0.72 0.14 85)",amber:"oklch(0.70 0.16 70)",orange:"oklch(0.66 0.18 55)",coral:"oklch(0.68 0.16 32)",terracotta:"oklch(0.55 0.12 42)",rust:"oklch(0.50 0.13 38)",brown:"oklch(0.45 0.07 55)",rose:"oklch(0.65 0.16 18)",red:"oklch(0.58 0.20 25)",crimson:"oklch(0.52 0.20 22)",wine:"oklch(0.42 0.13 18)",pink:"oklch(0.72 0.14 0)",magenta:"oklch(0.60 0.22 345)",lavender:"oklch(0.72 0.08 295)",violet:"oklch(0.58 0.19 295)",purple:"oklch(0.52 0.19 305)",plum:"oklch(0.45 0.13 325)",electric:"oklch(0.62 0.23 285)","clean white":"oklch(0.97 0.01 245)","cool gray":"oklch(0.62 0.02 245)",zinc:"oklch(0.60 0.012 250)",gray:"oklch(0.60 0.012 250)",grey:"oklch(0.60 0.012 250)",neutral:"oklch(0.60 0.005 250)",gunmetal:"oklch(0.30 0.015 255)"};function E(e){let o=e.colorSeeds??{primary:"slate",accent:"blue",neutral:"zinc"},c=e.surfaceMode,r=g(o.primary||"slate"),t=a(r),n=a(g(o.accent||"blue")),i=o.neutral?g(o.neutral):V(r),l=h(i.h),u,s,d,p,b,y;c==="dark"?(u=a({mode:"oklch",l:.14,c:.03,h:l}),s=a({mode:"oklch",l:.95,c:.02,h:l}),d=a({mode:"oklch",l:.2,c:.04,h:l}),p=a({mode:"oklch",l:.29,c:.05,h:l}),b=a({mode:"oklch",l:.78,c:.02,h:l}),y=a({mode:"oklch",l:.35,c:.06,h:l})):(u=a({mode:"oklch",l:.98,c:.01,h:l}),s=a({mode:"oklch",l:.2,c:.02,h:l}),d=a({mode:"oklch",l:.96,c:.015,h:l}),p=a({mode:"oklch",l:.92,c:.02,h:l}),b=a({mode:"oklch",l:.43,c:.02,h:l}),y=a({mode:"oklch",l:.84,c:.025,h:l}));let S=c!=="dark",D={"--background":u,"--foreground":s,"--card":d,"--card-foreground":s,"--muted":p,"--muted-foreground":b,"--border":y,"--input":y,"--ring":n,"--primary":t,"--primary-foreground":m(t),"--primary-hover":x(t,S),"--accent":n,"--accent-foreground":m(n),"--accent-ink":w(n,u),"--accent-subtle":j(n,S),"--accent-hover":x(n,S),"--overlay-on-dark":a({mode:"oklch",l:.96,c:.02,h:l}),"--overlay-on-light":a({mode:"oklch",l:.2,c:.02,h:l})},L=s,O=m(s),T=C(s,l),_=w(n,s),N=f(k(t)??t),B=h(N?.h),H=C(t,B),G=w(n,t);return R({...D,...{"--surface-inverse":L,"--surface-inverse-foreground":O,"--surface-inverse-muted":T,"--surface-inverse-accent-ink":_,"--surface-primary-muted":H,"--surface-primary-accent-ink":G}},o)}function R(e,o){let c=a({mode:"oklch",l:.58,c:.22,h:28}),r=a({mode:"oklch",l:.6,c:.14,h:150}),t=a({mode:"oklch",l:.75,c:.15,h:75}),n={...e,"--popover":"var(--card)","--popover-foreground":"var(--card-foreground)","--secondary":"var(--muted)","--secondary-foreground":"var(--foreground)","--destructive":c,"--destructive-foreground":m(c),"--success":r,"--success-foreground":m(r),"--warning":t,"--warning-foreground":m(t)},[i,l]=z(o,n);return n["--supporting-0"]=i,n["--supporting-1"]=l,q(n["--accent"]).forEach((s,d)=>{n[`--chart-${d+1}`]=s}),n}function z(e,o){let t=(e.supporting??[]).filter(i=>!!(i&&i.trim())).slice(0,2).map(i=>a(g(i))),n=[o["--primary"],o["--accent"]];for(;t.length<2;)t.push(n[t.length]);return[t[0],t[1]]}function g(e,o="paper"){let c=(e??"").trim();if(!c)return g(o);let r=$[c.toLowerCase()]??c,t=k(r);if(t){let n=f(t);if(n)return n}return U(c)}function U(e){let o=2166136261,c=e.toLowerCase();for(let i=0;i<c.length;i++)o^=c.charCodeAt(i),o=Math.imul(o,16777619)>>>0;let r=o%360,t=.08+(o>>>9)%9/100;return{mode:"oklch",l:.52+(o>>>18)%16/100,c:t,h:r}}function V(e){return{mode:"oklch",l:.6,c:.02,h:h(e.h)}}function x(e,o){let c=f(k(e)??e);if(!c)return e;let r=o?-.06:.06,t=Math.max(.06,Math.min(.97,h(c.l)+r));return a({mode:"oklch",l:t,c:h(c.c),h:h(c.h)})}function j(e,o){let c=f(k(e)??e),r=h(c?.h),t=Math.min(h(c?.c),o?.05:.06);return a({mode:"oklch",l:o?.95:.24,c:t,h:r})}function q(e){let o=f(k(e)??e),c=h(o?.h),r=Math.max(.12,Math.min(h(o?.c),.16));return[0,72,144,216,288].map(t=>a({mode:"oklch",l:.62,c:r,h:(c+t)%360}))}function m(e){let o=k(e),c=o?f(o):void 0,r=h(c?.h),t={mode:"oklch",l:.99,c:.01,h:r},n={mode:"oklch",l:.18,c:.02,h:r},i=v(o??e,t),l=v(o??e,n);return a(i>=l?t:n)}function w(e,o){let c=f(k(e)??e);if(!c)return e;let r=h(c.h),t=h(c.c),n=h(c.l),i=f(k(o)??o),u=(i?h(i.l)>=.5:!0)?-.02:.02;for(let s=0;s<=50;s++){let d=n+u*s;if(d<=0||d>=1)break;let p={mode:"oklch",l:d,c:t,h:r};if(v(p,o)>=M)return a(p)}return m(o)}function C(e,o){let c=f(k(e)??e),t=(c?h(c.l):.5)>=.5,n=t?.75:.35,i=t?-.02:.02;for(let l=0;l<=50;l++){let u=n+i*l;if(u<=0||u>=1)break;let s={mode:"oklch",l:u,c:.02,h:o};if(v(s,e)>=M)return a(s)}return m(e)}function h(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function a(e){let o=h(e.l),c=h(e.c),r=h(e.h);return`oklch(${o.toFixed(2)} ${c.toFixed(2)} ${r.toFixed(2)})`}var X=10,I=25,J=K("oklch"),Q=W();function Y(e){return typeof e.colorSeeds?.primary=="string"&&e.colorSeeds.primary.trim().length>0}function F(e){let o=J(e);return o&&typeof o.h=="number"?o.h:void 0}function A(e){let o=0;for(let c=0;c<e.length;c+=1)for(let r=c+1;r<e.length;r+=1){let t=e[c],n=e[r];if(t===void 0||n===void 0)continue;let i=Math.abs(t-n)%360,l=i>180?360-i:i;l>o&&(o=l)}return o}function Z(e){let o=0,c=1/0;for(let r=0;r<e.length;r+=1)for(let t=r+1;t<e.length;t+=1){let n=Q(e[r],e[t]);n>o&&(o=n),n<c&&(c=n)}return{max:o,min:c===1/0?0:c}}function re(e){let o=e.filter(Y);if(o.length<2)return{minBackgroundDeltaE:null,tooSimilar:!1,insufficient:!0};let c=o.map(s=>s.surfaceMode??"light"),r=o.map((s,d)=>E({colorSeeds:s.colorSeeds,surfaceMode:c[d]})),t=Z(r.map(s=>s["--background"])),n=A(r.map(s=>F(s["--primary"]))),i=A(r.map(s=>F(s["--accent"]))),u=!(new Set(c).size===1)||t.max>=X||n>=I||i>=I;return{minBackgroundDeltaE:t.min,tooSimilar:!u,insufficient:!1}}export{re as measureColorwayDistinctness};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** V1b provision 可定义的字段类型词表(非媒体、非分类;与 CMS 字段类型 1:1)。spec §5.3。 */
|
|
3
|
+
export declare const FIELD_TYPES: readonly ["title", "text", "richtext", "number", "boolean", "date", "datetime", "url", "email", "color", "select", "multiselect", "tag"];
|
|
4
|
+
export type FieldType = (typeof FIELD_TYPES)[number];
|
|
5
|
+
export declare const FieldDeclSchema: z.ZodObject<{
|
|
6
|
+
name: z.ZodString;
|
|
7
|
+
type: z.ZodEnum<{
|
|
8
|
+
number: "number";
|
|
9
|
+
boolean: "boolean";
|
|
10
|
+
title: "title";
|
|
11
|
+
text: "text";
|
|
12
|
+
richtext: "richtext";
|
|
13
|
+
date: "date";
|
|
14
|
+
datetime: "datetime";
|
|
15
|
+
url: "url";
|
|
16
|
+
email: "email";
|
|
17
|
+
color: "color";
|
|
18
|
+
select: "select";
|
|
19
|
+
multiselect: "multiselect";
|
|
20
|
+
tag: "tag";
|
|
21
|
+
}>;
|
|
22
|
+
label: z.ZodString;
|
|
23
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
export type FieldDecl = z.infer<typeof FieldDeclSchema>;
|
|
27
|
+
/** 从 CMS schema 读回的落定字段(含 CMS 原生类型字符串)。 */
|
|
28
|
+
export declare const ResolvedFieldSchema: z.ZodObject<{
|
|
29
|
+
name: z.ZodString;
|
|
30
|
+
cms_type: z.ZodString;
|
|
31
|
+
label: z.ZodOptional<z.ZodString>;
|
|
32
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
33
|
+
value_shape: z.ZodOptional<z.ZodString>;
|
|
34
|
+
front_display: z.ZodOptional<z.ZodEnum<{
|
|
35
|
+
visible: "visible";
|
|
36
|
+
internal: "internal";
|
|
37
|
+
forbidden: "forbidden";
|
|
38
|
+
}>>;
|
|
39
|
+
choices: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
40
|
+
value: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
41
|
+
label: z.ZodString;
|
|
42
|
+
}, z.core.$strip>>>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export type ResolvedField = z.infer<typeof ResolvedFieldSchema>;
|
|
45
|
+
export declare const ConnectDynamicCollectionInputSchema: z.ZodObject<{
|
|
46
|
+
route_file_path: z.ZodString;
|
|
47
|
+
target_component_path: z.ZodString;
|
|
48
|
+
content_type_hint: z.ZodString;
|
|
49
|
+
required_fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
50
|
+
name: z.ZodString;
|
|
51
|
+
type: z.ZodEnum<{
|
|
52
|
+
number: "number";
|
|
53
|
+
boolean: "boolean";
|
|
54
|
+
title: "title";
|
|
55
|
+
text: "text";
|
|
56
|
+
richtext: "richtext";
|
|
57
|
+
date: "date";
|
|
58
|
+
datetime: "datetime";
|
|
59
|
+
url: "url";
|
|
60
|
+
email: "email";
|
|
61
|
+
color: "color";
|
|
62
|
+
select: "select";
|
|
63
|
+
multiselect: "multiselect";
|
|
64
|
+
tag: "tag";
|
|
65
|
+
}>;
|
|
66
|
+
label: z.ZodString;
|
|
67
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
68
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
69
|
+
}, z.core.$strip>>>;
|
|
70
|
+
mode: z.ZodEnum<{
|
|
71
|
+
bind_existing: "bind_existing";
|
|
72
|
+
provision: "provision";
|
|
73
|
+
}>;
|
|
74
|
+
list_mode: z.ZodOptional<z.ZodEnum<{
|
|
75
|
+
page: "page";
|
|
76
|
+
embedded: "embedded";
|
|
77
|
+
}>>;
|
|
78
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
79
|
+
name: z.ZodString;
|
|
80
|
+
type: z.ZodEnum<{
|
|
81
|
+
number: "number";
|
|
82
|
+
boolean: "boolean";
|
|
83
|
+
title: "title";
|
|
84
|
+
text: "text";
|
|
85
|
+
richtext: "richtext";
|
|
86
|
+
date: "date";
|
|
87
|
+
datetime: "datetime";
|
|
88
|
+
url: "url";
|
|
89
|
+
email: "email";
|
|
90
|
+
color: "color";
|
|
91
|
+
select: "select";
|
|
92
|
+
multiselect: "multiselect";
|
|
93
|
+
tag: "tag";
|
|
94
|
+
}>;
|
|
95
|
+
label: z.ZodString;
|
|
96
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
97
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
98
|
+
}, z.core.$strip>>>;
|
|
99
|
+
seed_records: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
export type ConnectDynamicCollectionInput = z.infer<typeof ConnectDynamicCollectionInputSchema>;
|
|
102
|
+
export type ConnectDynamicCollectionResult = {
|
|
103
|
+
status: "bound" | "provisioned";
|
|
104
|
+
collection_slug: string;
|
|
105
|
+
detail_prefix: string;
|
|
106
|
+
schema: ResolvedField[];
|
|
107
|
+
list_view: string;
|
|
108
|
+
detail_view: string;
|
|
109
|
+
/** 逐字段人话渲染契约(LLM 写 view 的零猜测依据),确定性派生。 */
|
|
110
|
+
view_contract: string;
|
|
111
|
+
/** 工具已写入 working set 的确定性产物路径——LLM 绝不可再 create/覆盖。 */
|
|
112
|
+
created_files: string[];
|
|
113
|
+
/** 自定义消费场景照抄片段(与 already_bound 同口径);首次 bind 也回传,供 LLM 写额外自取数区块时照抄。 */
|
|
114
|
+
usage?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 幂等命中:该 collection 的 scaffold 已存在于 base snapshot(此前 run 绑定过),
|
|
118
|
+
* 本次零写入。LLM 收到后下一步:按实时重算的 view_contract + usage 片段直接写
|
|
119
|
+
* 新区块/消费代码;绝不重建 existing_files、绝不手写数据层。
|
|
120
|
+
*/
|
|
121
|
+
| {
|
|
122
|
+
status: "already_bound";
|
|
123
|
+
collection_slug: string;
|
|
124
|
+
/** 照常采样推断;采样失败回退空串(详情链接始终用 record.url,与 usage 同口径)。 */
|
|
125
|
+
detail_prefix: string;
|
|
126
|
+
schema: ResolvedField[];
|
|
127
|
+
/** 实时重算(与 bound 同源派生),不读旧产物。 */
|
|
128
|
+
view_contract: string;
|
|
129
|
+
/** 已存在的 scaffold 路径,绝不可重建(再 create 必撞 ALREADY_EXISTS)。 */
|
|
130
|
+
existing_files: string[];
|
|
131
|
+
/** 标准消费片段(嵌入区块/自定义消费场景照抄,杜绝凭记忆手写取数)。 */
|
|
132
|
+
usage: string;
|
|
133
|
+
} | {
|
|
134
|
+
status: "not_found_collection";
|
|
135
|
+
/** 站点全部可用低代码应用(slug+名称)。从中选最匹配项以 slug 或精确 name 重调,勿猜名。 */
|
|
136
|
+
available_collections: {
|
|
137
|
+
slug: string;
|
|
138
|
+
name: string;
|
|
139
|
+
}[];
|
|
140
|
+
} | {
|
|
141
|
+
status: "schema_incompatible";
|
|
142
|
+
missing_fields: string[];
|
|
143
|
+
schema: ResolvedField[];
|
|
144
|
+
} | {
|
|
145
|
+
status: "unsupported_url_template";
|
|
146
|
+
} | {
|
|
147
|
+
status: "cannot_infer_detail_prefix";
|
|
148
|
+
}
|
|
149
|
+
/** CMS 基础设施暂不可达(网络/5xx/530 瞬断),非「collection 不存在」——稍后重试,勿换名猜测。 */
|
|
150
|
+
| {
|
|
151
|
+
status: "cms_unreachable";
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* provision 编排失败专用结果态(V1b):slug 归一失败 / 内网未配置 /
|
|
155
|
+
* CMS 写链路任一步失败 / seed 发布 fail-closed。reason 是给 LLM 的
|
|
156
|
+
* 人话(含可自纠指引),不复用 not_found_collection 等 bind 语义。
|
|
157
|
+
*/
|
|
158
|
+
| {
|
|
159
|
+
status: "provision_failed";
|
|
160
|
+
reason: string;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* scaffold 写入失败(applyPatchBatch 未 applied):code 是真实失败码,
|
|
164
|
+
* 不再伪装成 not_found_collection/provision_failed(真实 run:伪装清单为空
|
|
165
|
+
* 骗 LLM 连环换名乱猜,最终绑错集合)。LLM 收到后下一步:文件已存在
|
|
166
|
+
* (PATCH_TARGET_ALREADY_EXISTS)≈ 已绑定过——原参重调本工具拿
|
|
167
|
+
* already_bound 契约;绝不换名重试或手写数据层。collection_slug 是
|
|
168
|
+
* 工具已解析落定的真实 slug(重调以它为锚,不回到 hint 猜测)。
|
|
169
|
+
*/
|
|
170
|
+
| {
|
|
171
|
+
status: "scaffold_write_failed";
|
|
172
|
+
collection_slug: string;
|
|
173
|
+
code: string;
|
|
174
|
+
reason: string;
|
|
175
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* connect_form provision 可声明的表单字段类型词表(非文件/媒体类)。
|
|
4
|
+
* 词表→CMS 表单字段类型映射在 agent 侧 `cms-forms/field-type-to-form.ts`,
|
|
5
|
+
* 与 connect-dynamic-collection 的 FIELD_TYPES/field-type-to-cms 同款分层。
|
|
6
|
+
*/
|
|
7
|
+
export declare const FORM_FIELD_TYPES: readonly ["text", "textarea", "email", "phone", "select", "radio", "multiselect", "boolean", "date", "number"];
|
|
8
|
+
export type FormFieldType = (typeof FORM_FIELD_TYPES)[number];
|
|
9
|
+
export declare const FormFieldDeclSchema: z.ZodObject<{
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
type: z.ZodEnum<{
|
|
12
|
+
number: "number";
|
|
13
|
+
boolean: "boolean";
|
|
14
|
+
text: "text";
|
|
15
|
+
date: "date";
|
|
16
|
+
email: "email";
|
|
17
|
+
select: "select";
|
|
18
|
+
multiselect: "multiselect";
|
|
19
|
+
textarea: "textarea";
|
|
20
|
+
phone: "phone";
|
|
21
|
+
radio: "radio";
|
|
22
|
+
}>;
|
|
23
|
+
label: z.ZodString;
|
|
24
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
25
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export type FormFieldDecl = z.infer<typeof FormFieldDeclSchema>;
|
|
28
|
+
export declare const ConnectFormInputSchema: z.ZodObject<{
|
|
29
|
+
form_hint: z.ZodString;
|
|
30
|
+
mode: z.ZodEnum<{
|
|
31
|
+
bind_existing: "bind_existing";
|
|
32
|
+
provision: "provision";
|
|
33
|
+
}>;
|
|
34
|
+
component_slug: z.ZodOptional<z.ZodString>;
|
|
35
|
+
name: z.ZodOptional<z.ZodString>;
|
|
36
|
+
description: z.ZodOptional<z.ZodString>;
|
|
37
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
38
|
+
name: z.ZodString;
|
|
39
|
+
type: z.ZodEnum<{
|
|
40
|
+
number: "number";
|
|
41
|
+
boolean: "boolean";
|
|
42
|
+
text: "text";
|
|
43
|
+
date: "date";
|
|
44
|
+
email: "email";
|
|
45
|
+
select: "select";
|
|
46
|
+
multiselect: "multiselect";
|
|
47
|
+
textarea: "textarea";
|
|
48
|
+
phone: "phone";
|
|
49
|
+
radio: "radio";
|
|
50
|
+
}>;
|
|
51
|
+
label: z.ZodString;
|
|
52
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
53
|
+
options: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
54
|
+
}, z.core.$strip>>>;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export type ConnectFormInput = z.infer<typeof ConnectFormInputSchema>;
|
|
57
|
+
/** 从 GET forms/{code} 读回的落定字段(field_name/field_label/field_type/is_required → 本形态)。 */
|
|
58
|
+
export declare const ResolvedFormFieldSchema: z.ZodObject<{
|
|
59
|
+
name: z.ZodString;
|
|
60
|
+
label: z.ZodString;
|
|
61
|
+
cms_type: z.ZodString;
|
|
62
|
+
required: z.ZodBoolean;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
export type ResolvedFormField = z.infer<typeof ResolvedFormFieldSchema>;
|
|
65
|
+
export type ConnectFormResult = {
|
|
66
|
+
status: "bound" | "provisioned";
|
|
67
|
+
form_code: string;
|
|
68
|
+
form_name: string;
|
|
69
|
+
/** 读回落定的表单字段(提交 data 的键 = name)。 */
|
|
70
|
+
fields: ResolvedFormField[];
|
|
71
|
+
/** 表单来源页 id(提交必带;null=CMS 未回,提交会被 cms 以 unknown_source_page 拒)。 */
|
|
72
|
+
source_page_id: number | null;
|
|
73
|
+
/** LLM 要写的表单 view 组件路径(必须 "use client")。 */
|
|
74
|
+
form_view: string;
|
|
75
|
+
/** 逐字段人话渲染契约 + 提交链路用法(LLM 写 form view 的零猜测依据),确定性派生。 */
|
|
76
|
+
form_contract: string;
|
|
77
|
+
/** 工具已写入 working set 的确定性产物路径——LLM 绝不可再 create/覆盖。 */
|
|
78
|
+
created_files: string[];
|
|
79
|
+
} | {
|
|
80
|
+
status: "not_found_form";
|
|
81
|
+
/** 站点全部可用表单(code+名称)。从中选最匹配项以 form_code 或精确 name 重调,勿猜名。 */
|
|
82
|
+
available_forms: {
|
|
83
|
+
code: string;
|
|
84
|
+
name: string;
|
|
85
|
+
}[];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 幂等命中:该表单的 scaffold 已存在于 base snapshot(此前 run 绑定过),
|
|
89
|
+
* 本次零写入。LLM 收到后下一步:按实时重算的 form_contract 写 form view,
|
|
90
|
+
* 绝不重建 existing_files、绝不手写提交链路(与 connect_dynamic_collection
|
|
91
|
+
* 的 already_bound 同款)。
|
|
92
|
+
*/
|
|
93
|
+
| {
|
|
94
|
+
status: "already_bound";
|
|
95
|
+
form_code: string;
|
|
96
|
+
form_name: string;
|
|
97
|
+
/** 实时读回落定的表单字段(提交 data 的键 = name)。 */
|
|
98
|
+
fields: ResolvedFormField[];
|
|
99
|
+
/** 表单来源页 id(提交必带;null=CMS 未回)。 */
|
|
100
|
+
source_page_id: number | null;
|
|
101
|
+
/** LLM 要写的表单 view 组件路径(必须 "use client")。 */
|
|
102
|
+
form_view: string;
|
|
103
|
+
/** 实时重算(与 bound 同源派生),不读旧产物。 */
|
|
104
|
+
form_contract: string;
|
|
105
|
+
/** 已存在的 scaffold 路径(容器 + 站点级基建),绝不可重建(再 create 必撞 ALREADY_EXISTS)。 */
|
|
106
|
+
existing_files: string[];
|
|
107
|
+
}
|
|
108
|
+
/** CMS 基础设施暂不可达(网络/5xx/530 瞬断),非「表单不存在」——稍后重试,勿换名猜测。 */
|
|
109
|
+
| {
|
|
110
|
+
status: "cms_unreachable";
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* provision 编排失败专用结果态:fields 缺失/选择类缺 options / 内网未配置 /
|
|
114
|
+
* CMS 写失败 / 读回失败。reason 是给 LLM 的人话(含可自纠指引),
|
|
115
|
+
* 不复用 not_found_form 等 bind 语义。
|
|
116
|
+
*/
|
|
117
|
+
| {
|
|
118
|
+
status: "provision_failed";
|
|
119
|
+
reason: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* scaffold 写入失败(applyPatchBatch 未 applied):code 是真实失败码,
|
|
123
|
+
* 不再伪装成 not_found_form 空清单(真实 run:伪装清单为空骗 LLM 连环换
|
|
124
|
+
* form_code 乱猜,或转去手写提交链路)。LLM 收到后下一步:文件已存在
|
|
125
|
+
* (PATCH_TARGET_ALREADY_EXISTS)≈ 已绑定过——原参重调本工具拿
|
|
126
|
+
* already_bound 契约;绝不换名重试或手写提交链路。form_code 是工具已解析
|
|
127
|
+
* 落定的真实 code(重调以它为锚,不回到 hint 猜测)。
|
|
128
|
+
*/
|
|
129
|
+
| {
|
|
130
|
+
status: "scaffold_write_failed";
|
|
131
|
+
form_code: string;
|
|
132
|
+
code: string;
|
|
133
|
+
reason: string;
|
|
134
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const DEPLOYMENT_STATUSES: readonly ["queued", "preparing_source", "building", "artifact_ready", "deploying", "released", "lock_failed", "source_prepare_failed", "build_failed", "artifact_fetch_failed", "artifact_validation_failed", "deploy_failed", "cleanup_failed"];
|
|
2
|
+
export interface RedisConnectionConfig {
|
|
3
|
+
url?: string;
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
password?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function resolveRedisConnectionConfig(env: Record<string, string | undefined>): RedisConnectionConfig;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Oklch } from "culori";
|
|
2
|
+
export type DesignSurfaceMode = "light" | "dark";
|
|
3
|
+
/** Brand color seeds. Only `primary` is conceptually required; the rest derive. */
|
|
4
|
+
export interface DesignColorSeeds {
|
|
5
|
+
primary?: string;
|
|
6
|
+
accent?: string;
|
|
7
|
+
neutral?: string;
|
|
8
|
+
supporting?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface DeriveDesignColorsInput {
|
|
11
|
+
colorSeeds?: DesignColorSeeds;
|
|
12
|
+
surfaceMode: DesignSurfaceMode;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Preferred seed vocabulary ported from cms-builder's
|
|
16
|
+
* `color_tokens.SEMANTIC_SEED_ALIASES` (oklch anchors that set hue/chroma
|
|
17
|
+
* tendency; lightness for surfaces is derived per surface mode). The trailing
|
|
18
|
+
* Tailwind neutral aliases are a thin VCP extension so the default neutral seed
|
|
19
|
+
* "zinc" (and common synonyms) resolves to a clean low-chroma neutral hue
|
|
20
|
+
* instead of hitting the unknown-label hash fallback.
|
|
21
|
+
*/
|
|
22
|
+
export declare const SEMANTIC_SEED_ALIASES: Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Returns the full color token map (`--background` … `--supporting-1`) derived
|
|
25
|
+
* from the seeds + surface mode. Pure: no I/O, deterministic.
|
|
26
|
+
*/
|
|
27
|
+
export declare function deriveDesignColors(input: DeriveDesignColorsInput): Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* Resolves a seed (alias name, CSS color, or hex) to an oklch color. Unknown
|
|
30
|
+
* domain words deterministically hash to a stable mid-tone color, mirroring
|
|
31
|
+
* cms-builder's `_color_from_unknown_label` intent.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isResolvableDesignColorSeed(seed: string): boolean;
|
|
34
|
+
/** Picks a near-white / near-black foreground with higher WCAG contrast. */
|
|
35
|
+
export declare function bestForegroundFor(background: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Readable accent *text* color for copy that sits directly on a page surface —
|
|
38
|
+
* eyebrow labels, emphasized words, prices, stat numbers, outline-button labels.
|
|
39
|
+
*
|
|
40
|
+
* `--accent` keeps the seed's own lightness so it works as a FILL: `bg-accent`
|
|
41
|
+
* paired with the adaptive `--accent-foreground`. That same value is usually too
|
|
42
|
+
* close to `--background` to read as TEXT (a light gold accent on a near-white
|
|
43
|
+
* surface lands around 2:1, well under WCAG AA). This derives a same-hue /
|
|
44
|
+
* same-chroma variant whose lightness is pushed toward the readable direction —
|
|
45
|
+
* darker on light surfaces, lighter on dark — until it clears 4.5:1 against the
|
|
46
|
+
* background, so `text-accent-ink` stays legible while remaining recognizably
|
|
47
|
+
* the brand accent. When the accent already clears 4.5:1 as-is (common on dark
|
|
48
|
+
* surfaces, or for an already-deep seed) its original lightness is kept.
|
|
49
|
+
*/
|
|
50
|
+
export declare function accentInkFor(accent: string, background: string): string;
|
|
51
|
+
/** NaN-safe channel read (achromatic colors have undefined hue in culori). */
|
|
52
|
+
export declare function channel(value: number | undefined): number;
|
|
53
|
+
/** Formats an oklch color as `oklch(L C H)` with 2-decimal precision. */
|
|
54
|
+
export declare function oklchString(color: Oklch): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{converter as _,parse as k,wcagContrast as y}from"culori";var m=_("oklch"),F=4.5,M={paper:"oklch(0.92 0.008 250)",cream:"oklch(0.90 0.035 85)",sand:"oklch(0.75 0.05 78)",stone:"oklch(0.60 0.02 75)",ash:"oklch(0.60 0.012 250)",slate:"oklch(0.45 0.025 250)",charcoal:"oklch(0.30 0.015 255)",ink:"oklch(0.25 0.04 260)",sky:"oklch(0.72 0.12 230)",blue:"oklch(0.58 0.17 250)","medical blue":"oklch(0.58 0.12 235)",indigo:"oklch(0.50 0.18 280)",navy:"oklch(0.40 0.10 258)",ocean:"oklch(0.55 0.13 220)","slate blue":"oklch(0.46 0.06 245)",teal:"oklch(0.60 0.12 195)","soft aqua":"oklch(0.78 0.07 190)",mint:"oklch(0.78 0.10 165)",sage:"oklch(0.65 0.05 145)",green:"oklch(0.58 0.15 145)","clinical green":"oklch(0.62 0.12 155)",emerald:"oklch(0.60 0.16 155)",forest:"oklch(0.45 0.10 145)",olive:"oklch(0.58 0.08 115)",lime:"oklch(0.72 0.17 130)",yellow:"oklch(0.82 0.15 100)",gold:"oklch(0.72 0.14 85)",amber:"oklch(0.70 0.16 70)",orange:"oklch(0.66 0.18 55)",coral:"oklch(0.68 0.16 32)",terracotta:"oklch(0.55 0.12 42)",rust:"oklch(0.50 0.13 38)",brown:"oklch(0.45 0.07 55)",rose:"oklch(0.65 0.16 18)",red:"oklch(0.58 0.20 25)",crimson:"oklch(0.52 0.20 22)",wine:"oklch(0.42 0.13 18)",pink:"oklch(0.72 0.14 0)",magenta:"oklch(0.60 0.22 345)",lavender:"oklch(0.72 0.08 295)",violet:"oklch(0.58 0.19 295)",purple:"oklch(0.52 0.19 305)",plum:"oklch(0.45 0.13 325)",electric:"oklch(0.62 0.23 285)","clean white":"oklch(0.97 0.01 245)","cool gray":"oklch(0.62 0.02 245)",zinc:"oklch(0.60 0.012 250)",gray:"oklch(0.60 0.012 250)",grey:"oklch(0.60 0.012 250)",neutral:"oklch(0.60 0.005 250)",gunmetal:"oklch(0.30 0.015 255)"};function W(e){let o=e.colorSeeds??{primary:"slate",accent:"blue",neutral:"zinc"},c=e.surfaceMode,l=g(o.primary||"slate"),r=n(l),t=n(g(o.accent||"blue")),h=o.neutral?g(o.neutral):z(l),s=a(h.h),u,i,d,p,b,v;c==="dark"?(u=n({mode:"oklch",l:.14,c:.03,h:s}),i=n({mode:"oklch",l:.95,c:.02,h:s}),d=n({mode:"oklch",l:.2,c:.04,h:s}),p=n({mode:"oklch",l:.29,c:.05,h:s}),b=n({mode:"oklch",l:.78,c:.02,h:s}),v=n({mode:"oklch",l:.35,c:.06,h:s})):(u=n({mode:"oklch",l:.98,c:.01,h:s}),i=n({mode:"oklch",l:.2,c:.02,h:s}),d=n({mode:"oklch",l:.96,c:.015,h:s}),p=n({mode:"oklch",l:.92,c:.02,h:s}),b=n({mode:"oklch",l:.43,c:.02,h:s}),v=n({mode:"oklch",l:.84,c:.025,h:s}));let w=c!=="dark",I={"--background":u,"--foreground":i,"--card":d,"--card-foreground":i,"--muted":p,"--muted-foreground":b,"--border":v,"--input":v,"--ring":t,"--primary":r,"--primary-foreground":f(r),"--primary-hover":S(r,w),"--accent":t,"--accent-foreground":f(t),"--accent-ink":x(t,u),"--accent-subtle":H(t,w),"--accent-hover":S(t,w),"--overlay-on-dark":n({mode:"oklch",l:.96,c:.02,h:s}),"--overlay-on-light":n({mode:"oklch",l:.2,c:.02,h:s})},A=i,L=f(i),T=C(i,s),O=x(t,i),E=m(k(r)??r),$=a(E?.h),N=C(r,$),P=x(t,r);return B({...I,...{"--surface-inverse":A,"--surface-inverse-foreground":L,"--surface-inverse-muted":T,"--surface-inverse-accent-ink":O,"--surface-primary-muted":N,"--surface-primary-accent-ink":P}},o)}function B(e,o){let c=n({mode:"oklch",l:.58,c:.22,h:28}),l=n({mode:"oklch",l:.6,c:.14,h:150}),r=n({mode:"oklch",l:.75,c:.15,h:75}),t={...e,"--popover":"var(--card)","--popover-foreground":"var(--card-foreground)","--secondary":"var(--muted)","--secondary-foreground":"var(--foreground)","--destructive":c,"--destructive-foreground":f(c),"--success":l,"--success-foreground":f(l),"--warning":r,"--warning-foreground":f(r)},[h,s]=D(o,t);return t["--supporting-0"]=h,t["--supporting-1"]=s,R(t["--accent"]).forEach((i,d)=>{t[`--chart-${d+1}`]=i}),t}function D(e,o){let r=(e.supporting??[]).filter(h=>!!(h&&h.trim())).slice(0,2).map(h=>n(g(h))),t=[o["--primary"],o["--accent"]];for(;r.length<2;)r.push(t[r.length]);return[r[0],r[1]]}function X(e){let o=(e??"").trim();if(!o||o.startsWith("#")&&!/^#[0-9A-Fa-f]{3,8}$/.test(o))return!1;let c=M[o.toLowerCase()]??o;return!!k(c)}function g(e,o="paper"){let c=(e??"").trim();if(!c)return g(o);let l=M[c.toLowerCase()]??c,r=k(l);if(r){let t=m(r);if(t)return t}return V(c)}function V(e){let o=2166136261,c=e.toLowerCase();for(let h=0;h<c.length;h++)o^=c.charCodeAt(h),o=Math.imul(o,16777619)>>>0;let l=o%360,r=.08+(o>>>9)%9/100;return{mode:"oklch",l:.52+(o>>>18)%16/100,c:r,h:l}}function z(e){return{mode:"oklch",l:.6,c:.02,h:a(e.h)}}function S(e,o){let c=m(k(e)??e);if(!c)return e;let l=o?-.06:.06,r=Math.max(.06,Math.min(.97,a(c.l)+l));return n({mode:"oklch",l:r,c:a(c.c),h:a(c.h)})}function H(e,o){let c=m(k(e)??e),l=a(c?.h),r=Math.min(a(c?.c),o?.05:.06);return n({mode:"oklch",l:o?.95:.24,c:r,h:l})}function R(e){let o=m(k(e)??e),c=a(o?.h),l=Math.max(.12,Math.min(a(o?.c),.16));return[0,72,144,216,288].map(r=>n({mode:"oklch",l:.62,c:l,h:(c+r)%360}))}function f(e){let o=k(e),c=o?m(o):void 0,l=a(c?.h),r={mode:"oklch",l:.99,c:.01,h:l},t={mode:"oklch",l:.18,c:.02,h:l},h=y(o??e,r),s=y(o??e,t);return n(h>=s?r:t)}function x(e,o){let c=m(k(e)??e);if(!c)return e;let l=a(c.h),r=a(c.c),t=a(c.l),h=m(k(o)??o),u=(h?a(h.l)>=.5:!0)?-.02:.02;for(let i=0;i<=50;i++){let d=t+u*i;if(d<=0||d>=1)break;let p={mode:"oklch",l:d,c:r,h:l};if(y(p,o)>=F)return n(p)}return f(o)}function C(e,o){let c=m(k(e)??e),r=(c?a(c.l):.5)>=.5,t=r?.75:.35,h=r?-.02:.02;for(let s=0;s<=50;s++){let u=t+h*s;if(u<=0||u>=1)break;let i={mode:"oklch",l:u,c:.02,h:o};if(y(i,e)>=F)return n(i)}return f(e)}function a(e){return typeof e=="number"&&Number.isFinite(e)?e:0}function n(e){let o=a(e.l),c=a(e.c),l=a(e.h);return`oklch(${o.toFixed(2)} ${c.toFixed(2)} ${l.toFixed(2)})`}export{M as SEMANTIC_SEED_ALIASES,x as accentInkFor,f as bestForegroundFor,a as channel,W as deriveDesignColors,X as isResolvableDesignColorSeed,n as oklchString};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated registry of site fonts accepted by DesignPlan. The deterministic
|
|
3
|
+
* root layout composer (see `buildDeterministicRouteContent`) emits
|
|
4
|
+
* `next/font/google` imports only for entries whose download policy allows it:
|
|
5
|
+
* large CJK families remain valid font-stack names, but are not downloaded by
|
|
6
|
+
* default because full CJK webfont slices can add multiple MB to generated
|
|
7
|
+
* Next.js output.
|
|
8
|
+
*
|
|
9
|
+
* Every entry below was verified against Next.js 16's
|
|
10
|
+
* `@next/font/google/font-data.json`:
|
|
11
|
+
* - `import` is the exact `next/font/google` export name.
|
|
12
|
+
* - `weights` is set ONLY for non-variable fonts that REQUIRE an explicit
|
|
13
|
+
* weight (i.e. fonts whose `font-data.json` weights do not include
|
|
14
|
+
* `"variable"`). Variable fonts omit `weights` so the default axis applies.
|
|
15
|
+
*
|
|
16
|
+
* Display names (the map keys) are what the DesignPlan prompt advertises and
|
|
17
|
+
* what the model is expected to choose from.
|
|
18
|
+
*/
|
|
19
|
+
export interface NextFontEntry {
|
|
20
|
+
/** Exact `next/font/google` export name (e.g. "Bebas_Neue", "Inter"). */
|
|
21
|
+
import: string;
|
|
22
|
+
/**
|
|
23
|
+
* Explicit weights, required only for non-variable fonts. Omitted for
|
|
24
|
+
* variable fonts (default axis is used).
|
|
25
|
+
*/
|
|
26
|
+
weights?: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Whether deterministic layout should emit a `next/font/google` download.
|
|
29
|
+
* Defaults to true. Set false for CJK/system-stack families.
|
|
30
|
+
*/
|
|
31
|
+
download?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare const NEXT_FONT_REGISTRY: Record<string, NextFontEntry>;
|
|
34
|
+
/** Safe default used whenever a requested font is not in the registry. */
|
|
35
|
+
export declare const DEFAULT_FONTS: {
|
|
36
|
+
readonly heading: "Inter";
|
|
37
|
+
readonly body: "Inter";
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Resolves a (possibly model-chosen) font name to a verified
|
|
41
|
+
* `next/font/google` entry. Matches by display name OR import name,
|
|
42
|
+
* case-insensitive and whitespace-normalized. Returns the safe Inter default
|
|
43
|
+
* when the name is unknown so we never emit an unverified font import.
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveFont(name: string): NextFontEntry;
|
|
46
|
+
/**
|
|
47
|
+
* Resolves a possibly user/LLM-supplied font name to the registry's
|
|
48
|
+
* canonical display name (e.g. `"noto_sans_sc"` / `"Noto_Sans_SC"` /
|
|
49
|
+
* `"noto sans sc"` all → `"Noto Sans SC"`). Returns `"Inter"` (the safe
|
|
50
|
+
* default) when the name is unknown, so any downstream caller can write
|
|
51
|
+
* the resolved name into `DesignPlan.siteDesignContext.fonts` and trust
|
|
52
|
+
* it passes the schema's NEXT_FONT_DISPLAY_NAMES validation.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveFontDisplayName(name: string): string;
|
|
55
|
+
/** Display names advertised to the DesignPlan prompt (kept in registry order). */
|
|
56
|
+
export declare const NEXT_FONT_DISPLAY_NAMES: readonly string[];
|
|
57
|
+
export declare function fontStack(value: string | undefined, fallback: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* The two site font CSS variables consumed by generated globals.css. Shared by
|
|
60
|
+
* the server materializer (design-css-materializer) and the workspace try-on
|
|
61
|
+
* path so the fallback semantics (sans follows body; heading falls back to
|
|
62
|
+
* body) can never drift between preview and apply.
|
|
63
|
+
*/
|
|
64
|
+
export declare function siteFontVariables(fonts?: {
|
|
65
|
+
heading?: string;
|
|
66
|
+
body?: string;
|
|
67
|
+
}): {
|
|
68
|
+
"--site-font-sans": string;
|
|
69
|
+
"--site-font-heading": string;
|
|
70
|
+
};
|
|
71
|
+
/** A curated heading/body pairing surfaced by the workspace design panel. */
|
|
72
|
+
export interface FontPairing {
|
|
73
|
+
/** Stable kebab-case id persisted nowhere; used for UI selection state. */
|
|
74
|
+
id: string;
|
|
75
|
+
/** Display name key into NEXT_FONT_REGISTRY. */
|
|
76
|
+
heading: string;
|
|
77
|
+
/** Display name key into NEXT_FONT_REGISTRY. */
|
|
78
|
+
body: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Pairings shown in the workspace design panel. Keep every name a valid
|
|
82
|
+
* NEXT_FONT_REGISTRY display-name key (enforced by font-catalog.test.ts).
|
|
83
|
+
* CJK pairings stay system-stack only (`download: false` entries).
|
|
84
|
+
*/
|
|
85
|
+
export declare const FONT_PAIRINGS: readonly FontPairing[];
|