@givolt/i3-composer-agent 3.2.1 → 4.0.0

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 (611) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude/commands/i3-build.md +1 -0
  3. package/.claude/commands/i3-code-simplify.md +1 -0
  4. package/.claude/commands/i3-constraints.md +1 -0
  5. package/.claude/commands/i3-plan.md +1 -0
  6. package/.claude/commands/i3-review.md +1 -0
  7. package/.claude/commands/i3-ship.md +1 -0
  8. package/.claude/commands/i3-spec.md +1 -0
  9. package/.claude/commands/i3-test.md +1 -0
  10. package/.claude/commands/i3-webperf.md +1 -0
  11. package/.claude-plugin/marketplace.json +1 -1
  12. package/.claude-plugin/plugin.json +1 -1
  13. package/.codex-plugin/plugin.json +2 -2
  14. package/README.md +31 -25
  15. package/bin/i3-composer-agent.cjs +4 -59
  16. package/bin/install.cjs +6 -14
  17. package/bin/native-layout.cjs +11 -2
  18. package/bin/native-migration.cjs +68 -28
  19. package/bin/retired-custom-fingerprints.json +1597 -0
  20. package/bin/wizard.cjs +2 -13
  21. package/docs/antigravity-setup.md +3 -1
  22. package/docs/codebuddy-setup.md +19 -76
  23. package/docs/codex-setup.md +10 -4
  24. package/docs/comparison.md +1 -1
  25. package/docs/copilot-cli-setup.md +4 -4
  26. package/docs/cursor-setup.md +1 -1
  27. package/docs/gemini-cli-setup.md +1 -1
  28. package/docs/other-hosts.md +2 -2
  29. package/docs/windsurf-setup.md +2 -2
  30. package/docs/workbuddy-setup.md +9 -16
  31. package/evals/README.md +10 -0
  32. package/evals/cases/i3-code-simplification.json +8 -0
  33. package/evals/cases/i3-documentation-and-adrs.json +4 -0
  34. package/evals/cases/i3-enterprise-sop.json +1 -1
  35. package/evals/cases/i3-frontend-ui-engineering.json +1 -1
  36. package/evals/cases/i3-security-and-hardening.json +4 -0
  37. package/evals/cases/i3-ui-demo.json +2 -2
  38. package/evals/cases/i3-using-agent-skills.json +5 -5
  39. package/evals/plugin/simplify-fires-on-pasted-function/graders/behavior-kept-and-explained.md +7 -0
  40. package/evals/plugin/simplify-fires-on-pasted-function/graders/skill-fired.md +5 -0
  41. package/evals/plugin/simplify-fires-on-pasted-function/prompt.md +30 -0
  42. package/evals/plugin/simplify-stays-quiet-on-make-it-fast/graders/not-fired.md +8 -0
  43. package/evals/plugin/simplify-stays-quiet-on-make-it-fast/prompt.md +20 -0
  44. package/evals/zh-CN/cases/i3-code-simplification.json +8 -0
  45. package/evals/zh-CN/cases/i3-documentation-and-adrs.json +4 -0
  46. package/evals/zh-CN/cases/i3-enterprise-sop.json +1 -1
  47. package/evals/zh-CN/cases/i3-frontend-ui-engineering.json +2 -2
  48. package/evals/zh-CN/cases/i3-security-and-hardening.json +4 -0
  49. package/evals/zh-CN/cases/i3-ui-demo.json +2 -2
  50. package/evals/zh-CN/cases/i3-using-agent-skills.json +6 -6
  51. package/hooks/SDD-CACHE.md +1 -1
  52. package/package.json +13 -80
  53. package/plugin.json +15 -2
  54. package/references/accessibility-checklist.md +4 -4
  55. package/references/performance-checklist.md +5 -4
  56. package/references/testing-patterns.md +2 -1
  57. package/scripts/floor-guard-reference-test.js +32 -0
  58. package/scripts/lib/execution-status.js +44 -0
  59. package/scripts/run-evals-test.js +157 -7
  60. package/scripts/run-evals.js +59 -12
  61. package/scripts/ui-demo-test.js +2 -2
  62. package/scripts/validate-artifact-paths-test.js +14 -0
  63. package/scripts/validate-artifact-paths.js +4 -2
  64. package/skills/i3-api-and-interface-design/SKILL.md +3 -1
  65. package/skills/i3-ci-cd-and-automation/SKILL.md +7 -4
  66. package/skills/i3-code-simplification/SKILL.md +3 -3
  67. package/skills/i3-constraint-driven-development/SKILL.md +4 -4
  68. package/skills/i3-constraint-driven-development/references/floor-guard.md +2 -2
  69. package/skills/i3-context-engineering/SKILL.md +1 -1
  70. package/skills/i3-debugging-and-error-recovery/SKILL.md +1 -1
  71. package/skills/i3-deprecation-and-migration/SKILL.md +6 -1
  72. package/skills/i3-documentation-and-adrs/SKILL.md +3 -2
  73. package/skills/i3-enterprise-sop/SKILL.md +37 -70
  74. package/skills/i3-enterprise-sop/references/engineering-skeleton/directory-standard.md +7 -7
  75. package/skills/i3-enterprise-sop/references/handoff.py +149 -120
  76. package/skills/i3-enterprise-sop/references/technical-baseline/baselines/enterprise-application-technical-baseline-v0-0-4.md +24 -24
  77. package/skills/i3-enterprise-sop/references/technical-baseline/templates/technical-baseline.md +8 -8
  78. package/skills/i3-enterprise-sop/references/templates/ad.md +31 -31
  79. package/skills/i3-enterprise-sop/references/templates/brd.md +6 -6
  80. package/skills/i3-enterprise-sop/references/templates/prd.md +37 -37
  81. package/skills/i3-enterprise-sop/references/templates/testcase.md +25 -25
  82. package/skills/i3-frontend-ui-engineering/SKILL.md +6 -10
  83. package/skills/i3-idea-refine/SKILL.md +4 -2
  84. package/skills/i3-incremental-implementation/SKILL.md +0 -4
  85. package/skills/i3-performance-optimization/SKILL.md +2 -2
  86. package/skills/i3-security-and-hardening/references/hardening-patterns.md +5 -0
  87. package/skills/i3-source-driven-development/SKILL.md +3 -2
  88. package/skills/i3-spec-driven-development/SKILL.md +1 -1
  89. package/skills/i3-ui-demo/SKILL.md +3 -1
  90. package/skills/i3-ui-demo/references/dependencies.md +1 -1
  91. package/skills/i3-ui-demo/references/resources.md +1 -1
  92. package/skills/i3-ui-demo/scripts/dependencies.cjs +0 -3
  93. package/skills/i3-using-agent-skills/SKILL.md +2 -2
  94. package/.claude/commands/i3-prototype.md +0 -23
  95. package/.gemini/commands/i3-prototype.toml +0 -23
  96. package/commands/i3-prototype.toml +0 -23
  97. package/evals/cases/i3-ui-prototype.json +0 -158
  98. package/evals/fixtures/i3-ui-prototype/admin-list/assets/reference.css +0 -3
  99. package/evals/fixtures/i3-ui-prototype/admin-list/assets/reference.js +0 -8
  100. package/evals/fixtures/i3-ui-prototype/admin-list/capability-definition.json +0 -67
  101. package/evals/fixtures/i3-ui-prototype/admin-list/index.html +0 -89
  102. package/evals/fixtures/i3-ui-prototype/admin-list/readme.md +0 -52
  103. package/evals/fixtures/i3-ui-prototype/admin-list/template.json +0 -8
  104. package/evals/fixtures/i3-ui-prototype/business-brief.md +0 -7
  105. package/evals/zh-CN/cases/i3-ui-prototype.json +0 -165
  106. package/hooks/PROTOTYPE.md +0 -31
  107. package/hooks/codebuddy-upstream.cjs +0 -93
  108. package/hooks/i3-prototype.cjs +0 -7
  109. package/hooks/manage.cjs +0 -169
  110. package/scripts/design-provider-discovery-test.js +0 -190
  111. package/scripts/design-provider-test.js +0 -75
  112. package/scripts/enterprise-template-test.js +0 -205
  113. package/scripts/lib/prototype-fixture.cjs +0 -17
  114. package/scripts/prototype-cache-test.js +0 -55
  115. package/scripts/prototype-generation-entry-test.js +0 -6
  116. package/scripts/prototype-generation-evidence-test.js +0 -10
  117. package/scripts/prototype-generation-native-test.js +0 -78
  118. package/scripts/prototype-generation-test.js +0 -99
  119. package/scripts/prototype-inventory-test.js +0 -43
  120. package/scripts/prototype-locations-test.js +0 -79
  121. package/scripts/prototype-project-test.js +0 -183
  122. package/scripts/template-adapter-test.js +0 -155
  123. package/scripts/ui-prototype-binding-recovery-test.js +0 -84
  124. package/scripts/ui-prototype-buddy-lifecycle-test.js +0 -102
  125. package/scripts/ui-prototype-codebuddy-hook-test.js +0 -112
  126. package/scripts/ui-prototype-content-test.js +0 -123
  127. package/scripts/ui-prototype-dependencies-test.js +0 -226
  128. package/scripts/ui-prototype-devtools-test.js +0 -53
  129. package/scripts/ui-prototype-execution-evidence-test.js +0 -62
  130. package/scripts/ui-prototype-execution-gates-test.js +0 -91
  131. package/scripts/ui-prototype-execution-policy-test.js +0 -53
  132. package/scripts/ui-prototype-execution-runtime-test.js +0 -27
  133. package/scripts/ui-prototype-ide-source-test.js +0 -73
  134. package/scripts/ui-prototype-native-test.js +0 -526
  135. package/scripts/ui-prototype-recovery-test.js +0 -81
  136. package/scripts/ui-prototype-registration-test.js +0 -53
  137. package/scripts/ui-prototype-template-test.js +0 -261
  138. package/scripts/ui-prototype-test.js +0 -124
  139. package/scripts/ui-prototype-transcript-auto-test.js +0 -67
  140. package/skills/i3-ui-prototype/SKILL.md +0 -256
  141. package/skills/i3-ui-prototype/assets/capabilities/generation.json +0 -833
  142. package/skills/i3-ui-prototype/assets/capabilities/management.json +0 -294
  143. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/acceptance.json +0 -51
  144. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/component-map.json +0 -13
  145. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/generation-component-map.json +0 -300
  146. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/index.html +0 -11
  147. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/package-lock.json +0 -2298
  148. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/package.json +0 -22
  149. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/public/prototype-config.json +0 -6
  150. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/App.vue +0 -136
  151. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/components/DeviceEditor.vue +0 -111
  152. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/config.ts +0 -19
  153. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/content.ts +0 -28
  154. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/domain/devices.ts +0 -50
  155. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/domain/theme.ts +0 -25
  156. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/main.ts +0 -18
  157. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/style.css +0 -50
  158. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/src/useDevices.ts +0 -66
  159. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/tests/devices.test.ts +0 -44
  160. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/tests/theme.test.ts +0 -26
  161. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/tsconfig.json +0 -15
  162. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/legacy-starter/vite.config.ts +0 -4
  163. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/profile.json +0 -174
  164. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/readme.md +0 -61
  165. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/index.html +0 -11
  166. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/package-lock.json +0 -2298
  167. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/package.json +0 -22
  168. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/public/prototype-config.json +0 -21
  169. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/App.vue +0 -62
  170. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/PrototypeShell.vue +0 -59
  171. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/config.ts +0 -23
  172. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/domain/presentation.ts +0 -29
  173. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/domain/theme.ts +0 -25
  174. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/main.ts +0 -18
  175. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/style.css +0 -26
  176. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/tests/presentation.test.ts +0 -23
  177. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/tests/theme.test.ts +0 -26
  178. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/tsconfig.json +0 -15
  179. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/vite.config.ts +0 -4
  180. package/skills/i3-ui-prototype/assets/hosts/codebuddy/profile.json +0 -17
  181. package/skills/i3-ui-prototype/assets/optional-skills/host-targets.json +0 -739
  182. package/skills/i3-ui-prototype/assets/optional-skills/sources.json +0 -27
  183. package/skills/i3-ui-prototype/assets/templates/catalog.js +0 -149
  184. package/skills/i3-ui-prototype/assets/templates/catalog.json +0 -149
  185. package/skills/i3-ui-prototype/assets/templates/classic-admin/manifest.json +0 -9
  186. package/skills/i3-ui-prototype/assets/templates/classic-admin/preset.json +0 -6
  187. package/skills/i3-ui-prototype/assets/templates/common/app/app.mjs +0 -89
  188. package/skills/i3-ui-prototype/assets/templates/common/app/config.json +0 -1
  189. package/skills/i3-ui-prototype/assets/templates/common/app/domain.mjs +0 -20
  190. package/skills/i3-ui-prototype/assets/templates/common/app/index.html +0 -17
  191. package/skills/i3-ui-prototype/assets/templates/common/app/serve.cjs +0 -16
  192. package/skills/i3-ui-prototype/assets/templates/common/app/styles.css +0 -670
  193. package/skills/i3-ui-prototype/assets/templates/common/app/tokens.css +0 -19
  194. package/skills/i3-ui-prototype/assets/templates/common/design-system/master.md +0 -20
  195. package/skills/i3-ui-prototype/assets/templates/common/gallery.html +0 -2
  196. package/skills/i3-ui-prototype/assets/templates/common/mocks/applications.json +0 -5
  197. package/skills/i3-ui-prototype/assets/templates/common/requirements-map.json +0 -8
  198. package/skills/i3-ui-prototype/assets/templates/common/serve-gallery.cjs +0 -16
  199. package/skills/i3-ui-prototype/assets/templates/credits.md +0 -17
  200. package/skills/i3-ui-prototype/assets/templates/data-operations/manifest.json +0 -9
  201. package/skills/i3-ui-prototype/assets/templates/data-operations/preset.json +0 -6
  202. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/capability-definition.json +0 -294
  203. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/component-inventory.json +0 -707
  204. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/design-system.md +0 -32
  205. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/generation.json +0 -49
  206. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/index.html +0 -534
  207. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/manifest.json +0 -9
  208. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/offline-build.json +0 -265
  209. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/offline.js +0 -8888
  210. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/origin.json +0 -344
  211. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/preset.json +0 -928
  212. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/app.js +0 -22
  213. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/assets/empty.svg +0 -1
  214. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/assets/reference-styles.json +0 -1
  215. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/assets/result-403.svg +0 -1
  216. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/assets/result-404.svg +0 -1
  217. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/assets-manifest.json +0 -334
  218. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/baseline.json +0 -173
  219. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/conversion.md +0 -30
  220. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/credits.md +0 -17
  221. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/design-tokens.json +0 -881
  222. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/index.html +0 -28
  223. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/licenses/@qin-ui-antdv-next-pro.txt +0 -9
  224. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/licenses/ant-design-icons.txt +0 -22
  225. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/licenses/antdv-next.txt +0 -21
  226. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/package.json +0 -12
  227. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/browser-routes.json +0 -298
  228. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/coverage.json +0 -180
  229. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/integrity.json +0 -13
  230. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/keyboard.json +0 -11
  231. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/responsive.json +0 -125
  232. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/review.md +0 -51
  233. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/rules.log +0 -150
  234. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/flow-editor-html.png +0 -0
  235. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/flow-editor-original.png +0 -0
  236. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/intent-create-html.png +0 -0
  237. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/intent-create-original.png +0 -0
  238. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/models-html.png +0 -0
  239. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/models-original.png +0 -0
  240. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/workbench-html.png +0 -0
  241. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/screenshots/workbench-original.png +0 -0
  242. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/selection.json +0 -9
  243. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/qa/visual-comparison.json +0 -342
  244. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/readme.md +0 -73
  245. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/reference.md +0 -59
  246. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/routes.json +0 -178
  247. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/controls.js +0 -99
  248. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/dialogs.js +0 -54
  249. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/dom.js +0 -264
  250. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/forms.js +0 -47
  251. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/icons.js +0 -41
  252. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/layout.js +0 -47
  253. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/router.js +0 -63
  254. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/state.js +0 -90
  255. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/table.js +0 -41
  256. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/runtime/widgets.js +0 -8
  257. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/AgentDetail.html +0 -3
  258. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/AgentDetail.js +0 -36
  259. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/AgentEditor.html +0 -2
  260. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/AgentEditor.js +0 -51
  261. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/AgentsPage.html +0 -3
  262. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/AgentsPage.js +0 -48
  263. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/CheckResults.html +0 -2
  264. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/CheckResults.js +0 -6
  265. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/ResourcePicker.html +0 -2
  266. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/ResourcePicker.js +0 -13
  267. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/data.js +0 -24
  268. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/domain.js +0 -32
  269. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/registry.js +0 -25
  270. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/agents/store.js +0 -85
  271. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentClose.html +0 -2
  272. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentClose.js +0 -17
  273. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentCreate.html +0 -2
  274. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentCreate.js +0 -66
  275. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentDecisions.html +0 -3
  276. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentDecisions.js +0 -38
  277. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentDetail.html +0 -2
  278. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentDetail.js +0 -66
  279. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentDocument.html +0 -2
  280. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentDocument.js +0 -5
  281. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentHeader.html +0 -2
  282. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentHeader.js +0 -12
  283. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentHistory.html +0 -2
  284. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentHistory.js +0 -11
  285. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentList.html +0 -2
  286. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentList.js +0 -116
  287. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentReplan.html +0 -2
  288. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentReplan.js +0 -32
  289. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentRevision.html +0 -2
  290. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentRevision.js +0 -49
  291. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentSummary.html +0 -2
  292. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentSummary.js +0 -10
  293. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentWorkspace.html +0 -2
  294. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/IntentWorkspace.js +0 -77
  295. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/data.js +0 -60
  296. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/domain.js +0 -105
  297. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/intents/store.js +0 -212
  298. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/AuditPanel.html +0 -2
  299. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/AuditPanel.js +0 -18
  300. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelDetail.html +0 -2
  301. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelDetail.js +0 -23
  302. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelEditor.html +0 -2
  303. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelEditor.js +0 -78
  304. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelGrant.html +0 -2
  305. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelGrant.js +0 -55
  306. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelReferences.html +0 -2
  307. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelReferences.js +0 -26
  308. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelRelease.html +0 -2
  309. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelRelease.js +0 -38
  310. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelStatus.html +0 -2
  311. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelStatus.js +0 -7
  312. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelTable.html +0 -2
  313. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelTable.js +0 -72
  314. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelTester.html +0 -2
  315. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelTester.js +0 -46
  316. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelsPage.html +0 -2
  317. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/ModelsPage.js +0 -52
  318. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/RowActions.html +0 -2
  319. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/RowActions.js +0 -19
  320. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/UsagePanel.html +0 -2
  321. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/UsagePanel.js +0 -30
  322. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/data.js +0 -48
  323. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/domain.js +0 -39
  324. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/models/store.js +0 -129
  325. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/IncidentDetail.html +0 -4
  326. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/IncidentDetail.js +0 -21
  327. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/IntentSource.html +0 -2
  328. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/IntentSource.js +0 -8
  329. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/OperationActionDialog.html +0 -2
  330. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/OperationActionDialog.js +0 -37
  331. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/OperationEntry.html +0 -2
  332. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/OperationEntry.js +0 -10
  333. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/OperationsPage.html +0 -2
  334. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/OperationsPage.js +0 -37
  335. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/RepairTrack.html +0 -2
  336. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/RepairTrack.js +0 -49
  337. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/RunDetail.html +0 -4
  338. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/RunDetail.js +0 -22
  339. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/SourceSummary.html +0 -2
  340. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/SourceSummary.js +0 -9
  341. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/commands.js +0 -82
  342. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/examples.js +0 -47
  343. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/model.js +0 -61
  344. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/repair.js +0 -68
  345. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/store.js +0 -55
  346. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/types.js +0 -1
  347. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/operations/workbench.js +0 -18
  348. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/ManagementTable.html +0 -3
  349. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/ManagementTable.js +0 -28
  350. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcCreateEntry.html +0 -2
  351. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcCreateEntry.js +0 -18
  352. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcDetail.html +0 -2
  353. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcDetail.js +0 -31
  354. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcEditor.html +0 -2
  355. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcEditor.js +0 -27
  356. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcLifecycle.html +0 -2
  357. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcLifecycle.js +0 -16
  358. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcPage.html +0 -2
  359. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcPage.js +0 -43
  360. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcPicker.html +0 -4
  361. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcPicker.js +0 -34
  362. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcProgress.html +0 -2
  363. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcProgress.js +0 -30
  364. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcWizard.html +0 -3
  365. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcWizard.js +0 -67
  366. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcWorkspace.html +0 -2
  367. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcWorkspace.js +0 -41
  368. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcsPage.html +0 -2
  369. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/PbcsPage.js +0 -31
  370. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/ServiceEditor.html +0 -2
  371. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/ServiceEditor.js +0 -26
  372. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/ServiceList.html +0 -2
  373. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/ServiceList.js +0 -70
  374. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/data.js +0 -8
  375. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/domain.js +0 -62
  376. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/management.js +0 -36
  377. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/managementStore.js +0 -49
  378. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/pbc/store.js +0 -132
  379. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/AdminList.html +0 -2
  380. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/AdminList.js +0 -38
  381. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/EffectiveGrants.html +0 -2
  382. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/EffectiveGrants.js +0 -11
  383. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/GrantEditor.html +0 -2
  384. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/GrantEditor.js +0 -45
  385. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/MemberEditor.html +0 -2
  386. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/MemberEditor.js +0 -54
  387. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/MembersPage.html +0 -3
  388. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/MembersPage.js +0 -27
  389. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/RecordsPage.html +0 -2
  390. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/RecordsPage.js +0 -12
  391. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/RoleEditor.html +0 -2
  392. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/RoleEditor.js +0 -45
  393. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/RolesPage.html +0 -3
  394. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/RolesPage.js +0 -38
  395. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/domain.js +0 -61
  396. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/state.js +0 -51
  397. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/permissions/store.js +0 -116
  398. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseActionDialog.html +0 -2
  399. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseActionDialog.js +0 -45
  400. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseDetail.html +0 -4
  401. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseDetail.js +0 -30
  402. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseEditor.html +0 -2
  403. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseEditor.js +0 -67
  404. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseExecution.html +0 -2
  405. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleaseExecution.js +0 -5
  406. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleasesPage.html +0 -4
  407. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/ReleasesPage.js +0 -60
  408. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/commands.js +0 -157
  409. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/model.js +0 -136
  410. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/releases/store.js +0 -76
  411. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewDetail.html +0 -3
  412. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewDetail.js +0 -26
  413. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewEvidence.html +0 -2
  414. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewEvidence.js +0 -14
  415. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewProcess.html +0 -2
  416. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewProcess.js +0 -113
  417. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewsPage.html +0 -3
  418. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/ReviewsPage.js +0 -62
  419. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/commands.js +0 -97
  420. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/model.js +0 -147
  421. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/reviews/store.js +0 -13
  422. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ColumnSettings.html +0 -2
  423. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ColumnSettings.js +0 -9
  424. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ListBatchBar.html +0 -2
  425. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ListBatchBar.js +0 -8
  426. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ListDeleteDialog.html +0 -2
  427. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ListDeleteDialog.js +0 -37
  428. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ListMore.html +0 -2
  429. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/ListMore.js +0 -8
  430. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/RecordMetadata.html +0 -2
  431. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/RecordMetadata.js +0 -17
  432. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/columns.js +0 -32
  433. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/deliveryGuide.js +0 -49
  434. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/deliveryView.js +0 -12
  435. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/listBatch.js +0 -15
  436. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/listSelection.js +0 -37
  437. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/policy.js +0 -68
  438. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shared/session.js +0 -44
  439. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/ConfirmationDialog.html +0 -2
  440. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/ConfirmationDialog.js +0 -25
  441. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/ConsoleShell.html +0 -2
  442. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/ConsoleShell.js +0 -53
  443. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/PrototypeGuide.html +0 -10
  444. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/PrototypeGuide.js +0 -30
  445. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/ScopePage.html +0 -2
  446. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/ScopePage.js +0 -10
  447. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/SessionDialog.html +0 -2
  448. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/SessionDialog.js +0 -9
  449. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/confirmation.js +0 -3
  450. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/shell/navigation.js +0 -19
  451. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecDocument.html +0 -2
  452. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecDocument.js +0 -8
  453. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecEdit.html +0 -2
  454. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecEdit.js +0 -32
  455. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecHeader.html +0 -2
  456. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecHeader.js +0 -15
  457. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecHistory.html +0 -2
  458. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecHistory.js +0 -11
  459. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecReview.html +0 -2
  460. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecReview.js +0 -57
  461. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecWorkspace.html +0 -2
  462. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/SpecWorkspace.js +0 -37
  463. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/data.js +0 -20
  464. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/domain.js +0 -55
  465. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/specs/store.js +0 -151
  466. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/ArtifactDetail.html +0 -3
  467. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/ArtifactDetail.js +0 -18
  468. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TaskCreate.html +0 -2
  469. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TaskCreate.js +0 -40
  470. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TaskDetail.html +0 -2
  471. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TaskDetail.js +0 -51
  472. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TaskLaunch.html +0 -2
  473. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TaskLaunch.js +0 -9
  474. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TasksPage.html +0 -5
  475. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/TasksPage.js +0 -48
  476. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/domain.js +0 -204
  477. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/exampleSource.js +0 -22
  478. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/registry.js +0 -135
  479. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/tasks/store.js +0 -137
  480. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workbench/WorkbenchPage.html +0 -3
  481. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workbench/WorkbenchPage.js +0 -36
  482. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workbench/model.js +0 -56
  483. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workbench/store.js +0 -15
  484. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/FlowCanvas.html +0 -2
  485. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/FlowCanvas.js +0 -27
  486. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/FlowDetail.html +0 -4
  487. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/FlowDetail.js +0 -31
  488. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/FlowEditor.html +0 -2
  489. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/FlowEditor.js +0 -68
  490. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/WorkflowsPage.html +0 -5
  491. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/WorkflowsPage.js +0 -55
  492. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/data.js +0 -16
  493. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/domain.js +0 -83
  494. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/registry.js +0 -18
  495. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/src/workflows/store.js +0 -61
  496. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/admin.css +0 -60
  497. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/agents.css +0 -46
  498. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/antdv.css +0 -295
  499. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/app.css +0 -102
  500. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/delivery.css +0 -4
  501. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/intents.css +0 -37
  502. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/native.css +0 -22
  503. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/operations.css +0 -2
  504. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/pbc.css +0 -3
  505. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/permissions.css +0 -22
  506. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/pro.css +0 -1
  507. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/releases.css +0 -4
  508. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/reset.css +0 -246
  509. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/reviews.css +0 -8
  510. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/tasks.css +0 -6
  511. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/tokens.css +0 -15
  512. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/workbench.css +0 -61
  513. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/styles/workflows.css +0 -1
  514. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/admin-rules.test.js +0 -96
  515. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/agents.test.js +0 -14
  516. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/intent-state.test.js +0 -37
  517. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/list-batch.test.js +0 -44
  518. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/operation-fixtures.js +0 -19
  519. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/operation-repair.test.js +0 -14
  520. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/operations.test.js +0 -25
  521. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/pbc-management.test.js +0 -17
  522. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/pbc-state.test.js +0 -24
  523. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/permission-config.test.js +0 -23
  524. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/permissions.test.js +0 -24
  525. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/releases.test.js +0 -50
  526. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/reviews.test.js +0 -36
  527. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/runtime-forms-router.test.js +0 -28
  528. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/runtime-state.test.js +0 -42
  529. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/runtime-stores.test.js +0 -16
  530. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/spec-state.test.js +0 -11
  531. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/tasks.test.js +0 -27
  532. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/workbench.test.js +0 -34
  533. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tests/workflows.test.js +0 -16
  534. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tools/convert.mjs +0 -168
  535. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tools/serve.mjs +0 -7
  536. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tools/styles.mjs +0 -11
  537. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/reference/tools/verify.mjs +0 -24
  538. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/serve.cjs +0 -16
  539. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/template-inventory.json +0 -28791
  540. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/template.json +0 -9
  541. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/usability.css +0 -44
  542. package/skills/i3-ui-prototype/assets/templates/gallery/index.html +0 -40
  543. package/skills/i3-ui-prototype/assets/templates/generation-options.js +0 -42
  544. package/skills/i3-ui-prototype/assets/templates/index.html +0 -3
  545. package/skills/i3-ui-prototype/assets/templates/modern-workspace/manifest.json +0 -9
  546. package/skills/i3-ui-prototype/assets/templates/modern-workspace/preset.json +0 -6
  547. package/skills/i3-ui-prototype/assets/templates/presentation.html +0 -17
  548. package/skills/i3-ui-prototype/assets/templates/serve-gallery.cjs +0 -23
  549. package/skills/i3-ui-prototype/references/artifact-contract.md +0 -66
  550. package/skills/i3-ui-prototype/references/content-template.md +0 -81
  551. package/skills/i3-ui-prototype/references/enterprise-admin.md +0 -44
  552. package/skills/i3-ui-prototype/references/entry-contract.md +0 -71
  553. package/skills/i3-ui-prototype/references/execution-evidence.md +0 -51
  554. package/skills/i3-ui-prototype/references/expert-adapter.md +0 -76
  555. package/skills/i3-ui-prototype/references/framework-contract.md +0 -76
  556. package/skills/i3-ui-prototype/references/generation-contract.md +0 -122
  557. package/skills/i3-ui-prototype/references/interaction-acceptance.md +0 -169
  558. package/skills/i3-ui-prototype/references/legacy-native.md +0 -58
  559. package/skills/i3-ui-prototype/references/optional-skills.md +0 -63
  560. package/skills/i3-ui-prototype/references/project-layout.md +0 -92
  561. package/skills/i3-ui-prototype/references/template-adapters.md +0 -63
  562. package/skills/i3-ui-prototype/references/workflow-contract.md +0 -77
  563. package/skills/i3-ui-prototype/scripts/adapters/easel-html.cjs +0 -30
  564. package/skills/i3-ui-prototype/scripts/adapters/legacy-html.cjs +0 -28
  565. package/skills/i3-ui-prototype/scripts/browser-workspace.cjs +0 -72
  566. package/skills/i3-ui-prototype/scripts/buddy-host.cjs +0 -40
  567. package/skills/i3-ui-prototype/scripts/check-design-provider.cjs +0 -9
  568. package/skills/i3-ui-prototype/scripts/check-prototype.cjs +0 -14
  569. package/skills/i3-ui-prototype/scripts/codebuddy-context.cjs +0 -92
  570. package/skills/i3-ui-prototype/scripts/codebuddy-hook.cjs +0 -298
  571. package/skills/i3-ui-prototype/scripts/codebuddy-ide-source.cjs +0 -69
  572. package/skills/i3-ui-prototype/scripts/codebuddy-registration.cjs +0 -125
  573. package/skills/i3-ui-prototype/scripts/content-template.cjs +0 -98
  574. package/skills/i3-ui-prototype/scripts/design-provider-discovery.cjs +0 -128
  575. package/skills/i3-ui-prototype/scripts/enterprise-template.cjs +0 -104
  576. package/skills/i3-ui-prototype/scripts/execution-assertions.cjs +0 -43
  577. package/skills/i3-ui-prototype/scripts/execution-diagnostics.cjs +0 -91
  578. package/skills/i3-ui-prototype/scripts/execution-evidence.cjs +0 -177
  579. package/skills/i3-ui-prototype/scripts/execution-gates.cjs +0 -216
  580. package/skills/i3-ui-prototype/scripts/execution-policy.cjs +0 -62
  581. package/skills/i3-ui-prototype/scripts/execution-recovery.cjs +0 -58
  582. package/skills/i3-ui-prototype/scripts/execution-runtime.cjs +0 -69
  583. package/skills/i3-ui-prototype/scripts/generation-assets.cjs +0 -18
  584. package/skills/i3-ui-prototype/scripts/generation-contract.cjs +0 -214
  585. package/skills/i3-ui-prototype/scripts/generation-evidence.cjs +0 -50
  586. package/skills/i3-ui-prototype/scripts/generation-replan.cjs +0 -34
  587. package/skills/i3-ui-prototype/scripts/hosts/codebuddy.cjs +0 -21
  588. package/skills/i3-ui-prototype/scripts/init-prototype.cjs +0 -8
  589. package/skills/i3-ui-prototype/scripts/manage-baseline.cjs +0 -11
  590. package/skills/i3-ui-prototype/scripts/native-browser.cjs +0 -785
  591. package/skills/i3-ui-prototype/scripts/native-build.cjs +0 -91
  592. package/skills/i3-ui-prototype/scripts/native-command.cjs +0 -35
  593. package/skills/i3-ui-prototype/scripts/native-delivery.cjs +0 -104
  594. package/skills/i3-ui-prototype/scripts/native-devtools.cjs +0 -92
  595. package/skills/i3-ui-prototype/scripts/native-files.cjs +0 -44
  596. package/skills/i3-ui-prototype/scripts/native-pilot-lib.cjs +0 -290
  597. package/skills/i3-ui-prototype/scripts/native-pilot.cjs +0 -59
  598. package/skills/i3-ui-prototype/scripts/native-tool-name.cjs +0 -5
  599. package/skills/i3-ui-prototype/scripts/native-tool-result.cjs +0 -14
  600. package/skills/i3-ui-prototype/scripts/optional-skill-install.cjs +0 -203
  601. package/skills/i3-ui-prototype/scripts/project-registry.cjs +0 -126
  602. package/skills/i3-ui-prototype/scripts/prototype-dependencies.cjs +0 -103
  603. package/skills/i3-ui-prototype/scripts/prototype-hooks.cjs +0 -94
  604. package/skills/i3-ui-prototype/scripts/prototype-lib.cjs +0 -277
  605. package/skills/i3-ui-prototype/scripts/prototype-locations.cjs +0 -69
  606. package/skills/i3-ui-prototype/scripts/ptc-callbacks.cjs +0 -131
  607. package/skills/i3-ui-prototype/scripts/sync-template.cjs +0 -19
  608. package/skills/i3-ui-prototype/scripts/template-adapters.cjs +0 -89
  609. package/skills/i3-ui-prototype/scripts/template-contract.cjs +0 -407
  610. package/skills/i3-ui-prototype/scripts/template-inventory.cjs +0 -78
  611. package/skills/i3-ui-prototype/scripts/validate-result.cjs +0 -117
@@ -1,785 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- // Installable native-pilot acceptance. Dedicated browser contexts; no user profile or auto-install.
5
- const assert = require('node:assert/strict');
6
- const fs = require('node:fs');
7
- const os = require('node:os');
8
- const path = require('node:path');
9
- const crypto = require('node:crypto');
10
- const { pathToFileURL } = require('node:url');
11
- const { spawnSync } = require('node:child_process');
12
- const lib = require('./native-pilot-lib.cjs');
13
- const digest = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
14
- const read = file => JSON.parse(fs.readFileSync(file, 'utf8'));
15
-
16
- function paginationPlan(directory) {
17
- const inputs = read(path.join(directory, 'inputs/capabilities.json'));
18
- const bindings = inputs.bindings.filter(binding => binding.id === 'devices/device-list/pagination');
19
- assert.equal(bindings.length, 1, 'Exactly one fixed device-list pagination binding required');
20
- return { source: 'inputs/capabilities.json', bindingId: bindings[0].id, ...require('./template-contract.cjs').resolvePaginationParameters(bindings[0].parameters) };
21
- }
22
- function themePlan(directory) {
23
- const binding=read(path.join(directory,'inputs/capabilities.json')).bindings.find(item=>item.id==='devices/device-list/theme');
24
- return binding?{source:'inputs/capabilities.json',bindingId:binding.id,...require('./template-contract.cjs').resolveThemeParameters(binding.parameters)}:null;
25
- }
26
- function paginationFocusPlan(directory) {
27
- const value=read(path.join(directory,'inputs/framework.json')).acceptance?.paginationFocusGuard;
28
- if(value===undefined)return false;
29
- assert.equal(value,true,'A fixed pagination focus guard cannot silently opt out');
30
- return true;
31
- }
32
-
33
- async function run(directory, options, runtime) {
34
- const { chromium } = require(runtime.modulePath);
35
- assert.ok(chromium?.launch, 'Playwright provider has no Chromium launcher');
36
- directory = path.resolve(directory);
37
- const startedAt = new Date().toISOString();
38
- const runId = `chrome-${Date.now()}`;
39
- const runRelative = `qa/runs/${runId}`;
40
- const runRoot = path.join(directory, runRelative);
41
- fs.mkdirSync(runRoot, { recursive: true });
42
- const before = lib.manifest(directory);
43
- const required = read(path.join(directory, 'inputs/acceptance.json'));
44
- const pagination = paginationPlan(directory);
45
- const themes = themePlan(directory);
46
- const checkPaginationFocus = paginationFocusPlan(directory);
47
- assert.equal(pagination.defaultPageSize, 10, 'The admin-list browser adapter requires a bound default capacity of ten; another default needs an explicit adapter');
48
- const preview = await lib.preview(directory, {});
49
- const runtimeConfig = read(path.join(preview.build.directory,'site/prototype-config.json'));
50
- const browser = await chromium.launch({ channel: options.browserChannel || process.env.PILOT_BROWSER_CHANNEL || 'chrome', headless: true }).catch(async error => { await new Promise(resolve => preview.server.close(resolve)); throw error; });
51
- const context = await browser.newContext({ viewport: { width: 1440, height: 1000 }, reducedMotion: 'no-preference' }).catch(async error => { await browser.close(); await new Promise(resolve => preview.server.close(resolve)); throw error; });
52
- await context.tracing.start({ screenshots: true, snapshots: true, sources: true });
53
- const consoleErrors = [], consoleWarnings = [], journeys = [], screenshots = [], observations = { paginationContract: pagination };
54
- const temporary = [];
55
- let traceSaved = false;
56
- const page = await context.newPage();
57
- const accessibilitySession=checkPaginationFocus?await context.newCDPSession(page):null;
58
- if(accessibilitySession)await accessibilitySession.send('Accessibility.enable');
59
- const source = path.resolve(__filename);
60
- const categoryInput = options.expectedCategories || process.env.PILOT_EXPECTED_CATEGORIES;
61
- const expectedCategories = typeof categoryInput === 'string' ? JSON.parse(categoryInput) : categoryInput || null;
62
- if (expectedCategories) assert.ok(Array.isArray(expectedCategories) && expectedCategories.length && expectedCategories.every(item => typeof item === 'string' && item.trim()), 'PILOT_EXPECTED_CATEGORIES must be a nonempty JSON string array');
63
- const prefix = 'devices/device-list/';
64
- const editor = 'devices/device-editor/';
65
- function observe(target) {
66
- target.on('pageerror', error => consoleErrors.push(error.message));
67
- target.on('console', message => {
68
- if (message.type() === 'error') consoleErrors.push(message.text());
69
- if (message.type() === 'warning') consoleWarnings.push(message.text());
70
- });
71
- }
72
- observe(page);
73
- const mark = (ids, checks) => {
74
- for (const id of ids) {
75
- assert.ok(!journeys.some(item => item.id === id), `Duplicate scenario ${id}`);
76
- journeys.push({ id, status: 'passed', checks });
77
- }
78
- };
79
- const rows = () => page.locator('tbody tr[data-row-key]');
80
- const row = id => page.locator(`tbody tr[data-row-key="device-${id}"]`);
81
- async function textContains(locator, text) { await locator.filter({ hasText: text }).first().waitFor({ state: 'visible' }); }
82
- async function assertNoHiddenFocus(target=page) {
83
- const focus=await target.evaluate(()=>{const active=document.activeElement,hidden=active?.closest('[aria-hidden="true"]');return {tag:active?.tagName,role:active?.getAttribute('role'),name:active?.getAttribute('aria-label'),hiddenAncestor:hidden?.outerHTML??null};});
84
- assert.equal(focus.hiddenAncestor,null,'Pagination retained focus within aria-hidden content');
85
- return focus;
86
- }
87
- async function verifyHiddenFocusFault() {
88
- const fault=await context.newPage(),warnings=[];
89
- try {
90
- fault.on('console',message=>{if(message.type()==='warning')warnings.push(message.text());});
91
- const session=await context.newCDPSession(fault);await session.send('Accessibility.enable');
92
- await fault.setContent('<!doctype html><button aria-hidden="true" tabindex="-1">Hidden focus fault</button>');
93
- await session.send('Accessibility.getFullAXTree');
94
- const warning=fault.waitForEvent('console',{predicate:message=>message.type()==='warning'&&message.text().includes('Blocked aria-hidden'),timeout:5000});
95
- await fault.locator('button').click();
96
- await assert.rejects(assertNoHiddenFocus(fault),/retained focus within aria-hidden/);
97
- await session.send('Accessibility.getFullAXTree');
98
- await warning;
99
- assert.ok(warnings.some(message=>message.includes('Blocked aria-hidden')),'The independent hidden-focus fault must produce the browser warning');
100
- return {rejected:true,warnings,scope:'Independent adversarial page; excluded from candidate console warnings'};
101
- } finally {await fault.close();}
102
- }
103
- async function assertSelectName(testId,label) {
104
- const control=page.getByTestId(testId),combobox=control.getByRole('combobox');
105
- assert.equal(await combobox.count(),1,`${testId}: one native combobox input required`);
106
- const associated=await combobox.evaluate(input=>[...(input.labels??[])].map(element=>({text:element.textContent.replace(/\s+/g,' ').trim(),before:getComputedStyle(element,'::before').content})));
107
- assert.deepEqual(associated.map(item=>item.text),[label],`${testId}: visible label must associate with the native input`);
108
- const requiredMark=associated[0].before.replace(/^['"]|['"]$/g,'').trim()==='*';
109
- const escaped=label.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
110
- const fullName=requiredMark?new RegExp(`^(?:\\*\\s*)?${escaped}$`):label;
111
- assert.equal(await control.getByRole('combobox',{name:fullName,exact:true}).count(),1,`${testId}: complete accessible name must match its label and actual required marker`);
112
- (observations.selectNames??=[]).push({control:testId,label,requiredMark,snapshot:await combobox.ariaSnapshot()});
113
- }
114
- async function screenshot(name, target = page) {
115
- const relative = `${runRelative}/${name}.png`;
116
- const overlayVisible = await target.locator('.ant-drawer-mask').first().isVisible();
117
- await target.screenshot({ path: path.join(directory, relative), fullPage: !overlayVisible, animations: 'allow' });
118
- screenshots.push(relative);
119
- return relative;
120
- }
121
- async function waitClosed() {
122
- await page.locator('.app-shell[data-editor-lifecycle="closed"]').waitFor();
123
- assert.equal(await page.getByTestId('editor-content').count(), 0);
124
- }
125
- async function assertVisibleCategories() {
126
- if (!expectedCategories) return;
127
- const values = await rows().locator('td:nth-child(4)').allTextContents();
128
- assert.ok(values.length && values.every(value => expectedCategories.includes(value.trim())), `Visible record category does not match fixed PRD: ${values.join(', ')}`);
129
- }
130
- async function reset() {
131
- if (await page.getByTestId('editor-content').count()) { await page.getByTestId('cancel-edit').click(); await waitClosed(); }
132
- const details = page.locator('details.demo-tools');
133
- if (!(await details.getAttribute('open'))) {
134
- if (!(await details.evaluate(element => element.open))) await details.locator('summary').click();
135
- }
136
- await page.getByTestId('reset-data').click();
137
- await textContains(page.getByTestId('success-notice'), '21');
138
- assert.equal(await rows().count(), 10);
139
- }
140
- async function motionClick(testId) {
141
- // Register before the real user action; sampling starts on the actual click event.
142
- await page.evaluate(id => {
143
- const button = document.querySelector(`[data-testid="${id}"]`);
144
- window.__pilotMotion = new Promise(resolve => {
145
- button.addEventListener('click', () => {
146
- const samples = [], start = performance.now();
147
- function sample() {
148
- const panel = document.querySelector('.ant-drawer-content-wrapper');
149
- const style = panel && getComputedStyle(panel);
150
- samples.push({ ms: performance.now() - start, exists: !!panel, content: !!document.querySelector('[data-testid="editor-content"]'), transform: style?.transform || null, width: panel?.getBoundingClientRect().width || 0 });
151
- if (performance.now() - start < 800) requestAnimationFrame(sample); else resolve(samples);
152
- }
153
- requestAnimationFrame(sample);
154
- }, { capture: true, once: true });
155
- });
156
- }, testId);
157
- await page.getByTestId(testId).click();
158
- return page.evaluate(() => window.__pilotMotion);
159
- }
160
- function assertMotion(samples, phase) {
161
- const partial = samples.filter(sample => {
162
- const match = sample.transform?.match(/^matrix\([^,]+,[^,]+,[^,]+,[^,]+,\s*([^,]+),/);
163
- const x = match ? Math.abs(Number(match[1])) : 0;
164
- return x > 1 && x < sample.width - 1;
165
- });
166
- assert.ok(partial.length >= 2, `${phase}: no multiple intermediate native transforms`);
167
- assert.ok(partial.every(sample => sample.content), `${phase}: editor was destroyed before animation completed`);
168
- if (phase === 'exit') assert.ok(samples.some(sample => !sample.content), 'exit: editor not destroyed after hidden');
169
- return { intermediateFrames: partial.length, samples };
170
- }
171
- async function assertBlur() {
172
- const actual = await page.locator('.ant-drawer-mask').evaluate(element => ({ filter: getComputedStyle(element).backdropFilter, rect: element.getBoundingClientRect().toJSON(), panel: document.querySelector('.ant-drawer-content-wrapper')?.getBoundingClientRect().toJSON(), viewport: { width: innerWidth, height: innerHeight } }));
173
- assert.match(actual.filter, /blur\((?!0(?:px)?\))[^)]+\)/, 'mask class exists but effective backdrop blur is missing');
174
- assert.ok(actual.rect.width >= 1000 && actual.rect.height >= 600, 'visible mask does not cover background');
175
- assert.ok(Math.abs(actual.rect.top) <= 1 && Math.abs(actual.rect.left) <= 1 && Math.abs(actual.rect.bottom - actual.viewport.height) <= 1 && Math.abs(actual.rect.right - actual.viewport.width) <= 1, 'mask does not cover current viewport bounds');
176
- assert.ok(actual.panel && Math.abs(actual.panel.top) <= 1 && Math.abs(actual.panel.bottom - actual.viewport.height) <= 1, 'drawer panel does not cover viewport height');
177
- return actual;
178
- }
179
- async function chooseTheme(target,id,picker='theme-picker-main') {
180
- const labels={light:'明亮',dark:'暗黑',fresh:'清新',tech:'科技'};
181
- assert.equal(await target.getByTestId(picker).getByRole('combobox',{name:'主题',exact:true}).count(),1,'The native theme combobox needs its own accessible name');
182
- await target.getByTestId(picker).click();
183
- const options=target.locator('.ant-select-dropdown:visible .ant-select-item-option');
184
- await options.first().waitFor();
185
- assert.deepEqual((await options.allTextContents()).map(text=>text.trim()),Object.values(labels),'Theme menu must show the four names without numeric aliases');
186
- await options.filter({hasText:new RegExp(`^${labels[id]}$`)}).click();
187
- await target.locator('.ant-select-dropdown:visible').waitFor({state:'hidden'});
188
- await target.waitForFunction(value=>document.documentElement.dataset.prototypeTheme===value,id);
189
- await target.evaluate(async()=>{await Promise.all(document.getAnimations().filter(animation=>animation.effect?.getTiming().iterations!==Infinity).map(animation=>animation.finished.catch(()=>{})));});
190
- }
191
- async function contrast(target) {
192
- return target.evaluate(element=>{
193
- const canvas=document.createElement('canvas'),context=canvas.getContext('2d',{willReadFrequently:true});canvas.width=canvas.height=1;
194
- function rgba(color){context.clearRect(0,0,1,1);context.fillStyle=color;context.fillRect(0,0,1,1);return [...context.getImageData(0,0,1,1).data].map((v,i)=>i===3?v/255:v);}
195
- const ancestors=[];for(let node=element;node;node=node.parentElement)ancestors.unshift(node);
196
- let background=[255,255,255];for(const node of ancestors){const value=rgba(getComputedStyle(node).backgroundColor);background=background.map((channel,i)=>value[i]*value[3]+channel*(1-value[3]));}
197
- const style=getComputedStyle(element),text=rgba(style.color),foreground=background.map((channel,i)=>text[i]*text[3]+channel*(1-text[3])),luminance=rgb=>rgb.map(v=>{v/=255;return v<=.04045?v/12.92:((v+.055)/1.055)**2.4}).reduce((sum,v,i)=>sum+v*[.2126,.7152,.0722][i],0);
198
- const a=luminance(foreground),b=luminance(background);
199
- return {color:style.color,background:background.map(Math.round),ratio:(Math.max(a,b)+.05)/(Math.min(a,b)+.05),luminance:b};
200
- });
201
- }
202
- async function verifyThemes() {
203
- if(!themes){assert.equal(await page.getByTestId('theme-picker-main').count(),0,'Unbound legacy instances must not acquire a theme menu');return;}
204
- observations.theme={contract:themes,presets:[]};
205
- const key=`${runtimeConfig.storageNamespace}:ui-theme:v1`;
206
- assert.equal(await page.getByTestId('theme-picker-main').innerText(),'明亮');
207
- await page.getByTestId('name-filter').fill('区');await page.getByTestId('query').click();
208
- assert.match(await page.locator('.ant-pagination-total-text').innerText(),/共\s*20\s*条/,'The submitted filter must exclude device-21 while retaining two pages');
209
- await page.getByRole('button',{name:'页 2',exact:true}).click();
210
- if(checkPaginationFocus)await assertNoHiddenFocus();
211
- const secondPageIds=await rows().evaluateAll(elements=>elements.map(element=>element.getAttribute('data-row-key')));
212
- assert.deepEqual(secondPageIds,Array.from({length:10},(_,index)=>`device-${index+11}`));
213
- await row(11).getByRole('checkbox').check();await page.getByTestId('edit-device-11').click();
214
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
215
- await page.getByTestId('edit-name').fill('主题切换未保存输入');
216
- const originalInput=await page.getByTestId('edit-name').elementHandle();
217
- for(const id of themes.presets){
218
- await chooseTheme(page,id,'theme-picker-editor');
219
- assert.equal(await originalInput.evaluate(element=>element.isConnected),true,'Theme switching remounted the editor');
220
- assert.equal(await page.getByTestId('edit-name').inputValue(),'主题切换未保存输入');
221
- assert.equal(await page.getByTestId('name-filter').inputValue(),'区');
222
- assert.match(await page.locator('.ant-pagination-total-text').innerText(),/共\s*20\s*条/,'Theme switching lost the submitted filter');
223
- assert.equal(await page.locator('.ant-pagination-item-active').innerText(),'2','Theme switching reset the current page');
224
- assert.deepEqual(await rows().evaluateAll(elements=>elements.map(element=>element.getAttribute('data-row-key'))),secondPageIds,'Theme switching changed visible records');
225
- assert.equal(await row(11).getByRole('checkbox').isChecked(),true,'Theme switching changed the selected identity');
226
- await textContains(page.getByTestId('selection-count'),'已选择 1 项');
227
- const samples={};
228
- for(const [name,locator]of Object.entries({heading:page.locator('h1'),description:page.locator('.page-description'),selection:page.getByTestId('selection-count'),table:row(12).locator('td').nth(2),selectedTable:row(11).locator('td').nth(2),tableHeading:page.locator('thead th').nth(2),editLink:page.getByTestId('edit-device-11'),statusTag:row(11).locator('.ant-tag'),form:page.locator('.ant-form-item-label label').first(),input:page.getByTestId('edit-name'),primaryButton:page.getByTestId('save-device')})){
229
- samples[name]=await contrast(locator);assert.ok(samples[name].ratio>=4.5,`${id} ${name}: contrast ${samples[name].ratio} below 4.5`);
230
- }
231
- await page.getByTestId('edit-name').fill('');await page.getByTestId('save-device').click();
232
- const validation=page.locator('.ant-form-item-explain-error');await validation.waitFor();
233
- samples.validation=await contrast(validation);assert.ok(samples.validation.ratio>=4.5,`${id} Form validation contrast below 4.5`);
234
- await screenshot(`theme-${id}-validation`);
235
- await page.getByTestId('edit-name').fill('主题切换未保存输入');await validation.waitFor({state:'hidden'});
236
- await page.getByTestId('edit-category').click();
237
- const popup=page.locator('.ant-select-dropdown:visible .ant-select-item-option-content').first();await popup.waitFor();
238
- await page.locator('.ant-select-dropdown:visible').evaluate(async element=>{await new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve)));await Promise.all(element.getAnimations({subtree:true}).map(animation=>animation.finished.catch(()=>{})));});
239
- samples.popup=await contrast(popup);
240
- samples.popupSurface=await contrast(page.locator('.ant-select-dropdown:visible'));
241
- samples.drawerSurface=await contrast(page.locator('.ant-drawer-body'));
242
- assert.ok(samples.popup.ratio>=4.5,`${id} popup contrast below 4.5`);
243
- const dark=['dark','tech'].includes(id);
244
- assert.ok(dark?samples.table.luminance<.15:samples.table.luminance>.7,`${id} Table surface did not follow native algorithm/tokens`);
245
- assert.ok(dark?samples.popupSurface.luminance<.15:samples.popupSurface.luminance>.7,`${id} teleported Select did not follow theme`);
246
- assert.ok(dark?samples.drawerSurface.luminance<.15:samples.drawerSurface.luminance>.7,`${id} Drawer surface did not follow theme`);
247
- await screenshot(`theme-${id}-drawer`);
248
- await page.getByTestId('edit-name').click();await page.locator('.ant-select-dropdown:visible').waitFor({state:'hidden'});
249
- const combo=page.getByTestId('theme-picker-editor').getByRole('combobox');await combo.focus();await page.keyboard.press('ArrowDown');
250
- await page.locator('.ant-select-dropdown:visible').waitFor();await page.keyboard.press('Escape');await page.locator('.ant-select-dropdown:visible').waitFor({state:'hidden'});
251
- assert.equal(await page.getByRole('dialog').evaluate(element=>element.contains(document.activeElement)),true);
252
- const picker=page.getByTestId('theme-picker-editor');
253
- const appearance=()=>picker.evaluate(async element=>{await Promise.all(element.getAnimations({subtree:true}).map(animation=>animation.finished.catch(()=>{})));const style=getComputedStyle(element),rect=element.getBoundingClientRect();return {border:style.border,shadow:style.boxShadow,outline:style.outline,outlineWidth:style.outlineWidth,outlineStyle:style.outlineStyle,width:rect.width,height:rect.height};});
254
- const focused=await appearance();await page.keyboard.press('Tab');const unfocused=await appearance();
255
- assert.ok(focused.width>5&&focused.height>5&&(focused.shadow!=='none'||(focused.outlineStyle!=='none'&&Number.parseFloat(focused.outlineWidth)>0)),`${id} theme control has no visible keyboard focus`);
256
- assert.ok(focused.border!==unfocused.border||focused.shadow!==unfocused.shadow||focused.outline!==unfocused.outline,`${id} theme focus indicator does not change on blur`);
257
- const focus={focused,unfocused};
258
- const narrowLayout=[];
259
- for(const width of [375,320]){
260
- await page.setViewportSize({width,height:850});assert.ok(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth+1));
261
- await page.locator('.ant-drawer-content-wrapper').evaluate(async element=>{await new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve)));await Promise.all(element.getAnimations({subtree:true}).map(animation=>animation.finished.catch(()=>{})));});
262
- const layout=await page.locator('.ant-drawer-content-wrapper').evaluate(element=>({panel:element.getBoundingClientRect().toJSON(),input:document.querySelector('[data-testid="edit-name"]').getBoundingClientRect().toJSON(),viewport:innerWidth}));
263
- for(const rect of [layout.panel,layout.input])assert.ok(rect.left>=-1&&rect.right<=layout.viewport+1,`${id} narrow Drawer clips controls outside the viewport`);
264
- narrowLayout.push(layout);await screenshot(`theme-${id}-${width}`);
265
- }
266
- await page.setViewportSize({width:1440,height:1000});
267
- await page.emulateMedia({reducedMotion:'reduce'});
268
- const duration=await page.locator('.ant-drawer-content-wrapper').evaluate(element=>getComputedStyle(element).transitionDuration.split(',').map(value=>parseFloat(value)*(value.trim().endsWith('ms')?1:1000)));
269
- assert.ok(duration.every(value=>value<=1),'Theme must respect reduced motion');await page.emulateMedia({reducedMotion:'no-preference'});
270
- observations.theme.presets.push({id,label:{light:'明亮',dark:'暗黑',fresh:'清新',tech:'科技'}[id],samples,focus,narrow:[375,320],narrowLayout,reducedMotion:duration});
271
- }
272
- observations.theme.statePreserved={filter:'区',filteredTotal:20,excludedIds:['device-21'],page:2,selectedIds:['device-11'],visibleIds:secondPageIds,unsavedInput:'主题切换未保存输入',inputNodeRetained:true};
273
- await page.getByTestId('cancel-edit').click();await waitClosed();assert.ok(!(await row(11).innerText()).includes('主题切换未保存输入'));
274
- for(const id of themes.presets){await chooseTheme(page,id);await screenshot(`theme-${id}-list`);}
275
- await page.reload({waitUntil:'networkidle'});await page.getByTestId('edit-device-1').waitFor();assert.equal(await page.getByTestId('theme-picker-main').innerText(),'科技','Theme preference must survive reload');
276
- const malformed=[];
277
- for(const raw of ['{','{"version":99,"themeId":"tech"}','{"version":1,"themeId":"unknown"}','{"version":1,"themeId":2}']){
278
- await page.evaluate(({key,raw})=>localStorage.setItem(key,raw),{key,raw});await page.reload({waitUntil:'networkidle'});await page.getByTestId('edit-device-1').waitFor();assert.equal(await page.getByTestId('theme-picker-main').innerText(),'明亮');malformed.push(raw);
279
- }
280
- const deniedCases=[];
281
- for(const mode of ['getter','write']){
282
- const denied=await context.newPage();observe(denied);await denied.addInitScript(mode=>{
283
- if(mode==='getter')Object.defineProperty(window,'localStorage',{get(){throw new DOMException('Storage denied','SecurityError');}});
284
- else {const original=Storage.prototype.setItem;Storage.prototype.setItem=function(key,value){if(key.endsWith(':ui-theme:v1'))throw new DOMException('Theme storage denied','QuotaExceededError');return original.call(this,key,value);};}
285
- },mode);
286
- await denied.goto(preview.url,{waitUntil:'networkidle'});await denied.getByTestId('edit-device-1').waitFor();assert.equal(await denied.getByTestId('theme-picker-main').innerText(),'明亮');
287
- await chooseTheme(denied,'dark');await denied.getByTestId('theme-storage-warning').waitFor();assert.equal(await denied.locator('tbody tr[data-row-key]').count(),10);
288
- await screenshot(`theme-denied-${mode}`,denied);await denied.reload({waitUntil:'networkidle'});await denied.getByTestId('edit-device-1').waitFor();assert.equal(await denied.getByTestId('theme-picker-main').innerText(),'明亮');await denied.close();deniedCases.push(mode);
289
- }
290
- await chooseTheme(page,'light');observations.theme.storage={key,reload:true,malformed,deniedCases};
291
- mark([`${prefix}theme/switch`],['four named native presets','Table/Form/Drawer/teleported Select follow tokens','input node, unsaved value, active filter excluding device-21, total 20, page two, exact visible records and selected identity preserved']);
292
- mark([`${prefix}theme/accessibility`],['sampled computed text contrast at least 4.5','keyboard opens and escapes theme menu inside dialog','320/375 layouts','reduced motion computed duration']);
293
- await reset();
294
- }
295
-
296
- try {
297
- // Compare actual browser response bytes against the build manifest.
298
- const requests = [];
299
- page.on('response', response => {
300
- if (!response.url().startsWith(preview.url)) return;
301
- requests.push((async () => {
302
- const relative = new URL(response.url()).pathname.replace(/^\//, '') || 'index.html';
303
- if (!preview.build.files[relative]) return;
304
- return { path: relative, url: response.url(), sha256: digest(await response.body()), status: response.status(), resourceType: response.request().resourceType() };
305
- })());
306
- });
307
- await page.goto(preview.url, { waitUntil: 'networkidle' });
308
- if(accessibilitySession)await accessibilitySession.send('Accessibility.getFullAXTree');
309
- await page.getByTestId('edit-device-1').waitFor();
310
- const responses = (await Promise.all(requests)).filter(Boolean);
311
- for (const response of responses) assert.equal(response.sha256, preview.build.files[response.path], `Loaded bytes differ: ${response.path}`);
312
- for (const extension of ['index.html', '.js', '.css', 'prototype-config.json']) assert.ok(responses.some(item => item.path.endsWith(extension)), `No actual loaded ${extension} proof`);
313
- const meta = await page.evaluate(() => window.__PROTOTYPE_META__);
314
- assert.equal(meta.candidateId, before.digest);
315
- observations.loadedResources = responses;
316
- if (options.expectedDescription) {
317
- const description = page.getByText(options.expectedDescription, { exact: true });
318
- await description.waitFor();
319
- observations.expectedDescription = await description.innerText();
320
- await screenshot('expected-description');
321
- }
322
- await reset();
323
- await assertVisibleCategories();
324
- await assertSelectName('status-filter',runtimeConfig.content?.fields?.queryStatus?.label||'运行状态');
325
- await verifyThemes();
326
-
327
- // Query combines both filters and handles no results.
328
- await page.getByTestId('name-filter').fill('北区');
329
- await page.getByTestId('status-filter').click();
330
- await page.locator('.ant-select-dropdown:visible .ant-select-item-option').filter({ hasText: '已停用' }).click();
331
- await page.getByTestId('query').click();
332
- assert.equal(await rows().count(), 2);
333
- assert.ok((await rows().allTextContents()).every(text => text.includes('北区') && text.includes('已停用')));
334
- await page.getByTestId('name-filter').fill('无此设备');
335
- await page.getByTestId('query').click();
336
- assert.equal(await rows().count(), 0);
337
- await textContains(page.getByTestId('device-table'), '暂无符合条件');
338
- mark([`${prefix}filter/query`], ['combined name/status yields two correct records', 'unmatched query yields actionable empty state']);
339
- await page.getByTestId('reset-filter').click();
340
- assert.equal(await page.getByTestId('name-filter').inputValue(), '');
341
- assert.equal(await rows().count(), 10);
342
- assert.match(await page.getByTestId('status-filter').innerText(), /全部状态/);
343
- mark([`${prefix}filter/reset`], ['clears both conditions', 'restores page one and ten records']);
344
-
345
- const checks = page.getByRole('checkbox');
346
- await checks.nth(1).check();
347
- await textContains(page.getByTestId('selection-count'), '已选择 1 项');
348
- if (options.verifyAtomicStatus === true) {
349
- const attributes = await page.getByTestId('selection-count').evaluate(element => ({ role: element.getAttribute('role'), live: element.getAttribute('aria-live'), atomic: element.getAttribute('aria-atomic'), text: element.textContent.trim() }));
350
- assert.deepEqual({ role: attributes.role, live: attributes.live, atomic: attributes.atomic }, { role: 'status', live: 'polite', atomic: 'true' });
351
- assert.match(attributes.text, /^已选择 1 项/);
352
- observations.atomicStatus = { ...attributes, scope: 'DOM accessibility semantics; speech output was not simulated' };
353
- }
354
- assert.equal(await checks.first().evaluate(element => element.indeterminate), true);
355
- await checks.first().check();
356
- await textContains(page.getByTestId('selection-count'), '已选择 10 项');
357
- assert.equal(await page.getByRole('checkbox', { checked: true }).count(), 11);
358
- await checks.first().uncheck();
359
- await textContains(page.getByTestId('selection-count'), '已选择 0 项');
360
- mark([`${prefix}selection/select-page`], ['single and partial state', 'current-page all ten', 'clear all']);
361
- await checks.nth(1).check();
362
- await page.getByRole('button', { name: '页 2', exact: true }).click();
363
- if(checkPaginationFocus){
364
- const pointer=await assertNoHiddenFocus();
365
- assert.deepEqual({tag:pointer.tag,role:pointer.role,name:pointer.name},{tag:'LI',role:'button',name:'页 2'},'Page-number pointer focus must stay on the native accessible outer control');
366
- observations.paginationFocus={pointer,fault:await verifyHiddenFocusFault()};
367
- }
368
- await textContains(page.getByTestId('selection-count'), '已选择 0 项');
369
- assert.equal(await rows().count(), 10);
370
- assert.match(await rows().first().innerText(), /DEV-011/);
371
- await assertVisibleCategories();
372
- await page.getByRole('button', { name: '页 3', exact: true }).click();
373
- if(checkPaginationFocus)await assertNoHiddenFocus();
374
- assert.equal(await rows().count(), 1);
375
- assert.match(await rows().first().innerText(), /DEV-021/);
376
- await assertVisibleCategories();
377
- assert.match(await page.locator('.ant-pagination-total-text').innerText(), /21/);
378
- mark([`${prefix}pagination/pages`], ['default capacity has three pages containing 10/10/1 records', 'correct first/middle/last IDs and total']);
379
- if (pagination.mode === 'fixed') {
380
- assert.equal(await page.locator('.ant-pagination-options').count(), 0, 'Fixed pagination must not expose a capacity changer');
381
- mark([`${prefix}pagination/page-size`], ['fixed capacity ten', 'no capacity changer']);
382
- } else {
383
- const changer = page.locator('.ant-pagination-options .ant-select');
384
- assert.equal(await changer.count(), 1, 'Adjustable pagination requires one native capacity changer');
385
- const transitions = [];
386
- for (const size of [...pagination.pageSizeOptions.filter(value => value !== pagination.defaultPageSize), pagination.defaultPageSize]) {
387
- const beforePage = Number(await page.locator('.ant-pagination-item-active').innerText());
388
- await page.getByRole('checkbox').nth(1).check();
389
- await textContains(page.getByTestId('selection-count'), '已选择 1 项');
390
- await changer.click();
391
- const options = page.locator('.ant-select-dropdown:visible .ant-select-item-option');
392
- await options.first().waitFor();
393
- const offered = (await options.allTextContents()).map(text => Number.parseInt(text.trim(), 10));
394
- assert.deepEqual([...offered].sort((a,b) => a-b), [...pagination.pageSizeOptions].sort((a,b) => a-b), 'Visible page-size options differ from the fixed binding');
395
- const desired = options.filter({ hasText: new RegExp(`^\\s*${size}(?=\\D|$)`) });
396
- assert.equal(await desired.count(), 1, `No unique native option for page size ${size}`);
397
- await desired.click();
398
- await page.locator('.ant-select-dropdown:visible').waitFor({ state: 'hidden' });
399
- await textContains(page.getByTestId('selection-count'), '已选择 0 项');
400
- const expectedRows = Math.min(size, 21);
401
- await page.waitForFunction(count => document.querySelectorAll('tbody tr[data-row-key]').length === count, expectedRows);
402
- assert.equal(Number(await page.locator('.ant-pagination-item-active').innerText()), 1, 'Capacity change must return to page one');
403
- assert.match(await rows().first().innerText(), /DEV-001/);
404
- assert.match(await page.locator('.ant-pagination-total-text').innerText(), /21/);
405
- const pages = (await page.locator('.ant-pagination-item').allTextContents()).map(text => Number(text.trim()));
406
- const totalPages = Math.ceil(21/size);
407
- assert.equal(pages[0], 1, 'Native pagination must expose its first page');
408
- assert.equal(pages.at(-1), totalPages, 'Native last-page control differs from the chosen capacity');
409
- assert.ok(pages.every((value,index) => Number.isInteger(value) && value >= 1 && value <= totalPages && (!index || value > pages[index-1])), 'Visible native page controls must be unique, ordered and in range');
410
- const observation = { requestedPageSize: size, previousPage: beforePage, activePage: 1, rows: await rows().count(), total: 21, totalPages, visiblePages: pages, selectionCleared: true, offeredOptions: offered };
411
- await assertVisibleCategories();
412
- await screenshot(`pagination-capacity-${size}`);
413
- if (size < 21) {
414
- await page.getByRole('button', { name: '页 2', exact: true }).click();
415
- assert.equal(await rows().count(), Math.min(size, 21-size));
416
- observation.secondPageRows = await rows().count();
417
- }
418
- if (totalPages > 1) await page.getByRole('button', { name: `页 ${totalPages}`, exact: true }).click();
419
- assert.equal(await rows().count(), 21-(totalPages-1)*size, 'Last-page remainder differs from the fixed data count');
420
- assert.match(await rows().first().innerText(), new RegExp(`DEV-${String((totalPages-1)*size+1).padStart(3,'0')}`));
421
- assert.match(await rows().last().innerText(), /DEV-021/);
422
- observation.lastPageRows = await rows().count();
423
- transitions.push(observation);
424
- }
425
- await page.getByRole('button', { name: '页 1', exact: true }).click();
426
- assert.equal(await rows().count(), pagination.defaultPageSize);
427
- observations.paginationSizes = { mode: pagination.mode, binding: pagination.bindingId, transitions, restoredDefault: pagination.defaultPageSize };
428
- mark([`${prefix}pagination/page-size`], ['native options equal the fixed binding', 'every declared capacity selected through the actual dropdown', 'row counts and page totals match 21 records', 'each capacity change resets page and selection', 'default capacity restored']);
429
- }
430
- await page.getByRole('checkbox').nth(1).check();
431
- await page.getByTestId('query').click();
432
- await textContains(page.getByTestId('selection-count'), '已选择 0 项');
433
- assert.equal(await rows().count(), 10);
434
- mark([`${prefix}selection/clear-on-change`], ['page change clears selection', 'query clears selection and returns page one']);
435
-
436
- assert.equal(await page.getByTestId('bulk-disable').isDisabled(), true);
437
- await row(1).getByRole('checkbox').check();
438
- await row(2).getByRole('checkbox').check();
439
- await page.getByTestId('bulk-disable').click();
440
- assert.match(await row(1).innerText(), /已停用/);
441
- assert.match(await row(2).innerText(), /已停用/);
442
- assert.match(await row(3).innerText(), /运行中/);
443
- await textContains(page.getByTestId('success-notice'), '2 台');
444
- assert.equal(await page.getByTestId('bulk-disable').isDisabled(), true);
445
- mark([`${prefix}bulk/selected-only`], ['disabled with none', 'only records one and two change', 'record three unchanged', 'affected count and selection reset']);
446
- await reset();
447
-
448
- const entry = assertMotion(await motionClick('edit-device-1'), 'entry');
449
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
450
- observations.entryMotion = entry;
451
- await assertSelectName('edit-category',runtimeConfig.content?.fields?.editCategory?.label||'设备分类');
452
- await assertSelectName('edit-status',runtimeConfig.content?.fields?.editStatus?.label||'运行状态');
453
- observations.blur = await assertBlur();
454
- if (expectedCategories) {
455
- await page.getByTestId('edit-category').click();
456
- const options = page.locator('.ant-select-dropdown:visible .ant-select-item-option');
457
- await options.first().waitFor();
458
- const actual = (await options.allTextContents()).map(value => value.trim());
459
- assert.deepEqual([...actual].sort(), [...expectedCategories].sort(), 'Editor categories do not match fixed PRD');
460
- await page.getByTestId('edit-name').click();
461
- await page.locator('.ant-select-dropdown:visible').waitFor({ state: 'hidden' });
462
- observations.businessCategoryMapping = { expected: expectedCategories, actual, verifiedAcrossThreePages: true };
463
- }
464
- await screenshot('desktop-editor-blur');
465
- const blurClip = { x: 100, y: 350, width: 300, height: 300 };
466
- const blurCropPath = `${runRelative}/background-blurred.png`;
467
- const blurred = await page.screenshot({ path: path.join(directory, blurCropPath), clip: blurClip, animations: 'allow' });
468
- screenshots.push(blurCropPath);
469
- // A class-only mask must fail the same real-style predicate.
470
- await page.locator('.ant-drawer-mask').evaluate(element => element.style.setProperty('backdrop-filter', 'none', 'important'));
471
- await assert.rejects(assertBlur(), /effective backdrop blur/);
472
- await screenshot('fault-mask-no-filter');
473
- const clearCropPath = `${runRelative}/background-no-filter.png`;
474
- const unblurred = await page.screenshot({ path: path.join(directory, clearCropPath), clip: blurClip, animations: 'allow' });
475
- screenshots.push(clearCropPath);
476
- assert.notEqual(digest(blurred), digest(unblurred), 'effective blur did not change rendered background pixels');
477
- observations.blurRenderDifference = { blurred: digest(blurred), unblurred: digest(unblurred), clip: blurClip };
478
- await page.locator('.ant-drawer-mask').evaluate(element => element.style.removeProperty('backdrop-filter'));
479
- await assertBlur();
480
- mark(['framework-mask-blur'], ['computed native blur(4px)', 'background screenshot', 'retaining class but removing effective filter is rejected']);
481
-
482
- if (options.verifyBlurValidation === true) {
483
- const name = page.getByTestId('edit-name');
484
- const item = name.locator('xpath=ancestor::div[contains(concat(" ", normalize-space(@class), " "), " ant-form-item ")][1]');
485
- const errors = item.locator('.ant-form-item-explain-error');
486
- await name.fill(' ');
487
- assert.equal(await errors.count(), 0, 'Validation ran on change before first blur');
488
- await page.getByTestId('edit-category').click();
489
- await errors.waitFor();
490
- observations.blurValidation = { beforeBlurNoError: true, afterBlurMessage: await errors.innerText() };
491
- await name.click(); await name.fill('验证有效输入');
492
- await page.getByTestId('edit-category').click();
493
- await errors.waitFor({ state: 'hidden' });
494
- await name.click();
495
- await page.locator('.ant-select-dropdown:visible').waitFor({ state: 'hidden' });
496
- }
497
- await page.getByTestId('edit-name').fill(' ');
498
- await page.getByTestId('save-device').click();
499
- await page.getByText(`请输入${meta.content?.fields.editName.label || '设备名称'}`, { exact: true }).waitFor();
500
- assert.equal(await page.getByTestId('editor-content').count(), 1);
501
- assert.equal(await page.getByTestId('edit-name').evaluate(element => document.activeElement === element), true, 'required field was not focused');
502
- assert.match(await row(1).innerText(), /北区设备 01/);
503
- mark([`${editor}edit/validation`], ['whitespace required error', 'drawer stays open', 'record unchanged']);
504
- const newName = '北区设备 01 · 浏览器验收';
505
- await page.getByTestId('edit-name').fill(newName);
506
- await page.getByTestId('fail-next-save').click();
507
- await page.getByTestId('save-device').click();
508
- await page.getByTestId('save-device').locator('.anticon-loading').waitFor();
509
- assert.equal(await page.getByTestId('edit-name').isDisabled(), true);
510
- await page.getByTestId('save-error').waitFor();
511
- assert.equal(await page.getByTestId('edit-name').inputValue(), newName);
512
- assert.doesNotMatch(await row(1).innerText(), /浏览器验收/);
513
- await page.getByTestId('save-device').click();
514
- await waitClosed();
515
- assert.match(await row(1).innerText(), /浏览器验收/);
516
- assert.match(await row(2).innerText(), /北区设备 02/);
517
- await textContains(page.getByTestId('success-notice'), 'DEV-001');
518
- mark([`${editor}edit/retry`, `${editor}edit/save`, `${editor}feedback/states`], ['submitting disables input', 'failure preserves entered name without changing record', 'retry success updates one record and reports success']);
519
-
520
- await page.getByTestId('edit-device-1').focus();
521
- await page.getByTestId('edit-device-1').press('Enter');
522
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
523
- assert.equal(await page.getByTestId('edit-name').evaluate(element => document.activeElement === element), true);
524
- observations.focusIndicators = [];
525
- const settle = target => target.evaluate(async element => { await Promise.all(element.getAnimations({ subtree: true }).map(animation => animation.finished.catch(() => {}))); });
526
- const appearance = target => target.evaluate(element => { const style = getComputedStyle(element), rect = element.getBoundingClientRect(); return { tag: element.tagName, classes: element.className, outline: style.outline, outlineStyle: style.outlineStyle, outlineWidth: style.outlineWidth, outlineColor: style.outlineColor, boxShadow: style.boxShadow, border: style.border, width: rect.width, height: rect.height }; });
527
- for (let index = 0; index < 12; index++) {
528
- const active = await page.evaluateHandle(() => document.activeElement);
529
- const target = await active.evaluateHandle(element => element.closest('.ant-select') || element);
530
- assert.equal(await active.evaluate(element => element.matches(':focus-visible')), true);
531
- await settle(target); const focused = await appearance(target);
532
- await page.keyboard.press('Tab');
533
- await settle(target); const unfocused = await appearance(target);
534
- const outline = focused.outlineStyle !== 'none' && Number.parseFloat(focused.outlineWidth) > 0 && focused.outlineColor !== 'rgba(0, 0, 0, 0)';
535
- const shadow = focused.boxShadow !== 'none' && !focused.boxShadow.startsWith('rgba(0, 0, 0, 0) ');
536
- assert.ok(focused.width > 5 && focused.height > 5 && (outline || shadow), 'No visible focus indicator on the rendered control');
537
- assert.ok(focused.outline !== unfocused.outline || focused.boxShadow !== unfocused.boxShadow || focused.border !== unfocused.border, 'Rendered focus indicator does not change on blur');
538
- observations.focusIndicators.push({ focused, unfocused });
539
- await active.dispose(); await target.dispose();
540
- assert.equal(await page.getByRole('dialog').evaluate(element => element.contains(document.activeElement)), true, 'Tab focus escaped dialog');
541
- }
542
- assert.match(await page.locator('body').evaluate(element => getComputedStyle(element).overflow), /hidden/);
543
- await page.keyboard.press('Escape');
544
- await waitClosed();
545
- assert.equal(await page.getByTestId('edit-device-1').evaluate(element => document.activeElement === element), true);
546
- assert.doesNotMatch(await page.locator('body').evaluate(element => getComputedStyle(element).overflow), /hidden/);
547
- mark(['framework-focus-scroll'], ['keyboard open', 'initial field focus', 'Tab focus trap', 'body lock', 'Escape close and opener/scroll restoration']);
548
-
549
- await page.getByTestId('edit-device-1').click();
550
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
551
- observations.exitMotion = assertMotion(await motionClick('cancel-edit'), 'exit');
552
- await waitClosed();
553
- mark([`${editor}edit/drawer-motion`, 'framework-drawer-motion'], ['multiple intermediate native entry/exit transforms', 'content survives partial exit', 'content destroyed after exit']);
554
- // Adversarial DOM mutation only: source/build bytes stay fixed.
555
- await page.getByTestId('edit-device-1').click();
556
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
557
- await page.getByTestId('cancel-edit').evaluate(element => element.addEventListener('click', () => document.querySelector('[data-testid="editor-content"]')?.remove(), { capture: true, once: true }));
558
- await assert.rejects(async () => assertMotion(await motionClick('cancel-edit'), 'exit'), /destroyed before animation/);
559
- observations.earlyUnmountFaultRejected = true;
560
- await page.reload({ waitUntil: 'networkidle' });
561
- await page.getByTestId('edit-device-1').waitFor();
562
-
563
- await reset();
564
- await page.getByTestId('show-loading').click();
565
- await page.locator('.ant-spin-spinning').waitFor();
566
- await page.getByTestId('restore-list').click();
567
- await page.getByTestId('show-empty').click();
568
- assert.equal(await rows().count(), 0);
569
- await page.getByTestId('clear-empty').click();
570
- assert.equal(await rows().count(), 10);
571
- await page.getByTestId('show-error').click();
572
- await page.getByTestId('list-error').waitFor();
573
- await page.getByTestId('retry-list').click();
574
- assert.equal(await rows().count(), 10);
575
- await page.getByTestId('reset-data').click();
576
- await textContains(page.getByTestId('success-notice'), '21');
577
- mark([`${prefix}feedback/states`, 'framework-states'], ['deterministic loading', 'empty with recovery', 'error with retry', 'success and deterministic reset']);
578
-
579
- observations.viewports = [];
580
- for (const width of [1440, 768, 375, 320]) {
581
- await page.setViewportSize({ width, height: 1000 });
582
- assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), true, `document overflow at ${width}`);
583
- await page.getByTestId('query').waitFor();
584
- await screenshot(`list-${width}`);
585
- observations.viewports.push(width);
586
- }
587
- await page.setViewportSize({ width: 1440, height: 1000 });
588
- await page.emulateMedia({ reducedMotion: 'reduce' });
589
- await page.getByTestId('edit-device-1').click();
590
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
591
- const durations = await page.locator('.ant-drawer-content-wrapper').evaluate(element => ({ transition: getComputedStyle(element).transitionDuration, animation: getComputedStyle(element).animationDuration }));
592
- const seconds = value => value.split(',').map(part => part.trim().endsWith('ms') ? Number.parseFloat(part) / 1000 : Number.parseFloat(part));
593
- assert.ok([...seconds(durations.transition), ...seconds(durations.animation)].every(value => value < .02), 'reduced motion still has long transitions');
594
- await screenshot('reduced-motion-editor');
595
- await page.getByTestId('cancel-edit').click();
596
- await waitClosed();
597
- await page.emulateMedia({ reducedMotion: 'no-preference' });
598
- observations.reducedMotion = durations;
599
- mark(['framework-responsive'], ['1440/768/375/320 screenshots and no page overflow', 'reduced-motion actual computed durations', 'close lifecycle intact']);
600
-
601
- // A second real generated build is routed under the same origin to test namespace isolation.
602
- const isolationProject = fs.mkdtempSync(path.join(os.tmpdir(), 'native-isolation-'));
603
- temporary.push(isolationProject);
604
- const authoring = lib.prepareTemplate({ project: isolationProject });
605
- const authoringFile = path.join(authoring.directory, 'index.html');
606
- let authored = fs.readFileSync(authoringFile, 'utf8');
607
- authored = authored.replace('<h1>设备管理</h1>', '<h1>模板手改资产管理</h1>')
608
- .replace('<h2 id="list-title">设备清单</h2>', '<h2 id="list-title">资产台账</h2>')
609
- .replace('<h2 id="editor-title">编辑设备</h2>', '<h2 id="editor-title">编辑资产</h2>')
610
- .replace(/(<th data-field-id="device-name">)[^<]+/, '$1资产名称')
611
- .replace('<label>设备名称 <span', '<label>资产名称 <span')
612
- .replace('data-field-id="edit-name"', 'data-field-id="edit-name" placeholder="请输入资产登记名称"')
613
- .replace(/(data-action-id="query"[^>]*>)[^<]+/, '$1检索设备')
614
- .replace(/(data-action-id="save-edit"[^>]*>)[^<]+/, '$1保存修改');
615
- if(themes)authored=authored.replace('<nav class="pagination"',`<aside data-capability-id="theme" data-capability-parameters='{"defaultTheme":"light","presets":["light","dark","fresh","tech"]}'>可选主题</aside><nav class="pagination"`);
616
- fs.writeFileSync(authoringFile, authored);
617
- require('./template-contract.cjs').syncTemplate(authoring.directory);
618
- let themeScope;
619
- if(themes){themeScope=path.join(isolationProject,'theme-scope.json');fs.writeFileSync(themeScope,JSON.stringify({schemaVersion:1,requirements:[{id:'THEME-ISOLATION',text:'同源命名主题隔离回归',source:{type:'user',reference:'native-browser/theme-isolation',statement:'Regression fixture only; verify isolated preferences'},capabilities:[{pageId:'devices',regionId:'device-list',capabilityId:'theme'}]}],exemptions:[]}));}
620
- const second = lib.createPrototype({ project: isolationProject, id: 'isolation-b', expertMode: 'template', templateRoot: authoring.directory,...(themeScope?{scope:themeScope}:{}) });
621
- // Keep the isolation fixture, dependency install and npm cache in the
622
- // agreed temporary directory; this tool never owns a user-level cache.
623
- const child = spawnSync(process.execPath, [path.join(__dirname, 'native-pilot.cjs'), 'build', second.directory, '--install'], {
624
- encoding: 'utf8', timeout: 180000, maxBuffer: 5 * 1024 * 1024,
625
- env: { ...process.env, npm_config_cache: path.join(isolationProject, '.npm-cache'), npm_config_update_notifier: 'false' },
626
- });
627
- assert.equal(child.status, 0, `Isolation build failed: ${child.stderr || child.stdout || child.error}`);
628
- const secondBuild = JSON.parse(child.stdout);
629
- const secondSite = path.join(secondBuild.directory, 'site');
630
- const mime = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json' };
631
- await context.route(`${preview.url}isolation/**`, async route => {
632
- const relative = new URL(route.request().url()).pathname.replace(/^\/isolation\/?/, '') || 'index.html';
633
- assert.ok(!relative.includes('..'));
634
- await route.fulfill({ path: path.join(secondSite, relative), contentType: mime[path.extname(relative)] || 'application/octet-stream' });
635
- });
636
- const other = await context.newPage(); observe(other);
637
- await other.goto(`${preview.url}isolation/`, { waitUntil: 'networkidle' });
638
- await other.getByTestId('edit-device-1').waitFor();
639
- assert.equal(await other.locator('h1').innerText(), '模板手改资产管理');
640
- assert.equal(await other.locator('.list-toolbar h2').innerText(), '资产台账');
641
- await other.getByRole('columnheader', { name: '资产名称', exact: true }).first().waitFor();
642
- assert.equal(await other.getByTestId('query').innerText(), '检索设备');
643
- await other.getByTestId('edit-device-1').click();
644
- await other.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
645
- await other.getByRole('dialog', { name: /编辑资产/ }).waitFor();
646
- assert.equal(await other.getByTestId('save-device').innerText(), '保存修改');
647
- assert.equal(await other.getByTestId('edit-name').getAttribute('placeholder'), '请输入资产登记名称');
648
- const projectedLabels=await other.getByTestId('edit-name').evaluate(input=>[...(input.labels??[])].map(label=>label.textContent.replace(/\s+/g,' ').trim()));
649
- assert.deepEqual(projectedLabels,['资产名称'],'Projected text must label the actual native editor input');
650
- await screenshot('edited-template-projection', other);
651
- await other.getByTestId('cancel-edit').click();
652
- await other.locator('.app-shell[data-editor-lifecycle="closed"]').waitFor();
653
- mark(['template-content-projection'], ['HTML title/list title/header/editor field/action changed before sync', 'new real generated build visibly displays each edit']);
654
- const otherMeta = await other.evaluate(() => window.__PROTOTYPE_META__);
655
- assert.notEqual(otherMeta.storageNamespace, meta.storageNamespace);
656
- await page.getByTestId('edit-device-1').click();
657
- await page.locator('.app-shell[data-editor-lifecycle="open"]').waitFor();
658
- await page.getByTestId('edit-name').fill('实例 A 独有修改');
659
- await page.getByTestId('save-device').click(); await waitClosed();
660
- await page.reload({ waitUntil: 'networkidle' });
661
- assert.match(await row(1).innerText(), /实例 A 独有修改/);
662
- await other.reload({ waitUntil: 'networkidle' });
663
- assert.match(await other.locator('tr[data-row-key="device-1"]').innerText(), /北区设备 01/);
664
- await other.locator('details summary').click();
665
- await other.getByTestId('reset-data').click();
666
- await page.reload({ waitUntil: 'networkidle' });
667
- assert.match(await row(1).innerText(), /实例 A 独有修改/);
668
- observations.instanceIsolation = { first: meta.instanceId, second: otherMeta.instanceId, sameOrigin: true, secondBuild: secondBuild.buildId };
669
- if(themes){
670
- const secondConfig=read(path.join(secondBuild.directory,'site/prototype-config.json'));
671
- assert.equal(await other.getByTestId('theme-picker-main').innerText(),'明亮');
672
- await chooseTheme(page,'tech');await chooseTheme(other,'dark');
673
- await page.reload({waitUntil:'networkidle'});await other.reload({waitUntil:'networkidle'});await page.getByTestId('edit-device-1').waitFor();await other.getByTestId('edit-device-1').waitFor();
674
- assert.equal(await page.getByTestId('theme-picker-main').innerText(),'科技');assert.equal(await other.getByTestId('theme-picker-main').innerText(),'暗黑');
675
- const firstKey=observations.theme.storage.key,secondKey=`${secondConfig.storageNamespace}:ui-theme:v1`;
676
- assert.notEqual(firstKey,secondKey);
677
- observations.theme.storage.isolation={sameOrigin:true,firstKey,secondKey,first:'tech',second:'dark',secondBuild:secondBuild.buildId};
678
- await screenshot('theme-second-instance',other);await chooseTheme(page,'light');
679
- mark([`${prefix}theme/persistence`],['preference survives reload','bad cache safely uses light','denied localStorage getter/write keeps app usable','same-origin instances independently persist tech and dark']);
680
- }
681
- await screenshot('second-instance', other);
682
- await other.close(); await reset();
683
- mark(['framework-instance-isolation'], ['two generated builds on same origin', 'different namespace', 'first instance edit survives reload', 'second instance remains seed', 'reset second does not change first']);
684
-
685
- // file:// authoring reference works with all HTTP(S) traffic blocked.
686
- const offline = await context.newPage(); observe(offline);
687
- const network = [];
688
- await offline.route(/^https?:/, route => { network.push(route.request().url()); return route.abort(); });
689
- await offline.goto(pathToFileURL(path.resolve(directory, '../../ui-templates/admin-list/index.html')).href);
690
- await offline.locator('h1').waitFor();
691
- assert.match(await offline.title(), /内容模板/);
692
- await offline.locator('[data-field-id="preview-state"]').selectOption('error');
693
- assert.match(await offline.locator('[data-preview-message]').innerText(), /失败/);
694
- assert.deepEqual(network, []);
695
- observations.offlineReference = { scheme: 'file:', externalRequests: network.length, stateSwitch: 'error' };
696
- await screenshot('offline-reference', offline); await offline.close();
697
-
698
- // Clone only the necessary candidate/build files; stale bytes are rejected without editing the real candidate.
699
- const stale = fs.mkdtempSync(path.join(os.tmpdir(), 'native-stale-')); temporary.push(stale);
700
- for (const item of ['prototype.json', 'inputs', 'requirements-map.json', 'app', 'mocks', 'design-system']) fs.cpSync(path.join(directory, item), path.join(stale, item), { recursive: true, filter: file => !file.split(path.sep).includes('node_modules') });
701
- fs.mkdirSync(path.join(stale, 'builds'), { recursive: true });
702
- fs.cpSync(preview.build.directory, path.join(stale, 'builds', preview.build.buildId), { recursive: true });
703
- fs.appendFileSync(path.join(stale, 'app/src/App.vue'), '\n<!-- changed candidate, old build -->\n');
704
- assert.throws(() => lib.verifyBuild(stale, preview.build.buildId), /old candidate|旧构建/);
705
- observations.staleBuildRejected = true;
706
-
707
- const allRequired = [...required.requiredScenarios, ...required.frameworkScenarios];
708
- for (const id of allRequired) assert.ok(journeys.some(item => item.id === id), `Required scenario has no executed assertions: ${id}`);
709
- assert.equal(lib.manifest(directory).digest, before.digest, 'Candidate changed during browser acceptance');
710
- assert.deepEqual(consoleErrors, []);
711
- assert.deepEqual(consoleWarnings, []);
712
- const trace = `${runRelative}/trace.zip`;
713
- await context.tracing.stop({ path: path.join(directory, trace) }); traceSaved = true;
714
- const report = { id: runId, status: 'passed', candidateDigest: before.digest, revision: before.revision, buildId: preview.build.buildId, buildDigest: preview.build.buildDigest, previewBaseURL: preview.url, baseUrl: preview.url, observedResources: responses, executor: options.executor || process.env.PILOT_EXECUTOR || 'prototype-native-browser', tool: `Playwright ${runtime.version}; ${options.browserChannel || process.env.PILOT_BROWSER_CHANNEL || 'chrome'} ${browser.version()}; ${os.platform()} ${os.release()}`, startedAt, completedAt: new Date().toISOString(), source, consoleErrors, consoleWarnings, journeys, screenshots, trace, viewports: observations.viewports, observations };
715
- fs.writeFileSync(path.join(runRoot, 'observations.json'), JSON.stringify(observations, null, 2));
716
- const result = lib.recordRun(directory, report);
717
- return { ...result, report: path.join(runRoot, 'report.json'), journeys: journeys.length };
718
- } catch (error) {
719
- if (!traceSaved) { await context.tracing.stop({ path: path.join(runRoot, 'failure-trace.zip') }).catch(() => {}); traceSaved = true; }
720
- await page.screenshot({ path: path.join(runRoot, 'failure.png'), fullPage: true }).catch(() => {});
721
- fs.writeFileSync(path.join(runRoot, 'failure.json'), JSON.stringify({ error: error.stack, journeys, observations, consoleErrors, consoleWarnings }, null, 2));
722
- throw error;
723
- } finally {
724
- await context.close(); await browser.close();
725
- await new Promise(resolve => preview.server.close(resolve));
726
- for (const folder of temporary) fs.rmSync(folder, { recursive: true, force: true });
727
- }
728
- }
729
-
730
- function resolvePlaywright(directory, options = {}) {
731
- const explicit = options.playwrightModule || process.env.PLAYWRIGHT_MODULE;
732
- const root = path.resolve(directory), project = path.resolve(root, '../..');
733
- const locations = require('./prototype-locations.cjs');
734
- const context = explicit ? null : locations.resolveLocations({ ...options, project });
735
- const prepared = context ? locations.toolBases(context).flatMap(([base]) => [path.join(base, 'tools/i3-prototype/playwright'), path.join(base, 'tools/i3-prototype')]) : [];
736
- const search = [...prepared, path.join(project, '.prototype-tools'), path.join(root, 'app'), root, project];
737
- // Resolve existing package directories individually: Node caches name-based
738
- // lookups, which can otherwise hide a newly prepared local tool provider.
739
- const candidates = explicit ? [explicit] : search.flatMap(base => ['playwright', 'playwright-core'].map(name => path.join(base, 'node_modules', name))).filter(file => fs.existsSync(file));
740
- const errors = [];
741
- for (const candidate of candidates) {
742
- try {
743
- const modulePath = require.resolve(candidate, { paths: search });
744
- let folder = path.dirname(modulePath), found;
745
- while (folder !== path.dirname(folder)) {
746
- const file = path.join(folder, 'package.json');
747
- if (fs.existsSync(file)) {
748
- const data = read(file);
749
- if (['playwright', 'playwright-core'].includes(data.name)) { found = { modulePath, packageRoot: folder, name: data.name, version: data.version }; break; }
750
- }
751
- folder = path.dirname(folder);
752
- }
753
- assert.ok(found, 'Provider must be an existing Playwright package');
754
- return found;
755
- } catch (error) { errors.push(error.message.split('\n')[0]); }
756
- }
757
- throw new Error(`Existing Playwright provider required / 缺少已安装浏览器模块。Use --playwright-module <existing package path> or install it only with separate authorization. ${errors.join('; ')}`);
758
- }
759
-
760
- async function main(directory, options = {}) {
761
- assert.ok(!read(path.join(directory,'prototype.json')).runtime?.contentReference,
762
- 'This regression runner targets historical device-list inputs only. Verify business acceptance.json with i3-browser-testing-with-devtools and record-run; do not reuse device scenarios.');
763
- directory = path.resolve(directory);
764
- const before = lib.manifest(directory), owner = `browser-${crypto.randomUUID()}`;
765
- // A browser run writes QA and verification metadata, so it owns this candidate
766
- // for the whole run. Competing revisions cannot race its evidence publication.
767
- lib.claim(directory, { owner, expectedRevision: before.revision, expectedDigest: before.digest });
768
- try {
769
- assert.equal(lib.inspect(directory).status, 'passed', 'Native structure must pass before browser acceptance');
770
- lib.inspectDesignReview(directory, before);
771
- const input = options.expectedCategories || process.env.PILOT_EXPECTED_CATEGORIES;
772
- if (input) {
773
- const categories = typeof input === 'string' ? JSON.parse(input) : input;
774
- assert.ok(Array.isArray(categories) && categories.length && categories.every(value => typeof value === 'string' && value.trim()), 'expectedCategories must be a nonempty JSON string array');
775
- options = { ...options, expectedCategories: categories };
776
- }
777
- return await run(directory, options, resolvePlaywright(directory, options));
778
- } finally { lib.release(directory, owner); }
779
- }
780
-
781
- if (require.main === module) {
782
- if (!process.argv[2]) { process.stderr.write('Usage: node native-browser.cjs <prototype-directory> [PLAYWRIGHT_MODULE=existing-package]\n'); process.exitCode = 1; }
783
- else main(process.argv[2]).then(result => process.stdout.write(JSON.stringify(result, null, 2) + '\n')).catch(error => { process.stderr.write(JSON.stringify({ status: 'failed', operation: 'browser', errors: [error.message] }) + '\n'); process.exitCode = 1; });
784
- }
785
- module.exports = { main, resolvePlaywright, paginationPlan, themePlan, paginationFocusPlan };