|
6 | 6 | useState, |
7 | 7 | type FormEvent, |
8 | 8 | } from 'react'; |
9 | | -import { useParams, useSearchParams, useNavigate } from 'react-router'; |
| 9 | +import { useParams, useSearchParams, useNavigate, useLocation } from 'react-router'; |
10 | 10 | import { AnimatePresence, motion } from 'framer-motion'; |
11 | 11 | import { LoaderCircle, MoreHorizontal, RotateCcw } from 'lucide-react'; |
12 | 12 | import clsx from 'clsx'; |
@@ -63,10 +63,19 @@ export default function Chat() { |
63 | 63 | const { chatId: urlChatId } = useParams(); |
64 | 64 |
|
65 | 65 | const [searchParams] = useSearchParams(); |
| 66 | + const location = useLocation(); |
66 | 67 | const userQuery = searchParams.get('query'); |
67 | 68 | const urlProjectType = searchParams.get('projectType') || 'app'; |
68 | 69 | const urlBehaviorType = searchParams.get('behaviorType') as BehaviorType | null; |
69 | 70 |
|
| 71 | + // Only auto-start a brand-new session when it originated from in-app |
| 72 | + // navigation (e.g. the home prompt box sets `fromPrompt`). Sessions opened |
| 73 | + // from a pasted/external link require explicit confirmation, since the |
| 74 | + // query is interpolated into the agent's system prompt. |
| 75 | + const startedFromInApp = |
| 76 | + (location.state as { fromPrompt?: boolean } | null)?.fromPrompt === true; |
| 77 | + const autoStart = urlChatId !== 'new' || startedFromInApp; |
| 78 | + |
70 | 79 | // Extract images from URL params if present |
71 | 80 | const userImages = useMemo(() => { |
72 | 81 | const imagesParam = searchParams.get('images'); |
@@ -171,12 +180,16 @@ export default function Chat() { |
171 | 180 | // Backend error dialog state |
172 | 181 | backendErrorDialog, |
173 | 182 | setBackendErrorDialog, |
| 183 | + // Externally-sourced session start gate |
| 184 | + awaitingStartConfirmation, |
| 185 | + confirmStart, |
174 | 186 | } = useChat({ |
175 | 187 | chatId: urlChatId, |
176 | 188 | query: userQuery, |
177 | 189 | images: userImages, |
178 | 190 | projectType: urlProjectType as ProjectType, |
179 | 191 | behaviorType: urlBehaviorType ?? undefined, |
| 192 | + autoStart, |
180 | 193 | onDebugMessage: addDebugMessage, |
181 | 194 | onVaultUnlockRequired: handleVaultUnlockRequired, |
182 | 195 | }); |
@@ -693,6 +706,31 @@ export default function Chat() { |
693 | 706 | }); |
694 | 707 | } |
695 | 708 |
|
| 709 | + if (awaitingStartConfirmation) { |
| 710 | + return ( |
| 711 | + <div className="size-full flex items-center justify-center p-6 text-text-primary"> |
| 712 | + <div className="max-w-lg w-full flex flex-col gap-4 rounded-xl border border-border-primary bg-bg-2 p-6"> |
| 713 | + <h1 className="text-lg font-medium">Start building this app?</h1> |
| 714 | + <p className="text-sm text-text-secondary"> |
| 715 | + This link wants to start a new project with the prompt below. |
| 716 | + Review it before continuing. |
| 717 | + </p> |
| 718 | + <div className="rounded-lg border border-border-primary bg-bg-3 p-4 max-h-64 overflow-y-auto"> |
| 719 | + <p className="text-sm text-text-primary whitespace-pre-wrap break-words"> |
| 720 | + {displayQuery} |
| 721 | + </p> |
| 722 | + </div> |
| 723 | + <div className="flex items-center justify-end gap-2"> |
| 724 | + <Button variant="outline" onClick={() => navigate('/')}> |
| 725 | + Cancel |
| 726 | + </Button> |
| 727 | + <Button onClick={confirmStart}>Start building</Button> |
| 728 | + </div> |
| 729 | + </div> |
| 730 | + </div> |
| 731 | + ); |
| 732 | + } |
| 733 | + |
696 | 734 | return ( |
697 | 735 | <div className="size-full flex flex-col min-h-0 text-text-primary"> |
698 | 736 | <div className="flex-1 flex min-h-0 overflow-hidden justify-center"> |
|
0 commit comments