@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.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/docs/content/local-file-mode.mdx +99 -489
- package/corpus/core/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
- package/corpus/core/docs/content/locales/ar-SA/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
- package/corpus/core/docs/content/locales/de-DE/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
- package/corpus/core/docs/content/locales/es-ES/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
- package/corpus/core/docs/content/locales/fr-FR/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
- package/corpus/core/docs/content/locales/hi-IN/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
- package/corpus/core/docs/content/locales/ja-JP/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
- package/corpus/core/docs/content/locales/ko-KR/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
- package/corpus/core/docs/content/locales/pt-BR/template-content.mdx +10 -24
- package/corpus/core/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
- package/corpus/core/docs/content/locales/zh-CN/template-content.mdx +9 -24
- package/corpus/core/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
- package/corpus/core/docs/content/locales/zh-TW/template-content.mdx +9 -24
- package/corpus/core/docs/content/template-content.mdx +26 -42
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/content-local.ts +86 -18
- package/corpus/core/src/cli/index.ts +2 -2
- package/corpus/core/src/cli/skills-content/content-skill.ts +36 -25
- package/corpus/core/src/cli/skills.ts +47 -13
- package/corpus/core/src/local-artifacts/index.ts +65 -0
- package/corpus/core/src/vite/client.ts +2 -0
- package/corpus/templates/assets/app/components/library/GenerationPresetsPanel.tsx +325 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +12 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +21 -0
- package/corpus/templates/assets/app/i18n-data.ts +215 -0
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +19 -479
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id_.settings.tsx +446 -0
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +12 -2
- package/corpus/templates/clips/app/components/player/settings-panel.tsx +30 -12
- package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
- package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +22 -3
- package/corpus/templates/clips/app/i18n/ar-SA.ts +3 -2
- package/corpus/templates/clips/app/i18n/de-DE.ts +4 -2
- package/corpus/templates/clips/app/i18n/en-US.ts +3 -2
- package/corpus/templates/clips/app/i18n/es-ES.ts +4 -2
- package/corpus/templates/clips/app/i18n/fr-FR.ts +3 -2
- package/corpus/templates/clips/app/i18n/hi-IN.ts +3 -2
- package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +3 -2
- package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -2
- package/corpus/templates/clips/app/i18n/zh-CN.ts +3 -2
- package/corpus/templates/clips/app/i18n/zh-TW.ts +3 -2
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +27 -1
- package/corpus/templates/clips/server/lib/share-password.ts +6 -3
- package/corpus/templates/content/.agents/skills/content/SKILL.md +26 -39
- package/corpus/templates/content/AGENTS.md +25 -30
- package/corpus/templates/content/actions/_builder-docs-client.ts +23 -0
- package/corpus/templates/content/actions/_content-database-source-adapters.ts +21 -3
- package/corpus/templates/content/actions/_content-files.ts +338 -0
- package/corpus/templates/content/actions/_content-space-access.ts +135 -0
- package/corpus/templates/content/actions/_content-spaces.ts +640 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +90 -7
- package/corpus/templates/content/actions/_database-utils.ts +7 -1
- package/corpus/templates/content/actions/_local-file-documents.ts +0 -9
- package/corpus/templates/content/actions/_local-folder-source.ts +53 -0
- package/corpus/templates/content/actions/_property-utils.ts +9 -4
- package/corpus/templates/content/actions/add-database-item.ts +108 -65
- package/corpus/templates/content/actions/backfill-content-files.ts +22 -0
- package/corpus/templates/content/actions/connect-local-folder-source.ts +221 -0
- package/corpus/templates/content/actions/create-content-database.ts +129 -3
- package/corpus/templates/content/actions/create-document.ts +65 -55
- package/corpus/templates/content/actions/create-inline-content-database.ts +6 -1
- package/corpus/templates/content/actions/delete-content-database.ts +3 -0
- package/corpus/templates/content/actions/delete-document.ts +7 -11
- package/corpus/templates/content/actions/disconnect-local-folder-source.ts +175 -0
- package/corpus/templates/content/actions/duplicate-database-item.ts +10 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +13 -0
- package/corpus/templates/content/actions/edit-document.ts +2 -28
- package/corpus/templates/content/actions/ensure-content-spaces.ts +26 -0
- package/corpus/templates/content/actions/export-content-source.ts +47 -9
- package/corpus/templates/content/actions/get-document.ts +0 -14
- package/corpus/templates/content/actions/import-content-source.ts +43 -3
- package/corpus/templates/content/actions/list-content-spaces.ts +103 -0
- package/corpus/templates/content/actions/list-documents.ts +12 -9
- package/corpus/templates/content/actions/move-document.ts +3 -14
- package/corpus/templates/content/actions/pull-document.ts +0 -23
- package/corpus/templates/content/actions/remove-local-file-source.ts +50 -29
- package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +442 -0
- package/corpus/templates/content/actions/reveal-local-source-file.ts +6 -17
- package/corpus/templates/content/actions/search-documents.ts +0 -34
- package/corpus/templates/content/actions/share-local-file-document.ts +25 -1
- package/corpus/templates/content/actions/submit-content-database-form.ts +12 -0
- package/corpus/templates/content/actions/sync-local-folder-source.ts +731 -0
- package/corpus/templates/content/actions/sync-manifest-local-folder-source.ts +123 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +10 -1
- package/corpus/templates/content/actions/update-document.ts +0 -15
- package/corpus/templates/content/actions/view-screen.ts +2 -50
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +76 -62
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +70 -22
- package/corpus/templates/content/app/components/editor/database/grouping.ts +2 -1
- package/corpus/templates/content/app/components/editor/database/settings.tsx +23 -20
- package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +330 -0
- package/corpus/templates/content/app/components/editor/database/types.ts +1 -0
- package/corpus/templates/content/app/components/editor/database/view-config.ts +3 -1
- package/corpus/templates/content/app/components/layout/Layout.tsx +25 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +209 -113
- package/corpus/templates/content/app/components/sidebar/select-content-space.ts +31 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +16 -0
- package/corpus/templates/content/app/hooks/use-content-spaces.ts +39 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +11 -0
- package/corpus/templates/content/app/i18n-data.ts +75 -0
- package/corpus/templates/content/app/routes/_app.local-files.tsx +174 -65
- package/corpus/templates/content/changelog/2026-07-16-content-callouts-can-now-be-reviewed-and-published-to-builder.md +6 -0
- package/corpus/templates/content/changelog/2026-07-16-heading-5-and-heading-6-are-available-from-the-editor-slash-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-16-organize-every-workspace-through-a-customizable-files-databa.md +6 -0
- package/corpus/templates/content/parity/matrix.md +2 -1
- package/corpus/templates/content/parity/matrix.ts +37 -1
- package/corpus/templates/content/scripts/dev-database.mjs +7 -5
- package/corpus/templates/content/server/db/schema.ts +113 -40
- package/corpus/templates/content/server/lib/document-context.ts +15 -1
- package/corpus/templates/content/server/lib/notion-sync.ts +6 -0
- package/corpus/templates/content/server/plugins/db.ts +153 -0
- package/corpus/templates/content/shared/api.ts +17 -3
- package/corpus/templates/content/shared/builder-mdx.ts +163 -16
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +59 -0
- package/corpus/templates/design/AGENTS.md +6 -1
- package/corpus/templates/design/actions/create-design-from-template.ts +19 -7
- package/corpus/templates/design/actions/list-design-templates.ts +69 -21
- package/corpus/templates/design/actions/navigate.ts +2 -2
- package/corpus/templates/design/actions/view-screen.ts +15 -2
- package/corpus/templates/design/agent-native.app-skill.json +5 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +281 -56
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +14 -2
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/design/app/i18n-data.ts +21 -2
- package/corpus/templates/design/app/i18n-template-feature.ts +218 -10
- package/corpus/templates/design/app/pages/Index.tsx +195 -24
- package/corpus/templates/design/app/pages/Templates.tsx +144 -55
- package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +12 -1
- package/corpus/templates/design/changelog/2026-07-14-templates-now-appear-in-the-new-design-picker-with-previews-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-15-templates-now-open-immediately-after-copying-even-while-the-.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/mail/AGENTS.md +23 -18
- package/corpus/templates/mail/actions/bulk-archive.ts +32 -28
- package/corpus/templates/mail/actions/mark-read.ts +131 -20
- package/corpus/templates/mail/actions/mark-thread-read.ts +1 -1
- package/corpus/templates/mail/actions/move-email.ts +30 -24
- package/corpus/templates/mail/actions/send-email.ts +73 -68
- package/corpus/templates/mail/changelog/2026-07-15-unread-inbox-cleanup-now-completes-reliably.md +6 -0
- package/corpus/templates/mail/server/handlers/emails.ts +218 -209
- package/corpus/templates/mail/server/lib/bulk-mark-read.ts +30 -0
- package/corpus/templates/mail/server/lib/email-state.ts +198 -113
- package/corpus/templates/mail/server/lib/google-auth.ts +218 -25
- package/corpus/templates/mail/server/lib/jobs.ts +69 -74
- package/corpus/templates/mail/server/lib/local-email-store.ts +265 -0
- package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
- package/dist/cli/content-local.d.ts +1 -0
- package/dist/cli/content-local.d.ts.map +1 -1
- package/dist/cli/content-local.js +75 -17
- package/dist/cli/content-local.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/skills-content/content-skill.d.ts +1 -1
- package/dist/cli/skills-content/content-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/content-skill.js +36 -25
- package/dist/cli/skills-content/content-skill.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +47 -14
- package/dist/cli/skills.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/local-artifacts/index.d.ts +10 -0
- package/dist/local-artifacts/index.d.ts.map +1 -1
- package/dist/local-artifacts/index.js +39 -0
- package/dist/local-artifacts/index.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +2 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/local-file-mode.mdx +99 -489
- package/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
- package/docs/content/locales/ar-SA/template-content.mdx +10 -24
- package/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
- package/docs/content/locales/de-DE/template-content.mdx +10 -24
- package/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
- package/docs/content/locales/es-ES/template-content.mdx +10 -24
- package/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
- package/docs/content/locales/fr-FR/template-content.mdx +10 -24
- package/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
- package/docs/content/locales/hi-IN/template-content.mdx +10 -24
- package/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
- package/docs/content/locales/ja-JP/template-content.mdx +10 -24
- package/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
- package/docs/content/locales/ko-KR/template-content.mdx +10 -24
- package/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
- package/docs/content/locales/pt-BR/template-content.mdx +10 -24
- package/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
- package/docs/content/locales/zh-CN/template-content.mdx +9 -24
- package/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
- package/docs/content/locales/zh-TW/template-content.mdx +9 -24
- package/docs/content/template-content.mdx +26 -42
- package/package.json +1 -1
- 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
|
-
|
|
242
|
+
value: string | null | undefined,
|
|
234
243
|
): ContentDatabaseSourceChangeDirection {
|
|
235
|
-
|
|
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(
|
|
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(
|
|
188
|
-
|
|
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
|
-
: "
|
|
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
|
-
|
|
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
|
|
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
|
+
});
|