From 705158395339892b1680e3330f49f6eac8a945db Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Wed, 15 Apr 2026 11:38:55 -0600 Subject: [PATCH] feat(application-starter): inject migration guide URLs into final prompt When the user brief indicates a Next.js or Remix/React Router migration, append an instruction telling the downstream agent to fetch the relevant tanstack.com migration guide and follow it. Keeps the guide out of the analyze stage and out of the UI; only affects the final generation prompt. --- src/components/application-builder/shared.ts | 23 ++++++++++++++++++++ src/utils/application-starter.server.ts | 10 ++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) 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}`,