@adminide-stack/yantra-mobile 12.0.121 → 12.0.123-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/lib/features/apps/appArt.js +1 -1
  2. package/lib/features/apps/appArt.js.map +1 -1
  3. package/lib/features/apps/mobileAppCatalog.js +15 -11
  4. package/lib/features/apps/mobileAppCatalog.js.map +1 -1
  5. package/lib/features/canvas/CanvasAgentChatPane.js +82 -20
  6. package/lib/features/canvas/CanvasAgentChatPane.js.map +1 -1
  7. package/lib/features/canvas/CanvasBoardsGrid.js +291 -100
  8. package/lib/features/canvas/CanvasBoardsGrid.js.map +1 -1
  9. package/lib/features/canvas/CanvasEditToolsPanel.js +105 -12
  10. package/lib/features/canvas/CanvasEditToolsPanel.js.map +1 -1
  11. package/lib/features/canvas/CanvasExperience.js +266 -68
  12. package/lib/features/canvas/CanvasExperience.js.map +1 -1
  13. package/lib/features/canvas/CanvasGeneratePanel.js +204 -66
  14. package/lib/features/canvas/CanvasGeneratePanel.js.map +1 -1
  15. package/lib/features/canvas/CanvasLibrarySheet.js +31 -13
  16. package/lib/features/canvas/CanvasLibrarySheet.js.map +1 -1
  17. package/lib/features/canvas/CanvasModelPicker.js +176 -0
  18. package/lib/features/canvas/CanvasModelPicker.js.map +1 -0
  19. package/lib/features/canvas/CanvasTasksPanel.js +325 -29
  20. package/lib/features/canvas/CanvasTasksPanel.js.map +1 -1
  21. package/lib/features/canvas/CanvasTemplatesPanel.js +5 -4
  22. package/lib/features/canvas/CanvasTemplatesPanel.js.map +1 -1
  23. package/lib/features/canvas/CanvasToolDock.js +137 -61
  24. package/lib/features/canvas/CanvasToolDock.js.map +1 -1
  25. package/lib/features/canvas/FrameExtractorExperience.js +33 -2
  26. package/lib/features/canvas/FrameExtractorExperience.js.map +1 -1
  27. package/lib/features/canvas/GeneratorReferenceSlots.js +197 -0
  28. package/lib/features/canvas/GeneratorReferenceSlots.js.map +1 -0
  29. package/lib/features/canvas/NativeCanvasViewer.js +89 -11
  30. package/lib/features/canvas/NativeCanvasViewer.js.map +1 -1
  31. package/lib/features/canvas/PromoContextFields.js +55 -2
  32. package/lib/features/canvas/PromoContextFields.js.map +1 -1
  33. package/lib/features/canvas/SetStudioExperience.js +323 -13
  34. package/lib/features/canvas/SetStudioExperience.js.map +1 -1
  35. package/lib/features/canvas/VideoEditExperience.js +1 -53
  36. package/lib/features/canvas/VideoEditExperience.js.map +1 -1
  37. package/lib/features/canvas/VideoEditorExperience.js +697 -506
  38. package/lib/features/canvas/VideoEditorExperience.js.map +1 -1
  39. package/lib/features/canvas/VideoGeneratorExperience.js +22 -5
  40. package/lib/features/canvas/VideoGeneratorExperience.js.map +1 -1
  41. package/lib/features/canvas/canvasAgentChat.js +125 -11
  42. package/lib/features/canvas/canvasAgentChat.js.map +1 -1
  43. package/lib/features/canvas/canvasCore.js +117 -12
  44. package/lib/features/canvas/canvasCore.js.map +1 -1
  45. package/lib/features/canvas/canvasEditOps.js +148 -111
  46. package/lib/features/canvas/canvasEditOps.js.map +1 -1
  47. package/lib/features/canvas/canvasTaskSync.js +235 -0
  48. package/lib/features/canvas/canvasTaskSync.js.map +1 -0
  49. package/lib/features/canvas/canvasTasks.js +98 -11
  50. package/lib/features/canvas/canvasTasks.js.map +1 -1
  51. package/lib/features/canvas/createTiles.js +247 -0
  52. package/lib/features/canvas/createTiles.js.map +1 -0
  53. package/lib/features/canvas/deepLinks.js +83 -0
  54. package/lib/features/canvas/deepLinks.js.map +1 -0
  55. package/lib/features/canvas/frameExtract.js +13 -1
  56. package/lib/features/canvas/frameExtract.js.map +1 -1
  57. package/lib/features/canvas/generationModels.js +36 -8
  58. package/lib/features/canvas/generationModels.js.map +1 -1
  59. package/lib/features/canvas/generatorCommands.js +106 -0
  60. package/lib/features/canvas/generatorCommands.js.map +1 -0
  61. package/lib/features/canvas/generatorReferences.js +82 -0
  62. package/lib/features/canvas/generatorReferences.js.map +1 -0
  63. package/lib/features/canvas/homeWork.js +74 -0
  64. package/lib/features/canvas/homeWork.js.map +1 -0
  65. package/lib/features/canvas/linksRpc.js +130 -0
  66. package/lib/features/canvas/linksRpc.js.map +1 -0
  67. package/lib/features/canvas/mediaRecheck.js +176 -0
  68. package/lib/features/canvas/mediaRecheck.js.map +1 -0
  69. package/lib/features/canvas/mediaUrls.js +258 -0
  70. package/lib/features/canvas/mediaUrls.js.map +1 -0
  71. package/lib/features/canvas/nativeViewerRegistry.js.map +1 -1
  72. package/lib/features/canvas/promoProjectImport.js +80 -13
  73. package/lib/features/canvas/promoProjectImport.js.map +1 -1
  74. package/lib/features/canvas/promoVideo.js +106 -15
  75. package/lib/features/canvas/promoVideo.js.map +1 -1
  76. package/lib/features/canvas/reframe.js +228 -0
  77. package/lib/features/canvas/reframe.js.map +1 -0
  78. package/lib/features/canvas/serverTasks.js +697 -0
  79. package/lib/features/canvas/serverTasks.js.map +1 -0
  80. package/lib/features/canvas/set/SetViewportWebView.js +207 -28
  81. package/lib/features/canvas/set/SetViewportWebView.js.map +1 -1
  82. package/lib/features/canvas/set/agent/prompt.js +66 -0
  83. package/lib/features/canvas/set/agent/prompt.js.map +1 -0
  84. package/lib/features/canvas/set/agent/setOps.js +203 -0
  85. package/lib/features/canvas/set/agent/setOps.js.map +1 -0
  86. package/lib/features/canvas/set/agent/setTurn.js +128 -0
  87. package/lib/features/canvas/set/agent/setTurn.js.map +1 -0
  88. package/lib/features/canvas/set/agent/snapshot.js +43 -0
  89. package/lib/features/canvas/set/agent/snapshot.js.map +1 -0
  90. package/lib/features/canvas/set/agent/tools.js +580 -0
  91. package/lib/features/canvas/set/agent/tools.js.map +1 -0
  92. package/lib/features/canvas/set/setProject.js +43 -4
  93. package/lib/features/canvas/set/setProject.js.map +1 -1
  94. package/lib/features/canvas/set/supplyLibrary.js +397 -0
  95. package/lib/features/canvas/set/supplyLibrary.js.map +1 -0
  96. package/lib/features/canvas/storageLibrary.js +113 -52
  97. package/lib/features/canvas/storageLibrary.js.map +1 -1
  98. package/lib/features/canvas/studioCatalog.js +15 -2
  99. package/lib/features/canvas/studioCatalog.js.map +1 -1
  100. package/lib/features/canvas/studioLooks.js +1 -8
  101. package/lib/features/canvas/studioLooks.js.map +1 -1
  102. package/lib/features/canvas/useBoardMediaRefresh.js +66 -0
  103. package/lib/features/canvas/useBoardMediaRefresh.js.map +1 -0
  104. package/lib/features/canvas/useMediaSource.js +84 -0
  105. package/lib/features/canvas/useMediaSource.js.map +1 -0
  106. package/lib/features/canvas/video3d.js +11 -10
  107. package/lib/features/canvas/video3d.js.map +1 -1
  108. package/lib/features/canvas/videoEditor/BlurBoxOverlay.js +46 -0
  109. package/lib/features/canvas/videoEditor/BlurBoxOverlay.js.map +1 -0
  110. package/lib/features/canvas/videoEditor/ExportTaskCard.js +134 -0
  111. package/lib/features/canvas/videoEditor/ExportTaskCard.js.map +1 -0
  112. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js +45 -7
  113. package/lib/features/canvas/videoEditor/agent/AgentCutPane.js.map +1 -1
  114. package/lib/features/canvas/videoEditor/agent/agentLoop.js +4 -2
  115. package/lib/features/canvas/videoEditor/agent/agentLoop.js.map +1 -1
  116. package/lib/features/canvas/videoEditor/agent/attachments.js +304 -0
  117. package/lib/features/canvas/videoEditor/agent/attachments.js.map +1 -0
  118. package/lib/features/canvas/videoEditor/agent/brainClient.js +3 -2
  119. package/lib/features/canvas/videoEditor/agent/brainClient.js.map +1 -1
  120. package/lib/features/canvas/videoEditor/agent/cutTools.js +207 -7
  121. package/lib/features/canvas/videoEditor/agent/cutTools.js.map +1 -1
  122. package/lib/features/canvas/videoEditor/blurBox.js +34 -0
  123. package/lib/features/canvas/videoEditor/blurBox.js.map +1 -0
  124. package/lib/features/canvas/videoEditor/compileTimeline.js +668 -0
  125. package/lib/features/canvas/videoEditor/compileTimeline.js.map +1 -0
  126. package/lib/features/canvas/videoEditor/editorModel.js +56 -22
  127. package/lib/features/canvas/videoEditor/editorModel.js.map +1 -1
  128. package/lib/features/canvas/videoEditor/exportPipeline.js +77 -0
  129. package/lib/features/canvas/videoEditor/exportPipeline.js.map +1 -0
  130. package/lib/features/canvas/videoEditor/exportRenderer.js +19 -12
  131. package/lib/features/canvas/videoEditor/exportRenderer.js.map +1 -1
  132. package/lib/features/canvas/videoEditor/exportTask.js +216 -0
  133. package/lib/features/canvas/videoEditor/exportTask.js.map +1 -0
  134. package/lib/features/canvas/videoEditor/formWidgets.js +142 -0
  135. package/lib/features/canvas/videoEditor/formWidgets.js.map +1 -0
  136. package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js +195 -0
  137. package/lib/features/canvas/videoEditor/produce/ProduceVideoSheet.js.map +1 -0
  138. package/lib/features/canvas/videoEditor/produce/produceScenes.js +158 -0
  139. package/lib/features/canvas/videoEditor/produce/produceScenes.js.map +1 -0
  140. package/lib/features/canvas/videoEditor/remoteMediaClient.js +17 -5
  141. package/lib/features/canvas/videoEditor/remoteMediaClient.js.map +1 -1
  142. package/lib/features/canvas/videoEditor/renderTimeline.js +207 -0
  143. package/lib/features/canvas/videoEditor/renderTimeline.js.map +1 -0
  144. package/lib/features/canvas/videoEditor/renewLinks.js +64 -0
  145. package/lib/features/canvas/videoEditor/renewLinks.js.map +1 -0
  146. package/lib/features/canvas/videoEditor/sceneLayers.js +101 -0
  147. package/lib/features/canvas/videoEditor/sceneLayers.js.map +1 -0
  148. package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js +283 -0
  149. package/lib/features/canvas/videoEditor/tools/ToolsDrawer.js.map +1 -0
  150. package/lib/features/canvas/videoEditor/tools/catalog.js +576 -0
  151. package/lib/features/canvas/videoEditor/tools/catalog.js.map +1 -0
  152. package/lib/features/canvas/videoEditor/videoProjectsStore.js +27 -3
  153. package/lib/features/canvas/videoEditor/videoProjectsStore.js.map +1 -1
  154. package/lib/features/webbuilder/WebBuilderExperience.js +29 -1
  155. package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
  156. package/lib/features/webbuilder/buildFragments.js +8 -4
  157. package/lib/features/webbuilder/buildFragments.js.map +1 -1
  158. package/lib/features/webbuilder/codezenHandoff.js +108 -0
  159. package/lib/features/webbuilder/codezenHandoff.js.map +1 -0
  160. package/lib/features/webbuilder/workflow.js.map +1 -1
  161. package/lib/hooks/useChatApi.js +1 -2
  162. package/lib/hooks/useChatApi.js.map +1 -1
  163. package/lib/screens/CanvasBoard/index.js +12 -1
  164. package/lib/screens/CanvasBoard/index.js.map +1 -1
  165. package/lib/screens/Home/HomeScreen.js.map +1 -1
  166. package/lib/screens/Home/components/HomeSuggestions.js +3 -3
  167. package/lib/screens/Home/components/HomeSuggestions.js.map +1 -1
  168. package/lib/screens/WebBuilder/index.js +4 -2
  169. package/lib/screens/WebBuilder/index.js.map +1 -1
  170. package/lib/screens/WebBuilderNative/index.js +29 -2
  171. package/lib/screens/WebBuilderNative/index.js.map +1 -1
  172. package/lib/screens/WebBuilderNative/useWebBuilderHost.js +30 -6
  173. package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
  174. package/package.json +4 -4
  175. /package/lib/assets/apps/{paper2poster.webp → poster.webp} +0 -0
@@ -0,0 +1,84 @@
1
+ import {useState,useRef,useEffect,useCallback}from'react';import {useMediaRecheck,markMediaFailed}from'./mediaRecheck.js';import {canonicalMediaUrl,isPresignedMediaUrl,signStoredMediaUrl}from'./mediaUrls.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ const initial = (stored) => ({
21
+ stored,
22
+ url: stored,
23
+ renewing: false
24
+ });
25
+ function renewMediaUrl(run) {
26
+ return async (url) => {
27
+ var _a;
28
+ const stored = canonicalMediaUrl(url);
29
+ if (!isPresignedMediaUrl(stored)) return url;
30
+ return (_a = await signStoredMediaUrl(run, stored)) != null ? _a : url;
31
+ };
32
+ }
33
+ function useMediaSource(stored, kind, renew) {
34
+ const [state, setState] = useState(() => initial(stored));
35
+ let current = state;
36
+ if (state.stored !== stored) {
37
+ current = initial(stored);
38
+ setState(current);
39
+ }
40
+ const recheck = useMediaRecheck(current.url || null);
41
+ const storedRef = useRef(stored);
42
+ useEffect(() => {
43
+ storedRef.current = stored;
44
+ }, [stored]);
45
+ const renewedFor = useRef(null);
46
+ const currentStored = current.stored;
47
+ const currentUrl = current.url;
48
+ const onError = useCallback(() => {
49
+ const failed = currentUrl;
50
+ if (!failed) return;
51
+ if (!renew || renewedFor.current === currentStored) {
52
+ markMediaFailed(failed, kind);
53
+ return;
54
+ }
55
+ renewedFor.current = currentStored;
56
+ setState((s) => s.stored === currentStored ? __spreadProps(__spreadValues({}, s), {
57
+ renewing: true
58
+ }) : s);
59
+ void renew(failed).catch(() => failed).then((fresh) => {
60
+ if (storedRef.current !== currentStored) return;
61
+ const next = fresh || failed;
62
+ if (next === failed) markMediaFailed(failed, kind);
63
+ setState((s) => s.stored === currentStored ? __spreadProps(__spreadValues({}, s), {
64
+ url: next,
65
+ renewing: false
66
+ }) : s);
67
+ });
68
+ }, [currentStored, currentUrl, kind, renew]);
69
+ const phase = current.renewing ? "renewing" : (recheck == null ? void 0 : recheck.status) === "pending" ? "waiting" : (recheck == null ? void 0 : recheck.status) === "gave_up" ? "broken" : "ok";
70
+ const ready = (recheck == null ? void 0 : recheck.status) === "ready" ? recheck : null;
71
+ return {
72
+ url: current.url,
73
+ src: ready ? ready.src : current.url,
74
+ key: ready ? `${current.url}#${ready.recoveredAt}` : current.url,
75
+ phase,
76
+ onError
77
+ };
78
+ }
79
+ function mediaPhaseLabel(phase) {
80
+ if (phase === "renewing") return "Renewing link\u2026";
81
+ if (phase === "waiting") return "Retrying\u2026";
82
+ if (phase === "broken") return "Preview unavailable";
83
+ return null;
84
+ }export{mediaPhaseLabel,renewMediaUrl,useMediaSource};//# sourceMappingURL=useMediaSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaSource.js","sources":["../../../src/features/canvas/useMediaSource.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `components/media/useMediaSource.ts` - what a\n * media tile should load, and what it does when that fails.\n *\n * The first failure trades the link for a fresh one through `renew` (a\n * presigned link re-signed, a raw object URL signed). When there is no lane,\n * the renewal hands back the same URL, or it fails, the URL goes to the shared\n * re-check (`mediaRecheck`) instead of being written off: the tile shows a\n * waiting state and swaps the media back in once it loads. Only a URL the\n * re-check gives up on is `broken`.\n *\n * Usage (expo-image or RN Image):\n * const media = useMediaSource(item.src, 'image', renewMediaUrl(run));\n * <Image key={media.key} source={{ uri: media.src }} onError={media.onError} />\n * {media.phase !== 'ok' ? <MediaStatusOverlay phase={media.phase} /> : null}\n */\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { type MediaKind, markMediaFailed, useMediaRecheck } from './mediaRecheck';\nimport { canonicalMediaUrl, isPresignedMediaUrl, signStoredMediaUrl } from './mediaUrls';\nimport type { RunMediaAction } from './videoEditor/mediaActions';\n\nexport type { MediaKind } from './mediaRecheck';\n\n/**\n * - `ok`: render the media from `src`.\n * - `renewing`: asking for a fresh link.\n * - `waiting`: failed, being re-checked in the background.\n * - `broken`: the re-check gave up; show the tile's unavailable state.\n */\nexport type MediaSourcePhase = 'ok' | 'renewing' | 'waiting' | 'broken';\n\nexport interface MediaSource {\n /** The link the asset is known by now: the stored one, or what a renewal traded it for. Hand THIS on. */\n url: string;\n /** What the element loads: `url`, or the re-check's copy of it that just loaded. */\n src: string;\n /** Changes whenever the element must be rebuilt to load again; use it as the element's `key`. */\n key: string;\n phase: MediaSourcePhase;\n /** Wire to the media element's `onError`. */\n onError: () => void;\n}\n\ninterface SourceState {\n stored: string;\n url: string;\n renewing: boolean;\n}\n\nconst initial = (stored: string): SourceState => ({ stored, url: stored, renewing: false });\n\n/**\n * The default renewal for a stored board/library link: re-sign a presigned\n * one (agent signer, then `yantra-storage`); anything else comes back as is.\n */\nexport function renewMediaUrl(run?: RunMediaAction): (url: string) => Promise<string> {\n return async (url) => {\n const stored = canonicalMediaUrl(url);\n if (!isPresignedMediaUrl(stored)) return url;\n return (await signStoredMediaUrl(run, stored)) ?? url;\n };\n}\n\n/**\n * @param stored The link as stored (a library row's URL, a board item's src).\n * @param kind How the re-check probes it.\n * @param renew Trades a link for a fresh one; resolves the same link when there is nothing to renew.\n */\nexport function useMediaSource(stored: string, kind: MediaKind, renew?: (url: string) => Promise<string>): MediaSource {\n const [state, setState] = useState(() => initial(stored));\n // A different stored link is a different asset: derive a fresh state during render.\n let current = state;\n if (state.stored !== stored) {\n current = initial(stored);\n setState(current);\n }\n const recheck = useMediaRecheck(current.url || null);\n\n const storedRef = useRef(stored);\n useEffect(() => {\n storedRef.current = stored;\n }, [stored]);\n // A ref, not state: two elements of one tile can fail in the same tick.\n const renewedFor = useRef<string | null>(null);\n\n const currentStored = current.stored;\n const currentUrl = current.url;\n const onError = useCallback(() => {\n const failed = currentUrl;\n if (!failed) return;\n if (!renew || renewedFor.current === currentStored) {\n markMediaFailed(failed, kind);\n return;\n }\n renewedFor.current = currentStored;\n setState((s) => (s.stored === currentStored ? { ...s, renewing: true } : s));\n void renew(failed)\n .catch(() => failed)\n .then((fresh) => {\n if (storedRef.current !== currentStored) return;\n const next = fresh || failed;\n // Same link back: nothing to swap in, so the re-check takes it from here.\n if (next === failed) markMediaFailed(failed, kind);\n setState((s) => (s.stored === currentStored ? { ...s, url: next, renewing: false } : s));\n });\n }, [currentStored, currentUrl, kind, renew]);\n\n const phase: MediaSourcePhase = current.renewing\n ? 'renewing'\n : recheck?.status === 'pending'\n ? 'waiting'\n : recheck?.status === 'gave_up'\n ? 'broken'\n : 'ok';\n const ready = recheck?.status === 'ready' ? recheck : null;\n return {\n url: current.url,\n src: ready ? ready.src : current.url,\n key: ready ? `${current.url}#${ready.recoveredAt}` : current.url,\n phase,\n onError,\n };\n}\n\n/** Short status line for a tile that is not showing its media. */\nexport function mediaPhaseLabel(phase: MediaSourcePhase): string | null {\n if (phase === 'renewing') return 'Renewing link…';\n if (phase === 'waiting') return 'Retrying…';\n if (phase === 'broken') return 'Preview unavailable';\n return null;\n}\n"],"names":[],"mappings":"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"}
@@ -91,19 +91,20 @@ async function generateObject3D(run, options) {
91
91
  }
92
92
  throw new Error("The 3D job is taking longer than expected. Try again in a minute.");
93
93
  }
94
- const SET_RENDER_INSTRUCTION = "Use the attached layout references as the exact composition: keep camera angle, position and scale of every subject, and the horizon. Replace untextured blocking with photographic detail. ";
94
+ const SET_RENDER_INSTRUCTION = "Use the attached 3D layout render as the exact composition reference: keep the camera angle, the position and scale of every object, and the horizon exactly as they are. Replace the untextured blocking geometry with photographic detail. ";
95
+ const MAX_SET_REFERENCES = 14;
95
96
  async function renderSetStill(run, options) {
96
- const prompt = `${SET_RENDER_INSTRUCTION}${options.look.trim() || "Photorealistic scene matching the layout."}`;
97
- const refs = options.referenceUrls.filter(Boolean).slice(0, 4);
98
- const result = await run("yantra-image-generation", "YANTRA_IMAGE_GENERATION_GENERATE", __spreadValues(__spreadValues({
97
+ const prompt = `${SET_RENDER_INSTRUCTION}${options.look.trim() || "Photographic, natural light, believable materials."}`;
98
+ const refs = options.referenceUrls.filter(Boolean).slice(0, MAX_SET_REFERENCES);
99
+ const result = await run("yantra-image-generation", "YANTRA_GEMINI_IMAGE_EDIT", __spreadValues({
99
100
  prompt,
100
- aspect_ratio: options.aspect || "16:9"
101
- }, refs[0] ? {
102
- referenceImageUrl: refs[0]
103
- } : {}), refs.length > 1 ? {
104
- referenceImageUrls: refs
101
+ referenceImages: refs.map((url2) => ({
102
+ url: url2
103
+ }))
104
+ }, options.aspect ? {
105
+ aspectRatio: options.aspect
105
106
  } : {}));
106
- const url = generationImageUrl(result) || resultUrl(result, "YANTRA_IMAGE_GENERATION_GENERATE") || "";
107
+ const url = generationImageUrl(result) || resultUrl(result, "YANTRA_GEMINI_IMAGE_EDIT") || "";
107
108
  if (!url) throw new Error("Set render returned no image");
108
109
  return url;
109
110
  }export{SET_RENDER_INSTRUCTION,VIDEO_3D_ACTIONS,VIDEO_3D_CONNECTOR,generateObject3D,generateWorld3D,renderSetStill};//# sourceMappingURL=video3d.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"video3d.js","sources":["../../../src/features/canvas/video3d.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/video3dRpc` — world + object mesh lanes\n * on `yantra-video-3d`. Phone has no Three.js set viewport; these RPCs power\n * the native Set studio (world / object / still render).\n */\nimport { resultUrl, generationImageUrl, type RunMediaAction } from './videoEditor/mediaActions';\n\nexport const VIDEO_3D_CONNECTOR = 'yantra-video-3d';\n\nexport const VIDEO_3D_ACTIONS = {\n objectGenerate: 'YANTRA_VIDEO_3D_OBJECT_GENERATE',\n objectStatus: 'YANTRA_VIDEO_3D_OBJECT_STATUS',\n worldGenerate: 'YANTRA_VIDEO_3D_WORLD_GENERATE',\n listModels: 'YANTRA_VIDEO_3D_LIST_MODELS',\n checkAvailability: 'YANTRA_VIDEO_3D_CHECK_AVAILABILITY',\n} as const;\n\nexport interface Object3DResult {\n modelUrl: string;\n previewUrl: string;\n model: string;\n requestId: string;\n stored: boolean;\n}\n\nexport interface World3DResult {\n imageUrl: string;\n model: string;\n provider: string;\n width: number;\n height: number;\n resolvedPrompt: string;\n stored: boolean;\n}\n\nfunction unwrap(result: Record<string, unknown>, what: string): Record<string, unknown> {\n if (result.successful === false) {\n throw new Error((result.error as string) || `${what} failed`);\n }\n const data = (result.data && typeof result.data === 'object' ? result.data : result) as Record<string, unknown>;\n if (data.successful === false) {\n throw new Error((data.error as string) || `${what} failed`);\n }\n return data;\n}\n\nconst asString = (value: unknown): string => (typeof value === 'string' ? value : '');\n\nconst toObjectResult = (data: Record<string, unknown>): Object3DResult => ({\n modelUrl: asString(data.modelUrl),\n previewUrl: asString(data.previewUrl) || asString(data.modelUrl),\n model: asString(data.model),\n requestId: asString(data.requestId),\n stored: data.stored !== false,\n});\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nconst POLL_INTERVAL_MS = 5_000;\nconst DEFAULT_TOTAL_TIMEOUT_MS = 360_000;\n\nexport async function generateWorld3D(\n run: RunMediaAction,\n options: { prompt: string; model?: string; width?: number },\n): Promise<World3DResult> {\n const data = unwrap(\n await run(VIDEO_3D_CONNECTOR, VIDEO_3D_ACTIONS.worldGenerate, {\n prompt: options.prompt,\n ...(options.model ? { model: options.model } : {}),\n ...(options.width ? { width: options.width } : {}),\n }),\n '3D world generation',\n );\n const imageUrl = asString(data.imageUrl) || resultUrl(data, VIDEO_3D_ACTIONS.worldGenerate);\n if (!imageUrl) throw new Error('World generation returned no image');\n return {\n imageUrl,\n model: asString(data.model),\n provider: asString(data.provider),\n width: typeof data.width === 'number' ? data.width : 0,\n height: typeof data.height === 'number' ? data.height : 0,\n resolvedPrompt: asString(data.resolvedPrompt) || options.prompt,\n stored: data.stored !== false,\n };\n}\n\nexport async function generateObject3D(\n run: RunMediaAction,\n options: {\n imageUrl?: string;\n prompt?: string;\n model?: string;\n texture?: boolean;\n totalTimeoutMs?: number;\n onProgress?: (message: string) => void;\n },\n): Promise<Object3DResult> {\n const params: Record<string, unknown> = {};\n if (options.imageUrl) params.imageUrl = options.imageUrl;\n if (options.prompt?.trim()) params.prompt = options.prompt.trim();\n if (options.model) params.model = options.model;\n if (options.texture !== undefined) params.texture = options.texture;\n if (!params.imageUrl && !params.prompt) {\n throw new Error('Give the object a source image or a prompt.');\n }\n\n options.onProgress?.('Submitting to the mesh model…');\n const first = unwrap(\n await run(VIDEO_3D_CONNECTOR, VIDEO_3D_ACTIONS.objectGenerate, params),\n '3D object generation',\n );\n if (first.status !== 'pending') return toObjectResult(first);\n\n const requestId = asString(first.requestId);\n const model = asString(first.model);\n if (!requestId || !model) throw new Error('The 3D job did not come back with anything to poll.');\n\n const deadline = Date.now() + (options.totalTimeoutMs ?? DEFAULT_TOTAL_TIMEOUT_MS);\n const typical = typeof first.typicalSeconds === 'number' ? first.typicalSeconds : 90;\n const startedAt = Date.now();\n\n while (Date.now() < deadline) {\n const waited = Math.round((Date.now() - startedAt) / 1000);\n options.onProgress?.(`Building the mesh — ${waited}s of about ${typical}s`);\n await sleep(POLL_INTERVAL_MS);\n const next = unwrap(\n await run(VIDEO_3D_CONNECTOR, VIDEO_3D_ACTIONS.objectStatus, { requestId, model }),\n '3D object status',\n );\n if (next.status !== 'pending') return toObjectResult(next);\n }\n throw new Error('The 3D job is taking longer than expected. Try again in a minute.');\n}\n\n/** Layout still from set props — image lane with a blocking instruction (web RenderPanel). */\nexport const SET_RENDER_INSTRUCTION =\n 'Use the attached layout references as the exact composition: keep camera angle, ' +\n 'position and scale of every subject, and the horizon. Replace untextured blocking ' +\n 'with photographic detail. ';\n\nexport async function renderSetStill(\n run: RunMediaAction,\n options: { look: string; referenceUrls: string[]; aspect?: string },\n): Promise<string> {\n const prompt = `${SET_RENDER_INSTRUCTION}${options.look.trim() || 'Photorealistic scene matching the layout.'}`;\n const refs = options.referenceUrls.filter(Boolean).slice(0, 4);\n const result = await run('yantra-image-generation', 'YANTRA_IMAGE_GENERATION_GENERATE', {\n prompt,\n aspect_ratio: options.aspect || '16:9',\n ...(refs[0] ? { referenceImageUrl: refs[0] } : {}),\n ...(refs.length > 1 ? { referenceImageUrls: refs } : {}),\n });\n const url = generationImageUrl(result) || resultUrl(result, 'YANTRA_IMAGE_GENERATION_GENERATE') || '';\n if (!url) throw new Error('Set render returned no image');\n return url;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"video3d.js","sources":["../../../src/features/canvas/video3d.ts"],"sourcesContent":["/**\n * Native twin of canvas-surface `rpc/video3dRpc` — world + object mesh lanes\n * on `yantra-video-3d`. Phone has no Three.js set viewport; these RPCs power\n * the native Set studio (world / object / still render).\n */\nimport { resultUrl, generationImageUrl, type RunMediaAction } from './videoEditor/mediaActions';\n\nexport const VIDEO_3D_CONNECTOR = 'yantra-video-3d';\n\nexport const VIDEO_3D_ACTIONS = {\n objectGenerate: 'YANTRA_VIDEO_3D_OBJECT_GENERATE',\n objectStatus: 'YANTRA_VIDEO_3D_OBJECT_STATUS',\n worldGenerate: 'YANTRA_VIDEO_3D_WORLD_GENERATE',\n listModels: 'YANTRA_VIDEO_3D_LIST_MODELS',\n checkAvailability: 'YANTRA_VIDEO_3D_CHECK_AVAILABILITY',\n} as const;\n\nexport interface Object3DResult {\n modelUrl: string;\n previewUrl: string;\n model: string;\n requestId: string;\n stored: boolean;\n}\n\nexport interface World3DResult {\n imageUrl: string;\n model: string;\n provider: string;\n width: number;\n height: number;\n resolvedPrompt: string;\n stored: boolean;\n}\n\nfunction unwrap(result: Record<string, unknown>, what: string): Record<string, unknown> {\n if (result.successful === false) {\n throw new Error((result.error as string) || `${what} failed`);\n }\n const data = (result.data && typeof result.data === 'object' ? result.data : result) as Record<string, unknown>;\n if (data.successful === false) {\n throw new Error((data.error as string) || `${what} failed`);\n }\n return data;\n}\n\nconst asString = (value: unknown): string => (typeof value === 'string' ? value : '');\n\nconst toObjectResult = (data: Record<string, unknown>): Object3DResult => ({\n modelUrl: asString(data.modelUrl),\n previewUrl: asString(data.previewUrl) || asString(data.modelUrl),\n model: asString(data.model),\n requestId: asString(data.requestId),\n stored: data.stored !== false,\n});\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nconst POLL_INTERVAL_MS = 5_000;\nconst DEFAULT_TOTAL_TIMEOUT_MS = 360_000;\n\nexport async function generateWorld3D(\n run: RunMediaAction,\n options: { prompt: string; model?: string; width?: number },\n): Promise<World3DResult> {\n const data = unwrap(\n await run(VIDEO_3D_CONNECTOR, VIDEO_3D_ACTIONS.worldGenerate, {\n prompt: options.prompt,\n ...(options.model ? { model: options.model } : {}),\n ...(options.width ? { width: options.width } : {}),\n }),\n '3D world generation',\n );\n const imageUrl = asString(data.imageUrl) || resultUrl(data, VIDEO_3D_ACTIONS.worldGenerate);\n if (!imageUrl) throw new Error('World generation returned no image');\n return {\n imageUrl,\n model: asString(data.model),\n provider: asString(data.provider),\n width: typeof data.width === 'number' ? data.width : 0,\n height: typeof data.height === 'number' ? data.height : 0,\n resolvedPrompt: asString(data.resolvedPrompt) || options.prompt,\n stored: data.stored !== false,\n };\n}\n\nexport async function generateObject3D(\n run: RunMediaAction,\n options: {\n imageUrl?: string;\n prompt?: string;\n model?: string;\n texture?: boolean;\n totalTimeoutMs?: number;\n onProgress?: (message: string) => void;\n },\n): Promise<Object3DResult> {\n const params: Record<string, unknown> = {};\n if (options.imageUrl) params.imageUrl = options.imageUrl;\n if (options.prompt?.trim()) params.prompt = options.prompt.trim();\n if (options.model) params.model = options.model;\n if (options.texture !== undefined) params.texture = options.texture;\n if (!params.imageUrl && !params.prompt) {\n throw new Error('Give the object a source image or a prompt.');\n }\n\n options.onProgress?.('Submitting to the mesh model…');\n const first = unwrap(\n await run(VIDEO_3D_CONNECTOR, VIDEO_3D_ACTIONS.objectGenerate, params),\n '3D object generation',\n );\n if (first.status !== 'pending') return toObjectResult(first);\n\n const requestId = asString(first.requestId);\n const model = asString(first.model);\n if (!requestId || !model) throw new Error('The 3D job did not come back with anything to poll.');\n\n const deadline = Date.now() + (options.totalTimeoutMs ?? DEFAULT_TOTAL_TIMEOUT_MS);\n const typical = typeof first.typicalSeconds === 'number' ? first.typicalSeconds : 90;\n const startedAt = Date.now();\n\n while (Date.now() < deadline) {\n const waited = Math.round((Date.now() - startedAt) / 1000);\n options.onProgress?.(`Building the mesh — ${waited}s of about ${typical}s`);\n await sleep(POLL_INTERVAL_MS);\n const next = unwrap(\n await run(VIDEO_3D_CONNECTOR, VIDEO_3D_ACTIONS.objectStatus, { requestId, model }),\n '3D object status',\n );\n if (next.status !== 'pending') return toObjectResult(next);\n }\n throw new Error('The 3D job is taking longer than expected. Try again in a minute.');\n}\n\n/** Layout still from set props — image EDIT over the layout capture (web RenderPanel). */\nexport const SET_RENDER_INSTRUCTION =\n 'Use the attached 3D layout render as the exact composition reference: keep the camera angle, ' +\n 'the position and scale of every object, and the horizon exactly as they are. ' +\n 'Replace the untextured blocking geometry with photographic detail. ';\n\n/** The edit action's schema rejects more references than this (web MAX_REFERENCE_IMAGES). */\nconst MAX_SET_REFERENCES = 14;\n\nexport async function renderSetStill(\n run: RunMediaAction,\n options: { look: string; referenceUrls: string[]; aspect?: string },\n): Promise<string> {\n const prompt = `${SET_RENDER_INSTRUCTION}${options.look.trim() || 'Photographic, natural light, believable materials.'}`;\n const refs = options.referenceUrls.filter(Boolean).slice(0, MAX_SET_REFERENCES);\n // YANTRA_GEMINI_IMAGE_EDIT is the action web renders sets with; the\n // GENERATE action this used to call exists on no connector.\n const result = await run('yantra-image-generation', 'YANTRA_GEMINI_IMAGE_EDIT', {\n prompt,\n referenceImages: refs.map((url) => ({ url })),\n ...(options.aspect ? { aspectRatio: options.aspect } : {}),\n });\n const url = generationImageUrl(result) || resultUrl(result, 'YANTRA_GEMINI_IMAGE_EDIT') || '';\n if (!url) throw new Error('Set render returned no image');\n return url;\n}\n"],"names":["url"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import {jsx}from'react/jsx-runtime';import {useRef}from'react';import {StyleSheet,View}from'react-native';import {GestureDetector,Gesture}from'react-native-gesture-handler';import {dragBlurBox}from'./blurBox.js';function BlurBoxOverlay({
2
+ box,
3
+ onChange
4
+ }) {
5
+ const stage = useRef({
6
+ w: 1,
7
+ h: 1
8
+ });
9
+ const start = useRef(box);
10
+ const gesture = (resize) => Gesture.Pan().runOnJS(true).onStart(() => {
11
+ start.current = box;
12
+ }).onUpdate((e) => {
13
+ onChange(dragBlurBox(start.current, resize, e.translationX / stage.current.w * 100, e.translationY / stage.current.h * 100));
14
+ });
15
+ return /* @__PURE__ */ jsx(View, { style: StyleSheet.absoluteFill, pointerEvents: "box-none", onLayout: (e) => {
16
+ stage.current = {
17
+ w: Math.max(1, e.nativeEvent.layout.width),
18
+ h: Math.max(1, e.nativeEvent.layout.height)
19
+ };
20
+ }, testID: "blur-box-overlay", children: /* @__PURE__ */ jsx(GestureDetector, { gesture: gesture(false), children: /* @__PURE__ */ jsx(View, { style: [styles.box, {
21
+ left: `${box.x}%`,
22
+ top: `${box.y}%`,
23
+ width: `${box.width}%`,
24
+ height: `${box.height}%`
25
+ }], accessibilityLabel: "Blur box - drag to move", children: /* @__PURE__ */ jsx(GestureDetector, { gesture: gesture(true), children: /* @__PURE__ */ jsx(View, { style: styles.handle, accessibilityLabel: "Resize blur box" }) }) }) }) });
26
+ }
27
+ const styles = StyleSheet.create({
28
+ box: {
29
+ position: "absolute",
30
+ borderWidth: 1.5,
31
+ borderColor: "#A78BFA",
32
+ borderStyle: "dashed",
33
+ backgroundColor: "rgba(200, 200, 215, 0.35)"
34
+ },
35
+ handle: {
36
+ position: "absolute",
37
+ right: -9,
38
+ bottom: -9,
39
+ width: 18,
40
+ height: 18,
41
+ borderRadius: 9,
42
+ backgroundColor: "#A78BFA",
43
+ borderWidth: 2,
44
+ borderColor: "#101013"
45
+ }
46
+ });export{BlurBoxOverlay,dragBlurBox};//# sourceMappingURL=BlurBoxOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlurBoxOverlay.js","sources":["../../../../src/features/canvas/videoEditor/BlurBoxOverlay.tsx"],"sourcesContent":["/**\n * The blur segment's box on the stage (web PreviewStage blur box): a frosted\n * rectangle that moves with one finger and resizes from its bottom-right\n * handle. Coordinates are frame % (0..100), as the compiler reads them.\n */\nimport React, { useRef } from 'react';\nimport { StyleSheet, View } from 'react-native';\nimport { Gesture, GestureDetector } from 'react-native-gesture-handler';\nimport type { BlurBox } from './editorModel';\nimport { dragBlurBox } from './blurBox';\n\nexport { dragBlurBox };\n\nexport function BlurBoxOverlay({ box, onChange }: { box: BlurBox; onChange: (next: BlurBox) => void }) {\n const stage = useRef({ w: 1, h: 1 });\n const start = useRef(box);\n const gesture = (resize: boolean) =>\n Gesture.Pan()\n .runOnJS(true)\n .onStart(() => {\n start.current = box;\n })\n .onUpdate((e) => {\n onChange(\n dragBlurBox(\n start.current,\n resize,\n (e.translationX / stage.current.w) * 100,\n (e.translationY / stage.current.h) * 100,\n ),\n );\n });\n return (\n <View\n style={StyleSheet.absoluteFill}\n pointerEvents=\"box-none\"\n onLayout={(e) => {\n stage.current = {\n w: Math.max(1, e.nativeEvent.layout.width),\n h: Math.max(1, e.nativeEvent.layout.height),\n };\n }}\n testID=\"blur-box-overlay\"\n >\n <GestureDetector gesture={gesture(false)}>\n <View\n style={[\n styles.box,\n { left: `${box.x}%`, top: `${box.y}%`, width: `${box.width}%`, height: `${box.height}%` },\n ]}\n accessibilityLabel=\"Blur box - drag to move\"\n >\n <GestureDetector gesture={gesture(true)}>\n <View style={styles.handle} accessibilityLabel=\"Resize blur box\" />\n </GestureDetector>\n </View>\n </GestureDetector>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n box: {\n position: 'absolute',\n borderWidth: 1.5,\n borderColor: '#A78BFA',\n borderStyle: 'dashed',\n backgroundColor: 'rgba(200, 200, 215, 0.35)',\n },\n handle: {\n position: 'absolute',\n right: -9,\n bottom: -9,\n width: 18,\n height: 18,\n borderRadius: 9,\n backgroundColor: '#A78BFA',\n borderWidth: 2,\n borderColor: '#101013',\n },\n});\n"],"names":[],"mappings":"oNAWO,SAAS,cAAe,CAAA;AAAA,EAC7B,GAAA;AAAA,EACA;AACF,CAGG,EAAA;AACD,EAAA,MAAM,QAAQ,MAAO,CAAA;AAAA,IACnB,CAAG,EAAA,CAAA;AAAA,IACH,CAAG,EAAA;AAAA,GACJ,CAAA;AACD,EAAM,MAAA,KAAA,GAAQ,OAAO,GAAG,CAAA;AACxB,EAAM,MAAA,OAAA,GAAU,CAAC,MAAA,KAAoB,OAAQ,CAAA,GAAA,GAAM,OAAQ,CAAA,IAAI,CAAE,CAAA,OAAA,CAAQ,MAAM;AAC7E,IAAA,KAAA,CAAM,OAAU,GAAA,GAAA;AAAA,GACjB,CAAE,CAAA,QAAA,CAAS,CAAK,CAAA,KAAA;AACf,IAAA,QAAA,CAAS,YAAY,KAAM,CAAA,OAAA,EAAS,MAAQ,EAAA,CAAA,CAAE,eAAe,KAAM,CAAA,OAAA,CAAQ,CAAI,GAAA,GAAA,EAAK,EAAE,YAAe,GAAA,KAAA,CAAM,OAAQ,CAAA,CAAA,GAAI,GAAG,CAAC,CAAA;AAAA,GAC5H,CAAA;AACD,EAAO,uBAAA,GAAA,CAAC,QAAK,KAAO,EAAA,UAAA,CAAW,cAAc,aAAc,EAAA,UAAA,EAAW,UAAU,CAAK,CAAA,KAAA;AACnF,IAAA,KAAA,CAAM,OAAU,GAAA;AAAA,MACd,GAAG,IAAK,CAAA,GAAA,CAAI,GAAG,CAAE,CAAA,WAAA,CAAY,OAAO,KAAK,CAAA;AAAA,MACzC,GAAG,IAAK,CAAA,GAAA,CAAI,GAAG,CAAE,CAAA,WAAA,CAAY,OAAO,MAAM;AAAA,KAC5C;AAAA,GACC,EAAA,MAAA,EAAO,kBACA,EAAA,QAAA,kBAAA,GAAA,CAAC,mBAAgB,OAAS,EAAA,OAAA,CAAQ,KAAK,CAAA,EACnC,QAAC,kBAAA,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,CAAC,OAAO,GAAK,EAAA;AAAA,IAClC,IAAA,EAAM,CAAG,EAAA,GAAA,CAAI,CAAC,CAAA,CAAA,CAAA;AAAA,IACd,GAAA,EAAK,CAAG,EAAA,GAAA,CAAI,CAAC,CAAA,CAAA,CAAA;AAAA,IACb,KAAA,EAAO,CAAG,EAAA,GAAA,CAAI,KAAK,CAAA,CAAA,CAAA;AAAA,IACnB,MAAA,EAAQ,CAAG,EAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAAA,GACtB,GAAG,kBAAmB,EAAA,yBAAA,EACT,8BAAC,eAAgB,EAAA,EAAA,OAAA,EAAS,QAAQ,IAAI,CAAA,EAClC,8BAAC,IAAK,EAAA,EAAA,KAAA,EAAO,OAAO,MAAQ,EAAA,kBAAA,EAAmB,mBAAkB,CACrE,EAAA,CAAA,EACJ,GACJ,CACJ,EAAA,CAAA;AACR;AACA,MAAM,MAAA,GAAS,WAAW,MAAO,CAAA;AAAA,EAC/B,GAAK,EAAA;AAAA,IACH,QAAU,EAAA,UAAA;AAAA,IACV,WAAa,EAAA,GAAA;AAAA,IACb,WAAa,EAAA,SAAA;AAAA,IACb,WAAa,EAAA,QAAA;AAAA,IACb,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA,UAAA;AAAA,IACV,KAAO,EAAA,EAAA;AAAA,IACP,MAAQ,EAAA,EAAA;AAAA,IACR,KAAO,EAAA,EAAA;AAAA,IACP,MAAQ,EAAA,EAAA;AAAA,IACR,YAAc,EAAA,CAAA;AAAA,IACd,eAAiB,EAAA,SAAA;AAAA,IACjB,WAAa,EAAA,CAAA;AAAA,IACb,WAAa,EAAA;AAAA;AAEjB,CAAC,CAAA"}
@@ -0,0 +1,134 @@
1
+ import {jsxs,jsx}from'react/jsx-runtime';import {useState,useEffect}from'react';import {StyleSheet,View,Text,Pressable,ActivityIndicator}from'react-native';import {getCanvasTask,subscribeCanvasTasks}from'../canvasTasks.js';import {friendlyMediaError}from'./mediaActions.js';import {renderProgressPct,renderTimeLeft}from'./renderTimeline.js';var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ function useCanvasTask(id) {
21
+ const [task, setTask] = useState(() => id ? getCanvasTask(id) : void 0);
22
+ const [, setTick] = useState(0);
23
+ useEffect(() => {
24
+ if (!id) {
25
+ setTask(void 0);
26
+ return void 0;
27
+ }
28
+ setTask(getCanvasTask(id));
29
+ const unsub = subscribeCanvasTasks(() => setTask(getCanvasTask(id)));
30
+ const clock = setInterval(() => setTick((n) => n + 1), 15e3);
31
+ return () => {
32
+ unsub();
33
+ clearInterval(clock);
34
+ };
35
+ }, [id]);
36
+ return task;
37
+ }
38
+ function exportCardLines(task, now = Date.now()) {
39
+ var _a;
40
+ const stage = task.lastLine || "Rendering\u2026";
41
+ const projected = (_a = task.render) == null ? void 0 : _a.projectedMs;
42
+ if (task.state !== "running" || !task.startedAt || task.local) return {
43
+ stage
44
+ };
45
+ const elapsed = Math.max(0, now - task.startedAt);
46
+ return __spreadProps(__spreadValues({
47
+ stage
48
+ }, projected ? {
49
+ timeLeft: renderTimeLeft(projected, elapsed)
50
+ } : {}), {
51
+ pct: Math.round(renderProgressPct(task.step, projected, elapsed))
52
+ });
53
+ }
54
+ function ExportTaskCard({
55
+ task,
56
+ onDismiss,
57
+ onBackground
58
+ }) {
59
+ var _a;
60
+ if (!task) return null;
61
+ if (task.state === "failed") {
62
+ return /* @__PURE__ */ jsxs(View, { style: styles.card, testID: "export-task-card", children: [
63
+ /* @__PURE__ */ jsx(Text, { style: styles.error, children: "Export failed" }),
64
+ /* @__PURE__ */ jsx(Text, { style: styles.stage, numberOfLines: 5, children: friendlyMediaError(new Error(task.error || "The render failed"), "video export") }),
65
+ /* @__PURE__ */ jsx(Pressable, { onPress: onDismiss, style: styles.button, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles.buttonLabel, children: "Dismiss" }) })
66
+ ] });
67
+ }
68
+ const lines = exportCardLines(task);
69
+ return /* @__PURE__ */ jsxs(View, { style: styles.card, testID: "export-task-card", children: [
70
+ /* @__PURE__ */ jsx(ActivityIndicator, { color: "#F7F7FA" }),
71
+ /* @__PURE__ */ jsx(Text, { style: styles.stage, numberOfLines: 2, children: lines.stage }),
72
+ lines.pct !== void 0 ? /* @__PURE__ */ jsx(View, { style: styles.bar, children: /* @__PURE__ */ jsx(View, { style: [styles.barFill, {
73
+ width: `${lines.pct}%`
74
+ }] }) }) : null,
75
+ lines.timeLeft ? /* @__PURE__ */ jsx(Text, { style: styles.meta, children: lines.timeLeft }) : null,
76
+ task.notice ? /* @__PURE__ */ jsx(Text, { style: styles.notice, children: task.notice }) : null,
77
+ ((_a = task.warnings) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsx(Text, { style: styles.meta, numberOfLines: 3, children: task.warnings[0] }) : null,
78
+ task.state === "running" && !task.local ? /* @__PURE__ */ jsx(Pressable, { onPress: onBackground, style: styles.button, accessibilityRole: "button", children: /* @__PURE__ */ jsx(Text, { style: styles.buttonLabel, children: "Keep rendering in background" }) }) : null
79
+ ] });
80
+ }
81
+ const styles = StyleSheet.create({
82
+ card: {
83
+ minWidth: 240,
84
+ maxWidth: 320,
85
+ padding: 20,
86
+ borderRadius: 16,
87
+ backgroundColor: "#1B1B21",
88
+ alignItems: "center",
89
+ gap: 10
90
+ },
91
+ stage: {
92
+ color: "#F7F7FA",
93
+ fontSize: 14,
94
+ textAlign: "center"
95
+ },
96
+ meta: {
97
+ color: "#A1A1AA",
98
+ fontSize: 12,
99
+ textAlign: "center"
100
+ },
101
+ notice: {
102
+ color: "#FBBF24",
103
+ fontSize: 12,
104
+ textAlign: "center"
105
+ },
106
+ error: {
107
+ color: "#F87171",
108
+ fontSize: 15,
109
+ fontWeight: "700"
110
+ },
111
+ bar: {
112
+ alignSelf: "stretch",
113
+ height: 4,
114
+ borderRadius: 2,
115
+ backgroundColor: "#2A2A33",
116
+ overflow: "hidden"
117
+ },
118
+ barFill: {
119
+ height: 4,
120
+ backgroundColor: "#8B5CF6"
121
+ },
122
+ button: {
123
+ marginTop: 4,
124
+ paddingHorizontal: 14,
125
+ paddingVertical: 8,
126
+ borderRadius: 10,
127
+ backgroundColor: "#2A2A33"
128
+ },
129
+ buttonLabel: {
130
+ color: "#F7F7FA",
131
+ fontSize: 13,
132
+ fontWeight: "600"
133
+ }
134
+ });export{ExportTaskCard,exportCardLines,useCanvasTask};//# sourceMappingURL=ExportTaskCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportTaskCard.js","sources":["../../../../src/features/canvas/videoEditor/ExportTaskCard.tsx"],"sourcesContent":["/**\n * The editor's export progress card for a durable export task: step, the\n * connector's projected time left, its time-limit notice, compile warnings,\n * and a \"keep in background\" exit (the render carries on in More → Tasks).\n */\nimport React, { useEffect, useState } from 'react';\nimport { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native';\nimport { getCanvasTask, subscribeCanvasTasks, type CanvasTask } from '../canvasTasks';\nimport { friendlyMediaError } from './mediaActions';\nimport { renderProgressPct, renderTimeLeft } from './renderTimeline';\n\n/** Live view of one canvas task (re-renders on every store change + a 15s clock for the time left). */\nexport function useCanvasTask(id: string | null): CanvasTask | undefined {\n const [task, setTask] = useState<CanvasTask | undefined>(() => (id ? getCanvasTask(id) : undefined));\n const [, setTick] = useState(0);\n useEffect(() => {\n if (!id) {\n setTask(undefined);\n return undefined;\n }\n setTask(getCanvasTask(id));\n const unsub = subscribeCanvasTasks(() => setTask(getCanvasTask(id)));\n const clock = setInterval(() => setTick((n) => n + 1), 15_000);\n return () => {\n unsub();\n clearInterval(clock);\n };\n }, [id]);\n return task;\n}\n\n/** Card copy for a task, pure (tested). */\nexport function exportCardLines(\n task: CanvasTask,\n now = Date.now(),\n): { stage: string; timeLeft?: string; pct?: number } {\n const stage = task.lastLine || 'Rendering…';\n const projected = task.render?.projectedMs;\n if (task.state !== 'running' || !task.startedAt || task.local) return { stage };\n const elapsed = Math.max(0, now - task.startedAt);\n return {\n stage,\n ...(projected ? { timeLeft: renderTimeLeft(projected, elapsed) } : {}),\n pct: Math.round(renderProgressPct(task.step, projected, elapsed)),\n };\n}\n\nexport function ExportTaskCard({\n task,\n onDismiss,\n onBackground,\n}: {\n task: CanvasTask | undefined;\n onDismiss: () => void;\n /** Leave the render running and get back to the canvas. */\n onBackground: () => void;\n}) {\n if (!task) return null;\n if (task.state === 'failed') {\n return (\n <View style={styles.card} testID=\"export-task-card\">\n <Text style={styles.error}>Export failed</Text>\n <Text style={styles.stage} numberOfLines={5}>\n {friendlyMediaError(new Error(task.error || 'The render failed'), 'video export')}\n </Text>\n <Pressable onPress={onDismiss} style={styles.button} accessibilityRole=\"button\">\n <Text style={styles.buttonLabel}>Dismiss</Text>\n </Pressable>\n </View>\n );\n }\n const lines = exportCardLines(task);\n return (\n <View style={styles.card} testID=\"export-task-card\">\n <ActivityIndicator color=\"#F7F7FA\" />\n <Text style={styles.stage} numberOfLines={2}>\n {lines.stage}\n </Text>\n {lines.pct !== undefined ? (\n <View style={styles.bar}>\n <View style={[styles.barFill, { width: `${lines.pct}%` }]} />\n </View>\n ) : null}\n {lines.timeLeft ? <Text style={styles.meta}>{lines.timeLeft}</Text> : null}\n {task.notice ? <Text style={styles.notice}>{task.notice}</Text> : null}\n {task.warnings?.length ? (\n <Text style={styles.meta} numberOfLines={3}>\n {task.warnings[0]}\n </Text>\n ) : null}\n {task.state === 'running' && !task.local ? (\n <Pressable onPress={onBackground} style={styles.button} accessibilityRole=\"button\">\n <Text style={styles.buttonLabel}>Keep rendering in background</Text>\n </Pressable>\n ) : null}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n card: {\n minWidth: 240,\n maxWidth: 320,\n padding: 20,\n borderRadius: 16,\n backgroundColor: '#1B1B21',\n alignItems: 'center',\n gap: 10,\n },\n stage: { color: '#F7F7FA', fontSize: 14, textAlign: 'center' },\n meta: { color: '#A1A1AA', fontSize: 12, textAlign: 'center' },\n notice: { color: '#FBBF24', fontSize: 12, textAlign: 'center' },\n error: { color: '#F87171', fontSize: 15, fontWeight: '700' },\n bar: { alignSelf: 'stretch', height: 4, borderRadius: 2, backgroundColor: '#2A2A33', overflow: 'hidden' },\n barFill: { height: 4, backgroundColor: '#8B5CF6' },\n button: { marginTop: 4, paddingHorizontal: 14, paddingVertical: 8, borderRadius: 10, backgroundColor: '#2A2A33' },\n buttonLabel: { color: '#F7F7FA', fontSize: 13, fontWeight: '600' },\n});\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,28 @@
1
- import {jsxs,jsx}from'react/jsx-runtime';import {useRef,useState}from'react';import {StyleSheet,View,Text,ScrollView,TextInput,Pressable,ActivityIndicator}from'react-native';import {deriveAgentEndpoint}from'../remoteMediaClient.js';import {runCutAgentTurn}from'./agentLoop.js';function AgentCutPane({
1
+ import {jsxs,jsx}from'react/jsx-runtime';import {useRef,useState}from'react';import {StyleSheet,View,Text,ScrollView,TextInput,Pressable,ActivityIndicator}from'react-native';import {deriveAgentEndpoint}from'../remoteMediaClient.js';import {reflowSceneChildren}from'../sceneLayers.js';import {runCutAgentTurn}from'./agentLoop.js';import {linksIn,intakeLinks,fetchLinkViaAgent}from'./attachments.js';var __defProp = Object.defineProperty;
2
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __spreadValues = (a, b) => {
7
+ for (var prop in b || (b = {}))
8
+ if (__hasOwnProp.call(b, prop))
9
+ __defNormalProp(a, prop, b[prop]);
10
+ if (__getOwnPropSymbols)
11
+ for (var prop of __getOwnPropSymbols(b)) {
12
+ if (__propIsEnum.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ }
15
+ return a;
16
+ };
17
+ function AgentCutPane({
2
18
  timeline,
3
19
  setTimeline,
4
20
  token,
5
- indexUrl
21
+ indexUrl,
22
+ runAction,
23
+ uploadMedia,
24
+ onAddMedia,
25
+ onFilm
6
26
  }) {
7
27
  const timelineRef = useRef(timeline);
8
28
  timelineRef.current = timeline;
@@ -25,19 +45,37 @@ import {jsxs,jsx}from'react/jsx-runtime';import {useRef,useState}from'react';imp
25
45
  content: text
26
46
  }]);
27
47
  try {
48
+ let attachments = [];
49
+ const links = linksIn(text);
50
+ if (links.length && runAction && uploadMedia && onAddMedia) {
51
+ setStatus(`Taking in ${links.length} link${links.length === 1 ? "" : "s"}\u2026`);
52
+ attachments = await intakeLinks(links, {
53
+ fetchUrl: (url, accept) => fetchLinkViaAgent(runAction, url, accept),
54
+ upload: (dataUrl) => uploadMedia(dataUrl),
55
+ addAsset: (asset) => onAddMedia(asset)
56
+ });
57
+ for (const a of attachments) {
58
+ setLog((l) => [...l, a.kind === "unusable" ? `Could not take in ${a.name}: ${a.reason}` : `Took in ${a.name}`]);
59
+ }
60
+ }
28
61
  const result = await runCutAgentTurn({
29
62
  history,
30
63
  userText: text,
64
+ attachments,
31
65
  token,
32
66
  agentEndpoint: deriveAgentEndpoint(indexUrl),
33
67
  onStatus: setStatus,
34
- ctx: {
68
+ ctx: __spreadValues({
35
69
  getTimeline: () => timelineRef.current,
70
+ // Scene-scoped layers move with their scenes on agent edits too.
36
71
  setTimeline: (next) => {
37
- timelineRef.current = next;
38
- setTimeline(next);
72
+ const reflowed = reflowSceneChildren(timelineRef.current, next);
73
+ timelineRef.current = reflowed;
74
+ setTimeline(reflowed);
39
75
  }
40
- }
76
+ }, onFilm ? {
77
+ film: onFilm
78
+ } : {})
41
79
  });
42
80
  for (const step of result.steps) setLog((l) => [...l, step.label]);
43
81
  setLog((l) => [...l, result.text]);
@@ -55,7 +93,7 @@ import {jsxs,jsx}from'react/jsx-runtime';import {useRef,useState}from'react';imp
55
93
  };
56
94
  return /* @__PURE__ */ jsxs(View, { style: styles.root, children: [
57
95
  /* @__PURE__ */ jsx(Text, { style: styles.title, children: "AI cut" }),
58
- /* @__PURE__ */ jsx(Text, { style: styles.fine, children: "Describe the cut. The agent can inspect, trim, reorder, and remove clips." }),
96
+ /* @__PURE__ */ jsx(Text, { style: styles.fine, children: "Describe the cut. The agent can inspect, trim, reorder and remove clips, add scenes to film and titles, and take in pasted links to pictures or videos." }),
59
97
  /* @__PURE__ */ jsx(ScrollView, { style: styles.log, contentContainerStyle: {
60
98
  paddingBottom: 8
61
99
  }, children: log.map((line, i) => /* @__PURE__ */ jsx(Text, { style: styles.logLine, children: line }, `${i}-${line.slice(0, 12)}`)) }),
@@ -1 +1 @@
1
- {"version":3,"file":"AgentCutPane.js","sources":["../../../../../src/features/canvas/videoEditor/agent/AgentCutPane.tsx"],"sourcesContent":["/**\n * Agentic cut pane inside the video editor — describe the cut, tools rearrange clips.\n */\nimport React, { useRef, useState } from 'react';\nimport { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';\nimport type { EditorTimeline } from '../editorModel';\nimport { deriveAgentEndpoint } from '../remoteMediaClient';\nimport { runCutAgentTurn } from './agentLoop';\n\nexport function AgentCutPane({\n timeline,\n setTimeline,\n token,\n indexUrl,\n}: {\n timeline: EditorTimeline;\n setTimeline: (next: EditorTimeline | ((prev: EditorTimeline) => EditorTimeline)) => void;\n token?: string | null;\n indexUrl?: string | null;\n}) {\n const timelineRef = useRef(timeline);\n timelineRef.current = timeline;\n const [prompt, setPrompt] = useState('Keep the strongest 3 clips and put the hero shot first');\n const [busy, setBusy] = useState(false);\n const [status, setStatus] = useState<string | null>(null);\n const [log, setLog] = useState<string[]>([]);\n const [history, setHistory] = useState<Array<{ role: 'user' | 'assistant'; content: string }>>([]);\n\n const run = async () => {\n if (!token || !indexUrl) {\n setLog((l) => [...l, 'Sign in needed for AI cut.']);\n return;\n }\n const text = prompt.trim();\n if (!text || busy) return;\n setBusy(true);\n setStatus('Starting…');\n setHistory((h) => [...h, { role: 'user', content: text }]);\n try {\n const result = await runCutAgentTurn({\n history,\n userText: text,\n token,\n agentEndpoint: deriveAgentEndpoint(indexUrl),\n onStatus: setStatus,\n ctx: {\n getTimeline: () => timelineRef.current,\n setTimeline: (next) => {\n timelineRef.current = next;\n setTimeline(next);\n },\n },\n });\n for (const step of result.steps) setLog((l) => [...l, step.label]);\n setLog((l) => [...l, result.text]);\n setHistory((h) => [...h, { role: 'assistant', content: result.text }]);\n setPrompt('');\n } catch (err: unknown) {\n setLog((l) => [...l, err instanceof Error ? err.message : String(err)]);\n } finally {\n setBusy(false);\n setStatus(null);\n }\n };\n\n return (\n <View style={styles.root}>\n <Text style={styles.title}>AI cut</Text>\n <Text style={styles.fine}>Describe the cut. The agent can inspect, trim, reorder, and remove clips.</Text>\n <ScrollView style={styles.log} contentContainerStyle={{ paddingBottom: 8 }}>\n {log.map((line, i) => (\n <Text key={`${i}-${line.slice(0, 12)}`} style={styles.logLine}>\n {line}\n </Text>\n ))}\n </ScrollView>\n {status ? <Text style={styles.status}>{status}</Text> : null}\n <TextInput\n value={prompt}\n onChangeText={setPrompt}\n style={styles.input}\n multiline\n placeholderTextColor=\"#94a3b8\"\n placeholder=\"e.g. Drop the last clip and tighten the open\"\n />\n <Pressable onPress={() => void run()} disabled={busy} style={[styles.cta, busy && styles.ctaOff]}>\n {busy ? <ActivityIndicator color=\"#0f172a\" /> : <Text style={styles.ctaLabel}>Run cut</Text>}\n </Pressable>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n root: { padding: 12, gap: 8 },\n title: { fontSize: 14, fontWeight: '700', color: '#0f172a' },\n fine: { fontSize: 12, color: '#64748b', lineHeight: 16 },\n log: { maxHeight: 140, backgroundColor: '#f8fafc', borderRadius: 10, padding: 8 },\n logLine: { fontSize: 12, color: '#334155', marginBottom: 4 },\n status: { fontSize: 12, color: '#7c3aed' },\n input: {\n minHeight: 64,\n borderRadius: 10,\n borderWidth: 1,\n borderColor: '#e2e8f0',\n paddingHorizontal: 10,\n paddingVertical: 8,\n color: '#0f172a',\n textAlignVertical: 'top',\n },\n cta: {\n alignItems: 'center',\n paddingVertical: 11,\n borderRadius: 10,\n backgroundColor: '#e2e8f0',\n },\n ctaOff: { opacity: 0.5 },\n ctaLabel: { fontWeight: '700', color: '#0f172a' },\n});\n"],"names":[],"mappings":"qRAQO,SAAS,YAAa,CAAA;AAAA,EAC3B,QAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAKG,EAAA;AACD,EAAM,MAAA,WAAA,GAAc,OAAO,QAAQ,CAAA;AACnC,EAAA,WAAA,CAAY,OAAU,GAAA,QAAA;AACtB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,wDAAwD,CAAA;AAC7F,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,KAAK,CAAA;AACtC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAwB,IAAI,CAAA;AACxD,EAAA,MAAM,CAAC,GAAK,EAAA,MAAM,CAAI,GAAA,QAAA,CAAmB,EAAE,CAAA;AAC3C,EAAA,MAAM,CAAC,OAAS,EAAA,UAAU,CAAI,GAAA,QAAA,CAG1B,EAAE,CAAA;AACN,EAAA,MAAM,MAAM,YAAY;AACtB,IAAI,IAAA,CAAC,KAAS,IAAA,CAAC,QAAU,EAAA;AACvB,MAAA,MAAA,CAAO,CAAK,CAAA,KAAA,CAAC,GAAG,CAAA,EAAG,4BAA4B,CAAC,CAAA;AAChD,MAAA;AAAA;AAEF,IAAM,MAAA,IAAA,GAAO,OAAO,IAAK,EAAA;AACzB,IAAI,IAAA,CAAC,QAAQ,IAAM,EAAA;AACnB,IAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,IAAA,SAAA,CAAU,gBAAW,CAAA;AACrB,IAAW,UAAA,CAAA,CAAA,CAAA,KAAK,CAAC,GAAG,CAAG,EAAA;AAAA,MACrB,IAAM,EAAA,MAAA;AAAA,MACN,OAAS,EAAA;AAAA,KACV,CAAC,CAAA;AACF,IAAI,IAAA;AACF,MAAM,MAAA,MAAA,GAAS,MAAM,eAAgB,CAAA;AAAA,QACnC,OAAA;AAAA,QACA,QAAU,EAAA,IAAA;AAAA,QACV,KAAA;AAAA,QACA,aAAA,EAAe,oBAAoB,QAAQ,CAAA;AAAA,QAC3C,QAAU,EAAA,SAAA;AAAA,QACV,GAAK,EAAA;AAAA,UACH,WAAA,EAAa,MAAM,WAAY,CAAA,OAAA;AAAA,UAC/B,aAAa,CAAQ,IAAA,KAAA;AACnB,YAAA,WAAA,CAAY,OAAU,GAAA,IAAA;AACtB,YAAA,WAAA,CAAY,IAAI,CAAA;AAAA;AAClB;AACF,OACD,CAAA;AACD,MAAW,KAAA,MAAA,IAAA,IAAQ,MAAO,CAAA,KAAA,EAAc,MAAA,CAAA,CAAA,CAAA,KAAK,CAAC,GAAG,CAAA,EAAG,IAAK,CAAA,KAAK,CAAC,CAAA;AAC/D,MAAA,MAAA,CAAO,OAAK,CAAC,GAAG,CAAG,EAAA,MAAA,CAAO,IAAI,CAAC,CAAA;AAC/B,MAAW,UAAA,CAAA,CAAA,CAAA,KAAK,CAAC,GAAG,CAAG,EAAA;AAAA,QACrB,IAAM,EAAA,WAAA;AAAA,QACN,SAAS,MAAO,CAAA;AAAA,OACjB,CAAC,CAAA;AACF,MAAA,SAAA,CAAU,EAAE,CAAA;AAAA,aACL,GAAc,EAAA;AACrB,MAAO,MAAA,CAAA,CAAA,CAAA,KAAK,CAAC,GAAG,CAAG,EAAA,GAAA,YAAe,KAAQ,GAAA,GAAA,CAAI,OAAU,GAAA,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAAA,KACpE,SAAA;AACA,MAAA,OAAA,CAAQ,KAAK,CAAA;AACb,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA;AAChB,GACF;AACA,EAAA,uBAAQ,IAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,IACjB,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,MAAO,CAAA,KAAA,EAAO,QAAM,EAAA,QAAA,EAAA,CAAA;AAAA,oBAChC,GAAA,CAAA,IAAA,EAAA,EAAK,KAAO,EAAA,MAAA,CAAO,MAAM,QAAyE,EAAA,2EAAA,EAAA,CAAA;AAAA,oBAClG,GAAA,CAAA,UAAA,EAAA,EAAW,KAAO,EAAA,MAAA,CAAO,KAAK,qBAAuB,EAAA;AAAA,MAC5D,aAAe,EAAA;AAAA,KACjB,EACa,cAAI,GAAI,CAAA,CAAC,MAAM,CAAM,qBAAA,GAAA,CAAC,IAAuC,EAAA,EAAA,KAAA,EAAO,MAAO,CAAA,OAAA,EACnE,kBADwB,CAAG,EAAA,CAAC,IAAI,IAAK,CAAA,KAAA,CAAM,GAAG,EAAE,CAAC,CAEtD,CAAA,CAAO,CACf,EAAA,CAAA;AAAA,IACC,yBAAU,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,MAAO,CAAA,MAAA,EAAS,kBAAO,CAAU,GAAA,IAAA;AAAA,oBACvD,GAAA,CAAA,SAAA,EAAA,EAAU,KAAO,EAAA,MAAA,EAAQ,cAAc,SAAW,EAAA,KAAA,EAAO,MAAO,CAAA,KAAA,EAAO,SAAS,EAAA,IAAA,EAAC,oBAAqB,EAAA,SAAA,EAAU,aAAY,8CAA+C,EAAA,CAAA;AAAA,oBAC3K,GAAA,CAAA,SAAA,EAAA,EAAU,OAAS,EAAA,MAAM,KAAK,GAAA,EAAO,EAAA,QAAA,EAAU,IAAM,EAAA,KAAA,EAAO,CAAC,MAAA,CAAO,GAAK,EAAA,IAAA,IAAQ,MAAO,CAAA,MAAM,CAC1F,EAAA,QAAA,EAAA,IAAA,mBAAQ,GAAA,CAAA,iBAAA,EAAA,EAAkB,KAAM,EAAA,SAAA,EAAU,CAAK,mBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,KAAA,EAAO,MAAO,CAAA,QAAA,EAAU,qBAAO,CACzF,EAAA;AAAA,GACJ,EAAA,CAAA;AACR;AACA,MAAM,MAAA,GAAS,WAAW,MAAO,CAAA;AAAA,EAC/B,IAAM,EAAA;AAAA,IACJ,OAAS,EAAA,EAAA;AAAA,IACT,GAAK,EAAA;AAAA,GACP;AAAA,EACA,KAAO,EAAA;AAAA,IACL,QAAU,EAAA,EAAA;AAAA,IACV,UAAY,EAAA,KAAA;AAAA,IACZ,KAAO,EAAA;AAAA,GACT;AAAA,EACA,IAAM,EAAA;AAAA,IACJ,QAAU,EAAA,EAAA;AAAA,IACV,KAAO,EAAA,SAAA;AAAA,IACP,UAAY,EAAA;AAAA,GACd;AAAA,EACA,GAAK,EAAA;AAAA,IACH,SAAW,EAAA,GAAA;AAAA,IACX,eAAiB,EAAA,SAAA;AAAA,IACjB,YAAc,EAAA,EAAA;AAAA,IACd,OAAS,EAAA;AAAA,GACX;AAAA,EACA,OAAS,EAAA;AAAA,IACP,QAAU,EAAA,EAAA;AAAA,IACV,KAAO,EAAA,SAAA;AAAA,IACP,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,QAAU,EAAA,EAAA;AAAA,IACV,KAAO,EAAA;AAAA,GACT;AAAA,EACA,KAAO,EAAA;AAAA,IACL,SAAW,EAAA,EAAA;AAAA,IACX,YAAc,EAAA,EAAA;AAAA,IACd,WAAa,EAAA,CAAA;AAAA,IACb,WAAa,EAAA,SAAA;AAAA,IACb,iBAAmB,EAAA,EAAA;AAAA,IACnB,eAAiB,EAAA,CAAA;AAAA,IACjB,KAAO,EAAA,SAAA;AAAA,IACP,iBAAmB,EAAA;AAAA,GACrB;AAAA,EACA,GAAK,EAAA;AAAA,IACH,UAAY,EAAA,QAAA;AAAA,IACZ,eAAiB,EAAA,EAAA;AAAA,IACjB,YAAc,EAAA,EAAA;AAAA,IACd,eAAiB,EAAA;AAAA,GACnB;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,OAAS,EAAA;AAAA,GACX;AAAA,EACA,QAAU,EAAA;AAAA,IACR,UAAY,EAAA,KAAA;AAAA,IACZ,KAAO,EAAA;AAAA;AAEX,CAAC,CAAA"}
1
+ {"version":3,"file":"AgentCutPane.js","sources":["../../../../../src/features/canvas/videoEditor/agent/AgentCutPane.tsx"],"sourcesContent":["/**\n * Agentic cut pane inside the video editor — describe the cut, tools rearrange clips.\n */\nimport React, { useRef, useState } from 'react';\nimport { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native';\nimport type { EditorTimeline } from '../editorModel';\nimport type { RunMediaAction } from '../mediaActions';\nimport { deriveAgentEndpoint } from '../remoteMediaClient';\nimport { reflowSceneChildren } from '../sceneLayers';\nimport { runCutAgentTurn } from './agentLoop';\nimport { fetchLinkViaAgent, intakeLinks, linksIn, type AgentAttachment, type LinkMediaKind } from './attachments';\n\nexport function AgentCutPane({\n timeline,\n setTimeline,\n token,\n indexUrl,\n runAction,\n uploadMedia,\n onAddMedia,\n onFilm,\n}: {\n timeline: EditorTimeline;\n setTimeline: (next: EditorTimeline | ((prev: EditorTimeline) => EditorTimeline)) => void;\n token?: string | null;\n indexUrl?: string | null;\n /** Pasted links are fetched through the storage connector with this runner. */\n runAction?: RunMediaAction;\n /** Stores a fetched link's bytes (data: URL) and returns the hosted URL. */\n uploadMedia?: (localUri: string) => Promise<string>;\n /** Put a taken-in link into the editor library; returns its id. */\n onAddMedia?: (asset: { type: LinkMediaKind; src: string; name: string }) => string;\n /** film_scenes: film these colour scenes in the background. */\n onFilm?: (sceneIds: string[]) => void;\n}) {\n const timelineRef = useRef(timeline);\n timelineRef.current = timeline;\n const [prompt, setPrompt] = useState('Keep the strongest 3 clips and put the hero shot first');\n const [busy, setBusy] = useState(false);\n const [status, setStatus] = useState<string | null>(null);\n const [log, setLog] = useState<string[]>([]);\n const [history, setHistory] = useState<Array<{ role: 'user' | 'assistant'; content: string }>>([]);\n\n const run = async () => {\n if (!token || !indexUrl) {\n setLog((l) => [...l, 'Sign in needed for AI cut.']);\n return;\n }\n const text = prompt.trim();\n if (!text || busy) return;\n setBusy(true);\n setStatus('Starting…');\n setHistory((h) => [...h, { role: 'user', content: text }]);\n try {\n // Pasted links become library media the model is told about (pictures it sees).\n let attachments: AgentAttachment[] = [];\n const links = linksIn(text);\n if (links.length && runAction && uploadMedia && onAddMedia) {\n setStatus(`Taking in ${links.length} link${links.length === 1 ? '' : 's'}…`);\n attachments = await intakeLinks(links, {\n fetchUrl: (url, accept) => fetchLinkViaAgent(runAction, url, accept),\n upload: (dataUrl) => uploadMedia(dataUrl),\n addAsset: (asset) => onAddMedia(asset),\n });\n for (const a of attachments) {\n setLog((l) => [\n ...l,\n a.kind === 'unusable' ? `Could not take in ${a.name}: ${a.reason}` : `Took in ${a.name}`,\n ]);\n }\n }\n const result = await runCutAgentTurn({\n history,\n userText: text,\n attachments,\n token,\n agentEndpoint: deriveAgentEndpoint(indexUrl),\n onStatus: setStatus,\n ctx: {\n getTimeline: () => timelineRef.current,\n // Scene-scoped layers move with their scenes on agent edits too.\n setTimeline: (next) => {\n const reflowed = reflowSceneChildren(timelineRef.current, next);\n timelineRef.current = reflowed;\n setTimeline(reflowed);\n },\n ...(onFilm ? { film: onFilm } : {}),\n },\n });\n for (const step of result.steps) setLog((l) => [...l, step.label]);\n setLog((l) => [...l, result.text]);\n setHistory((h) => [...h, { role: 'assistant', content: result.text }]);\n setPrompt('');\n } catch (err: unknown) {\n setLog((l) => [...l, err instanceof Error ? err.message : String(err)]);\n } finally {\n setBusy(false);\n setStatus(null);\n }\n };\n\n return (\n <View style={styles.root}>\n <Text style={styles.title}>AI cut</Text>\n <Text style={styles.fine}>\n Describe the cut. The agent can inspect, trim, reorder and remove clips, add scenes to film and titles,\n and take in pasted links to pictures or videos.\n </Text>\n <ScrollView style={styles.log} contentContainerStyle={{ paddingBottom: 8 }}>\n {log.map((line, i) => (\n <Text key={`${i}-${line.slice(0, 12)}`} style={styles.logLine}>\n {line}\n </Text>\n ))}\n </ScrollView>\n {status ? <Text style={styles.status}>{status}</Text> : null}\n <TextInput\n value={prompt}\n onChangeText={setPrompt}\n style={styles.input}\n multiline\n placeholderTextColor=\"#94a3b8\"\n placeholder=\"e.g. Drop the last clip and tighten the open\"\n />\n <Pressable onPress={() => void run()} disabled={busy} style={[styles.cta, busy && styles.ctaOff]}>\n {busy ? <ActivityIndicator color=\"#0f172a\" /> : <Text style={styles.ctaLabel}>Run cut</Text>}\n </Pressable>\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n root: { padding: 12, gap: 8 },\n title: { fontSize: 14, fontWeight: '700', color: '#0f172a' },\n fine: { fontSize: 12, color: '#64748b', lineHeight: 16 },\n log: { maxHeight: 140, backgroundColor: '#f8fafc', borderRadius: 10, padding: 8 },\n logLine: { fontSize: 12, color: '#334155', marginBottom: 4 },\n status: { fontSize: 12, color: '#7c3aed' },\n input: {\n minHeight: 64,\n borderRadius: 10,\n borderWidth: 1,\n borderColor: '#e2e8f0',\n paddingHorizontal: 10,\n paddingVertical: 8,\n color: '#0f172a',\n textAlignVertical: 'top',\n },\n cta: {\n alignItems: 'center',\n paddingVertical: 11,\n borderRadius: 10,\n backgroundColor: '#e2e8f0',\n },\n ctaOff: { opacity: 0.5 },\n ctaLabel: { fontWeight: '700', color: '#0f172a' },\n});\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
- import {brainChat}from'./brainClient.js';import {CUT_AGENT_TOOLS,executeCutTool}from'./cutTools.js';const SYSTEM = `You are a video editor assistant on a phone timeline.
1
+ import {brainChat}from'./brainClient.js';import {CUT_AGENT_TOOLS,executeCutTool}from'./cutTools.js';import {userContent}from'./attachments.js';const SYSTEM = `You are a video editor assistant on a phone timeline.
2
2
  Use tools to inspect and rearrange clips. Prefer short clear replies.
3
+ When the user wants scenes the cut does not have, add_scene one shot per beat (picture only, 4-8s each), lay titles with add_text, then call film_scenes once - the footage lands in place in a few minutes; do not wait for it.
4
+ Pictures attached to a message are shown to you; the [Attached with this message] block names the library id each became.
3
5
  Only use the provided tools. When done, summarize in two sentences.`;
4
6
  async function runCutAgentTurn(args) {
5
7
  var _a, _b, _c, _d;
@@ -12,7 +14,7 @@ async function runCutAgentTurn(args) {
12
14
  content: m.content
13
15
  })), {
14
16
  role: "user",
15
- content: args.userText
17
+ content: userContent(args.userText, args.attachments)
16
18
  }];
17
19
  const maxRounds = (_a = args.maxRounds) != null ? _a : 10;
18
20
  for (let round = 0; round < maxRounds; round += 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"agentLoop.js","sources":["../../../../../src/features/canvas/videoEditor/agent/agentLoop.ts"],"sourcesContent":["/**\n * One agentic cut turn — twin of web agentLoop (cut tools only).\n */\nimport { brainChat, type BrainMessage, type BrainReply } from './brainClient';\nimport { CUT_AGENT_TOOLS, executeCutTool, type AgentToolContext } from './cutTools';\n\nexport interface AgentTurnResult {\n text: string;\n steps: Array<{ label: string; detail?: string }>;\n}\n\nconst SYSTEM = `You are a video editor assistant on a phone timeline.\nUse tools to inspect and rearrange clips. Prefer short clear replies.\nOnly use the provided tools. When done, summarize in two sentences.`;\n\nexport async function runCutAgentTurn(args: {\n history: Array<{ role: 'user' | 'assistant'; content: string }>;\n userText: string;\n ctx: AgentToolContext;\n token: string;\n agentEndpoint: string;\n onStatus?: (text: string) => void;\n maxRounds?: number;\n}): Promise<AgentTurnResult> {\n const steps: AgentTurnResult['steps'] = [];\n const messages: BrainMessage[] = [\n { role: 'system', content: SYSTEM },\n ...args.history.slice(-10).map((m) => ({ role: m.role as 'user' | 'assistant', content: m.content })),\n { role: 'user', content: args.userText },\n ];\n const maxRounds = args.maxRounds ?? 10;\n\n for (let round = 0; round < maxRounds; round += 1) {\n args.onStatus?.(round === 0 ? 'Thinking…' : `Working (round ${round + 1})…`);\n let reply: BrainReply;\n try {\n reply = await brainChat({\n messages,\n tools: CUT_AGENT_TOOLS,\n token: args.token,\n agentEndpoint: args.agentEndpoint,\n });\n } catch (err) {\n return {\n text: err instanceof Error ? err.message : String(err),\n steps,\n };\n }\n\n if (!reply.tool_calls?.length) {\n return { text: reply.content.trim() || 'Done.', steps };\n }\n\n messages.push({\n role: 'assistant',\n content: reply.content || '',\n });\n\n for (const call of reply.tool_calls) {\n let parsed: unknown = {};\n try {\n parsed = JSON.parse(call.function.arguments || '{}');\n } catch {\n parsed = {};\n }\n args.onStatus?.(call.function.name);\n const outcome = await executeCutTool(call.function.name, parsed, args.ctx);\n steps.push({ label: outcome.label, detail: outcome.detail });\n messages.push({\n role: 'tool',\n tool_call_id: call.id,\n name: call.function.name,\n content: outcome.content,\n });\n }\n }\n\n return { text: 'Stopped after the tool budget. Ask me to continue if needed.', steps };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agentLoop.js","sources":["../../../../../src/features/canvas/videoEditor/agent/agentLoop.ts"],"sourcesContent":["/**\n * One agentic cut turn — twin of web agentLoop (cut tools only).\n */\nimport { brainChat, type BrainMessage, type BrainReply } from './brainClient';\nimport { CUT_AGENT_TOOLS, executeCutTool, type AgentToolContext } from './cutTools';\nimport { userContent, type AgentAttachment } from './attachments';\n\nexport interface AgentTurnResult {\n text: string;\n steps: Array<{ label: string; detail?: string }>;\n}\n\nconst SYSTEM = `You are a video editor assistant on a phone timeline.\nUse tools to inspect and rearrange clips. Prefer short clear replies.\nWhen the user wants scenes the cut does not have, add_scene one shot per beat (picture only, 4-8s each), lay titles with add_text, then call film_scenes once - the footage lands in place in a few minutes; do not wait for it.\nPictures attached to a message are shown to you; the [Attached with this message] block names the library id each became.\nOnly use the provided tools. When done, summarize in two sentences.`;\n\nexport async function runCutAgentTurn(args: {\n history: Array<{ role: 'user' | 'assistant'; content: string }>;\n userText: string;\n /** Files/links taken in with this message: named in a block, pictures sent as image parts. */\n attachments?: AgentAttachment[];\n ctx: AgentToolContext;\n token: string;\n agentEndpoint: string;\n onStatus?: (text: string) => void;\n maxRounds?: number;\n}): Promise<AgentTurnResult> {\n const steps: AgentTurnResult['steps'] = [];\n const messages: BrainMessage[] = [\n { role: 'system', content: SYSTEM },\n ...args.history.slice(-10).map((m) => ({ role: m.role as 'user' | 'assistant', content: m.content })),\n { role: 'user', content: userContent(args.userText, args.attachments) },\n ];\n const maxRounds = args.maxRounds ?? 10;\n\n for (let round = 0; round < maxRounds; round += 1) {\n args.onStatus?.(round === 0 ? 'Thinking…' : `Working (round ${round + 1})…`);\n let reply: BrainReply;\n try {\n reply = await brainChat({\n messages,\n tools: CUT_AGENT_TOOLS,\n token: args.token,\n agentEndpoint: args.agentEndpoint,\n });\n } catch (err) {\n return {\n text: err instanceof Error ? err.message : String(err),\n steps,\n };\n }\n\n if (!reply.tool_calls?.length) {\n return { text: reply.content.trim() || 'Done.', steps };\n }\n\n messages.push({\n role: 'assistant',\n content: reply.content || '',\n });\n\n for (const call of reply.tool_calls) {\n let parsed: unknown = {};\n try {\n parsed = JSON.parse(call.function.arguments || '{}');\n } catch {\n parsed = {};\n }\n args.onStatus?.(call.function.name);\n const outcome = await executeCutTool(call.function.name, parsed, args.ctx);\n steps.push({ label: outcome.label, detail: outcome.detail });\n messages.push({\n role: 'tool',\n tool_call_id: call.id,\n name: call.function.name,\n content: outcome.content,\n });\n }\n }\n\n return { text: 'Stopped after the tool budget. Ask me to continue if needed.', steps };\n}\n"],"names":[],"mappings":"+IAaA,MAAM,MAAS,GAAA,CAAA;AAAA;AAAA;AAAA;AAAA,mEAAA,CAAA;AAKf,eAAsB,gBAAgB,IAaT,EAAA;AA/B7B,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAgCE,EAAA,MAAM,QAAkC,EAAC;AACzC,EAAA,MAAM,WAA2B,CAAC;AAAA,IAChC,IAAM,EAAA,QAAA;AAAA,IACN,OAAS,EAAA;AAAA,GACX,EAAG,GAAG,IAAK,CAAA,OAAA,CAAQ,MAAM,GAAG,CAAA,CAAE,IAAI,CAAM,CAAA,MAAA;AAAA,IACtC,MAAM,CAAE,CAAA,IAAA;AAAA,IACR,SAAS,CAAE,CAAA;AAAA,IACX,CAAG,EAAA;AAAA,IACH,IAAM,EAAA,MAAA;AAAA,IACN,OAAS,EAAA,WAAA,CAAY,IAAK,CAAA,QAAA,EAAU,KAAK,WAAW;AAAA,GACrD,CAAA;AACD,EAAM,MAAA,SAAA,GAAA,CAAY,EAAK,GAAA,IAAA,CAAA,SAAA,KAAL,IAAkB,GAAA,EAAA,GAAA,EAAA;AACpC,EAAA,KAAA,IAAS,KAAQ,GAAA,CAAA,EAAG,KAAQ,GAAA,SAAA,EAAW,SAAS,CAAG,EAAA;AACjD,IAAA,CAAA,EAAA,GAAA,IAAA,CAAK,aAAL,IAAgB,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,IAAA,EAAA,KAAA,KAAU,IAAI,gBAAc,GAAA,CAAA,eAAA,EAAkB,QAAQ,CAAC,CAAA,OAAA,CAAA,CAAA;AACvE,IAAI,IAAA,KAAA;AACJ,IAAI,IAAA;AACF,MAAA,KAAA,GAAQ,MAAM,SAAU,CAAA;AAAA,QACtB,QAAA;AAAA,QACA,KAAO,EAAA,eAAA;AAAA,QACP,OAAO,IAAK,CAAA,KAAA;AAAA,QACZ,eAAe,IAAK,CAAA;AAAA,OACrB,CAAA;AAAA,aACM,GAAK,EAAA;AACZ,MAAO,OAAA;AAAA,QACL,MAAM,GAAe,YAAA,KAAA,GAAQ,GAAI,CAAA,OAAA,GAAU,OAAO,GAAG,CAAA;AAAA,QACrD;AAAA,OACF;AAAA;AAEF,IAAA,IAAI,EAAC,CAAA,EAAA,GAAA,KAAA,CAAM,UAAN,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAkB,MAAQ,CAAA,EAAA;AAC7B,MAAO,OAAA;AAAA,QACL,IAAM,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,EAAU,IAAA,OAAA;AAAA,QAC9B;AAAA,OACF;AAAA;AAEF,IAAA,QAAA,CAAS,IAAK,CAAA;AAAA,MACZ,IAAM,EAAA,WAAA;AAAA,MACN,OAAA,EAAS,MAAM,OAAW,IAAA;AAAA,KAC3B,CAAA;AACD,IAAW,KAAA,MAAA,IAAA,IAAQ,MAAM,UAAY,EAAA;AACnC,MAAA,IAAI,SAAkB,EAAC;AACvB,MAAI,IAAA;AACF,QAAA,MAAA,GAAS,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,QAAA,CAAS,aAAa,IAAI,CAAA;AAAA,OAC7C,CAAA,OAAA,CAAA,EAAA;AACN,QAAA,MAAA,GAAS,EAAC;AAAA;AAEZ,MAAK,CAAA,EAAA,GAAA,IAAA,CAAA,QAAA,KAAL,IAAgB,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,IAAA,EAAA,IAAA,CAAK,QAAS,CAAA,IAAA,CAAA;AAC9B,MAAM,MAAA,OAAA,GAAU,MAAM,cAAe,CAAA,IAAA,CAAK,SAAS,IAAM,EAAA,MAAA,EAAQ,KAAK,GAAG,CAAA;AACzE,MAAA,KAAA,CAAM,IAAK,CAAA;AAAA,QACT,OAAO,OAAQ,CAAA,KAAA;AAAA,QACf,QAAQ,OAAQ,CAAA;AAAA,OACjB,CAAA;AACD,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,IAAM,EAAA,MAAA;AAAA,QACN,cAAc,IAAK,CAAA,EAAA;AAAA,QACnB,IAAA,EAAM,KAAK,QAAS,CAAA,IAAA;AAAA,QACpB,SAAS,OAAQ,CAAA;AAAA,OAClB,CAAA;AAAA;AACH;AAEF,EAAO,OAAA;AAAA,IACL,IAAM,EAAA,8DAAA;AAAA,IACN;AAAA,GACF;AACF"}