@@ -196,6 +196,10 @@ export interface ActivePlugin {
196196 // legitimately equal the chip's default plugin id (e.g. the prototype rail's
197197 // `example-web-prototype`).
198198 explicitPick : boolean ;
199+ // Temporary text inserted by a type tab rather than authored by the user.
200+ // Persist it with the chip so a remount does not convert mode UI into a
201+ // user-owned draft.
202+ promptSeedKind ?: 'web-clone' | null ;
199203}
200204
201205// `inlineBacked` distinguishes a context inserted as an inline `@mention` pill
@@ -352,6 +356,7 @@ interface HomeComposerChipDraft {
352356 pluginId : string ;
353357 projectKind : ProjectKind | null ;
354358 prototypeSubtypeId ?: string | null ;
359+ promptSeedKind ?: 'web-clone' | null ;
355360}
356361// `EntryShell` keeps `HomeView` permanently mounted and toggles it with CSS
357362// visibility instead of unmounting it on every Home/Community/... view
@@ -426,6 +431,7 @@ function readHomeComposerChipDraft(): HomeComposerChipDraft | null {
426431 pluginId : parsed . pluginId ,
427432 projectKind : typeof parsed . projectKind === 'string' ? ( parsed . projectKind as ProjectKind ) : null ,
428433 prototypeSubtypeId : parsedPrototypeSubtype ?. slug ?? legacyPrototypeSubtype ?. slug ?? null ,
434+ promptSeedKind : parsed . promptSeedKind === 'web-clone' ? 'web-clone' : null ,
429435 } ;
430436 } catch {
431437 return null ;
@@ -459,6 +465,23 @@ export function seedHomeComposerPrompt(prompt: string): void {
459465 }
460466}
461467
468+ function shouldClearWebClonePromptSeedOnTypeSwitch ( {
469+ activeChipId,
470+ nextChipId,
471+ promptEditedByUser,
472+ promptSeedKind,
473+ } : {
474+ activeChipId : string | null ;
475+ nextChipId : string ;
476+ promptEditedByUser : boolean ;
477+ promptSeedKind : ActivePlugin [ 'promptSeedKind' ] ;
478+ } ) : boolean {
479+ return activeChipId === 'web-clone'
480+ && nextChipId !== 'web-clone'
481+ && ! promptEditedByUser
482+ && promptSeedKind === 'web-clone' ;
483+ }
484+
462485export function HomeView ( {
463486 isActive = true ,
464487 projects,
@@ -644,6 +667,15 @@ export function HomeView({
644667 } ;
645668 }
646669 const restoredDraft = restoredDraftRef . current ;
670+ // Upgrade cleanup for drafts produced by the old behavior: after a user
671+ // switched away from Website clone, the chip draft already named the new
672+ // type while the untouched Website-clone scaffold remained in the prompt.
673+ // That exact impossible pairing is safe to discard on the first fixed load.
674+ const restoredPrompt = pendingChipRestore ?. chipId
675+ && pendingChipRestore . chipId !== 'web-clone'
676+ && restoredDraft . prompt === t ( 'homeHero.chip.webClonePromptSeed' )
677+ ? ''
678+ : restoredDraft . prompt ;
647679 const [ designSystemId , setDesignSystemId ] = useState < string | null > ( ( ) =>
648680 restoredDraft . designSystemId ??
649681 homeDefaultDesignSystemId ( designSystems , defaultDesignSystemId ) ,
@@ -679,11 +711,20 @@ export function HomeView({
679711 } , [ ] ) ;
680712 const [ mcpServers , setMcpServers ] = useState < McpServerConfig [ ] > ( [ ] ) ;
681713 const [ mcpLoading , setMcpLoading ] = useState ( true ) ;
682- const [ prompt , setPrompt ] = useState ( ( ) => restoredDraft . prompt ) ;
714+ const [ prompt , setPrompt ] = useState ( ( ) => restoredPrompt ) ;
683715 // Treat a restored non-empty prompt as user-edited so the plugin/skill
684- // replacement guard still asks before clobbering it.
716+ // replacement guard still asks before clobbering it. The Website-clone
717+ // scaffold is mode UI, not a user draft; the exact-text fallback migrates
718+ // drafts saved before promptSeedKind was persisted.
685719 const [ promptEditedByUser , setPromptEditedByUser ] = useState (
686- ( ) => restoredDraft . prompt . trim ( ) . length > 0 ,
720+ ( ) => restoredPrompt . trim ( ) . length > 0
721+ && ! (
722+ pendingChipRestore ?. chipId === 'web-clone'
723+ && (
724+ pendingChipRestore . promptSeedKind === 'web-clone'
725+ || restoredPrompt === t ( 'homeHero.chip.webClonePromptSeed' )
726+ )
727+ ) ,
687728 ) ;
688729 // Persist the composer draft on every change so it survives the unmount that
689730 // a tab switch triggers (see the module note above). Empty values clear the
@@ -716,6 +757,7 @@ export function HomeView({
716757 ...( active . prototypeSubtypeId
717758 ? { prototypeSubtypeId : active . prototypeSubtypeId }
718759 : { } ) ,
760+ ...( active . promptSeedKind ? { promptSeedKind : active . promptSeedKind } : { } ) ,
719761 }
720762 : null ,
721763 ) ;
@@ -1391,6 +1433,7 @@ export function HomeView({
13911433 // or Community card / detail modal) rather than a type chip's default
13921434 // plugin. Stored on `active.explicitPick`; gates the chip's clear button.
13931435 explicitPick ?: boolean ;
1436+ promptSeedKind ?: ActivePlugin [ 'promptSeedKind' ] ;
13941437 } ,
13951438 // Resolves true when the bound plugin left the composer submittable
13961439 // (inputs valid, apply not failed/superseded) — callers use this to
@@ -1460,6 +1503,7 @@ export function HomeView({
14601503 preserveInputFields : options ?. preserveInputFields === true ,
14611504 suppressPromptSync : suppressPromptUpdate ,
14621505 explicitPick : options ?. explicitPick === true ,
1506+ promptSeedKind : options ?. promptSeedKind ?? null ,
14631507 } ) ;
14641508 setFallbackProjectKind ( null ) ;
14651509 setFallbackProjectMetadata ( null ) ;
@@ -1611,6 +1655,7 @@ export function HomeView({
16111655 replaceWithoutConfirmation ?: boolean ;
16121656 suppressPromptUpdate ?: boolean ;
16131657 deferApply ?: boolean ;
1658+ promptSeedKind ?: ActivePlugin [ 'promptSeedKind' ] ;
16141659 } ,
16151660 ) {
16161661 const inputFields = options ?. inputFields ?? record . manifest ?. od ?. inputs ?? [ ] ;
@@ -1833,6 +1878,13 @@ export function HomeView({
18331878 ? findChip ( restore . chipId )
18341879 : null ;
18351880 const restoredAction = restoredActionChip ?. action ;
1881+ const restoredPromptSeedKind = restore . promptSeedKind
1882+ ?? (
1883+ restore . chipId === 'web-clone'
1884+ && prompt === t ( 'homeHero.chip.webClonePromptSeed' )
1885+ ? 'web-clone'
1886+ : null
1887+ ) ;
18361888 requestActivePlugin ( record , undefined , {
18371889 chipId : restore . chipId ?? undefined ,
18381890 prototypeSubtypeId : restoredSubtype ?. slug ?? null ,
@@ -1848,6 +1900,7 @@ export function HomeView({
18481900 replaceWithoutConfirmation : true ,
18491901 suppressPromptUpdate : true ,
18501902 deferApply : true ,
1903+ promptSeedKind : restoredPromptSeedKind ,
18511904 } ) ;
18521905 // eslint-disable-next-line react-hooks/exhaustive-deps
18531906 } , [ pendingChipRestore , pluginsLoading , plugins , active , pendingPluginUseHandoff ] ) ;
@@ -2030,6 +2083,9 @@ export function HomeView({
20302083 function handlePromptChange ( nextPrompt : string ) {
20312084 setPrompt ( nextPrompt ) ;
20322085 setPromptEditedByUser ( true ) ;
2086+ if ( active ?. promptSeedKind ) {
2087+ setActive ( { ...active , promptSeedKind : null } ) ;
2088+ }
20332089 if ( ! active ?. queryTemplate ) return ;
20342090 const extracted = extractPluginInputsFromPrompt (
20352091 active . queryTemplate ,
@@ -2442,6 +2498,20 @@ export function HomeView({
24422498 ) ;
24432499 return ;
24442500 }
2501+ // Website clone is the only type tab that inserts a scaffold directly
2502+ // into an empty composer. Treat that exact untouched scaffold as mode
2503+ // UI, not as a user draft, so it cannot leak into the next type tab.
2504+ // Any edit (including typing the same text manually) transfers
2505+ // ownership to the user and keeps the normal draft-preservation rule.
2506+ if ( shouldClearWebClonePromptSeedOnTypeSwitch ( {
2507+ activeChipId : active ?. chipId ?? null ,
2508+ nextChipId : activeChipId ,
2509+ promptEditedByUser,
2510+ promptSeedKind : active ?. promptSeedKind ?? null ,
2511+ } ) ) {
2512+ setPrompt ( '' ) ;
2513+ setPromptEditedByUser ( false ) ;
2514+ }
24452515 const mediaSurface = homeMediaSurfaceForChipId ( chip . id ) ;
24462516 if ( mediaSurface ) {
24472517 const composer = buildHomeMediaComposer (
@@ -2504,6 +2574,7 @@ export function HomeView({
25042574 ...pluginOptions ,
25052575 suppressPromptUpdate : promptSeed === null ,
25062576 deferApply : true ,
2577+ promptSeedKind : promptSeed === null ? null : 'web-clone' ,
25072578 } ) ;
25082579 } else {
25092580 requestActivePlugin ( record , undefined , pluginOptions ) ;
0 commit comments