@mmerterden/multi-agent-pipeline 11.2.0 → 11.3.1

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 (335) hide show
  1. package/CHANGELOG.md +68 -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 +39 -17
  8. package/install/copilot.mjs +22 -16
  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/lib/credential-store.sh +8 -4
  33. package/pipeline/{commands/multi-agent → multi-agent-refs}/_account-picker.md +2 -2
  34. package/pipeline/{commands/multi-agent → multi-agent-refs}/_dev-context.md +2 -2
  35. package/pipeline/{commands/multi-agent → multi-agent-refs}/_repo-picker.md +2 -2
  36. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/android-guide.md +1 -1
  37. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/jira.md +1 -1
  38. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/wiki.md +7 -7
  39. package/pipeline/multi-agent-refs/component-dispatch.md +92 -0
  40. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/cross-cli-contract.md +10 -77
  41. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/verify-by-test.md +1 -1
  42. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/generate-issue.md +2 -2
  43. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/issue-jira-triad.md +1 -1
  44. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/keychain.md +1 -1
  45. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/log-format.md +1 -1
  46. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/modes.md +2 -2
  47. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/operations.md +1 -1
  48. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-0-init.md +10 -10
  49. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-1-analysis.md +6 -6
  50. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-2-planning.md +3 -3
  51. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-3-dev.md +10 -10
  52. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-4-review.md +8 -8
  53. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-5-test.md +3 -3
  54. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-6-commit.md +4 -4
  55. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-7-report.md +6 -6
  56. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases.md +12 -12
  57. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/progress-contract.md +4 -4
  58. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/swiftui-guide.md +1 -1
  59. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/tracker-contract.md +3 -3
  60. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/wiki-capture.md +4 -4
  61. package/pipeline/preferences-template.json +17 -1
  62. package/pipeline/rules/figma-pipeline.md +2 -2
  63. package/pipeline/schemas/prefs.schema.json +0 -34
  64. package/pipeline/scripts/README.md +1 -3
  65. package/pipeline/scripts/build-skills-index.mjs +3 -6
  66. package/pipeline/scripts/eval-mine-corpus.mjs +187 -0
  67. package/pipeline/scripts/fixtures/install-layout.tsv +6 -5
  68. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  69. package/pipeline/scripts/lint-skills.mjs +26 -1
  70. package/pipeline/scripts/phase-banner.sh +2 -2
  71. package/pipeline/scripts/review-scope.mjs +94 -0
  72. package/pipeline/scripts/scan-agent-config.sh +2 -2
  73. package/pipeline/scripts/smoke-agent-log-cost.sh +1 -1
  74. package/pipeline/scripts/smoke-agent-model-routing.sh +4 -4
  75. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +2 -2
  76. package/pipeline/scripts/smoke-channels-approval-gate.sh +2 -2
  77. package/pipeline/scripts/smoke-channels-flow.sh +5 -5
  78. package/pipeline/scripts/smoke-clarify.sh +1 -1
  79. package/pipeline/scripts/smoke-commands-skills-parity.sh +3 -3
  80. package/pipeline/scripts/smoke-community-gates.sh +1 -1
  81. package/pipeline/scripts/smoke-compliance-skills.sh +2 -2
  82. package/pipeline/scripts/smoke-cost-summary.sh +1 -1
  83. package/pipeline/scripts/smoke-cross-cli-behavior.sh +17 -43
  84. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +1 -1
  85. package/pipeline/scripts/smoke-dev-critic.sh +1 -1
  86. package/pipeline/scripts/smoke-diff-explain.sh +1 -1
  87. package/pipeline/scripts/smoke-diff-risk.sh +1 -1
  88. package/pipeline/scripts/smoke-evidence-gate.sh +1 -1
  89. package/pipeline/scripts/smoke-figma-dispatch.sh +46 -57
  90. package/pipeline/scripts/smoke-gate-hooks.sh +1 -1
  91. package/pipeline/scripts/smoke-generate-issue.sh +8 -8
  92. package/pipeline/scripts/smoke-handoff-contract.sh +3 -3
  93. package/pipeline/scripts/smoke-identity-isolation.sh +2 -2
  94. package/pipeline/scripts/smoke-intent-guard.sh +1 -1
  95. package/pipeline/scripts/smoke-issue-comment-template.sh +2 -2
  96. package/pipeline/scripts/smoke-issue-jira-triad.sh +4 -4
  97. package/pipeline/scripts/smoke-language-axis.sh +6 -6
  98. package/pipeline/scripts/smoke-learnings-ledger.sh +3 -3
  99. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +16 -16
  100. package/pipeline/scripts/smoke-model-fallback.sh +3 -3
  101. package/pipeline/scripts/smoke-multi-repo-integration.sh +2 -2
  102. package/pipeline/scripts/smoke-multi-repo-worktree.sh +1 -1
  103. package/pipeline/scripts/smoke-no-token-prompt.sh +5 -5
  104. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +1 -1
  105. package/pipeline/scripts/smoke-phase-6-multi.sh +1 -1
  106. package/pipeline/scripts/smoke-phase4-gates.sh +45 -0
  107. package/pipeline/scripts/smoke-plan-approval-gate.sh +5 -5
  108. package/pipeline/scripts/smoke-plan-todos.sh +3 -3
  109. package/pipeline/scripts/smoke-pr-review-actions.sh +3 -3
  110. package/pipeline/scripts/smoke-prefs-language.sh +1 -1
  111. package/pipeline/scripts/smoke-progress-contract.sh +2 -2
  112. package/pipeline/scripts/smoke-push-retry.sh +1 -1
  113. package/pipeline/scripts/smoke-repo-map.sh +2 -2
  114. package/pipeline/scripts/smoke-shadow-git.sh +1 -1
  115. package/pipeline/scripts/smoke-skill-authoring.sh +4 -9
  116. package/pipeline/scripts/smoke-tasklist-ordering.sh +10 -10
  117. package/pipeline/scripts/smoke-test-gap.sh +1 -1
  118. package/pipeline/scripts/smoke-token-budget.sh +1 -1
  119. package/pipeline/scripts/smoke-token-preflight.sh +2 -2
  120. package/pipeline/scripts/smoke-tracker-contract.sh +13 -13
  121. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +5 -5
  122. package/pipeline/scripts/smoke-triage-memory.sh +2 -2
  123. package/pipeline/scripts/smoke-update-check.sh +1 -1
  124. package/pipeline/scripts/smoke-url-enrichment.sh +2 -2
  125. package/pipeline/scripts/smoke-validator-gates.sh +1 -1
  126. package/pipeline/scripts/smoke-verify-by-test.sh +3 -3
  127. package/pipeline/scripts/smoke-wiki-integration.sh +9 -33
  128. package/pipeline/scripts/smoke-work-summary.sh +1 -1
  129. package/pipeline/scripts/smoke-worktree-path-convention.sh +4 -4
  130. package/pipeline/scripts/test-integrity-gate.mjs +83 -0
  131. package/pipeline/scripts/uninstall.mjs +17 -6
  132. package/pipeline/skills/.skill-manifest.json +40 -160
  133. package/pipeline/skills/.skills-index.json +3 -373
  134. package/pipeline/skills/shared/README.md +1 -1
  135. package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -1
  136. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +2 -2
  137. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +3 -3
  138. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
  139. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
  140. package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
  141. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +1 -1
  142. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +116 -51
  143. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +8 -30
  144. package/pipeline/skills/shared/external/compose-components/SKILL.md +14 -14
  145. package/pipeline/skills/skills-index.md +3 -44
  146. package/pipeline/commands/multi-agent/refactor.md +0 -188
  147. package/pipeline/commands/multi-agent/refs/component-dispatch.md +0 -92
  148. package/pipeline/scripts/smoke-existing-discovery-gate.sh +0 -71
  149. package/pipeline/scripts/smoke-figma-android-parity.sh +0 -148
  150. package/pipeline/scripts/smoke-figma-credential-store.sh +0 -105
  151. package/pipeline/scripts/smoke-figma-cross-cli-inventory.sh +0 -177
  152. package/pipeline/scripts/smoke-figma-sync.sh +0 -149
  153. package/pipeline/scripts/smoke-sync-delegation.sh +0 -74
  154. package/pipeline/skills/figma-android/README.md +0 -38
  155. package/pipeline/skills/figma-android/figma-component-code-connect/SKILL.md +0 -62
  156. package/pipeline/skills/figma-android/figma-component-implement/SKILL.md +0 -158
  157. package/pipeline/skills/figma-android/figma-component-test/SKILL.md +0 -120
  158. package/pipeline/skills/figma-android/figma-component-wiki/SKILL.md +0 -35
  159. package/pipeline/skills/figma-android/figma-to-component/SKILL.md +0 -124
  160. package/pipeline/skills/figma-common/README.md +0 -64
  161. package/pipeline/skills/figma-common/figma-bottom-sheets/SKILL.md +0 -152
  162. package/pipeline/skills/figma-common/figma-cli-iterate/SKILL.md +0 -282
  163. package/pipeline/skills/figma-common/figma-cli-iterate-mend/SKILL.md +0 -503
  164. package/pipeline/skills/figma-common/figma-cli-lean-iterate/SKILL.md +0 -288
  165. package/pipeline/skills/figma-common/figma-cli-skip/SKILL.md +0 -362
  166. package/pipeline/skills/figma-common/figma-commit/COMMON_REBASE.md +0 -206
  167. package/pipeline/skills/figma-common/figma-commit/REVIEW.md +0 -337
  168. package/pipeline/skills/figma-common/figma-commit/SKILL.md +0 -216
  169. package/pipeline/skills/figma-common/figma-component-confluence-sync/SKILL.md +0 -223
  170. package/pipeline/skills/figma-common/figma-component-start/SKILL.md +0 -251
  171. package/pipeline/skills/figma-common/figma-component-status-update/SKILL.md +0 -78
  172. package/pipeline/skills/figma-common/figma-evolve-component/SKILL.md +0 -61
  173. package/pipeline/skills/figma-common/figma-fix/SKILL.md +0 -321
  174. package/pipeline/skills/figma-common/figma-form-integration/SKILL.md +0 -542
  175. package/pipeline/skills/figma-common/figma-issue/SKILL.md +0 -750
  176. package/pipeline/skills/figma-common/figma-iterate/SKILL.md +0 -208
  177. package/pipeline/skills/figma-common/figma-iteration-commit/SKILL.md +0 -1020
  178. package/pipeline/skills/figma-common/figma-mend/SKILL.md +0 -331
  179. package/pipeline/skills/figma-common/figma-navigation/SKILL.md +0 -156
  180. package/pipeline/skills/figma-common/figma-overlays/SKILL.md +0 -142
  181. package/pipeline/skills/figma-common/figma-price-integration/SKILL.md +0 -398
  182. package/pipeline/skills/figma-common/figma-remote-mcp-auth/SKILL.md +0 -104
  183. package/pipeline/skills/figma-common/figma-review/SKILL.md +0 -400
  184. package/pipeline/skills/figma-common/figma-setup/SKILL.md +0 -514
  185. package/pipeline/skills/figma-common/figma-setup/scripts/fetch-mcp-token.py +0 -592
  186. package/pipeline/skills/figma-common/figma-skip/SKILL.md +0 -129
  187. package/pipeline/skills/figma-common/figma-ui-patterns/SKILL.md +0 -105
  188. package/pipeline/skills/figma-common/figma-ui-patterns/patterns/animated-gradient-border.md +0 -116
  189. package/pipeline/skills/figma-common/figma-utility/SKILL.md +0 -274
  190. package/pipeline/skills/figma-common/figma-utility/scripts/figma-utility.py +0 -808
  191. package/pipeline/skills/figma-common/figma-validate/SKILL.md +0 -633
  192. package/pipeline/skills/figma-common/performance-iteration-commit-all/SKILL.md +0 -716
  193. package/pipeline/skills/figma-common/performance-review-next/SKILL.md +0 -238
  194. package/pipeline/skills/figma-common/performance-start/SKILL.md +0 -430
  195. package/pipeline/skills/figma-common/performance-swiftui/SKILL.md +0 -706
  196. package/pipeline/skills/figma-common/performance-tour/SKILL.md +0 -423
  197. package/pipeline/skills/figma-ios/REVIEW_CHECKLIST.md +0 -67
  198. package/pipeline/skills/figma-ios/figma-component-code-connect/SKILL.md +0 -178
  199. package/pipeline/skills/figma-ios/figma-component-implement/SKILL.md +0 -184
  200. package/pipeline/skills/figma-ios/figma-component-test/SKILL.md +0 -219
  201. package/pipeline/skills/figma-ios/figma-component-wiki/SKILL.md +0 -274
  202. package/pipeline/skills/figma-ios/figma-to-component/SKILL.md +0 -416
  203. package/pipeline/skills/figma-ios/figma-to-component/halt-return-protocol.md +0 -57
  204. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-0-init.md +0 -307
  205. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1-gathering.md +0 -119
  206. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1.5-existing-discovery.md +0 -174
  207. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2-orchestrator.md +0 -333
  208. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2a-testing-identifiers.md +0 -368
  209. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2b-localization.md +0 -393
  210. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2c-accessibility.md +0 -617
  211. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2d-analytics.md +0 -352
  212. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3-orchestrator.md +0 -337
  213. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3a-location.md +0 -206
  214. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3b-tokens.md +0 -235
  215. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3c-nested.md +0 -214
  216. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3d-patterns.md +0 -902
  217. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3e-assets.md +0 -156
  218. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3f-utilities.md +0 -175
  219. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3g-property-coverage.md +0 -176
  220. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3h-variant-config.md +0 -333
  221. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4-orchestrator.md +0 -412
  222. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4a-configuration.md +0 -336
  223. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4b-view.md +0 -705
  224. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4c-documentation.md +0 -332
  225. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4d-preview.md +0 -380
  226. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4e-modifiers.md +0 -262
  227. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5-orchestrator.md +0 -482
  228. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5a-viewinspector.md +0 -274
  229. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5b-snapshot.md +0 -636
  230. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5c-unit.md +0 -142
  231. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-6-code-connect.md +0 -547
  232. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7-wiki.md +0 -39
  233. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-confluence-generate.md +0 -659
  234. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-wiki-generate.md +0 -580
  235. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-8-cleanup.md +0 -51
  236. package/pipeline/skills/figma-ios/figma-to-component/reference/accessibility.md +0 -183
  237. package/pipeline/skills/figma-ios/figma-to-component/reference/analytics-events.md +0 -64
  238. package/pipeline/skills/figma-ios/figma-to-component/reference/code-connect.md +0 -531
  239. package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-api.md +0 -89
  240. package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-xhtml.md +0 -155
  241. package/pipeline/skills/figma-ios/figma-to-component/reference/figma-to-swiftui-effects.md +0 -196
  242. package/pipeline/skills/figma-ios/figma-to-component/reference/halt-return-protocol.md +0 -57
  243. package/pipeline/skills/figma-ios/figma-to-component/reference/localization-naming.md +0 -89
  244. package/pipeline/skills/figma-ios/figma-to-component/reference/macros.md +0 -227
  245. package/pipeline/skills/figma-ios/figma-to-component/reference/missing-tokens.md +0 -157
  246. package/pipeline/skills/figma-ios/figma-to-component/reference/orchestrator-discipline.md +0 -90
  247. package/pipeline/skills/figma-ios/figma-to-component/reference/registry.md +0 -116
  248. package/pipeline/skills/figma-ios/figma-to-component/reference/remote-mcp-script.md +0 -153
  249. package/pipeline/skills/figma-ios/figma-to-component/reference/rest-api-script.md +0 -130
  250. package/pipeline/skills/figma-ios/figma-to-component/reference/scripts-inventory.md +0 -218
  251. package/pipeline/skills/figma-ios/figma-to-component/reference/snapshot-testing.md +0 -188
  252. package/pipeline/skills/figma-ios/figma-to-component/reference/subcomponent-graph.md +0 -93
  253. package/pipeline/skills/figma-ios/figma-to-component/reference/testing-identifiers-naming.md +0 -98
  254. package/pipeline/skills/figma-ios/figma-to-component/reference/tools.md +0 -261
  255. package/pipeline/skills/figma-ios/figma-to-component/reference/viewinspector.md +0 -147
  256. package/pipeline/skills/figma-ios/figma-to-component/reference/wiki-to-confluence-mapping.md +0 -182
  257. package/pipeline/skills/figma-ios/figma-to-component/scripts/apply-author-login-map.py +0 -185
  258. package/pipeline/skills/figma-ios/figma-to-component/scripts/backfill-status.py +0 -609
  259. package/pipeline/skills/figma-ios/figma-to-component/scripts/build-author-registry.py +0 -332
  260. package/pipeline/skills/figma-ios/figma-to-component/scripts/bulk-sync-issues.py +0 -261
  261. package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-data-gather.py +0 -184
  262. package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-publish.sh +0 -188
  263. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status-upload.py +0 -768
  264. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status.py +0 -191
  265. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-data-gather.py +0 -420
  266. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-page-ids.example.json +0 -9
  267. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-publish.py +0 -336
  268. package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-subcomponent-graph.py +0 -391
  269. package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-update.py +0 -292
  270. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/__init__.py +0 -1
  271. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/issue_sync_propagate.py +0 -93
  272. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/registry_writer.py +0 -299
  273. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_backfill_status.py +0 -343
  274. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update.py +0 -206
  275. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update_http.py +0 -149
  276. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_phase_clis.py +0 -281
  277. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_registry_writer.py +0 -332
  278. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_issue.py +0 -176
  279. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_review.py +0 -98
  280. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue.py +0 -298
  281. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue_gh.py +0 -195
  282. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase1-gather.py +0 -1298
  283. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase2-finalize.py +0 -228
  284. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase3-scripts.py +0 -1089
  285. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase4-finalize.py +0 -141
  286. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase5-finalize.py +0 -106
  287. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase6-finalize.py +0 -162
  288. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase7-finalize.py +0 -105
  289. package/pipeline/skills/figma-ios/figma-to-component/scripts/register-icons-codeconnect.py +0 -179
  290. package/pipeline/skills/figma-ios/figma-to-component/scripts/remote-mcp-fetch.py +0 -260
  291. package/pipeline/skills/figma-ios/figma-to-component/scripts/resolve-author-logins.py +0 -260
  292. package/pipeline/skills/figma-ios/figma-to-component/scripts/run-uicomponents-tests.sh +0 -86
  293. package/pipeline/skills/figma-ios/figma-to-component/scripts/sidebar-generator.py +0 -321
  294. package/pipeline/skills/figma-ios/figma-to-component/scripts/update-issue-from-registry.py +0 -1470
  295. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase4.sh +0 -176
  296. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase6.sh +0 -147
  297. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase7a.py +0 -629
  298. /package/pipeline/commands/multi-agent/{delete.md → delete/SKILL.md} +0 -0
  299. /package/pipeline/commands/multi-agent/{diff-explain.md → diff-explain/SKILL.md} +0 -0
  300. /package/pipeline/commands/multi-agent/{garbage-collect.md → garbage-collect/SKILL.md} +0 -0
  301. /package/pipeline/commands/multi-agent/{issue.md → issue/SKILL.md} +0 -0
  302. /package/pipeline/commands/multi-agent/{jira.md → jira/SKILL.md} +0 -0
  303. /package/pipeline/commands/multi-agent/{kill.md → kill/SKILL.md} +0 -0
  304. /package/pipeline/commands/multi-agent/{language.md → language/SKILL.md} +0 -0
  305. /package/pipeline/commands/multi-agent/{log.md → log/SKILL.md} +0 -0
  306. /package/pipeline/commands/multi-agent/{prune-logs.md → prune-logs/SKILL.md} +0 -0
  307. /package/pipeline/commands/multi-agent/{purge.md → purge/SKILL.md} +0 -0
  308. /package/pipeline/commands/multi-agent/{scan.md → scan/SKILL.md} +0 -0
  309. /package/pipeline/commands/multi-agent/{search.md → search/SKILL.md} +0 -0
  310. /package/pipeline/commands/multi-agent/{stack.md → stack/SKILL.md} +0 -0
  311. /package/pipeline/commands/multi-agent/{status.md → status/SKILL.md} +0 -0
  312. /package/pipeline/commands/multi-agent/{test.md → test/SKILL.md} +0 -0
  313. /package/pipeline/commands/multi-agent/{update.md → update/SKILL.md} +0 -0
  314. /package/pipeline/{commands/multi-agent → multi-agent-refs}/_input-parser.md +0 -0
  315. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/analysis-template.md +0 -0
  316. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/audit-guide.md +0 -0
  317. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/backend-guide.md +0 -0
  318. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/confluence.md +0 -0
  319. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/issue-comment.md +0 -0
  320. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr-review-actions.md +0 -0
  321. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr.md +0 -0
  322. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/conventions-defaults.md +0 -0
  323. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/autopilot-circuit-breaker.md +0 -0
  324. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/dev-critic.md +0 -0
  325. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/external-context-injection.md +0 -0
  326. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/model-fallback.md +0 -0
  327. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/plan-todos.md +0 -0
  328. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/prior-fix-detection.md +0 -0
  329. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/repo-map.md +0 -0
  330. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/shadow-git.md +0 -0
  331. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/frontend-guide.md +0 -0
  332. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/knowledge.md +0 -0
  333. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/multi-repo-integration-build.md +0 -0
  334. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/picker-contract.md +0 -0
  335. /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()