@tangle-network/agent-app 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-DTS5TZRN.js +293 -0
- package/dist/chunk-DTS5TZRN.js.map +1 -0
- package/dist/completion-Kaqp_tWk.d.ts +41 -0
- package/dist/intakes/api.d.ts +2 -2
- package/dist/intakes/drizzle.d.ts +2 -2
- package/dist/intakes/index.d.ts +108 -32
- package/dist/intakes/index.js +66 -0
- package/dist/intakes/index.js.map +1 -1
- package/dist/intakes-react/index.d.ts +1 -1
- package/dist/intakes-react/lazy.d.ts +1 -1
- package/dist/{model-Cuj7d-xT.d.ts → model-Bzi5i63l.d.ts} +1 -1
- package/dist/studio/index.d.ts +132 -0
- package/dist/studio/index.js +59 -0
- package/dist/studio/index.js.map +1 -0
- package/dist/studio-react/index.d.ts +193 -0
- package/dist/studio-react/index.js +1216 -0
- package/dist/studio-react/index.js.map +1 -0
- package/dist/studio-react/studio.css +73 -0
- package/package.json +36 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/studio-react/studio-workspace.tsx","../../src/studio-react/use-studio-generations.ts","../../src/studio-react/composer-hero.tsx","../../src/studio-react/type-config.ts","../../src/studio-react/composer-shell.tsx","../../src/studio-react/image-composer.tsx","../../src/studio-react/video-composer.tsx","../../src/studio-react/speech-composer.tsx","../../src/studio-react/avatar-composer.tsx","../../src/studio-react/transcription-composer.tsx","../../src/studio-react/publish-package-composer.tsx","../../src/studio-react/studio-header.tsx","../../src/studio-react/result-canvas.tsx","../../src/studio-react/library-drawer.tsx","../../src/studio-react/studio-sheet.tsx","../../src/studio-react/generation-card.tsx","../../src/studio-react/generation-detail.tsx"],"sourcesContent":["import { useRef, useState } from 'react'\nimport { useSearchParams } from 'react-router'\nimport { Button } from '@tangle-network/sandbox-ui/primitives'\nimport { Images } from 'lucide-react'\nimport type { Generation } from '../studio'\nimport { useStudioGenerations } from './use-studio-generations'\nimport { ComposerHero } from './composer-hero'\nimport { StudioHeader } from './studio-header'\nimport { ResultCanvas } from './result-canvas'\nimport { LibraryDrawer } from './library-drawer'\n\nexport type StudioRole = 'owner' | 'admin' | 'editor' | 'viewer'\n\nexport interface StudioWorkspaceProps {\n generations: Generation[]\n totalCost: number\n workspaceId?: string\n role: StudioRole\n /** Polling endpoint override (default `/api/generations`). */\n generationsEndpoint?: string\n /** Build a vault link, optionally to a specific file. Defaults to `/app/<workspaceId>/vault`. */\n vaultHref?: (filePath?: string | null) => string\n /** Integrations page href for the publish-package \"Connect\" link. Defaults to `/app/<workspaceId>/integrations`. */\n integrationsHref?: string\n}\n\n/**\n * The full studio surface: header + composer + result canvas + library drawer,\n * with the generation orchestrator (merge/poll/revalidate) wired in. The host\n * route owns the loader (auth, RBAC, the generation query) and the server\n * endpoints (`/api/generate`, `/api/media-models`, `/api/generations`); this\n * shell renders that data and drives the live UI. Role gates the composer\n * (viewers get a read-only library) and the integration-management affordances.\n */\nexport function StudioWorkspace({\n generations,\n totalCost,\n workspaceId,\n role,\n generationsEndpoint,\n vaultHref,\n integrationsHref,\n}: StudioWorkspaceProps) {\n const [searchParams, setSearchParams] = useSearchParams()\n const typeFilter = searchParams.get('type')\n const [drawerOpen, setDrawerOpen] = useState(false)\n const [selected, setSelected] = useState<Generation | null>(null)\n const canvasRef = useRef<HTMLDivElement>(null)\n const canGenerate = role !== 'viewer'\n const canManageIntegrations = role === 'owner' || role === 'admin'\n // Default the navigation hrefs to the conventional /app/<workspaceId>/… routes;\n // a host on a different route scheme passes its own builders.\n const resolvedVaultHref = vaultHref ?? (workspaceId\n ? (filePath?: string | null) => (filePath\n ? `/app/${workspaceId}/vault?file=${encodeURIComponent(filePath)}`\n : `/app/${workspaceId}/vault`)\n : undefined)\n const resolvedIntegrationsHref = integrationsHref\n ?? (workspaceId ? `/app/${workspaceId}/integrations` : undefined)\n\n const { mergedGenerations, latestBatch, onGenerated } = useStudioGenerations(generations, {\n workspaceId,\n generationsEndpoint,\n })\n\n function setFilter(type: string | null) {\n if (type) setSearchParams({ type })\n else setSearchParams({})\n }\n\n function openLibrary() {\n setSelected(null)\n setDrawerOpen(true)\n }\n\n function openDetail(generation: Generation) {\n setSelected(generation)\n setDrawerOpen(true)\n }\n\n return (\n <div className=\"min-h-0 flex-1 overflow-y-auto bg-background\">\n <StudioHeader\n count={mergedGenerations.length}\n canGenerate={canGenerate}\n onOpenLibrary={openLibrary}\n />\n\n <div className=\"mx-auto w-full max-w-3xl space-y-4 px-4 py-6 sm:px-6\">\n {canGenerate ? (\n <>\n <ComposerHero\n workspaceId={workspaceId}\n integrationsHref={resolvedIntegrationsHref}\n canManageIntegrations={canManageIntegrations}\n onGenerated={(generation) => {\n onGenerated(generation)\n requestAnimationFrame(() => {\n canvasRef.current?.scrollIntoView({ behavior: 'smooth', block: 'center' })\n })\n }}\n />\n <div ref={canvasRef}>\n <ResultCanvas\n batch={latestBatch}\n onOpenLibrary={openLibrary}\n onSelect={openDetail}\n />\n </div>\n </>\n ) : (\n <section className=\"flex flex-col items-center justify-center gap-3 rounded-xl border border-border bg-card p-10 text-center shadow-sm\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted\">\n <Images className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n <p className=\"text-sm font-medium text-foreground\">\n {mergedGenerations.length > 0\n ? `${mergedGenerations.length} asset${mergedGenerations.length !== 1 ? 's' : ''} in this workspace`\n : 'No generations yet'}\n </p>\n <p className=\"max-w-sm text-xs text-muted-foreground\">\n When workspace members generate images, video, voice, avatars, or transcripts, they appear in the library.\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={openLibrary}>\n <Images className=\"mr-1.5 h-4 w-4\" />\n Open library\n </Button>\n </section>\n )}\n </div>\n\n <LibraryDrawer\n open={drawerOpen}\n onOpenChange={(open) => { setDrawerOpen(open); if (!open) setSelected(null) }}\n generations={mergedGenerations}\n totalCost={totalCost}\n typeFilter={typeFilter}\n onFilterChange={setFilter}\n vaultHref={resolvedVaultHref}\n selected={selected}\n onSelect={(generation) => { setSelected(generation); if (generation) setDrawerOpen(true) }}\n />\n </div>\n )\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useRevalidator } from 'react-router'\nimport {\n type Generation,\n generationStatus,\n isLocalGeneration,\n latestBatchOf,\n mergeLiveGeneration,\n mergeLoaderAndLive,\n} from '../studio'\n\n/**\n * The generation orchestrator behind a studio surface: it merges the loader's\n * rows with in-flight live generations, computes the latest batch for the\n * canvas, polls running generations until they settle, and revalidates the\n * route loader when a status changes.\n *\n * The merge keeps the canvas, the library, and the polling path looking at the\n * same full list. Polling hits `generationsEndpoint` (default `/api/generations`,\n * the convention both apps already serve); pass an override if a product routes\n * it elsewhere. `onGenerated` is wired to the composer's per-result callback.\n */\nexport function useStudioGenerations(\n loaderGenerations: Generation[],\n options: { workspaceId?: string; generationsEndpoint?: string } = {},\n) {\n const { workspaceId, generationsEndpoint = '/api/generations' } = options\n const revalidator = useRevalidator()\n const [liveGenerations, setLiveGenerations] = useState<Generation[]>([])\n\n const mergedGenerations = useMemo(\n () => mergeLoaderAndLive(loaderGenerations, liveGenerations),\n [loaderGenerations, liveGenerations],\n )\n\n const latestBatch = useMemo(() => latestBatchOf(mergedGenerations), [mergedGenerations])\n\n const runningGenerationIds = useMemo(() => mergedGenerations\n .filter((gen) => {\n const status = generationStatus(gen)\n return status === 'pending' || status === 'running'\n })\n .map((gen) => gen.id)\n .filter((id) => !id.startsWith('local-')), [mergedGenerations])\n\n // The poll loop must not churn the effect. `runningGenerationIds` is a fresh\n // array every render and react-router's `revalidator` identity flips while a\n // revalidation is in flight — depending on either restarts the interval on\n // every tick, collapsing the 4s cadence into a request flood. Key the effect\n // on the STABLE join of the running ids (re-subscribe only when the set\n // actually changes) and reach the live ids / revalidate through refs.\n const runningIdsRef = useRef(runningGenerationIds)\n runningIdsRef.current = runningGenerationIds\n const revalidateRef = useRef(revalidator.revalidate)\n revalidateRef.current = revalidator.revalidate\n const runningKey = runningGenerationIds.join(',')\n\n useEffect(() => {\n if (!workspaceId || !runningKey) return\n let cancelled = false\n const poll = async () => {\n const responses = await Promise.all(runningIdsRef.current.map(async (id) => {\n const res = await fetch(`${generationsEndpoint}?workspaceId=${encodeURIComponent(workspaceId)}&id=${encodeURIComponent(id)}`)\n if (!res.ok) return null\n const data = await res.json() as { generation?: Generation }\n return data.generation ?? null\n }))\n if (cancelled) return\n const refreshed = responses.filter((gen): gen is Generation => Boolean(gen))\n if (refreshed.length > 0) {\n setLiveGenerations((current) => refreshed.reduce(mergeLiveGeneration, current))\n }\n if (refreshed.some((gen) => generationStatus(gen) !== 'running' && generationStatus(gen) !== 'pending')) {\n revalidateRef.current()\n }\n }\n const interval = window.setInterval(() => { void poll() }, 4_000)\n void poll()\n return () => {\n cancelled = true\n window.clearInterval(interval)\n }\n }, [runningKey, workspaceId, generationsEndpoint])\n\n const onGenerated = useCallback((generation: Generation) => {\n setLiveGenerations((current) => mergeLiveGeneration(current, generation))\n if (!isLocalGeneration(generation)) revalidateRef.current()\n }, [])\n\n return { mergedGenerations, latestBatch, onGenerated }\n}\n","import { useEffect, useMemo, useRef, useState } from 'react'\nimport {\n Badge, Button, Input, Label, Textarea,\n Select, SelectContent, SelectItem, SelectTrigger, SelectValue,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { useIntegrations } from '@tangle-network/sandbox-ui/integrations'\nimport { Sparkles } from 'lucide-react'\nimport {\n type Generation,\n type GenerationType,\n type MediaModelCatalogResponse,\n CADENCES,\n DESTINATIONS,\n buildGenerationRequestBody,\n buildPublishPackage,\n failedOptimisticGeneration,\n isDestinationConnected,\n modelMessage,\n normalizeImageCount,\n optimisticGeneration,\n outputPathFor,\n preferredModelId,\n selectedModelsWithDefaults,\n userSafeGenerationMessage,\n} from '../studio'\nimport { TYPE_CONFIG, typeConfigFor } from './type-config'\nimport { ComposerDisclosure, Field } from './composer-shell'\nimport { ImageComposer } from './image-composer'\nimport { VideoComposer } from './video-composer'\nimport { SpeechComposer } from './speech-composer'\nimport { AvatarComposer } from './avatar-composer'\nimport { TranscriptionComposer, TranscriptionOptions } from './transcription-composer'\nimport { PublishPackageComposer } from './publish-package-composer'\n\nconst HUB_BASE_URL = '/api/integrations/hub'\n\nconst SUGGESTIONS: Array<{ label: string; prompt: string; type: GenerationType }> = [\n {\n label: 'Storyboard frame',\n type: 'image',\n prompt: 'A vertical storyboard frame for a product launch teaser — dark cinematic lighting, sleek studio aesthetic, 9:16 composition.',\n },\n {\n label: 'Launch teaser clip',\n type: 'video',\n prompt: 'A 6-second vertical launch teaser: animated product reveal, dynamic camera move, hero music swell.',\n },\n {\n label: 'Scratch voiceover',\n type: 'speech',\n prompt: 'A confident 12-second scratch voiceover for a product launch teaser: warm tone, conversational pace.',\n },\n {\n label: 'Transcribe dailies',\n type: 'transcription',\n prompt: 'Transcribe the latest dailies recording with timestamps, speaker labels, and key story beats highlighted.',\n },\n]\n\nexport function ComposerHero({\n workspaceId,\n integrationsHref,\n canManageIntegrations,\n onGenerated,\n}: {\n workspaceId?: string\n integrationsHref?: string\n canManageIntegrations: boolean\n onGenerated: (generation: Generation) => void\n}) {\n const [type, setType] = useState<GenerationType>('image')\n const [prompt, setPrompt] = useState('')\n const [negativePrompt, setNegativePrompt] = useState('')\n const [outputPath, setOutputPath] = useState(outputPathFor('image'))\n const [caption, setCaption] = useState('')\n const [postDescription, setPostDescription] = useState('')\n const [mentions, setMentions] = useState('')\n const [cadence, setCadence] = useState(CADENCES[0] ?? 'Manual approval')\n const [selectedDestinations, setSelectedDestinations] = useState<string[]>([])\n const [size, setSize] = useState('1536x1024')\n const [quality, setQuality] = useState('high')\n const [imageCount, setImageCount] = useState(1)\n const [duration, setDuration] = useState('6')\n const [resolution, setResolution] = useState('720p')\n const [aspectRatio, setAspectRatio] = useState('16:9')\n const [referenceImageUrl, setReferenceImageUrl] = useState('')\n const [voice, setVoice] = useState('alloy')\n const [avatarAudioUrl, setAvatarAudioUrl] = useState('')\n const [avatarImageUrl, setAvatarImageUrl] = useState('')\n const [avatarId, setAvatarId] = useState('')\n const [transcriptionAudioUrl, setTranscriptionAudioUrl] = useState('')\n const [transcriptionLanguage, setTranscriptionLanguage] = useState('')\n const [transcriptionResponseFormat, setTranscriptionResponseFormat] = useState('json')\n const [transcriptionTemperature, setTranscriptionTemperature] = useState('0')\n const [mediaModels, setMediaModels] = useState<MediaModelCatalogResponse | null>(null)\n const [mediaModelsLoading, setMediaModelsLoading] = useState(false)\n const [mediaModelsError, setMediaModelsError] = useState<string | null>(null)\n const [selectedModels, setSelectedModels] = useState<Partial<Record<GenerationType, string>>>({})\n const submitLockRef = useRef(false)\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const modelsForType = mediaModels?.models[type] ?? []\n const selectedModel = selectedModels[type] ?? preferredModelId(type, mediaModels) ?? ''\n const selectedModelOption = modelsForType.find((model) => model.id === selectedModel)\n const modelReady = Boolean(selectedModelOption)\n && selectedModelOption?.status !== 'unavailable'\n && !mediaModelsLoading\n && !mediaModelsError\n const hasRequiredInput = type === 'transcription'\n ? Boolean(transcriptionAudioUrl.trim())\n : type === 'avatar'\n ? Boolean(avatarAudioUrl.trim())\n : Boolean(prompt.trim())\n const canSubmit = Boolean(workspaceId)\n && modelReady\n && hasRequiredInput\n && !isSubmitting\n const integrations = useIntegrations({ apiBaseUrl: HUB_BASE_URL })\n const selectedConnectedDestinations = useMemo(() => selectedDestinations.filter((destinationId) => {\n const destination = DESTINATIONS.find((item) => item.id === destinationId)\n return Boolean(destination && isDestinationConnected(destination, integrations.connections))\n }), [integrations.connections, selectedDestinations])\n\n useEffect(() => {\n if (!workspaceId) return\n let cancelled = false\n setMediaModelsLoading(true)\n setMediaModelsError(null)\n\n fetch(`/api/media-models?workspaceId=${encodeURIComponent(workspaceId)}`)\n .then(async (res) => {\n const data = await res.json() as MediaModelCatalogResponse\n if (!res.ok) throw new Error(data.error ?? 'Could not load media models')\n return data\n })\n .then((data) => {\n if (cancelled) return\n setMediaModels(data)\n setSelectedModels((current) => selectedModelsWithDefaults(current, data))\n })\n .catch((err) => {\n if (cancelled) return\n setMediaModels(null)\n setMediaModelsError(err instanceof Error ? err.message : 'Could not load media models')\n })\n .finally(() => {\n if (!cancelled) setMediaModelsLoading(false)\n })\n\n return () => {\n cancelled = true\n }\n }, [workspaceId])\n\n function changeType(next: GenerationType) {\n setType(next)\n setOutputPath(outputPathFor(next))\n }\n\n async function generate() {\n if (!workspaceId || submitLockRef.current) return\n const promptText = prompt.trim()\n const avatarAudioUrlText = avatarAudioUrl.trim()\n const transcriptionAudioUrlText = transcriptionAudioUrl.trim()\n if (type !== 'transcription' && type !== 'avatar' && !promptText) {\n setError('prompt is required')\n return\n }\n if (type === 'avatar' && !avatarAudioUrlText) {\n setError('audioUrl is required')\n return\n }\n if (type === 'transcription' && !transcriptionAudioUrlText) {\n setError('audioUrl is required')\n return\n }\n if (!selectedModelOption || selectedModelOption.status === 'unavailable') {\n setError(`Select an available ${typeConfigFor(type).label} model`)\n return\n }\n if (cadence === 'Publish now' && selectedConnectedDestinations.length === 0) {\n setError('Select a connected destination to publish now')\n return\n }\n submitLockRef.current = true\n setIsSubmitting(true)\n setError(null)\n const clientRequestId = crypto.randomUUID()\n const requestedImageCount = type === 'image' ? normalizeImageCount(imageCount) : 1\n if (type === 'image' && requestedImageCount !== imageCount) setImageCount(requestedImageCount)\n const localGenerations = Array.from({ length: requestedImageCount }, (_, outputIndex) => optimisticGeneration({\n type,\n // avatar hides the prompt field (promptText is stale); transcription's is\n // an optional vocab hint. Never surface the source audio URL as the prompt.\n prompt: type === 'avatar' ? '' : promptText,\n model: selectedModel,\n clientRequestId,\n outputIndex: type === 'image' ? outputIndex : undefined,\n outputCount: type === 'image' ? requestedImageCount : undefined,\n }))\n localGenerations.slice().reverse().forEach(onGenerated)\n setPrompt('')\n let receivedServerGeneration = false\n try {\n const body = buildGenerationRequestBody({\n workspaceId,\n clientRequestId,\n type,\n model: selectedModel,\n prompt,\n negativePrompt,\n outputPath,\n publishPackage: buildPublishPackage({\n caption,\n postDescription,\n mentions,\n cadence,\n destinations: selectedConnectedDestinations,\n }),\n image: { size, quality, count: requestedImageCount },\n video: { duration, resolution, aspectRatio, referenceImageUrl },\n speech: { voice },\n avatar: { audioUrl: avatarAudioUrl, imageUrl: avatarImageUrl, avatarId },\n transcription: {\n audioUrl: transcriptionAudioUrl,\n language: transcriptionLanguage,\n responseFormat: transcriptionResponseFormat,\n temperature: transcriptionTemperature,\n },\n })\n\n const res = await fetch('/api/generate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n const data = await res.json() as { generation?: Generation; generations?: Generation[]; error?: string }\n const serverGenerations = data.generations?.length ? data.generations : data.generation ? [data.generation] : []\n if (serverGenerations.length > 0) {\n receivedServerGeneration = true\n serverGenerations.slice().reverse().forEach(onGenerated)\n }\n if (!res.ok || serverGenerations.length === 0) throw new Error(data.error ?? 'Generation failed')\n } catch (err) {\n if (!receivedServerGeneration) localGenerations.map(failedOptimisticGeneration).forEach(onGenerated)\n setError(err instanceof Error ? userSafeGenerationMessage(err.message) : 'Generation failed')\n } finally {\n submitLockRef.current = false\n setIsSubmitting(false)\n }\n }\n\n const mediaTypes = Object.entries(TYPE_CONFIG) as Array<[GenerationType, typeof TYPE_CONFIG[string]]>\n const hasInlineParams = type === 'image' || type === 'video' || type === 'speech'\n\n return (\n <section className=\"rounded-xl border border-border bg-card p-5 shadow-sm\">\n <Field label=\"Media type\" className=\"space-y-1.5\">\n <div\n role=\"tablist\"\n aria-label=\"Generation type\"\n className=\"grid grid-cols-5 gap-1 rounded-lg border border-border bg-muted/40 p-1\"\n >\n {mediaTypes.map(([key, cfg]) => {\n const Icon = cfg.icon\n const active = type === key\n return (\n <button\n key={key}\n type=\"button\"\n role=\"tab\"\n aria-selected={active}\n onClick={() => changeType(key)}\n className={`flex items-center justify-center gap-1.5 rounded-md px-2 py-2 text-xs font-medium transition-all ${\n active\n ? 'bg-primary/15 text-primary shadow-sm ring-1 ring-inset ring-primary/30'\n : 'text-muted-foreground hover:bg-foreground/[0.04] hover:text-foreground'\n }`}\n >\n <Icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"truncate\">{cfg.label}</span>\n </button>\n )\n })}\n </div>\n </Field>\n\n {type !== 'avatar' && (\n <div className=\"mt-4 space-y-2\">\n <Label htmlFor=\"studio-prompt\" className=\"block text-sm font-medium\">\n What do you want to create?\n </Label>\n <Textarea\n id=\"studio-prompt\"\n value={prompt}\n onChange={(event) => setPrompt(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n void generate()\n }\n }}\n rows={4}\n placeholder={type === 'transcription'\n ? 'Optional vocabulary, speaker names, timestamp style, or context...'\n : 'A vertical hero frame for a product launch teaser, dark cinematic lighting...'}\n className=\"resize-none text-sm\"\n />\n <div className=\"flex flex-wrap items-center gap-1.5 text-xs text-muted-foreground\">\n <span>Try:</span>\n {SUGGESTIONS.map((suggestion) => (\n <button\n key={suggestion.label}\n type=\"button\"\n onClick={() => {\n setPrompt(suggestion.prompt)\n changeType(suggestion.type)\n }}\n className=\"rounded-full border border-border bg-background px-2.5 py-1 text-xs text-foreground/80 transition-colors hover:border-primary/40 hover:bg-muted\"\n >\n {suggestion.label}\n </button>\n ))}\n </div>\n {type === 'transcription' && (\n <p className=\"text-xs text-muted-foreground\">\n Optional — biases the transcript's spelling, vocabulary, and speaker names. It isn't an instruction for the model to follow.\n </p>\n )}\n </div>\n )}\n\n {type === 'avatar' && (\n <AvatarComposer\n audioUrl={avatarAudioUrl}\n imageUrl={avatarImageUrl}\n avatarId={avatarId}\n onAudioUrlChange={setAvatarAudioUrl}\n onImageUrlChange={setAvatarImageUrl}\n onAvatarIdChange={setAvatarId}\n />\n )}\n {type === 'transcription' && (\n <TranscriptionComposer\n audioUrl={transcriptionAudioUrl}\n language={transcriptionLanguage}\n onAudioUrlChange={setTranscriptionAudioUrl}\n onLanguageChange={setTranscriptionLanguage}\n />\n )}\n\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2\">\n <Field\n label=\"Model\"\n htmlFor=\"studio-media-model\"\n className={`space-y-1.5 ${hasInlineParams ? '' : 'sm:col-span-2'}`}\n >\n <Select\n value={selectedModel || undefined}\n onValueChange={(value) => setSelectedModels((current) => ({ ...current, [type]: value }))}\n disabled={mediaModelsLoading || Boolean(mediaModelsError) || modelsForType.length === 0}\n >\n <SelectTrigger id=\"studio-media-model\" className=\"h-9 w-full\">\n <SelectValue placeholder={mediaModelsLoading ? 'Loading models…' : 'Select a model'} />\n </SelectTrigger>\n <SelectContent>\n {modelsForType.map((model) => (\n <SelectItem key={model.id} value={model.id} disabled={model.status === 'unavailable'}>\n <span className=\"flex w-full items-center justify-between gap-3\">\n <span className=\"truncate\">\n {model.name || model.id}{model.provider ? ` · ${model.provider}` : ''}\n </span>\n {model.status !== 'available' && (\n <span className=\"shrink-0 text-[10px] capitalize text-muted-foreground\">{model.status}</span>\n )}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </Field>\n {type === 'image' && (\n <ImageComposer\n size={size}\n quality={quality}\n imageCount={imageCount}\n onSizeChange={setSize}\n onQualityChange={setQuality}\n onImageCountChange={setImageCount}\n />\n )}\n {type === 'video' && (\n <VideoComposer\n duration={duration}\n resolution={resolution}\n aspectRatio={aspectRatio}\n referenceImageUrl={referenceImageUrl}\n onDurationChange={setDuration}\n onResolutionChange={setResolution}\n onAspectRatioChange={setAspectRatio}\n onReferenceImageUrlChange={setReferenceImageUrl}\n />\n )}\n {type === 'speech' && (\n <SpeechComposer voice={voice} onVoiceChange={setVoice} />\n )}\n </div>\n\n {(mediaModelsError || modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length)) && (\n <p className={`mt-2 text-xs ${mediaModelsError || selectedModelOption?.status === 'unavailable' ? 'text-destructive' : 'text-muted-foreground'}`}>\n {mediaModelsError ?? modelMessage(selectedModelOption, mediaModelsLoading, modelsForType.length)}\n </p>\n )}\n\n {error && (\n <div className=\"mt-3 rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive\">\n {error}\n </div>\n )}\n\n <div className=\"mt-4 space-y-2\">\n <ComposerDisclosure summary=\"Advanced options\">\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Negative prompt\">\n <Textarea\n value={negativePrompt}\n onChange={(event) => setNegativePrompt(event.target.value)}\n rows={2}\n placeholder=\"Avoid artifacts, off-style composition...\"\n />\n </Field>\n <Field label=\"Save to\">\n <Input value={outputPath} onChange={(event) => setOutputPath(event.target.value)} />\n </Field>\n {type === 'transcription' && (\n <TranscriptionOptions\n responseFormat={transcriptionResponseFormat}\n temperature={transcriptionTemperature}\n onResponseFormatChange={setTranscriptionResponseFormat}\n onTemperatureChange={setTranscriptionTemperature}\n />\n )}\n </div>\n </ComposerDisclosure>\n\n <ComposerDisclosure\n summary={(\n <>\n Schedule a post\n {selectedConnectedDestinations.length > 0 && (\n <Badge variant=\"outline\" className=\"ml-1 text-[10px]\">\n {selectedConnectedDestinations.length}\n </Badge>\n )}\n </>\n )}\n >\n <PublishPackageComposer\n caption={caption}\n postDescription={postDescription}\n mentions={mentions}\n cadence={cadence}\n selectedDestinations={selectedDestinations}\n connections={integrations.connections}\n connectionError={integrations.error}\n connectionsLoading={integrations.isLoading}\n integrationsHref={integrationsHref}\n canManageIntegrations={canManageIntegrations}\n onCaptionChange={setCaption}\n onDescriptionChange={setPostDescription}\n onMentionsChange={setMentions}\n onCadenceChange={setCadence}\n onDestinationToggle={(destination) => {\n const destinationConfig = DESTINATIONS.find((item) => item.id === destination)\n if (!destinationConfig || !isDestinationConnected(destinationConfig, integrations.connections)) return\n setSelectedDestinations((current) => current.includes(destination)\n ? current.filter((item) => item !== destination)\n : [...current, destination])\n }}\n />\n </ComposerDisclosure>\n </div>\n\n <Button onClick={generate} disabled={!canSubmit} size=\"lg\" className=\"mt-4 w-full\">\n <Sparkles className=\"mr-2 h-4 w-4\" />\n Generate\n <span className=\"ml-2 text-[10px] opacity-60\">⌘↵</span>\n </Button>\n </section>\n )\n}\n","import { Film, FileText, Image, Mic, Video } from 'lucide-react'\n\nexport interface TypeConfig {\n label: string\n icon: typeof Image\n color: string\n}\n\nconst IMAGE: TypeConfig = { label: 'Image', icon: Image, color: 'bg-blue-500/10 text-blue-600 border-blue-500/20' }\n\n// string-keyed so list cards can index by Generation.type\nexport const TYPE_CONFIG: Record<string, TypeConfig> = {\n image: IMAGE,\n video: { label: 'Video', icon: Video, color: 'bg-red-500/10 text-red-600 border-red-500/20' },\n avatar: { label: 'Avatar', icon: Film, color: 'bg-purple-500/10 text-purple-600 border-purple-500/20' },\n speech: { label: 'Audio', icon: Mic, color: 'bg-orange-500/10 text-orange-600 border-orange-500/20' },\n transcription: { label: 'Transcript', icon: FileText, color: 'bg-emerald-500/10 text-emerald-600 border-emerald-500/20' },\n}\n\n// Safe lookup for an arbitrary `Generation.type` — always defined (the table is\n// declared `Record<string, …>`, so a raw index is `T | undefined`). Falls back\n// to the image config, matching the prior `?? TYPE_CONFIG.image` call sites.\nexport function typeConfigFor(type: string): TypeConfig {\n return TYPE_CONFIG[type] ?? IMAGE\n}\n","import type { ReactNode, SelectHTMLAttributes } from 'react'\nimport { Label } from '@tangle-network/sandbox-ui/primitives'\nimport { ChevronRight } from 'lucide-react'\n\nexport function Field({\n label,\n htmlFor,\n className = 'space-y-1.5',\n children,\n}: {\n label: string\n htmlFor?: string\n className?: string\n children: ReactNode\n}) {\n return (\n <div className={className}>\n <Label htmlFor={htmlFor} className=\"text-sm\">{label}</Label>\n {children}\n </div>\n )\n}\n\nexport function ComposerDisclosure({ summary, children }: { summary: ReactNode; children: ReactNode }) {\n return (\n <details className=\"group rounded-lg border border-border bg-muted/30 transition-colors open:bg-muted/40\">\n <summary className=\"flex cursor-pointer list-none items-center gap-1.5 px-3 py-2.5 text-xs font-medium text-foreground/80 transition-colors hover:text-foreground [&::-webkit-details-marker]:hidden\">\n <ChevronRight className=\"h-3.5 w-3.5 text-muted-foreground transition-transform group-open:rotate-90\" />\n {summary}\n </summary>\n <div className=\"border-t border-border px-3 py-3\">{children}</div>\n </details>\n )\n}\n\nexport function NativeSelect(props: SelectHTMLAttributes<HTMLSelectElement>) {\n return (\n <select {...props} className=\"h-9 w-full rounded-md border border-input bg-background px-3 text-sm\" />\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { MIN_IMAGE_COUNT, MAX_IMAGE_COUNT, normalizeImageCount } from '../studio'\nimport { Field } from './composer-shell'\n\nexport function ImageComposer({\n size,\n quality,\n imageCount,\n onSizeChange,\n onQualityChange,\n onImageCountChange,\n}: {\n size: string\n quality: string\n imageCount: number\n onSizeChange: (value: string) => void\n onQualityChange: (value: string) => void\n onImageCountChange: (value: number) => void\n}) {\n return (\n <>\n <Field label=\"Size\"><Input value={size} onChange={(event) => onSizeChange(event.target.value)} /></Field>\n <Field label=\"Quality\"><Input value={quality} onChange={(event) => onQualityChange(event.target.value)} /></Field>\n <Field label=\"Images\"><Input type=\"number\" min={MIN_IMAGE_COUNT} max={MAX_IMAGE_COUNT} value={imageCount} onChange={(event) => onImageCountChange(normalizeImageCount(event.target.value))} /></Field>\n </>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field } from './composer-shell'\n\nexport function VideoComposer({\n duration,\n resolution,\n aspectRatio,\n referenceImageUrl,\n onDurationChange,\n onResolutionChange,\n onAspectRatioChange,\n onReferenceImageUrlChange,\n}: {\n duration: string\n resolution: string\n aspectRatio: string\n referenceImageUrl: string\n onDurationChange: (value: string) => void\n onResolutionChange: (value: string) => void\n onAspectRatioChange: (value: string) => void\n onReferenceImageUrlChange: (value: string) => void\n}) {\n return (\n <>\n <Field label=\"Duration (s)\"><Input value={duration} onChange={(event) => onDurationChange(event.target.value)} /></Field>\n <Field label=\"Resolution\"><Input value={resolution} onChange={(event) => onResolutionChange(event.target.value)} /></Field>\n <Field label=\"Aspect ratio\"><Input value={aspectRatio} onChange={(event) => onAspectRatioChange(event.target.value)} /></Field>\n <Field label=\"Reference image URL\"><Input value={referenceImageUrl} onChange={(event) => onReferenceImageUrlChange(event.target.value)} /></Field>\n </>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field } from './composer-shell'\n\nexport function SpeechComposer({\n voice,\n onVoiceChange,\n}: {\n voice: string\n onVoiceChange: (value: string) => void\n}) {\n return (\n <Field label=\"Voice\"><Input value={voice} onChange={(event) => onVoiceChange(event.target.value)} /></Field>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field } from './composer-shell'\n\nexport function AvatarComposer({\n audioUrl,\n imageUrl,\n avatarId,\n onAudioUrlChange,\n onImageUrlChange,\n onAvatarIdChange,\n}: {\n audioUrl: string\n imageUrl: string\n avatarId: string\n onAudioUrlChange: (value: string) => void\n onImageUrlChange: (value: string) => void\n onAvatarIdChange: (value: string) => void\n}) {\n return (\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2\">\n <Field label=\"Audio URL\" htmlFor=\"studio-audio-url\">\n <Input\n id=\"studio-audio-url\"\n value={audioUrl}\n onChange={(event) => onAudioUrlChange(event.target.value)}\n placeholder=\"https://cdn.example.com/source-audio.mp3\"\n />\n </Field>\n <Field label=\"Image URL\" htmlFor=\"studio-avatar-image-url\">\n <Input\n id=\"studio-avatar-image-url\"\n value={imageUrl}\n onChange={(event) => onImageUrlChange(event.target.value)}\n placeholder=\"https://cdn.example.com/portrait.png\"\n />\n </Field>\n <Field label=\"Avatar ID\" htmlFor=\"studio-avatar-id\">\n <Input\n id=\"studio-avatar-id\"\n value={avatarId}\n onChange={(event) => onAvatarIdChange(event.target.value)}\n placeholder=\"Optional provider avatar id\"\n />\n </Field>\n </div>\n )\n}\n","import { Input } from '@tangle-network/sandbox-ui/primitives'\nimport { Field, NativeSelect } from './composer-shell'\n\nexport function TranscriptionComposer({\n audioUrl,\n language,\n onAudioUrlChange,\n onLanguageChange,\n}: {\n audioUrl: string\n language: string\n onAudioUrlChange: (value: string) => void\n onLanguageChange: (value: string) => void\n}) {\n return (\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2\">\n <Field label=\"Audio URL\" htmlFor=\"studio-audio-url\">\n <Input\n id=\"studio-audio-url\"\n value={audioUrl}\n onChange={(event) => onAudioUrlChange(event.target.value)}\n placeholder=\"https://cdn.example.com/source-audio.mp3\"\n />\n </Field>\n <Field label=\"Language\" htmlFor=\"studio-transcription-language\">\n <Input\n id=\"studio-transcription-language\"\n value={language}\n onChange={(event) => onLanguageChange(event.target.value)}\n placeholder=\"en\"\n />\n </Field>\n </div>\n )\n}\n\nexport function TranscriptionOptions({\n responseFormat,\n temperature,\n onResponseFormatChange,\n onTemperatureChange,\n}: {\n responseFormat: string\n temperature: string\n onResponseFormatChange: (value: string) => void\n onTemperatureChange: (value: string) => void\n}) {\n return (\n <>\n <Field label=\"Response format\">\n <NativeSelect value={responseFormat} onChange={(event) => onResponseFormatChange(event.target.value)}>\n <option value=\"json\">JSON</option>\n <option value=\"text\">Text</option>\n <option value=\"srt\">SRT</option>\n <option value=\"verbose_json\">Verbose JSON</option>\n <option value=\"vtt\">VTT</option>\n </NativeSelect>\n </Field>\n <Field label=\"Temperature\"><Input type=\"number\" min=\"0\" max=\"1\" step=\"0.1\" value={temperature} onChange={(event) => onTemperatureChange(event.target.value)} /></Field>\n </>\n )\n}\n","import { Link } from 'react-router'\nimport { Badge, Button, Input, Textarea } from '@tangle-network/sandbox-ui/primitives'\nimport type { IntegrationConnection } from '@tangle-network/sandbox-ui/integrations'\nimport { AlertTriangle, CalendarClock, Check } from 'lucide-react'\nimport { CADENCES, DESTINATIONS, isDestinationConnected } from '../studio'\nimport { Field, NativeSelect } from './composer-shell'\n\nexport function PublishPackageComposer({\n caption,\n postDescription,\n mentions,\n cadence,\n selectedDestinations,\n connections,\n connectionError,\n connectionsLoading,\n integrationsHref,\n canManageIntegrations,\n onCaptionChange,\n onDescriptionChange,\n onMentionsChange,\n onCadenceChange,\n onDestinationToggle,\n}: {\n caption: string\n postDescription: string\n mentions: string\n cadence: string\n selectedDestinations: string[]\n connections: IntegrationConnection[]\n connectionError: Error | null\n connectionsLoading: boolean\n integrationsHref?: string\n canManageIntegrations: boolean\n onCaptionChange: (value: string) => void\n onDescriptionChange: (value: string) => void\n onMentionsChange: (value: string) => void\n onCadenceChange: (value: string) => void\n onDestinationToggle: (destination: string) => void\n}) {\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n {connectionError ? (\n <div className=\"flex items-center gap-2 rounded-md border border-warning/20 bg-warning/5 px-2.5 py-1.5 text-xs text-warning\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0\" />\n Couldn't load connected apps. Check Integrations.\n </div>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n {connectionsLoading\n ? 'Checking connected apps…'\n : 'Stage captions, destinations, cadence. Saved with the generated asset.'}\n </p>\n )}\n {integrationsHref && canManageIntegrations && (\n <Link to={integrationsHref} prefetch=\"intent\" className=\"shrink-0\">\n <Button variant=\"outline\" size=\"sm\">Connect</Button>\n </Link>\n )}\n </div>\n <div className=\"grid gap-2\">\n {DESTINATIONS.map((destination) => {\n const connected = isDestinationConnected(destination, connections)\n const active = connected && selectedDestinations.includes(destination.id)\n return (\n <button\n key={destination.id}\n type=\"button\"\n disabled={!connected}\n aria-pressed={active}\n onClick={() => onDestinationToggle(destination.id)}\n className={`rounded-md border p-2 text-left transition-colors disabled:cursor-not-allowed disabled:opacity-60 ${\n active\n ? 'border-primary bg-primary/5 ring-1 ring-primary/20'\n : 'border-border hover:bg-muted/50'\n }`}\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"flex items-center gap-1.5 text-xs font-medium text-foreground\">\n {active && <Check className=\"h-3.5 w-3.5 text-primary\" />}\n {destination.label}\n </span>\n <Badge variant={active || connected ? 'default' : 'outline'}>{active ? 'Selected' : connected ? 'Ready' : 'Not connected'}</Badge>\n </div>\n <p className=\"mt-1 text-xs text-muted-foreground\">{destination.fields}</p>\n </button>\n )\n })}\n </div>\n <Field label=\"Caption\" className=\"space-y-2\">\n <Textarea value={caption} onChange={(event) => onCaptionChange(event.target.value)} rows={3} placeholder=\"Write or generate the caption for selected destinations...\" />\n </Field>\n <Field label=\"Description / CTA\" className=\"space-y-2\">\n <Textarea value={postDescription} onChange={(event) => onDescriptionChange(event.target.value)} rows={2} placeholder=\"Release note, product context, link, or approval instruction...\" />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Mentions\" className=\"space-y-2\">\n <Input value={mentions} onChange={(event) => onMentionsChange(event.target.value)} placeholder=\"@creator, @partner\" />\n </Field>\n <Field label=\"Cadence\" className=\"space-y-2\">\n <NativeSelect value={cadence} onChange={(event) => onCadenceChange(event.target.value)}>\n {CADENCES.map((option) => <option key={option} value={option}>{option}</option>)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"flex items-center gap-2 rounded-md bg-muted/40 p-2 text-xs text-muted-foreground\">\n <CalendarClock className=\"h-3.5 w-3.5\" />\n Publish packages stay attached to generated media and can run through connected GTM apps.\n </div>\n </div>\n )\n}\n","import { Button } from '@tangle-network/sandbox-ui/primitives'\nimport { Images } from 'lucide-react'\n\nexport function StudioHeader({\n count,\n onOpenLibrary,\n canGenerate,\n}: {\n count: number\n onOpenLibrary: () => void\n canGenerate: boolean\n}) {\n return (\n <header className=\"sticky top-0 z-20 border-b border-border bg-background/80 backdrop-blur-md\">\n <div className=\"mx-auto flex w-full max-w-3xl items-center justify-between gap-3 px-4 py-3 sm:px-6\">\n <div className=\"min-w-0\">\n <h1 className=\"text-lg font-semibold tracking-tight text-foreground\">Studio</h1>\n <p className=\"truncate text-xs text-muted-foreground\">\n {canGenerate\n ? 'Generate images, video, voice, avatars, and transcripts.'\n : 'Browse images, video, voice, avatars, and transcripts your team has created.'}\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={onOpenLibrary} className=\"shrink-0\">\n <Images className=\"mr-1.5 h-4 w-4\" />\n Library\n {count > 0 && (\n <span className=\"ml-2 inline-flex h-5 min-w-5 items-center justify-center rounded-full bg-primary/15 px-1.5 text-[10px] font-semibold text-primary\">\n {count}\n </span>\n )}\n </Button>\n </div>\n </header>\n )\n}\n","import { Badge } from '@tangle-network/sandbox-ui/primitives'\nimport { ArrowRight, Sparkles } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationStatus,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\n\nexport function ResultCanvas({\n batch,\n onOpenLibrary,\n onSelect,\n}: {\n batch: Generation[]\n onOpenLibrary: () => void\n onSelect: (generation: Generation) => void\n}) {\n const cardClass = 'rounded-xl border border-border bg-card shadow-sm'\n\n if (batch.length === 0) {\n return (\n <section className={`${cardClass} flex min-h-[180px] flex-col items-center justify-center gap-2 p-8 text-center`}>\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-muted\">\n <Sparkles className=\"h-6 w-6 text-muted-foreground/40\" />\n </div>\n <p className=\"text-sm font-medium text-foreground\">Your creations appear here</p>\n <p className=\"max-w-xs text-xs text-muted-foreground\">\n Write a prompt above and hit Generate — your latest result blooms here, and everything lives in your library.\n </p>\n </section>\n )\n }\n\n const cfg = typeConfigFor(batch[0]?.type ?? 'image')\n const statuses = batch.map(generationStatus)\n const runLabel = statuses.some((s) => s === 'pending' || s === 'running')\n ? 'Generating…'\n : statuses.every((s) => s === 'failed')\n ? 'Last run failed'\n : 'Latest creation'\n const isWorking = statuses.some((s) => s === 'pending' || s === 'running')\n\n return (\n <section className={`${cardClass} p-5`}>\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"outline\" className={`${cfg.color} text-[10px]`}>{cfg.label}</Badge>\n <span className=\"text-sm font-medium text-foreground\">{runLabel}</span>\n {isWorking && <span className=\"h-2 w-2 animate-pulse rounded-full bg-primary\" />}\n </div>\n <button\n type=\"button\"\n onClick={onOpenLibrary}\n className=\"flex items-center gap-1 text-xs font-medium text-primary transition-colors hover:text-primary/80\"\n >\n View in Library\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n <div className={`grid gap-3 ${batch.length === 1 ? 'grid-cols-1' : 'grid-cols-2'}`}>\n {batch.map((generation) => (\n <button\n key={generation.id}\n type=\"button\"\n onClick={() => onSelect(generation)}\n className=\"studio-bloom group relative aspect-video overflow-hidden rounded-lg border border-border bg-muted/40 transition-colors hover:border-primary/40\"\n >\n <CanvasTile generation={generation} />\n </button>\n ))}\n </div>\n\n {batch.length > 1 && (\n <p className=\"mt-2 text-xs text-muted-foreground\">{batch.length} results from this run</p>\n )}\n </section>\n )\n}\n\nfunction CanvasTile({ generation }: { generation: Generation }) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const status = generationStatus(generation)\n\n if (status === 'pending' || status === 'running') {\n return <div className=\"studio-shimmer absolute inset-0 h-full w-full\" />\n }\n if (status === 'failed') {\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-2 p-4 text-center\">\n <Icon className=\"h-6 w-6 text-destructive/50\" />\n <p className=\"line-clamp-3 text-xs text-destructive\">{generationError(generation) ?? 'Generation failed'}</p>\n </div>\n )\n }\n if (generation.type === 'image' && generation.result) {\n return <img src={generation.result} alt={generation.prompt} className=\"absolute inset-0 h-full w-full object-contain\" />\n }\n if ((generation.type === 'video' || generation.type === 'avatar') && generation.result) {\n return <video src={generation.result} controls className=\"absolute inset-0 h-full w-full object-contain\" />\n }\n if (generation.type === 'speech' && generation.result) {\n return (\n <div className=\"absolute inset-0 flex items-center justify-center p-4\">\n <audio src={generation.result} controls className=\"w-full\" />\n </div>\n )\n }\n if (generation.type === 'transcription' && generation.result) {\n return (\n <div className=\"absolute inset-0 overflow-y-auto p-4\">\n <p className=\"whitespace-pre-wrap text-xs text-foreground\">{generation.result}</p>\n </div>\n )\n }\n return (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )\n}\n","import { useMemo } from 'react'\nimport { Link } from 'react-router'\nimport {\n Button, EmptyState,\n Tabs, TabsList, TabsTrigger,\n} from '@tangle-network/sandbox-ui/primitives'\nimport { ArrowLeft, DollarSign, Film, FolderOpen, Sparkles, X } from 'lucide-react'\nimport {\n type Generation,\n isGenerationType,\n} from '../studio'\nimport { TYPE_CONFIG } from './type-config'\nimport { StudioSheet } from './studio-sheet'\nimport { GenerationCard } from './generation-card'\nimport { GenerationDetail } from './generation-detail'\n\nexport function LibraryDrawer({\n open,\n onOpenChange,\n generations,\n totalCost,\n typeFilter,\n onFilterChange,\n vaultHref,\n selected,\n onSelect,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n generations: Generation[]\n totalCost: number\n typeFilter: string | null\n onFilterChange: (type: string | null) => void\n vaultHref?: (filePath?: string | null) => string\n selected: Generation | null\n onSelect: (generation: Generation | null) => void\n}) {\n const visible = useMemo(() => {\n if (!typeFilter || !isGenerationType(typeFilter)) return generations\n return generations.filter((generation) => generation.type === typeFilter)\n }, [generations, typeFilter])\n\n return (\n <StudioSheet open={open} onOpenChange={onOpenChange} title=\"Asset library\">\n <header className=\"flex shrink-0 items-center justify-between gap-3 border-b border-border px-4 py-3\">\n {selected ? (\n <button\n type=\"button\"\n onClick={() => onSelect(null)}\n className=\"flex items-center gap-1.5 text-sm font-medium text-foreground transition-colors hover:text-primary\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to library\n </button>\n ) : (\n <h2 className=\"text-sm font-semibold text-foreground\">Asset library</h2>\n )}\n <button\n type=\"button\"\n aria-label=\"Close library\"\n onClick={() => onOpenChange(false)}\n className=\"rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </header>\n\n {selected ? (\n <div className=\"flex-1 overflow-y-auto p-4\">\n <GenerationDetail\n generation={selected}\n vaultHref={vaultHref}\n onNavigate={() => onOpenChange(false)}\n />\n </div>\n ) : (\n <>\n <div className=\"shrink-0 border-b border-border px-4 pt-3\">\n <div className=\"mb-2 flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-3 text-xs text-muted-foreground\">\n <span>{visible.length} generation{visible.length !== 1 ? 's' : ''}</span>\n <span className=\"flex items-center gap-0.5\">\n <DollarSign className=\"h-3 w-3\" />\n {totalCost.toFixed(2)} spent\n </span>\n </div>\n {vaultHref && (\n <Link to={vaultHref()} prefetch=\"intent\" onClick={() => onOpenChange(false)}>\n <Button size=\"sm\" variant=\"outline\">\n <FolderOpen className=\"mr-1.5 h-3.5 w-3.5\" />\n Vault\n </Button>\n </Link>\n )}\n </div>\n <Tabs value={typeFilter ?? 'all'} onValueChange={(v) => onFilterChange(v === 'all' ? null : v)}>\n <TabsList className=\"h-9 w-full justify-start gap-1 overflow-x-auto bg-transparent\">\n <TabsTrigger value=\"all\" className=\"text-xs\">All</TabsTrigger>\n {Object.entries(TYPE_CONFIG).map(([key, cfg]) => (\n <TabsTrigger key={key} value={key} className=\"text-xs\">{cfg.label}</TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-4\">\n {visible.length === 0 ? (\n <EmptyState\n icon={typeFilter\n ? <Film className=\"h-8 w-8 text-muted-foreground/30\" />\n : <Sparkles className=\"h-10 w-10 text-muted-foreground/30\" />}\n title={typeFilter\n ? `No ${TYPE_CONFIG[typeFilter]?.label ?? typeFilter} generations`\n : 'No generations yet'}\n description={typeFilter\n ? 'Try a different filter or change the type in the composer.'\n : 'Everything you and the agent create lives here.'}\n className=\"py-16\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {visible.map((generation) => (\n <GenerationCard key={generation.id} generation={generation} onSelect={onSelect} />\n ))}\n </div>\n )}\n </div>\n </>\n )}\n </StudioSheet>\n )\n}\n","import type { ReactNode } from 'react'\nimport * as Dialog from '@radix-ui/react-dialog'\n\n/**\n * Right-side overlay sheet built on Radix Dialog — gives focus-trap, scroll-lock,\n * and Escape-to-close for free. Slide/fade come from the studio-sheet-* classes in\n * ./studio.css (driven by Radix data-state), not tailwindcss-animate.\n */\nexport function StudioSheet({\n open,\n onOpenChange,\n title,\n children,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n title: string\n children: ReactNode\n}) {\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"studio-sheet-overlay fixed inset-0 z-50 bg-black/50 backdrop-blur-sm\" />\n <Dialog.Content\n className=\"studio-sheet-content fixed inset-y-0 right-0 z-50 flex w-[min(92vw,30rem)] flex-col border-l border-border bg-card shadow-lg focus:outline-none\"\n aria-describedby={undefined}\n >\n <Dialog.Title className=\"sr-only\">{title}</Dialog.Title>\n {children}\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","import { Card, CardContent, Badge } from '@tangle-network/sandbox-ui/primitives'\nimport { Send } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationStatus,\n isPublishPackage,\n relativeTime,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\n\nexport function GenerationCard({\n generation,\n onSelect,\n}: {\n generation: Generation\n onSelect: (generation: Generation) => void\n}) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const status = generationStatus(generation)\n const publishPackage = generation.metadata?.publishPackage\n return (\n <button type=\"button\" onClick={() => onSelect(generation)} className=\"group text-left animate-row-in\">\n <Card className=\"overflow-hidden transition-all group-hover:border-primary/50 group-hover:shadow-md\">\n <div className=\"relative aspect-video bg-muted/50\">\n {generation.type === 'image' && generation.result ? (\n <img src={generation.result} alt={generation.prompt} className=\"h-full w-full object-cover\" />\n ) : (generation.type === 'video' || generation.type === 'avatar') && generation.result ? (\n <video src={generation.result} className=\"h-full w-full object-cover\" muted />\n ) : generation.type === 'speech' && generation.result ? (\n <div className=\"flex h-full items-center justify-center\">\n <div className=\"flex items-center gap-2\">\n <Icon className=\"h-6 w-6 text-muted-foreground/40\" />\n <span className=\"text-xs text-muted-foreground\">Audio</span>\n </div>\n </div>\n ) : generation.type === 'transcription' && generation.result ? (\n <div className=\"flex h-full items-center justify-center p-4\">\n <p className=\"line-clamp-5 text-xs text-muted-foreground\">{generation.result}</p>\n </div>\n ) : status === 'pending' || status === 'running' ? (\n <div className=\"shimmer h-full w-full\" />\n ) : (\n <div className=\"flex h-full items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )}\n <div className=\"absolute left-2 top-2\">\n <Badge variant=\"outline\" className={`${cfg.color} text-[10px] backdrop-blur-sm`}>\n {cfg.label}\n </Badge>\n </div>\n <GenerationStatusBadge generation={generation} />\n </div>\n <CardContent className=\"p-3\">\n <p className=\"mb-2 line-clamp-2 text-xs text-foreground\">{generation.prompt}</p>\n {status === 'failed' && (\n <p className=\"mb-2 line-clamp-2 text-[10px] text-destructive\">{generationError(generation)}</p>\n )}\n <div className=\"flex items-center justify-between\">\n {generation.model && (\n <span className=\"truncate text-[10px] text-muted-foreground\">{generation.model}</span>\n )}\n <div className=\"flex shrink-0 items-center gap-2\">\n {generation.cost != null && (\n <span className=\"text-[10px] text-muted-foreground\">${generation.cost.toFixed(3)}</span>\n )}\n <span className=\"text-[10px] text-muted-foreground\">{relativeTime(generation.createdAt)}</span>\n </div>\n </div>\n {isPublishPackage(publishPackage) && (\n <div className=\"mt-3 rounded-md border border-border bg-muted/30 p-2\">\n <div className=\"mb-1 flex items-center gap-1.5 text-[10px] font-medium text-foreground\">\n <Send className=\"h-3 w-3\" />\n {(publishPackage.destinations ?? []).join(', ') || 'Publish package'}\n </div>\n <p className=\"line-clamp-2 text-[10px] text-muted-foreground\">\n {publishPackage.caption || 'Caption pending'}\n </p>\n </div>\n )}\n </CardContent>\n </Card>\n </button>\n )\n}\n\nexport function GenerationStatusBadge({\n generation,\n inline = false,\n}: {\n generation: Generation\n inline?: boolean\n}) {\n const status = generationStatus(generation)\n if (status === 'succeeded') return null\n\n const label = status === 'failed' ? 'Failed' : status === 'running' ? 'Running' : 'Pending'\n const className = status === 'failed'\n ? 'border-destructive/25 bg-destructive/10 text-destructive'\n : 'border-warning/25 bg-warning/10 text-warning'\n\n return (\n <div className={inline ? '' : 'absolute bottom-2 left-2'}>\n <Badge variant=\"outline\" className={`${className} text-[10px] backdrop-blur-sm`}>\n {label}\n </Badge>\n </div>\n )\n}\n","import { Link } from 'react-router'\nimport { Badge, Button } from '@tangle-network/sandbox-ui/primitives'\nimport { FolderOpen } from 'lucide-react'\nimport {\n type Generation,\n generationError,\n generationVaultPath,\n} from '../studio'\nimport { typeConfigFor } from './type-config'\nimport { GenerationStatusBadge } from './generation-card'\n\nexport function GenerationDetail({\n generation,\n vaultHref,\n onNavigate,\n}: {\n generation: Generation\n vaultHref?: (filePath?: string | null) => string\n onNavigate?: () => void\n}) {\n const cfg = typeConfigFor(generation.type)\n const Icon = cfg.icon\n const href = vaultHref ? vaultHref(generationVaultPath(generation)) : null\n\n return (\n <div className=\"space-y-4\">\n <div className=\"overflow-hidden rounded-lg bg-muted/50\">\n {generation.type === 'image' && generation.result ? (\n <img src={generation.result} alt={generation.prompt} className=\"max-h-[420px] w-full object-contain\" />\n ) : (generation.type === 'video' || generation.type === 'avatar') && generation.result ? (\n <video src={generation.result} controls className=\"max-h-[420px] w-full\" />\n ) : generation.type === 'speech' && generation.result ? (\n <div className=\"p-6\">\n <audio src={generation.result} controls className=\"w-full\" />\n </div>\n ) : (\n <div className=\"flex h-32 items-center justify-center\">\n <Icon className=\"h-8 w-8 text-muted-foreground/20\" />\n </div>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\" className={cfg.color}>{cfg.label}</Badge>\n <GenerationStatusBadge generation={generation} inline />\n {generationError(generation) && (\n <span className=\"text-xs text-destructive\">{generationError(generation)}</span>\n )}\n </div>\n\n <div>\n <span className=\"mb-1 block text-xs font-medium text-muted-foreground\">Prompt</span>\n <p className=\"text-sm text-foreground\">{generation.prompt}</p>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-4\">\n {generation.model && (\n <div>\n <span className=\"block text-[10px] font-medium text-muted-foreground\">Model</span>\n <span className=\"text-xs text-foreground\">{generation.model}</span>\n </div>\n )}\n {generation.cost != null && (\n <div>\n <span className=\"block text-[10px] font-medium text-muted-foreground\">Cost</span>\n <span className=\"text-xs text-foreground\">${generation.cost.toFixed(4)}</span>\n </div>\n )}\n {generation.createdAt && (\n <div>\n <span className=\"block text-[10px] font-medium text-muted-foreground\">Created</span>\n <span className=\"text-xs text-foreground\">{new Date(generation.createdAt).toLocaleString()}</span>\n </div>\n )}\n </div>\n\n {generation.type === 'transcription' && generation.result && (\n <div>\n <span className=\"mb-1 block text-xs font-medium text-muted-foreground\">Transcription</span>\n <pre className=\"max-h-64 overflow-y-auto whitespace-pre-wrap rounded-lg bg-muted/50 p-4 text-sm text-foreground\">\n {generation.result}\n </pre>\n </div>\n )}\n\n {href && (\n <div className=\"border-t border-border pt-2\">\n <Link to={href} prefetch=\"intent\" onClick={onNavigate}>\n <Button size=\"sm\" variant=\"outline\">\n <FolderOpen className=\"mr-1.5 h-3.5 w-3.5\" />\n Open in Vault\n </Button>\n </Link>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["useRef","useState","Button","Images","useEffect","useMemo","useRef","useState","Badge","Button","Input","Label","Textarea","jsx","jsxs","Input","Fragment","jsx","jsxs","Input","Input","jsx","Input","Input","jsx","jsxs","Input","Input","Fragment","jsx","jsxs","Input","Input","jsx","jsxs","Input","Fragment","jsx","jsxs","useState","useRef","useMemo","useEffect","Label","Textarea","Input","Badge","Button","Button","jsx","jsxs","Badge","Sparkles","jsx","jsxs","Sparkles","Badge","useMemo","Link","Button","Film","FolderOpen","Sparkles","jsx","jsxs","Badge","jsx","jsxs","Badge","Link","Badge","Button","jsx","jsxs","Badge","Link","Button","Fragment","jsx","jsxs","useMemo","Link","Button","FolderOpen","Film","Sparkles","Fragment","jsx","jsxs","useState","useRef","Images","Button"]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Studio animations: the right-side library sheet slide/fade, the result-canvas
|
|
3
|
+
* bloom-in, and the neutral skeleton shimmer. Ships as a raw stylesheet (the
|
|
4
|
+
* `./styles` precedent) so apps that don't already define these classes can
|
|
5
|
+
* `import '@tangle-network/agent-app/studio-react/styles'` once. Token-driven
|
|
6
|
+
* (`--muted`, `--muted-foreground`) so it inherits the consuming app's theme.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* ── Studio: library sheet + result canvas ── */
|
|
10
|
+
@keyframes studio-sheet-in {
|
|
11
|
+
from { transform: translateX(100%); }
|
|
12
|
+
to { transform: translateX(0); }
|
|
13
|
+
}
|
|
14
|
+
@keyframes studio-sheet-out {
|
|
15
|
+
from { transform: translateX(0); }
|
|
16
|
+
to { transform: translateX(100%); }
|
|
17
|
+
}
|
|
18
|
+
@keyframes studio-overlay-fade {
|
|
19
|
+
from { opacity: 0; }
|
|
20
|
+
to { opacity: 1; }
|
|
21
|
+
}
|
|
22
|
+
@keyframes studio-bloom {
|
|
23
|
+
from { opacity: 0; transform: translateY(6px) scale(0.99); }
|
|
24
|
+
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Dedicated classes (not tailwindcss-animate .animate-in) so the right-side
|
|
28
|
+
sheet is unaffected by a conflicting .animate-in rule. Driven by Radix's
|
|
29
|
+
data-state on the dialog parts. */
|
|
30
|
+
.studio-sheet-content[data-state='open'] { animation: studio-sheet-in 0.28s cubic-bezier(0.32, 0.72, 0, 1); }
|
|
31
|
+
.studio-sheet-content[data-state='closed'] { animation: studio-sheet-out 0.2s cubic-bezier(0.4, 0, 1, 1); }
|
|
32
|
+
.studio-sheet-overlay[data-state='open'] { animation: studio-overlay-fade 0.28s ease-out; }
|
|
33
|
+
.studio-sheet-overlay[data-state='closed'] { animation: studio-overlay-fade 0.2s ease-in reverse; }
|
|
34
|
+
.studio-bloom { animation: studio-bloom 0.3s cubic-bezier(0.22, 1, 0.36, 1); }
|
|
35
|
+
|
|
36
|
+
/* Neutral skeleton shimmer — a soft grey band sweeps the muted surface.
|
|
37
|
+
`.shimmer` is an alias so the generation card and result canvas share one
|
|
38
|
+
skeleton treatment. */
|
|
39
|
+
@keyframes studio-shimmer {
|
|
40
|
+
0% { background-position: 200% 0; }
|
|
41
|
+
100% { background-position: -200% 0; }
|
|
42
|
+
}
|
|
43
|
+
.studio-shimmer,
|
|
44
|
+
.shimmer {
|
|
45
|
+
background-color: hsl(var(--muted));
|
|
46
|
+
background-image: linear-gradient(
|
|
47
|
+
90deg,
|
|
48
|
+
transparent 0%,
|
|
49
|
+
hsl(var(--muted-foreground) / 0.22) 50%,
|
|
50
|
+
transparent 100%
|
|
51
|
+
);
|
|
52
|
+
background-size: 200% 100%;
|
|
53
|
+
background-repeat: no-repeat;
|
|
54
|
+
animation: studio-shimmer 1.7s ease-in-out infinite;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Library card entrance. */
|
|
58
|
+
@keyframes studio-row-in {
|
|
59
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
60
|
+
to { opacity: 1; transform: translateY(0); }
|
|
61
|
+
}
|
|
62
|
+
.animate-row-in { animation: studio-row-in 0.25s ease-out both; }
|
|
63
|
+
|
|
64
|
+
@media (prefers-reduced-motion: reduce) {
|
|
65
|
+
.studio-sheet-content[data-state='open'],
|
|
66
|
+
.studio-sheet-content[data-state='closed'],
|
|
67
|
+
.studio-sheet-overlay[data-state='open'],
|
|
68
|
+
.studio-sheet-overlay[data-state='closed'],
|
|
69
|
+
.studio-bloom,
|
|
70
|
+
.studio-shimmer,
|
|
71
|
+
.shimmer,
|
|
72
|
+
.animate-row-in { animation: none; }
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent→app tool side channel, integration-hub client, per-workspace billing, and crypto — composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|
|
@@ -228,6 +228,17 @@
|
|
|
228
228
|
"import": "./dist/design-canvas-react/lazy.js",
|
|
229
229
|
"default": "./dist/design-canvas-react/lazy.js"
|
|
230
230
|
},
|
|
231
|
+
"./studio": {
|
|
232
|
+
"types": "./dist/studio/index.d.ts",
|
|
233
|
+
"import": "./dist/studio/index.js",
|
|
234
|
+
"default": "./dist/studio/index.js"
|
|
235
|
+
},
|
|
236
|
+
"./studio-react": {
|
|
237
|
+
"types": "./dist/studio-react/index.d.ts",
|
|
238
|
+
"import": "./dist/studio-react/index.js",
|
|
239
|
+
"default": "./dist/studio-react/index.js"
|
|
240
|
+
},
|
|
241
|
+
"./studio-react/styles": "./dist/studio-react/studio.css",
|
|
231
242
|
"./teams": {
|
|
232
243
|
"types": "./dist/teams/index.d.ts",
|
|
233
244
|
"import": "./dist/teams/index.js",
|
|
@@ -310,11 +321,14 @@
|
|
|
310
321
|
"knip": "knip"
|
|
311
322
|
},
|
|
312
323
|
"devDependencies": {
|
|
324
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
313
325
|
"@tangle-network/agent-eval": "^0.83.0",
|
|
314
326
|
"@tangle-network/agent-integrations": "^0.32.0",
|
|
315
|
-
"@tangle-network/agent-runtime": "^0.52.0",
|
|
316
327
|
"@tangle-network/agent-knowledge": "^1.5.2",
|
|
328
|
+
"@tangle-network/agent-runtime": "^0.52.0",
|
|
317
329
|
"@tangle-network/sandbox": "^0.4.4",
|
|
330
|
+
"@tangle-network/sandbox-ui": "^0.39.1",
|
|
331
|
+
"@tangle-network/ui": "^4.1.0",
|
|
318
332
|
"@testing-library/dom": "^10.4.1",
|
|
319
333
|
"@testing-library/react": "^16.3.2",
|
|
320
334
|
"@types/better-sqlite3": "^7.6.13",
|
|
@@ -327,24 +341,30 @@
|
|
|
327
341
|
"jsdom": "^29.1.1",
|
|
328
342
|
"knip": "^5.46.0",
|
|
329
343
|
"konva": "^10.3.0",
|
|
344
|
+
"lucide-react": "^1.16.0",
|
|
330
345
|
"react": "^19.0.0",
|
|
331
346
|
"react-dom": "^19.2.7",
|
|
332
347
|
"react-konva": "^19.2.5",
|
|
348
|
+
"react-router": "^7.15.1",
|
|
333
349
|
"tsup": "^8.0.0",
|
|
334
350
|
"typescript": "^5.7.0",
|
|
335
351
|
"vitest": "^3.0.0"
|
|
336
352
|
},
|
|
337
353
|
"peerDependencies": {
|
|
338
354
|
"@huggingface/transformers": ">=3",
|
|
355
|
+
"@radix-ui/react-dialog": ">=1.1",
|
|
339
356
|
"@tangle-network/agent-eval": ">=0.83.0",
|
|
340
357
|
"@tangle-network/agent-integrations": ">=0.32.0",
|
|
341
358
|
"@tangle-network/agent-knowledge": ">=1.5.0",
|
|
342
359
|
"@tangle-network/agent-runtime": ">=0.52.0",
|
|
343
360
|
"@tangle-network/sandbox": ">=0.4",
|
|
361
|
+
"@tangle-network/sandbox-ui": ">=0.32",
|
|
344
362
|
"drizzle-orm": ">=0.36",
|
|
345
|
-
"react": ">=18",
|
|
346
363
|
"konva": ">=9",
|
|
347
|
-
"react
|
|
364
|
+
"lucide-react": ">=1",
|
|
365
|
+
"react": ">=18",
|
|
366
|
+
"react-konva": ">=18",
|
|
367
|
+
"react-router": ">=7"
|
|
348
368
|
},
|
|
349
369
|
"peerDependenciesMeta": {
|
|
350
370
|
"@huggingface/transformers": {
|
|
@@ -370,6 +390,18 @@
|
|
|
370
390
|
},
|
|
371
391
|
"react-konva": {
|
|
372
392
|
"optional": true
|
|
393
|
+
},
|
|
394
|
+
"@tangle-network/sandbox-ui": {
|
|
395
|
+
"optional": true
|
|
396
|
+
},
|
|
397
|
+
"react-router": {
|
|
398
|
+
"optional": true
|
|
399
|
+
},
|
|
400
|
+
"lucide-react": {
|
|
401
|
+
"optional": true
|
|
402
|
+
},
|
|
403
|
+
"@radix-ui/react-dialog": {
|
|
404
|
+
"optional": true
|
|
373
405
|
}
|
|
374
406
|
},
|
|
375
407
|
"dependencies": {
|