@agent-native/core 0.102.2 → 0.103.1

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 (205) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -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/local-artifacts/index.ts +65 -0
  31. package/corpus/core/src/vite/client.ts +2 -0
  32. package/corpus/templates/assets/app/components/library/GenerationPresetsPanel.tsx +325 -0
  33. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +12 -0
  34. package/corpus/templates/assets/app/i18n/zh-TW.ts +21 -0
  35. package/corpus/templates/assets/app/i18n-data.ts +215 -0
  36. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +19 -479
  37. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1 -1
  38. package/corpus/templates/assets/app/routes/brand-kits.$id_.settings.tsx +446 -0
  39. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +12 -2
  40. package/corpus/templates/clips/app/components/player/settings-panel.tsx +30 -12
  41. package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
  42. package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +22 -3
  43. package/corpus/templates/clips/app/i18n/ar-SA.ts +3 -2
  44. package/corpus/templates/clips/app/i18n/de-DE.ts +4 -2
  45. package/corpus/templates/clips/app/i18n/en-US.ts +3 -2
  46. package/corpus/templates/clips/app/i18n/es-ES.ts +4 -2
  47. package/corpus/templates/clips/app/i18n/fr-FR.ts +3 -2
  48. package/corpus/templates/clips/app/i18n/hi-IN.ts +3 -2
  49. package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -1
  50. package/corpus/templates/clips/app/i18n/ko-KR.ts +3 -2
  51. package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -2
  52. package/corpus/templates/clips/app/i18n/zh-CN.ts +3 -2
  53. package/corpus/templates/clips/app/i18n/zh-TW.ts +3 -2
  54. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +27 -1
  55. package/corpus/templates/clips/server/lib/share-password.ts +6 -3
  56. package/corpus/templates/content/.agents/skills/content/SKILL.md +26 -39
  57. package/corpus/templates/content/AGENTS.md +25 -30
  58. package/corpus/templates/content/actions/_builder-docs-client.ts +23 -0
  59. package/corpus/templates/content/actions/_content-database-source-adapters.ts +21 -3
  60. package/corpus/templates/content/actions/_content-files.ts +338 -0
  61. package/corpus/templates/content/actions/_content-space-access.ts +135 -0
  62. package/corpus/templates/content/actions/_content-spaces.ts +640 -0
  63. package/corpus/templates/content/actions/_database-source-utils.ts +90 -7
  64. package/corpus/templates/content/actions/_database-utils.ts +7 -1
  65. package/corpus/templates/content/actions/_local-file-documents.ts +0 -9
  66. package/corpus/templates/content/actions/_local-folder-source.ts +53 -0
  67. package/corpus/templates/content/actions/_property-utils.ts +9 -4
  68. package/corpus/templates/content/actions/add-database-item.ts +108 -65
  69. package/corpus/templates/content/actions/backfill-content-files.ts +22 -0
  70. package/corpus/templates/content/actions/connect-local-folder-source.ts +221 -0
  71. package/corpus/templates/content/actions/create-content-database.ts +129 -3
  72. package/corpus/templates/content/actions/create-document.ts +65 -55
  73. package/corpus/templates/content/actions/create-inline-content-database.ts +6 -1
  74. package/corpus/templates/content/actions/delete-content-database.ts +3 -0
  75. package/corpus/templates/content/actions/delete-document.ts +7 -11
  76. package/corpus/templates/content/actions/disconnect-local-folder-source.ts +175 -0
  77. package/corpus/templates/content/actions/duplicate-database-item.ts +10 -0
  78. package/corpus/templates/content/actions/duplicate-database-items.ts +13 -0
  79. package/corpus/templates/content/actions/edit-document.ts +2 -28
  80. package/corpus/templates/content/actions/ensure-content-spaces.ts +26 -0
  81. package/corpus/templates/content/actions/export-content-source.ts +47 -9
  82. package/corpus/templates/content/actions/get-document.ts +0 -14
  83. package/corpus/templates/content/actions/import-content-source.ts +43 -3
  84. package/corpus/templates/content/actions/list-content-spaces.ts +103 -0
  85. package/corpus/templates/content/actions/list-documents.ts +12 -9
  86. package/corpus/templates/content/actions/move-document.ts +3 -14
  87. package/corpus/templates/content/actions/pull-document.ts +0 -23
  88. package/corpus/templates/content/actions/remove-local-file-source.ts +50 -29
  89. package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +442 -0
  90. package/corpus/templates/content/actions/reveal-local-source-file.ts +6 -17
  91. package/corpus/templates/content/actions/search-documents.ts +0 -34
  92. package/corpus/templates/content/actions/share-local-file-document.ts +25 -1
  93. package/corpus/templates/content/actions/submit-content-database-form.ts +12 -0
  94. package/corpus/templates/content/actions/sync-local-folder-source.ts +731 -0
  95. package/corpus/templates/content/actions/sync-manifest-local-folder-source.ts +123 -0
  96. package/corpus/templates/content/actions/update-content-database-view.ts +10 -1
  97. package/corpus/templates/content/actions/update-document.ts +0 -15
  98. package/corpus/templates/content/actions/view-screen.ts +2 -50
  99. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +76 -62
  100. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +70 -22
  101. package/corpus/templates/content/app/components/editor/database/grouping.ts +2 -1
  102. package/corpus/templates/content/app/components/editor/database/settings.tsx +23 -20
  103. package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
  104. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +330 -0
  105. package/corpus/templates/content/app/components/editor/database/types.ts +1 -0
  106. package/corpus/templates/content/app/components/editor/database/view-config.ts +3 -1
  107. package/corpus/templates/content/app/components/layout/Layout.tsx +25 -1
  108. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +209 -113
  109. package/corpus/templates/content/app/components/sidebar/select-content-space.ts +31 -0
  110. package/corpus/templates/content/app/hooks/use-content-database.ts +16 -0
  111. package/corpus/templates/content/app/hooks/use-content-spaces.ts +39 -0
  112. package/corpus/templates/content/app/i18n/zh-TW.ts +11 -0
  113. package/corpus/templates/content/app/i18n-data.ts +75 -0
  114. package/corpus/templates/content/app/routes/_app.local-files.tsx +174 -65
  115. package/corpus/templates/content/changelog/2026-07-16-content-callouts-can-now-be-reviewed-and-published-to-builder.md +6 -0
  116. package/corpus/templates/content/changelog/2026-07-16-heading-5-and-heading-6-are-available-from-the-editor-slash-.md +6 -0
  117. package/corpus/templates/content/changelog/2026-07-16-organize-every-workspace-through-a-customizable-files-databa.md +6 -0
  118. package/corpus/templates/content/parity/matrix.md +2 -1
  119. package/corpus/templates/content/parity/matrix.ts +37 -1
  120. package/corpus/templates/content/scripts/dev-database.mjs +7 -5
  121. package/corpus/templates/content/server/db/schema.ts +113 -40
  122. package/corpus/templates/content/server/lib/document-context.ts +15 -1
  123. package/corpus/templates/content/server/lib/notion-sync.ts +6 -0
  124. package/corpus/templates/content/server/plugins/db.ts +153 -0
  125. package/corpus/templates/content/shared/api.ts +17 -3
  126. package/corpus/templates/content/shared/builder-mdx.ts +163 -16
  127. package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +59 -0
  128. package/corpus/templates/design/AGENTS.md +6 -1
  129. package/corpus/templates/design/actions/create-design-from-template.ts +19 -7
  130. package/corpus/templates/design/actions/list-design-templates.ts +69 -21
  131. package/corpus/templates/design/actions/navigate.ts +2 -2
  132. package/corpus/templates/design/actions/view-screen.ts +15 -2
  133. package/corpus/templates/design/agent-native.app-skill.json +5 -0
  134. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +281 -56
  135. package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +14 -2
  136. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -2
  137. package/corpus/templates/design/app/i18n/zh-TW.ts +3 -3
  138. package/corpus/templates/design/app/i18n-data.ts +21 -2
  139. package/corpus/templates/design/app/i18n-template-feature.ts +218 -10
  140. package/corpus/templates/design/app/pages/Index.tsx +195 -24
  141. package/corpus/templates/design/app/pages/Templates.tsx +144 -55
  142. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +12 -1
  143. package/corpus/templates/design/changelog/2026-07-14-templates-now-appear-in-the-new-design-picker-with-previews-.md +6 -0
  144. package/corpus/templates/design/changelog/2026-07-15-templates-now-open-immediately-after-copying-even-while-the-.md +6 -0
  145. package/corpus/templates/design/server/plugins/agent-chat.ts +1 -1
  146. package/corpus/templates/mail/AGENTS.md +23 -18
  147. package/corpus/templates/mail/actions/bulk-archive.ts +32 -28
  148. package/corpus/templates/mail/actions/mark-read.ts +131 -20
  149. package/corpus/templates/mail/actions/mark-thread-read.ts +1 -1
  150. package/corpus/templates/mail/actions/move-email.ts +30 -24
  151. package/corpus/templates/mail/actions/send-email.ts +73 -68
  152. package/corpus/templates/mail/changelog/2026-07-15-unread-inbox-cleanup-now-completes-reliably.md +6 -0
  153. package/corpus/templates/mail/server/handlers/emails.ts +218 -209
  154. package/corpus/templates/mail/server/lib/bulk-mark-read.ts +30 -0
  155. package/corpus/templates/mail/server/lib/email-state.ts +198 -113
  156. package/corpus/templates/mail/server/lib/google-auth.ts +218 -25
  157. package/corpus/templates/mail/server/lib/jobs.ts +69 -74
  158. package/corpus/templates/mail/server/lib/local-email-store.ts +265 -0
  159. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  160. package/dist/cli/content-local.d.ts +1 -0
  161. package/dist/cli/content-local.d.ts.map +1 -1
  162. package/dist/cli/content-local.js +75 -17
  163. package/dist/cli/content-local.js.map +1 -1
  164. package/dist/cli/index.js +2 -2
  165. package/dist/cli/index.js.map +1 -1
  166. package/dist/cli/skills-content/content-skill.d.ts +1 -1
  167. package/dist/cli/skills-content/content-skill.d.ts.map +1 -1
  168. package/dist/cli/skills-content/content-skill.js +36 -25
  169. package/dist/cli/skills-content/content-skill.js.map +1 -1
  170. package/dist/cli/skills.d.ts.map +1 -1
  171. package/dist/cli/skills.js +47 -14
  172. package/dist/cli/skills.js.map +1 -1
  173. package/dist/collab/struct-routes.d.ts +1 -1
  174. package/dist/local-artifacts/index.d.ts +10 -0
  175. package/dist/local-artifacts/index.d.ts.map +1 -1
  176. package/dist/local-artifacts/index.js +39 -0
  177. package/dist/local-artifacts/index.js.map +1 -1
  178. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  179. package/dist/vite/client.d.ts.map +1 -1
  180. package/dist/vite/client.js +2 -0
  181. package/dist/vite/client.js.map +1 -1
  182. package/docs/content/local-file-mode.mdx +99 -489
  183. package/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
  184. package/docs/content/locales/ar-SA/template-content.mdx +10 -24
  185. package/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
  186. package/docs/content/locales/de-DE/template-content.mdx +10 -24
  187. package/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
  188. package/docs/content/locales/es-ES/template-content.mdx +10 -24
  189. package/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
  190. package/docs/content/locales/fr-FR/template-content.mdx +10 -24
  191. package/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
  192. package/docs/content/locales/hi-IN/template-content.mdx +10 -24
  193. package/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
  194. package/docs/content/locales/ja-JP/template-content.mdx +10 -24
  195. package/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
  196. package/docs/content/locales/ko-KR/template-content.mdx +10 -24
  197. package/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
  198. package/docs/content/locales/pt-BR/template-content.mdx +10 -24
  199. package/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
  200. package/docs/content/locales/zh-CN/template-content.mdx +9 -24
  201. package/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
  202. package/docs/content/locales/zh-TW/template-content.mdx +9 -24
  203. package/docs/content/template-content.mdx +26 -42
  204. package/package.json +1 -1
  205. package/corpus/templates/assets/app/components/library/EditLibraryDialog.tsx +0 -126
@@ -1214,9 +1214,10 @@ Clips में उपयोगकर्ताओं को दिखने व
1214
1214
  visibilityOrg: "Organization (स्थानीयकृत)",
1215
1215
  visibilityPublic: "Public (स्थानीयकृत)",
1216
1216
  passwordProtection: "Password protection (स्थानीयकृत)",
1217
- passwordSetPlaceholder:
1218
- "Password is set — type to replace, leave empty + Save to clear (स्थानीयकृत)",
1217
+ passwordSetPlaceholder: "Password is set — type to replace (स्थानीयकृत)",
1219
1218
  noPasswordPlaceholder: "No password (स्थानीयकृत)",
1219
+ passwordWhitespaceOnly: "Spaces alone aren't a valid password. (स्थानीयकृत)",
1220
+ removePassword: "Remove (स्थानीयकृत)",
1220
1221
  expiry: "Expiry (स्थानीयकृत)",
1221
1222
  viewerOptions: "Viewer options (स्थानीयकृत)",
1222
1223
  comments: "Comments (स्थानीयकृत)",
@@ -1237,8 +1237,11 @@ Clips のユーザー向けの主な変更はここに記録されます。コ
1237
1237
  visibilityPublic: "Public (ローカライズ済み)",
1238
1238
  passwordProtection: "Password protection (ローカライズ済み)",
1239
1239
  passwordSetPlaceholder:
1240
- "Password is set — type to replace, leave empty + Save to clear (ローカライズ済み)",
1240
+ "Password is set — type to replace (ローカライズ済み)",
1241
1241
  noPasswordPlaceholder: "No password (ローカライズ済み)",
1242
+ passwordWhitespaceOnly:
1243
+ "Spaces alone aren't a valid password. (ローカライズ済み)",
1244
+ removePassword: "Remove (ローカライズ済み)",
1242
1245
  expiry: "Expiry (ローカライズ済み)",
1243
1246
  viewerOptions: "Viewer options (ローカライズ済み)",
1244
1247
  comments: "Comments (ローカライズ済み)",
@@ -1224,9 +1224,10 @@ Clips의 모든 사용자 대상 변경 사항은 여기에 기록됩니다. 명
1224
1224
  visibilityOrg: "Organization (현지화됨)",
1225
1225
  visibilityPublic: "Public (현지화됨)",
1226
1226
  passwordProtection: "Password protection (현지화됨)",
1227
- passwordSetPlaceholder:
1228
- "Password is set — type to replace, leave empty + Save to clear (현지화됨)",
1227
+ passwordSetPlaceholder: "Password is set — type to replace (현지화됨)",
1229
1228
  noPasswordPlaceholder: "No password (현지화됨)",
1229
+ passwordWhitespaceOnly: "Spaces alone aren't a valid password. (현지화됨)",
1230
+ removePassword: "Remove (현지화됨)",
1230
1231
  expiry: "Expiry (현지화됨)",
1231
1232
  viewerOptions: "Viewer options (현지화됨)",
1232
1233
  comments: "Comments (현지화됨)",
@@ -1242,9 +1242,11 @@ Todas as mudanças visíveis para usuários do Clips são documentadas aqui. Voc
1242
1242
  visibilityOrg: "Organization (Localizado)",
1243
1243
  visibilityPublic: "Public (Localizado)",
1244
1244
  passwordProtection: "Password protection (Localizado)",
1245
- passwordSetPlaceholder:
1246
- "Password is set — type to replace, leave empty + Save to clear (Localizado)",
1245
+ passwordSetPlaceholder: "Password is set — type to replace (Localizado)",
1247
1246
  noPasswordPlaceholder: "No password (Localizado)",
1247
+ passwordWhitespaceOnly:
1248
+ "Spaces alone aren't a valid password. (Localizado)",
1249
+ removePassword: "Remove (Localizado)",
1248
1250
  expiry: "Expiry (Localizado)",
1249
1251
  viewerOptions: "Viewer options (Localizado)",
1250
1252
  comments: "Comments (Localizado)",
@@ -1186,9 +1186,10 @@ Clips 中所有面向用户的重要更改都会记录在这里。你可以随
1186
1186
  visibilityOrg: "Organization (已本地化)",
1187
1187
  visibilityPublic: "Public (已本地化)",
1188
1188
  passwordProtection: "Password protection (已本地化)",
1189
- passwordSetPlaceholder:
1190
- "Password is set — type to replace, leave empty + Save to clear (已本地化)",
1189
+ passwordSetPlaceholder: "Password is set — type to replace (已本地化)",
1191
1190
  noPasswordPlaceholder: "No password (已本地化)",
1191
+ passwordWhitespaceOnly: "Spaces alone aren't a valid password. (已本地化)",
1192
+ removePassword: "Remove (已本地化)",
1192
1193
  expiry: "Expiry (已本地化)",
1193
1194
  viewerOptions: "Viewer options (已本地化)",
1194
1195
  comments: "Comments (已本地化)",
@@ -1171,9 +1171,10 @@ const messages = {
1171
1171
  visibilityOrg: "組織",
1172
1172
  visibilityPublic: "公開",
1173
1173
  passwordProtection: "密碼保護",
1174
- passwordSetPlaceholder:
1175
- "已設定密碼。輸入新密碼即可取代;留空並儲存即可清除。",
1174
+ passwordSetPlaceholder: "已設定密碼。輸入新密碼即可取代。",
1176
1175
  noPasswordPlaceholder: "無密碼",
1176
+ passwordWhitespaceOnly: "只有空格不是有效的密碼。",
1177
+ removePassword: "移除",
1177
1178
  expiry: "到期時間",
1178
1179
  viewerOptions: "觀看者選項",
1179
1180
  comments: "留言",
@@ -20,6 +20,7 @@ import {
20
20
  isLoomEmbedBackedRecording,
21
21
  isLoomRecordingSource,
22
22
  } from "@shared/loom";
23
+ import { CLIP_SHARE_REF, REF_PARAM } from "@shared/share-attribution";
23
24
  import {
24
25
  IconShare3,
25
26
  IconArrowLeft,
@@ -336,6 +337,31 @@ export default function RecordingPage() {
336
337
  },
337
338
  );
338
339
 
340
+ const playerDataAccessStatus = playerDataQ.isError
341
+ ? (playerDataQ.error as { status?: number } | undefined)?.status
342
+ : undefined;
343
+ // Signed-out requests never even reach `resolveAccess` — the action route's
344
+ // default auth gate rejects them with 401 first. Authenticated viewers with
345
+ // no share grant (or a deleted/mismatched id) get 403 from `resolveAccess`
346
+ // inside `get-recording-player-data`. Both mean "can't open the direct
347
+ // owner/editor route here".
348
+ const playerDataForbidden =
349
+ playerDataAccessStatus === 401 || playerDataAccessStatus === 403;
350
+
351
+ // A direct `/r/:id` visit without edit/view access (signed out, no share
352
+ // grant, wrong org) can't do anything useful here — send the visitor to the
353
+ // public share flow instead, which knows how to prompt for sign-in or a
354
+ // password.
355
+ useEffect(() => {
356
+ if (!recordingId || !playerDataForbidden) return;
357
+ navigate(
358
+ `/share/${encodeURIComponent(recordingId)}?${REF_PARAM}=${CLIP_SHARE_REF}`,
359
+ {
360
+ replace: true,
361
+ },
362
+ );
363
+ }, [recordingId, playerDataForbidden, navigate]);
364
+
339
365
  const recording = playerDataQ.data?.recording;
340
366
  const role = playerDataQ.data?.role as
341
367
  | "owner"
@@ -717,7 +743,7 @@ export default function RecordingPage() {
717
743
 
718
744
  if (!recordingId) return null;
719
745
 
720
- if (playerDataQ.isLoading) {
746
+ if (playerDataQ.isLoading || playerDataForbidden) {
721
747
  return (
722
748
  <div className="flex items-center justify-center h-screen w-full bg-background">
723
749
  <Spinner className="h-8 w-8" />
@@ -18,13 +18,16 @@ import {
18
18
  } from "@agent-native/core/secrets/crypto";
19
19
 
20
20
  /**
21
- * Encrypt a share password for storage. Empty / nullish clears it (returns
22
- * null), matching the prior `args.password ?? null` semantics.
21
+ * Encrypt a share password for storage. Empty / nullish / whitespace-only
22
+ * input clears it (returns null), matching the prior `args.password ?? null`
23
+ * semantics while also rejecting spaces-only "passwords". Real values are
24
+ * trimmed so accidental leading/trailing whitespace doesn't get baked into
25
+ * the stored password.
23
26
  */
24
27
  export function encryptSharePassword(
25
28
  raw: string | null | undefined,
26
29
  ): string | null {
27
- const value = typeof raw === "string" ? raw : "";
30
+ const value = typeof raw === "string" ? raw.trim() : "";
28
31
  if (!value) return null;
29
32
  return encryptSecretValue(value);
30
33
  }
@@ -3,7 +3,7 @@ name: content
3
3
  description: >-
4
4
  Use Content for repo-backed Markdown/MDX docs, blogs, resources, rich
5
5
  document editing, Notion-style databases and boards, structured intake
6
- forms, local components, shareable copies, and Content local-file workspaces.
6
+ forms, local components, shareable copies, and connected local folders.
7
7
  Prefer Content actions over raw filesystem writes when available.
8
8
  metadata:
9
9
  visibility: exported
@@ -17,7 +17,7 @@ marketing pages, internal notes, and local MDX components. Also use Content for
17
17
  Notion-style databases, tables, boards, structured request intake, and forms
18
18
  whose submissions become database row pages. Content gives the agent a document
19
19
  tree, a rich editor, structured database properties and views, normal document
20
- actions, and an optional local-file source of truth.
20
+ actions, and local folders that sync into the same database model.
21
21
 
22
22
  ## Choose The Path
23
23
 
@@ -33,9 +33,9 @@ actions, and an optional local-file source of truth.
33
33
  its exact title, then inspect it with `get-content-database` before creating
34
34
  or submitting anything. Do not create a second database when the canonical
35
35
  one already exists.
36
- - In Local File Mode, Content actions read and write the repo files declared in
37
- `agent-native.json`; SQL remains cache/history/search glue, not the source of
38
- truth for those pages.
36
+ - Local folders are sources attached to a space's canonical Files database.
37
+ Imported pages are normal SQL-backed Content documents; the trusted local
38
+ bridge handles pull, export, stable file identity, and conflict review.
39
39
  - If Content tools are not visible and no local Content app or Desktop bridge is
40
40
  running, treat this skill as repo-editing guidance. Edit configured
41
41
  `.md`/`.mdx` files directly, preserve frontmatter and MDX imports, and tell
@@ -47,10 +47,10 @@ Prefer JSON input for action calls:
47
47
 
48
48
  ```bash
49
49
  pnpm action list-documents
50
- pnpm action get-document '{"id":"local-file:..."}'
51
- pnpm action edit-document '{"id":"local-file:...","find":"old copy","replace":"new copy"}'
52
- pnpm action update-document '{"id":"local-file:...","content":"# Updated\n\nBody"}'
53
- pnpm action share-local-file-document '{"id":"local-file:..."}'
50
+ pnpm action get-document '{"id":"<document-id>"}'
51
+ pnpm action edit-document '{"id":"<document-id>","find":"old copy","replace":"new copy"}'
52
+ pnpm action update-document '{"id":"<document-id>","content":"# Updated\n\nBody"}'
53
+ pnpm action connect-local-folder-source '{"connectionId":"<opaque-bridge-id>","label":"Docs","createSourceBackedSpace":true,"truthPolicy":"source_primary"}'
54
54
  ```
55
55
 
56
56
  Run `refresh-list` after create/update/delete operations when you need the open
@@ -132,7 +132,7 @@ guesswork:
132
132
  writing. If a named person cannot be resolved unambiguously, clarify in the
133
133
  originating Slack thread; never omit, downgrade, or silently drop the person.
134
134
 
135
- ## Local File Mode
135
+ ## Local Folder Sources
136
136
 
137
137
  Install into an existing repo with:
138
138
 
@@ -140,40 +140,27 @@ Install into an existing repo with:
140
140
  npx @agent-native/core@latest skills add content --mode local-files --scope project
141
141
  ```
142
142
 
143
- The installer copies this skill and writes or updates `agent-native.json` with
144
- Content roots for `docs/`, `blog/`, `content/`, and `resources/`, plus a
145
- `components/` folder for local MDX components. A typical manifest looks like:
143
+ The compatibility spelling still installs the skill, but it no longer enables
144
+ a separate data mode. The CLI writes or updates `agent-native.json` with
145
+ declarative local-folder sources and launches normal database-backed Content.
146
+ A typical root looks like:
146
147
 
147
148
  ```json
148
149
  {
149
150
  "version": 1,
150
151
  "apps": {
151
152
  "content": {
152
- "mode": "local-files",
153
153
  "roots": [
154
154
  {
155
155
  "name": "Docs",
156
156
  "path": "docs",
157
157
  "kind": "docs",
158
- "extensions": [".md", ".mdx"]
159
- },
160
- {
161
- "name": "Blog",
162
- "path": "blog",
163
- "kind": "blog",
164
- "extensions": [".md", ".mdx"]
165
- },
166
- {
167
- "name": "Content",
168
- "path": "content",
169
- "kind": "content",
170
- "extensions": [".md", ".mdx"]
171
- },
172
- {
173
- "name": "Resources",
174
- "path": "resources",
175
- "kind": "resources",
176
- "extensions": [".md", ".mdx"]
158
+ "extensions": [".md", ".mdx"],
159
+ "source": {
160
+ "type": "local-folder",
161
+ "connectionId": "local-folder:<opaque-id>",
162
+ "truthPolicy": "source_primary"
163
+ }
177
164
  }
178
165
  ],
179
166
  "components": "components",
@@ -184,9 +171,10 @@ Content roots for `docs/`, `blog/`, `content/`, and `resources/`, plus a
184
171
  }
185
172
  ```
186
173
 
187
- Local File Mode does not make the host language model local, and the hosted
188
- Content app cannot read private repo files by itself. File access requires a
189
- local Content app, Agent Native Desktop, or another trusted local bridge.
174
+ Content never stores an absolute local path or raw file body in source metadata.
175
+ File access still requires a local Content app, Agent Native Desktop, or another
176
+ trusted bridge. Disconnecting a folder leaves the SQL pages and disk files in
177
+ place. Concurrent edits and missing source files require explicit review.
190
178
 
191
179
  ## MDX And Components
192
180
 
@@ -202,9 +190,8 @@ local Content app, Agent Native Desktop, or another trusted local bridge.
202
190
 
203
191
  ## Boundaries
204
192
 
205
- - Moving, renaming, and reordering local-file pages are not first-class Content
206
- UI operations yet. Use normal file operations when the user asks for those,
207
- then let Content rediscover the file tree.
193
+ - Preserve a page's frontmatter `id` when renaming a source file so the next
194
+ sync recognizes it as the same global Content page.
208
195
  - Do not push/pull Notion, Builder.io, or other provider-backed content unless
209
196
  the user explicitly asks for provider sync.
210
197
  - Do not paste secrets, private provider data, or credential-looking values into
@@ -96,6 +96,11 @@ cd templates/content && pnpm action <name> [args]
96
96
  | `list-documents` | `[--format json]` | List document metadata/tree; no full bodies |
97
97
  | `export-content-source` | `[--format json]` | Export editable docs as `content/*.mdx` source files |
98
98
  | `import-content-source` | `--files <json> [--dryRun true\|false]` | Import `.md`/`.mdx` source files into editable docs |
99
+ | `connect-local-folder-source` | `--connectionId <opaque-id> --label <name> [--spaceId <id>\|--databaseId <id>\|--createSourceBackedSpace true] [--truthPolicy database_primary\|source_primary\|reviewed_bidirectional]` | Connect a trusted browser/Desktop folder registry entry to canonical Files without storing its path or handle in SQL |
100
+ | `sync-local-folder-source` | `--sourceId <id> --files <json> [--dryRun true\|false]` | Materialize a connected folder through Files source rows and record concurrent changes for review |
101
+ | `sync-manifest-local-folder-source` | `--connectionId <opaque-id> [--file <relative-path>] [--spaceId <id>] [--dryRun true\|false]` | Use the trusted local server bridge to materialize a manifest-declared folder into normal SQL-backed Content |
102
+ | `resolve-local-folder-conflict` | `--changeSetId <id> --decision keep_content\|accept_source [--sourceContent <text>]` | Resolve a reviewed folder conflict; accepting requires the exact hashed folder revision |
103
+ | `disconnect-local-folder-source` | `--sourceId <id>` | Disconnect a folder adapter without deleting local files or its SQL-backed Content pages |
99
104
  | `list-builder-docs` | `[--model docs-content\|blog-article] [--limit <n>]` | List Builder docs/blog entries available for `.builder.mdx` pull |
100
105
  | `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 |
101
106
  | `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 |
@@ -112,7 +117,10 @@ cd templates/content && pnpm action <name> [args]
112
117
  | `remove-local-file-source` | `[--sourceRootPath <path>]` | Unlink local-file sources from Content without deleting local Markdown/MDX files |
113
118
  | `list-local-component-files` | | List registered local MDX component source files |
114
119
  | `write-local-component-file` | `--workspaceId <id> --path <relative-component-path> --content <source>` | Create or update a file in a registered local `components/` folder |
115
- | `create-content-database` | `[--documentId <id>] [--parentId <id>] [--title <text>] [--description <text>]` | Create a described database page or convert an existing page into a database |
120
+ | `ensure-content-spaces` | | Idempotently provision the signed-in user's personal and current organization Content spaces, system databases, and catalog references |
121
+ | `backfill-content-files` | | Assign legacy pages to Content spaces and reconcile exactly one canonical Files database membership per non-system page |
122
+ | `list-content-spaces` | | List already-provisioned Content spaces authorized by the signed-in user's current ownership or organization memberships |
123
+ | `create-content-database` | `[--documentId <id>] [--spaceId <id>] [--parentId <id>] [--title <text>] [--description <text>]` | Create a described database page in a Content space or convert an existing page into a database |
116
124
  | `create-inline-content-database` | `--hostDocumentId <id> [--title <text>] [--description <text>]` | Create a described database owned by an inline database block in the host document |
117
125
  | `get-content-database` | `--databaseId <id>` or `--documentId <id>` | Get a database with its description, property/option schema guidance, item pages, and computed ancestry context |
118
126
  | `list-trashed-content-databases` | | List soft-deleted databases visible in the sidebar Trash surface |
@@ -193,37 +201,24 @@ strip of the markdown.
193
201
 
194
202
  ### Local Source Files
195
203
 
196
- Content has two file workflows:
204
+ Content has one database-backed document model with optional folder sources:
197
205
 
198
- - **Database mode local folders:** the `/local-files` view links one or more
206
+ - **Local folder sources:** the `/local-files` view links one or more
199
207
  browser or Agent Native Desktop folders to SQL-backed documents. The UI uses
200
- folder rows: **Pull** reads local `.md`/`.mdx` files through
201
- `import-content-source`, **Check** runs the same import as `--dryRun true`,
202
- and **Push** uses `export-content-source` to write Content documents back to
203
- the chosen folder. Files with known `id` values update existing docs only
204
- when the caller has editor access, and files without ids create new private
205
- docs for the current user. Imported rows keep `source.mode: "local-files"`
206
- and `source.path`, so `list-documents`/`get-document` can distinguish them
207
- from ordinary private pages and the sidebar can show them under Local files.
208
- With one linked folder, imported paths stay flat (`content/page.mdx`); with
209
- multiple linked folders, paths are prefixed by folder name so Local files can
210
- group them by folder. Once a source folder is linked, the selected
211
- `.md`/`.mdx` file is authoritative: opening the page reads the file, editor
212
- saves write the file first, and SQL is updated afterward as
213
- cache/history/search glue. Use `--dryRun true` before a large import when the
214
- source folder may contain unexpected files.
215
- - **Local File Mode editing:** when the app runs with `AGENT_NATIVE_MODE=local-files`
216
- or an `agent-native.json` whose app config enables local files, the standard
217
- Content editor reads and writes configured repo files directly. The left
218
- sidebar is populated from local roots such as `docs/`, `blog/`, `content/`,
219
- and `resources/`; selecting a file opens `/page/<local-file-id>` and
220
- `update-document` writes the selected `.md`/`.mdx` file. The document id is
221
- derived from the file path, and unknown frontmatter is preserved when title,
222
- content, icon, or favorite state changes.
223
- Repos can opt into `profile: "docs/no-bookkeeping"` to keep docs edits from
224
- adding absent `updatedAt`, `icon`, or `isFavorite` frontmatter. Content-only
225
- edits under that profile preserve existing frontmatter but do not create new
226
- bookkeeping keys; explicit title/icon/favorite edits still persist.
208
+ folder rows: **Pull** calls `sync-local-folder-source`, **Check** runs the
209
+ same action with `dryRun: true`, and **Push** uses the source-scoped
210
+ `export-content-source`. Imported files become ordinary SQL documents in the
211
+ target space's canonical Files database. Preserve frontmatter `id` across
212
+ renames; missing files and concurrent changes become reviewable incoming
213
+ change sets instead of silently deleting or overwriting a page. SQL stores
214
+ only opaque connection identity, relative paths, and hashes. Disconnecting a
215
+ folder keeps both the Content pages and disk files.
216
+ - **Manifest/CLI bridge:** `agent-native content local-files <target>` remains
217
+ as a compatibility spelling, but it launches normal database-backed Content.
218
+ `agent-native.json` declares `source.type: "local-folder"` and an opaque
219
+ `connectionId`; it does not select a separate application mode. The trusted
220
+ local server bridge materializes that source through
221
+ `sync-manifest-local-folder-source`.
227
222
  - **Local MDX components:** local file workspaces can expose React components
228
223
  from the configured `components` folder. Export PascalCase components such as
229
224
  `ImpactCounter` from `.tsx` files, then use `<ImpactCounter />` in MDX or pick
@@ -36,6 +36,12 @@ import {
36
36
  type BuilderCmsSourceEntry,
37
37
  } from "./_builder-cms-source-adapter.js";
38
38
  import { executeBuilderCmsWrite } from "./_builder-cms-write-client.js";
39
+ import { ensureDocumentFilesMembership } from "./_content-files.js";
40
+ import {
41
+ organizationContentSpaceId,
42
+ personalContentSpaceId,
43
+ provisionContentSpaces,
44
+ } from "./_content-spaces.js";
39
45
  import { flushOpenDocumentEditorToSql } from "./_document-flush.js";
40
46
 
41
47
  type FetchLike = typeof fetch;
@@ -524,6 +530,17 @@ export async function pullBuilderDocIntoContent(args: {
524
530
  if (!ownerEmail) throw new Error("no authenticated user");
525
531
  const orgId = getRequestOrgId() ?? null;
526
532
  const db = getDb();
533
+ const provisioned = args.dryRun
534
+ ? null
535
+ : await provisionContentSpaces(db, ownerEmail);
536
+ const targetSpaceId = orgId
537
+ ? organizationContentSpaceId(orgId)
538
+ : personalContentSpaceId(ownerEmail);
539
+ if (provisioned && !provisioned.spaceIds.includes(targetSpaceId)) {
540
+ throw new Error(
541
+ "The active organization does not have a writable Content space.",
542
+ );
543
+ }
527
544
  const entry = await readFullBuilderDocsEntry({
528
545
  model: args.model,
529
546
  entryId: args.entryId,
@@ -554,6 +571,9 @@ export async function pullBuilderDocIntoContent(args: {
554
571
  `Requires editor access to update document "${documentId}".`,
555
572
  );
556
573
  }
574
+ if (existing?.spaceId && existing.spaceId !== targetSpaceId) {
575
+ throw new Error("Builder document belongs to a different Content space.");
576
+ }
557
577
 
558
578
  const sourceFields = builderDocumentSourceFields(bundle, now);
559
579
 
@@ -562,6 +582,7 @@ export async function pullBuilderDocIntoContent(args: {
562
582
  await db
563
583
  .update(schema.documents)
564
584
  .set({
585
+ spaceId: existing.spaceId ?? targetSpaceId,
565
586
  title: bundle.mdx.title,
566
587
  content: bundle.mdx.body,
567
588
  updatedAt: now,
@@ -571,6 +592,7 @@ export async function pullBuilderDocIntoContent(args: {
571
592
  } else {
572
593
  await db.insert(schema.documents).values({
573
594
  id: documentId,
595
+ spaceId: targetSpaceId,
574
596
  ownerEmail,
575
597
  orgId,
576
598
  parentId: null,
@@ -586,6 +608,7 @@ export async function pullBuilderDocIntoContent(args: {
586
608
  ...sourceFields,
587
609
  });
588
610
  }
611
+ await ensureDocumentFilesMembership(db, documentId, now);
589
612
  await replaceBuilderDocumentSidecars({
590
613
  db,
591
614
  documentId,
@@ -68,13 +68,31 @@ const notionDatabaseAdapter: ContentDatabaseSourceAdapter = {
68
68
  read: readNotionDatabaseSource,
69
69
  };
70
70
 
71
+ const localFolderAdapter: ContentDatabaseSourceAdapter = {
72
+ sourceType: "local-folder",
73
+ async read() {
74
+ return {
75
+ state: "error",
76
+ entries: [],
77
+ fields: [],
78
+ fetchedAt: new Date().toISOString(),
79
+ message:
80
+ "Local folder refresh requires the trusted browser or Desktop bridge.",
81
+ metadata: { bridgeRequired: true },
82
+ };
83
+ },
84
+ };
85
+
71
86
  const adapters = new Map<
72
87
  ContentDatabaseSourceType,
73
88
  ContentDatabaseSourceAdapter
74
89
  >(
75
- [builderCmsAdapter, localTableAdapter, notionDatabaseAdapter].map(
76
- (adapter) => [adapter.sourceType, adapter],
77
- ),
90
+ [
91
+ builderCmsAdapter,
92
+ localTableAdapter,
93
+ notionDatabaseAdapter,
94
+ localFolderAdapter,
95
+ ].map((adapter) => [adapter.sourceType, adapter]),
78
96
  );
79
97
 
80
98
  export function getContentDatabaseSourceAdapter(