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