@@ -129,7 +129,8 @@ export function activate(context: vscode.ExtensionContext) {
129129 vscode . commands . registerCommand ( 'ralph-runner.openSettings' , ( ) => {
130130 vscode . commands . executeCommand ( 'workbench.action.openSettings' , 'ralph-runner' ) ;
131131 } ) ,
132- vscode . commands . registerCommand ( 'ralph-runner.showMenu' , ( ) => showCommandMenu ( ) )
132+ vscode . commands . registerCommand ( 'ralph-runner.showMenu' , ( ) => showCommandMenu ( ) ) ,
133+ vscode . commands . registerCommand ( 'ralph-runner.quickStart' , ( ) => quickStart ( ) )
133134 ) ;
134135
135136 log ( 'RALPH Runner extension activated.' ) ;
@@ -809,6 +810,7 @@ function updateStatusBar(state: 'idle' | 'running'): void {
809810
810811async function showCommandMenu ( ) : Promise < void > {
811812 const items : vscode . QuickPickItem [ ] = [
813+ { label : '$(zap) Quick Start' , description : 'Set up migration plan & state files (or generate them via Copilot)' } ,
812814 { label : '$(play) Start Migration' , description : 'Begin or resume the autonomous migration loop' } ,
813815 { label : '$(debug-stop) Stop Migration' , description : 'Cancel the current migration run' } ,
814816 { label : '$(info) Show Status' , description : 'Display migration progress summary' } ,
@@ -823,6 +825,7 @@ async function showCommandMenu(): Promise<void> {
823825 if ( ! selected ) { return ; }
824826
825827 const commandMap : Record < string , string > = {
828+ '$(zap) Quick Start' : 'ralph-runner.quickStart' ,
826829 '$(play) Start Migration' : 'ralph-runner.start' ,
827830 '$(debug-stop) Stop Migration' : 'ralph-runner.stop' ,
828831 '$(info) Show Status' : 'ralph-runner.status' ,
@@ -835,3 +838,257 @@ async function showCommandMenu(): Promise<void> {
835838 vscode . commands . executeCommand ( cmd ) ;
836839 }
837840}
841+
842+ // ── Quick Start ─────────────────────────────────────────────────────────────
843+ // Guides the user through setting up MIGRATION_PLAN.md and MIGRATION_STATE.md.
844+ // 1. Checks if the files already exist in the workspace root.
845+ // 2. If missing, asks the user to provide paths to existing files.
846+ // 3. If the user doesn't have them, asks what they want to accomplish and
847+ // uses Copilot to generate both files in the expected format.
848+
849+ async function quickStart ( ) : Promise < void > {
850+ const workspaceRoot = getWorkspaceRoot ( ) ;
851+ if ( ! workspaceRoot ) {
852+ vscode . window . showErrorMessage ( 'No workspace folder open.' ) ;
853+ return ;
854+ }
855+
856+ outputChannel . show ( true ) ;
857+ log ( '═══════════════════════════════════════════════════' ) ;
858+ log ( 'RALPH Quick Start' ) ;
859+ log ( '═══════════════════════════════════════════════════' ) ;
860+
861+ const planPath = path . join ( workspaceRoot , 'MIGRATION_PLAN.md' ) ;
862+ const statePath = path . join ( workspaceRoot , 'MIGRATION_STATE.md' ) ;
863+
864+ const planExists = fs . existsSync ( planPath ) ;
865+ const stateExists = fs . existsSync ( statePath ) ;
866+
867+ // ── Case 1: Both files already exist ────────────────────────────────────
868+ if ( planExists && stateExists ) {
869+ log ( 'Both MIGRATION_PLAN.md and MIGRATION_STATE.md already exist.' ) ;
870+ const action = await vscode . window . showInformationMessage (
871+ 'RALPH: MIGRATION_PLAN.md and MIGRATION_STATE.md already exist in the workspace root.' ,
872+ 'Start Migration' , 'Open Plan' , 'Open State'
873+ ) ;
874+ if ( action === 'Start Migration' ) {
875+ vscode . commands . executeCommand ( 'ralph-runner.start' ) ;
876+ } else if ( action === 'Open Plan' ) {
877+ const doc = await vscode . workspace . openTextDocument ( planPath ) ;
878+ vscode . window . showTextDocument ( doc ) ;
879+ } else if ( action === 'Open State' ) {
880+ const doc = await vscode . workspace . openTextDocument ( statePath ) ;
881+ vscode . window . showTextDocument ( doc ) ;
882+ }
883+ return ;
884+ }
885+
886+ // ── Case 2: One or both files missing — ask user how to proceed ─────────
887+ const missingFiles : string [ ] = [ ] ;
888+ if ( ! planExists ) { missingFiles . push ( 'MIGRATION_PLAN.md' ) ; }
889+ if ( ! stateExists ) { missingFiles . push ( 'MIGRATION_STATE.md' ) ; }
890+
891+ log ( `Missing: ${ missingFiles . join ( ', ' ) } ` ) ;
892+
893+ const choice = await vscode . window . showQuickPick (
894+ [
895+ {
896+ label : '$(file-directory) I have these files — let me provide the path' ,
897+ description : 'Browse for existing MIGRATION_PLAN.md and MIGRATION_STATE.md files' ,
898+ value : 'provide'
899+ } ,
900+ {
901+ label : '$(sparkle) I don\'t have them — generate via Copilot' ,
902+ description : 'Describe your migration goal and let Copilot create both files' ,
903+ value : 'generate'
904+ }
905+ ] ,
906+ { placeHolder : `${ missingFiles . join ( ' and ' ) } not found in workspace root. How would you like to proceed?` }
907+ ) ;
908+
909+ if ( ! choice ) { return ; }
910+
911+ if ( choice . value === 'provide' ) {
912+ await quickStartProvideFiles ( planPath , statePath , planExists , stateExists ) ;
913+ } else {
914+ await quickStartGenerate ( planPath , statePath , workspaceRoot ) ;
915+ }
916+ }
917+
918+ /**
919+ * Let the user browse for existing MIGRATION_PLAN.md / MIGRATION_STATE.md files
920+ * and copy them into the workspace root.
921+ */
922+ async function quickStartProvideFiles (
923+ planPath : string , statePath : string ,
924+ planExists : boolean , stateExists : boolean
925+ ) : Promise < void > {
926+ if ( ! planExists ) {
927+ const uris = await vscode . window . showOpenDialog ( {
928+ title : 'Select your MIGRATION_PLAN.md file' ,
929+ canSelectMany : false ,
930+ canSelectFolders : false ,
931+ filters : { 'Markdown' : [ 'md' ] , 'All Files' : [ '*' ] } ,
932+ openLabel : 'Select MIGRATION_PLAN.md'
933+ } ) ;
934+ if ( ! uris || uris . length === 0 ) {
935+ vscode . window . showWarningMessage ( 'RALPH Quick Start cancelled — no MIGRATION_PLAN.md selected.' ) ;
936+ return ;
937+ }
938+ const srcPath = uris [ 0 ] . fsPath ;
939+ fs . copyFileSync ( srcPath , planPath ) ;
940+ log ( `Copied MIGRATION_PLAN.md from ${ srcPath } ` ) ;
941+ }
942+
943+ if ( ! stateExists ) {
944+ const uris = await vscode . window . showOpenDialog ( {
945+ title : 'Select your MIGRATION_STATE.md file' ,
946+ canSelectMany : false ,
947+ canSelectFolders : false ,
948+ filters : { 'Markdown' : [ 'md' ] , 'All Files' : [ '*' ] } ,
949+ openLabel : 'Select MIGRATION_STATE.md'
950+ } ) ;
951+ if ( ! uris || uris . length === 0 ) {
952+ vscode . window . showWarningMessage ( 'RALPH Quick Start cancelled — no MIGRATION_STATE.md selected.' ) ;
953+ return ;
954+ }
955+ const srcPath = uris [ 0 ] . fsPath ;
956+ fs . copyFileSync ( srcPath , statePath ) ;
957+ log ( `Copied MIGRATION_STATE.md from ${ srcPath } ` ) ;
958+ }
959+
960+ vscode . window . showInformationMessage ( 'RALPH: Migration files are ready! You can now run "RALPH: Start Migration".' ) ;
961+ log ( 'Quick Start complete — files placed in workspace root.' ) ;
962+ }
963+
964+ /**
965+ * Ask the user what they want to accomplish, then send a Copilot prompt that
966+ * generates both MIGRATION_PLAN.md and MIGRATION_STATE.md in the expected
967+ * formats used by the RALPH Runner extension.
968+ */
969+ async function quickStartGenerate (
970+ planPath : string , statePath : string , workspaceRoot : string
971+ ) : Promise < void > {
972+ const userGoal = await vscode . window . showInputBox ( {
973+ title : 'RALPH Quick Start — Describe your goal' ,
974+ prompt : 'What are you trying to accomplish? (e.g. "Migrate a Java EE 8 app to Spring Boot 3", "Convert a jQuery front-end to React")' ,
975+ placeHolder : 'Describe the migration or transformation you want to perform…' ,
976+ ignoreFocusOut : true
977+ } ) ;
978+
979+ if ( ! userGoal || userGoal . trim ( ) . length === 0 ) {
980+ vscode . window . showWarningMessage ( 'RALPH Quick Start cancelled — no goal provided.' ) ;
981+ return ;
982+ }
983+
984+ log ( `User goal: ${ userGoal } ` ) ;
985+ log ( 'Sending generation prompt to Copilot…' ) ;
986+
987+ const prompt = buildQuickStartPrompt ( userGoal , workspaceRoot ) ;
988+
989+ try {
990+ await vscode . commands . executeCommand ( 'workbench.action.chat.open' , {
991+ query : prompt ,
992+ isPartialQuery : false
993+ } ) ;
994+ } catch {
995+ try {
996+ await vscode . commands . executeCommand ( 'workbench.panel.chat.view.copilot.focus' ) ;
997+ await sleep ( 1000 ) ;
998+ await vscode . commands . executeCommand ( 'workbench.action.chat.open' , prompt ) ;
999+ } catch {
1000+ log ( 'WARNING: Could not programmatically send to Copilot. Copying to clipboard.' ) ;
1001+ await vscode . env . clipboard . writeText ( prompt ) ;
1002+ await vscode . commands . executeCommand ( 'workbench.action.chat.open' ) ;
1003+ vscode . window . showInformationMessage ( 'RALPH: Prompt copied to clipboard — paste it into Copilot Chat.' ) ;
1004+ }
1005+ }
1006+
1007+ vscode . window . showInformationMessage (
1008+ 'RALPH: Copilot is generating your migration files. Once they appear in the workspace root, run "RALPH: Start Migration".'
1009+ ) ;
1010+ log ( 'Quick Start prompt sent to Copilot. Waiting for file generation…' ) ;
1011+ }
1012+
1013+ /**
1014+ * Builds the Copilot prompt that instructs it to generate MIGRATION_PLAN.md
1015+ * and MIGRATION_STATE.md in the exact formats the RALPH Runner expects.
1016+ */
1017+ function buildQuickStartPrompt ( userGoal : string , workspaceRoot : string ) : string {
1018+ return [
1019+ `The user wants to accomplish the following goal:` ,
1020+ `` ,
1021+ `> ${ userGoal } ` ,
1022+ `` ,
1023+ `Workspace root: ${ workspaceRoot } ` ,
1024+ `` ,
1025+ `Please analyze the workspace and generate TWO files in the workspace root:` ,
1026+ `` ,
1027+ `────────────────────────────────────────────────────` ,
1028+ `FILE 1: MIGRATION_PLAN.md` ,
1029+ `────────────────────────────────────────────────────` ,
1030+ `` ,
1031+ `This file must contain a \`\`\`json code block with the following structure:` ,
1032+ `` ,
1033+ '```' ,
1034+ `{` ,
1035+ ` "steps": [` ,
1036+ ` {` ,
1037+ ` "id": 1,` ,
1038+ ` "phase": "Phase name (e.g. Setup, Analysis, Migration, Testing)",` ,
1039+ ` "action": "run_terminal | create_file | copilot_task",` ,
1040+ ` "command": "(only for run_terminal) the shell command to run",` ,
1041+ ` "path": "(only for create_file) relative path of the file to create",` ,
1042+ ` "instruction": "(only for copilot_task) detailed instruction for Copilot",` ,
1043+ ` "description": "Human-readable description of what this step does"` ,
1044+ ` }` ,
1045+ ` ]` ,
1046+ `}` ,
1047+ '```' ,
1048+ `` ,
1049+ `Action types:` ,
1050+ `- "run_terminal": executes a shell command (requires "command" field)` ,
1051+ `- "create_file": creates a file at the given path (requires "path" field)` ,
1052+ `- "copilot_task": a general Copilot coding task (requires "instruction" field)` ,
1053+ `` ,
1054+ `The plan should have a logical sequence of steps organized into phases.` ,
1055+ `Each step should be granular enough to be independently executable and verifiable.` ,
1056+ `Number steps sequentially starting from 1.` ,
1057+ `` ,
1058+ `────────────────────────────────────────────────────` ,
1059+ `FILE 2: MIGRATION_STATE.md` ,
1060+ `────────────────────────────────────────────────────` ,
1061+ `` ,
1062+ `This file tracks progress. It MUST contain:` ,
1063+ `` ,
1064+ `1. A Quick Status section with this exact table format:` ,
1065+ `` ,
1066+ `| Metric | Count |` ,
1067+ `|--------|-------|` ,
1068+ `| Total Steps | <N> |` ,
1069+ `| Completed | 0 |` ,
1070+ `| In Progress | 0 |` ,
1071+ `| Failed | 0 |` ,
1072+ `| Pending | <N> |` ,
1073+ `` ,
1074+ `**Current Phase:** Step 1` ,
1075+ `**Last Completed Step:** —` ,
1076+ `` ,
1077+ `2. A detailed step tracking table with this exact format:` ,
1078+ `` ,
1079+ `| Step | Phase | Action | Status | Timestamp | Notes |` ,
1080+ `|------|-------|--------|--------|-----------|-------|` ,
1081+ `| 1 | Phase name | \`action\` — description | \`pending\` | | |` ,
1082+ `` ,
1083+ `One row per step matching the plan. All steps should start as \`pending\`.` ,
1084+ `` ,
1085+ `────────────────────────────────────────────────────` ,
1086+ `` ,
1087+ `IMPORTANT:` ,
1088+ `- Create BOTH files at the workspace root: ${ workspaceRoot } ` ,
1089+ `- The JSON in MIGRATION_PLAN.md must be inside a \`\`\`json fenced code block` ,
1090+ `- The state table rows must follow the exact pipe-delimited format shown above` ,
1091+ `- Be thorough: include all necessary steps for the user's goal` ,
1092+ `- Actually create the files — do not just show their content` ,
1093+ ] . join ( '\n' ) ;
1094+ }
0 commit comments