@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,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)