@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,332 +0,0 @@
1
- """Unit tests for registry_writer.py.
2
-
3
- Run: python3 -m unittest test_registry_writer.py
4
- Or: python3 test_registry_writer.py
5
-
6
- Uses tempfile for isolation - no network, no repo writes, no dependencies
7
- beyond the Python standard library.
8
- """
9
-
10
- import json
11
- import sys
12
- import tempfile
13
- import time
14
- import unittest
15
- from pathlib import Path
16
-
17
- sys.path.insert(0, str(Path(__file__).parent))
18
-
19
- from registry_writer import ( # noqa: E402
20
- FLAGS,
21
- PLATFORMS,
22
- _blank_platform_status,
23
- get_flag_state,
24
- mark_stale,
25
- set_flag,
26
- set_implemented,
27
- )
28
-
29
-
30
- class RegistryWriterTests(unittest.TestCase):
31
- def setUp(self):
32
- self.tmp = tempfile.TemporaryDirectory()
33
- self.registry_dir = Path(self.tmp.name)
34
- self.node_id = "10447:6925"
35
- self.path = self.registry_dir / "10447-6925.json"
36
-
37
- def tearDown(self):
38
- self.tmp.cleanup()
39
-
40
- def _load(self):
41
- return json.loads(self.path.read_text())
42
-
43
- def _write_seed(self, data):
44
- self.path.write_text(json.dumps(data, indent=2) + "\n")
45
-
46
- # ------------------------------------------------------------------
47
- # set_implemented
48
- # ------------------------------------------------------------------
49
-
50
- def test_set_implemented_creates_new_file(self):
51
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
52
- data = self._load()
53
- self.assertEqual(data["nodeId"], self.node_id)
54
- impl = data["status"]["ios"]["implemented"]
55
- self.assertTrue(impl["value"])
56
- self.assertEqual(impl["version"], 1)
57
- self.assertIsNotNone(impl["at"])
58
- self.assertEqual(data["updatedBy"], "phase-4-view")
59
-
60
- def test_set_implemented_creates_both_platform_blocks(self):
61
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
62
- data = self._load()
63
- # ios written, android exists but untouched
64
- self.assertTrue(data["status"]["ios"]["implemented"]["value"])
65
- self.assertFalse(data["status"]["android"]["implemented"]["value"])
66
- self.assertEqual(data["status"]["android"]["implemented"]["version"], 0)
67
-
68
- def test_set_implemented_preserves_existing_top_level_fields(self):
69
- seed = {
70
- "nodeId": self.node_id,
71
- "componentName": {"ios": "Button", "android": "Button"},
72
- "fileKey": "abc123",
73
- "skip": False,
74
- "codeConnect": {"ios": False, "android": True},
75
- "confluence": {"page": "https://x", "ios": None, "android": None},
76
- "lastUpdated": "2025-01-01",
77
- "updatedBy": "manual",
78
- "testingIdentifiers": [{"key": "foo"}],
79
- "localizationKeys": [],
80
- "accessibilityKeys": [],
81
- "analyticsEvents": [],
82
- }
83
- self._write_seed(seed)
84
-
85
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
86
- data = self._load()
87
-
88
- self.assertEqual(data["componentName"], {"ios": "Button", "android": "Button"})
89
- self.assertEqual(data["fileKey"], "abc123")
90
- self.assertEqual(data["skip"], False)
91
- self.assertEqual(data["confluence"]["page"], "https://x")
92
- self.assertEqual(data["testingIdentifiers"], [{"key": "foo"}])
93
- # Legacy codeConnect UNTOUCHED by set_implemented
94
- self.assertEqual(data["codeConnect"], {"ios": False, "android": True})
95
- # New block present
96
- self.assertTrue(data["status"]["ios"]["implemented"]["value"])
97
-
98
- def test_set_implemented_second_call_without_source_bumps(self):
99
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
100
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
101
- data = self._load()
102
- self.assertEqual(data["status"]["ios"]["implemented"]["version"], 2)
103
-
104
- def test_set_implemented_no_bump_on_byte_identical_source(self):
105
- src = self.registry_dir / "Button.swift"
106
- src.write_text("struct Button {}\n")
107
-
108
- set_implemented(self.registry_dir, self.node_id, "ios", source_file=src, updater="phase-4-view")
109
- first = self._load()["status"]["ios"]["implemented"]
110
- self.assertEqual(first["version"], 1)
111
- self.assertIsNotNone(first["hash"])
112
-
113
- # Identical re-run
114
- time.sleep(0.01)
115
- set_implemented(self.registry_dir, self.node_id, "ios", source_file=src, updater="phase-4-view")
116
- second = self._load()["status"]["ios"]["implemented"]
117
-
118
- self.assertEqual(second["version"], 1) # no bump
119
- self.assertEqual(second["hash"], first["hash"])
120
- self.assertEqual(second["at"], first["at"]) # at unchanged on no-op
121
-
122
- def test_set_implemented_bumps_on_content_change(self):
123
- src = self.registry_dir / "Button.swift"
124
- src.write_text("struct Button {}\n")
125
- set_implemented(self.registry_dir, self.node_id, "ios", source_file=src, updater="phase-4-view")
126
- v1 = self._load()["status"]["ios"]["implemented"]["version"]
127
-
128
- src.write_text("struct Button { let label: String }\n")
129
- set_implemented(self.registry_dir, self.node_id, "ios", source_file=src, updater="phase-4-view")
130
- v2 = self._load()["status"]["ios"]["implemented"]["version"]
131
-
132
- self.assertEqual(v1, 1)
133
- self.assertEqual(v2, 2)
134
-
135
- def test_set_implemented_clears_stale_on_same_platform_only(self):
136
- seed = {
137
- "nodeId": self.node_id,
138
- "status": {
139
- "ios": {
140
- "stale": True,
141
- "implemented": {"value": True, "version": 1, "hash": None, "at": "2026-04-01T00:00:00Z"},
142
- "tested": {"value": False, "against": 0, "at": None},
143
- "codeConnect": {"value": False, "against": 0, "at": None},
144
- "wiki": {"value": False, "against": 0, "at": None},
145
- },
146
- "android": {
147
- "stale": True,
148
- "implemented": {"value": True, "version": 1, "hash": None, "at": "2026-04-01T00:00:00Z"},
149
- "tested": {"value": False, "against": 0, "at": None},
150
- "codeConnect": {"value": False, "against": 0, "at": None},
151
- "wiki": {"value": False, "against": 0, "at": None},
152
- },
153
- },
154
- }
155
- self._write_seed(seed)
156
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
157
- data = self._load()
158
- self.assertFalse(data["status"]["ios"]["stale"])
159
- self.assertTrue(data["status"]["android"]["stale"]) # untouched
160
-
161
- def test_set_implemented_rejects_unknown_platform(self):
162
- with self.assertRaises(ValueError):
163
- set_implemented(self.registry_dir, self.node_id, "windows", updater="phase-4-view")
164
-
165
- # ------------------------------------------------------------------
166
- # set_flag
167
- # ------------------------------------------------------------------
168
-
169
- def test_set_flag_records_against_current_impl_version(self):
170
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
171
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
172
- # impl is now version 2
173
- set_flag(self.registry_dir, self.node_id, "ios", "tested", updater="phase-5-test")
174
- data = self._load()
175
- self.assertTrue(data["status"]["ios"]["tested"]["value"])
176
- self.assertEqual(data["status"]["ios"]["tested"]["against"], 2)
177
-
178
- def test_set_flag_rejects_unknown_flag(self):
179
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
180
- with self.assertRaises(ValueError):
181
- set_flag(self.registry_dir, self.node_id, "ios", "bogus", updater="x")
182
-
183
- def test_set_flag_rejects_implemented_as_flag(self):
184
- # 'implemented' is not in FLAGS - use set_implemented instead
185
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
186
- with self.assertRaises(ValueError):
187
- set_flag(self.registry_dir, self.node_id, "ios", "implemented", updater="x")
188
-
189
- def test_set_flag_codeconnect_mirrors_legacy_field(self):
190
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
191
- set_flag(self.registry_dir, self.node_id, "ios", "codeConnect", updater="phase-6")
192
- data = self._load()
193
- self.assertTrue(data["codeConnect"]["ios"])
194
- self.assertFalse(data["codeConnect"]["android"])
195
-
196
- def test_set_flag_tested_does_not_touch_legacy_codeconnect(self):
197
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
198
- # Pre-seed a legacy codeConnect=True
199
- data = self._load()
200
- data["codeConnect"] = {"ios": True, "android": False}
201
- self.path.write_text(json.dumps(data, indent=2) + "\n")
202
-
203
- set_flag(self.registry_dir, self.node_id, "ios", "tested", updater="phase-5")
204
- data = self._load()
205
- # Legacy unchanged
206
- self.assertTrue(data["codeConnect"]["ios"])
207
-
208
- def test_set_flag_all_three_flags_work(self):
209
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
210
- for flag in FLAGS:
211
- set_flag(self.registry_dir, self.node_id, "ios", flag, updater=f"phase-{flag}")
212
- data = self._load()
213
- for flag in FLAGS:
214
- self.assertTrue(data["status"]["ios"][flag]["value"], f"{flag} should be true")
215
- self.assertEqual(data["status"]["ios"][flag]["against"], 1)
216
-
217
- # ------------------------------------------------------------------
218
- # mark_stale
219
- # ------------------------------------------------------------------
220
-
221
- def test_mark_stale_updates_when_figma_is_newer(self):
222
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
223
- updated = mark_stale(self.registry_dir, self.node_id, "2026-04-15T10:00:00Z")
224
- self.assertTrue(updated)
225
- data = self._load()
226
- self.assertEqual(data["figmaUpdatedAt"], "2026-04-15T10:00:00Z")
227
- self.assertTrue(data["status"]["ios"]["stale"])
228
-
229
- def test_mark_stale_noop_when_figma_is_older(self):
230
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
231
- mark_stale(self.registry_dir, self.node_id, "2026-04-15T10:00:00Z")
232
-
233
- updated = mark_stale(self.registry_dir, self.node_id, "2026-04-10T00:00:00Z")
234
- self.assertFalse(updated)
235
- data = self._load()
236
- self.assertEqual(data["figmaUpdatedAt"], "2026-04-15T10:00:00Z")
237
-
238
- def test_mark_stale_only_marks_implemented_platforms(self):
239
- # Seed: ios implemented, android not
240
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
241
-
242
- mark_stale(self.registry_dir, self.node_id, "2026-04-15T10:00:00Z")
243
- data = self._load()
244
- self.assertTrue(data["status"]["ios"]["stale"])
245
- self.assertFalse(data["status"]["android"]["stale"]) # nothing to make stale
246
-
247
- def test_mark_stale_returns_false_for_missing_registry(self):
248
- updated = mark_stale(self.registry_dir, "9999:9999", "2026-04-15T10:00:00Z")
249
- self.assertFalse(updated)
250
- self.assertFalse((self.registry_dir / "9999-9999.json").exists())
251
-
252
- # ------------------------------------------------------------------
253
- # get_flag_state (yellow rule)
254
- # ------------------------------------------------------------------
255
-
256
- def test_get_flag_state_gray_for_missing_file(self):
257
- state = get_flag_state(self.registry_dir, self.node_id, "ios", "implemented")
258
- self.assertEqual(state, "gray")
259
-
260
- def test_get_flag_state_green_after_impl(self):
261
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
262
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", "implemented"), "green")
263
-
264
- def test_get_flag_state_gray_for_unset_tested(self):
265
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
266
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", "tested"), "gray")
267
-
268
- def test_get_flag_state_green_after_set_flag(self):
269
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
270
- set_flag(self.registry_dir, self.node_id, "ios", "tested", updater="phase-5")
271
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", "tested"), "green")
272
-
273
- def test_get_flag_state_yellow_when_impl_ahead(self):
274
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
275
- set_flag(self.registry_dir, self.node_id, "ios", "tested", updater="phase-5")
276
- set_flag(self.registry_dir, self.node_id, "ios", "codeConnect", updater="phase-6")
277
- set_flag(self.registry_dir, self.node_id, "ios", "wiki", updater="phase-7")
278
- # All green against version 1
279
- for flag in FLAGS:
280
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", flag), "green")
281
-
282
- # Re-implement - version bumps to 2
283
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
284
-
285
- # Everything downstream is now yellow
286
- for flag in FLAGS:
287
- self.assertEqual(
288
- get_flag_state(self.registry_dir, self.node_id, "ios", flag),
289
- "yellow",
290
- f"{flag} should be yellow after impl bump",
291
- )
292
- # impl itself stays green
293
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", "implemented"), "green")
294
-
295
- def test_yellow_clears_when_flag_re_set(self):
296
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
297
- set_flag(self.registry_dir, self.node_id, "ios", "tested", updater="phase-5")
298
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
299
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", "tested"), "yellow")
300
-
301
- set_flag(self.registry_dir, self.node_id, "ios", "tested", updater="phase-5")
302
- self.assertEqual(get_flag_state(self.registry_dir, self.node_id, "ios", "tested"), "green")
303
-
304
- # ------------------------------------------------------------------
305
- # Platform isolation + invariants
306
- # ------------------------------------------------------------------
307
-
308
- def test_ios_and_android_independent(self):
309
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
310
- set_implemented(self.registry_dir, self.node_id, "ios", updater="phase-4-view")
311
-
312
- data = self._load()
313
- self.assertEqual(data["status"]["ios"]["implemented"]["version"], 2)
314
- self.assertEqual(data["status"]["android"]["implemented"]["version"], 0)
315
- self.assertFalse(data["status"]["android"]["implemented"]["value"])
316
-
317
- def test_blank_platform_shape_matches_flags_constant(self):
318
- blank = _blank_platform_status()
319
- self.assertIn("stale", blank)
320
- self.assertIn("implemented", blank)
321
- for flag in FLAGS:
322
- self.assertIn(flag, blank)
323
- self.assertFalse(blank[flag]["value"])
324
- self.assertEqual(blank[flag]["against"], 0)
325
- self.assertIsNone(blank[flag]["at"])
326
-
327
- def test_platforms_constant_is_complete(self):
328
- self.assertEqual(set(PLATFORMS), {"ios", "android"})
329
-
330
-
331
- if __name__ == "__main__":
332
- unittest.main(verbosity=2)
@@ -1,176 +0,0 @@
1
- """Execute the embedded Python block from figma-issue/SKILL.md STEP 1.5a.
2
-
3
- The readiness check is a Python one-liner embedded inside a bash heredoc.
4
- This test extracts it, substitutes ${FIGMA_DIR} and <NODE_ID>, runs it
5
- against a fixture registry, and asserts the output JSON matches the
6
- expected per-component status.
7
-
8
- This is the *only* automated test that proves Step 6's blocker-logic
9
- edit actually works. If my edit has a syntax error or wrong field
10
- access, this fails.
11
-
12
- Run: python3 -m unittest test_skill_figma_issue.py
13
- """
14
-
15
- import json
16
- import re
17
- import subprocess
18
- import sys
19
- import tempfile
20
- import unittest
21
- from pathlib import Path
22
-
23
- REPO_ROOT = Path(__file__).resolve().parents[5]
24
- SKILL_MD = REPO_ROOT / ".instructions" / "figma" / "figma-issue" / "SKILL.md"
25
-
26
-
27
- def extract_readiness_python(skill_md: Path) -> str:
28
- """Pull the Python block from STEP 1.5a out of the SKILL.md.
29
-
30
- The block is inside a bash heredoc:
31
- python3 -c "
32
- import json, os, glob
33
- ...
34
- "
35
- We find the opening `python3 -c "` and read until the closing `"` on
36
- its own line before the code fence.
37
- """
38
- text = skill_md.read_text(encoding="utf-8")
39
- m = re.search(
40
- r'python3 -c "\n(.*?)\n"\n```',
41
- text,
42
- re.DOTALL,
43
- )
44
- if not m:
45
- raise RuntimeError("Could not locate readiness Python block in SKILL.md")
46
- return m.group(1)
47
-
48
-
49
- class SkillFigmaIssueReadinessTests(unittest.TestCase):
50
- @classmethod
51
- def setUpClass(cls):
52
- cls.code = extract_readiness_python(SKILL_MD)
53
-
54
- def setUp(self):
55
- self.tmp = tempfile.TemporaryDirectory()
56
- self.root = Path(self.tmp.name)
57
- self.figma_dir = self.root / "Figma"
58
- self.components_dir = self.figma_dir / "Components"
59
- self.components_dir.mkdir(parents=True)
60
-
61
- # Graph with one parent that depends on several sub-components
62
- graph = {
63
- "graph": {
64
- "1:1": {
65
- "subComponents": [
66
- "NewStyleButton", # new status block, implemented
67
- "LegacyButton", # legacy codeConnect=true
68
- "SkipButton", # skip=true
69
- "UnimplementedButton", # has entry but no impl
70
- "UnknownButton", # not in registry
71
- ],
72
- },
73
- },
74
- }
75
- (self.figma_dir / "sub-component-graph.json").write_text(json.dumps(graph))
76
-
77
- self._write_component("1-101.json", {
78
- "nodeId": "1:101",
79
- "componentName": {"ios": "NewStyleButton", "android": "NewStyleButton"},
80
- "skip": False,
81
- "codeConnect": {"ios": False, "android": False},
82
- "status": {
83
- "ios": {
84
- "stale": False,
85
- "implemented": {"value": True, "version": 1, "hash": None, "at": "..."},
86
- "tested": {"value": False, "against": 0, "at": None},
87
- "codeConnect": {"value": False, "against": 0, "at": None},
88
- "wiki": {"value": False, "against": 0, "at": None},
89
- },
90
- "android": {
91
- "stale": False,
92
- "implemented": {"value": False, "version": 0, "hash": None, "at": None},
93
- "tested": {"value": False, "against": 0, "at": None},
94
- "codeConnect": {"value": False, "against": 0, "at": None},
95
- "wiki": {"value": False, "against": 0, "at": None},
96
- },
97
- },
98
- })
99
-
100
- self._write_component("1-102.json", {
101
- "nodeId": "1:102",
102
- "componentName": {"ios": "LegacyButton", "android": "LegacyButton"},
103
- "skip": False,
104
- "codeConnect": {"ios": True, "android": False},
105
- # No status block at all - pure legacy shape
106
- })
107
-
108
- self._write_component("1-103.json", {
109
- "nodeId": "1:103",
110
- "componentName": {"ios": "SkipButton", "android": "SkipButton"},
111
- "skip": True,
112
- "codeConnect": {"ios": False, "android": False},
113
- })
114
-
115
- self._write_component("1-104.json", {
116
- "nodeId": "1:104",
117
- "componentName": {"ios": "UnimplementedButton", "android": "UnimplementedButton"},
118
- "skip": False,
119
- "codeConnect": {"ios": False, "android": False},
120
- })
121
-
122
- def tearDown(self):
123
- self.tmp.cleanup()
124
-
125
- def _write_component(self, filename: str, data: dict):
126
- (self.components_dir / filename).write_text(json.dumps(data))
127
-
128
- def _run_readiness(self, node_id: str = "1:1") -> dict:
129
- """Substitute placeholders and run the embedded block."""
130
- code = self.code.replace("${FIGMA_DIR}", str(self.figma_dir)).replace("<NODE_ID>", node_id)
131
- r = subprocess.run(
132
- ["python3", "-c", code],
133
- capture_output=True,
134
- text=True,
135
- check=False,
136
- )
137
- if r.returncode != 0:
138
- raise AssertionError(f"Readiness block crashed:\nSTDERR:\n{r.stderr}\nSTDOUT:\n{r.stdout}")
139
- return json.loads(r.stdout)
140
-
141
- def test_block_can_be_extracted(self):
142
- self.assertIn("status", self.code)
143
- self.assertIn("codeConnect", self.code)
144
-
145
- def test_new_status_implemented_is_implemented(self):
146
- out = self._run_readiness("1:1")
147
- subs = {s["name"]: s["status"] for s in out["subComponents"]}
148
- self.assertEqual(subs["NewStyleButton"], "implemented")
149
-
150
- def test_legacy_codeconnect_true_is_implemented(self):
151
- out = self._run_readiness("1:1")
152
- subs = {s["name"]: s["status"] for s in out["subComponents"]}
153
- self.assertEqual(subs["LegacyButton"], "implemented")
154
-
155
- def test_skip_true_is_skipped(self):
156
- out = self._run_readiness("1:1")
157
- subs = {s["name"]: s["status"] for s in out["subComponents"]}
158
- self.assertEqual(subs["SkipButton"], "skipped")
159
-
160
- def test_no_impl_is_not_implemented(self):
161
- out = self._run_readiness("1:1")
162
- subs = {s["name"]: s["status"] for s in out["subComponents"]}
163
- self.assertEqual(subs["UnimplementedButton"], "not_implemented")
164
-
165
- def test_unknown_component_is_unresolved(self):
166
- out = self._run_readiness("1:1")
167
- subs = {s["name"]: s["status"] for s in out["subComponents"]}
168
- self.assertEqual(subs["UnknownButton"], "unresolved")
169
-
170
- def test_no_deps_case(self):
171
- out = self._run_readiness("9:99") # not in graph
172
- self.assertEqual(out["status"], "no_deps")
173
-
174
-
175
- if __name__ == "__main__":
176
- unittest.main(verbosity=2)
@@ -1,98 +0,0 @@
1
- """Execute the embedded Python block from figma-review/SKILL.md STEP 0.
2
-
3
- Step 8 added a registry lookup block to figma-review/SKILL.md that
4
- resolves a ComponentName to a Figma nodeId so the issue can be found
5
- by `"{nodeId}" in:body` search. This test extracts that block,
6
- substitutes placeholders, and runs it against a fixture registry.
7
-
8
- Run: python3 -m unittest test_skill_figma_review.py
9
- """
10
-
11
- import json
12
- import re
13
- import subprocess
14
- import sys
15
- import tempfile
16
- import unittest
17
- from pathlib import Path
18
-
19
- REPO_ROOT = Path(__file__).resolve().parents[5]
20
- SKILL_MD = REPO_ROOT / ".instructions" / "figma" / "figma-review" / "SKILL.md"
21
-
22
-
23
- def extract_nodeid_lookup_python(skill_md: Path) -> str:
24
- """Pull the Python block that resolves ComponentName → nodeId."""
25
- text = skill_md.read_text(encoding="utf-8")
26
- m = re.search(
27
- r'NODE_ID=\$\(python3 -c "\n(.*?)\n"\)',
28
- text,
29
- re.DOTALL,
30
- )
31
- if not m:
32
- raise RuntimeError("Could not locate node-id lookup block in figma-review SKILL.md")
33
- return m.group(1)
34
-
35
-
36
- class SkillFigmaReviewLookupTests(unittest.TestCase):
37
- @classmethod
38
- def setUpClass(cls):
39
- cls.code = extract_nodeid_lookup_python(SKILL_MD)
40
-
41
- def setUp(self):
42
- self.tmp = tempfile.TemporaryDirectory()
43
- self.root = Path(self.tmp.name)
44
- self.figma_dir = self.root / "Figma"
45
- self.components_dir = self.figma_dir / "Components"
46
- self.components_dir.mkdir(parents=True)
47
-
48
- # Fixture: three components with different shapes
49
- (self.components_dir / "5-17752.json").write_text(json.dumps({
50
- "nodeId": "5:17752",
51
- "componentName": {"ios": "TurkishButton", "android": "TurkishButton"},
52
- }))
53
- (self.components_dir / "1-100.json").write_text(json.dumps({
54
- "nodeId": "1:100",
55
- "componentName": {"ios": "FlightCard", "android": "FlightCard"},
56
- }))
57
- # Legacy bare-string componentName
58
- (self.components_dir / "7-200.json").write_text(json.dumps({
59
- "nodeId": "7:200",
60
- "componentName": "InputArea",
61
- }))
62
-
63
- def tearDown(self):
64
- self.tmp.cleanup()
65
-
66
- def _run_lookup(self, component_name: str) -> str:
67
- code = self.code.replace("${FIGMA_DIR}", str(self.figma_dir)).replace("{ComponentName}", component_name)
68
- r = subprocess.run(
69
- ["python3", "-c", code],
70
- capture_output=True,
71
- text=True,
72
- check=False,
73
- )
74
- if r.returncode != 0:
75
- raise AssertionError(f"Lookup crashed:\nSTDERR:\n{r.stderr}\nSTDOUT:\n{r.stdout}")
76
- return r.stdout.strip()
77
-
78
- def test_block_can_be_extracted(self):
79
- self.assertIn("componentName", self.code)
80
- self.assertIn("nodeId", self.code)
81
-
82
- def test_dict_component_name_resolves(self):
83
- self.assertEqual(self._run_lookup("TurkishButton"), "5:17752")
84
-
85
- def test_different_component_resolves(self):
86
- self.assertEqual(self._run_lookup("FlightCard"), "1:100")
87
-
88
- def test_unknown_component_returns_empty(self):
89
- self.assertEqual(self._run_lookup("NonExistent"), "")
90
-
91
- def test_bare_string_component_name_resolves(self):
92
- # Real registry data has entries where componentName is "InputArea"
93
- # instead of {"ios": "InputArea", "android": "InputArea"}
94
- self.assertEqual(self._run_lookup("InputArea"), "7:200")
95
-
96
-
97
- if __name__ == "__main__":
98
- unittest.main(verbosity=2)