diff --git a/src/components/application-builder/shared.ts b/src/components/application-builder/shared.ts index ca71817b..009065cc 100644 --- a/src/components/application-builder/shared.ts +++ b/src/components/application-builder/shared.ts @@ -52,8 +52,15 @@ export type StarterPartnerButtonStyle = CSSProperties & { const nextJsMigrationPattern = /migrat(?:e|ing|ion).*(next(?:\.js)?)|(next(?:\.js)?).*(migrat(?:e|ing|ion))/i +const remixMigrationPattern = + /migrat(?:e|ing|ion).*(remix|react[\s-]?router)|(remix|react[\s-]?router).*(migrat(?:e|ing|ion))/i const migrationRepositoryUrlPattern = /^(https?:\/\/\S+|git@\S+|ssh:\/\/\S+)$/i +export const STARTER_NEXTJS_MIGRATION_GUIDE_URL = + 'https://tanstack.com/start/latest/docs/framework/react/migrate-from-next-js' +export const STARTER_REMIX_MIGRATION_GUIDE_URL = + 'https://tanstack.com/router/latest/docs/guide/how-to/migrate-from-react-router' + export const starterPinnedLibraryIds = [ 'start', 'router', @@ -142,6 +149,22 @@ export function isNextJsMigrationInput(input: string) { return nextJsMigrationPattern.test(input) } +export function isRemixMigrationInput(input: string) { + return remixMigrationPattern.test(input) +} + +export function getStarterMigrationGuideUrl(input: string) { + if (isNextJsMigrationInput(input)) { + return STARTER_NEXTJS_MIGRATION_GUIDE_URL + } + + if (isRemixMigrationInput(input)) { + return STARTER_REMIX_MIGRATION_GUIDE_URL + } + + return null +} + export function normalizeMigrationRepositoryUrl(value: string) { return value.trim() } diff --git a/src/utils/application-starter.server.ts b/src/utils/application-starter.server.ts index 13a69a87..c3a9f5e0 100644 --- a/src/utils/application-starter.server.ts +++ b/src/utils/application-starter.server.ts @@ -17,7 +17,10 @@ import { type ApplicationStarterResult, } from '~/utils/application-starter' import type { LibraryId } from '~/libraries' -import { starterAddonLibraryIds } from '~/components/application-builder/shared' +import { + getStarterMigrationGuideUrl, + starterAddonLibraryIds, +} from '~/components/application-builder/shared' import { getApplicationStarterGuidanceLines, getApplicationStarterPartnerSuggestions, @@ -400,6 +403,10 @@ function buildPromptGenerationRequest({ ].join('\n') const userBrief = getApplicationStarterUserBrief(request.input) const starterGuidanceLines = getApplicationStarterGuidanceLines(request.input) + const migrationGuideUrl = getStarterMigrationGuideUrl(request.input) + const migrationGuideInstruction = migrationGuideUrl + ? `The prompt must instruct the agent to fetch ${migrationGuideUrl} and use it as the primary reference for the migration, following its steps in order.` + : null return [ 'Write a short, natural final prompt for a stronger coding agent.', @@ -417,6 +424,7 @@ function buildPromptGenerationRequest({ 'If the user says things like make it cool, keep it minimal, or do not include something, restate those instructions explicitly in the final prompt instead of compressing them away.', 'Use the resolved starter plan as fixed input. Do not redesign the stack unless the original brief requires sequencing work after scaffolding.', 'Keep the prompt concise and plain-English. Avoid internal process language like fixed input, resolved plan, objective, implementation notes, or deliverable.', + ...(migrationGuideInstruction ? [migrationGuideInstruction] : []), '', `Context: ${request.context}`, `User request: ${userBrief}`,