@agent-native/core 0.80.2 → 0.80.5

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 (322) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +66 -2
  3. package/corpus/core/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  4. package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -1
  5. package/corpus/core/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  6. package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  8. package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -1
  9. package/corpus/core/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  10. package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -1
  11. package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -1
  12. package/corpus/core/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  13. package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -1
  14. package/corpus/core/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  15. package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -1
  16. package/corpus/core/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  17. package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -1
  18. package/corpus/core/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  19. package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -1
  20. package/corpus/core/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  21. package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -1
  22. package/corpus/core/docs/content/real-time-collaboration.mdx +2 -2
  23. package/corpus/core/docs/content/template-design.mdx +1 -1
  24. package/corpus/core/package.json +3 -7
  25. package/corpus/core/src/action.ts +32 -0
  26. package/corpus/core/src/agent/durable-background.ts +32 -11
  27. package/corpus/core/src/agent/production-agent.ts +14 -1
  28. package/corpus/core/src/agent/run-loop-with-resume.ts +3 -1
  29. package/corpus/core/src/brand-kit/fig/index.ts +17 -37
  30. package/corpus/core/src/cli/index.ts +1 -1
  31. package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
  32. package/corpus/core/src/cli/plan-local.ts +445 -108
  33. package/corpus/core/src/cli/skills.ts +32 -8
  34. package/corpus/core/src/client/AssistantChat.tsx +11 -1
  35. package/corpus/core/src/client/agent-chat.ts +12 -1
  36. package/corpus/core/src/client/composer/PromptComposer.tsx +100 -41
  37. package/corpus/core/src/client/org/OrgSwitcher.tsx +1 -1
  38. package/corpus/core/src/client/sharing/ShareButton.tsx +3 -27
  39. package/corpus/core/src/collab/presence.ts +1 -1
  40. package/corpus/core/src/mcp/connect-route.ts +34 -5
  41. package/corpus/core/src/server/action-discovery.ts +4 -0
  42. package/corpus/core/src/server/action-routes.ts +14 -0
  43. package/corpus/core/src/server/agent-chat-plugin.ts +20 -0
  44. package/corpus/core/src/vite/client.ts +15 -1
  45. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
  46. package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
  47. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  48. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
  49. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
  51. package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
  52. package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
  53. package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
  54. package/corpus/templates/assets/actions/generate-image.ts +3 -0
  55. package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
  56. package/corpus/templates/assets/netlify.toml +3 -3
  57. package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
  58. package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
  59. package/corpus/templates/clips/app/components/player/timestamped-comment-button.tsx +162 -0
  60. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
  61. package/corpus/templates/clips/app/i18n/ar-SA.ts +4 -0
  62. package/corpus/templates/clips/app/i18n/de-DE.ts +4 -0
  63. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  64. package/corpus/templates/clips/app/i18n/es-ES.ts +4 -0
  65. package/corpus/templates/clips/app/i18n/fr-FR.ts +4 -0
  66. package/corpus/templates/clips/app/i18n/hi-IN.ts +4 -0
  67. package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -0
  68. package/corpus/templates/clips/app/i18n/ko-KR.ts +4 -0
  69. package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -0
  70. package/corpus/templates/clips/app/i18n/zh-CN.ts +4 -0
  71. package/corpus/templates/clips/app/i18n/zh-TW.ts +4 -0
  72. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +42 -18
  73. package/corpus/templates/content/AGENTS.md +12 -0
  74. package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
  75. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
  76. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
  77. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
  78. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
  79. package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
  80. package/corpus/templates/content/app/global.css +9 -0
  81. package/corpus/templates/content/app/i18n/zh-TW.ts +12 -0
  82. package/corpus/templates/content/app/i18n-data.ts +140 -0
  83. package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
  84. package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
  85. package/corpus/templates/content/shared/builder-mdx.ts +141 -4
  86. package/corpus/templates/content/shared/nfm.ts +62 -0
  87. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
  88. package/corpus/templates/design/AGENTS.md +5 -0
  89. package/corpus/templates/design/_gitignore +7 -0
  90. package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
  91. package/corpus/templates/design/actions/create-design-system.ts +15 -4
  92. package/corpus/templates/design/actions/create-file.ts +20 -1
  93. package/corpus/templates/design/actions/delete-design-system.ts +2 -2
  94. package/corpus/templates/design/actions/duplicate-design.ts +35 -9
  95. package/corpus/templates/design/actions/generate-design.ts +146 -69
  96. package/corpus/templates/design/actions/generate-screens.ts +51 -19
  97. package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
  98. package/corpus/templates/design/actions/get-design.ts +2 -0
  99. package/corpus/templates/design/actions/import-design-project.ts +28 -9
  100. package/corpus/templates/design/actions/import-document.ts +22 -8
  101. package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
  102. package/corpus/templates/design/actions/navigate.ts +105 -54
  103. package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
  104. package/corpus/templates/design/actions/show-design-questions.ts +2 -0
  105. package/corpus/templates/design/actions/update-design.ts +2 -1
  106. package/corpus/templates/design/actions/view-screen.ts +12 -6
  107. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
  108. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
  109. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
  110. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
  111. package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
  112. package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
  113. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
  114. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
  115. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  116. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
  117. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
  118. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
  119. package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
  120. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
  121. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
  122. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
  123. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
  124. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
  125. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
  126. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
  127. package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
  128. package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
  129. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
  130. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
  131. package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
  132. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  133. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
  134. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
  135. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
  136. package/corpus/templates/design/app/global.css +4 -0
  137. package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
  138. package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
  139. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
  140. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  141. package/corpus/templates/design/app/i18n-data.ts +527 -0
  142. package/corpus/templates/design/app/lib/design-systems.ts +6 -4
  143. package/corpus/templates/design/app/lib/design-templates.ts +15 -3
  144. package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
  145. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
  146. package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
  147. package/corpus/templates/design/app/root.tsx +42 -9
  148. package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
  149. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
  150. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
  151. package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
  152. package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
  153. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
  154. package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
  155. package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  156. package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
  157. package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
  158. package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
  159. package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
  160. package/corpus/templates/design/e2e/README.md +71 -0
  161. package/corpus/templates/design/e2e/global-setup.ts +157 -0
  162. package/corpus/templates/design/e2e/helpers.ts +148 -0
  163. package/corpus/templates/design/netlify.toml +3 -4
  164. package/corpus/templates/design/package.json +5 -1
  165. package/corpus/templates/design/playwright.config.ts +51 -0
  166. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
  167. package/corpus/templates/design/server/handlers/uploads.ts +89 -38
  168. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
  169. package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
  170. package/corpus/templates/design/server/lib/design-export.ts +35 -8
  171. package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
  172. package/corpus/templates/design/server/plugins/auth.ts +10 -1
  173. package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  174. package/corpus/templates/design/shared/api.ts +2 -0
  175. package/corpus/templates/design/shared/apply-edits.ts +12 -8
  176. package/corpus/templates/design/shared/canvas-math.ts +19 -1
  177. package/corpus/templates/design/shared/code-layer.ts +87 -28
  178. package/corpus/templates/design/shared/generation-session.ts +1 -0
  179. package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
  180. package/corpus/templates/design/shared/shader-presets.ts +10 -0
  181. package/corpus/templates/design/shared/source-mode.ts +9 -0
  182. package/corpus/templates/design/vitest.config.ts +2 -1
  183. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  184. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
  185. package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +14 -5
  186. package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +14 -5
  187. package/corpus/templates/plan/AGENTS.md +1 -1
  188. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  189. package/corpus/templates/plan/actions/validate-local-plan-source.ts +110 -0
  190. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
  191. package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
  192. package/corpus/templates/plan/server/lib/plan-connector-catalog.ts +1 -0
  193. package/corpus/templates/plan/server/lib/public-action-paths.ts +1 -0
  194. package/corpus/templates/plan/server/plan-content.ts +1 -1
  195. package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
  196. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
  197. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
  198. package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
  199. package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
  200. package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
  201. package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  202. package/corpus/templates/slides/netlify.toml +3 -6
  203. package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
  204. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
  205. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
  206. package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  207. package/dist/action.d.ts +23 -0
  208. package/dist/action.d.ts.map +1 -1
  209. package/dist/action.js +9 -0
  210. package/dist/action.js.map +1 -1
  211. package/dist/agent/durable-background.d.ts +9 -7
  212. package/dist/agent/durable-background.d.ts.map +1 -1
  213. package/dist/agent/durable-background.js +27 -11
  214. package/dist/agent/durable-background.js.map +1 -1
  215. package/dist/agent/production-agent.d.ts +10 -0
  216. package/dist/agent/production-agent.d.ts.map +1 -1
  217. package/dist/agent/production-agent.js +4 -1
  218. package/dist/agent/production-agent.js.map +1 -1
  219. package/dist/agent/run-loop-with-resume.d.ts +2 -1
  220. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  221. package/dist/agent/run-loop-with-resume.js +2 -2
  222. package/dist/agent/run-loop-with-resume.js.map +1 -1
  223. package/dist/brand-kit/fig/index.d.ts +4 -4
  224. package/dist/brand-kit/fig/index.d.ts.map +1 -1
  225. package/dist/brand-kit/fig/index.js +14 -27
  226. package/dist/brand-kit/fig/index.js.map +1 -1
  227. package/dist/cli/index.js +1 -1
  228. package/dist/cli/index.js.map +1 -1
  229. package/dist/cli/mcp-config-writers.d.ts +15 -7
  230. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  231. package/dist/cli/mcp-config-writers.js +198 -45
  232. package/dist/cli/mcp-config-writers.js.map +1 -1
  233. package/dist/cli/plan-local.d.ts +30 -0
  234. package/dist/cli/plan-local.d.ts.map +1 -1
  235. package/dist/cli/plan-local.js +281 -56
  236. package/dist/cli/plan-local.js.map +1 -1
  237. package/dist/cli/skills.d.ts +2 -2
  238. package/dist/cli/skills.d.ts.map +1 -1
  239. package/dist/cli/skills.js +32 -8
  240. package/dist/cli/skills.js.map +1 -1
  241. package/dist/client/AssistantChat.d.ts.map +1 -1
  242. package/dist/client/AssistantChat.js +11 -1
  243. package/dist/client/AssistantChat.js.map +1 -1
  244. package/dist/client/agent-chat.d.ts.map +1 -1
  245. package/dist/client/agent-chat.js +15 -2
  246. package/dist/client/agent-chat.js.map +1 -1
  247. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  248. package/dist/client/composer/PromptComposer.js +35 -1
  249. package/dist/client/composer/PromptComposer.js.map +1 -1
  250. package/dist/client/org/OrgSwitcher.js +1 -1
  251. package/dist/client/org/OrgSwitcher.js.map +1 -1
  252. package/dist/client/sharing/ShareButton.d.ts +1 -1
  253. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  254. package/dist/client/sharing/ShareButton.js +2 -15
  255. package/dist/client/sharing/ShareButton.js.map +1 -1
  256. package/dist/collab/presence.d.ts +1 -1
  257. package/dist/collab/presence.js +1 -1
  258. package/dist/collab/presence.js.map +1 -1
  259. package/dist/collab/routes.d.ts +1 -1
  260. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  261. package/dist/mcp/connect-route.d.ts.map +1 -1
  262. package/dist/mcp/connect-route.js +34 -5
  263. package/dist/mcp/connect-route.js.map +1 -1
  264. package/dist/observability/routes.d.ts +2 -2
  265. package/dist/progress/routes.d.ts +1 -1
  266. package/dist/resources/handlers.d.ts +1 -1
  267. package/dist/server/action-discovery.d.ts.map +1 -1
  268. package/dist/server/action-discovery.js +5 -0
  269. package/dist/server/action-discovery.js.map +1 -1
  270. package/dist/server/action-routes.d.ts.map +1 -1
  271. package/dist/server/action-routes.js +14 -0
  272. package/dist/server/action-routes.js.map +1 -1
  273. package/dist/server/agent-chat-plugin.d.ts +6 -0
  274. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  275. package/dist/server/agent-chat-plugin.js +12 -3
  276. package/dist/server/agent-chat-plugin.js.map +1 -1
  277. package/dist/vite/client.d.ts.map +1 -1
  278. package/dist/vite/client.js +12 -1
  279. package/dist/vite/client.js.map +1 -1
  280. package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  281. package/docs/content/locales/ar-SA/template-design.mdx +1 -1
  282. package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  283. package/docs/content/locales/de-DE/template-design.mdx +1 -1
  284. package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  285. package/docs/content/locales/es-ES/template-design.mdx +1 -1
  286. package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  287. package/docs/content/locales/fr-FR/template-design.mdx +1 -1
  288. package/docs/content/locales/hi-IN/template-design.mdx +1 -1
  289. package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  290. package/docs/content/locales/ja-JP/template-design.mdx +1 -1
  291. package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  292. package/docs/content/locales/ko-KR/template-design.mdx +1 -1
  293. package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  294. package/docs/content/locales/pt-BR/template-design.mdx +1 -1
  295. package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  296. package/docs/content/locales/zh-CN/template-design.mdx +1 -1
  297. package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  298. package/docs/content/locales/zh-TW/template-design.mdx +1 -1
  299. package/docs/content/real-time-collaboration.mdx +2 -2
  300. package/docs/content/template-design.mdx +1 -1
  301. package/package.json +3 -7
  302. package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
  303. package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
  304. package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
  305. package/corpus/templates/design/actions/import-figma.ts +0 -55
  306. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
  307. package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
  308. package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
  309. package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
  310. package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
  311. package/dist/brand-kit/fig/decode.d.ts +0 -33
  312. package/dist/brand-kit/fig/decode.d.ts.map +0 -1
  313. package/dist/brand-kit/fig/decode.js +0 -358
  314. package/dist/brand-kit/fig/decode.js.map +0 -1
  315. package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
  316. package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
  317. package/dist/brand-kit/fig/extract-design-system.js +0 -752
  318. package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
  319. package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
  320. package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
  321. package/dist/brand-kit/fig/fig-to-html.js +0 -1506
  322. package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
@@ -18,9 +18,11 @@
18
18
  * GUARDRAIL: when `isAgentChatDurableBackgroundEnabled()` returns false, the
19
19
  * agent-chat handler must behave byte-for-byte like the current synchronous
20
20
  * path. The gate is true only when ALL of these hold:
21
- * 1. `AGENT_CHAT_DURABLE_BACKGROUND` env is explicitly enabled. It is
22
- * DEFAULT-OFF (opt-in): unset/empty/unknown counts as disabled; set it to a
23
- * truthy value (`true`/`1`/`yes`/`on`) to opt a specific app in.
21
+ * 1. `AGENT_CHAT_DURABLE_BACKGROUND` env is explicitly enabled, or a
22
+ * workspace app's agent-chat plugin opts in with `durableBackgroundRuns`
23
+ * where the workspace deploy emits a per-app background function by
24
+ * default. Single-template Netlify deploys must set the env flag because
25
+ * that same flag controls whether `server-agent-background` is emitted.
24
26
  * 2. The runtime is hosted/serverless (local dev keeps the inline path so SSE
25
27
  * stays a single live stream and no second function is needed).
26
28
  * 3. `A2A_SECRET` is configured (the HMAC handoff is required to authenticate
@@ -259,17 +261,36 @@ function isFlagEnabled(): boolean {
259
261
  );
260
262
  }
261
263
 
264
+ function isFlagExplicitlyDisabled(): boolean {
265
+ const raw = process.env.AGENT_CHAT_DURABLE_BACKGROUND;
266
+ if (raw == null) return false;
267
+ const normalized = raw.trim().toLowerCase();
268
+ return (
269
+ normalized === "0" ||
270
+ normalized === "false" ||
271
+ normalized === "no" ||
272
+ normalized === "off"
273
+ );
274
+ }
275
+
262
276
  /**
263
- * The single gate. True when the flag is explicitly enabled (opt-in/default-off)
264
- * AND the runtime is hosted AND A2A_SECRET is configured. False otherwise and
265
- * false means the current synchronous behavior is used, unchanged. So a local /
266
- * non-hosted / unconfigured app stays synchronous, and an app that has not opted
267
- * in stays synchronous; durable only engages where it is explicitly enabled and
268
- * the runtime actually supports it.
277
+ * The single gate. True when the env flag is explicitly enabled, or a workspace
278
+ * app opted in and has a per-app background-function target, AND the runtime is
279
+ * hosted AND A2A_SECRET is configured. False otherwise and false means the
280
+ * current synchronous behavior is used unchanged. Single-template Netlify app
281
+ * opt-ins deliberately require the env flag too because that flag controls
282
+ * whether the `server-agent-background` function exists in the deploy output.
269
283
  */
270
- export function isAgentChatDurableBackgroundEnabled(): boolean {
284
+ export function isAgentChatDurableBackgroundEnabled(options?: {
285
+ appOptIn?: boolean;
286
+ }): boolean {
287
+ const envOptIn = isFlagEnabled();
288
+ const workspaceAppOptIn =
289
+ options?.appOptIn === true &&
290
+ !isFlagExplicitlyDisabled() &&
291
+ resolveWorkspaceBackgroundFunctionUrlPath() !== null;
271
292
  return (
272
- isFlagEnabled() &&
293
+ (envOptIn || workspaceAppOptIn) &&
273
294
  isHostedRuntimeForDurableBackground() &&
274
295
  hasConfiguredA2ASecret()
275
296
  );
@@ -534,6 +534,9 @@ export interface ActionEntry {
534
534
  * Defaults to true; false lets safe metadata/read actions run with
535
535
  * `ctx.userEmail` undefined when auth resolution returns 401/403. */
536
536
  requiresAuth?: boolean;
537
+ /** Max HTTP request body in bytes; the route 413s on `Content-Length` before
538
+ * parsing. For public, no-auth POST actions. */
539
+ maxBodyBytes?: number;
537
540
  /** Whether the action is exposed to the agent as a callable tool. Only an
538
541
  * explicit `false` hides it from every agent tool surface (in-app assistant,
539
542
  * MCP, A2A, job/trigger runners) while leaving it frontend/HTTP-callable.
@@ -888,6 +891,13 @@ export interface ProductionAgentOptions {
888
891
  * timeout. When reached, the client receives an internal auto-continuation
889
892
  * signal instead of a user-facing warning. */
890
893
  runSoftTimeoutMs?: number;
894
+ /**
895
+ * Opt this app into durable Netlify background-function agent-chat runs. This
896
+ * is a runtime opt-in layered on top of the hosted-runtime + A2A_SECRET gates;
897
+ * single-template Netlify deploys must also enable the deploy-time
898
+ * `AGENT_CHAT_DURABLE_BACKGROUND` flag so the background function is emitted.
899
+ */
900
+ durableBackgroundRuns?: boolean;
891
901
  /** Called when a run starts, with the send function for emitting events and the threadId */
892
902
  onRunStart?: (
893
903
  send: (event: AgentChatEvent) => void,
@@ -3991,7 +4001,10 @@ export function createProductionAgentHandler(
3991
4001
  // The foreground POST decides whether to dispatch into a background
3992
4002
  // function. The background worker itself never re-dispatches.
3993
4003
  const dispatchToBackground =
3994
- !isBackgroundWorker && isAgentChatDurableBackgroundEnabled();
4004
+ !isBackgroundWorker &&
4005
+ isAgentChatDurableBackgroundEnabled({
4006
+ appOptIn: options.durableBackgroundRuns === true,
4007
+ });
3995
4008
  const requestBrowserTabId = normalizeBrowserTabId(browserTabId);
3996
4009
  const requestChatScope = normalizeChatScope(scope);
3997
4010
  const requestRunCtx = ensureRequestRunContext();
@@ -29,6 +29,7 @@ import {
29
29
  continuationReasonForResumableError,
30
30
  } from "./production-agent.js";
31
31
  import { resolveRunSoftTimeoutMs } from "./run-manager.js";
32
+ import type { ResolveRunSoftTimeoutOptions } from "./run-manager.js";
32
33
  import { getCurrentTurnEventsForThread } from "./run-store.js";
33
34
  import {
34
35
  classifyToolCallJournal,
@@ -120,8 +121,9 @@ export const RUN_BUDGET_EXHAUSTED_MESSAGE =
120
121
  export async function runAgentLoopDirectWithSoftTimeout(
121
122
  opts: Parameters<typeof runAgentLoop>[0],
122
123
  softTimeoutMs?: number,
124
+ timeoutOptions?: ResolveRunSoftTimeoutOptions,
123
125
  ): Promise<Awaited<ReturnType<typeof runAgentLoop>>> {
124
- const timeoutMs = resolveRunSoftTimeoutMs(softTimeoutMs);
126
+ const timeoutMs = resolveRunSoftTimeoutMs(softTimeoutMs, timeoutOptions);
125
127
  if (timeoutMs <= 0) return runAgentLoop(opts);
126
128
 
127
129
  const upstreamSignal = opts.signal;
@@ -1,10 +1,4 @@
1
1
  import type { BrandKitData, BrandKitDefaults } from "../types.js";
2
- import { decodeFig } from "./decode.js";
3
- import { extractDesignSystemFromFig } from "./extract-design-system.js";
4
-
5
- export * from "./decode.js";
6
- export * from "./extract-design-system.js";
7
- export * from "./fig-to-html.js";
8
2
 
9
3
  export interface FigBrandKitPreview {
10
4
  gradients: string[];
@@ -25,6 +19,12 @@ export interface FigBrandKitExtraction {
25
19
 
26
20
  export const MAX_FIG_THUMBNAIL_BYTES = 512 * 1024;
27
21
 
22
+ function unsupportedFigImport(): never {
23
+ throw new Error(
24
+ "Local .fig design-system extraction has moved to Builder indexing. Connect Builder and use the design system indexing flow instead.",
25
+ );
26
+ }
27
+
28
28
  export function looksLikeFigFile(data: Uint8Array): boolean {
29
29
  const isZip =
30
30
  data[0] === 0x50 &&
@@ -42,39 +42,19 @@ export function figThumbnailDataUrl(thumbnail: Buffer | null): string | null {
42
42
  }
43
43
 
44
44
  export function extractFigBrandKit(
45
- input: Buffer | Uint8Array,
45
+ _input: Buffer | Uint8Array,
46
46
  ): FigBrandKitExtraction {
47
- const decoded = decodeFig(Buffer.from(input));
48
- if (!decoded.document) {
49
- throw new Error(
50
- "Decoded the file but found no document. It may be a partial or corrupt export.",
51
- );
52
- }
47
+ return unsupportedFigImport();
48
+ }
53
49
 
54
- const extracted = extractDesignSystemFromFig(decoded.document);
55
- const {
56
- customInstructions,
57
- gradients,
58
- palette,
59
- namedColors,
60
- nodeCount,
61
- ...data
62
- } = extracted;
50
+ export function decodeFig(_input: Buffer | Uint8Array): never {
51
+ return unsupportedFigImport();
52
+ }
63
53
 
64
- const thumbnailDataUrl = figThumbnailDataUrl(decoded.thumbnail);
54
+ export function extractDesignSystemFromFig(_document: unknown): never {
55
+ return unsupportedFigImport();
56
+ }
65
57
 
66
- return {
67
- format: decoded.format,
68
- version: decoded.version ?? null,
69
- data,
70
- customInstructions: customInstructions ?? "",
71
- preview: {
72
- gradients: gradients ?? [],
73
- palette: palette ?? [],
74
- namedColors: namedColors ?? {},
75
- thumbnailDataUrl,
76
- nodeCount: nodeCount ?? 0,
77
- imageCount: decoded.images.length,
78
- },
79
- };
58
+ export function figToHtml(_node: unknown): never {
59
+ return unsupportedFigImport();
80
60
  }
@@ -927,7 +927,7 @@ Usage:
927
927
  reinstalling app skills/connectors.
928
928
  agent-native app-skill <cmd> Install, launch, or package app-backed skills.
929
929
  cmds: ensure | launch | pack
930
- agent-native skills add assets|content|design-exploration|visual-plan|visual-recap|context-xray
930
+ agent-native skills add assets|content|design-exploration|visual-edit|visual-plan|visual-recap|context-xray
931
931
  Install the skill instructions, register the MCP
932
932
  connector, AND authenticate it in one step.
933
933
  --no-connect skips auth (run 'connect' later);
@@ -392,8 +392,124 @@ function codexMcpHeader(name: string): string {
392
392
  return `[mcp_servers.${tomlQuote(name)}]`;
393
393
  }
394
394
 
395
- function legacyCodexMcpHeader(name: string): string | null {
396
- return /^[A-Za-z0-9_-]+$/.test(name) ? `[mcp_servers.${name}]` : null;
395
+ /**
396
+ * Parse a TOML table-header line such as `[mcp_servers."plan".http_headers]`
397
+ * or `[mcp_servers.plan] # local note` into its decoded dotted-key components
398
+ * (`["mcp_servers", "plan", "http_headers"]`). Returns `null` when the line is
399
+ * not a single `[table]` header — blank lines, key/value pairs, comments,
400
+ * invalid trailing content, and `[[array-of-tables]]` headers all return `null`,
401
+ * so the result doubles as a reliable "is this line a table boundary?" check.
402
+ *
403
+ * Handles bare keys (`A-Za-z0-9_-`) and quoted keys (basic `"..."` with `\`
404
+ * escapes, and literal `'...'`), tolerating whitespace around the dot
405
+ * separators per the TOML spec. Quoted-key escape handling mirrors the inverse
406
+ * of `tomlQuote` (`\"` → `"`, `\\` → `\`).
407
+ */
408
+ function parseTomlTableHeader(line: string): string[] | null {
409
+ const trimmed = line.trim();
410
+ if (trimmed.length < 2 || trimmed[0] !== "[") return null;
411
+ // `[[array-of-tables]]` is a different construct — leave it untouched.
412
+ if (trimmed[1] === "[") return null;
413
+
414
+ let quote: '"' | "'" | null = null;
415
+ let escaped = false;
416
+ let closeIndex = -1;
417
+ for (let i = 1; i < trimmed.length; i++) {
418
+ const ch = trimmed[i];
419
+ if (quote === '"') {
420
+ if (escaped) {
421
+ escaped = false;
422
+ continue;
423
+ }
424
+ if (ch === "\\") {
425
+ escaped = true;
426
+ continue;
427
+ }
428
+ if (ch === '"') quote = null;
429
+ continue;
430
+ }
431
+ if (quote === "'") {
432
+ if (ch === "'") quote = null;
433
+ continue;
434
+ }
435
+ if (ch === '"' || ch === "'") {
436
+ quote = ch;
437
+ continue;
438
+ }
439
+ if (ch === "]") {
440
+ closeIndex = i;
441
+ break;
442
+ }
443
+ }
444
+ if (closeIndex < 0) return null;
445
+ const trailing = trimmed.slice(closeIndex + 1).trim();
446
+ if (trailing && !trailing.startsWith("#")) return null;
447
+
448
+ const inner = trimmed.slice(1, closeIndex);
449
+ const keys: string[] = [];
450
+ const isWs = (c: string) => c === " " || c === "\t";
451
+ const isBare = (c: string) => /[A-Za-z0-9_-]/.test(c);
452
+ let i = 0;
453
+ let expectKey = true;
454
+ while (i < inner.length) {
455
+ while (i < inner.length && isWs(inner[i])) i++;
456
+ if (i >= inner.length) break;
457
+ const ch = inner[i];
458
+ if (ch === ".") {
459
+ if (expectKey) return null; // leading or doubled dot
460
+ expectKey = true;
461
+ i++;
462
+ continue;
463
+ }
464
+ if (!expectKey) return null; // two keys with no dot between them
465
+ if (ch === '"' || ch === "'") {
466
+ const quote = ch;
467
+ i++;
468
+ let key = "";
469
+ while (i < inner.length && inner[i] !== quote) {
470
+ if (quote === '"' && inner[i] === "\\" && i + 1 < inner.length) {
471
+ const next = inner[i + 1];
472
+ key += next === '"' ? '"' : next === "\\" ? "\\" : `\\${next}`;
473
+ i += 2;
474
+ continue;
475
+ }
476
+ key += inner[i];
477
+ i++;
478
+ }
479
+ if (i >= inner.length) return null; // unterminated quote
480
+ i++; // consume the closing quote
481
+ keys.push(key);
482
+ expectKey = false;
483
+ } else if (isBare(ch)) {
484
+ let key = "";
485
+ while (i < inner.length && isBare(inner[i])) {
486
+ key += inner[i];
487
+ i++;
488
+ }
489
+ keys.push(key);
490
+ expectKey = false;
491
+ } else {
492
+ return null; // unexpected character — not a table header
493
+ }
494
+ }
495
+ if (expectKey) return null; // empty header or trailing dot
496
+ return keys.length ? keys : null;
497
+ }
498
+
499
+ /**
500
+ * The MCP server name a TOML table header belongs to, or `undefined` when the
501
+ * header is not under `[mcp_servers.*]`. The server's own table
502
+ * (`[mcp_servers.<name>]`) AND every sub-table of it
503
+ * (`[mcp_servers.<name>.http_headers]`, `[mcp_servers.<name>.env]`, …) resolve
504
+ * to the same `<name>`, so callers can treat a server and all its sub-tables as
505
+ * one removable unit. This is what prevents a re-install from orphaning a stale
506
+ * `[mcp_servers.<name>.http_headers]` sub-table that would then collide with the
507
+ * freshly written inline `http_headers` (a TOML duplicate-key error).
508
+ */
509
+ function codexServerNameOfHeader(line: string): string | undefined {
510
+ const keys = parseTomlTableHeader(line);
511
+ if (!keys || keys.length < 2 || keys[0] !== "mcp_servers") return undefined;
512
+ return keys[1];
397
513
  }
398
514
 
399
515
  /** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */
@@ -439,11 +555,16 @@ export function buildCodexLocalBlock(
439
555
  }
440
556
 
441
557
  /**
442
- * Replace (or append) the `[mcp_servers.<name>]` block in a TOML file
443
- * without disturbing other content. A block is the header line plus every
444
- * following line until the next top-level `[` table header or EOF. Pass
445
- * `block === null` to remove the block. Identical algorithm to `mcp.ts`'s
446
- * `writeCodexBlock` so the two never diverge.
558
+ * Replace (or append) the entire `[mcp_servers.<name>]` footprint in a TOML
559
+ * file without disturbing other content. The footprint is the server's own
560
+ * table AND every sub-table of it (`[mcp_servers.<name>.http_headers]`,
561
+ * `[mcp_servers.<name>.env]`, …), each spanning its header line plus every
562
+ * following line until the next table header or EOF. Removing the whole
563
+ * footprint — wherever the pieces sit in the file — is what keeps a re-install
564
+ * from leaving a stale sub-table that collides with the freshly written inline
565
+ * block (a TOML duplicate-key error). Matches both the canonical quoted header
566
+ * and the legacy bare header. Pass `block === null` to remove the footprint.
567
+ * Identical algorithm to `mcp.ts`'s `writeCodexBlock` so the two never diverge.
447
568
  */
448
569
  export function writeCodexBlock(
449
570
  file: string,
@@ -457,22 +578,18 @@ export function writeCodexBlock(
457
578
  content = "";
458
579
  }
459
580
 
460
- const headers = new Set(
461
- [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(
462
- Boolean,
463
- ) as string[],
464
- );
465
581
  const lines = content.split(/\r?\n/);
466
582
  const out: string[] = [];
467
583
  let i = 0;
468
584
  let removed = false;
469
585
  while (i < lines.length) {
470
586
  const line = lines[i];
471
- if (headers.has(line.trim())) {
472
- // Skip this block entirely (header + body until next table header).
587
+ if (codexServerNameOfHeader(line) === name) {
588
+ // Skip this table and its body (until the next table header), covering
589
+ // the server table itself and any of its sub-tables.
473
590
  removed = true;
474
591
  i++;
475
- while (i < lines.length && !/^\s*\[/.test(lines[i])) i++;
592
+ while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;
476
593
  continue;
477
594
  }
478
595
  out.push(line);
@@ -496,12 +613,9 @@ export function writeCodexBlock(
496
613
  export function codexHasBlock(file: string, name: string): boolean {
497
614
  try {
498
615
  const content = fs.readFileSync(file, "utf-8");
499
- const headers = new Set(
500
- [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(
501
- Boolean,
502
- ) as string[],
503
- );
504
- return content.split(/\r?\n/).some((line) => headers.has(line.trim()));
616
+ return content
617
+ .split(/\r?\n/)
618
+ .some((line) => codexServerNameOfHeader(line) === name);
505
619
  } catch {
506
620
  return false;
507
621
  }
@@ -620,8 +734,11 @@ export function removeJsonSameUrlDuplicates(
620
734
 
621
735
  /**
622
736
  * After writing the canonical `keepName` Codex block, remove any OTHER
623
- * `[mcp_servers.*]` blocks in the same TOML file whose `url =` line
624
- * normalises to the same value as `mcpUrl`. Returns removed entry names.
737
+ * `[mcp_servers.*]` servers in the same TOML file whose `url =` line normalises
738
+ * to the same value as `mcpUrl`. A server's entire footprint is removed its
739
+ * own table AND any sub-tables (`.http_headers`, `.env`, …), even when they are
740
+ * not contiguous — so cleanup never leaves an orphaned sub-table behind.
741
+ * Returns removed entry names in first-seen order.
625
742
  */
626
743
  export function removeCodexSameUrlDuplicates(
627
744
  file: string,
@@ -638,52 +755,71 @@ export function removeCodexSameUrlDuplicates(
638
755
  if (!targetCanonical) return [];
639
756
 
640
757
  const lines = content.split(/\r?\n/);
641
- const out: string[] = [];
642
- const removed: string[] = [];
758
+
759
+ // Pass 1: map each server name to the canonical URL declared on its own
760
+ // table, preserving first-seen order. Sub-tables don't carry the URL, so they
761
+ // only register the name.
762
+ const serverUrls = new Map<string, string | undefined>();
643
763
  let i = 0;
644
764
  while (i < lines.length) {
645
- const line = lines[i];
646
- const trimmed = line.trim();
647
- const quoted = trimmed.match(/^\[mcp_servers\."((?:\\.|[^"])*)"\]$/);
648
- const bare = trimmed.match(/^\[mcp_servers\.([A-Za-z0-9_-]+)\]$/);
649
- const serverName = quoted
650
- ? quoted[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\")
651
- : bare?.[1];
652
- if (serverName !== undefined && serverName !== keepName) {
653
- // Collect the block
654
- const block: string[] = [line];
765
+ const keys = parseTomlTableHeader(lines[i]);
766
+ const name =
767
+ keys && keys.length >= 2 && keys[0] === "mcp_servers"
768
+ ? keys[1]
769
+ : undefined;
770
+ if (name === undefined) {
655
771
  i++;
656
- while (i < lines.length && !/^\s*\[/.test(lines[i])) {
657
- block.push(lines[i]);
658
- i++;
659
- }
660
- // Check url in block
661
- const urlMatch = block
772
+ continue;
773
+ }
774
+ const isServerTable = keys!.length === 2;
775
+ const body: string[] = [];
776
+ i++;
777
+ while (i < lines.length && parseTomlTableHeader(lines[i]) === null) {
778
+ body.push(lines[i]);
779
+ i++;
780
+ }
781
+ if (isServerTable) {
782
+ const urlMatch = body
662
783
  .join("\n")
663
784
  .match(/^\s*url\s*=\s*"((?:\\.|[^"])*)"/m);
664
785
  const blockUrl = urlMatch
665
786
  ? urlMatch[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\")
666
787
  : undefined;
667
- if (canonicalUrl(blockUrl) === targetCanonical) {
668
- removed.push(serverName);
669
- // Skip this block (don't push to out)
670
- continue;
671
- }
672
- // Not a duplicate — keep it
673
- for (const l of block) out.push(l);
788
+ serverUrls.set(name, canonicalUrl(blockUrl));
789
+ } else if (!serverUrls.has(name)) {
790
+ serverUrls.set(name, undefined);
791
+ }
792
+ }
793
+
794
+ const removeSet = new Set<string>();
795
+ for (const [name, canonical] of serverUrls) {
796
+ if (name !== keepName && canonical && canonical === targetCanonical) {
797
+ removeSet.add(name);
798
+ }
799
+ }
800
+ if (removeSet.size === 0) return [];
801
+
802
+ // Pass 2: rebuild, dropping every table/sub-table belonging to a removed
803
+ // server.
804
+ const out: string[] = [];
805
+ i = 0;
806
+ while (i < lines.length) {
807
+ const name = codexServerNameOfHeader(lines[i]);
808
+ if (name !== undefined && removeSet.has(name)) {
809
+ i++;
810
+ while (i < lines.length && parseTomlTableHeader(lines[i]) === null) i++;
674
811
  continue;
675
812
  }
676
- out.push(line);
813
+ out.push(lines[i]);
677
814
  i++;
678
815
  }
679
816
 
680
- if (removed.length === 0) return [];
681
817
  const next = out
682
818
  .join("\n")
683
819
  .replace(/\n{3,}/g, "\n\n")
684
820
  .replace(/\n*$/, "\n");
685
821
  writeFileAtomic(file, next);
686
- return removed;
822
+ return [...removeSet];
687
823
  }
688
824
 
689
825
  /**