VP-TSX 双向环路
VP-TSX 双向环路(页面 ⇆ 代码)
在编辑器的 AI 对话里,除了细粒度的 page_* 工具外,还提供一条「代码化」通路:把当前页面导出为 VP-TSX 源码,让 AI(或人)以代码方式改写整页,再编译写回页面。适合重排整页布局、批量增删组件、成套换配色,或需要先从代码角度看懂整页的场景。
真源始终是页面 JSON;VP-TSX 是「每次导出即从当前页再生的代码视图」,因此人为改过页面后再次导出,得到的就是最新代码——无需双向合并。
工具
page_export_tsx({ path?, screenUid? }):把当前页导出为 VP-TSX。省略screenUid= 整工程(screen+screens[]+windows[]+ 前景/背景层 + 连接/数据/规则,单文件承载全部);给screenUid只导该屏(便于分页独立编辑)。**推荐(同机)**给path(调用方会话工作目录里的绝对路径),服务端把代码写到该文件并只回元数据;省略path才内联返回tsx(跨机无共享盘时用)。- 编辑器 UI 同款出口:顶栏「另存为」→ 格式选 工程代码(.vp.tsx)(单文件整工程,回导需借助平台编译)或 TSX 工程包(.zip)——代码 + 自包含编译环境(runtime/类型/编译器/校验器/选项 schema)一起打包,解压
npm i && npm run build即可脱离仓库编译出.vpproj.json,npm run typecheck做 JSX 全量类型检查。 page_apply_project({ path? | tsx? | envelope?, screenUid? })(仅编辑态):推荐传path(要应用的.vp.tsx绝对路径),服务端以自身进程权限直接读该文件、编译并应用回页面;tsx/envelope为跨机内联后备。
同机为什么用路径:调用方(如嵌入 SDK 的会话)在自己的工作目录建/改文件,唯杰AI可视化平台用自身 OS 权限按绝对路径读/写——与会话侧文件工具的目录权限无关。只传路径也避免整段代码占用 token。允许根由
VP_VPTSX_ALLOWED_ROOTS控制(缺省覆盖仓库根上级),并按扩展名白名单(写.vp.tsx/.tsx、读再加.vpproj.json/.json)收窄可读写范围。写入额外拒绝落在平台仓库内的目标(VP_VPTSX_WORKDIR除外),防止覆盖仓库源码。
自适应应用
page_apply_project 先把编译结果与当前页做 diff,再按改动量选择:
- 增量:仅选项值 / 数据行 / 参数 / 工程名变化 → 用批量设值/写数据/写参数应用(选项写入合并为一步可撤销;数据/参数写入不进撤销栈)。
- 整屏替换:出现结构性变化(增删组件、改序、改父、复杂子结构、连接定义变化、屏级选项变化、删除选项键)或增量条目超阈值 → 等价重新导入该工程(会重置撤销历史)。替换前会留一次性恢复快照:紧接着执行一次撤销(
page_historyaction=undo)即可还原替换前页面;做任何其它修改后快照失效。 - 无差异:返回
changed: false,页面不会被改动。
单屏文件(只含一个 screen,可以是主屏/子页面/前景层/背景层/窗口)会按 uid 合并进当前整工程,保留其它页;合并对连接是「并集」语义(增改不删),dataRules 仅在非空时整体覆盖。前景/背景层与普通页面一样参与 diff 与合并。
复用与节点级字段
复用不靠 import(VP-TSX 只允许 runtime 一条导入):画面复用走 project.windows[] + window-instance 画面组件(或 switchWindow 动作);组件组复用走 component-instance 组合组件(节点顶层 masterId/props/overrides/master)。这些节点顶层字段(还包括 extensions 二开脚本、privateData 私有数据、states/state 多状态、enabled/locked、页面根 pending/guideLines 等)在导出与应用间无损往返,任一变化按整屏替换应用。注意:单屏导出不携带 windows 定义(live 合并会保留现有窗口);增删窗口本身需整工程导出→应用。
编译(服务端内部,内容驱动)
page_apply_project 拿到 path(读文件)或内联 tsx 后,服务端先做单 import 门禁(编译是执行式的,只允许唯一的 runtime 导入,多余 import 与动态 import()/require() 一律拒绝,防任意代码执行),再把源码写到与 runtime.ts 同目录的临时文件——并强制把首个 import … from '<x>' 的说明符改写为 ./runtime(覆盖 ''、../runtime、任意值,避免空导入编译炸)——再起 Node 子进程编译(compile.mts),编译完删除临时文件。因此源码来自哪里都能编译,无需调用方与服务端共享编译目录。编译产物(以及内联 envelope / 直采的 .vpproj.json)在应用前还会过一道最小结构校验(uid 存在且全局唯一、type 非空),坏结构直接报错不落页。相关环境变量:
VP_VPTSX_REPO/VP_VPTSX_COMPILE/VP_VPTSX_NODE:仓库根 / 编译脚本 / Node 命令(缺省pnpm exec tsx)。VP_VPTSX_NO_VALIDATE:设置后跳过工程 JSON 校验。VP_VPTSX_ALLOWED_ROOTS(;分隔):允许按绝对路径读/写的根,缺省仓库根上级(本机覆盖唯杰AI可视化平台 + 同级会话 worktree)。读/写另受扩展名白名单约束。VP_VPTSX_WORKDIR:相对路径落点,缺省<repo>/.vptsx-live。
若运行环境没有 Node/pnpm,可在调用方自行编译出工程 JSON,用 page_apply_project 的 envelope 参数内联传入(直接采用,不再编译)。
怎么写 VP-TSX
见 generate-vp-project 技能与组件文档:一份文件 export default defineProject({...}),布局用 JSX(<组件type kebab-属性={值}>子组件</组件type>)、数据用 JSON 字面量;属性名与取值必须来自真实 schema(get_widget_metadata / page_get_schemas 同源),不可臆造。