@muloka/figma-console-mcp 0.1.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 (443) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +898 -0
  3. package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts +14 -0
  4. package/dist/apps/design-system-dashboard/scoring/accessibility.d.ts.map +1 -0
  5. package/dist/apps/design-system-dashboard/scoring/accessibility.js +278 -0
  6. package/dist/apps/design-system-dashboard/scoring/accessibility.js.map +1 -0
  7. package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts +29 -0
  8. package/dist/apps/design-system-dashboard/scoring/component-metadata.d.ts.map +1 -0
  9. package/dist/apps/design-system-dashboard/scoring/component-metadata.js +358 -0
  10. package/dist/apps/design-system-dashboard/scoring/component-metadata.js.map +1 -0
  11. package/dist/apps/design-system-dashboard/scoring/consistency.d.ts +14 -0
  12. package/dist/apps/design-system-dashboard/scoring/consistency.d.ts.map +1 -0
  13. package/dist/apps/design-system-dashboard/scoring/consistency.js +342 -0
  14. package/dist/apps/design-system-dashboard/scoring/consistency.js.map +1 -0
  15. package/dist/apps/design-system-dashboard/scoring/coverage.d.ts +14 -0
  16. package/dist/apps/design-system-dashboard/scoring/coverage.d.ts.map +1 -0
  17. package/dist/apps/design-system-dashboard/scoring/coverage.js +231 -0
  18. package/dist/apps/design-system-dashboard/scoring/coverage.js.map +1 -0
  19. package/dist/apps/design-system-dashboard/scoring/engine.d.ts +27 -0
  20. package/dist/apps/design-system-dashboard/scoring/engine.d.ts.map +1 -0
  21. package/dist/apps/design-system-dashboard/scoring/engine.js +93 -0
  22. package/dist/apps/design-system-dashboard/scoring/engine.js.map +1 -0
  23. package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts +14 -0
  24. package/dist/apps/design-system-dashboard/scoring/naming-semantics.d.ts.map +1 -0
  25. package/dist/apps/design-system-dashboard/scoring/naming-semantics.js +309 -0
  26. package/dist/apps/design-system-dashboard/scoring/naming-semantics.js.map +1 -0
  27. package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts +14 -0
  28. package/dist/apps/design-system-dashboard/scoring/token-architecture.d.ts.map +1 -0
  29. package/dist/apps/design-system-dashboard/scoring/token-architecture.js +350 -0
  30. package/dist/apps/design-system-dashboard/scoring/token-architecture.js.map +1 -0
  31. package/dist/apps/design-system-dashboard/scoring/types.d.ts +89 -0
  32. package/dist/apps/design-system-dashboard/scoring/types.d.ts.map +1 -0
  33. package/dist/apps/design-system-dashboard/scoring/types.js +41 -0
  34. package/dist/apps/design-system-dashboard/scoring/types.js.map +1 -0
  35. package/dist/apps/design-system-dashboard/server.d.ts +24 -0
  36. package/dist/apps/design-system-dashboard/server.d.ts.map +1 -0
  37. package/dist/apps/design-system-dashboard/server.js +160 -0
  38. package/dist/apps/design-system-dashboard/server.js.map +1 -0
  39. package/dist/apps/token-browser/server.d.ts +26 -0
  40. package/dist/apps/token-browser/server.d.ts.map +1 -0
  41. package/dist/apps/token-browser/server.js +137 -0
  42. package/dist/apps/token-browser/server.js.map +1 -0
  43. package/dist/browser/base.d.ts +58 -0
  44. package/dist/browser/base.d.ts.map +1 -0
  45. package/dist/browser/base.js +6 -0
  46. package/dist/browser/base.js.map +1 -0
  47. package/dist/browser/local.d.ts +87 -0
  48. package/dist/browser/local.d.ts.map +1 -0
  49. package/dist/browser/local.js +318 -0
  50. package/dist/browser/local.js.map +1 -0
  51. package/dist/cloudflare/apps/design-system-dashboard/scoring/accessibility.js +277 -0
  52. package/dist/cloudflare/apps/design-system-dashboard/scoring/component-metadata.js +357 -0
  53. package/dist/cloudflare/apps/design-system-dashboard/scoring/consistency.js +341 -0
  54. package/dist/cloudflare/apps/design-system-dashboard/scoring/coverage.js +230 -0
  55. package/dist/cloudflare/apps/design-system-dashboard/scoring/engine.js +92 -0
  56. package/dist/cloudflare/apps/design-system-dashboard/scoring/naming-semantics.js +308 -0
  57. package/dist/cloudflare/apps/design-system-dashboard/scoring/token-architecture.js +349 -0
  58. package/dist/cloudflare/apps/design-system-dashboard/scoring/types.js +40 -0
  59. package/dist/cloudflare/apps/design-system-dashboard/server.js +159 -0
  60. package/dist/cloudflare/apps/token-browser/server.js +136 -0
  61. package/dist/cloudflare/browser-manager.js +157 -0
  62. package/dist/cloudflare/core/accessibility-tools.js +361 -0
  63. package/dist/cloudflare/core/annotation-tools.js +230 -0
  64. package/dist/cloudflare/core/cloud-websocket-connector.js +419 -0
  65. package/dist/cloudflare/core/cloud-websocket-relay.js +198 -0
  66. package/dist/cloudflare/core/comment-tools.js +292 -0
  67. package/dist/cloudflare/core/config.js +153 -0
  68. package/dist/cloudflare/core/console-monitor.js +427 -0
  69. package/dist/cloudflare/core/deep-component-tools.js +128 -0
  70. package/dist/cloudflare/core/design-code-tools.js +2793 -0
  71. package/dist/cloudflare/core/design-system-manifest.js +265 -0
  72. package/dist/cloudflare/core/design-system-tools.js +882 -0
  73. package/dist/cloudflare/core/diagnose-tool.js +100 -0
  74. package/dist/cloudflare/core/diff/changelog-formatter.js +275 -0
  75. package/dist/cloudflare/core/diff/diff-engine.js +334 -0
  76. package/dist/cloudflare/core/diff/property-compare.js +36 -0
  77. package/dist/cloudflare/core/diff/version-cache.js +74 -0
  78. package/dist/cloudflare/core/enrichment/enrichment-service.js +374 -0
  79. package/dist/cloudflare/core/enrichment/index.js +7 -0
  80. package/dist/cloudflare/core/enrichment/relationship-mapper.js +351 -0
  81. package/dist/cloudflare/core/enrichment/style-resolver.js +346 -0
  82. package/dist/cloudflare/core/figjam-tools.js +547 -0
  83. package/dist/cloudflare/core/figma-api.js +509 -0
  84. package/dist/cloudflare/core/figma-connector.js +7 -0
  85. package/dist/cloudflare/core/figma-reconstruction-spec.js +402 -0
  86. package/dist/cloudflare/core/figma-style-extractor.js +311 -0
  87. package/dist/cloudflare/core/figma-tools.js +3302 -0
  88. package/dist/cloudflare/core/identity.js +96 -0
  89. package/dist/cloudflare/core/library-tools.js +580 -0
  90. package/dist/cloudflare/core/logger.js +53 -0
  91. package/dist/cloudflare/core/port-discovery.js +935 -0
  92. package/dist/cloudflare/core/resolve-package-root.js +11 -0
  93. package/dist/cloudflare/core/slides-tools.js +714 -0
  94. package/dist/cloudflare/core/slot-tools.js +334 -0
  95. package/dist/cloudflare/core/snippet-injector.js +96 -0
  96. package/dist/cloudflare/core/tokens/alias-resolver.js +205 -0
  97. package/dist/cloudflare/core/tokens/config.js +294 -0
  98. package/dist/cloudflare/core/tokens/dialect.js +232 -0
  99. package/dist/cloudflare/core/tokens/figma-converter.js +323 -0
  100. package/dist/cloudflare/core/tokens/formatters/css-vars.js +338 -0
  101. package/dist/cloudflare/core/tokens/formatters/dtcg.js +376 -0
  102. package/dist/cloudflare/core/tokens/formatters/index.js +45 -0
  103. package/dist/cloudflare/core/tokens/formatters/json.js +205 -0
  104. package/dist/cloudflare/core/tokens/formatters/less.js +4 -0
  105. package/dist/cloudflare/core/tokens/formatters/scss.js +258 -0
  106. package/dist/cloudflare/core/tokens/formatters/stubs.js +13 -0
  107. package/dist/cloudflare/core/tokens/formatters/style-dictionary-v3.js +213 -0
  108. package/dist/cloudflare/core/tokens/formatters/tailwind-v3.js +237 -0
  109. package/dist/cloudflare/core/tokens/formatters/tailwind-v4.js +335 -0
  110. package/dist/cloudflare/core/tokens/formatters/tokens-studio.js +256 -0
  111. package/dist/cloudflare/core/tokens/formatters/ts-module.js +198 -0
  112. package/dist/cloudflare/core/tokens/index.js +16 -0
  113. package/dist/cloudflare/core/tokens/parsers/css-vars.js +4 -0
  114. package/dist/cloudflare/core/tokens/parsers/dtcg.js +280 -0
  115. package/dist/cloudflare/core/tokens/parsers/index.js +138 -0
  116. package/dist/cloudflare/core/tokens/parsers/json.js +7 -0
  117. package/dist/cloudflare/core/tokens/parsers/scss.js +4 -0
  118. package/dist/cloudflare/core/tokens/parsers/stubs.js +20 -0
  119. package/dist/cloudflare/core/tokens/parsers/style-dictionary-v3.js +4 -0
  120. package/dist/cloudflare/core/tokens/parsers/tailwind-v3.js +4 -0
  121. package/dist/cloudflare/core/tokens/parsers/tailwind-v4.js +4 -0
  122. package/dist/cloudflare/core/tokens/parsers/tokens-studio.js +4 -0
  123. package/dist/cloudflare/core/tokens/schemas.js +152 -0
  124. package/dist/cloudflare/core/tokens/transforms/color.js +12 -0
  125. package/dist/cloudflare/core/tokens/transforms/index.js +29 -0
  126. package/dist/cloudflare/core/tokens/transforms/size.js +7 -0
  127. package/dist/cloudflare/core/tokens/types.js +18 -0
  128. package/dist/cloudflare/core/tokens-tools.js +1788 -0
  129. package/dist/cloudflare/core/types/design-code.js +4 -0
  130. package/dist/cloudflare/core/types/enriched.js +5 -0
  131. package/dist/cloudflare/core/types/index.js +4 -0
  132. package/dist/cloudflare/core/variable-resolver.js +85 -0
  133. package/dist/cloudflare/core/version-tools.js +1199 -0
  134. package/dist/cloudflare/core/websocket-connector.js +436 -0
  135. package/dist/cloudflare/core/websocket-server.js +956 -0
  136. package/dist/cloudflare/core/write-tools.js +2506 -0
  137. package/dist/cloudflare/index.js +3010 -0
  138. package/dist/core/accessibility-tools.d.ts +21 -0
  139. package/dist/core/accessibility-tools.d.ts.map +1 -0
  140. package/dist/core/accessibility-tools.js +362 -0
  141. package/dist/core/accessibility-tools.js.map +1 -0
  142. package/dist/core/annotation-tools.d.ts +14 -0
  143. package/dist/core/annotation-tools.d.ts.map +1 -0
  144. package/dist/core/annotation-tools.js +231 -0
  145. package/dist/core/annotation-tools.js.map +1 -0
  146. package/dist/core/comment-tools.d.ts +11 -0
  147. package/dist/core/comment-tools.d.ts.map +1 -0
  148. package/dist/core/comment-tools.js +293 -0
  149. package/dist/core/comment-tools.js.map +1 -0
  150. package/dist/core/config.d.ts +17 -0
  151. package/dist/core/config.d.ts.map +1 -0
  152. package/dist/core/config.js +154 -0
  153. package/dist/core/config.js.map +1 -0
  154. package/dist/core/console-monitor.d.ts +82 -0
  155. package/dist/core/console-monitor.d.ts.map +1 -0
  156. package/dist/core/console-monitor.js +428 -0
  157. package/dist/core/console-monitor.js.map +1 -0
  158. package/dist/core/deep-component-tools.d.ts +14 -0
  159. package/dist/core/deep-component-tools.d.ts.map +1 -0
  160. package/dist/core/deep-component-tools.js +129 -0
  161. package/dist/core/deep-component-tools.js.map +1 -0
  162. package/dist/core/design-code-tools.d.ts +116 -0
  163. package/dist/core/design-code-tools.d.ts.map +1 -0
  164. package/dist/core/design-code-tools.js +2794 -0
  165. package/dist/core/design-code-tools.js.map +1 -0
  166. package/dist/core/design-system-manifest.d.ts +273 -0
  167. package/dist/core/design-system-manifest.d.ts.map +1 -0
  168. package/dist/core/design-system-manifest.js +266 -0
  169. package/dist/core/design-system-manifest.js.map +1 -0
  170. package/dist/core/design-system-tools.d.ts +67 -0
  171. package/dist/core/design-system-tools.d.ts.map +1 -0
  172. package/dist/core/design-system-tools.js +883 -0
  173. package/dist/core/design-system-tools.js.map +1 -0
  174. package/dist/core/diagnose-tool.d.ts +41 -0
  175. package/dist/core/diagnose-tool.d.ts.map +1 -0
  176. package/dist/core/diagnose-tool.js +101 -0
  177. package/dist/core/diagnose-tool.js.map +1 -0
  178. package/dist/core/diff/changelog-formatter.d.ts +35 -0
  179. package/dist/core/diff/changelog-formatter.d.ts.map +1 -0
  180. package/dist/core/diff/changelog-formatter.js +276 -0
  181. package/dist/core/diff/changelog-formatter.js.map +1 -0
  182. package/dist/core/diff/diff-engine.d.ts +127 -0
  183. package/dist/core/diff/diff-engine.d.ts.map +1 -0
  184. package/dist/core/diff/diff-engine.js +335 -0
  185. package/dist/core/diff/diff-engine.js.map +1 -0
  186. package/dist/core/diff/property-compare.d.ts +19 -0
  187. package/dist/core/diff/property-compare.d.ts.map +1 -0
  188. package/dist/core/diff/property-compare.js +37 -0
  189. package/dist/core/diff/property-compare.js.map +1 -0
  190. package/dist/core/diff/version-cache.d.ts +40 -0
  191. package/dist/core/diff/version-cache.d.ts.map +1 -0
  192. package/dist/core/diff/version-cache.js +75 -0
  193. package/dist/core/diff/version-cache.js.map +1 -0
  194. package/dist/core/enrichment/enrichment-service.d.ts +52 -0
  195. package/dist/core/enrichment/enrichment-service.d.ts.map +1 -0
  196. package/dist/core/enrichment/enrichment-service.js +375 -0
  197. package/dist/core/enrichment/enrichment-service.js.map +1 -0
  198. package/dist/core/enrichment/index.d.ts +8 -0
  199. package/dist/core/enrichment/index.d.ts.map +1 -0
  200. package/dist/core/enrichment/index.js +8 -0
  201. package/dist/core/enrichment/index.js.map +1 -0
  202. package/dist/core/enrichment/relationship-mapper.d.ts +106 -0
  203. package/dist/core/enrichment/relationship-mapper.d.ts.map +1 -0
  204. package/dist/core/enrichment/relationship-mapper.js +352 -0
  205. package/dist/core/enrichment/relationship-mapper.js.map +1 -0
  206. package/dist/core/enrichment/style-resolver.d.ts +85 -0
  207. package/dist/core/enrichment/style-resolver.d.ts.map +1 -0
  208. package/dist/core/enrichment/style-resolver.js +347 -0
  209. package/dist/core/enrichment/style-resolver.js.map +1 -0
  210. package/dist/core/figjam-tools.d.ts +8 -0
  211. package/dist/core/figjam-tools.d.ts.map +1 -0
  212. package/dist/core/figjam-tools.js +548 -0
  213. package/dist/core/figjam-tools.js.map +1 -0
  214. package/dist/core/figma-api.d.ts +254 -0
  215. package/dist/core/figma-api.d.ts.map +1 -0
  216. package/dist/core/figma-api.js +510 -0
  217. package/dist/core/figma-api.js.map +1 -0
  218. package/dist/core/figma-connector.d.ts +214 -0
  219. package/dist/core/figma-connector.d.ts.map +1 -0
  220. package/dist/core/figma-connector.js +8 -0
  221. package/dist/core/figma-connector.js.map +1 -0
  222. package/dist/core/figma-desktop-connector.d.ts +312 -0
  223. package/dist/core/figma-desktop-connector.d.ts.map +1 -0
  224. package/dist/core/figma-desktop-connector.js +1298 -0
  225. package/dist/core/figma-desktop-connector.js.map +1 -0
  226. package/dist/core/figma-reconstruction-spec.d.ts +166 -0
  227. package/dist/core/figma-reconstruction-spec.d.ts.map +1 -0
  228. package/dist/core/figma-reconstruction-spec.js +403 -0
  229. package/dist/core/figma-reconstruction-spec.js.map +1 -0
  230. package/dist/core/figma-style-extractor.d.ts +76 -0
  231. package/dist/core/figma-style-extractor.d.ts.map +1 -0
  232. package/dist/core/figma-style-extractor.js +312 -0
  233. package/dist/core/figma-style-extractor.js.map +1 -0
  234. package/dist/core/figma-tools.d.ts +22 -0
  235. package/dist/core/figma-tools.d.ts.map +1 -0
  236. package/dist/core/figma-tools.js +3303 -0
  237. package/dist/core/figma-tools.js.map +1 -0
  238. package/dist/core/identity.d.ts +41 -0
  239. package/dist/core/identity.d.ts.map +1 -0
  240. package/dist/core/identity.js +97 -0
  241. package/dist/core/identity.js.map +1 -0
  242. package/dist/core/library-tools.d.ts +17 -0
  243. package/dist/core/library-tools.d.ts.map +1 -0
  244. package/dist/core/library-tools.js +581 -0
  245. package/dist/core/library-tools.js.map +1 -0
  246. package/dist/core/logger.d.ts +22 -0
  247. package/dist/core/logger.d.ts.map +1 -0
  248. package/dist/core/logger.js +54 -0
  249. package/dist/core/logger.js.map +1 -0
  250. package/dist/core/port-discovery.d.ts +211 -0
  251. package/dist/core/port-discovery.d.ts.map +1 -0
  252. package/dist/core/port-discovery.js +936 -0
  253. package/dist/core/port-discovery.js.map +1 -0
  254. package/dist/core/resolve-package-root.d.ts +2 -0
  255. package/dist/core/resolve-package-root.d.ts.map +1 -0
  256. package/dist/core/resolve-package-root.js +12 -0
  257. package/dist/core/resolve-package-root.js.map +1 -0
  258. package/dist/core/slides-tools.d.ts +8 -0
  259. package/dist/core/slides-tools.d.ts.map +1 -0
  260. package/dist/core/slides-tools.js +715 -0
  261. package/dist/core/slides-tools.js.map +1 -0
  262. package/dist/core/slot-tools.d.ts +7 -0
  263. package/dist/core/slot-tools.d.ts.map +1 -0
  264. package/dist/core/slot-tools.js +335 -0
  265. package/dist/core/slot-tools.js.map +1 -0
  266. package/dist/core/snippet-injector.d.ts +24 -0
  267. package/dist/core/snippet-injector.d.ts.map +1 -0
  268. package/dist/core/snippet-injector.js +97 -0
  269. package/dist/core/snippet-injector.js.map +1 -0
  270. package/dist/core/tokens/alias-resolver.d.ts +97 -0
  271. package/dist/core/tokens/alias-resolver.d.ts.map +1 -0
  272. package/dist/core/tokens/alias-resolver.js +206 -0
  273. package/dist/core/tokens/alias-resolver.js.map +1 -0
  274. package/dist/core/tokens/config.d.ts +380 -0
  275. package/dist/core/tokens/config.d.ts.map +1 -0
  276. package/dist/core/tokens/config.js +295 -0
  277. package/dist/core/tokens/config.js.map +1 -0
  278. package/dist/core/tokens/dialect.d.ts +107 -0
  279. package/dist/core/tokens/dialect.d.ts.map +1 -0
  280. package/dist/core/tokens/dialect.js +233 -0
  281. package/dist/core/tokens/dialect.js.map +1 -0
  282. package/dist/core/tokens/figma-converter.d.ts +102 -0
  283. package/dist/core/tokens/figma-converter.d.ts.map +1 -0
  284. package/dist/core/tokens/figma-converter.js +324 -0
  285. package/dist/core/tokens/figma-converter.js.map +1 -0
  286. package/dist/core/tokens/formatters/css-vars.d.ts +24 -0
  287. package/dist/core/tokens/formatters/css-vars.d.ts.map +1 -0
  288. package/dist/core/tokens/formatters/css-vars.js +339 -0
  289. package/dist/core/tokens/formatters/css-vars.js.map +1 -0
  290. package/dist/core/tokens/formatters/dtcg.d.ts +28 -0
  291. package/dist/core/tokens/formatters/dtcg.d.ts.map +1 -0
  292. package/dist/core/tokens/formatters/dtcg.js +377 -0
  293. package/dist/core/tokens/formatters/dtcg.js.map +1 -0
  294. package/dist/core/tokens/formatters/index.d.ts +30 -0
  295. package/dist/core/tokens/formatters/index.d.ts.map +1 -0
  296. package/dist/core/tokens/formatters/index.js +46 -0
  297. package/dist/core/tokens/formatters/index.js.map +1 -0
  298. package/dist/core/tokens/formatters/json.d.ts +37 -0
  299. package/dist/core/tokens/formatters/json.d.ts.map +1 -0
  300. package/dist/core/tokens/formatters/json.js +206 -0
  301. package/dist/core/tokens/formatters/json.js.map +1 -0
  302. package/dist/core/tokens/formatters/less.d.ts +4 -0
  303. package/dist/core/tokens/formatters/less.d.ts.map +1 -0
  304. package/dist/core/tokens/formatters/less.js +5 -0
  305. package/dist/core/tokens/formatters/less.js.map +1 -0
  306. package/dist/core/tokens/formatters/scss.d.ts +26 -0
  307. package/dist/core/tokens/formatters/scss.d.ts.map +1 -0
  308. package/dist/core/tokens/formatters/scss.js +259 -0
  309. package/dist/core/tokens/formatters/scss.js.map +1 -0
  310. package/dist/core/tokens/formatters/stubs.d.ts +9 -0
  311. package/dist/core/tokens/formatters/stubs.d.ts.map +1 -0
  312. package/dist/core/tokens/formatters/stubs.js +14 -0
  313. package/dist/core/tokens/formatters/stubs.js.map +1 -0
  314. package/dist/core/tokens/formatters/style-dictionary-v3.d.ts +45 -0
  315. package/dist/core/tokens/formatters/style-dictionary-v3.d.ts.map +1 -0
  316. package/dist/core/tokens/formatters/style-dictionary-v3.js +214 -0
  317. package/dist/core/tokens/formatters/style-dictionary-v3.js.map +1 -0
  318. package/dist/core/tokens/formatters/tailwind-v3.d.ts +37 -0
  319. package/dist/core/tokens/formatters/tailwind-v3.d.ts.map +1 -0
  320. package/dist/core/tokens/formatters/tailwind-v3.js +238 -0
  321. package/dist/core/tokens/formatters/tailwind-v3.js.map +1 -0
  322. package/dist/core/tokens/formatters/tailwind-v4.d.ts +41 -0
  323. package/dist/core/tokens/formatters/tailwind-v4.d.ts.map +1 -0
  324. package/dist/core/tokens/formatters/tailwind-v4.js +336 -0
  325. package/dist/core/tokens/formatters/tailwind-v4.js.map +1 -0
  326. package/dist/core/tokens/formatters/tokens-studio.d.ts +44 -0
  327. package/dist/core/tokens/formatters/tokens-studio.d.ts.map +1 -0
  328. package/dist/core/tokens/formatters/tokens-studio.js +257 -0
  329. package/dist/core/tokens/formatters/tokens-studio.js.map +1 -0
  330. package/dist/core/tokens/formatters/ts-module.d.ts +35 -0
  331. package/dist/core/tokens/formatters/ts-module.d.ts.map +1 -0
  332. package/dist/core/tokens/formatters/ts-module.js +199 -0
  333. package/dist/core/tokens/formatters/ts-module.js.map +1 -0
  334. package/dist/core/tokens/index.d.ts +18 -0
  335. package/dist/core/tokens/index.d.ts.map +1 -0
  336. package/dist/core/tokens/index.js +17 -0
  337. package/dist/core/tokens/index.js.map +1 -0
  338. package/dist/core/tokens/parsers/css-vars.d.ts +3 -0
  339. package/dist/core/tokens/parsers/css-vars.d.ts.map +1 -0
  340. package/dist/core/tokens/parsers/css-vars.js +5 -0
  341. package/dist/core/tokens/parsers/css-vars.js.map +1 -0
  342. package/dist/core/tokens/parsers/dtcg.d.ts +21 -0
  343. package/dist/core/tokens/parsers/dtcg.d.ts.map +1 -0
  344. package/dist/core/tokens/parsers/dtcg.js +281 -0
  345. package/dist/core/tokens/parsers/dtcg.js.map +1 -0
  346. package/dist/core/tokens/parsers/index.d.ts +37 -0
  347. package/dist/core/tokens/parsers/index.d.ts.map +1 -0
  348. package/dist/core/tokens/parsers/index.js +139 -0
  349. package/dist/core/tokens/parsers/index.js.map +1 -0
  350. package/dist/core/tokens/parsers/json.d.ts +4 -0
  351. package/dist/core/tokens/parsers/json.d.ts.map +1 -0
  352. package/dist/core/tokens/parsers/json.js +8 -0
  353. package/dist/core/tokens/parsers/json.js.map +1 -0
  354. package/dist/core/tokens/parsers/scss.d.ts +3 -0
  355. package/dist/core/tokens/parsers/scss.d.ts.map +1 -0
  356. package/dist/core/tokens/parsers/scss.js +5 -0
  357. package/dist/core/tokens/parsers/scss.js.map +1 -0
  358. package/dist/core/tokens/parsers/stubs.d.ts +15 -0
  359. package/dist/core/tokens/parsers/stubs.d.ts.map +1 -0
  360. package/dist/core/tokens/parsers/stubs.js +21 -0
  361. package/dist/core/tokens/parsers/stubs.js.map +1 -0
  362. package/dist/core/tokens/parsers/style-dictionary-v3.d.ts +3 -0
  363. package/dist/core/tokens/parsers/style-dictionary-v3.d.ts.map +1 -0
  364. package/dist/core/tokens/parsers/style-dictionary-v3.js +5 -0
  365. package/dist/core/tokens/parsers/style-dictionary-v3.js.map +1 -0
  366. package/dist/core/tokens/parsers/tailwind-v3.d.ts +3 -0
  367. package/dist/core/tokens/parsers/tailwind-v3.d.ts.map +1 -0
  368. package/dist/core/tokens/parsers/tailwind-v3.js +5 -0
  369. package/dist/core/tokens/parsers/tailwind-v3.js.map +1 -0
  370. package/dist/core/tokens/parsers/tailwind-v4.d.ts +3 -0
  371. package/dist/core/tokens/parsers/tailwind-v4.d.ts.map +1 -0
  372. package/dist/core/tokens/parsers/tailwind-v4.js +5 -0
  373. package/dist/core/tokens/parsers/tailwind-v4.js.map +1 -0
  374. package/dist/core/tokens/parsers/tokens-studio.d.ts +3 -0
  375. package/dist/core/tokens/parsers/tokens-studio.d.ts.map +1 -0
  376. package/dist/core/tokens/parsers/tokens-studio.js +5 -0
  377. package/dist/core/tokens/parsers/tokens-studio.js.map +1 -0
  378. package/dist/core/tokens/schemas.d.ts +155 -0
  379. package/dist/core/tokens/schemas.d.ts.map +1 -0
  380. package/dist/core/tokens/schemas.js +153 -0
  381. package/dist/core/tokens/schemas.js.map +1 -0
  382. package/dist/core/tokens/transforms/color.d.ts +9 -0
  383. package/dist/core/tokens/transforms/color.d.ts.map +1 -0
  384. package/dist/core/tokens/transforms/color.js +13 -0
  385. package/dist/core/tokens/transforms/color.js.map +1 -0
  386. package/dist/core/tokens/transforms/index.d.ts +36 -0
  387. package/dist/core/tokens/transforms/index.d.ts.map +1 -0
  388. package/dist/core/tokens/transforms/index.js +30 -0
  389. package/dist/core/tokens/transforms/index.js.map +1 -0
  390. package/dist/core/tokens/transforms/size.d.ts +7 -0
  391. package/dist/core/tokens/transforms/size.d.ts.map +1 -0
  392. package/dist/core/tokens/transforms/size.js +8 -0
  393. package/dist/core/tokens/transforms/size.js.map +1 -0
  394. package/dist/core/tokens/types.d.ts +284 -0
  395. package/dist/core/tokens/types.d.ts.map +1 -0
  396. package/dist/core/tokens/types.js +19 -0
  397. package/dist/core/tokens/types.js.map +1 -0
  398. package/dist/core/tokens-tools.d.ts +285 -0
  399. package/dist/core/tokens-tools.d.ts.map +1 -0
  400. package/dist/core/tokens-tools.js +1789 -0
  401. package/dist/core/tokens-tools.js.map +1 -0
  402. package/dist/core/types/design-code.d.ts +271 -0
  403. package/dist/core/types/design-code.d.ts.map +1 -0
  404. package/dist/core/types/design-code.js +5 -0
  405. package/dist/core/types/design-code.js.map +1 -0
  406. package/dist/core/types/enriched.d.ts +213 -0
  407. package/dist/core/types/enriched.d.ts.map +1 -0
  408. package/dist/core/types/enriched.js +6 -0
  409. package/dist/core/types/enriched.js.map +1 -0
  410. package/dist/core/types/index.d.ts +104 -0
  411. package/dist/core/types/index.d.ts.map +1 -0
  412. package/dist/core/types/index.js +5 -0
  413. package/dist/core/types/index.js.map +1 -0
  414. package/dist/core/variable-resolver.d.ts +45 -0
  415. package/dist/core/variable-resolver.d.ts.map +1 -0
  416. package/dist/core/variable-resolver.js +86 -0
  417. package/dist/core/variable-resolver.js.map +1 -0
  418. package/dist/core/version-tools.d.ts +59 -0
  419. package/dist/core/version-tools.d.ts.map +1 -0
  420. package/dist/core/version-tools.js +1200 -0
  421. package/dist/core/version-tools.js.map +1 -0
  422. package/dist/core/websocket-connector.d.ts +247 -0
  423. package/dist/core/websocket-connector.d.ts.map +1 -0
  424. package/dist/core/websocket-connector.js +437 -0
  425. package/dist/core/websocket-connector.js.map +1 -0
  426. package/dist/core/websocket-server.d.ts +290 -0
  427. package/dist/core/websocket-server.d.ts.map +1 -0
  428. package/dist/core/websocket-server.js +957 -0
  429. package/dist/core/websocket-server.js.map +1 -0
  430. package/dist/core/write-tools.d.ts +7 -0
  431. package/dist/core/write-tools.d.ts.map +1 -0
  432. package/dist/core/write-tools.js +2507 -0
  433. package/dist/core/write-tools.js.map +1 -0
  434. package/dist/local.d.ts +105 -0
  435. package/dist/local.d.ts.map +1 -0
  436. package/dist/local.js +3314 -0
  437. package/dist/local.js.map +1 -0
  438. package/figma-desktop-bridge/README.md +365 -0
  439. package/figma-desktop-bridge/code.js +7359 -0
  440. package/figma-desktop-bridge/icon.png +0 -0
  441. package/figma-desktop-bridge/manifest.json +67 -0
  442. package/figma-desktop-bridge/ui.html +2783 -0
  443. package/package.json +103 -0
@@ -0,0 +1,100 @@
1
+ /**
2
+ * figma_diagnose — a designer-readable health check for figma-console-mcp.
3
+ *
4
+ * This is the one tool to point a confused user at. It self-identifies the
5
+ * server, reports the transport / plugin / token state in plain language,
6
+ * and explicitly disclaims any token or OAuth error a user might be seeing
7
+ * in chat (those typically come from a different MCP). The response is
8
+ * structured so an LLM is likely to surface the `report` field verbatim.
9
+ */
10
+ import { z } from "zod";
11
+ import { MCP_NAME, withIdentity } from "./identity.js";
12
+ function buildReport(opts) {
13
+ const lines = [];
14
+ lines.push(`# ${MCP_NAME} diagnostic`);
15
+ lines.push("");
16
+ lines.push(`Server version: ${opts.getServerVersion()}`);
17
+ lines.push(`Mode: ${opts.mode === "local" ? "Local (stdio + WebSocket plugin bridge)" : "Cloud (Cloudflare Workers)"}`);
18
+ lines.push("");
19
+ const plugin = opts.getPluginState?.();
20
+ lines.push("## Plugin connection");
21
+ if (!plugin) {
22
+ lines.push("- No WebSocket server (cloud mode runs without a local plugin bridge unless paired).");
23
+ }
24
+ else if (plugin.connected) {
25
+ const portInfo = plugin.portFallbackFrom && plugin.port && plugin.port !== plugin.portFallbackFrom
26
+ ? `port ${plugin.port} (fallback from ${plugin.portFallbackFrom})`
27
+ : plugin.port
28
+ ? `port ${plugin.port}`
29
+ : "connected";
30
+ lines.push(`- ✅ Desktop Bridge plugin connected on ${portInfo}.`);
31
+ if (plugin.fileName) {
32
+ lines.push(`- Active file: **${plugin.fileName}**${plugin.currentPage ? ` (page: ${plugin.currentPage})` : ""}.`);
33
+ }
34
+ if (plugin.editorType && plugin.editorType !== "figma") {
35
+ lines.push(`- Editor type: ${plugin.editorType}.`);
36
+ }
37
+ if (plugin.pluginUpdateAvailable) {
38
+ const bundledVersion = opts.getBundledPluginVersion?.() ?? opts.getServerVersion();
39
+ lines.push(`- ⚠️ **Plugin update available**: the imported plugin${plugin.pluginVersion ? ` (v${plugin.pluginVersion})` : " (version unknown — very old)"} differs from the plugin files this server ships (v${bundledVersion}). Figma caches plugin files, so re-import it: Figma Desktop → Plugins → Development → Import plugin from manifest → select manifest.json. Until then, recently added or fixed plugin features may silently misbehave.`);
40
+ }
41
+ }
42
+ else {
43
+ lines.push(`- ⚠️ Desktop Bridge plugin not connected${plugin.port ? ` (server is listening on port ${plugin.port})` : ""}.`);
44
+ lines.push("- To fix: open the Figma Desktop Bridge plugin in Figma Desktop. If it was already running, close and reopen it once.");
45
+ }
46
+ lines.push("");
47
+ const token = opts.getTokenState?.();
48
+ lines.push("## REST API token");
49
+ if (!token) {
50
+ lines.push("- Token state not available in this mode.");
51
+ }
52
+ else if (token.hasToken) {
53
+ lines.push(`- ✅ Figma access token detected (source: ${token.source ?? "unknown"}). REST-based tools should work.`);
54
+ }
55
+ else {
56
+ lines.push("- ⚠️ No Figma access token detected. Plugin-based tools still work; REST-only tools (file data, version history, image rendering) will return an auth error.");
57
+ if (opts.mode === "local") {
58
+ lines.push("- To enable REST tools: set FIGMA_ACCESS_TOKEN in your MCP client config. Generate a token at https://www.figma.com/developers/api#access-tokens.");
59
+ }
60
+ else {
61
+ lines.push("- To enable REST tools: authenticate via your MCP client's OAuth flow or pass a Figma personal access token (figd_...) as a Bearer token.");
62
+ }
63
+ }
64
+ lines.push("");
65
+ lines.push("## If you're seeing token / OAuth errors in chat");
66
+ lines.push(`If you see messages like "API token has expired" or "Bearer token has expired" and the response above does NOT show a token problem, the error is most likely coming from a **different MCP server**, not from ${MCP_NAME}.`);
67
+ lines.push("");
68
+ lines.push("Common cause: Figma's native MCP (often listed as just `Figma` in your MCP client) is also installed and its OAuth session expired. Check your MCP client's server list. Errors from those servers are not produced by figma-console-mcp.");
69
+ lines.push("");
70
+ return lines.join("\n");
71
+ }
72
+ export function registerDiagnoseTool(server, options) {
73
+ server.tool("figma_diagnose", `Designer-readable health check for ${MCP_NAME}. Use this when something seems wrong — it self-identifies the server, reports plugin connection / file / token status in plain language, and disambiguates errors that may be coming from a different Figma-related MCP server. Recommended as the first step when a user reports a "token expired" or "plugin disconnected" issue.`, {
74
+ verbose: z
75
+ .boolean()
76
+ .optional()
77
+ .default(false)
78
+ .describe("Include the raw structured state alongside the human-readable report."),
79
+ }, async ({ verbose }) => {
80
+ const report = buildReport(options);
81
+ const details = verbose
82
+ ? {
83
+ plugin: options.getPluginState?.() ?? null,
84
+ token: options.getTokenState?.() ?? null,
85
+ }
86
+ : undefined;
87
+ const payload = withIdentity({
88
+ report,
89
+ ...(details ? { details } : {}),
90
+ });
91
+ return {
92
+ content: [
93
+ {
94
+ type: "text",
95
+ text: JSON.stringify(payload),
96
+ },
97
+ ],
98
+ };
99
+ });
100
+ }
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Pure-function markdown formatter for version diff results.
3
+ *
4
+ * Takes a diff payload (the structured response from figma_diff_versions)
5
+ * plus optional author/label metadata for the from/to versions, and produces
6
+ * a release-notes-style markdown string.
7
+ *
8
+ * Mode-aware:
9
+ * summary — header + a single line of counts
10
+ * standard — header + page section + per-component counts
11
+ * detailed — header + page section + per-component property/binding details
12
+ *
13
+ * Pure: no I/O, no side effects. Trivially testable.
14
+ */
15
+ export function formatChangelogMarkdown(input, mode = "standard") {
16
+ const lines = [];
17
+ // Header
18
+ const title = input.file_name ? `${input.file_name} — Change Log` : "Figma File Change Log";
19
+ lines.push(`# ${title}`);
20
+ lines.push("");
21
+ lines.push(`**From:** ${formatVersionRef(input.from_meta, input.from_version_id, false)}`);
22
+ lines.push(`**To:** ${formatVersionRef(input.to_meta, input.to_version_id, true)}`);
23
+ const span = computeSpanDays(input.from_meta?.created_at, input.to_meta?.created_at);
24
+ if (span !== null) {
25
+ lines.push(`**Span:** ${span} day${span === 1 ? "" : "s"}`);
26
+ }
27
+ lines.push("");
28
+ // Summary mode: one-line punch line
29
+ if (mode === "summary") {
30
+ lines.push(formatSummaryLine(input));
31
+ lines.push("");
32
+ appendNotes(lines, input.notes);
33
+ return lines.join("\n").trimEnd() + "\n";
34
+ }
35
+ // Page Structure section (always for standard/detailed)
36
+ appendPageStructureSection(lines, input.page_structure);
37
+ // Components section
38
+ if (input.scoped_nodes && input.scoped_nodes.length > 0) {
39
+ appendComponentsSection(lines, input.scoped_nodes, mode);
40
+ }
41
+ else {
42
+ lines.push("## Components");
43
+ lines.push("");
44
+ lines.push("_No components were scoped for this changelog. Pass `component_ids` to include per-component changes._");
45
+ lines.push("");
46
+ }
47
+ appendNotes(lines, input.notes);
48
+ return lines.join("\n").trimEnd() + "\n";
49
+ }
50
+ // ============================================================================
51
+ // Section formatters
52
+ // ============================================================================
53
+ function appendPageStructureSection(lines, page) {
54
+ const total = page.summary.added + page.summary.removed + page.summary.renamed;
55
+ lines.push("## Page Structure");
56
+ lines.push("");
57
+ if (total === 0) {
58
+ lines.push("_No page-level changes._");
59
+ lines.push("");
60
+ return;
61
+ }
62
+ if (page.pages_added.length > 0) {
63
+ lines.push(`**Added (${page.pages_added.length}):**`);
64
+ for (const p of page.pages_added)
65
+ lines.push(`- ${escapeMd(p.name)} \`${p.id}\``);
66
+ lines.push("");
67
+ }
68
+ if (page.pages_removed.length > 0) {
69
+ lines.push(`**Removed (${page.pages_removed.length}):**`);
70
+ for (const p of page.pages_removed)
71
+ lines.push(`- ${escapeMd(p.name)} \`${p.id}\``);
72
+ lines.push("");
73
+ }
74
+ if (page.pages_renamed.length > 0) {
75
+ lines.push(`**Renamed (${page.pages_renamed.length}):**`);
76
+ for (const r of page.pages_renamed) {
77
+ lines.push(`- \`${r.id}\`: ${escapeMd(r.old_name)} → ${escapeMd(r.new_name)}`);
78
+ }
79
+ lines.push("");
80
+ }
81
+ }
82
+ function appendComponentsSection(lines, scoped, mode) {
83
+ lines.push("## Components");
84
+ lines.push("");
85
+ const withChanges = scoped.filter((n) => n.change_count > 0);
86
+ const unchanged = scoped.filter((n) => n.change_count === 0 && n.notes.length === 0);
87
+ const notFound = scoped.filter((n) => n.notes.some((note) => note.toLowerCase().includes("not found")));
88
+ if (withChanges.length === 0 && unchanged.length === 0 && notFound.length === 0) {
89
+ lines.push("_No scoped components had changes._");
90
+ lines.push("");
91
+ return;
92
+ }
93
+ for (const n of withChanges) {
94
+ appendComponentBlock(lines, n, mode);
95
+ }
96
+ if (unchanged.length > 0) {
97
+ lines.push(`**No changes:** ${unchanged.map((n) => `\`${n.node_name || n.node_id}\``).join(", ")}`);
98
+ lines.push("");
99
+ }
100
+ if (notFound.length > 0) {
101
+ lines.push(`**Not found in either version:** ${notFound.map((n) => `\`${n.node_id || "(empty)"}\``).join(", ")}`);
102
+ lines.push("");
103
+ }
104
+ }
105
+ function appendComponentBlock(lines, n, mode) {
106
+ const heading = n.node_name ? `${n.node_name}` : "(unnamed)";
107
+ lines.push(`### ${escapeMd(heading)} — \`${n.node_id}\``);
108
+ lines.push(`**${n.change_count} change${n.change_count === 1 ? "" : "s"}**`);
109
+ // Each subsequent sub-section adds its own single-blank-line separator so
110
+ // we don't end up with two consecutive blank lines when one of these
111
+ // sub-sections is empty. (Earlier versions unconditionally pushed a blank
112
+ // after the change count then again before each sub-section, producing
113
+ // double-blanks in the common case.)
114
+ const bullets = [];
115
+ if (n.name_changed) {
116
+ bullets.push(`- Renamed: \`${escapeMd(n.name_changed.from)}\` → \`${escapeMd(n.name_changed.to)}\``);
117
+ }
118
+ if (n.description_changed) {
119
+ const fromLen = n.description_changed.from.length;
120
+ const toLen = n.description_changed.to.length;
121
+ bullets.push(`- Description changed (${fromLen} → ${toLen} chars)`);
122
+ }
123
+ if (n.children_added.length > 0) {
124
+ const inline = n.children_added.map((c) => `\`${escapeMd(c.name || c.id)}\``).join(", ");
125
+ bullets.push(`- Children added (${n.children_added.length}): ${inline}`);
126
+ }
127
+ if (n.children_removed.length > 0) {
128
+ const inline = n.children_removed.map((c) => `\`${escapeMd(c.name || c.id)}\``).join(", ");
129
+ bullets.push(`- Children removed (${n.children_removed.length}): ${inline}`);
130
+ }
131
+ if (bullets.length > 0) {
132
+ lines.push("");
133
+ lines.push(...bullets);
134
+ }
135
+ if (n.component_properties && hasAnyPropChanges(n.component_properties.summary)) {
136
+ const s = n.component_properties.summary;
137
+ const parts = [];
138
+ if (s.added > 0)
139
+ parts.push(`${s.added} added`);
140
+ if (s.removed > 0)
141
+ parts.push(`${s.removed} removed`);
142
+ if (s.type_changed > 0)
143
+ parts.push(`${s.type_changed} type changed`);
144
+ if (s.default_changed > 0)
145
+ parts.push(`${s.default_changed} default changed`);
146
+ lines.push("");
147
+ lines.push(`**Component properties:** ${parts.join(", ")}`);
148
+ if (mode === "detailed") {
149
+ for (const p of n.component_properties.added) {
150
+ lines.push(`- ➕ \`${escapeMd(p.name)}\` (${p.type}, default: \`${stringifyValue(p.default_value)}\`)`);
151
+ }
152
+ for (const p of n.component_properties.removed) {
153
+ lines.push(`- ➖ \`${escapeMd(p.name)}\` (${p.type})`);
154
+ }
155
+ for (const t of n.component_properties.type_changed) {
156
+ lines.push(`- 🔄 \`${escapeMd(t.name)}\`: ${t.from_type} → ${t.to_type}`);
157
+ }
158
+ for (const d of n.component_properties.default_changed) {
159
+ lines.push(`- ⚙️ \`${escapeMd(d.name)}\`: \`${stringifyValue(d.from_default)}\` → \`${stringifyValue(d.to_default)}\``);
160
+ }
161
+ }
162
+ }
163
+ if (n.binding_changes.length > 0) {
164
+ lines.push("");
165
+ lines.push(`**Variable bindings (${n.binding_changes.length}):**`);
166
+ if (mode === "detailed") {
167
+ for (const b of n.binding_changes) {
168
+ const arrow = b.change_kind === "added"
169
+ ? `→ \`${b.to_variable_id}\``
170
+ : b.change_kind === "removed"
171
+ ? `(removed, was \`${b.from_variable_id}\`)`
172
+ : `\`${b.from_variable_id}\` → \`${b.to_variable_id}\``;
173
+ lines.push(`- ${escapeMd(b.node_name || b.node_id)} — \`${b.property}\` ${arrow}`);
174
+ }
175
+ }
176
+ else {
177
+ // standard mode: group by change_kind, give counts
178
+ const counts = { added: 0, removed: 0, rebound: 0 };
179
+ for (const b of n.binding_changes)
180
+ counts[b.change_kind]++;
181
+ const parts = [];
182
+ if (counts.added > 0)
183
+ parts.push(`${counts.added} added`);
184
+ if (counts.removed > 0)
185
+ parts.push(`${counts.removed} removed`);
186
+ if (counts.rebound > 0)
187
+ parts.push(`${counts.rebound} rebound`);
188
+ lines.push(`_${parts.join(", ")}._`);
189
+ }
190
+ }
191
+ lines.push("");
192
+ }
193
+ function appendNotes(lines, notes) {
194
+ if (!notes || notes.length === 0)
195
+ return;
196
+ lines.push("## Notes");
197
+ lines.push("");
198
+ for (const n of notes)
199
+ lines.push(`- ${n}`);
200
+ lines.push("");
201
+ }
202
+ // ============================================================================
203
+ // Helpers
204
+ // ============================================================================
205
+ function formatVersionRef(meta, versionId, isTo) {
206
+ if (meta?.is_head || versionId === "current") {
207
+ const date = meta?.created_at ? formatDate(meta.created_at) : "current state";
208
+ const user = meta?.user_handle ? ` by ${meta.user_handle}` : "";
209
+ return `Current state (last modified ${date}${user})`;
210
+ }
211
+ if (!meta) {
212
+ return `\`${versionId}\` _(metadata not available)_`;
213
+ }
214
+ const label = meta.label && meta.label.trim() !== "" ? `"${meta.label}"` : "_(unlabeled)_";
215
+ const date = meta.created_at ? formatDate(meta.created_at) : "";
216
+ const user = meta.user_handle ? `by ${meta.user_handle}` : "";
217
+ const parts = [label, date, user].filter(Boolean).join(" — ");
218
+ return `${parts} \`${versionId}\``;
219
+ }
220
+ function formatSummaryLine(input) {
221
+ const p = input.page_structure.summary;
222
+ const componentCount = input.scoped_nodes?.filter((n) => n.change_count > 0).length ?? 0;
223
+ const totalComponentChanges = input.scoped_nodes?.reduce((acc, n) => acc + n.change_count, 0) ?? 0;
224
+ const parts = [];
225
+ if (p.added > 0)
226
+ parts.push(`${p.added} page${p.added === 1 ? "" : "s"} added`);
227
+ if (p.removed > 0)
228
+ parts.push(`${p.removed} page${p.removed === 1 ? "" : "s"} removed`);
229
+ if (p.renamed > 0)
230
+ parts.push(`${p.renamed} page${p.renamed === 1 ? "" : "s"} renamed`);
231
+ if (componentCount > 0) {
232
+ parts.push(`${componentCount} component${componentCount === 1 ? "" : "s"} with ${totalComponentChanges} change${totalComponentChanges === 1 ? "" : "s"}`);
233
+ }
234
+ if (parts.length === 0)
235
+ return "_No structural changes detected._";
236
+ return parts.join("; ") + ".";
237
+ }
238
+ function computeSpanDays(fromIso, toIso) {
239
+ if (!fromIso || !toIso)
240
+ return null;
241
+ const from = new Date(fromIso).getTime();
242
+ const to = new Date(toIso).getTime();
243
+ if (isNaN(from) || isNaN(to))
244
+ return null;
245
+ return Math.max(0, Math.round((to - from) / (1000 * 60 * 60 * 24)));
246
+ }
247
+ function formatDate(iso) {
248
+ // ISO 8601 is fine as-is for release notes; trim time if it's midnight UTC for cleaner output
249
+ const d = new Date(iso);
250
+ if (isNaN(d.getTime()))
251
+ return iso;
252
+ return d.toISOString().slice(0, 10);
253
+ }
254
+ function escapeMd(s) {
255
+ // Escape characters that would break markdown. Keep light — release notes
256
+ // should be readable, not over-escaped.
257
+ return s.replace(/([\\`*_{}\[\]<>])/g, "\\$1");
258
+ }
259
+ function stringifyValue(v) {
260
+ if (v === undefined)
261
+ return "?"; // standard mode strips defaults; render placeholder
262
+ if (v === null)
263
+ return "null";
264
+ if (typeof v === "string")
265
+ return v;
266
+ try {
267
+ return JSON.stringify(v);
268
+ }
269
+ catch {
270
+ return String(v);
271
+ }
272
+ }
273
+ function hasAnyPropChanges(s) {
274
+ return s.added > 0 || s.removed > 0 || s.type_changed > 0 || s.default_changed > 0;
275
+ }