@agent-native/core 0.92.12 → 0.94.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 (1836) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +64 -0
  3. package/corpus/core/docs/content/a2a-protocol.mdx +21 -5
  4. package/corpus/core/docs/content/actions.mdx +9 -23
  5. package/corpus/core/docs/content/agent-mentions.mdx +31 -29
  6. package/corpus/core/docs/content/agent-native-toolkit.mdx +15 -6
  7. package/corpus/core/docs/content/agent-surfaces.mdx +9 -13
  8. package/corpus/core/docs/content/agent-teams.mdx +1 -0
  9. package/corpus/core/docs/content/authentication.mdx +10 -3
  10. package/corpus/core/docs/content/automation-connectors.mdx +123 -0
  11. package/corpus/core/docs/content/automations.mdx +17 -3
  12. package/corpus/core/docs/content/blueprint-installer.mdx +11 -4
  13. package/corpus/core/docs/content/cli-adapters.mdx +9 -6
  14. package/corpus/core/docs/content/client.mdx +16 -0
  15. package/corpus/core/docs/content/cloneable-saas.mdx +14 -11
  16. package/corpus/core/docs/content/code-agents-ui.mdx +65 -0
  17. package/corpus/core/docs/content/components.mdx +30 -14
  18. package/corpus/core/docs/content/context-awareness.mdx +27 -15
  19. package/corpus/core/docs/content/creating-templates.mdx +15 -9
  20. package/corpus/core/docs/content/cross-app-sso.mdx +16 -6
  21. package/corpus/core/docs/content/data-programs.mdx +1 -1
  22. package/corpus/core/docs/content/database.mdx +17 -5
  23. package/corpus/core/docs/content/deployment.mdx +19 -18
  24. package/corpus/core/docs/content/dispatch.mdx +6 -2
  25. package/corpus/core/docs/content/drop-in-agent.mdx +10 -4
  26. package/corpus/core/docs/content/durable-background-runs.mdx +9 -5
  27. package/corpus/core/docs/content/durable-resume.mdx +9 -4
  28. package/corpus/core/docs/content/embedding-sdk.mdx +26 -8
  29. package/corpus/core/docs/content/evals.mdx +3 -5
  30. package/corpus/core/docs/content/extensions.mdx +23 -2
  31. package/corpus/core/docs/content/external-agents.mdx +25 -34
  32. package/corpus/core/docs/content/faq.mdx +8 -0
  33. package/corpus/core/docs/content/file-uploads.mdx +12 -3
  34. package/corpus/core/docs/content/frames.mdx +16 -0
  35. package/corpus/core/docs/content/generative-ui.mdx +1 -1
  36. package/corpus/core/docs/content/getting-started.mdx +34 -21
  37. package/corpus/core/docs/content/harness-agents.mdx +8 -4
  38. package/corpus/core/docs/content/human-approval.mdx +8 -3
  39. package/corpus/core/docs/content/internationalization.mdx +9 -4
  40. package/corpus/core/docs/content/key-concepts.mdx +13 -20
  41. package/corpus/core/docs/content/local-file-mode.mdx +14 -8
  42. package/corpus/core/docs/content/locales/ar-SA/actions.mdx +2 -2
  43. package/corpus/core/docs/content/locales/ar-SA/agent-native-toolkit.mdx +2 -2
  44. package/corpus/core/docs/content/locales/ar-SA/agent-surfaces.mdx +8 -10
  45. package/corpus/core/docs/content/locales/ar-SA/agent-teams.mdx +1 -0
  46. package/corpus/core/docs/content/locales/ar-SA/authentication.mdx +1 -1
  47. package/corpus/core/docs/content/locales/ar-SA/components.mdx +11 -1
  48. package/corpus/core/docs/content/locales/ar-SA/creating-templates.mdx +3 -7
  49. package/corpus/core/docs/content/locales/ar-SA/cross-app-sso.mdx +16 -6
  50. package/corpus/core/docs/content/locales/ar-SA/deployment.mdx +8 -0
  51. package/corpus/core/docs/content/locales/ar-SA/extensions.mdx +8 -0
  52. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +2 -7
  53. package/corpus/core/docs/content/locales/ar-SA/key-concepts.mdx +13 -20
  54. package/corpus/core/docs/content/locales/ar-SA/messaging.mdx +84 -15
  55. package/corpus/core/docs/content/locales/ar-SA/multi-tenancy.mdx +5 -5
  56. package/corpus/core/docs/content/locales/ar-SA/notifications.mdx +18 -10
  57. package/corpus/core/docs/content/locales/ar-SA/processors.mdx +11 -5
  58. package/corpus/core/docs/content/locales/ar-SA/server.mdx +17 -10
  59. package/corpus/core/docs/content/locales/ar-SA/sharing.mdx +10 -10
  60. package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +34 -17
  61. package/corpus/core/docs/content/locales/ar-SA/template-assets.mdx +16 -13
  62. package/corpus/core/docs/content/locales/ar-SA/template-brain.mdx +3 -1
  63. package/corpus/core/docs/content/locales/ar-SA/template-clips.mdx +4 -3
  64. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +4 -1
  65. package/corpus/core/docs/content/locales/ar-SA/template-dispatch.mdx +5 -1
  66. package/corpus/core/docs/content/locales/ar-SA/template-mail.mdx +8 -0
  67. package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +9 -6
  68. package/corpus/core/docs/content/locales/ar-SA/using-your-agent.mdx +0 -7
  69. package/corpus/core/docs/content/locales/ar-SA/voice-input.mdx +6 -0
  70. package/corpus/core/docs/content/locales/ar-SA/workspace-connections.mdx +9 -2
  71. package/corpus/core/docs/content/locales/ar-SA/workspace.mdx +19 -18
  72. package/corpus/core/docs/content/locales/de-DE/actions.mdx +2 -2
  73. package/corpus/core/docs/content/locales/de-DE/agent-native-toolkit.mdx +2 -2
  74. package/corpus/core/docs/content/locales/de-DE/agent-surfaces.mdx +8 -10
  75. package/corpus/core/docs/content/locales/de-DE/agent-teams.mdx +1 -0
  76. package/corpus/core/docs/content/locales/de-DE/authentication.mdx +1 -1
  77. package/corpus/core/docs/content/locales/de-DE/components.mdx +11 -1
  78. package/corpus/core/docs/content/locales/de-DE/creating-templates.mdx +3 -7
  79. package/corpus/core/docs/content/locales/de-DE/cross-app-sso.mdx +16 -6
  80. package/corpus/core/docs/content/locales/de-DE/deployment.mdx +8 -0
  81. package/corpus/core/docs/content/locales/de-DE/extensions.mdx +10 -0
  82. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +3 -7
  83. package/corpus/core/docs/content/locales/de-DE/key-concepts.mdx +13 -20
  84. package/corpus/core/docs/content/locales/de-DE/messaging.mdx +92 -15
  85. package/corpus/core/docs/content/locales/de-DE/multi-tenancy.mdx +5 -5
  86. package/corpus/core/docs/content/locales/de-DE/notifications.mdx +18 -10
  87. package/corpus/core/docs/content/locales/de-DE/processors.mdx +11 -5
  88. package/corpus/core/docs/content/locales/de-DE/server.mdx +18 -10
  89. package/corpus/core/docs/content/locales/de-DE/sharing.mdx +10 -10
  90. package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +34 -17
  91. package/corpus/core/docs/content/locales/de-DE/template-assets.mdx +16 -13
  92. package/corpus/core/docs/content/locales/de-DE/template-brain.mdx +3 -1
  93. package/corpus/core/docs/content/locales/de-DE/template-clips.mdx +4 -3
  94. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +4 -1
  95. package/corpus/core/docs/content/locales/de-DE/template-dispatch.mdx +5 -1
  96. package/corpus/core/docs/content/locales/de-DE/template-mail.mdx +8 -0
  97. package/corpus/core/docs/content/locales/de-DE/tracking.mdx +9 -6
  98. package/corpus/core/docs/content/locales/de-DE/using-your-agent.mdx +0 -7
  99. package/corpus/core/docs/content/locales/de-DE/voice-input.mdx +6 -0
  100. package/corpus/core/docs/content/locales/de-DE/workspace-connections.mdx +9 -2
  101. package/corpus/core/docs/content/locales/de-DE/workspace.mdx +19 -18
  102. package/corpus/core/docs/content/locales/es-ES/actions.mdx +2 -2
  103. package/corpus/core/docs/content/locales/es-ES/agent-native-toolkit.mdx +2 -2
  104. package/corpus/core/docs/content/locales/es-ES/agent-surfaces.mdx +8 -10
  105. package/corpus/core/docs/content/locales/es-ES/agent-teams.mdx +1 -0
  106. package/corpus/core/docs/content/locales/es-ES/authentication.mdx +1 -1
  107. package/corpus/core/docs/content/locales/es-ES/components.mdx +11 -1
  108. package/corpus/core/docs/content/locales/es-ES/creating-templates.mdx +3 -7
  109. package/corpus/core/docs/content/locales/es-ES/cross-app-sso.mdx +16 -6
  110. package/corpus/core/docs/content/locales/es-ES/deployment.mdx +8 -0
  111. package/corpus/core/docs/content/locales/es-ES/extensions.mdx +10 -0
  112. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +3 -7
  113. package/corpus/core/docs/content/locales/es-ES/key-concepts.mdx +13 -20
  114. package/corpus/core/docs/content/locales/es-ES/messaging.mdx +91 -15
  115. package/corpus/core/docs/content/locales/es-ES/multi-tenancy.mdx +5 -5
  116. package/corpus/core/docs/content/locales/es-ES/notifications.mdx +18 -10
  117. package/corpus/core/docs/content/locales/es-ES/processors.mdx +11 -5
  118. package/corpus/core/docs/content/locales/es-ES/server.mdx +17 -10
  119. package/corpus/core/docs/content/locales/es-ES/sharing.mdx +10 -10
  120. package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +34 -17
  121. package/corpus/core/docs/content/locales/es-ES/template-assets.mdx +16 -13
  122. package/corpus/core/docs/content/locales/es-ES/template-brain.mdx +3 -1
  123. package/corpus/core/docs/content/locales/es-ES/template-clips.mdx +4 -3
  124. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +4 -1
  125. package/corpus/core/docs/content/locales/es-ES/template-dispatch.mdx +5 -1
  126. package/corpus/core/docs/content/locales/es-ES/template-mail.mdx +8 -0
  127. package/corpus/core/docs/content/locales/es-ES/tracking.mdx +9 -6
  128. package/corpus/core/docs/content/locales/es-ES/using-your-agent.mdx +0 -7
  129. package/corpus/core/docs/content/locales/es-ES/voice-input.mdx +6 -0
  130. package/corpus/core/docs/content/locales/es-ES/workspace-connections.mdx +9 -2
  131. package/corpus/core/docs/content/locales/es-ES/workspace.mdx +19 -18
  132. package/corpus/core/docs/content/locales/fr-FR/actions.mdx +2 -2
  133. package/corpus/core/docs/content/locales/fr-FR/agent-native-toolkit.mdx +2 -2
  134. package/corpus/core/docs/content/locales/fr-FR/agent-surfaces.mdx +8 -10
  135. package/corpus/core/docs/content/locales/fr-FR/agent-teams.mdx +1 -0
  136. package/corpus/core/docs/content/locales/fr-FR/authentication.mdx +1 -1
  137. package/corpus/core/docs/content/locales/fr-FR/components.mdx +11 -1
  138. package/corpus/core/docs/content/locales/fr-FR/creating-templates.mdx +3 -7
  139. package/corpus/core/docs/content/locales/fr-FR/cross-app-sso.mdx +16 -6
  140. package/corpus/core/docs/content/locales/fr-FR/deployment.mdx +8 -0
  141. package/corpus/core/docs/content/locales/fr-FR/extensions.mdx +10 -0
  142. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +3 -7
  143. package/corpus/core/docs/content/locales/fr-FR/key-concepts.mdx +13 -20
  144. package/corpus/core/docs/content/locales/fr-FR/messaging.mdx +91 -15
  145. package/corpus/core/docs/content/locales/fr-FR/multi-tenancy.mdx +5 -5
  146. package/corpus/core/docs/content/locales/fr-FR/notifications.mdx +18 -10
  147. package/corpus/core/docs/content/locales/fr-FR/processors.mdx +11 -5
  148. package/corpus/core/docs/content/locales/fr-FR/server.mdx +17 -10
  149. package/corpus/core/docs/content/locales/fr-FR/sharing.mdx +10 -10
  150. package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +34 -17
  151. package/corpus/core/docs/content/locales/fr-FR/template-assets.mdx +16 -13
  152. package/corpus/core/docs/content/locales/fr-FR/template-brain.mdx +3 -1
  153. package/corpus/core/docs/content/locales/fr-FR/template-clips.mdx +4 -3
  154. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +4 -1
  155. package/corpus/core/docs/content/locales/fr-FR/template-dispatch.mdx +5 -1
  156. package/corpus/core/docs/content/locales/fr-FR/template-mail.mdx +8 -0
  157. package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +9 -6
  158. package/corpus/core/docs/content/locales/fr-FR/using-your-agent.mdx +0 -7
  159. package/corpus/core/docs/content/locales/fr-FR/voice-input.mdx +6 -0
  160. package/corpus/core/docs/content/locales/fr-FR/workspace-connections.mdx +9 -2
  161. package/corpus/core/docs/content/locales/fr-FR/workspace.mdx +19 -18
  162. package/corpus/core/docs/content/locales/hi-IN/actions.mdx +2 -2
  163. package/corpus/core/docs/content/locales/hi-IN/agent-native-toolkit.mdx +2 -2
  164. package/corpus/core/docs/content/locales/hi-IN/agent-surfaces.mdx +8 -10
  165. package/corpus/core/docs/content/locales/hi-IN/agent-teams.mdx +1 -0
  166. package/corpus/core/docs/content/locales/hi-IN/authentication.mdx +1 -1
  167. package/corpus/core/docs/content/locales/hi-IN/components.mdx +11 -1
  168. package/corpus/core/docs/content/locales/hi-IN/creating-templates.mdx +3 -7
  169. package/corpus/core/docs/content/locales/hi-IN/cross-app-sso.mdx +16 -6
  170. package/corpus/core/docs/content/locales/hi-IN/deployment.mdx +8 -0
  171. package/corpus/core/docs/content/locales/hi-IN/extensions.mdx +8 -0
  172. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +2 -7
  173. package/corpus/core/docs/content/locales/hi-IN/key-concepts.mdx +13 -20
  174. package/corpus/core/docs/content/locales/hi-IN/messaging.mdx +81 -15
  175. package/corpus/core/docs/content/locales/hi-IN/multi-tenancy.mdx +5 -5
  176. package/corpus/core/docs/content/locales/hi-IN/notifications.mdx +18 -10
  177. package/corpus/core/docs/content/locales/hi-IN/processors.mdx +11 -5
  178. package/corpus/core/docs/content/locales/hi-IN/server.mdx +17 -10
  179. package/corpus/core/docs/content/locales/hi-IN/sharing.mdx +10 -10
  180. package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +34 -17
  181. package/corpus/core/docs/content/locales/hi-IN/template-assets.mdx +16 -13
  182. package/corpus/core/docs/content/locales/hi-IN/template-brain.mdx +3 -1
  183. package/corpus/core/docs/content/locales/hi-IN/template-clips.mdx +4 -3
  184. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +4 -1
  185. package/corpus/core/docs/content/locales/hi-IN/template-dispatch.mdx +5 -1
  186. package/corpus/core/docs/content/locales/hi-IN/template-mail.mdx +8 -0
  187. package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +9 -6
  188. package/corpus/core/docs/content/locales/hi-IN/using-your-agent.mdx +0 -7
  189. package/corpus/core/docs/content/locales/hi-IN/voice-input.mdx +6 -0
  190. package/corpus/core/docs/content/locales/hi-IN/workspace-connections.mdx +9 -2
  191. package/corpus/core/docs/content/locales/hi-IN/workspace.mdx +19 -18
  192. package/corpus/core/docs/content/locales/ja-JP/actions.mdx +2 -2
  193. package/corpus/core/docs/content/locales/ja-JP/agent-native-toolkit.mdx +2 -2
  194. package/corpus/core/docs/content/locales/ja-JP/agent-surfaces.mdx +8 -10
  195. package/corpus/core/docs/content/locales/ja-JP/agent-teams.mdx +1 -0
  196. package/corpus/core/docs/content/locales/ja-JP/authentication.mdx +1 -1
  197. package/corpus/core/docs/content/locales/ja-JP/components.mdx +11 -1
  198. package/corpus/core/docs/content/locales/ja-JP/creating-templates.mdx +3 -7
  199. package/corpus/core/docs/content/locales/ja-JP/cross-app-sso.mdx +16 -6
  200. package/corpus/core/docs/content/locales/ja-JP/deployment.mdx +8 -0
  201. package/corpus/core/docs/content/locales/ja-JP/extensions.mdx +9 -0
  202. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +2 -7
  203. package/corpus/core/docs/content/locales/ja-JP/key-concepts.mdx +13 -20
  204. package/corpus/core/docs/content/locales/ja-JP/messaging.mdx +81 -15
  205. package/corpus/core/docs/content/locales/ja-JP/multi-tenancy.mdx +5 -5
  206. package/corpus/core/docs/content/locales/ja-JP/notifications.mdx +18 -10
  207. package/corpus/core/docs/content/locales/ja-JP/processors.mdx +11 -5
  208. package/corpus/core/docs/content/locales/ja-JP/server.mdx +17 -10
  209. package/corpus/core/docs/content/locales/ja-JP/sharing.mdx +10 -10
  210. package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +34 -17
  211. package/corpus/core/docs/content/locales/ja-JP/template-assets.mdx +16 -13
  212. package/corpus/core/docs/content/locales/ja-JP/template-brain.mdx +3 -1
  213. package/corpus/core/docs/content/locales/ja-JP/template-clips.mdx +4 -4
  214. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +4 -1
  215. package/corpus/core/docs/content/locales/ja-JP/template-dispatch.mdx +5 -1
  216. package/corpus/core/docs/content/locales/ja-JP/template-mail.mdx +8 -0
  217. package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +9 -6
  218. package/corpus/core/docs/content/locales/ja-JP/using-your-agent.mdx +0 -7
  219. package/corpus/core/docs/content/locales/ja-JP/voice-input.mdx +6 -0
  220. package/corpus/core/docs/content/locales/ja-JP/workspace-connections.mdx +9 -2
  221. package/corpus/core/docs/content/locales/ja-JP/workspace.mdx +19 -18
  222. package/corpus/core/docs/content/locales/ko-KR/actions.mdx +2 -2
  223. package/corpus/core/docs/content/locales/ko-KR/agent-native-toolkit.mdx +2 -2
  224. package/corpus/core/docs/content/locales/ko-KR/agent-surfaces.mdx +8 -10
  225. package/corpus/core/docs/content/locales/ko-KR/agent-teams.mdx +1 -0
  226. package/corpus/core/docs/content/locales/ko-KR/authentication.mdx +1 -1
  227. package/corpus/core/docs/content/locales/ko-KR/components.mdx +11 -1
  228. package/corpus/core/docs/content/locales/ko-KR/creating-templates.mdx +3 -7
  229. package/corpus/core/docs/content/locales/ko-KR/cross-app-sso.mdx +16 -6
  230. package/corpus/core/docs/content/locales/ko-KR/deployment.mdx +8 -0
  231. package/corpus/core/docs/content/locales/ko-KR/extensions.mdx +8 -0
  232. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +2 -7
  233. package/corpus/core/docs/content/locales/ko-KR/key-concepts.mdx +13 -20
  234. package/corpus/core/docs/content/locales/ko-KR/messaging.mdx +80 -15
  235. package/corpus/core/docs/content/locales/ko-KR/multi-tenancy.mdx +5 -5
  236. package/corpus/core/docs/content/locales/ko-KR/notifications.mdx +18 -10
  237. package/corpus/core/docs/content/locales/ko-KR/processors.mdx +11 -5
  238. package/corpus/core/docs/content/locales/ko-KR/server.mdx +17 -10
  239. package/corpus/core/docs/content/locales/ko-KR/sharing.mdx +10 -10
  240. package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +34 -17
  241. package/corpus/core/docs/content/locales/ko-KR/template-assets.mdx +16 -13
  242. package/corpus/core/docs/content/locales/ko-KR/template-brain.mdx +3 -1
  243. package/corpus/core/docs/content/locales/ko-KR/template-clips.mdx +4 -4
  244. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +4 -1
  245. package/corpus/core/docs/content/locales/ko-KR/template-dispatch.mdx +5 -1
  246. package/corpus/core/docs/content/locales/ko-KR/template-mail.mdx +8 -0
  247. package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +9 -6
  248. package/corpus/core/docs/content/locales/ko-KR/using-your-agent.mdx +0 -7
  249. package/corpus/core/docs/content/locales/ko-KR/voice-input.mdx +6 -0
  250. package/corpus/core/docs/content/locales/ko-KR/workspace-connections.mdx +9 -2
  251. package/corpus/core/docs/content/locales/ko-KR/workspace.mdx +19 -18
  252. package/corpus/core/docs/content/locales/pt-BR/actions.mdx +2 -2
  253. package/corpus/core/docs/content/locales/pt-BR/agent-native-toolkit.mdx +2 -2
  254. package/corpus/core/docs/content/locales/pt-BR/agent-surfaces.mdx +8 -10
  255. package/corpus/core/docs/content/locales/pt-BR/agent-teams.mdx +1 -0
  256. package/corpus/core/docs/content/locales/pt-BR/authentication.mdx +1 -1
  257. package/corpus/core/docs/content/locales/pt-BR/components.mdx +11 -1
  258. package/corpus/core/docs/content/locales/pt-BR/creating-templates.mdx +3 -7
  259. package/corpus/core/docs/content/locales/pt-BR/cross-app-sso.mdx +16 -6
  260. package/corpus/core/docs/content/locales/pt-BR/deployment.mdx +8 -0
  261. package/corpus/core/docs/content/locales/pt-BR/extensions.mdx +9 -0
  262. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +3 -7
  263. package/corpus/core/docs/content/locales/pt-BR/key-concepts.mdx +13 -20
  264. package/corpus/core/docs/content/locales/pt-BR/messaging.mdx +88 -15
  265. package/corpus/core/docs/content/locales/pt-BR/multi-tenancy.mdx +5 -5
  266. package/corpus/core/docs/content/locales/pt-BR/notifications.mdx +18 -10
  267. package/corpus/core/docs/content/locales/pt-BR/processors.mdx +11 -5
  268. package/corpus/core/docs/content/locales/pt-BR/server.mdx +17 -10
  269. package/corpus/core/docs/content/locales/pt-BR/sharing.mdx +10 -10
  270. package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +34 -17
  271. package/corpus/core/docs/content/locales/pt-BR/template-assets.mdx +16 -13
  272. package/corpus/core/docs/content/locales/pt-BR/template-brain.mdx +3 -1
  273. package/corpus/core/docs/content/locales/pt-BR/template-clips.mdx +4 -3
  274. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +4 -1
  275. package/corpus/core/docs/content/locales/pt-BR/template-dispatch.mdx +5 -1
  276. package/corpus/core/docs/content/locales/pt-BR/template-mail.mdx +8 -0
  277. package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +9 -6
  278. package/corpus/core/docs/content/locales/pt-BR/using-your-agent.mdx +0 -7
  279. package/corpus/core/docs/content/locales/pt-BR/voice-input.mdx +6 -0
  280. package/corpus/core/docs/content/locales/pt-BR/workspace-connections.mdx +9 -2
  281. package/corpus/core/docs/content/locales/pt-BR/workspace.mdx +19 -18
  282. package/corpus/core/docs/content/locales/zh-CN/actions.mdx +2 -2
  283. package/corpus/core/docs/content/locales/zh-CN/agent-native-toolkit.mdx +2 -2
  284. package/corpus/core/docs/content/locales/zh-CN/agent-surfaces.mdx +8 -10
  285. package/corpus/core/docs/content/locales/zh-CN/agent-teams.mdx +1 -0
  286. package/corpus/core/docs/content/locales/zh-CN/authentication.mdx +1 -1
  287. package/corpus/core/docs/content/locales/zh-CN/components.mdx +11 -1
  288. package/corpus/core/docs/content/locales/zh-CN/creating-templates.mdx +3 -7
  289. package/corpus/core/docs/content/locales/zh-CN/cross-app-sso.mdx +16 -6
  290. package/corpus/core/docs/content/locales/zh-CN/deployment.mdx +8 -0
  291. package/corpus/core/docs/content/locales/zh-CN/extensions.mdx +6 -0
  292. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +2 -7
  293. package/corpus/core/docs/content/locales/zh-CN/key-concepts.mdx +13 -20
  294. package/corpus/core/docs/content/locales/zh-CN/messaging.mdx +78 -15
  295. package/corpus/core/docs/content/locales/zh-CN/multi-tenancy.mdx +5 -5
  296. package/corpus/core/docs/content/locales/zh-CN/notifications.mdx +18 -10
  297. package/corpus/core/docs/content/locales/zh-CN/processors.mdx +11 -5
  298. package/corpus/core/docs/content/locales/zh-CN/server.mdx +16 -10
  299. package/corpus/core/docs/content/locales/zh-CN/sharing.mdx +10 -10
  300. package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +34 -17
  301. package/corpus/core/docs/content/locales/zh-CN/template-assets.mdx +16 -13
  302. package/corpus/core/docs/content/locales/zh-CN/template-brain.mdx +3 -1
  303. package/corpus/core/docs/content/locales/zh-CN/template-clips.mdx +4 -4
  304. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +4 -1
  305. package/corpus/core/docs/content/locales/zh-CN/template-dispatch.mdx +5 -1
  306. package/corpus/core/docs/content/locales/zh-CN/template-mail.mdx +8 -0
  307. package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +9 -6
  308. package/corpus/core/docs/content/locales/zh-CN/using-your-agent.mdx +0 -7
  309. package/corpus/core/docs/content/locales/zh-CN/voice-input.mdx +6 -0
  310. package/corpus/core/docs/content/locales/zh-CN/workspace-connections.mdx +9 -2
  311. package/corpus/core/docs/content/locales/zh-CN/workspace.mdx +19 -18
  312. package/corpus/core/docs/content/locales/zh-TW/actions.mdx +2 -2
  313. package/corpus/core/docs/content/locales/zh-TW/agent-native-toolkit.mdx +2 -2
  314. package/corpus/core/docs/content/locales/zh-TW/agent-surfaces.mdx +8 -10
  315. package/corpus/core/docs/content/locales/zh-TW/agent-teams.mdx +1 -0
  316. package/corpus/core/docs/content/locales/zh-TW/authentication.mdx +1 -1
  317. package/corpus/core/docs/content/locales/zh-TW/components.mdx +11 -1
  318. package/corpus/core/docs/content/locales/zh-TW/creating-templates.mdx +3 -7
  319. package/corpus/core/docs/content/locales/zh-TW/cross-app-sso.mdx +16 -6
  320. package/corpus/core/docs/content/locales/zh-TW/deployment.mdx +8 -0
  321. package/corpus/core/docs/content/locales/zh-TW/extensions.mdx +6 -0
  322. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +2 -7
  323. package/corpus/core/docs/content/locales/zh-TW/key-concepts.mdx +13 -20
  324. package/corpus/core/docs/content/locales/zh-TW/messaging.mdx +78 -15
  325. package/corpus/core/docs/content/locales/zh-TW/multi-tenancy.mdx +5 -5
  326. package/corpus/core/docs/content/locales/zh-TW/notifications.mdx +18 -10
  327. package/corpus/core/docs/content/locales/zh-TW/processors.mdx +11 -5
  328. package/corpus/core/docs/content/locales/zh-TW/server.mdx +16 -10
  329. package/corpus/core/docs/content/locales/zh-TW/sharing.mdx +10 -10
  330. package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +34 -17
  331. package/corpus/core/docs/content/locales/zh-TW/template-assets.mdx +16 -13
  332. package/corpus/core/docs/content/locales/zh-TW/template-brain.mdx +3 -1
  333. package/corpus/core/docs/content/locales/zh-TW/template-clips.mdx +4 -4
  334. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +4 -1
  335. package/corpus/core/docs/content/locales/zh-TW/template-dispatch.mdx +5 -1
  336. package/corpus/core/docs/content/locales/zh-TW/template-mail.mdx +8 -0
  337. package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +9 -6
  338. package/corpus/core/docs/content/locales/zh-TW/using-your-agent.mdx +0 -7
  339. package/corpus/core/docs/content/locales/zh-TW/voice-input.mdx +6 -0
  340. package/corpus/core/docs/content/locales/zh-TW/workspace-connections.mdx +9 -2
  341. package/corpus/core/docs/content/locales/zh-TW/workspace.mdx +19 -18
  342. package/corpus/core/docs/content/mcp-apps.mdx +14 -32
  343. package/corpus/core/docs/content/mcp-clients.mdx +48 -54
  344. package/corpus/core/docs/content/mcp-protocol.mdx +25 -10
  345. package/corpus/core/docs/content/messaging.mdx +238 -48
  346. package/corpus/core/docs/content/multi-app-workspace.mdx +11 -96
  347. package/corpus/core/docs/content/multi-tenancy.mdx +5 -5
  348. package/corpus/core/docs/content/native-chat-ui.mdx +4 -4
  349. package/corpus/core/docs/content/notifications.mdx +19 -12
  350. package/corpus/core/docs/content/observability.mdx +2 -4
  351. package/corpus/core/docs/content/observational-memory.mdx +7 -3
  352. package/corpus/core/docs/content/onboarding.mdx +9 -2
  353. package/corpus/core/docs/content/plan-plugin.mdx +10 -2
  354. package/corpus/core/docs/content/pr-visual-recap.mdx +1 -1
  355. package/corpus/core/docs/content/processors.mdx +11 -5
  356. package/corpus/core/docs/content/pure-agent-apps.mdx +5 -1
  357. package/corpus/core/docs/content/real-time-collaboration.mdx +30 -67
  358. package/corpus/core/docs/content/recurring-jobs.mdx +8 -6
  359. package/corpus/core/docs/content/routing.mdx +3 -4
  360. package/corpus/core/docs/content/sandbox-adapters.mdx +30 -53
  361. package/corpus/core/docs/content/security.mdx +8 -0
  362. package/corpus/core/docs/content/server.mdx +17 -10
  363. package/corpus/core/docs/content/sharing.mdx +10 -10
  364. package/corpus/core/docs/content/skills-guide.mdx +35 -16
  365. package/corpus/core/docs/content/template-analytics.mdx +11 -8
  366. package/corpus/core/docs/content/template-assets.mdx +16 -13
  367. package/corpus/core/docs/content/template-brain.mdx +3 -1
  368. package/corpus/core/docs/content/template-calendar.mdx +12 -4
  369. package/corpus/core/docs/content/template-chat.mdx +4 -4
  370. package/corpus/core/docs/content/template-clips.mdx +6 -3
  371. package/corpus/core/docs/content/template-content.mdx +23 -18
  372. package/corpus/core/docs/content/template-design.mdx +7 -1
  373. package/corpus/core/docs/content/template-dispatch.mdx +5 -1
  374. package/corpus/core/docs/content/template-mail.mdx +14 -2
  375. package/corpus/core/docs/content/template-plan.mdx +22 -15
  376. package/corpus/core/docs/content/template-slides.mdx +11 -3
  377. package/corpus/core/docs/content/toolkit-agent-ux.mdx +46 -3
  378. package/corpus/core/docs/content/toolkit-collaboration.mdx +58 -4
  379. package/corpus/core/docs/content/toolkit-command-navigation.mdx +8 -2
  380. package/corpus/core/docs/content/toolkit-comments-review.mdx +10 -2
  381. package/corpus/core/docs/content/toolkit-history.mdx +8 -3
  382. package/corpus/core/docs/content/toolkit-observability.mdx +48 -2
  383. package/corpus/core/docs/content/toolkit-org-team.mdx +8 -2
  384. package/corpus/core/docs/content/toolkit-resources.mdx +45 -2
  385. package/corpus/core/docs/content/toolkit-settings.mdx +8 -2
  386. package/corpus/core/docs/content/toolkit-setup-connections.mdx +7 -2
  387. package/corpus/core/docs/content/toolkit-sharing.mdx +46 -3
  388. package/corpus/core/docs/content/toolkit-ui.mdx +82 -11
  389. package/corpus/core/docs/content/tracking.mdx +10 -8
  390. package/corpus/core/docs/content/using-your-agent.mdx +0 -12
  391. package/corpus/core/docs/content/voice-input.mdx +7 -1
  392. package/corpus/core/docs/content/what-is-agent-native.mdx +7 -8
  393. package/corpus/core/docs/content/workspace-connections.mdx +16 -23
  394. package/corpus/core/docs/content/workspace-management.mdx +16 -4
  395. package/corpus/core/docs/content/workspace.mdx +19 -18
  396. package/corpus/core/package.json +5 -1
  397. package/corpus/core/src/a2a/artifact-response.ts +131 -2
  398. package/corpus/core/src/a2a/client.ts +10 -0
  399. package/corpus/core/src/a2a/handlers.ts +40 -76
  400. package/corpus/core/src/a2a/types.ts +2 -0
  401. package/corpus/core/src/agent/context-xray/tokenize.ts +6 -1
  402. package/corpus/core/src/agent/durable-background.ts +24 -0
  403. package/corpus/core/src/agent/engine/ai-sdk-engine.ts +9 -5
  404. package/corpus/core/src/agent/engine/anthropic-engine.ts +2 -4
  405. package/corpus/core/src/agent/engine/builder-engine.ts +5 -7
  406. package/corpus/core/src/agent/engine/index.ts +1 -0
  407. package/corpus/core/src/agent/engine/registry.ts +40 -0
  408. package/corpus/core/src/agent/harness/ai-sdk-adapter.ts +6 -1
  409. package/corpus/core/src/agent/harness/background.ts +96 -19
  410. package/corpus/core/src/agent/harness/index.ts +11 -0
  411. package/corpus/core/src/agent/harness/lifecycle.ts +498 -0
  412. package/corpus/core/src/agent/harness/runner.ts +38 -0
  413. package/corpus/core/src/agent/harness/store.ts +22 -3
  414. package/corpus/core/src/agent/model-config.ts +4 -1
  415. package/corpus/core/src/agent/production-agent.ts +205 -9
  416. package/corpus/core/src/agent/run-manager.ts +135 -11
  417. package/corpus/core/src/agent/run-store.ts +225 -15
  418. package/corpus/core/src/agent/types.ts +23 -0
  419. package/corpus/core/src/application-state/index.ts +1 -0
  420. package/corpus/core/src/application-state/store.ts +32 -0
  421. package/corpus/core/src/audit/record.ts +31 -0
  422. package/corpus/core/src/audit/store.ts +69 -3
  423. package/corpus/core/src/audit/types.ts +13 -0
  424. package/corpus/core/src/automation/index.ts +802 -0
  425. package/corpus/core/src/cli/code-agent-connector.ts +263 -8
  426. package/corpus/core/src/cli/code-agent-executor.ts +15 -1
  427. package/corpus/core/src/cli/create.ts +12 -5
  428. package/corpus/core/src/cli/design-connect.ts +596 -36
  429. package/corpus/core/src/client/AgentPanel.tsx +92 -44
  430. package/corpus/core/src/client/AssistantChat.tsx +324 -149
  431. package/corpus/core/src/client/MultiTabAssistantChat.tsx +36 -40
  432. package/corpus/core/src/client/RunStuckBanner.tsx +69 -20
  433. package/corpus/core/src/client/agent-chat-adapter.ts +54 -5
  434. package/corpus/core/src/client/appearance.ts +8 -5
  435. package/corpus/core/src/client/automation.ts +22 -0
  436. package/corpus/core/src/client/chat/connectors.ts +293 -29
  437. package/corpus/core/src/client/chat/message-components.tsx +23 -1
  438. package/corpus/core/src/client/chat/run-recovery.tsx +67 -50
  439. package/corpus/core/src/client/chat/runtime.ts +126 -25
  440. package/corpus/core/src/client/chat/tool-call-display.tsx +45 -4
  441. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +294 -0
  442. package/corpus/core/src/client/composer/TiptapComposer.tsx +29 -20
  443. package/corpus/core/src/client/composer/VoiceButton.tsx +20 -0
  444. package/corpus/core/src/client/composer/index.ts +22 -0
  445. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +640 -0
  446. package/corpus/core/src/client/guided-questions.tsx +12 -3
  447. package/corpus/core/src/client/index.ts +48 -0
  448. package/corpus/core/src/client/integrations/api.ts +295 -0
  449. package/corpus/core/src/client/integrations/index.ts +26 -0
  450. package/corpus/core/src/client/settings/DemoModeSection.tsx +4 -3
  451. package/corpus/core/src/client/settings/SettingsPanel.tsx +4 -0
  452. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +95 -37
  453. package/corpus/core/src/client/transcription/use-live-transcription.ts +68 -5
  454. package/corpus/core/src/client/use-chat-models.ts +17 -17
  455. package/corpus/core/src/client/use-db-sync.ts +108 -7
  456. package/corpus/core/src/client/use-run-stuck-detection.ts +41 -3
  457. package/corpus/core/src/code-agents/background-controller.ts +18 -0
  458. package/corpus/core/src/collab/ydoc-manager.ts +41 -6
  459. package/corpus/core/src/db/migrations.ts +17 -1
  460. package/corpus/core/src/demo/fetch-interceptor.ts +16 -11
  461. package/corpus/core/src/deploy/build.ts +59 -3
  462. package/corpus/core/src/deploy/workspace-deploy.ts +37 -2
  463. package/corpus/core/src/file-upload/types.ts +2 -0
  464. package/corpus/core/src/index.ts +37 -0
  465. package/corpus/core/src/integrations/a2a-continuations-store.ts +6 -4
  466. package/corpus/core/src/integrations/adapters/discord.ts +362 -0
  467. package/corpus/core/src/integrations/adapters/index.ts +29 -0
  468. package/corpus/core/src/integrations/adapters/microsoft-teams.ts +411 -0
  469. package/corpus/core/src/integrations/adapters/slack.ts +900 -27
  470. package/corpus/core/src/integrations/adapters/telegram.ts +54 -15
  471. package/corpus/core/src/integrations/adapters/whatsapp.ts +41 -17
  472. package/corpus/core/src/integrations/awaiting-input-store.ts +130 -0
  473. package/corpus/core/src/integrations/catalog.ts +571 -0
  474. package/corpus/core/src/integrations/computer-supervision-store.ts +423 -0
  475. package/corpus/core/src/integrations/computer-supervision.ts +213 -0
  476. package/corpus/core/src/integrations/controls-store.ts +187 -0
  477. package/corpus/core/src/integrations/index.ts +129 -1
  478. package/corpus/core/src/integrations/installations-store.ts +677 -0
  479. package/corpus/core/src/integrations/integration-memory.ts +187 -0
  480. package/corpus/core/src/integrations/pending-tasks-retry-job.ts +6 -6
  481. package/corpus/core/src/integrations/pending-tasks-store.ts +83 -5
  482. package/corpus/core/src/integrations/plugin.ts +916 -49
  483. package/corpus/core/src/integrations/remote-commands-store.ts +334 -3
  484. package/corpus/core/src/integrations/remote-devices-store.ts +68 -9
  485. package/corpus/core/src/integrations/remote-json-safety.ts +127 -0
  486. package/corpus/core/src/integrations/remote-run-events-store.ts +104 -19
  487. package/corpus/core/src/integrations/remote-types.ts +66 -3
  488. package/corpus/core/src/integrations/scope-store.ts +498 -0
  489. package/corpus/core/src/integrations/slack-manifest.ts +78 -0
  490. package/corpus/core/src/integrations/slack-oauth.ts +343 -0
  491. package/corpus/core/src/integrations/types.ts +179 -0
  492. package/corpus/core/src/integrations/usage-budget-store.ts +906 -0
  493. package/corpus/core/src/integrations/webhook-handler.ts +723 -53
  494. package/corpus/core/src/jobs/scheduler.ts +100 -2
  495. package/corpus/core/src/jobs/tools.ts +45 -9
  496. package/corpus/core/src/localization/default-messages.ts +28 -0
  497. package/corpus/core/src/mcp-client/config.ts +48 -2
  498. package/corpus/core/src/mcp-client/index.ts +35 -2
  499. package/corpus/core/src/mcp-client/tool-policy.ts +182 -0
  500. package/corpus/core/src/provider-api/index.ts +72 -1
  501. package/corpus/core/src/resources/handlers.ts +88 -14
  502. package/corpus/core/src/resources/script-helpers.ts +36 -7
  503. package/corpus/core/src/resources/store.ts +59 -52
  504. package/corpus/core/src/scripts/call-agent.ts +107 -1
  505. package/corpus/core/src/secrets/register-framework-secrets.ts +27 -4
  506. package/corpus/core/src/server/agent-chat-plugin.ts +356 -127
  507. package/corpus/core/src/server/auth.ts +10 -14
  508. package/corpus/core/src/server/builder-design-systems.ts +16 -1
  509. package/corpus/core/src/server/edge.ts +18 -0
  510. package/corpus/core/src/server/index.ts +42 -0
  511. package/corpus/core/src/server/realtime-voice.ts +590 -0
  512. package/corpus/core/src/server/request-context.ts +18 -0
  513. package/corpus/core/src/server/social-og-image.ts +3 -2
  514. package/corpus/core/src/shared/reasoning-effort.ts +61 -19
  515. package/corpus/core/src/styles/agent-conversation.css +17 -0
  516. package/corpus/core/src/styles/agent-native.css +62 -44
  517. package/corpus/core/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
  518. package/corpus/core/src/templates/default/AGENTS.md +7 -3
  519. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
  520. package/corpus/core/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
  521. package/corpus/core/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
  522. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
  523. package/corpus/core/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
  524. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -5
  525. package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -2
  526. package/corpus/core/src/usage/store.ts +37 -2
  527. package/corpus/templates/analytics/.agents/skills/capture-learnings/SKILL.md +22 -9
  528. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +23 -0
  529. package/corpus/templates/analytics/.builder/skills/provider-api/SKILL.md +15 -0
  530. package/corpus/templates/analytics/actions/save-monitor.ts +25 -2
  531. package/corpus/templates/analytics/app/lib/data-sources.ts +28 -0
  532. package/corpus/templates/analytics/changelog/2026-07-10-agent-created-uptime-monitors-now-return-a-direct-link-to-th.md +6 -0
  533. package/corpus/templates/analytics/changelog/2026-07-10-dashboard-email-reports-still-arrive-when-screenshot-capture-temporarily-fails.md +6 -0
  534. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +3 -7
  535. package/corpus/templates/analytics/server/lib/credential-keys.ts +12 -0
  536. package/corpus/templates/analytics/server/lib/dashboard-report.ts +5 -1
  537. package/corpus/templates/analytics/server/lib/provider-credentials.ts +2 -0
  538. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +16 -0
  539. package/corpus/templates/assets/.agents/skills/capture-learnings/SKILL.md +22 -9
  540. package/corpus/templates/brain/.agents/skills/capture-learnings/SKILL.md +22 -9
  541. package/corpus/templates/brain/app/lib/settings-navigation.ts +22 -0
  542. package/corpus/templates/brain/app/routes/settings.tsx +367 -252
  543. package/corpus/templates/brain/changelog/2026-07-10-brain-settings-now-separate-assistant-behavior-publishing-re.md +6 -0
  544. package/corpus/templates/brain/changelog/2026-07-10-organization-settings-now-opens-directly-from-the-workspace-.md +6 -0
  545. package/corpus/templates/calendar/.agents/skills/capture-learnings/SKILL.md +22 -9
  546. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +36 -4
  547. package/corpus/templates/calendar/AGENTS.md +4 -0
  548. package/corpus/templates/calendar/actions/create-event.ts +7 -19
  549. package/corpus/templates/calendar/actions/delete-event.ts +10 -3
  550. package/corpus/templates/calendar/actions/rsvp-event.ts +1 -1
  551. package/corpus/templates/calendar/actions/update-event.ts +4 -3
  552. package/corpus/templates/calendar/app/components/calendar/CommandPalette.tsx +98 -108
  553. package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +100 -13
  554. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +12 -4
  555. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +97 -90
  556. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +3 -3
  557. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +86 -8
  558. package/corpus/templates/calendar/app/components/calendar/EventDialog.tsx +3 -1
  559. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +12 -4
  560. package/corpus/templates/calendar/app/hooks/use-events.ts +1 -0
  561. package/corpus/templates/calendar/app/lib/event-account-selection.ts +36 -0
  562. package/corpus/templates/calendar/app/lib/event-form-initialization.ts +21 -0
  563. package/corpus/templates/calendar/app/lib/event-mutation-inputs.ts +18 -0
  564. package/corpus/templates/calendar/app/pages/CalendarView.tsx +119 -26
  565. package/corpus/templates/calendar/changelog/2026-07-10-choose-which-connected-google-account-receives-a-new-event-w.md +6 -0
  566. package/corpus/templates/calendar/changelog/2026-07-10-event-guest-details-and-option-menus-now-use-valid-accessibl.md +6 -0
  567. package/corpus/templates/calendar/changelog/2026-07-10-natural-language-event-phrases-stay-available-as-quick-creat.md +6 -0
  568. package/corpus/templates/calendar/server/db/schema.ts +2 -0
  569. package/corpus/templates/calendar/server/handlers/bookings.ts +43 -6
  570. package/corpus/templates/calendar/server/handlers/events.ts +28 -9
  571. package/corpus/templates/calendar/server/lib/google-calendar.ts +66 -38
  572. package/corpus/templates/calendar/server/plugins/db.ts +5 -0
  573. package/corpus/templates/chat/.agents/skills/capture-learnings/SKILL.md +22 -9
  574. package/corpus/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
  575. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +12 -3
  576. package/corpus/templates/clips/.agents/skills/capture-learnings/SKILL.md +22 -9
  577. package/corpus/templates/clips/.agents/skills/meetings/SKILL.md +1 -1
  578. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +17 -1
  579. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +8 -0
  580. package/corpus/templates/clips/AGENTS.md +12 -5
  581. package/corpus/templates/clips/actions/finalize-recording.ts +63 -23
  582. package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -2
  583. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +72 -9
  584. package/corpus/templates/clips/actions/list-recordings.ts +19 -3
  585. package/corpus/templates/clips/actions/navigate.ts +2 -0
  586. package/corpus/templates/clips/actions/regenerate-title.ts +53 -7
  587. package/corpus/templates/clips/actions/reprocess-recording.ts +20 -6
  588. package/corpus/templates/clips/actions/request-transcript.ts +168 -72
  589. package/corpus/templates/clips/actions/save-browser-transcript.ts +11 -9
  590. package/corpus/templates/clips/actions/view-screen.ts +57 -5
  591. package/corpus/templates/clips/app/components/layout/Header.tsx +1 -0
  592. package/corpus/templates/clips/app/components/library/empty-state.tsx +2 -0
  593. package/corpus/templates/clips/app/components/library/library-grid.tsx +69 -42
  594. package/corpus/templates/clips/app/components/library/library-layout.tsx +15 -1
  595. package/corpus/templates/clips/app/components/library/recording-card.tsx +81 -68
  596. package/corpus/templates/clips/app/components/library/search-bar.tsx +4 -3
  597. package/corpus/templates/clips/app/components/player/comments-panel.tsx +101 -53
  598. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +9 -3
  599. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +102 -0
  600. package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -1
  601. package/corpus/templates/clips/app/components/player/video-player.tsx +10 -1
  602. package/corpus/templates/clips/app/hooks/use-auto-title.ts +14 -0
  603. package/corpus/templates/clips/app/hooks/use-library.ts +1 -1
  604. package/corpus/templates/clips/app/hooks/use-navigation-state.ts +10 -2
  605. package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -1
  606. package/corpus/templates/clips/app/i18n/de-DE.ts +7 -1
  607. package/corpus/templates/clips/app/i18n/en-US.ts +7 -1
  608. package/corpus/templates/clips/app/i18n/es-ES.ts +7 -1
  609. package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -1
  610. package/corpus/templates/clips/app/i18n/hi-IN.ts +7 -1
  611. package/corpus/templates/clips/app/i18n/ja-JP.ts +7 -1
  612. package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -1
  613. package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -1
  614. package/corpus/templates/clips/app/i18n/zh-CN.ts +8 -1
  615. package/corpus/templates/clips/app/i18n/zh-TW.ts +8 -1
  616. package/corpus/templates/clips/app/lib/recording-visibility.ts +70 -0
  617. package/corpus/templates/clips/app/routes/_app.shared.tsx +20 -0
  618. package/corpus/templates/clips/app/routes/download.tsx +24 -8
  619. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +2 -0
  620. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +115 -2
  621. package/corpus/templates/clips/app/routes/record.tsx +62 -0
  622. package/corpus/templates/clips/app/routes/share.$shareId.tsx +25 -16
  623. package/corpus/templates/clips/changelog/2026-07-10-clips-desktop-is-now-available-for-linux-with-appimage-debia.md +6 -0
  624. package/corpus/templates/clips/changelog/2026-07-10-clips-downloads-updates-sooner-in-the-background-and-offers-.md +6 -0
  625. package/corpus/templates/clips/changelog/2026-07-10-clips-shared-with-you-now-appear-in-a-searchable-shared-with.md +6 -0
  626. package/corpus/templates/clips/changelog/2026-07-10-clips-with-missing-mobile-video-frames-can-be-repaired-witho.md +6 -0
  627. package/corpus/templates/clips/changelog/2026-07-10-comment-replies-now-open-inline-and-focus-immediately-while-.md +6 -0
  628. package/corpus/templates/clips/changelog/2026-07-10-dismissed-upload-warnings-now-keep-recordings-in-clip-drafts.md +6 -0
  629. package/corpus/templates/clips/changelog/2026-07-10-dragging-the-meeting-recorder-no-longer-opens-the-expanded.md +6 -0
  630. package/corpus/templates/clips/changelog/2026-07-10-finishing-meeting-notes-no-longer-opens-your-browser.md +6 -0
  631. package/corpus/templates/clips/changelog/2026-07-10-meeting-recordings-now-keep-microphone-audio-and-recover-tra.md +6 -0
  632. package/corpus/templates/clips/changelog/2026-07-10-mobile-camera-recordings-pause-while-backgrounded.md +6 -0
  633. package/corpus/templates/clips/changelog/2026-07-10-mp4-downloads-now-show-progress-immediately-after-the-option.md +6 -0
  634. package/corpus/templates/clips/changelog/2026-07-10-recording-pages-now-open-as-soon-as-you-stop-with-a-share-li.md +6 -0
  635. package/corpus/templates/clips/changelog/2026-07-10-recording-pause-and-resume-controls-now-respond-reliably-on-.md +6 -0
  636. package/corpus/templates/clips/changelog/2026-07-10-recordings-now-seek-smoothly-downloads-use-the-correct-file-.md +6 -0
  637. package/corpus/templates/clips/changelog/2026-07-10-s3-compatible-storage-now-saves-hosted-recordings-without-re.md +6 -0
  638. package/corpus/templates/clips/changelog/2026-07-10-starting-and-joining-a-meeting-now-closes-the-desktop-popover.md +6 -0
  639. package/corpus/templates/clips/changelog/2026-07-10-timestamped-comments-now-appear-over-the-video-as-playback-r.md +6 -0
  640. package/corpus/templates/clips/changelog/2026-07-10-transcript-backed-titles-and-summaries-now-finish-after-recording.md +6 -0
  641. package/corpus/templates/clips/changelog/2026-07-10-zoom-meetings-now-open-directly-in-the-desktop-app.md +6 -0
  642. package/corpus/templates/clips/chrome-extension/src/overlay.ts +49 -7
  643. package/corpus/templates/clips/desktop/README.md +22 -6
  644. package/corpus/templates/clips/desktop/package.json +1 -1
  645. package/corpus/templates/clips/desktop/src/app.tsx +102 -61
  646. package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +15 -9
  647. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -14
  648. package/corpus/templates/clips/desktop/src/lib/finalization-guard.ts +22 -0
  649. package/corpus/templates/clips/desktop/src/lib/meeting-join-url.ts +33 -0
  650. package/corpus/templates/clips/desktop/src/lib/pause-transition.ts +79 -0
  651. package/corpus/templates/clips/desktop/src/lib/permissions.ts +3 -1
  652. package/corpus/templates/clips/desktop/src/lib/pill-interaction.ts +19 -0
  653. package/corpus/templates/clips/desktop/src/lib/recorder.ts +187 -159
  654. package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +3 -2
  655. package/corpus/templates/clips/desktop/src/lib/updater.ts +26 -4
  656. package/corpus/templates/clips/desktop/src/overlays/finalizing.tsx +4 -8
  657. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +3 -2
  658. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +32 -6
  659. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +50 -5
  660. package/corpus/templates/clips/desktop/src/styles.css +11 -19
  661. package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +1 -1
  662. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +2 -2
  663. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -1
  664. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +121 -4
  665. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +97 -17
  666. package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +11 -7
  667. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +80 -5
  668. package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -1
  669. package/corpus/templates/clips/desktop/src-tauri/tauri.linux.conf.json +11 -0
  670. package/corpus/templates/clips/netlify.toml +3 -0
  671. package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +106 -0
  672. package/corpus/templates/clips/server/lib/public-agent-context.ts +9 -1
  673. package/corpus/templates/clips/server/lib/resumable-upload-provider.ts +52 -0
  674. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +433 -85
  675. package/corpus/templates/clips/server/lib/video-remux.ts +114 -0
  676. package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +109 -0
  677. package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +22 -11
  678. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +4 -2
  679. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +47 -5
  680. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +10 -2
  681. package/corpus/templates/clips/shared/share-loader-response.ts +12 -0
  682. package/corpus/templates/clips/shared/transcript-status.ts +40 -0
  683. package/corpus/templates/clips/vitest.config.ts +23 -0
  684. package/corpus/templates/content/.agents/skills/capture-learnings/SKILL.md +22 -9
  685. package/corpus/templates/content/.agents/skills/content/SKILL.md +57 -5
  686. package/corpus/templates/content/AGENTS.md +65 -55
  687. package/corpus/templates/content/actions/_builder-cms-read-client.ts +10 -16
  688. package/corpus/templates/content/actions/_database-source-utils.ts +58 -11
  689. package/corpus/templates/content/actions/_property-utils.ts +30 -2
  690. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +312 -114
  691. package/corpus/templates/content/actions/submit-content-database-form.ts +497 -0
  692. package/corpus/templates/content/actions/update-content-database-view.ts +8 -1
  693. package/corpus/templates/content/actions/view-screen.ts +4 -1
  694. package/corpus/templates/content/agent-native.app-skill.json +1 -1
  695. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +28 -9
  696. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +250 -64
  697. package/corpus/templates/content/app/components/editor/database/FormView.tsx +460 -0
  698. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +3 -0
  699. package/corpus/templates/content/app/components/editor/database/settings.tsx +30 -37
  700. package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
  701. package/corpus/templates/content/app/components/editor/database/view-config.ts +29 -1
  702. package/corpus/templates/content/app/components/ui/textarea.tsx +1 -0
  703. package/corpus/templates/content/app/hooks/use-content-database.ts +22 -0
  704. package/corpus/templates/content/app/i18n/zh-TW.ts +21 -0
  705. package/corpus/templates/content/app/i18n-data.ts +225 -0
  706. package/corpus/templates/content/changelog/2026-07-10-builder-backed-properties-now-load-current-source-values-as-.md +6 -0
  707. package/corpus/templates/content/changelog/2026-07-10-builder-database-refreshes-now-stay-explicit-and-accurate.md +6 -0
  708. package/corpus/templates/content/changelog/2026-07-10-database-form-views-now-collect-ordered-required-answers-and.md +6 -0
  709. package/corpus/templates/content/changelog/2026-07-10-database-tables-now-use-a-quieter-more-compact-layout-with-c.md +6 -0
  710. package/corpus/templates/content/changelog/2026-07-10-open-documents-no-longer-make-constant-background-requests-w.md +6 -0
  711. package/corpus/templates/content/changelog/2026-07-10-slack-intake-routes-to-content-database-forms.md +6 -0
  712. package/corpus/templates/content/parity/matrix.md +1 -0
  713. package/corpus/templates/content/parity/matrix.ts +18 -0
  714. package/corpus/templates/content/shared/api.ts +27 -1
  715. package/corpus/templates/content/shared/database-form.ts +53 -0
  716. package/corpus/templates/design/.agents/skills/capture-learnings/SKILL.md +22 -9
  717. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +26 -0
  718. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +106 -16
  719. package/corpus/templates/design/AGENTS.md +79 -18
  720. package/corpus/templates/design/DESIGN.md +1 -1
  721. package/corpus/templates/design/DEVELOPING.md +1 -1
  722. package/corpus/templates/design/FIGMA_INTEROPERABILITY.md +116 -0
  723. package/corpus/templates/design/actions/create-design-from-template.ts +220 -0
  724. package/corpus/templates/design/actions/create-design-system.ts +92 -16
  725. package/corpus/templates/design/actions/delete-design-template.ts +28 -0
  726. package/corpus/templates/design/actions/delete-file.ts +7 -0
  727. package/corpus/templates/design/actions/edit-design.ts +3 -0
  728. package/corpus/templates/design/actions/export-design-as-figma-svg.ts +137 -5
  729. package/corpus/templates/design/actions/export-pdf.ts +1 -1
  730. package/corpus/templates/design/actions/generate-design.ts +3 -0
  731. package/corpus/templates/design/actions/get-design-snapshot.ts +9 -0
  732. package/corpus/templates/design/actions/get-figma-connection-status.ts +26 -0
  733. package/corpus/templates/design/actions/get-figma-design-context.ts +138 -0
  734. package/corpus/templates/design/actions/get-figma-styles.ts +2 -2
  735. package/corpus/templates/design/actions/import-figma-clipboard.ts +112 -16
  736. package/corpus/templates/design/actions/import-figma-frame.ts +15 -4
  737. package/corpus/templates/design/actions/index-design-system-with-builder.ts +4 -0
  738. package/corpus/templates/design/actions/list-design-templates.ts +118 -0
  739. package/corpus/templates/design/actions/navigate.ts +16 -2
  740. package/corpus/templates/design/actions/provider-api-request.ts +11 -1
  741. package/corpus/templates/design/actions/save-design-as-template.ts +156 -0
  742. package/corpus/templates/design/actions/set-active-breakpoint.ts +13 -4
  743. package/corpus/templates/design/actions/take-design-screenshot.ts +73 -3
  744. package/corpus/templates/design/actions/update-file.ts +39 -22
  745. package/corpus/templates/design/actions/view-screen.ts +36 -1
  746. package/corpus/templates/design/actions/write-local-file.ts +50 -38
  747. package/corpus/templates/design/app/components/design/AutoLayoutSuggestionDialog.tsx +151 -0
  748. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +20 -0
  749. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +383 -29
  750. package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +3 -3
  751. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +384 -9
  752. package/corpus/templates/design/app/components/design/EditPanel.tsx +105 -32
  753. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +131 -46
  754. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +6 -0
  755. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +545 -54
  756. package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +40 -0
  757. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +1 -0
  758. package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +1 -0
  759. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +5 -1
  760. package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
  761. package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +3 -1
  762. package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +2 -0
  763. package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +19 -0
  764. package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +1 -0
  765. package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +27 -0
  766. package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +137 -81
  767. package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +25 -5
  768. package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +1 -1
  769. package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +350 -3
  770. package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +13 -0
  771. package/corpus/templates/design/app/components/design/multi-screen/types.ts +22 -1
  772. package/corpus/templates/design/app/components/design/types.ts +4 -0
  773. package/corpus/templates/design/app/components/design-system/ProductionDesignSystemShowcase.tsx +208 -0
  774. package/corpus/templates/design/app/components/editor/FigmaLinkComposerBubble.tsx +321 -0
  775. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +24 -4
  776. package/corpus/templates/design/app/components/layout/Layout.tsx +16 -2
  777. package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -0
  778. package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +72 -0
  779. package/corpus/templates/design/app/global.css +2 -35
  780. package/corpus/templates/design/app/hooks/use-navigation-state.ts +10 -0
  781. package/corpus/templates/design/app/i18n/zh-TW.ts +127 -5
  782. package/corpus/templates/design/app/i18n-breakpoints.ts +209 -0
  783. package/corpus/templates/design/app/i18n-data.ts +1317 -59
  784. package/corpus/templates/design/app/i18n-template-feature.ts +458 -0
  785. package/corpus/templates/design/app/lib/clipboard-content-lineage.ts +64 -0
  786. package/corpus/templates/design/app/lib/design-clipboard-managed-styles.ts +247 -0
  787. package/corpus/templates/design/app/lib/design-clipboard.ts +259 -0
  788. package/corpus/templates/design/app/lib/design-file-upload.ts +87 -0
  789. package/corpus/templates/design/app/lib/design-import.ts +198 -13
  790. package/corpus/templates/design/app/lib/desktop-design-preview.ts +423 -0
  791. package/corpus/templates/design/app/lib/figma-clipboard.ts +74 -8
  792. package/corpus/templates/design/app/lib/figma-connection.ts +161 -0
  793. package/corpus/templates/design/app/lib/figma-svg-copy.ts +814 -22
  794. package/corpus/templates/design/app/lib/figma-url.ts +77 -0
  795. package/corpus/templates/design/app/lib/pending-generation.ts +35 -0
  796. package/corpus/templates/design/app/pages/DesignSystems.tsx +236 -177
  797. package/corpus/templates/design/app/pages/Index.tsx +38 -0
  798. package/corpus/templates/design/app/pages/Templates.tsx +498 -0
  799. package/corpus/templates/design/app/pages/design-editor/auto-layout-suggestion.ts +328 -0
  800. package/corpus/templates/design/app/pages/design-editor/clone-idrefs.ts +113 -0
  801. package/corpus/templates/design/app/pages/design-editor/created-screen-navigation.ts +55 -0
  802. package/corpus/templates/design/app/pages/design-editor/editor-session.ts +32 -0
  803. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +49 -2
  804. package/corpus/templates/design/app/pages/design-editor/export-capture.ts +296 -0
  805. package/corpus/templates/design/app/pages/design-editor/history.ts +101 -2
  806. package/corpus/templates/design/app/pages/design-editor/latest-write-queue.ts +56 -0
  807. package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +28 -1
  808. package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +34 -0
  809. package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +202 -6
  810. package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +92 -0
  811. package/corpus/templates/design/app/pages/design-editor/performance-buffer-guard.ts +80 -0
  812. package/corpus/templates/design/app/pages/design-editor/save-failure.ts +58 -0
  813. package/corpus/templates/design/app/routes/templates.tsx +4 -6
  814. package/corpus/templates/design/changelog/2026-07-10-app-workspaces-now-use-clean-borderless-main-surfaces-throug.md +6 -0
  815. package/corpus/templates/design/changelog/2026-07-10-ask-chat-what-s-in-a-figma-file-or-frame-structure-screensho.md +6 -0
  816. package/corpus/templates/design/changelog/2026-07-10-canvas-edits-now-reject-malformed-html-before-it-can-corrupt.md +6 -0
  817. package/corpus/templates/design/changelog/2026-07-10-complex-designs-now-export-as-valid-secure-svgs-and-crisp-ra.md +6 -0
  818. package/corpus/templates/design/changelog/2026-07-10-complex-figma-masks-arcs-rich-text-transformed-images-and-ad.md +6 -0
  819. package/corpus/templates/design/changelog/2026-07-10-concurrent-agent-and-artboard-edits-no-longer-show-misleadin.md +6 -0
  820. package/corpus/templates/design/changelog/2026-07-10-copied-layers-paste-across-designs-and-browser-tabs.md +6 -0
  821. package/corpus/templates/design/changelog/2026-07-10-copy-and-download-editable-figma-svg.md +6 -0
  822. package/corpus/templates/design/changelog/2026-07-10-copying-design-text-now-pastes-readable-text-into-other-apps.md +6 -0
  823. package/corpus/templates/design/changelog/2026-07-10-deleted-screens-can-be-restored-with-undo-and-removed-again-.md +6 -0
  824. package/corpus/templates/design/changelog/2026-07-10-design-changes-now-save-before-switching-apps-and-retry-when.md +6 -0
  825. package/corpus/templates/design/changelog/2026-07-10-design-stays-usable-on-phones-by-keeping-editor-panels-and-f.md +6 -0
  826. package/corpus/templates/design/changelog/2026-07-10-designs-with-html-examples-inside-alpine-attributes-or-comme.md +6 -0
  827. package/corpus/templates/design/changelog/2026-07-10-download-all-screens-as-one-multi-page-pdf-from-the-overview.md +6 -0
  828. package/corpus/templates/design/changelog/2026-07-10-duplicated-layers-now-keep-labels-aria-relationships-fragmen.md +6 -0
  829. package/corpus/templates/design/changelog/2026-07-10-fig-import-results-stay-compact.md +6 -0
  830. package/corpus/templates/design/changelog/2026-07-10-figma-imports-now-load-real-fonts-fix-rotated-gradient-dashe.md +6 -0
  831. package/corpus/templates/design/changelog/2026-07-10-figma-links-in-chat-and-the-import-tab-now-offer-secure-one-.md +6 -0
  832. package/corpus/templates/design/changelog/2026-07-10-fixed-cmd-z-not-restoring-content-after-an-agent-driven-desi.md +6 -0
  833. package/corpus/templates/design/changelog/2026-07-10-fixed-download-pdf-being-unreachable-from-the-export-panel-e.md +6 -0
  834. package/corpus/templates/design/changelog/2026-07-10-fixed-dragging-a-layer-out-of-an-auto-layout-row-column-no-l.md +6 -0
  835. package/corpus/templates/design/changelog/2026-07-10-fixed-figma-svg-export-text-wrapping-sizing-and-inner-layer.md +6 -0
  836. package/corpus/templates/design/changelog/2026-07-10-fixed-hiding-or-locking-one-layer-no-longer-hides-or-blocks-.md +6 -0
  837. package/corpus/templates/design/changelog/2026-07-10-fixed-png-screenshots-of-tall-screens-being-cropped-to-one-v.md +6 -0
  838. package/corpus/templates/design/changelog/2026-07-10-fixed-png-svg-exports-capturing-broken-layout-when-webfonts-.md +6 -0
  839. package/corpus/templates/design/changelog/2026-07-10-frame-tool-now-offers-standard-ad-unit-size-presets-medium-r.md +6 -0
  840. package/corpus/templates/design/changelog/2026-07-10-full-view-controls-stay-within-their-frame-instead-of-coveri.md +6 -0
  841. package/corpus/templates/design/changelog/2026-07-10-hover-focus-focus-visible-pressed-and-disabled-states-now-pr.md +6 -0
  842. package/corpus/templates/design/changelog/2026-07-10-interactive-designs-no-longer-appear-blank-in-the-canvas-whe.md +6 -0
  843. package/corpus/templates/design/changelog/2026-07-10-layer-drops-now-land-in-the-intended-grid-row-stay-visually-.md +6 -0
  844. package/corpus/templates/design/changelog/2026-07-10-local-code-workspaces-now-keep-unsaved-edits-across-panel-sw.md +6 -0
  845. package/corpus/templates/design/changelog/2026-07-10-local-visual-editing-now-keeps-authenticated-sessions-shared.md +6 -0
  846. package/corpus/templates/design/changelog/2026-07-10-long-overview-editing-sessions-lots-of-pan-zoom-screen-switc.md +6 -0
  847. package/corpus/templates/design/changelog/2026-07-10-long-running-agent-work-no-longer-shows-a-premature-stuck-wa.md +6 -0
  848. package/corpus/templates/design/changelog/2026-07-10-managed-figma-connections-are-recognized-automatically.md +6 -0
  849. package/corpus/templates/design/changelog/2026-07-10-new-designs-can-open-directly-in-the-editor-without-a-pr.md +6 -0
  850. package/corpus/templates/design/changelog/2026-07-10-new-screens-are-selected-and-revealed-immediately.md +6 -0
  851. package/corpus/templates/design/changelog/2026-07-10-new-text-layers-undo-as-one-safe-creation.md +6 -0
  852. package/corpus/templates/design/changelog/2026-07-10-preview-and-apply-inferred-auto-layout-without-changing-yo.md +5 -0
  853. package/corpus/templates/design/changelog/2026-07-10-print-pdf-exports-and-paper-size-presets-letter-a4-now-match.md +6 -0
  854. package/corpus/templates/design/changelog/2026-07-10-rapid-breakpoint-and-edit-scope-changes-no-longer-jump-back-.md +6 -0
  855. package/corpus/templates/design/changelog/2026-07-10-responsive-breakpoint-previews-stay-visible-while-panning-ac.md +6 -0
  856. package/corpus/templates/design/changelog/2026-07-10-responsive-frame-editing.md +6 -0
  857. package/corpus/templates/design/changelog/2026-07-10-reusable-design-templates.md +6 -0
  858. package/corpus/templates/design/changelog/2026-07-10-rich-design-clipboard-markers-are-now-accepted-only-from-the.md +6 -0
  859. package/corpus/templates/design/changelog/2026-07-10-screen-overview-frames-now-use-a-clearer-interact-action-wit.md +6 -0
  860. package/corpus/templates/design/changelog/2026-07-10-start-designs-from-source-linked-material-3-carbon-or-primer.md +6 -0
  861. package/corpus/templates/design/changelog/2026-07-10-tweaks-guidance.md +6 -0
  862. package/corpus/templates/design/changelog/2026-07-10-uploaded-fig-files-can-now-become-editable-design-screens-wi.md +6 -0
  863. package/corpus/templates/design/e2e/helpers.ts +18 -7
  864. package/corpus/templates/design/package.json +2 -0
  865. package/corpus/templates/design/scripts/qa-figma-stress-import.ts +96 -0
  866. package/corpus/templates/design/server/db/index.ts +10 -0
  867. package/corpus/templates/design/server/db/schema.ts +44 -0
  868. package/corpus/templates/design/server/handlers/import-design-file.ts +114 -80
  869. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +19 -6
  870. package/corpus/templates/design/server/lib/design-export.ts +240 -3
  871. package/corpus/templates/design/server/lib/design-template-data.ts +89 -0
  872. package/corpus/templates/design/server/lib/design-to-figma-svg.ts +250 -26
  873. package/corpus/templates/design/server/lib/fig-file-decoder.ts +839 -0
  874. package/corpus/templates/design/server/lib/fig-file-import.ts +287 -0
  875. package/corpus/templates/design/server/lib/fig-file-limits.ts +3 -0
  876. package/corpus/templates/design/server/lib/fig-file-to-html.ts +2568 -0
  877. package/corpus/templates/design/server/lib/figma-design-context.ts +359 -0
  878. package/corpus/templates/design/server/lib/figma-node-import.ts +478 -22
  879. package/corpus/templates/design/server/lib/figma-node-to-html.ts +554 -29
  880. package/corpus/templates/design/server/lib/local-figma-qa-upload.ts +112 -0
  881. package/corpus/templates/design/server/lib/verify-write-grant.ts +16 -2
  882. package/corpus/templates/design/server/lib/visible-clipboard-html.ts +13 -3
  883. package/corpus/templates/design/server/plugins/agent-chat.ts +7 -0
  884. package/corpus/templates/design/server/plugins/db.ts +42 -0
  885. package/corpus/templates/design/server/plugins/local-figma-qa-upload.ts +7 -0
  886. package/corpus/templates/design/server/register-secrets.ts +8 -8
  887. package/corpus/templates/design/server/routes/api/qa-figma-import-assets/[assetId].get.ts +46 -0
  888. package/corpus/templates/design/server/source-workspace.ts +131 -13
  889. package/corpus/templates/design/shared/code-layer.ts +105 -28
  890. package/corpus/templates/design/shared/design-system-templates.ts +301 -0
  891. package/corpus/templates/design/shared/design-template-presets.ts +195 -0
  892. package/corpus/templates/design/shared/figma-url.ts +8 -0
  893. package/corpus/templates/design/shared/html-integrity.ts +401 -0
  894. package/corpus/templates/design/shared/interaction-states.ts +318 -23
  895. package/corpus/templates/design/shared/locked-layers.ts +151 -0
  896. package/corpus/templates/dispatch/.agents/skills/capture-learnings/SKILL.md +22 -9
  897. package/corpus/templates/dispatch/AGENTS.md +10 -2
  898. package/corpus/templates/dispatch/actions/view-screen.ts +11 -0
  899. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +13 -0
  900. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +51 -0
  901. package/corpus/templates/dispatch/app/i18n-data.ts +572 -1
  902. package/corpus/templates/dispatch/app/routes/operations.tsx +1 -0
  903. package/corpus/templates/dispatch/changelog/2026-07-10-connect-slack-workspaces-with-oauth-and-manage-channel-ident.md +6 -0
  904. package/corpus/templates/dispatch/changelog/2026-07-10-dispatch-now-has-a-cleaner-chat-history-and-quieter-sidebar-.md +6 -0
  905. package/corpus/templates/dispatch/changelog/2026-07-10-microsoft-teams-bots-and-discord-slash-commands-can-now-conn.md +6 -0
  906. package/corpus/templates/dispatch/changelog/2026-07-10-operations-console-brings-agent-monitoring-and-database-inspection-tog.md +6 -0
  907. package/corpus/templates/dispatch/changelog/2026-07-10-slack-and-telegram-now-route-uptime-monitor-requests-to-anal.md +6 -0
  908. package/corpus/templates/forms/.agents/skills/capture-learnings/SKILL.md +22 -9
  909. package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +7 -0
  910. package/corpus/templates/forms/AGENTS.md +4 -0
  911. package/corpus/templates/forms/actions/create-form.ts +44 -7
  912. package/corpus/templates/forms/actions/lib/assert-publishable-form.ts +38 -0
  913. package/corpus/templates/forms/actions/patch-form-fields.ts +4 -0
  914. package/corpus/templates/forms/actions/update-form.ts +2 -36
  915. package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
  916. package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
  917. package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
  918. package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
  919. package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
  920. package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
  921. package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
  922. package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
  923. package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
  924. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  925. package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
  926. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +17 -0
  927. package/corpus/templates/forms/changelog/2026-07-10-agent-created-published-forms-now-return-the-anonymous-publi.md +6 -0
  928. package/corpus/templates/forms/changelog/2026-07-10-published-forms-can-no-longer-be-edited-into-an-unusable-emp.md +6 -0
  929. package/corpus/templates/forms/server/handlers/submissions.ts +4 -3
  930. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  931. package/corpus/templates/forms/shared/types.ts +5 -0
  932. package/corpus/templates/mail/.agents/skills/capture-learnings/SKILL.md +22 -9
  933. package/corpus/templates/mail/actions/get-integration-statuses.ts +36 -0
  934. package/corpus/templates/mail/app/components/email/EmailThread.tsx +3 -2
  935. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +3 -3
  936. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
  937. package/corpus/templates/mail/app/hooks/use-apollo.ts +5 -71
  938. package/corpus/templates/mail/app/hooks/use-draft-queue.ts +1 -1
  939. package/corpus/templates/mail/app/hooks/use-integrations.ts +51 -48
  940. package/corpus/templates/mail/app/lib/integration-status.ts +31 -0
  941. package/corpus/templates/mail/app/lib/sync-invalidation.ts +5 -0
  942. package/corpus/templates/mail/app/pages/SettingsPage.tsx +3 -0
  943. package/corpus/templates/mail/app/root.tsx +22 -12
  944. package/corpus/templates/mail/changelog/2026-07-10-email-content-backgrounds-now-blend-cleanly-with-dark-mode.md +6 -0
  945. package/corpus/templates/mail/changelog/2026-07-10-mail-navigation-now-uses-a-clean-borderless-drawer.md +6 -0
  946. package/corpus/templates/mail/changelog/2026-07-10-mail-settings-now-group-drafting-automation-and-connected-se.md +6 -0
  947. package/corpus/templates/mail/changelog/2026-07-10-organization-settings-now-opens-directly-from-the-workspace-.md +6 -0
  948. package/corpus/templates/plan/.agents/skills/capture-learnings/SKILL.md +22 -9
  949. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +4 -1
  950. package/corpus/templates/plan/changelog/2026-07-10-local-plans-now-keep-valid-content-visible-when-one-generate.md +6 -0
  951. package/corpus/templates/plan/server/lib/local-plan-files.ts +4 -1
  952. package/corpus/templates/slides/.agents/skills/capture-learnings/SKILL.md +22 -9
  953. package/dist/a2a/artifact-response.d.ts.map +1 -1
  954. package/dist/a2a/artifact-response.js +88 -2
  955. package/dist/a2a/artifact-response.js.map +1 -1
  956. package/dist/a2a/client.d.ts +9 -0
  957. package/dist/a2a/client.d.ts.map +1 -1
  958. package/dist/a2a/client.js +1 -0
  959. package/dist/a2a/client.js.map +1 -1
  960. package/dist/a2a/handlers.d.ts.map +1 -1
  961. package/dist/a2a/handlers.js +24 -69
  962. package/dist/a2a/handlers.js.map +1 -1
  963. package/dist/a2a/types.d.ts +2 -0
  964. package/dist/a2a/types.d.ts.map +1 -1
  965. package/dist/a2a/types.js.map +1 -1
  966. package/dist/agent/context-xray/tokenize.d.ts.map +1 -1
  967. package/dist/agent/context-xray/tokenize.js +6 -1
  968. package/dist/agent/context-xray/tokenize.js.map +1 -1
  969. package/dist/agent/durable-background.d.ts +11 -0
  970. package/dist/agent/durable-background.d.ts.map +1 -1
  971. package/dist/agent/durable-background.js +17 -0
  972. package/dist/agent/durable-background.js.map +1 -1
  973. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  974. package/dist/agent/engine/ai-sdk-engine.js +8 -3
  975. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  976. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  977. package/dist/agent/engine/anthropic-engine.js +2 -4
  978. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  979. package/dist/agent/engine/builder-engine.d.ts +1 -1
  980. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  981. package/dist/agent/engine/builder-engine.js +2 -3
  982. package/dist/agent/engine/builder-engine.js.map +1 -1
  983. package/dist/agent/engine/index.d.ts +1 -1
  984. package/dist/agent/engine/index.d.ts.map +1 -1
  985. package/dist/agent/engine/index.js +1 -1
  986. package/dist/agent/engine/index.js.map +1 -1
  987. package/dist/agent/engine/registry.d.ts +13 -0
  988. package/dist/agent/engine/registry.d.ts.map +1 -1
  989. package/dist/agent/engine/registry.js +33 -0
  990. package/dist/agent/engine/registry.js.map +1 -1
  991. package/dist/agent/harness/ai-sdk-adapter.d.ts.map +1 -1
  992. package/dist/agent/harness/ai-sdk-adapter.js +3 -1
  993. package/dist/agent/harness/ai-sdk-adapter.js.map +1 -1
  994. package/dist/agent/harness/background.d.ts +9 -9
  995. package/dist/agent/harness/background.d.ts.map +1 -1
  996. package/dist/agent/harness/background.js +77 -19
  997. package/dist/agent/harness/background.js.map +1 -1
  998. package/dist/agent/harness/index.d.ts +1 -0
  999. package/dist/agent/harness/index.d.ts.map +1 -1
  1000. package/dist/agent/harness/index.js +1 -0
  1001. package/dist/agent/harness/index.js.map +1 -1
  1002. package/dist/agent/harness/lifecycle.d.ts +45 -0
  1003. package/dist/agent/harness/lifecycle.d.ts.map +1 -0
  1004. package/dist/agent/harness/lifecycle.js +318 -0
  1005. package/dist/agent/harness/lifecycle.js.map +1 -0
  1006. package/dist/agent/harness/runner.d.ts.map +1 -1
  1007. package/dist/agent/harness/runner.js +29 -1
  1008. package/dist/agent/harness/runner.js.map +1 -1
  1009. package/dist/agent/harness/store.d.ts +2 -0
  1010. package/dist/agent/harness/store.d.ts.map +1 -1
  1011. package/dist/agent/harness/store.js +17 -3
  1012. package/dist/agent/harness/store.js.map +1 -1
  1013. package/dist/agent/model-config.d.ts +2 -2
  1014. package/dist/agent/model-config.d.ts.map +1 -1
  1015. package/dist/agent/model-config.js +4 -1
  1016. package/dist/agent/model-config.js.map +1 -1
  1017. package/dist/agent/production-agent.d.ts +40 -2
  1018. package/dist/agent/production-agent.d.ts.map +1 -1
  1019. package/dist/agent/production-agent.js +150 -9
  1020. package/dist/agent/production-agent.js.map +1 -1
  1021. package/dist/agent/run-manager.d.ts +44 -2
  1022. package/dist/agent/run-manager.d.ts.map +1 -1
  1023. package/dist/agent/run-manager.js +90 -9
  1024. package/dist/agent/run-manager.js.map +1 -1
  1025. package/dist/agent/run-store.d.ts +109 -0
  1026. package/dist/agent/run-store.d.ts.map +1 -1
  1027. package/dist/agent/run-store.js +206 -15
  1028. package/dist/agent/run-store.js.map +1 -1
  1029. package/dist/agent/types.d.ts +22 -0
  1030. package/dist/agent/types.d.ts.map +1 -1
  1031. package/dist/agent/types.js.map +1 -1
  1032. package/dist/application-state/index.d.ts +1 -1
  1033. package/dist/application-state/index.d.ts.map +1 -1
  1034. package/dist/application-state/index.js +1 -1
  1035. package/dist/application-state/index.js.map +1 -1
  1036. package/dist/application-state/store.d.ts +6 -0
  1037. package/dist/application-state/store.d.ts.map +1 -1
  1038. package/dist/application-state/store.js +31 -0
  1039. package/dist/application-state/store.js.map +1 -1
  1040. package/dist/audit/record.d.ts.map +1 -1
  1041. package/dist/audit/record.js +29 -0
  1042. package/dist/audit/record.js.map +1 -1
  1043. package/dist/audit/store.d.ts.map +1 -1
  1044. package/dist/audit/store.js +62 -3
  1045. package/dist/audit/store.js.map +1 -1
  1046. package/dist/audit/types.d.ts +13 -0
  1047. package/dist/audit/types.d.ts.map +1 -1
  1048. package/dist/audit/types.js.map +1 -1
  1049. package/dist/automation/index.d.ts +193 -0
  1050. package/dist/automation/index.d.ts.map +1 -0
  1051. package/dist/automation/index.js +464 -0
  1052. package/dist/automation/index.js.map +1 -0
  1053. package/dist/cli/code-agent-connector.d.ts +9 -0
  1054. package/dist/cli/code-agent-connector.d.ts.map +1 -1
  1055. package/dist/cli/code-agent-connector.js +212 -10
  1056. package/dist/cli/code-agent-connector.js.map +1 -1
  1057. package/dist/cli/code-agent-executor.d.ts +2 -0
  1058. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  1059. package/dist/cli/code-agent-executor.js +8 -1
  1060. package/dist/cli/code-agent-executor.js.map +1 -1
  1061. package/dist/cli/create.d.ts.map +1 -1
  1062. package/dist/cli/create.js +10 -3
  1063. package/dist/cli/create.js.map +1 -1
  1064. package/dist/cli/design-connect.d.ts.map +1 -1
  1065. package/dist/cli/design-connect.js +492 -35
  1066. package/dist/cli/design-connect.js.map +1 -1
  1067. package/dist/client/AgentPanel.d.ts +7 -1
  1068. package/dist/client/AgentPanel.d.ts.map +1 -1
  1069. package/dist/client/AgentPanel.js +38 -13
  1070. package/dist/client/AgentPanel.js.map +1 -1
  1071. package/dist/client/AssistantChat.d.ts +21 -0
  1072. package/dist/client/AssistantChat.d.ts.map +1 -1
  1073. package/dist/client/AssistantChat.js +147 -49
  1074. package/dist/client/AssistantChat.js.map +1 -1
  1075. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  1076. package/dist/client/MultiTabAssistantChat.js +17 -38
  1077. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  1078. package/dist/client/RunStuckBanner.d.ts +14 -1
  1079. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  1080. package/dist/client/RunStuckBanner.js +35 -7
  1081. package/dist/client/RunStuckBanner.js.map +1 -1
  1082. package/dist/client/agent-chat-adapter.d.ts +4 -1
  1083. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  1084. package/dist/client/agent-chat-adapter.js +49 -4
  1085. package/dist/client/agent-chat-adapter.js.map +1 -1
  1086. package/dist/client/appearance.d.ts +4 -2
  1087. package/dist/client/appearance.d.ts.map +1 -1
  1088. package/dist/client/appearance.js +8 -5
  1089. package/dist/client/appearance.js.map +1 -1
  1090. package/dist/client/automation.d.ts +14 -0
  1091. package/dist/client/automation.d.ts.map +1 -0
  1092. package/dist/client/automation.js +9 -0
  1093. package/dist/client/automation.js.map +1 -0
  1094. package/dist/client/chat/connectors.d.ts.map +1 -1
  1095. package/dist/client/chat/connectors.js +206 -28
  1096. package/dist/client/chat/connectors.js.map +1 -1
  1097. package/dist/client/chat/message-components.d.ts.map +1 -1
  1098. package/dist/client/chat/message-components.js +17 -1
  1099. package/dist/client/chat/message-components.js.map +1 -1
  1100. package/dist/client/chat/run-recovery.d.ts +4 -0
  1101. package/dist/client/chat/run-recovery.d.ts.map +1 -1
  1102. package/dist/client/chat/run-recovery.js +12 -10
  1103. package/dist/client/chat/run-recovery.js.map +1 -1
  1104. package/dist/client/chat/runtime.d.ts.map +1 -1
  1105. package/dist/client/chat/runtime.js +84 -24
  1106. package/dist/client/chat/runtime.js.map +1 -1
  1107. package/dist/client/chat/tool-call-display.d.ts +8 -1
  1108. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  1109. package/dist/client/chat/tool-call-display.js +21 -3
  1110. package/dist/client/chat/tool-call-display.js.map +1 -1
  1111. package/dist/client/composer/RealtimeVoiceMode.d.ts +54 -0
  1112. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -0
  1113. package/dist/client/composer/RealtimeVoiceMode.js +63 -0
  1114. package/dist/client/composer/RealtimeVoiceMode.js.map +1 -0
  1115. package/dist/client/composer/TiptapComposer.d.ts +1 -0
  1116. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  1117. package/dist/client/composer/TiptapComposer.js +25 -20
  1118. package/dist/client/composer/TiptapComposer.js.map +1 -1
  1119. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  1120. package/dist/client/composer/VoiceButton.js +9 -0
  1121. package/dist/client/composer/VoiceButton.js.map +1 -1
  1122. package/dist/client/composer/index.d.ts +2 -0
  1123. package/dist/client/composer/index.d.ts.map +1 -1
  1124. package/dist/client/composer/index.js +2 -0
  1125. package/dist/client/composer/index.js.map +1 -1
  1126. package/dist/client/composer/useRealtimeVoiceMode.d.ts +56 -0
  1127. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -0
  1128. package/dist/client/composer/useRealtimeVoiceMode.js +492 -0
  1129. package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -0
  1130. package/dist/client/guided-questions.d.ts.map +1 -1
  1131. package/dist/client/guided-questions.js +7 -2
  1132. package/dist/client/guided-questions.js.map +1 -1
  1133. package/dist/client/index.d.ts +3 -1
  1134. package/dist/client/index.d.ts.map +1 -1
  1135. package/dist/client/index.js +3 -1
  1136. package/dist/client/index.js.map +1 -1
  1137. package/dist/client/integrations/api.d.ts +115 -0
  1138. package/dist/client/integrations/api.d.ts.map +1 -0
  1139. package/dist/client/integrations/api.js +123 -0
  1140. package/dist/client/integrations/api.js.map +1 -0
  1141. package/dist/client/integrations/index.d.ts +1 -0
  1142. package/dist/client/integrations/index.d.ts.map +1 -1
  1143. package/dist/client/integrations/index.js +1 -0
  1144. package/dist/client/integrations/index.js.map +1 -1
  1145. package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
  1146. package/dist/client/settings/DemoModeSection.js +4 -3
  1147. package/dist/client/settings/DemoModeSection.js.map +1 -1
  1148. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  1149. package/dist/client/settings/SettingsPanel.js +4 -0
  1150. package/dist/client/settings/SettingsPanel.js.map +1 -1
  1151. package/dist/client/settings/SettingsTabsPage.d.ts +10 -3
  1152. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  1153. package/dist/client/settings/SettingsTabsPage.js +49 -11
  1154. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  1155. package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
  1156. package/dist/client/transcription/use-live-transcription.js +59 -5
  1157. package/dist/client/transcription/use-live-transcription.js.map +1 -1
  1158. package/dist/client/use-chat-models.d.ts.map +1 -1
  1159. package/dist/client/use-chat-models.js +6 -14
  1160. package/dist/client/use-chat-models.js.map +1 -1
  1161. package/dist/client/use-db-sync.d.ts.map +1 -1
  1162. package/dist/client/use-db-sync.js +87 -7
  1163. package/dist/client/use-db-sync.js.map +1 -1
  1164. package/dist/client/use-run-stuck-detection.d.ts +16 -1
  1165. package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
  1166. package/dist/client/use-run-stuck-detection.js +23 -4
  1167. package/dist/client/use-run-stuck-detection.js.map +1 -1
  1168. package/dist/code-agents/background-controller.d.ts +1 -1
  1169. package/dist/code-agents/background-controller.d.ts.map +1 -1
  1170. package/dist/code-agents/background-controller.js +17 -1
  1171. package/dist/code-agents/background-controller.js.map +1 -1
  1172. package/dist/collab/routes.d.ts +1 -1
  1173. package/dist/collab/ydoc-manager.d.ts +9 -1
  1174. package/dist/collab/ydoc-manager.d.ts.map +1 -1
  1175. package/dist/collab/ydoc-manager.js +30 -6
  1176. package/dist/collab/ydoc-manager.js.map +1 -1
  1177. package/dist/db/migrations.d.ts.map +1 -1
  1178. package/dist/db/migrations.js +4 -2
  1179. package/dist/db/migrations.js.map +1 -1
  1180. package/dist/demo/fetch-interceptor.d.ts +5 -1
  1181. package/dist/demo/fetch-interceptor.d.ts.map +1 -1
  1182. package/dist/demo/fetch-interceptor.js +16 -12
  1183. package/dist/demo/fetch-interceptor.js.map +1 -1
  1184. package/dist/deploy/build.d.ts.map +1 -1
  1185. package/dist/deploy/build.js +49 -4
  1186. package/dist/deploy/build.js.map +1 -1
  1187. package/dist/deploy/workspace-deploy.d.ts.map +1 -1
  1188. package/dist/deploy/workspace-deploy.js +31 -2
  1189. package/dist/deploy/workspace-deploy.js.map +1 -1
  1190. package/dist/file-upload/types.d.ts +2 -0
  1191. package/dist/file-upload/types.d.ts.map +1 -1
  1192. package/dist/file-upload/types.js.map +1 -1
  1193. package/dist/index.d.ts +2 -0
  1194. package/dist/index.d.ts.map +1 -1
  1195. package/dist/index.js +2 -0
  1196. package/dist/index.js.map +1 -1
  1197. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  1198. package/dist/integrations/a2a-continuations-store.js +6 -4
  1199. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  1200. package/dist/integrations/adapters/discord.d.ts +3 -0
  1201. package/dist/integrations/adapters/discord.d.ts.map +1 -0
  1202. package/dist/integrations/adapters/discord.js +261 -0
  1203. package/dist/integrations/adapters/discord.js.map +1 -0
  1204. package/dist/integrations/adapters/index.d.ts +4 -0
  1205. package/dist/integrations/adapters/index.d.ts.map +1 -0
  1206. package/dist/integrations/adapters/index.js +26 -0
  1207. package/dist/integrations/adapters/index.js.map +1 -0
  1208. package/dist/integrations/adapters/microsoft-teams.d.ts +5 -0
  1209. package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -0
  1210. package/dist/integrations/adapters/microsoft-teams.js +295 -0
  1211. package/dist/integrations/adapters/microsoft-teams.js.map +1 -0
  1212. package/dist/integrations/adapters/slack.d.ts +10 -2
  1213. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  1214. package/dist/integrations/adapters/slack.js +772 -27
  1215. package/dist/integrations/adapters/slack.js.map +1 -1
  1216. package/dist/integrations/adapters/telegram.d.ts +0 -2
  1217. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  1218. package/dist/integrations/adapters/telegram.js +49 -15
  1219. package/dist/integrations/adapters/telegram.js.map +1 -1
  1220. package/dist/integrations/adapters/whatsapp.d.ts +0 -2
  1221. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  1222. package/dist/integrations/adapters/whatsapp.js +40 -17
  1223. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  1224. package/dist/integrations/awaiting-input-store.d.ts +27 -0
  1225. package/dist/integrations/awaiting-input-store.d.ts.map +1 -0
  1226. package/dist/integrations/awaiting-input-store.js +112 -0
  1227. package/dist/integrations/awaiting-input-store.js.map +1 -0
  1228. package/dist/integrations/catalog.d.ts +75 -0
  1229. package/dist/integrations/catalog.d.ts.map +1 -0
  1230. package/dist/integrations/catalog.js +451 -0
  1231. package/dist/integrations/catalog.js.map +1 -0
  1232. package/dist/integrations/computer-supervision-store.d.ts +65 -0
  1233. package/dist/integrations/computer-supervision-store.d.ts.map +1 -0
  1234. package/dist/integrations/computer-supervision-store.js +296 -0
  1235. package/dist/integrations/computer-supervision-store.js.map +1 -0
  1236. package/dist/integrations/computer-supervision.d.ts +11 -0
  1237. package/dist/integrations/computer-supervision.d.ts.map +1 -0
  1238. package/dist/integrations/computer-supervision.js +160 -0
  1239. package/dist/integrations/computer-supervision.js.map +1 -0
  1240. package/dist/integrations/controls-store.d.ts +44 -0
  1241. package/dist/integrations/controls-store.d.ts.map +1 -0
  1242. package/dist/integrations/controls-store.js +129 -0
  1243. package/dist/integrations/controls-store.js.map +1 -0
  1244. package/dist/integrations/index.d.ts +19 -4
  1245. package/dist/integrations/index.d.ts.map +1 -1
  1246. package/dist/integrations/index.js +14 -2
  1247. package/dist/integrations/index.js.map +1 -1
  1248. package/dist/integrations/installations-store.d.ts +112 -0
  1249. package/dist/integrations/installations-store.d.ts.map +1 -0
  1250. package/dist/integrations/installations-store.js +493 -0
  1251. package/dist/integrations/installations-store.js.map +1 -0
  1252. package/dist/integrations/integration-memory.d.ts +24 -0
  1253. package/dist/integrations/integration-memory.d.ts.map +1 -0
  1254. package/dist/integrations/integration-memory.js +136 -0
  1255. package/dist/integrations/integration-memory.js.map +1 -0
  1256. package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
  1257. package/dist/integrations/pending-tasks-retry-job.js +6 -5
  1258. package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
  1259. package/dist/integrations/pending-tasks-store.d.ts +17 -0
  1260. package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
  1261. package/dist/integrations/pending-tasks-store.js +71 -5
  1262. package/dist/integrations/pending-tasks-store.js.map +1 -1
  1263. package/dist/integrations/plugin.d.ts.map +1 -1
  1264. package/dist/integrations/plugin.js +725 -38
  1265. package/dist/integrations/plugin.js.map +1 -1
  1266. package/dist/integrations/remote-commands-store.d.ts +15 -1
  1267. package/dist/integrations/remote-commands-store.d.ts.map +1 -1
  1268. package/dist/integrations/remote-commands-store.js +273 -3
  1269. package/dist/integrations/remote-commands-store.js.map +1 -1
  1270. package/dist/integrations/remote-devices-store.d.ts +4 -3
  1271. package/dist/integrations/remote-devices-store.d.ts.map +1 -1
  1272. package/dist/integrations/remote-devices-store.js +49 -2
  1273. package/dist/integrations/remote-devices-store.js.map +1 -1
  1274. package/dist/integrations/remote-json-safety.d.ts +6 -0
  1275. package/dist/integrations/remote-json-safety.d.ts.map +1 -0
  1276. package/dist/integrations/remote-json-safety.js +114 -0
  1277. package/dist/integrations/remote-json-safety.js.map +1 -0
  1278. package/dist/integrations/remote-run-events-store.d.ts +11 -1
  1279. package/dist/integrations/remote-run-events-store.d.ts.map +1 -1
  1280. package/dist/integrations/remote-run-events-store.js +85 -17
  1281. package/dist/integrations/remote-run-events-store.js.map +1 -1
  1282. package/dist/integrations/remote-types.d.ts +54 -3
  1283. package/dist/integrations/remote-types.d.ts.map +1 -1
  1284. package/dist/integrations/remote-types.js.map +1 -1
  1285. package/dist/integrations/scope-store.d.ts +65 -0
  1286. package/dist/integrations/scope-store.d.ts.map +1 -0
  1287. package/dist/integrations/scope-store.js +361 -0
  1288. package/dist/integrations/scope-store.js.map +1 -0
  1289. package/dist/integrations/slack-manifest.d.ts +66 -0
  1290. package/dist/integrations/slack-manifest.d.ts.map +1 -0
  1291. package/dist/integrations/slack-manifest.js +70 -0
  1292. package/dist/integrations/slack-manifest.js.map +1 -0
  1293. package/dist/integrations/slack-oauth.d.ts +99 -0
  1294. package/dist/integrations/slack-oauth.d.ts.map +1 -0
  1295. package/dist/integrations/slack-oauth.js +226 -0
  1296. package/dist/integrations/slack-oauth.js.map +1 -0
  1297. package/dist/integrations/types.d.ts +144 -0
  1298. package/dist/integrations/types.d.ts.map +1 -1
  1299. package/dist/integrations/types.js +16 -1
  1300. package/dist/integrations/types.js.map +1 -1
  1301. package/dist/integrations/usage-budget-store.d.ts +84 -0
  1302. package/dist/integrations/usage-budget-store.d.ts.map +1 -0
  1303. package/dist/integrations/usage-budget-store.js +650 -0
  1304. package/dist/integrations/usage-budget-store.js.map +1 -0
  1305. package/dist/integrations/webhook-handler.d.ts +4 -0
  1306. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  1307. package/dist/integrations/webhook-handler.js +548 -51
  1308. package/dist/integrations/webhook-handler.js.map +1 -1
  1309. package/dist/jobs/scheduler.d.ts +6 -0
  1310. package/dist/jobs/scheduler.d.ts.map +1 -1
  1311. package/dist/jobs/scheduler.js +83 -4
  1312. package/dist/jobs/scheduler.js.map +1 -1
  1313. package/dist/jobs/tools.d.ts.map +1 -1
  1314. package/dist/jobs/tools.js +43 -11
  1315. package/dist/jobs/tools.js.map +1 -1
  1316. package/dist/localization/default-messages.d.ts +26 -0
  1317. package/dist/localization/default-messages.d.ts.map +1 -1
  1318. package/dist/localization/default-messages.js +26 -0
  1319. package/dist/localization/default-messages.js.map +1 -1
  1320. package/dist/mcp-client/config.d.ts.map +1 -1
  1321. package/dist/mcp-client/config.js +44 -3
  1322. package/dist/mcp-client/config.js.map +1 -1
  1323. package/dist/mcp-client/index.d.ts +6 -1
  1324. package/dist/mcp-client/index.d.ts.map +1 -1
  1325. package/dist/mcp-client/index.js +11 -3
  1326. package/dist/mcp-client/index.js.map +1 -1
  1327. package/dist/mcp-client/tool-policy.d.ts +24 -0
  1328. package/dist/mcp-client/tool-policy.d.ts.map +1 -0
  1329. package/dist/mcp-client/tool-policy.js +139 -0
  1330. package/dist/mcp-client/tool-policy.js.map +1 -0
  1331. package/dist/observability/routes.d.ts +1 -1
  1332. package/dist/progress/routes.d.ts +1 -1
  1333. package/dist/provider-api/index.d.ts +4 -4
  1334. package/dist/provider-api/index.d.ts.map +1 -1
  1335. package/dist/provider-api/index.js +72 -1
  1336. package/dist/provider-api/index.js.map +1 -1
  1337. package/dist/resources/handlers.d.ts.map +1 -1
  1338. package/dist/resources/handlers.js +57 -15
  1339. package/dist/resources/handlers.js.map +1 -1
  1340. package/dist/resources/script-helpers.d.ts.map +1 -1
  1341. package/dist/resources/script-helpers.js +34 -8
  1342. package/dist/resources/script-helpers.js.map +1 -1
  1343. package/dist/resources/store.d.ts +10 -0
  1344. package/dist/resources/store.d.ts.map +1 -1
  1345. package/dist/resources/store.js +54 -47
  1346. package/dist/resources/store.js.map +1 -1
  1347. package/dist/scripts/call-agent.d.ts.map +1 -1
  1348. package/dist/scripts/call-agent.js +106 -1
  1349. package/dist/scripts/call-agent.js.map +1 -1
  1350. package/dist/secrets/register-framework-secrets.d.ts +3 -4
  1351. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  1352. package/dist/secrets/register-framework-secrets.js +25 -4
  1353. package/dist/secrets/register-framework-secrets.js.map +1 -1
  1354. package/dist/secrets/routes.d.ts +9 -9
  1355. package/dist/server/agent-chat-plugin.d.ts +15 -4
  1356. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  1357. package/dist/server/agent-chat-plugin.js +300 -118
  1358. package/dist/server/agent-chat-plugin.js.map +1 -1
  1359. package/dist/server/auth.d.ts.map +1 -1
  1360. package/dist/server/auth.js +10 -14
  1361. package/dist/server/auth.js.map +1 -1
  1362. package/dist/server/builder-design-systems.d.ts +3 -1
  1363. package/dist/server/builder-design-systems.d.ts.map +1 -1
  1364. package/dist/server/builder-design-systems.js +9 -2
  1365. package/dist/server/builder-design-systems.js.map +1 -1
  1366. package/dist/server/edge.d.ts +1 -1
  1367. package/dist/server/edge.d.ts.map +1 -1
  1368. package/dist/server/edge.js +1 -1
  1369. package/dist/server/edge.js.map +1 -1
  1370. package/dist/server/index.d.ts +4 -2
  1371. package/dist/server/index.d.ts.map +1 -1
  1372. package/dist/server/index.js +4 -2
  1373. package/dist/server/index.js.map +1 -1
  1374. package/dist/server/realtime-voice.d.ts +53 -0
  1375. package/dist/server/realtime-voice.d.ts.map +1 -0
  1376. package/dist/server/realtime-voice.js +404 -0
  1377. package/dist/server/realtime-voice.js.map +1 -0
  1378. package/dist/server/request-context.d.ts +18 -0
  1379. package/dist/server/request-context.d.ts.map +1 -1
  1380. package/dist/server/request-context.js.map +1 -1
  1381. package/dist/server/social-og-image.d.ts.map +1 -1
  1382. package/dist/server/social-og-image.js +3 -2
  1383. package/dist/server/social-og-image.js.map +1 -1
  1384. package/dist/server/transcribe-voice.d.ts +1 -1
  1385. package/dist/shared/reasoning-effort.d.ts +20 -0
  1386. package/dist/shared/reasoning-effort.d.ts.map +1 -1
  1387. package/dist/shared/reasoning-effort.js +52 -18
  1388. package/dist/shared/reasoning-effort.js.map +1 -1
  1389. package/dist/styles/agent-conversation.css +17 -0
  1390. package/dist/styles/agent-native.css +62 -44
  1391. package/dist/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
  1392. package/dist/templates/default/AGENTS.md +7 -3
  1393. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
  1394. package/dist/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
  1395. package/dist/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
  1396. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
  1397. package/dist/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
  1398. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -5
  1399. package/dist/templates/workspace-core/AGENTS.md +3 -2
  1400. package/dist/usage/store.d.ts +7 -0
  1401. package/dist/usage/store.d.ts.map +1 -1
  1402. package/dist/usage/store.js +24 -3
  1403. package/dist/usage/store.js.map +1 -1
  1404. package/docs/content/a2a-protocol.mdx +21 -5
  1405. package/docs/content/actions.mdx +9 -23
  1406. package/docs/content/agent-mentions.mdx +31 -29
  1407. package/docs/content/agent-native-toolkit.mdx +15 -6
  1408. package/docs/content/agent-surfaces.mdx +9 -13
  1409. package/docs/content/agent-teams.mdx +1 -0
  1410. package/docs/content/authentication.mdx +10 -3
  1411. package/docs/content/automation-connectors.mdx +123 -0
  1412. package/docs/content/automations.mdx +17 -3
  1413. package/docs/content/blueprint-installer.mdx +11 -4
  1414. package/docs/content/cli-adapters.mdx +9 -6
  1415. package/docs/content/client.mdx +16 -0
  1416. package/docs/content/cloneable-saas.mdx +14 -11
  1417. package/docs/content/code-agents-ui.mdx +65 -0
  1418. package/docs/content/components.mdx +30 -14
  1419. package/docs/content/context-awareness.mdx +27 -15
  1420. package/docs/content/creating-templates.mdx +15 -9
  1421. package/docs/content/cross-app-sso.mdx +16 -6
  1422. package/docs/content/data-programs.mdx +1 -1
  1423. package/docs/content/database.mdx +17 -5
  1424. package/docs/content/deployment.mdx +19 -18
  1425. package/docs/content/dispatch.mdx +6 -2
  1426. package/docs/content/drop-in-agent.mdx +10 -4
  1427. package/docs/content/durable-background-runs.mdx +9 -5
  1428. package/docs/content/durable-resume.mdx +9 -4
  1429. package/docs/content/embedding-sdk.mdx +26 -8
  1430. package/docs/content/evals.mdx +3 -5
  1431. package/docs/content/extensions.mdx +23 -2
  1432. package/docs/content/external-agents.mdx +25 -34
  1433. package/docs/content/faq.mdx +8 -0
  1434. package/docs/content/file-uploads.mdx +12 -3
  1435. package/docs/content/frames.mdx +16 -0
  1436. package/docs/content/generative-ui.mdx +1 -1
  1437. package/docs/content/getting-started.mdx +34 -21
  1438. package/docs/content/harness-agents.mdx +8 -4
  1439. package/docs/content/human-approval.mdx +8 -3
  1440. package/docs/content/internationalization.mdx +9 -4
  1441. package/docs/content/key-concepts.mdx +13 -20
  1442. package/docs/content/local-file-mode.mdx +14 -8
  1443. package/docs/content/locales/ar-SA/actions.mdx +2 -2
  1444. package/docs/content/locales/ar-SA/agent-native-toolkit.mdx +2 -2
  1445. package/docs/content/locales/ar-SA/agent-surfaces.mdx +8 -10
  1446. package/docs/content/locales/ar-SA/agent-teams.mdx +1 -0
  1447. package/docs/content/locales/ar-SA/authentication.mdx +1 -1
  1448. package/docs/content/locales/ar-SA/components.mdx +11 -1
  1449. package/docs/content/locales/ar-SA/creating-templates.mdx +3 -7
  1450. package/docs/content/locales/ar-SA/cross-app-sso.mdx +16 -6
  1451. package/docs/content/locales/ar-SA/deployment.mdx +8 -0
  1452. package/docs/content/locales/ar-SA/extensions.mdx +8 -0
  1453. package/docs/content/locales/ar-SA/external-agents.mdx +2 -7
  1454. package/docs/content/locales/ar-SA/key-concepts.mdx +13 -20
  1455. package/docs/content/locales/ar-SA/messaging.mdx +84 -15
  1456. package/docs/content/locales/ar-SA/multi-tenancy.mdx +5 -5
  1457. package/docs/content/locales/ar-SA/notifications.mdx +18 -10
  1458. package/docs/content/locales/ar-SA/processors.mdx +11 -5
  1459. package/docs/content/locales/ar-SA/server.mdx +17 -10
  1460. package/docs/content/locales/ar-SA/sharing.mdx +10 -10
  1461. package/docs/content/locales/ar-SA/skills-guide.mdx +34 -17
  1462. package/docs/content/locales/ar-SA/template-assets.mdx +16 -13
  1463. package/docs/content/locales/ar-SA/template-brain.mdx +3 -1
  1464. package/docs/content/locales/ar-SA/template-clips.mdx +4 -3
  1465. package/docs/content/locales/ar-SA/template-design.mdx +4 -1
  1466. package/docs/content/locales/ar-SA/template-dispatch.mdx +5 -1
  1467. package/docs/content/locales/ar-SA/template-mail.mdx +8 -0
  1468. package/docs/content/locales/ar-SA/tracking.mdx +9 -6
  1469. package/docs/content/locales/ar-SA/using-your-agent.mdx +0 -7
  1470. package/docs/content/locales/ar-SA/voice-input.mdx +6 -0
  1471. package/docs/content/locales/ar-SA/workspace-connections.mdx +9 -2
  1472. package/docs/content/locales/ar-SA/workspace.mdx +19 -18
  1473. package/docs/content/locales/de-DE/actions.mdx +2 -2
  1474. package/docs/content/locales/de-DE/agent-native-toolkit.mdx +2 -2
  1475. package/docs/content/locales/de-DE/agent-surfaces.mdx +8 -10
  1476. package/docs/content/locales/de-DE/agent-teams.mdx +1 -0
  1477. package/docs/content/locales/de-DE/authentication.mdx +1 -1
  1478. package/docs/content/locales/de-DE/components.mdx +11 -1
  1479. package/docs/content/locales/de-DE/creating-templates.mdx +3 -7
  1480. package/docs/content/locales/de-DE/cross-app-sso.mdx +16 -6
  1481. package/docs/content/locales/de-DE/deployment.mdx +8 -0
  1482. package/docs/content/locales/de-DE/extensions.mdx +10 -0
  1483. package/docs/content/locales/de-DE/external-agents.mdx +3 -7
  1484. package/docs/content/locales/de-DE/key-concepts.mdx +13 -20
  1485. package/docs/content/locales/de-DE/messaging.mdx +92 -15
  1486. package/docs/content/locales/de-DE/multi-tenancy.mdx +5 -5
  1487. package/docs/content/locales/de-DE/notifications.mdx +18 -10
  1488. package/docs/content/locales/de-DE/processors.mdx +11 -5
  1489. package/docs/content/locales/de-DE/server.mdx +18 -10
  1490. package/docs/content/locales/de-DE/sharing.mdx +10 -10
  1491. package/docs/content/locales/de-DE/skills-guide.mdx +34 -17
  1492. package/docs/content/locales/de-DE/template-assets.mdx +16 -13
  1493. package/docs/content/locales/de-DE/template-brain.mdx +3 -1
  1494. package/docs/content/locales/de-DE/template-clips.mdx +4 -3
  1495. package/docs/content/locales/de-DE/template-design.mdx +4 -1
  1496. package/docs/content/locales/de-DE/template-dispatch.mdx +5 -1
  1497. package/docs/content/locales/de-DE/template-mail.mdx +8 -0
  1498. package/docs/content/locales/de-DE/tracking.mdx +9 -6
  1499. package/docs/content/locales/de-DE/using-your-agent.mdx +0 -7
  1500. package/docs/content/locales/de-DE/voice-input.mdx +6 -0
  1501. package/docs/content/locales/de-DE/workspace-connections.mdx +9 -2
  1502. package/docs/content/locales/de-DE/workspace.mdx +19 -18
  1503. package/docs/content/locales/es-ES/actions.mdx +2 -2
  1504. package/docs/content/locales/es-ES/agent-native-toolkit.mdx +2 -2
  1505. package/docs/content/locales/es-ES/agent-surfaces.mdx +8 -10
  1506. package/docs/content/locales/es-ES/agent-teams.mdx +1 -0
  1507. package/docs/content/locales/es-ES/authentication.mdx +1 -1
  1508. package/docs/content/locales/es-ES/components.mdx +11 -1
  1509. package/docs/content/locales/es-ES/creating-templates.mdx +3 -7
  1510. package/docs/content/locales/es-ES/cross-app-sso.mdx +16 -6
  1511. package/docs/content/locales/es-ES/deployment.mdx +8 -0
  1512. package/docs/content/locales/es-ES/extensions.mdx +10 -0
  1513. package/docs/content/locales/es-ES/external-agents.mdx +3 -7
  1514. package/docs/content/locales/es-ES/key-concepts.mdx +13 -20
  1515. package/docs/content/locales/es-ES/messaging.mdx +91 -15
  1516. package/docs/content/locales/es-ES/multi-tenancy.mdx +5 -5
  1517. package/docs/content/locales/es-ES/notifications.mdx +18 -10
  1518. package/docs/content/locales/es-ES/processors.mdx +11 -5
  1519. package/docs/content/locales/es-ES/server.mdx +17 -10
  1520. package/docs/content/locales/es-ES/sharing.mdx +10 -10
  1521. package/docs/content/locales/es-ES/skills-guide.mdx +34 -17
  1522. package/docs/content/locales/es-ES/template-assets.mdx +16 -13
  1523. package/docs/content/locales/es-ES/template-brain.mdx +3 -1
  1524. package/docs/content/locales/es-ES/template-clips.mdx +4 -3
  1525. package/docs/content/locales/es-ES/template-design.mdx +4 -1
  1526. package/docs/content/locales/es-ES/template-dispatch.mdx +5 -1
  1527. package/docs/content/locales/es-ES/template-mail.mdx +8 -0
  1528. package/docs/content/locales/es-ES/tracking.mdx +9 -6
  1529. package/docs/content/locales/es-ES/using-your-agent.mdx +0 -7
  1530. package/docs/content/locales/es-ES/voice-input.mdx +6 -0
  1531. package/docs/content/locales/es-ES/workspace-connections.mdx +9 -2
  1532. package/docs/content/locales/es-ES/workspace.mdx +19 -18
  1533. package/docs/content/locales/fr-FR/actions.mdx +2 -2
  1534. package/docs/content/locales/fr-FR/agent-native-toolkit.mdx +2 -2
  1535. package/docs/content/locales/fr-FR/agent-surfaces.mdx +8 -10
  1536. package/docs/content/locales/fr-FR/agent-teams.mdx +1 -0
  1537. package/docs/content/locales/fr-FR/authentication.mdx +1 -1
  1538. package/docs/content/locales/fr-FR/components.mdx +11 -1
  1539. package/docs/content/locales/fr-FR/creating-templates.mdx +3 -7
  1540. package/docs/content/locales/fr-FR/cross-app-sso.mdx +16 -6
  1541. package/docs/content/locales/fr-FR/deployment.mdx +8 -0
  1542. package/docs/content/locales/fr-FR/extensions.mdx +10 -0
  1543. package/docs/content/locales/fr-FR/external-agents.mdx +3 -7
  1544. package/docs/content/locales/fr-FR/key-concepts.mdx +13 -20
  1545. package/docs/content/locales/fr-FR/messaging.mdx +91 -15
  1546. package/docs/content/locales/fr-FR/multi-tenancy.mdx +5 -5
  1547. package/docs/content/locales/fr-FR/notifications.mdx +18 -10
  1548. package/docs/content/locales/fr-FR/processors.mdx +11 -5
  1549. package/docs/content/locales/fr-FR/server.mdx +17 -10
  1550. package/docs/content/locales/fr-FR/sharing.mdx +10 -10
  1551. package/docs/content/locales/fr-FR/skills-guide.mdx +34 -17
  1552. package/docs/content/locales/fr-FR/template-assets.mdx +16 -13
  1553. package/docs/content/locales/fr-FR/template-brain.mdx +3 -1
  1554. package/docs/content/locales/fr-FR/template-clips.mdx +4 -3
  1555. package/docs/content/locales/fr-FR/template-design.mdx +4 -1
  1556. package/docs/content/locales/fr-FR/template-dispatch.mdx +5 -1
  1557. package/docs/content/locales/fr-FR/template-mail.mdx +8 -0
  1558. package/docs/content/locales/fr-FR/tracking.mdx +9 -6
  1559. package/docs/content/locales/fr-FR/using-your-agent.mdx +0 -7
  1560. package/docs/content/locales/fr-FR/voice-input.mdx +6 -0
  1561. package/docs/content/locales/fr-FR/workspace-connections.mdx +9 -2
  1562. package/docs/content/locales/fr-FR/workspace.mdx +19 -18
  1563. package/docs/content/locales/hi-IN/actions.mdx +2 -2
  1564. package/docs/content/locales/hi-IN/agent-native-toolkit.mdx +2 -2
  1565. package/docs/content/locales/hi-IN/agent-surfaces.mdx +8 -10
  1566. package/docs/content/locales/hi-IN/agent-teams.mdx +1 -0
  1567. package/docs/content/locales/hi-IN/authentication.mdx +1 -1
  1568. package/docs/content/locales/hi-IN/components.mdx +11 -1
  1569. package/docs/content/locales/hi-IN/creating-templates.mdx +3 -7
  1570. package/docs/content/locales/hi-IN/cross-app-sso.mdx +16 -6
  1571. package/docs/content/locales/hi-IN/deployment.mdx +8 -0
  1572. package/docs/content/locales/hi-IN/extensions.mdx +8 -0
  1573. package/docs/content/locales/hi-IN/external-agents.mdx +2 -7
  1574. package/docs/content/locales/hi-IN/key-concepts.mdx +13 -20
  1575. package/docs/content/locales/hi-IN/messaging.mdx +81 -15
  1576. package/docs/content/locales/hi-IN/multi-tenancy.mdx +5 -5
  1577. package/docs/content/locales/hi-IN/notifications.mdx +18 -10
  1578. package/docs/content/locales/hi-IN/processors.mdx +11 -5
  1579. package/docs/content/locales/hi-IN/server.mdx +17 -10
  1580. package/docs/content/locales/hi-IN/sharing.mdx +10 -10
  1581. package/docs/content/locales/hi-IN/skills-guide.mdx +34 -17
  1582. package/docs/content/locales/hi-IN/template-assets.mdx +16 -13
  1583. package/docs/content/locales/hi-IN/template-brain.mdx +3 -1
  1584. package/docs/content/locales/hi-IN/template-clips.mdx +4 -3
  1585. package/docs/content/locales/hi-IN/template-design.mdx +4 -1
  1586. package/docs/content/locales/hi-IN/template-dispatch.mdx +5 -1
  1587. package/docs/content/locales/hi-IN/template-mail.mdx +8 -0
  1588. package/docs/content/locales/hi-IN/tracking.mdx +9 -6
  1589. package/docs/content/locales/hi-IN/using-your-agent.mdx +0 -7
  1590. package/docs/content/locales/hi-IN/voice-input.mdx +6 -0
  1591. package/docs/content/locales/hi-IN/workspace-connections.mdx +9 -2
  1592. package/docs/content/locales/hi-IN/workspace.mdx +19 -18
  1593. package/docs/content/locales/ja-JP/actions.mdx +2 -2
  1594. package/docs/content/locales/ja-JP/agent-native-toolkit.mdx +2 -2
  1595. package/docs/content/locales/ja-JP/agent-surfaces.mdx +8 -10
  1596. package/docs/content/locales/ja-JP/agent-teams.mdx +1 -0
  1597. package/docs/content/locales/ja-JP/authentication.mdx +1 -1
  1598. package/docs/content/locales/ja-JP/components.mdx +11 -1
  1599. package/docs/content/locales/ja-JP/creating-templates.mdx +3 -7
  1600. package/docs/content/locales/ja-JP/cross-app-sso.mdx +16 -6
  1601. package/docs/content/locales/ja-JP/deployment.mdx +8 -0
  1602. package/docs/content/locales/ja-JP/extensions.mdx +9 -0
  1603. package/docs/content/locales/ja-JP/external-agents.mdx +2 -7
  1604. package/docs/content/locales/ja-JP/key-concepts.mdx +13 -20
  1605. package/docs/content/locales/ja-JP/messaging.mdx +81 -15
  1606. package/docs/content/locales/ja-JP/multi-tenancy.mdx +5 -5
  1607. package/docs/content/locales/ja-JP/notifications.mdx +18 -10
  1608. package/docs/content/locales/ja-JP/processors.mdx +11 -5
  1609. package/docs/content/locales/ja-JP/server.mdx +17 -10
  1610. package/docs/content/locales/ja-JP/sharing.mdx +10 -10
  1611. package/docs/content/locales/ja-JP/skills-guide.mdx +34 -17
  1612. package/docs/content/locales/ja-JP/template-assets.mdx +16 -13
  1613. package/docs/content/locales/ja-JP/template-brain.mdx +3 -1
  1614. package/docs/content/locales/ja-JP/template-clips.mdx +4 -4
  1615. package/docs/content/locales/ja-JP/template-design.mdx +4 -1
  1616. package/docs/content/locales/ja-JP/template-dispatch.mdx +5 -1
  1617. package/docs/content/locales/ja-JP/template-mail.mdx +8 -0
  1618. package/docs/content/locales/ja-JP/tracking.mdx +9 -6
  1619. package/docs/content/locales/ja-JP/using-your-agent.mdx +0 -7
  1620. package/docs/content/locales/ja-JP/voice-input.mdx +6 -0
  1621. package/docs/content/locales/ja-JP/workspace-connections.mdx +9 -2
  1622. package/docs/content/locales/ja-JP/workspace.mdx +19 -18
  1623. package/docs/content/locales/ko-KR/actions.mdx +2 -2
  1624. package/docs/content/locales/ko-KR/agent-native-toolkit.mdx +2 -2
  1625. package/docs/content/locales/ko-KR/agent-surfaces.mdx +8 -10
  1626. package/docs/content/locales/ko-KR/agent-teams.mdx +1 -0
  1627. package/docs/content/locales/ko-KR/authentication.mdx +1 -1
  1628. package/docs/content/locales/ko-KR/components.mdx +11 -1
  1629. package/docs/content/locales/ko-KR/creating-templates.mdx +3 -7
  1630. package/docs/content/locales/ko-KR/cross-app-sso.mdx +16 -6
  1631. package/docs/content/locales/ko-KR/deployment.mdx +8 -0
  1632. package/docs/content/locales/ko-KR/extensions.mdx +8 -0
  1633. package/docs/content/locales/ko-KR/external-agents.mdx +2 -7
  1634. package/docs/content/locales/ko-KR/key-concepts.mdx +13 -20
  1635. package/docs/content/locales/ko-KR/messaging.mdx +80 -15
  1636. package/docs/content/locales/ko-KR/multi-tenancy.mdx +5 -5
  1637. package/docs/content/locales/ko-KR/notifications.mdx +18 -10
  1638. package/docs/content/locales/ko-KR/processors.mdx +11 -5
  1639. package/docs/content/locales/ko-KR/server.mdx +17 -10
  1640. package/docs/content/locales/ko-KR/sharing.mdx +10 -10
  1641. package/docs/content/locales/ko-KR/skills-guide.mdx +34 -17
  1642. package/docs/content/locales/ko-KR/template-assets.mdx +16 -13
  1643. package/docs/content/locales/ko-KR/template-brain.mdx +3 -1
  1644. package/docs/content/locales/ko-KR/template-clips.mdx +4 -4
  1645. package/docs/content/locales/ko-KR/template-design.mdx +4 -1
  1646. package/docs/content/locales/ko-KR/template-dispatch.mdx +5 -1
  1647. package/docs/content/locales/ko-KR/template-mail.mdx +8 -0
  1648. package/docs/content/locales/ko-KR/tracking.mdx +9 -6
  1649. package/docs/content/locales/ko-KR/using-your-agent.mdx +0 -7
  1650. package/docs/content/locales/ko-KR/voice-input.mdx +6 -0
  1651. package/docs/content/locales/ko-KR/workspace-connections.mdx +9 -2
  1652. package/docs/content/locales/ko-KR/workspace.mdx +19 -18
  1653. package/docs/content/locales/pt-BR/actions.mdx +2 -2
  1654. package/docs/content/locales/pt-BR/agent-native-toolkit.mdx +2 -2
  1655. package/docs/content/locales/pt-BR/agent-surfaces.mdx +8 -10
  1656. package/docs/content/locales/pt-BR/agent-teams.mdx +1 -0
  1657. package/docs/content/locales/pt-BR/authentication.mdx +1 -1
  1658. package/docs/content/locales/pt-BR/components.mdx +11 -1
  1659. package/docs/content/locales/pt-BR/creating-templates.mdx +3 -7
  1660. package/docs/content/locales/pt-BR/cross-app-sso.mdx +16 -6
  1661. package/docs/content/locales/pt-BR/deployment.mdx +8 -0
  1662. package/docs/content/locales/pt-BR/extensions.mdx +9 -0
  1663. package/docs/content/locales/pt-BR/external-agents.mdx +3 -7
  1664. package/docs/content/locales/pt-BR/key-concepts.mdx +13 -20
  1665. package/docs/content/locales/pt-BR/messaging.mdx +88 -15
  1666. package/docs/content/locales/pt-BR/multi-tenancy.mdx +5 -5
  1667. package/docs/content/locales/pt-BR/notifications.mdx +18 -10
  1668. package/docs/content/locales/pt-BR/processors.mdx +11 -5
  1669. package/docs/content/locales/pt-BR/server.mdx +17 -10
  1670. package/docs/content/locales/pt-BR/sharing.mdx +10 -10
  1671. package/docs/content/locales/pt-BR/skills-guide.mdx +34 -17
  1672. package/docs/content/locales/pt-BR/template-assets.mdx +16 -13
  1673. package/docs/content/locales/pt-BR/template-brain.mdx +3 -1
  1674. package/docs/content/locales/pt-BR/template-clips.mdx +4 -3
  1675. package/docs/content/locales/pt-BR/template-design.mdx +4 -1
  1676. package/docs/content/locales/pt-BR/template-dispatch.mdx +5 -1
  1677. package/docs/content/locales/pt-BR/template-mail.mdx +8 -0
  1678. package/docs/content/locales/pt-BR/tracking.mdx +9 -6
  1679. package/docs/content/locales/pt-BR/using-your-agent.mdx +0 -7
  1680. package/docs/content/locales/pt-BR/voice-input.mdx +6 -0
  1681. package/docs/content/locales/pt-BR/workspace-connections.mdx +9 -2
  1682. package/docs/content/locales/pt-BR/workspace.mdx +19 -18
  1683. package/docs/content/locales/zh-CN/actions.mdx +2 -2
  1684. package/docs/content/locales/zh-CN/agent-native-toolkit.mdx +2 -2
  1685. package/docs/content/locales/zh-CN/agent-surfaces.mdx +8 -10
  1686. package/docs/content/locales/zh-CN/agent-teams.mdx +1 -0
  1687. package/docs/content/locales/zh-CN/authentication.mdx +1 -1
  1688. package/docs/content/locales/zh-CN/components.mdx +11 -1
  1689. package/docs/content/locales/zh-CN/creating-templates.mdx +3 -7
  1690. package/docs/content/locales/zh-CN/cross-app-sso.mdx +16 -6
  1691. package/docs/content/locales/zh-CN/deployment.mdx +8 -0
  1692. package/docs/content/locales/zh-CN/extensions.mdx +6 -0
  1693. package/docs/content/locales/zh-CN/external-agents.mdx +2 -7
  1694. package/docs/content/locales/zh-CN/key-concepts.mdx +13 -20
  1695. package/docs/content/locales/zh-CN/messaging.mdx +78 -15
  1696. package/docs/content/locales/zh-CN/multi-tenancy.mdx +5 -5
  1697. package/docs/content/locales/zh-CN/notifications.mdx +18 -10
  1698. package/docs/content/locales/zh-CN/processors.mdx +11 -5
  1699. package/docs/content/locales/zh-CN/server.mdx +16 -10
  1700. package/docs/content/locales/zh-CN/sharing.mdx +10 -10
  1701. package/docs/content/locales/zh-CN/skills-guide.mdx +34 -17
  1702. package/docs/content/locales/zh-CN/template-assets.mdx +16 -13
  1703. package/docs/content/locales/zh-CN/template-brain.mdx +3 -1
  1704. package/docs/content/locales/zh-CN/template-clips.mdx +4 -4
  1705. package/docs/content/locales/zh-CN/template-design.mdx +4 -1
  1706. package/docs/content/locales/zh-CN/template-dispatch.mdx +5 -1
  1707. package/docs/content/locales/zh-CN/template-mail.mdx +8 -0
  1708. package/docs/content/locales/zh-CN/tracking.mdx +9 -6
  1709. package/docs/content/locales/zh-CN/using-your-agent.mdx +0 -7
  1710. package/docs/content/locales/zh-CN/voice-input.mdx +6 -0
  1711. package/docs/content/locales/zh-CN/workspace-connections.mdx +9 -2
  1712. package/docs/content/locales/zh-CN/workspace.mdx +19 -18
  1713. package/docs/content/locales/zh-TW/actions.mdx +2 -2
  1714. package/docs/content/locales/zh-TW/agent-native-toolkit.mdx +2 -2
  1715. package/docs/content/locales/zh-TW/agent-surfaces.mdx +8 -10
  1716. package/docs/content/locales/zh-TW/agent-teams.mdx +1 -0
  1717. package/docs/content/locales/zh-TW/authentication.mdx +1 -1
  1718. package/docs/content/locales/zh-TW/components.mdx +11 -1
  1719. package/docs/content/locales/zh-TW/creating-templates.mdx +3 -7
  1720. package/docs/content/locales/zh-TW/cross-app-sso.mdx +16 -6
  1721. package/docs/content/locales/zh-TW/deployment.mdx +8 -0
  1722. package/docs/content/locales/zh-TW/extensions.mdx +6 -0
  1723. package/docs/content/locales/zh-TW/external-agents.mdx +2 -7
  1724. package/docs/content/locales/zh-TW/key-concepts.mdx +13 -20
  1725. package/docs/content/locales/zh-TW/messaging.mdx +78 -15
  1726. package/docs/content/locales/zh-TW/multi-tenancy.mdx +5 -5
  1727. package/docs/content/locales/zh-TW/notifications.mdx +18 -10
  1728. package/docs/content/locales/zh-TW/processors.mdx +11 -5
  1729. package/docs/content/locales/zh-TW/server.mdx +16 -10
  1730. package/docs/content/locales/zh-TW/sharing.mdx +10 -10
  1731. package/docs/content/locales/zh-TW/skills-guide.mdx +34 -17
  1732. package/docs/content/locales/zh-TW/template-assets.mdx +16 -13
  1733. package/docs/content/locales/zh-TW/template-brain.mdx +3 -1
  1734. package/docs/content/locales/zh-TW/template-clips.mdx +4 -4
  1735. package/docs/content/locales/zh-TW/template-design.mdx +4 -1
  1736. package/docs/content/locales/zh-TW/template-dispatch.mdx +5 -1
  1737. package/docs/content/locales/zh-TW/template-mail.mdx +8 -0
  1738. package/docs/content/locales/zh-TW/tracking.mdx +9 -6
  1739. package/docs/content/locales/zh-TW/using-your-agent.mdx +0 -7
  1740. package/docs/content/locales/zh-TW/voice-input.mdx +6 -0
  1741. package/docs/content/locales/zh-TW/workspace-connections.mdx +9 -2
  1742. package/docs/content/locales/zh-TW/workspace.mdx +19 -18
  1743. package/docs/content/mcp-apps.mdx +14 -32
  1744. package/docs/content/mcp-clients.mdx +48 -54
  1745. package/docs/content/mcp-protocol.mdx +25 -10
  1746. package/docs/content/messaging.mdx +238 -48
  1747. package/docs/content/multi-app-workspace.mdx +11 -96
  1748. package/docs/content/multi-tenancy.mdx +5 -5
  1749. package/docs/content/native-chat-ui.mdx +4 -4
  1750. package/docs/content/notifications.mdx +19 -12
  1751. package/docs/content/observability.mdx +2 -4
  1752. package/docs/content/observational-memory.mdx +7 -3
  1753. package/docs/content/onboarding.mdx +9 -2
  1754. package/docs/content/plan-plugin.mdx +10 -2
  1755. package/docs/content/pr-visual-recap.mdx +1 -1
  1756. package/docs/content/processors.mdx +11 -5
  1757. package/docs/content/pure-agent-apps.mdx +5 -1
  1758. package/docs/content/real-time-collaboration.mdx +30 -67
  1759. package/docs/content/recurring-jobs.mdx +8 -6
  1760. package/docs/content/routing.mdx +3 -4
  1761. package/docs/content/sandbox-adapters.mdx +30 -53
  1762. package/docs/content/security.mdx +8 -0
  1763. package/docs/content/server.mdx +17 -10
  1764. package/docs/content/sharing.mdx +10 -10
  1765. package/docs/content/skills-guide.mdx +35 -16
  1766. package/docs/content/template-analytics.mdx +11 -8
  1767. package/docs/content/template-assets.mdx +16 -13
  1768. package/docs/content/template-brain.mdx +3 -1
  1769. package/docs/content/template-calendar.mdx +12 -4
  1770. package/docs/content/template-chat.mdx +4 -4
  1771. package/docs/content/template-clips.mdx +6 -3
  1772. package/docs/content/template-content.mdx +23 -18
  1773. package/docs/content/template-design.mdx +7 -1
  1774. package/docs/content/template-dispatch.mdx +5 -1
  1775. package/docs/content/template-mail.mdx +14 -2
  1776. package/docs/content/template-plan.mdx +22 -15
  1777. package/docs/content/template-slides.mdx +11 -3
  1778. package/docs/content/toolkit-agent-ux.mdx +46 -3
  1779. package/docs/content/toolkit-collaboration.mdx +58 -4
  1780. package/docs/content/toolkit-command-navigation.mdx +8 -2
  1781. package/docs/content/toolkit-comments-review.mdx +10 -2
  1782. package/docs/content/toolkit-history.mdx +8 -3
  1783. package/docs/content/toolkit-observability.mdx +48 -2
  1784. package/docs/content/toolkit-org-team.mdx +8 -2
  1785. package/docs/content/toolkit-resources.mdx +45 -2
  1786. package/docs/content/toolkit-settings.mdx +8 -2
  1787. package/docs/content/toolkit-setup-connections.mdx +7 -2
  1788. package/docs/content/toolkit-sharing.mdx +46 -3
  1789. package/docs/content/toolkit-ui.mdx +82 -11
  1790. package/docs/content/tracking.mdx +10 -8
  1791. package/docs/content/using-your-agent.mdx +0 -12
  1792. package/docs/content/voice-input.mdx +7 -1
  1793. package/docs/content/what-is-agent-native.mdx +7 -8
  1794. package/docs/content/workspace-connections.mdx +16 -23
  1795. package/docs/content/workspace-management.mdx +16 -4
  1796. package/docs/content/workspace.mdx +19 -18
  1797. package/package.json +5 -1
  1798. package/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
  1799. package/src/templates/default/AGENTS.md +7 -3
  1800. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
  1801. package/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
  1802. package/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
  1803. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
  1804. package/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
  1805. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -5
  1806. package/src/templates/workspace-core/AGENTS.md +3 -2
  1807. package/corpus/core/docs/content/locales/ar-SA/migration-workbench.mdx +0 -76
  1808. package/corpus/core/docs/content/locales/de-DE/migration-workbench.mdx +0 -76
  1809. package/corpus/core/docs/content/locales/es-ES/migration-workbench.mdx +0 -76
  1810. package/corpus/core/docs/content/locales/fr-FR/migration-workbench.mdx +0 -76
  1811. package/corpus/core/docs/content/locales/hi-IN/migration-workbench.mdx +0 -74
  1812. package/corpus/core/docs/content/locales/ja-JP/migration-workbench.mdx +0 -76
  1813. package/corpus/core/docs/content/locales/ko-KR/migration-workbench.mdx +0 -74
  1814. package/corpus/core/docs/content/locales/pt-BR/migration-workbench.mdx +0 -76
  1815. package/corpus/core/docs/content/locales/zh-CN/migration-workbench.mdx +0 -74
  1816. package/corpus/core/docs/content/locales/zh-TW/migration-workbench.mdx +0 -74
  1817. package/corpus/core/docs/content/migration-workbench.mdx +0 -74
  1818. package/corpus/core/docs/content/toolkit-app-adapters.mdx +0 -55
  1819. package/corpus/core/docs/content/toolkit-collaboration-ui.mdx +0 -60
  1820. package/corpus/core/docs/content/toolkit-sharing-ui.mdx +0 -45
  1821. package/corpus/core/docs/content/toolkit-shell-hooks.mdx +0 -36
  1822. package/docs/content/locales/ar-SA/migration-workbench.mdx +0 -76
  1823. package/docs/content/locales/de-DE/migration-workbench.mdx +0 -76
  1824. package/docs/content/locales/es-ES/migration-workbench.mdx +0 -76
  1825. package/docs/content/locales/fr-FR/migration-workbench.mdx +0 -76
  1826. package/docs/content/locales/hi-IN/migration-workbench.mdx +0 -74
  1827. package/docs/content/locales/ja-JP/migration-workbench.mdx +0 -76
  1828. package/docs/content/locales/ko-KR/migration-workbench.mdx +0 -74
  1829. package/docs/content/locales/pt-BR/migration-workbench.mdx +0 -76
  1830. package/docs/content/locales/zh-CN/migration-workbench.mdx +0 -74
  1831. package/docs/content/locales/zh-TW/migration-workbench.mdx +0 -74
  1832. package/docs/content/migration-workbench.mdx +0 -74
  1833. package/docs/content/toolkit-app-adapters.mdx +0 -55
  1834. package/docs/content/toolkit-collaboration-ui.mdx +0 -60
  1835. package/docs/content/toolkit-sharing-ui.mdx +0 -45
  1836. package/docs/content/toolkit-shell-hooks.mdx +0 -36
@@ -0,0 +1,2568 @@
1
+ /**
2
+ * Convert a decoded Figma document (NODE_CHANGES message) into one HTML
3
+ * file per top-level frame. Each node renders as a <div> (or <span> for
4
+ * TEXT) with an inline `style="..."` covering layout, background, border,
5
+ * radius, shadows, blurs, text, transform, autolayout (flexbox), and
6
+ * opacity/blend. Component instances are inlined and tagged with
7
+ * data-component-name / data-variant-name / data-component-description /
8
+ * data-component-doc-link / data-annotations attributes, matching the
9
+ * figma-plugin smart-export conventions.
10
+ */
11
+
12
+ import * as path from "node:path";
13
+
14
+ export interface Guid {
15
+ sessionID: number;
16
+ localID: number;
17
+ }
18
+
19
+ interface Color {
20
+ r: number;
21
+ g: number;
22
+ b: number;
23
+ a: number;
24
+ }
25
+
26
+ interface Paint {
27
+ type?: string;
28
+ color?: Color;
29
+ opacity?: number;
30
+ visible?: boolean;
31
+ blendMode?: string;
32
+ stops?: Array<{ color: Color; position: number }>;
33
+ transform?: {
34
+ m00: number;
35
+ m01: number;
36
+ m02: number;
37
+ m10: number;
38
+ m11: number;
39
+ m12: number;
40
+ };
41
+ // hash may be a hex string (JSON-decoded) or raw bytes (kiwi-decoder).
42
+ image?: { hash?: string | Uint8Array | number[]; name?: string };
43
+ imageScaleMode?: string;
44
+ rotation?: number;
45
+ scale?: number;
46
+ }
47
+
48
+ interface Effect {
49
+ type?: string;
50
+ visible?: boolean;
51
+ color?: Color;
52
+ offset?: { x: number; y: number };
53
+ radius?: number;
54
+ spread?: number;
55
+ blendMode?: string;
56
+ }
57
+
58
+ interface Annotation {
59
+ label?: string;
60
+ labelV2?: string;
61
+ properties?: unknown[];
62
+ }
63
+
64
+ interface ComponentPropDef {
65
+ id?: Guid;
66
+ name?: string;
67
+ type?: string;
68
+ }
69
+
70
+ export interface FigNode {
71
+ guid?: Guid;
72
+ // Library-stable identifier used by override paths (`symbolOverrides[].guidPath`)
73
+ // and `derivedSymbolData[].guidPath`. When a node is a remix of a library
74
+ // component, the `guid` is local to this document but `overrideKey` is the
75
+ // GUID from the source library. Override-path matching MUST use this when
76
+ // available so that overrides authored against the library still apply.
77
+ overrideKey?: Guid;
78
+ parentIndex?: { guid?: Guid; position?: string };
79
+ type?: string;
80
+ name?: string;
81
+ description?: string;
82
+ componentKey?: string;
83
+ componentPropDefs?: ComponentPropDef[];
84
+ componentPropAssignments?: unknown[];
85
+ componentPropRefs?: unknown[];
86
+ annotations?: Annotation[];
87
+ isSymbolPublishable?: boolean;
88
+ visible?: boolean;
89
+ size?: { x: number; y: number };
90
+ // Auto-layout min/max constraints. Either axis may be null when unconstrained.
91
+ // A min-width keeps e.g. a single-digit count badge circular.
92
+ minSize?: { value?: { x: number | null; y: number | null } };
93
+ maxSize?: { value?: { x: number | null; y: number | null } };
94
+ transform?: {
95
+ m00: number;
96
+ m01: number;
97
+ m02: number;
98
+ m10: number;
99
+ m11: number;
100
+ m12: number;
101
+ };
102
+ fillPaints?: Paint[];
103
+ strokePaints?: Paint[];
104
+ // Style references — when present, the actual paint comes from the
105
+ // referenced shared-style node's fillPaints/strokePaints rather than the
106
+ // stale `fillPaints`/`strokePaints` cached on this node.
107
+ styleIdForFill?: {
108
+ guid?: Guid;
109
+ assetRef?: { key?: string; version?: string };
110
+ };
111
+ styleIdForStroke?: {
112
+ guid?: Guid;
113
+ assetRef?: { key?: string; version?: string };
114
+ };
115
+ styleIdForText?: {
116
+ guid?: Guid;
117
+ assetRef?: { key?: string; version?: string };
118
+ };
119
+ // Library style nodes carry their stable key here (matched against
120
+ // `styleIdForFill.assetRef.key` etc. on the consuming nodes).
121
+ key?: string;
122
+ styleType?: string;
123
+ strokeWeight?: number;
124
+ strokeAlign?: string;
125
+ strokeTopWeight?: number;
126
+ strokeRightWeight?: number;
127
+ strokeBottomWeight?: number;
128
+ strokeLeftWeight?: number;
129
+ effects?: Effect[];
130
+ opacity?: number;
131
+ blendMode?: string;
132
+ cornerRadius?: number;
133
+ rectangleTopLeftCornerRadius?: number;
134
+ rectangleTopRightCornerRadius?: number;
135
+ rectangleBottomLeftCornerRadius?: number;
136
+ rectangleBottomRightCornerRadius?: number;
137
+ fontSize?: number;
138
+ fontName?: { family?: string; style?: string };
139
+ letterSpacing?: { value: number; units?: string };
140
+ lineHeight?: { value: number; units?: string };
141
+ textAlignHorizontal?: string;
142
+ textAlignVertical?: string;
143
+ textData?: { characters?: string };
144
+ textAutoResize?: string;
145
+ symbolData?: {
146
+ symbolID?: Guid;
147
+ symbolOverrides?: SymbolOverride[];
148
+ };
149
+ stackMode?: string;
150
+ stackPrimaryAlignItems?: string;
151
+ stackCounterAlignItems?: string;
152
+ stackSpacing?: number;
153
+ stackHorizontalPadding?: number;
154
+ stackVerticalPadding?: number;
155
+ stackPaddingLeft?: number;
156
+ stackPaddingRight?: number;
157
+ stackPaddingTop?: number;
158
+ stackPaddingBottom?: number;
159
+ stackPrimarySizing?: string;
160
+ stackCounterSizing?: string;
161
+ stackChildPrimaryGrow?: number;
162
+ stackChildAlignSelf?: string;
163
+ // "ABSOLUTE" marks a child that ignores its parent's auto-layout (Figma's
164
+ // "ignore auto layout"): it is positioned by its own transform and removed
165
+ // from the flex flow instead of stacking as a flex item.
166
+ stackPositioning?: string;
167
+ resizeToFit?: boolean;
168
+ horizontalConstraint?: string;
169
+ verticalConstraint?: string;
170
+ frameMaskDisabled?: boolean;
171
+ internalOnly?: boolean;
172
+ // Vector geometry. Each path's `commandsBlob` is an index into the
173
+ // document `blobs` array; the bytes there are a Figma path command
174
+ // stream (see decodePathCommands).
175
+ fillGeometry?: Array<{
176
+ commandsBlob?: number;
177
+ windingRule?: string;
178
+ styleID?: number;
179
+ }>;
180
+ strokeGeometry?: Array<{
181
+ commandsBlob?: number;
182
+ windingRule?: string;
183
+ styleID?: number;
184
+ }>;
185
+ strokeJoin?: string;
186
+ strokeCap?: string;
187
+ strokeDashes?: number[];
188
+ vectorData?: {
189
+ normalizedSize?: { x: number; y: number };
190
+ vectorNetworkBlob?: number;
191
+ };
192
+ // Literal values are stale baked snapshots; resolveVariableBindings rewrites from here.
193
+ variableConsumptionMap?: {
194
+ entries?: Array<{
195
+ variableField?: string;
196
+ variableData?: { value?: VariableValue };
197
+ }>;
198
+ };
199
+ // Which mode to resolve for each variable set; set may be referenced by assetRef.key or guid.
200
+ variableModeBySetMap?: {
201
+ entries?: Array<{
202
+ variableSetID?: VariableSetRef;
203
+ variableModeID?: Guid;
204
+ }>;
205
+ };
206
+ // On VARIABLE_SET nodes: the modes this set defines (first is the default).
207
+ variableSetModes?: Array<{ id?: Guid; name?: string }>;
208
+ // On VARIABLE nodes: this variable's per-mode values and owning set.
209
+ variableSetID?: VariableSetRef;
210
+ variableDataValues?: {
211
+ entries?: Array<{
212
+ modeID?: Guid;
213
+ variableData?: { value?: VariableValue };
214
+ }>;
215
+ };
216
+ }
217
+
218
+ // IS_TRUTHY(alias) expressions appear on VISIBLE bindings driven by variant props.
219
+ interface VariableValue {
220
+ alias?: { guid?: Guid; assetRef?: { key?: string } };
221
+ boolValue?: boolean;
222
+ expressionValue?: {
223
+ expressionFunction?: string;
224
+ expressionArguments?: Array<{ value?: VariableValue }>;
225
+ };
226
+ [field: string]: unknown;
227
+ }
228
+
229
+ // A variable set is referenced either by its published `assetRef.key` or, for
230
+ // a set local to the document, by `guid`.
231
+ interface VariableSetRef {
232
+ guid?: Guid;
233
+ assetRef?: { key?: string };
234
+ }
235
+
236
+ /**
237
+ * Names Figma assigns by default — when a layer keeps its placeholder name
238
+ * we treat it as having no meaningful name (matches the figma-plugin's
239
+ * smart-export `isDummyName`).
240
+ */
241
+ /**
242
+ * Split a Figma component master name into a base component name and a
243
+ * variant suffix. Figma uses two conventions:
244
+ *
245
+ * - Slash-separated: "ComponentName/VariantA/VariantB" — everything after
246
+ * the first slash is the variant name (this matches the plugin's
247
+ * smart-export behavior).
248
+ * - Variant-set children: a SYMBOL named like "Style=Action, Size=Large"
249
+ * is one variant inside a parent component-set FRAME. In that case the
250
+ * SYMBOL name IS the variant key/value list and the real component
251
+ * name is the parent FRAME's name (resolved separately by the caller).
252
+ */
253
+ function isVariantSymbolName(name: string | undefined): boolean {
254
+ if (!name) return false;
255
+ // Variant SYMBOL naming: comma-separated `Key=Value` pairs.
256
+ return /^[^/=]+=[^=]+(,\s*[^/=]+=[^=]+)*$/.test(name);
257
+ }
258
+
259
+ function splitComponentName(name: string | undefined): {
260
+ base: string;
261
+ variant: string | null;
262
+ } {
263
+ if (!name) return { base: "", variant: null };
264
+ if (isVariantSymbolName(name)) return { base: "", variant: name };
265
+ const i = name.indexOf("/");
266
+ if (i < 0) return { base: name, variant: null };
267
+ return { base: name.slice(0, i), variant: name.slice(i + 1) };
268
+ }
269
+
270
+ /**
271
+ * Resolve the canonical component name + variant string for a SYMBOL,
272
+ * walking up to the parent component-set FRAME when the SYMBOL itself is
273
+ * a variant child (e.g. "Style=Action" inside a "Right Element" FRAME).
274
+ */
275
+ function resolveComponentIdentity(
276
+ symbol: FigNode,
277
+ ctx: Ctx,
278
+ ): { base: string; variant: string | null } {
279
+ const ident = splitComponentName(symbol.name);
280
+ if (ident.base) return ident;
281
+ // Variant SYMBOL — use the parent FRAME (component set) as the base name.
282
+ const parentKey = guidKey(symbol.parentIndex?.guid);
283
+ const parent = ctx.byGuid.get(parentKey);
284
+ const parentName = parent?.name?.trim();
285
+ if (parentName) {
286
+ return { base: parentName, variant: ident.variant };
287
+ }
288
+ return { base: symbol.name ?? "", variant: null };
289
+ }
290
+
291
+ function htmlToPlain(html: string | undefined): string {
292
+ if (!html) return "";
293
+ return html
294
+ .replace(/<br\s*\/?>/gi, "\n")
295
+ .replace(/<\/p>\s*<p[^>]*>/gi, "\n\n")
296
+ .replace(/<[^>]+>/g, "")
297
+ .replace(/&nbsp;/g, " ")
298
+ .replace(/&amp;/g, "&")
299
+ .replace(/&lt;/g, "<")
300
+ .replace(/&gt;/g, ">")
301
+ .replace(/&quot;/g, '"')
302
+ .replace(/&#39;/g, "'")
303
+ .trim();
304
+ }
305
+
306
+ function extractDocLinks(html: string | undefined): string[] {
307
+ if (!html) return [];
308
+ const out: string[] = [];
309
+ const re = /href="([^"]+)"/gi;
310
+ let m: RegExpExecArray | null;
311
+ while ((m = re.exec(html)) !== null) out.push(m[1]!);
312
+ return out;
313
+ }
314
+
315
+ export function guidKey(g: Guid | undefined): string {
316
+ return g ? `${g.sessionID}:${g.localID}` : "";
317
+ }
318
+
319
+ /**
320
+ * Collect the raw Figma component-prop data on a node into a single object
321
+ * suitable for stringifying into a `props="..."` attribute.
322
+ *
323
+ * - SYMBOL nodes get their `componentPropDefs` (the prop schema)
324
+ * - INSTANCE nodes get the `componentPropAssignments` (overrides) plus any
325
+ * `componentPropRefs` (per-child wirings) and the master's defs for
326
+ * context.
327
+ * - Any node may have its own `componentPropRefs` (e.g. an inner layer
328
+ * bound to a parent component prop).
329
+ */
330
+ function collectRawProps(
331
+ node: FigNode,
332
+ componentSymbol: FigNode | null,
333
+ ): Record<string, unknown> | null {
334
+ const out: Record<string, unknown> = {};
335
+ const sym = componentSymbol ?? (node.type === "SYMBOL" ? node : null);
336
+ if (sym?.componentPropDefs?.length) out.defs = sym.componentPropDefs;
337
+ if (
338
+ node.componentPropAssignments &&
339
+ (node.componentPropAssignments as unknown[]).length
340
+ )
341
+ out.assignments = node.componentPropAssignments;
342
+ if (node.componentPropRefs && (node.componentPropRefs as unknown[]).length)
343
+ out.refs = node.componentPropRefs;
344
+ return Object.keys(out).length > 0 ? out : null;
345
+ }
346
+
347
+ /**
348
+ * A resolved Figma component prop value, normalized across the (legacy)
349
+ * `value` and (modern) `varValue` shapes. Only the fields we actually act on
350
+ * are extracted: bool (for VISIBLE), text (for TEXT_DATA), and guid (for
351
+ * OVERRIDDEN_SYMBOL_ID and SLOT_CONTENT_ID).
352
+ */
353
+ interface ResolvedPropValue {
354
+ bool?: boolean;
355
+ text?: string;
356
+ guid?: Guid;
357
+ }
358
+
359
+ function resolvePropAssignment(a: unknown): ResolvedPropValue | null {
360
+ const ax = a as {
361
+ value?: {
362
+ boolValue?: boolean;
363
+ textValue?: { characters?: string };
364
+ guidValue?: Guid;
365
+ };
366
+ varValue?: {
367
+ value?: {
368
+ boolValue?: boolean;
369
+ textValue?: { characters?: string };
370
+ guidValue?: Guid;
371
+ symbolIdValue?: { guid?: Guid };
372
+ textIdValue?: { value?: string };
373
+ };
374
+ };
375
+ };
376
+ const vv = ax.varValue?.value;
377
+ const v = ax.value;
378
+ const out: ResolvedPropValue = {};
379
+ if (typeof vv?.boolValue === "boolean") out.bool = vv.boolValue;
380
+ else if (typeof v?.boolValue === "boolean") out.bool = v.boolValue;
381
+ if (vv?.textValue?.characters !== undefined)
382
+ out.text = vv.textValue.characters;
383
+ else if (v?.textValue?.characters !== undefined)
384
+ out.text = v.textValue.characters;
385
+ else if (vv?.textIdValue?.value !== undefined)
386
+ out.text = vv.textIdValue.value;
387
+ if (vv?.symbolIdValue?.guid) out.guid = vv.symbolIdValue.guid;
388
+ else if (vv?.guidValue) out.guid = vv.guidValue;
389
+ else if (v?.guidValue) out.guid = v.guidValue;
390
+ return Object.keys(out).length > 0 ? out : null;
391
+ }
392
+
393
+ function buildPropEnv(
394
+ node: FigNode,
395
+ inherited: Map<string, ResolvedPropValue>,
396
+ ): Map<string, ResolvedPropValue> {
397
+ const assignments = (node.componentPropAssignments ?? []) as Array<{
398
+ defID?: Guid;
399
+ }>;
400
+ if (assignments.length === 0) return inherited;
401
+ const next = new Map(inherited);
402
+ for (const a of assignments) {
403
+ const key = guidKey(a.defID);
404
+ if (!key) continue;
405
+ const resolved = resolvePropAssignment(a);
406
+ if (resolved) next.set(key, resolved);
407
+ }
408
+ return next;
409
+ }
410
+
411
+ /**
412
+ * Apply parent-instance prop overrides to a node. Returns either the same
413
+ * node (no overrides), a shallow-cloned node with `textData` / `symbolData`
414
+ * patched, or `null` to indicate the node should be hidden by a VISIBLE
415
+ * prop ref resolving to false.
416
+ */
417
+ function applyPropRefs(
418
+ node: FigNode,
419
+ env: Map<string, ResolvedPropValue>,
420
+ ): FigNode | null {
421
+ const refs = (node.componentPropRefs ?? []) as Array<{
422
+ defID?: Guid;
423
+ componentPropNodeField?: string;
424
+ }>;
425
+ if (refs.length === 0 || env.size === 0) return node;
426
+ let patched = node;
427
+ for (const ref of refs) {
428
+ const v = env.get(guidKey(ref.defID));
429
+ if (!v) continue;
430
+ const field = ref.componentPropNodeField;
431
+ if (field === "VISIBLE" && v.bool === false) return null;
432
+ if (field === "TEXT_DATA" && v.text !== undefined) {
433
+ patched = {
434
+ ...patched,
435
+ textData: { ...(patched.textData ?? {}), characters: v.text },
436
+ };
437
+ }
438
+ if (field === "OVERRIDDEN_SYMBOL_ID" && v.guid) {
439
+ patched = {
440
+ ...patched,
441
+ symbolData: { ...(patched.symbolData ?? {}), symbolID: v.guid },
442
+ };
443
+ }
444
+ }
445
+ return patched;
446
+ }
447
+
448
+ /**
449
+ * A raw symbol override entry from `symbolData.symbolOverrides`. It is
450
+ * effectively a partial NodeChange targeting a descendant of the master
451
+ * symbol via `guidPath`. Any field present (other than `guidPath` and
452
+ * `overriddenSymbolID`) is shallow-merged onto the descendant node when
453
+ * it's emitted, so layout-affecting overrides like `size`, `textAutoResize`,
454
+ * `stackChildAlignSelf`, `stackCounterSizing`, `textAlignVertical`, etc.
455
+ * all flow through.
456
+ */
457
+ interface SymbolOverride extends Partial<FigNode> {
458
+ overriddenSymbolID?: Guid;
459
+ guidPath?: { guids?: Guid[] };
460
+ }
461
+
462
+ type OverrideEntry = SymbolOverride;
463
+
464
+ /**
465
+ * An active override scope contributed by an enclosing INSTANCE. `startIndex`
466
+ * is the position in the running guid path at which this instance's master
467
+ * tree begins; override keys in `map` are joined-guid paths RELATIVE to that
468
+ * point (matching what Figma stores in `symbolOverrides[].guidPath`).
469
+ *
470
+ * Multiple layers stack: an outer instance's overrides remain valid even
471
+ * after we descend through nested inner instances, because the descendant's
472
+ * absolute path under the outer instance is still well-defined.
473
+ */
474
+ interface OverrideLayer {
475
+ startIndex: number;
476
+ map: Map<string, OverrideEntry>;
477
+ }
478
+
479
+ function buildSymbolOverrideLayer(node: FigNode): Map<string, OverrideEntry> {
480
+ const out = new Map<string, OverrideEntry>();
481
+ for (const o of node.symbolData?.symbolOverrides ?? []) {
482
+ const guids = o.guidPath?.guids ?? [];
483
+ if (guids.length === 0) continue;
484
+ const key = guids.map((g) => guidKey(g)).join("/");
485
+ // Multiple override entries can share the same guidPath (e.g. one with
486
+ // `overriddenSymbolID` for a variant swap and another with layout
487
+ // tweaks). Merge them so neither is lost.
488
+ const existing = out.get(key);
489
+ if (existing) {
490
+ out.set(key, { ...existing, ...o });
491
+ } else {
492
+ out.set(key, o);
493
+ }
494
+ }
495
+ // `derivedSymbolData` carries pre-computed geometry / text layout for
496
+ // descendants of this instance whose actual definition lives in a remote
497
+ // library (so the local document has only a stub master). Each entry is
498
+ // keyed by a guidPath into the library tree — same coordinate space as
499
+ // `symbolOverrides[].guidPath` — so we can fold them into the same layer.
500
+ // Only fill/stroke geometry are merged; positional fields (`transform`,
501
+ // `size`) and `derivedTextData` are intentionally skipped because they
502
+ // describe library-resolved layout that would overwrite the (already
503
+ // correct) values cached on the local master node.
504
+ for (const d of (
505
+ node as {
506
+ derivedSymbolData?: Array<
507
+ Partial<FigNode> & { guidPath?: { guids?: Guid[] } }
508
+ >;
509
+ }
510
+ ).derivedSymbolData ?? []) {
511
+ const guids = d.guidPath?.guids ?? [];
512
+ if (guids.length === 0) continue;
513
+ if (!d.fillGeometry?.length && !d.strokeGeometry?.length) continue;
514
+ const key = guids.map((g) => guidKey(g)).join("/");
515
+ const patch: SymbolOverride = {};
516
+ if (d.fillGeometry?.length) patch.fillGeometry = d.fillGeometry;
517
+ if (d.strokeGeometry?.length) patch.strokeGeometry = d.strokeGeometry;
518
+ const existing = out.get(key);
519
+ out.set(key, existing ? { ...existing, ...patch } : patch);
520
+ }
521
+ return out;
522
+ }
523
+
524
+ /**
525
+ * Apply any matching override entry from the active override layers to a
526
+ * node about to be emitted. Returns `null` if the node is hidden by an
527
+ * override; otherwise returns the (possibly patched) node.
528
+ */
529
+ function applyOverrideLayers(
530
+ node: FigNode,
531
+ layers: OverrideLayer[],
532
+ instancePath: string[],
533
+ ): FigNode | null {
534
+ if (layers.length === 0) return node;
535
+ // The lookup key for THIS node within a layer is the chain of inner
536
+ // INSTANCE overrideKeys we've descended into since that layer was pushed,
537
+ // followed by this node's own overrideKey. Override paths only grow at
538
+ // INSTANCE boundaries — descending through plain frames/groups within the
539
+ // same master keeps the path the same length.
540
+ const nodeKey = guidKey(node.overrideKey ?? node.guid);
541
+ if (!nodeKey) return node;
542
+ for (const layer of layers) {
543
+ const prefix = instancePath.slice(layer.startIndex);
544
+ const relKey =
545
+ prefix.length > 0 ? `${prefix.join("/")}/${nodeKey}` : nodeKey;
546
+ const entry = layer.map.get(relKey);
547
+ if (!entry) continue;
548
+ if (entry.visible === false) return null;
549
+ // Shallow-merge every field present on the override (except the
550
+ // routing fields and `overriddenSymbolID`, which goes into symbolData).
551
+ // This applies layout overrides like `size`, `textAutoResize`,
552
+ // `stackChildAlignSelf`, `stackCounterSizing`, `textAlignVertical`,
553
+ // styling fields, etc., in addition to text/visibility.
554
+ const merged: FigNode = { ...node };
555
+ for (const [field, value] of Object.entries(entry)) {
556
+ if (field === "guidPath" || field === "overriddenSymbolID") continue;
557
+ if (value === undefined) continue;
558
+ (merged as Record<string, unknown>)[field] = value;
559
+ }
560
+ if (entry.overriddenSymbolID) {
561
+ merged.symbolData = {
562
+ ...(merged.symbolData ?? {}),
563
+ symbolID: entry.overriddenSymbolID,
564
+ };
565
+ }
566
+ node = merged;
567
+ }
568
+ return node;
569
+ }
570
+
571
+ function sanitizeFilename(name: string | undefined, fallback: string): string {
572
+ if (!name) return fallback;
573
+ const cleaned = name
574
+ .replace(/[\\/:*?"<>|]/g, "-")
575
+ .replace(/\s+/g, " ")
576
+ .trim()
577
+ .slice(0, 80);
578
+ return cleaned || fallback;
579
+ }
580
+
581
+ function escapeHtmlText(s: string): string {
582
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
583
+ }
584
+
585
+ function escapeHtmlAttr(s: string): string {
586
+ return s
587
+ .replace(/&/g, "&amp;")
588
+ .replace(/"/g, "&quot;")
589
+ .replace(/</g, "&lt;")
590
+ .replace(/\n/g, "&#10;");
591
+ }
592
+
593
+ function kebabCase(prop: string): string {
594
+ return prop.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
595
+ }
596
+
597
+ function colorToCss(c: Color | undefined, alphaMul = 1): string | null {
598
+ if (!c) return null;
599
+ const r = Math.round(c.r * 255);
600
+ const g = Math.round(c.g * 255);
601
+ const b = Math.round(c.b * 255);
602
+ const a = c.a * alphaMul;
603
+ if (a >= 0.999) return `rgb(${r}, ${g}, ${b})`;
604
+ return `rgba(${r}, ${g}, ${b}, ${Number(a.toFixed(3))})`;
605
+ }
606
+
607
+ function num(n: number | null | undefined): number | null {
608
+ if (typeof n !== "number" || !Number.isFinite(n)) return null;
609
+ return Math.round(n * 100) / 100;
610
+ }
611
+
612
+ function tagFor(type: string | undefined): string {
613
+ // Everything renders as a real DOM tag rather than a synthetic component.
614
+ // TEXT becomes <span> so it inlines nicely; everything else is <div>.
615
+ if (type === "TEXT") return "span";
616
+ return "div";
617
+ }
618
+
619
+ const STACK_ALIGN: Record<string, string> = {
620
+ MIN: "flex-start",
621
+ CENTER: "center",
622
+ MAX: "flex-end",
623
+ BASELINE: "baseline",
624
+ SPACE_BETWEEN: "space-between",
625
+ };
626
+
627
+ const TEXT_ALIGN: Record<string, string> = {
628
+ LEFT: "left",
629
+ CENTER: "center",
630
+ RIGHT: "right",
631
+ JUSTIFIED: "justify",
632
+ };
633
+
634
+ function fontWeightFromStyle(style: string | undefined): number | null {
635
+ if (!style) return null;
636
+ const s = style.toLowerCase();
637
+ if (s.includes("thin")) return 100;
638
+ if (s.includes("extralight") || s.includes("ultralight")) return 200;
639
+ if (s.includes("light")) return 300;
640
+ if (s.includes("regular") || s === "normal") return 400;
641
+ if (s.includes("medium")) return 500;
642
+ if (s.includes("semibold") || s.includes("demibold")) return 600;
643
+ if (s.includes("extrabold") || s.includes("ultrabold")) return 800;
644
+ if (s.includes("black") || s.includes("heavy")) return 900;
645
+ if (s.includes("bold")) return 700;
646
+ return null;
647
+ }
648
+
649
+ function lengthFromUnits(
650
+ v: { value: number; units?: string } | undefined,
651
+ fontSize?: number,
652
+ ) {
653
+ if (!v) return null;
654
+ if (v.units === "PIXELS") return `${num(v.value)}px`;
655
+ if (v.units === "PERCENT") {
656
+ if (fontSize) return `${num((v.value / 100) * fontSize)}px`;
657
+ return `${num(v.value)}%`;
658
+ }
659
+ if (v.units === "RAW") return num(v.value);
660
+ return num(v.value);
661
+ }
662
+
663
+ /**
664
+ * Normalize a Figma image hash into a hex string. The kiwi decoder emits
665
+ * the hash as a Uint8Array / number[]; the JSON-roundtripped form is
666
+ * already a hex string.
667
+ */
668
+ function hashToHex(
669
+ h: string | Uint8Array | number[] | undefined,
670
+ ): string | null {
671
+ if (!h) return null;
672
+ if (typeof h === "string") return h;
673
+ const arr = h instanceof Uint8Array ? Array.from(h) : (h as number[]);
674
+ return arr.map((b) => b.toString(16).padStart(2, "0")).join("");
675
+ }
676
+
677
+ /**
678
+ * Resolve an image hash to a usable URL path. Looks up the actual filename
679
+ * (which may be `<hash>` or `<hash>.png` depending on whether the source
680
+ * was a zip-format or kiwi-format `.fig`) in the ctx imageMap.
681
+ */
682
+ function imageUrl(hashHex: string, ctx: Ctx): string {
683
+ const resolved = ctx.imageMap.get(hashHex);
684
+ if (!resolved && ctx.missingImageUrl) return ctx.missingImageUrl;
685
+ const filename = resolved ?? hashHex;
686
+ if (/^(?:https?:|blob:|about:)/i.test(filename)) return filename;
687
+ const base = ctx.imageRefBase ?? "images";
688
+ return `${base}/${filename}`;
689
+ }
690
+
691
+ /**
692
+ * Resolve a style reference (`styleIdForFill` / `styleIdForStroke` /
693
+ * `styleIdForText`) to the actual style node. Style refs come in two
694
+ * flavors: a local `guid` for in-document styles and an `assetRef.key`
695
+ * for library styles. Library style definitions get embedded in the
696
+ * document under the same `key`, so we look them up via `ctx.byKey`.
697
+ */
698
+ function resolveStyleNode(
699
+ ref: { guid?: Guid; assetRef?: { key?: string } } | undefined,
700
+ ctx: Ctx,
701
+ ): FigNode | undefined {
702
+ if (!ref) return undefined;
703
+ if (ref.guid) {
704
+ const n = ctx.byGuid.get(guidKey(ref.guid));
705
+ if (n) return n;
706
+ }
707
+ if (ref.assetRef?.key) {
708
+ const n = ctx.byKey.get(ref.assetRef.key);
709
+ if (n) return n;
710
+ }
711
+ return undefined;
712
+ }
713
+
714
+ /**
715
+ * Resolve the effective fill paints for a node. When the node references a
716
+ * shared FILL style via `styleIdForFill`, the cached `fillPaints` baked
717
+ * into the node may be stale (the design token's actual color can have
718
+ * changed since). Prefer the style node's `fillPaints` whenever a fill
719
+ * style reference is present.
720
+ *
721
+ * Do NOT fall back to `styleIdForText` here: a text style carries
722
+ * typography (font/size/weight/line-height) and its `fillPaints` is just
723
+ * the swatch color used for the style's preview glyphs ("Ag") — typically
724
+ * black regardless of where the style is actually applied. The text node's
725
+ * own `fillPaints` is the source of truth for color.
726
+ */
727
+ function effectiveFillPaints(node: FigNode, ctx: Ctx): Paint[] | undefined {
728
+ const style = resolveStyleNode(node.styleIdForFill, ctx);
729
+ if (style?.fillPaints?.length) return style.fillPaints;
730
+ return node.fillPaints;
731
+ }
732
+
733
+ function effectiveStrokePaints(node: FigNode, ctx: Ctx): Paint[] | undefined {
734
+ const style = resolveStyleNode(node.styleIdForStroke, ctx);
735
+ if (style?.fillPaints?.length) return style.fillPaints;
736
+ if (style?.strokePaints?.length) return style.strokePaints;
737
+ return node.strokePaints;
738
+ }
739
+
740
+ function paintToBackground(p: Paint, _node: FigNode, ctx: Ctx): string | null {
741
+ if (p.visible === false) return null;
742
+ if (p.type === "SOLID") return colorToCss(p.color, p.opacity ?? 1);
743
+ if (p.type?.startsWith("GRADIENT") && Array.isArray(p.stops)) {
744
+ const stops = p.stops
745
+ .map(
746
+ (s) =>
747
+ `${colorToCss(s.color, p.opacity ?? 1)} ${num(s.position * 100)}%`,
748
+ )
749
+ .join(", ");
750
+ if (p.type === "GRADIENT_LINEAR") return `linear-gradient(${stops})`;
751
+ if (p.type === "GRADIENT_RADIAL") return `radial-gradient(${stops})`;
752
+ if (p.type === "GRADIENT_ANGULAR") return `conic-gradient(${stops})`;
753
+ if (p.type === "GRADIENT_DIAMOND") return `radial-gradient(${stops})`;
754
+ }
755
+ if (p.type === "IMAGE") {
756
+ const hex = hashToHex(p.image?.hash);
757
+ if (hex) return `url("${imageUrl(hex, ctx)}")`;
758
+ }
759
+ return null;
760
+ }
761
+
762
+ function backgroundShorthand(
763
+ node: FigNode,
764
+ ctx: Ctx,
765
+ ): {
766
+ backgroundColor?: string;
767
+ backgroundImage?: string;
768
+ backgroundSize?: string;
769
+ backgroundPosition?: string;
770
+ backgroundRepeat?: string;
771
+ } {
772
+ const fills = (effectiveFillPaints(node, ctx) ?? []).filter(
773
+ (f) => f.visible !== false,
774
+ );
775
+ if (fills.length === 0) return {};
776
+ const result: {
777
+ backgroundColor?: string;
778
+ backgroundImage?: string;
779
+ backgroundSize?: string;
780
+ backgroundPosition?: string;
781
+ backgroundRepeat?: string;
782
+ } = {};
783
+ const bgImages: string[] = [];
784
+ for (const f of fills) {
785
+ if (f.type === "SOLID" && !result.backgroundColor) {
786
+ const c = colorToCss(f.color, f.opacity ?? 1);
787
+ if (c) result.backgroundColor = c;
788
+ continue;
789
+ }
790
+ const v = paintToBackground(f, node, ctx);
791
+ if (v) bgImages.push(v);
792
+ if (f.type === "IMAGE") {
793
+ if (f.imageScaleMode === "FILL") result.backgroundSize = "cover";
794
+ else if (f.imageScaleMode === "FIT") result.backgroundSize = "contain";
795
+ else if (f.imageScaleMode === "TILE") {
796
+ result.backgroundSize = "auto";
797
+ result.backgroundRepeat = "repeat";
798
+ } else if (f.imageScaleMode === "STRETCH")
799
+ result.backgroundSize = "100% 100%";
800
+ // Figma centers image fills by default (CSS defaults to top-left, which
801
+ // crops the wrong edges for FILL/FIT). TILE keeps the default origin so
802
+ // the tile pattern starts at top-left.
803
+ if (f.imageScaleMode !== "TILE") result.backgroundPosition = "center";
804
+ }
805
+ }
806
+ if (bgImages.length > 0) result.backgroundImage = bgImages.join(", ");
807
+ return result;
808
+ }
809
+
810
+ function borderShorthand(node: FigNode, ctx: Ctx): Record<string, string> {
811
+ const strokes = (effectiveStrokePaints(node, ctx) ?? []).filter(
812
+ (p) => p.visible !== false,
813
+ );
814
+ if (strokes.length === 0) return {};
815
+ const first = strokes[0]!;
816
+ const color = colorToCss(first.color, first.opacity ?? 1) ?? "rgb(0, 0, 0)";
817
+
818
+ const hasPerSide =
819
+ node.strokeTopWeight !== undefined ||
820
+ node.strokeRightWeight !== undefined ||
821
+ node.strokeBottomWeight !== undefined ||
822
+ node.strokeLeftWeight !== undefined;
823
+
824
+ const uniformW = node.strokeWeight ?? 0;
825
+
826
+ if (!hasPerSide) {
827
+ if (!uniformW) return {};
828
+ if (node.strokeAlign === "OUTSIDE") {
829
+ return { outline: `${num(uniformW)}px solid ${color}` };
830
+ }
831
+ if (node.strokeAlign === "INSIDE") {
832
+ // box-shadow keeps the border inside the element without expanding its dimensions
833
+ return { boxShadow: `inset 0 0 0 ${num(uniformW)}px ${color}` };
834
+ }
835
+ return { border: `${num(uniformW)}px solid ${color}` };
836
+ }
837
+
838
+ // Per-side stroke weights: fall back to uniformW for unspecified sides
839
+ const topW = node.strokeTopWeight ?? uniformW;
840
+ const rightW = node.strokeRightWeight ?? uniformW;
841
+ const bottomW = node.strokeBottomWeight ?? uniformW;
842
+ const leftW = node.strokeLeftWeight ?? uniformW;
843
+
844
+ if (!topW && !rightW && !bottomW && !leftW) return {};
845
+
846
+ const result: Record<string, string> = {};
847
+
848
+ if (node.strokeAlign === "INSIDE") {
849
+ // Use border-side + border-box so the border stays within Figma's stated dimensions.
850
+ // For absolute children this is only exact when there's no top or left border
851
+ // (the common case for Fluent UI's active bottom border).
852
+ if (topW) result.borderTop = `${num(topW)}px solid ${color}`;
853
+ if (rightW) result.borderRight = `${num(rightW)}px solid ${color}`;
854
+ if (bottomW) result.borderBottom = `${num(bottomW)}px solid ${color}`;
855
+ if (leftW) result.borderLeft = `${num(leftW)}px solid ${color}`;
856
+ result.boxSizing = "border-box";
857
+ return result;
858
+ }
859
+
860
+ if (node.strokeAlign === "OUTSIDE") {
861
+ // outline doesn't support per-side; simulate with box-shadow (no inset)
862
+ const shadows: string[] = [];
863
+ if (topW) shadows.push(`0 -${num(topW)}px 0 0 ${color}`);
864
+ if (rightW) shadows.push(`${num(rightW)}px 0 0 0 ${color}`);
865
+ if (bottomW) shadows.push(`0 ${num(bottomW)}px 0 0 ${color}`);
866
+ if (leftW) shadows.push(`-${num(leftW)}px 0 0 0 ${color}`);
867
+ return shadows.length ? { boxShadow: shadows.join(", ") } : {};
868
+ }
869
+
870
+ // CENTER: individual border-side properties
871
+ if (topW) result.borderTop = `${num(topW)}px solid ${color}`;
872
+ if (rightW) result.borderRight = `${num(rightW)}px solid ${color}`;
873
+ if (bottomW) result.borderBottom = `${num(bottomW)}px solid ${color}`;
874
+ if (leftW) result.borderLeft = `${num(leftW)}px solid ${color}`;
875
+ return result;
876
+ }
877
+
878
+ function radiusStyles(node: FigNode): Record<string, number | string> {
879
+ const out: Record<string, number | string> = {};
880
+ const corners = [
881
+ node.rectangleTopLeftCornerRadius,
882
+ node.rectangleTopRightCornerRadius,
883
+ node.rectangleBottomRightCornerRadius,
884
+ node.rectangleBottomLeftCornerRadius,
885
+ ];
886
+ const allEqual =
887
+ corners.every((c) => c === corners[0]) &&
888
+ typeof corners[0] === "number" &&
889
+ corners[0] > 0;
890
+ if (allEqual) {
891
+ out.borderRadius = `${num(corners[0])}px`;
892
+ return out;
893
+ }
894
+ if (corners.some((c) => typeof c === "number" && c > 0)) {
895
+ out.borderTopLeftRadius = `${num(corners[0] ?? 0)}px`;
896
+ out.borderTopRightRadius = `${num(corners[1] ?? 0)}px`;
897
+ out.borderBottomRightRadius = `${num(corners[2] ?? 0)}px`;
898
+ out.borderBottomLeftRadius = `${num(corners[3] ?? 0)}px`;
899
+ return out;
900
+ }
901
+ if (typeof node.cornerRadius === "number" && node.cornerRadius > 0) {
902
+ out.borderRadius = `${num(node.cornerRadius)}px`;
903
+ }
904
+ if (node.type === "ELLIPSE") out.borderRadius = "50%";
905
+ return out;
906
+ }
907
+
908
+ /**
909
+ * @param shadowAsFilter Render DROP_SHADOWs as `filter: drop-shadow()` instead
910
+ * of `box-shadow`. `box-shadow` traces the element's box, so an overflowing
911
+ * child (e.g. a tooltip's caret) is left shadowless and the box shadow cuts
912
+ * straight across behind it. `filter: drop-shadow()` follows the element's
913
+ * rendered alpha — body plus caret — at the cost of the (here unused) spread.
914
+ */
915
+ function effectStyles(
916
+ node: FigNode,
917
+ shadowAsFilter = false,
918
+ ): Record<string, string> {
919
+ const effects = node.effects?.filter((e) => e.visible !== false) ?? [];
920
+ if (effects.length === 0) return {};
921
+ const shadows: string[] = [];
922
+ const filters: string[] = [];
923
+ let backdropBlur: string | null = null;
924
+ for (const e of effects) {
925
+ if (e.type === "DROP_SHADOW") {
926
+ const c = colorToCss(e.color) ?? "rgba(0, 0, 0, 0.25)";
927
+ if (shadowAsFilter) {
928
+ filters.push(
929
+ `drop-shadow(${num(e.offset?.x ?? 0)}px ${num(e.offset?.y ?? 0)}px ${num(e.radius ?? 0)}px ${c})`,
930
+ );
931
+ } else {
932
+ shadows.push(
933
+ `${num(e.offset?.x ?? 0)}px ${num(e.offset?.y ?? 0)}px ${num(e.radius ?? 0)}px ${num(e.spread ?? 0)}px ${c}`,
934
+ );
935
+ }
936
+ } else if (e.type === "INNER_SHADOW") {
937
+ // Inner shadows have no filter equivalent; always emit as box-shadow.
938
+ const c = colorToCss(e.color) ?? "rgba(0, 0, 0, 0.25)";
939
+ shadows.push(
940
+ `inset ${num(e.offset?.x ?? 0)}px ${num(e.offset?.y ?? 0)}px ${num(e.radius ?? 0)}px ${num(e.spread ?? 0)}px ${c}`,
941
+ );
942
+ } else if (e.type === "FOREGROUND_BLUR" || e.type === "LAYER_BLUR") {
943
+ filters.push(`blur(${num(e.radius ?? 0)}px)`);
944
+ } else if (e.type === "BACKGROUND_BLUR") {
945
+ backdropBlur = `blur(${num(e.radius ?? 0)}px)`;
946
+ }
947
+ }
948
+ const out: Record<string, string> = {};
949
+ if (shadows.length) out.boxShadow = shadows.join(", ");
950
+ if (filters.length) out.filter = filters.join(" ");
951
+ if (backdropBlur) out.backdropFilter = backdropBlur;
952
+ return out;
953
+ }
954
+
955
+ function transformStyle(node: FigNode): {
956
+ transform?: string;
957
+ transformOrigin?: string;
958
+ } {
959
+ const t = node.transform;
960
+ if (!t) return {};
961
+ // Decompose: rotation = atan2(m10, m00), scale assumed 1.
962
+ const angle = Math.atan2(t.m10, t.m00);
963
+ const deg = (angle * 180) / Math.PI;
964
+ if (Math.abs(deg) < 0.01) return {};
965
+ return { transform: `rotate(${num(deg)}deg)`, transformOrigin: "top left" };
966
+ }
967
+
968
+ function autolayoutStyles(node: FigNode): Record<string, string | number> {
969
+ if (!node.stackMode || node.stackMode === "NONE") return {};
970
+ const out: Record<string, string | number> = {
971
+ display: "flex",
972
+ flexDirection: node.stackMode === "VERTICAL" ? "column" : "row",
973
+ };
974
+ if (node.stackPrimaryAlignItems)
975
+ out.justifyContent =
976
+ STACK_ALIGN[node.stackPrimaryAlignItems] ?? "flex-start";
977
+ if (node.stackCounterAlignItems)
978
+ out.alignItems = STACK_ALIGN[node.stackCounterAlignItems] ?? "flex-start";
979
+ if (typeof node.stackSpacing === "number")
980
+ out.gap = `${num(node.stackSpacing)}px`;
981
+ // Padding: prefer per-side; fall back to horizontal/vertical.
982
+ const pl = node.stackPaddingLeft ?? node.stackHorizontalPadding;
983
+ const pr = node.stackPaddingRight ?? node.stackHorizontalPadding;
984
+ const pt = node.stackPaddingTop ?? node.stackVerticalPadding;
985
+ const pb = node.stackPaddingBottom ?? node.stackVerticalPadding;
986
+ if ([pl, pr, pt, pb].some((v) => typeof v === "number" && v !== 0)) {
987
+ out.padding = `${num(pt ?? 0)}px ${num(pr ?? 0)}px ${num(pb ?? 0)}px ${num(pl ?? 0)}px`;
988
+ }
989
+ return out;
990
+ }
991
+
992
+ function textStyles(node: FigNode, ctx?: Ctx): Record<string, string | number> {
993
+ if (node.type !== "TEXT") return {};
994
+ const out: Record<string, string | number> = {};
995
+ // A TEXT node may reference a shared text style (`styleIdForText`) whose
996
+ // font properties (family, weight, size, line-height, letter-spacing,
997
+ // alignment) override the values cached on the node itself. The cached
998
+ // values are often stale snapshots of the master and don't reflect the
999
+ // current style — prefer the style node when present.
1000
+ const styleNode = ctx
1001
+ ? resolveStyleNode(node.styleIdForText, ctx)
1002
+ : undefined;
1003
+ const fontName = styleNode?.fontName ?? node.fontName;
1004
+ const fontSize =
1005
+ typeof styleNode?.fontSize === "number"
1006
+ ? styleNode.fontSize
1007
+ : node.fontSize;
1008
+ const lineHeight = styleNode?.lineHeight ?? node.lineHeight;
1009
+ const letterSpacing = styleNode?.letterSpacing ?? node.letterSpacing;
1010
+ const textAlignHorizontal =
1011
+ styleNode?.textAlignHorizontal ?? node.textAlignHorizontal;
1012
+
1013
+ if (fontName?.family) {
1014
+ // Quote families with spaces so the inline style stays valid.
1015
+ const fam = fontName.family;
1016
+ out.fontFamily = /\s/.test(fam) ? `"${fam}"` : fam;
1017
+ }
1018
+ const weight = fontWeightFromStyle(fontName?.style);
1019
+ if (weight !== null) out.fontWeight = weight;
1020
+ // Track this family/weight/italic combo so the frame template can request
1021
+ // it from Google Fonts in <head>.
1022
+ if (ctx && fontName?.family) {
1023
+ const italic = !!(fontName.style && /italic|oblique/i.test(fontName.style));
1024
+ ctx.fontUsage.add(`${fontName.family}|${weight ?? 400}|${italic ? 1 : 0}`);
1025
+ }
1026
+ if (fontName?.style && /italic|oblique/i.test(fontName.style)) {
1027
+ out.fontStyle = "italic";
1028
+ }
1029
+ if (typeof fontSize === "number") out.fontSize = `${num(fontSize)}px`;
1030
+ const lh = lengthFromUnits(lineHeight, fontSize);
1031
+ if (lh !== null && lh !== undefined) out.lineHeight = lh;
1032
+ const ls = lengthFromUnits(letterSpacing, fontSize);
1033
+ if (ls !== null && ls !== undefined) out.letterSpacing = ls;
1034
+ if (textAlignHorizontal)
1035
+ out.textAlign = TEXT_ALIGN[textAlignHorizontal] ?? "left";
1036
+ // Text color comes from the first SOLID fill paint, dereferenced through
1037
+ // any `styleIdForFill` shared style (NOT `styleIdForText`, which is
1038
+ // typography-only — see `effectiveFillPaints`).
1039
+ if (ctx) {
1040
+ const solidFill = effectiveFillPaints(node, ctx)?.find(
1041
+ (f) => f.visible !== false && f.type === "SOLID",
1042
+ );
1043
+ if (solidFill) {
1044
+ const c = colorToCss(solidFill.color, solidFill.opacity ?? 1);
1045
+ if (c) out.color = c;
1046
+ }
1047
+ }
1048
+ return out;
1049
+ }
1050
+
1051
+ function blendModeCss(mode: string | undefined): string | null {
1052
+ if (!mode || mode === "NORMAL" || mode === "PASS_THROUGH") return null;
1053
+ return mode.toLowerCase().replace(/_/g, "-");
1054
+ }
1055
+
1056
+ function isAutolayout(parent: FigNode | null): boolean {
1057
+ return !!(parent && parent.stackMode && parent.stackMode !== "NONE");
1058
+ }
1059
+
1060
+ /**
1061
+ * Compose an INSTANCE node with its inlined master's autolayout / padding /
1062
+ * sizing properties. The master is the source of truth for how children are
1063
+ * arranged; the instance's cached `stack*` fields can be a stale snapshot of
1064
+ * a previous variant. Per-axis sizing (`size`) stays on the instance — only
1065
+ * the layout description is taken from the master.
1066
+ */
1067
+ function withMasterLayout(instance: FigNode, master: FigNode): FigNode {
1068
+ const layoutFields: (keyof FigNode)[] = [
1069
+ "stackMode",
1070
+ "stackPrimaryAlignItems",
1071
+ "stackCounterAlignItems",
1072
+ "stackSpacing",
1073
+ "stackPaddingLeft",
1074
+ "stackPaddingRight",
1075
+ "stackPaddingTop",
1076
+ "stackPaddingBottom",
1077
+ "stackHorizontalPadding",
1078
+ "stackVerticalPadding",
1079
+ "stackPrimarySizing",
1080
+ "stackCounterSizing",
1081
+ ];
1082
+ const merged: FigNode = { ...instance };
1083
+ // If the master defines its own stack direction, the instance's cached
1084
+ // stack-related fields are stale (they were captured against whatever
1085
+ // variant the instance originally pointed at). Take ALL layout fields
1086
+ // from the master wholesale — including `undefined` values — so we don't
1087
+ // leak e.g. `stackPrimarySizing="FIXED"` from a HORIZONTAL variant onto a
1088
+ // VERTICAL one whose master leaves it undefined (HUG).
1089
+ const masterDrivesLayout =
1090
+ typeof master.stackMode === "string" && master.stackMode !== "NONE";
1091
+ for (const f of layoutFields) {
1092
+ const mv = (master as Record<string, unknown>)[f as string];
1093
+ if (masterDrivesLayout) {
1094
+ (merged as Record<string, unknown>)[f as string] = mv;
1095
+ } else if (mv !== undefined) {
1096
+ (merged as Record<string, unknown>)[f as string] = mv;
1097
+ }
1098
+ }
1099
+ return merged;
1100
+ }
1101
+
1102
+ /**
1103
+ * Derive the Figma plugin API's `layoutSizingHorizontal` / `layoutSizingVertical`
1104
+ * for a node. The kiwi document doesn't store these directly — they're
1105
+ * computed from the underlying stack/sizing/grow fields the same way
1106
+ * `figma.currentPage.selection[i].layoutSizingHorizontal` is.
1107
+ *
1108
+ * Returns "FIXED" | "HUG" | "FILL" per axis. The cached `node.size` always
1109
+ * carries a baked pixel value, so callers must consult the derived sizing
1110
+ * before deciding whether to emit an explicit `width`/`height`.
1111
+ */
1112
+ function layoutSizing(
1113
+ node: FigNode,
1114
+ parent: FigNode | null,
1115
+ ): {
1116
+ horizontal: "FIXED" | "HUG" | "FILL";
1117
+ vertical: "FIXED" | "HUG" | "FILL";
1118
+ } {
1119
+ let horizontal: "FIXED" | "HUG" | "FILL" = "FIXED";
1120
+ let vertical: "FIXED" | "HUG" | "FILL" = "FIXED";
1121
+
1122
+ // 1) Self auto-layout (this node has its own stack). Kiwi default for an
1123
+ // omitted `stackPrimarySizing`/`stackCounterSizing` is HUG, not FIXED.
1124
+ if (node.stackMode && node.stackMode !== "NONE") {
1125
+ // An omitted `stackPrimarySizing` is HUG (Figma writes it only when set,
1126
+ // and it's only ever written as FIXED). An omitted `stackCounterSizing`,
1127
+ // however, behaves as FIXED: Figma bakes the counter-axis size (a HUG
1128
+ // badge would collapse to its content height, but the design keeps its
1129
+ // fixed height). Treat only an explicit RESIZE_TO_FIT* as HUG.
1130
+ const primaryHug = (node.stackPrimarySizing ?? "RESIZE_TO_FIT") !== "FIXED";
1131
+ const counterHug = (node.stackCounterSizing ?? "FIXED") !== "FIXED";
1132
+ if (node.stackMode === "HORIZONTAL") {
1133
+ horizontal = primaryHug ? "HUG" : "FIXED";
1134
+ vertical = counterHug ? "HUG" : "FIXED";
1135
+ } else {
1136
+ vertical = primaryHug ? "HUG" : "FIXED";
1137
+ horizontal = counterHug ? "HUG" : "FIXED";
1138
+ }
1139
+ }
1140
+
1141
+ // 2) Non-autolayout frames can still hug content via `resizeToFit`.
1142
+ if (!node.stackMode || node.stackMode === "NONE") {
1143
+ if (node.resizeToFit) {
1144
+ horizontal = "HUG";
1145
+ vertical = "HUG";
1146
+ }
1147
+ }
1148
+
1149
+ // 3) TEXT auto-resize hugs along the indicated axis/axes.
1150
+ if (node.type === "TEXT" && node.textAutoResize) {
1151
+ if (node.textAutoResize === "WIDTH_AND_HEIGHT") {
1152
+ horizontal = "HUG";
1153
+ vertical = "HUG";
1154
+ } else if (node.textAutoResize === "HEIGHT") {
1155
+ vertical = "HUG";
1156
+ }
1157
+ }
1158
+
1159
+ // 4) Auto-layout child of an auto-layout parent: grow/stretch -> FILL.
1160
+ // A child that ignores auto-layout (stackPositioning ABSOLUTE) is not a
1161
+ // flex item, so it keeps its FIXED pixel size from `node.size`.
1162
+ if (
1163
+ parent &&
1164
+ parent.stackMode &&
1165
+ parent.stackMode !== "NONE" &&
1166
+ node.stackPositioning !== "ABSOLUTE"
1167
+ ) {
1168
+ const grow = (node.stackChildPrimaryGrow ?? 0) > 0;
1169
+ const stretch = node.stackChildAlignSelf === "STRETCH";
1170
+ if (parent.stackMode === "HORIZONTAL") {
1171
+ if (grow) horizontal = "FILL";
1172
+ if (stretch) vertical = "FILL";
1173
+ } else {
1174
+ if (grow) vertical = "FILL";
1175
+ if (stretch) horizontal = "FILL";
1176
+ }
1177
+ }
1178
+
1179
+ return { horizontal, vertical };
1180
+ }
1181
+
1182
+ /**
1183
+ * Pin an absolutely-positioned node to the edge(s) implied by its Figma
1184
+ * constraint on one axis. MIN keeps the start offset (top/left); MAX anchors
1185
+ * to the end edge (bottom/right) so the node stays put when the container is
1186
+ * taller/wider than Figma's baked size; STRETCH pins both edges and returns
1187
+ * `true` to drop the fixed size on that axis. CENTER/SCALE fall back to the
1188
+ * baked start offset. Anchoring to the end edge needs the parent's size; when
1189
+ * it's unknown we fall back to the start offset. Returns whether the axis's
1190
+ * fixed width/height should be suppressed.
1191
+ */
1192
+ function applyAxisConstraint(
1193
+ css: Record<string, unknown>,
1194
+ constraint: string | undefined,
1195
+ pos: number | null,
1196
+ nodeSize: number | null,
1197
+ parentSize: number | null,
1198
+ startProp: "left" | "top",
1199
+ endProp: "right" | "bottom",
1200
+ ): boolean {
1201
+ const endVal =
1202
+ pos !== null && nodeSize !== null && parentSize !== null
1203
+ ? parentSize - (pos + nodeSize)
1204
+ : null;
1205
+ if (constraint === "MAX" && endVal !== null) {
1206
+ css[endProp] = `${endVal}px`;
1207
+ return false;
1208
+ }
1209
+ if (constraint === "STRETCH" && endVal !== null) {
1210
+ if (pos !== null) css[startProp] = `${pos}px`;
1211
+ css[endProp] = `${endVal}px`;
1212
+ return true;
1213
+ }
1214
+ if (pos !== null) css[startProp] = `${pos}px`;
1215
+ return false;
1216
+ }
1217
+
1218
+ function buildCss(
1219
+ node: FigNode,
1220
+ parent: FigNode | null,
1221
+ ctx: Ctx,
1222
+ isPositioned: boolean,
1223
+ vectorLike = false,
1224
+ hasAbsoluteChild = false,
1225
+ shadowAsFilter = false,
1226
+ ): Record<string, unknown> {
1227
+ const css: Record<string, unknown> = {};
1228
+ // An absolutely-positioned node is out of the parent's flex flow, so it must
1229
+ // not receive flex-child hints (flex-grow / align-self) below.
1230
+ const parentFlex = !isPositioned && isAutolayout(parent);
1231
+
1232
+ // Position / size — mirrors smart-export:
1233
+ // parent is auto-layout -> position: relative, no left/top, dimensions
1234
+ // may be replaced by flex hints below.
1235
+ // parent is not -> position: absolute with left/top/width/height.
1236
+ // Constraints decide which edges an absolutely-positioned node is pinned to.
1237
+ // STRETCH pins both edges (and drops the fixed size on that axis).
1238
+ let suppressWidth = false;
1239
+ let suppressHeight = false;
1240
+ if (isPositioned) {
1241
+ css.position = "absolute";
1242
+ const x = node.transform ? num(node.transform.m02) : null;
1243
+ const y = node.transform ? num(node.transform.m12) : null;
1244
+ const nodeW = node.size ? num(node.size.x) : null;
1245
+ const nodeH = node.size ? num(node.size.y) : null;
1246
+ const parentW = parent?.size ? num(parent.size.x) : null;
1247
+ const parentH = parent?.size ? num(parent.size.y) : null;
1248
+ suppressWidth = applyAxisConstraint(
1249
+ css,
1250
+ node.horizontalConstraint,
1251
+ x,
1252
+ nodeW,
1253
+ parentW,
1254
+ "left",
1255
+ "right",
1256
+ );
1257
+ suppressHeight = applyAxisConstraint(
1258
+ css,
1259
+ node.verticalConstraint,
1260
+ y,
1261
+ nodeH,
1262
+ parentH,
1263
+ "top",
1264
+ "bottom",
1265
+ );
1266
+ } else if (parentFlex) {
1267
+ css.position = "relative";
1268
+ } else if (hasAbsoluteChild) {
1269
+ // Establish a positioning context so an "ignore auto layout" child
1270
+ // (position: absolute) is offset relative to this container rather than
1271
+ // the page. Top-level frames are otherwise statically positioned.
1272
+ css.position = "relative";
1273
+ }
1274
+
1275
+ // Decide whether to emit width/height. The Figma plugin API exposes a
1276
+ // unified `layoutSizingHorizontal`/`layoutSizingVertical` derived from the
1277
+ // raw stack/grow/textAutoResize fields (kiwi doesn't store those derived
1278
+ // values). Only emit a pixel dimension on a FIXED axis — HUG and FILL both
1279
+ // mean "let CSS size it" via flex / intrinsic content.
1280
+ const sizing = layoutSizing(node, parent);
1281
+ const emitWidth = sizing.horizontal === "FIXED";
1282
+ const emitHeight = sizing.vertical === "FIXED";
1283
+
1284
+ if (node.size) {
1285
+ const w = num(node.size.x);
1286
+ const h = num(node.size.y);
1287
+ if (w !== null && emitWidth && !suppressWidth) css.width = `${w}px`;
1288
+ if (h !== null && emitHeight && !suppressHeight) css.height = `${h}px`;
1289
+ }
1290
+
1291
+ // Auto-layout min/max size constraints. Each axis is independent and may be
1292
+ // unconstrained (null). Only emit positive values — a zero constraint is a
1293
+ // no-op and a min-width keeps a hugging container (e.g. a badge) circular.
1294
+ const minX = num(node.minSize?.value?.x);
1295
+ const minY = num(node.minSize?.value?.y);
1296
+ const maxX = num(node.maxSize?.value?.x);
1297
+ const maxY = num(node.maxSize?.value?.y);
1298
+ if (minX !== null && minX > 0) css.minWidth = `${minX}px`;
1299
+ if (minY !== null && minY > 0) css.minHeight = `${minY}px`;
1300
+ if (maxX !== null && maxX > 0) css.maxWidth = `${maxX}px`;
1301
+ if (maxY !== null && maxY > 0) css.maxHeight = `${maxY}px`;
1302
+
1303
+ // Auto-layout child hints (flex-grow / align-self). Skipped for children
1304
+ // that ignore auto-layout — they're positioned absolutely, not as flex items.
1305
+ if (parentFlex && node.stackPositioning !== "ABSOLUTE") {
1306
+ if ((node.stackChildPrimaryGrow ?? 0) > 0) {
1307
+ css.flex = "1 0 0";
1308
+ }
1309
+ if (node.stackChildAlignSelf) {
1310
+ const a = STACK_ALIGN[node.stackChildAlignSelf];
1311
+ if (a)
1312
+ css.alignSelf = node.stackChildAlignSelf === "STRETCH" ? "stretch" : a;
1313
+ else if (node.stackChildAlignSelf === "STRETCH")
1314
+ css.alignSelf = "stretch";
1315
+ }
1316
+ }
1317
+
1318
+ // Background (TEXT uses fillPaints for color, not background; vector
1319
+ // nodes paint via <path fill> inside the <svg>).
1320
+ if (node.type !== "TEXT" && !vectorLike) {
1321
+ Object.assign(css, backgroundShorthand(node, ctx));
1322
+ }
1323
+
1324
+ // Border / outline (skipped for vector nodes — strokes go on <path>).
1325
+ // Merge box-shadows from border (e.g. INSIDE strokes) and effects so neither overwrites the other.
1326
+ const borderStyle = !vectorLike ? borderShorthand(node, ctx) : {};
1327
+ const { boxShadow: borderBoxShadow, ...restBorderStyle } = borderStyle;
1328
+ Object.assign(css, restBorderStyle);
1329
+ // Radius
1330
+ Object.assign(css, radiusStyles(node));
1331
+ // Effects (shadows, blurs)
1332
+ const effectStyle = effectStyles(node, shadowAsFilter);
1333
+ const { boxShadow: effectBoxShadow, ...restEffectStyle } = effectStyle;
1334
+ Object.assign(css, restEffectStyle);
1335
+ const mergedBoxShadows = (
1336
+ [borderBoxShadow, effectBoxShadow] as Array<string | undefined>
1337
+ ).filter(Boolean);
1338
+ if (mergedBoxShadows.length > 0) css.boxShadow = mergedBoxShadows.join(", ");
1339
+ // Rotation
1340
+ Object.assign(css, transformStyle(node));
1341
+ // Text styling
1342
+ Object.assign(css, textStyles(node, ctx));
1343
+ // Autolayout (flex)
1344
+ Object.assign(css, autolayoutStyles(node));
1345
+
1346
+ // Opacity / blend mode / overflow / visibility
1347
+ if (typeof node.opacity === "number" && node.opacity < 0.999)
1348
+ css.opacity = node.opacity;
1349
+ const bm = blendModeCss(node.blendMode);
1350
+ if (bm) css.mixBlendMode = bm;
1351
+ if (
1352
+ (node.type === "FRAME" || node.type === "INSTANCE") &&
1353
+ node.frameMaskDisabled !== true
1354
+ ) {
1355
+ css.overflow = "hidden";
1356
+ }
1357
+ // (Hidden nodes are dropped entirely in emitNode; no display:none needed.)
1358
+
1359
+ return css;
1360
+ }
1361
+
1362
+ /** Render a css object as a single inline `style` declaration string. */
1363
+ function formatStyleString(css: Record<string, unknown>): string {
1364
+ return Object.entries(css)
1365
+ .map(([k, v]) => `${kebabCase(k)}: ${String(v)}`)
1366
+ .join("; ");
1367
+ }
1368
+
1369
+ interface Ctx {
1370
+ byGuid: Map<string, FigNode>;
1371
+ // Library style nodes (and other keyed nodes) indexed by their stable
1372
+ // `key` so we can resolve `styleIdForFill.assetRef.key` lookups.
1373
+ byKey: Map<string, FigNode>;
1374
+ childrenOf: Map<string, FigNode[]>;
1375
+ symbolByGuid: Map<string, FigNode>;
1376
+ // Boolean visibility vars often carry no variableSetID; this index maps mode id → owning set.
1377
+ modeToSet: Map<string, string>;
1378
+ imageRefBase?: string;
1379
+ /** Raw blob bytes (for path command decoding). Indexed by blob index. */
1380
+ blobs: Buffer[];
1381
+ /** Hex hash -> on-disk filename (e.g. `<hash>` or `<hash>.png`). */
1382
+ imageMap: Map<string, string>;
1383
+ missingImageUrl?: string;
1384
+ /**
1385
+ * Set of `family|weight|italic` triples seen while emitting the current
1386
+ * frame. We use it to build a Google Fonts <link> in <head> so the custom
1387
+ * font families used in the design are actually loaded by the browser.
1388
+ */
1389
+ fontUsage: Set<string>;
1390
+ /** SYMBOLs currently being inlined (cycle guard). */
1391
+ inliningStack: Set<string>;
1392
+ renderedNodeCount: number;
1393
+ maxRenderedNodes: number;
1394
+ maxTreeDepth: number;
1395
+ maxFrameOutputBytes: number;
1396
+ maxTotalOutputBytes: number;
1397
+ totalOutputBytes: number;
1398
+ }
1399
+
1400
+ /**
1401
+ * Figma's path-command blob format. A stream of:
1402
+ * [op:byte] [args:float32 * N]
1403
+ * Opcodes (discovered empirically and confirmed against rounded rect /
1404
+ * vector / ellipse blobs):
1405
+ * 0 = ClosePath (no args)
1406
+ * 1 = MoveTo (x, y)
1407
+ * 2 = LineTo (x, y)
1408
+ * 3 = QuadTo (x1, y1, x, y)
1409
+ * 4 = CubicTo (x1, y1, x2, y2, x, y)
1410
+ */
1411
+ function decodePathCommands(bytes: Buffer | undefined): string {
1412
+ if (!bytes || bytes.length === 0) return "";
1413
+ const out: string[] = [];
1414
+ const fmt = (n: number) => {
1415
+ if (!Number.isFinite(n)) return "0";
1416
+ const r = Math.round(n * 1000) / 1000;
1417
+ return Object.is(r, -0) ? "0" : String(r);
1418
+ };
1419
+ let i = 0;
1420
+ while (i < bytes.length) {
1421
+ const op = bytes[i]!;
1422
+ let n = 0;
1423
+ let letter = "";
1424
+ if (op === 0) {
1425
+ letter = "Z";
1426
+ n = 0;
1427
+ } else if (op === 1) {
1428
+ letter = "M";
1429
+ n = 2;
1430
+ } else if (op === 2) {
1431
+ letter = "L";
1432
+ n = 2;
1433
+ } else if (op === 3) {
1434
+ letter = "Q";
1435
+ n = 4;
1436
+ } else if (op === 4) {
1437
+ letter = "C";
1438
+ n = 6;
1439
+ } else {
1440
+ // Unknown opcode — stop decoding gracefully so we don't run off
1441
+ // the end of the buffer.
1442
+ break;
1443
+ }
1444
+ if (i + 1 + n * 4 > bytes.length) break;
1445
+ const args: string[] = [];
1446
+ for (let j = 0; j < n; j++)
1447
+ args.push(fmt(bytes.readFloatLE(i + 1 + j * 4)));
1448
+ out.push(args.length ? `${letter}${args.join(" ")}` : letter);
1449
+ i += 1 + n * 4;
1450
+ }
1451
+ return out.join(" ");
1452
+ }
1453
+
1454
+ /** SVG paint attribute (fill / stroke) for the first visible solid paint. */
1455
+ function paintToSvgFill(
1456
+ paints: Paint[] | undefined,
1457
+ ): { color: string; opacity?: number } | null {
1458
+ const p = paints?.find((x) => x.visible !== false && x.type === "SOLID");
1459
+ if (!p || !p.color) return null;
1460
+ const c = p.color;
1461
+ const r = Math.round(c.r * 255);
1462
+ const g = Math.round(c.g * 255);
1463
+ const b = Math.round(c.b * 255);
1464
+ const opacity = c.a * (p.opacity ?? 1);
1465
+ return {
1466
+ color: `rgb(${r}, ${g}, ${b})`,
1467
+ opacity: opacity < 0.999 ? Number(opacity.toFixed(3)) : undefined,
1468
+ };
1469
+ }
1470
+
1471
+ const VECTOR_LIKE_TYPES = new Set([
1472
+ "VECTOR",
1473
+ "BOOLEAN_OPERATION",
1474
+ "ELLIPSE",
1475
+ "BRUSH",
1476
+ "STAR",
1477
+ "REGULAR_POLYGON",
1478
+ "LINE",
1479
+ "VECTOR_PATH",
1480
+ ]);
1481
+
1482
+ function isVectorLike(node: FigNode): boolean {
1483
+ if (!node.type || !VECTOR_LIKE_TYPES.has(node.type)) return false;
1484
+ if (
1485
+ (node.fillGeometry?.length ?? 0) === 0 &&
1486
+ (node.strokeGeometry?.length ?? 0) === 0
1487
+ ) {
1488
+ return false;
1489
+ }
1490
+ // Nodes with an IMAGE fill render better as a regular <div> with
1491
+ // `background-image` (and `background-color` as a fallback) than as an
1492
+ // <svg> with a <pattern>. Skip the vector path so backgroundShorthand
1493
+ // can stack image + color fills via CSS.
1494
+ if (node.fillPaints?.some((p) => p.visible !== false && p.type === "IMAGE")) {
1495
+ return false;
1496
+ }
1497
+ return true;
1498
+ }
1499
+
1500
+ /**
1501
+ * Render a vector-like node as an inline `<svg>`. The element itself keeps
1502
+ * the same outer attrs (layer-name, position/size style) as a regular div
1503
+ * so it slots into auto-layout / absolute positioning identically; the
1504
+ * vector geometry lives inside as `<path>` children.
1505
+ */
1506
+ function emitSvgBody(
1507
+ node: FigNode,
1508
+ ctx: Ctx,
1509
+ indent: string,
1510
+ lines: string[],
1511
+ ): void {
1512
+ const w = node.size?.x ?? 0;
1513
+ const h = node.size?.y ?? 0;
1514
+ const fillRule =
1515
+ node.fillGeometry?.[0]?.windingRule === "ODD" ? "evenodd" : "nonzero";
1516
+ const fillPaint = paintToSvgFill(effectiveFillPaints(node, ctx));
1517
+ const strokePaint = paintToSvgFill(effectiveStrokePaints(node, ctx));
1518
+ const strokeWeight = node.strokeWeight ?? 0;
1519
+
1520
+ // Fill paths
1521
+ for (const g of node.fillGeometry ?? []) {
1522
+ if (typeof g.commandsBlob !== "number") continue;
1523
+ const d = decodePathCommands(ctx.blobs[g.commandsBlob]);
1524
+ if (!d) continue;
1525
+ const attrs = [`d="${d}"`, `fill-rule="${fillRule}"`];
1526
+ if (fillPaint) {
1527
+ attrs.push(`fill="${fillPaint.color}"`);
1528
+ if (fillPaint.opacity !== undefined)
1529
+ attrs.push(`fill-opacity="${fillPaint.opacity}"`);
1530
+ } else {
1531
+ attrs.push(`fill="none"`);
1532
+ }
1533
+ lines.push(`${indent} <path ${attrs.join(" ")} />`);
1534
+ }
1535
+ // Stroke paths
1536
+ if (strokePaint && strokeWeight > 0) {
1537
+ for (const g of node.strokeGeometry ?? node.fillGeometry ?? []) {
1538
+ if (typeof g.commandsBlob !== "number") continue;
1539
+ const d = decodePathCommands(ctx.blobs[g.commandsBlob]);
1540
+ if (!d) continue;
1541
+ const attrs = [
1542
+ `d="${d}"`,
1543
+ `fill="none"`,
1544
+ `stroke="${strokePaint.color}"`,
1545
+ `stroke-width="${num(strokeWeight)}"`,
1546
+ ];
1547
+ if (strokePaint.opacity !== undefined)
1548
+ attrs.push(`stroke-opacity="${strokePaint.opacity}"`);
1549
+ if (node.strokeJoin)
1550
+ attrs.push(`stroke-linejoin="${node.strokeJoin.toLowerCase()}"`);
1551
+ if (node.strokeCap)
1552
+ attrs.push(`stroke-linecap="${node.strokeCap.toLowerCase()}"`);
1553
+ lines.push(`${indent} <path ${attrs.join(" ")} />`);
1554
+ }
1555
+ }
1556
+ // Best-effort viewBox so the geometry scales with the element box.
1557
+ if (w > 0 && h > 0) {
1558
+ // The path coordinates are already in the node's local pixel space, so
1559
+ // viewBox = 0 0 w h works without further transforms.
1560
+ }
1561
+ }
1562
+
1563
+ function getChildren(node: FigNode, ctx: Ctx): FigNode[] {
1564
+ const kids = ctx.childrenOf.get(guidKey(node.guid)) ?? [];
1565
+ return kids.slice().sort((a, b) => {
1566
+ const pa = a.parentIndex?.position ?? "";
1567
+ const pb = b.parentIndex?.position ?? "";
1568
+ return pa < pb ? -1 : pa > pb ? 1 : 0;
1569
+ });
1570
+ }
1571
+
1572
+ function buildAttrs(
1573
+ node: FigNode,
1574
+ parent: FigNode | null,
1575
+ ctx: Ctx,
1576
+ isPositioned: boolean,
1577
+ componentSymbol: FigNode | null,
1578
+ vectorLike = false,
1579
+ hasAbsoluteChild = false,
1580
+ shadowAsFilter = false,
1581
+ ): string[] {
1582
+ const attrs: string[] = [];
1583
+
1584
+ // layer-name: emit whenever the node has a name at all (matches the
1585
+ // figma-plugin's smart-export, which always carries the layer name when
1586
+ // present).
1587
+ if (node.name) attrs.push(`layer-name="${escapeHtmlAttr(node.name)}"`);
1588
+
1589
+ // Component metadata: pulled from the SYMBOL master that an INSTANCE renders,
1590
+ // or from the SYMBOL itself when emitting a master directly.
1591
+ const symbolForMeta =
1592
+ componentSymbol ??
1593
+ (node.type === "SYMBOL" || node.type === "INSTANCE" ? node : null);
1594
+ if (symbolForMeta && symbolForMeta.type === "SYMBOL") {
1595
+ const { base, variant } = resolveComponentIdentity(symbolForMeta, ctx);
1596
+ if (base) attrs.push(`data-component-name="${escapeHtmlAttr(base)}"`);
1597
+ if (variant) attrs.push(`data-variant-name="${escapeHtmlAttr(variant)}"`);
1598
+ // Expose individual variant key/value pairs as parsed JSON so consumers
1599
+ // can read e.g. `Style=Action` directly without re-parsing the variant
1600
+ // string. Mirrors how the figma-plugin surfaces variant props.
1601
+ if (variant && /=/.test(variant)) {
1602
+ const variantProps: Record<string, string> = {};
1603
+ for (const pair of variant.split(/,\s*/)) {
1604
+ const [key, val] = pair.split("=");
1605
+ if (key && val !== undefined) variantProps[key.trim()] = val.trim();
1606
+ }
1607
+ if (Object.keys(variantProps).length > 0) {
1608
+ const json = JSON.stringify(variantProps).replace(/'/g, "&#39;");
1609
+ attrs.push(`data-variant-props='${json}'`);
1610
+ }
1611
+ }
1612
+ if (symbolForMeta.componentKey)
1613
+ attrs.push(
1614
+ `data-component-key="${escapeHtmlAttr(symbolForMeta.componentKey)}"`,
1615
+ );
1616
+ const desc = htmlToPlain(symbolForMeta.description);
1617
+ if (desc)
1618
+ attrs.push(`data-component-description="${escapeHtmlAttr(desc)}"`);
1619
+ const links = extractDocLinks(symbolForMeta.description);
1620
+ if (links.length > 0)
1621
+ attrs.push(`data-component-doc-link="${escapeHtmlAttr(links[0]!)}"`);
1622
+ if (links.length > 1)
1623
+ attrs.push(
1624
+ `data-component-doc-links="${escapeHtmlAttr(links.join(" | "))}"`,
1625
+ );
1626
+ const propDefNames = (symbolForMeta.componentPropDefs ?? [])
1627
+ .map((p) => p.name)
1628
+ .filter(Boolean) as string[];
1629
+ if (propDefNames.length > 0)
1630
+ attrs.push(
1631
+ `data-component-props="${escapeHtmlAttr(propDefNames.join(", "))}"`,
1632
+ );
1633
+ }
1634
+
1635
+ // `props`: a stringified JSON object of the raw Figma component props on
1636
+ // this node. Includes the prop definitions on a SYMBOL/INSTANCE and the
1637
+ // assignments/refs that override them.
1638
+ const rawProps = collectRawProps(node, componentSymbol);
1639
+ if (rawProps) {
1640
+ // Use single-quoted attribute value so the inner JSON's double quotes
1641
+ // stay readable (no `&quot;` noise). Escape stray single quotes inside
1642
+ // the JSON for safety.
1643
+ const json = JSON.stringify(rawProps).replace(/'/g, "&#39;");
1644
+ attrs.push(`props='${json}'`);
1645
+ }
1646
+
1647
+ // Per-node annotations (Figma's annotation feature).
1648
+ if (Array.isArray(node.annotations) && node.annotations.length > 0) {
1649
+ const labels = node.annotations
1650
+ .map((a) => htmlToPlain(a.labelV2 || a.label))
1651
+ .filter(Boolean);
1652
+ if (labels.length > 0)
1653
+ attrs.push(`data-annotations="${escapeHtmlAttr(labels.join(" | "))}"`);
1654
+ }
1655
+
1656
+ const css = buildCss(
1657
+ node,
1658
+ parent,
1659
+ ctx,
1660
+ isPositioned,
1661
+ vectorLike,
1662
+ hasAbsoluteChild,
1663
+ shadowAsFilter,
1664
+ );
1665
+ if (Object.keys(css).length > 0) {
1666
+ attrs.push(`style="${escapeHtmlAttr(formatStyleString(css))}"`);
1667
+ }
1668
+ return attrs;
1669
+ }
1670
+
1671
+ // Prefer published key (stable across documents) so consumers and the mode→set index agree.
1672
+ function canonicalSetId(setNode: FigNode | undefined): string | null {
1673
+ if (!setNode) return null;
1674
+ if (setNode.key) return `key:${setNode.key}`;
1675
+ if (setNode.guid) return `guid:${guidKey(setNode.guid)}`;
1676
+ return null;
1677
+ }
1678
+
1679
+ // Resolves through the actual set node so the result matches canonicalSetId regardless of reference form.
1680
+ function refSetId(ref: VariableSetRef | undefined, ctx: Ctx): string | null {
1681
+ const setNode = ref?.assetRef?.key
1682
+ ? ctx.byKey.get(ref.assetRef.key)
1683
+ : ref?.guid
1684
+ ? ctx.byGuid.get(guidKey(ref.guid))
1685
+ : undefined;
1686
+ const canonical = canonicalSetId(setNode);
1687
+ if (canonical) return canonical;
1688
+ if (ref?.assetRef?.key) return `key:${ref.assetRef.key}`;
1689
+ if (ref?.guid) return `guid:${guidKey(ref.guid)}`;
1690
+ return null;
1691
+ }
1692
+
1693
+ function lookupVarNode(
1694
+ alias: VariableValue["alias"],
1695
+ ctx: Ctx,
1696
+ ): FigNode | undefined {
1697
+ if (alias?.guid) return ctx.byGuid.get(guidKey(alias.guid));
1698
+ if (alias?.assetRef?.key) return ctx.byKey.get(alias.assetRef.key);
1699
+ return undefined;
1700
+ }
1701
+
1702
+ // Boolean vars often carry no variableSetID; owning set is recovered via ctx.modeToSet.
1703
+ // Falls back to the first declared value when no active mode applies.
1704
+ function resolveVarBool(
1705
+ v: FigNode | undefined,
1706
+ varModes: Map<string, string>,
1707
+ ctx: Ctx,
1708
+ seen: Set<string>,
1709
+ ): boolean {
1710
+ if (!v) return false;
1711
+ const id = guidKey(v.guid);
1712
+ if (seen.has(id)) return false;
1713
+ seen.add(id);
1714
+ const entries = v.variableDataValues?.entries ?? [];
1715
+ if (entries.length === 0) return false;
1716
+ const setId = ctx.modeToSet.get(guidKey(entries[0]?.modeID));
1717
+ const wantMode = setId ? varModes.get(setId) : undefined;
1718
+ const entry =
1719
+ (wantMode && entries.find((e) => guidKey(e.modeID) === wantMode)) ||
1720
+ entries[0];
1721
+ const val = entry?.variableData?.value;
1722
+ if (!val) return false;
1723
+ if (typeof val.boolValue === "boolean") return val.boolValue;
1724
+ if (val.alias) {
1725
+ return resolveVarBool(lookupVarNode(val.alias, ctx), varModes, ctx, seen);
1726
+ }
1727
+ return false;
1728
+ }
1729
+
1730
+ // Variant props (e.g. "Arrow position") are stored in symbolOverrides, not just variableModeBySetMap.
1731
+ function collectInstanceVarModes(node: FigNode, ctx: Ctx): Map<string, string> {
1732
+ const out = new Map<string, string>();
1733
+ const apply = (
1734
+ entries:
1735
+ | Array<{ variableSetID?: VariableSetRef; variableModeID?: Guid }>
1736
+ | undefined,
1737
+ ) => {
1738
+ for (const e of entries ?? []) {
1739
+ const sid = refSetId(e.variableSetID, ctx);
1740
+ if (sid && e.variableModeID) out.set(sid, guidKey(e.variableModeID));
1741
+ }
1742
+ };
1743
+ apply(node.variableModeBySetMap?.entries);
1744
+ for (const o of node.symbolData?.symbolOverrides ?? []) {
1745
+ apply(o.variableModeBySetMap?.entries);
1746
+ }
1747
+ return out;
1748
+ }
1749
+
1750
+ // Returns undefined when no VISIBLE binding exists (caller falls back to literal `visible`).
1751
+ // Masters hide all variant layers by default; the active mode enables exactly one.
1752
+ function resolveBoundVisibility(
1753
+ node: FigNode,
1754
+ varModes: Map<string, string>,
1755
+ ctx: Ctx,
1756
+ ): boolean | undefined {
1757
+ const entry = node.variableConsumptionMap?.entries?.find(
1758
+ (e) => e.variableField === "VISIBLE",
1759
+ );
1760
+ const val = entry?.variableData?.value;
1761
+ if (!val) return undefined;
1762
+ const expr = val.expressionValue;
1763
+ if (expr?.expressionFunction === "IS_TRUTHY") {
1764
+ const arg = expr.expressionArguments?.[0]?.value;
1765
+ if (arg?.alias) {
1766
+ return resolveVarBool(
1767
+ lookupVarNode(arg.alias, ctx),
1768
+ varModes,
1769
+ ctx,
1770
+ new Set(),
1771
+ );
1772
+ }
1773
+ return undefined;
1774
+ }
1775
+ if (val.alias) {
1776
+ return resolveVarBool(
1777
+ lookupVarNode(val.alias, ctx),
1778
+ varModes,
1779
+ ctx,
1780
+ new Set(),
1781
+ );
1782
+ }
1783
+ return undefined;
1784
+ }
1785
+
1786
+ function emitNode(
1787
+ node: FigNode,
1788
+ parent: FigNode | null,
1789
+ ctx: Ctx,
1790
+ depth: number,
1791
+ parentIsFlex: boolean,
1792
+ lines: string[],
1793
+ propEnv: Map<string, ResolvedPropValue> = new Map(),
1794
+ /**
1795
+ * Stack of active symbol-override scopes contributed by enclosing
1796
+ * INSTANCEs. Each layer's keys are descendant guidPaths RELATIVE to where
1797
+ * that instance was entered (matching what Figma stores in
1798
+ * `symbolOverrides[].guidPath` and `derivedSymbolData[].guidPath`).
1799
+ * Lookup uses `instancePath.slice(layer.startIndex)` plus the current
1800
+ * node's overrideKey as the leaf segment.
1801
+ *
1802
+ * Outer layers stay active across nested inner instances so that deep
1803
+ * overrides like `[outerInstanceKey, innerNodeKey]` still match.
1804
+ */
1805
+ overrideLayers: OverrideLayer[] = [],
1806
+ /**
1807
+ * Stack of INSTANCE overrideKeys we've descended INTO (i.e., crossed the
1808
+ * instance->master boundary). Plain frame/group nesting does NOT grow this
1809
+ * path. Used together with `overrideLayers` to look up `symbolOverrides` /
1810
+ * `derivedSymbolData` entries that target a descendant by library guidPath.
1811
+ */
1812
+ instancePath: string[] = [],
1813
+ /** Active variable mode per set (set id → mode guid) inherited from enclosing INSTANCEs. */
1814
+ varModes: Map<string, string> = new Map(),
1815
+ ): void {
1816
+ if (depth > ctx.maxTreeDepth) {
1817
+ throw new Error(".fig render tree is nested too deeply.");
1818
+ }
1819
+ ctx.renderedNodeCount += 1;
1820
+ if (ctx.renderedNodeCount > ctx.maxRenderedNodes) {
1821
+ throw new Error(".fig render exceeded its expanded-node budget.");
1822
+ }
1823
+ // Match smart-export: skip invisible nodes entirely. Variable bindings override the literal flag —
1824
+ // masters hide all variant layers by default and the active mode turns one on.
1825
+ const boundVisible = resolveBoundVisibility(node, varModes, ctx);
1826
+ if (boundVisible === false) return;
1827
+ if (boundVisible === undefined && node.visible === false) return;
1828
+
1829
+ // Apply enclosing-instance symbol overrides (variant swap, text override,
1830
+ // visibility flip) targeted at this node by guidPath.
1831
+ const overridden = applyOverrideLayers(node, overrideLayers, instancePath);
1832
+ if (overridden === null) return;
1833
+ node = overridden;
1834
+
1835
+ // Apply parent-instance prop overrides for this node (text/symbol/swap,
1836
+ // visibility). May hide the node entirely or rewrite its textData /
1837
+ // symbolData before we resolve the inlined symbol below.
1838
+ const patched = applyPropRefs(node, propEnv);
1839
+ if (patched === null) return;
1840
+ node = patched;
1841
+
1842
+ const indent = " ".repeat(depth);
1843
+
1844
+ // INSTANCE: inline the master SYMBOL's children inside this element so the
1845
+ // implementation is self-contained. Cycle guard: don't recursively inline a
1846
+ // SYMBOL that's already being inlined further up the chain.
1847
+ let inlinedSymbol: FigNode | null = null;
1848
+ if (node.type === "INSTANCE" && node.symbolData?.symbolID) {
1849
+ const symKey = guidKey(node.symbolData.symbolID);
1850
+ if (!ctx.inliningStack.has(symKey)) {
1851
+ const sym = ctx.symbolByGuid.get(symKey);
1852
+ if (sym) inlinedSymbol = sym;
1853
+ }
1854
+ }
1855
+
1856
+ // When entering an INSTANCE, extend the prop env with its assignments so
1857
+ // descendants (whether the instance's own children or the inlined SYMBOL's
1858
+ // children) see the override values. Likewise build a fresh
1859
+ // symbolOverrides map (overrides scope to a single instance), and reset
1860
+ // the current path so descendant guidPaths are evaluated against the new
1861
+ // master.
1862
+ const childPropEnv =
1863
+ node.type === "INSTANCE" ? buildPropEnv(node, propEnv) : propEnv;
1864
+ // When entering an INSTANCE that will inline a master, descendants live
1865
+ // one level deeper in the instance-path. Push the new override layer with
1866
+ // startIndex pointing at that future depth so its keys (relative paths
1867
+ // inside this instance's master) are evaluated against an empty prefix at
1868
+ // the master's first level. Outer layers stay active so deeper overrides
1869
+ // from enclosing instances still apply across nested boundaries.
1870
+ const childInstancePath =
1871
+ node.type === "INSTANCE" && inlinedSymbol
1872
+ ? [...instancePath, guidKey(node.overrideKey ?? node.guid)]
1873
+ : instancePath;
1874
+ let childOverrideLayers = overrideLayers;
1875
+ if (node.type === "INSTANCE") {
1876
+ const map = buildSymbolOverrideLayer(node);
1877
+ if (map.size > 0) {
1878
+ childOverrideLayers = [
1879
+ ...overrideLayers,
1880
+ { startIndex: childInstancePath.length, map },
1881
+ ];
1882
+ }
1883
+ }
1884
+ // Layer this instance's variant prop modes over inherited ones before descending into the master.
1885
+ let childVarModes = varModes;
1886
+ if (node.type === "INSTANCE") {
1887
+ const added = collectInstanceVarModes(node, ctx);
1888
+ if (added.size > 0) {
1889
+ childVarModes = new Map(varModes);
1890
+ for (const [k, v] of added) childVarModes.set(k, v);
1891
+ }
1892
+ }
1893
+
1894
+ // A node is rendered as an SVG when it has its own vector geometry, OR
1895
+ // when it's an INSTANCE of a SYMBOL whose root is itself a vector (e.g.
1896
+ // single-shape icon components). For the latter we paint the master's
1897
+ // geometry inside the instance element so the icon actually shows up
1898
+ // instead of an empty div.
1899
+ const selfVector = isVectorLike(node);
1900
+ const symbolVector = !!inlinedSymbol && isVectorLike(inlinedSymbol);
1901
+ const vectorLike = selfVector || symbolVector;
1902
+ const vectorSourceNode = selfVector
1903
+ ? node
1904
+ : symbolVector
1905
+ ? inlinedSymbol!
1906
+ : node;
1907
+ const tag = vectorLike ? "svg" : tagFor(node.type);
1908
+ // Children of a flex (autolayout) parent flow normally; otherwise absolute.
1909
+ // A child can opt out of the stack with `stackPositioning: "ABSOLUTE"`
1910
+ // (e.g. a tooltip's caret that overlaps the body): it ignores its parent's
1911
+ // auto-layout and is positioned by its own transform even inside a flex
1912
+ // parent (Figma's "ignore auto layout").
1913
+ const isPositioned = !parentIsFlex || node.stackPositioning === "ABSOLUTE";
1914
+
1915
+ // For INSTANCE nodes with an inlined master, the autolayout / padding /
1916
+ // sizing properties cached on the instance reflect the *previous* master
1917
+ // and become stale after a variant swap. Use the master's values for the
1918
+ // instance's own container styling so the rendered layout matches the
1919
+ // currently-resolved variant.
1920
+ const layoutNode = inlinedSymbol
1921
+ ? withMasterLayout(node, inlinedSymbol)
1922
+ : node;
1923
+ // If any rendered child ignores auto-layout (position: absolute), this
1924
+ // container must establish a positioning context so the child is offset
1925
+ // relative to it. Check the actually-rendered children (the inlined
1926
+ // master's, for an INSTANCE).
1927
+ const childSource = inlinedSymbol ?? node;
1928
+ const hasAbsoluteChild = (
1929
+ ctx.childrenOf.get(guidKey(childSource.guid)) ?? []
1930
+ ).some((c) => c.stackPositioning === "ABSOLUTE");
1931
+ // A container whose drop shadow must wrap an overflowing absolute child
1932
+ // (e.g. a tooltip caret) needs `filter: drop-shadow()` rather than
1933
+ // `box-shadow`, which would only trace the body's box. Children render from
1934
+ // the inlined master for an INSTANCE.
1935
+ const shadowAsFilter = getChildren(inlinedSymbol ?? node, ctx).some(
1936
+ (c) => c.stackPositioning === "ABSOLUTE" && c.visible !== false,
1937
+ );
1938
+ const attrs = buildAttrs(
1939
+ layoutNode,
1940
+ parent,
1941
+ ctx,
1942
+ isPositioned,
1943
+ inlinedSymbol,
1944
+ vectorLike,
1945
+ hasAbsoluteChild,
1946
+ shadowAsFilter,
1947
+ );
1948
+ if (vectorLike) {
1949
+ // viewBox prefers the geometry source node's intrinsic size so the
1950
+ // SVG draws correctly when the instance is scaled differently from
1951
+ // the master.
1952
+ const vw = vectorSourceNode.size?.x ?? node.size?.x ?? 0;
1953
+ const vh = vectorSourceNode.size?.y ?? node.size?.y ?? 0;
1954
+ if (vw > 0 && vh > 0) {
1955
+ attrs.push(`viewBox="0 0 ${num(vw)} ${num(vh)}"`);
1956
+ }
1957
+ attrs.push(`xmlns="http://www.w3.org/2000/svg"`);
1958
+ attrs.push(`fill="none"`);
1959
+ }
1960
+
1961
+ const isFlex = layoutNode.stackMode && layoutNode.stackMode !== "NONE";
1962
+
1963
+ // Single HTML comment above the element with component name + description
1964
+ // + doc links, when present. (Same metadata is also on data-* attrs.)
1965
+ const symbolForMeta = inlinedSymbol ?? (node.type === "SYMBOL" ? node : null);
1966
+ if (symbolForMeta) {
1967
+ const desc = htmlToPlain(symbolForMeta.description);
1968
+ const links = extractDocLinks(symbolForMeta.description);
1969
+ if (desc || links.length > 0) {
1970
+ const parts = [
1971
+ `Component: ${(symbolForMeta.name ?? "<unnamed>").replace(/--/g, "\u2013")}`,
1972
+ ];
1973
+ // HTML comments must not contain "--" — replace any with an en-dash.
1974
+ if (desc) parts.push(desc.replace(/--/g, "\u2013"));
1975
+ if (links.length > 0) parts.push(`docs: ${links.join(", ")}`);
1976
+ lines.push(`${indent}<!-- ${parts.join(" \u2014 ")} -->`);
1977
+ }
1978
+ }
1979
+
1980
+ if (vectorLike) {
1981
+ emitOpenWithChildren(tag, attrs, indent, lines);
1982
+ emitSvgBody(vectorSourceNode, ctx, indent, lines);
1983
+ lines.push(`${indent}</${tag}>`);
1984
+ return;
1985
+ }
1986
+
1987
+ if (node.type === "TEXT") {
1988
+ const chars = node.textData?.characters ?? "";
1989
+ if (chars.length === 0) {
1990
+ emitOpenWithChildren(tag, attrs, indent, lines);
1991
+ lines.push(`${indent}</${tag}>`);
1992
+ return;
1993
+ }
1994
+ emitOpenWithChildren(tag, attrs, indent, lines);
1995
+ // Preserve newlines in the source by splitting into <br>-separated lines
1996
+ // (HTML otherwise collapses whitespace).
1997
+ const escaped = escapeHtmlText(chars).replace(/\n/g, "<br>");
1998
+ lines.push(`${indent} ${escaped}`);
1999
+ lines.push(`${indent}</${tag}>`);
2000
+ return;
2001
+ }
2002
+
2003
+ // Pick which children to render: the inlined SYMBOL's, or the node's own.
2004
+ let children: FigNode[];
2005
+ let symKeyForCycle: string | null = null;
2006
+ if (inlinedSymbol) {
2007
+ symKeyForCycle = guidKey(inlinedSymbol.guid);
2008
+ ctx.inliningStack.add(symKeyForCycle);
2009
+ children = getChildren(inlinedSymbol, ctx);
2010
+ } else {
2011
+ children = getChildren(node, ctx);
2012
+ }
2013
+
2014
+ try {
2015
+ if (children.length === 0) {
2016
+ emitOpenWithChildren(tag, attrs, indent, lines);
2017
+ lines.push(`${indent}</${tag}>`);
2018
+ return;
2019
+ }
2020
+ emitOpenWithChildren(tag, attrs, indent, lines);
2021
+ // When inlining a SYMBOL, its child positions are relative to the SYMBOL's
2022
+ // own frame, which now coincides with this INSTANCE's frame. So they keep
2023
+ // their original transforms.
2024
+ const childParentIsFlex = inlinedSymbol
2025
+ ? !!(inlinedSymbol.stackMode && inlinedSymbol.stackMode !== "NONE")
2026
+ : !!isFlex;
2027
+ const childParentNode = inlinedSymbol ?? node;
2028
+ for (const child of children) {
2029
+ emitNode(
2030
+ child,
2031
+ childParentNode,
2032
+ ctx,
2033
+ depth + 1,
2034
+ childParentIsFlex,
2035
+ lines,
2036
+ childPropEnv,
2037
+ childOverrideLayers,
2038
+ childInstancePath,
2039
+ childVarModes,
2040
+ );
2041
+ }
2042
+ lines.push(`${indent}</${tag}>`);
2043
+ } finally {
2044
+ if (symKeyForCycle) ctx.inliningStack.delete(symKeyForCycle);
2045
+ }
2046
+ }
2047
+
2048
+ function emitOpenWithChildren(
2049
+ tag: string,
2050
+ attrs: string[],
2051
+ indent: string,
2052
+ lines: string[],
2053
+ ): void {
2054
+ if (attrs.length === 0) {
2055
+ lines.push(`${indent}<${tag}>`);
2056
+ return;
2057
+ }
2058
+ // Single-line for short attribute lists; multi-line otherwise.
2059
+ const oneLine = `${indent}<${tag} ${attrs.join(" ")}>`;
2060
+ if (attrs.length <= 2 && oneLine.length <= 200) {
2061
+ lines.push(oneLine);
2062
+ return;
2063
+ }
2064
+ lines.push(`${indent}<${tag}`);
2065
+ for (const a of attrs) lines.push(`${indent} ${a}`);
2066
+ lines.push(`${indent}>`);
2067
+ }
2068
+
2069
+ /**
2070
+ * Build a Google Fonts CSS2 URL from the set of font family/weight/italic
2071
+ * combos collected while emitting a frame. Returns null when no fonts are
2072
+ * recorded.
2073
+ */
2074
+ function buildGoogleFontsUrl(fontUsage: Set<string>): string | null {
2075
+ if (fontUsage.size === 0) return null;
2076
+ const byFamily = new Map<
2077
+ string,
2078
+ Array<{ weight: number; italic: boolean }>
2079
+ >();
2080
+ for (const entry of fontUsage) {
2081
+ const [family, weightStr, italicStr] = entry.split("|");
2082
+ if (!family) continue;
2083
+ const weight = Number(weightStr) || 400;
2084
+ const italic = italicStr === "1";
2085
+ if (!byFamily.has(family)) byFamily.set(family, []);
2086
+ byFamily.get(family)!.push({ weight, italic });
2087
+ }
2088
+ const families: string[] = [];
2089
+ for (const [family, variants] of byFamily) {
2090
+ const hasItalic = variants.some((v) => v.italic);
2091
+ const weights = Array.from(new Set(variants.map((v) => v.weight))).sort(
2092
+ (a, b) => a - b,
2093
+ );
2094
+ const famParam = family.replace(/\s+/g, "+");
2095
+ if (hasItalic) {
2096
+ const tuples = variants
2097
+ .map((v) => `${v.italic ? 1 : 0},${v.weight}`)
2098
+ .sort();
2099
+ families.push(
2100
+ `family=${famParam}:ital,wght@${Array.from(new Set(tuples)).join(";")}`,
2101
+ );
2102
+ } else {
2103
+ families.push(`family=${famParam}:wght@${weights.join(";")}`);
2104
+ }
2105
+ }
2106
+ return `https://fonts.googleapis.com/css2?${families.join("&")}&display=swap`;
2107
+ }
2108
+
2109
+ function emitFrameTemplate(frame: FigNode, ctx: Ctx, pageName: string): string {
2110
+ // Reset per-frame font usage; emitNode populates it via textStyles.
2111
+ ctx.fontUsage.clear();
2112
+ const bodyLines: string[] = new BudgetedLines(ctx.maxFrameOutputBytes);
2113
+ emitNode(frame, null, ctx, 1, true, bodyLines, new Map(), [], []);
2114
+
2115
+ const lines: string[] = [];
2116
+ lines.push("<!doctype html>");
2117
+ lines.push(
2118
+ `<!-- Auto-generated from Figma. Frame: ${frame.name ?? "<unnamed>"} (page: ${pageName}) -->`,
2119
+ );
2120
+ lines.push("<html>");
2121
+ lines.push("<head>");
2122
+ lines.push(' <meta charset="utf-8">');
2123
+ lines.push(
2124
+ ` <title>${escapeHtmlText(`${pageName} \u2014 ${frame.name ?? "frame"}`)}</title>`,
2125
+ );
2126
+ // Figma sizes are border-box (stroke INSIDE; size includes padding + border).
2127
+ // Default CSS content-box would inflate every explicit width/height/min-size
2128
+ // by the padding + border, so normalize to border-box.
2129
+ lines.push(
2130
+ " <style>*, *::before, *::after { box-sizing: border-box; }</style>",
2131
+ );
2132
+ // Custom font families used by the frame -> request them from Google
2133
+ // Fonts. (Smart-export does the same for design hand-off so the layout
2134
+ // renders with the intended typography.)
2135
+ const fontsUrl = buildGoogleFontsUrl(ctx.fontUsage);
2136
+ if (fontsUrl) {
2137
+ lines.push(' <link rel="preconnect" href="https://fonts.googleapis.com">');
2138
+ lines.push(
2139
+ ' <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',
2140
+ );
2141
+ lines.push(` <link rel="stylesheet" href="${escapeHtmlAttr(fontsUrl)}">`);
2142
+ }
2143
+ lines.push("</head>");
2144
+ lines.push("<body>");
2145
+ for (const l of bodyLines) lines.push(l);
2146
+ lines.push("</body>");
2147
+ lines.push("</html>");
2148
+ lines.push("");
2149
+ return lines.join("\n");
2150
+ }
2151
+
2152
+ class BudgetedLines extends Array<string> {
2153
+ private bytes = 0;
2154
+
2155
+ constructor(private readonly maxBytes: number) {
2156
+ super();
2157
+ }
2158
+
2159
+ override push(...items: string[]): number {
2160
+ for (const item of items) {
2161
+ this.bytes += Buffer.byteLength(item, "utf8") + 1;
2162
+ if (this.bytes > this.maxBytes) {
2163
+ throw new Error(".fig frame exceeded its render output budget.");
2164
+ }
2165
+ }
2166
+ return super.push(...items);
2167
+ }
2168
+ }
2169
+
2170
+ export interface RenderedFrame {
2171
+ pageName: string;
2172
+ pageDirName: string;
2173
+ frameName: string;
2174
+ /** Sanitized + de-duplicated filename including the `.html` extension. */
2175
+ fileName: string;
2176
+ /** Path relative to the render root, e.g. `page-1/login.html`. */
2177
+ relativePath: string;
2178
+ html: string;
2179
+ width?: number;
2180
+ height?: number;
2181
+ }
2182
+
2183
+ export interface RenderHtmlResult {
2184
+ pageCount: number;
2185
+ frameCount: number;
2186
+ frames: RenderedFrame[];
2187
+ }
2188
+
2189
+ export interface RenderHtmlOptions {
2190
+ /** Optional prefix for image url() references (default: "../images") */
2191
+ imageRefBase?: string;
2192
+ /** Pre-built `hash -> filename` map for image references. */
2193
+ imageMap?: Map<string, string>;
2194
+ /** Safe URL used when an embedded image was omitted (for example no storage provider). */
2195
+ missingImageUrl?: string;
2196
+ /*** Optional set of page (CANVAS) and/or frame GUID keys */
2197
+ selection?: Set<string>;
2198
+ maxFrames?: number;
2199
+ maxRenderedNodes?: number;
2200
+ maxTreeDepth?: number;
2201
+ maxFrameOutputBytes?: number;
2202
+ maxTotalOutputBytes?: number;
2203
+ }
2204
+
2205
+ const DEFAULT_MAX_RENDER_FRAMES = 200;
2206
+ const DEFAULT_MAX_RENDERED_NODES = 250_000;
2207
+ const DEFAULT_MAX_TREE_DEPTH = 256;
2208
+ const DEFAULT_MAX_FRAME_OUTPUT_BYTES = 4 * 1024 * 1024;
2209
+ const DEFAULT_MAX_TOTAL_OUTPUT_BYTES = 24 * 1024 * 1024;
2210
+
2211
+ const TOP_LEVEL_RENDERABLE_TYPES = new Set(["FRAME", "SYMBOL", "INSTANCE"]);
2212
+
2213
+ /**
2214
+ * Collect the renderable top-level units on a page. Figma allows SECTION
2215
+ * nodes (and nested sections) to wrap frames; sections are organizational
2216
+ * containers, not standalone designs, so we recurse THROUGH them and
2217
+ * collect the frames inside. Anything that isn't a SECTION or a
2218
+ * renderable type is ignored. Children are returned in document order
2219
+ * (depth-first across sections).
2220
+ */
2221
+ export function collectTopLevelFrames(
2222
+ parent: FigNode,
2223
+ childrenOf: Map<string, FigNode[]>,
2224
+ ): FigNode[] {
2225
+ const sortChildren = (kids: FigNode[]): FigNode[] =>
2226
+ kids.slice().sort((a, b) => {
2227
+ const pa = a.parentIndex?.position ?? "";
2228
+ const pb = b.parentIndex?.position ?? "";
2229
+ return pa < pb ? -1 : pa > pb ? 1 : 0;
2230
+ });
2231
+ const out: FigNode[] = [];
2232
+ const visitedSections = new Set<string>();
2233
+ const stack = sortChildren(childrenOf.get(guidKey(parent.guid)) ?? [])
2234
+ .reverse()
2235
+ .map((node) => ({ node, depth: 1 }));
2236
+ let visited = 0;
2237
+ while (stack.length > 0) {
2238
+ const { node, depth } = stack.pop()!;
2239
+ visited += 1;
2240
+ if (visited > DEFAULT_MAX_RENDERED_NODES) {
2241
+ throw new Error(".fig section traversal exceeded its node budget.");
2242
+ }
2243
+ if (depth > DEFAULT_MAX_TREE_DEPTH) {
2244
+ throw new Error(".fig section tree is nested too deeply.");
2245
+ }
2246
+ if (!node.type || node.visible === false) continue;
2247
+ if (node.type === "SECTION") {
2248
+ const key = guidKey(node.guid);
2249
+ if (visitedSections.has(key)) {
2250
+ throw new Error(".fig section tree contains a cycle.");
2251
+ }
2252
+ visitedSections.add(key);
2253
+ const children = sortChildren(childrenOf.get(key) ?? []);
2254
+ for (let index = children.length - 1; index >= 0; index -= 1) {
2255
+ stack.push({ node: children[index]!, depth: depth + 1 });
2256
+ }
2257
+ continue;
2258
+ }
2259
+ if (TOP_LEVEL_RENDERABLE_TYPES.has(node.type)) out.push(node);
2260
+ }
2261
+ return out;
2262
+ }
2263
+ // Maps a Figma `variableField` (on a node's variableConsumptionMap entry) to
2264
+ // the literal FigNode field it overrides. Only layout-affecting numeric fields
2265
+ // are listed — colors/text tokens are resolved elsewhere or left as baked.
2266
+ const VARIABLE_FIELD_TO_PROP: Record<string, keyof FigNode> = {
2267
+ STACK_PADDING_LEFT: "stackPaddingLeft",
2268
+ STACK_PADDING_RIGHT: "stackPaddingRight",
2269
+ STACK_PADDING_TOP: "stackPaddingTop",
2270
+ STACK_PADDING_BOTTOM: "stackPaddingBottom",
2271
+ STACK_HORIZONTAL_PADDING: "stackHorizontalPadding",
2272
+ STACK_VERTICAL_PADDING: "stackVerticalPadding",
2273
+ STACK_SPACING: "stackSpacing",
2274
+ RECTANGLE_TOP_LEFT_CORNER_RADIUS: "rectangleTopLeftCornerRadius",
2275
+ RECTANGLE_TOP_RIGHT_CORNER_RADIUS: "rectangleTopRightCornerRadius",
2276
+ RECTANGLE_BOTTOM_LEFT_CORNER_RADIUS: "rectangleBottomLeftCornerRadius",
2277
+ RECTANGLE_BOTTOM_RIGHT_CORNER_RADIUS: "rectangleBottomRightCornerRadius",
2278
+ CORNER_RADIUS: "cornerRadius",
2279
+ BORDER_TOP_WEIGHT: "strokeTopWeight",
2280
+ BORDER_BOTTOM_WEIGHT: "strokeBottomWeight",
2281
+ BORDER_LEFT_WEIGHT: "strokeLeftWeight",
2282
+ BORDER_RIGHT_WEIGHT: "strokeRightWeight",
2283
+ STROKE_WEIGHT: "strokeWeight",
2284
+ };
2285
+
2286
+ /**
2287
+ * Rewrites bound design-token variables into literal layout fields (padding, corner radius,
2288
+ * spacing, border weight) so the renderer doesn't need to know about variables.
2289
+ *
2290
+ * Figma bakes a literal alongside each binding, but the literal can be stale (e.g. the mode
2291
+ * changed after the node was created). We overwrite a present literal only when the active mode
2292
+ * was found explicitly on the node or an ancestor — the collection default is NOT recoverable
2293
+ * from the document, so when no explicit mode exists we leave the baked value alone. A missing
2294
+ * literal is always filled.
2295
+ *
2296
+ * Local variables with a unique published counterpart by name are redirected to the published
2297
+ * one; Figma drops stale local copies on paste and this matches what renders in isolation.
2298
+ *
2299
+ * Mutates nodes in place; unresolvable bindings leave the literal untouched.
2300
+ */
2301
+ function resolveVariableBindings(
2302
+ nodes: FigNode[],
2303
+ byGuid: Map<string, FigNode>,
2304
+ byKey: Map<string, FigNode>,
2305
+ ): void {
2306
+ // Published variables indexed by name. A name shared by multiple published
2307
+ // variables is ambiguous (stored as null) and never used for redirection.
2308
+ const publishedByName = new Map<string, FigNode | null>();
2309
+ for (const n of nodes) {
2310
+ if (n.type !== "VARIABLE" || !n.key || !n.name) continue;
2311
+ publishedByName.set(n.name, publishedByName.has(n.name) ? null : n);
2312
+ }
2313
+
2314
+ const setIdOf = (ref: VariableSetRef | undefined): string | null => {
2315
+ if (ref?.assetRef?.key) return `key:${ref.assetRef.key}`;
2316
+ if (ref?.guid) return `guid:${guidKey(ref.guid)}`;
2317
+ return null;
2318
+ };
2319
+ const lookupVar = (alias: VariableValue["alias"]): FigNode | undefined => {
2320
+ const direct = alias?.guid
2321
+ ? byGuid.get(guidKey(alias.guid))
2322
+ : alias?.assetRef?.key
2323
+ ? byKey.get(alias.assetRef.key)
2324
+ : undefined;
2325
+ // Redirect a stale local variable to its unique published counterpart.
2326
+ if (direct && !direct.key && direct.name) {
2327
+ const published = publishedByName.get(direct.name);
2328
+ if (published) return published;
2329
+ }
2330
+ return direct;
2331
+ };
2332
+ const lookupSet = (ref: VariableSetRef | undefined): FigNode | undefined => {
2333
+ if (ref?.assetRef?.key) return byKey.get(ref.assetRef.key);
2334
+ if (ref?.guid) return byGuid.get(guidKey(ref.guid));
2335
+ return undefined;
2336
+ };
2337
+
2338
+ // Active mode for a variable's owning set. `explicit` is true when the mode
2339
+ // came from a `variableModeBySetMap` entry on the consumer or an ancestor;
2340
+ // false when we fell back to the set's first declared mode (a guess).
2341
+ const activeModeForSet = (
2342
+ consumer: FigNode,
2343
+ setId: string,
2344
+ ): { mode: string | null; explicit: boolean } => {
2345
+ let cur: FigNode | undefined = consumer;
2346
+ let depth = 0;
2347
+ while (cur && depth < 60) {
2348
+ for (const e of cur.variableModeBySetMap?.entries ?? []) {
2349
+ if (setIdOf(e.variableSetID) === setId) {
2350
+ return { mode: guidKey(e.variableModeID), explicit: true };
2351
+ }
2352
+ }
2353
+ cur = byGuid.get(guidKey(cur.parentIndex?.guid));
2354
+ depth++;
2355
+ }
2356
+ return { mode: null, explicit: false };
2357
+ };
2358
+
2359
+ // Resolve the alias chain to a number, tracking whether every mode choice
2360
+ // was made with confidence (explicit override, or an unambiguous single-mode
2361
+ // set) so a present literal can be safely overwritten.
2362
+ const resolve = (
2363
+ value: VariableValue | undefined,
2364
+ consumer: FigNode,
2365
+ seen: Set<string>,
2366
+ ): { value: number | null; confident: boolean } => {
2367
+ if (value == null) return { value: null, confident: true };
2368
+ if (value.alias) {
2369
+ const v = lookupVar(value.alias);
2370
+ if (!v) return { value: null, confident: true };
2371
+ const id = guidKey(v.guid);
2372
+ if (seen.has(id)) return { value: null, confident: true };
2373
+ seen.add(id);
2374
+ const setId = setIdOf(v.variableSetID);
2375
+ const entries = v.variableDataValues?.entries ?? [];
2376
+ const singleMode = entries.length <= 1;
2377
+ const { mode, explicit } = setId
2378
+ ? activeModeForSet(consumer, setId)
2379
+ : { mode: null, explicit: false };
2380
+ const fallbackMode = guidKey(
2381
+ lookupSet(v.variableSetID)?.variableSetModes?.[0]?.id,
2382
+ );
2383
+ const wantMode = mode ?? fallbackMode;
2384
+ const entry =
2385
+ entries.find((e) => guidKey(e.modeID) === wantMode) ?? entries[0];
2386
+ const next = resolve(entry?.variableData?.value, consumer, seen);
2387
+ return {
2388
+ value: next.value,
2389
+ confident: next.confident && (explicit || singleMode),
2390
+ };
2391
+ }
2392
+ for (const k of Object.keys(value)) {
2393
+ if (typeof value[k] === "number") {
2394
+ return { value: value[k] as number, confident: true };
2395
+ }
2396
+ }
2397
+ return { value: null, confident: true };
2398
+ };
2399
+
2400
+ for (const node of nodes) {
2401
+ const entries = node.variableConsumptionMap?.entries;
2402
+ if (!entries?.length) continue;
2403
+ for (const entry of entries) {
2404
+ const field = entry.variableField;
2405
+ if (!field) continue;
2406
+ const prop = VARIABLE_FIELD_TO_PROP[field];
2407
+ if (!prop) continue;
2408
+ const { value, confident } = resolve(
2409
+ entry.variableData?.value,
2410
+ node,
2411
+ new Set(),
2412
+ );
2413
+ if (value === null) continue;
2414
+ const hasLiteral = (node as Record<string, unknown>)[prop] !== undefined;
2415
+ if (!hasLiteral || confident) {
2416
+ (node as Record<string, unknown>)[prop] = value;
2417
+ }
2418
+ }
2419
+ }
2420
+ }
2421
+
2422
+ export function renderHtmlTemplates(
2423
+ document: unknown,
2424
+ options: RenderHtmlOptions = {},
2425
+ ): RenderHtmlResult {
2426
+ const doc = document as {
2427
+ nodeChanges?: FigNode[];
2428
+ blobs?: Array<{ bytes?: string | Buffer | Uint8Array }>;
2429
+ };
2430
+ const nodes = doc.nodeChanges ?? [];
2431
+
2432
+ // Decode blob bytes once. The kiwi document JSON-serializes blob bytes as
2433
+ // hex strings; Buffer / Uint8Array values may also appear depending on how
2434
+ // the caller decoded the document.
2435
+ const blobs: Buffer[] = (doc.blobs ?? []).map((b) => {
2436
+ const v = b?.bytes;
2437
+ if (!v) return Buffer.alloc(0);
2438
+ if (Buffer.isBuffer(v)) return v;
2439
+ if (v instanceof Uint8Array) return Buffer.from(v);
2440
+ if (typeof v === "string") return Buffer.from(v, "hex");
2441
+ return Buffer.alloc(0);
2442
+ });
2443
+
2444
+ const byGuid = new Map<string, FigNode>();
2445
+ const byKey = new Map<string, FigNode>();
2446
+ const childrenOf = new Map<string, FigNode[]>();
2447
+ const symbolByGuid = new Map<string, FigNode>();
2448
+ const modeToSet = new Map<string, string>();
2449
+ for (const n of nodes) {
2450
+ byGuid.set(guidKey(n.guid), n);
2451
+ if (n.key) byKey.set(n.key, n);
2452
+ if (n.type === "SYMBOL") {
2453
+ symbolByGuid.set(guidKey(n.guid), n);
2454
+ }
2455
+ if (n.type === "VARIABLE_SET") {
2456
+ const sid = canonicalSetId(n);
2457
+ if (sid) {
2458
+ for (const m of n.variableSetModes ?? []) {
2459
+ if (m.id) modeToSet.set(guidKey(m.id), sid);
2460
+ }
2461
+ }
2462
+ }
2463
+ const pk = guidKey(n.parentIndex?.guid);
2464
+ if (!pk) continue;
2465
+ let arr = childrenOf.get(pk);
2466
+ if (!arr) {
2467
+ arr = [];
2468
+ childrenOf.set(pk, arr);
2469
+ }
2470
+ arr.push(n);
2471
+ }
2472
+
2473
+ // Bake variable-bound layout values (padding/radius/spacing/border) into the
2474
+ // literal fields the renderer reads, before any rendering or master/instance
2475
+ // composition consults them.
2476
+ resolveVariableBindings(nodes, byGuid, byKey);
2477
+
2478
+ const ctx: Ctx = {
2479
+ byGuid,
2480
+ byKey,
2481
+ childrenOf,
2482
+ symbolByGuid,
2483
+ modeToSet,
2484
+ imageRefBase: options.imageRefBase,
2485
+ blobs,
2486
+ imageMap: options.imageMap ?? new Map<string, string>(),
2487
+ missingImageUrl: options.missingImageUrl,
2488
+ fontUsage: new Set(),
2489
+ inliningStack: new Set(),
2490
+ renderedNodeCount: 0,
2491
+ maxRenderedNodes: options.maxRenderedNodes ?? DEFAULT_MAX_RENDERED_NODES,
2492
+ maxTreeDepth: options.maxTreeDepth ?? DEFAULT_MAX_TREE_DEPTH,
2493
+ maxFrameOutputBytes:
2494
+ options.maxFrameOutputBytes ?? DEFAULT_MAX_FRAME_OUTPUT_BYTES,
2495
+ maxTotalOutputBytes:
2496
+ options.maxTotalOutputBytes ?? DEFAULT_MAX_TOTAL_OUTPUT_BYTES,
2497
+ totalOutputBytes: 0,
2498
+ };
2499
+
2500
+ const documentNode = nodes.find((n) => n.type === "DOCUMENT");
2501
+ if (!documentNode) return { pageCount: 0, frameCount: 0, frames: [] };
2502
+
2503
+ const allPages = (childrenOf.get(guidKey(documentNode.guid)) ?? []).filter(
2504
+ (n) => n.type === "CANVAS" && !n.internalOnly,
2505
+ );
2506
+
2507
+ const selection =
2508
+ options.selection && options.selection.size > 0 ? options.selection : null;
2509
+
2510
+ const pages = selection
2511
+ ? allPages.filter((page) => {
2512
+ if (selection.has(guidKey(page.guid))) return true;
2513
+ const children = childrenOf.get(guidKey(page.guid)) ?? [];
2514
+ return children.some((c) => selection.has(guidKey(c.guid)));
2515
+ })
2516
+ : allPages;
2517
+
2518
+ const frames: RenderedFrame[] = [];
2519
+ for (let pageIdx = 0; pageIdx < pages.length; pageIdx++) {
2520
+ const page = pages[pageIdx]!;
2521
+ const pageDirName = sanitizeFilename(page.name, `page-${pageIdx + 1}`);
2522
+ const pageSelected = selection?.has(guidKey(page.guid)) ?? false;
2523
+ const pageFrames = collectTopLevelFrames(page, ctx.childrenOf).filter(
2524
+ (c) => {
2525
+ if (!selection || pageSelected) return true;
2526
+ return selection.has(guidKey(c.guid));
2527
+ },
2528
+ );
2529
+ if (
2530
+ frames.length + pageFrames.length >
2531
+ (options.maxFrames ?? DEFAULT_MAX_RENDER_FRAMES)
2532
+ ) {
2533
+ throw new Error(".fig document has too many top-level frames.");
2534
+ }
2535
+
2536
+ const seen = new Map<string, number>();
2537
+ for (let frameIdx = 0; frameIdx < pageFrames.length; frameIdx++) {
2538
+ const frame = pageFrames[frameIdx]!;
2539
+ const baseFile = sanitizeFilename(frame.name, `frame-${frameIdx + 1}`);
2540
+ const dupeIdx = seen.get(baseFile) ?? 0;
2541
+ seen.set(baseFile, dupeIdx + 1);
2542
+ const fileName =
2543
+ dupeIdx === 0 ? `${baseFile}.html` : `${baseFile}-${dupeIdx + 1}.html`;
2544
+ const pageName = page.name ?? `page-${pageIdx + 1}`;
2545
+ const html = emitFrameTemplate(frame, ctx, pageName);
2546
+ ctx.totalOutputBytes += Buffer.byteLength(html, "utf8");
2547
+ if (ctx.totalOutputBytes > ctx.maxTotalOutputBytes) {
2548
+ throw new Error(".fig render exceeded its total output budget.");
2549
+ }
2550
+ frames.push({
2551
+ pageName,
2552
+ pageDirName,
2553
+ frameName: frame.name ?? `frame-${frameIdx + 1}`,
2554
+ fileName,
2555
+ relativePath: path.posix.join(pageDirName, fileName),
2556
+ html,
2557
+ width: frame.size?.x,
2558
+ height: frame.size?.y,
2559
+ });
2560
+ }
2561
+ }
2562
+
2563
+ return {
2564
+ pageCount: pages.length,
2565
+ frameCount: frames.length,
2566
+ frames,
2567
+ };
2568
+ }