@givolt/i3-composer-agent 2.3.1 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude/commands/i3-prototype.md +5 -7
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/.claude-plugin/plugin.json +1 -1
  5. package/.codex-plugin/plugin.json +1 -1
  6. package/.gemini/commands/i3-prototype.toml +5 -7
  7. package/README.md +12 -7
  8. package/bin/i3-composer-agent.cjs +33 -2
  9. package/bin/install.cjs +14 -0
  10. package/bin/native-migration.cjs +27 -3
  11. package/commands/i3-prototype.toml +5 -7
  12. package/docs/codebuddy-setup.md +65 -2
  13. package/docs/codex-setup.md +4 -0
  14. package/docs/other-hosts.md +1 -1
  15. package/docs/ui-prototype-native/MAIN-SESSION-REPORT.md +66 -0
  16. package/docs/ui-prototype-native/USAGE.md +91 -0
  17. package/docs/workbuddy-setup.md +4 -0
  18. package/evals/cases/i3-frontend-ui-engineering.json +16 -0
  19. package/evals/cases/i3-ui-prototype.json +109 -0
  20. package/evals/cases/i3-using-agent-skills.json +28 -0
  21. package/evals/fixtures/i3-ui-prototype/admin-list/assets/reference.css +3 -0
  22. package/evals/fixtures/i3-ui-prototype/admin-list/assets/reference.js +8 -0
  23. package/evals/fixtures/i3-ui-prototype/admin-list/capability-definition.json +67 -0
  24. package/evals/fixtures/i3-ui-prototype/admin-list/index.html +89 -0
  25. package/evals/fixtures/i3-ui-prototype/admin-list/readme.md +52 -0
  26. package/evals/fixtures/i3-ui-prototype/admin-list/template.json +8 -0
  27. package/evals/zh-CN/cases/i3-frontend-ui-engineering.json +17 -0
  28. package/evals/zh-CN/cases/i3-ui-prototype.json +115 -0
  29. package/evals/zh-CN/cases/i3-using-agent-skills.json +30 -0
  30. package/package.json +31 -1
  31. package/plugin.json +1 -1
  32. package/scripts/design-provider-test.js +7 -0
  33. package/scripts/enterprise-template-test.js +27 -1
  34. package/scripts/lib/prototype-fixture.cjs +17 -0
  35. package/scripts/prototype-locations-test.js +58 -0
  36. package/scripts/ui-prototype-content-test.js +123 -0
  37. package/scripts/ui-prototype-dependencies-test.js +213 -0
  38. package/scripts/ui-prototype-devtools-test.js +53 -0
  39. package/scripts/ui-prototype-native-test.js +504 -0
  40. package/scripts/ui-prototype-template-test.js +261 -0
  41. package/scripts/ui-prototype-test.js +10 -0
  42. package/skills/i3-ui-prototype/SKILL.md +138 -19
  43. package/skills/i3-ui-prototype/assets/capabilities/management.json +294 -0
  44. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/acceptance.json +51 -0
  45. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/component-map.json +13 -0
  46. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/index.html +11 -0
  47. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/package-lock.json +2298 -0
  48. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/package.json +22 -0
  49. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/public/prototype-config.json +6 -0
  50. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/App.vue +136 -0
  51. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/components/DeviceEditor.vue +111 -0
  52. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/config.ts +19 -0
  53. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/content.ts +28 -0
  54. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/domain/devices.ts +50 -0
  55. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/domain/theme.ts +25 -0
  56. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/main.ts +18 -0
  57. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/style.css +50 -0
  58. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/useDevices.ts +66 -0
  59. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/tests/devices.test.ts +44 -0
  60. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/tests/theme.test.ts +26 -0
  61. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/tsconfig.json +15 -0
  62. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/vite.config.ts +4 -0
  63. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/profile.json +174 -0
  64. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/readme.md +61 -0
  65. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/index.html +11 -0
  66. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/package-lock.json +2298 -0
  67. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/package.json +22 -0
  68. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/public/prototype-config.json +21 -0
  69. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/App.vue +51 -0
  70. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/config.ts +18 -0
  71. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/domain/theme.ts +25 -0
  72. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/main.ts +18 -0
  73. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/style.css +13 -0
  74. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/tests/theme.test.ts +26 -0
  75. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/tsconfig.json +15 -0
  76. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/vite.config.ts +4 -0
  77. package/skills/i3-ui-prototype/assets/optional-skills/host-targets.json +737 -0
  78. package/skills/i3-ui-prototype/assets/optional-skills/sources.json +27 -0
  79. package/skills/i3-ui-prototype/assets/templates/catalog.js +149 -0
  80. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/capability-definition.json +294 -0
  81. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/index.html +507 -2
  82. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/offline-build.json +265 -0
  83. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/offline.js +8888 -0
  84. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/template.json +9 -0
  85. package/skills/i3-ui-prototype/assets/templates/gallery/index.html +4 -4
  86. package/skills/i3-ui-prototype/assets/templates/index.html +3 -0
  87. package/skills/i3-ui-prototype/references/artifact-contract.md +25 -0
  88. package/skills/i3-ui-prototype/references/content-template.md +76 -0
  89. package/skills/i3-ui-prototype/references/enterprise-admin.md +6 -0
  90. package/skills/i3-ui-prototype/references/entry-contract.md +71 -0
  91. package/skills/i3-ui-prototype/references/expert-adapter.md +33 -5
  92. package/skills/i3-ui-prototype/references/framework-contract.md +76 -0
  93. package/skills/i3-ui-prototype/references/interaction-acceptance.md +165 -0
  94. package/skills/i3-ui-prototype/references/legacy-native.md +58 -0
  95. package/skills/i3-ui-prototype/references/optional-skills.md +59 -0
  96. package/skills/i3-ui-prototype/references/template-adapters.md +1 -1
  97. package/skills/i3-ui-prototype/references/workflow-contract.md +58 -4
  98. package/skills/i3-ui-prototype/scripts/adapters/easel-html.cjs +1 -1
  99. package/skills/i3-ui-prototype/scripts/content-template.cjs +98 -0
  100. package/skills/i3-ui-prototype/scripts/enterprise-template.cjs +13 -6
  101. package/skills/i3-ui-prototype/scripts/manage-baseline.cjs +1 -1
  102. package/skills/i3-ui-prototype/scripts/native-browser.cjs +785 -0
  103. package/skills/i3-ui-prototype/scripts/native-build.cjs +91 -0
  104. package/skills/i3-ui-prototype/scripts/native-delivery.cjs +91 -0
  105. package/skills/i3-ui-prototype/scripts/native-devtools.cjs +91 -0
  106. package/skills/i3-ui-prototype/scripts/native-files.cjs +35 -0
  107. package/skills/i3-ui-prototype/scripts/native-pilot-lib.cjs +244 -0
  108. package/skills/i3-ui-prototype/scripts/native-pilot.cjs +34 -0
  109. package/skills/i3-ui-prototype/scripts/optional-skill-install.cjs +203 -0
  110. package/skills/i3-ui-prototype/scripts/prototype-dependencies.cjs +81 -0
  111. package/skills/i3-ui-prototype/scripts/prototype-lib.cjs +26 -6
  112. package/skills/i3-ui-prototype/scripts/prototype-locations.cjs +65 -0
  113. package/skills/i3-ui-prototype/scripts/sync-template.cjs +19 -0
  114. package/skills/i3-ui-prototype/scripts/template-contract.cjs +398 -0
  115. package/skills/i3-ui-prototype/scripts/validate-result.cjs +117 -0
  116. package/skills/i3-using-agent-skills/SKILL.md +2 -5
@@ -0,0 +1,58 @@
1
+ # 已有设备列表 v2 的固定合同
2
+
3
+ <!-- i3:zh-guide:start -->
4
+ ## 中文使用说明
5
+
6
+ 按下文完整工程步骤、检查项与验证条件执行。根据任务选择适用步骤,保留证据、风险和退出条件;正文示例中的英文标签在面向用户输出时译为中文。
7
+
8
+ 默认使用简体中文解释、追问及生成报告;用户明确要求其他语言时可切换。原方法正文、引用、阈值和审批条件完整保留。代码标识、路径、命令、工具参数、JSON 键/枚举与原文引用保持原样。
9
+ <!-- i3:zh-guide:end -->
10
+
11
+ 仅在检查/修订已有设备列表输入时读取。小 HTML 资源已移至配套工具的测试夹具;新项目使用完整内容模板。已有工作副本和 inputs 快照仍可同步或按原合同检查,不从安装目录恢复小模板。
12
+
13
+ 原生组件存在不等于应用行为完成。历史设备列表的 fixed 绑定用 21 条数据、每页 10 条,必须出现三页;仅画分页条不合格。需求为可调页大小时必须显式适配下述 adjustable 合同,不能把 fixedPageSize 当 default。无选择的批量按钮、只改变提示而不改记录的保存也不合格。
14
+
15
+ ### 分页语义与创建前适配
16
+
17
+ - 旧绑定 `{"fixedPageSize":10,"minimumTestPages":3}` 继续是 fixed,也可显式写 `"mode":"fixed"`;固定模式不允许 defaultPageSize/pageSizeOptions。
18
+ - 可调绑定为 `{"mode":"adjustable","defaultPageSize":10,"pageSizeOptions":[10,20,50],"minimumTestPages":3}`,不允许 fixedPageSize。defaultPageSize 是正整数,必须属于至少两个不同正整数构成的 pageSizeOptions。缺失、重复、字符串、零值或未知模式均须处理,不能隐式纠正为 fixed。
19
+
20
+ PRD 要求可调而当前模板为 fixed 时,analyze 返回部分覆盖及需适配;不改文件、不删除该需求、不把支持计划写为现状。create 在用户授权的工作模板上按以下顺序固定目标:
21
+
22
+ ```sh
23
+ # 编辑 <project-root>/ui-templates/admin-list/index.html:保留 pagination 绑定身份,
24
+ # 将它的 data-capability-parameters 改为下面的 adjustable 参数,移除 fixedPageSize。
25
+ node <skill-root>/scripts/native-pilot.cjs sync-template <project-root>/ui-templates/admin-list
26
+ node <skill-root>/scripts/native-pilot.cjs sync-template <project-root>/ui-templates/admin-list --check
27
+ node <skill-root>/scripts/native-pilot.cjs create --project <project-root> --id devices --template-root <project-root>/ui-templates/admin-list --expert-mode professional --provider <uiux-root> --scope <requirements-scope.json>
28
+ ```
29
+
30
+ 用户工作 HTML 的参数示例,保留该区域原有 pageId/regionId/capabilityId:
31
+
32
+ ```html
33
+ data-capability-id="pagination"
34
+ data-capability-parameters='{"mode":"adjustable","defaultPageSize":10,"pageSizeOptions":[10,20,50],"minimumTestPages":3}'
35
+ ```
36
+
37
+ create 将同步后的模板、能力与范围快照固定到实例 inputs;无新分页 CLI flag,也不通过修改 SDK 切换语义。其后仍须按 PRD 实现原生 showSizeChanger、受控 pageSize 及页大小改变时的页码/选择处理。minimumTestPages 按默认 10 条基线检查,21 条是三页,不要求 20/50 也各有三页。可调模式在既有 pagination/page-size 场景内验证 20、50、恢复 10 后页容量、页码/总数、选择清空和列表一致,不虚增已完成场景数。目标来自固定 inputs,不能接受页面自报参数来替换合同。
38
+
39
+ 旧 fixed 实例不自动变成 adjustable。已有实例更改固定输入时,按 workflow-contract 整理完整新 inputs 与需求映射,再显式 `revise --accept-inputs`;不能仅改全局工作模板或改页面就声称旧输入已更新。
40
+
41
+ ### 可选主题与创建前绑定
42
+
43
+ `theme` 是 management-list 区域的可选能力,不加入默认必需集合。用户明确需要换肤时,在用户 HTML 工作副本的 `devices/device-list` 区域追加内容绑定,再同步/检查;不用修改已安装 SDK 或用静态 HTML 效果代替原生主题。历史工作 HTML 的 `OPTIONAL_FOUR_THEMES` 注释提供可解开的 `aside` 示例,具体步骤及 scope 来源结构见本实例固定模板说明。保留注释时无绑定;解开并同步后,仅显式采用该工作副本的新实例启用。主会话执行者须完成本次实际新实例的固定输入、真实组件适配和验证,不能以模板已有色值作为需求完成。
44
+
45
+ ```html
46
+ <aside data-capability-id="theme"
47
+ data-capability-parameters='{"defaultTheme":"light","presets":["light","dark","fresh","tech"]}'>
48
+ 可选主题:明亮、暗黑、清新、科技
49
+ </aside>
50
+ ```
51
+
52
+ 本次 scope.requirements 同时保留有效来源(type、reference、statement)并引用 `{pageId:"devices",regionId:"device-list",capabilityId:"theme"}`,才能启用为本实例的必验能力。孤立 HTML 绑定不代表需求来源;不能自行删来源或把可选能力提升为所有列表的必需项。create 固定这组 inputs,并投影 `prototype-config.json` 的 `theme: {defaultTheme:"light",presets:["light","dark","fresh","tech"]}`;仍须实现并验收,配置存在不等于效果完成。
53
+
54
+ 菜单精确显示“明亮、暗黑、清新、科技”,不显示编号;默认“明亮”。light 为蓝白明亮、dark 为深灰暗黑、fresh 为浅青绿清新、tech 为深蓝青绿科技。使用目标 antDv-next 1.5.3 的原生 ConfigProvider theme.algorithm/token:该包导出的 theme.defaultAlgorithm、theme.darkAlgorithm、theme.useToken/getDesignToken 可作为实现来源,不能凭回退的 1.5.2 CLI 推定 API。主题色、文字、背景、边框和焦点均按语义 token 映射,自有页面布局与 Drawer/Select 传送浮层取得相同主题;不能只切原生组件而留下硬编码浅色外壳。保留 reduced-motion 及组件原生动效,不重挂整棵应用来换主题。
55
+
56
+ 偏好独立保存在 `${storageNamespace}:ui-theme:v1`,值为 `{version:1,themeId}`。它不复用 devices/mockVersion 键,不写全局、宿主记忆或其他实例。缺失、旧版、非法值和存储拒绝均安全回退明亮;存储拒绝时本页仍可切换。切换不丢筛选、页码、选择或抽屉未保存输入,重置业务数据不顺带清除主题偏好。
57
+
58
+ 无绑定的原型不写 config.theme、不显示菜单,保留原绿色外观;旧 v1/v2 固定输入、批准快照与原 PRD 不被改写。旧实例要新增主题时,由当前负责人按已授权范围整理新输入并显式 revise --accept-inputs。开启后才增加 `devices/device-list/theme/switch`、`persistence`、`accessibility` 三个场景,原 20 项保持;真实效果与兼容性检查见 interaction-acceptance。
@@ -0,0 +1,59 @@
1
+ # 可选官方依赖与宿主工具目录
2
+
3
+ <!-- i3:zh-guide:start -->
4
+ ## 中文使用说明
5
+
6
+ 按下文完整工程步骤、检查项与验证条件执行。根据任务选择适用步骤,保留证据、风险和退出条件;正文示例中的英文标签在面向用户输出时译为中文。
7
+
8
+ 默认使用简体中文解释、追问及生成报告;用户明确要求其他语言时可切换。原方法正文、引用、阈值和审批条件完整保留。代码标识、路径、命令、工具参数、JSON 键/枚举与原文引用保持原样。
9
+ <!-- i3:zh-guide:end -->
10
+
11
+ UIUX Pro Max 和 antDv 官方 Skill 独立可选,保留原名、许可和来源。默认不安装;以后补装重新检测即可。工具跟随 i3 安装器现有宿主目标与安装范围,固定在 `<host-base>/tools/i3-prototype/`。本功能不改变上游工程 Skill、原型业务输入或验收合同。
12
+
13
+ ## 宿主与范围
14
+
15
+ | 宿主 | 项目基址 | 全局基址 |
16
+ | --- | --- | --- |
17
+ | CodeBuddy | `<project>/.codebuddy` | `~/.codebuddy` |
18
+ | WorkBuddy | `<project>/.codebuddy` | `~/.workbuddy` |
19
+ | Codex | `<project>/.agents` | `~/.agents` |
20
+ | Claude Code | `<project>/.claude` | `CLAUDE_CONFIG_DIR` 或 `~/.claude` |
21
+
22
+ OpenClaw 项目 Skill 保持原根 skills 约定,仅辅助工具放到项目 .openclaw/tools/i3-prototype,避免新建业务根 tools。其他宿主复用安装器目标表,包括它已支持的配置目录覆盖和替代路径。未登记全局目录的宿主拒绝 global。多宿主共用同一项目物理目标时只准备一次。检测脚本自带经过核对的目标表镜像,维护测试要求与核心表完全一致。
23
+
24
+ ## 只读检测
25
+
26
+ ```sh
27
+ node <skill-root>/scripts/prototype-dependencies.cjs check --host <host-id> --scope project --project <project-root>
28
+ # 只检测对应全局安装,排除业务项目依赖:
29
+ node <skill-root>/scripts/prototype-dependencies.cjs check --host <host-id> --scope global --project <project-root>
30
+ ```
31
+
32
+ 明确传递当前宿主;单宿主原生安装可从安装清单识别,多宿主有歧义时要求 --host。默认 scope=project。项目检查依次检测当前宿主项目和全局;antDv 还兼容旧项目的独立及混合工具布局。实际已存在但不可执行的高优先级工具报告 unusable,不静默改用另一副本。`--tool <绝对antDv包目录>` 仅检测指定工具;`--provider <UIUX根>` 仅检测指定 UIUX。每次重新检查,不缓存跳过状态。
33
+
34
+ UIUX 执行真实只读查询;项目与全局检查保留原已支持宿主的已启用用户插件发现及停用/歧义诊断;global 从用户 home 检索注册,不借用本业务项目的插件。CodeBuddy 原 CODEBUDDY_CONFIG_DIR 独立 Skill 位置继续只读兼容,安装写入仍遵循核心目标表。antDv Skill 文件发现、CLI 可执行及知识版本分别报告。检测不下载、安装、迁移或写原型;`invocationVerified=false`。宿主必要时刷新/新建会话,实际 Skill 调用另留证。
35
+
36
+ 专业模式需要可用 UIUX;缺项时定位/修复或由用户明确选择基础模板模式,功能和主题验收不降低。antDv Skill 不可调用时按框架合同使用版本匹配的官方文档/类型/源码,不能冒认 Skill 已调用。原型工程的 Vue/antdv-next 依赖仍在工程内,独立于这里的查询工具。
37
+
38
+ ## 明确选择后的安装与补装
39
+
40
+ ```sh
41
+ node <skill-root>/scripts/prototype-dependencies.cjs install --host <host-id> --scope project --project <project-root> --skills uiux,antdv
42
+ node <skill-root>/scripts/prototype-dependencies.cjs install --host <host-id> --scope global --project <project-root> --skills uiux,antdv
43
+ ```
44
+
45
+ skills 可选 none、uiux、antdv、uiux,antdv;none 不下载、不写入。global 只在全局目标准备 Skill、工具、锁与临时资源,不向业务项目新增目录。项目安装可复用已经可用的同宿主全局依赖。安装多个物理宿主目标时逐目标准备;某目标失败如实报告已完成部分。
46
+
47
+ 需要访问 npm 和 GitHub,固定根包与官方文件摘要,不修改代理、注册源、证书、宿主设置或系统 Python。已有同名但不完整目录保留并提示修复;不支持 force 覆盖第三方资源。资源在对应 tools 目录临时准备,验证后再发布,失败回滚并清理本次创建的空目录。可选资源独立于核心归属,升级 i3 保留它们。
48
+
49
+ - UIUX:固定 `ui-ux-pro-max-cli@2.15.0` 官方 CLI 生成完整资源;按官方模板已有占位符填写当前宿主实际脚本路径,官方模板正文与程序不改,渲染参数和模板摘要记在来源记录。项目路径相对业务根,全局路径为实际绝对路径,空格正确引用。Python 脚本/数据留在 `skills/ui-ux-pro-max/`,临时 CLI 清理;缺 Python 如实报告查询不可用。
50
+ - antDv:官方 Skill 固定提交 `2b0dc514ee48bc130048724a5c5a0a76ec632aa1`,安装至所选宿主 `skills/antdv/`;Skill 原文不改。固定 `@antdv-next/cli@0.0.0-beta.1` 位于 `tools/i3-prototype/antdv-cli/`,保留依赖锁、source.tgz 和来源记录。检测返回实际 Node 入口,避免 `.bin` 重定位失效。
51
+ - 根包 SHA-512、官方文件 SHA-256 在 `assets/optional-skills/sources.json`。当前 CLI 知识为 1.5.2,目标框架 1.5.3,报告 `exactKnowledgeMatch=false`;查询结果仅供参考,继续核对实际 1.5.3 类型/源码。Error 文本、退出码 0 或占位 lint 都不能作为成功。
52
+
53
+ ## 旧目录兼容与显式迁移
54
+
55
+ 旧项目 `.prototype-tools/antdv-cli` 和 `.prototype-tools/node_modules` 可继续查询,安装/检测默认不搬动。要清理本安装器生成的独立旧工具,在项目补装命令中明确增加 `--migrate-tools`,并选择 antdv。只接受固定来源记录、版本和完整性相符且实际查询有效的独立 antDv 目录;混合 node_modules 或来源不明目录不接管。
56
+
57
+ 迁移在同一项目中移动,目标存在则保留并停止;失败恢复旧位置。成功后重验实际入口,仅删除空的旧根;旧根其他内容保留。global 不迁移业务项目工具。查询和迁移不会修改已有原型、输入、基线或旧验收。安装后的模式变更仍须明确修订。
58
+
59
+ 官方来源:[UIUX](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill#installation)、[antDv Skill](https://github.com/antdv-next/cli/blob/2b0dc514ee48bc130048724a5c5a0a76ec632aa1/skills/antdv/SKILL.md)。
@@ -12,7 +12,7 @@
12
12
 
13
13
  `assets/templates/catalog.json` 负责类型、可用状态、版本和预览入口,并用 `defaultTemplate` 指定默认类型。可生成条目必须指向自己目录下的 `manifest.json`;planned 条目不要求资源目录,不能初始化,也不会回退为其他模板。
14
14
 
15
- 当前企业后台使用 `easel-html`:完整 EASEL `reference/`、`origin.json` 来源清单、设计 token 和独立滚动适配。原始 326 个文件保持原样。AI 工作台、数字孪生大屏和移动端仅为 planned 目录条目,没有假模板包。旧三套兼容模板明确使用 `legacy-html`,共享 `common/`,各自保留 preset;不能把这些兼容演示当成新三类已经实现。
15
+ 完整内容参考可直接离线打开,native-pilot prepare-template 也复用同一资产(见 [content-template.md](content-template.md))。HTML 审查实例的企业后台运行合同仍使用 `easel-html`:完整 EASEL `reference/`、`origin.json` 来源清单、设计 token 和独立滚动适配。原始 326 个文件保持原样。AI 工作台、数字孪生大屏和移动端仅为 planned 目录条目,没有假模板包。旧三套兼容模板明确使用 `legacy-html`,共享 `common/`,各自保留 preset;不能把这些兼容演示当成新三类已经实现。
16
16
 
17
17
  模板选择页按 catalog 展示可用类型并切换预览,只负责查看资源;点击卡片不会创建业务原型、采用专业建议或确认基线。实际生成仍走技能操作并按业务适配,浏览器验证和用户认可分别保存。
18
18
 
@@ -8,12 +8,66 @@
8
8
  默认使用简体中文解释、追问及生成报告;用户明确要求其他语言时可切换。原方法正文、引用、阈值和审批条件完整保留。代码标识、路径、命令、工具参数、JSON 键/枚举与原文引用保持原样。
9
9
  <!-- i3:zh-guide:end -->
10
10
 
11
- create 读取业务上下文、检测默认专业增强模式、展示四类模板的可用状态并记录选择,然后初始化和适配原型。企业后台当前可用;AI 工作台、数字孪生大屏和移动端尚待建设,不能自动替换为其他模板。兼容旧版三套模板仅供已有项目继续使用。脚本返回 needs-design-provider 时不得冒充创建成功;允许先完成需求和模板比较,等待安装或用户选择 template。已有原型的 expertMode 作为迭代默认值。
11
+ ## 公共前置与副作用
12
12
 
13
- revise 必须指定未使用的新版本;改变全局导航、token、组件行为或业务状态时解释影响并形成新的评审候选。inspect 可写检查报告但不修改页面或冻结基线。confirm-baseline 必须有用户对具体内容的明确认可和完整必需证据。
13
+ 主会话通过自然语言、命令、元技能或直接 Skill 使用同一顺序:识别操作及限制,读取实际文件和清单,恢复固定输入/版本/交接,确认实际工具,确定单一修改负责人,再进入对应运行层。入口仅发现工作 Skill,不强制分派角色,不绕回命令或元技能。按操作需要复用 frontend、框架官方、UIUX 和 browser 技能,各工程技能保留原有方法。
14
14
 
15
- verification 使用 not-run、partial、passed、failed、blocked;review 使用 pending-review、changes-requested、approved。expert 使用 pending、used、skipped、missing、unusable、no-match。它们分别表示检查、用户认可及专业能力使用;不相互推断。
15
+ | 操作 | 允许范围 |
16
+ | --- | --- |
17
+ | analyze | 只读文件和已核对的只读查询,分析留在会话 |
18
+ | create | 在授权项目内准备未存在的用户模板副本、同步索引、创建新实例并实现 |
19
+ | revise | 基于实际文件及固定合同形成新候选,保留手改和旧基线 |
20
+ | inspect | 检查当前实例;用户明确只读时不保存报告或运行状态 |
21
+ | confirm-baseline | 用户认可具体版本且验收匹配后,保存不可覆盖的快照 |
16
22
 
17
- 原型可从草拟需求开始。需求确认、原型认可、正式规格批准和生产授权各自保存。返回 scope、revision、mode、verification、review、openQuestions 和下一项必要动作,避免笼统地报告全部完成。
23
+ 明确“不改代码/不写文件”优先于默认 create。analyze 不创建目录、安装升级、写 provider 结果、初始化运行记录或改变状态;约束包括检查器、官方 Skill、UIUX 和浏览器助手的下游行为。用户要求保存分析文档时只写指定输出。只读期间不得为了记录执行模式而落盘。
24
+
25
+ analyze 返回需求/通用能力覆盖、模板与框架选型、验收计划和未决项,信息足够后停止探索并回传。已有来源的固定 profile/component-map/acceptance 可支持选型,不等于逐组件逐 Prop 实施核验;只对影响选型的具体疑点定向查本地 API。完整目标版本包/源码验证留 create,不遍历 starter、node_modules、整套 CLI 帮助或组件清单来证明分析;必要定向读取仍可进行。未知点保留 openItems,不把 UIUX 准入、逐条采纳、构建或浏览器当分析前置,不把计划写成已验证结果。
26
+
27
+ 能力覆盖包含绑定参数,不能只按 Table/pagination 等名称匹配。PRD 要求可调页大小而当前绑定 `fixedPageSize: 10` 时,报告部分覆盖、明确在可写阶段需显式适配;固定值不是默认值,不能借已有通用分页能力宣称全部满足。分析完整交付可 status=complete,但覆盖检查与 openItems 如实保留冲突;仅分析未完成才 partial/blocked。只读期间不改需求、绑定或固定输入,后续计划不记为已实现或已验收。
28
+
29
+ 先按实际 `--host`、`--scope` 只读检测宿主基址 `tools/i3-prototype/` 下的工具,保留旧项目 `.prototype-tools` 检测;或使用宿主已经明确给出的绝对入口,核对固定版本后直接调用;不要反复扫描 node_modules。analyze 不运行 npm exec/npx 或任何会自动安装/补缓存的命令;缺工具报告未决项,改用现有只读资料。可写模式同样使用准备好的本地固定 CLI,只有工具准备另有授权时才在明确工具目录安装;该授权不包含业务文件、已安装 SDK、宿主设置或未选择的全局目录。项目构建依赖的 --install 是另一项写操作,不能借用查询工具授权。
30
+
31
+ create/revise 的项目写入范围不包含用户级长期记忆或宿主 auto-memory;未经用户明确要求,不创建或更新这些文件。纯文件续接依靠实例合同与交接;测试启动时核对宿主记忆开关和工具写入范围,不将 no-session-persistence 视为禁止 auto-memory,不更改全局偏好。
32
+
33
+ 执行阶段保持一个源码/合同修改负责人;另有授权的协作按实际工具和执行记录留证,不冒认其他执行者的工作。连续性来自文件。写入前核对预期 revision/candidateDigest,遇到并发变化停止该次写入并重读,不覆盖较新候选。
34
+
35
+ ## 原生组件 v2
36
+
37
+ 已有实例优先用 native-pilot.cjs state 一次恢复合同、身份、设计/构建/QA及精确 commands,不遍历依赖或反复读控制器实现。真实查询与人工设计取舍完成后,本轮 CodeBuddy 原生流程依次为 build→宿主实际加载 i3-browser-testing-with-devtools Skill→Chrome DevTools MCP 按能力执行并取得实际观测→新业务场景实测及 record-run(旧设备合同另用 browser 专项回归)→state→finalize→独立最终回复。Skill 的 DOM/计算样式、截图、console、network、a11y 与 performance 观测不能只列计划或挂名;缺任一必需工具/执行时整链不 complete。analyze 只提出这份验收计划,不启动检查。
38
+
39
+ browser 是历史设备合同的 Playwright 专项工具,自行管理服务,不替代上述 Skill 或 MCP。实际 DevTools 检查后用 record-devtools-review --report 登记独立 qa/devtools-review.json;新 create 的固定 acceptance.browserReview 要求当前报告,state 列缺项,finalize 拒绝缺失/过期/证据变化。脚本只核结构、文件和当前身份,不证明真实调用,仍输出 invocationVerified=false。主会话另核原始宿主 stream、实际观测及同一 candidate/build,交付前核对当前 state/delivery,再以自然语言给出结果和证据位置。详细证据合同见 interaction-acceptance。旧 v1 和无 browserReview 的已有 v2 保留原验收,新要求仅进入新实例或显式接受变更的输入;其他宿主的等效工具结果单列,不冒充这条指定链。
40
+
41
+ create 使用完整 enterprise-admin 内容模板、实际 scope.pages/regions 和 vue-antdv-next 框架,使用 native-pilot.cjs。用户 HTML 工作副本升级不覆盖。创建前检查标识、绑定和索引一致,固定本次范围、模板、能力、框架及必需场景。PRD 可简短,但明确/假设/待确认/范围外须有来源。
42
+
43
+ 目标目录须留给原子 create:provider 先 probe,初始化后才在实例 qa 下保存查询和设计证据。初始化前需要保存的官方/UIUX 查询使用独立准备目录,不能预先创建 prototypes/<id>/qa。没有 prototype.json 的已有目录先核对来源,不能调用 revise 冒充实例。只有确认整个目录均由本次准备操作产生,才可整体移走,确保目标不存在后重试;只移文件留下空目录仍会失败。含用户或未知文件时保留并报告冲突。
44
+
45
+ required 不可任意 N/A;检查器按已声明业务区域重算必需集合,实际页面与区域的对应由前端/浏览器复核。缺失语义、参数或范围仍待处理,不能为通过删能力。新流程的分页与四主题默认及 scope 格式见 [content-template.md](content-template.md)。初始化状态为 needs-adaptation,主会话继续实现实际业务;完成后标 adapted,才进入当前候选验收。旧设备列表的固定容量、可选主题和验收数量仍按旧 inputs,不追溯追加要求。
46
+
47
+ revise 使用 `native-pilot.cjs revise <root> --revision <new> --expected-revision <current> --expected-digest <currentDigest>`,保留实际源码而非重复制 starter。模板或框架升级是显式输入变更,旧实例继续检查固定输入。手改后旧证据失效;新交互补映射,删除必需功能产生缺口。
48
+
49
+ 确需更改固定输入时,由当前修改负责人先整理 inputs 中完整新快照、能力/范围/场景及 requirements-map,再使用同一 revise 命令加 `--accept-inputs`。该选项在锁和预期版本保护下完整校验新合同,成功才接受新 inputDigest 和版本并清除旧验证状态;失败不推进版本。它不自动下载或套用新模板、框架,不补造需求映射。普通 revise 遇到输入变化会拒绝,避免新版本带着旧摘要。
50
+
51
+ inspect、manifest、build 按 v2 合同执行;不得让 legacy 写接口接管。首次可写构建使用 `build <root> --install` 安装固定锁依赖,后续 build 复用依赖。preview 输出 URL 并持续服务,--build-id 可选择固定构建。浏览器证据导入后 `inspect <root> --acceptance` 检查覆盖与身份。
52
+
53
+ 持续写任务可 `claim <root> --owner <owner> --expected-revision <revision> --expected-digest <digest>`;revise 传同一 owner,编辑结束 `release <root> --owner <owner>` 后再验收/确认。临时修改由脚本 claim/release。锁不进入候选身份,丢失 Agent 不自动清除别人仍持有的修改权。
54
+
55
+ compare-baseline 只比较当前候选与已保存基线;confirm-baseline --confirmation 接收具体版本的人类确认,再核对当前验收并保存不可覆盖快照。证据不齐保留待确认候选,不手工构造批准状态。
56
+
57
+ ## Legacy HTML
58
+
59
+ legacy create 读取业务上下文、检测专业模式、展示四类模板可用状态并记录选择,再初始化和适配。企业后台可用;AI 工作台、数字孪生大屏和移动端 planned,不能替换生成。旧三套模板供历史实例。needs-design-provider 不等于成功;可先比较需求和模板,按已有授权修复或等待明确选择 template。已有 expertMode 作为迭代默认。
60
+
61
+ legacy revise 指定未使用版本,改变导航、token、组件行为或业务状态时解释影响。inspect 写报告服从本次范围,不改页面或冻结。确认须有具体版本的用户认可和完整必需证据。旧实例不补写 v2 metadata,不改原摘要及已冻结历史。
62
+
63
+ ## 状态与交付
64
+
65
+ verification 使用 not-run、partial、passed、failed、blocked;review 使用 pending-review、changes-requested、approved。expert 使用 pending、used、reviewed、skipped、missing、unusable、no-match。它们分别表示检查、用户认可及专业能力使用;不相互推断。
66
+
67
+ 专业查询成功、建议处理、采用和效果验证独立保存。有依据的零采用可完成复核,冻结不自动改 used。template 明确跳过专业查询但不降低功能验收。provider 不可用报告具体原因,不静默切模式。
68
+
69
+ 原型可从草拟需求开始。需求确认、原型认可、正式规格批准和生产授权分别保存。返回 operation、scope、revision、executionMode、mode、verification、review、openQuestions 和下一项必要动作;说明结构、真实宿主、浏览器和人类确认各自结果。
70
+
71
+ 各入口在工具之后用自然语言交付实际范围、身份、证据、缺项和下一步,不强制父子 JSON、标记或结构校验。validate-result.cjs 可作特定维护工具,不是普通原型入口前置。业务、当前 state/delivery、真实 QA 分别核对,不能由结构结果推断。analyze 留在会话、不写收据;参数冲突以部分覆盖和未决项说明,不把分析完成等同覆盖通过。
18
72
 
19
73
  企业后台默认 purpose=business-prototype,完整参考副本的 business.status=needs-adaptation;必须完成实际业务适配才能验收。用户明确评审 EASEL 模板本身时,使用 purpose=template-review,并将 reference-demo 范围写进交接。模板认可不等于任何新业务的需求或原型认可。
@@ -8,7 +8,7 @@ module.exports = {
8
8
  kind: 'easel-html', identityFields: ['purpose', 'business', 'runtime'],
9
9
  requiredFiles: ['app/app.js', 'app/enterprise-bootstrap.mjs', 'app/routes.json', 'app/runtime/dom.js', 'app/styles/tokens.css', 'design-system/source.json'],
10
10
  excludedBrowserPrefixes: ['app/tools/', 'app/tests/', 'app/qa/'],
11
- protectedFiles: ['app/tokens.css', 'app/styles.css', 'app/index.html', 'app/domain.mjs', 'requirements-map.json', 'app/app.js', 'app/routes.json', 'app/config.json', 'app/enterprise-bootstrap.mjs', 'app/usability.css'],
11
+ protectedFiles: ['app/tokens.css', 'app/styles.css', 'app/index.html', 'app/domain.mjs', 'requirements-map.json', 'app/app.js', 'app/routes.json', 'app/config.json', 'app/enterprise-bootstrap.mjs', 'app/usability.css', 'app/offline.js'],
12
12
  protectedDirectories: ['design-system/', 'app/styles/', 'app/runtime/', 'app/src/'],
13
13
  },
14
14
  fingerprintInputs(context) {
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+ const assert = require('node:assert/strict');
5
+ const read = file => JSON.parse(fs.readFileSync(file, 'utf8'));
6
+
7
+ function extract(directory, manifest, files) {
8
+ assert.equal(manifest.entry, 'index.html', 'Content templates use the offline index.html convention');
9
+ const html = fs.readFileSync(path.join(directory, manifest.entry), 'utf8');
10
+ assert.ok(!/<script\b[^>]*type=["']module/i.test(html), 'Offline entry cannot use modules');
11
+ const routesMatch = html.match(/id="prototype-offline-routes">([\s\S]*?)<\/script>/);
12
+ assert.ok(routesMatch, 'Editable route inventory is required');
13
+ const routes = JSON.parse(routesMatch[1]);
14
+ const fragments = new Map([...html.matchAll(/^<template data-source="([^"]+)">\n([\s\S]*?)^<\/template>/gm)].map(match => [match[1], match[2]]));
15
+ assert.ok(fragments.size, 'Editable HTML fragments are required');
16
+ const resources = [];
17
+ for (const match of html.matchAll(/<(script|link)\b[^>]*\b(src|href)="([^"]+)"/gi)) {
18
+ if (match[3].startsWith('data:')) continue;
19
+ assert.ok(!/^(?:[a-z]+:|\/)/i.test(match[3]) && !match[3].split('/').includes('..'), 'Offline resources must remain inside the template');
20
+ const resource = match[3].split(/[?#]/)[0];
21
+ assert.ok(files.some(file => file.path === resource), `Offline resource missing: ${resource}`);
22
+ resources.push({ file: manifest.entry, path: resource });
23
+ if (match[1].toLowerCase() === 'script') {
24
+ const script = fs.readFileSync(path.join(directory, resource), 'utf8');
25
+ assert.ok(!/\bfetch\s*\(|\bXMLHttpRequest\b|\bimport\s*(?:\(|["'{*])|\bfrom\s*["']/.test(script), 'Offline runtime cannot load modules or remote HTML');
26
+ }
27
+ }
28
+ const pages = [...new Set(routes.map(route => route.component).filter(Boolean))].map(component => {
29
+ const fragment = 'reference/' + component.replace(/^\.\//, '').replace(/\.js$/, '.html');
30
+ assert.ok(fragments.has(fragment), `Missing page HTML: ${fragment}`);
31
+ const title = fragments.get(fragment).match(/<h1[^>]*>([^<{]+)<\/h1>/)?.[1]?.trim();
32
+ return { id: path.posix.basename(component, '.js').replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(),
33
+ title: title || path.posix.basename(component, '.js'), file: 'index.html', fragment,
34
+ routes: routes.filter(route => route.component === component).map(route => route.path) };
35
+ });
36
+ assert.equal(new Set(pages.map(page => page.id)).size, pages.length, 'Duplicate content page identity');
37
+ return { kind: 'content-reference', pages, regions: [], bindings: [], fields: [], actions: [], resources,
38
+ htmlFragments: [...fragments.keys()], routes, requiredBindings: [], requiredScenarios: [] };
39
+ }
40
+
41
+ function scopeInputs(snapshot, scope, contract) {
42
+ assert.ok(Array.isArray(scope?.pages) && scope.pages.length, 'Provide sourced PRD scope.pages; the reference is not the business requirement');
43
+ assert.ok(scope.requirements?.length, 'Provide sourced business requirements');
44
+ const known = new Set(snapshot.index.pages.map(page => page.id));
45
+ const seen = new Set(['app-shell']), regions = [{ pageId: 'app-shell', id: 'appearance', mode: 'application-shell' }], bindings = [];
46
+ const defaults = {
47
+ theme: { defaultTheme: 'light', presets: ['light', 'dark', 'fresh', 'tech'] },
48
+ filter: { resetPage: true, clearSelection: true }, selection: { strategy: 'current-page-clear-on-change' },
49
+ pagination: { mode: 'adjustable', defaultPageSize: 10, pageSizeOptions: [10, 20, 50], minimumTestPages: 3 },
50
+ bulk: { target: 'selected-only' }, edit: { presentation: 'drawer', preserveOnFailure: true },
51
+ };
52
+ for (const page of scope.pages) {
53
+ assert.match(page.id || '', /^[a-z][a-z0-9-]{0,63}$/);
54
+ assert.ok(!seen.has(page.id), `Duplicate business page: ${page.id}`); seen.add(page.id);
55
+ assert.ok(page.title?.trim() && known.has(page.referencePage), `Missing explicit template reference page: ${page.id}`);
56
+ assert.ok(page.regions?.length, `Declare the actual region modes: ${page.id}`);
57
+ for (const region of page.regions) {
58
+ assert.match(region.id || '', /^[a-z][a-z0-9-]{0,63}$/);
59
+ assert.ok(['management-list', 'edit-form', 'content'].includes(region.mode), `Unknown business region mode: ${region.mode}`);
60
+ regions.push({ pageId: page.id, id: region.id, mode: region.mode });
61
+ }
62
+ }
63
+ for (const region of regions) for (const capability of snapshot.definition.capabilities) {
64
+ if (capability.requirement !== 'required' || !capability.appliesTo.includes(region.mode)) continue;
65
+ const configured = scope.pages.find(page => page.id === region.pageId)?.regions.find(item => item.id === region.id)?.parameters?.[capability.id];
66
+ const parameters = configured || (capability.id === 'feedback'
67
+ ? { states: region.mode === 'edit-form' ? ['loading', 'error', 'success'] : ['loading', 'empty', 'error', 'success'] }
68
+ : defaults[capability.id]);
69
+ bindings.push({ id: `${region.pageId}/${region.id}/${capability.id}`, pageId: region.pageId, regionId: region.id, capabilityId: capability.id, parameters });
70
+ }
71
+ const requirementIds = new Set();
72
+ for (const requirement of scope.requirements) {
73
+ assert.ok(typeof requirement.id==='string'&&requirement.id.trim()&&!requirementIds.has(requirement.id), `Missing or duplicate requirement identity: ${requirement.id}`);
74
+ requirementIds.add(requirement.id);
75
+ assert.ok(requirement.pages?.length && requirement.pages.every(page => seen.has(page) && page !== 'app-shell'), `Map each business requirement to its pages: ${requirement.id}`);
76
+ }
77
+ for (const page of scope.pages) assert.ok(scope.requirements.some(requirement => requirement.pages?.includes(page.id)), `Business page lacks a requirement: ${page.id}`);
78
+ const fixed = { schemaVersion: 1, definition: snapshot.definition, regions, bindings, decisions: scope.decisions || [] };
79
+ assert.ok(!fixed.decisions.some(decision=>decision.bindingId==='app-shell/appearance/theme'&&decision.status==='not-applicable'), 'The default four-theme contract must retain its acceptance');
80
+ const result = contract.checkCapabilities({ ...fixed, scope });
81
+ assert.equal(result.status, 'passed', result.errors.join('; '));
82
+ return { fixed, result };
83
+ }
84
+ function checkInputs(inputsRoot, contract) {
85
+ const snapshot = read(path.join(inputsRoot, 'template-snapshot.json')), scope = read(path.join(inputsRoot, 'scope.json'));
86
+ const expected = scopeInputs(snapshot, scope, contract), fixed = read(path.join(inputsRoot, 'capabilities.json'));
87
+ assert.deepEqual(fixed, expected.fixed, 'Business capability bindings differ from the fixed sourced page/region contract');
88
+ return expected.result;
89
+ }
90
+ function pageContent(snapshot, pageId) {
91
+ assert.equal(snapshot.kind, 'content-reference');
92
+ const page = snapshot.index.pages.find(entry=>entry.id===pageId);
93
+ assert.ok(page, `Unknown reference page: ${pageId}`);
94
+ const html = Buffer.from(snapshot.files.find(file=>file.path==='index.html').content, 'base64').toString('utf8');
95
+ const fragments = new Map([...html.matchAll(/^<template data-source="([^"]+)">\n([\s\S]*?)^<\/template>/gm)].map(match=>[match[1],match[2]]));
96
+ return { ...page, html: fragments.get(page.fragment), templateDigest: snapshot.digest, readOnly: true };
97
+ }
98
+ module.exports = { extract, scopeInputs, checkInputs, pageContent };
@@ -74,12 +74,19 @@ function initialize(directory, { id, title, purpose, templateRoot = assetRoot })
74
74
  adaptations.push({ file, reason: reasons.join(';'), source: origin.files[file], generated: hash(next) });
75
75
  }
76
76
  }
77
- const index = path.join(app, 'index.html'), original = fs.readFileSync(index, 'utf8');
78
- assert.ok(original.includes('src="app.js"'), 'Review changed EASEL boot entry before adapting');
79
- const adapted = brandRuntimeResource('index.html', original).replace('</head>', ' <link rel="stylesheet" href="tokens.css">\n <link rel="stylesheet" href="usability.css">\n</head>')
80
- .replace('src="app.js"', 'src="enterprise-bootstrap.mjs"');
77
+ const index = path.join(app, 'index.html');
78
+ const portable = fs.readFileSync(path.join(templateRoot, 'index.html'), 'utf8');
79
+ assert.ok(portable.includes('src="offline.js"') && !portable.includes('type="module"'), 'Offline enterprise entry required');
80
+ const adapted = portable.replaceAll('href="reference/', 'href="').replaceAll('data-source="reference/', 'data-source="')
81
+ .replace('</head>', ' <link rel="stylesheet" href="tokens.css">\n</head>')
82
+ .replace(/(<script type="application\/json" id="prototype-offline-config">)[\s\S]*?(<\/script>)/,
83
+ (_, start, end) => start + JSON.stringify({ title }).replaceAll('<', '\\u003c') + end);
81
84
  fs.writeFileSync(index, adapted);
82
- adaptations.push({ file: 'index.html', reason: '默认品牌统一为 i3-Composer;接入原有设计 token、实例配置和独立滚动适配,完整保留页面内容', source: origin.files['index.html'], generated: hash(adapted) });
85
+ const offline = fs.readFileSync(path.join(templateRoot, 'offline.js'), 'utf8')
86
+ .replaceAll('new URL("reference/', 'new URL("').replaceAll('i3-prototype-antdv-', storagePrefix);
87
+ fs.writeFileSync(path.join(app, 'offline.js'), offline);
88
+ adaptations.push({ file: 'index.html', reason: 'i3-Composer 完整可编辑 HTML 片段、路由和实例配置内嵌;经典脚本支持 file://;保留全部内容与本地样式', source: origin.files['index.html'], generated: hash(adapted) });
89
+ adaptations.push({ file: 'offline.js', reason: '来源模块的离线运行适配,实例存储前缀隔离;原始模块仍保留', generated: hash(offline) });
83
90
  fs.copyFileSync(path.join(templateRoot, 'usability.css'), path.join(app, 'usability.css'));
84
91
  fs.writeFileSync(path.join(app, 'enterprise-bootstrap.mjs'), "const response = await fetch(new URL('./config.json', import.meta.url));\nif (!response.ok) throw new Error('无法读取企业后台实例配置');\nconst config = await response.json();\ndocument.title = config.title;\nawait import('./app.js');\n");
85
92
  fs.copyFileSync(path.join(templateRoot, 'serve.cjs'), path.join(app, 'serve.cjs'));
@@ -92,6 +99,6 @@ function initialize(directory, { id, title, purpose, templateRoot = assetRoot })
92
99
  fs.mkdirSync(path.join(directory, 'mocks'), { recursive: true });
93
100
  fs.writeFileSync(path.join(directory, 'mocks/README.md'), '# 演示数据\n\n完整 i3-Composer 示例的数据与规则保留在 app/src/ 各模块中,并使用实例独立的本地存储。它们用于模板审查;新业务需要按需求替换,不能当作真实服务或已完成业务适配。\n');
94
101
  fs.writeFileSync(path.join(directory, 'requirements-map.json'), JSON.stringify(mapping, null, 2) + '\n');
95
- return { kind: 'easel-html', entry: 'app/index.html', sourceVersion: origin.sourceVersion, instanceId, storagePrefix };
102
+ return { kind: 'easel-html', entry: 'app/index.html', sourceVersion: origin.sourceVersion, instanceId, storagePrefix, offlineVersion: 1 };
96
103
  }
97
104
  module.exports = { verifyReference, initialize, brandRuntimeResource };
@@ -5,7 +5,7 @@ try {
5
5
  const { options, positional } = lib.parseArgs(process.argv.slice(2));
6
6
  const [operation, directory] = positional;
7
7
  if (!directory || !['inspect', 'manifest', 'revise', 'confirm-baseline'].includes(operation)) throw new Error('Usage: manage-baseline.cjs <inspect|manifest|revise|confirm-baseline> <directory> [--revision r002] [--confirmation file.json]');
8
- const result = operation === 'manifest' ? lib.contentManifest(directory) : operation === 'inspect' ? lib.compareBaseline(directory) : operation === 'revise' ? lib.revisePrototype(directory, options.revision) : lib.freezeBaseline(directory, JSON.parse(fs.readFileSync(options.confirmation, 'utf8')));
8
+ const result = operation === 'manifest' ? lib.contentManifest(directory) : operation === 'inspect' ? lib.compareBaseline(directory) : operation === 'revise' ? lib.revisePrototype(directory, options.revision, options) : lib.freezeBaseline(directory, JSON.parse(fs.readFileSync(options.confirmation, 'utf8')));
9
9
  process.stdout.write(JSON.stringify(result, null, 2) + '\n');
10
10
  if (result.status === 'corrupt-baseline') process.exitCode = 1;
11
11
  } catch (error) { process.stderr.write(error.message + '\n'); process.exitCode = 1; }