@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.
- package/CHANGELOG.md +37 -0
- package/README.md +2 -2
- package/docs/FIGMA_PIPELINE.md +12 -25
- package/docs/architecture.md +3 -5
- package/docs/features.md +8 -8
- package/install/_dev-only-files.mjs +0 -6
- package/install/claude.mjs +33 -15
- package/install/copilot.mjs +16 -14
- package/install/templates/copilot-instructions.md +3 -3
- package/package.json +1 -1
- package/pipeline/commands/{multi-agent.md → multi-agent/SKILL.md} +39 -39
- package/pipeline/commands/multi-agent/{analysis.md → analysis/SKILL.md} +18 -18
- package/pipeline/commands/multi-agent/{analysis-resolve.md → analysis-resolve/SKILL.md} +4 -4
- package/pipeline/commands/multi-agent/{autopilot.md → autopilot/SKILL.md} +4 -4
- package/pipeline/commands/multi-agent/{build-optimize.md → build-optimize/SKILL.md} +1 -1
- package/pipeline/commands/multi-agent/{channels.md → channels/SKILL.md} +12 -12
- package/pipeline/commands/multi-agent/{dev.md → dev/SKILL.md} +4 -4
- package/pipeline/commands/multi-agent/{dev-autopilot.md → dev-autopilot/SKILL.md} +4 -4
- package/pipeline/commands/multi-agent/{dev-local.md → dev-local/SKILL.md} +5 -5
- package/pipeline/commands/multi-agent/{dev-local-autopilot.md → dev-local-autopilot/SKILL.md} +4 -4
- package/pipeline/commands/multi-agent/{finish.md → finish/SKILL.md} +6 -6
- package/pipeline/commands/multi-agent/{generate.md → generate/SKILL.md} +3 -3
- package/pipeline/commands/multi-agent/{help.md → help/SKILL.md} +4 -4
- package/pipeline/commands/multi-agent/{local.md → local/SKILL.md} +5 -5
- package/pipeline/commands/multi-agent/{local-autopilot.md → local-autopilot/SKILL.md} +5 -5
- package/pipeline/commands/multi-agent/{manual-test.md → manual-test/SKILL.md} +1 -1
- package/pipeline/commands/multi-agent/refactor/SKILL.md +257 -0
- package/pipeline/commands/multi-agent/{resume.md → resume/SKILL.md} +1 -1
- package/pipeline/commands/multi-agent/{review.md → review/SKILL.md} +5 -5
- package/pipeline/commands/multi-agent/{setup.md → setup/SKILL.md} +1 -1
- package/pipeline/commands/multi-agent/{sync.md → sync/SKILL.md} +20 -58
- package/pipeline/{commands/multi-agent → multi-agent-refs}/_account-picker.md +2 -2
- package/pipeline/{commands/multi-agent → multi-agent-refs}/_dev-context.md +2 -2
- package/pipeline/{commands/multi-agent → multi-agent-refs}/_repo-picker.md +2 -2
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/android-guide.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/jira.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/wiki.md +7 -7
- package/pipeline/multi-agent-refs/component-dispatch.md +92 -0
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/cross-cli-contract.md +10 -77
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/verify-by-test.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/generate-issue.md +2 -2
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/issue-jira-triad.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/keychain.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/log-format.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/modes.md +2 -2
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/operations.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-0-init.md +10 -10
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-1-analysis.md +6 -6
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-2-planning.md +3 -3
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-3-dev.md +10 -10
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-4-review.md +8 -8
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-5-test.md +3 -3
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-6-commit.md +4 -4
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-7-report.md +6 -6
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases.md +12 -12
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/progress-contract.md +4 -4
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/swiftui-guide.md +1 -1
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/tracker-contract.md +3 -3
- package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/wiki-capture.md +4 -4
- package/pipeline/preferences-template.json +17 -1
- package/pipeline/rules/figma-pipeline.md +2 -2
- package/pipeline/schemas/prefs.schema.json +0 -34
- package/pipeline/scripts/README.md +1 -3
- package/pipeline/scripts/fixtures/install-layout.tsv +6 -5
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/phase-banner.sh +2 -2
- package/pipeline/scripts/review-scope.mjs +94 -0
- package/pipeline/scripts/scan-agent-config.sh +2 -2
- package/pipeline/scripts/smoke-agent-log-cost.sh +1 -1
- package/pipeline/scripts/smoke-agent-model-routing.sh +4 -4
- package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +2 -2
- package/pipeline/scripts/smoke-channels-approval-gate.sh +2 -2
- package/pipeline/scripts/smoke-channels-flow.sh +5 -5
- package/pipeline/scripts/smoke-clarify.sh +1 -1
- package/pipeline/scripts/smoke-commands-skills-parity.sh +3 -3
- package/pipeline/scripts/smoke-community-gates.sh +1 -1
- package/pipeline/scripts/smoke-compliance-skills.sh +2 -2
- package/pipeline/scripts/smoke-cost-summary.sh +1 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +17 -43
- package/pipeline/scripts/smoke-cross-phase-cohesion.sh +1 -1
- package/pipeline/scripts/smoke-dev-critic.sh +1 -1
- package/pipeline/scripts/smoke-diff-explain.sh +1 -1
- package/pipeline/scripts/smoke-diff-risk.sh +1 -1
- package/pipeline/scripts/smoke-evidence-gate.sh +1 -1
- package/pipeline/scripts/smoke-figma-dispatch.sh +46 -57
- package/pipeline/scripts/smoke-gate-hooks.sh +1 -1
- package/pipeline/scripts/smoke-generate-issue.sh +8 -8
- package/pipeline/scripts/smoke-handoff-contract.sh +3 -3
- package/pipeline/scripts/smoke-identity-isolation.sh +2 -2
- package/pipeline/scripts/smoke-intent-guard.sh +1 -1
- package/pipeline/scripts/smoke-issue-comment-template.sh +2 -2
- package/pipeline/scripts/smoke-issue-jira-triad.sh +4 -4
- package/pipeline/scripts/smoke-language-axis.sh +6 -6
- package/pipeline/scripts/smoke-learnings-ledger.sh +3 -3
- package/pipeline/scripts/smoke-mode-dispatch-drift.sh +16 -16
- package/pipeline/scripts/smoke-model-fallback.sh +3 -3
- package/pipeline/scripts/smoke-multi-repo-integration.sh +2 -2
- package/pipeline/scripts/smoke-multi-repo-worktree.sh +1 -1
- package/pipeline/scripts/smoke-no-token-prompt.sh +5 -5
- package/pipeline/scripts/smoke-phase-0-multi-repo.sh +1 -1
- package/pipeline/scripts/smoke-phase-6-multi.sh +1 -1
- package/pipeline/scripts/smoke-phase4-gates.sh +45 -0
- package/pipeline/scripts/smoke-plan-approval-gate.sh +5 -5
- package/pipeline/scripts/smoke-plan-todos.sh +3 -3
- package/pipeline/scripts/smoke-pr-review-actions.sh +3 -3
- package/pipeline/scripts/smoke-prefs-language.sh +1 -1
- package/pipeline/scripts/smoke-progress-contract.sh +2 -2
- package/pipeline/scripts/smoke-push-retry.sh +1 -1
- package/pipeline/scripts/smoke-repo-map.sh +2 -2
- package/pipeline/scripts/smoke-shadow-git.sh +1 -1
- package/pipeline/scripts/smoke-skill-authoring.sh +4 -9
- package/pipeline/scripts/smoke-tasklist-ordering.sh +10 -10
- package/pipeline/scripts/smoke-test-gap.sh +1 -1
- package/pipeline/scripts/smoke-token-budget.sh +1 -1
- package/pipeline/scripts/smoke-token-preflight.sh +2 -2
- package/pipeline/scripts/smoke-tracker-contract.sh +13 -13
- package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +5 -5
- package/pipeline/scripts/smoke-triage-memory.sh +2 -2
- package/pipeline/scripts/smoke-update-check.sh +1 -1
- package/pipeline/scripts/smoke-url-enrichment.sh +2 -2
- package/pipeline/scripts/smoke-validator-gates.sh +1 -1
- package/pipeline/scripts/smoke-verify-by-test.sh +3 -3
- package/pipeline/scripts/smoke-wiki-integration.sh +9 -33
- package/pipeline/scripts/smoke-work-summary.sh +1 -1
- package/pipeline/scripts/smoke-worktree-path-convention.sh +4 -4
- package/pipeline/scripts/test-integrity-gate.mjs +83 -0
- package/pipeline/scripts/uninstall.mjs +2 -2
- package/pipeline/skills/.skill-manifest.json +40 -160
- package/pipeline/skills/.skills-index.json +3 -372
- package/pipeline/skills/shared/README.md +1 -1
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +116 -51
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +8 -30
- package/pipeline/skills/shared/external/compose-components/SKILL.md +14 -14
- package/pipeline/skills/skills-index.md +2 -43
- package/pipeline/commands/multi-agent/refactor.md +0 -188
- package/pipeline/commands/multi-agent/refs/component-dispatch.md +0 -92
- package/pipeline/scripts/smoke-existing-discovery-gate.sh +0 -71
- package/pipeline/scripts/smoke-figma-android-parity.sh +0 -148
- package/pipeline/scripts/smoke-figma-credential-store.sh +0 -105
- package/pipeline/scripts/smoke-figma-cross-cli-inventory.sh +0 -177
- package/pipeline/scripts/smoke-figma-sync.sh +0 -149
- package/pipeline/scripts/smoke-sync-delegation.sh +0 -74
- package/pipeline/skills/figma-android/README.md +0 -38
- package/pipeline/skills/figma-android/figma-component-code-connect/SKILL.md +0 -62
- package/pipeline/skills/figma-android/figma-component-implement/SKILL.md +0 -158
- package/pipeline/skills/figma-android/figma-component-test/SKILL.md +0 -120
- package/pipeline/skills/figma-android/figma-component-wiki/SKILL.md +0 -35
- package/pipeline/skills/figma-android/figma-to-component/SKILL.md +0 -124
- package/pipeline/skills/figma-common/README.md +0 -64
- package/pipeline/skills/figma-common/figma-bottom-sheets/SKILL.md +0 -152
- package/pipeline/skills/figma-common/figma-cli-iterate/SKILL.md +0 -282
- package/pipeline/skills/figma-common/figma-cli-iterate-mend/SKILL.md +0 -503
- package/pipeline/skills/figma-common/figma-cli-lean-iterate/SKILL.md +0 -288
- package/pipeline/skills/figma-common/figma-cli-skip/SKILL.md +0 -362
- package/pipeline/skills/figma-common/figma-commit/COMMON_REBASE.md +0 -206
- package/pipeline/skills/figma-common/figma-commit/REVIEW.md +0 -337
- package/pipeline/skills/figma-common/figma-commit/SKILL.md +0 -216
- package/pipeline/skills/figma-common/figma-component-confluence-sync/SKILL.md +0 -223
- package/pipeline/skills/figma-common/figma-component-start/SKILL.md +0 -251
- package/pipeline/skills/figma-common/figma-component-status-update/SKILL.md +0 -78
- package/pipeline/skills/figma-common/figma-evolve-component/SKILL.md +0 -61
- package/pipeline/skills/figma-common/figma-fix/SKILL.md +0 -321
- package/pipeline/skills/figma-common/figma-form-integration/SKILL.md +0 -542
- package/pipeline/skills/figma-common/figma-issue/SKILL.md +0 -750
- package/pipeline/skills/figma-common/figma-iterate/SKILL.md +0 -208
- package/pipeline/skills/figma-common/figma-iteration-commit/SKILL.md +0 -1020
- package/pipeline/skills/figma-common/figma-mend/SKILL.md +0 -331
- package/pipeline/skills/figma-common/figma-navigation/SKILL.md +0 -156
- package/pipeline/skills/figma-common/figma-overlays/SKILL.md +0 -142
- package/pipeline/skills/figma-common/figma-price-integration/SKILL.md +0 -398
- package/pipeline/skills/figma-common/figma-remote-mcp-auth/SKILL.md +0 -104
- package/pipeline/skills/figma-common/figma-review/SKILL.md +0 -400
- package/pipeline/skills/figma-common/figma-setup/SKILL.md +0 -514
- package/pipeline/skills/figma-common/figma-setup/scripts/fetch-mcp-token.py +0 -592
- package/pipeline/skills/figma-common/figma-skip/SKILL.md +0 -129
- package/pipeline/skills/figma-common/figma-ui-patterns/SKILL.md +0 -105
- package/pipeline/skills/figma-common/figma-ui-patterns/patterns/animated-gradient-border.md +0 -116
- package/pipeline/skills/figma-common/figma-utility/SKILL.md +0 -274
- package/pipeline/skills/figma-common/figma-utility/scripts/figma-utility.py +0 -808
- package/pipeline/skills/figma-common/figma-validate/SKILL.md +0 -633
- package/pipeline/skills/figma-common/performance-iteration-commit-all/SKILL.md +0 -716
- package/pipeline/skills/figma-common/performance-review-next/SKILL.md +0 -238
- package/pipeline/skills/figma-common/performance-start/SKILL.md +0 -430
- package/pipeline/skills/figma-common/performance-swiftui/SKILL.md +0 -706
- package/pipeline/skills/figma-common/performance-tour/SKILL.md +0 -423
- package/pipeline/skills/figma-ios/REVIEW_CHECKLIST.md +0 -67
- package/pipeline/skills/figma-ios/figma-component-code-connect/SKILL.md +0 -178
- package/pipeline/skills/figma-ios/figma-component-implement/SKILL.md +0 -184
- package/pipeline/skills/figma-ios/figma-component-test/SKILL.md +0 -219
- package/pipeline/skills/figma-ios/figma-component-wiki/SKILL.md +0 -274
- package/pipeline/skills/figma-ios/figma-to-component/SKILL.md +0 -416
- package/pipeline/skills/figma-ios/figma-to-component/halt-return-protocol.md +0 -57
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-0-init.md +0 -307
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1-gathering.md +0 -119
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1.5-existing-discovery.md +0 -174
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2-orchestrator.md +0 -333
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2a-testing-identifiers.md +0 -368
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2b-localization.md +0 -393
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2c-accessibility.md +0 -617
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2d-analytics.md +0 -352
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3-orchestrator.md +0 -337
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3a-location.md +0 -206
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3b-tokens.md +0 -235
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3c-nested.md +0 -214
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3d-patterns.md +0 -902
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3e-assets.md +0 -156
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3f-utilities.md +0 -175
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3g-property-coverage.md +0 -176
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3h-variant-config.md +0 -333
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4-orchestrator.md +0 -412
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4a-configuration.md +0 -336
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4b-view.md +0 -705
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4c-documentation.md +0 -332
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4d-preview.md +0 -380
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4e-modifiers.md +0 -262
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5-orchestrator.md +0 -482
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5a-viewinspector.md +0 -274
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5b-snapshot.md +0 -636
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5c-unit.md +0 -142
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-6-code-connect.md +0 -547
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7-wiki.md +0 -39
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-confluence-generate.md +0 -659
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-wiki-generate.md +0 -580
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-8-cleanup.md +0 -51
- package/pipeline/skills/figma-ios/figma-to-component/reference/accessibility.md +0 -183
- package/pipeline/skills/figma-ios/figma-to-component/reference/analytics-events.md +0 -64
- package/pipeline/skills/figma-ios/figma-to-component/reference/code-connect.md +0 -531
- package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-api.md +0 -89
- package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-xhtml.md +0 -155
- package/pipeline/skills/figma-ios/figma-to-component/reference/figma-to-swiftui-effects.md +0 -196
- package/pipeline/skills/figma-ios/figma-to-component/reference/halt-return-protocol.md +0 -57
- package/pipeline/skills/figma-ios/figma-to-component/reference/localization-naming.md +0 -89
- package/pipeline/skills/figma-ios/figma-to-component/reference/macros.md +0 -227
- package/pipeline/skills/figma-ios/figma-to-component/reference/missing-tokens.md +0 -157
- package/pipeline/skills/figma-ios/figma-to-component/reference/orchestrator-discipline.md +0 -90
- package/pipeline/skills/figma-ios/figma-to-component/reference/registry.md +0 -116
- package/pipeline/skills/figma-ios/figma-to-component/reference/remote-mcp-script.md +0 -153
- package/pipeline/skills/figma-ios/figma-to-component/reference/rest-api-script.md +0 -130
- package/pipeline/skills/figma-ios/figma-to-component/reference/scripts-inventory.md +0 -218
- package/pipeline/skills/figma-ios/figma-to-component/reference/snapshot-testing.md +0 -188
- package/pipeline/skills/figma-ios/figma-to-component/reference/subcomponent-graph.md +0 -93
- package/pipeline/skills/figma-ios/figma-to-component/reference/testing-identifiers-naming.md +0 -98
- package/pipeline/skills/figma-ios/figma-to-component/reference/tools.md +0 -261
- package/pipeline/skills/figma-ios/figma-to-component/reference/viewinspector.md +0 -147
- package/pipeline/skills/figma-ios/figma-to-component/reference/wiki-to-confluence-mapping.md +0 -182
- package/pipeline/skills/figma-ios/figma-to-component/scripts/apply-author-login-map.py +0 -185
- package/pipeline/skills/figma-ios/figma-to-component/scripts/backfill-status.py +0 -609
- package/pipeline/skills/figma-ios/figma-to-component/scripts/build-author-registry.py +0 -332
- package/pipeline/skills/figma-ios/figma-to-component/scripts/bulk-sync-issues.py +0 -261
- package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-data-gather.py +0 -184
- package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-publish.sh +0 -188
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status-upload.py +0 -768
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status.py +0 -191
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-data-gather.py +0 -420
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-page-ids.example.json +0 -9
- package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-publish.py +0 -336
- package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-subcomponent-graph.py +0 -391
- package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-update.py +0 -292
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/__init__.py +0 -1
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/issue_sync_propagate.py +0 -93
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/registry_writer.py +0 -299
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_backfill_status.py +0 -343
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update.py +0 -206
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update_http.py +0 -149
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_phase_clis.py +0 -281
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_registry_writer.py +0 -332
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_issue.py +0 -176
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_review.py +0 -98
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue.py +0 -298
- package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue_gh.py +0 -195
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase1-gather.py +0 -1298
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase2-finalize.py +0 -228
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase3-scripts.py +0 -1089
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase4-finalize.py +0 -141
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase5-finalize.py +0 -106
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase6-finalize.py +0 -162
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase7-finalize.py +0 -105
- package/pipeline/skills/figma-ios/figma-to-component/scripts/register-icons-codeconnect.py +0 -179
- package/pipeline/skills/figma-ios/figma-to-component/scripts/remote-mcp-fetch.py +0 -260
- package/pipeline/skills/figma-ios/figma-to-component/scripts/resolve-author-logins.py +0 -260
- package/pipeline/skills/figma-ios/figma-to-component/scripts/run-uicomponents-tests.sh +0 -86
- package/pipeline/skills/figma-ios/figma-to-component/scripts/sidebar-generator.py +0 -321
- package/pipeline/skills/figma-ios/figma-to-component/scripts/update-issue-from-registry.py +0 -1470
- package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase4.sh +0 -176
- package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase6.sh +0 -147
- package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase7a.py +0 -629
- /package/pipeline/commands/multi-agent/{delete.md → delete/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{diff-explain.md → diff-explain/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{garbage-collect.md → garbage-collect/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{issue.md → issue/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{jira.md → jira/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{kill.md → kill/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{language.md → language/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{log.md → log/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{prune-logs.md → prune-logs/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{purge.md → purge/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{scan.md → scan/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{search.md → search/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{stack.md → stack/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{status.md → status/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{test.md → test/SKILL.md} +0 -0
- /package/pipeline/commands/multi-agent/{update.md → update/SKILL.md} +0 -0
- /package/pipeline/{commands/multi-agent → multi-agent-refs}/_input-parser.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/analysis-template.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/audit-guide.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/backend-guide.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/confluence.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/issue-comment.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr-review-actions.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/conventions-defaults.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/autopilot-circuit-breaker.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/dev-critic.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/external-context-injection.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/model-fallback.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/plan-todos.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/prior-fix-detection.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/repo-map.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/shadow-git.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/frontend-guide.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/knowledge.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/multi-repo-integration-build.md +0 -0
- /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/picker-contract.md +0 -0
- /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 & < > " ' &#...)
|
|
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()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|