@mmerterden/multi-agent-pipeline 11.2.0 → 11.3.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 (331) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +2 -2
  3. package/docs/FIGMA_PIPELINE.md +12 -25
  4. package/docs/architecture.md +3 -5
  5. package/docs/features.md +8 -8
  6. package/install/_dev-only-files.mjs +0 -6
  7. package/install/claude.mjs +33 -15
  8. package/install/copilot.mjs +16 -14
  9. package/install/templates/copilot-instructions.md +3 -3
  10. package/package.json +1 -1
  11. package/pipeline/commands/{multi-agent.md → multi-agent/SKILL.md} +39 -39
  12. package/pipeline/commands/multi-agent/{analysis.md → analysis/SKILL.md} +18 -18
  13. package/pipeline/commands/multi-agent/{analysis-resolve.md → analysis-resolve/SKILL.md} +4 -4
  14. package/pipeline/commands/multi-agent/{autopilot.md → autopilot/SKILL.md} +4 -4
  15. package/pipeline/commands/multi-agent/{build-optimize.md → build-optimize/SKILL.md} +1 -1
  16. package/pipeline/commands/multi-agent/{channels.md → channels/SKILL.md} +12 -12
  17. package/pipeline/commands/multi-agent/{dev.md → dev/SKILL.md} +4 -4
  18. package/pipeline/commands/multi-agent/{dev-autopilot.md → dev-autopilot/SKILL.md} +4 -4
  19. package/pipeline/commands/multi-agent/{dev-local.md → dev-local/SKILL.md} +5 -5
  20. package/pipeline/commands/multi-agent/{dev-local-autopilot.md → dev-local-autopilot/SKILL.md} +4 -4
  21. package/pipeline/commands/multi-agent/{finish.md → finish/SKILL.md} +6 -6
  22. package/pipeline/commands/multi-agent/{generate.md → generate/SKILL.md} +3 -3
  23. package/pipeline/commands/multi-agent/{help.md → help/SKILL.md} +4 -4
  24. package/pipeline/commands/multi-agent/{local.md → local/SKILL.md} +5 -5
  25. package/pipeline/commands/multi-agent/{local-autopilot.md → local-autopilot/SKILL.md} +5 -5
  26. package/pipeline/commands/multi-agent/{manual-test.md → manual-test/SKILL.md} +1 -1
  27. package/pipeline/commands/multi-agent/refactor/SKILL.md +257 -0
  28. package/pipeline/commands/multi-agent/{resume.md → resume/SKILL.md} +1 -1
  29. package/pipeline/commands/multi-agent/{review.md → review/SKILL.md} +5 -5
  30. package/pipeline/commands/multi-agent/{setup.md → setup/SKILL.md} +1 -1
  31. package/pipeline/commands/multi-agent/{sync.md → sync/SKILL.md} +20 -58
  32. package/pipeline/{commands/multi-agent → multi-agent-refs}/_account-picker.md +2 -2
  33. package/pipeline/{commands/multi-agent → multi-agent-refs}/_dev-context.md +2 -2
  34. package/pipeline/{commands/multi-agent → multi-agent-refs}/_repo-picker.md +2 -2
  35. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/android-guide.md +1 -1
  36. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/jira.md +1 -1
  37. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/wiki.md +7 -7
  38. package/pipeline/multi-agent-refs/component-dispatch.md +92 -0
  39. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/cross-cli-contract.md +10 -77
  40. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/verify-by-test.md +1 -1
  41. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/generate-issue.md +2 -2
  42. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/issue-jira-triad.md +1 -1
  43. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/keychain.md +1 -1
  44. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/log-format.md +1 -1
  45. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/modes.md +2 -2
  46. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/operations.md +1 -1
  47. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-0-init.md +10 -10
  48. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-1-analysis.md +6 -6
  49. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-2-planning.md +3 -3
  50. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-3-dev.md +10 -10
  51. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-4-review.md +8 -8
  52. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-5-test.md +3 -3
  53. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-6-commit.md +4 -4
  54. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-7-report.md +6 -6
  55. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases.md +12 -12
  56. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/progress-contract.md +4 -4
  57. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/swiftui-guide.md +1 -1
  58. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/tracker-contract.md +3 -3
  59. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/wiki-capture.md +4 -4
  60. package/pipeline/preferences-template.json +17 -1
  61. package/pipeline/rules/figma-pipeline.md +2 -2
  62. package/pipeline/schemas/prefs.schema.json +0 -34
  63. package/pipeline/scripts/README.md +1 -3
  64. package/pipeline/scripts/fixtures/install-layout.tsv +6 -5
  65. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  66. package/pipeline/scripts/phase-banner.sh +2 -2
  67. package/pipeline/scripts/review-scope.mjs +94 -0
  68. package/pipeline/scripts/scan-agent-config.sh +2 -2
  69. package/pipeline/scripts/smoke-agent-log-cost.sh +1 -1
  70. package/pipeline/scripts/smoke-agent-model-routing.sh +4 -4
  71. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +2 -2
  72. package/pipeline/scripts/smoke-channels-approval-gate.sh +2 -2
  73. package/pipeline/scripts/smoke-channels-flow.sh +5 -5
  74. package/pipeline/scripts/smoke-clarify.sh +1 -1
  75. package/pipeline/scripts/smoke-commands-skills-parity.sh +3 -3
  76. package/pipeline/scripts/smoke-community-gates.sh +1 -1
  77. package/pipeline/scripts/smoke-compliance-skills.sh +2 -2
  78. package/pipeline/scripts/smoke-cost-summary.sh +1 -1
  79. package/pipeline/scripts/smoke-cross-cli-behavior.sh +17 -43
  80. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +1 -1
  81. package/pipeline/scripts/smoke-dev-critic.sh +1 -1
  82. package/pipeline/scripts/smoke-diff-explain.sh +1 -1
  83. package/pipeline/scripts/smoke-diff-risk.sh +1 -1
  84. package/pipeline/scripts/smoke-evidence-gate.sh +1 -1
  85. package/pipeline/scripts/smoke-figma-dispatch.sh +46 -57
  86. package/pipeline/scripts/smoke-gate-hooks.sh +1 -1
  87. package/pipeline/scripts/smoke-generate-issue.sh +8 -8
  88. package/pipeline/scripts/smoke-handoff-contract.sh +3 -3
  89. package/pipeline/scripts/smoke-identity-isolation.sh +2 -2
  90. package/pipeline/scripts/smoke-intent-guard.sh +1 -1
  91. package/pipeline/scripts/smoke-issue-comment-template.sh +2 -2
  92. package/pipeline/scripts/smoke-issue-jira-triad.sh +4 -4
  93. package/pipeline/scripts/smoke-language-axis.sh +6 -6
  94. package/pipeline/scripts/smoke-learnings-ledger.sh +3 -3
  95. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +16 -16
  96. package/pipeline/scripts/smoke-model-fallback.sh +3 -3
  97. package/pipeline/scripts/smoke-multi-repo-integration.sh +2 -2
  98. package/pipeline/scripts/smoke-multi-repo-worktree.sh +1 -1
  99. package/pipeline/scripts/smoke-no-token-prompt.sh +5 -5
  100. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +1 -1
  101. package/pipeline/scripts/smoke-phase-6-multi.sh +1 -1
  102. package/pipeline/scripts/smoke-phase4-gates.sh +45 -0
  103. package/pipeline/scripts/smoke-plan-approval-gate.sh +5 -5
  104. package/pipeline/scripts/smoke-plan-todos.sh +3 -3
  105. package/pipeline/scripts/smoke-pr-review-actions.sh +3 -3
  106. package/pipeline/scripts/smoke-prefs-language.sh +1 -1
  107. package/pipeline/scripts/smoke-progress-contract.sh +2 -2
  108. package/pipeline/scripts/smoke-push-retry.sh +1 -1
  109. package/pipeline/scripts/smoke-repo-map.sh +2 -2
  110. package/pipeline/scripts/smoke-shadow-git.sh +1 -1
  111. package/pipeline/scripts/smoke-skill-authoring.sh +4 -9
  112. package/pipeline/scripts/smoke-tasklist-ordering.sh +10 -10
  113. package/pipeline/scripts/smoke-test-gap.sh +1 -1
  114. package/pipeline/scripts/smoke-token-budget.sh +1 -1
  115. package/pipeline/scripts/smoke-token-preflight.sh +2 -2
  116. package/pipeline/scripts/smoke-tracker-contract.sh +13 -13
  117. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +5 -5
  118. package/pipeline/scripts/smoke-triage-memory.sh +2 -2
  119. package/pipeline/scripts/smoke-update-check.sh +1 -1
  120. package/pipeline/scripts/smoke-url-enrichment.sh +2 -2
  121. package/pipeline/scripts/smoke-validator-gates.sh +1 -1
  122. package/pipeline/scripts/smoke-verify-by-test.sh +3 -3
  123. package/pipeline/scripts/smoke-wiki-integration.sh +9 -33
  124. package/pipeline/scripts/smoke-work-summary.sh +1 -1
  125. package/pipeline/scripts/smoke-worktree-path-convention.sh +4 -4
  126. package/pipeline/scripts/test-integrity-gate.mjs +83 -0
  127. package/pipeline/scripts/uninstall.mjs +2 -2
  128. package/pipeline/skills/.skill-manifest.json +40 -160
  129. package/pipeline/skills/.skills-index.json +3 -372
  130. package/pipeline/skills/shared/README.md +1 -1
  131. package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -1
  132. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +2 -2
  133. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +3 -3
  134. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
  135. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
  136. package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
  137. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +1 -1
  138. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +116 -51
  139. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +8 -30
  140. package/pipeline/skills/shared/external/compose-components/SKILL.md +14 -14
  141. package/pipeline/skills/skills-index.md +2 -43
  142. package/pipeline/commands/multi-agent/refactor.md +0 -188
  143. package/pipeline/commands/multi-agent/refs/component-dispatch.md +0 -92
  144. package/pipeline/scripts/smoke-existing-discovery-gate.sh +0 -71
  145. package/pipeline/scripts/smoke-figma-android-parity.sh +0 -148
  146. package/pipeline/scripts/smoke-figma-credential-store.sh +0 -105
  147. package/pipeline/scripts/smoke-figma-cross-cli-inventory.sh +0 -177
  148. package/pipeline/scripts/smoke-figma-sync.sh +0 -149
  149. package/pipeline/scripts/smoke-sync-delegation.sh +0 -74
  150. package/pipeline/skills/figma-android/README.md +0 -38
  151. package/pipeline/skills/figma-android/figma-component-code-connect/SKILL.md +0 -62
  152. package/pipeline/skills/figma-android/figma-component-implement/SKILL.md +0 -158
  153. package/pipeline/skills/figma-android/figma-component-test/SKILL.md +0 -120
  154. package/pipeline/skills/figma-android/figma-component-wiki/SKILL.md +0 -35
  155. package/pipeline/skills/figma-android/figma-to-component/SKILL.md +0 -124
  156. package/pipeline/skills/figma-common/README.md +0 -64
  157. package/pipeline/skills/figma-common/figma-bottom-sheets/SKILL.md +0 -152
  158. package/pipeline/skills/figma-common/figma-cli-iterate/SKILL.md +0 -282
  159. package/pipeline/skills/figma-common/figma-cli-iterate-mend/SKILL.md +0 -503
  160. package/pipeline/skills/figma-common/figma-cli-lean-iterate/SKILL.md +0 -288
  161. package/pipeline/skills/figma-common/figma-cli-skip/SKILL.md +0 -362
  162. package/pipeline/skills/figma-common/figma-commit/COMMON_REBASE.md +0 -206
  163. package/pipeline/skills/figma-common/figma-commit/REVIEW.md +0 -337
  164. package/pipeline/skills/figma-common/figma-commit/SKILL.md +0 -216
  165. package/pipeline/skills/figma-common/figma-component-confluence-sync/SKILL.md +0 -223
  166. package/pipeline/skills/figma-common/figma-component-start/SKILL.md +0 -251
  167. package/pipeline/skills/figma-common/figma-component-status-update/SKILL.md +0 -78
  168. package/pipeline/skills/figma-common/figma-evolve-component/SKILL.md +0 -61
  169. package/pipeline/skills/figma-common/figma-fix/SKILL.md +0 -321
  170. package/pipeline/skills/figma-common/figma-form-integration/SKILL.md +0 -542
  171. package/pipeline/skills/figma-common/figma-issue/SKILL.md +0 -750
  172. package/pipeline/skills/figma-common/figma-iterate/SKILL.md +0 -208
  173. package/pipeline/skills/figma-common/figma-iteration-commit/SKILL.md +0 -1020
  174. package/pipeline/skills/figma-common/figma-mend/SKILL.md +0 -331
  175. package/pipeline/skills/figma-common/figma-navigation/SKILL.md +0 -156
  176. package/pipeline/skills/figma-common/figma-overlays/SKILL.md +0 -142
  177. package/pipeline/skills/figma-common/figma-price-integration/SKILL.md +0 -398
  178. package/pipeline/skills/figma-common/figma-remote-mcp-auth/SKILL.md +0 -104
  179. package/pipeline/skills/figma-common/figma-review/SKILL.md +0 -400
  180. package/pipeline/skills/figma-common/figma-setup/SKILL.md +0 -514
  181. package/pipeline/skills/figma-common/figma-setup/scripts/fetch-mcp-token.py +0 -592
  182. package/pipeline/skills/figma-common/figma-skip/SKILL.md +0 -129
  183. package/pipeline/skills/figma-common/figma-ui-patterns/SKILL.md +0 -105
  184. package/pipeline/skills/figma-common/figma-ui-patterns/patterns/animated-gradient-border.md +0 -116
  185. package/pipeline/skills/figma-common/figma-utility/SKILL.md +0 -274
  186. package/pipeline/skills/figma-common/figma-utility/scripts/figma-utility.py +0 -808
  187. package/pipeline/skills/figma-common/figma-validate/SKILL.md +0 -633
  188. package/pipeline/skills/figma-common/performance-iteration-commit-all/SKILL.md +0 -716
  189. package/pipeline/skills/figma-common/performance-review-next/SKILL.md +0 -238
  190. package/pipeline/skills/figma-common/performance-start/SKILL.md +0 -430
  191. package/pipeline/skills/figma-common/performance-swiftui/SKILL.md +0 -706
  192. package/pipeline/skills/figma-common/performance-tour/SKILL.md +0 -423
  193. package/pipeline/skills/figma-ios/REVIEW_CHECKLIST.md +0 -67
  194. package/pipeline/skills/figma-ios/figma-component-code-connect/SKILL.md +0 -178
  195. package/pipeline/skills/figma-ios/figma-component-implement/SKILL.md +0 -184
  196. package/pipeline/skills/figma-ios/figma-component-test/SKILL.md +0 -219
  197. package/pipeline/skills/figma-ios/figma-component-wiki/SKILL.md +0 -274
  198. package/pipeline/skills/figma-ios/figma-to-component/SKILL.md +0 -416
  199. package/pipeline/skills/figma-ios/figma-to-component/halt-return-protocol.md +0 -57
  200. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-0-init.md +0 -307
  201. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1-gathering.md +0 -119
  202. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1.5-existing-discovery.md +0 -174
  203. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2-orchestrator.md +0 -333
  204. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2a-testing-identifiers.md +0 -368
  205. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2b-localization.md +0 -393
  206. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2c-accessibility.md +0 -617
  207. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2d-analytics.md +0 -352
  208. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3-orchestrator.md +0 -337
  209. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3a-location.md +0 -206
  210. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3b-tokens.md +0 -235
  211. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3c-nested.md +0 -214
  212. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3d-patterns.md +0 -902
  213. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3e-assets.md +0 -156
  214. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3f-utilities.md +0 -175
  215. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3g-property-coverage.md +0 -176
  216. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3h-variant-config.md +0 -333
  217. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4-orchestrator.md +0 -412
  218. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4a-configuration.md +0 -336
  219. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4b-view.md +0 -705
  220. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4c-documentation.md +0 -332
  221. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4d-preview.md +0 -380
  222. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4e-modifiers.md +0 -262
  223. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5-orchestrator.md +0 -482
  224. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5a-viewinspector.md +0 -274
  225. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5b-snapshot.md +0 -636
  226. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5c-unit.md +0 -142
  227. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-6-code-connect.md +0 -547
  228. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7-wiki.md +0 -39
  229. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-confluence-generate.md +0 -659
  230. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-wiki-generate.md +0 -580
  231. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-8-cleanup.md +0 -51
  232. package/pipeline/skills/figma-ios/figma-to-component/reference/accessibility.md +0 -183
  233. package/pipeline/skills/figma-ios/figma-to-component/reference/analytics-events.md +0 -64
  234. package/pipeline/skills/figma-ios/figma-to-component/reference/code-connect.md +0 -531
  235. package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-api.md +0 -89
  236. package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-xhtml.md +0 -155
  237. package/pipeline/skills/figma-ios/figma-to-component/reference/figma-to-swiftui-effects.md +0 -196
  238. package/pipeline/skills/figma-ios/figma-to-component/reference/halt-return-protocol.md +0 -57
  239. package/pipeline/skills/figma-ios/figma-to-component/reference/localization-naming.md +0 -89
  240. package/pipeline/skills/figma-ios/figma-to-component/reference/macros.md +0 -227
  241. package/pipeline/skills/figma-ios/figma-to-component/reference/missing-tokens.md +0 -157
  242. package/pipeline/skills/figma-ios/figma-to-component/reference/orchestrator-discipline.md +0 -90
  243. package/pipeline/skills/figma-ios/figma-to-component/reference/registry.md +0 -116
  244. package/pipeline/skills/figma-ios/figma-to-component/reference/remote-mcp-script.md +0 -153
  245. package/pipeline/skills/figma-ios/figma-to-component/reference/rest-api-script.md +0 -130
  246. package/pipeline/skills/figma-ios/figma-to-component/reference/scripts-inventory.md +0 -218
  247. package/pipeline/skills/figma-ios/figma-to-component/reference/snapshot-testing.md +0 -188
  248. package/pipeline/skills/figma-ios/figma-to-component/reference/subcomponent-graph.md +0 -93
  249. package/pipeline/skills/figma-ios/figma-to-component/reference/testing-identifiers-naming.md +0 -98
  250. package/pipeline/skills/figma-ios/figma-to-component/reference/tools.md +0 -261
  251. package/pipeline/skills/figma-ios/figma-to-component/reference/viewinspector.md +0 -147
  252. package/pipeline/skills/figma-ios/figma-to-component/reference/wiki-to-confluence-mapping.md +0 -182
  253. package/pipeline/skills/figma-ios/figma-to-component/scripts/apply-author-login-map.py +0 -185
  254. package/pipeline/skills/figma-ios/figma-to-component/scripts/backfill-status.py +0 -609
  255. package/pipeline/skills/figma-ios/figma-to-component/scripts/build-author-registry.py +0 -332
  256. package/pipeline/skills/figma-ios/figma-to-component/scripts/bulk-sync-issues.py +0 -261
  257. package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-data-gather.py +0 -184
  258. package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-publish.sh +0 -188
  259. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status-upload.py +0 -768
  260. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status.py +0 -191
  261. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-data-gather.py +0 -420
  262. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-page-ids.example.json +0 -9
  263. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-publish.py +0 -336
  264. package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-subcomponent-graph.py +0 -391
  265. package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-update.py +0 -292
  266. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/__init__.py +0 -1
  267. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/issue_sync_propagate.py +0 -93
  268. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/registry_writer.py +0 -299
  269. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_backfill_status.py +0 -343
  270. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update.py +0 -206
  271. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update_http.py +0 -149
  272. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_phase_clis.py +0 -281
  273. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_registry_writer.py +0 -332
  274. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_issue.py +0 -176
  275. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_review.py +0 -98
  276. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue.py +0 -298
  277. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue_gh.py +0 -195
  278. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase1-gather.py +0 -1298
  279. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase2-finalize.py +0 -228
  280. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase3-scripts.py +0 -1089
  281. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase4-finalize.py +0 -141
  282. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase5-finalize.py +0 -106
  283. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase6-finalize.py +0 -162
  284. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase7-finalize.py +0 -105
  285. package/pipeline/skills/figma-ios/figma-to-component/scripts/register-icons-codeconnect.py +0 -179
  286. package/pipeline/skills/figma-ios/figma-to-component/scripts/remote-mcp-fetch.py +0 -260
  287. package/pipeline/skills/figma-ios/figma-to-component/scripts/resolve-author-logins.py +0 -260
  288. package/pipeline/skills/figma-ios/figma-to-component/scripts/run-uicomponents-tests.sh +0 -86
  289. package/pipeline/skills/figma-ios/figma-to-component/scripts/sidebar-generator.py +0 -321
  290. package/pipeline/skills/figma-ios/figma-to-component/scripts/update-issue-from-registry.py +0 -1470
  291. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase4.sh +0 -176
  292. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase6.sh +0 -147
  293. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase7a.py +0 -629
  294. /package/pipeline/commands/multi-agent/{delete.md → delete/SKILL.md} +0 -0
  295. /package/pipeline/commands/multi-agent/{diff-explain.md → diff-explain/SKILL.md} +0 -0
  296. /package/pipeline/commands/multi-agent/{garbage-collect.md → garbage-collect/SKILL.md} +0 -0
  297. /package/pipeline/commands/multi-agent/{issue.md → issue/SKILL.md} +0 -0
  298. /package/pipeline/commands/multi-agent/{jira.md → jira/SKILL.md} +0 -0
  299. /package/pipeline/commands/multi-agent/{kill.md → kill/SKILL.md} +0 -0
  300. /package/pipeline/commands/multi-agent/{language.md → language/SKILL.md} +0 -0
  301. /package/pipeline/commands/multi-agent/{log.md → log/SKILL.md} +0 -0
  302. /package/pipeline/commands/multi-agent/{prune-logs.md → prune-logs/SKILL.md} +0 -0
  303. /package/pipeline/commands/multi-agent/{purge.md → purge/SKILL.md} +0 -0
  304. /package/pipeline/commands/multi-agent/{scan.md → scan/SKILL.md} +0 -0
  305. /package/pipeline/commands/multi-agent/{search.md → search/SKILL.md} +0 -0
  306. /package/pipeline/commands/multi-agent/{stack.md → stack/SKILL.md} +0 -0
  307. /package/pipeline/commands/multi-agent/{status.md → status/SKILL.md} +0 -0
  308. /package/pipeline/commands/multi-agent/{test.md → test/SKILL.md} +0 -0
  309. /package/pipeline/commands/multi-agent/{update.md → update/SKILL.md} +0 -0
  310. /package/pipeline/{commands/multi-agent → multi-agent-refs}/_input-parser.md +0 -0
  311. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/analysis-template.md +0 -0
  312. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/audit-guide.md +0 -0
  313. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/backend-guide.md +0 -0
  314. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/confluence.md +0 -0
  315. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/issue-comment.md +0 -0
  316. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr-review-actions.md +0 -0
  317. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr.md +0 -0
  318. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/conventions-defaults.md +0 -0
  319. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/autopilot-circuit-breaker.md +0 -0
  320. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/dev-critic.md +0 -0
  321. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/external-context-injection.md +0 -0
  322. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/model-fallback.md +0 -0
  323. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/plan-todos.md +0 -0
  324. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/prior-fix-detection.md +0 -0
  325. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/repo-map.md +0 -0
  326. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/shadow-git.md +0 -0
  327. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/frontend-guide.md +0 -0
  328. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/knowledge.md +0 -0
  329. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/multi-repo-integration-build.md +0 -0
  330. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/picker-contract.md +0 -0
  331. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/rules.md +0 -0
@@ -1,629 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Phase 7A validation script.
4
-
5
- Supports two modes:
6
- - confluence: validates Confluence XHTML (main.html + ios.html)
7
- - wiki: validates wiki markdown ({ComponentName}.md)
8
-
9
- Usage:
10
- # Confluence mode (default)
11
- python3 validate-phase7a.py \
12
- --confluence-path "path/to/confluence" \
13
- --component-name "ComponentName"
14
-
15
- # Wiki mode
16
- python3 validate-phase7a.py \
17
- --wiki-path "path/to/wiki/component" \
18
- --component-name "ComponentName" \
19
- --mode wiki
20
-
21
- Exit codes:
22
- 0 = all checks pass
23
- 1 = validation failures found (details in JSON stdout)
24
- """
25
-
26
- import argparse
27
- import json
28
- import os
29
- import re
30
- import sys
31
- from pathlib import Path
32
- from typing import Dict, List, Optional, Set, Tuple
33
-
34
-
35
- def find_image_references(html_content: str) -> List[str]:
36
- """Extract all ri:filename values from <ac:image> and <ri:attachment> tags."""
37
- return re.findall(r'ri:filename="([^"]+)"', html_content)
38
-
39
-
40
- def find_template_variables(html_content: str) -> List[str]:
41
- """Find unreplaced template variables like {ComponentName}, {DESCRIPTION}, etc."""
42
- # Match {WORD} but exclude known Confluence macro params like {printable}
43
- confluence_params = {"true", "false", "disc", "circle", "square", "none"}
44
- matches = re.findall(r"\{([A-Z][A-Za-z_]+)\}", html_content)
45
- return [f"{{{m}}}" for m in matches if m.lower() not in confluence_params]
46
-
47
-
48
- def find_html_comments(html_content: str) -> List[str]:
49
- """Find remaining HTML comments (template conditionals)."""
50
- return re.findall(r"<!--\s*(IF|END|ELSE)[^>]*-->", html_content)
51
-
52
-
53
- def find_swift_code_leaks(html_content: str) -> List[str]:
54
- """Detect Swift code patterns that shouldn't be in main.html."""
55
- patterns = [
56
- (r"import\s+UIComponents", "import UIComponents"),
57
- (r"\.accessibilityIdentifier\(", ".accessibilityIdentifier("),
58
- (r"func\s+test_", "func test_"),
59
- (r"@testable\s+import", "@testable import"),
60
- ]
61
- leaks = []
62
- for pattern, label in patterns:
63
- if re.search(pattern, html_content):
64
- leaks.append(label)
65
- return leaks
66
-
67
-
68
- def check_required_sections(html_content: str, required: List[str]) -> Tuple[List[str], List[str]]:
69
- """Check which required <h2> sections are present/missing."""
70
- present = []
71
- missing = []
72
- for section in required:
73
- if f"<h2>{section}</h2>" in html_content:
74
- present.append(section)
75
- else:
76
- missing.append(section)
77
- return present, missing
78
-
79
-
80
- def check_unescaped_ampersands(html_content: str) -> List[str]:
81
- """Find unescaped & in XML attribute values."""
82
- violations = []
83
- # Check ri:filename and ri:content-title attributes for bare &
84
- for attr in ["ri:filename", "ri:content-title"]:
85
- for match in re.finditer(rf'{attr}="([^"]*)"', html_content):
86
- value = match.group(1)
87
- # Find bare & (not &amp; &lt; &gt; &quot; &apos; &#...)
88
- if re.search(r"&(?!amp;|lt;|gt;|quot;|apos;|#)", value):
89
- violations.append(f'{attr}="{value}"')
90
- return violations
91
-
92
-
93
- def validate_snapshot_coverage(
94
- assets_dir: Path,
95
- snapshot_source_dir: Optional[str],
96
- ios_html: str,
97
- component_name: str,
98
- ) -> dict:
99
- """Validate snapshot test coverage: every variant has assets + XHTML references."""
100
- result = {
101
- "variants_found": [],
102
- "missing_assets": [],
103
- "missing_references": [],
104
- "orphan_assets": [],
105
- "rtl_variants_found": [],
106
- "rtl_missing_assets": [],
107
- "rtl_missing_references": [],
108
- }
109
-
110
- # Collect all ios_ prefixed assets
111
- ios_assets = set()
112
- if assets_dir.exists():
113
- for f in assets_dir.iterdir():
114
- if f.name.startswith("ios_") and f.name.endswith(".png"):
115
- ios_assets.add(f.name)
116
-
117
- # Extract image references from ios.html
118
- ios_refs = set(find_image_references(ios_html))
119
- ios_image_refs = {r for r in ios_refs if r.startswith("ios_")}
120
-
121
- # Determine variants from asset files
122
- # Pattern: ios_light_{variant}.png, ios_dark_{variant}.png
123
- light_variants = set()
124
- dark_variants = set()
125
- rtl_light_variants = set()
126
- rtl_dark_variants = set()
127
-
128
- for asset in ios_assets:
129
- name = asset[:-4] # strip .png
130
- if name.startswith("ios_rtl_light_"):
131
- rtl_light_variants.add(name[len("ios_rtl_light_"):])
132
- elif name.startswith("ios_rtl_dark_"):
133
- rtl_dark_variants.add(name[len("ios_rtl_dark_"):])
134
- elif name.startswith("ios_light_"):
135
- light_variants.add(name[len("ios_light_"):])
136
- elif name.startswith("ios_dark_"):
137
- dark_variants.add(name[len("ios_dark_"):])
138
-
139
- # All variants = union of light and dark
140
- all_variants = light_variants | dark_variants
141
- result["variants_found"] = sorted(all_variants)
142
-
143
- # Check each variant has both light and dark assets
144
- for variant in sorted(all_variants):
145
- light_file = f"ios_light_{variant}.png"
146
- dark_file = f"ios_dark_{variant}.png"
147
- if light_file not in ios_assets:
148
- result["missing_assets"].append(light_file)
149
- if dark_file not in ios_assets:
150
- result["missing_assets"].append(dark_file)
151
- # Check XHTML references
152
- if light_file not in ios_image_refs:
153
- result["missing_references"].append(light_file)
154
- if dark_file not in ios_image_refs:
155
- result["missing_references"].append(dark_file)
156
-
157
- # RTL variants
158
- all_rtl = rtl_light_variants | rtl_dark_variants
159
- result["rtl_variants_found"] = sorted(all_rtl)
160
-
161
- for variant in sorted(all_rtl):
162
- light_file = f"ios_rtl_light_{variant}.png"
163
- dark_file = f"ios_rtl_dark_{variant}.png"
164
- if light_file not in ios_assets:
165
- result["rtl_missing_assets"].append(light_file)
166
- if dark_file not in ios_assets:
167
- result["rtl_missing_assets"].append(dark_file)
168
- if light_file not in ios_image_refs:
169
- result["rtl_missing_references"].append(light_file)
170
- if dark_file not in ios_image_refs:
171
- result["rtl_missing_references"].append(dark_file)
172
-
173
- # Orphan check: ios_ assets not referenced in XHTML
174
- for asset in sorted(ios_assets):
175
- if asset not in ios_image_refs:
176
- result["orphan_assets"].append(asset)
177
-
178
- return result
179
-
180
-
181
- def find_wiki_image_references(md_content: str) -> List[str]:
182
- """Extract all asset filenames from wiki image syntax [[/path/assets/file.png]] or [[/path/assets/file.png|alt]]."""
183
- matches = re.findall(r'\[\[/[^|\]]*?/assets/([^|\]]+?)(?:\|[^\]]*?)?\]\]', md_content)
184
- return matches
185
-
186
-
187
- def check_required_md_sections(md_content: str, required: List[str]) -> Tuple[List[str], List[str]]:
188
- """Check which required ## sections are present/missing in markdown."""
189
- present = []
190
- missing = []
191
- for section in required:
192
- pattern = rf'^## {re.escape(section)}\s*$'
193
- if re.search(pattern, md_content, re.MULTILINE):
194
- present.append(section)
195
- else:
196
- missing.append(section)
197
- return present, missing
198
-
199
-
200
- def check_required_md_subsections(md_content: str, required: List[str]) -> Tuple[List[str], List[str]]:
201
- """Check which required ### sections are present/missing in markdown."""
202
- present = []
203
- missing = []
204
- for section in required:
205
- pattern = rf'^### {re.escape(section)}\s*$'
206
- if re.search(pattern, md_content, re.MULTILINE):
207
- present.append(section)
208
- else:
209
- missing.append(section)
210
- return present, missing
211
-
212
-
213
- def validate_wiki_snapshot_coverage(
214
- assets_dir: Path,
215
- md_content: str,
216
- component_name: str,
217
- ) -> dict:
218
- """Validate snapshot test coverage in wiki markdown."""
219
- result = {
220
- "variants_found": [],
221
- "missing_assets": [],
222
- "missing_references": [],
223
- "orphan_assets": [],
224
- "rtl_variants_found": [],
225
- "rtl_missing_assets": [],
226
- "rtl_missing_references": [],
227
- }
228
-
229
- ios_assets = set()
230
- if assets_dir.exists():
231
- for f in assets_dir.iterdir():
232
- if f.name.startswith("ios_") and f.name.endswith(".png"):
233
- ios_assets.add(f.name)
234
-
235
- md_refs = set(find_wiki_image_references(md_content))
236
- ios_image_refs = {r for r in md_refs if r.startswith("ios_")}
237
-
238
- light_variants = set()
239
- dark_variants = set()
240
- rtl_light_variants = set()
241
- rtl_dark_variants = set()
242
-
243
- for asset in ios_assets:
244
- name = asset[:-4]
245
- if name.startswith("ios_rtl_light_"):
246
- rtl_light_variants.add(name[len("ios_rtl_light_"):])
247
- elif name.startswith("ios_rtl_dark_"):
248
- rtl_dark_variants.add(name[len("ios_rtl_dark_"):])
249
- elif name.startswith("ios_light_"):
250
- light_variants.add(name[len("ios_light_"):])
251
- elif name.startswith("ios_dark_"):
252
- dark_variants.add(name[len("ios_dark_"):])
253
-
254
- all_variants = light_variants | dark_variants
255
- result["variants_found"] = sorted(all_variants)
256
-
257
- for variant in sorted(all_variants):
258
- light_file = f"ios_light_{variant}.png"
259
- dark_file = f"ios_dark_{variant}.png"
260
- if light_file not in ios_assets:
261
- result["missing_assets"].append(light_file)
262
- if dark_file not in ios_assets:
263
- result["missing_assets"].append(dark_file)
264
- if light_file not in ios_image_refs:
265
- result["missing_references"].append(light_file)
266
- if dark_file not in ios_image_refs:
267
- result["missing_references"].append(dark_file)
268
-
269
- all_rtl = rtl_light_variants | rtl_dark_variants
270
- result["rtl_variants_found"] = sorted(all_rtl)
271
-
272
- for variant in sorted(all_rtl):
273
- light_file = f"ios_rtl_light_{variant}.png"
274
- dark_file = f"ios_rtl_dark_{variant}.png"
275
- if light_file not in ios_assets:
276
- result["rtl_missing_assets"].append(light_file)
277
- if dark_file not in ios_assets:
278
- result["rtl_missing_assets"].append(dark_file)
279
- if light_file not in ios_image_refs:
280
- result["rtl_missing_references"].append(light_file)
281
- if dark_file not in ios_image_refs:
282
- result["rtl_missing_references"].append(dark_file)
283
-
284
- for asset in sorted(ios_assets):
285
- if asset not in ios_image_refs:
286
- result["orphan_assets"].append(asset)
287
-
288
- return result
289
-
290
-
291
- def validate_wiki(wiki_path: Path, component_name: str) -> dict:
292
- """Validate wiki markdown documentation."""
293
- violations = []
294
- warnings = []
295
- stats = {}
296
-
297
- assets_dir = wiki_path / "assets"
298
- md_file = wiki_path / f"{component_name}.md"
299
- screenshot_file = assets_dir / "screenshot.png"
300
-
301
- if not md_file.exists():
302
- violations.append(f"{component_name}.md does not exist")
303
- return {"status": "FAIL", "violations": violations, "warnings": warnings, "stats": stats}
304
-
305
- if not screenshot_file.exists():
306
- violations.append("assets/screenshot.png does not exist")
307
-
308
- md_content = md_file.read_text(encoding="utf-8")
309
-
310
- # Required ## sections
311
- required_sections = [
312
- "Overview", "Testing Identifiers", "Localization Keys",
313
- "Accessibility", "Analytics Events", "Sub-Components",
314
- "Platform Implementations", "Changelog", "iOS Implementation",
315
- ]
316
- present, missing = check_required_md_sections(md_content, required_sections)
317
-
318
- # Allow placeholder text as alternative
319
- for section in list(missing):
320
- placeholders = {
321
- "Testing Identifiers": "No testing identifiers",
322
- "Localization Keys": "No localization keys",
323
- "Accessibility": "No dedicated accessibility keys",
324
- "Analytics Events": "No analytics events",
325
- "Sub-Components": "No nested View components",
326
- }
327
- if section in placeholders and placeholders[section] in md_content:
328
- missing.remove(section)
329
- present.append(f"{section} (placeholder)")
330
-
331
- if missing:
332
- violations.append(f"Missing sections: {missing}")
333
- stats["sections"] = len(present)
334
-
335
- # iOS subsections (under ## iOS Implementation)
336
- ios_start = md_content.find("## iOS Implementation")
337
- if ios_start >= 0:
338
- ios_content = md_content[ios_start:]
339
- ios_required = ["Initializer", "Usage"]
340
- ios_present, ios_missing = check_required_md_subsections(ios_content, ios_required)
341
- if ios_missing:
342
- violations.append(f"iOS missing subsections: {ios_missing}")
343
-
344
- has_snapshot_assets = any(
345
- f.startswith("ios_") and f.endswith(".png")
346
- for f in (os.listdir(assets_dir) if assets_dir.exists() else [])
347
- )
348
- has_snapshot_section = "## Snapshot Tests" in ios_content or "### Snapshot Tests" in md_content
349
- if has_snapshot_assets and not has_snapshot_section:
350
- violations.append("Missing Snapshot Tests section but snapshot assets exist")
351
- else:
352
- violations.append("Missing ## iOS Implementation split marker")
353
-
354
- # Template variables
355
- template_vars = find_template_variables(md_content)
356
- if template_vars:
357
- violations.append(f"Unreplaced template variables: {template_vars}")
358
-
359
- # HTML comments
360
- html_comments = find_html_comments(md_content)
361
- if html_comments:
362
- violations.append(f"Remaining template comments: {html_comments}")
363
-
364
- # Asset reference integrity
365
- md_refs = set(find_wiki_image_references(md_content))
366
- existing_assets = set()
367
- if assets_dir.exists():
368
- existing_assets = {f.name for f in assets_dir.iterdir() if f.is_file()}
369
-
370
- missing_assets = md_refs - existing_assets
371
- if missing_assets:
372
- violations.append(f"Referenced but missing from assets/: {sorted(missing_assets)}")
373
-
374
- orphan_assets = existing_assets - md_refs
375
- if orphan_assets:
376
- warnings.append(f"Assets not referenced in markdown: {sorted(orphan_assets)}")
377
-
378
- stats["assets_total"] = len(existing_assets)
379
- stats["assets_referenced"] = len(md_refs & existing_assets)
380
- stats["assets_orphaned"] = len(orphan_assets)
381
-
382
- # Snapshot coverage
383
- snapshot_result = validate_wiki_snapshot_coverage(assets_dir, md_content, component_name)
384
- stats["snapshot_variants"] = len(snapshot_result["variants_found"])
385
- stats["snapshot_rtl_variants"] = len(snapshot_result["rtl_variants_found"])
386
-
387
- if snapshot_result["missing_assets"]:
388
- violations.append(f"Snapshot variants missing asset files: {snapshot_result['missing_assets']}")
389
- if snapshot_result["missing_references"]:
390
- violations.append(f"Snapshot assets not referenced in markdown: {snapshot_result['missing_references']}")
391
- if snapshot_result["rtl_missing_assets"]:
392
- violations.append(f"RTL snapshot variants missing asset files: {snapshot_result['rtl_missing_assets']}")
393
- if snapshot_result["rtl_missing_references"]:
394
- violations.append(f"RTL snapshot assets not referenced in markdown: {snapshot_result['rtl_missing_references']}")
395
- if snapshot_result["orphan_assets"]:
396
- warnings.append(f"ios_ assets not referenced in markdown: {snapshot_result['orphan_assets']}")
397
-
398
- # Variant screenshots
399
- variant_assets = {a for a in existing_assets if not a.startswith("ios_") and a != "screenshot.png"}
400
- if variant_assets:
401
- variant_refs = {r for r in md_refs if not r.startswith("ios_") and r != "screenshot.png"}
402
- missing_variant_refs = variant_assets - variant_refs
403
- if missing_variant_refs:
404
- warnings.append(f"Variant assets not referenced in markdown: {sorted(missing_variant_refs)}")
405
- stats["variant_screenshots"] = len(variant_assets)
406
- else:
407
- stats["variant_screenshots"] = 0
408
-
409
- status = "PASS" if not violations else "FAIL"
410
- return {
411
- "status": status,
412
- "violations": violations,
413
- "warnings": warnings,
414
- "stats": stats,
415
- "snapshot_coverage": {
416
- "variants": snapshot_result["variants_found"],
417
- "rtl_variants": snapshot_result["rtl_variants_found"],
418
- "missing_assets": snapshot_result["missing_assets"],
419
- "missing_references": snapshot_result["missing_references"],
420
- },
421
- }
422
-
423
-
424
- def main():
425
- parser = argparse.ArgumentParser(description="Validate Phase 7A output (wiki or confluence)")
426
- parser.add_argument("--confluence-path", default=None, help="Path to confluence output directory")
427
- parser.add_argument("--wiki-path", default=None, help="Path to wiki component directory")
428
- parser.add_argument("--snapshot-dir", default=None, help="Path to __Snapshots__/ComponentSnapshotTests/ (optional)")
429
- parser.add_argument("--component-name", required=True, help="Component name (e.g., LabelBadge)")
430
- parser.add_argument("--mode", default="confluence", choices=["confluence", "wiki"], help="Validation mode")
431
- args = parser.parse_args()
432
-
433
- if args.mode == "wiki":
434
- if not args.wiki_path:
435
- print(json.dumps({"status": "FAIL", "violations": ["--wiki-path required for wiki mode"]}))
436
- sys.exit(1)
437
- output = validate_wiki(Path(args.wiki_path), args.component_name)
438
- print(json.dumps(output, indent=2))
439
- sys.exit(0 if output["status"] == "PASS" else 1)
440
-
441
- # Confluence mode (original behavior)
442
- if not args.confluence_path:
443
- print(json.dumps({"status": "FAIL", "violations": ["--confluence-path required for confluence mode"]}))
444
- sys.exit(1)
445
-
446
- confluence_path = Path(args.confluence_path)
447
- assets_dir = confluence_path / "assets"
448
-
449
- violations = []
450
- warnings = []
451
- stats = {}
452
-
453
- # --- 1. File existence ---
454
- main_file = confluence_path / "main.html"
455
- ios_file = confluence_path / "ios.html"
456
- screenshot_file = assets_dir / "screenshot.png"
457
-
458
- if not main_file.exists():
459
- violations.append("main.html does not exist")
460
- if not ios_file.exists():
461
- violations.append("ios.html does not exist")
462
- if not screenshot_file.exists():
463
- violations.append("assets/screenshot.png does not exist")
464
-
465
- if not main_file.exists() or not ios_file.exists():
466
- print(json.dumps({
467
- "status": "FAIL",
468
- "violations": violations,
469
- "warnings": warnings,
470
- }, indent=2))
471
- sys.exit(1)
472
-
473
- main_html = main_file.read_text(encoding="utf-8")
474
- ios_html = ios_file.read_text(encoding="utf-8")
475
-
476
- # --- 2. main.html required sections ---
477
- main_required = [
478
- "Variants", "Overview", "Testing Identifiers", "Localization Keys",
479
- "Accessibility", "Analytics Events", "Sub-Components",
480
- "Platform Implementations", "Changelog",
481
- ]
482
- main_present, main_missing = check_required_sections(main_html, main_required)
483
- # Sections can be replaced with placeholder text, check for that
484
- for section in list(main_missing):
485
- # Allow "No ..." placeholder as alternative to <h2> section
486
- placeholders = {
487
- "Testing Identifiers": "No testing identifiers",
488
- "Localization Keys": "No localization keys",
489
- "Accessibility": "No dedicated accessibility keys",
490
- "Analytics Events": "No analytics events",
491
- "Sub-Components": "No nested View components",
492
- }
493
- if section in placeholders and placeholders[section] in main_html:
494
- main_missing.remove(section)
495
- main_present.append(f"{section} (placeholder)")
496
-
497
- if main_missing:
498
- violations.append(f"main.html missing sections: {main_missing}")
499
- stats["main_sections"] = len(main_present)
500
-
501
- # --- 3. ios.html required sections ---
502
- ios_required = ["Initializer", "Usage", "Changelog"]
503
- ios_present, ios_missing = check_required_sections(ios_html, ios_required)
504
- if ios_missing:
505
- violations.append(f"ios.html missing sections: {ios_missing}")
506
-
507
- # Back-link check
508
- if "ri:content-title=" not in ios_html or "Back to" not in ios_html:
509
- violations.append("ios.html missing back-link to main page")
510
-
511
- # Snapshot Tests section (required if snapshot assets exist)
512
- has_snapshot_assets = any(
513
- f.startswith("ios_") and f.endswith(".png")
514
- for f in (os.listdir(assets_dir) if assets_dir.exists() else [])
515
- )
516
- has_snapshot_section = "<h2>Snapshot Tests</h2>" in ios_html
517
- if has_snapshot_assets and not has_snapshot_section:
518
- violations.append("ios.html missing <h2>Snapshot Tests</h2> section but snapshot assets exist")
519
- if has_snapshot_section:
520
- ios_present.append("Snapshot Tests")
521
- stats["ios_sections"] = len(ios_present)
522
-
523
- # Code Connect section (optional but tracked)
524
- if "<h2>Code Connect</h2>" in ios_html:
525
- ios_present.append("Code Connect")
526
-
527
- # --- 4. Template variables ---
528
- main_vars = find_template_variables(main_html)
529
- ios_vars = find_template_variables(ios_html)
530
- if main_vars:
531
- violations.append(f"main.html has unreplaced template variables: {main_vars}")
532
- if ios_vars:
533
- violations.append(f"ios.html has unreplaced template variables: {ios_vars}")
534
-
535
- # --- 5. HTML comments ---
536
- main_comments = find_html_comments(main_html)
537
- ios_comments = find_html_comments(ios_html)
538
- if main_comments:
539
- violations.append(f"main.html has remaining template comments: {main_comments}")
540
- if ios_comments:
541
- violations.append(f"ios.html has remaining template comments: {ios_comments}")
542
-
543
- # --- 6. Swift code leaks (main.html only) ---
544
- leaks = find_swift_code_leaks(main_html)
545
- if leaks:
546
- violations.append(f"main.html contains Swift code patterns: {leaks}")
547
-
548
- # --- 7. Unescaped ampersands ---
549
- main_amps = check_unescaped_ampersands(main_html)
550
- ios_amps = check_unescaped_ampersands(ios_html)
551
- if main_amps:
552
- violations.append(f"main.html has unescaped & in attributes: {main_amps}")
553
- if ios_amps:
554
- violations.append(f"ios.html has unescaped & in attributes: {ios_amps}")
555
-
556
- # --- 8. Asset reference integrity ---
557
- main_refs = set(find_image_references(main_html))
558
- ios_refs = set(find_image_references(ios_html))
559
- all_refs = main_refs | ios_refs
560
-
561
- existing_assets = set()
562
- if assets_dir.exists():
563
- existing_assets = {f.name for f in assets_dir.iterdir() if f.is_file()}
564
-
565
- # Referenced but missing
566
- missing_assets = all_refs - existing_assets
567
- if missing_assets:
568
- violations.append(f"Referenced in XHTML but missing from assets/: {sorted(missing_assets)}")
569
-
570
- # Existing but unreferenced (orphans)
571
- orphan_assets = existing_assets - all_refs
572
- if orphan_assets:
573
- warnings.append(f"Assets not referenced in any XHTML: {sorted(orphan_assets)}")
574
-
575
- stats["assets_total"] = len(existing_assets)
576
- stats["assets_referenced"] = len(all_refs & existing_assets)
577
- stats["assets_orphaned"] = len(orphan_assets)
578
-
579
- # --- 9. Snapshot coverage ---
580
- snapshot_result = validate_snapshot_coverage(
581
- assets_dir, args.snapshot_dir, ios_html, args.component_name
582
- )
583
- stats["snapshot_variants"] = len(snapshot_result["variants_found"])
584
- stats["snapshot_rtl_variants"] = len(snapshot_result["rtl_variants_found"])
585
-
586
- if snapshot_result["missing_assets"]:
587
- violations.append(f"Snapshot variants missing asset files: {snapshot_result['missing_assets']}")
588
- if snapshot_result["missing_references"]:
589
- violations.append(f"Snapshot assets not referenced in ios.html: {snapshot_result['missing_references']}")
590
- if snapshot_result["rtl_missing_assets"]:
591
- violations.append(f"RTL snapshot variants missing asset files: {snapshot_result['rtl_missing_assets']}")
592
- if snapshot_result["rtl_missing_references"]:
593
- violations.append(f"RTL snapshot assets not referenced in ios.html: {snapshot_result['rtl_missing_references']}")
594
- if snapshot_result["orphan_assets"]:
595
- warnings.append(f"ios_ assets not referenced in ios.html: {snapshot_result['orphan_assets']}")
596
-
597
- # --- 10. Variant section in main.html ---
598
- # If variant screenshots exist (non-ios_, non-screenshot.png), Variants section should have <ac:image>
599
- variant_assets = {a for a in existing_assets if not a.startswith("ios_") and a != "screenshot.png"}
600
- if variant_assets:
601
- variant_images_in_main = {r for r in main_refs if not r.startswith("ios_") and r != "screenshot.png"}
602
- missing_variant_refs = variant_assets - variant_images_in_main
603
- if missing_variant_refs:
604
- warnings.append(f"Variant assets not referenced in main.html: {sorted(missing_variant_refs)}")
605
- stats["variant_screenshots"] = len(variant_assets)
606
- else:
607
- stats["variant_screenshots"] = 0
608
-
609
- # --- Output ---
610
- status = "PASS" if not violations else "FAIL"
611
- output = {
612
- "status": status,
613
- "violations": violations,
614
- "warnings": warnings,
615
- "stats": stats,
616
- "snapshot_coverage": {
617
- "variants": snapshot_result["variants_found"],
618
- "rtl_variants": snapshot_result["rtl_variants_found"],
619
- "missing_assets": snapshot_result["missing_assets"],
620
- "missing_references": snapshot_result["missing_references"],
621
- },
622
- }
623
-
624
- print(json.dumps(output, indent=2))
625
- sys.exit(0 if status == "PASS" else 1)
626
-
627
-
628
- if __name__ == "__main__":
629
- main()