integrate_point_schema:
  type: object
  additionalProperties: false
  properties:
    page:
      $ref: '#/integrate_point_schema/definitions/SinglePage'
      $comment: 导航配置，用于定义插件在页面上的图标、名称和国际化信息
    view:
      $ref: '#/integrate_point_schema/definitions/SingleView'
      $comment: 视图位配置，用于定义插件的视图展示，包含工作项类型
    dashboard:
      $ref: '#/integrate_point_schema/definitions/SingleDashboard'
      $comment: 详情页位配置，用于定义插件的详情页展示
    configuration:
      $ref: '#/integrate_point_schema/definitions/SingleConfiguration'
      $comment: 插件管理配置页位配置，用于定义插件的配置页面入口
    control:
      $ref: '#/integrate_point_schema/definitions/MultiControl'
      $comment: >
        控件配置（Control），用于定义插件的自定义 UI 组件，可嵌入表格列、详情页表单、节点表单。
        ⚠️ 选型指南（control vs customField）：
        控件适用于「展示/交互优先、数据由开发者自行存储」的场景。
        平台不存储控件数据，因此不支持筛选、排序、分组、度量、条件流转、OpenAPI 读写。
        同一工作项中每个控件只能出现一次。
        如需「数据存储在飞书项目、可被筛选/排序/度量/用于流转条件」，请选择 customField（扩展字段-字段类型）。
        详见下方 ControlPoint 与 CustomFieldPoint 的 $comment。
    button:
      $ref: '#/integrate_point_schema/definitions/MultiButton'
      $comment: 按钮位配置，用于定义插件的按钮功能
    intercept:
      $ref: '#/integrate_point_schema/definitions/SingleIntercept'
      $comment: 拦截位配置，用于定义插件的请求拦截功能
    listen_event:
      $ref: '#/integrate_point_schema/definitions/SingleListenEvent'
      $comment: 监听事件位配置，用于定义插件的事件监听功能
    component:
      $ref: '#/integrate_point_schema/definitions/SingleComponentSchedule'
      $comment: 组件位配置，用于定义插件的组件（定时任务等）
    customField:
      $ref: '#/integrate_point_schema/definitions/MultiCustomField'
      $comment: >
        扩展字段-字段类型（CustomField），用于定义插件的自定义字段类型。
        ⚠️ 选型指南（customField vs control）：
        字段模板适用于「需要平台存储数据、可被筛选/排序/分组/度量/用于节点流转条件」的场景。
        它等同于飞书项目一方字段类型，管理员可像普通字段一样在字段管理中创建、拖拽配置。
        同一工作项可以拥有多个该类型下的字段实例（如同一个「评分」类型可创建「技术评分」和「设计评分」两个字段）。
        必须同时实现 web 和 mobile 双端。
        如仅需「自定义 UI 展示、数据由开发者自行存储、无需平台级筛选/度量」，请选择 control（控件）。
        详见下方 ControlPoint 与 CustomFieldPoint 的 $comment。
    liteAppComponent:
      $ref: '#/integrate_point_schema/definitions/MultiLiteAppComponent'
      $comment: 轻应用组件位配置，用于定义插件的轻应用组件（拖拽式布局等）
    aiNode:
      $ref: '#/integrate_point_schema/definitions/AINodePoint'
      $comment: >
        AI 节点位配置（单对象，非数组）。仅 app_type=ai_node 的插件可使用，
        且全工程恰好一个；与所有非 AI 点位互斥。CLI preflight 会按 plugin.config.json 的 app_type 硬卡。
    aiField:
      $ref: '#/integrate_point_schema/definitions/AIFieldPoint'
      $comment: >
        AI 字段位配置（单对象，非数组）。仅 app_type=ai_field 的插件可使用，
        且全工程恰好一个；与所有非 AI 点位互斥。CLI preflight 会按 plugin.config.json 的 app_type 硬卡。

  definitions:
    # -----------------------------
    # Common atoms
    # -----------------------------
    NonEmptyString:
      type: string
      minLength: 1
      $comment: 非空字符串，用于需要用户输入且不能为空的字段

    PointKey:
      type: string
      minLength: 1
      description: 点位 key，新增时生成（只读），只要当前不存在重复的即可

    ResourceId:
      type: string
      minLength: 1
      pattern: '^[a-zA-Z0-9_-]+$'
      description: 平台资源 ID（resource），不能重复。

    UrlHttp:
      type: string
      minLength: 1
      pattern: '^https?://'
      description: 需以 http(s):// 开头的 URL。

    TokenString:
      type: string
      anyOf:
        - const: ''
        - minLength: 36
          maxLength: 36
      $comment: Token 字符串；留空串或省略字段时 CLI 在 local-config set 自动生成 36 位随机数/UUID 填入，提供非空值则固定 36 位

    PageIconSchema:
      type: string
      description: >
        导航点位图标配置（JSON 字符串），格式为 {"color": "#RRGGBB", "type": "<图标标识符>"}。
        color 为 hex 颜色值，必须为 ALL_COLOR 中的值；
        type 为图标标识符，对应代码中的 allDeveloperIcon 或默认图标。
      dslSchema:
        type: object
        required: [color, type]
        properties:
          color:
            type: string
            enum: ["#B449C2", "#6F5FF4", "#5E6FC4", "#30ACF1", "#2CB8C5", "#5AC262", "#A7DA2C", "#F3C641", "#FDA633", "#EF57AD"]
            description: 图标颜色，对应代码中的 ALL_COLOR。
          type:
            type: string
            enum: [
              "icon-openapp_integrate_points", "icon-openapp_automation_points", "icon-openapp_publish", "icon-openapp_perm_select",
              "icon-openapp_developer", "icon-openapp_app_key", "icon-openapp_base_info", "icon-openapp_doc", "icon-openapp_shop",
              "icon-openapp_approval", "icon-openapp_share", "icon-openapp_listen", "icon-openapp_mcp", "icon-openapp_test",
              "work_object_icon_version"
            ]
            description: 图标标识符，对应代码中的 allDeveloperIcon 或默认图标。
      $comment: 导航点位图标配置

    ViewIconSchema:
      type: string
      description: >
        视图点位图标配置（JSON 字符串），格式为 {"color": "#RRGGBB", "type": "<图标标识符>"}。
        color 为 hex 颜色值，必须为 ALL_COLOR 中的值；
        type 为视图特有图标标识符，对应代码中的 ALL_VIEW_ICONS。
      dslSchema:
        type: object
        required: [color, type]
        properties:
          color:
            type: string
            enum: ["#B449C2", "#6F5FF4", "#5E6FC4", "#30ACF1", "#2CB8C5", "#5AC262", "#A7DA2C", "#F3C641", "#FDA633", "#EF57AD"]
            description: 图标颜色，对应代码中的 ALL_COLOR。
          type:
            type: string
            enum: [
              "icon-openapp_view_chart", "icon-openapp_view_flow", "icon-openapp_view_pie", "icon-openapp_view_pie2",
              "icon-openapp_view_line", "icon-openapp_view_graph", "icon-openapp_view_ecg"
            ]
            description: 图标标识符，对应代码中的 ALL_VIEW_ICONS。
      $comment: 视图点位图标配置

    I18nInfo:
      type: object
      minProperties: 1
      description: |
        多语言名称配置（board/view/dashboard/control/button/intercept 点位使用）。
        结构：key 为语言标识（如 zh-cn、en-us），value 为 { name, description }。
        ⚠️ 注意：不同点位的 i18n_info 结构不同，共三种形态——
          1. 本定义（I18nInfo）：Record<langKey, {name, description}>，langKey 为任意字符串。
          2. customField：平铺对象 {name, description}，无语言 key，存储时固定映射到 zh-cn。
          3. liteAppComponent：语言 key 固定为 zh-cn / en-us / ja-jp（横线格式，非下划线）。
      additionalProperties:
        type: object
        additionalProperties: false
        required: [name]
        properties:
          name:
            $ref: '#/integrate_point_schema/definitions/NonEmptyString'
            maxLength: 100
            description: 国际化名称，用于显示在界面上（与顶层 name 保持一致上限 100）
          description:
            type: string
            maxLength: 50
            description: 国际化描述，用于说明点位的用途

    WorkItemTypeArray:
      description: 工作项类型；_all 与其它互斥。
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
          $comment: 使用 _all 表示支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            enum: [story, issue, version, sprint, work_object]
          $comment: 使用枚举值指定支持的工作项类型列表
      $comment: 工作项类型配置，_all 表示支持所有类型，否则为枚举值数组

    CustomWorkItemTypeArray:
      type: array
      uniqueItems: true
      items:
        type: string
        minLength: 1
        maxLength: 255
        pattern: '^[a-z0-9_]+$'
      $comment: 自定义工作项类型数组，用于 work_object 类型

    # 各点位类型的工作项类型定义
    WorkItemTypeForControl:
      description: 控件工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: issue
                description: 缺陷
              - const: version
                description: 版本
              - const: sprint
                description: 迭代
              - const: work_object
                description: 其他工作项
      $comment: 控件工作项类型，支持全部或指定类型

    WorkItemTypeForButton:
      description: 按钮位工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: issue
                description: 缺陷
              - const: version
                description: 版本
              - const: sprint
                description: 迭代
              - const: work_object
                description: 其他工作项
      $comment: 按钮位工作项类型，支持全部或指定类型

    WorkItemTypeForDashboard:
      description: 详情页位工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: issue
                description: 缺陷
              - const: version
                description: 版本
              - const: sprint
                description: 迭代
              - const: work_object
                description: 其他工作项
      $comment: 详情页位工作项类型，支持全部或指定类型

    WorkItemTypeForView:
      description: 视图位工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: issue
                description: 缺陷
              - const: version
                description: 版本
              - const: sprint
                description: 迭代
              - const: work_object
                description: 其他工作项
      $comment: 视图位工作项类型，支持全部或指定类型

    WorkItemTypeForIntercept:
      description: 拦截位工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: issue
                description: 缺陷
              - const: version
                description: 版本
              - const: sprint
                description: 迭代
              - const: work_object
                description: 其他工作项
      $comment: 拦截位工作项类型，支持全部或指定类型

    WorkItemTypeForListenEvent:
      description: 监听事件位工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: issue
                description: 缺陷
              - const: version
                description: 版本
              - const: sprint
                description: 迭代
              - const: work_object
                description: 其他工作项
      $comment: 监听事件位工作项类型，支持全部或指定类型

    WorkItemTypeForComponentSchedule:
      description: 组件位（定时任务）工作项类型配置
      oneOf:
        - type: array
          minItems: 1
          maxItems: 1
          items:
            const: _all
            description: 全部 - 支持所有工作项类型
        - type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: story
                description: 需求
              - const: work_object
                description: 其他工作项
      $comment: 组件位（定时任务）工作项类型，仅支持全部、需求、其他工作项

    WorkItemTypeForLiteAppComponent:
      type: array
      minItems: 1
      maxItems: 1
      items:
        const: _all
        description: 全部 - 支持所有工作项类型
      $comment: 轻应用组件位工作项类型，仅支持全部

    WorkItemTypeForCustomField:
      type: array
      minItems: 1
      maxItems: 1
      items:
        const: _all
        description: 全部 - 支持所有工作项类型
      $comment: 字段模板位工作项类型，仅支持全部

    SceneArray:
      type: array
      uniqueItems: true
      items:
        type: integer
      $comment: 场景数组，用于指定插件适用的场景编号

    SceneArrayRequired:
      type: array
      minItems: 1
      uniqueItems: true
      items:
        type: integer
      $comment: 场景数组（必填），用于指定插件适用的场景编号，至少包含一个场景

    # 各点位类型的场景定义
    SceneForControlWeb:
      type: array
      uniqueItems: true
      items:
        oneOf:
          - const: 1
            description: 表格页
          - const: 2
            description: 表单页
          - const: 6
            description: 节点表单
      $comment: 控件 Web 平台场景数组

    SceneForControlMobile:
      type: array
      uniqueItems: true
      items:
        oneOf:
          - const: 2
            description: 表单页
          - const: 6
            description: 节点表单
      $comment: 控件 Mobile 平台场景数组

    SceneForButtonWeb:
      type: array
      minItems: 1
      uniqueItems: true
      items:
        oneOf:
          - const: 3
            description: 工作项 - 更多
          - const: 4
            description: 节点 - 更多
          - const: 5
            description: 新增工作项实例
          - const: 7
            description: 节点流转
          - const: 8
            description: 计划表节点-更多
      $comment: 按钮位 Web 平台场景数组（必填）

    SceneForButtonMobile:
      type: array
      minItems: 1
      uniqueItems: true
      items:
        oneOf:
          - const: 3
            description: 工作项 - 更多
          - const: 4
            description: 节点 - 更多
          - const: 7
            description: 节点流转
      $comment: 按钮位 Mobile 平台场景数组（必填）

    SceneForComponentSchedule:
      type: array
      minItems: 1
      uniqueItems: true
      description: >
        组件位场景数组，必填。可选值：0（全部）、1（节点排期）、2（计划表排期）。
        ⚠️ 互斥规则：0（全部）与具体场景值不能共存，选 0 时数组只能是 [0]，不能同时包含 1 或 2。
      items:
        oneOf:
          - const: 0
            description: 全部（与 1/2 互斥，选此项时数组只能为 [0]）
          - const: 1
            description: 节点排期
          - const: 2
            description: 计划表排期
      $comment: 组件位（定时任务）场景数组（必填），0 与 1/2 互斥
      allOf:
        - if:
            contains:
              const: 0
          then:
            maxItems: 1
            $comment: 包含 0（全部）时，数组长度最多为 1，即不能再包含其他场景值

    # 控件专用平台定义
    PlatformWebForControl:
      type: object
      additionalProperties: true
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
          description: 网页端 resourceId
          $comment: 网页端 resourceId
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneForControlWeb'
        table_cell:
          oneOf:
            - type: object
            - type: string
              minLength: 1
              description: 向后兼容：老 yaml 中为 JSON 字符串；CLI 会在归一化阶段 JSON.parse 一次
          description: |
            网页端表格页展示态布局配置，当 scene 包含 1（表格页）时必填。
            支持两种写法（CLI 会自动归一化，等价后再发往后端）：
              1. 裸 template：直接写根节点对象（必含顶层 `type` 字段），CLI 自动包成 { definitions: {data:{}, $i18n:{}, $colorTokens:{}}, template: <你写的> }；
              2. 完整对象：形如 { definitions: {data, $i18n, $colorTokens}, template }，缺失的 definitions 子键会被补成空对象 {}。
            ⚠️ 硬规则（CLI 不会自动声明，运行时缺失会报错）：
              - 裸 template 仅限"零变量引用"场景；template 中只要出现 {{varName}} / {{$colorTokens.x}} / {{$i18n.x}} 任一引用，必须改用完整对象形式，并在 definitions 对应分类下显式声明该 key。
              - {{$container.width/height}}、{{$fieldValue}}（仅 CustomField 场景）由平台注入，无需声明。
            ⚠️ 与"编辑态"的关系（scene 同时包含 1 与 2/6 时）：
              - scene 仅 [1]：表格列纯展示，双击不可编辑；用户只能通过 OpenAPI 或其他入口改值。
              - scene 包含 [1, 2] 或 [1, 6]：控件同时实现了表单产物（resource 指向的 JS 入口），表格列双击会以模态框形式加载该表单产物，提供"表格内编辑"体验。
                * 是否允许某一行被双击编辑，由展示态数据接口响应中的 editable 字段逐行控制（true 才唤起弹窗）。
                * 此时 platform.web.resource 必填（表单产物入口），同时本字段（table_cell）依然必填（决定展示态外观）。
              - scene 仅 [2]/[6]：不需要写本字段（table_cell 不会生效）。
            template 树最大嵌套深度 ≤ 5（由 validateDefinitionJSON 校验）。
            兼容老版本：本字段也接受 JSON 字符串，CLI 会自动 JSON.parse 一次。
          dslSchema:
            type: object
            properties:
              definitions:
                type: object
                description: 可选
                properties:
                  data:
                    type: object
                    description: 数据变量声明，可在 template 中用 {{varName}} 引用
                    additionalProperties:
                      type: object
                      properties:
                        name:
                          type: string
                          description: 显示名
                        type:
                          type: string
                          enum: [string, number]
                          description: 类型，仅支持 string / number（数据接口返回值类型也仅限这两种）
                        mockValue:
                          description: 预览值（开发调试时用，需与 type 匹配）
                  $i18n:
                    type: object
                    description: 国际化文案，每个 key 对应多语言字符串
                    additionalProperties:
                      type: object
                      properties:
                        zh_CN:
                          type: string
                        en_US:
                          type: string
                        ja_JP:
                          type: string
                  $colorTokens:
                    type: object
                    description: 颜色 token，支持亮/暗色模式，值为 hex 或 rgba 格式
                    additionalProperties:
                      type: object
                      properties:
                        light:
                          type: string
                          description: "#RRGGBB 或 rgba(...)"
                        dark:
                          type: string
                          description: "#RRGGBB 或 rgba(...)"
              template:
                type: object
                description: 必填，渲染节点树，最大深度 5 层
                required: [type]
                properties:
                  type:
                    type: string
                    enum: [view, text, image, popover]
                    description: |
                      节点类型：
                      - view: 容器节点，支持 children 嵌套；display 仅支持 flex（不支持 block/grid）
                      - text: 文本节点，使用 props.content
                      - image: 图片节点，使用 props.src，必须设置 width/height 否则不可见
                      - popover: 容器节点，点击/悬浮触发弹层；style 作用于 trigger 子元素，弹层内容由 props.entry 指定
                  props:
                    type: object
                    properties:
                      hidden:
                        type: boolean
                        description: 可选，是否隐藏该节点，默认 false
                        default: false
                      content:
                        description: text 节点的文本内容（支持模板表达式 {{...}}），允许 string 或 number
                        oneOf:
                          - type: string
                          - type: number
                      src:
                        type: string
                        description: image 节点的图片地址，image 节点必填；支持 png/jpeg/svg，不支持 gif
                      entry:
                        type: string
                        description: popover 节点的弹层入口，必填；指向打包产物中导出的入口函数名（用于渲染弹层内容）
                      width:
                        type: number
                        description: popover 弹窗宽度（像素），可选；不填时按弹层产物内容自适应
                      height:
                        type: number
                        description: popover 弹窗高度（像素），可选；不填时按弹层产物内容自适应
                      style:
                        type: object
                        description: |
                          数值类样式（width/height/margin/padding/borderWidth/borderRadius/font*/flex*）**同时接受** number 与字符串模板表达式（如 "{{$container.width}}"、"{{progress * 100}}"）。
                          字符串值将在运行时由模板引擎求值为 number；颜色类（borderColor/backgroundColor/color）字符串值支持 hex / rgba / {{$colorTokens.x}}。
                        properties:
                          width:
                            description: 尺寸（像素）或模板表达式字符串
                            oneOf: [{ type: number }, { type: string }]
                          height:
                            oneOf: [{ type: number }, { type: string }]
                          marginTop:
                            oneOf: [{ type: number }, { type: string }]
                          marginBottom:
                            oneOf: [{ type: number }, { type: string }]
                          marginLeft:
                            oneOf: [{ type: number }, { type: string }]
                          marginRight:
                            oneOf: [{ type: number }, { type: string }]
                          paddingTop:
                            oneOf: [{ type: number }, { type: string }]
                          paddingBottom:
                            oneOf: [{ type: number }, { type: string }]
                          paddingLeft:
                            oneOf: [{ type: number }, { type: string }]
                          paddingRight:
                            oneOf: [{ type: number }, { type: string }]
                          borderWidth:
                            oneOf: [{ type: number }, { type: string }]
                          borderColor:
                            type: string
                            description: hex / rgba / 模板表达式（如 {{$colorTokens.xxx}}）
                          borderRadius:
                            type: object
                            properties:
                              topLeft:
                                oneOf: [{ type: number }, { type: string }]
                              topRight:
                                oneOf: [{ type: number }, { type: string }]
                              bottomLeft:
                                oneOf: [{ type: number }, { type: string }]
                              bottomRight:
                                oneOf: [{ type: number }, { type: string }]
                          backgroundColor:
                            type: string
                            description: hex / rgba / 模板表达式
                          color:
                            type: string
                            description: 字体颜色，hex / rgba / 模板表达式
                          fontSize:
                            oneOf: [{ type: number }, { type: string }]
                          fontWeight:
                            oneOf: [{ type: number }, { type: string }]
                          flexDirection:
                            type: string
                            enum: [row, column]
                          alignItems:
                            type: string
                            enum: [stretch, flex-start, flex-end, center]
                          justifyContent:
                            type: string
                            enum: [stretch, flex-start, flex-end, center, space-between, space-around]
                          flexBasis:
                            oneOf: [{ type: number }, { type: string }]
                          flexGrow:
                            oneOf: [{ type: number }, { type: string }]
                          flexShrink:
                            oneOf: [{ type: number }, { type: string }]
                          overflow:
                            type: string
                            enum: [visible, hidden, scroll, auto]
                          textOverflow:
                            type: string
                            enum: [clip, ellipsis, visible, wrap]
                            description: text 节点文本溢出处理，默认 ellipsis
                          cursor:
                            type: string
                            enum: [default, none, pointer, wait, help, auto]
                      onClick:
                        type: object
                        description: 可选，点击事件
                        properties:
                          action:
                            type: string
                            enum: [openLink, httpRequest, writeTextToClipboard, openWorkItemCreatePage, openWorkItemDetailPage, openModal]
                            description: |
                              事件触发的动作类型：
                              - openLink: 新标签页打开 URL
                              - httpRequest: 发起网络请求；请求完成后平台会**自动重新拉取展示态数据接口**刷新本单元格；请求**不携带浏览器 Cookies**，需自行做鉴权（可校验 token/signature）
                              - writeTextToClipboard: 写入剪贴板
                              - openWorkItemCreatePage: 打开工作项新建页
                              - openWorkItemDetailPage: 打开工作项详情页
                              - openModal: 打开自定义弹窗（加载产物中导出的入口函数）
                          params:
                            type: object
                            description: |
                              - openLink: { "url": "..." }
                              - httpRequest: { "method": "GET|POST|PUT|DELETE", "url": "...", "headers"?: {...}, "params"?: {...}, "body"?: {...} }
                              - writeTextToClipboard: { "content": "..." }
                              - openWorkItemCreatePage: { "spaceSimpleName": "...", "workObjectId": "...", "supportedWorkObjectIds"?: ["..."] }
                              - openWorkItemDetailPage: { "spaceSimpleName": "...", "workObjectId": "...", "workItemId": number }
                              - openModal: { "entry": "...", "width"?: number, "height"?: number, "fullScreen"?: false, "maskClosable"?: true }
                                * entry：必填，产物中导出的入口函数名（用于渲染弹窗内容）
                                * fullScreen：默认 false；maskClosable：默认 true
                          eventParams:
                            type: object
                            properties:
                              stopPropagation:
                                type: boolean
                                description: 可选，是否阻止冒泡，默认 false
                      onDoubleClick:
                        type: object
                        description: 可选，双击事件，结构与 onClick 完全一致（action / params / eventParams）
                        properties:
                          action:
                            type: string
                            enum: [openLink, httpRequest, writeTextToClipboard, openWorkItemCreatePage, openWorkItemDetailPage, openModal]
                          params:
                            type: object
                          eventParams:
                            type: object
                            properties:
                              stopPropagation:
                                type: boolean
                  children:
                    type: array
                    description: 子节点数组，结构同 template，递归，总深度 ≤ 5
                    items:
                      $ref: '#/integrate_point_schema/definitions/PlatformWebForControl/properties/table_cell/dslSchema/properties/template'
            templateExpressions:
              description: |
                props / style 中的字符串值支持 Mustache 风格模板表达式 {{expression}}：

                【可引用的变量】
                - {{varName}}：definitions.data 中声明的自定义变量（值由展示态数据接口返回）
                - {{$container.width}} / {{$container.height}}：当前单元格的宽/高（像素）
                - {{$colorTokens.tokenName}}：自定义颜色 token（自动适配亮/暗色模式）
                - {{$i18n.key}}：自定义多语言词条（自动使用当前用户语言）

                【支持的操作符】
                - 分组：( )
                - 属性 / 数组访问：x.y、a[i]
                - 算术：+  -  *  /  %
                - 比较：==  !=  >=  <=  >  <
                - 三元：x ? y : z

                【示例】
                - {{$container.height * 0.5}}                           // 容器高度的一半
                - {{list[0].status == 1 ? 'done' : 'todo'}}            // 三元 + 属性访问
                - {{openRate * 100}}%                                   // 算术
                - 颜色：{{$colorTokens.font_color}}
            availableVariables:
              description: |
                变量分两类：

                【A. 平台注入（无需声明，直接引用）】
                  - {{$container.width}} / {{$container.height}}：当前单元格宽高（像素）
                  - {{$fieldValue}}：仅 CustomField 场景下可用，结构见下方"CustomField 场景"

                【B. 必须在 definitions 中显式声明，否则运行时报错】
                  - {{varName}}        → definitions.data.<varName>      （必填 type/name/mockValue）
                  - {{$colorTokens.x}} → definitions.$colorTokens.<x>    （必填 light / dark）
                  - {{$i18n.x}}        → definitions.$i18n.<x>           （必填 zh_CN / en_US / ja_JP）
                CLI 仅兜底"补三个空对象壳子"，不会替你声明 key；裸 template 简写仅在零引用时可用。

                【Control（控件）场景】
                  仅支持上面列出的平台变量；业务数据全部来自 data 声明 + 展示态数据接口返回。

                【CustomField（扩展字段-字段类型）场景】
                  额外支持 {{$fieldValue}}：当前单元格对应字段的实例值，类型为数组
                  （为何是数组：参见 CustomFieldValue 文档），结构为：
                    $fieldValue: Array<{ [subFieldKey: string]: SubFieldValue }>
                  其中 subFieldKey 为开发者后台中"子字段"的 key。
                  五种子字段类型对应的 SubFieldValue 结构：
                    - 数字:        number
                    - 多行文本:    string
                    - 日期+时间:   number（毫秒时间戳）
                    - 多选人员:    Array<{ name: string; userKey: string }>
                    - 级联多选:    Array<{ label: string; value: string }>

                  常见用法（以子字段 key 为 sub_field_xxx 为例）：
                    // 文本/数字
                    "{{($fieldValue && $fieldValue[0] && $fieldValue[0].sub_field_xxx) ? $fieldValue[0].sub_field_xxx : '空'}}"
                    // 级联多选取首个 label
                    "{{($fieldValue && $fieldValue[0] && $fieldValue[0].sub_field_xxx && $fieldValue[0].sub_field_xxx[0]) ? $fieldValue[0].sub_field_xxx[0].label : '空'}}"
                    // 多选人员取首个 name
                    "{{($fieldValue && $fieldValue[0] && $fieldValue[0].sub_field_xxx && $fieldValue[0].sub_field_xxx[0]) ? $fieldValue[0].sub_field_xxx[0].name : '空'}}"
            tableDataInterface:
              description: |
                展示态数据接口（control.table_url.url 或 customfield.platform.web.table_data_url）协议：

                【请求】POST  Content-Type: application/json
                  Body: {
                    "request_time": 1733381298,
                    "signature": "...",                  // 用于校验来源（结合 token 计算）
                    "project_key": "...",                // 当前空间 ID
                    "user_language": "zh-cn|en-us|ja-jp",
                    "plugin_info": { "plugin_key", "plugin_version", "point_type", "point_key" },
                    "user_info":   { "user_key", "name_cn", "name_en", "email" },
                    "work_item_infos": [                  // 当前可视区域的行，单次最多 20 条
                      { "work_item_id": 5165731777, "work_item_type_key": "story" }
                    ]
                  }

                【响应】Status 200
                  Body: {
                    "code": 0,                            // 0 成功，非 0 异常（整体丢弃）
                    "msg": "",
                    "data": {
                      "work_item_datas": [
                        {
                          "work_item_id": 5165731777,     // 对应请求里的 work_item_id
                          "result": true,                  // false 时该行数据被丢弃
                          "err_msg": "...",                // result=false 时显示给用户
                          "editable": true,                // true 且控件实现了表单场景，则双击可唤起编辑弹窗
                          "work_item_data": {              // 仅 string / number 字面值，对应 definitions.data 中声明的变量
                            "openRate": 0.3,
                            "label": "进行中"
                          }
                        }
                      ]
                    }
                  }

                【性能要求】
                - 单次请求响应时间 < 3s
                - 单次响应体体积 < 100kB
          $comment: 网页端表格页展示态布局 DSL（对象），scene=[1] 时必填；支持裸 template 或完整 {definitions, template}，CLI 自动归一化；最大嵌套深度 ≤ 5
        table_url:
          type: object
          additionalProperties: false
          properties:
            url:
              $ref: '#/integrate_point_schema/definitions/UrlHttp'
              description: 网页端表格页展示态数据接口（可选）；填写后 token 由 CLI 自动生成，无需手动校验
              $comment: 网页端表格页展示态数据接口，填写后 token 由 CLI 自动生成
            token:
              $ref: '#/integrate_point_schema/definitions/TokenString'
              description: 网页端表格页展示态数据接口 Token；当 url 填写时由 CLI 自动生成（36 位 UUID），无需手动填写
              $comment: 网页端表格页展示态数据接口 Token，url 有值时由 CLI 自动生成（schema 不强校验）
      $comment: 控件 Web 平台配置
      allOf:
        # 当 scene 包含表单页(2)或节点表单(6)时，resource 和 scene 必填
        - if:
            properties:
              scene:
                type: array
                contains:
                  oneOf:
                    - const: 2
                    - const: 6
          then:
            required: [resource, scene]
        # 当 scene 包含表格页(1)时，table_cell 必填
        - if:
            properties:
              scene:
                type: array
                contains:
                  const: 1
          then:
            required: [table_cell]

    PlatformMobileForControl:
      type: object
      additionalProperties: true
      required: [resource, scene, mobile_block_style]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
          description: 移动端 resourceId
          $comment: 移动端 resourceId
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneForControlMobile'
        mobile_block_style:
          type: string
          enum: [not_display, small, medium, big]
          description: 移动端概览，控制移动端展示尺寸
          $comment: 移动端概览，控制移动端展示尺寸
      $comment: 控件 Mobile 平台配置，包含资源 ID、场景数组和移动端概览

    # 组件排期专用平台定义
    PlatformWebForComponentSchedule:
      type: object
      additionalProperties: true
      required: [resource, scene]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneForComponentSchedule'
      $comment: 组件排期 Web 平台配置，必须包含资源 ID 和场景数组
    PlatformWebForButton:
      type: object
      additionalProperties: true
      required: [resource, scene, mode]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneForButtonWeb'
        mode:
          type: string
          enum: [ui, script]
          description: 点击后效果：ui（弹窗）或 script（执行脚本）
          $comment: 点击后效果
        init_size:
          type: object
          required: [width, height, width_type, height_type]
          properties:
            width:
              type: integer
              minimum: 1
              description: 弹窗宽度（px），必须为正整数，默认 448
            height:
              type: integer
              minimum: 1
              description: 弹窗高度（px），必须为正整数，默认 400
            width_type:
              type: string
              enum: [static, dynamic]
              description: 宽度类型，如 static
            height_type:
              type: string
              enum: [static, dynamic]
              description: 高度类型，如 static
          description: 弹窗初始尺寸，当 mode 为 ui 时必填；默认值为 {width_type:static, height_type:static, width:448, height:400}
          $comment: 弹窗初始尺寸配置，width/height 必须为正整数
      $comment: 按钮位 Web 平台配置，必须包含资源 ID、场景数组和点击后效果
      allOf:
        # 当 mode 为 ui（弹窗）时，init_size 必填；否则不允许携带 init_size
        - if:
            properties:
              mode:
                const: ui
          then:
            required: [init_size]
          else:
            properties:
              init_size: false

    PlatformMobileForButton:
      type: object
      additionalProperties: true
      required: [resource, scene]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneForButtonMobile'
      $comment: 按钮位 Mobile 平台配置，必须包含资源 ID 和场景数组

    PlatformWebWithScene:
      type: object
      additionalProperties: true
      required: [resource]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneArray'
      $comment: Web 平台配置，包含资源 ID 和场景数组

    PlatformMobileWithScene:
      type: object
      additionalProperties: true
      required: [resource]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneArray'
      $comment: Mobile 平台配置，包含资源 ID 和场景数组

    PlatformWebNoScene:
      type: object
      additionalProperties: true
      required: [resource]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
      $comment: Web 平台配置（无场景），仅包含资源 ID

    PlatformMobileNoScene:
      type: object
      additionalProperties: true
      required: [resource]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
      $comment: Mobile 平台配置（无场景），仅包含资源 ID

    PlatformWebWithRequiredScene:
      type: object
      additionalProperties: true
      required: [resource, scene]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneArrayRequired'
      $comment: Web 平台配置，必须包含资源 ID 和场景数组

    PlatformMobileWithRequiredScene:
      type: object
      additionalProperties: true
      required: [resource, scene]
      properties:
        resource:
          $ref: '#/integrate_point_schema/definitions/ResourceId'
        scene:
          $ref: '#/integrate_point_schema/definitions/SceneArrayRequired'
      $comment: Mobile 平台配置，必须包含资源 ID 和场景数组

    # -----------------------------
    # Board
    # -----------------------------
    PagePoint:
      type: object
      additionalProperties: false
      required: [name, key, icon, i18n_info, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^board_'
          description: 导航唯一标识（Key），生成规则：不能重复，前缀为 board_，后面默认随机生成6位
        icon:
          $ref: '#/integrate_point_schema/definitions/PageIconSchema'
          default: '{"color":"#B449C2","type":"work_object_icon_version"}'
        name:
          type: string
          maxLength: 15
          description: 页面名称，用于在导航菜单中显示
        description:
          type: string
          maxLength: 50
          description: 描述，用于说明导航页面的用途
        i18n_info:
          $ref: '#/integrate_point_schema/definitions/I18nInfo'
          $comment: 多语言信息，包含页面名称(name)和可选的描述(description)
        platform:
          type: object
          additionalProperties: false
          anyOf:
            - required: [web]
            - required: [mobile]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebNoScene'
              $comment: 网页端配置，仅包含 resourceId
              $description: 网页端配置，仅包含 resourceId
            mobile:
              $ref: '#/integrate_point_schema/definitions/PlatformMobileNoScene'
              $comment: 移动端配置，仅包含 resourceId
              $description: 移动端配置，仅包含 resourceId
      $comment: 导航配置，用于定义插件在侧边栏或顶部导航的入口，包含页面名称、图标、适用端等

    SinglePage:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/PagePoint'
      $comment: 单个板块位配置数组，最多只能有一个

    # -----------------------------
    # View
    # -----------------------------
    ViewPoint:
      type: object
      additionalProperties: false
      required: [name, key, icon, i18n_info, work_item_type, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^view_'
          description: 视图唯一标识（Key），生成规则：不能重复，前缀为 view_，后面默认随机生成6位
        icon:
          $ref: '#/integrate_point_schema/definitions/ViewIconSchema'
          default: '{"color":"#B449C2","type":"icon-openapp_view_chart"}'
        name:
          type: string
          maxLength: 15
          description: 视图名称，用于在列表中显示
        description:
          type: string
          maxLength: 50
          description: 描述，用于说明视图的用途
        i18n_info:
          $ref: '#/integrate_point_schema/definitions/I18nInfo'
          $comment: 多语言信息，包含视图名称(name)和可选的描述(description)
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForView'
          $comment: 工作项类型配置，支持全部或指定类型
        platform:
          type: object
          additionalProperties: false
          required: [web]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebNoScene'
              $comment: 网页端配置，仅包含 resourceId
              $description: 网页端配置，仅包含 resourceId
      $comment: 视图配置，用于定义插件的工作项视图页面，包含视图名称、图标、工作项类型和适用端等

    SingleView:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/ViewPoint'
      $comment: 单个视图位配置数组，最多只能有一个

    # -----------------------------
    # Dashboard
    # -----------------------------
    DashboardPoint:
      type: object
      additionalProperties: false
      required: [name, key, i18n_info, work_item_type, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^dashboard_'
          description: 详情页唯一标识（Key），生成规则：不能重复，前缀为 dashboard_，后面默认随机生成6位
        name:
          type: string
          maxLength: 15
          description: 详情页名称，用于在列表中显示
        description:
          type: string
          maxLength: 50
          description: 描述，用于说明详情页的用途
        i18n_info:
          $ref: '#/integrate_point_schema/definitions/I18nInfo'
          $comment: 多语言信息，包含详情页名称(name)和可选的描述(description)
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForDashboard'
          $comment: 工作项类型配置，支持全部或指定类型
        custom_work_item_type:
          $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
          $comment: 自定义工作项类型配置，当 work_item_type 包含 work_object 时使用
        platform:
          type: object
          additionalProperties: false
          anyOf:
            - required: [web]
            - required: [mobile]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebNoScene'
              $comment: 网页端配置，仅包含 resourceId
              $description: 网页端配置，仅包含 resourceId
            mobile:
              $ref: '#/integrate_point_schema/definitions/PlatformMobileNoScene'
              $comment: 移动端配置，仅包含 resourceId
              $description: 移动端配置，仅包含 resourceId
      $comment: 详情页配置，用于定义插件的详情页展示、工作项类型和适用端等
      # 动态联动：仅当 work_item_type 包含 work_object 时，custom_work_item_type 才出现且必填
      allOf:
        - if:
            properties:
              work_item_type:
                type: array
                contains:
                  const: work_object
          then:
            required: [custom_work_item_type]
            properties:
              custom_work_item_type:
                allOf:
                  - $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
                  - minItems: 1
          else:
            not:
              required: [custom_work_item_type]

    SingleDashboard:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/DashboardPoint'
      $comment: 单个仪表盘位配置数组，最多只能有一个

    # -----------------------------
    # Config (plugin config page)
    # -----------------------------
    ConfigurationPoint:
      type: object
      additionalProperties: false
      required: [key, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^config_'
          description: 插件配置唯一标识（Key），生成规则：不能重复，前缀为 config_，后面默认随机生成6位
        platform:
          type: object
          additionalProperties: false
          required: [web]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebNoScene'
              $comment: 网页端配置，仅包含 resourceId
              $description: 网页端配置，仅包含 resourceId
      $comment: 插件配置，用于定义插件的配置页面入口和适用端等

    SingleConfiguration:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/ConfigurationPoint'
      $comment: 单个配置页位配置数组，最多只能有一个

    # -----------------------------
    # Control
    # -----------------------------
    ControlPoint:
      type: object
      additionalProperties: false
      required: [key, i18n_info, work_item_type, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^control_'
          description: 控件唯一标识（Key），生成规则：不能重复，前缀为 control_，后面默认随机生成6位
        name:
          type: string
          maxLength: 100
          description: 控件名称，用于在列表中显示。maxLength 为 100（其他点位为 15），因控件名用作字段标签，允许更长的描述性名称。
        description:
          type: string
          maxLength: 50
          description: 描述，用于说明控件的用途
        i18n_info:
          $ref: '#/integrate_point_schema/definitions/I18nInfo'
          $comment: 多语言信息，包含控件名称(name)和可选的描述(description)
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForControl'
          $comment: 工作项类型配置，支持全部或指定类型
        # Control 表单有"新建页可见"逻辑；后端字段仍是 url/token
        url:
          $ref: '#/integrate_point_schema/definitions/UrlHttp'
          description: Webhook 回调地址，开启"新建页可见"时必填，需以 http(s):// 开头
          $comment: Webhook 回调地址，开启"新建页可见"时必填，需以 http(s):// 开头
        token:
          $ref: '#/integrate_point_schema/definitions/TokenString'
          description: Webhook 回调地址 Token；当 url 填写时自动生成（36 位 UUID），无需手动填写。
          $comment: Webhook 回调地址 Token，url 有值时自动生成
        platform:
          type: object
          additionalProperties: false
          required: [web]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebForControl'
              $comment: 网页端配置，包含资源 ID、场景和表格页展示态相关配置
            mobile:
              $ref: '#/integrate_point_schema/definitions/PlatformMobileForControl'
              $comment: 移动端配置，包含资源 ID、场景和移动端概览配置
      $comment: >
        控件（Control）点位配置。

        【什么是控件】
        控件是由开发者自定义的页面表单组件，可嵌入表格列视图、详情页表单、节点表单中。
        开发者可自定义控件的展示样式，并通过客户端/服务端 API 消费平台数据，但平台不提供控件相关数据的存储。
        适用场景：评分组件、进度条组件、POI 地址组件、审批面板等「展示/交互优先」的场景。
        JSSDK 命名空间：window.JSSDK.control.*

        【control vs customField 能力对比】
        |  能力维度           | control（控件）                      | customField（扩展字段-字段类型）         |
        |---------------------|--------------------------------------|---------------------------------------------|
        | 数据存储            | ❌ 平台不存储，开发者自行管理          | ✅ 存储在飞书项目，系统可感知                |
        | 工作项实例数量      | 每个控件只能出现 1 次                 | 同类型可创建多个字段实例                     |
        | 工作项类型范围      | schema 强校（_all 或指定类型，admin 不能改） | schema 仅 _all；admin 装字段时按一方流程，可挂任意工作项类型 |
        | 字段配置（有效性等）| ❌                                    | ✅ 响应有效性、授权角色、权限配置            |
        | 布局配置（必填等）  | ❌                                    | ✅ 响应新建页可见性、新建页必填              |
        | 条件配置（流转条件）| ❌                                    | ✅ 可用于节点流转条件                        |
        | 视图筛选/排序/分组  | ❌ 仅可添加为自定义列                  | ✅ 可筛选、可排序、可分组、可设为预置列      |
        | 度量                | ❌                                    | ✅（即将上线）                               |
        | OpenAPI 读写        | ❌                                    | ✅ 任意插件可读，开发插件可写                |
        | 新建页支持          | 需自建 Webhook 存储逻辑               | 原生支持，与一方字段一致                     |

        【选型决策树】（三层：术语明示 → 独家信号 → 歧义停下问）

        —— Step 0：用户**字面**写出点位名？（不靠语义引申）

        题面字面包含 "扩展字段 / 拓展字段 / 字段模板 / 自定义字段 / customField" → customField
        题面字面包含 "控件 / 控件组件 / control" → control
        字面**没出现**这些词（如题面只说 "客户备注 / 打分 / 进度" 等业务词）→ **不命中 Step 0**，进 Step 1
        ⚠️ 例外：术语与需求描述冲突（如"控件 + 进视图筛选"）→ stop-and-ask 不盲从

        —— Step 1：题面是否有 customField / control 独家能力的强信号？

        【明确 customField 独家信号】（任一命中即定 customField）：
          - admin 在字段配置面 / 配置弹窗自定义 X（如颜色 / 文案 / 阈值）
          - 同字段挂多个实例（"3 档评分各一个" / 联系人列表）
          - 字段值要进流转条件 / 度量 / 视图自定义列
          - 受 admin 必填 / 可见性 / 授权角色 / 权限管控

        【明确 control 独家信号】（任一命中即定 control）：
          - UI 组件语义（审批面板 / 进度条 / 状态切换器 / 历史时间线 / 操作按钮组），不是字段值
          - 嵌新建页 + webhook 关联自建后端
          - 仅表格列纯展示（DSL only 零 React，无字段值绑定）
          - 数据只存储在业务后端，不会存储在飞书项目中

        —— Step 2：Step 0/1 都未命中 OR 题面同时有 customField 和 control 都说得通的描述 → 题面歧义

        【铁律】（违反 = process 错，HARD 失败）：
          - **禁止预先表态选型**（"应选 customField" / "候选点位类型 customField" 都算违规）
          - **必须列两个候选并列展开**（单个不算列）
          - **必须扫题面 3 类歧义信号全套**——① 数据来源 / ② 数据存储归属 / ③ 数据形态——每条命中信号对应一个用户决策问题，不漏（端支持差异不在此列：mobile 不展示两路径都能搞定，非真歧义）

        典型歧义点（每条都要查一遍）：
          - 数据来源是外部系统（CRM / ERP）→ 是否落地飞项被筛 / 排 / 度量？(落地 → customField；不落地 → control)
          - 没有需要作为一方字段的能力，单纯在表单/表格上自定义展示和交互 → control

        强制流程（echo 完整能力对比表 → 3 类信号扫描 → 双候选并列展开 → 决策问题清单 → 用户拍板）由 plan 工作流的 §P2.5.1（customField vs control 选型边界特例分支）执行，全做完才能向用户拍板。

    MultiControl:
      type: array
      items:
        $ref: '#/integrate_point_schema/definitions/ControlPoint'
      $comment: 多个控件配置数组

    # -----------------------------
    # Button
    # -----------------------------
    ButtonPoint:
      type: object
      additionalProperties: false
      required: [key, i18n_info, work_item_type, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^button_'
          description: 点位唯一标识，生成规则：不能重复，前缀为 button_，后面默认随机生成6位
          $comment: 点位唯一标识，生成规则：不能重复，前缀为 button_，后面默认随机生成6位
        name:
          type: string
          maxLength: 15
          $comment: 按钮名称，用于在列表中显示
        description:
          type: string
          maxLength: 50
          $comment: 按钮描述，用于说明按钮的用途
        i18n_info:
          $ref: '#/integrate_point_schema/definitions/I18nInfo'
          $comment: 国际化信息，包含 name 和可选的 description
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForButton'
          $comment: 按钮位工作项类型配置，支持全部或指定类型
        custom_work_item_type:
          $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
          $comment: 自定义工作项类型配置，当 work_item_type 包含 work_object 时使用
        platform:
          type: object
          additionalProperties: false
          anyOf:
            - required: [web]
            - required: [mobile]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebForButton'
              $comment: 按钮位 Web 平台配置，必须包含资源 ID 和场景数组
            mobile:
              $ref: '#/integrate_point_schema/definitions/PlatformMobileForButton'
              $comment: 按钮位 Mobile 平台配置，必须包含资源 ID 和场景数组
      $comment: 按钮位配置，用于定义插件的按钮功能，包含工作项类型、平台配置和扩展配置
      # 动态联动：仅当 work_item_type 包含 work_object 时，custom_work_item_type 才出现且必填
      allOf:
        - if:
            properties:
              work_item_type:
                type: array
                contains:
                  const: work_object
          then:
            required: [custom_work_item_type]
            properties:
              custom_work_item_type:
                allOf:
                  - $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
                  - minItems: 1
          else:
            not:
              required: [custom_work_item_type]

    MultiButton:
      type: array
      items:
        $ref: '#/integrate_point_schema/definitions/ButtonPoint'
      $comment: 多个按钮位配置数组

    # -----------------------------
    # Intercept
    # -----------------------------
    InterceptEventConfig:
      type: object
      additionalProperties: false
      required: [work_item_type, event_type]
      properties:
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForIntercept'
          $comment: 工作项类型配置，支持全部或指定类型
        event_type:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: 100
                description: 工作项（包含所有工作项事件）
              - const: 1001
                description: 新建工作项
              - const: 1002
                description: 删除工作项
              - const: 1003
                description: 批量删除工作项
              - const: 1004
                description: 恢复需求
              - const: 1005
                description: 终止需求
              - const: 1006
                description: 模板升级
              - const: 1007
                description: 批量模板升级
              - const: 1008
                description: 导出工作项
              - const: 1009
                description: 修改字段
              - const: 1010
                description: 批量修改字段
              - const: 101
                description: 计划表（包含所有计划表事件）
              - const: 1011
                description: 发布草稿
              - const: 1012
                description: 创建草稿
              - const: 200
                description: 节点（包含所有节点事件）
              - const: 2001
                description: 完成节点
              - const: 2002
                description: 删除节点
              - const: 2003
                description: 恢复节点
              - const: 2004
                description: 回滚节点
              - const: 2005
                description: 填写排期与估分
              - const: 2006
                description: 修改节点负责人
              - const: 2008
                description: 修改排期联动子项
              - const: 300
                description: 状态（包含所有状态事件）
              - const: 3001
                description: 变更状态
              - const: 400
                description: 子任务（包含所有子任务事件）
              - const: 4001
                description: 新增子任务
              - const: 4002
                description: 删除子任务
              - const: 4003
                description: 完成子任务
              - const: 4004
                description: 取消完成子任务
              - const: 4005
                description: 修改子任务负责人
              - const: 4006
                description: 修改子任务估分
              - const: 4007
                description: 修改子任务排期
              - const: 4008
                description: 修改子任务实际工时
          description: |
            触发事件类型 code 数组。事件分组：工作项(100)、计划表(101)、节点(200)、状态(300)、子任务(400)。
            ⚠️ 父子互斥规则（由 allOf 强制执行）：若传入父级 code，则不能同时包含其子 code。
              - 传 100 → 不能再传 1001~1010
              - 传 101 → 不能再传 1011~1012
              - 传 200 → 不能再传 2001~2008
              - 传 300 → 不能再传 3001
              - 传 400 → 不能再传 4001~4008
          $comment: 触发事件类型 code 数组，父子互斥
      $comment: 拦截事件配置组，包含工作项类型 and 触发事件类型
      allOf:
        - if:
            properties:
              event_type:
                contains:
                  const: 100
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010]
        - if:
            properties:
              event_type:
                contains:
                  const: 101
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [1011, 1012]
        - if:
            properties:
              event_type:
                contains:
                  const: 200
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [2001, 2002, 2003, 2004, 2005, 2006, 2008]
        - if:
            properties:
              event_type:
                contains:
                  const: 300
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [3001]
        - if:
            properties:
              event_type:
                contains:
                  const: 400
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008]

    InterceptPoint:
      type: object
      additionalProperties: false
      required: [key, name, i18n_info, url, token, event_config, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^intercept_'
          description: 拦截事件唯一标识（Key），生成规则：不能重复，前缀为 intercept_，后面默认随机生成6位
        type:
          const: intercept
          $comment: 点位类型，固定为 intercept
        name:
          type: string
          maxLength: 15
          description: 拦截事件名称，用于在列表中显示
          $comment: 拦截事件名称，用于在列表中显示
        description:
          type: string
          maxLength: 50
          description: 描述，用于说明拦截事件的用途
        i18n_info:
          $ref: '#/integrate_point_schema/definitions/I18nInfo'
          $comment: 多语言信息，包含拦截事件名称(name)和可选的描述(description)
        url:
          $ref: '#/integrate_point_schema/definitions/UrlHttp'
          description: 回调接口，用于接收所拦截的事件（推荐使用 https 协议）
          $comment: 回调接口，用于接收所拦截的事件（推荐使用 https 协议）
        token:
          $ref: '#/integrate_point_schema/definitions/TokenString'
          description: 回调 token
          $comment: 回调 token
        event_config:
          type: array
          minItems: 1
          items:
            $ref: '#/integrate_point_schema/definitions/InterceptEventConfig'
          $comment: 配置组，包含工作项类型和触发事件类型，可添加多组
        platform:
          type: object
          additionalProperties: false
          required: [web, mobile]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebNoScene'
              $comment: 网页端配置，仅包含 resourceId
              $description: 网页端配置，仅包含 resourceId
            mobile:
              $ref: '#/integrate_point_schema/definitions/PlatformMobileNoScene'
              $comment: 移动端配置，仅包含 resourceId
              $description: 移动端配置，仅包含 resourceId
      $comment: 拦截配置，用于定义插件的请求拦截功能，包含基本信息、配置组、回调接口和适用端等

    SingleIntercept:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/InterceptPoint'
      $comment: 单个拦截点配置数组，最多只能有一个

    # -----------------------------
    # Listen Event
    # -----------------------------
    ListenEventConfig:
      type: object
      additionalProperties: false
      required: [work_item_type, event_type]
      properties:
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForListenEvent'
          $comment: 监听事件位工作项类型配置，支持全部或指定类型
        custom_work_item_type:
          $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
          $comment: 自定义工作项类型配置，当 work_item_type 包含 work_object 时使用
        event_type:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            oneOf:
              - const: 100
                description: 工作项（包含所有工作项事件）
              - const: 1001
                description: 新建工作项
              - const: 1002
                description: 删除工作项
              - const: 1004
                description: 恢复工作项
              - const: 1005
                description: 终止工作项
              - const: 1006
                description: 模版升级
              - const: 1009
                description: 修改字段
              - const: 200
                description: 节点（包含所有节点事件）
              - const: 2001
                description: 完成节点
              - const: 2002
                description: 删除节点
              - const: 2003
                description: 恢复节点
              - const: 2004
                description: 回滚节点
              - const: 2005
                description: 修改排期与估分
              - const: 2006
                description: 修改节点负责人
              - const: 2007
                description: 修改实际工时
              - const: 2009
                description: 多人确认节点流转
              - const: 300
                description: 状态（包含所有状态事件）
              - const: 3001
                description: 变更状态
              - const: 400
                description: 子任务（包含所有子任务事件）
              - const: 4001
                description: 新建子任务
              - const: 4002
                description: 删除子任务
              - const: 4003
                description: 完成子任务
              - const: 4004
                description: 取消完成子任务
              - const: 4005
                description: 修改子任务负责人
              - const: 4006
                description: 修改子任务估分
              - const: 4007
                description: 修改子任务排期
              - const: 4008
                description: 修改子任务实际工时
              - const: 4009
                description: 修改子任务字段
              - const: 500
                description: 空间（包含所有空间事件）
              - const: 5001
                description: 添加成员
              - const: 5002
                description: 删除成员
          description: |
            监听事件类型 code 数组。事件分组：工作项(100)、节点(200)、状态(300)、子任务(400)、空间(500)。
            ⚠️ 父子互斥规则（由 allOf 强制执行）：若传入父级 code，则不能同时包含其子 code。
              - 传 100 → 不能再传 1001/1002/1004/1005/1006/1009
              - 传 200 → 不能再传 2001~2007/2009
              - 传 300 → 不能再传 3001
              - 传 400 → 不能再传 4001~4009
              - 传 500 → 不能再传 5001/5002
          $comment: 监听事件类型 code 数组，父子互斥
      $comment: 监听事件配置，包含工作项类型、自定义工作项类型和事件类型
      # 动态联动：仅当 work_item_type 包含 work_object 时，custom_work_item_type 才出现且必填
      allOf:
        - if:
            properties:
              work_item_type:
                type: array
                contains:
                  const: work_object
          then:
            required: [custom_work_item_type]
            properties:
              custom_work_item_type:
                allOf:
                  - $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
                  - minItems: 1
          else:
            not:
              required: [custom_work_item_type]
        - if:
            properties:
              event_type:
                contains:
                  const: 100
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [1001, 1002, 1004, 1005, 1006, 1009]
        - if:
            properties:
              event_type:
                contains:
                  const: 200
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009]
        - if:
            properties:
              event_type:
                contains:
                  const: 300
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [3001]
        - if:
            properties:
              event_type:
                contains:
                  const: 400
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009]
        - if:
            properties:
              event_type:
                contains:
                  const: 500
          then:
            properties:
              event_type:
                not:
                  contains:
                    enum: [5001, 5002]

    ListenEventPoint:
      type: object
      additionalProperties: false
      required: [url, token, event_config]
      properties:
        type:
          const: listen_event
          $comment: 点位类型，固定为 listen_event
        url:
          $ref: '#/integrate_point_schema/definitions/UrlHttp'
          $comment: 监听请求 URL，需以 http(s):// 开头
        token:
          $ref: '#/integrate_point_schema/definitions/TokenString'
          $comment: 监听请求 Token，用于身份验证
          description: 监听请求 Token，用于验证请求来源
        event_config:
          type: array
          minItems: 1
          items:
            $ref: '#/integrate_point_schema/definitions/ListenEventConfig'
          $comment: 监听事件配置数组，包含工作项类型和事件类型
      $comment: 监听事件点配置，用于定义插件的事件监听功能，包含 URL、Token、事件配置

    SingleListenEvent:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/ListenEventPoint'
      $comment: 单个监听事件点配置数组，最多只能有一个

    # -----------------------------
    # Component (schedule)
    # -----------------------------
    ComponentSchedulePoint:
      type: object
      additionalProperties: false
      required: [key, component_type, work_item_type, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^component_schedule_'
          description: 节点排期唯一标识（Key），生成规则：不能重复，前缀为 component_schedule_，后面默认随机生成6位
        component_type:
          const: schedule
          $comment: 组件类型，固定为 schedule（节点排期）
        work_item_type:
          $ref: '#/integrate_point_schema/definitions/WorkItemTypeForComponentSchedule'
          $comment: 节点排期工作项类型配置，支持全部、需求、其他工作项
        custom_work_item_type:
          $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
          $comment: 自定义工作项类型配置，当 work_item_type 包含 work_object 时使用
        platform:
          type: object
          additionalProperties: false
          required: [web]
          properties:
            web:
              $ref: '#/integrate_point_schema/definitions/PlatformWebForComponentSchedule'
              $comment: 网页端配置，包含替换位置和资源 ID
              $description: 网页端配置，包含替换位置和资源 ID
      $comment: 节点排期配置，用于定义插件的排期组件，包含工作项类型和适用端等
      # 动态联动：仅当 work_item_type 包含 work_object 时，custom_work_item_type 才出现且必填
      allOf:
        - if:
            properties:
              work_item_type:
                type: array
                contains:
                  const: work_object
          then:
            required: [custom_work_item_type]
            properties:
              custom_work_item_type:
                allOf:
                  - $ref: '#/integrate_point_schema/definitions/CustomWorkItemTypeArray'
                  - minItems: 1
          else:
            not:
              required: [custom_work_item_type]

    SingleComponentSchedule:
      type: array
      maxItems: 1
      items:
        $ref: '#/integrate_point_schema/definitions/ComponentSchedulePoint'
      $comment: 单个定时任务组件位配置数组，最多只能有一个

    # -----------------------------
    # Field Template
    # -----------------------------
    TreeSelectOption:
      type: object
      additionalProperties: false
      required: [label, value, translation]
      properties:
        label:
          type: string
          description: 选项显示名称
        value:
          type: string
          description: 选项值
        color:
          type: string
          description: 选项颜色
        translation:
          type: object
          additionalProperties: false
          required: [zh, en, ja]
          properties:
            zh:
              type: string
              description: 中文翻译
            en:
              type: string
              description: 英文翻译
            ja:
              type: string
              description: 日文翻译
        children:
          type: array
          items:
            $ref: '#/integrate_point_schema/definitions/TreeSelectOption'
          description: 子选项（级联结构）
      $comment: 级联选择器的选项配置，支持多语言翻译和嵌套子项

    CustomFieldPoint:
      type: object
      additionalProperties: false
      required: [key, i18n_info, subfield, platform]
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^field_template_'
          description: 点位唯一标识，只读。生成规则：不能重复，前缀为 field_template_，后面默认随机生成6位。
          $comment: 点位唯一标识，只读。生成规则：不能重复，前缀为 field_template_，后面默认随机生成6位。
        i18n_info:
          type: object
          required: [name, description]
          description: >
            字段模板的名称与描述。⚠️ 结构与其他点位不同：此处为平铺对象 {name, description}，无语言 key。
            存储到后端时固定写入 zh-cn 语言 key（与 I18nInfo 通用定义的 Record<langKey,...> 形态不同）。
          properties:
            name:
              type: string
              maxLength: 50
              description: 字段类型名称，必填。不能与 Meego 系统字段重名，不能在同一插件下和其他点位重名。
            description:
              type: string
              maxLength: 50
              description: 描述，必填。
        subfield:
          type: array
          minItems: 1
          maxItems: 10
          uniqueItems: true
          x-unique-fields: ["name", "field_key"]
          items:
            type: object
            required: [i18n_info, field_type, field_key]
            properties:
              name:
                type: string
                maxLength: 254
                description: 子字段名称，非必填。为空时使用 i18n_info 中的中文 name。
              desc:
                type: string
                maxLength: 50
                description: 描述。
              i18n_info:
                type: object
                description: '子字段多语言信息，必填。格式如 {zh: {name: "人员", desc: ""}}。'
                additionalProperties: false
                required: [zh]
                properties:
                  zh:
                    type: object
                    additionalProperties: false
                    required: [name]
                    properties:
                      name:
                        type: string
                        description: 中文名称
                      desc:
                        type: string
                        description: 中文描述
                  en:
                    type: object
                    additionalProperties: false
                    required: [name]
                    properties:
                      name:
                        type: string
                        description: 英文名称
                      desc:
                        type: string
                        description: 英文描述
                  ja:
                    type: object
                    additionalProperties: false
                    required: [name]
                    properties:
                      name:
                        type: string
                        description: 日文名称
                      desc:
                        type: string
                        description: 日文描述
              field_type:
                type: string
                enum: [multi-pure-text, tree-multi-select, number, multi-user, precise_date]
                description: 子字段类型：multi-pure-text(多行文本), tree-multi-select(级联多选), number(数字), multi-user(人员多选), precise_date(日期时间)。必填。
              field_key:
                type: string
                pattern: '^sub_field_'
                description: 子字段 Key，只读，由系统自动生成。前缀固定为 sub_field_（schema 通过 pattern 约束，但实际值由系统生成，勿手动填写）。
              options:
                type: array
                items:
                  $ref: '#/integrate_point_schema/definitions/TreeSelectOption'
                description: 选项配置。当 field_type 为 tree-multi-select(级联多选) 时建议填写，包含多语言翻译(zh/en/ja)和嵌套层级结构。默认为空数组 []。
                default: []
        platform:
          type: object
          additionalProperties: false
          required: [web, mobile]
          properties:
            web:
              type: object
              required: [resource, table_layout]
              properties:
                resource:
                  $ref: '#/integrate_point_schema/definitions/ResourceId'
                  description: 网页端 resourceId，必填。
                need_extra_config:
                  type: boolean
                  description: 提供扩展字段配置开关。开启后可进一步配置展示态布局及数据接口。
                table_layout:
                  type: object
                  description: |
                    网页端表格页展示态布局（必填），结构同 control.table_cell：
                      1. 裸 template（含顶层 `type`），CLI 自动包装；
                      2. 完整 { definitions, template }，缺失的 definitions 子键会被补齐为空对象。
                    与 control 不同：CustomField 表格列默认双击可编辑——平台会加载 web 产物中导出的 FEATURE_CUSTOMFIELD_TABLE_EDIT 入口作为编辑弹窗内容（无需通过 scene 配置）；展示态依旧由本字段控制。
                    本字段中可读取 {{$fieldValue}} 直接访问当前字段实例值（结构见 availableVariables）。
                    template 树最大嵌套深度 ≤ 5（由 validateDefinitionJSON 校验）。
                  dslSchema:
                    $ref: '#/integrate_point_schema/definitions/PlatformWebForControl/properties/table_cell/dslSchema'
                  $comment: 展示态布局 DSL，最大嵌套深度 ≤ 5；与 control.table_cell 等价
                table_data_url:
                  $ref: '#/integrate_point_schema/definitions/UrlHttp'
                  description: 网页端表格页展示态数据接口（可选）；填写后 table_data_token 将自动生成。支持 https/http 地址。
                  $comment: 展示态数据接口，填写后 table_data_token 必填
                table_data_token:
                  $ref: '#/integrate_point_schema/definitions/TokenString'
                  description: 网页端表格页展示态数据接口 Token；当 table_data_url 填写时自动生成（36 位 UUID）。
                  $comment: 展示态数据接口 Token，table_data_url 有值时必填
            mobile:
              type: object
              required: [resource, mobile_block_style]
              properties:
                resource:
                  $ref: '#/integrate_point_schema/definitions/ResourceId'
                  description: 移动端 resourceId，必填。
                mobile_block_style:
                  type: string
                  enum: [not_display, small, medium, big]
                  default: not_display
                  description: 移动端概览尺寸：not_display(不展示), small(小尺寸-80px), medium(中尺寸-160px), big(大尺寸-240px)。必填。
      # 动态联动：table_data_url 有值时，table_data_token 必填
      allOf:
        - if:
            properties:
              platform:
                properties:
                  web:
                    required: [table_data_url]
                    properties:
                      table_data_url:
                        minLength: 1
          then:
            properties:
              platform:
                properties:
                  web:
                    required: [table_data_token]
      $comment: >
        扩展字段-字段类型（CustomField）点位配置。

        【什么是字段模板】
        扩展字段-字段类型是由开发者自定义的字段类型，几乎媲美飞书项目一方字段类型，前端交互由开发者自定义。
        管理员可在「空间配置 > 工作项 > 字段配置」中像使用普通字段一样使用插件引入的字段类型——开发者注册时不限定工作项类型，admin 装字段时按需挂到具体工作项。
        数据存储在飞书项目平台，因此享一方字段全套能力：筛选 / 排序 / 分组 / 度量（即将上线）/ 流转条件 / 字段配置（有效性、授权角色、权限）/ 布局配置（新建页可见性、必填）。
        OpenAPI 读取任意插件可调，写入仅开发该字段类型的插件可调（防脏数据引入）。
        JSSDK 命名空间：window.JSSDK.customField.*

        【典型场景举例】
        - 企业名片字段：子字段包含名称、地址、联系电话、邮箱、联系人
        - 项目评估字段：子字段包含评估说明（文本）、评估维度（级联多选）、评估分数（数字）、评估人（人员）、评估日期（日期）
        - 任何需要「结构化数据 + 平台级筛选/度量/条件流转」的自定义字段

        【子字段设计要点】
        子字段是字段类型的数据结构定义，支持 5 种类型：
        - multi-pure-text（多行文本）：承载文字数据，如客户名称
        - tree-multi-select（级联多选）：承载选项数据，如所属区县
        - number（数字）：承载数字数据，如评分、经度
        - multi-user（多选人员）：承载人员数据，如拜访人
        - precise_date（日期+时间）：承载时间数据，如拜访日期
        最多 20 个子字段，用户会在筛选、条件配置等场景频繁使用子字段。

        【与控件（control）的选型对比】
        详见 ControlPoint 的 $comment 中的能力对比表和选型决策树。
        核心区别：customField 数据存储在平台（可筛选/度量/流转条件），control 数据由开发者管理（仅自定义 UI）。

        【开发要求】
        必须同时实现 web 和 mobile 双端，确保移动端新建页必填等场景无阻塞。
        - web 产物：支持表单、表格编辑弹窗、字段配置弹窗三种场景
        - mobile 产物：仅支持表单场景
        插件卸载后，已创建的字段会回退为复合字段样式；重新安装后恢复插件实现。

    MultiCustomField:
      type: array
      items:
        $ref: '#/integrate_point_schema/definitions/CustomFieldPoint'
      $comment: 多个字段模板位配置数组

    # -----------------------------
    # Builder Comp
    # -----------------------------
    BuilderLayout:
      type: object
      additionalProperties: false
      required: [mode]
      properties:
        mode:
          type: integer
          enum: [0, 1]
          description: 尺寸模式：0-固定值（staticHeight 模式）, 1-栅格（Grid 模式）。
        staticHeight:
          type: number
          maximum: 10000
          description: >
            固定高度 (px)。仅 mode=0 使用；真实范围 24–10000。
            mode=1 时应缺失或为 0（sentinel，兼容 local-config get --remote 的残留字段）。
            具体下限 / sentinel 约束由下方 allOf 的条件分支强制，property 层不设置 minimum
            以避免与 mode=1 的 0 残留互相冲突。
        staticWidth:
          type: number
          maximum: 12
          description: >
            固定宽度 (栅格)。仅 mode=0 使用；真实范围 1–12。
            mode=1 时应缺失或为 0（sentinel，兼容 local-config get --remote 的残留字段）。
            具体下限 / sentinel 约束由下方 allOf 的条件分支强制，property 层不设置 minimum
            以避免与 mode=1 的 0 残留互相冲突。
        minW:
          type: number
          minimum: 1
          maximum: 12
          description: 最小宽度 (栅格)。适用于 mode=1；范围 1–12，须 ≤ maxW。
        maxW:
          type: number
          minimum: 1
          maximum: 12
          description: 最大宽度 (栅格)。适用于 mode=1；范围 1–12，须 ≥ minW。
        minH:
          type: number
          minimum: 1
          maximum: 24
          description: 最小高度 (栅格)。适用于 mode=1；范围 1–24，须 ≤ maxH。
        maxH:
          type: number
          minimum: 1
          maximum: 24
          description: 最大高度 (栅格)。适用于 mode=1；范围 1–24，须 ≥ minH。
        presetW:
          type: number
          minimum: 1
          maximum: 12
          description: 默认宽度 (栅格)。适用于 mode=1；范围 1–12。语义要求须在 [minW, maxW] 之间
        presetH:
          type: number
          minimum: 1
          maximum: 24
          description: 默认高度 (栅格)。适用于 mode=1；范围 1–24。语义要求须在 [minH, maxH] 之间
      $comment: >
        构建器布局配置，用于定义拖拽式布局组件的尺寸模式和相关尺寸参数。
        来自 LayoutConfig.tsx 的约束：MIN_PIXEL_H=24, MAX_PIXEL_H=10000, MIN_GRID_W=1, MAX_GRID_W=12, MIN_GRID_H=1, MAX_GRID_H=24。
        注意：presetW 须在 [minW, maxW] 之间，presetH 须在 [minH, maxH] 之间
      allOf:
        - if:
            properties:
              mode: { const: 0 }
          then:
            required: [staticHeight, staticWidth]
            properties:
              staticHeight: { minimum: 24 }
              staticWidth: { minimum: 1 }
          $comment: mode=0 时，静态高度和宽度必填，且需满足真实下限（高度 ≥24，宽度 ≥1）
        - if:
            properties:
              mode: { const: 1 }
          then:
            required: [minW, maxW, minH, maxH, presetW, presetH]
            properties:
              staticHeight:
                enum: [0]
                $comment: mode=1 时 staticHeight 仅允许缺失或为 0 sentinel，其他值是语义错误
              staticWidth:
                enum: [0]
                $comment: mode=1 时 staticWidth 仅允许缺失或为 0 sentinel，其他值是语义错误
            x-field-lte:
              - [minW, maxW, "minW must be <= maxW"]
              - [minH, maxH, "minH must be <= maxH"]
            x-field-range:
              - [presetW, minW, maxW, "presetW must be between minW and maxW"]
              - [presetH, minH, maxH, "presetH must be between minH and maxH"]
          $comment: mode=1 时，最小/最大宽度、最小/最大高度、预设宽度/高度必填，且须满足跨字段约束

    LiteAppComponentPoint:
      type: object
      additionalProperties: false
      required: [key, i18n_info, platform]
      x-cross-unique-fields:
        - [[properties, outputs], prop_key]
      # 组件必须至少有一个对外属性：properties（输入）或 outputs（输出）二者至少一个非空。
      # 两者皆空（或皆不声明）的"空壳组件"无意义，且会让后端 builder_comp_prop_config.sub_comp 为空。
      anyOf:
        - required: [properties]
          properties:
            properties:
              minItems: 1
        - required: [outputs]
          properties:
            outputs:
              minItems: 1
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^lite_app_'
          description: 组件 key，只读。生成规则：不能重复，前缀为 lite_app_，后面默认随机生成6位。
        i18n_info:
          type: object
          minProperties: 1
          description: >
            轻应用组件的多语言名称配置。⚠️ 语言 key 固定为 zh-cn / en-us / ja-jp（横线格式），
            与其他点位的 zh_CN / en_US（下划线格式）不同。至少提供一种语言，建议同时填写 zh-cn 和 en-us。
          properties:
            zh-cn:
              type: object
              required: [name, description]
              properties:
                name: { type: string, minLength: 1, maxLength: 50, description: "组件名称，必填。" }
                description: { type: string, minLength: 1, maxLength: 50, description: "描述，必填。" }
            en-us:
              type: object
              required: [name, description]
              properties:
                name: { type: string, minLength: 1, maxLength: 50 }
                description: { type: string, minLength: 1, maxLength: 50 }
            ja-jp:
              type: object
              required: [name, description]
              properties:
                name: { type: string, minLength: 1, maxLength: 50 }
                description: { type: string, minLength: 1, maxLength: 50 }
        icon_url:
          type: string
          pattern: '^$|\.(svg|png|jpe?g|bmp)$'
          description: >
            AI 不用传入，后端会统一使用插件级 icon 兜底。
        properties:
          type: array
          uniqueItems: true
          x-unique-fields: ["name", "prop_key"]
          description: >
            组件的**输入属性**列表（INPUT）。这些属性会展示在组件的设置面板中，供管理员手动填写/选择，
            运行时通过 `JSSDK.liteAppComponent.getProps()[propKey]` / `getDataSourceResult(propKey, ...)` 读取。
            与 `outputs`（OUTPUT 输出属性）互补，⚠️ 两者不能同时为空：`properties` 与 `outputs`
            至少有一个声明且非空（组件必须有对外属性）。需求不需要管理员输入配置时可不声明本字段，
            但此时必须声明至少一个 `outputs`。
            ⚠️ **位置规则**：所有"组件读取的属性"（管理员配 → 组件 getProps 读，包括 data_source）一律放这里；
            "组件向外推的属性"放 `outputs`。同名 prop_type（如 data_source）在两侧语义不同，按数组判方向。
            ⚠️ 字段溯源原则（给 AI 生成器）：此数组里的每一项都必须对应用户明确表达过的"可配置项"诉求，
            不要自行编造占位属性（如"默认视图""主题色"等）。
          items:
            type: object
            required: [name, prop_type, prop_key]
            properties:
              name:
                type: object
                minProperties: 1
                properties:
                  zh: { type: string, minLength: 1, maxLength: 100 }
                  en: { type: string, minLength: 1, maxLength: 100 }
                  ja: { type: string, minLength: 1, maxLength: 100 }
                description: 属性名称，必填且在同一组件内不能重复（至少提供一种语言）。
              prop_type:
                type: string
                enum: [text, number, select, boolean, multi_select, precise_date, date_range, work_item_instance, work_item_type, view_select, data_source, dataSource]
                description: >
                  属性类型，必填。⚠️ data_source 为数据源类型的规范写法（与其余 snake_case 类型统一）；
                  驼峰 dataSource 是历史遗留写法，仅为兼容存量配置而保留，新建/AI 生成请一律用 data_source。
              prop_key:
                type: string
                pattern: '^[a-z0-9]{6}$'
                description: 属性 key，只读且不能重复。随机生成6位。
              with_field:
                type: boolean
                description: >
                  是否关联字段。仅对 work_item_instance / work_item_type / data_source 三种"对象型"属性生效。
                  true 时，开发者后台会让用户从对象（工作项类型/数据源）上挑选若干实例字段（fieldList）；
                  被挑选的字段会随每个实例返回到组件运行时（LiteAppWorkItemInstance.fields[fieldKey]）。
                  ⚠️ 如果你只需要"数据源中每个实例的某个字段值"（如排期、负责人、状态、优先级），
                  正确方案是单个 data_source 属性设 with_field=true，不要再额外声明 date_range / text /
                  precise_date 等顶层属性来承载"字段本身"——那些类型承载的是"单个静态值"，
                  与"按实例携带字段"是两种语义。
              options:
                type: array
                minItems: 1
                items:
                  type: object
                  required: [label, translation]
                  properties:
                    label: { type: string, minLength: 1 }
                    translation:
                      type: object
                      required: [zh, en, ja]
                      properties:
                        zh: { type: string, minLength: 1 }
                        en: { type: string, minLength: 1 }
                        ja: { type: string, minLength: 1 }
                description: 选项配置。
            allOf:
              - if:
                  properties:
                    prop_type: { enum: [select, multi_select] }
                then:
                  required: [options]
                  $comment: 单选/多选类型时，options 必填
              - if:
                  properties:
                    prop_type: { enum: [work_item_instance, work_item_type, data_source, dataSource] }
                then:
                  required: [with_field]
                  $comment: 关联对象类型时，with_field 必填
        outputs:
          type: array
          uniqueItems: true
          x-unique-fields: ["name", "prop_key"]
          description: >
            组件的**输出属性**列表（OUTPUT）。⚠️ 与 `properties` 至少有一个声明且非空
            （组件必须有对外属性）；仅当 `properties` 已非空时本字段才可省略。
            这些属性是组件向下游推送的接口面，开发者通过
            `JSSDK.liteAppComponent.notify(propKey, payload)` 推数据，下游组件
            （一方"工作项视图" / 其他自定义组件 `properties[].data_source` 槽位）订阅消费。
            ⚠️ payload 形态由 prop_type 决定：data_source → { moql: "SELECT ..." }、
            text → string、number → number、precise_date → number(毫秒时间戳)、
            date_range → { start, end }、view_select → { viewId }、
            work_item_instance → { workObjectId, workItemId }、
            work_item_type → { workObjectId }；详见 runtime LiteAppSubscribedPropertyValueType。
            ⚠️ 不支持 select / multi_select / boolean 类型（仅 properties 输入侧支持）。
            ⚠️ 输出属性没有"字段输出"能力——组件只能推完整 payload，不能"勾选要返回哪些字段"
            （那是 properties 输入侧 with_field 的语义）。
          items:
            type: object
            additionalProperties: false
            required: [name, prop_type, prop_key]
            properties:
              name:
                type: object
                minProperties: 1
                properties:
                  zh: { type: string, minLength: 1, maxLength: 100 }
                  en: { type: string, minLength: 1, maxLength: 100 }
                  ja: { type: string, minLength: 1, maxLength: 100 }
                description: 属性名称，必填且在同一组件内不能重复（至少提供一种语言）。
              prop_type:
                type: string
                enum: [text, number, precise_date, date_range, work_item_instance, work_item_type, view_select, data_source, dataSource]
                description: >
                  输出属性类型：text(文本), number(数字), precise_date(精确日期), date_range(日期范围),
                  work_item_instance(工作项实例), work_item_type(工作项类型), view_select(视图),
                  data_source(数据集；runtime API 里也叫 dataSet，payload 是 { moql })。必填。
                  ⚠️ 驼峰 dataSource 是历史遗留写法，仅为兼容存量配置保留，新建/AI 生成请用 data_source。
              prop_key:
                type: string
                pattern: '^[a-z0-9]{6}$'
                description: 属性 key，只读且不能重复。随机生成6位。
        platform:
          type: object
          additionalProperties: false
          required: [web]
          properties:
            web:
              type: object
              required: [resource, layout]
              properties:
                resource:
                  allOf:
                    - $ref: '#/integrate_point_schema/definitions/ResourceId'
                    - pattern: '^lite_app_web_'
                  description: 网页端 resourceId，必填且只读。前缀为 lite_app_web_。
                layout:
                  $ref: '#/integrate_point_schema/definitions/BuilderLayout'
                  description: 布局配置。
      $comment: 轻应用组件位配置，用于定义插件的拖拽式组件，包含国际化信息、属性配置、输出属性、平台配置等

    MultiLiteAppComponent:
      type: array
      maxItems: 20
      items:
        $ref: '#/integrate_point_schema/definitions/LiteAppComponentPoint'
      $comment: 多个轻应用组件位配置数组，最多 20 个

    # ─────────────────────────────────────────────────────────────────────
    # AI Node / AI Field（AI 插件专用，与 GUI 表单同构）
    #
    # 总览（写给 AI 生成器读 — 决定要不要选 ai_node / ai_field 的关键信号）：
    #   • ai_node 用于"在工作流中插入 AI 任务"——管理员把 AI 节点拖到流程里，工作项推进到该节点
    #     时，平台向开发者 Webhook 推送事件，开发者调 OpenAPI 把结果写回完成节点。
    #     仅支持「完成 / 回滚」操作；不支持计划表配置。
    #   • ai_field 用于"为字段类型提供 AI 计算"——管理员在字段管理添加 AI 字段，引用本应用，
    #     用户使用时平台触发 Webhook，开发者通过「更新 AI 字段」OpenAPI 写回 field_value。
    #     无需前端产物（lpm publish 可传 frontVersion='0'）。
    #
    # 形态约束：本类型为单对象（不是数组），AI 插件全工程恰好一个；schema 与 preflight 双重
    # 阻断写成数组的形态。app_type=ai_node 工程不可出现 aiField 顶层 key，反之亦然。
    # ─────────────────────────────────────────────────────────────────────

    AIPropNameI18nText:
      type: object
      minProperties: 1
      additionalProperties: false
      description: |
        AI 点位 property 的"属性名"多语言文本，至少填一种语言；**单语言上限 50 字符**（对齐 GUI 表单）。
        语言 key 与 LiteAppComponent property 保持一致（zh / en / ja，无连字符）。
      properties:
        zh: { type: string, minLength: 1, maxLength: 50, description: 中文文本（≤ 50 字符） }
        en: { type: string, minLength: 1, maxLength: 50, description: 英文文本（≤ 50 字符） }
        ja: { type: string, minLength: 1, maxLength: 50, description: 日文文本（≤ 50 字符） }

    AIPropDescI18nText:
      type: object
      minProperties: 1
      additionalProperties: false
      $comment: 与 AIPropNameI18nText 同款 type，仅 maxLength 不同（200 vs 50）。
      description: |
        AI 点位 property 的"描述"多语言文本，至少填一种语言；**单语言上限 200 字符**（对齐 GUI 表单）。
        语言 key 与 AIPropNameI18nText 同款（zh / en / ja，无连字符）。
      properties:
        zh: { type: string, minLength: 1, maxLength: 200, description: 中文文本（≤ 200 字符） }
        en: { type: string, minLength: 1, maxLength: 200, description: 英文文本（≤ 200 字符） }
        ja: { type: string, minLength: 1, maxLength: 200, description: 日文文本（≤ 200 字符） }

    AIPropOption:
      type: object
      required: [label, translation]
      additionalProperties: false
      description: |
        property 的单条选项配置，仅 data_type=select / multi_select 时需要。
        label 是该选项的内部值（webhook 事件回传该值给开发者代码），translation 是
        给最终用户展示的多语言文案（zh / en / ja 三种均必填，避免某语言缺失退回 label）。
      properties:
        label:
          type: string
          minLength: 1
          description: 选项内部值（webhook 事件的 `value`，开发者在代码里识别这个）
        translation:
          type: object
          required: [zh, en, ja]
          additionalProperties: false
          description: 选项展示多语言文案（三种语言都必填）
          properties:
            zh: { type: string, minLength: 1, description: 简体中文展示文本 }
            en: { type: string, minLength: 1, description: 英文展示文本 }
            ja: { type: string, minLength: 1, description: 日文展示文本 }

    AIPropFieldTypeKey:
      type: string
      description: |
        AI 节点 / AI 字段 properties 的"输入端"字段类型 key 白名单——共 27 项，
        ai_node 与 ai_field 共用同一份。

        语义：管理员在配置 AI 应用时，对每条 property 选择"管理员可映射哪些字段类型的工作项字段"
        作为输入数据，本字段限定可选的字段类型。
      enum:
        - text                            # 文本
        - multi-text                      # 富文本
        - select                          # 单选
        - radio                           # 单选按钮
        - multi-select                    # 多选
        - date                            # 日期
        - schedule                        # 日期区间
        - user                            # 单选人员
        - multi-user                      # 多选人员
        - vote-boolean                    # 投票（是/否）
        - vote-option                     # 投票（单选）
        - vote-option-multi               # 投票（多选）
        - tree-select                     # 级联单选
        - tree-multi-select               # 级联多选
        - workitem_related_select         # 工作项关联（单选）
        - workitem_related_multi_select   # 工作项关联（多选）
        - bool                            # 布尔
        - link                            # 链接
        - link_cloud_doc                  # 关联云文档
        - compound_field                  # 复合字段
        - multi_user_compound_field       # 多人员复合字段
        - telephone                       # 电话
        - email                           # 邮箱
        - number                          # 数字
        - multi-file                      # 多文件
        - signal                          # 信号
        - multi-signal                    # 多信号

    AINodeProperty:
      type: object
      additionalProperties: false
      required: [key, name, data_type]
      description: |
        AI 节点单条输入属性。运行时管理员在【AI 配置】页给这条属性映射工作项字段或填默认值，
        节点执行时平台把（属性 key + 解析后的值）作为 `field_ai_entity` 通过 Webhook 推送给
        开发者代码；开发者也可调"获取 AI 节点信息"OpenAPI 主动拉取。
      properties:
        key:
          type: string
          pattern: '^[a-z0-9]{6}$'
          description: |
            属性 key，pattern `6 位 base36`，同一节点内不可重复。
            出现在 webhook 事件的 `props[].prop_key`，开发者代码用它定位每个属性。
        name:
          $ref: '#/integrate_point_schema/definitions/AIPropNameI18nText'
          description: 属性显示名称（多语言；同节点内 name 不可重复；单语言上限 50 字符）
        description:
          $ref: '#/integrate_point_schema/definitions/AIPropDescI18nText'
          description: 属性描述（多语言，可选；单语言上限 200 字符）
        data_type:
          type: array
          minItems: 1
          uniqueItems: true
          description: |
            AI 节点属性的"属性类型"，分两组（互斥）：

            **工作项数据组**（平台解析后用 prop_value.field 推回 webhook）：
              - field        工作项字段
              - node_form    节点表单字段
              - node_field   节点字段
              内部互斥规则：**field 与 node_form 不可同时选**；node_field 可与 field 或 node_form 叠加。

            **自定义属性组**（管理员直接填值，用 prop_value.custom_property 推回 webhook）：
              - select       单选
              - multi_select 多选
              - text         自定义文本
              - number       自定义数字
              内部互斥规则：**只能选其中 1 项**。

            **跨组互斥**：工作项数据组与自定义属性组不可混搭。

            **跨字段联动**（见 allOf）：
              - 选工作项数据组任一项 ⇒ input_field_types + max_field_count 必填，input_field_types 非空数组
              - 选 select / multi_select ⇒ options 必填且 ≥ 1 项
              - 选 text / number ⇒ 禁止携带 input_field_types / max_field_count / options
          oneOf:
            - description: 工作项数据组——field/node_form/node_field 子集，field↔node_form 互斥
              items:
                enum: [field, node_form, node_field]
              not:
                allOf:
                  - contains: { const: field }
                  - contains: { const: node_form }
              $comment: 组 1，工作项数据；field↔node_form 互斥；node_field 可叠加
            - description: 自定义属性组——select/multi_select/text/number 之一（单选）
              items:
                enum: [select, multi_select, text, number]
              maxItems: 1
              $comment: 组 2，自定义属性；内部单选
        input_field_types:
          type: array
          uniqueItems: true
          items:
            $ref: '#/integrate_point_schema/definitions/AIPropFieldTypeKey'
          description: |
            输入端字段类型过滤白名单——限定管理员能把哪些字段类型的工作项字段映射给本属性作为输入。
            **仅在 data_type 选工作项数据组时允许出现，且必填非空**（见 allOf）。
            每项必须在 AIPropFieldTypeKey 27 项白名单内。
        max_field_count:
          type: integer
          minimum: 1
          maximum: 20
          description: |
            数据上限——限制此属性最多可关联多少个字段。**仅在 data_type 选工作项数据组时允许出现且必填**
            （见 allOf）；取值 1-20，常用 1。**仅 ai_node 支持，ai_field 不允许**。
        options:
          type: array
          maxItems: 100
          items:
            $ref: '#/integrate_point_schema/definitions/AIPropOption'
          description: |
            选项列表。**仅在 data_type 含 select / multi_select 时允许出现且必填非空**（见 allOf）；
            上限 100 项。
      allOf:
        - if:
            properties:
              data_type:
                contains:
                  enum: [field, node_form, node_field]
          then:
            required: [input_field_types, max_field_count]
            properties:
              input_field_types: { minItems: 1 }
            $comment: 选工作项数据组 ⇒ input_field_types + max_field_count 必填，input_field_types 非空
          else:
            properties:
              input_field_types: false
              max_field_count: false
            $comment: 未选工作项数据组 ⇒ 禁止携带 input_field_types / max_field_count
        - if:
            properties:
              data_type:
                contains:
                  enum: [select, multi_select]
          then:
            required: [options]
            properties:
              options: { minItems: 1 }
            $comment: 含 select / multi_select ⇒ options 必填且 ≥ 1 项
          else:
            properties:
              options: false
            $comment: 不含 select / multi_select ⇒ 禁止携带 options

    AIFieldProperty:
      type: object
      additionalProperties: false
      required: [key, name, data_type]
      description: |
        AI 字段单条输入属性——AI 字段开发者定义的"配置项"，最终用户在工作项视图为该字段
        填值时实际填的是这些属性值，平台触发 Webhook 时打包进 field_ai_entity 推送。
      properties:
        key:
          type: string
          pattern: '^prop_[a-z0-9]{6}$'
          description: 属性 key，pattern `prop_<6 位 base36>`，同一字段内不可重复
        name:
          $ref: '#/integrate_point_schema/definitions/AIPropNameI18nText'
          description: 属性显示名称（多语言；同字段内 name 不可重复；单语言上限 50 字符）
        description:
          $ref: '#/integrate_point_schema/definitions/AIPropDescI18nText'
          description: 属性描述（多语言，可选；单语言上限 200 字符）
        data_type:
          type: array
          minItems: 1
          uniqueItems: true
          description: |
            AI 字段属性的"属性类型"，分两组（互斥）：

            **工作项数据组**（平台解析后用 prop_value.field 推回 webhook）：
              - field        工作项字段
              - role_type    角色类型（如负责人、审阅人、自定义角色）
              内部互斥规则：**无**——field 与 role_type 可单独或同时选。

            **自定义属性组**（管理员直接填值，用 prop_value.custom_property 推回 webhook）：
              - select       单选
              - multi_select 多选
              - text         自定义文本
              - number       自定义数字
              内部互斥规则：**只能选其中 1 项**。

            **跨组互斥**：工作项数据组与自定义属性组不可混搭。

            **跨字段联动**（见 allOf）：
              - 选 field ⇒ input_field_types 必填且非空数组（role_type 不触发）
              - 选 select / multi_select ⇒ options 必填且 ≥ 1 项
              - 选 role_type / text / number ⇒ 禁止携带 input_field_types / options

            **与 ai_node 区别**：本枚举无 `node_form` / `node_field`（节点级数据是 ai_node 专有）；
            不支持 `max_field_count`（ai_node 专有）。
          oneOf:
            - description: 工作项数据组——field/role_type 子集（无内部互斥）
              items:
                enum: [field, role_type]
              $comment: 组 1，工作项数据；field 与 role_type 可单独或同时选
            - description: 自定义属性组——select/multi_select/text/number 之一（单选）
              items:
                enum: [select, multi_select, text, number]
              maxItems: 1
              $comment: 组 2，自定义属性；内部单选
        input_field_types:
          type: array
          uniqueItems: true
          items:
            $ref: '#/integrate_point_schema/definitions/AIPropFieldTypeKey'
          description: |
            输入端字段类型过滤白名单——限定管理员能把哪些字段类型的工作项字段映射给本属性作为输入。
            **仅在 data_type 含 `field` 时允许出现且必填非空**（见 allOf；role_type 不触发，因为角色
            类型本身已经是字段语义）。每项必须在 AIPropFieldTypeKey 27 项白名单内。
        options:
          type: array
          maxItems: 100
          items:
            $ref: '#/integrate_point_schema/definitions/AIPropOption'
          description: |
            选项列表。**仅在 data_type 含 select / multi_select 时允许出现且必填非空**（见 allOf）；
            上限 100 项。
      allOf:
        - if:
            properties:
              data_type:
                contains:
                  enum: [field]
          then:
            required: [input_field_types]
            properties:
              input_field_types: { minItems: 1 }
            $comment: 含 field ⇒ input_field_types 必填且非空（role_type 不触发）
          else:
            properties:
              input_field_types: false
            $comment: 不含 field ⇒ 禁止携带 input_field_types
        - if:
            properties:
              data_type:
                contains:
                  enum: [select, multi_select]
          then:
            required: [options]
            properties:
              options: { minItems: 1 }
            $comment: 含 select / multi_select ⇒ options 必填且 ≥ 1 项
          else:
            properties:
              options: false
            $comment: 不含 select / multi_select ⇒ 禁止携带 options

    AINodePoint:
      type: object
      additionalProperties: false
      required: [key, url]
      description: |
        AI 节点位配置（单对象）—— 仅 app_type=ai_node 的插件可使用，全工程恰好一个，
        **且与所有非 AI 点位互斥**：本点位必须是全工程唯一点位，不得与 listen_event / button /
        liteAppComponent / customField / 任何其他点位共存（CLI preflight 按 plugin.config.json 的 app_type 硬卡，
        共存会被拒绝）。"流程推进自动触发"由本点位自身模型承载，不要再加 listen_event 去"监听节点流转"。

        AI 节点的运行模型：管理员把节点拖到工作流模板，工作项推进到此节点时平台向 url
        发 Webhook（含 task_id / props / 工作项上下文），开发者代码用这些信息跑 AI，
        通过【修改 AI 节点数据】+【完成 AI 节点】OpenAPI 写回结果并完成节点。
        创建后默认开启的 OpenAPI 权限：获取 AI 节点实例信息 / 修改 AI 节点实例数据 / 完成 AI 节点。

        **输入端**：`properties[]`——开发者声明需要哪些工作项数据 / 自定义属性作为 AI 任务的入参。
        **输出形式**：节点卡片（见 `needCustomCard` 开关）——开启即在工作项详情页渲染开发者自写的 React 卡片，
        关闭即节点执行完没有"输出形式"（只是节点流转结束）。

        **选 ai_node 还是 ai_field**：本类型由"工作流推进到节点"触发、`properties` 由管理员在节点配置时预设、结果写回节点。
        若诉求是"最终用户在工作项给某字段填 / 选值后即时出结果"，那是 ai_field。两者的 `properties` 都是输入，
        "需求里要一个可配置参数 / 选项"不构成区别——看触发时机与写回落点。
      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^ai_node_'
          description: AI 节点点位唯一标识（Key），不能重复，前缀为 ai_node_，后面默认随机生成6位
        type:
          const: ai_node
          $comment: 点位类型，固定 ai_node（CLI 转换时会强制覆盖，可省略不写）
        url:
          $ref: '#/integrate_point_schema/definitions/UrlHttp'
          description: |
            **Webhook 回调地址**（必填）。接收 AI 节点生命周期事件——节点开始 / 重试 / 取消等。
            必须 https（生产）；localhost / 内网调试时用 http 也可，但发布前需切到 https。
        token:
          $ref: '#/integrate_point_schema/definitions/TokenString'
          description: |
            Webhook 签名 Token——开放平台向 url 发请求时附 HMAC(token, body)，开发者侧用本 token
            验签确认请求来自飞书项目。

            **本 token 与 `plugin.config.json` 里的 `pluginSecret` 是两套独立 secret，用途完全不同**：
              - 本字段（webhook token）：用于 webhook 请求**验签**（HMAC-SHA256(token, rawBody) === signature）
              - pluginSecret：用于**调用 OpenAPI 时换 access_token**（OAuth 应用鉴权）

            **若留空 / 整个字段省略，CLI 在 `local-config set` 时自动生成 36 位 UUID 填入**——推荐让 CLI 兜底，
            不要在配置里手填，避免不同环境拷贝时 token 漂移。
          $comment: 省略字段或留空串时 CLI 自动生成 36 位 UUID 填入；提供非空值则按 36 位校验。
        properties:
          type: array
          uniqueItems: true
          maxItems: 20
          x-unique-fields: ["key", "name"]
          items:
            $ref: '#/integrate_point_schema/definitions/AINodeProperty'
          description: |
            节点输入属性列表（input；可空）——开发者在此声明节点对哪些"工作项字段 / 节点字段 /
            自定义文本数字单选多选"感兴趣，管理员配工作流时为这些属性映射真实字段。
            **官方上限：最多 20 组属性**（合计一级 ≤ 20）；CLI 通过 maxItems 强校验。
        needCustomCard:
          type: boolean
          description: |
            AI 节点的"输出形式"开关——决定节点执行完后是否在工作项详情页渲染开发者自写的卡片。

            • false（默认）：节点执行完即流转结束，**无输出形式**；插件无前端产物，lpm publish 可传 frontVersion='0'。
            • true：在工作项详情页渲染开发者写的 React 页面（用 JSSDK AINode API 取上下文）。
                    必须配 platform.web 和/或 platform.mobile，且需要在工程里写
                    `src/features/{web,mobile}/<resource>/index.tsx` 提供卡片实现，
                    随后跑 `lpm release` 上传产物，发布时绑定 frontVersion。
        platform:
          type: object
          additionalProperties: false
          description: |
            自定义卡片平台资源——仅 needCustomCard=true 时填，至少一端。Web / Mobile 双端
            **代码各自独立维护**（不会自动适配，详情页内容也可以差异化）。
            ResourceId 是开发者自定义、平台用来在对应端加载插件代码的唯一标识。
          properties:
            web:
              type: object
              additionalProperties: false
              required: [resource]
              description: 网页端卡片
              properties:
                resource:
                  allOf:
                    - $ref: '#/integrate_point_schema/definitions/ResourceId'
                    - pattern: '^ai_node_web_'
                  description: |
                    网页端 ResourceId（前缀 `ai_node_web_`）——映射到工程
                    `src/features/web/<resource>/index.tsx`，平台运行时用此 key 加载产物。
            mobile:
              type: object
              additionalProperties: false
              required: [resource]
              description: 移动端卡片
              properties:
                resource:
                  allOf:
                    - $ref: '#/integrate_point_schema/definitions/ResourceId'
                    - pattern: '^ai_node_mobile_'
                  description: |
                    移动端 ResourceId（前缀 `ai_node_mobile_`）——映射到工程
                    `src/features/mobile/<resource>/index.tsx`。
      allOf:
        - if:
            required: [needCustomCard]
            properties:
              needCustomCard: { const: true }
          then:
            required: [platform]
            properties:
              platform:
                anyOf:
                  - required: [web]
                  - required: [mobile]
            $comment: needCustomCard=true ⇒ platform 必填且 web / mobile 至少一端
          else:
            not:
              required: [platform]
            $comment: needCustomCard 缺省 / false 时禁止携带 platform，避免歧义（线上不会加载）
      $comment: AI 节点位配置（单对象）。AI 插件全工程仅一个；与 GUI 表单同构。

    AIFieldPoint:
      type: object
      additionalProperties: false
      required: [key, url, output_field_types]
      description: |
        AI 字段位配置（单对象）—— 仅 app_type=ai_field 的插件可使用，全工程恰好一个，
        **且与所有非 AI 点位互斥**：本点位必须是全工程唯一点位，不得与 listen_event / button /
        liteAppComponent / customField / 任何其他点位共存（CLI preflight 按 plugin.config.json 的 app_type 硬卡，
        共存会被拒绝）。**"字段值不用人填、源字段更新就自动重算"由本点位自身触发模型承载**——
        绑定的输入字段（如需求描述）变化时平台会重新触发本 AI 字段执行，**不要为"监听字段变更"另加 listen_event 点位**，
        那会触碰互斥约束、被 preflight 拒绝。

        AI 字段的运行模型：管理员在【字段管理】把"AI 字段"绑定到本应用 + 选输出字段类型，
        最终用户在视图为该字段填属性值并触发执行；平台向 url 发 Webhook（含 ai_task_id +
        field_ai_entity + 自定义属性）；开发者代码处理后通过【更新 AI 字段】OpenAPI 写回
        ai_task_id + field_value（field_value 必须符合所选输出类型的字段值规范）。

        **输入端**：`properties[]`——开发者声明字段需要哪些配置项（含工作项数据 / 自定义属性）。
        每条 property 的 `input_field_types` 是子级输入端字段类型白名单（27 项，与 ai_node 共用）。
        **输出端**：`output_field_types`（顶层）——本 AI 字段应用能被绑定到哪些字段类型作为输出
        （10 项白名单）。

        与 ai_node 区别：
        • 触发与配置：最终用户在工作项给该字段填 / 选值时即时触发、`properties` 由用户当场填；ai_node 是流程推进到节点自动跑、`properties` 由管理员预设。"用户当场选参数→即时出结果"只有 ai_field 能做（ai_node 也能读用户预先填在工作项字段里的值，但要等流程推进到节点才出结果，不是当场选当场出）
        • 无前端产物——AI 字段不需要客户端工程，lpm publish 可传 frontVersion='0'
        • 无 needCustomCard / platform 字段（输出形式不是节点卡片，而是 output_field_types）
        • 支持 role_type 额外的属性类型（相比 ai_node 多出来的）
        • 必须显式声明 output_field_types

      properties:
        key:
          allOf:
            - $ref: '#/integrate_point_schema/definitions/PointKey'
            - pattern: '^ai_field_'
          description: AI 字段点位唯一标识（Key），不能重复，前缀为 ai_field_，后面默认随机生成6位
        type:
          const: ai_field
          $comment: 点位类型，固定 ai_field（CLI 转换时会强制覆盖，可省略不写）
        url:
          $ref: '#/integrate_point_schema/definitions/UrlHttp'
          description: |
            **Webhook 回调地址**（必填）。接收 AI 字段事件——管理员触发 / 用户重新计算等。
        token:
          $ref: '#/integrate_point_schema/definitions/TokenString'
          description: |
            Webhook 签名 Token——开放平台给 webhook 请求加签，开发者用本 token 验签确认请求来自飞书项目而非伪造。

            **本 token 与 `plugin.config.json` 里的 `pluginSecret` 是两套独立 secret，用途完全不同**：
              - 本字段（webhook token）：用于 webhook 请求**验签**（HMAC-SHA256(token, rawBody) === signature）
              - pluginSecret：用于**调用 OpenAPI 时换 access_token**（OAuth 应用鉴权）

            **若留空 / 整个字段省略，CLI 在 `local-config set` 时自动生成 36 位 UUID 填入**——推荐让 CLI 兜底，
            不要在配置里手填，避免不同环境拷贝时 token 漂移。
          $comment: 省略字段或留空串时 CLI 自动生成 36 位 UUID 填入；提供非空值则按 36 位校验。
        properties:
          type: array
          uniqueItems: true
          maxItems: 20
          x-unique-fields: ["key", "name"]
          items:
            $ref: '#/integrate_point_schema/definitions/AIFieldProperty'
          description: |
            字段输入属性列表（input；可空）——开发者声明本 AI 字段需要哪些配置项；
            管理员在字段编辑页填这些属性，触发执行时平台 Webhook 透传给开发者。
            **官方上限：最多 20 组属性**。
        output_field_types:
          description: |
            输出端字段类型 key 列表（必填，至少一项）—— 决定本 AI 字段应用可被绑定到哪些字段类型作为输出。
            管理员创建 AI 字段时，仅能关联输出类型集合包含目标字段类型的应用——选错就配不通。

            **两种合法写法（互斥）**：
            - 通配：单独写 `['all']`，CLI 转后端时展开成完整 10 项真实 key（与 GUI 选「全部」等价）
            - 显式：从下面 enum 10 项中挑任意子集，但不能再混入 `'all'`——写了 `'all'` 就只能这一项

            CLI 转后端时映射到顶层 `field_types`（IDL 字段名）。
          oneOf:
            - type: array
              minItems: 1
              maxItems: 1
              items:
                const: all
              $comment: 通配——单独写 'all'；与下面显式 enum 互斥
            - type: array
              minItems: 1
              uniqueItems: true
              items:
                type: string
                enum:
                  - text         # 普通文本
                  - number       # 数字
                  - date         # 日期
                  - schedule     # 日期区间（key 是 schedule，不是 date_range）
                  - bool         # 布尔
                  - multi-text   # 富文本（key 是 multi-text，不是 rich_text / rich-text）
                  - multi-user   # 多人员
                  - user         # 单人员
                  - multi-file   # 多文件
                  - link         # 链接
              $comment: 显式列举——从 10 项中挑任意子集（不含 'all'）
          $comment: |
            enum 对齐 AI 字段输出类型白名单；
            'all' 由 CLI localToBackend 展开成 10 项真实 key（后端不收 'all'）。
            'all' 与其它 enum 值通过 oneOf 互斥（仿 WorkItemTypeArray 的 _all 互斥模板）。
            业务侧扩展白名单时需同步：schema enum + CLI 展开逻辑 + 远端 TCC。
      $comment: AI 字段位配置（单对象）。AI 插件全工程仅一个；与 GUI 表单同构。

basic_schema:
  type: object
  required: [name, description, categoryIds]
  properties:
    name: { type: string, minLength: 1, maxLength: 100 }
    description: { type: string, minLength: 1, maxLength: 100 }
    icon: { type: string }
    categoryIds: { type: array, items: { type: integer } }
publish_schema:
  type: object
  additionalProperties: false
  required:
    - version
    - descZh
    - productVersion
  properties:
    version:
      type: string
      pattern: "^([0-9]|[1-9]\\d*)\\.([0-9]|[1-9]\\d*)\\.([0-9]|[1-9]\\d*)$"
    descZh:
      type: string
      minLength: 1
    productVersion:
      type: string
      pattern: "^([0-9]|[1-9]\\d*)\\.([0-9]|[1-9]\\d*)\\.([0-9]|[1-9]\\d*)$"
    store:
      type: string
      enum:
        - publish
        - no-publish
      default: no-publish
    upgrade:
      type: string
      enum:
        - manual
        - all
        - limit
      default: manual
    upgradeLimitVersion:
      type: string
      pattern: "^([0-9]|[1-9]\\d*)\\.([0-9]|[1-9]\\d*)\\.([0-9]|[1-9]\\d*)$"
    upgradeLimitType:
      type: string
      enum:
        - higher
        - lower
      default: higher
  allOf:
  - if:
      properties:
        upgrade:
          const: limit
      required:
        - upgrade
    then:
      required:
        - upgradeLimitVersion
    else:
      not:
        anyOf:
          - required:
              - upgradeLimitVersion
          - required:
              - upgradeLimitType