@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,808 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Figma Utility Script
4
- Standalone tool for querying Figma data via REST API and MCP.
5
-
6
- Usage:
7
- python3 figma-utility.py <command> [options]
8
-
9
- Commands:
10
- screenshot --url <figma-url> [--output path] [--scale 1|2|3|4]
11
- metadata --url <figma-url> [--output path]
12
- properties --url <figma-url> [--output path]
13
- tokens --url <figma-url> [--output path]
14
- context --url <figma-url> [--output path]
15
- code-connect --url <figma-url> [--output path]
16
- node --url <figma-url> [--output path] [--depth N]
17
- components --url <figma-url> [--output path]
18
- styles --url <figma-url> [--output path]
19
- file --url <figma-url> [--output path] [--depth N]
20
- whoami
21
-
22
- Token resolution: --figma-token / --mcp-token CLI arg > macOS Keychain > Claude Code credentials
23
-
24
- Exit 0 = success (prints result to stdout)
25
- Exit 1 = failure (prints JSON error to stderr)
26
- """
27
-
28
- import argparse
29
- import base64
30
- import http.client
31
- import json
32
- import os
33
- import re
34
- import subprocess
35
- import sys
36
- from pathlib import Path
37
- from urllib.error import HTTPError, URLError
38
- from urllib.parse import urlparse
39
- from urllib.request import Request, urlopen
40
-
41
-
42
- # ─── Globals ─────────────────────────────────────────────────────────────────
43
-
44
- MCP_MODE = None # "remote" or "local"
45
- MCP_URL = "http://127.0.0.1:3845/mcp"
46
- MCP_TOKEN = None
47
- SESSION_ID = None
48
- FIGMA_TOKEN = None
49
-
50
-
51
- def log(msg):
52
- print(f"[figma-utility] {msg}", file=sys.stderr)
53
-
54
-
55
- def error_exit(code, message, hint=""):
56
- print(json.dumps({
57
- "status": "error",
58
- "message": message,
59
- "hint": hint,
60
- }, indent=2), file=sys.stderr)
61
- sys.exit(code)
62
-
63
-
64
- # ─── URL Parsing ─────────────────────────────────────────────────────────────
65
-
66
- def parse_figma_url(url):
67
- """Extract fileKey and nodeId from a Figma URL.
68
-
69
- Returns (fileKey, nodeId) where nodeId uses colon format (e.g. '123:456').
70
- nodeId may be None if not present in the URL.
71
- """
72
- if not url:
73
- return None, None
74
-
75
- # Match: figma.com/design/{fileKey}/... or figma.com/file/{fileKey}/...
76
- m = re.search(r'figma\.com/(?:design|file)/([A-Za-z0-9]+)', url)
77
- if not m:
78
- # Try branch URL
79
- m = re.search(r'figma\.com/(?:design|file)/[^/]+/[^?]*\?.*branch-id=([A-Za-z0-9]+)', url)
80
- file_key = m.group(1) if m else None
81
-
82
- # Extract node-id from query params
83
- node_id = None
84
- nm = re.search(r'node-id=([0-9]+-[0-9]+)', url)
85
- if nm:
86
- node_id = nm.group(1).replace("-", ":")
87
- else:
88
- nm = re.search(r'node-id=([0-9]+%3A[0-9]+)', url)
89
- if nm:
90
- node_id = nm.group(1).replace("%3A", ":")
91
-
92
- return file_key, node_id
93
-
94
-
95
- # ─── Token Resolution ────────────────────────────────────────────────────────
96
-
97
- def get_figma_token(cli_token=None):
98
- """Resolve Figma REST API token: CLI arg > Keychain FIGMA_ACCESS_TOKEN."""
99
- if cli_token:
100
- return cli_token
101
- try:
102
- token = subprocess.check_output(
103
- ["security", "find-generic-password", "-a", os.environ["USER"],
104
- "-s", "FIGMA_ACCESS_TOKEN", "-w"],
105
- stderr=subprocess.DEVNULL,
106
- ).decode().strip()
107
- if token:
108
- log("REST token from Keychain: FIGMA_ACCESS_TOKEN")
109
- return token
110
- except (subprocess.CalledProcessError, KeyError):
111
- pass
112
- return None
113
-
114
-
115
- def get_mcp_token(cli_token=None):
116
- """Resolve MCP OAuth token: CLI arg > Keychain FIGMA_MCP_TOKEN > Claude Code credentials."""
117
- if cli_token:
118
- return cli_token
119
- # Keychain: dedicated entry
120
- try:
121
- token = subprocess.check_output(
122
- ["security", "find-generic-password", "-a", os.environ["USER"],
123
- "-s", "FIGMA_MCP_TOKEN", "-w"],
124
- stderr=subprocess.DEVNULL,
125
- ).decode().strip()
126
- if token:
127
- log("MCP token from Keychain: FIGMA_MCP_TOKEN")
128
- return token
129
- except (subprocess.CalledProcessError, KeyError):
130
- pass
131
- # Keychain: extract from Claude Code credentials
132
- try:
133
- raw = subprocess.check_output(
134
- ["security", "find-generic-password", "-s", "Claude Code-credentials",
135
- "-a", os.environ["USER"], "-w"],
136
- stderr=subprocess.DEVNULL,
137
- ).decode()
138
- match = re.search(
139
- r'"figma-remote\|[^"]+":\{[^}]*"accessToken":"([^"]+)"', raw
140
- )
141
- if match:
142
- log("MCP token extracted from Claude Code credentials")
143
- return match.group(1)
144
- except (subprocess.CalledProcessError, KeyError):
145
- pass
146
- return None
147
-
148
-
149
- # ─── REST API ────────────────────────────────────────────────────────────────
150
-
151
- def figma_get(endpoint):
152
- """GET from Figma REST API. Returns parsed JSON."""
153
- if not FIGMA_TOKEN:
154
- error_exit(1, "No Figma REST API token found.",
155
- "Run /figma-setup or pass --figma-token.")
156
- url = f"https://api.figma.com/v1/{endpoint}"
157
- req = Request(url, headers={"X-Figma-Token": FIGMA_TOKEN})
158
- try:
159
- with urlopen(req, timeout=60) as resp:
160
- return json.loads(resp.read().decode())
161
- except HTTPError as e:
162
- body = e.read().decode() if hasattr(e, 'read') else ""
163
- error_exit(1, f"Figma API HTTP {e.code}: {body[:300]}",
164
- f"Endpoint: {endpoint}")
165
- except URLError as e:
166
- error_exit(1, f"Figma API connection error: {e.reason}",
167
- "Check your network connection.")
168
-
169
-
170
- def download_file(url, dest):
171
- """Download a URL to a local file path."""
172
- req = Request(url)
173
- with urlopen(req, timeout=60) as resp:
174
- Path(dest).parent.mkdir(parents=True, exist_ok=True)
175
- with open(dest, "wb") as f:
176
- f.write(resp.read())
177
- return True
178
-
179
-
180
- # ─── MCP Helpers ─────────────────────────────────────────────────────────────
181
-
182
- def _parse_sse_json(raw):
183
- """Parse JSON from SSE response. Handles multiline data payloads."""
184
- data_start = raw.find("\ndata: ")
185
- if data_start == -1:
186
- data_start = raw.find("data: ")
187
- if data_start == -1:
188
- return None
189
-
190
- json_str = raw[raw.index("data: ", data_start) + 6:].strip()
191
- try:
192
- return json.loads(json_str)
193
- except json.JSONDecodeError:
194
- depth = 0
195
- end = 0
196
- for i, ch in enumerate(json_str):
197
- if ch == "{":
198
- depth += 1
199
- elif ch == "}":
200
- depth -= 1
201
- if depth == 0:
202
- end = i + 1
203
- break
204
- if end > 0:
205
- try:
206
- return json.loads(json_str[:end])
207
- except json.JSONDecodeError:
208
- pass
209
- return None
210
-
211
-
212
- def _mcp_post_local(body_dict):
213
- """POST to local MCP (HTTP, session-based)."""
214
- parsed = urlparse(MCP_URL)
215
- conn = http.client.HTTPConnection(parsed.hostname, parsed.port, timeout=120)
216
- headers = {
217
- "Content-Type": "application/json",
218
- "Accept": "application/json, text/event-stream",
219
- }
220
- if SESSION_ID:
221
- headers["mcp-session-id"] = SESSION_ID
222
- conn.request("POST", parsed.path, body=json.dumps(body_dict), headers=headers)
223
- resp = conn.getresponse()
224
- session = resp.getheader("mcp-session-id")
225
- raw = resp.read().decode()
226
- conn.close()
227
- return _parse_sse_json(raw), session
228
-
229
-
230
- def _mcp_post_remote(body_dict):
231
- """POST to remote MCP (HTTPS, Bearer auth, stateless)."""
232
- conn = http.client.HTTPSConnection("mcp.figma.com", timeout=120)
233
- headers = {
234
- "Content-Type": "application/json",
235
- "Accept": "application/json, text/event-stream",
236
- "Authorization": f"Bearer {MCP_TOKEN}",
237
- }
238
- conn.request("POST", "/mcp", body=json.dumps(body_dict), headers=headers)
239
- resp = conn.getresponse()
240
- raw = resp.read().decode()
241
- conn.close()
242
- if resp.status != 200:
243
- raise RuntimeError(f"Remote MCP HTTP {resp.status}: {raw[:200]}")
244
- return _parse_sse_json(raw), None
245
-
246
-
247
- def _mcp_post(body_dict):
248
- if MCP_MODE == "remote":
249
- return _mcp_post_remote(body_dict)
250
- else:
251
- return _mcp_post_local(body_dict)
252
-
253
-
254
- def mcp_init():
255
- """Initialize MCP connection. Tries local first, falls back to remote."""
256
- global MCP_MODE, SESSION_ID
257
-
258
- init_body = {
259
- "jsonrpc": "2.0",
260
- "method": "initialize",
261
- "params": {
262
- "capabilities": {},
263
- "clientInfo": {"name": "figma-utility", "version": "1.0.0"},
264
- "protocolVersion": "2025-03-26",
265
- },
266
- "id": 1,
267
- }
268
-
269
- # Try local first (faster, no rate limits)
270
- try:
271
- log(f"MCP: trying local ({MCP_URL})...")
272
- result, session = _mcp_post_local(init_body)
273
- if session:
274
- SESSION_ID = session
275
- MCP_MODE = "local"
276
- log(f"MCP: local connected (session: {SESSION_ID[:12]}...)")
277
- return True
278
- except Exception as exc:
279
- log(f"MCP: local failed ({exc})")
280
-
281
- # Fall back to remote
282
- if MCP_TOKEN:
283
- try:
284
- log("MCP: trying remote (mcp.figma.com)...")
285
- result, _ = _mcp_post_remote(init_body)
286
- if result:
287
- MCP_MODE = "remote"
288
- log("MCP: remote connected")
289
- return True
290
- except Exception as exc:
291
- log(f"MCP: remote failed ({exc})")
292
-
293
- return False
294
-
295
-
296
- _MCP_CALL_ID = 10
297
-
298
-
299
- def mcp_call(tool_name, arguments, file_key=None):
300
- """Call an MCP tool. Returns (texts, images) lists."""
301
- global _MCP_CALL_ID
302
- _MCP_CALL_ID += 1
303
-
304
- # Remote MCP requires fileKey
305
- if MCP_MODE == "remote" and file_key and "fileKey" not in arguments:
306
- arguments = {**arguments, "fileKey": file_key}
307
-
308
- body = {
309
- "jsonrpc": "2.0",
310
- "method": "tools/call",
311
- "params": {"name": tool_name, "arguments": arguments},
312
- "id": _MCP_CALL_ID,
313
- }
314
-
315
- result_json, _ = _mcp_post(body)
316
- if not result_json:
317
- raise RuntimeError(f"MCP {tool_name}: empty response")
318
- if "error" in result_json:
319
- raise RuntimeError(f"MCP {tool_name}: {result_json['error']}")
320
-
321
- texts = []
322
- images = []
323
- content = (result_json.get("result") or {}).get("content", [])
324
- for item in content:
325
- if item.get("type") == "text":
326
- texts.append(item["text"])
327
- elif item.get("type") == "image":
328
- images.append({
329
- "mimeType": item.get("mimeType", "image/png"),
330
- "data": item.get("data", ""),
331
- })
332
- return texts, images
333
-
334
-
335
- # ─── Commands ────────────────────────────────────────────────────────────────
336
-
337
- def cmd_screenshot(file_key, node_id, output_path=None, scale=2):
338
- """Get PNG screenshot of a node."""
339
- # Try REST API first (returns URL, more efficient for saving)
340
- if FIGMA_TOKEN:
341
- log(f"Fetching screenshot via REST API (scale={scale})...")
342
- data = figma_get(f"images/{file_key}?ids={node_id}&format=png&scale={scale}")
343
- images = data.get("images", {})
344
- img_url = images.get(node_id)
345
- if img_url:
346
- if output_path:
347
- download_file(img_url, output_path)
348
- log(f"Screenshot saved: {output_path}")
349
- print(json.dumps({
350
- "status": "ok",
351
- "command": "screenshot",
352
- "output": output_path,
353
- "source": "rest-api",
354
- }, indent=2))
355
- return
356
- else:
357
- print(json.dumps({
358
- "status": "ok",
359
- "command": "screenshot",
360
- "url": img_url,
361
- "source": "rest-api",
362
- "hint": "Use --output to save to file",
363
- }, indent=2))
364
- return
365
-
366
- # Fallback to MCP
367
- if MCP_MODE:
368
- log("Fetching screenshot via MCP...")
369
- texts, images = mcp_call("get_screenshot", {"nodeId": node_id}, file_key)
370
- if images:
371
- img_data = base64.b64decode(images[0]["data"])
372
- if output_path:
373
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
374
- with open(output_path, "wb") as f:
375
- f.write(img_data)
376
- log(f"Screenshot saved: {output_path} ({len(img_data)} bytes)")
377
- print(json.dumps({
378
- "status": "ok",
379
- "command": "screenshot",
380
- "output": output_path,
381
- "bytes": len(img_data),
382
- "source": f"mcp-{MCP_MODE}",
383
- }, indent=2))
384
- return
385
- else:
386
- print(json.dumps({
387
- "status": "ok",
388
- "command": "screenshot",
389
- "bytes": len(img_data),
390
- "source": f"mcp-{MCP_MODE}",
391
- "hint": "Use --output to save to file (base64 data available via MCP)",
392
- }, indent=2))
393
- return
394
-
395
- error_exit(1, "No screenshot source available.",
396
- "Provide --figma-token for REST API or ensure MCP is available.")
397
-
398
-
399
- def cmd_metadata(file_key, node_id, output_path=None):
400
- """Get layer hierarchy (XML) of a node."""
401
- if not MCP_MODE:
402
- error_exit(1, "MCP required for metadata.", "Ensure Figma Desktop or remote MCP is available.")
403
-
404
- log("Fetching metadata via MCP...")
405
- texts, _ = mcp_call("get_metadata", {"nodeId": node_id}, file_key)
406
- result = "\n".join(texts)
407
-
408
- if output_path:
409
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
410
- Path(output_path).write_text(result)
411
- log(f"Metadata saved: {output_path} ({len(result)} chars)")
412
-
413
- print(result)
414
-
415
-
416
- def cmd_properties(file_key, node_id, output_path=None):
417
- """Get component properties/variants via REST API."""
418
- log("Fetching node data via REST API...")
419
- data = figma_get(f"files/{file_key}/nodes?ids={node_id}")
420
-
421
- nodes = data.get("nodes", {})
422
- node_data = nodes.get(node_id, {})
423
- document = node_data.get("document", {})
424
-
425
- # Extract component property definitions
426
- prop_defs = document.get("componentPropertyDefinitions", {})
427
-
428
- # Also check children for component set
429
- if not prop_defs and document.get("type") == "COMPONENT_SET":
430
- children = document.get("children", [])
431
- if children:
432
- prop_defs = children[0].get("componentPropertyDefinitions", {})
433
-
434
- # Build structured output
435
- properties = {}
436
- for prop_name, prop_def in prop_defs.items():
437
- properties[prop_name] = {
438
- "type": prop_def.get("type"),
439
- "defaultValue": prop_def.get("defaultValue"),
440
- }
441
- if prop_def.get("variantOptions"):
442
- properties[prop_name]["options"] = prop_def["variantOptions"]
443
-
444
- result = {
445
- "status": "ok",
446
- "command": "properties",
447
- "nodeId": node_id,
448
- "name": document.get("name", ""),
449
- "type": document.get("type", ""),
450
- "propertyCount": len(properties),
451
- "properties": properties,
452
- }
453
-
454
- # Count variants if component set
455
- if document.get("type") == "COMPONENT_SET":
456
- result["variantCount"] = len(document.get("children", []))
457
-
458
- output = json.dumps(result, indent=2)
459
- if output_path:
460
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
461
- Path(output_path).write_text(output)
462
- log(f"Properties saved: {output_path}")
463
-
464
- print(output)
465
-
466
-
467
- def cmd_tokens(file_key, node_id, output_path=None):
468
- """Get design tokens/variables for a node."""
469
- if not MCP_MODE:
470
- # Fallback to REST API (may 403 on non-Enterprise)
471
- log("MCP unavailable, trying REST API for variables...")
472
- try:
473
- data = figma_get(f"files/{file_key}/variables/local")
474
- output = json.dumps({"status": "ok", "command": "tokens", "source": "rest-api", "data": data}, indent=2)
475
- if output_path:
476
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
477
- Path(output_path).write_text(output)
478
- print(output)
479
- return
480
- except SystemExit:
481
- error_exit(1, "Neither MCP nor REST API available for tokens.",
482
- "Ensure Figma Desktop or remote MCP is available.")
483
-
484
- log("Fetching tokens via MCP...")
485
- texts, _ = mcp_call("get_variable_defs", {"nodeId": node_id}, file_key)
486
- result_text = "\n".join(texts)
487
-
488
- # Try to parse as JSON for structured output
489
- try:
490
- token_data = json.loads(result_text)
491
- output = json.dumps({
492
- "status": "ok",
493
- "command": "tokens",
494
- "source": f"mcp-{MCP_MODE}",
495
- "tokenCount": len(token_data) if isinstance(token_data, dict) else None,
496
- "data": token_data,
497
- }, indent=2)
498
- except json.JSONDecodeError:
499
- output = result_text
500
-
501
- if output_path:
502
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
503
- Path(output_path).write_text(output)
504
- log(f"Tokens saved: {output_path}")
505
-
506
- print(output)
507
-
508
-
509
- def cmd_context(file_key, node_id, output_path=None):
510
- """Get design context (code generation) for a node."""
511
- if not MCP_MODE:
512
- error_exit(1, "MCP required for design context.", "Ensure Figma Desktop or remote MCP is available.")
513
-
514
- log("Fetching design context via MCP...")
515
- args = {
516
- "nodeId": node_id,
517
- "disableCodeConnect": True,
518
- }
519
- texts, _ = mcp_call("get_design_context", args, file_key)
520
- result = "\n".join(texts)
521
-
522
- if output_path:
523
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
524
- Path(output_path).write_text(result)
525
- log(f"Design context saved: {output_path} ({len(result)} chars)")
526
-
527
- print(result)
528
-
529
-
530
- def cmd_code_connect(file_key, node_id, output_path=None):
531
- """Get Code Connect mappings for a node."""
532
- if not MCP_MODE:
533
- error_exit(1, "MCP required for Code Connect.", "Ensure Figma Desktop or remote MCP is available.")
534
-
535
- log("Fetching Code Connect mappings via MCP...")
536
- args = {"nodeId": node_id, "codeConnectLabel": "SwiftUI"}
537
- texts, _ = mcp_call("get_code_connect_map", args, file_key)
538
- result = "\n".join(texts)
539
-
540
- # Try to structure the output
541
- try:
542
- cc_data = json.loads(result)
543
- output = json.dumps({
544
- "status": "ok",
545
- "command": "code-connect",
546
- "source": f"mcp-{MCP_MODE}",
547
- "mappings": cc_data,
548
- }, indent=2)
549
- except json.JSONDecodeError:
550
- output = result
551
-
552
- if output_path:
553
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
554
- Path(output_path).write_text(output)
555
- log(f"Code Connect saved: {output_path}")
556
-
557
- print(output)
558
-
559
-
560
- def cmd_node(file_key, node_id, output_path=None, depth=None):
561
- """Get raw node data from REST API."""
562
- log("Fetching node data via REST API...")
563
- endpoint = f"files/{file_key}/nodes?ids={node_id}"
564
- if depth is not None:
565
- endpoint += f"&depth={depth}"
566
-
567
- data = figma_get(endpoint)
568
- output = json.dumps(data, indent=2)
569
-
570
- if output_path:
571
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
572
- Path(output_path).write_text(output)
573
- log(f"Node data saved: {output_path} ({len(output)} chars)")
574
-
575
- print(output)
576
-
577
-
578
- def cmd_components(file_key, output_path=None):
579
- """List all components in a Figma file."""
580
- log("Fetching components via REST API...")
581
- data = figma_get(f"files/{file_key}/components")
582
-
583
- components = data.get("meta", {}).get("components", [])
584
- result = {
585
- "status": "ok",
586
- "command": "components",
587
- "fileKey": file_key,
588
- "count": len(components),
589
- "components": [
590
- {
591
- "key": c.get("key"),
592
- "name": c.get("name"),
593
- "nodeId": c.get("node_id"),
594
- "containingFrame": c.get("containing_frame", {}).get("name"),
595
- "pageName": c.get("containing_frame", {}).get("pageName"),
596
- }
597
- for c in components
598
- ],
599
- }
600
- output = json.dumps(result, indent=2)
601
-
602
- if output_path:
603
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
604
- Path(output_path).write_text(output)
605
- log(f"Components saved: {output_path}")
606
-
607
- print(output)
608
-
609
-
610
- def cmd_styles(file_key, output_path=None):
611
- """Get all styles in a Figma file."""
612
- log("Fetching styles via REST API...")
613
- data = figma_get(f"files/{file_key}/styles")
614
-
615
- styles = data.get("meta", {}).get("styles", [])
616
- result = {
617
- "status": "ok",
618
- "command": "styles",
619
- "fileKey": file_key,
620
- "count": len(styles),
621
- "styles": [
622
- {
623
- "key": s.get("key"),
624
- "name": s.get("name"),
625
- "styleType": s.get("style_type"),
626
- "nodeId": s.get("node_id"),
627
- "description": s.get("description"),
628
- }
629
- for s in styles
630
- ],
631
- }
632
- output = json.dumps(result, indent=2)
633
-
634
- if output_path:
635
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
636
- Path(output_path).write_text(output)
637
- log(f"Styles saved: {output_path}")
638
-
639
- print(output)
640
-
641
-
642
- def cmd_file(file_key, output_path=None, depth=None):
643
- """Get file document tree (summary)."""
644
- log("Fetching file tree via REST API...")
645
- endpoint = f"files/{file_key}"
646
- if depth is not None:
647
- endpoint += f"?depth={depth}"
648
-
649
- data = figma_get(endpoint)
650
-
651
- # Build summary
652
- doc = data.get("document", {})
653
- pages = []
654
- for page in doc.get("children", []):
655
- page_info = {
656
- "name": page.get("name"),
657
- "id": page.get("id"),
658
- "childCount": len(page.get("children", [])),
659
- }
660
- pages.append(page_info)
661
-
662
- result = {
663
- "status": "ok",
664
- "command": "file",
665
- "fileName": data.get("name"),
666
- "lastModified": data.get("lastModified"),
667
- "version": data.get("version"),
668
- "pageCount": len(pages),
669
- "pages": pages,
670
- }
671
-
672
- # If output requested, save full data; otherwise print summary
673
- if output_path:
674
- full_output = json.dumps(data, indent=2)
675
- Path(output_path).parent.mkdir(parents=True, exist_ok=True)
676
- Path(output_path).write_text(full_output)
677
- log(f"File data saved: {output_path} ({len(full_output)} chars)")
678
- print(json.dumps(result, indent=2))
679
- else:
680
- print(json.dumps(result, indent=2))
681
-
682
-
683
- def cmd_whoami():
684
- """Check MCP auth status."""
685
- if not MCP_MODE:
686
- error_exit(1, "MCP not available.", "Ensure Figma Desktop or remote MCP is available.")
687
-
688
- if MCP_MODE == "local":
689
- print(json.dumps({
690
- "status": "ok",
691
- "command": "whoami",
692
- "mode": "local",
693
- "message": "Connected to local Figma MCP (Figma Desktop)",
694
- "endpoint": MCP_URL,
695
- }, indent=2))
696
- return
697
-
698
- # Remote: call whoami
699
- log("Calling whoami on remote MCP...")
700
- texts, _ = mcp_call("whoami", {})
701
- result = "\n".join(texts)
702
- try:
703
- user_data = json.loads(result)
704
- print(json.dumps({
705
- "status": "ok",
706
- "command": "whoami",
707
- "mode": "remote",
708
- "data": user_data,
709
- }, indent=2))
710
- except json.JSONDecodeError:
711
- print(json.dumps({
712
- "status": "ok",
713
- "command": "whoami",
714
- "mode": "remote",
715
- "raw": result,
716
- }, indent=2))
717
-
718
-
719
- # ─── Main ────────────────────────────────────────────────────────────────────
720
-
721
- def main():
722
- parser = argparse.ArgumentParser(
723
- description="Figma Utility - query Figma data via REST API and MCP",
724
- formatter_class=argparse.RawDescriptionHelpFormatter,
725
- )
726
- parser.add_argument("command", choices=[
727
- "screenshot", "metadata", "properties", "tokens", "context",
728
- "code-connect", "node", "components", "styles", "file", "whoami",
729
- ])
730
- parser.add_argument("--url", help="Figma URL")
731
- parser.add_argument("--file-key", help="Figma file key (alternative to URL)")
732
- parser.add_argument("--node-id", help="Node ID in colon format e.g. 123:456 (alternative to URL)")
733
- parser.add_argument("--output", "-o", help="Save output to file path")
734
- parser.add_argument("--scale", type=int, default=2, choices=[1, 2, 3, 4],
735
- help="Screenshot scale (default: 2)")
736
- parser.add_argument("--depth", type=int, help="Depth limit for node/file tree")
737
- parser.add_argument("--figma-token", help="Figma REST API token (falls back to Keychain)")
738
- parser.add_argument("--mcp-token", help="MCP OAuth token (falls back to Keychain)")
739
- parser.add_argument("--mcp-url", default="http://127.0.0.1:3845/mcp",
740
- help="Local MCP endpoint URL")
741
-
742
- args = parser.parse_args()
743
-
744
- # ── Resolve tokens ──
745
- global FIGMA_TOKEN, MCP_TOKEN, MCP_URL
746
- FIGMA_TOKEN = get_figma_token(args.figma_token)
747
- MCP_TOKEN = get_mcp_token(args.mcp_token)
748
- MCP_URL = args.mcp_url
749
-
750
- # ── Parse URL or use explicit file-key/node-id ──
751
- file_key = args.file_key
752
- node_id = args.node_id
753
-
754
- if args.url:
755
- url_fk, url_nid = parse_figma_url(args.url)
756
- file_key = file_key or url_fk
757
- node_id = node_id or url_nid
758
-
759
- # ── Validate required params ──
760
- if args.command == "whoami":
761
- # whoami doesn't need URL
762
- pass
763
- elif args.command in ("components", "styles", "file"):
764
- # These only need file_key
765
- if not file_key:
766
- error_exit(1, "File key required.", "Provide --url or --file-key.")
767
- else:
768
- # All other commands need file_key + node_id
769
- if not file_key:
770
- error_exit(1, "File key required.", "Provide --url or --file-key.")
771
- if not node_id:
772
- error_exit(1, "Node ID required.", "Provide a URL with node-id or --node-id.")
773
-
774
- # ── Init MCP for commands that need it ──
775
- mcp_commands = {"metadata", "tokens", "context", "code-connect", "whoami", "screenshot"}
776
- if args.command in mcp_commands:
777
- mcp_ok = mcp_init()
778
- if not mcp_ok and args.command not in ("screenshot", "tokens"):
779
- error_exit(1, "MCP connection failed.",
780
- "Ensure Figma Desktop is running (Dev Mode) or remote MCP token is available.")
781
-
782
- # ── Dispatch ──
783
- if args.command == "screenshot":
784
- cmd_screenshot(file_key, node_id, args.output, args.scale)
785
- elif args.command == "metadata":
786
- cmd_metadata(file_key, node_id, args.output)
787
- elif args.command == "properties":
788
- cmd_properties(file_key, node_id, args.output)
789
- elif args.command == "tokens":
790
- cmd_tokens(file_key, node_id, args.output)
791
- elif args.command == "context":
792
- cmd_context(file_key, node_id, args.output)
793
- elif args.command == "code-connect":
794
- cmd_code_connect(file_key, node_id, args.output)
795
- elif args.command == "node":
796
- cmd_node(file_key, node_id, args.output, args.depth)
797
- elif args.command == "components":
798
- cmd_components(file_key, args.output)
799
- elif args.command == "styles":
800
- cmd_styles(file_key, args.output)
801
- elif args.command == "file":
802
- cmd_file(file_key, args.output, args.depth)
803
- elif args.command == "whoami":
804
- cmd_whoami()
805
-
806
-
807
- if __name__ == "__main__":
808
- main()