@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
@@ -26,6 +26,7 @@ import {
26
26
  IconPhotoPlus,
27
27
  IconRefresh,
28
28
  IconSearch,
29
+ IconSettings,
29
30
  IconTrash,
30
31
  IconUpload,
31
32
  IconVideo,
@@ -57,7 +58,6 @@ import {
57
58
  } from "react-router";
58
59
  import { toast } from "sonner";
59
60
 
60
- import { EditLibraryDialog } from "@/components/library/EditLibraryDialog";
61
61
  import {
62
62
  AlertDialog,
63
63
  AlertDialogAction,
@@ -98,10 +98,8 @@ import {
98
98
  SelectTrigger,
99
99
  SelectValue,
100
100
  } from "@/components/ui/select";
101
- import { Separator } from "@/components/ui/separator";
102
101
  import { Spinner } from "@/components/ui/spinner";
103
102
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
104
- import { Textarea } from "@/components/ui/textarea";
105
103
  import {
106
104
  Tooltip,
107
105
  TooltipContent,
@@ -110,7 +108,6 @@ import {
110
108
  } from "@/components/ui/tooltip";
111
109
  import { assetPreviewSources } from "@/lib/asset-preview-sources";
112
110
  import { assetMediaUrl } from "@/lib/asset-urls";
113
- import { getLibraryCustomInstructions } from "@/lib/libraries";
114
111
  import {
115
112
  chunkAssetUploads,
116
113
  getFailedUploadCount,
@@ -119,14 +116,7 @@ import {
119
116
  type AssetUploadResult,
120
117
  } from "@/lib/upload-results";
121
118
 
122
- import {
123
- IMAGE_CATEGORIES,
124
- ASPECT_RATIOS,
125
- type AssetVariantState,
126
- type AspectRatio,
127
- type ImageCategory,
128
- type ImageRole,
129
- } from "../../shared/api";
119
+ import { type AssetVariantState, type ImageRole } from "../../shared/api";
130
120
 
131
121
  export type VariantSlot = AssetVariantState["slots"][number];
132
122
 
@@ -288,12 +278,6 @@ function removeVariantSlotsByScopeFromCache(
288
278
  );
289
279
  }
290
280
 
291
- function paletteDraftFromColors(colors: unknown): string {
292
- return Array.isArray(colors)
293
- ? colors.filter((color) => typeof color === "string").join(", ")
294
- : "";
295
- }
296
-
297
281
  function referenceRoleForAsset(asset: any): ImageRole {
298
282
  if (asset?.mediaType === "video" || asset?.mimeType?.startsWith("video/")) {
299
283
  return "video_reference";
@@ -317,22 +301,6 @@ function assetUpdatedTime(asset: any): number {
317
301
  return Number.isNaN(time) ? 0 : time;
318
302
  }
319
303
 
320
- function parsePaletteDraft(value: string): string[] {
321
- const seen = new Set<string>();
322
- const colors: string[] = [];
323
- for (const raw of value.split(/[\s,]+/)) {
324
- const trimmed = raw.trim();
325
- if (!trimmed) continue;
326
- const color = trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
327
- if (!/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(color)) continue;
328
- const normalized = color.toLowerCase();
329
- if (seen.has(normalized)) continue;
330
- seen.add(normalized);
331
- colors.push(normalized);
332
- }
333
- return colors;
334
- }
335
-
336
304
  export function loader({ params, request }: LoaderFunctionArgs) {
337
305
  const url = new URL(request.url);
338
306
  return redirect(`/library/${params.id}${url.search}`);
@@ -386,7 +354,6 @@ export function BrandKitDetailRoute({
386
354
  const [folderOpen, setFolderOpen] = useState(false);
387
355
  const [uploading, setUploading] = useState(false);
388
356
  const [pendingUploads, setPendingUploads] = useState<PendingUpload[]>([]);
389
- const [editOpen, setEditOpen] = useState(false);
390
357
  const [archiveOpen, setArchiveOpen] = useState(false);
391
358
  const [headerPrimaryActionsTarget, setHeaderPrimaryActionsTarget] =
392
359
  useState<HTMLElement | null>(null);
@@ -415,9 +382,6 @@ export function BrandKitDetailRoute({
415
382
  "all",
416
383
  );
417
384
  const [search, setSearch] = useState("");
418
- const [styleDescriptionDraft, setStyleDescriptionDraft] = useState("");
419
- const [customInstructionsDraft, setCustomInstructionsDraft] = useState("");
420
- const [paletteDraft, setPaletteDraft] = useState("");
421
385
  const fileInputRef = useRef<HTMLInputElement>(null);
422
386
  const dragCounterRef = useRef(0);
423
387
  const [isDragOver, setIsDragOver] = useState(false);
@@ -432,9 +396,13 @@ export function BrandKitDetailRoute({
432
396
  });
433
397
 
434
398
  useEffect(() => {
399
+ if (urlTab === "settings") {
400
+ navigate(`/brand-kits/${libraryId}/settings`, { replace: true });
401
+ return;
402
+ }
435
403
  if (!urlTab) return;
436
404
  setActiveTab((current) => (current === urlTab ? current : urlTab));
437
- }, [urlTab]);
405
+ }, [urlTab, libraryId, navigate]);
438
406
 
439
407
  useEffect(() => {
440
408
  if (headerMode !== "actions" || typeof document === "undefined") {
@@ -502,11 +470,6 @@ export function BrandKitDetailRoute({
502
470
  (asset.status === "reference" && !isContentOnlyReference(asset)),
503
471
  );
504
472
  const unfiledCount = libraryAssets.filter((asset) => !asset.folderId).length;
505
- const customInstructions = getLibraryCustomInstructions(library);
506
- const libraryStyleDescription = library?.styleBrief?.description ?? "";
507
- const libraryPaletteDraft = paletteDraftFromColors(
508
- library?.styleBrief?.palette,
509
- );
510
473
  const liveVariantsForLibrary =
511
474
  liveVariants?.libraryId === libraryId ? liveVariants : null;
512
475
  const liveCandidateSlots = useMemo(
@@ -547,17 +510,6 @@ export function BrandKitDetailRoute({
547
510
  );
548
511
  }, [assets, liveCandidateSlots]);
549
512
 
550
- useEffect(() => {
551
- setStyleDescriptionDraft(libraryStyleDescription);
552
- }, [library?.id, libraryStyleDescription]);
553
-
554
- useEffect(() => {
555
- setCustomInstructionsDraft(customInstructions ?? "");
556
- }, [library?.id, customInstructions]);
557
-
558
- useEffect(() => {
559
- setPaletteDraft(libraryPaletteDraft);
560
- }, [library?.id, libraryPaletteDraft]);
561
513
  const pendingVisibleUploads = pendingUploads.filter((upload) => {
562
514
  if (mediaFilter !== "all" && upload.mediaType !== mediaFilter) return false;
563
515
  if (activeFolderId === "all") return true;
@@ -841,37 +793,6 @@ export function BrandKitDetailRoute({
841
793
  );
842
794
  }
843
795
 
844
- function analyzeBrand() {
845
- if (!library) return;
846
- const anchorIds = assets
847
- .filter(
848
- (asset) =>
849
- asset.metadata?.isStyleAnchor ||
850
- library.settings?.canonicalStyleAssetIds?.includes(asset.id),
851
- )
852
- .map((asset) => asset.id);
853
- sendToAgentChat({
854
- message: [
855
- "Analyze this Assets library brand.",
856
- `Call analyze-collection-style with libraryId: ${library.id}.`,
857
- "Update the reusable style brief with palette and visual traits, then summarize what changed.",
858
- ].join("\n"),
859
- context: [
860
- "## Assets library context",
861
- `Library: ${library.title} (${library.id})`,
862
- `Description: ${library.description || ""}`,
863
- `Reference assets: ${references.length}`,
864
- `Anchor assets: ${anchorIds.length ? anchorIds.join(", ") : "none"}`,
865
- `Current style brief: ${JSON.stringify(library.styleBrief ?? {})}`,
866
- customInstructions
867
- ? `Custom instructions: ${customInstructions}`
868
- : "Custom instructions: none",
869
- ].join("\n"),
870
- submit: true,
871
- newTab: true,
872
- });
873
- }
874
-
875
796
  async function upload(files: FileList | null, category = "style-only") {
876
797
  if (!files?.length || uploading) return;
877
798
  const selectedFiles = Array.from(files);
@@ -1107,8 +1028,7 @@ export function BrandKitDetailRoute({
1107
1028
  );
1108
1029
  }
1109
1030
  const assetById = new Map(assets.map((asset) => [asset.id, asset]));
1110
- const activeSurfaceTab =
1111
- activeTab === "runs" || activeTab === "settings" ? activeTab : "assets";
1031
+ const activeSurfaceTab = activeTab === "runs" ? activeTab : "assets";
1112
1032
  const hideEmptyLanes =
1113
1033
  activeFolderId !== "all" || mediaFilter !== "all" || search.trim() !== "";
1114
1034
  const uploadAction = (
@@ -1141,6 +1061,13 @@ export function BrandKitDetailRoute({
1141
1061
  </Button>
1142
1062
  </DropdownMenuTrigger>
1143
1063
  <DropdownMenuContent align="end">
1064
+ <DropdownMenuItem asChild>
1065
+ <Link to={`/brand-kits/${libraryId}/settings`}>
1066
+ <IconSettings className="mr-2 h-4 w-4 shrink-0" />
1067
+ {t("library.settings")}
1068
+ </Link>
1069
+ </DropdownMenuItem>
1070
+ <DropdownMenuSeparator />
1144
1071
  <DropdownMenuItem
1145
1072
  onSelect={(event) => {
1146
1073
  event.preventDefault();
@@ -1224,10 +1151,12 @@ export function BrandKitDetailRoute({
1224
1151
  variant="ghost"
1225
1152
  size="icon"
1226
1153
  className="h-8 w-8 text-muted-foreground hover:text-foreground"
1227
- onClick={() => setEditOpen(true)}
1154
+ asChild
1228
1155
  aria-label={t("library.editBrandKit")}
1229
1156
  >
1230
- <IconPencil className="h-4 w-4" />
1157
+ <Link to={`/brand-kits/${libraryId}/settings`}>
1158
+ <IconPencil className="h-4 w-4" />
1159
+ </Link>
1231
1160
  </Button>
1232
1161
  </div>
1233
1162
  <p className="mt-1 max-w-3xl text-sm text-muted-foreground">
@@ -1248,11 +1177,6 @@ export function BrandKitDetailRoute({
1248
1177
  onChange={(event) => upload(event.target.files)}
1249
1178
  />
1250
1179
 
1251
- <EditLibraryDialog
1252
- library={library}
1253
- open={editOpen}
1254
- onOpenChange={setEditOpen}
1255
- />
1256
1180
  <AlertDialog open={archiveOpen} onOpenChange={setArchiveOpen}>
1257
1181
  <AlertDialogContent>
1258
1182
  <AlertDialogHeader>
@@ -1339,7 +1263,6 @@ export function BrandKitDetailRoute({
1339
1263
  <TabsList>
1340
1264
  <TabsTrigger value="assets">{t("library.assetsTab")}</TabsTrigger>
1341
1265
  <TabsTrigger value="runs">{t("library.runs")}</TabsTrigger>
1342
- <TabsTrigger value="settings">{t("library.settings")}</TabsTrigger>
1343
1266
  </TabsList>
1344
1267
 
1345
1268
  <TabsContent value="assets" className="space-y-5">
@@ -1502,107 +1425,6 @@ export function BrandKitDetailRoute({
1502
1425
  </div>
1503
1426
  )}
1504
1427
  </TabsContent>
1505
-
1506
- <TabsContent value="settings">
1507
- <div className="assets-brand-kit-settings-grid grid gap-4">
1508
- <div className="space-y-4 rounded-lg border border-border p-4">
1509
- <Label>{t("brandKitDetail.styleDescription")}</Label>
1510
- <Textarea
1511
- value={styleDescriptionDraft}
1512
- onChange={(event) =>
1513
- setStyleDescriptionDraft(event.target.value)
1514
- }
1515
- onBlur={() =>
1516
- updateLibrary.mutate({
1517
- id: library.id,
1518
- styleBrief: {
1519
- ...library.styleBrief,
1520
- description: styleDescriptionDraft,
1521
- },
1522
- })
1523
- }
1524
- className="min-h-40"
1525
- />
1526
- <Separator />
1527
- <Label>{t("brandKitDetail.customInstructions")}</Label>
1528
- <Textarea
1529
- value={customInstructionsDraft}
1530
- onChange={(event) =>
1531
- setCustomInstructionsDraft(event.target.value)
1532
- }
1533
- onBlur={() =>
1534
- updateLibrary.mutate({
1535
- id: library.id,
1536
- customInstructions: customInstructionsDraft,
1537
- })
1538
- }
1539
- placeholder={t(
1540
- "brandKitDetail.customInstructionsPlaceholder",
1541
- )}
1542
- className="min-h-28"
1543
- />
1544
- <Separator />
1545
- <div className="flex items-center justify-between">
1546
- <div>
1547
- <div className="text-sm font-medium">
1548
- {t("brandKitDetail.palette")}
1549
- </div>
1550
- <div className="mt-2 flex flex-wrap gap-2">
1551
- {(library.styleBrief?.palette ?? []).map(
1552
- (color: string) => (
1553
- <span
1554
- key={color}
1555
- className="h-7 w-7 rounded-md border border-border"
1556
- style={{ backgroundColor: color }}
1557
- title={color}
1558
- />
1559
- ),
1560
- )}
1561
- </div>
1562
- <Input
1563
- value={paletteDraft}
1564
- onChange={(event) => setPaletteDraft(event.target.value)}
1565
- onBlur={() => {
1566
- const palette = parsePaletteDraft(paletteDraft);
1567
- setPaletteDraft(palette.join(", "));
1568
- updateLibrary.mutate({
1569
- id: library.id,
1570
- styleBrief: {
1571
- ...library.styleBrief,
1572
- palette,
1573
- },
1574
- });
1575
- }}
1576
- placeholder={"#111827, #f8fafc, #2563eb"}
1577
- className="mt-3 h-9 max-w-md text-xs"
1578
- />
1579
- </div>
1580
- <Button variant="outline" onClick={analyzeBrand}>
1581
- {library.settings?.brandAnalysis?.analyzedAt
1582
- ? t("brandKitDetail.refreshBrand")
1583
- : t("brandKitDetail.analyzeBrand")}
1584
- </Button>
1585
- </div>
1586
- </div>
1587
- <div className="space-y-4">
1588
- <GenerationPresetsPanel
1589
- libraryId={libraryId}
1590
- presets={generationPresets}
1591
- />
1592
- <div className="rounded-lg border border-border p-4">
1593
- <h3 className="text-sm font-semibold">
1594
- {t("brandKitDetail.agentUsage")}
1595
- </h3>
1596
- <p className="mt-2 text-sm text-muted-foreground">
1597
- {t("brandKitDetail.agentUsageDescription")}
1598
- </p>
1599
- <code className="mt-3 block rounded-md bg-muted p-3 text-xs">
1600
- {library.id}
1601
- </code>
1602
- </div>
1603
- </div>
1604
- </div>
1605
- </TabsContent>
1606
1428
  </Tabs>
1607
1429
  </div>
1608
1430
  </div>
@@ -2084,288 +1906,6 @@ function SessionCard({
2084
1906
  );
2085
1907
  }
2086
1908
 
2087
- function GenerationPresetsPanel({
2088
- libraryId,
2089
- presets,
2090
- }: {
2091
- libraryId: string;
2092
- presets: any[];
2093
- }) {
2094
- const t = useT();
2095
- const createPreset = useActionMutation("create-generation-preset");
2096
- const deletePreset = useActionMutation("delete-generation-preset");
2097
- const [open, setOpen] = useState(false);
2098
- const [confirmPresetId, setConfirmPresetId] = useState<string | null>(null);
2099
- const [title, setTitle] = useState("");
2100
- const [category, setCategory] = useState<ImageCategory>("social");
2101
- const [aspectRatio, setAspectRatio] = useState<AspectRatio>("1:1");
2102
- const [promptTemplate, setPromptTemplate] = useState("");
2103
- const [textPolicy, setTextPolicy] = useState(t("library.defaultTextPolicy"));
2104
- const [includeLogo, setIncludeLogo] = useState(false);
2105
-
2106
- function reset() {
2107
- setTitle("");
2108
- setCategory("social");
2109
- setAspectRatio("1:1");
2110
- setPromptTemplate("");
2111
- setTextPolicy(t("library.defaultTextPolicy"));
2112
- setIncludeLogo(false);
2113
- }
2114
-
2115
- function submit() {
2116
- const trimmed = title.trim();
2117
- if (!trimmed) return;
2118
- createPreset.mutate(
2119
- {
2120
- libraryId,
2121
- title: trimmed,
2122
- category,
2123
- aspectRatio,
2124
- imageSize: "2K",
2125
- promptTemplate: promptTemplate.trim() || undefined,
2126
- textPolicy,
2127
- referencePolicy: "auto",
2128
- includeLogo,
2129
- },
2130
- {
2131
- onSuccess: () => {
2132
- toast.success(t("brandKitDetail.generationPresetCreated"));
2133
- reset();
2134
- setOpen(false);
2135
- },
2136
- onError: (error: Error) => {
2137
- toast.error(
2138
- error.message || t("brandKitDetail.couldNotCreatePreset"),
2139
- );
2140
- },
2141
- },
2142
- );
2143
- }
2144
-
2145
- return (
2146
- <div className="rounded-lg border border-border p-4">
2147
- <div className="flex items-center justify-between gap-3">
2148
- <div>
2149
- <h3 className="text-sm font-semibold">
2150
- {t("brandKitDetail.generationPresets")}
2151
- </h3>
2152
- <p className="mt-1 text-sm text-muted-foreground">
2153
- {t("brandKitDetail.generationPresetsDescription")}
2154
- </p>
2155
- </div>
2156
- <Button variant="outline" size="sm" onClick={() => setOpen(true)}>
2157
- {t("brandKitDetail.new")}
2158
- </Button>
2159
- </div>
2160
- <div className="mt-3 space-y-2">
2161
- {presets.slice(0, 5).map((preset) => (
2162
- <div
2163
- key={preset.id}
2164
- className="flex items-start justify-between gap-3 rounded-md border border-border bg-background p-3"
2165
- >
2166
- <div className="min-w-0">
2167
- <div className="flex flex-wrap items-center gap-2">
2168
- <Link
2169
- to={`/brand-kits/${libraryId}/presets/${preset.id}`}
2170
- className="truncate text-sm font-medium underline-offset-4 hover:underline"
2171
- >
2172
- {preset.title}
2173
- </Link>
2174
- <Badge variant="outline">{preset.aspectRatio}</Badge>
2175
- {preset.includeLogo ? (
2176
- <Badge variant="secondary">{t("brandKitDetail.logo")}</Badge>
2177
- ) : null}
2178
- </div>
2179
- <p className="mt-1 line-clamp-2 text-xs text-muted-foreground">
2180
- {preset.textPolicy || preset.description || preset.category}
2181
- </p>
2182
- </div>
2183
- <div className="flex shrink-0 items-center gap-1">
2184
- <Button variant="ghost" size="sm" asChild>
2185
- <Link to={`/brand-kits/${libraryId}/presets/${preset.id}`}>
2186
- {t("brandKitDetail.edit")}
2187
- </Link>
2188
- </Button>
2189
- <Button
2190
- variant="ghost"
2191
- size="icon"
2192
- className="h-8 w-8 text-muted-foreground hover:text-destructive"
2193
- aria-label={`${t("brandKitDetail.delete")} ${preset.title}`}
2194
- onClick={() => setConfirmPresetId(preset.id)}
2195
- >
2196
- <IconTrash className="h-4 w-4" />
2197
- </Button>
2198
- </div>
2199
- </div>
2200
- ))}
2201
- {!presets.length ? (
2202
- <p className="rounded-md border border-dashed border-border p-3 text-sm text-muted-foreground">
2203
- {t("brandKitDetail.noPresetsYet")}
2204
- </p>
2205
- ) : null}
2206
- </div>
2207
-
2208
- <AlertDialog
2209
- open={confirmPresetId !== null}
2210
- onOpenChange={(isOpen) => {
2211
- if (!isOpen) setConfirmPresetId(null);
2212
- }}
2213
- >
2214
- <AlertDialogContent>
2215
- <AlertDialogHeader>
2216
- <AlertDialogTitle>
2217
- {t("brandKitDetail.deleteGenerationPreset")}
2218
- </AlertDialogTitle>
2219
- <AlertDialogDescription>
2220
- {t("brandKitDetail.deleteGenerationPresetDescription")}
2221
- </AlertDialogDescription>
2222
- </AlertDialogHeader>
2223
- <AlertDialogFooter>
2224
- <AlertDialogCancel>{t("brandKitDetail.cancel")}</AlertDialogCancel>
2225
- <AlertDialogAction
2226
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
2227
- disabled={!confirmPresetId || deletePreset.isPending}
2228
- onClick={(event) => {
2229
- event.preventDefault();
2230
- if (!confirmPresetId) return;
2231
- deletePreset.mutate(
2232
- { id: confirmPresetId },
2233
- {
2234
- onSuccess: () => {
2235
- setConfirmPresetId(null);
2236
- toast.success(
2237
- t("brandKitDetail.generationPresetDeleted"),
2238
- );
2239
- },
2240
- onError: (error: Error) => {
2241
- toast.error(
2242
- error.message ||
2243
- t("brandKitDetail.couldNotDeletePreset"),
2244
- );
2245
- },
2246
- },
2247
- );
2248
- }}
2249
- >
2250
- {t("assetDetail.delete")}
2251
- </AlertDialogAction>
2252
- </AlertDialogFooter>
2253
- </AlertDialogContent>
2254
- </AlertDialog>
2255
-
2256
- <Dialog open={open} onOpenChange={setOpen}>
2257
- <DialogContent className="sm:max-w-lg">
2258
- <DialogHeader>
2259
- <DialogTitle>{t("brandKitDetail.newGenerationPreset")}</DialogTitle>
2260
- <DialogDescription>
2261
- {t("brandKitDetail.newGenerationPresetDescription")}
2262
- </DialogDescription>
2263
- </DialogHeader>
2264
- <div className="grid gap-4">
2265
- <div className="grid gap-2">
2266
- <Label htmlFor="preset-title">{t("brandKitDetail.name")}</Label>
2267
- <Input
2268
- id="preset-title"
2269
- value={title}
2270
- onChange={(event) => setTitle(event.target.value)}
2271
- placeholder={t("brandKitDetail.campaignLaunch")}
2272
- />
2273
- </div>
2274
- <div className="grid grid-cols-2 gap-3">
2275
- <div className="grid gap-2">
2276
- <Label>{t("brandKitDetail.category")}</Label>
2277
- <Select
2278
- value={category}
2279
- onValueChange={(value) => setCategory(value as ImageCategory)}
2280
- >
2281
- <SelectTrigger>
2282
- <SelectValue />
2283
- </SelectTrigger>
2284
- <SelectContent>
2285
- {IMAGE_CATEGORIES.map((item) => (
2286
- <SelectItem key={item} value={item}>
2287
- {item}
2288
- </SelectItem>
2289
- ))}
2290
- </SelectContent>
2291
- </Select>
2292
- </div>
2293
- <div className="grid gap-2">
2294
- <Label>{t("brandKitDetail.aspectRatio")}</Label>
2295
- <Select
2296
- value={aspectRatio}
2297
- onValueChange={(value) =>
2298
- setAspectRatio(value as AspectRatio)
2299
- }
2300
- >
2301
- <SelectTrigger>
2302
- <SelectValue />
2303
- </SelectTrigger>
2304
- <SelectContent>
2305
- {ASPECT_RATIOS.map((ratio) => (
2306
- <SelectItem key={ratio} value={ratio}>
2307
- {ratio}
2308
- </SelectItem>
2309
- ))}
2310
- </SelectContent>
2311
- </Select>
2312
- </div>
2313
- </div>
2314
- <div className="grid gap-2">
2315
- <Label htmlFor="preset-template">
2316
- {t("brandKitDetail.promptTemplate")}
2317
- </Label>
2318
- <Textarea
2319
- id="preset-template"
2320
- value={promptTemplate}
2321
- onChange={(event) => setPromptTemplate(event.target.value)}
2322
- placeholder={t("library.promptTemplatePlaceholder")}
2323
- />
2324
- </div>
2325
- <div className="grid gap-2">
2326
- <Label htmlFor="preset-text-policy">
2327
- {t("brandKitDetail.textPolicy")}
2328
- </Label>
2329
- <Textarea
2330
- id="preset-text-policy"
2331
- value={textPolicy}
2332
- onChange={(event) => setTextPolicy(event.target.value)}
2333
- />
2334
- </div>
2335
- <label
2336
- htmlFor="preset-include-logo"
2337
- className="flex items-start gap-3 rounded-md border border-border p-3"
2338
- >
2339
- <Checkbox
2340
- id="preset-include-logo"
2341
- checked={includeLogo}
2342
- onCheckedChange={(checked) => setIncludeLogo(checked === true)}
2343
- className="mt-0.5"
2344
- />
2345
- <span className="grid gap-1">
2346
- <span className="text-sm font-medium leading-none">
2347
- {t("brandKitDetail.compositeCanonicalLogo")}
2348
- </span>
2349
- <span className="text-xs text-muted-foreground">
2350
- {t("brandKitDetail.compositeCanonicalLogoHint")}
2351
- </span>
2352
- </span>
2353
- </label>
2354
- </div>
2355
- <DialogFooter>
2356
- <Button variant="outline" onClick={() => setOpen(false)}>
2357
- {t("brandKitDetail.cancel")}
2358
- </Button>
2359
- <Button disabled={!title.trim()} onClick={submit}>
2360
- {t("brandKitDetail.create")}
2361
- </Button>
2362
- </DialogFooter>
2363
- </DialogContent>
2364
- </Dialog>
2365
- </div>
2366
- );
2367
- }
2368
-
2369
1909
  function FolderChip({
2370
1910
  active,
2371
1911
  label,
@@ -642,7 +642,7 @@ export default function GenerationPresetEditorRoute() {
642
642
  );
643
643
  }, [referenceAssetSearch, skeletonBackgroundAssets]);
644
644
  const settingsHref = libraryId
645
- ? `/library/${encodeURIComponent(libraryId)}?tab=settings`
645
+ ? `/brand-kits/${encodeURIComponent(libraryId)}/settings`
646
646
  : "/library";
647
647
 
648
648
  function updateForm(patch: Partial<PresetFormState>) {