@mmerterden/multi-agent-pipeline 11.2.0 → 11.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +2 -2
  3. package/docs/FIGMA_PIPELINE.md +12 -25
  4. package/docs/architecture.md +3 -5
  5. package/docs/features.md +8 -8
  6. package/install/_dev-only-files.mjs +0 -6
  7. package/install/claude.mjs +33 -15
  8. package/install/copilot.mjs +16 -14
  9. package/install/templates/copilot-instructions.md +3 -3
  10. package/package.json +1 -1
  11. package/pipeline/commands/{multi-agent.md → multi-agent/SKILL.md} +39 -39
  12. package/pipeline/commands/multi-agent/{analysis.md → analysis/SKILL.md} +18 -18
  13. package/pipeline/commands/multi-agent/{analysis-resolve.md → analysis-resolve/SKILL.md} +4 -4
  14. package/pipeline/commands/multi-agent/{autopilot.md → autopilot/SKILL.md} +4 -4
  15. package/pipeline/commands/multi-agent/{build-optimize.md → build-optimize/SKILL.md} +1 -1
  16. package/pipeline/commands/multi-agent/{channels.md → channels/SKILL.md} +12 -12
  17. package/pipeline/commands/multi-agent/{dev.md → dev/SKILL.md} +4 -4
  18. package/pipeline/commands/multi-agent/{dev-autopilot.md → dev-autopilot/SKILL.md} +4 -4
  19. package/pipeline/commands/multi-agent/{dev-local.md → dev-local/SKILL.md} +5 -5
  20. package/pipeline/commands/multi-agent/{dev-local-autopilot.md → dev-local-autopilot/SKILL.md} +4 -4
  21. package/pipeline/commands/multi-agent/{finish.md → finish/SKILL.md} +6 -6
  22. package/pipeline/commands/multi-agent/{generate.md → generate/SKILL.md} +3 -3
  23. package/pipeline/commands/multi-agent/{help.md → help/SKILL.md} +4 -4
  24. package/pipeline/commands/multi-agent/{local.md → local/SKILL.md} +5 -5
  25. package/pipeline/commands/multi-agent/{local-autopilot.md → local-autopilot/SKILL.md} +5 -5
  26. package/pipeline/commands/multi-agent/{manual-test.md → manual-test/SKILL.md} +1 -1
  27. package/pipeline/commands/multi-agent/refactor/SKILL.md +257 -0
  28. package/pipeline/commands/multi-agent/{resume.md → resume/SKILL.md} +1 -1
  29. package/pipeline/commands/multi-agent/{review.md → review/SKILL.md} +5 -5
  30. package/pipeline/commands/multi-agent/{setup.md → setup/SKILL.md} +1 -1
  31. package/pipeline/commands/multi-agent/{sync.md → sync/SKILL.md} +20 -58
  32. package/pipeline/{commands/multi-agent → multi-agent-refs}/_account-picker.md +2 -2
  33. package/pipeline/{commands/multi-agent → multi-agent-refs}/_dev-context.md +2 -2
  34. package/pipeline/{commands/multi-agent → multi-agent-refs}/_repo-picker.md +2 -2
  35. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/android-guide.md +1 -1
  36. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/jira.md +1 -1
  37. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/wiki.md +7 -7
  38. package/pipeline/multi-agent-refs/component-dispatch.md +92 -0
  39. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/cross-cli-contract.md +10 -77
  40. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/verify-by-test.md +1 -1
  41. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/generate-issue.md +2 -2
  42. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/issue-jira-triad.md +1 -1
  43. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/keychain.md +1 -1
  44. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/log-format.md +1 -1
  45. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/modes.md +2 -2
  46. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/operations.md +1 -1
  47. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-0-init.md +10 -10
  48. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-1-analysis.md +6 -6
  49. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-2-planning.md +3 -3
  50. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-3-dev.md +10 -10
  51. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-4-review.md +8 -8
  52. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-5-test.md +3 -3
  53. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-6-commit.md +4 -4
  54. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases/phase-7-report.md +6 -6
  55. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/phases.md +12 -12
  56. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/progress-contract.md +4 -4
  57. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/swiftui-guide.md +1 -1
  58. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/tracker-contract.md +3 -3
  59. package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/wiki-capture.md +4 -4
  60. package/pipeline/preferences-template.json +17 -1
  61. package/pipeline/rules/figma-pipeline.md +2 -2
  62. package/pipeline/schemas/prefs.schema.json +0 -34
  63. package/pipeline/scripts/README.md +1 -3
  64. package/pipeline/scripts/fixtures/install-layout.tsv +6 -5
  65. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  66. package/pipeline/scripts/phase-banner.sh +2 -2
  67. package/pipeline/scripts/review-scope.mjs +94 -0
  68. package/pipeline/scripts/scan-agent-config.sh +2 -2
  69. package/pipeline/scripts/smoke-agent-log-cost.sh +1 -1
  70. package/pipeline/scripts/smoke-agent-model-routing.sh +4 -4
  71. package/pipeline/scripts/smoke-autopilot-circuit-breaker.sh +2 -2
  72. package/pipeline/scripts/smoke-channels-approval-gate.sh +2 -2
  73. package/pipeline/scripts/smoke-channels-flow.sh +5 -5
  74. package/pipeline/scripts/smoke-clarify.sh +1 -1
  75. package/pipeline/scripts/smoke-commands-skills-parity.sh +3 -3
  76. package/pipeline/scripts/smoke-community-gates.sh +1 -1
  77. package/pipeline/scripts/smoke-compliance-skills.sh +2 -2
  78. package/pipeline/scripts/smoke-cost-summary.sh +1 -1
  79. package/pipeline/scripts/smoke-cross-cli-behavior.sh +17 -43
  80. package/pipeline/scripts/smoke-cross-phase-cohesion.sh +1 -1
  81. package/pipeline/scripts/smoke-dev-critic.sh +1 -1
  82. package/pipeline/scripts/smoke-diff-explain.sh +1 -1
  83. package/pipeline/scripts/smoke-diff-risk.sh +1 -1
  84. package/pipeline/scripts/smoke-evidence-gate.sh +1 -1
  85. package/pipeline/scripts/smoke-figma-dispatch.sh +46 -57
  86. package/pipeline/scripts/smoke-gate-hooks.sh +1 -1
  87. package/pipeline/scripts/smoke-generate-issue.sh +8 -8
  88. package/pipeline/scripts/smoke-handoff-contract.sh +3 -3
  89. package/pipeline/scripts/smoke-identity-isolation.sh +2 -2
  90. package/pipeline/scripts/smoke-intent-guard.sh +1 -1
  91. package/pipeline/scripts/smoke-issue-comment-template.sh +2 -2
  92. package/pipeline/scripts/smoke-issue-jira-triad.sh +4 -4
  93. package/pipeline/scripts/smoke-language-axis.sh +6 -6
  94. package/pipeline/scripts/smoke-learnings-ledger.sh +3 -3
  95. package/pipeline/scripts/smoke-mode-dispatch-drift.sh +16 -16
  96. package/pipeline/scripts/smoke-model-fallback.sh +3 -3
  97. package/pipeline/scripts/smoke-multi-repo-integration.sh +2 -2
  98. package/pipeline/scripts/smoke-multi-repo-worktree.sh +1 -1
  99. package/pipeline/scripts/smoke-no-token-prompt.sh +5 -5
  100. package/pipeline/scripts/smoke-phase-0-multi-repo.sh +1 -1
  101. package/pipeline/scripts/smoke-phase-6-multi.sh +1 -1
  102. package/pipeline/scripts/smoke-phase4-gates.sh +45 -0
  103. package/pipeline/scripts/smoke-plan-approval-gate.sh +5 -5
  104. package/pipeline/scripts/smoke-plan-todos.sh +3 -3
  105. package/pipeline/scripts/smoke-pr-review-actions.sh +3 -3
  106. package/pipeline/scripts/smoke-prefs-language.sh +1 -1
  107. package/pipeline/scripts/smoke-progress-contract.sh +2 -2
  108. package/pipeline/scripts/smoke-push-retry.sh +1 -1
  109. package/pipeline/scripts/smoke-repo-map.sh +2 -2
  110. package/pipeline/scripts/smoke-shadow-git.sh +1 -1
  111. package/pipeline/scripts/smoke-skill-authoring.sh +4 -9
  112. package/pipeline/scripts/smoke-tasklist-ordering.sh +10 -10
  113. package/pipeline/scripts/smoke-test-gap.sh +1 -1
  114. package/pipeline/scripts/smoke-token-budget.sh +1 -1
  115. package/pipeline/scripts/smoke-token-preflight.sh +2 -2
  116. package/pipeline/scripts/smoke-tracker-contract.sh +13 -13
  117. package/pipeline/scripts/smoke-tracker-tokens-invocation.sh +5 -5
  118. package/pipeline/scripts/smoke-triage-memory.sh +2 -2
  119. package/pipeline/scripts/smoke-update-check.sh +1 -1
  120. package/pipeline/scripts/smoke-url-enrichment.sh +2 -2
  121. package/pipeline/scripts/smoke-validator-gates.sh +1 -1
  122. package/pipeline/scripts/smoke-verify-by-test.sh +3 -3
  123. package/pipeline/scripts/smoke-wiki-integration.sh +9 -33
  124. package/pipeline/scripts/smoke-work-summary.sh +1 -1
  125. package/pipeline/scripts/smoke-worktree-path-convention.sh +4 -4
  126. package/pipeline/scripts/test-integrity-gate.mjs +83 -0
  127. package/pipeline/scripts/uninstall.mjs +2 -2
  128. package/pipeline/skills/.skill-manifest.json +40 -160
  129. package/pipeline/skills/.skills-index.json +3 -372
  130. package/pipeline/skills/shared/README.md +1 -1
  131. package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -1
  132. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +2 -2
  133. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +3 -3
  134. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
  135. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
  136. package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
  137. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +1 -1
  138. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +116 -51
  139. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +8 -30
  140. package/pipeline/skills/shared/external/compose-components/SKILL.md +14 -14
  141. package/pipeline/skills/skills-index.md +2 -43
  142. package/pipeline/commands/multi-agent/refactor.md +0 -188
  143. package/pipeline/commands/multi-agent/refs/component-dispatch.md +0 -92
  144. package/pipeline/scripts/smoke-existing-discovery-gate.sh +0 -71
  145. package/pipeline/scripts/smoke-figma-android-parity.sh +0 -148
  146. package/pipeline/scripts/smoke-figma-credential-store.sh +0 -105
  147. package/pipeline/scripts/smoke-figma-cross-cli-inventory.sh +0 -177
  148. package/pipeline/scripts/smoke-figma-sync.sh +0 -149
  149. package/pipeline/scripts/smoke-sync-delegation.sh +0 -74
  150. package/pipeline/skills/figma-android/README.md +0 -38
  151. package/pipeline/skills/figma-android/figma-component-code-connect/SKILL.md +0 -62
  152. package/pipeline/skills/figma-android/figma-component-implement/SKILL.md +0 -158
  153. package/pipeline/skills/figma-android/figma-component-test/SKILL.md +0 -120
  154. package/pipeline/skills/figma-android/figma-component-wiki/SKILL.md +0 -35
  155. package/pipeline/skills/figma-android/figma-to-component/SKILL.md +0 -124
  156. package/pipeline/skills/figma-common/README.md +0 -64
  157. package/pipeline/skills/figma-common/figma-bottom-sheets/SKILL.md +0 -152
  158. package/pipeline/skills/figma-common/figma-cli-iterate/SKILL.md +0 -282
  159. package/pipeline/skills/figma-common/figma-cli-iterate-mend/SKILL.md +0 -503
  160. package/pipeline/skills/figma-common/figma-cli-lean-iterate/SKILL.md +0 -288
  161. package/pipeline/skills/figma-common/figma-cli-skip/SKILL.md +0 -362
  162. package/pipeline/skills/figma-common/figma-commit/COMMON_REBASE.md +0 -206
  163. package/pipeline/skills/figma-common/figma-commit/REVIEW.md +0 -337
  164. package/pipeline/skills/figma-common/figma-commit/SKILL.md +0 -216
  165. package/pipeline/skills/figma-common/figma-component-confluence-sync/SKILL.md +0 -223
  166. package/pipeline/skills/figma-common/figma-component-start/SKILL.md +0 -251
  167. package/pipeline/skills/figma-common/figma-component-status-update/SKILL.md +0 -78
  168. package/pipeline/skills/figma-common/figma-evolve-component/SKILL.md +0 -61
  169. package/pipeline/skills/figma-common/figma-fix/SKILL.md +0 -321
  170. package/pipeline/skills/figma-common/figma-form-integration/SKILL.md +0 -542
  171. package/pipeline/skills/figma-common/figma-issue/SKILL.md +0 -750
  172. package/pipeline/skills/figma-common/figma-iterate/SKILL.md +0 -208
  173. package/pipeline/skills/figma-common/figma-iteration-commit/SKILL.md +0 -1020
  174. package/pipeline/skills/figma-common/figma-mend/SKILL.md +0 -331
  175. package/pipeline/skills/figma-common/figma-navigation/SKILL.md +0 -156
  176. package/pipeline/skills/figma-common/figma-overlays/SKILL.md +0 -142
  177. package/pipeline/skills/figma-common/figma-price-integration/SKILL.md +0 -398
  178. package/pipeline/skills/figma-common/figma-remote-mcp-auth/SKILL.md +0 -104
  179. package/pipeline/skills/figma-common/figma-review/SKILL.md +0 -400
  180. package/pipeline/skills/figma-common/figma-setup/SKILL.md +0 -514
  181. package/pipeline/skills/figma-common/figma-setup/scripts/fetch-mcp-token.py +0 -592
  182. package/pipeline/skills/figma-common/figma-skip/SKILL.md +0 -129
  183. package/pipeline/skills/figma-common/figma-ui-patterns/SKILL.md +0 -105
  184. package/pipeline/skills/figma-common/figma-ui-patterns/patterns/animated-gradient-border.md +0 -116
  185. package/pipeline/skills/figma-common/figma-utility/SKILL.md +0 -274
  186. package/pipeline/skills/figma-common/figma-utility/scripts/figma-utility.py +0 -808
  187. package/pipeline/skills/figma-common/figma-validate/SKILL.md +0 -633
  188. package/pipeline/skills/figma-common/performance-iteration-commit-all/SKILL.md +0 -716
  189. package/pipeline/skills/figma-common/performance-review-next/SKILL.md +0 -238
  190. package/pipeline/skills/figma-common/performance-start/SKILL.md +0 -430
  191. package/pipeline/skills/figma-common/performance-swiftui/SKILL.md +0 -706
  192. package/pipeline/skills/figma-common/performance-tour/SKILL.md +0 -423
  193. package/pipeline/skills/figma-ios/REVIEW_CHECKLIST.md +0 -67
  194. package/pipeline/skills/figma-ios/figma-component-code-connect/SKILL.md +0 -178
  195. package/pipeline/skills/figma-ios/figma-component-implement/SKILL.md +0 -184
  196. package/pipeline/skills/figma-ios/figma-component-test/SKILL.md +0 -219
  197. package/pipeline/skills/figma-ios/figma-component-wiki/SKILL.md +0 -274
  198. package/pipeline/skills/figma-ios/figma-to-component/SKILL.md +0 -416
  199. package/pipeline/skills/figma-ios/figma-to-component/halt-return-protocol.md +0 -57
  200. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-0-init.md +0 -307
  201. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1-gathering.md +0 -119
  202. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-1.5-existing-discovery.md +0 -174
  203. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2-orchestrator.md +0 -333
  204. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2a-testing-identifiers.md +0 -368
  205. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2b-localization.md +0 -393
  206. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2c-accessibility.md +0 -617
  207. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-2d-analytics.md +0 -352
  208. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3-orchestrator.md +0 -337
  209. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3a-location.md +0 -206
  210. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3b-tokens.md +0 -235
  211. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3c-nested.md +0 -214
  212. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3d-patterns.md +0 -902
  213. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3e-assets.md +0 -156
  214. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3f-utilities.md +0 -175
  215. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3g-property-coverage.md +0 -176
  216. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-3h-variant-config.md +0 -333
  217. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4-orchestrator.md +0 -412
  218. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4a-configuration.md +0 -336
  219. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4b-view.md +0 -705
  220. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4c-documentation.md +0 -332
  221. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4d-preview.md +0 -380
  222. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-4e-modifiers.md +0 -262
  223. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5-orchestrator.md +0 -482
  224. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5a-viewinspector.md +0 -274
  225. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5b-snapshot.md +0 -636
  226. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-5c-unit.md +0 -142
  227. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-6-code-connect.md +0 -547
  228. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7-wiki.md +0 -39
  229. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-confluence-generate.md +0 -659
  230. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-7a-wiki-generate.md +0 -580
  231. package/pipeline/skills/figma-ios/figma-to-component/phases/phase-8-cleanup.md +0 -51
  232. package/pipeline/skills/figma-ios/figma-to-component/reference/accessibility.md +0 -183
  233. package/pipeline/skills/figma-ios/figma-to-component/reference/analytics-events.md +0 -64
  234. package/pipeline/skills/figma-ios/figma-to-component/reference/code-connect.md +0 -531
  235. package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-api.md +0 -89
  236. package/pipeline/skills/figma-ios/figma-to-component/reference/confluence-xhtml.md +0 -155
  237. package/pipeline/skills/figma-ios/figma-to-component/reference/figma-to-swiftui-effects.md +0 -196
  238. package/pipeline/skills/figma-ios/figma-to-component/reference/halt-return-protocol.md +0 -57
  239. package/pipeline/skills/figma-ios/figma-to-component/reference/localization-naming.md +0 -89
  240. package/pipeline/skills/figma-ios/figma-to-component/reference/macros.md +0 -227
  241. package/pipeline/skills/figma-ios/figma-to-component/reference/missing-tokens.md +0 -157
  242. package/pipeline/skills/figma-ios/figma-to-component/reference/orchestrator-discipline.md +0 -90
  243. package/pipeline/skills/figma-ios/figma-to-component/reference/registry.md +0 -116
  244. package/pipeline/skills/figma-ios/figma-to-component/reference/remote-mcp-script.md +0 -153
  245. package/pipeline/skills/figma-ios/figma-to-component/reference/rest-api-script.md +0 -130
  246. package/pipeline/skills/figma-ios/figma-to-component/reference/scripts-inventory.md +0 -218
  247. package/pipeline/skills/figma-ios/figma-to-component/reference/snapshot-testing.md +0 -188
  248. package/pipeline/skills/figma-ios/figma-to-component/reference/subcomponent-graph.md +0 -93
  249. package/pipeline/skills/figma-ios/figma-to-component/reference/testing-identifiers-naming.md +0 -98
  250. package/pipeline/skills/figma-ios/figma-to-component/reference/tools.md +0 -261
  251. package/pipeline/skills/figma-ios/figma-to-component/reference/viewinspector.md +0 -147
  252. package/pipeline/skills/figma-ios/figma-to-component/reference/wiki-to-confluence-mapping.md +0 -182
  253. package/pipeline/skills/figma-ios/figma-to-component/scripts/apply-author-login-map.py +0 -185
  254. package/pipeline/skills/figma-ios/figma-to-component/scripts/backfill-status.py +0 -609
  255. package/pipeline/skills/figma-ios/figma-to-component/scripts/build-author-registry.py +0 -332
  256. package/pipeline/skills/figma-ios/figma-to-component/scripts/bulk-sync-issues.py +0 -261
  257. package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-data-gather.py +0 -184
  258. package/pipeline/skills/figma-ios/figma-to-component/scripts/code-connect-publish.sh +0 -188
  259. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status-upload.py +0 -768
  260. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-component-status.py +0 -191
  261. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-data-gather.py +0 -420
  262. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-page-ids.example.json +0 -9
  263. package/pipeline/skills/figma-ios/figma-to-component/scripts/confluence-publish.py +0 -336
  264. package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-subcomponent-graph.py +0 -391
  265. package/pipeline/skills/figma-ios/figma-to-component/scripts/figma-update.py +0 -292
  266. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/__init__.py +0 -1
  267. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/issue_sync_propagate.py +0 -93
  268. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/registry_writer.py +0 -299
  269. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_backfill_status.py +0 -343
  270. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update.py +0 -206
  271. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_figma_update_http.py +0 -149
  272. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_phase_clis.py +0 -281
  273. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_registry_writer.py +0 -332
  274. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_issue.py +0 -176
  275. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_skill_figma_review.py +0 -98
  276. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue.py +0 -298
  277. package/pipeline/skills/figma-ios/figma-to-component/scripts/lib/test_update_issue_gh.py +0 -195
  278. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase1-gather.py +0 -1298
  279. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase2-finalize.py +0 -228
  280. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase3-scripts.py +0 -1089
  281. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase4-finalize.py +0 -141
  282. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase5-finalize.py +0 -106
  283. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase6-finalize.py +0 -162
  284. package/pipeline/skills/figma-ios/figma-to-component/scripts/phase7-finalize.py +0 -105
  285. package/pipeline/skills/figma-ios/figma-to-component/scripts/register-icons-codeconnect.py +0 -179
  286. package/pipeline/skills/figma-ios/figma-to-component/scripts/remote-mcp-fetch.py +0 -260
  287. package/pipeline/skills/figma-ios/figma-to-component/scripts/resolve-author-logins.py +0 -260
  288. package/pipeline/skills/figma-ios/figma-to-component/scripts/run-uicomponents-tests.sh +0 -86
  289. package/pipeline/skills/figma-ios/figma-to-component/scripts/sidebar-generator.py +0 -321
  290. package/pipeline/skills/figma-ios/figma-to-component/scripts/update-issue-from-registry.py +0 -1470
  291. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase4.sh +0 -176
  292. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase6.sh +0 -147
  293. package/pipeline/skills/figma-ios/figma-to-component/scripts/validate-phase7a.py +0 -629
  294. /package/pipeline/commands/multi-agent/{delete.md → delete/SKILL.md} +0 -0
  295. /package/pipeline/commands/multi-agent/{diff-explain.md → diff-explain/SKILL.md} +0 -0
  296. /package/pipeline/commands/multi-agent/{garbage-collect.md → garbage-collect/SKILL.md} +0 -0
  297. /package/pipeline/commands/multi-agent/{issue.md → issue/SKILL.md} +0 -0
  298. /package/pipeline/commands/multi-agent/{jira.md → jira/SKILL.md} +0 -0
  299. /package/pipeline/commands/multi-agent/{kill.md → kill/SKILL.md} +0 -0
  300. /package/pipeline/commands/multi-agent/{language.md → language/SKILL.md} +0 -0
  301. /package/pipeline/commands/multi-agent/{log.md → log/SKILL.md} +0 -0
  302. /package/pipeline/commands/multi-agent/{prune-logs.md → prune-logs/SKILL.md} +0 -0
  303. /package/pipeline/commands/multi-agent/{purge.md → purge/SKILL.md} +0 -0
  304. /package/pipeline/commands/multi-agent/{scan.md → scan/SKILL.md} +0 -0
  305. /package/pipeline/commands/multi-agent/{search.md → search/SKILL.md} +0 -0
  306. /package/pipeline/commands/multi-agent/{stack.md → stack/SKILL.md} +0 -0
  307. /package/pipeline/commands/multi-agent/{status.md → status/SKILL.md} +0 -0
  308. /package/pipeline/commands/multi-agent/{test.md → test/SKILL.md} +0 -0
  309. /package/pipeline/commands/multi-agent/{update.md → update/SKILL.md} +0 -0
  310. /package/pipeline/{commands/multi-agent → multi-agent-refs}/_input-parser.md +0 -0
  311. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/analysis-template.md +0 -0
  312. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/audit-guide.md +0 -0
  313. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/backend-guide.md +0 -0
  314. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/confluence.md +0 -0
  315. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/issue-comment.md +0 -0
  316. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr-review-actions.md +0 -0
  317. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/channels/pr.md +0 -0
  318. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/conventions-defaults.md +0 -0
  319. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/autopilot-circuit-breaker.md +0 -0
  320. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/dev-critic.md +0 -0
  321. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/external-context-injection.md +0 -0
  322. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/model-fallback.md +0 -0
  323. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/plan-todos.md +0 -0
  324. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/prior-fix-detection.md +0 -0
  325. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/repo-map.md +0 -0
  326. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/features/shadow-git.md +0 -0
  327. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/frontend-guide.md +0 -0
  328. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/knowledge.md +0 -0
  329. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/multi-repo-integration-build.md +0 -0
  330. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/picker-contract.md +0 -0
  331. /package/pipeline/{commands/multi-agent/refs → multi-agent-refs}/rules.md +0 -0
@@ -1,298 +0,0 @@
1
- """Unit tests for update-issue-from-registry.py pure logic.
2
-
3
- Covers:
4
- - compute_flag_states (dict return, all branches)
5
- - build_progress_table + rewrite_progress_table
6
- - build_missing_issue_body
7
- - is_icon_entry
8
- - pick_survivor (duplicate rule)
9
- - sync_one skip short-circuits
10
- """
11
-
12
- import importlib.util
13
- import json
14
- import sys
15
- import tempfile
16
- import unittest
17
- from pathlib import Path
18
-
19
- SCRIPTS_DIR = Path(__file__).parent.parent
20
- spec = importlib.util.spec_from_file_location(
21
- "update_issue", SCRIPTS_DIR / "update-issue-from-registry.py"
22
- )
23
- update_issue = importlib.util.module_from_spec(spec)
24
- sys.modules["update_issue"] = update_issue
25
- spec.loader.exec_module(update_issue)
26
-
27
-
28
- def _fresh_entry(node_id: str = "1:1") -> dict:
29
- return {
30
- "nodeId": node_id,
31
- "componentName": {"ios": "Button", "android": "Button"},
32
- "fileKey": "ABC",
33
- "skip": False,
34
- "status": {
35
- "ios": {
36
- "stale": False,
37
- "implemented": {"value": False, "version": 0, "hash": None, "at": None},
38
- "tested": {"value": False, "against": 0, "at": None},
39
- "codeConnect": {"value": False, "against": 0, "at": None},
40
- "wiki": {"value": False, "against": 0, "at": None},
41
- },
42
- "android": {
43
- "stale": False,
44
- "implemented": {"value": False, "version": 0, "hash": None, "at": None},
45
- "tested": {"value": False, "against": 0, "at": None},
46
- "codeConnect": {"value": False, "against": 0, "at": None},
47
- "wiki": {"value": False, "against": 0, "at": None},
48
- },
49
- },
50
- }
51
-
52
-
53
- class ComputeFlagStatesTests(unittest.TestCase):
54
- def test_empty_entry_all_gray(self):
55
- result = update_issue.compute_flag_states({}, "ios")
56
- self.assertEqual(result, {
57
- "implemented": "gray",
58
- "tested": "gray",
59
- "codeConnect": "gray",
60
- "wiki": "gray",
61
- })
62
-
63
- def test_returns_all_four_keys_always(self):
64
- result = update_issue.compute_flag_states({"nodeId": "1:1"}, "ios")
65
- self.assertEqual(set(result.keys()), {"implemented", "tested", "codeConnect", "wiki"})
66
-
67
- def test_implemented_green_when_value_and_not_stale(self):
68
- e = _fresh_entry()
69
- e["status"]["ios"]["implemented"] = {"value": True, "version": 1, "hash": None, "at": "..."}
70
- result = update_issue.compute_flag_states(e, "ios")
71
- self.assertEqual(result["implemented"], "green")
72
- self.assertEqual(result["tested"], "gray")
73
-
74
- def test_implemented_yellow_when_stale(self):
75
- e = _fresh_entry()
76
- e["status"]["ios"]["stale"] = True
77
- e["status"]["ios"]["implemented"] = {"value": True, "version": 1, "hash": None, "at": "..."}
78
- result = update_issue.compute_flag_states(e, "ios")
79
- self.assertEqual(result["implemented"], "yellow")
80
-
81
- def test_all_green_against_version_1(self):
82
- e = _fresh_entry()
83
- e["status"]["ios"]["implemented"] = {"value": True, "version": 1, "hash": None, "at": "..."}
84
- for f in ("tested", "codeConnect", "wiki"):
85
- e["status"]["ios"][f] = {"value": True, "against": 1, "at": "..."}
86
- result = update_issue.compute_flag_states(e, "ios")
87
- self.assertEqual(result, {
88
- "implemented": "green",
89
- "tested": "green",
90
- "codeConnect": "green",
91
- "wiki": "green",
92
- })
93
-
94
- def test_mixed_yellow_when_impl_ahead(self):
95
- e = _fresh_entry()
96
- e["status"]["ios"]["implemented"] = {"value": True, "version": 3, "hash": None, "at": "..."}
97
- e["status"]["ios"]["tested"] = {"value": True, "against": 1, "at": "..."}
98
- e["status"]["ios"]["codeConnect"] = {"value": True, "against": 3, "at": "..."}
99
- e["status"]["ios"]["wiki"] = {"value": False, "against": 0, "at": None}
100
- result = update_issue.compute_flag_states(e, "ios")
101
- self.assertEqual(result["implemented"], "green")
102
- self.assertEqual(result["tested"], "yellow")
103
- self.assertEqual(result["codeConnect"], "green")
104
- self.assertEqual(result["wiki"], "gray")
105
-
106
- def test_android_platform_independent(self):
107
- e = _fresh_entry()
108
- e["status"]["ios"]["implemented"] = {"value": True, "version": 1, "hash": None, "at": "..."}
109
- result = update_issue.compute_flag_states(e, "android")
110
- self.assertEqual(result["implemented"], "gray")
111
-
112
-
113
- class BuildProgressTableTests(unittest.TestCase):
114
- def test_all_gray(self):
115
- t = update_issue.build_progress_table({
116
- "implemented": "gray", "tested": "gray", "codeConnect": "gray", "wiki": "gray",
117
- })
118
- self.assertEqual(t.count("⚪"), 4)
119
- self.assertNotIn("🟢", t)
120
- self.assertNotIn("🟡", t)
121
- self.assertIn("Implementation", t)
122
- self.assertIn("Code Connect", t)
123
-
124
- def test_all_green(self):
125
- t = update_issue.build_progress_table({
126
- "implemented": "green", "tested": "green", "codeConnect": "green", "wiki": "green",
127
- })
128
- self.assertEqual(t.count("🟢"), 4)
129
- self.assertNotIn("⚪", t)
130
-
131
- def test_mixed(self):
132
- t = update_issue.build_progress_table({
133
- "implemented": "green", "tested": "yellow", "codeConnect": "green", "wiki": "gray",
134
- })
135
- self.assertIn("🟢", t)
136
- self.assertIn("🟡", t)
137
- self.assertEqual(t.count("⚪"), 1)
138
-
139
- def test_missing_keys_default_to_gray(self):
140
- t = update_issue.build_progress_table({})
141
- self.assertEqual(t.count("⚪"), 4)
142
-
143
-
144
- class RewriteProgressTableTests(unittest.TestCase):
145
- def _green(self):
146
- return {"implemented": "green", "tested": "gray", "codeConnect": "gray", "wiki": "gray"}
147
-
148
- def test_replaces_existing_section(self):
149
- body = "### Figma URL\n\nhttps://x\n\n### Progress\n\nOLD CONTENT\n\n### Notes\n\nhi\n"
150
- new = update_issue.rewrite_progress_table(body, self._green())
151
- self.assertNotIn("OLD CONTENT", new)
152
- self.assertIn("🟢", new)
153
- self.assertIn("### Notes", new)
154
-
155
- def test_appends_when_missing(self):
156
- body = "### Figma URL\n\nhttps://x\n\n### Notes\n\nhi\n"
157
- new = update_issue.rewrite_progress_table(body, self._green())
158
- self.assertIn("### Progress", new)
159
- self.assertIn("🟢", new)
160
-
161
- def test_preserves_surrounding_sections(self):
162
- body = (
163
- "### Figma URL\n\nhttps://x\n\n"
164
- "### Progress\n\nOLD\n\n"
165
- "### Acceptance Criteria\n\nfoo\n\n"
166
- "### Notes\n\nhi\n"
167
- )
168
- gray = {"implemented": "gray", "tested": "gray", "codeConnect": "gray", "wiki": "gray"}
169
- new = update_issue.rewrite_progress_table(body, gray)
170
- self.assertIn("### Figma URL", new)
171
- self.assertIn("### Acceptance Criteria", new)
172
- self.assertIn("foo", new)
173
- self.assertIn("### Notes", new)
174
- self.assertNotIn("OLD", new)
175
-
176
-
177
- class BuildMissingIssueBodyTests(unittest.TestCase):
178
- def test_dict_component_name(self):
179
- entry = {
180
- "nodeId": "5:17752",
181
- "componentName": {"ios": "TurkishButton", "android": "TurkishButton"},
182
- "fileKey": "ABCxyz",
183
- }
184
- states = {"implemented": "green", "tested": "gray", "codeConnect": "gray", "wiki": "gray"}
185
- body = update_issue.build_missing_issue_body(entry, states)
186
- self.assertIn("TurkishButton", body)
187
- self.assertIn("5:17752", body)
188
- self.assertIn("ABCxyz", body)
189
- self.assertIn("### Progress", body)
190
- self.assertIn("🟢", body)
191
-
192
- def test_bare_string_component_name(self):
193
- entry = {"nodeId": "7:200", "componentName": "InputArea", "fileKey": "K"}
194
- body = update_issue.build_missing_issue_body(entry, {})
195
- self.assertIn("InputArea", body)
196
- self.assertIn("⚪", body)
197
-
198
- def test_missing_filekey_uses_no_response(self):
199
- entry = {"nodeId": "1:1", "componentName": {"ios": "X"}}
200
- body = update_issue.build_missing_issue_body(entry, {})
201
- self.assertIn("_No response_", body)
202
-
203
-
204
- class IsIconEntryTests(unittest.TestCase):
205
- def test_ios_image_prefix_is_icon(self):
206
- self.assertTrue(update_issue.is_icon_entry({"componentName": {"ios": "Image.screwdriver"}}))
207
-
208
- def test_android_images_prefix_is_icon(self):
209
- self.assertTrue(update_issue.is_icon_entry({"componentName": {"android": "Images.screwdriver"}}))
210
-
211
- def test_normal_component_not_icon(self):
212
- self.assertFalse(update_issue.is_icon_entry({"componentName": {"ios": "Button"}}))
213
-
214
- def test_bare_string_image_prefix(self):
215
- self.assertTrue(update_issue.is_icon_entry({"componentName": "Image.foo"}))
216
-
217
- def test_bare_string_normal(self):
218
- self.assertFalse(update_issue.is_icon_entry({"componentName": "FlightCard"}))
219
-
220
- def test_missing_componentName(self):
221
- self.assertFalse(update_issue.is_icon_entry({}))
222
-
223
-
224
- class PickSurvivorTests(unittest.TestCase):
225
- def test_lowest_number_when_no_sub_issues(self):
226
- issues = [
227
- {"number": 42, "sub_issue_count": 0},
228
- {"number": 17, "sub_issue_count": 0},
229
- {"number": 99, "sub_issue_count": 0},
230
- ]
231
- survivor = update_issue.pick_survivor(issues)
232
- self.assertEqual(survivor["number"], 17)
233
-
234
- def test_issue_with_sub_issues_wins(self):
235
- issues = [
236
- {"number": 17, "sub_issue_count": 0},
237
- {"number": 42, "sub_issue_count": 3},
238
- {"number": 99, "sub_issue_count": 0},
239
- ]
240
- survivor = update_issue.pick_survivor(issues)
241
- self.assertEqual(survivor["number"], 42)
242
-
243
- def test_lowest_number_among_those_with_sub_issues(self):
244
- issues = [
245
- {"number": 42, "sub_issue_count": 5},
246
- {"number": 17, "sub_issue_count": 2},
247
- {"number": 99, "sub_issue_count": 0},
248
- ]
249
- survivor = update_issue.pick_survivor(issues)
250
- self.assertEqual(survivor["number"], 17)
251
-
252
- def test_single_issue_is_survivor(self):
253
- issues = [{"number": 42, "sub_issue_count": 0}]
254
- survivor = update_issue.pick_survivor(issues)
255
- self.assertEqual(survivor["number"], 42)
256
-
257
-
258
- class SyncOneSkipTests(unittest.TestCase):
259
- def setUp(self):
260
- self.tmp = tempfile.TemporaryDirectory()
261
- self.registry_dir = Path(self.tmp.name)
262
-
263
- def tearDown(self):
264
- self.tmp.cleanup()
265
-
266
- def _write(self, node_id: str, data: dict):
267
- (self.registry_dir / f"{node_id.replace(':', '-')}.json").write_text(json.dumps(data))
268
-
269
- def test_skip_marked_skip_short_circuits(self):
270
- self._write("1:1", {"nodeId": "1:1", "componentName": {"ios": "X"}, "skip": True})
271
- result = update_issue.sync_one(
272
- registry_dir=self.registry_dir, node_id="1:1", platform="ios",
273
- repo="fake/repo", team_label="team:core", dry_run=True,
274
- )
275
- self.assertEqual(result["action"], "skip_marked_skip")
276
-
277
- def test_skip_icon_short_circuits(self):
278
- self._write("1:2", {
279
- "nodeId": "1:2",
280
- "componentName": {"ios": "Image.foo", "android": "Images.foo"},
281
- "skip": False,
282
- })
283
- result = update_issue.sync_one(
284
- registry_dir=self.registry_dir, node_id="1:2", platform="ios",
285
- repo="fake/repo", team_label="team:core", dry_run=True,
286
- )
287
- self.assertEqual(result["action"], "skip_icon")
288
-
289
- def test_missing_entry_returns_error(self):
290
- result = update_issue.sync_one(
291
- registry_dir=self.registry_dir, node_id="9:99", platform="ios",
292
- repo="fake/repo", team_label="team:core", dry_run=False,
293
- )
294
- self.assertEqual(result["status"], "error")
295
-
296
-
297
- if __name__ == "__main__":
298
- unittest.main(verbosity=2)
@@ -1,195 +0,0 @@
1
- """Subprocess path tests for update-issue-from-registry.py.
2
-
3
- Covers gh wrapper, gh_graphql wrapper, close_duplicate,
4
- create_missing_issue, get_issue_body, rewrite_issue_body.
5
-
6
- sync_one is not fully exercised here - its full happy path requires
7
- mocking the entire REST-then-GraphQL sequence, which gets brittle.
8
- Instead we trust the unit tests for pure-logic pieces
9
- (compute_flag_states, pick_survivor, etc.) and the real single-node
10
- smoke run (tracked in temp/step7.7-*.md) to verify end-to-end.
11
- """
12
-
13
- import importlib.util
14
- import json
15
- import sys
16
- import unittest
17
- from pathlib import Path
18
- from unittest.mock import MagicMock, patch
19
-
20
- SCRIPTS_DIR = Path(__file__).parent.parent
21
- spec = importlib.util.spec_from_file_location(
22
- "update_issue", SCRIPTS_DIR / "update-issue-from-registry.py"
23
- )
24
- update_issue = importlib.util.module_from_spec(spec)
25
- sys.modules["update_issue"] = update_issue
26
- spec.loader.exec_module(update_issue)
27
-
28
-
29
- def _mock_gh_result(stdout: str = "", returncode: int = 0, stderr: str = "") -> MagicMock:
30
- r = MagicMock()
31
- r.stdout = stdout
32
- r.returncode = returncode
33
- r.stderr = stderr
34
- return r
35
-
36
-
37
- class GhWrapperTests(unittest.TestCase):
38
- def test_dry_run_skips_subprocess(self):
39
- with patch.object(update_issue.subprocess, "run") as mock_run:
40
- result = update_issue.gh(["issue", "view", "1"], dry_run=True)
41
- mock_run.assert_not_called()
42
- self.assertEqual(result, "")
43
-
44
- def test_success_returns_stdout(self):
45
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result("hello")):
46
- out = update_issue.gh(["issue", "view", "1"])
47
- self.assertEqual(out, "hello")
48
-
49
- def test_failure_raises(self):
50
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result("", 1, "boom")):
51
- with self.assertRaises(RuntimeError):
52
- update_issue.gh(["issue", "view", "1"])
53
-
54
- def test_missing_binary(self):
55
- with patch.object(update_issue.subprocess, "run", side_effect=FileNotFoundError()):
56
- with self.assertRaises(RuntimeError):
57
- update_issue.gh(["issue", "view", "1"])
58
-
59
- def test_always_captures(self):
60
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result("ok")) as mock_run:
61
- update_issue.gh(["issue", "view", "1"])
62
- self.assertTrue(mock_run.call_args[1].get("capture_output"))
63
-
64
-
65
- class GhGraphqlTests(unittest.TestCase):
66
- def test_parses_data_field(self):
67
- payload = json.dumps({"data": {"viewer": {"login": "me"}}})
68
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result(payload)):
69
- out = update_issue.gh_graphql("query { viewer { login } }")
70
- self.assertEqual(out, {"viewer": {"login": "me"}})
71
-
72
- def test_raises_on_errors(self):
73
- payload = json.dumps({"errors": [{"message": "bad"}]})
74
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result(payload)):
75
- with self.assertRaises(RuntimeError):
76
- update_issue.gh_graphql("query { x }")
77
-
78
- def test_dry_run_returns_empty_dict(self):
79
- with patch.object(update_issue.subprocess, "run") as mock_run:
80
- out = update_issue.gh_graphql("query { x }", dry_run=True)
81
- mock_run.assert_not_called()
82
- self.assertEqual(out, {})
83
-
84
- def test_bad_json_raises(self):
85
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result("not json")):
86
- with self.assertRaises(RuntimeError):
87
- update_issue.gh_graphql("query { x }")
88
-
89
-
90
- class CloseDuplicateTests(unittest.TestCase):
91
- def test_posts_comment_then_closes(self):
92
- calls = []
93
-
94
- def fake_run(args, **kwargs):
95
- calls.append(list(args))
96
- return _mock_gh_result("")
97
-
98
- with patch.object(update_issue.subprocess, "run", side_effect=fake_run):
99
- update_issue.close_duplicate(99, 42, "r", dry_run=False)
100
-
101
- self.assertEqual(len(calls), 2)
102
- self.assertIn("comment", calls[0])
103
- self.assertIn("99", calls[0])
104
- self.assertIn("close", calls[1])
105
- self.assertIn("99", calls[1])
106
- body_idx = calls[0].index("--body") + 1
107
- self.assertIn("#42", calls[0][body_idx])
108
-
109
-
110
- class CreateMissingIssueTests(unittest.TestCase):
111
- def test_builds_correct_gh_create_invocation(self):
112
- entry = {
113
- "nodeId": "5:17752",
114
- "componentName": {"ios": "Button", "android": "Button"},
115
- "fileKey": "K",
116
- }
117
- create_stdout = "https://github.com/o/r/issues/123\n"
118
- states = {"implemented": "green", "tested": "gray", "codeConnect": "gray", "wiki": "gray"}
119
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result(create_stdout)) as mock_run:
120
- num = update_issue.create_missing_issue(
121
- entry, states, "o/r", "team:core", dry_run=False,
122
- )
123
-
124
- self.assertEqual(num, 123)
125
- args = mock_run.call_args[0][0]
126
- self.assertIn("create", args)
127
- label_values = [args[i + 1] for i, a in enumerate(args) if a == "--label"]
128
- self.assertIn("component", label_values)
129
- self.assertIn("team:core", label_values)
130
- # Critical: no flag labels applied at creation
131
- self.assertNotIn("implemented:green", label_values)
132
- self.assertNotIn("implemented:yellow", label_values)
133
-
134
- def test_title_uses_component_name(self):
135
- entry = {"nodeId": "1:1", "componentName": "MyThing", "fileKey": "K"}
136
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result("https://gh/issues/5")) as mock_run:
137
- update_issue.create_missing_issue(entry, {}, "o/r", "team:core", dry_run=False)
138
- args = mock_run.call_args[0][0]
139
- title_idx = args.index("--title") + 1
140
- self.assertIn("MyThing", args[title_idx])
141
-
142
- def test_dry_run_returns_none(self):
143
- entry = {"nodeId": "1:1", "componentName": {"ios": "X"}, "fileKey": "K"}
144
- with patch.object(update_issue.subprocess, "run") as mock_run:
145
- num = update_issue.create_missing_issue(entry, {}, "o/r", "team:core", dry_run=True)
146
- mock_run.assert_not_called()
147
- self.assertIsNone(num)
148
-
149
-
150
- class GetIssueBodyTests(unittest.TestCase):
151
- def test_parses_json_body(self):
152
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result(json.dumps({"body": "hello"}))):
153
- body = update_issue.get_issue_body(42, "r")
154
- self.assertEqual(body, "hello")
155
-
156
- def test_handles_bad_json(self):
157
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result("not json")):
158
- body = update_issue.get_issue_body(42, "r")
159
- self.assertEqual(body, "")
160
-
161
-
162
- class SyncProjectFieldsTests(unittest.TestCase):
163
- def test_calls_graphql_once_per_flag(self):
164
- graphql_calls = []
165
-
166
- def fake_run(args, **kwargs):
167
- # Only graphql calls matter
168
- graphql_calls.append(args)
169
- return _mock_gh_result(json.dumps({"data": {"updateProjectV2ItemFieldValue": {"projectV2Item": {"id": "X"}}}}))
170
-
171
- states = {"implemented": "green", "tested": "yellow", "codeConnect": "gray", "wiki": "green"}
172
- with patch.object(update_issue.subprocess, "run", side_effect=fake_run):
173
- applied = update_issue.sync_project_fields(
174
- item_id="I",
175
- flag_states=states,
176
- )
177
- # All 4 flags mapped
178
- self.assertEqual(len(graphql_calls), 4)
179
- self.assertEqual(applied["implemented"], "green")
180
- self.assertEqual(applied["tested"], "yellow")
181
- self.assertEqual(applied["codeConnect"], "gray")
182
- self.assertEqual(applied["wiki"], "green")
183
-
184
- def test_unknown_flag_is_skipped(self):
185
- with patch.object(update_issue.subprocess, "run", return_value=_mock_gh_result(json.dumps({"data": {}}))) as mock_run:
186
- applied = update_issue.sync_project_fields(
187
- item_id="I",
188
- flag_states={"implemented": "green", "bogus": "green"},
189
- )
190
- self.assertIn("implemented", applied)
191
- self.assertNotIn("bogus", applied)
192
-
193
-
194
- if __name__ == "__main__":
195
- unittest.main(verbosity=2)