@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,592 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Figma Remote MCP Token Fetcher
4
-
5
- Retrieves or refreshes a Figma MCP OAuth token. Three modes:
6
-
7
- MODE 1 - Extract (default):
8
- Reads existing token from Keychain or Claude Code credentials.
9
- python3 fetch-mcp-token.py
10
-
11
- MODE 2 - OAuth (--oauth):
12
- Runs full OAuth flow. Opens browser for Figma consent, runs local
13
- callback server, exchanges code for token. Works from ANY terminal.
14
- python3 fetch-mcp-token.py --oauth --client-id X --client-secret Y --save-keychain
15
-
16
- Credentials are extracted from Claude Code keychain if available,
17
- or must be provided via --client-id and --client-secret.
18
-
19
- COMMON FLAGS:
20
- --save-keychain Save token to macOS Keychain as FIGMA_MCP_TOKEN
21
- --verify Verify token against Figma MCP server
22
- --quiet Only print the token to stdout
23
- --port PORT Local callback server port (default: 8923)
24
- --client-id OAuth client ID (required for --oauth if no Claude Code)
25
- --client-secret OAuth client secret (required for --oauth if no Claude Code)
26
- --show-clients Show OAuth clients from Claude Code credentials
27
- """
28
-
29
- import argparse
30
- import base64
31
- import hashlib
32
- import http.server
33
- import json
34
- import os
35
- import re
36
- import secrets
37
- import subprocess
38
- import sys
39
- import threading
40
- import time
41
- import urllib.parse
42
- import urllib.request
43
-
44
- # ─── Configuration ──────────────────────────────────────────────────────────
45
-
46
- KEYCHAIN_SERVICE = "FIGMA_MCP_TOKEN"
47
- KEYCHAIN_REFRESH_SERVICE = "FIGMA_MCP_REFRESH_TOKEN"
48
- KEYCHAIN_CLIENT_ID_SERVICE = "FIGMA_MCP_CLIENT_ID"
49
- KEYCHAIN_CLIENT_SECRET_SERVICE = "FIGMA_MCP_CLIENT_SECRET"
50
- CLAUDE_CREDENTIALS_SERVICE = "Claude Code-credentials"
51
- MCP_SERVER_URL = "https://mcp.figma.com/mcp"
52
- AUTH_ENDPOINT = "https://www.figma.com/oauth/mcp"
53
- TOKEN_ENDPOINT = "https://api.figma.com/v1/oauth/token"
54
- REFRESH_ENDPOINT = "https://api.figma.com/v1/oauth/refresh"
55
- DEFAULT_PORT = 8923
56
-
57
-
58
- # ─── Helpers ────────────────────────────────────────────────────────────────
59
-
60
- def log(msg):
61
- print(f"[fetch-mcp-token] {msg}", file=sys.stderr)
62
-
63
-
64
- def get_claude_credentials_raw():
65
- """Read raw Claude Code credentials from Keychain."""
66
- try:
67
- return subprocess.check_output(
68
- ["security", "find-generic-password", "-s", CLAUDE_CREDENTIALS_SERVICE,
69
- "-a", os.environ["USER"], "-w"],
70
- stderr=subprocess.DEVNULL
71
- ).decode()
72
- except (subprocess.CalledProcessError, KeyError):
73
- return None
74
-
75
-
76
- # ─── Token Sources ──────────────────────────────────────────────────────────
77
-
78
- def get_from_dedicated_keychain():
79
- """Source 1: Dedicated FIGMA_MCP_TOKEN keychain entry."""
80
- try:
81
- token = subprocess.check_output(
82
- ["security", "find-generic-password", "-a", os.environ["USER"],
83
- "-s", KEYCHAIN_SERVICE, "-w"],
84
- stderr=subprocess.DEVNULL
85
- ).decode().strip()
86
- if token and token.startswith("figu_"):
87
- return token, "keychain:FIGMA_MCP_TOKEN"
88
- except (subprocess.CalledProcessError, KeyError):
89
- pass
90
- return None, None
91
-
92
-
93
- def get_from_claude_credentials():
94
- """Source 2: Extract accessToken from Claude Code's credential store."""
95
- raw = get_claude_credentials_raw()
96
- if not raw:
97
- return None, None
98
- match = re.search(
99
- r'"figma-remote\|[^"]+":\{[^}]*"accessToken":"([^"]+)"', raw
100
- )
101
- if match:
102
- token = match.group(1)
103
- if token.startswith("figu_"):
104
- return token, "keychain:Claude Code-credentials"
105
- return None, None
106
-
107
-
108
- def get_expiry_from_claude_credentials():
109
- """Extract expiresAt from Claude Code credentials."""
110
- raw = get_claude_credentials_raw()
111
- if not raw:
112
- return None
113
- match = re.search(
114
- r'"figma-remote\|[^"]+":\{[^}]*"expiresAt":(\d+)', raw
115
- )
116
- if match:
117
- import datetime
118
- ts = int(match.group(1)) / 1000
119
- return datetime.datetime.fromtimestamp(ts).isoformat()
120
- return None
121
-
122
-
123
- def get_client_credentials_from_claude():
124
- """Extract clientId + clientSecret from Claude Code credentials."""
125
- raw = get_claude_credentials_raw()
126
- if not raw:
127
- return []
128
- clients = []
129
- # Find all clientRegistration blocks with their parent server context
130
- for m in re.finditer(r'"clientId":"([^"]+)"', raw):
131
- cid = m.group(1)
132
- # Look for clientSecret right after
133
- after = raw[m.end():m.end() + 200]
134
- sec_match = re.search(r'"clientSecret":"([^"]+)"', after)
135
- # Look backwards for serverName
136
- before = raw[max(0, m.start() - 500):m.start()]
137
- srv_match = re.search(r'"serverName":"([^"]+)"', before)
138
- url_match = re.search(r'"serverUrl":"([^"]+)"', before)
139
- clients.append({
140
- "clientId": cid,
141
- "clientSecret": sec_match.group(1) if sec_match else None,
142
- "serverName": srv_match.group(1) if srv_match else "unknown",
143
- "serverUrl": url_match.group(1) if url_match else "unknown",
144
- })
145
- return clients
146
-
147
-
148
- # ─── Keychain & Verify ──────────────────────────────────────────────────────
149
-
150
- def save_to_keychain(token, service=KEYCHAIN_SERVICE):
151
- """Save token to macOS Keychain."""
152
- user = os.environ.get("USER", "")
153
- subprocess.run(
154
- ["security", "delete-generic-password", "-a", user, "-s", service],
155
- capture_output=True
156
- )
157
- result = subprocess.run(
158
- ["security", "add-generic-password", "-a", user, "-s", service, "-w", token],
159
- capture_output=True
160
- )
161
- return result.returncode == 0
162
-
163
-
164
- def get_refresh_token_from_keychain():
165
- """Read refresh token from macOS Keychain."""
166
- try:
167
- return subprocess.check_output(
168
- ["security", "find-generic-password", "-a", os.environ["USER"],
169
- "-s", KEYCHAIN_REFRESH_SERVICE, "-w"],
170
- stderr=subprocess.DEVNULL
171
- ).decode().strip() or None
172
- except (subprocess.CalledProcessError, KeyError):
173
- return None
174
-
175
-
176
- def get_client_credentials_from_keychain():
177
- """Read client_id and client_secret from macOS Keychain."""
178
- try:
179
- cid = subprocess.check_output(
180
- ["security", "find-generic-password", "-a", os.environ["USER"],
181
- "-s", KEYCHAIN_CLIENT_ID_SERVICE, "-w"],
182
- stderr=subprocess.DEVNULL
183
- ).decode().strip()
184
- csec = subprocess.check_output(
185
- ["security", "find-generic-password", "-a", os.environ["USER"],
186
- "-s", KEYCHAIN_CLIENT_SECRET_SERVICE, "-w"],
187
- stderr=subprocess.DEVNULL
188
- ).decode().strip()
189
- if cid and csec:
190
- return cid, csec
191
- except (subprocess.CalledProcessError, KeyError):
192
- pass
193
- return None, None
194
-
195
-
196
- def refresh_access_token(refresh_token, client_id, client_secret):
197
- """Use refresh_token to obtain a new access_token from Figma."""
198
- auth_str = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()
199
- body = urllib.parse.urlencode({"refresh_token": refresh_token}).encode()
200
- req = urllib.request.Request(
201
- REFRESH_ENDPOINT,
202
- data=body,
203
- headers={
204
- "Content-Type": "application/x-www-form-urlencoded",
205
- "Authorization": f"Basic {auth_str}",
206
- },
207
- method="POST",
208
- )
209
- try:
210
- with urllib.request.urlopen(req) as resp:
211
- result = json.loads(resp.read().decode())
212
- except urllib.error.HTTPError as e:
213
- body_text = e.read().decode()
214
- log(f"Refresh failed (HTTP {e.code}): {body_text}")
215
- return None
216
-
217
- new_token = result.get("access_token")
218
- expires_in = result.get("expires_in", "unknown")
219
- if new_token:
220
- log(f"Token refreshed: {new_token[:10]}...{new_token[-6:]}")
221
- log(f"Expires in: {expires_in}s")
222
- else:
223
- log(f"No access_token in refresh response: {json.dumps(result, indent=2)}")
224
- return new_token
225
-
226
-
227
- def verify_token(token):
228
- """Verify token against Figma MCP server."""
229
- try:
230
- req = urllib.request.Request(
231
- MCP_SERVER_URL,
232
- data=json.dumps({
233
- "jsonrpc": "2.0",
234
- "method": "initialize",
235
- "params": {
236
- "capabilities": {},
237
- "clientInfo": {"name": "token-verify", "version": "1.0.0"},
238
- "protocolVersion": "2025-03-26"
239
- },
240
- "id": 1
241
- }).encode(),
242
- headers={
243
- "Content-Type": "application/json",
244
- "Accept": "application/json, text/event-stream",
245
- "Authorization": f"Bearer {token}"
246
- },
247
- method="POST"
248
- )
249
- with urllib.request.urlopen(req) as resp:
250
- return resp.status == 200
251
- except urllib.error.HTTPError as e:
252
- if e.code == 401:
253
- return False
254
- raise
255
- except Exception:
256
- return False
257
-
258
-
259
- # ─── OAuth Flow ─────────────────────────────────────────────────────────────
260
-
261
- class OAuthCallbackHandler(http.server.BaseHTTPRequestHandler):
262
- """HTTP handler that captures the OAuth callback."""
263
- auth_code = None
264
- auth_state = None
265
- error = None
266
-
267
- def do_GET(self):
268
- parsed = urllib.parse.urlparse(self.path)
269
- params = urllib.parse.parse_qs(parsed.query)
270
- if parsed.path == "/callback":
271
- if "error" in params:
272
- OAuthCallbackHandler.error = params["error"][0]
273
- self._respond(200, "<h2>Authorization failed.</h2><p>You can close this tab.</p>")
274
- elif "code" in params:
275
- OAuthCallbackHandler.auth_code = params["code"][0]
276
- OAuthCallbackHandler.auth_state = params.get("state", [None])[0]
277
- self._respond(200, "<h2>Authorization successful!</h2><p>Return to your terminal.</p>")
278
- else:
279
- self._respond(400, "Missing code parameter")
280
- else:
281
- self._respond(404, "Not found")
282
-
283
- def _respond(self, code, body):
284
- self.send_response(code)
285
- self.send_header("Content-Type", "text/html")
286
- self.end_headers()
287
- self.wfile.write(f"<html><body>{body}</body></html>".encode())
288
-
289
- def log_message(self, format, *args):
290
- pass
291
-
292
-
293
- def generate_pkce():
294
- """Generate PKCE code_verifier and code_challenge (S256)."""
295
- verifier = secrets.token_urlsafe(64)[:128]
296
- digest = hashlib.sha256(verifier.encode("ascii")).digest()
297
- challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
298
- return verifier, challenge
299
-
300
-
301
- def run_oauth_flow(client_id, client_secret, port):
302
- """Run the full OAuth 2.0 + PKCE flow and return access_token."""
303
- redirect_uri = f"http://localhost:{port}/callback"
304
-
305
- # Reset handler state
306
- OAuthCallbackHandler.auth_code = None
307
- OAuthCallbackHandler.auth_state = None
308
- OAuthCallbackHandler.error = None
309
-
310
- # Generate PKCE
311
- code_verifier, code_challenge = generate_pkce()
312
- state = secrets.token_urlsafe(32)
313
-
314
- # Start callback server
315
- log(f"Starting callback server on port {port}...")
316
- server = http.server.HTTPServer(("localhost", port), OAuthCallbackHandler)
317
- server_thread = threading.Thread(target=server.serve_forever, daemon=True)
318
- server_thread.start()
319
-
320
- # Build authorization URL
321
- auth_params = urllib.parse.urlencode({
322
- "client_id": client_id,
323
- "redirect_uri": redirect_uri,
324
- "response_type": "code",
325
- "scope": "mcp:connect",
326
- "state": state,
327
- "code_challenge": code_challenge,
328
- "code_challenge_method": "S256",
329
- })
330
- auth_url = f"{AUTH_ENDPOINT}?{auth_params}"
331
-
332
- log("Opening browser for Figma authorization...")
333
- log(f" If browser doesn't open, visit:")
334
- log(f" {auth_url}")
335
-
336
- import webbrowser
337
- webbrowser.open(auth_url)
338
-
339
- # Wait for callback
340
- log("Waiting for authorization (120s timeout)...")
341
- timeout = 120
342
- start = time.time()
343
- while OAuthCallbackHandler.auth_code is None and OAuthCallbackHandler.error is None:
344
- if time.time() - start > timeout:
345
- server.shutdown()
346
- log("Timeout waiting for authorization.")
347
- return None
348
- time.sleep(0.5)
349
-
350
- server.shutdown()
351
-
352
- if OAuthCallbackHandler.error:
353
- log(f"Authorization error: {OAuthCallbackHandler.error}")
354
- return None
355
-
356
- if OAuthCallbackHandler.auth_state != state:
357
- log("State mismatch - possible CSRF.")
358
- return None
359
-
360
- auth_code = OAuthCallbackHandler.auth_code
361
- log("Authorization code received. Exchanging for token...")
362
-
363
- # Exchange code for token
364
- token_data = urllib.parse.urlencode({
365
- "grant_type": "authorization_code",
366
- "code": auth_code,
367
- "redirect_uri": redirect_uri,
368
- "client_id": client_id,
369
- "client_secret": client_secret,
370
- "code_verifier": code_verifier,
371
- }).encode()
372
-
373
- req = urllib.request.Request(
374
- TOKEN_ENDPOINT,
375
- data=token_data,
376
- headers={"Content-Type": "application/x-www-form-urlencoded"},
377
- method="POST",
378
- )
379
-
380
- try:
381
- with urllib.request.urlopen(req) as resp:
382
- result = json.loads(resp.read().decode())
383
- except urllib.error.HTTPError as e:
384
- body = e.read().decode()
385
- log(f"Token exchange failed (HTTP {e.code}): {body}")
386
- return None
387
-
388
- access_token = result.get("access_token")
389
- refresh_token = result.get("refresh_token")
390
- expires_in = result.get("expires_in", "unknown")
391
-
392
- if access_token:
393
- log(f"Token obtained: {access_token[:10]}...{access_token[-6:]}")
394
- log(f"Expires in: {expires_in}s")
395
- if refresh_token:
396
- log(f"Refresh token obtained: {refresh_token[:10]}...{refresh_token[-6:]}")
397
- else:
398
- log(f"No access_token in response: {json.dumps(result, indent=2)}")
399
-
400
- return access_token, refresh_token
401
-
402
-
403
- # ─── Main ───────────────────────────────────────────────────────────────────
404
-
405
- def main():
406
- parser = argparse.ArgumentParser(
407
- description="Retrieve or refresh Figma MCP OAuth token"
408
- )
409
- parser.add_argument("--oauth", action="store_true",
410
- help="Run full OAuth flow (opens browser)")
411
- parser.add_argument("--client-id",
412
- help="OAuth client ID (extracted from Claude Code or provided manually)")
413
- parser.add_argument("--client-secret",
414
- help="OAuth client secret")
415
- parser.add_argument("--show-clients", action="store_true",
416
- help="Show registered OAuth clients from Claude Code credentials")
417
- parser.add_argument("--save-keychain", action="store_true",
418
- help=f"Save token to macOS Keychain as {KEYCHAIN_SERVICE}")
419
- parser.add_argument("--verify", action="store_true",
420
- help="Verify token against Figma MCP server")
421
- parser.add_argument("--quiet", action="store_true",
422
- help="Only print the token to stdout")
423
- parser.add_argument("--port", type=int, default=DEFAULT_PORT,
424
- help=f"Callback server port (default: {DEFAULT_PORT})")
425
- args = parser.parse_args()
426
-
427
- # ── Show clients mode ───────────────────────────────────────────────
428
- if args.show_clients:
429
- clients = get_client_credentials_from_claude()
430
- if not clients:
431
- log("No OAuth clients found in Claude Code credentials.")
432
- sys.exit(1)
433
- for i, c in enumerate(clients):
434
- print(f"Client {i+1}:")
435
- print(f" Server: {c['serverName']}")
436
- print(f" URL: {c['serverUrl']}")
437
- print(f" clientId: {c['clientId']}")
438
- print(f" clientSecret: {c['clientSecret']}")
439
- print()
440
- log(f"Found {len(clients)} registered client(s).")
441
- log("Use with: --oauth --client-id <id> --client-secret <secret>")
442
- sys.exit(0)
443
-
444
- # ── OAuth mode ──────────────────────────────────────────────────────
445
- if args.oauth:
446
- client_id = args.client_id
447
- client_secret = args.client_secret
448
-
449
- # Auto-extract from Claude Code credentials if not provided
450
- if not client_id or not client_secret:
451
- clients = get_client_credentials_from_claude()
452
- figma_clients = [c for c in clients if "figma" in c.get("serverUrl", "")]
453
- if figma_clients:
454
- client_id = client_id or figma_clients[0]["clientId"]
455
- client_secret = client_secret or figma_clients[0]["clientSecret"]
456
- else:
457
- log("No client credentials provided and none found in Claude Code.")
458
- log("Use: --client-id <id> --client-secret <secret>")
459
- sys.exit(1)
460
-
461
- if not args.quiet:
462
- log(f"Using client credentials ({client_id})")
463
-
464
- token, refresh_token = run_oauth_flow(client_id, client_secret, args.port)
465
- if not token:
466
- sys.exit(1)
467
-
468
- if args.verify:
469
- if not args.quiet:
470
- log("Verifying token...")
471
- if verify_token(token):
472
- if not args.quiet:
473
- log("Token is VALID.")
474
- else:
475
- if not args.quiet:
476
- log("Token is INVALID.")
477
- sys.exit(2)
478
-
479
- if args.save_keychain:
480
- if save_to_keychain(token):
481
- if not args.quiet:
482
- log(f"Saved to Keychain as '{KEYCHAIN_SERVICE}'.")
483
- else:
484
- if not args.quiet:
485
- log("Failed to save to Keychain.")
486
- sys.exit(3)
487
- # Save refresh_token alongside access_token
488
- if refresh_token:
489
- if save_to_keychain(refresh_token, service=KEYCHAIN_REFRESH_SERVICE):
490
- if not args.quiet:
491
- log(f"Saved refresh token to Keychain as '{KEYCHAIN_REFRESH_SERVICE}'.")
492
- else:
493
- if not args.quiet:
494
- log("Failed to save refresh token to Keychain.")
495
- # Save client credentials for future auto-refresh
496
- save_to_keychain(client_id, service=KEYCHAIN_CLIENT_ID_SERVICE)
497
- save_to_keychain(client_secret, service=KEYCHAIN_CLIENT_SECRET_SERVICE)
498
- if not args.quiet:
499
- log("Saved client credentials to Keychain for future auto-refresh.")
500
-
501
- print(token)
502
- sys.exit(0)
503
-
504
- # ── Extract mode (default) ──────────────────────────────────────────
505
- token, source = get_from_dedicated_keychain()
506
- if not token:
507
- token, source = get_from_claude_credentials()
508
-
509
- if not token:
510
- if not args.quiet:
511
- log("No Figma MCP token found.")
512
- log("")
513
- log("Options:")
514
- log(" 1. Run with --oauth to get a new token via browser")
515
- log(" 2. Use an MCP-enabled session to trigger OAuth first")
516
- log(" 3. Get credentials from a colleague: --show-clients")
517
- sys.exit(1)
518
-
519
- if not args.quiet:
520
- log(f"Token from: {source}")
521
- log(f"Token: {token[:10]}...{token[-6:]}")
522
- expiry = get_expiry_from_claude_credentials()
523
- if expiry:
524
- log(f"Expires: {expiry}")
525
-
526
- if args.verify:
527
- if not args.quiet:
528
- log("Verifying...")
529
- if verify_token(token):
530
- if not args.quiet:
531
- log("Token is VALID.")
532
- else:
533
- # Token invalid - try auto-refresh before giving up
534
- if not args.quiet:
535
- log("Token is INVALID or EXPIRED. Attempting auto-refresh...")
536
- refresh_tok = get_refresh_token_from_keychain()
537
- refreshed = False
538
- if refresh_tok:
539
- # Need client credentials for refresh
540
- cid = args.client_id
541
- csec = args.client_secret
542
- # Try Keychain first (saved during --oauth --save-keychain)
543
- if not cid or not csec:
544
- kc_cid, kc_csec = get_client_credentials_from_keychain()
545
- cid = cid or kc_cid
546
- csec = csec or kc_csec
547
- # Fall back to Claude Code credentials
548
- if not cid or not csec:
549
- clients = get_client_credentials_from_claude()
550
- figma_clients = [c for c in clients if "figma" in c.get("serverUrl", "")]
551
- if figma_clients:
552
- cid = cid or figma_clients[0]["clientId"]
553
- csec = csec or figma_clients[0]["clientSecret"]
554
- if cid and csec:
555
- new_token = refresh_access_token(refresh_tok, cid, csec)
556
- if new_token and verify_token(new_token):
557
- token = new_token
558
- refreshed = True
559
- if not args.quiet:
560
- log("Token refreshed successfully.")
561
- if args.save_keychain or source == f"keychain:{KEYCHAIN_SERVICE}":
562
- save_to_keychain(token)
563
- if not args.quiet:
564
- log(f"Updated Keychain '{KEYCHAIN_SERVICE}'.")
565
- else:
566
- if not args.quiet:
567
- log("Refresh failed - token or credentials expired.")
568
- else:
569
- if not args.quiet:
570
- log("No client credentials available for refresh.")
571
- else:
572
- if not args.quiet:
573
- log("No refresh token in Keychain.")
574
- if not refreshed:
575
- if not args.quiet:
576
- log("Try --oauth to get a new token via browser.")
577
- sys.exit(2)
578
-
579
- if args.save_keychain and source != f"keychain:{KEYCHAIN_SERVICE}":
580
- if save_to_keychain(token):
581
- if not args.quiet:
582
- log(f"Saved to Keychain as '{KEYCHAIN_SERVICE}'.")
583
- else:
584
- if not args.quiet:
585
- log("Failed to save to Keychain.")
586
- sys.exit(3)
587
-
588
- print(token)
589
-
590
-
591
- if __name__ == "__main__":
592
- main()