@agent-native/core 0.102.1 → 0.103.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +15 -0
  3. package/corpus/core/docs/content/local-file-mode.mdx +99 -489
  4. package/corpus/core/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
  5. package/corpus/core/docs/content/locales/ar-SA/template-content.mdx +10 -24
  6. package/corpus/core/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
  7. package/corpus/core/docs/content/locales/de-DE/template-content.mdx +10 -24
  8. package/corpus/core/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
  9. package/corpus/core/docs/content/locales/es-ES/template-content.mdx +10 -24
  10. package/corpus/core/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
  11. package/corpus/core/docs/content/locales/fr-FR/template-content.mdx +10 -24
  12. package/corpus/core/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
  13. package/corpus/core/docs/content/locales/hi-IN/template-content.mdx +10 -24
  14. package/corpus/core/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
  15. package/corpus/core/docs/content/locales/ja-JP/template-content.mdx +10 -24
  16. package/corpus/core/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
  17. package/corpus/core/docs/content/locales/ko-KR/template-content.mdx +10 -24
  18. package/corpus/core/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
  19. package/corpus/core/docs/content/locales/pt-BR/template-content.mdx +10 -24
  20. package/corpus/core/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
  21. package/corpus/core/docs/content/locales/zh-CN/template-content.mdx +9 -24
  22. package/corpus/core/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
  23. package/corpus/core/docs/content/locales/zh-TW/template-content.mdx +9 -24
  24. package/corpus/core/docs/content/template-content.mdx +26 -42
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/cli/content-local.ts +86 -18
  27. package/corpus/core/src/cli/index.ts +2 -2
  28. package/corpus/core/src/cli/skills-content/content-skill.ts +36 -25
  29. package/corpus/core/src/cli/skills.ts +47 -13
  30. package/corpus/core/src/client/AgentPanel.tsx +7 -0
  31. package/corpus/core/src/client/AssistantChat.tsx +7 -0
  32. package/corpus/core/src/client/agent-chat-adapter.ts +7 -1
  33. package/corpus/core/src/client/chat/message-components.tsx +17 -3
  34. package/corpus/core/src/client/composer/ComposerPlusMenu.tsx +96 -6
  35. package/corpus/core/src/client/composer/asset-picker-url.ts +80 -0
  36. package/corpus/core/src/client/error-format.ts +24 -0
  37. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +8 -1
  38. package/corpus/core/src/local-artifacts/index.ts +65 -0
  39. package/corpus/templates/assets/app/components/library/GenerationPresetsPanel.tsx +325 -0
  40. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +12 -0
  41. package/corpus/templates/assets/app/i18n/zh-TW.ts +21 -0
  42. package/corpus/templates/assets/app/i18n-data.ts +215 -0
  43. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +19 -479
  44. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1 -1
  45. package/corpus/templates/assets/app/routes/brand-kits.$id_.settings.tsx +446 -0
  46. package/corpus/templates/assets/app/routes/library.tsx +69 -0
  47. package/corpus/templates/assets/changelog/2026-07-15-fixed-top-level-image-picker-selections-returning-to-the-com.md +6 -0
  48. package/corpus/templates/clips/actions/disconnect-calendar.ts +57 -9
  49. package/corpus/templates/clips/actions/generate-workflow.ts +102 -59
  50. package/corpus/templates/clips/actions/get-recording-player-data.ts +64 -1
  51. package/corpus/templates/clips/actions/regenerate-summary.ts +7 -0
  52. package/corpus/templates/clips/actions/regenerate-title.ts +29 -11
  53. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +34 -13
  54. package/corpus/templates/clips/app/components/editor/thumbnail-picker.tsx +87 -9
  55. package/corpus/templates/clips/app/components/editor/trim-handles.tsx +15 -0
  56. package/corpus/templates/clips/app/components/editor/waveform.tsx +21 -8
  57. package/corpus/templates/clips/app/components/library/folder-tree.tsx +52 -0
  58. package/corpus/templates/clips/app/components/player/settings-panel.tsx +116 -58
  59. package/corpus/templates/clips/app/components/player/share-dialog.tsx +43 -37
  60. package/corpus/templates/clips/app/components/player/video-player.tsx +50 -2
  61. package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +22 -3
  62. package/corpus/templates/clips/app/i18n/ar-SA.ts +5 -2
  63. package/corpus/templates/clips/app/i18n/de-DE.ts +6 -2
  64. package/corpus/templates/clips/app/i18n/en-US.ts +5 -2
  65. package/corpus/templates/clips/app/i18n/es-ES.ts +6 -2
  66. package/corpus/templates/clips/app/i18n/fr-FR.ts +5 -2
  67. package/corpus/templates/clips/app/i18n/hi-IN.ts +5 -2
  68. package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -1
  69. package/corpus/templates/clips/app/i18n/ko-KR.ts +5 -2
  70. package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -2
  71. package/corpus/templates/clips/app/i18n/zh-CN.ts +5 -2
  72. package/corpus/templates/clips/app/i18n/zh-TW.ts +5 -2
  73. package/corpus/templates/clips/app/lib/timestamp-mapping.ts +14 -0
  74. package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -2
  75. package/corpus/templates/clips/app/routes/_index.tsx +1 -2
  76. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +98 -32
  77. package/corpus/templates/clips/app/routes/share.$shareId.tsx +4 -1
  78. package/corpus/templates/clips/changelog/2026-07-15-ai-workflow-generation-now-stays-visible-avoids-duplicate-re.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-15-clip-playback-and-cta-controls-remain-interactive-through-ed.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-15-clip-titles-no-longer-describe-the-product-as-a-loom-alterna.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-15-description-regeneration-now-opens-the-agent-chat-so-progres.md +6 -0
  82. package/corpus/templates/clips/changelog/2026-07-15-direct-recording-urls-now-respect-share-link-and-password-ac.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-07-15-disconnecting-a-calendar-now-clears-unrecorded-synced-meetin.md +6 -0
  84. package/corpus/templates/clips/changelog/2026-07-15-folders-now-expose-rename-and-delete-actions-directly-in-the.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-07-15-recording-pages-now-explain-sign-in-access-and-avoid-showing.md +6 -0
  86. package/corpus/templates/clips/changelog/2026-07-15-the-clips-extension-quick-actions-toolbar-can-be-moved-out-o.md +6 -0
  87. package/corpus/templates/clips/changelog/2026-07-15-the-editor-now-skips-cut-sections-during-preview-and-keeps-t.md +6 -0
  88. package/corpus/templates/clips/changelog/2026-07-15-thumbnail-capture-now-updates-previews-while-scrubbing-and-l.md +6 -0
  89. package/corpus/templates/clips/changelog/2026-07-15-windows-permission-links-open-the-matching-settings-page.md +6 -0
  90. package/corpus/templates/clips/chrome-extension/src/content-script.ts +117 -2
  91. package/corpus/templates/clips/chrome-extension/src/overlay.ts +27 -0
  92. package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -1
  93. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +139 -101
  94. package/corpus/templates/clips/server/lib/recording-page-access.ts +35 -0
  95. package/corpus/templates/clips/server/lib/share-password.ts +6 -3
  96. package/corpus/templates/content/.agents/skills/content/SKILL.md +26 -39
  97. package/corpus/templates/content/AGENTS.md +25 -30
  98. package/corpus/templates/content/actions/_builder-docs-client.ts +23 -0
  99. package/corpus/templates/content/actions/_content-database-source-adapters.ts +21 -3
  100. package/corpus/templates/content/actions/_content-files.ts +338 -0
  101. package/corpus/templates/content/actions/_content-space-access.ts +135 -0
  102. package/corpus/templates/content/actions/_content-spaces.ts +640 -0
  103. package/corpus/templates/content/actions/_database-source-utils.ts +90 -7
  104. package/corpus/templates/content/actions/_database-utils.ts +7 -1
  105. package/corpus/templates/content/actions/_local-file-documents.ts +0 -9
  106. package/corpus/templates/content/actions/_local-folder-source.ts +53 -0
  107. package/corpus/templates/content/actions/_property-utils.ts +9 -4
  108. package/corpus/templates/content/actions/add-database-item.ts +108 -65
  109. package/corpus/templates/content/actions/backfill-content-files.ts +22 -0
  110. package/corpus/templates/content/actions/connect-local-folder-source.ts +221 -0
  111. package/corpus/templates/content/actions/create-content-database.ts +129 -3
  112. package/corpus/templates/content/actions/create-document.ts +65 -55
  113. package/corpus/templates/content/actions/create-inline-content-database.ts +6 -1
  114. package/corpus/templates/content/actions/delete-content-database.ts +3 -0
  115. package/corpus/templates/content/actions/delete-document.ts +7 -11
  116. package/corpus/templates/content/actions/disconnect-local-folder-source.ts +175 -0
  117. package/corpus/templates/content/actions/duplicate-database-item.ts +10 -0
  118. package/corpus/templates/content/actions/duplicate-database-items.ts +13 -0
  119. package/corpus/templates/content/actions/edit-document.ts +2 -28
  120. package/corpus/templates/content/actions/ensure-content-spaces.ts +26 -0
  121. package/corpus/templates/content/actions/export-content-source.ts +47 -9
  122. package/corpus/templates/content/actions/get-document.ts +0 -14
  123. package/corpus/templates/content/actions/import-content-source.ts +43 -3
  124. package/corpus/templates/content/actions/list-content-spaces.ts +103 -0
  125. package/corpus/templates/content/actions/list-documents.ts +12 -9
  126. package/corpus/templates/content/actions/move-document.ts +3 -14
  127. package/corpus/templates/content/actions/pull-document.ts +0 -23
  128. package/corpus/templates/content/actions/remove-local-file-source.ts +50 -29
  129. package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +442 -0
  130. package/corpus/templates/content/actions/reveal-local-source-file.ts +6 -17
  131. package/corpus/templates/content/actions/search-documents.ts +0 -34
  132. package/corpus/templates/content/actions/share-local-file-document.ts +25 -1
  133. package/corpus/templates/content/actions/submit-content-database-form.ts +12 -0
  134. package/corpus/templates/content/actions/sync-local-folder-source.ts +731 -0
  135. package/corpus/templates/content/actions/sync-manifest-local-folder-source.ts +123 -0
  136. package/corpus/templates/content/actions/update-content-database-view.ts +10 -1
  137. package/corpus/templates/content/actions/update-document.ts +0 -15
  138. package/corpus/templates/content/actions/view-screen.ts +2 -50
  139. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +76 -62
  140. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +70 -22
  141. package/corpus/templates/content/app/components/editor/database/grouping.ts +2 -1
  142. package/corpus/templates/content/app/components/editor/database/settings.tsx +23 -20
  143. package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
  144. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +330 -0
  145. package/corpus/templates/content/app/components/editor/database/types.ts +1 -0
  146. package/corpus/templates/content/app/components/editor/database/view-config.ts +3 -1
  147. package/corpus/templates/content/app/components/layout/Layout.tsx +25 -1
  148. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +209 -113
  149. package/corpus/templates/content/app/components/sidebar/select-content-space.ts +31 -0
  150. package/corpus/templates/content/app/hooks/use-content-database.ts +16 -0
  151. package/corpus/templates/content/app/hooks/use-content-spaces.ts +39 -0
  152. package/corpus/templates/content/app/i18n/zh-TW.ts +11 -0
  153. package/corpus/templates/content/app/i18n-data.ts +75 -0
  154. package/corpus/templates/content/app/routes/_app.local-files.tsx +174 -65
  155. package/corpus/templates/content/changelog/2026-07-16-content-callouts-can-now-be-reviewed-and-published-to-builder.md +6 -0
  156. package/corpus/templates/content/changelog/2026-07-16-heading-5-and-heading-6-are-available-from-the-editor-slash-.md +6 -0
  157. package/corpus/templates/content/changelog/2026-07-16-organize-every-workspace-through-a-customizable-files-databa.md +6 -0
  158. package/corpus/templates/content/parity/matrix.md +2 -1
  159. package/corpus/templates/content/parity/matrix.ts +37 -1
  160. package/corpus/templates/content/scripts/dev-database.mjs +7 -5
  161. package/corpus/templates/content/server/db/schema.ts +113 -40
  162. package/corpus/templates/content/server/lib/document-context.ts +15 -1
  163. package/corpus/templates/content/server/lib/notion-sync.ts +6 -0
  164. package/corpus/templates/content/server/plugins/db.ts +153 -0
  165. package/corpus/templates/content/shared/api.ts +17 -3
  166. package/corpus/templates/content/shared/builder-mdx.ts +163 -16
  167. package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +59 -0
  168. package/corpus/templates/design/AGENTS.md +6 -1
  169. package/corpus/templates/design/actions/create-design-from-template.ts +19 -7
  170. package/corpus/templates/design/actions/list-design-templates.ts +69 -21
  171. package/corpus/templates/design/actions/navigate.ts +2 -2
  172. package/corpus/templates/design/actions/view-screen.ts +15 -2
  173. package/corpus/templates/design/agent-native.app-skill.json +5 -0
  174. package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +7 -3
  175. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +281 -56
  176. package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +14 -2
  177. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -2
  178. package/corpus/templates/design/app/i18n/zh-TW.ts +3 -3
  179. package/corpus/templates/design/app/i18n-data.ts +21 -2
  180. package/corpus/templates/design/app/i18n-template-feature.ts +218 -10
  181. package/corpus/templates/design/app/pages/Index.tsx +195 -24
  182. package/corpus/templates/design/app/pages/Templates.tsx +144 -55
  183. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +12 -1
  184. package/corpus/templates/design/changelog/2026-07-14-templates-now-appear-in-the-new-design-picker-with-previews-.md +6 -0
  185. package/corpus/templates/design/changelog/2026-07-15-prototype-print-and-download-buttons-now-work-in-preview.md +6 -0
  186. package/corpus/templates/design/changelog/2026-07-15-templates-now-open-immediately-after-copying-even-while-the-.md +6 -0
  187. package/corpus/templates/design/server/plugins/agent-chat.ts +1 -1
  188. package/corpus/templates/mail/AGENTS.md +23 -18
  189. package/corpus/templates/mail/actions/bulk-archive.ts +32 -28
  190. package/corpus/templates/mail/actions/mark-read.ts +131 -20
  191. package/corpus/templates/mail/actions/mark-thread-read.ts +1 -1
  192. package/corpus/templates/mail/actions/move-email.ts +30 -24
  193. package/corpus/templates/mail/actions/send-email.ts +73 -68
  194. package/corpus/templates/mail/changelog/2026-07-15-unread-inbox-cleanup-now-completes-reliably.md +6 -0
  195. package/corpus/templates/mail/server/handlers/emails.ts +218 -209
  196. package/corpus/templates/mail/server/lib/bulk-mark-read.ts +30 -0
  197. package/corpus/templates/mail/server/lib/email-state.ts +198 -113
  198. package/corpus/templates/mail/server/lib/google-auth.ts +218 -25
  199. package/corpus/templates/mail/server/lib/jobs.ts +69 -74
  200. package/corpus/templates/mail/server/lib/local-email-store.ts +265 -0
  201. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  202. package/corpus/templates/slides/actions/extract-pdf.ts +1 -1
  203. package/corpus/templates/slides/actions/import-file.ts +4 -1
  204. package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
  205. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +9 -12
  206. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +29 -21
  207. package/corpus/templates/slides/app/i18n/ar-SA.ts +1 -0
  208. package/corpus/templates/slides/app/i18n/de-DE.ts +1 -0
  209. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  210. package/corpus/templates/slides/app/i18n/es-ES.ts +1 -0
  211. package/corpus/templates/slides/app/i18n/fr-FR.ts +1 -0
  212. package/corpus/templates/slides/app/i18n/hi-IN.ts +1 -0
  213. package/corpus/templates/slides/app/i18n/ja-JP.ts +1 -0
  214. package/corpus/templates/slides/app/i18n/ko-KR.ts +1 -0
  215. package/corpus/templates/slides/app/i18n/pt-BR.ts +1 -0
  216. package/corpus/templates/slides/app/i18n/zh-CN.ts +1 -0
  217. package/corpus/templates/slides/app/i18n/zh-TW.ts +1 -0
  218. package/corpus/templates/slides/changelog/2026-07-15-image-search-and-generation-controls-now-use-the-registered-.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-07-15-pdf-deck-references-can-be-imported-for-slide-inspiration-ag.md +6 -0
  220. package/corpus/templates/slides/changelog/2026-07-15-stable-style-inspector-dock.md +6 -0
  221. package/dist/cli/content-local.d.ts +1 -0
  222. package/dist/cli/content-local.d.ts.map +1 -1
  223. package/dist/cli/content-local.js +75 -17
  224. package/dist/cli/content-local.js.map +1 -1
  225. package/dist/cli/index.js +2 -2
  226. package/dist/cli/index.js.map +1 -1
  227. package/dist/cli/skills-content/content-skill.d.ts +1 -1
  228. package/dist/cli/skills-content/content-skill.d.ts.map +1 -1
  229. package/dist/cli/skills-content/content-skill.js +36 -25
  230. package/dist/cli/skills-content/content-skill.js.map +1 -1
  231. package/dist/cli/skills.d.ts.map +1 -1
  232. package/dist/cli/skills.js +47 -14
  233. package/dist/cli/skills.js.map +1 -1
  234. package/dist/client/AgentPanel.d.ts.map +1 -1
  235. package/dist/client/AgentPanel.js +5 -0
  236. package/dist/client/AgentPanel.js.map +1 -1
  237. package/dist/client/AssistantChat.d.ts.map +1 -1
  238. package/dist/client/AssistantChat.js +7 -0
  239. package/dist/client/AssistantChat.js.map +1 -1
  240. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  241. package/dist/client/agent-chat-adapter.js +8 -1
  242. package/dist/client/agent-chat-adapter.js.map +1 -1
  243. package/dist/client/chat/message-components.d.ts +4 -0
  244. package/dist/client/chat/message-components.d.ts.map +1 -1
  245. package/dist/client/chat/message-components.js +10 -3
  246. package/dist/client/chat/message-components.js.map +1 -1
  247. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
  248. package/dist/client/composer/ComposerPlusMenu.js +58 -6
  249. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  250. package/dist/client/composer/asset-picker-url.d.ts +16 -0
  251. package/dist/client/composer/asset-picker-url.d.ts.map +1 -0
  252. package/dist/client/composer/asset-picker-url.js +64 -0
  253. package/dist/client/composer/asset-picker-url.js.map +1 -0
  254. package/dist/client/error-format.d.ts.map +1 -1
  255. package/dist/client/error-format.js +17 -0
  256. package/dist/client/error-format.js.map +1 -1
  257. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  258. package/dist/client/resources/McpIntegrationDialog.js +6 -1
  259. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  260. package/dist/collab/awareness.d.ts +2 -2
  261. package/dist/collab/awareness.d.ts.map +1 -1
  262. package/dist/collab/struct-routes.d.ts +1 -1
  263. package/dist/local-artifacts/index.d.ts +10 -0
  264. package/dist/local-artifacts/index.d.ts.map +1 -1
  265. package/dist/local-artifacts/index.js +39 -0
  266. package/dist/local-artifacts/index.js.map +1 -1
  267. package/dist/notifications/routes.d.ts +1 -1
  268. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  269. package/dist/resources/handlers.d.ts +3 -3
  270. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  271. package/dist/server/transcribe-voice.d.ts +1 -1
  272. package/docs/content/local-file-mode.mdx +99 -489
  273. package/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
  274. package/docs/content/locales/ar-SA/template-content.mdx +10 -24
  275. package/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
  276. package/docs/content/locales/de-DE/template-content.mdx +10 -24
  277. package/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
  278. package/docs/content/locales/es-ES/template-content.mdx +10 -24
  279. package/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
  280. package/docs/content/locales/fr-FR/template-content.mdx +10 -24
  281. package/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
  282. package/docs/content/locales/hi-IN/template-content.mdx +10 -24
  283. package/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
  284. package/docs/content/locales/ja-JP/template-content.mdx +10 -24
  285. package/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
  286. package/docs/content/locales/ko-KR/template-content.mdx +10 -24
  287. package/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
  288. package/docs/content/locales/pt-BR/template-content.mdx +10 -24
  289. package/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
  290. package/docs/content/locales/zh-CN/template-content.mdx +9 -24
  291. package/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
  292. package/docs/content/locales/zh-TW/template-content.mdx +9 -24
  293. package/docs/content/template-content.mdx +26 -42
  294. package/package.json +1 -1
  295. package/corpus/templates/assets/app/components/library/EditLibraryDialog.tsx +0 -126
@@ -81,6 +81,11 @@ import {
81
81
  type ExistingBuilderSourceRowIdentity,
82
82
  } from "./_builder-cms-source-adapter.js";
83
83
  import { mergeBuilderCmsWriteSettingsIntoJson } from "./_builder-cms-write-settings.js";
84
+ import { ensureDocumentsFilesMembership } from "./_content-files.js";
85
+ import {
86
+ organizationContentSpaceId,
87
+ provisionContentSpaces,
88
+ } from "./_content-spaces.js";
84
89
  import {
85
90
  databaseItemsPositionScope,
86
91
  documentsPositionScope,
@@ -142,6 +147,9 @@ type SourceMetadataRecord = {
142
147
  allowPublicationTransitions?: boolean;
143
148
  notes?: string | null;
144
149
  readMode?: string | null;
150
+ connectionId?: string | null;
151
+ connectionLabel?: string | null;
152
+ truthPolicy?: ContentDatabaseSource["metadata"]["truthPolicy"];
145
153
  liveReadConfigured?: boolean;
146
154
  lastReadEntryCount?: number;
147
155
  lastReadMatchedRowCount?: number;
@@ -213,7 +221,8 @@ function normalizeSourceType(
213
221
  if (
214
222
  value === "builder-cms" ||
215
223
  value === "local-table" ||
216
- value === "notion-database"
224
+ value === "notion-database" ||
225
+ value === "local-folder"
217
226
  )
218
227
  return value;
219
228
  return "mock-local";
@@ -230,12 +239,9 @@ function normalizeChangeKind(
230
239
  }
231
240
 
232
241
  function normalizeChangeDirection(
233
- _value: string | null | undefined,
242
+ value: string | null | undefined,
234
243
  ): ContentDatabaseSourceChangeDirection {
235
- // Integrations are the source of truth; change-sets only flow outbound
236
- // (local → provider). Any legacy "incoming" rows coerce to outbound and are
237
- // pruned by the resync cleanup.
238
- return "outbound";
244
+ return value === "incoming" ? "incoming" : "outbound";
239
245
  }
240
246
 
241
247
  function normalizePushMode(
@@ -296,6 +302,9 @@ function normalizeCapabilities(
296
302
  canStageLocalRevision: parsed?.canStageLocalRevision === true,
297
303
  liveWritesEnabled: parsed?.liveWritesEnabled === true,
298
304
  readOnlyRefresh: parsed?.readOnlyRefresh !== false,
305
+ canRename: parsed?.canRename === true,
306
+ canReveal: parsed?.canReveal === true,
307
+ canUseLocalComponents: parsed?.canUseLocalComponents === true,
299
308
  };
300
309
  }
301
310
 
@@ -306,6 +315,7 @@ function sourceMetadataLabel(
306
315
  if (sourceType === "builder-cms") return `builder.cms.${sourceTable}`;
307
316
  if (sourceType === "local-table") return `local.table.${sourceTable}`;
308
317
  if (sourceType === "notion-database") return `notion.database.${sourceTable}`;
318
+ if (sourceType === "local-folder") return `local.folder.${sourceTable}`;
309
319
  return `mock-local.${sourceTable}`;
310
320
  }
311
321
 
@@ -3710,6 +3720,14 @@ async function loadSourceSnapshot(
3710
3720
  metadata.allowPublicationTransitions === true,
3711
3721
  notes: metadata.notes ?? null,
3712
3722
  readMode: metadata.readMode ?? null,
3723
+ connectionId: metadata.connectionId ?? null,
3724
+ connectionLabel: metadata.connectionLabel ?? null,
3725
+ truthPolicy:
3726
+ metadata.truthPolicy === "database_primary" ||
3727
+ metadata.truthPolicy === "source_primary" ||
3728
+ metadata.truthPolicy === "reviewed_bidirectional"
3729
+ ? metadata.truthPolicy
3730
+ : undefined,
3713
3731
  liveReadConfigured: metadata.liveReadConfigured === true,
3714
3732
  lastReadEntryCount:
3715
3733
  typeof metadata.lastReadEntryCount === "number"
@@ -5105,6 +5123,7 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
5105
5123
  .select()
5106
5124
  .from(schema.documents)
5107
5125
  .where(eq(schema.documents.id, args.database.documentId));
5126
+ if (!databaseDocument) throw new Error("Database page not found.");
5108
5127
  const currentItems = await db
5109
5128
  .select({
5110
5129
  item: schema.contentDatabaseItems,
@@ -5116,6 +5135,63 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
5116
5135
  eq(schema.documents.id, schema.contentDatabaseItems.documentId),
5117
5136
  )
5118
5137
  .where(eq(schema.contentDatabaseItems.databaseId, args.database.id));
5138
+ let resolvedDatabaseSpaceId =
5139
+ args.database.spaceId ?? databaseDocument.spaceId;
5140
+ if (
5141
+ args.database.spaceId &&
5142
+ databaseDocument.spaceId &&
5143
+ args.database.spaceId !== databaseDocument.spaceId
5144
+ ) {
5145
+ throw new Error(
5146
+ "Database page and database belong to different Content spaces.",
5147
+ );
5148
+ }
5149
+ if (!resolvedDatabaseSpaceId) {
5150
+ const provisioned = await provisionContentSpaces(
5151
+ db,
5152
+ args.database.ownerEmail,
5153
+ );
5154
+ const legacyOrgId = args.database.orgId ?? databaseDocument.orgId;
5155
+ resolvedDatabaseSpaceId = legacyOrgId
5156
+ ? organizationContentSpaceId(legacyOrgId)
5157
+ : provisioned.personalSpaceId;
5158
+ }
5159
+ const databaseSpaceId = resolvedDatabaseSpaceId;
5160
+ if (
5161
+ currentItems.some(
5162
+ (row) => row.document.spaceId && row.document.spaceId !== databaseSpaceId,
5163
+ )
5164
+ ) {
5165
+ throw new Error("Database contains a row from a different Content space.");
5166
+ }
5167
+ const legacyDocumentIds = [
5168
+ databaseDocument.id,
5169
+ ...currentItems
5170
+ .filter((row) => !row.document.spaceId)
5171
+ .map((row) => row.document.id),
5172
+ ];
5173
+ if (
5174
+ args.database.spaceId !== databaseSpaceId ||
5175
+ databaseDocument.spaceId !== databaseSpaceId ||
5176
+ legacyDocumentIds.length > 1
5177
+ ) {
5178
+ await db.transaction(async (tx) => {
5179
+ await tx
5180
+ .update(schema.contentDatabases)
5181
+ .set({ spaceId: databaseSpaceId, updatedAt: args.now })
5182
+ .where(eq(schema.contentDatabases.id, args.database.id));
5183
+ await tx
5184
+ .update(schema.documents)
5185
+ .set({ spaceId: databaseSpaceId, updatedAt: args.now })
5186
+ .where(inArray(schema.documents.id, legacyDocumentIds));
5187
+ await ensureDocumentsFilesMembership(
5188
+ tx,
5189
+ legacyDocumentIds,
5190
+ args.now,
5191
+ args.database.ownerEmail,
5192
+ );
5193
+ });
5194
+ }
5119
5195
  const representedDocumentIds = new Set(
5120
5196
  (args.existingSourceRows ?? [])
5121
5197
  .map((row) => row.documentId)
@@ -5196,6 +5272,7 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
5196
5272
  );
5197
5273
  documentRows.push({
5198
5274
  id: documentId,
5275
+ spaceId: databaseSpaceId,
5199
5276
  ownerEmail: args.database.ownerEmail,
5200
5277
  orgId: args.database.orgId,
5201
5278
  parentId: args.database.documentId,
@@ -5226,7 +5303,7 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
5226
5303
  await db.transaction(async (tx) => {
5227
5304
  for (const chunk of chunks(
5228
5305
  documentRows,
5229
- bulkChunkSizeForColumnCount(13),
5306
+ bulkChunkSizeForColumnCount(14),
5230
5307
  )) {
5231
5308
  await tx
5232
5309
  .insert(schema.documents)
@@ -5242,6 +5319,12 @@ export async function importBuilderCmsEntriesAsDatabaseItems(args: {
5242
5319
  .values(chunk)
5243
5320
  .onConflictDoNothing();
5244
5321
  }
5322
+ await ensureDocumentsFilesMembership(
5323
+ tx,
5324
+ documentRows.map((row) => row.id),
5325
+ args.now,
5326
+ args.database.ownerEmail,
5327
+ );
5245
5328
  });
5246
5329
 
5247
5330
  return { imported: itemRows.length, importedEntriesByDocumentId };
@@ -43,6 +43,7 @@ type DocumentListRow = Omit<typeof schema.documents.$inferSelect, "content">;
43
43
  // string below; opened documents use their dedicated document read path instead.
44
44
  export const contentDatabaseListDocumentSelection = {
45
45
  id: schema.documents.id,
46
+ spaceId: schema.documents.spaceId,
46
47
  parentId: schema.documents.parentId,
47
48
  title: schema.documents.title,
48
49
  description: schema.documents.description,
@@ -462,7 +463,12 @@ export async function getDatabaseItemByDocumentId(
462
463
  schema.contentDatabaseItems.id,
463
464
  ),
464
465
  )
465
- .where(and(...clauses));
466
+ .where(and(...clauses))
467
+ .orderBy(
468
+ sql`CASE WHEN ${schema.contentDatabaseSourceRows.sourceId} IS NOT NULL THEN 0 ELSE 1 END`,
469
+ sql`CASE WHEN ${schema.contentDatabases.systemRole} IS NULL THEN 0 ELSE 1 END`,
470
+ asc(schema.contentDatabases.id),
471
+ );
466
472
  return row ?? null;
467
473
  }
468
474
 
@@ -4,7 +4,6 @@ import {
4
4
  deleteLocalArtifactFile,
5
5
  ensureLocalArtifactRoot,
6
6
  getLocalArtifactApp,
7
- isAgentNativeLocalFileMode,
8
7
  loadAgentNativeManifest,
9
8
  listLocalArtifactFiles,
10
9
  readLocalArtifactFile,
@@ -57,13 +56,6 @@ function localOptions(): LocalArtifactOptions {
57
56
  };
58
57
  }
59
58
 
60
- export async function isContentLocalFileMode() {
61
- return isAgentNativeLocalFileMode({
62
- appId: CONTENT_APP_ID,
63
- defaults: CONTENT_LOCAL_DEFAULTS,
64
- });
65
- }
66
-
67
59
  function encodeIdPath(filePath: string): string {
68
60
  return Buffer.from(filePath, "utf8").toString("base64url");
69
61
  }
@@ -242,7 +234,6 @@ function localFileDocumentsCacheScope() {
242
234
  return JSON.stringify({
243
235
  manifest: process.env.AGENT_NATIVE_MANIFEST,
244
236
  manifestPath: process.env.AGENT_NATIVE_MANIFEST_PATH,
245
- mode: process.env.AGENT_NATIVE_MODE,
246
237
  dataMode: process.env.AGENT_NATIVE_DATA_MODE,
247
238
  });
248
239
  }
@@ -0,0 +1,53 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import type {
4
+ ContentDatabaseSourceCapabilities,
5
+ ContentDatabaseSourceTruthPolicy,
6
+ } from "../shared/api.js";
7
+
8
+ export const LOCAL_FOLDER_SOURCE_TYPE = "local-folder" as const;
9
+
10
+ export function localFolderSourceId(databaseId: string, connectionId: string) {
11
+ return `content_database_source_local_folder_${createHash("sha256")
12
+ .update(`${databaseId}:${connectionId}`)
13
+ .digest("hex")
14
+ .slice(0, 32)}`;
15
+ }
16
+
17
+ export function localFolderSourceCapabilities(): ContentDatabaseSourceCapabilities {
18
+ return {
19
+ canRefresh: true,
20
+ canCreateChangeSets: true,
21
+ canWriteFields: true,
22
+ canWriteBody: true,
23
+ canPush: true,
24
+ canPull: true,
25
+ canPublish: false,
26
+ canDelete: true,
27
+ canStageLocalRevision: true,
28
+ liveWritesEnabled: false,
29
+ readOnlyRefresh: false,
30
+ canRename: true,
31
+ canReveal: true,
32
+ canUseLocalComponents: true,
33
+ };
34
+ }
35
+
36
+ export function localFolderSourceMetadata(input: {
37
+ connectionId: string;
38
+ label: string;
39
+ truthPolicy: ContentDatabaseSourceTruthPolicy;
40
+ }) {
41
+ return {
42
+ primaryKey: "relative_path",
43
+ naturalKeyField: "relative_path",
44
+ titleField: "title",
45
+ readMode: "trusted-local-bridge",
46
+ connectionId: input.connectionId,
47
+ connectionLabel: input.label,
48
+ truthPolicy: input.truthPolicy,
49
+ writeMode: "stage_only" as const,
50
+ notes:
51
+ "The trusted local bridge owns the folder handle or path; SQL stores only this opaque connection identity.",
52
+ };
53
+ }
@@ -184,8 +184,10 @@ export function serializeDatabaseViewConfig(
184
184
  return JSON.stringify(normalizeDatabaseViewConfig(value));
185
185
  }
186
186
 
187
- function defaultDatabaseViewConfig(): ContentDatabaseViewConfig {
188
- const view = defaultDatabaseView();
187
+ export function defaultDatabaseViewConfig(
188
+ type: ContentDatabaseView["type"] = "table",
189
+ ): ContentDatabaseViewConfig {
190
+ const view = defaultDatabaseView({}, type);
189
191
  return {
190
192
  activeViewId: view.id,
191
193
  views: [view],
@@ -258,7 +260,9 @@ function defaultDatabaseView(
258
260
  ? "Timeline"
259
261
  : type === "form"
260
262
  ? "Form"
261
- : "Table",
263
+ : type === "sidebar"
264
+ ? "Sidebar"
265
+ : "Table",
262
266
  type,
263
267
  sorts: values.sorts ?? [],
264
268
  filters: values.filters ?? [],
@@ -289,7 +293,8 @@ function normalizeDatabaseView(value: unknown): ContentDatabaseView | null {
289
293
  view.type === "gallery" ||
290
294
  view.type === "calendar" ||
291
295
  view.type === "timeline" ||
292
- view.type === "form"
296
+ view.type === "form" ||
297
+ view.type === "sidebar"
293
298
  ? view.type
294
299
  : "table";
295
300
  return {
@@ -10,6 +10,7 @@ import {
10
10
  isComputedPropertyType,
11
11
  type DocumentPropertyType,
12
12
  } from "../shared/properties.js";
13
+ import { ensureDocumentFilesMembership } from "./_content-files.js";
13
14
  import { getContentDatabaseResponse } from "./_database-utils.js";
14
15
  import {
15
16
  databaseItemsPositionScope,
@@ -47,60 +48,42 @@ export default defineAction({
47
48
  "editor",
48
49
  );
49
50
  const databaseDocument = access.resource;
51
+ if (
52
+ database.spaceId &&
53
+ databaseDocument.spaceId &&
54
+ databaseDocument.spaceId !== database.spaceId
55
+ ) {
56
+ throw new Error(
57
+ `Database "${databaseId}" has inconsistent Content space`,
58
+ );
59
+ }
50
60
  const now = new Date().toISOString();
61
+ const databaseSpaceId =
62
+ database.spaceId ?? (databaseDocument.spaceId as string | null);
63
+ if (!databaseSpaceId) {
64
+ throw new Error("Database does not belong to a Content space.");
65
+ }
66
+ if (databaseSpaceId && (!database.spaceId || !databaseDocument.spaceId)) {
67
+ await db.transaction(async (tx) => {
68
+ if (!database.spaceId) {
69
+ await tx
70
+ .update(schema.contentDatabases)
71
+ .set({ spaceId: databaseSpaceId, updatedAt: now })
72
+ .where(eq(schema.contentDatabases.id, databaseId));
73
+ }
74
+ if (!databaseDocument.spaceId) {
75
+ await tx
76
+ .update(schema.documents)
77
+ .set({ spaceId: databaseSpaceId, updatedAt: now })
78
+ .where(eq(schema.documents.id, database.documentId));
79
+ }
80
+ await ensureDocumentFilesMembership(tx, database.documentId, now);
81
+ });
82
+ }
51
83
 
52
84
  const documentId = nanoid();
53
85
  const itemId = nanoid();
54
86
 
55
- await withPositionLock(
56
- documentsPositionScope(database.ownerEmail, database.documentId),
57
- async () => {
58
- const [maxDocPos] = await db
59
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
60
- .from(schema.documents)
61
- .where(
62
- and(
63
- eq(schema.documents.ownerEmail, database.ownerEmail),
64
- eq(schema.documents.parentId, database.documentId),
65
- ),
66
- );
67
-
68
- await db.insert(schema.documents).values({
69
- id: documentId,
70
- ownerEmail: database.ownerEmail,
71
- orgId: database.orgId,
72
- parentId: database.documentId,
73
- title: title?.trim() ?? "",
74
- content: "",
75
- icon: null,
76
- position: (maxDocPos?.max ?? -1) + 1,
77
- isFavorite: 0,
78
- hideFromSearch: databaseDocument.hideFromSearch ?? 0,
79
- visibility: databaseDocument.visibility ?? "private",
80
- createdAt: now,
81
- updatedAt: now,
82
- });
83
- },
84
- );
85
-
86
- await withPositionLock(databaseItemsPositionScope(databaseId), async () => {
87
- const [maxItemPos] = await db
88
- .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
89
- .from(schema.contentDatabaseItems)
90
- .where(eq(schema.contentDatabaseItems.databaseId, databaseId));
91
-
92
- await db.insert(schema.contentDatabaseItems).values({
93
- id: itemId,
94
- ownerEmail: database.ownerEmail,
95
- orgId: database.orgId,
96
- databaseId,
97
- documentId,
98
- position: (maxItemPos?.max ?? -1) + 1,
99
- createdAt: now,
100
- updatedAt: now,
101
- });
102
- });
103
-
104
87
  const inheritedShares = await db
105
88
  .select({
106
89
  principalType: schema.documentShares.principalType,
@@ -110,21 +93,10 @@ export default defineAction({
110
93
  .from(schema.documentShares)
111
94
  .where(eq(schema.documentShares.resourceId, database.documentId));
112
95
 
113
- if (inheritedShares.length > 0) {
114
- await db.insert(schema.documentShares).values(
115
- inheritedShares.map((share) => ({
116
- id: nanoid(),
117
- resourceId: documentId,
118
- principalType: share.principalType,
119
- principalId: share.principalId,
120
- role: share.role,
121
- createdBy: getRequestUserEmail() ?? database.ownerEmail,
122
- createdAt: now,
123
- })),
124
- );
125
- }
126
-
127
96
  const initialValues = Object.entries(propertyValues ?? {});
97
+ const propertyValueRows: Array<
98
+ typeof schema.documentPropertyValues.$inferInsert
99
+ > = [];
128
100
  if (initialValues.length > 0) {
129
101
  const requestedPropertyIds = initialValues.map(
130
102
  ([propertyId]) => propertyId,
@@ -153,7 +125,7 @@ export default defineAction({
153
125
  const definition = definitionById.get(propertyId);
154
126
  const type = definition?.type as DocumentPropertyType | undefined;
155
127
  if (!definition || !type || isComputedPropertyType(type)) continue;
156
- await db.insert(schema.documentPropertyValues).values({
128
+ propertyValueRows.push({
157
129
  id: nanoid(),
158
130
  ownerEmail: database.ownerEmail,
159
131
  documentId,
@@ -165,7 +137,78 @@ export default defineAction({
165
137
  }
166
138
  }
167
139
 
168
- await writeAppState("refresh-signal", { ts: Date.now() });
140
+ await withPositionLock(
141
+ documentsPositionScope(database.ownerEmail, database.documentId),
142
+ () =>
143
+ withPositionLock(databaseItemsPositionScope(databaseId), async () => {
144
+ await db.transaction(async (tx) => {
145
+ const [maxDocPos] = await tx
146
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
147
+ .from(schema.documents)
148
+ .where(
149
+ and(
150
+ eq(schema.documents.ownerEmail, database.ownerEmail),
151
+ eq(schema.documents.parentId, database.documentId),
152
+ ),
153
+ );
154
+ const [maxItemPos] = await tx
155
+ .select({ max: sql<number>`COALESCE(MAX(position), -1)` })
156
+ .from(schema.contentDatabaseItems)
157
+ .where(eq(schema.contentDatabaseItems.databaseId, databaseId));
158
+
159
+ await tx.insert(schema.documents).values({
160
+ id: documentId,
161
+ spaceId: databaseSpaceId,
162
+ ownerEmail: database.ownerEmail,
163
+ orgId: database.orgId,
164
+ parentId: database.documentId,
165
+ title: title?.trim() ?? "",
166
+ content: "",
167
+ icon: null,
168
+ position: (maxDocPos?.max ?? -1) + 1,
169
+ isFavorite: 0,
170
+ hideFromSearch: databaseDocument.hideFromSearch ?? 0,
171
+ visibility: databaseDocument.visibility ?? "private",
172
+ createdAt: now,
173
+ updatedAt: now,
174
+ });
175
+ await tx.insert(schema.contentDatabaseItems).values({
176
+ id: itemId,
177
+ ownerEmail: database.ownerEmail,
178
+ orgId: database.orgId,
179
+ databaseId,
180
+ documentId,
181
+ position: (maxItemPos?.max ?? -1) + 1,
182
+ createdAt: now,
183
+ updatedAt: now,
184
+ });
185
+ if (inheritedShares.length > 0) {
186
+ await tx.insert(schema.documentShares).values(
187
+ inheritedShares.map((share) => ({
188
+ id: nanoid(),
189
+ resourceId: documentId,
190
+ principalType: share.principalType,
191
+ principalId: share.principalId,
192
+ role: share.role,
193
+ createdBy: getRequestUserEmail() ?? database.ownerEmail,
194
+ createdAt: now,
195
+ })),
196
+ );
197
+ }
198
+ if (propertyValueRows.length > 0) {
199
+ await tx
200
+ .insert(schema.documentPropertyValues)
201
+ .values(propertyValueRows);
202
+ }
203
+ await ensureDocumentFilesMembership(tx, documentId, now);
204
+ });
205
+ }),
206
+ );
207
+
208
+ await writeAppState("refresh-signal", { ts: Date.now() }).catch(() => {
209
+ // The row is already committed; polling will reconcile if a concurrent
210
+ // SQLite writer briefly blocks this best-effort refresh hint.
211
+ });
169
212
 
170
213
  return {
171
214
  ...(await getContentDatabaseResponse(databaseId)),
@@ -0,0 +1,22 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { writeAppState } from "@agent-native/core/application-state";
3
+ import { getRequestUserEmail } from "@agent-native/core/server/request-context";
4
+ import { z } from "zod";
5
+
6
+ import { getDb } from "../server/db/index.js";
7
+ import { reconcileContentFilesMemberships } from "./_content-files.js";
8
+ import { provisionContentSpaces } from "./_content-spaces.js";
9
+
10
+ export default defineAction({
11
+ description:
12
+ "Assign legacy pages to Content spaces and reconcile their canonical Files database memberships.",
13
+ schema: z.object({}),
14
+ run: async () => {
15
+ const userEmail = getRequestUserEmail();
16
+ if (!userEmail) throw new Error("no authenticated user");
17
+ await provisionContentSpaces(getDb(), userEmail);
18
+ const result = await reconcileContentFilesMemberships(getDb(), userEmail);
19
+ await writeAppState("refresh-signal", { ts: Date.now() });
20
+ return result;
21
+ },
22
+ });