@mmerterden/multi-agent-pipeline 11.2.0 → 11.3.1

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