@agent-native/core 0.80.4 → 0.80.6

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 (341) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +28 -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 +21 -0
  26. package/corpus/core/src/agent/durable-background.ts +32 -11
  27. package/corpus/core/src/agent/production-agent.ts +11 -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/create.ts +1 -0
  31. package/corpus/core/src/cli/index.ts +1 -1
  32. package/corpus/core/src/cli/mcp-config-writers.ts +187 -51
  33. package/corpus/core/src/cli/skills.ts +18 -3
  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/agent-chat-plugin.ts +20 -0
  43. package/corpus/core/src/sharing/registry.ts +17 -0
  44. package/corpus/core/src/templates/default/pnpm-workspace.yaml +1 -0
  45. package/corpus/core/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
  46. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +2 -0
  47. package/corpus/templates/analytics/actions/update-dashboard.ts +8 -0
  48. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -1
  49. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +117 -33
  50. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +4 -0
  51. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +7 -0
  52. package/corpus/templates/analytics/changelog/2026-06-27-dashboards-can-now-nest-under-a-parent-in-the-sidebar-via-a-.md +6 -0
  53. package/corpus/templates/analytics/changelog/2026-06-29-analytics-pages-now-sit-closer-under-the-header-with-tighter.md +6 -0
  54. package/corpus/templates/assets/actions/generate-image-batch.ts +3 -0
  55. package/corpus/templates/assets/actions/generate-image.ts +3 -0
  56. package/corpus/templates/assets/changelog/2026-06-29-longer-agent-generation-window.md +6 -0
  57. package/corpus/templates/assets/netlify.toml +3 -3
  58. package/corpus/templates/assets/server/plugins/agent-chat.ts +4 -1
  59. package/corpus/templates/clips/app/components/capture-install-options.tsx +7 -8
  60. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +1 -1
  61. package/corpus/templates/content/AGENTS.md +57 -44
  62. package/corpus/templates/content/README.md +16 -0
  63. package/corpus/templates/content/actions/_builder-cms-read-client.ts +125 -0
  64. package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +28 -6
  65. package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +238 -69
  66. package/corpus/templates/content/actions/_builder-cms-write-settings.ts +125 -43
  67. package/corpus/templates/content/actions/_database-source-utils.ts +746 -97
  68. package/corpus/templates/content/actions/_database-utils.ts +17 -14
  69. package/corpus/templates/content/actions/_federation-join.ts +14 -2
  70. package/corpus/templates/content/actions/_join-suggestion.ts +89 -14
  71. package/corpus/templates/content/actions/_local-file-documents.ts +2 -1
  72. package/corpus/templates/content/actions/attach-content-database-source.ts +124 -5
  73. package/corpus/templates/content/actions/bind-content-database-source-field.ts +256 -0
  74. package/corpus/templates/content/actions/change-content-database-source-role.ts +420 -0
  75. package/corpus/templates/content/actions/create-document.ts +8 -0
  76. package/corpus/templates/content/actions/execute-builder-source-batch.ts +282 -0
  77. package/corpus/templates/content/actions/execute-builder-source-execution.ts +220 -8
  78. package/corpus/templates/content/actions/get-content-database.ts +10 -2
  79. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +19 -2
  80. package/corpus/templates/content/actions/prepare-builder-source-review.ts +47 -15
  81. package/corpus/templates/content/actions/refresh-content-database-source.ts +11 -4
  82. package/corpus/templates/content/actions/review-content-database-source-change-set.ts +6 -2
  83. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +32 -12
  84. package/corpus/templates/content/actions/stage-builder-revision.ts +14 -10
  85. package/corpus/templates/content/actions/validate-builder-source-execution.ts +25 -3
  86. package/corpus/templates/content/app/blocks/BuilderDocsBlocks.tsx +10 -0
  87. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -0
  88. package/corpus/templates/content/app/components/editor/ContentReferencePreview.tsx +185 -0
  89. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +1520 -553
  90. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -0
  91. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +150 -1
  92. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +19 -0
  93. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +647 -66
  94. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +543 -204
  95. package/corpus/templates/content/app/components/editor/extensions/ContentReferenceNode.tsx +82 -0
  96. package/corpus/templates/content/app/global.css +9 -0
  97. package/corpus/templates/content/app/hooks/use-content-database.ts +62 -0
  98. package/corpus/templates/content/app/i18n/zh-TW.ts +76 -0
  99. package/corpus/templates/content/app/i18n-data.ts +924 -0
  100. package/corpus/templates/content/changelog/2026-06-29-builder-review-checks-now-preserve-publish-and-unpublish-cho.md +6 -0
  101. package/corpus/templates/content/changelog/2026-06-29-database-sources-can-now-be-added-as-more-rows-or-matched.md +6 -0
  102. package/corpus/templates/content/changelog/2026-06-29-fixed-loading-the-final-rows-in-larger-databases-without-bre.md +6 -0
  103. package/corpus/templates/content/changelog/2026-06-29-reusable-mdx-references-now-preview-linked-local-documents-i.md +6 -0
  104. package/corpus/templates/content/shared/api.ts +91 -1
  105. package/corpus/templates/content/shared/builder-docs-blocks.ts +8 -0
  106. package/corpus/templates/content/shared/builder-mdx.ts +141 -4
  107. package/corpus/templates/content/shared/nfm.ts +62 -0
  108. package/corpus/templates/content/vite.config.ts +14 -7
  109. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +10 -11
  110. package/corpus/templates/design/AGENTS.md +5 -0
  111. package/corpus/templates/design/_gitignore +7 -0
  112. package/corpus/templates/design/actions/apply-visual-edit.ts +22 -12
  113. package/corpus/templates/design/actions/create-design-system.ts +15 -4
  114. package/corpus/templates/design/actions/create-file.ts +20 -1
  115. package/corpus/templates/design/actions/delete-design-system.ts +2 -2
  116. package/corpus/templates/design/actions/duplicate-design.ts +35 -9
  117. package/corpus/templates/design/actions/generate-design.ts +146 -69
  118. package/corpus/templates/design/actions/generate-screens.ts +51 -19
  119. package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
  120. package/corpus/templates/design/actions/get-design.ts +2 -0
  121. package/corpus/templates/design/actions/import-design-project.ts +28 -9
  122. package/corpus/templates/design/actions/import-document.ts +22 -8
  123. package/corpus/templates/design/actions/index-design-system-with-builder.ts +6 -153
  124. package/corpus/templates/design/actions/navigate.ts +105 -54
  125. package/corpus/templates/design/actions/set-default-design-system.ts +17 -3
  126. package/corpus/templates/design/actions/show-design-questions.ts +2 -0
  127. package/corpus/templates/design/actions/update-design.ts +2 -1
  128. package/corpus/templates/design/actions/view-screen.ts +12 -6
  129. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +4 -4
  130. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +159 -41
  131. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +8 -4
  132. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +37 -42
  133. package/corpus/templates/design/app/components/design/EditPanel.tsx +336 -183
  134. package/corpus/templates/design/app/components/design/LayersPanel.tsx +153 -34
  135. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +135 -33
  136. package/corpus/templates/design/app/components/design/QuestionFlow.tsx +6 -0
  137. package/corpus/templates/design/app/components/design/TweaksPanel.tsx +2 -1
  138. package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +4 -10
  139. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +84 -43
  140. package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +4 -4
  141. package/corpus/templates/design/app/components/design/inspector/{FigmaColorPicker.tsx → DesignColorPicker.tsx} +89 -62
  142. package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +14 -26
  143. package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +40 -12
  144. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +13 -4
  145. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +13 -13
  146. package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +13 -9
  147. package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +13 -4
  148. package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +6 -6
  149. package/corpus/templates/design/app/components/design/inspector/{figma-icons.tsx → design-icons.tsx} +2 -2
  150. package/corpus/templates/design/app/components/design/inspector/index.ts +12 -12
  151. package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +5 -2
  152. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +3 -3
  153. package/corpus/templates/design/app/components/layout/Layout.tsx +5 -2
  154. package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
  155. package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +167 -91
  156. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +16 -3
  157. package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +15 -0
  158. package/corpus/templates/design/app/global.css +4 -0
  159. package/corpus/templates/design/app/hooks/use-design-system.ts +4 -1
  160. package/corpus/templates/design/app/hooks/use-navigation-state.ts +38 -3
  161. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +9 -2
  162. package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
  163. package/corpus/templates/design/app/i18n-data.ts +527 -0
  164. package/corpus/templates/design/app/lib/design-systems.ts +6 -4
  165. package/corpus/templates/design/app/lib/design-templates.ts +15 -3
  166. package/corpus/templates/design/app/pages/DesignEditor.tsx +641 -158
  167. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +42 -34
  168. package/corpus/templates/design/app/pages/VisualEdit.tsx +100 -0
  169. package/corpus/templates/design/app/root.tsx +42 -9
  170. package/corpus/templates/design/app/routes/visual-edit.tsx +7 -0
  171. package/corpus/templates/design/changelog/2026-06-28-live-cursors-now-keep-names-beside-a-cleaner-pointer-marker.md +1 -1
  172. package/corpus/templates/design/changelog/2026-06-28-mode-switching-now-lives-in-a-compact-bottom-right-icon-dock.md +1 -1
  173. package/corpus/templates/design/changelog/2026-06-28-visual-code-design-mode.md +6 -0
  174. package/corpus/templates/design/changelog/2026-06-29-design-generation-prompts-now-show-connect-ai-before-sending.md +6 -0
  175. package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +1 -1
  176. package/corpus/templates/design/changelog/2026-06-29-fixed-design-editor-exports-and-gradient-edits-so-multi-scre.md +6 -0
  177. package/corpus/templates/design/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  178. package/corpus/templates/design/changelog/2026-06-29-png-export-handles-modern-css-color-functions-more-reliably.md +6 -0
  179. package/corpus/templates/design/changelog/2026-06-29-png-export-now-ignores-duplicate-clicks-while-a-download-is-.md +6 -0
  180. package/corpus/templates/design/changelog/2026-06-29-public-visual-edit-and-shared-design-links-now-invite-visito.md +6 -0
  181. package/corpus/templates/design/changelog/2026-06-29-visual-edit-actions-now-reject-missing-design-targets-before.md +6 -0
  182. package/corpus/templates/design/e2e/README.md +71 -0
  183. package/corpus/templates/design/e2e/global-setup.ts +157 -0
  184. package/corpus/templates/design/e2e/helpers.ts +148 -0
  185. package/corpus/templates/design/netlify.toml +3 -4
  186. package/corpus/templates/design/package.json +5 -1
  187. package/corpus/templates/design/playwright.config.ts +51 -0
  188. package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +121 -0
  189. package/corpus/templates/design/server/handlers/uploads.ts +89 -38
  190. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +181 -0
  191. package/corpus/templates/design/server/lib/coding-handoff.ts +33 -4
  192. package/corpus/templates/design/server/lib/design-export.ts +35 -8
  193. package/corpus/templates/design/server/plugins/agent-chat.ts +4 -0
  194. package/corpus/templates/design/server/plugins/auth.ts +10 -1
  195. package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  196. package/corpus/templates/design/shared/api.ts +2 -0
  197. package/corpus/templates/design/shared/apply-edits.ts +12 -8
  198. package/corpus/templates/design/shared/canvas-math.ts +19 -1
  199. package/corpus/templates/design/shared/code-layer.ts +87 -28
  200. package/corpus/templates/design/shared/generation-session.ts +1 -0
  201. package/corpus/templates/design/shared/resolve-tweaks.ts +4 -3
  202. package/corpus/templates/design/shared/shader-presets.ts +10 -0
  203. package/corpus/templates/design/shared/source-mode.ts +9 -0
  204. package/corpus/templates/design/vitest.config.ts +2 -1
  205. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  206. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +1 -1
  207. package/corpus/templates/plan/AGENTS.md +1 -1
  208. package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
  209. package/corpus/templates/plan/actions/validate-local-plan-source.ts +2 -10
  210. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -0
  211. package/corpus/templates/plan/docs/commenting-ux-plan.md +2 -2
  212. package/corpus/templates/plan/server/plan-content.ts +1 -1
  213. package/corpus/templates/plan/server/ui-plan-html.ts +2 -2
  214. package/corpus/templates/slides/actions/index-design-system-with-builder.ts +6 -153
  215. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +53 -38
  216. package/corpus/templates/slides/app/components/design-system/{fig-import-response.ts → builder-index-response.ts} +9 -6
  217. package/corpus/templates/slides/app/components/visual-editor/MultiSelectChip.tsx +1 -1
  218. package/corpus/templates/slides/changelog/2026-06-29-design-system-setup-now-indexes-uploaded-design-files-throug.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-06-29-longer-hosted-agent-turns.md +6 -0
  220. package/corpus/templates/slides/netlify.toml +3 -6
  221. package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +116 -0
  222. package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +179 -0
  223. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -1
  224. package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +1 -0
  225. package/dist/action.d.ts +15 -0
  226. package/dist/action.d.ts.map +1 -1
  227. package/dist/action.js +6 -0
  228. package/dist/action.js.map +1 -1
  229. package/dist/agent/durable-background.d.ts +9 -7
  230. package/dist/agent/durable-background.d.ts.map +1 -1
  231. package/dist/agent/durable-background.js +27 -11
  232. package/dist/agent/durable-background.js.map +1 -1
  233. package/dist/agent/production-agent.d.ts +7 -0
  234. package/dist/agent/production-agent.d.ts.map +1 -1
  235. package/dist/agent/production-agent.js +4 -1
  236. package/dist/agent/production-agent.js.map +1 -1
  237. package/dist/agent/run-loop-with-resume.d.ts +2 -1
  238. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  239. package/dist/agent/run-loop-with-resume.js +2 -2
  240. package/dist/agent/run-loop-with-resume.js.map +1 -1
  241. package/dist/brand-kit/fig/index.d.ts +4 -4
  242. package/dist/brand-kit/fig/index.d.ts.map +1 -1
  243. package/dist/brand-kit/fig/index.js +14 -27
  244. package/dist/brand-kit/fig/index.js.map +1 -1
  245. package/dist/cli/create.d.ts.map +1 -1
  246. package/dist/cli/create.js +1 -0
  247. package/dist/cli/create.js.map +1 -1
  248. package/dist/cli/index.js +1 -1
  249. package/dist/cli/index.js.map +1 -1
  250. package/dist/cli/mcp-config-writers.d.ts +15 -7
  251. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  252. package/dist/cli/mcp-config-writers.js +198 -45
  253. package/dist/cli/mcp-config-writers.js.map +1 -1
  254. package/dist/cli/skills.d.ts +1 -1
  255. package/dist/cli/skills.d.ts.map +1 -1
  256. package/dist/cli/skills.js +18 -3
  257. package/dist/cli/skills.js.map +1 -1
  258. package/dist/client/AssistantChat.d.ts.map +1 -1
  259. package/dist/client/AssistantChat.js +11 -1
  260. package/dist/client/AssistantChat.js.map +1 -1
  261. package/dist/client/agent-chat.d.ts.map +1 -1
  262. package/dist/client/agent-chat.js +15 -2
  263. package/dist/client/agent-chat.js.map +1 -1
  264. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  265. package/dist/client/composer/PromptComposer.js +35 -1
  266. package/dist/client/composer/PromptComposer.js.map +1 -1
  267. package/dist/client/org/OrgSwitcher.js +1 -1
  268. package/dist/client/org/OrgSwitcher.js.map +1 -1
  269. package/dist/client/sharing/ShareButton.d.ts +1 -1
  270. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  271. package/dist/client/sharing/ShareButton.js +2 -15
  272. package/dist/client/sharing/ShareButton.js.map +1 -1
  273. package/dist/collab/presence.d.ts +1 -1
  274. package/dist/collab/presence.js +1 -1
  275. package/dist/collab/presence.js.map +1 -1
  276. package/dist/collab/routes.d.ts +1 -1
  277. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  278. package/dist/mcp/connect-route.d.ts.map +1 -1
  279. package/dist/mcp/connect-route.js +34 -5
  280. package/dist/mcp/connect-route.js.map +1 -1
  281. package/dist/notifications/routes.d.ts +2 -2
  282. package/dist/observability/routes.d.ts +8 -8
  283. package/dist/resources/handlers.d.ts +1 -1
  284. package/dist/server/action-discovery.d.ts.map +1 -1
  285. package/dist/server/action-discovery.js +5 -0
  286. package/dist/server/action-discovery.js.map +1 -1
  287. package/dist/server/agent-chat-plugin.d.ts +6 -0
  288. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  289. package/dist/server/agent-chat-plugin.js +12 -3
  290. package/dist/server/agent-chat-plugin.js.map +1 -1
  291. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  292. package/dist/sharing/registry.d.ts.map +1 -1
  293. package/dist/sharing/registry.js +11 -0
  294. package/dist/sharing/registry.js.map +1 -1
  295. package/dist/templates/default/pnpm-workspace.yaml +1 -0
  296. package/dist/templates/workspace-root/pnpm-workspace.yaml +1 -0
  297. package/docs/content/locales/ar-SA/real-time-collaboration.mdx +2 -2
  298. package/docs/content/locales/ar-SA/template-design.mdx +1 -1
  299. package/docs/content/locales/de-DE/real-time-collaboration.mdx +3 -3
  300. package/docs/content/locales/de-DE/template-design.mdx +1 -1
  301. package/docs/content/locales/es-ES/real-time-collaboration.mdx +2 -2
  302. package/docs/content/locales/es-ES/template-design.mdx +1 -1
  303. package/docs/content/locales/fr-FR/real-time-collaboration.mdx +2 -2
  304. package/docs/content/locales/fr-FR/template-design.mdx +1 -1
  305. package/docs/content/locales/hi-IN/template-design.mdx +1 -1
  306. package/docs/content/locales/ja-JP/real-time-collaboration.mdx +2 -2
  307. package/docs/content/locales/ja-JP/template-design.mdx +1 -1
  308. package/docs/content/locales/ko-KR/real-time-collaboration.mdx +2 -2
  309. package/docs/content/locales/ko-KR/template-design.mdx +1 -1
  310. package/docs/content/locales/pt-BR/real-time-collaboration.mdx +2 -2
  311. package/docs/content/locales/pt-BR/template-design.mdx +1 -1
  312. package/docs/content/locales/zh-CN/real-time-collaboration.mdx +2 -2
  313. package/docs/content/locales/zh-CN/template-design.mdx +1 -1
  314. package/docs/content/locales/zh-TW/real-time-collaboration.mdx +2 -2
  315. package/docs/content/locales/zh-TW/template-design.mdx +1 -1
  316. package/docs/content/real-time-collaboration.mdx +2 -2
  317. package/docs/content/template-design.mdx +1 -1
  318. package/package.json +3 -7
  319. package/src/templates/default/pnpm-workspace.yaml +1 -0
  320. package/src/templates/workspace-root/pnpm-workspace.yaml +1 -0
  321. package/corpus/core/src/brand-kit/fig/decode.ts +0 -410
  322. package/corpus/core/src/brand-kit/fig/extract-design-system.ts +0 -947
  323. package/corpus/core/src/brand-kit/fig/fig-to-html.ts +0 -1906
  324. package/corpus/templates/design/actions/import-figma.ts +0 -55
  325. package/corpus/templates/design/changelog/2026-06-28-figma-style-code-design-mode.md +0 -6
  326. package/corpus/templates/design/server/handlers/import-figma-system.ts +0 -86
  327. package/corpus/templates/design/server/routes/api/import-figma-system.post.ts +0 -1
  328. package/corpus/templates/slides/server/handlers/import-figma-system.ts +0 -101
  329. package/corpus/templates/slides/server/routes/api/import-figma-system.post.ts +0 -1
  330. package/dist/brand-kit/fig/decode.d.ts +0 -33
  331. package/dist/brand-kit/fig/decode.d.ts.map +0 -1
  332. package/dist/brand-kit/fig/decode.js +0 -358
  333. package/dist/brand-kit/fig/decode.js.map +0 -1
  334. package/dist/brand-kit/fig/extract-design-system.d.ts +0 -44
  335. package/dist/brand-kit/fig/extract-design-system.d.ts.map +0 -1
  336. package/dist/brand-kit/fig/extract-design-system.js +0 -752
  337. package/dist/brand-kit/fig/extract-design-system.js.map +0 -1
  338. package/dist/brand-kit/fig/fig-to-html.d.ts +0 -246
  339. package/dist/brand-kit/fig/fig-to-html.d.ts.map +0 -1
  340. package/dist/brand-kit/fig/fig-to-html.js +0 -1506
  341. package/dist/brand-kit/fig/fig-to-html.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { useT } from "@agent-native/core/client";
1
+ import { appPath, useT } from "@agent-native/core/client";
2
2
  import {
3
3
  IconBrandApple,
4
4
  IconBrandChrome,
@@ -8,7 +8,6 @@ import {
8
8
  IconExternalLink,
9
9
  } from "@tabler/icons-react";
10
10
  import { type ReactNode } from "react";
11
- import { Link } from "react-router";
12
11
 
13
12
  import { Button, type ButtonProps } from "@/components/ui/button";
14
13
  import {
@@ -91,8 +90,8 @@ function InstallOptionsContent({ desktopHref = "/download" }) {
91
90
  </div>
92
91
  )}
93
92
 
94
- <Link
95
- to={desktopHref}
93
+ <a
94
+ href={appPath(desktopHref)}
96
95
  className="flex items-start gap-3 rounded-md border border-border p-3 text-start transition hover:bg-accent"
97
96
  >
98
97
  <DesktopIcon className="mt-0.5 h-4 w-4 shrink-0 text-primary" />
@@ -104,7 +103,7 @@ function InstallOptionsContent({ desktopHref = "/download" }) {
104
103
  {t("captureInstall.desktopDescription")}
105
104
  </span>
106
105
  </span>
107
- </Link>
106
+ </a>
108
107
  </div>
109
108
  );
110
109
  }
@@ -120,7 +119,7 @@ export function CaptureInstallButton({
120
119
  if (!clipsChromeExtensionEnabled) {
121
120
  return (
122
121
  <Button asChild className={className} {...buttonProps}>
123
- <Link to={desktopHref}>{children}</Link>
122
+ <a href={appPath(desktopHref)}>{children}</a>
124
123
  </Button>
125
124
  );
126
125
  }
@@ -149,9 +148,9 @@ export function CaptureInstallInlineLink({
149
148
  }: CaptureInstallInlineLinkProps) {
150
149
  if (!clipsChromeExtensionEnabled) {
151
150
  return (
152
- <Link to={desktopHref} className={className}>
151
+ <a href={appPath(desktopHref)} className={className}>
153
152
  {children}
154
- </Link>
153
+ </a>
155
154
  );
156
155
  }
157
156
 
@@ -194,7 +194,7 @@ const SCREEN_CAPTURE_MAX_HEIGHT = 1080;
194
194
  // client-side (ffmpeg.wasm re-encode is disabled — see COMPRESSION_ENABLED in
195
195
  // `@/lib/compress`) and the upload provider streams large files directly, so we
196
196
  // capture at a crisp 1080p bitrate instead of a tight budget. 1.2 Mbps left
197
- // dense UI (fine text, Figma, code) visibly fuzzy; 8 Mbps keeps it sharp.
197
+ // dense UI (fine text and code) visibly fuzzy; 8 Mbps keeps it sharp.
198
198
  // Dial down here if file sizes become a concern for a deployment.
199
199
  const RECORDING_VIDEO_BITRATE_BPS = 8_000_000;
200
200
  const RECORDING_AUDIO_BITRATE_BPS = 128_000;
@@ -87,50 +87,51 @@ cd templates/content && pnpm action <name> [args]
87
87
 
88
88
  ### Document Operations
89
89
 
90
- | Action | Args | Purpose |
91
- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
92
- | `list-documents` | `[--format json]` | List document metadata/tree; no full bodies |
93
- | `export-content-source` | `[--format json]` | Export editable docs as `content/*.mdx` source files |
94
- | `import-content-source` | `--files <json> [--dryRun true\|false]` | Import `.md`/`.mdx` source files into editable docs |
95
- | `list-builder-docs` | `[--model docs-content\|blog-article] [--limit <n>]` | List Builder docs/blog entries available for `.builder.mdx` pull |
96
- | `pull-builder-doc` | `--model <model> --entryId <builder-entry-id> [--dryRun true\|false]` | Pull one Builder entry into Content and return `.builder.mdx` plus `content/builder/.raw` sidecar files |
97
- | `check-builder-doc` | `--files <json> [--path <file.builder.mdx>]` or `--documentId <id>` | Validate Builder MDX round-trip, sidecar hashes, and remote conflict status before push |
98
- | `push-builder-doc` | `--files <json> [--path <file.builder.mdx>] [--dryRun true\|false]` | Guarded Builder autosave PATCH for the safe Builder test model; never publishes |
99
- | `navigate` | `--path <path>` or `--documentId <id>` or `--databaseId <id>` | Open a route, document page, or database page in the UI |
100
- | `search-documents` | `--query <text> [--format json]` | Search by title/content and return snippets |
101
- | `get-document` | `--id <id> [--format json]` | Get a single document with content |
102
- | `pull-document` | `--id <id> [--format markdown\|text]` | Collab-aware "ingest the final" read |
103
- | `create-document` | `--title <text> [--content] [--parentId] [--icon]` | Create a new document |
104
- | `edit-document` | `--id <id> --find <text> --replace <text>` | Surgical text edit (preferred for modifications) |
105
- | `edit-document` | `--id <id> --edits <json>` | Batch surgical text edits |
106
- | `update-document` | `--id <id> [--title] [--content] [--icon]` | Full rewrite of document fields |
107
- | `share-local-file-document` | `--id <local-file-document-id>` | Create or refresh a DB-backed shareable copy of a local file document |
108
- | `list-local-component-files` | | List registered local MDX component source files |
109
- | `write-local-component-file` | `--workspaceId <id> --path <relative-component-path> --content <source>` | Create or update a file in a registered local `components/` folder |
110
- | `create-content-database` | `[--documentId <id>] [--parentId <id>] [--title <text>]` | Create a database page or convert an existing page into a database |
111
- | `get-content-database` | `--databaseId <id>` or `--documentId <id>` | Get a database table with property schema and item pages |
112
- | `get-content-database-source` | `--databaseId <id>` or `--documentId <id>` | Inspect local/no-source or source-backed status, mappings, row identity, freshness, and change sets |
113
- | `attach-content-database-source` | `--databaseId <id>` or `--documentId <id> [--sourceType mock\|builder-cms] [--sourceName] [--sourceTable]` | Attach a source binding; Builder CMS live writes are disabled by default |
114
- | `refresh-content-database-source` | `--databaseId <id>` or `--documentId <id>` | Refresh the read-only source status envelope; Builder CMS reads live entries only when configured |
115
- | `set-content-database-source-write-mode` | `--databaseId <id>` or `--documentId <id> --liveWritesEnabled true\|false [--allowedWriteModes <json>]` | Enable/disable per-source Builder live writes; enabling is allowed only for `agent-native-blog-article-test` with explicit modes |
116
- | `stage-builder-revision` | `--databaseId <id>` or `--documentId <id>` | Stage pending local Builder CMS changes as a local-only save-revision record; never calls Builder |
117
- | `review-content-database-source-change-set` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> --decision approve\|reject [--note]` | Approve or reject a local source change-set review record without provider writes |
118
- | `prepare-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--pushModeConfirmation autosave\|draft\|publish]` | Prepare a dry-run Builder execution gate with request semantics/idempotency key; never calls Builder |
119
- | `validate-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--idempotencyKey <key>]` | Validate/replay a prepared Builder execution gate locally as a dry run; never calls Builder |
120
- | `execute-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--idempotencyKey <key>] [--pushModeConfirmation autosave\|draft\|publish]` | Execute a guarded live Builder write only when approved, validated, enabled, idempotent, and targeting `agent-native-blog-article-test` |
121
- | `add-database-item` | `--databaseId <id> [--title <text>] [--propertyValues <json>]` | Add a page row to a database, optionally seeding property values |
122
- | `duplicate-database-item` | `--itemId <id>` or `--documentId <id> [--title <text>]` | Duplicate a database row page and its stored property values |
123
- | `move-database-item` | `--itemId <id>` or `--documentId <id> --position <number>` | Move a database row page to a new zero-based table position |
124
- | `update-content-database-view` | `--databaseId <id> --viewConfig <json>` | Persist database views, sorts, filters, hidden properties, and view settings |
125
- | `list-document-properties` | `--documentId <id> [--format json]` | List Notion-style property definitions and values for a document |
126
- | `configure-document-property` | `--documentId <id> [--id <propertyId>] --name <name> --type <type> [--visibility always_show\|hide_when_empty\|always_hide]` | Create or update a property definition |
127
- | `duplicate-document-property` | `--documentId <id> --propertyId <propertyId>` | Duplicate a property definition and its stored values |
128
- | `delete-document-property` | `--documentId <id> --propertyId <propertyId>` | Delete a property definition and its stored values |
129
- | `set-document-property` | `--documentId <id> --propertyId <propertyId> --value <json>` | Set a document property value (for a `blocks` field, the value is its markdown content) |
130
- | `reorder-document-property` | `--documentId <id> --propertyId <propertyId> --targetPropertyId <id> [--position before\|after]` | Reorder a property definition within its database (used to reorder Blocks fields on the page) |
131
- | `set-document-discoverability` | `--id <id> --hideFromSearch true\|false [--includeChildren true\|false]` | Hide/show an org-accessible document in Organization/search while keeping link access |
132
- | `move-document` | `--id <id> [--parentId] [--position]` | Move or reorder a document in the page tree |
133
- | `delete-document` | `--id <id>` | Delete with recursive children |
90
+ | Action | Args | Purpose |
91
+ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
92
+ | `list-documents` | `[--format json]` | List document metadata/tree; no full bodies |
93
+ | `export-content-source` | `[--format json]` | Export editable docs as `content/*.mdx` source files |
94
+ | `import-content-source` | `--files <json> [--dryRun true\|false]` | Import `.md`/`.mdx` source files into editable docs |
95
+ | `list-builder-docs` | `[--model docs-content\|blog-article] [--limit <n>]` | List Builder docs/blog entries available for `.builder.mdx` pull |
96
+ | `pull-builder-doc` | `--model <model> --entryId <builder-entry-id> [--dryRun true\|false]` | Pull one Builder entry into Content and return `.builder.mdx` plus `content/builder/.raw` sidecar files |
97
+ | `check-builder-doc` | `--files <json> [--path <file.builder.mdx>]` or `--documentId <id>` | Validate Builder MDX round-trip, sidecar hashes, and remote conflict status before push |
98
+ | `push-builder-doc` | `--files <json> [--path <file.builder.mdx>] [--dryRun true\|false]` | Guarded Builder autosave PATCH for the safe Builder test model; never publishes |
99
+ | `navigate` | `--path <path>` or `--documentId <id>` or `--databaseId <id>` | Open a route, document page, or database page in the UI |
100
+ | `search-documents` | `--query <text> [--format json]` | Search by title/content and return snippets |
101
+ | `get-document` | `--id <id> [--format json]` | Get a single document with content |
102
+ | `pull-document` | `--id <id> [--format markdown\|text]` | Collab-aware "ingest the final" read |
103
+ | `create-document` | `--title <text> [--content] [--parentId] [--icon]` | Create a new document |
104
+ | `edit-document` | `--id <id> --find <text> --replace <text>` | Surgical text edit (preferred for modifications) |
105
+ | `edit-document` | `--id <id> --edits <json>` | Batch surgical text edits |
106
+ | `update-document` | `--id <id> [--title] [--content] [--icon]` | Full rewrite of document fields |
107
+ | `share-local-file-document` | `--id <local-file-document-id>` | Create or refresh a DB-backed shareable copy of a local file document |
108
+ | `list-local-component-files` | | List registered local MDX component source files |
109
+ | `write-local-component-file` | `--workspaceId <id> --path <relative-component-path> --content <source>` | Create or update a file in a registered local `components/` folder |
110
+ | `create-content-database` | `[--documentId <id>] [--parentId <id>] [--title <text>]` | Create a database page or convert an existing page into a database |
111
+ | `get-content-database` | `--databaseId <id>` or `--documentId <id>` | Get a database table with property schema and item pages |
112
+ | `get-content-database-source` | `--databaseId <id>` or `--documentId <id>` | Inspect local/no-source or source-backed status, mappings, row identity, freshness, and change sets |
113
+ | `attach-content-database-source` | `--databaseId <id>` or `--documentId <id> [--sourceType mock\|builder-cms] [--sourceName] [--sourceTable] [--relationshipMode items\|details] [--join <json>]` | Attach a source binding; use `items` to add more rows and `details` to match a source onto existing rows |
114
+ | `change-content-database-source-role` | `--databaseId <id>` or `--documentId <id> --sourceId <id> --relationshipMode items\|details [--join <json>]` | Change an attached source between adding rows and adding matched detail columns without removing the source |
115
+ | `refresh-content-database-source` | `--databaseId <id>` or `--documentId <id>` | Refresh the read-only source status envelope; Builder CMS reads live entries only when configured |
116
+ | `set-content-database-source-write-mode` | `--databaseId <id>` or `--documentId <id> --liveWritesEnabled true\|false [--allowedWriteModes <json>]` | Enable/disable per-source Builder live writes; enabling is allowed only for `agent-native-blog-article-test` with explicit modes |
117
+ | `stage-builder-revision` | `--databaseId <id>` or `--documentId <id>` | Stage pending local Builder CMS changes as a local-only save-revision record; never calls Builder |
118
+ | `review-content-database-source-change-set` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> --decision approve\|reject [--note]` | Approve or reject a local source change-set review record without provider writes |
119
+ | `prepare-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--pushModeConfirmation autosave\|draft\|publish]` | Prepare a dry-run Builder execution gate with request semantics/idempotency key; never calls Builder |
120
+ | `validate-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--idempotencyKey <key>]` | Validate/replay a prepared Builder execution gate locally as a dry run; never calls Builder |
121
+ | `execute-builder-source-execution` | `--databaseId <id>` or `--documentId <id> --changeSetId <id> [--idempotencyKey <key>] [--pushModeConfirmation autosave\|draft\|publish]` | Execute a guarded live Builder write only when approved, validated, enabled, idempotent, and targeting `agent-native-blog-article-test` |
122
+ | `add-database-item` | `--databaseId <id> [--title <text>] [--propertyValues <json>]` | Add a page row to a database, optionally seeding property values |
123
+ | `duplicate-database-item` | `--itemId <id>` or `--documentId <id> [--title <text>]` | Duplicate a database row page and its stored property values |
124
+ | `move-database-item` | `--itemId <id>` or `--documentId <id> --position <number>` | Move a database row page to a new zero-based table position |
125
+ | `update-content-database-view` | `--databaseId <id> --viewConfig <json>` | Persist database views, sorts, filters, hidden properties, and view settings |
126
+ | `list-document-properties` | `--documentId <id> [--format json]` | List Notion-style property definitions and values for a document |
127
+ | `configure-document-property` | `--documentId <id> [--id <propertyId>] --name <name> --type <type> [--visibility always_show\|hide_when_empty\|always_hide]` | Create or update a property definition |
128
+ | `duplicate-document-property` | `--documentId <id> --propertyId <propertyId>` | Duplicate a property definition and its stored values |
129
+ | `delete-document-property` | `--documentId <id> --propertyId <propertyId>` | Delete a property definition and its stored values |
130
+ | `set-document-property` | `--documentId <id> --propertyId <propertyId> --value <json>` | Set a document property value (for a `blocks` field, the value is its markdown content) |
131
+ | `reorder-document-property` | `--documentId <id> --propertyId <propertyId> --targetPropertyId <id> [--position before\|after]` | Reorder a property definition within its database (used to reorder Blocks fields on the page) |
132
+ | `set-document-discoverability` | `--id <id> --hideFromSearch true\|false [--includeChildren true\|false]` | Hide/show an org-accessible document in Organization/search while keeping link access |
133
+ | `move-document` | `--id <id> [--parentId] [--position]` | Move or reorder a document in the page tree |
134
+ | `delete-document` | `--id <id>` | Delete with recursive children |
134
135
 
135
136
  Database views follow Notion-style tab labels. When creating or duplicating
136
137
  views in `viewConfig`, use unique default names (`Table 2`, `SEO copy 2`, etc.)
@@ -195,6 +196,18 @@ Content has two file workflows:
195
196
  `select` fields; selecting the component in the editor shows a corner edit
196
197
  button that rewrites the MDX props. JSX expression props are preserved in
197
198
  source but shown as an unsupported preview.
199
+ - **Reusable MDX references:** local-file MDX can embed another local document
200
+ with `<ContentReference sourcePath="./shared/example.mdx" />`. The editor
201
+ resolves `sourcePath` relative to the current file, previews the referenced
202
+ MDX read-only in place, and preserves the original tag in source. Use this for
203
+ reusable docs fragments instead of copy/pasting shared content.
204
+ - **Builder Symbols:** Builder MDX pulls preserve Symbol blocks as
205
+ `<BuilderSymbol ... />`. When Builder returns enriched symbol content, the
206
+ pull also writes a referenced `.builder.mdx` file under
207
+ `content/builder/symbols/` and sets the Symbol block's `source` attribute.
208
+ Edit reusable symbol content in that emitted source file; do not retarget
209
+ `entry`, `model`, or `source` in the parent MDX unless a dedicated Builder
210
+ retargeting workflow is added.
198
211
  - **Picked folders and components:** browser-picked folders can be the
199
212
  source of truth for `.md`/`.mdx` files, but the browser does not expose an
200
213
  absolute path that Vite can compile. Component previews from a picked
@@ -28,3 +28,19 @@ Open http://localhost:8080 and create your first page.
28
28
  ## Data
29
29
 
30
30
  Documents are stored in the app's SQL database. Local development defaults to SQLite at `data/app.db`; deployed apps should set `DATABASE_URL` to a persistent SQL database. The agent should use content actions for normal document operations and reserve `db-query` / `db-exec` for inspection or maintenance.
31
+
32
+ ## Enable Builder live writes
33
+
34
+ Connect Builder through the existing Builder Connect flow, the same connection used by the AI assistant. Once connected, Content resolves the key automatically for the user, or for org owners/admins through the org connection. There is no separate key entry. In local development, `BUILDER_PRIVATE_KEY` and `BUILDER_PUBLIC_KEY` in `.env.local` also work; see `DEVELOPING.md` for local env opt-in details.
35
+
36
+ Live writes are only allowed for the safe write model `agent-native-blog-article-test` (`BUILDER_CMS_SAFE_WRITE_MODEL`). Other Builder models stay read-only by design.
37
+
38
+ Write access is an intentional per-source choice from the source panel selector. Sources start at `read_only`, can move to `stage_only` to push approved changes as Builder autosave revisions, and can move to `publish_updates` for state-preserving live writes. Autosave staging stays quiet; update-in-place and publish writes trigger Builder webhooks so downstream rebuilds can run.
39
+
40
+ In `publish_updates`, Content PATCHes the Builder entry in place and preserves its current publication state: published entries stay published and drafts stay draft. Content never sends a `published` field, so a normal content push cannot publish or unpublish. Builder merges the field changes and preserves the entry envelope, including scheduling and targeting.
41
+
42
+ Publication transitions are explicit per-row choices in the review/diff, only when the source enables **Allow publish/unpublish per item**. Publishing a draft or unpublishing a published entry is never a bulk default, and unpublish requires confirmation because it takes live content down. New Builder entries are created as drafts.
43
+
44
+ **Push all approved (N)** runs approved rows in a concurrency-capped batch. It continues after individual errors, reports per-item `succeeded`, `blocked`, or `failed` status, and can be resumed because already-succeeded items are skipped.
45
+
46
+ Before each write, Content reads the target's current state from Builder. A write blocks if the entry changed or was deleted since the diff, or if a requested publish/unpublish transition no longer matches the real Builder state. Body diffs remain non-executable for now; they are planned for a later slice.
@@ -19,6 +19,13 @@ export interface BuilderCmsReadResult {
19
19
  message: string | null;
20
20
  }
21
21
 
22
+ export interface BuilderCmsEntryLiveState {
23
+ exists: boolean;
24
+ published: "published" | "draft" | string | null;
25
+ lastUpdated: number | string | null;
26
+ id: string | null;
27
+ }
28
+
22
29
  type FetchLike = typeof fetch;
23
30
 
24
31
  type BuilderMcpContentPart = {
@@ -52,6 +59,80 @@ function entryArrayFromResponse(value: unknown) {
52
59
  return Array.isArray(record.results) ? record.results : [];
53
60
  }
54
61
 
62
+ function stringFromUnknown(value: unknown) {
63
+ return typeof value === "string" && value.trim() ? value.trim() : null;
64
+ }
65
+
66
+ function stringOrNumberFromUnknown(value: unknown) {
67
+ if (typeof value === "number" && Number.isFinite(value)) return value;
68
+ return stringFromUnknown(value);
69
+ }
70
+
71
+ function liveStateFromBuilderEntry(value: unknown): BuilderCmsEntryLiveState {
72
+ if (Array.isArray(value)) {
73
+ return value.length > 0
74
+ ? liveStateFromBuilderEntry(value[0])
75
+ : {
76
+ exists: false,
77
+ published: null,
78
+ lastUpdated: null,
79
+ id: null,
80
+ };
81
+ }
82
+ if (!value || typeof value !== "object") {
83
+ return {
84
+ exists: false,
85
+ published: null,
86
+ lastUpdated: null,
87
+ id: null,
88
+ };
89
+ }
90
+
91
+ const record = value as Record<string, unknown>;
92
+ if (Array.isArray(record.results)) {
93
+ return liveStateFromBuilderEntry(record.results);
94
+ }
95
+ if (Object.keys(record).length === 0) {
96
+ return {
97
+ exists: false,
98
+ published: null,
99
+ lastUpdated: null,
100
+ id: null,
101
+ };
102
+ }
103
+
104
+ const data =
105
+ record.data &&
106
+ typeof record.data === "object" &&
107
+ !Array.isArray(record.data)
108
+ ? (record.data as Record<string, unknown>)
109
+ : {};
110
+ const id =
111
+ stringFromUnknown(record.id) ??
112
+ stringFromUnknown(record["@id"]) ??
113
+ stringFromUnknown(record.uuid);
114
+ if (!id) {
115
+ return {
116
+ exists: false,
117
+ published: null,
118
+ lastUpdated: null,
119
+ id: null,
120
+ };
121
+ }
122
+
123
+ return {
124
+ exists: true,
125
+ published:
126
+ stringFromUnknown(record.published) ?? stringFromUnknown(data.published),
127
+ lastUpdated:
128
+ stringOrNumberFromUnknown(record.lastUpdated) ??
129
+ stringOrNumberFromUnknown(record.updatedDate) ??
130
+ stringOrNumberFromUnknown(record.updatedAt) ??
131
+ stringOrNumberFromUnknown(data.updatedAt),
132
+ id,
133
+ };
134
+ }
135
+
55
136
  function readLimit(limit: number | undefined) {
56
137
  if (typeof limit === "number" && Number.isFinite(limit) && limit > 0) {
57
138
  return Math.min(Math.floor(limit), BUILDER_CMS_MAX_READ_LIMIT);
@@ -506,6 +587,50 @@ async function readBuilderCmsContentEntriesViaContentApi(args: {
506
587
  };
507
588
  }
508
589
 
590
+ export async function readBuilderCmsEntryLiveState(args: {
591
+ model: string;
592
+ entryId: string;
593
+ fetchImpl?: FetchLike;
594
+ }): Promise<BuilderCmsEntryLiveState> {
595
+ const publicKey = await resolveBuilderCredential("BUILDER_PUBLIC_KEY");
596
+ if (!publicKey) {
597
+ throw new Error(
598
+ "Builder CMS live entry read skipped because BUILDER_PUBLIC_KEY is not configured.",
599
+ );
600
+ }
601
+
602
+ const url = new URL(
603
+ `/api/v3/content/${encodeURIComponent(args.model)}/${encodeURIComponent(
604
+ args.entryId,
605
+ )}`,
606
+ builderContentApiHost(),
607
+ );
608
+ url.searchParams.set("apiKey", publicKey);
609
+ url.searchParams.set("includeUnpublished", "true");
610
+ url.searchParams.set("cachebust", String(Date.now()));
611
+
612
+ const response = await fetchBuilderContentPage({
613
+ fetchImpl: args.fetchImpl ?? fetch,
614
+ url,
615
+ });
616
+ if (response.status === 404) {
617
+ return {
618
+ exists: false,
619
+ published: null,
620
+ lastUpdated: null,
621
+ id: null,
622
+ };
623
+ }
624
+ if (!response.ok) {
625
+ throw new Error(
626
+ `Builder CMS live entry read failed with HTTP ${response.status}.`,
627
+ );
628
+ }
629
+
630
+ const json = (await response.json()) as unknown;
631
+ return liveStateFromBuilderEntry(json);
632
+ }
633
+
509
634
  export async function listBuilderCmsModels(
510
635
  args: {
511
636
  fetchImpl?: FetchLike;
@@ -164,11 +164,13 @@ export function builderCmsSourceMetadata(sourceTable: string) {
164
164
  primaryKey: "id",
165
165
  titleField: "data.title",
166
166
  naturalKeyField: "/blog/[slug]",
167
- pushMode: "autosave" as const,
168
- pushModeLabel: "Save revision / autosave",
167
+ pushMode: "none" as const,
168
+ pushModeLabel: "No writes",
169
169
  pushModeDescription:
170
- "Local-only Builder revision staging. No Builder API write runs in this slice.",
171
- allowedWriteModes: ["autosave"],
170
+ "Read-only Builder source. Choose a write tier before any Builder API write can run.",
171
+ writeMode: "read_only" as const,
172
+ allowPublicationTransitions: false,
173
+ allowedWriteModes: [],
172
174
  allowDraftWrites: false,
173
175
  allowPublishWrites: false,
174
176
  notes:
@@ -196,6 +198,22 @@ function stringFromRecord(
196
198
  return null;
197
199
  }
198
200
 
201
+ function timestampStringFromRecord(
202
+ value: Record<string, unknown>,
203
+ keys: string[],
204
+ ): string | null {
205
+ for (const key of keys) {
206
+ const candidate = value[key];
207
+ if (typeof candidate === "number" && Number.isFinite(candidate)) {
208
+ return String(candidate);
209
+ }
210
+ if (typeof candidate === "string" && candidate.trim()) {
211
+ return candidate.trim();
212
+ }
213
+ }
214
+ return null;
215
+ }
216
+
199
217
  function pickStringField(
200
218
  obj: Record<string, unknown>,
201
219
  keys: string[],
@@ -317,8 +335,12 @@ export function normalizeBuilderCmsApiEntry(
317
335
  stringFromRecord(data, ["url", "urlPath", "path"]) ??
318
336
  (slug ? `/blog/${slug.replace(/^\/+/, "")}` : `/blog/${id}`);
319
337
  const updatedAt =
320
- stringFromRecord(record, ["lastUpdated", "updatedDate", "updatedAt"]) ??
321
- stringFromRecord(data, ["updatedAt"]) ??
338
+ timestampStringFromRecord(record, [
339
+ "lastUpdated",
340
+ "updatedDate",
341
+ "updatedAt",
342
+ ]) ??
343
+ timestampStringFromRecord(data, ["updatedAt"]) ??
322
344
  new Date().toISOString();
323
345
 
324
346
  return {