From f086e09bd9924a01c57dd36ef7872fc44626cccc Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Mon, 24 Mar 2025 12:43:58 -0700
Subject: [PATCH 01/16] first commit for csb
---
 .../codemodernizer/CodeTransformChatApp.kt    |  8 ++-
 .../InboundAppMessagesHandler.kt              |  4 ++
 .../constants/CodeTransformChatItems.kt       | 39 +++++++++++
 .../controller/CodeTransformChatController.kt | 70 ++++++++++++++++++-
 .../ideMaven/MavenRunnerUtils.kt              |  7 ++
 .../messages/CodeTransformMessage.kt          | 10 +++
 .../model/CodeModernizerSessionContext.kt     |  1 +
 .../codemodernizer/model/CustomerSelection.kt |  3 +-
 .../utils/CodeTransformFileUtils.kt           | 12 ++++
 .../CodeWhispererCodeModernizerUtilsTest.kt   | 41 +++++++++++
 .../ui/apps/codeTransformChatConnector.ts     | 14 +++-
 .../mynah-ui/src/mynah-ui/ui/commands.ts      |  2 +
 .../src/mynah-ui/ui/forms/constants.ts        |  4 ++
 13 files changed, 210 insertions(+), 5 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
index b102d348d11..584a3424607 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
@@ -41,9 +41,11 @@ private enum class CodeTransformMessageTypes(val type: String) {
     ChatPrompt("chat-prompt"), // for getting the transformation objective
     CodeTransformStart("codetransform-start"),
     CodeTransformSelectSQLMetadata("codetransform-select-sql-metadata"),
+    CodeTransformConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"),
     CodeTransformSelectSQLModuleSchema("codetransform-select-sql-module-schema"),
     CodeTransformStop("codetransform-stop"),
     CodeTransformCancel("codetransform-cancel"),
+    CodeTransformContinue("codetransform-continue"),
     CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"),
     CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"),
     CodeTransformNew("codetransform-new"),
@@ -74,9 +76,11 @@ class CodeTransformChatApp : AmazonQApp {
             CodeTransformMessageTypes.Transform.type to IncomingCodeTransformMessage.Transform::class,
             CodeTransformMessageTypes.CodeTransformStart.type to IncomingCodeTransformMessage.CodeTransformStart::class,
             CodeTransformMessageTypes.CodeTransformSelectSQLMetadata.type to IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata::class,
+            CodeTransformMessageTypes.CodeTransformConfirmCustomDependencyVersions.type to IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions::class,
             CodeTransformMessageTypes.CodeTransformSelectSQLModuleSchema.type to IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema::class,
             CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class,
             CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class,
+            CodeTransformMessageTypes.CodeTransformContinue.type to IncomingCodeTransformMessage.CodeTransformContinue::class,
             CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class,
             CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class,
             CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class,
@@ -182,12 +186,14 @@ class CodeTransformChatApp : AmazonQApp {
             is IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata -> inboundAppMessagesHandler.processCodeTransformSelectSQLMetadataAction(message)
             is IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema ->
                 inboundAppMessagesHandler.processCodeTransformSelectSQLModuleSchemaAction(message)
-
+            is IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions ->
+                inboundAppMessagesHandler.processCodeTransformCustomDependencyVersions(message)
             is IncomingCodeTransformMessage.CodeTransformCancel -> inboundAppMessagesHandler.processCodeTransformCancelAction(message)
             is IncomingCodeTransformMessage.CodeTransformStop -> inboundAppMessagesHandler.processCodeTransformStopAction(message.tabId)
             is IncomingCodeTransformMessage.ChatPrompt -> inboundAppMessagesHandler.processChatPromptMessage(message)
             is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message)
             is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message)
+            is IncomingCodeTransformMessage.CodeTransformContinue -> inboundAppMessagesHandler.processCodeTransformContinueAction(message)
             is IncomingCodeTransformMessage.CodeTransformNew -> inboundAppMessagesHandler.processCodeTransformNewAction(message)
             is IncomingCodeTransformMessage.CodeTransformOpenTransformHub -> inboundAppMessagesHandler.processCodeTransformOpenTransformHub(message)
             is IncomingCodeTransformMessage.CodeTransformOpenMvnBuild -> inboundAppMessagesHandler.processCodeTransformOpenMvnBuild(message)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
index 1312328243e..434516178bd 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
@@ -11,12 +11,16 @@ interface InboundAppMessagesHandler {
 
     suspend fun processCodeTransformCancelAction(message: IncomingCodeTransformMessage.CodeTransformCancel)
 
+    suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue)
+
     suspend fun processCodeTransformStartAction(message: IncomingCodeTransformMessage.CodeTransformStart)
 
     suspend fun processCodeTransformSelectSQLMetadataAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata)
 
     suspend fun processCodeTransformSelectSQLModuleSchemaAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema)
 
+    suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions)
+
     suspend fun processCodeTransformStopAction(tabId: String)
 
     suspend fun processChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index c39d530e6b2..a68e81cef23 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -44,6 +44,14 @@ private val cancelUserSelectionButton = Button(
     id = CodeTransformButtonId.CancelTransformation.id,
 )
 
+// used to continue transformation without providing custom YAML file
+private val continueTransformationButton = Button(
+    keepCardAfterClick = false,
+    waitMandatoryFormItems = false,
+    text = "Continue without this",
+    id = CodeTransformButtonId.ContinueTransformation.id,
+)
+
 private val confirmUserSelectionLanguageUpgradeButton = Button(
     keepCardAfterClick = false,
     waitMandatoryFormItems = true,
@@ -79,6 +87,13 @@ private val confirmOneOrMultipleDiffsSelectionButton = Button(
     id = CodeTransformButtonId.ConfirmOneOrMultipleDiffs.id,
 )
 
+private val confirmCustomDependencyVersionsButton = Button(
+    keepCardAfterClick = true,
+    waitMandatoryFormItems = true, // TODO: what does this do?
+    text = "Select file",
+    id = CodeTransformButtonId.ConfirmCustomDependencyVersions.id,
+)
+
 private val openMvnBuildButton = Button(
     id = CodeTransformButtonId.OpenMvnBuild.id,
     text = message("codemodernizer.chat.message.button.view_build"),
@@ -375,6 +390,20 @@ fun buildUserInputSQLConversionMetadataChatContent() = CodeTransformChatMessageC
     type = CodeTransformChatMessageType.FinalizedAnswer,
 )
 
+fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessageContent(
+    message = "Optionally, provide a .YAML file which specifies custom dependency versions you want Q to upgrade to.",
+    buttons = listOf(
+        confirmCustomDependencyVersionsButton,
+        continueTransformationButton,
+    ),
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+)
+
+fun buildCustomDependencyVersionsFileValidChatContent() = CodeTransformChatMessageContent(
+    message = "I received your .yaml file and will upload it to Q.",
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+)
+
 fun buildModuleSchemaFormChatContent(project: Project, javaModules: List, schemaOptions: Set) = CodeTransformChatMessageContent(
     type = CodeTransformChatMessageType.FinalizedAnswer,
     buttons = listOf(
@@ -416,6 +445,11 @@ fun buildSQLMetadataValidationErrorChatContent(errorReason: String) = CodeTransf
     message = errorReason,
 )
 
+fun buildCustomDependencyVersionsFileInvalidChatContent() = CodeTransformChatMessageContent(
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+    message = "The .yaml file you uploaded does not follow the format of the sample YAML file provided.",
+)
+
 fun buildUserCancelledChatContent() = CodeTransformChatMessageContent(
     type = CodeTransformChatMessageType.FinalizedAnswer,
     message = message("codemodernizer.chat.message.transform_cancelled_by_user"),
@@ -451,6 +485,11 @@ fun buildUserLanguageUpgradeSelectionSummaryChatContent(moduleName: String, targ
     message = getUserLanguageUpgradeSelectionFormattedMarkdown(moduleName, targetJdkVersion)
 )
 
+fun buildContinueTransformationChatContent() = CodeTransformChatMessageContent(
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+    message = "Ok, I will continue without this information.",
+)
+
 fun buildCompileLocalInProgressChatContent() = CodeTransformChatMessageContent(
     type = CodeTransformChatMessageType.PendingAnswer,
     message = message("codemodernizer.chat.message.local_build_begin"),
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index b292aaf6aaa..322f745a8fb 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -11,6 +11,7 @@ import com.intellij.openapi.module.ModuleUtil
 import com.intellij.openapi.projectRoots.JavaSdkVersion
 import com.intellij.openapi.util.io.FileUtil.createTempDirectory
 import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.readText
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -43,6 +44,9 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCo
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCompileLocalFailedNoJdkChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCompileLocalInProgressChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCompileLocalSuccessChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildContinueTransformationChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCustomDependencyVersionsFileInvalidChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCustomDependencyVersionsFileValidChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildDownloadFailureChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilCannotResumeContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilErrorContent
@@ -71,6 +75,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserCancelledChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserHilSelection
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputCustomDependencyVersionsChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent
@@ -112,9 +117,14 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.toVirtualFi
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.tryGetJdk
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
 import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.fileEditor.FileEditorManager
+import com.intellij.testFramework.LightVirtualFile
+import org.jetbrains.yaml.YAMLFileType
 import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
 
@@ -353,7 +363,7 @@ class CodeTransformChatController(
         withContext(EDT) {
             val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
                 .withDescription("Select metadata file")
-                .withFileFilter { it.extension == "zip" }
+                .withExtensionFilter("zip")
 
             val selectedZipFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
             val extractedZip = createTempDirectory("codeTransformSQLMetadata", null)
@@ -422,9 +432,65 @@ class CodeTransformChatController(
         }
         telemetry.submitSelection(message.oneOrMultipleDiffsSelection)
         codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection))
-        codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
+        codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent())
+        val sampleYAML = """
+name: "custom-dependency-management"
+description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
+
+dependencyManagement:
+  dependencies:
+    - identifier: "com.example:library1"
+      targetVersion: "2.1.0"
+      versionProperty: "library1.version"  # Optional
+      originType: "FIRST_PARTY" # or "THIRD_PARTY"  # Optional
+    - identifier: "com.example:library2"
+      targetVersion: "3.0.0"
+      originType: "THIRD_PARTY"
+  plugins:
+    - identifier: "com.example.plugin"
+      targetVersion: "1.2.0"
+      versionProperty: "plugin.version"  # Optional
+""".trimIndent()
+
+        val virtualFile = LightVirtualFile("sample-dependency-management.yaml", YAMLFileType.YML, sampleYAML)
+        virtualFile.isWritable = true
+        ApplicationManager.getApplication().invokeLater {
+            FileEditorManager.getInstance(context.project).openFile(virtualFile, true)
+        }
         codeModernizerManager.codeTransformationSession?.let {
             it.sessionContext.transformCapabilities = transformCapabilities
+        }
+    }
+
+    override suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) {
+        withContext(EDT) {
+            val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
+                .withDescription("Select .yaml file")
+                .withExtensionFilter("yaml")
+            val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
+            val isValid = validateYamlFile(selectedFile.readText())
+            if (!isValid) {
+                codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent())
+                codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
+                return@withContext
+            }
+            codeModernizerManager.codeTransformationSession?.let {
+                it.sessionContext.customDependencyVersionsFile = selectedFile
+            }
+            codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent())
+            codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
+            codeModernizerManager.codeTransformationSession?.let {
+                codeModernizerManager.runLocalMavenBuild(context.project, it)
+            }
+        }
+    }
+
+    override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) {
+        codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent())
+        // if user doesn't provide a custom .yaml file, just move on with local build
+        // TODO: potentially we want to ask user to provide target JDK path?
+        codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
+        codeModernizerManager.codeTransformationSession?.let {
             codeModernizerManager.runLocalMavenBuild(context.project, it)
         }
     }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
index 6629b8c2d34..e8c58ac552e 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
@@ -6,6 +6,7 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven
 import com.intellij.openapi.application.runInEdt
 import com.intellij.openapi.module.ModuleUtilCore
 import com.intellij.openapi.project.Project
+import com.intellij.openapi.projectRoots.ProjectJdkTable
 import com.intellij.openapi.roots.ModuleRootManager
 import com.intellij.openapi.roots.ProjectRootManager
 import com.intellij.openapi.vfs.LocalFileSystem
@@ -19,6 +20,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTele
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerSessionContext
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenCopyCommandsResult
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenDependencyReportCommandsResult
+import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.telemetry.CodeTransformBuildCommand
 import software.aws.toolkits.telemetry.Result
 import java.io.File
@@ -80,6 +82,11 @@ fun runMavenCopyCommands(
         val transformMvnRunner = TransformMavenRunner(project)
         context.mavenRunnerQueue.add(transformMvnRunner)
         val mvnSettings = MavenRunner.getInstance(project).settings.clone() // clone required to avoid editing user settings
+        notifyStickyInfo("current jreName", mvnSettings.jreName)
+        mvnSettings.setJreName("corretto-21")
+        // use ProjectJdkTable.getInstance().allJdks to join all of the "name"s of the list
+        val jreNames = ProjectJdkTable.getInstance().allJdks.joinToString(", ") { it.name }
+        notifyStickyInfo("jreNames", jreNames)
 
         val sourceVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(sourceFolder)
         val module = sourceVirtualFile?.let { ModuleUtilCore.findModuleForFile(it, project) }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
index 9a32e82aff5..b26fcbaeae2 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
@@ -20,8 +20,10 @@ enum class CodeTransformButtonId(val id: String) {
     SelectSQLMetadata("codetransform-input-select-sql-metadata"),
     SelectSQLModuleSchema("codetransform-input-select-sql-module-schema"),
     CancelTransformation("codetransform-input-cancel"),
+    ContinueTransformation("codetransform-input-continue"),
     ConfirmSkipTests("codetransform-input-confirm-skip-tests"),
     ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"),
+    ConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"),
     StopTransformation("stop_transform"),
     OpenTransformationHub("open_transformation_hub"),
     OpenMvnBuild("open_mvn_build"),
@@ -103,6 +105,10 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage {
         @JsonProperty("tabID") val tabId: String,
     ) : IncomingCodeTransformMessage
 
+    data class CodeTransformContinue(
+        @JsonProperty("tabID") val tabId: String,
+    ) : IncomingCodeTransformMessage
+
     data class CodeTransformConfirmSkipTests(
         @JsonProperty("tabID") val tabId: String,
         val skipTestsSelection: String,
@@ -113,6 +119,10 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage {
         val oneOrMultipleDiffsSelection: String,
     ) : IncomingCodeTransformMessage
 
+    data class CodeTransformConfirmCustomDependencyVersions(
+        @JsonProperty("tabID") val tabId: String,
+    ) : IncomingCodeTransformMessage
+
     data class CodeTransformOpenMvnBuild(
         @JsonProperty("tabID") val tabId: String,
     ) : IncomingCodeTransformMessage
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
index a0da0824a76..aed2867328d 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
@@ -74,6 +74,7 @@ data class CodeModernizerSessionContext(
     val sourceServerName: String? = null,
     var schema: String? = null,
     val sqlMetadataZip: File? = null,
+    var customDependencyVersionsFile: VirtualFile? = null,
 ) : Disposable {
     private val mapper = jacksonObjectMapper()
     private val ignoredDependencyFileExtensions = setOf(INVALID_SUFFIX_SHA, INVALID_SUFFIX_REPOSITORIES)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt
index 151187c165a..d5e1ea24962 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt
@@ -15,5 +15,6 @@ data class CustomerSelection(
     val targetVendor: String? = null,
     val sourceServerName: String? = null,
     val sqlMetadataZip: File? = null,
-    // note: schema and customBuildCommand are passed in to CodeModernizerSessionContext separately, *after* CodeModernizerSession is created
+    // note: schema / customBuildCommand / customDependencyVersionsFile are passed in to CodeModernizerSessionContext separately,
+    // *after* CodeModernizerSession is created
 )
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
index bba84915c2b..585bbb11877 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
@@ -8,6 +8,7 @@ import com.intellij.openapi.application.runReadAction
 import com.intellij.openapi.fileEditor.FileDocumentManager
 import com.intellij.openapi.util.io.FileUtil
 import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.readText
 import software.aws.toolkits.core.utils.createParentDirectories
 import software.aws.toolkits.core.utils.error
 import software.aws.toolkits.core.utils.exists
@@ -142,6 +143,17 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo
     return report
 }
 
+fun validateYamlFile(fileContents: String): Boolean {
+    val requiredKeys = listOf("dependencyManagement:", "identifier:", "targetVersion:")
+    for (key in requiredKeys) {
+        if (!fileContents.contains(key)) {
+            getLogger().error { "Missing yaml key: $key" }
+            return false
+        }
+    }
+    return true
+}
+
 fun validateSctMetadata(sctFile: File?): SqlMetadataValidationResult {
     if (sctFile == null) {
         return SqlMetadataValidationResult(false, message("codemodernizer.chat.message.validation.error.missing_sct_file"))
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index 948024cc99d..74416f5d4f5 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -28,6 +28,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransfo
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
 import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile
 import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
 import software.aws.toolkits.resources.message
 import java.util.concurrent.atomic.AtomicBoolean
@@ -240,6 +241,46 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
         assertThat(expected).isEqualTo(actual)
     }
 
+    @Test
+    fun `WHEN validateYamlFile on fully valid yaml file THEN passes validation`() {
+        val sampleFileContents = """name: "custom-dependency-management"
+description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
+dependencyManagement:
+  dependencies:
+    - identifier: "com.example:library1"
+        targetVersion: "2.1.0"
+        versionProperty: "library1.version"
+        originType: "FIRST_PARTY"
+  plugins:
+    - identifier: "com.example.plugin"
+        targetVersion: "1.2.0"
+        versionProperty: "plugin.version"
+        """.trimIndent()
+
+        val isValidYaml = validateYamlFile(sampleFileContents)
+        assertThat(isValidYaml).isTrue()
+    }
+
+    @Test
+    fun `WHEN validateYamlFile on invalid yaml file THEN fails validation`() {
+        val sampleFileContents = """name: "custom-dependency-management"
+description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
+invalidKey:
+  dependencies:
+    - identifier: "com.example:library1"
+        targetVersion: "2.1.0"
+        versionProperty: "library1.version"
+        originType: "FIRST_PARTY"
+  plugins:
+    - identifier: "com.example.plugin"
+        targetVersion: "1.2.0"
+        versionProperty: "plugin.version"
+        """.trimIndent()
+
+        val isValidYaml = validateYamlFile(sampleFileContents)
+        assertThat(isValidYaml).isFalse()
+    }
+
     @Test
     fun `WHEN validateMetadataFile on fully valid sct file THEN passes validation`() {
         val sampleFileContents = """
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
index 86ac9a3fe6f..00f759af458 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
@@ -280,7 +280,13 @@ export class CodeTransformChatConnector {
                 tabID,
                 tabType: 'codetransform',
             })
-        }  else if (action.id === FormButtonIds.CodeTransformInputSkipTests) {
+        } else if (action.id === FormButtonIds.CodeTransformInputContinue) {
+            this.sendMessageToExtension({
+                command: 'codetransform-continue',
+                tabID,
+                tabType: 'codetransform',
+            })
+        } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) {
             this.sendMessageToExtension({
                 command: 'codetransform-confirm-skip-tests',
                 tabID,
@@ -294,6 +300,12 @@ export class CodeTransformChatConnector {
                 tabType: 'codetransform',
                 oneOrMultipleDiffsSelection: action.formItemValues?.oneOrMultipleDiffsSelection
             })
+        } else if (action.id === FormButtonIds.CodeTransformInputCustomDependencyVersions) {
+            this.sendMessageToExtension({
+                command: 'codetransform-input-confirm-custom-dependency-versions',
+                tabID,
+                tabType: 'codetransform',
+            })
         } else if (action.id === FormButtonIds.OpenTransformationHub) {
             this.sendMessageToExtension({
                 command: 'codetransform-open-transform-hub',
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
index 5df19981b3f..01486f01f2a 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
@@ -36,8 +36,10 @@ type MessageCommand =
     | 'codetransform-select-sql-module-schema'
     | 'codetransform-cancel'
     | 'codetransform-stop'
+    | 'codetransform-continue'
     | 'codetransform-confirm-skip-tests'
     | 'codetransform-confirm-one-or-multiple-diffs'
+    | 'codetransform-input-confirm-custom-dependency-versions'
     | 'codetransform-new'
     | 'codetransform-open-transform-hub'
     | 'codetransform-open-mvn-build'
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
index e400e2a5541..22b913acf96 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
@@ -8,8 +8,10 @@ export const enum FormButtonIds {
   CodeTransformInputSQLMetadata = 'codetransform-input-select-sql-metadata',
   CodeTransformInputSQLModuleSchema = 'codetransform-input-select-sql-module-schema',
   CodeTransformInputCancel = 'codetransform-input-cancel',
+  CodeTransformInputContinue = 'codetransform-input-continue',
   CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests',
   CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs',
+  CodeTransformInputCustomDependencyVersions = 'codetransform-input-confirm-custom-dependency-versions',
   OpenMvnBuild = 'open_mvn_build',
   StopTransform = 'stop_transform',
   OpenTransformationHub = 'open_transformation_hub',
@@ -46,7 +48,9 @@ export const isFormButtonCodeTransform = (id: string): boolean => {
     id === FormButtonIds.CodeTransformInputSQLMetadata ||
     id === FormButtonIds.CodeTransformInputSQLModuleSchema ||
     id === FormButtonIds.CodeTransformInputSkipTests ||
+    id === FormButtonIds.CodeTransformInputContinue ||
     id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs ||
+    id === FormButtonIds.CodeTransformInputCustomDependencyVersions ||
     id === FormButtonIds.CodeTransformViewDiff ||
     id === FormButtonIds.CodeTransformViewSummary ||
     id === FormButtonIds.CodeTransformViewBuildLog ||
From 4a66e31c7eca3e753a0e701bdd4ce7aee647dd8e Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Wed, 16 Apr 2025 11:18:19 -0700
Subject: [PATCH 02/16] rest of CSB
---
 .../META-INF/codetransform-ext-java.xml       |   2 +-
 .../codemodernizer/ArtifactHandler.kt         |  26 +---
 .../codemodernizer/CodeModernizerManager.kt   |   2 +-
 .../codemodernizer/CodeModernizerSession.kt   |  23 ++--
 .../codemodernizer/CodeTransformChatApp.kt    |   3 +
 .../InboundAppMessagesHandler.kt              |   2 +
 .../codemodernizer/client/GumbyClient.kt      |  11 +-
 .../constants/CodeTransformChatItems.kt       |  26 +++-
 .../controller/CodeTransformChatController.kt | 101 +++++++++-----
 .../ideMaven/MavenRunnerUtils.kt              |  69 ++++++++--
 .../ideMaven/TransformMavenRunner.kt          |  28 ++--
 .../ideMaven/TransformRunnable.kt             |   2 +-
 .../messages/CodeTransformMessage.kt          |   5 +
 .../BuildProgressTimelineStepDetailsList.kt   |   2 +-
 .../model/CodeModernizerSessionContext.kt     |  18 ++-
 .../model/CodeTransformConversationState.kt   |  10 ++
 .../codemodernizer/model/ZipManifest.kt       |   3 +-
 .../panels/BuildProgressStepDetailsPanel.kt   |   2 +-
 .../codemodernizer/session/Session.kt         |   3 +
 .../utils/CodeTransformApiUtils.kt            | 129 ++++++++++++++++++
 .../utils/CodeTransformFileUtils.kt           |  56 +++++++-
 .../utils/CodeTransformUtils.kt               |  21 +++
 .../CodeWhispererCodeModernizerTest.kt        |  44 +++++-
 .../CodeWhispererCodeModernizerTestBase.kt    |   1 -
 .../CodeWhispererCodeModernizerUtilsTest.kt   | 100 ++++++++++++++
 .../ui/apps/codeTransformChatConnector.ts     |   8 +-
 .../mynah-ui/src/mynah-ui/ui/commands.ts      |   1 +
 .../src/mynah-ui/ui/forms/constants.ts        |   2 +
 .../resources/MessagesBundle.properties       |   3 +-
 29 files changed, 589 insertions(+), 114 deletions(-)
 create mode 100644 plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt
diff --git a/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml b/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml
index 614c5e18b10..9a4bb0e5d25 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml
+++ b/plugins/amazonq/codetransform/jetbrains-community/resources/META-INF/codetransform-ext-java.xml
@@ -18,7 +18,7 @@
         
         
+                    icon="AllIcons.Actions.Properties"/>
         
         
     
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt
index 93d3da48e7e..6623f19ffa9 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt
@@ -50,13 +50,13 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.state.CodeModerni
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getPathToHilArtifactDir
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isValidCodeTransformConnection
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.openTroubleshootingGuideNotificationAction
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.zipToPath
 import software.aws.toolkits.jetbrains.utils.notifyInfo
 import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
 import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.CodeTransformArtifactType
 import java.io.File
-import java.nio.file.Files
 import java.nio.file.Path
 import java.time.Instant
 import java.util.concurrent.atomic.AtomicBoolean
@@ -112,32 +112,12 @@ class ArtifactHandler(
         }
     }
 
-    suspend fun unzipToPath(byteArrayList: List, outputDirPath: Path? = null): Pair {
-        val zipFilePath = withContext(getCoroutineBgContext()) {
-            if (outputDirPath == null) {
-                Files.createTempFile(null, ".zip")
-            } else {
-                Files.createTempFile(outputDirPath, null, ".zip")
-            }
-        }
-        var totalDownloadBytes = 0
-        withContext(getCoroutineBgContext()) {
-            Files.newOutputStream(zipFilePath).use {
-                for (bytes in byteArrayList) {
-                    it.write(bytes)
-                    totalDownloadBytes += bytes.size
-                }
-            }
-        }
-        return zipFilePath to totalDownloadBytes
-    }
-
     suspend fun downloadHilArtifact(jobId: JobId, artifactId: String, tmpDir: File): CodeTransformHilDownloadArtifact? {
         val downloadResultsResponse = clientAdaptor.downloadExportResultArchive(jobId, artifactId)
 
         return try {
             val tmpPath = tmpDir.toPath()
-            val (downloadZipFilePath, _) = unzipToPath(downloadResultsResponse, tmpPath)
+            val (downloadZipFilePath, _) = zipToPath(downloadResultsResponse, tmpPath)
             LOG.info { "Successfully converted the hil artifact download to a zip at ${downloadZipFilePath.toAbsolutePath()}." }
             CodeTransformHilDownloadArtifact.create(downloadZipFilePath, getPathToHilArtifactDir(tmpPath))
         } catch (e: Exception) {
@@ -211,7 +191,7 @@ class ArtifactHandler(
             val totalDownloadBytes: Int
             val zipPath: String
             try {
-                val result = unzipToPath(downloadResultsResponse)
+                val result = zipToPath(downloadResultsResponse)
                 path = result.first
                 totalDownloadBytes = result.second
                 zipPath = path.toAbsolutePath().toString()
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt
index 9b2db462a41..77b95e0e255 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerManager.kt
@@ -909,7 +909,7 @@ class CodeModernizerManager(private val project: Project) : PersistentStateCompo
                 // Add delay between upload complete and trying to resume
                 delay(500)
 
-                codeTransformationSession?.resumeTransformFromHil()
+                codeTransformationSession?.resumeTransformation()
             } else {
                 throw CodeModernizerException("Cannot create dependency zip for HIL")
             }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
index 921a9ac0f2c..828b36d7db8 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
@@ -20,6 +20,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdateStatus
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUserActionStatus
+import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
 import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType
 import software.amazon.awssdk.services.ssooidc.model.SsoOidcException
 import software.aws.toolkits.core.utils.Waiters.waitUntil
@@ -174,6 +175,7 @@ class CodeModernizerSession(
             }
             // for language upgrades, copyResult should always be Successful here, failure cases already handled
             val result = sessionContext.createZipWithModuleFiles(copyResult)
+            sessionContext.originalUploadZipPath = result.payload.toPath()
 
             if (result is ZipCreationResult.Missing1P) {
                 telemetryErrorMessage = "Missing 1p dependencies"
@@ -283,9 +285,7 @@ class CodeModernizerSession(
             return CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER(e.localizedMessage))
         } finally {
             telemetry.uploadProject(payloadSize, startTime, true, telemetryErrorMessage)
-            if (payload != null) {
-                deleteUploadArtifact(payload)
-            }
+            // do not delete upload ZIP; re-used for client-side build
         }
 
         // Send upload completion message to chat (only if successful)
@@ -309,12 +309,6 @@ class CodeModernizerSession(
         }
     }
 
-    internal fun deleteUploadArtifact(payload: File) {
-        if (!payload.delete()) {
-            LOG.warn { "Unable to delete upload artifact." }
-        }
-    }
-
     private fun startJob(uploadId: String): StartTransformationResponse {
         val sourceLanguage = sessionContext.sourceJavaVersion.name.toTransformationLanguage()
         val targetLanguage = sessionContext.targetJavaVersion.name.toTransformationLanguage()
@@ -341,9 +335,10 @@ class CodeModernizerSession(
      */
     fun resumeJob(startTime: Instant, jobId: JobId) = state.putJobHistory(sessionContext, TransformationStatus.STARTED, jobId.id, startTime)
 
-    fun resumeTransformFromHil() {
+    fun resumeTransformation() {
         val clientAdaptor = GumbyClient.getInstance(sessionContext.project)
         clientAdaptor.resumeCodeTransformation(state.currentJobId as JobId, TransformationUserActionStatus.COMPLETED)
+        getLogger().info("Successfully resumed transformation with status of COMPLETED")
     }
 
     fun rejectHilAndContinue(): ResumeTransformationResponse {
@@ -390,7 +385,7 @@ class CodeModernizerSession(
     /**
      * Adapted from [CodeWhispererCodeScanSession]
      */
-    suspend fun uploadPayload(payload: File): String {
+    suspend fun uploadPayload(payload: File, uploadContext: UploadContext? = null): String {
         val sha256checksum: String = Base64.getEncoder().encodeToString(
             withContext(getCoroutineBgContext()) {
                 DigestUtils.sha256(FileInputStream(payload))
@@ -400,7 +395,7 @@ class CodeModernizerSession(
             throw AlreadyDisposedException("Disposed when about to create upload URL")
         }
         val clientAdaptor = GumbyClient.getInstance(sessionContext.project)
-        val createUploadUrlResponse = clientAdaptor.createGumbyUploadUrl(sha256checksum)
+        val createUploadUrlResponse = clientAdaptor.createGumbyUploadUrl(sha256checksum, uploadContext)
 
         LOG.info {
             "Uploading project artifact at ${payload.path} with checksum $sha256checksum using uploadId: ${
@@ -428,9 +423,9 @@ class CodeModernizerSession(
                 createUploadUrlResponse.kmsKeyArn().orEmpty(),
             ) { shouldStop.get() }
         }
-        LOG.info { "Upload to S3 succeeded" }
+        LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of ${uploadContext.toString()}" }
         if (!shouldStop.get()) {
-            LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())}ms" }
+            LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())} ms" }
         }
         return createUploadUrlResponse.uploadId()
     }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
index 584a3424607..c7c51457d50 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
@@ -46,6 +46,7 @@ private enum class CodeTransformMessageTypes(val type: String) {
     CodeTransformStop("codetransform-stop"),
     CodeTransformCancel("codetransform-cancel"),
     CodeTransformContinue("codetransform-continue"),
+    CodeTransformAgree("codetransform-agree"),
     CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"),
     CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"),
     CodeTransformNew("codetransform-new"),
@@ -81,6 +82,7 @@ class CodeTransformChatApp : AmazonQApp {
             CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class,
             CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class,
             CodeTransformMessageTypes.CodeTransformContinue.type to IncomingCodeTransformMessage.CodeTransformContinue::class,
+            CodeTransformMessageTypes.CodeTransformAgree.type to IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild::class,
             CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class,
             CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class,
             CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class,
@@ -194,6 +196,7 @@ class CodeTransformChatApp : AmazonQApp {
             is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message)
             is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message)
             is IncomingCodeTransformMessage.CodeTransformContinue -> inboundAppMessagesHandler.processCodeTransformContinueAction(message)
+            is IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild -> inboundAppMessagesHandler.processCodeTransformAgreeToLocalBuild(message)
             is IncomingCodeTransformMessage.CodeTransformNew -> inboundAppMessagesHandler.processCodeTransformNewAction(message)
             is IncomingCodeTransformMessage.CodeTransformOpenTransformHub -> inboundAppMessagesHandler.processCodeTransformOpenTransformHub(message)
             is IncomingCodeTransformMessage.CodeTransformOpenMvnBuild -> inboundAppMessagesHandler.processCodeTransformOpenMvnBuild(message)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
index 434516178bd..208a8ad67d3 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
@@ -13,6 +13,8 @@ interface InboundAppMessagesHandler {
 
     suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue)
 
+    suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild)
+
     suspend fun processCodeTransformStartAction(message: IncomingCodeTransformMessage.CodeTransformStart)
 
     suspend fun processCodeTransformSelectSQLMetadataAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt
index 6134e69ca22..f94e25d166f 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/client/GumbyClient.kt
@@ -61,12 +61,13 @@ class GumbyClient(private val project: Project) {
     private val amazonQStreamingClient
         get() = AmazonQStreamingClient.getInstance(project)
 
-    fun createGumbyUploadUrl(sha256Checksum: String): CreateUploadUrlResponse {
+    fun createGumbyUploadUrl(sha256Checksum: String, context: UploadContext? = null): CreateUploadUrlResponse {
         val request = CreateUploadUrlRequest.builder()
             .contentChecksumType(ContentChecksumType.SHA_256)
             .contentChecksum(sha256Checksum)
             .uploadIntent(UploadIntent.TRANSFORMATION)
             .profileArn(QRegionProfileManager.getInstance().activeProfile(project)?.arn)
+            .uploadContext(context)
             .build()
         return callApi({ bearerClient().createUploadUrl(request) }, apiName = "CreateUploadUrl")
     }
@@ -164,12 +165,12 @@ class GumbyClient(private val project: Project) {
 
     suspend fun downloadExportResultArchive(
         jobId: JobId,
-        hilDownloadArtifactId: String? = null,
+        downloadArtifactId: String? = null,
         downloadArtifactType: TransformationDownloadArtifactType? = TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS,
     ): MutableList = amazonQStreamingClient.exportResultArchive(
         jobId.id,
         ExportIntent.TRANSFORMATION,
-        if (hilDownloadArtifactId == null) {
+        if (downloadArtifactId == null) {
             null
         } else {
             ExportContext
@@ -177,14 +178,14 @@ class GumbyClient(private val project: Project) {
                 .transformationExportContext(
                     TransformationExportContext
                         .builder()
-                        .downloadArtifactId(hilDownloadArtifactId)
+                        .downloadArtifactId(downloadArtifactId)
                         .downloadArtifactType(downloadArtifactType.toString())
                         .build()
                 )
                 .build()
         },
         { e ->
-            LOG.error(e) { "ExportResultArchive failed: ${e.message}" }
+            LOG.error(e) { "ExportResultArchive on job ${jobId.id} and artifact $downloadArtifactId failed: ${e.message}" }
         },
         { startTime ->
             LOG.info { "ExportResultArchive latency: ${calculateTotalLatency(startTime, Instant.now())}" }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index a68e81cef23..b408bcff53a 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -52,6 +52,14 @@ private val continueTransformationButton = Button(
     id = CodeTransformButtonId.ContinueTransformation.id,
 )
 
+// used to agree to local build
+private val agreeToLocalBuildButton = Button(
+    keepCardAfterClick = false,
+    waitMandatoryFormItems = false,
+    text = "Agree",
+    id = CodeTransformButtonId.AgreeToLocalBuild.id,
+)
+
 private val confirmUserSelectionLanguageUpgradeButton = Button(
     keepCardAfterClick = false,
     waitMandatoryFormItems = true,
@@ -282,11 +290,20 @@ fun buildChooseTransformationObjectiveChatContent() = CodeTransformChatMessageCo
     type = CodeTransformChatMessageType.FinalizedAnswer,
 )
 
-fun buildObjectiveChosenChatContent(objective: String) = CodeTransformChatMessageContent(
-    message = objective,
+fun buildUserReplyChatContent(reply: String) = CodeTransformChatMessageContent(
+    message = reply,
     type = CodeTransformChatMessageType.Prompt,
 )
 
+fun buildPermissionToBuildChatContent() = CodeTransformChatMessageContent(
+    message = message("codemodernizer.chat.message.permission_to_build"),
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+    buttons = listOf(
+        cancelUserSelectionButton,
+        agreeToLocalBuildButton
+    )
+)
+
 fun buildCheckingValidProjectChatContent() = CodeTransformChatMessageContent(
     message = message("codemodernizer.chat.message.validation.check_eligible_modules"),
     type = CodeTransformChatMessageType.PendingAnswer,
@@ -399,6 +416,11 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa
     type = CodeTransformChatMessageType.FinalizedAnswer,
 )
 
+fun buildPromptTargetJDKPathChatContent(prompt: String) = CodeTransformChatMessageContent(
+    message = prompt,
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+)
+
 fun buildCustomDependencyVersionsFileValidChatContent() = CodeTransformChatMessageContent(
     message = "I received your .yaml file and will upload it to Q.",
     type = CodeTransformChatMessageType.FinalizedAnswer,
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index 322f745a8fb..d6a8b6ac958 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -57,7 +57,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHi
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildLanguageUpgradeProjectValidChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormIntroChatContent
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildObjectiveChosenChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectInvalidChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationErrorChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationSuccessDetailsChatContent
@@ -125,6 +125,13 @@ import com.intellij.openapi.application.ApplicationManager
 import com.intellij.openapi.fileEditor.FileEditorManager
 import com.intellij.testFramework.LightVirtualFile
 import org.jetbrains.yaml.YAMLFileType
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPermissionToBuildChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKPathChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt
+import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
 
@@ -140,9 +147,16 @@ class CodeTransformChatController(
     private val telemetry = CodeTransformTelemetryManager.getInstance(context.project)
 
     override suspend fun processChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) {
+        if (chatSessionStorage.getSession(message.tabId).conversationState == CodeTransformConversationState.PROMPT_TARGET_JDK_PATH) {
+            // we are prompting user for target JDK path
+            processJDKPathChatPromptMessage(message)
+            return
+        }
+
+        // otherwise, we are asking for transformation objective
         val objective = message.message.trim().lowercase()
 
-        codeTransformChatHelper.addNewMessage(buildObjectiveChosenChatContent(objective))
+        codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(objective))
         codeTransformChatHelper.sendChatInputEnabledMessage(message.tabId, false)
         codeTransformChatHelper.sendUpdatePlaceholderMessage(message.tabId, "Open a new tab to chat with Q")
 
@@ -196,6 +210,7 @@ class CodeTransformChatController(
     }
 
     private suspend fun getUserObjective(tabId: String) {
+        chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_OBJECTIVE
         codeTransformChatHelper.addNewMessage(buildChooseTransformationObjectiveChatContent())
         codeTransformChatHelper.sendChatInputEnabledMessage(tabId, true)
         codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, message("codemodernizer.chat.message.choose_objective_placeholder"))
@@ -424,14 +439,52 @@ class CodeTransformChatController(
         val transformCapabilities = when (message.oneOrMultipleDiffsSelection) {
             message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs") -> listOf(
                 EXPLAINABILITY_V1,
+                CLIENT_SIDE_BUILD,
                 SELECTIVE_TRANSFORMATION_V1
             )
             else -> listOf(
-                EXPLAINABILITY_V1
+                EXPLAINABILITY_V1,
+                CLIENT_SIDE_BUILD
             )
         }
         telemetry.submitSelection(message.oneOrMultipleDiffsSelection)
         codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection))
+        codeModernizerManager.codeTransformationSession?.let {
+            it.sessionContext.transformCapabilities = transformCapabilities
+        }
+        promptForTargetJdkPath(message.tabId)
+        // TODO: when custom 1P upgrades ready, delete line above and uncomment line below
+        // promptForCustomYamlFile()
+    }
+
+    override suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) {
+        withContext(EDT) {
+            val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
+                .withDescription("Select .yaml file")
+                .withExtensionFilter("yaml")
+            val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
+            val isValid = validateYamlFile(selectedFile.readText())
+            if (!isValid) {
+                codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent())
+                codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
+                return@withContext
+            }
+            codeModernizerManager.codeTransformationSession?.let {
+                it.sessionContext.customDependencyVersionsFile = selectedFile
+            }
+            codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent())
+            promptForTargetJdkPath(message.tabId)
+        }
+    }
+
+    private suspend fun processJDKPathChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) {
+        codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkPath = message.message.trim()
+        codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(message.message.trim()))
+        codeTransformChatHelper.addNewMessage(buildPermissionToBuildChatContent())
+    }
+
+    /*
+    private suspend fun promptForCustomYamlFile() {
         codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent())
         val sampleYAML = """
 name: "custom-dependency-management"
@@ -457,44 +510,30 @@ dependencyManagement:
         ApplicationManager.getApplication().invokeLater {
             FileEditorManager.getInstance(context.project).openFile(virtualFile, true)
         }
-        codeModernizerManager.codeTransformationSession?.let {
-            it.sessionContext.transformCapabilities = transformCapabilities
-        }
-    }
-
-    override suspend fun processCodeTransformCustomDependencyVersions(message: IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions) {
-        withContext(EDT) {
-            val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
-                .withDescription("Select .yaml file")
-                .withExtensionFilter("yaml")
-            val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
-            val isValid = validateYamlFile(selectedFile.readText())
-            if (!isValid) {
-                codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent())
-                codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
-                return@withContext
-            }
-            codeModernizerManager.codeTransformationSession?.let {
-                it.sessionContext.customDependencyVersionsFile = selectedFile
-            }
-            codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent())
-            codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
-            codeModernizerManager.codeTransformationSession?.let {
-                codeModernizerManager.runLocalMavenBuild(context.project, it)
-            }
-        }
     }
+    */
 
     override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) {
         codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent())
-        // if user doesn't provide a custom .yaml file, just move on with local build
-        // TODO: potentially we want to ask user to provide target JDK path?
+        promptForTargetJdkPath(message.tabId)
+    }
+
+    override suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild) {
         codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
         codeModernizerManager.codeTransformationSession?.let {
             codeModernizerManager.runLocalMavenBuild(context.project, it)
         }
     }
 
+    private suspend fun promptForTargetJdkPath(tabId: String) {
+        chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_PATH
+        val targetJdk = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty()
+        val javaHomePrompt = createJavaHomePrompt(targetJdk)
+        codeTransformChatHelper.addNewMessage(buildPromptTargetJDKPathChatContent(javaHomePrompt))
+        codeTransformChatHelper.sendChatInputEnabledMessage(tabId, true)
+        codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, "Enter the path to your Java installation")
+    }
+
     private fun getSourceJdk(moduleConfigurationFile: VirtualFile): JavaSdkVersion {
         // this should never throw the RuntimeException since invalid JDK case is already handled in previous validation step
         val moduleJdkVersion = ModuleUtil.findModuleForFile(moduleConfigurationFile, context.project)?.tryGetJdk(context.project)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
index e8c58ac552e..7ddf17d2082 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
@@ -4,29 +4,52 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven
 
 import com.intellij.openapi.application.runInEdt
+import com.intellij.openapi.fileEditor.FileEditorManager
 import com.intellij.openapi.module.ModuleUtilCore
 import com.intellij.openapi.project.Project
-import com.intellij.openapi.projectRoots.ProjectJdkTable
 import com.intellij.openapi.roots.ModuleRootManager
 import com.intellij.openapi.roots.ProjectRootManager
 import com.intellij.openapi.vfs.LocalFileSystem
+import com.intellij.openapi.vfs.VirtualFile
 import org.jetbrains.idea.maven.execution.MavenRunner
 import org.jetbrains.idea.maven.execution.MavenRunnerParameters
 import org.jetbrains.idea.maven.execution.MavenRunnerSettings
 import org.slf4j.Logger
 import software.aws.toolkits.core.utils.error
 import software.aws.toolkits.core.utils.info
+import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerSessionContext
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.MAVEN_BUILD_RUN_UNIT_TESTS
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenCopyCommandsResult
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.MavenDependencyReportCommandsResult
-import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.telemetry.CodeTransformBuildCommand
 import software.aws.toolkits.telemetry.Result
 import java.io.File
 import java.nio.file.Files
 import java.nio.file.Path
 
+fun runClientSideBuild(targetDir: VirtualFile, logger: Logger, project: Project): Pair {
+    // run mvn test-compile or mvn test
+    val transformMvnRunner = TransformMavenRunner(project)
+    val mvnSettings = MavenRunner.getInstance(project).settings.clone()
+    val buildRunnable = runClientSideBuild(targetDir, mvnSettings, transformMvnRunner, logger, project)
+    buildRunnable.await()
+    // write build output to a new text file and open it
+    val buildLogOutput = buildRunnable.getOutput().toString()
+    // first line is a long Maven String showing the build command; not useful or needed
+    val outputWithoutFirstLine = buildLogOutput.lines().drop(1).joinToString("\n")
+    val buildLogOutputFile = Files.createTempFile("build-logs-", ".txt")
+    Files.write(buildLogOutputFile, outputWithoutFirstLine.toByteArray())
+    val buildLogOutputVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(buildLogOutputFile.toFile())
+    runInEdt {
+        if (buildLogOutputVirtualFile != null) {
+            FileEditorManager.getInstance(project).openFile(buildLogOutputVirtualFile, true)
+        }
+    }
+    return buildRunnable.exitCode to buildRunnable.getOutput().toString()
+}
+
 fun runHilMavenCopyDependency(
     context: CodeModernizerSessionContext,
     sourceFolder: File,
@@ -82,12 +105,6 @@ fun runMavenCopyCommands(
         val transformMvnRunner = TransformMavenRunner(project)
         context.mavenRunnerQueue.add(transformMvnRunner)
         val mvnSettings = MavenRunner.getInstance(project).settings.clone() // clone required to avoid editing user settings
-        notifyStickyInfo("current jreName", mvnSettings.jreName)
-        mvnSettings.setJreName("corretto-21")
-        // use ProjectJdkTable.getInstance().allJdks to join all of the "name"s of the list
-        val jreNames = ProjectJdkTable.getInstance().allJdks.joinToString(", ") { it.name }
-        notifyStickyInfo("jreNames", jreNames)
-
         val sourceVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(sourceFolder)
         val module = sourceVirtualFile?.let { ModuleUtilCore.findModuleForFile(it, project) }
         val moduleSdk = module?.let { ModuleRootManager.getInstance(it).sdk }
@@ -198,6 +215,36 @@ private fun runMavenCopyDependencies(
     return copyTransformRunnable
 }
 
+private fun runClientSideBuild(
+    targetDir: VirtualFile,
+    mvnSettings: MavenRunnerSettings,
+    transformMavenRunner: TransformMavenRunner,
+    logger: Logger,
+    project: Project
+): TransformRunnable {
+    val customBuildCommand = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.customBuildCommand
+    val clientSideBuildCommand = if (customBuildCommand == MAVEN_BUILD_RUN_UNIT_TESTS) "test" else "test-compile"
+    val buildParams = MavenRunnerParameters(
+        false,
+        targetDir.path,
+        null,
+        listOf(clientSideBuildCommand),
+        null,
+        null
+    )
+    val buildTransformRunnable = TransformRunnable()
+    runInEdt {
+        try {
+            CodeModernizerManager.getInstance(project).getMvnBuildWindow().show()
+            transformMavenRunner.run(buildParams, mvnSettings, buildTransformRunnable, true)
+        } catch (t: Throwable) {
+            logger.error(t) { "Maven Build: Unexpected error when executing bundled Maven $clientSideBuildCommand" }
+            buildTransformRunnable.setExitCode(Integer.MIN_VALUE) // to stop looking for the exitCode
+        }
+    }
+    return buildTransformRunnable
+}
+
 private fun runMavenClean(
     sourceFolder: File,
     buildlogBuilder: StringBuilder,
@@ -212,7 +259,7 @@ private fun runMavenClean(
         sourceFolder.absolutePath,
         null,
         listOf("-Dmaven.repo.local=$destinationDir", "clean"),
-        emptyList(),
+        null,
         null
     )
     val cleanTransformRunnable = TransformRunnable()
@@ -248,7 +295,7 @@ private fun runMavenInstall(
         sourceFolder.absolutePath,
         null,
         flags,
-        emptyList(),
+        null,
         null
     )
     val installTransformRunnable = TransformRunnable()
@@ -284,7 +331,7 @@ private fun runMavenDependencyUpdatesReport(
         sourceFolder.absolutePath,
         null,
         dependencyUpdatesReportCommandList,
-        emptyList(),
+        null,
         null
     )
     val dependencyUpdatesReportRunnable = TransformRunnable()
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt
index a68c659ba6f..f071a071835 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt
@@ -6,7 +6,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
 import com.intellij.execution.process.ProcessHandler
-import com.intellij.execution.process.ProcessOutputTypes
 import com.intellij.execution.runners.ProgramRunner
 import com.intellij.execution.ui.RunContentDescriptor
 import com.intellij.openapi.fileEditor.FileDocumentManager
@@ -15,17 +14,28 @@ import com.intellij.openapi.util.Key
 import org.jetbrains.idea.maven.execution.MavenRunConfigurationType
 import org.jetbrains.idea.maven.execution.MavenRunnerParameters
 import org.jetbrains.idea.maven.execution.MavenRunnerSettings
+import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
+import com.intellij.openapi.projectRoots.ProjectJdkTable
 
 class TransformMavenRunner(val project: Project) {
     private var handler: ProcessHandler? = null
+    fun run(parameters: MavenRunnerParameters, settings: MavenRunnerSettings, onComplete: TransformRunnable, isClientSideBuild: Boolean = false) {
+        if (isClientSideBuild) {
+            // TODO: if we go with this implementation 1) consult UX and
+            // 2) run this check much sooner in chat with an appropriate error message if JDK is not found
+            val targetJdkPath = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.targetJdkPath
+                ?: throw RuntimeException("No target JDK path provided by user; cannot run client-side build")
+            val jdkTable = ProjectJdkTable.getInstance()
+            val targetJdkName = jdkTable.allJdks.find { it.homePath == targetJdkPath }?.name
+                ?: throw RuntimeException("Could not find user's target JDK; cannot run client-side build")
+            settings.setJreName(targetJdkName)
+        }
 
-    fun run(parameters: MavenRunnerParameters, settings: MavenRunnerSettings, onComplete: TransformRunnable) {
         FileDocumentManager.getInstance().saveAllDocuments()
         val callback = ProgramRunner.Callback { descriptor: RunContentDescriptor ->
             val handler = descriptor.processHandler
             this.handler = handler
             if (handler == null) {
-                // add log error here
                 onComplete.setExitCode(-1)
                 return@Callback
             }
@@ -33,13 +43,9 @@ class TransformMavenRunner(val project: Project) {
                 var output: String = ""
 
                 override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) {
-                    when (outputType) {
-                        ProcessOutputTypes.STDOUT -> {
-                            output += event.text
-                        }
-                        ProcessOutputTypes.STDERR -> {
-                            output += event.text
-                        }
+                    // IntelliJ includes some unneeded lines in stdout; exclude those from build logs
+                    if (!event.text.startsWith("[IJ]")) {
+                        output += event.text
                     }
                 }
 
@@ -49,8 +55,6 @@ class TransformMavenRunner(val project: Project) {
                 }
             })
         }
-        // Change runner from IntelliJ controlled to Maven controlled
-        // Setting isDelegateBuild = true  allows us to set the JRE used by Maven during runtime
         MavenRunConfigurationType.runConfiguration(project, parameters, null, settings, callback, false)
     }
 
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt
index c4ab0e6fc44..7741306cb7c 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt
@@ -4,7 +4,7 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven
 
 class TransformRunnable : Runnable {
-    private var exitCode: Int? = null
+    var exitCode: Int? = null
     private var output: String? = null
 
     fun setExitCode(i: Int) {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
index b26fcbaeae2..3e64f8b7442 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
@@ -21,6 +21,7 @@ enum class CodeTransformButtonId(val id: String) {
     SelectSQLModuleSchema("codetransform-input-select-sql-module-schema"),
     CancelTransformation("codetransform-input-cancel"),
     ContinueTransformation("codetransform-input-continue"),
+    AgreeToLocalBuild("codetransform-input-agree"),
     ConfirmSkipTests("codetransform-input-confirm-skip-tests"),
     ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"),
     ConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"),
@@ -109,6 +110,10 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage {
         @JsonProperty("tabID") val tabId: String,
     ) : IncomingCodeTransformMessage
 
+    data class CodeTransformAgreeToLocalBuild(
+        @JsonProperty("tabID") val tabId: String,
+    ) : IncomingCodeTransformMessage
+
     data class CodeTransformConfirmSkipTests(
         @JsonProperty("tabID") val tabId: String,
         val skipTestsSelection: String,
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt
index 77f15eea0c3..1409559b139 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/BuildProgressTimelineStepDetailsList.kt
@@ -25,7 +25,7 @@ fun getTransformationProgressStepsByTransformationStepId(
             if (progressStep != null) {
                 val itemToAdd = BuildProgressTimelineStepDetailItem(
                     progressStep.name(),
-                    progressStep.description(),
+                    progressStep.description().orEmpty(),
                     mapTransformationPlanApiStatus(progressStep.status()),
                     progressStep.startTime()?.toString(),
                     progressStep.endTime()?.toString()
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
index aed2867328d..288c20a4a50 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
@@ -46,9 +46,11 @@ const val MANIFEST_PATH = "manifest.json"
 const val ZIP_SOURCES_PATH = "sources"
 const val ZIP_DEPENDENCIES_PATH = "dependencies"
 const val BUILD_LOG_PATH = "build-logs.txt"
+const val CUSTOM_DEPENDENCY_VERSIONS_FILE_PATH = "custom-upgrades.yaml"
 const val UPLOAD_ZIP_MANIFEST_VERSION = "1.0"
 const val HIL_1P_UPGRADE_CAPABILITY = "HIL_1pDependency_VersionUpgrade"
 const val EXPLAINABILITY_V1 = "EXPLAINABILITY_V1"
+const val CLIENT_SIDE_BUILD = "CLIENT_SIDE_BUILD"
 const val MAVEN_CONFIGURATION_FILE_NAME = "pom.xml"
 const val MAVEN_BUILD_RUN_UNIT_TESTS = "clean test"
 const val MAVEN_BUILD_SKIP_UNIT_TESTS = "clean test-compile"
@@ -67,7 +69,7 @@ data class CodeModernizerSessionContext(
     var configurationFile: VirtualFile? = null, // used to ZIP module
     val sourceJavaVersion: JavaSdkVersion, // always needed for startJob API
     val targetJavaVersion: JavaSdkVersion, // 17 or 21
-    var transformCapabilities: List = listOf(EXPLAINABILITY_V1),
+    var transformCapabilities: List = listOf(),
     var customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS, // run unit tests by default
     val sourceVendor: String = ORACLE_DB, // only one supported
     val targetVendor: String? = null,
@@ -75,6 +77,8 @@ data class CodeModernizerSessionContext(
     var schema: String? = null,
     val sqlMetadataZip: File? = null,
     var customDependencyVersionsFile: VirtualFile? = null,
+    var targetJdkPath: String? = null,
+    var originalUploadZipPath: Path? = null
 ) : Disposable {
     private val mapper = jacksonObjectMapper()
     private val ignoredDependencyFileExtensions = setOf(INVALID_SUFFIX_SHA, INVALID_SUFFIX_REPOSITORIES)
@@ -269,7 +273,15 @@ data class CodeModernizerSessionContext(
 
                     LOG.info { "Dependency files size = ${dependencyFiles.sumOf { it.length().toInt() }}" }
 
-                    // 3) Sources
+                    // 3) Custom YAML file
+                    // TODO: where to put this? VS Code puts it in custom-upgrades/dependency-versions.yaml; here we put it at the root
+                    if (customDependencyVersionsFile != null) {
+                        customDependencyVersionsFile?.inputStream?.use {
+                            zip.putNextEntry(Path(CUSTOM_DEPENDENCY_VERSIONS_FILE_PATH).toString(), it)
+                        }
+                    }
+
+                    // 4) Sources
                     files?.forEach { file ->
                         val relativePath = File(file.path).relativeTo(sourceFolder)
                         val paddedPath = zipSources.resolve(relativePath)
@@ -290,7 +302,7 @@ data class CodeModernizerSessionContext(
 
                     LOG.info { "Source code files size = ${files?.sumOf { it.length.toInt() }}" }
 
-                    // 4) Build Log
+                    // 5) Initial Maven copy-deps / install build log
                     buildLogBuilder.toString().byteInputStream().use {
                         zip.putNextEntry(Path(BUILD_LOG_PATH).toString(), it)
                     }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt
new file mode 100644
index 00000000000..467c7c5b289
--- /dev/null
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt
@@ -0,0 +1,10 @@
+// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package software.aws.toolkits.jetbrains.services.codemodernizer.model
+
+enum class CodeTransformConversationState {
+    PROMPT_OBJECTIVE,
+    PROMPT_TARGET_JDK_PATH,
+    IDLE,
+}
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt
index 9267de9ddb9..e5bb80ad77a 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt
@@ -3,13 +3,14 @@
 
 package software.aws.toolkits.jetbrains.services.codemodernizer.model
 
+// TODO: include custom yaml file path in manifest.json?
 data class ZipManifest(
     val sourcesRoot: String = ZIP_SOURCES_PATH,
     val dependenciesRoot: String = ZIP_DEPENDENCIES_PATH,
     val buildLogs: String = BUILD_LOG_PATH,
     val version: String = UPLOAD_ZIP_MANIFEST_VERSION,
     val hilCapabilities: List = listOf(HIL_1P_UPGRADE_CAPABILITY),
-    val transformCapabilities: List = listOf(EXPLAINABILITY_V1),
+    val transformCapabilities: List = listOf(EXPLAINABILITY_V1, CLIENT_SIDE_BUILD),
     val customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS,
     val requestedConversions: RequestedConversions? = null, // only used for SQL conversions for now
 )
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt
index 28bd980c1aa..0f60b3ceb23 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/panels/BuildProgressStepDetailsPanel.kt
@@ -72,7 +72,7 @@ class BuildProgressStepDetailsPanel : JPanel(BorderLayout()) {
                 it.description
             } else {
                 if (it.status == BuildStepStatus.DONE) {
-                    message("codemodernizer.migration_plan.substeps.description_succeed")
+                    message("codemodernizer.migration_plan.substeps.description_completed")
                 } else if (it.status == BuildStepStatus.ERROR) {
                     message("codemodernizer.migration_plan.substeps.description_failed")
                 } else {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt
index f32c78f206c..550d3205705 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/session/Session.kt
@@ -3,9 +3,12 @@
 
 package software.aws.toolkits.jetbrains.services.codemodernizer.session
 
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
+
 data class Session(
     val tabId: String,
 ) {
     var isAuthenticating: Boolean = false
     var authNeededNotified: Boolean = false
+    var conversationState: CodeTransformConversationState = CodeTransformConversationState.IDLE
 }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index 9ddc086d819..4f83182684c 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -4,6 +4,14 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.utils
 
 import com.fasterxml.jackson.module.kotlin.readValue
+import com.intellij.openapi.application.runInEdt
+import com.intellij.openapi.fileEditor.FileEditorManager
+import com.intellij.openapi.diff.impl.patch.PatchReader
+import com.intellij.openapi.diff.impl.patch.formove.PatchApplier
+import com.intellij.openapi.roots.ModuleRootManager
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.module.JavaModuleType
+import com.intellij.openapi.module.ModuleManager
 import com.intellij.notification.NotificationAction
 import com.intellij.openapi.project.Project
 import com.intellij.serviceContainer.AlreadyDisposedException
@@ -18,6 +26,7 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationPlan
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
+import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep
 import software.amazon.awssdk.services.codewhispererruntime.model.ValidationException
 import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
 import software.aws.toolkits.core.utils.WaiterUnrecoverableException
@@ -36,6 +45,17 @@ import software.aws.toolkits.resources.message
 import java.time.Duration
 import java.util.Locale
 import java.util.concurrent.atomic.AtomicBoolean
+import com.intellij.openapi.util.io.FileUtil.createTempDirectory
+import com.intellij.openapi.vfs.LocalFileSystem
+import kotlinx.coroutines.withContext
+import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUploadContext
+import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
+import software.aws.toolkits.core.utils.getLogger
+import software.aws.toolkits.jetbrains.core.coroutines.EDT
+import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
+import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runClientSideBuild
+import java.nio.file.Path
+import java.nio.file.Paths
 
 data class PollingResult(
     val succeeded: Boolean,
@@ -97,6 +117,9 @@ suspend fun JobId.pollTransformationStatusAndPlan(
                     delay(sleepDurationMillis)
                     newPlan = clientAdaptor.getCodeModernizationPlan(this).transformationPlan()
                 }
+                if (newStatus == TransformationStatus.TRANSFORMING && newPlan != null) {
+                    attemptLocalBuild(newPlan, this, project)
+                }
                 if (newStatus != state) {
                     telemetry.jobStatusChanged(this, newStatus.toString(), state.toString())
                 }
@@ -144,6 +167,112 @@ suspend fun JobId.pollTransformationStatusAndPlan(
     return PollingResult(true, transformationResponse?.transformationJob(), state, transformationPlan)
 }
 
+suspend fun attemptLocalBuild(plan: TransformationPlan, jobId: JobId, project: Project) {
+    val artifactId = getClientInstructionArtifactId(plan)
+    getLogger().info("Found artifactId: $artifactId")
+    if (artifactId != null) {
+        val clientInstructionsPath = downloadClientInstructions(jobId, artifactId, project)
+        getLogger().info("Downloaded client instructions for job ${jobId.id} and artifact $artifactId at: $clientInstructionsPath")
+        processClientInstructions(clientInstructionsPath, jobId, artifactId, project)
+        getLogger().info("Finished processing client instructions for job ${jobId.id} and artifact $artifactId")
+    }
+}
+
+suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId, artifactId: String, project: Project) {
+    var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_${artifactId}", null).toPath()
+    getLogger().info("About to copy the original project ZIP to: $copyOfProjectSources")
+    val originalProjectZip = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.originalUploadZipPath
+    originalProjectZip?.let { unzipFile(it, copyOfProjectSources, isSqlMetadata = false, extractOnlySources = true) }
+    copyOfProjectSources = copyOfProjectSources.resolve("sources") // where the user's source code is within the upload ZIP
+    getLogger().info("Copied and unzipped original project sources to: $copyOfProjectSources")
+
+    val targetDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(copyOfProjectSources.toFile())
+        ?: throw RuntimeException("Cannot find copy of project sources directory")
+
+    withContext(EDT) {
+        runWriteAction {
+            // create temp module with project copy so that we can apply diff.patch
+            val modifiableModel = ModuleManager.getInstance(project).getModifiableModel()
+            val tempModule = modifiableModel.newModule(
+                Paths.get(targetDir.path).resolve("temp.iml").toString(),
+                JavaModuleType.getModuleType().id
+            )
+
+            try {
+                val moduleModel = ModuleRootManager.getInstance(tempModule).modifiableModel
+                moduleModel.addContentEntry(targetDir.url)
+                moduleModel.commit()
+                modifiableModel.commit()
+
+                // apply diff.patch
+                val patchReader = PatchReader(clientInstructionsPath)
+                patchReader.parseAllPatches()
+                PatchApplier(
+                    project,
+                    targetDir,
+                    patchReader.allPatches,
+                    null,
+                    null
+                ).execute()
+                getLogger().info("Successfully applied patch file at $clientInstructionsPath")
+
+                val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(clientInstructionsPath.toFile())
+                    ?: throw RuntimeException("Cannot find patch file at $clientInstructionsPath")
+                FileEditorManager.getInstance(project).openFile(virtualFile, true)
+            } catch (e: Exception) {
+                getLogger().error("Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " +
+                    "$clientInstructionsPath: $e")
+            } finally {
+                runWriteAction {
+                    ModuleManager.getInstance(project).disposeModule(tempModule)
+                }
+            }
+        }
+    }
+
+    val (exitCode, buildOutput) = runClientSideBuild(targetDir, CodeModernizerManager.LOG, project)
+    getLogger().info("Ran client-side build with an exit code of $exitCode")
+    val uploadZip = createClientSideBuildUploadZip(exitCode, buildOutput)
+    getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}")
+    val uploadContext = UploadContext.fromTransformationUploadContext(TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build())
+    getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId")
+    CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext)
+    getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now")
+    CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation()
+    uploadZip.deleteRecursively()
+    copyOfProjectSources.toFile().deleteRecursively()
+    getLogger().info("Deleted copy of project sources and client-side build upload ZIP")
+    // switch back to Transformation Hub view
+    runInEdt {
+        CodeModernizerManager.getInstance(project).getBottomToolWindow().show()
+    }
+}
+
+suspend fun downloadClientInstructions(jobId: JobId, artifactId: String, project: Project): Path {
+    val exportDestination = "downloadClientInstructions_${jobId.id}_$artifactId"
+    val exportZipPath = createTempDirectory(exportDestination, null)
+    val client = GumbyClient.getInstance(project)
+    val downloadBytes = client.downloadExportResultArchive(jobId, artifactId)
+    val downloadZipPath = zipToPath(downloadBytes, exportZipPath.toPath()).first.toAbsolutePath()
+    unzipFile(downloadZipPath, exportZipPath.toPath())
+    return exportZipPath.toPath().resolve("diff.patch")
+}
+
+fun getClientInstructionArtifactId(plan: TransformationPlan): String? {
+    val steps = plan.transformationSteps().drop(1)
+    val progressUpdate = findDownloadArtifactProgressUpdate(steps)
+    val artifactId = progressUpdate?.downloadArtifacts()?.firstOrNull()?.downloadArtifactId()
+    return artifactId
+}
+
+fun findDownloadArtifactProgressUpdate(transformationSteps: List) =
+    transformationSteps
+        .flatMap { it.progressUpdates().orEmpty() }
+        .firstOrNull { update ->
+            update.status().name == "AWAITING_CLIENT_ACTION" &&
+                update.downloadArtifacts()?.firstOrNull()?.downloadArtifactId() != null
+        }
+
 // "name" holds the ID of the corresponding plan step (where table will go) and "description" holds the plan data
 fun getTableMapping(stepZeroProgressUpdates: List): Map {
     if (stepZeroProgressUpdates.isNotEmpty()) {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
index 585bbb11877..8ca05bf3946 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
@@ -3,17 +3,21 @@
 
 package software.aws.toolkits.jetbrains.services.codemodernizer.utils
 
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import com.fasterxml.jackson.module.kotlin.readValue
 import com.intellij.openapi.application.runReadAction
 import com.intellij.openapi.fileEditor.FileDocumentManager
 import com.intellij.openapi.util.io.FileUtil
 import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.readText
+import kotlinx.coroutines.withContext
 import software.aws.toolkits.core.utils.createParentDirectories
+import software.aws.toolkits.core.utils.createTemporaryZipFile
 import software.aws.toolkits.core.utils.error
 import software.aws.toolkits.core.utils.exists
 import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.core.utils.info
+import software.aws.toolkits.core.utils.putNextEntry
+import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager.Companion.LOG
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_ARTIFACT_DIR_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_ARTIFACT_POMFOLDER_DIR_NAME
@@ -36,6 +40,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.util.content
 import software.aws.toolkits.resources.message
 import java.io.File
 import java.io.FileOutputStream
+import java.nio.file.Files
 import java.nio.file.Path
 import java.util.zip.ZipFile
 import kotlin.io.path.Path
@@ -61,6 +66,27 @@ fun filterOnlyParentFiles(filePaths: Set): List {
     return shortestRoots.toList()
 }
 
+fun createClientSideBuildUploadZip(exitCode: Int?, stdout: String): File {
+    val mapper = jacksonObjectMapper()
+    val outputFile = createTemporaryZipFile { zip ->
+        val manifest = mapOf(
+            "capability" to "CLIENT_SIDE_BUILD",
+            "exitCode" to exitCode,
+            "commandLogFileName" to "build-output.log"
+        )
+        mapper.writeValueAsString(manifest)
+            .byteInputStream()
+            .use { inputStream ->
+                zip.putNextEntry(Path("manifest.json").toString(), inputStream)
+            }
+
+        stdout.byteInputStream().use { inputStream ->
+            zip.putNextEntry(Path("build-output.log").toString(), inputStream)
+        }
+    }
+    return outputFile.toFile()
+}
+
 /**
  * @description For every directory, check if any supported build files (pom.xml etc) exists.
  * If we find a valid build file, store it and stop further recursion.
@@ -114,7 +140,7 @@ fun parseBuildFile(buildFile: VirtualFile?): String? {
 /**
  * Unzips a zip into a dir. Returns the true when successfully unzips the file pointed to by [zipFilePath] to [destDir]
  */
-fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false): Boolean {
+fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false, extractOnlySources: Boolean = false): Boolean {
     if (!zipFilePath.exists()) return false
     val zipFile = ZipFile(zipFilePath.toFile())
     zipFile.use { file ->
@@ -122,6 +148,12 @@ fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false):
             .filterNot { it.isDirectory }
             .map { zipEntry ->
                 var fileName = zipEntry.name
+                if (extractOnlySources) {
+                    // used to copy just the source code for client-side build
+                    if (!fileName.startsWith("sources")) {
+                        return@map
+                    }
+                }
                 if (isSqlMetadata) {
                     // when manually compressing ZIP files, the files get unzipped under a subdirectory where we extract them to,
                     // this change puts the files directly under the root of the target directory, which is what we want
@@ -137,6 +169,26 @@ fun unzipFile(zipFilePath: Path, destDir: Path, isSqlMetadata: Boolean = false):
     return true
 }
 
+suspend fun zipToPath(byteArrayList: List, outputDirPath: Path? = null): Pair {
+    val zipFilePath = withContext(getCoroutineBgContext()) {
+        if (outputDirPath == null) {
+            Files.createTempFile(null, ".zip")
+        } else {
+            Files.createTempFile(outputDirPath, null, ".zip")
+        }
+    }
+    var totalDownloadBytes = 0
+    withContext(getCoroutineBgContext()) {
+        Files.newOutputStream(zipFilePath).use {
+            for (bytes in byteArrayList) {
+                it.write(bytes)
+                totalDownloadBytes += bytes.size
+            }
+        }
+    }
+    return zipFilePath to totalDownloadBytes
+}
+
 fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesReport {
     val reportFile = pathToXmlDependency.toFile()
     val report = XML_MAPPER.readValue(reportFile, DependencyUpdatesReport::class.java)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt
index 5c8a01f20a9..9ae256b6f0d 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt
@@ -83,3 +83,24 @@ fun String.toTransformationLanguage() = when (this) {
     "JDK_21" -> TransformationLanguage.JAVA_21
     else -> TransformationLanguage.UNKNOWN_TO_SDK_VERSION
 }
+
+fun createJavaHomePrompt(jdkVersion: String): String {
+    var javaHomePrompt = "Enter the path to $jdkVersion.\n\n"
+    val os = System.getProperty("os.name").lowercase()
+    if (os.contains("windows")) {
+        javaHomePrompt += "To find the JDK path, run the following commands in a new terminal: `cd \"C:/Program Files/Java\"` and then `dir`. " +
+            "If you see your JDK version, run `cd ` and then `cd` to show the path."
+    } else if (os.contains("mac") || os.contains("darwin")) {
+        val version = when (jdkVersion) {
+            "JDK_1_8" -> "1.8"
+            "JDK_11" -> "11"
+            "JDK_17" -> "17"
+            "JDK_21" -> "21"
+            else -> "JAVA_VERSION" // shouldn't happen; we only support Java 8, 11, 17, and 21
+        }
+        javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `/usr/libexec/java_home -v $version`"
+    } else {
+        javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `update-java-alternatives --list`"
+    }
+    return javaHomePrompt
+}
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
index 633879f4872..2f6fc255672 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
@@ -4,10 +4,16 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer
 
 import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog
+import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.testFramework.LightVirtualFile
+import java.util.zip.ZipOutputStream
+import java.util.zip.ZipEntry
+import java.io.FileOutputStream
 import junit.framework.TestCase.assertEquals
 import junit.framework.TestCase.assertFalse
+import junit.framework.TestCase.assertTrue
 import kotlinx.coroutines.runBlocking
+import org.jetbrains.idea.maven.execution.MavenRunnerSettings
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mockito.doAnswer
@@ -30,8 +36,10 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransfo
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadArtifactResult
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.DownloadFailureReason
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.InvalidTelemetryReason
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.ParseZipFailureReason
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.ValidationResult
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.downloadClientInstructions
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.filterOnlyParentFiles
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
@@ -157,12 +165,22 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() {
         val mockDownloadResult = listOf()
         doReturn(mockDownloadResult).whenever(clientAdaptorSpy)
             .downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS)
-        doReturn(Pair(exampleZipPath, 0)).whenever(handler).unzipToPath(mockDownloadResult)
         val result = handler.downloadArtifact(jobId, TransformationDownloadArtifactType.LOGS, false)
         verify(clientAdaptorSpy, times(1)).downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS)
         assertEquals(expected, result)
     }
 
+    @Test
+    fun `downloadClientInstructions downloads and extracts patch file`() = runBlocking {
+        val jobId = JobId("test-job-id")
+        val artifactId = "test-artifact-id"
+        val mockBytes = "mock content".toByteArray()
+        doReturn(mockBytes).whenever(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId)
+        val result = downloadClientInstructions(jobId, artifactId, project)
+        verify(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId)
+        assertEquals(result.fileName.toString(), "diff.patch")
+    }
+
     @Test
     fun `CodeModernizerArtifact can process a valid zip file`() {
         val artifact = CodeModernizerArtifact.create(exampleZipPath.toAbsolutePath().toString())
@@ -196,6 +214,30 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() {
         assert(tempDir.resolve(validZipPatchFilePath).exists())
     }
 
+    @Test
+    fun `can unzip only sources folder`() {
+        val tempDir = createTempDirectory("test_zip")
+        val destDir = createTempDirectory("test_unzip")
+        // create test zip file with both source and non-source files
+        val zipPath = tempDir.resolve("test.zip")
+        ZipOutputStream(FileOutputStream(zipPath.toFile())).use { zos ->
+            zos.putNextEntry(ZipEntry("sources/Test.kt"))
+            zos.write("test content".toByteArray())
+            zos.closeEntry()
+
+            zos.putNextEntry(ZipEntry("other/Other.kt"))
+            zos.write("other content".toByteArray())
+            zos.closeEntry()
+        }
+
+        val result = unzipFile(zipPath, destDir, extractOnlySources = true)
+        assertTrue(result)
+        assertTrue(destDir.resolve("sources/Test.kt").exists())
+        assertFalse(destDir.resolve("other/Other.kt").exists())
+        tempDir.toFile().deleteRecursively()
+        destDir.toFile().deleteRecursively()
+    }
+
     @Test
     fun `returns False when unable to unzip file`() {
         assertFalse(unzipFile(Path("dummy1"), Path("dummy2")))
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt
index a02cd5baa97..9c20dfa9b5d 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTestBase.kt
@@ -313,7 +313,6 @@ open class CodeWhispererCodeModernizerTestBase(
         )
 
         testSessionSpy = spy(CodeModernizerSession(testSessionContextSpy, 0, 0))
-        doNothing().whenever(testSessionSpy).deleteUploadArtifact(any())
         doReturn(Job()).whenever(codeModernizerManagerSpy).launchModernizationJob(any(), any())
         testCodeModernizerArtifact =
             spy(
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index 74416f5d4f5..9722c6a47fc 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -6,6 +6,7 @@ import io.mockk.every
 import io.mockk.just
 import io.mockk.mockkStatic
 import io.mockk.runs
+import java.util.zip.ZipFile
 import io.mockk.verify
 import kotlinx.coroutines.runBlocking
 import org.assertj.core.api.Assertions.assertThat
@@ -17,11 +18,17 @@ import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 import software.amazon.awssdk.services.codewhispererruntime.model.AccessDeniedException
+import software.amazon.awssdk.services.codewhispererruntime.model.TransformationDownloadArtifact
+import software.amazon.awssdk.services.codewhispererruntime.model.TransformationPlan
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
+import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep
 import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createClientSideBuildUploadZip
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getClientInstructionArtifactId
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getTableMapping
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildFile
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
@@ -219,6 +226,99 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
         assertThat(expected).isEqualTo(actual)
     }
 
+    @Test
+    fun `getClientInstructionArtifactId extracts artifact ID from transformation plan`() {
+        val step1 = TransformationStep.builder()
+            .name("name of step 1")
+            .description("description of step 1")
+            .build()
+        val step2 = TransformationStep.builder()
+            .name("name of step 2")
+            .description("description of step 2")
+            .build()
+        val step3 = TransformationStep.builder()
+            .name("name of step 3")
+            .description("description of step 3")
+            .progressUpdates(
+                TransformationProgressUpdate.builder()
+                    .name("Requesting client-side build")
+                    .status("AWAITING_CLIENT_ACTION")
+                    .downloadArtifacts(
+                        TransformationDownloadArtifact.builder()
+                            .downloadArtifactId("id-123")
+                            .build()
+                    )
+                    .build()
+            )
+            .build()
+        val plan = TransformationPlan.builder()
+            .transformationSteps(listOf(step1, step2, step3))
+            .build()
+
+        val actual = getClientInstructionArtifactId(plan)
+        assertThat(actual).isEqualTo("id-123")
+    }
+
+    @Test
+    fun `getClientInstructionArtifactId returns null when no download artifacts present`() {
+        val step1 = TransformationStep.builder()
+            .name("name of step 1")
+            .description("description of step 1")
+            .build()
+        val step2 = TransformationStep.builder()
+            .name("name of step 2")
+            .description("description of step 2")
+            .progressUpdates(
+                TransformationProgressUpdate.builder()
+                    .name("NOT requesting client-side build")
+                    .status("NOT awaiting_client_action")
+                    .build()
+            )
+            .build()
+        val plan = TransformationPlan.builder()
+            .transformationSteps(listOf(step1, step2))
+            .build()
+
+        val actual = getClientInstructionArtifactId(plan)
+        assertThat(actual).isNull()
+    }
+
+    @Test
+    fun `createClientSideBuildUploadZip creates zip with manifest and build output`() {
+        val exitCode = 0
+        val stdout = "Build completed successfully"
+        val zipFile = createClientSideBuildUploadZip(exitCode, stdout)
+        ZipFile(zipFile).use { zip ->
+            val manifestEntry = zip.getEntry("manifest.json")
+            assertThat(manifestEntry).isNotNull
+            val manifestContent = zip.getInputStream(manifestEntry).bufferedReader().use { it.readText() }
+            assertThat(manifestContent).contains("\"capability\":\"CLIENT_SIDE_BUILD\"")
+            assertThat(manifestContent).contains("\"exitCode\":0")
+            assertThat(manifestContent).contains("\"commandLogFileName\":\"build-output.log\"")
+            val logEntry = zip.getEntry("build-output.log")
+            assertThat(logEntry).isNotNull
+            val logContent = zip.getInputStream(logEntry).bufferedReader().use { it.readText() }
+            assertThat(logContent).isEqualTo("Build completed successfully")
+        }
+        zipFile.delete()
+    }
+
+    @Test
+    fun `createJavaHomePrompt returns Windows instructions when on Windows`() {
+        System.setProperty("os.name", "Windows 10")
+        val prompt = createJavaHomePrompt("JDK_11")
+        assertThat(prompt).contains("Enter the path to JDK_11")
+        assertThat(prompt).contains("cd \"C:/Program Files/Java\"")
+    }
+
+    @Test
+    fun `createJavaHomePrompt returns Mac instructions with correct version`() {
+        System.setProperty("os.name", "Mac OS X")
+        val prompt = createJavaHomePrompt("JDK_11")
+        assertThat(prompt).contains("Enter the path to JDK_11")
+        assertThat(prompt).contains("/usr/libexec/java_home -v 11")
+    }
+
     @Test
     fun `parseBuildFile can detect absolute paths in build file`() {
         val module = projectRule.module
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
index 00f759af458..d4b483635c9 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
@@ -267,8 +267,6 @@ export class CodeTransformChatConnector {
                 tabType: 'codetransform',
             })
         } else if (action.id === FormButtonIds.OpenMvnBuild) {
-            console.log('open_mvn_build')
-
             this.sendMessageToExtension({
                 command: 'codetransform-open-mvn-build',
                 tabID,
@@ -286,6 +284,12 @@ export class CodeTransformChatConnector {
                 tabID,
                 tabType: 'codetransform',
             })
+        } else if (action.id === FormButtonIds.CodeTransformInputAgree) {
+            this.sendMessageToExtension({
+                command: 'codetransform-agree',
+                tabID,
+                tabType: 'codetransform',
+            })
         } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) {
             this.sendMessageToExtension({
                 command: 'codetransform-confirm-skip-tests',
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
index 01486f01f2a..aa56bd48569 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
@@ -37,6 +37,7 @@ type MessageCommand =
     | 'codetransform-cancel'
     | 'codetransform-stop'
     | 'codetransform-continue'
+    | 'codetransform-agree'
     | 'codetransform-confirm-skip-tests'
     | 'codetransform-confirm-one-or-multiple-diffs'
     | 'codetransform-input-confirm-custom-dependency-versions'
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
index 22b913acf96..0c8e96247eb 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
@@ -9,6 +9,7 @@ export const enum FormButtonIds {
   CodeTransformInputSQLModuleSchema = 'codetransform-input-select-sql-module-schema',
   CodeTransformInputCancel = 'codetransform-input-cancel',
   CodeTransformInputContinue = 'codetransform-input-continue',
+  CodeTransformInputAgree = 'codetransform-input-agree',
   CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests',
   CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs',
   CodeTransformInputCustomDependencyVersions = 'codetransform-input-confirm-custom-dependency-versions',
@@ -49,6 +50,7 @@ export const isFormButtonCodeTransform = (id: string): boolean => {
     id === FormButtonIds.CodeTransformInputSQLModuleSchema ||
     id === FormButtonIds.CodeTransformInputSkipTests ||
     id === FormButtonIds.CodeTransformInputContinue ||
+    id === FormButtonIds.CodeTransformInputAgree ||
     id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs ||
     id === FormButtonIds.CodeTransformInputCustomDependencyVersions ||
     id === FormButtonIds.CodeTransformViewDiff ||
diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
index c7e667e7bc8..bb57dda2f4f 100644
--- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
+++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
@@ -674,6 +674,7 @@ codemodernizer.chat.message.one_or_multiple_diffs=If you would like to update an
 codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs
 codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff
 codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} with my proposed changes.
+codemodernizer.chat.message.permission_to_build=I will build your project on this machine throughout the transformation.
 codemodernizer.chat.message.result.fail=Sorry, I ran into an issue during the transformation. Please try again.
 codemodernizer.chat.message.result.fail_initial_build=I am having trouble building your project in the secure build environment and couldn't complete the transformation.
 codemodernizer.chat.message.result.fail_initial_build_no_build_log=I am having trouble building your project in the secure build environment: {0}.
@@ -754,7 +755,7 @@ codemodernizer.migration_plan.header.description=Plan to transform your module
 codemodernizer.migration_plan.header.title=Code Transformation plan by Amazon Q
 codemodernizer.migration_plan.substeps.description_failed=Build failed
 codemodernizer.migration_plan.substeps.description_stopped=Job is stopped
-codemodernizer.migration_plan.substeps.description_succeed=Build succeeded
+codemodernizer.migration_plan.substeps.description_completed=Build completed
 codemodernizer.migration_summary.header.title=Transformation summary
 codemodernizer.notification.info.download.started.content=Downloading the updated code
 codemodernizer.notification.info.download.started.title=Download Started
From d1b0c60584be2045a3cb01f1ecf47d8512f7a0cd Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Wed, 16 Apr 2025 12:54:16 -0700
Subject: [PATCH 03/16] remove agree to local build form
---
 .../codemodernizer/CodeTransformChatApp.kt    |  3 ---
 .../InboundAppMessagesHandler.kt              |  2 --
 .../constants/CodeTransformChatItems.kt       | 17 ----------------
 .../controller/CodeTransformChatController.kt | 20 +++++--------------
 .../messages/CodeTransformMessage.kt          |  5 -----
 .../ui/apps/codeTransformChatConnector.ts     |  6 ------
 .../mynah-ui/src/mynah-ui/ui/commands.ts      |  1 -
 .../src/mynah-ui/ui/forms/constants.ts        |  2 --
 8 files changed, 5 insertions(+), 51 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
index c7c51457d50..584a3424607 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
@@ -46,7 +46,6 @@ private enum class CodeTransformMessageTypes(val type: String) {
     CodeTransformStop("codetransform-stop"),
     CodeTransformCancel("codetransform-cancel"),
     CodeTransformContinue("codetransform-continue"),
-    CodeTransformAgree("codetransform-agree"),
     CodeTransformConfirmSkipTests("codetransform-confirm-skip-tests"),
     CodeTransformConfirmOneOrMultipleDiffs("codetransform-confirm-one-or-multiple-diffs"),
     CodeTransformNew("codetransform-new"),
@@ -82,7 +81,6 @@ class CodeTransformChatApp : AmazonQApp {
             CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class,
             CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class,
             CodeTransformMessageTypes.CodeTransformContinue.type to IncomingCodeTransformMessage.CodeTransformContinue::class,
-            CodeTransformMessageTypes.CodeTransformAgree.type to IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild::class,
             CodeTransformMessageTypes.ChatPrompt.type to IncomingCodeTransformMessage.ChatPrompt::class,
             CodeTransformMessageTypes.CodeTransformConfirmSkipTests.type to IncomingCodeTransformMessage.CodeTransformConfirmSkipTests::class,
             CodeTransformMessageTypes.CodeTransformConfirmOneOrMultipleDiffs.type to IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs::class,
@@ -196,7 +194,6 @@ class CodeTransformChatApp : AmazonQApp {
             is IncomingCodeTransformMessage.CodeTransformConfirmSkipTests -> inboundAppMessagesHandler.processCodeTransformConfirmSkipTests(message)
             is IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs -> inboundAppMessagesHandler.processCodeTransformOneOrMultipleDiffs(message)
             is IncomingCodeTransformMessage.CodeTransformContinue -> inboundAppMessagesHandler.processCodeTransformContinueAction(message)
-            is IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild -> inboundAppMessagesHandler.processCodeTransformAgreeToLocalBuild(message)
             is IncomingCodeTransformMessage.CodeTransformNew -> inboundAppMessagesHandler.processCodeTransformNewAction(message)
             is IncomingCodeTransformMessage.CodeTransformOpenTransformHub -> inboundAppMessagesHandler.processCodeTransformOpenTransformHub(message)
             is IncomingCodeTransformMessage.CodeTransformOpenMvnBuild -> inboundAppMessagesHandler.processCodeTransformOpenMvnBuild(message)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
index 208a8ad67d3..434516178bd 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/InboundAppMessagesHandler.kt
@@ -13,8 +13,6 @@ interface InboundAppMessagesHandler {
 
     suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue)
 
-    suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild)
-
     suspend fun processCodeTransformStartAction(message: IncomingCodeTransformMessage.CodeTransformStart)
 
     suspend fun processCodeTransformSelectSQLMetadataAction(message: IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index b408bcff53a..38a6d8a98d1 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -52,14 +52,6 @@ private val continueTransformationButton = Button(
     id = CodeTransformButtonId.ContinueTransformation.id,
 )
 
-// used to agree to local build
-private val agreeToLocalBuildButton = Button(
-    keepCardAfterClick = false,
-    waitMandatoryFormItems = false,
-    text = "Agree",
-    id = CodeTransformButtonId.AgreeToLocalBuild.id,
-)
-
 private val confirmUserSelectionLanguageUpgradeButton = Button(
     keepCardAfterClick = false,
     waitMandatoryFormItems = true,
@@ -295,15 +287,6 @@ fun buildUserReplyChatContent(reply: String) = CodeTransformChatMessageContent(
     type = CodeTransformChatMessageType.Prompt,
 )
 
-fun buildPermissionToBuildChatContent() = CodeTransformChatMessageContent(
-    message = message("codemodernizer.chat.message.permission_to_build"),
-    type = CodeTransformChatMessageType.FinalizedAnswer,
-    buttons = listOf(
-        cancelUserSelectionButton,
-        agreeToLocalBuildButton
-    )
-)
-
 fun buildCheckingValidProjectChatContent() = CodeTransformChatMessageContent(
     message = message("codemodernizer.chat.message.validation.check_eligible_modules"),
     type = CodeTransformChatMessageType.PendingAnswer,
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index d6a8b6ac958..7d643fc3c24 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -121,17 +121,10 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYam
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
 import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.fileEditor.FileEditorManager
-import com.intellij.testFramework.LightVirtualFile
-import org.jetbrains.yaml.YAMLFileType
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPermissionToBuildChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKPathChatContent
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt
-import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
 
@@ -480,7 +473,11 @@ class CodeTransformChatController(
     private suspend fun processJDKPathChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) {
         codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkPath = message.message.trim()
         codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(message.message.trim()))
-        codeTransformChatHelper.addNewMessage(buildPermissionToBuildChatContent())
+        // start local build once we get target JDK path
+        codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
+        codeModernizerManager.codeTransformationSession?.let {
+            codeModernizerManager.runLocalMavenBuild(context.project, it)
+        }
     }
 
     /*
@@ -518,13 +515,6 @@ dependencyManagement:
         promptForTargetJdkPath(message.tabId)
     }
 
-    override suspend fun processCodeTransformAgreeToLocalBuild(message: IncomingCodeTransformMessage.CodeTransformAgreeToLocalBuild) {
-        codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
-        codeModernizerManager.codeTransformationSession?.let {
-            codeModernizerManager.runLocalMavenBuild(context.project, it)
-        }
-    }
-
     private suspend fun promptForTargetJdkPath(tabId: String) {
         chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_PATH
         val targetJdk = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty()
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
index 3e64f8b7442..b26fcbaeae2 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/messages/CodeTransformMessage.kt
@@ -21,7 +21,6 @@ enum class CodeTransformButtonId(val id: String) {
     SelectSQLModuleSchema("codetransform-input-select-sql-module-schema"),
     CancelTransformation("codetransform-input-cancel"),
     ContinueTransformation("codetransform-input-continue"),
-    AgreeToLocalBuild("codetransform-input-agree"),
     ConfirmSkipTests("codetransform-input-confirm-skip-tests"),
     ConfirmOneOrMultipleDiffs("codetransform-input-confirm-one-or-multiple-diffs"),
     ConfirmCustomDependencyVersions("codetransform-input-confirm-custom-dependency-versions"),
@@ -110,10 +109,6 @@ sealed interface IncomingCodeTransformMessage : CodeTransformBaseMessage {
         @JsonProperty("tabID") val tabId: String,
     ) : IncomingCodeTransformMessage
 
-    data class CodeTransformAgreeToLocalBuild(
-        @JsonProperty("tabID") val tabId: String,
-    ) : IncomingCodeTransformMessage
-
     data class CodeTransformConfirmSkipTests(
         @JsonProperty("tabID") val tabId: String,
         val skipTestsSelection: String,
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
index d4b483635c9..08d1335a03f 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/apps/codeTransformChatConnector.ts
@@ -284,12 +284,6 @@ export class CodeTransformChatConnector {
                 tabID,
                 tabType: 'codetransform',
             })
-        } else if (action.id === FormButtonIds.CodeTransformInputAgree) {
-            this.sendMessageToExtension({
-                command: 'codetransform-agree',
-                tabID,
-                tabType: 'codetransform',
-            })
         } else if (action.id === FormButtonIds.CodeTransformInputSkipTests) {
             this.sendMessageToExtension({
                 command: 'codetransform-confirm-skip-tests',
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
index aa56bd48569..01486f01f2a 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/commands.ts
@@ -37,7 +37,6 @@ type MessageCommand =
     | 'codetransform-cancel'
     | 'codetransform-stop'
     | 'codetransform-continue'
-    | 'codetransform-agree'
     | 'codetransform-confirm-skip-tests'
     | 'codetransform-confirm-one-or-multiple-diffs'
     | 'codetransform-input-confirm-custom-dependency-versions'
diff --git a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
index 0c8e96247eb..22b913acf96 100644
--- a/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
+++ b/plugins/amazonq/mynah-ui/src/mynah-ui/ui/forms/constants.ts
@@ -9,7 +9,6 @@ export const enum FormButtonIds {
   CodeTransformInputSQLModuleSchema = 'codetransform-input-select-sql-module-schema',
   CodeTransformInputCancel = 'codetransform-input-cancel',
   CodeTransformInputContinue = 'codetransform-input-continue',
-  CodeTransformInputAgree = 'codetransform-input-agree',
   CodeTransformInputSkipTests = 'codetransform-input-confirm-skip-tests',
   CodeTransformInputOneOrMultipleDiffs = 'codetransform-input-confirm-one-or-multiple-diffs',
   CodeTransformInputCustomDependencyVersions = 'codetransform-input-confirm-custom-dependency-versions',
@@ -50,7 +49,6 @@ export const isFormButtonCodeTransform = (id: string): boolean => {
     id === FormButtonIds.CodeTransformInputSQLModuleSchema ||
     id === FormButtonIds.CodeTransformInputSkipTests ||
     id === FormButtonIds.CodeTransformInputContinue ||
-    id === FormButtonIds.CodeTransformInputAgree ||
     id === FormButtonIds.CodeTransformInputOneOrMultipleDiffs ||
     id === FormButtonIds.CodeTransformInputCustomDependencyVersions ||
     id === FormButtonIds.CodeTransformViewDiff ||
From edf97738cc996a267dea3563848a9768eae2ef47 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Wed, 16 Apr 2025 15:18:24 -0700
Subject: [PATCH 04/16] prompt for jdk name instead of path
---
 .../constants/CodeTransformChatItems.kt       | 12 ++++-
 .../controller/CodeTransformChatController.kt | 44 ++++++++++++-------
 .../ideMaven/TransformMavenRunner.kt          | 10 +----
 .../model/CodeModernizerSessionContext.kt     |  2 +-
 .../model/CodeTransformConversationState.kt   |  2 +-
 .../utils/CodeTransformUtils.kt               | 21 ---------
 .../CodeWhispererCodeModernizerUtilsTest.kt   | 17 -------
 .../resources/MessagesBundle.properties       |  2 +-
 8 files changed, 42 insertions(+), 68 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index 38a6d8a98d1..3f294ec5714 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -399,11 +399,19 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa
     type = CodeTransformChatMessageType.FinalizedAnswer,
 )
 
-fun buildPromptTargetJDKPathChatContent(prompt: String) = CodeTransformChatMessageContent(
-    message = prompt,
+fun buildPromptTargetJDKNameChatContent(version: String) = CodeTransformChatMessageContent(
+    // TODO: get this text reviewed by Allie
+    message = "Enter the name of your $version from Settings -> Project Structure -> SDKs.",
     type = CodeTransformChatMessageType.FinalizedAnswer,
 )
 
+fun buildInvalidTargetJdkNameChatContent(jdkName: String) = CodeTransformChatMessageContent(
+    // TODO: get this text reviewed by Allie
+    message = "I could not find '$jdkName' under Settings -> Project Structure -> SDKs. Please add the target JDK there and try again.",
+    type = CodeTransformChatMessageType.FinalizedAnswer,
+    followUps = listOf(startNewTransformFollowUp)
+)
+
 fun buildCustomDependencyVersionsFileValidChatContent() = CodeTransformChatMessageContent(
     message = "I received your .yaml file and will upload it to Q.",
     type = CodeTransformChatMessageType.FinalizedAnswer,
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index 7d643fc3c24..16736007d84 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -9,6 +9,7 @@ import com.intellij.openapi.fileChooser.FileChooser
 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
 import com.intellij.openapi.module.ModuleUtil
 import com.intellij.openapi.projectRoots.JavaSdkVersion
+import com.intellij.openapi.projectRoots.ProjectJdkTable
 import com.intellij.openapi.util.io.FileUtil.createTempDirectory
 import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.openapi.vfs.readText
@@ -54,6 +55,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHi
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilRejectContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilResumeWithErrorContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildHilResumedContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildInvalidTargetJdkNameChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildLanguageUpgradeProjectValidChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormIntroChatContent
@@ -75,7 +77,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserCancelledChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserHilSelection
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputCustomDependencyVersionsChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent
@@ -121,10 +122,10 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYam
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
 import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKPathChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKNameChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
-import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt
+import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
 
@@ -140,9 +141,9 @@ class CodeTransformChatController(
     private val telemetry = CodeTransformTelemetryManager.getInstance(context.project)
 
     override suspend fun processChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) {
-        if (chatSessionStorage.getSession(message.tabId).conversationState == CodeTransformConversationState.PROMPT_TARGET_JDK_PATH) {
-            // we are prompting user for target JDK path
-            processJDKPathChatPromptMessage(message)
+        if (chatSessionStorage.getSession(message.tabId).conversationState == CodeTransformConversationState.PROMPT_TARGET_JDK_NAME) {
+            // we are prompting user for target JDK name
+            processJDKNameChatPromptMessage(message)
             return
         }
 
@@ -445,7 +446,7 @@ class CodeTransformChatController(
         codeModernizerManager.codeTransformationSession?.let {
             it.sessionContext.transformCapabilities = transformCapabilities
         }
-        promptForTargetJdkPath(message.tabId)
+        promptForTargetJdkName(message.tabId)
         // TODO: when custom 1P upgrades ready, delete line above and uncomment line below
         // promptForCustomYamlFile()
     }
@@ -466,12 +467,22 @@ class CodeTransformChatController(
                 it.sessionContext.customDependencyVersionsFile = selectedFile
             }
             codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent())
-            promptForTargetJdkPath(message.tabId)
+            promptForTargetJdkName(message.tabId)
         }
     }
 
-    private suspend fun processJDKPathChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) {
-        codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkPath = message.message.trim()
+    private suspend fun processJDKNameChatPromptMessage(message: IncomingCodeTransformMessage.ChatPrompt) {
+        chatSessionStorage.getSession(message.tabId).conversationState = CodeTransformConversationState.IDLE
+        codeTransformChatHelper.sendChatInputEnabledMessage(message.tabId, false)
+        codeTransformChatHelper.sendUpdatePlaceholderMessage(message.tabId, "")
+
+        val providedJdkName = message.message.trim().lowercase()
+        val targetJdkName = ProjectJdkTable.getInstance().allJdks.find { it.name.trim().lowercase() == providedJdkName }?.name
+        if (targetJdkName == null) {
+            codeTransformChatHelper.addNewMessage(buildInvalidTargetJdkNameChatContent(providedJdkName))
+            return
+        }
+        codeModernizerManager.codeTransformationSession?.sessionContext?.targetJdkName = targetJdkName
         codeTransformChatHelper.addNewMessage(buildUserReplyChatContent(message.message.trim()))
         // start local build once we get target JDK path
         codeTransformChatHelper.addNewMessage(buildCompileLocalInProgressChatContent())
@@ -512,16 +523,15 @@ dependencyManagement:
 
     override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) {
         codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent())
-        promptForTargetJdkPath(message.tabId)
+        promptForTargetJdkName(message.tabId)
     }
 
-    private suspend fun promptForTargetJdkPath(tabId: String) {
-        chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_PATH
-        val targetJdk = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty()
-        val javaHomePrompt = createJavaHomePrompt(targetJdk)
-        codeTransformChatHelper.addNewMessage(buildPromptTargetJDKPathChatContent(javaHomePrompt))
+    private suspend fun promptForTargetJdkName(tabId: String) {
+        chatSessionStorage.getSession(tabId).conversationState = CodeTransformConversationState.PROMPT_TARGET_JDK_NAME
+        val targetJdkVersion = codeModernizerManager.codeTransformationSession?.sessionContext?.targetJavaVersion?.name.orEmpty()
+        codeTransformChatHelper.addNewMessage(buildPromptTargetJDKNameChatContent(targetJdkVersion))
         codeTransformChatHelper.sendChatInputEnabledMessage(tabId, true)
-        codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, "Enter the path to your Java installation")
+        codeTransformChatHelper.sendUpdatePlaceholderMessage(tabId, "Enter the name of your $targetJdkVersion")
     }
 
     private fun getSourceJdk(moduleConfigurationFile: VirtualFile): JavaSdkVersion {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt
index f071a071835..4590c529793 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformMavenRunner.kt
@@ -15,19 +15,13 @@ import org.jetbrains.idea.maven.execution.MavenRunConfigurationType
 import org.jetbrains.idea.maven.execution.MavenRunnerParameters
 import org.jetbrains.idea.maven.execution.MavenRunnerSettings
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
-import com.intellij.openapi.projectRoots.ProjectJdkTable
 
 class TransformMavenRunner(val project: Project) {
     private var handler: ProcessHandler? = null
     fun run(parameters: MavenRunnerParameters, settings: MavenRunnerSettings, onComplete: TransformRunnable, isClientSideBuild: Boolean = false) {
         if (isClientSideBuild) {
-            // TODO: if we go with this implementation 1) consult UX and
-            // 2) run this check much sooner in chat with an appropriate error message if JDK is not found
-            val targetJdkPath = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.targetJdkPath
-                ?: throw RuntimeException("No target JDK path provided by user; cannot run client-side build")
-            val jdkTable = ProjectJdkTable.getInstance()
-            val targetJdkName = jdkTable.allJdks.find { it.homePath == targetJdkPath }?.name
-                ?: throw RuntimeException("Could not find user's target JDK; cannot run client-side build")
+            val targetJdkName = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.targetJdkName
+                ?: throw RuntimeException("Could not find user's target JDK; cannot run client-side build") // should not happen; already validated earlier
             settings.setJreName(targetJdkName)
         }
 
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
index 288c20a4a50..8df6b979c05 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
@@ -77,7 +77,7 @@ data class CodeModernizerSessionContext(
     var schema: String? = null,
     val sqlMetadataZip: File? = null,
     var customDependencyVersionsFile: VirtualFile? = null,
-    var targetJdkPath: String? = null,
+    var targetJdkName: String? = null,
     var originalUploadZipPath: Path? = null
 ) : Disposable {
     private val mapper = jacksonObjectMapper()
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt
index 467c7c5b289..0d4c73c208f 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeTransformConversationState.kt
@@ -5,6 +5,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer.model
 
 enum class CodeTransformConversationState {
     PROMPT_OBJECTIVE,
-    PROMPT_TARGET_JDK_PATH,
+    PROMPT_TARGET_JDK_NAME,
     IDLE,
 }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt
index 9ae256b6f0d..5c8a01f20a9 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformUtils.kt
@@ -83,24 +83,3 @@ fun String.toTransformationLanguage() = when (this) {
     "JDK_21" -> TransformationLanguage.JAVA_21
     else -> TransformationLanguage.UNKNOWN_TO_SDK_VERSION
 }
-
-fun createJavaHomePrompt(jdkVersion: String): String {
-    var javaHomePrompt = "Enter the path to $jdkVersion.\n\n"
-    val os = System.getProperty("os.name").lowercase()
-    if (os.contains("windows")) {
-        javaHomePrompt += "To find the JDK path, run the following commands in a new terminal: `cd \"C:/Program Files/Java\"` and then `dir`. " +
-            "If you see your JDK version, run `cd ` and then `cd` to show the path."
-    } else if (os.contains("mac") || os.contains("darwin")) {
-        val version = when (jdkVersion) {
-            "JDK_1_8" -> "1.8"
-            "JDK_11" -> "11"
-            "JDK_17" -> "17"
-            "JDK_21" -> "21"
-            else -> "JAVA_VERSION" // shouldn't happen; we only support Java 8, 11, 17, and 21
-        }
-        javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `/usr/libexec/java_home -v $version`"
-    } else {
-        javaHomePrompt += "To find the JDK path, run the following command in a new terminal: `update-java-alternatives --list`"
-    }
-    return javaHomePrompt
-}
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index 9722c6a47fc..d71b4c62321 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -25,7 +25,6 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep
 import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
-import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createJavaHomePrompt
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.createClientSideBuildUploadZip
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getBillingText
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getClientInstructionArtifactId
@@ -303,22 +302,6 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
         zipFile.delete()
     }
 
-    @Test
-    fun `createJavaHomePrompt returns Windows instructions when on Windows`() {
-        System.setProperty("os.name", "Windows 10")
-        val prompt = createJavaHomePrompt("JDK_11")
-        assertThat(prompt).contains("Enter the path to JDK_11")
-        assertThat(prompt).contains("cd \"C:/Program Files/Java\"")
-    }
-
-    @Test
-    fun `createJavaHomePrompt returns Mac instructions with correct version`() {
-        System.setProperty("os.name", "Mac OS X")
-        val prompt = createJavaHomePrompt("JDK_11")
-        assertThat(prompt).contains("Enter the path to JDK_11")
-        assertThat(prompt).contains("/usr/libexec/java_home -v 11")
-    }
-
     @Test
     fun `parseBuildFile can detect absolute paths in build file`() {
         val module = projectRule.module
diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
index bb57dda2f4f..66f6307f935 100644
--- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
+++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
@@ -674,7 +674,6 @@ codemodernizer.chat.message.one_or_multiple_diffs=If you would like to update an
 codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs=Multiple diffs
 codemodernizer.chat.message.one_or_multiple_diffs_form.one_diff=One diff
 codemodernizer.chat.message.one_or_multiple_diffs_form.response=Okay, I will create {0} with my proposed changes.
-codemodernizer.chat.message.permission_to_build=I will build your project on this machine throughout the transformation.
 codemodernizer.chat.message.result.fail=Sorry, I ran into an issue during the transformation. Please try again.
 codemodernizer.chat.message.result.fail_initial_build=I am having trouble building your project in the secure build environment and couldn't complete the transformation.
 codemodernizer.chat.message.result.fail_initial_build_no_build_log=I am having trouble building your project in the secure build environment: {0}.
@@ -685,6 +684,7 @@ codemodernizer.chat.message.result.success=I successfully completed your transfo
 codemodernizer.chat.message.result.success.multiple_diffs=I successfully completed your transformation. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs. The transformation summary has details about the changes I'm proposing.
 codemodernizer.chat.message.result.zip_too_large=Sorry, your project size exceeds the Amazon Q Code Transformation upload limit of 2GB.
 codemodernizer.chat.message.resume_ongoing=I'm still transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub.
+// TODO: get text from Allie for this
 codemodernizer.chat.message.skip_tests=I will build your module using `mvn test` by default. If you would like me to build your module without running unit tests, I will use `mvn test-compile`.
 codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module.
 codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests
From d312c59dfd5f2dd2bb24b266bbe7e7c73a66ff83 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Wed, 16 Apr 2025 15:41:37 -0700
Subject: [PATCH 05/16] delete artifacts
---
 .../codemodernizer/utils/CodeTransformApiUtils.kt | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index 4f83182684c..471d739072b 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -236,12 +236,15 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
     getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}")
     val uploadContext = UploadContext.fromTransformationUploadContext(TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build())
     getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId")
-    CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext)
-    getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now")
-    CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation()
-    uploadZip.deleteRecursively()
-    copyOfProjectSources.toFile().deleteRecursively()
-    getLogger().info("Deleted copy of project sources and client-side build upload ZIP")
+    try {
+        CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext)
+        getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now")
+        CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation()
+    } finally {
+        uploadZip.deleteRecursively()
+        copyOfProjectSources.toFile().deleteRecursively()
+        getLogger().info("Deleted copy of project sources and client-side build upload ZIP")
+    }
     // switch back to Transformation Hub view
     runInEdt {
         CodeModernizerManager.getInstance(project).getBottomToolWindow().show()
From 31c767462aff56b14cfee8454b6571d0dc6e0e11 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Thu, 17 Apr 2025 15:06:40 -0700
Subject: [PATCH 06/16] fix detekt
---
 .../codemodernizer/ArtifactHandler.kt         |  1 -
 .../codemodernizer/CodeModernizerSession.kt   |  2 +-
 .../codemodernizer/CodeTransformChatApp.kt    |  3 +-
 .../constants/CodeTransformChatItems.kt       |  6 +--
 .../controller/CodeTransformChatController.kt | 15 +++----
 .../ideMaven/MavenRunnerUtils.kt              |  2 +-
 .../model/CodeModernizerSessionContext.kt     |  3 +-
 .../utils/CodeTransformApiUtils.kt            | 44 ++++++++++---------
 .../CodeWhispererCodeModernizerTest.kt        |  2 -
 .../CodeWhispererCodeModernizerUtilsTest.kt   |  7 +--
 .../resources/MessagesBundle.properties       |  5 ++-
 11 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt
index 6623f19ffa9..ab4af2a8d4c 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ArtifactHandler.kt
@@ -24,7 +24,6 @@ import software.aws.toolkits.core.utils.exists
 import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.core.utils.info
 import software.aws.toolkits.jetbrains.core.coroutines.EDT
-import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
 import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
 import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.NoTokenInitializedException
 import software.aws.toolkits.jetbrains.services.amazonq.CODE_TRANSFORM_TROUBLESHOOT_DOC_DOWNLOAD_ERROR_OVERVIEW
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
index 828b36d7db8..b19bd8e1fcf 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
@@ -423,7 +423,7 @@ class CodeModernizerSession(
                 createUploadUrlResponse.kmsKeyArn().orEmpty(),
             ) { shouldStop.get() }
         }
-        LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of ${uploadContext.toString()}" }
+        LOG.info { "Upload of ${payload.path} to S3 succeeded with upload context of $uploadContext" }
         if (!shouldStop.get()) {
             LOG.info { "Uploaded artifact. Latency: ${calculateTotalLatency(uploadStartTime, Instant.now())} ms" }
         }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
index 584a3424607..edbf0afa7be 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeTransformChatApp.kt
@@ -76,7 +76,8 @@ class CodeTransformChatApp : AmazonQApp {
             CodeTransformMessageTypes.Transform.type to IncomingCodeTransformMessage.Transform::class,
             CodeTransformMessageTypes.CodeTransformStart.type to IncomingCodeTransformMessage.CodeTransformStart::class,
             CodeTransformMessageTypes.CodeTransformSelectSQLMetadata.type to IncomingCodeTransformMessage.CodeTransformSelectSQLMetadata::class,
-            CodeTransformMessageTypes.CodeTransformConfirmCustomDependencyVersions.type to IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions::class,
+            CodeTransformMessageTypes.CodeTransformConfirmCustomDependencyVersions.type to
+                IncomingCodeTransformMessage.CodeTransformConfirmCustomDependencyVersions::class,
             CodeTransformMessageTypes.CodeTransformSelectSQLModuleSchema.type to IncomingCodeTransformMessage.CodeTransformSelectSQLModuleSchema::class,
             CodeTransformMessageTypes.CodeTransformStop.type to IncomingCodeTransformMessage.CodeTransformStop::class,
             CodeTransformMessageTypes.CodeTransformCancel.type to IncomingCodeTransformMessage.CodeTransformCancel::class,
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index 3f294ec5714..946ce58449b 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -400,14 +400,12 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa
 )
 
 fun buildPromptTargetJDKNameChatContent(version: String) = CodeTransformChatMessageContent(
-    // TODO: get this text reviewed by Allie
-    message = "Enter the name of your $version from Settings -> Project Structure -> SDKs.",
+    message = message("codemodernizer.chat.message.enter_jdk_name", version),
     type = CodeTransformChatMessageType.FinalizedAnswer,
 )
 
 fun buildInvalidTargetJdkNameChatContent(jdkName: String) = CodeTransformChatMessageContent(
-    // TODO: get this text reviewed by Allie
-    message = "I could not find '$jdkName' under Settings -> Project Structure -> SDKs. Please add the target JDK there and try again.",
+    message = message("codemodernizer.chat.message.enter_jdk_name_error", jdkName),
     type = CodeTransformChatMessageType.FinalizedAnswer,
     followUps = listOf(startNewTransformFollowUp)
 )
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index 16736007d84..cc0505daa8c 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -36,7 +36,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFO
 import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
 import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformActionMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformCommand
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.FEATURE_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildAbsolutePathWarning
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCheckingValidProjectChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildChooseTransformationObjectiveChatContent
@@ -59,8 +58,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildIn
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildLanguageUpgradeProjectValidChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildModuleSchemaFormIntroChatContent
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildProjectInvalidChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKNameChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationErrorChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationSuccessDetailsChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildSQLMetadataValidationSuccessIntroChatContent
@@ -85,15 +84,19 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUs
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputSkipTestsFlagChatIntroContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserLanguageUpgradeSelectionSummaryChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserOneOrMultipleDiffsSelectionChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserReplyChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSQLConversionSelectionSummaryChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSkipTestsFlagSelectionChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserStopTransformChatContent
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.FEATURE_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.AuthenticationNeededExceptionMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformCommandMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.IncomingCodeTransformMessage
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult
+import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformHilDownloadArtifact
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CustomerSelection
@@ -122,10 +125,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYam
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
 import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildPromptTargetJDKNameChatContent
-import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD
-import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
-import software.aws.toolkits.jetbrains.utils.notifyStickyInfo
 import software.aws.toolkits.resources.message
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
 
@@ -491,7 +490,7 @@ class CodeTransformChatController(
         }
     }
 
-    /*
+/*
     private suspend fun promptForCustomYamlFile() {
         codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent())
         val sampleYAML = """
@@ -519,7 +518,7 @@ dependencyManagement:
             FileEditorManager.getInstance(context.project).openFile(virtualFile, true)
         }
     }
-    */
+*/
 
     override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) {
         codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent())
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
index 7ddf17d2082..2168e00eb23 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
@@ -220,7 +220,7 @@ private fun runClientSideBuild(
     mvnSettings: MavenRunnerSettings,
     transformMavenRunner: TransformMavenRunner,
     logger: Logger,
-    project: Project
+    project: Project,
 ): TransformRunnable {
     val customBuildCommand = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.customBuildCommand
     val clientSideBuildCommand = if (customBuildCommand == MAVEN_BUILD_RUN_UNIT_TESTS) "test" else "test-compile"
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
index 8df6b979c05..93bf8a20b1a 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CodeModernizerSessionContext.kt
@@ -17,7 +17,6 @@ import software.aws.toolkits.core.utils.error
 import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.core.utils.info
 import software.aws.toolkits.core.utils.putNextEntry
-import software.aws.toolkits.jetbrains.services.codemodernizer.EXPLAINABILITY_V1
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_DEPENDENCIES_ROOT_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.HIL_MANIFEST_FILE_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.TransformMavenRunner
@@ -78,7 +77,7 @@ data class CodeModernizerSessionContext(
     val sqlMetadataZip: File? = null,
     var customDependencyVersionsFile: VirtualFile? = null,
     var targetJdkName: String? = null,
-    var originalUploadZipPath: Path? = null
+    var originalUploadZipPath: Path? = null,
 ) : Disposable {
     private val mapper = jacksonObjectMapper()
     private val ignoredDependencyFileExtensions = setOf(INVALID_SUFFIX_SHA, INVALID_SUFFIX_REPOSITORIES)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index 471d739072b..687a9c68ee6 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -4,18 +4,21 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.utils
 
 import com.fasterxml.jackson.module.kotlin.readValue
+import com.intellij.notification.NotificationAction
 import com.intellij.openapi.application.runInEdt
-import com.intellij.openapi.fileEditor.FileEditorManager
+import com.intellij.openapi.application.runWriteAction
 import com.intellij.openapi.diff.impl.patch.PatchReader
 import com.intellij.openapi.diff.impl.patch.formove.PatchApplier
-import com.intellij.openapi.roots.ModuleRootManager
-import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.fileEditor.FileEditorManager
 import com.intellij.openapi.module.JavaModuleType
 import com.intellij.openapi.module.ModuleManager
-import com.intellij.notification.NotificationAction
 import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ModuleRootManager
+import com.intellij.openapi.util.io.FileUtil.createTempDirectory
+import com.intellij.openapi.vfs.LocalFileSystem
 import com.intellij.serviceContainer.AlreadyDisposedException
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.withContext
 import software.amazon.awssdk.awscore.exception.AwsServiceException
 import software.amazon.awssdk.services.codewhispererruntime.model.AccessDeniedException
 import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException
@@ -27,35 +30,32 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationProgressUpdate
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStep
+import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUploadContext
+import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
 import software.amazon.awssdk.services.codewhispererruntime.model.ValidationException
 import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
+import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.core.utils.WaiterUnrecoverableException
 import software.aws.toolkits.core.utils.Waiters.waitUntil
-import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager
+import software.aws.toolkits.jetbrains.core.coroutines.EDT
 import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
+import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
+import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager
 import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.BILLING_RATE
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.JOB_STATISTICS_TABLE_KEY
+import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runClientSideBuild
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact.Companion.MAPPER
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformType
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.JobId
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.PlanTable
 import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
 import software.aws.toolkits.resources.message
+import java.nio.file.Path
+import java.nio.file.Paths
 import java.time.Duration
 import java.util.Locale
 import java.util.concurrent.atomic.AtomicBoolean
-import com.intellij.openapi.util.io.FileUtil.createTempDirectory
-import com.intellij.openapi.vfs.LocalFileSystem
-import kotlinx.coroutines.withContext
-import software.amazon.awssdk.services.codewhispererruntime.model.TransformationUploadContext
-import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
-import software.aws.toolkits.core.utils.getLogger
-import software.aws.toolkits.jetbrains.core.coroutines.EDT
-import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
-import software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven.runClientSideBuild
-import java.nio.file.Path
-import java.nio.file.Paths
 
 data class PollingResult(
     val succeeded: Boolean,
@@ -179,7 +179,7 @@ suspend fun attemptLocalBuild(plan: TransformationPlan, jobId: JobId, project: P
 }
 
 suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId, artifactId: String, project: Project) {
-    var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_${artifactId}", null).toPath()
+    var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_$artifactId", null).toPath()
     getLogger().info("About to copy the original project ZIP to: $copyOfProjectSources")
     val originalProjectZip = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.originalUploadZipPath
     originalProjectZip?.let { unzipFile(it, copyOfProjectSources, isSqlMetadata = false, extractOnlySources = true) }
@@ -220,8 +220,10 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
                     ?: throw RuntimeException("Cannot find patch file at $clientInstructionsPath")
                 FileEditorManager.getInstance(project).openFile(virtualFile, true)
             } catch (e: Exception) {
-                getLogger().error("Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " +
-                    "$clientInstructionsPath: $e")
+                getLogger().error(
+                    "Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " +
+                    "$clientInstructionsPath: $e"
+                )
             } finally {
                 runWriteAction {
                     ModuleManager.getInstance(project).disposeModule(tempModule)
@@ -234,7 +236,9 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
     getLogger().info("Ran client-side build with an exit code of $exitCode")
     val uploadZip = createClientSideBuildUploadZip(exitCode, buildOutput)
     getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}")
-    val uploadContext = UploadContext.fromTransformationUploadContext(TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build())
+    val uploadContext = UploadContext.fromTransformationUploadContext(
+        TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build()
+    )
     getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId")
     try {
         CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
index 2f6fc255672..99d59891d09 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
@@ -4,7 +4,6 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer
 
 import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog
-import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.testFramework.LightVirtualFile
 import java.util.zip.ZipOutputStream
 import java.util.zip.ZipEntry
@@ -13,7 +12,6 @@ import junit.framework.TestCase.assertEquals
 import junit.framework.TestCase.assertFalse
 import junit.framework.TestCase.assertTrue
 import kotlinx.coroutines.runBlocking
-import org.jetbrains.idea.maven.execution.MavenRunnerSettings
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mockito.doAnswer
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index d71b4c62321..eebcef29f33 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -2,12 +2,13 @@
 // SPDX-License-Identifier: Apache-2.0
 
 package software.aws.toolkits.jetbrains.services.codemodernizer
+
 import io.mockk.every
 import io.mockk.just
 import io.mockk.mockkStatic
 import io.mockk.runs
-import java.util.zip.ZipFile
 import io.mockk.verify
+import kotlin.io.path.createTempFile
 import kotlinx.coroutines.runBlocking
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.Before
@@ -33,12 +34,12 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildF
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
-import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile
+import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
 import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
 import software.aws.toolkits.resources.message
 import java.util.concurrent.atomic.AtomicBoolean
-import kotlin.io.path.createTempFile
+import java.util.zip.ZipFile
 
 class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase() {
     @Before
diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
index 66f6307f935..8f1a0d07c0e 100644
--- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
+++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
@@ -647,6 +647,8 @@ codemodernizer.chat.message.download_failed_invalid_artifact=Sorry, I was unable
 codemodernizer.chat.message.download_failed_other=Sorry, I ran into an issue while trying to download your {0}. Please try again. {1}
 codemodernizer.chat.message.download_failed_ssl=Sorry, I couldn''t download your {0} because of an issue with your certificate. Please make sure all your certificates for your proxy client have been set up correctly for your IDE.
 codemodernizer.chat.message.download_failed_wildcard=Sorry, I couldn''t download your {0} because of an issue with your proxy client. Please check your IDE proxy settings and remove any wildcard (*) references, then restart your IDE.
+codemodernizer.chat.message.enter_jdk_name=Enter the name of the {0} you are using. You can find the name in Settings > Project Structure > Platform Settings > SDKs. If you do not see the name of your JDK in the SDK settings, add your JDK, and then return to this chat and enter the name here.
+codemodernizer.chat.message.enter_jdk_name_error=I could not find "{0}" in Settings > Project Structure > Platform Settings > SDKs. Please add the target JDK there and try again.
 codemodernizer.chat.message.error_request=Request failed
 codemodernizer.chat.message.follow_up.new_transformation=Start a new transformation
 codemodernizer.chat.message.hil.cannot_resume=I ran into an issue trying to resume your transformation.
@@ -684,8 +686,7 @@ codemodernizer.chat.message.result.success=I successfully completed your transfo
 codemodernizer.chat.message.result.success.multiple_diffs=I successfully completed your transformation. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs. The transformation summary has details about the changes I'm proposing.
 codemodernizer.chat.message.result.zip_too_large=Sorry, your project size exceeds the Amazon Q Code Transformation upload limit of 2GB.
 codemodernizer.chat.message.resume_ongoing=I'm still transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub.
-// TODO: get text from Allie for this
-codemodernizer.chat.message.skip_tests=I will build your module using `mvn test` by default. If you would like me to build your module without running unit tests, I will use `mvn test-compile`.
+codemodernizer.chat.message.skip_tests=I will build generated code in your local environment, not on the server side. For information on how I scan code to reduce security risks associated with building the code in your local environment, see the [Amazon Q Developer documentation](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/code-transformation.html#java-local-builds).\n\nI will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`.
 codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module.
 codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests
 codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests
From 530d63baabb25e2359f7c2917f6dfa485dc2d4bd Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Thu, 24 Apr 2025 15:37:11 -0700
Subject: [PATCH 07/16] final CSB commit
---
 .../constants/CodeTransformChatItems.kt       |  4 ++--
 .../controller/CodeTransformChatController.kt | 19 +++++++--------
 .../codemodernizer/model/ZipManifest.kt       |  3 ++-
 .../utils/CodeTransformApiUtils.kt            |  5 +++-
 .../resources/MessagesBundle.properties       |  6 ++---
 .../transformTests/TransformChatTest.kt       | 23 ++++++++++++++++++-
 6 files changed, 43 insertions(+), 17 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index 946ce58449b..5800c9ff5ad 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -89,7 +89,7 @@ private val confirmOneOrMultipleDiffsSelectionButton = Button(
 
 private val confirmCustomDependencyVersionsButton = Button(
     keepCardAfterClick = true,
-    waitMandatoryFormItems = true, // TODO: what does this do?
+    waitMandatoryFormItems = true,
     text = "Select file",
     id = CodeTransformButtonId.ConfirmCustomDependencyVersions.id,
 )
@@ -396,7 +396,7 @@ fun buildUserInputCustomDependencyVersionsChatContent() = CodeTransformChatMessa
         confirmCustomDependencyVersionsButton,
         continueTransformationButton,
     ),
-    type = CodeTransformChatMessageType.FinalizedAnswer,
+    type = CodeTransformChatMessageType.PendingAnswer,
 )
 
 fun buildPromptTargetJDKNameChatContent(version: String) = CodeTransformChatMessageContent(
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index cc0505daa8c..461c6552cbd 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -4,18 +4,22 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.controller
 
 import com.intellij.ide.BrowserUtil
+import com.intellij.openapi.application.ApplicationManager
 import com.intellij.openapi.application.runInEdt
 import com.intellij.openapi.fileChooser.FileChooser
 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
+import com.intellij.openapi.fileEditor.FileEditorManager
 import com.intellij.openapi.module.ModuleUtil
 import com.intellij.openapi.projectRoots.JavaSdkVersion
 import com.intellij.openapi.projectRoots.ProjectJdkTable
 import com.intellij.openapi.util.io.FileUtil.createTempDirectory
 import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.openapi.vfs.readText
+import com.intellij.testFramework.LightVirtualFile
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
+import org.jetbrains.yaml.YAMLFileType
 import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType
 import software.aws.toolkits.core.utils.debug
 import software.aws.toolkits.core.utils.error
@@ -76,6 +80,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserCancelledChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserHilSelection
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputCustomDependencyVersionsChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent
@@ -93,7 +98,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.messages.Authenti
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformCommandMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.IncomingCodeTransformMessage
-import software.aws.toolkits.jetbrains.services.codemodernizer.model.CLIENT_SIDE_BUILD
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerArtifact
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeTransformConversationState
@@ -430,23 +434,22 @@ class CodeTransformChatController(
 
     override suspend fun processCodeTransformOneOrMultipleDiffs(message: IncomingCodeTransformMessage.CodeTransformConfirmOneOrMultipleDiffs) {
         val transformCapabilities = when (message.oneOrMultipleDiffsSelection) {
+            // TODO: add CLIENT_SIDE_BUILD to both below when releasing CSB
             message("codemodernizer.chat.message.one_or_multiple_diffs_form.multiple_diffs") -> listOf(
                 EXPLAINABILITY_V1,
-                CLIENT_SIDE_BUILD,
                 SELECTIVE_TRANSFORMATION_V1
             )
             else -> listOf(
                 EXPLAINABILITY_V1,
-                CLIENT_SIDE_BUILD
             )
         }
         telemetry.submitSelection(message.oneOrMultipleDiffsSelection)
         codeTransformChatHelper.addNewMessage(buildUserOneOrMultipleDiffsSelectionChatContent(message.oneOrMultipleDiffsSelection))
         codeModernizerManager.codeTransformationSession?.let {
             it.sessionContext.transformCapabilities = transformCapabilities
+            codeModernizerManager.runLocalMavenBuild(context.project, it)
         }
-        promptForTargetJdkName(message.tabId)
-        // TODO: when custom 1P upgrades ready, delete line above and uncomment line below
+        // TODO: when releasing CSB, delete "runLocalMavenBuild" line above and uncomment line below
         // promptForCustomYamlFile()
     }
 
@@ -458,14 +461,14 @@ class CodeTransformChatController(
             val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
             val isValid = validateYamlFile(selectedFile.readText())
             if (!isValid) {
-                codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileInvalidChatContent())
+                codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent())
                 codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
                 return@withContext
             }
             codeModernizerManager.codeTransformationSession?.let {
                 it.sessionContext.customDependencyVersionsFile = selectedFile
             }
-            codeTransformChatHelper.addNewMessage(buildCustomDependencyVersionsFileValidChatContent())
+            codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileValidChatContent())
             promptForTargetJdkName(message.tabId)
         }
     }
@@ -490,7 +493,6 @@ class CodeTransformChatController(
         }
     }
 
-/*
     private suspend fun promptForCustomYamlFile() {
         codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent())
         val sampleYAML = """
@@ -518,7 +520,6 @@ dependencyManagement:
             FileEditorManager.getInstance(context.project).openFile(virtualFile, true)
         }
     }
-*/
 
     override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) {
         codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent())
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt
index e5bb80ad77a..e65b08f7e12 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/ZipManifest.kt
@@ -10,7 +10,8 @@ data class ZipManifest(
     val buildLogs: String = BUILD_LOG_PATH,
     val version: String = UPLOAD_ZIP_MANIFEST_VERSION,
     val hilCapabilities: List = listOf(HIL_1P_UPGRADE_CAPABILITY),
-    val transformCapabilities: List = listOf(EXPLAINABILITY_V1, CLIENT_SIDE_BUILD),
+    // TODO: add CLIENT_SIDE_BUILD to transformCapabilities when releasing CSB
+    val transformCapabilities: List = listOf(EXPLAINABILITY_V1),
     val customBuildCommand: String = MAVEN_BUILD_RUN_UNIT_TESTS,
     val requestedConversions: RequestedConversions? = null, // only used for SQL conversions for now
 )
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index 687a9c68ee6..722591d5c30 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -64,6 +64,8 @@ data class PollingResult(
     val transformationPlan: TransformationPlan?,
 )
 
+private const val isClientSideBuildEnabled = false
+
 /**
  * Wrapper around [waitUntil] that polls the API DescribeMigrationJob to check the migration job status.
  */
@@ -117,7 +119,8 @@ suspend fun JobId.pollTransformationStatusAndPlan(
                     delay(sleepDurationMillis)
                     newPlan = clientAdaptor.getCodeModernizationPlan(this).transformationPlan()
                 }
-                if (newStatus == TransformationStatus.TRANSFORMING && newPlan != null) {
+                // TODO: remove flag when releasing CSB
+                if (isClientSideBuildEnabled && newStatus == TransformationStatus.TRANSFORMING && newPlan != null) {
                     attemptLocalBuild(newPlan, this, project)
                 }
                 if (newStatus != state) {
diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
index 8f1a0d07c0e..6ded544b51d 100644
--- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
+++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
@@ -647,8 +647,8 @@ codemodernizer.chat.message.download_failed_invalid_artifact=Sorry, I was unable
 codemodernizer.chat.message.download_failed_other=Sorry, I ran into an issue while trying to download your {0}. Please try again. {1}
 codemodernizer.chat.message.download_failed_ssl=Sorry, I couldn''t download your {0} because of an issue with your certificate. Please make sure all your certificates for your proxy client have been set up correctly for your IDE.
 codemodernizer.chat.message.download_failed_wildcard=Sorry, I couldn''t download your {0} because of an issue with your proxy client. Please check your IDE proxy settings and remove any wildcard (*) references, then restart your IDE.
-codemodernizer.chat.message.enter_jdk_name=Enter the name of the {0} you are using. You can find the name in Settings > Project Structure > Platform Settings > SDKs. If you do not see the name of your JDK in the SDK settings, add your JDK, and then return to this chat and enter the name here.
-codemodernizer.chat.message.enter_jdk_name_error=I could not find "{0}" in Settings > Project Structure > Platform Settings > SDKs. Please add the target JDK there and try again.
+codemodernizer.chat.message.enter_jdk_name=Enter the name of the {0} you are using. You can find the name in File > Project Structure > Platform Settings > SDKs. If you do not see the name of your JDK in the SDK settings, add your JDK, and then return to this chat and enter the name here.
+codemodernizer.chat.message.enter_jdk_name_error=I could not find "{0}" in File > Project Structure > Platform Settings > SDKs. Please add the target JDK there and try again.
 codemodernizer.chat.message.error_request=Request failed
 codemodernizer.chat.message.follow_up.new_transformation=Start a new transformation
 codemodernizer.chat.message.hil.cannot_resume=I ran into an issue trying to resume your transformation.
@@ -686,7 +686,7 @@ codemodernizer.chat.message.result.success=I successfully completed your transfo
 codemodernizer.chat.message.result.success.multiple_diffs=I successfully completed your transformation. You will be able to accept changes from one diff at a time. If you reject changes in one diff, you will not be able to view or accept changes in the other diffs. The transformation summary has details about the changes I'm proposing.
 codemodernizer.chat.message.result.zip_too_large=Sorry, your project size exceeds the Amazon Q Code Transformation upload limit of 2GB.
 codemodernizer.chat.message.resume_ongoing=I'm still transforming your code. It can take 10 to 30 minutes to upgrade your code, depending on the size of your module. To monitor progress, go to the Transformation Hub.
-codemodernizer.chat.message.skip_tests=I will build generated code in your local environment, not on the server side. For information on how I scan code to reduce security risks associated with building the code in your local environment, see the [Amazon Q Developer documentation](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/code-transformation.html#java-local-builds).\n\nI will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`.
+codemodernizer.chat.message.skip_tests=I will build your project using `mvn clean test` by default. If you would like me to build your project without running unit tests, I will use `mvn clean test-compile`.
 codemodernizer.chat.message.skip_tests_form.response=Okay, I will {0} when building your module.
 codemodernizer.chat.message.skip_tests_form.run_tests=Run unit tests
 codemodernizer.chat.message.skip_tests_form.skip=Skip unit tests
diff --git a/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt b/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt
index c51be54d50f..82951c22738 100644
--- a/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt
+++ b/ui-tests-starter/tst-243+/software/aws/toolkits/jetbrains/uitests/transformTests/TransformChatTest.kt
@@ -81,7 +81,25 @@ async function testNavigation() {
                 const button = document.querySelector('button[action-id="codetransform-input-confirm-one-or-multiple-diffs"]')
                 button.click()
             })
-              
+/*
+            const selectCustomVersionsForm = await page.waitForSelector('button[action-id="codetransform-input-confirm-custom-dependency-versions"]', {
+                timeout: 5000
+            })
+            console.log('Custom dependency versions file form appeared:', selectCustomVersionsForm !== null)
+
+            await page.evaluate(() => {
+                const button = document.querySelector('button[action-id="codetransform-input-continue"]')
+                button.click()
+            })
+
+            await page.type('.mynah-chat-prompt-input', 'dummy-target-jdk-name-here')
+            await page.keyboard.press('Enter')
+
+            const errorMessage = await page.waitForSelector('text/I could not find "dummy-target-jdk-name-here" in File > Project Structure > Platform Settings > SDKs.', {
+                timeout: 5000
+            })
+*/
+            // TODO: delete errorMessage below, and uncomment the above when releasing CSB
             const errorMessage = await page.waitForSelector('text/Sorry, I couldn\'t run the Maven clean install command', {
                 timeout: 5000
             })
@@ -149,6 +167,9 @@ class TransformChatTest {
                     "Skip tests form appeared: true",
                     "One or multiple diffs form appeared: true",
                     "couldn't run the Maven clean install command"
+                    // TODO: delete line above, and uncomment lines below when releasing CSB
+                    // "I could not find \"dummy-target-jdk-name-here\"",
+                    // "Custom dependency versions file form appeared: true",
                 )
             }
     }
From 398ba578e8c2a5b8917d813629e63f053f3c7426 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Thu, 24 Apr 2025 16:12:34 -0700
Subject: [PATCH 08/16] fix detekt
---
 .../controller/CodeTransformChatController.kt       | 13 +++++--------
 .../codemodernizer/model/CustomerSelection.kt       |  3 ++-
 .../codemodernizer/utils/CodeTransformApiUtils.kt   | 10 +++++-----
 .../CodeWhispererCodeModernizerTest.kt              |  6 +++---
 .../CodeWhispererCodeModernizerUtilsTest.kt         |  2 +-
 5 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index 461c6552cbd..4ce408528c1 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -4,22 +4,18 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.controller
 
 import com.intellij.ide.BrowserUtil
-import com.intellij.openapi.application.ApplicationManager
 import com.intellij.openapi.application.runInEdt
 import com.intellij.openapi.fileChooser.FileChooser
 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
-import com.intellij.openapi.fileEditor.FileEditorManager
 import com.intellij.openapi.module.ModuleUtil
 import com.intellij.openapi.projectRoots.JavaSdkVersion
 import com.intellij.openapi.projectRoots.ProjectJdkTable
 import com.intellij.openapi.util.io.FileUtil.createTempDirectory
 import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.openapi.vfs.readText
-import com.intellij.testFramework.LightVirtualFile
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
-import org.jetbrains.yaml.YAMLFileType
 import software.amazon.awssdk.services.codewhispererstreaming.model.TransformationDownloadArtifactType
 import software.aws.toolkits.core.utils.debug
 import software.aws.toolkits.core.utils.error
@@ -40,6 +36,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.SELECTIVE_TRANSFO
 import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
 import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformActionMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformCommand
+import software.aws.toolkits.jetbrains.services.codemodernizer.constants.FEATURE_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildAbsolutePathWarning
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildCheckingValidProjectChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildChooseTransformationObjectiveChatContent
@@ -80,7 +77,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTr
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildTransformStoppingChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserCancelledChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserHilSelection
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputCustomDependencyVersionsChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputLanguageUpgradeChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsChatIntroContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserInputOneOrMultipleDiffsFlagChatContent
@@ -93,7 +89,6 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUs
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSQLConversionSelectionSummaryChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserSkipTestsFlagSelectionChatContent
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.buildUserStopTransformChatContent
-import software.aws.toolkits.jetbrains.services.codemodernizer.constants.FEATURE_NAME
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.AuthenticationNeededExceptionMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformChatMessage
 import software.aws.toolkits.jetbrains.services.codemodernizer.messages.CodeTransformCommandMessage
@@ -493,6 +488,8 @@ class CodeTransformChatController(
         }
     }
 
+    // TODO: uncomment when releasing CSB
+/*
     private suspend fun promptForCustomYamlFile() {
         codeTransformChatHelper.addNewMessage(buildUserInputCustomDependencyVersionsChatContent())
         val sampleYAML = """
@@ -512,7 +509,7 @@ dependencyManagement:
     - identifier: "com.example.plugin"
       targetVersion: "1.2.0"
       versionProperty: "plugin.version"  # Optional
-""".trimIndent()
+        """.trimIndent()
 
         val virtualFile = LightVirtualFile("sample-dependency-management.yaml", YAMLFileType.YML, sampleYAML)
         virtualFile.isWritable = true
@@ -520,7 +517,7 @@ dependencyManagement:
             FileEditorManager.getInstance(context.project).openFile(virtualFile, true)
         }
     }
-
+*/
     override suspend fun processCodeTransformContinueAction(message: IncomingCodeTransformMessage.CodeTransformContinue) {
         codeTransformChatHelper.addNewMessage(buildContinueTransformationChatContent())
         promptForTargetJdkName(message.tabId)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt
index d5e1ea24962..5c9828a1e0e 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/model/CustomerSelection.kt
@@ -15,6 +15,7 @@ data class CustomerSelection(
     val targetVendor: String? = null,
     val sourceServerName: String? = null,
     val sqlMetadataZip: File? = null,
-    // note: schema / customBuildCommand / customDependencyVersionsFile are passed in to CodeModernizerSessionContext separately,
+    // note: schema / customBuildCommand / customDependencyVersionsFile / targetJdkName / originalUploadZipPath
+    // are passed in to CodeModernizerSessionContext separately,
     // *after* CodeModernizerSession is created
 )
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index 722591d5c30..6c010c39af6 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -34,13 +34,13 @@ import software.amazon.awssdk.services.codewhispererruntime.model.Transformation
 import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
 import software.amazon.awssdk.services.codewhispererruntime.model.ValidationException
 import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
-import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.core.utils.WaiterUnrecoverableException
 import software.aws.toolkits.core.utils.Waiters.waitUntil
+import software.aws.toolkits.core.utils.getLogger
 import software.aws.toolkits.jetbrains.core.coroutines.EDT
-import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager
+import software.aws.toolkits.jetbrains.services.codemodernizer.client.GumbyClient
 import software.aws.toolkits.jetbrains.services.codemodernizer.commands.CodeTransformMessageListener
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.BILLING_RATE
 import software.aws.toolkits.jetbrains.services.codemodernizer.constants.JOB_STATISTICS_TABLE_KEY
@@ -64,7 +64,7 @@ data class PollingResult(
     val transformationPlan: TransformationPlan?,
 )
 
-private const val isClientSideBuildEnabled = false
+private const val IS_CLIENT_SIDE_BUILD_ENABLED = false
 
 /**
  * Wrapper around [waitUntil] that polls the API DescribeMigrationJob to check the migration job status.
@@ -120,7 +120,7 @@ suspend fun JobId.pollTransformationStatusAndPlan(
                     newPlan = clientAdaptor.getCodeModernizationPlan(this).transformationPlan()
                 }
                 // TODO: remove flag when releasing CSB
-                if (isClientSideBuildEnabled && newStatus == TransformationStatus.TRANSFORMING && newPlan != null) {
+                if (IS_CLIENT_SIDE_BUILD_ENABLED && newStatus == TransformationStatus.TRANSFORMING && newPlan != null) {
                     attemptLocalBuild(newPlan, this, project)
                 }
                 if (newStatus != state) {
@@ -225,7 +225,7 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
             } catch (e: Exception) {
                 getLogger().error(
                     "Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " +
-                    "$clientInstructionsPath: $e"
+                        "$clientInstructionsPath: $e"
                 )
             } finally {
                 runWriteAction {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
index 99d59891d09..f21c3e7ccd8 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
@@ -5,9 +5,6 @@ package software.aws.toolkits.jetbrains.services.codemodernizer
 
 import com.intellij.openapi.vcs.changes.patch.ApplyPatchDifferentiatedDialog
 import com.intellij.testFramework.LightVirtualFile
-import java.util.zip.ZipOutputStream
-import java.util.zip.ZipEntry
-import java.io.FileOutputStream
 import junit.framework.TestCase.assertEquals
 import junit.framework.TestCase.assertFalse
 import junit.framework.TestCase.assertTrue
@@ -41,6 +38,9 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.downloadCli
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.filterOnlyParentFiles
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
+import java.io.FileOutputStream
+import java.util.zip.ZipEntry
+import java.util.zip.ZipOutputStream
 import kotlin.io.path.Path
 import kotlin.io.path.createTempDirectory
 import kotlin.io.path.exists
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index eebcef29f33..d4d13b0d418 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -8,7 +8,6 @@ import io.mockk.just
 import io.mockk.mockkStatic
 import io.mockk.runs
 import io.mockk.verify
-import kotlin.io.path.createTempFile
 import kotlinx.coroutines.runBlocking
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.Before
@@ -40,6 +39,7 @@ import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
 import software.aws.toolkits.resources.message
 import java.util.concurrent.atomic.AtomicBoolean
 import java.util.zip.ZipFile
+import kotlin.io.path.createTempFile
 
 class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase() {
     @Before
From 15270ec08c3f31406916beafe9b01f5e60db2fb9 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Mon, 28 Apr 2025 09:45:32 -0700
Subject: [PATCH 09/16] alphabetize messages
---
 .../software/aws/toolkits/resources/MessagesBundle.properties   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
index 6ded544b51d..3720c69650e 100644
--- a/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
+++ b/plugins/core/resources/resources/software/aws/toolkits/resources/MessagesBundle.properties
@@ -754,9 +754,9 @@ codemodernizer.migration_plan.header.awsq=
{0} lines of code were submitted for transformation. If you reach the quota for lines of code included in your subscription, you will be charged ${1} for each additional line of code. You might be charged up to ${2} for this transformation. To avoid being charged, stop the transformation job before it completes. For more information on pricing and quotas, see Amazon Q Developer pricing.
 codemodernizer.migration_plan.header.description=Plan to transform your module
 codemodernizer.migration_plan.header.title=Code Transformation plan by Amazon Q
+codemodernizer.migration_plan.substeps.description_completed=Build completed
 codemodernizer.migration_plan.substeps.description_failed=Build failed
 codemodernizer.migration_plan.substeps.description_stopped=Job is stopped
-codemodernizer.migration_plan.substeps.description_completed=Build completed
 codemodernizer.migration_summary.header.title=Transformation summary
 codemodernizer.notification.info.download.started.content=Downloading the updated code
 codemodernizer.notification.info.download.started.title=Download Started
From 6e71b8e281ce1c4ed268b24dfd9ea0b91cc48059 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Mon, 28 Apr 2025 16:28:58 -0700
Subject: [PATCH 10/16] fix detekt
---
 .../codemodernizer/constants/CodeTransformChatItems.kt    | 2 +-
 .../controller/CodeTransformChatController.kt             | 4 +---
 .../codemodernizer/utils/CodeTransformFileUtils.kt        | 8 +++++++-
 3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
index 5800c9ff5ad..dc983f6e6d7 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/constants/CodeTransformChatItems.kt
@@ -458,7 +458,7 @@ fun buildSQLMetadataValidationErrorChatContent(errorReason: String) = CodeTransf
 
 fun buildCustomDependencyVersionsFileInvalidChatContent() = CodeTransformChatMessageContent(
     type = CodeTransformChatMessageType.FinalizedAnswer,
-    message = "The .yaml file you uploaded does not follow the format of the sample YAML file provided.",
+    message = "The file you uploaded does not follow the format of the sample YAML file provided.",
 )
 
 fun buildUserCancelledChatContent() = CodeTransformChatMessageContent(
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index 4ce408528c1..b7575464125 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -370,7 +370,6 @@ class CodeTransformChatController(
         withContext(EDT) {
             val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
                 .withDescription("Select metadata file")
-                .withExtensionFilter("zip")
 
             val selectedZipFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
             val extractedZip = createTempDirectory("codeTransformSQLMetadata", null)
@@ -452,9 +451,8 @@ class CodeTransformChatController(
         withContext(EDT) {
             val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
                 .withDescription("Select .yaml file")
-                .withExtensionFilter("yaml")
             val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
-            val isValid = validateYamlFile(selectedFile.readText())
+            val isValid = validateYamlFile(selectedFile)
             if (!isValid) {
                 codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent())
                 codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
index 8ca05bf3946..2a7dff2aee0 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
@@ -9,6 +9,7 @@ import com.intellij.openapi.application.runReadAction
 import com.intellij.openapi.fileEditor.FileDocumentManager
 import com.intellij.openapi.util.io.FileUtil
 import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.readText
 import kotlinx.coroutines.withContext
 import software.aws.toolkits.core.utils.createParentDirectories
 import software.aws.toolkits.core.utils.createTemporaryZipFile
@@ -195,7 +196,12 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo
     return report
 }
 
-fun validateYamlFile(fileContents: String): Boolean {
+fun validateYamlFile(file: VirtualFile): Boolean {
+    if (!file.name.lowercase().endsWith(".yaml")) {
+        getLogger().error { "Custom versions file is not a YAML file: ${file.name}"}
+        return false
+    }
+    val fileContents = file.readText()
     val requiredKeys = listOf("dependencyManagement:", "identifier:", "targetVersion:")
     for (key in requiredKeys) {
         if (!fileContents.contains(key)) {
From a572783f97456e609b9dbf437ead91f12626589a Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Mon, 28 Apr 2025 16:43:23 -0700
Subject: [PATCH 11/16] add test
---
 .../controller/CodeTransformChatController.kt |  5 +--
 .../utils/CodeTransformFileUtils.kt           |  2 +-
 .../CodeWhispererCodeModernizerUtilsTest.kt   | 39 +++++++++++++++----
 3 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
index b7575464125..7e1f17ce257 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/controller/CodeTransformChatController.kt
@@ -12,7 +12,6 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion
 import com.intellij.openapi.projectRoots.ProjectJdkTable
 import com.intellij.openapi.util.io.FileUtil.createTempDirectory
 import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.readText
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.withContext
@@ -119,8 +118,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTrans
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.toVirtualFile
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.tryGetJdk
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateCustomVersionsFile
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
-import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
 import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
 import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
@@ -452,7 +451,7 @@ class CodeTransformChatController(
             val descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
                 .withDescription("Select .yaml file")
             val selectedFile = FileChooser.chooseFile(descriptor, null, null) ?: return@withContext
-            val isValid = validateYamlFile(selectedFile)
+            val isValid = validateCustomVersionsFile(selectedFile)
             if (!isValid) {
                 codeTransformChatHelper.updateLastPendingMessage(buildCustomDependencyVersionsFileInvalidChatContent())
                 codeTransformChatHelper.addNewMessage(buildStartNewTransformFollowup())
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
index 2a7dff2aee0..c160f157b5b 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
@@ -196,7 +196,7 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo
     return report
 }
 
-fun validateYamlFile(file: VirtualFile): Boolean {
+fun validateCustomVersionsFile(file: VirtualFile): Boolean {
     if (!file.name.lowercase().endsWith(".yaml")) {
         getLogger().error { "Custom versions file is not a YAML file: ${file.name}"}
         return false
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index d4d13b0d418..21bc2cf302d 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -3,6 +3,7 @@
 
 package software.aws.toolkits.jetbrains.services.codemodernizer
 
+import com.intellij.testFramework.LightVirtualFile
 import io.mockk.every
 import io.mockk.just
 import io.mockk.mockkStatic
@@ -10,6 +11,7 @@ import io.mockk.runs
 import io.mockk.verify
 import kotlinx.coroutines.runBlocking
 import org.assertj.core.api.Assertions.assertThat
+import org.jetbrains.yaml.YAMLFileType
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mockito
@@ -33,7 +35,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildF
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
-import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateYamlFile
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateCustomVersionsFile
 import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
 import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
 import software.aws.toolkits.resources.message
@@ -326,7 +328,7 @@ class CodeWhispererCodeModernizerUtilsTest : CodeWhispererCodeModernizerTestBase
     }
 
     @Test
-    fun `WHEN validateYamlFile on fully valid yaml file THEN passes validation`() {
+    fun `WHEN validateCustomVersionsFile on fully valid yaml file THEN passes validation`() {
         val sampleFileContents = """name: "custom-dependency-management"
 description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
 dependencyManagement:
@@ -341,12 +343,13 @@ dependencyManagement:
         versionProperty: "plugin.version"
         """.trimIndent()
 
-        val isValidYaml = validateYamlFile(sampleFileContents)
-        assertThat(isValidYaml).isTrue()
+        val virtualFile = LightVirtualFile("test-valid.yaml", YAMLFileType.YML, sampleFileContents)
+        val isValidFile = validateCustomVersionsFile(virtualFile)
+        assertThat(isValidFile).isTrue()
     }
 
     @Test
-    fun `WHEN validateYamlFile on invalid yaml file THEN fails validation`() {
+    fun `WHEN validateCustomVersionsFile on invalid yaml file THEN fails validation`() {
         val sampleFileContents = """name: "custom-dependency-management"
 description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
 invalidKey:
@@ -361,8 +364,30 @@ invalidKey:
         versionProperty: "plugin.version"
         """.trimIndent()
 
-        val isValidYaml = validateYamlFile(sampleFileContents)
-        assertThat(isValidYaml).isFalse()
+        val virtualFile = LightVirtualFile("test-invalid.yaml", YAMLFileType.YML, sampleFileContents)
+        val isValidFile = validateCustomVersionsFile(virtualFile)
+        assertThat(isValidFile).isFalse()
+    }
+
+    @Test
+    fun `WHEN validateCustomVersionsFile on non-yaml file THEN fails validation`() {
+        val sampleFileContents = """name: "custom-dependency-management"
+description: "Custom dependency version management for Java migration from JDK 8/11/17 to JDK 17/21"
+dependencyManagement:
+  dependencies:
+    - identifier: "com.example:library1"
+        targetVersion: "2.1.0"
+        versionProperty: "library1.version"
+        originType: "FIRST_PARTY"
+  plugins:
+    - identifier: "com.example.plugin"
+        targetVersion: "1.2.0"
+        versionProperty: "plugin.version"
+        """.trimIndent()
+
+        val virtualFile = LightVirtualFile("test-invalid-file-type.txt", sampleFileContents)
+        val isValidFile = validateCustomVersionsFile(virtualFile)
+        assertThat(isValidFile).isFalse()
     }
 
     @Test
From efd0412c87d1458967580132ce2a03f770346369 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Mon, 28 Apr 2025 17:30:45 -0700
Subject: [PATCH 12/16] fix detekt again
---
 .../codemodernizer/CodeModernizerSession.kt   |  2 +-
 .../utils/CodeTransformApiUtils.kt            | 26 ++++++++++---------
 .../utils/CodeTransformFileUtils.kt           |  2 +-
 .../CodeWhispererCodeModernizerUtilsTest.kt   |  2 +-
 4 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
index b19bd8e1fcf..b1ff57d6c8d 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/CodeModernizerSession.kt
@@ -338,7 +338,7 @@ class CodeModernizerSession(
     fun resumeTransformation() {
         val clientAdaptor = GumbyClient.getInstance(sessionContext.project)
         clientAdaptor.resumeCodeTransformation(state.currentJobId as JobId, TransformationUserActionStatus.COMPLETED)
-        getLogger().info("Successfully resumed transformation with status of COMPLETED")
+        getLogger().info { "Successfully resumed transformation with status of COMPLETED" }
     }
 
     fun rejectHilAndContinue(): ResumeTransformationResponse {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index 6c010c39af6..a3f97a4aec6 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -36,7 +36,9 @@ import software.amazon.awssdk.services.codewhispererruntime.model.ValidationExce
 import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
 import software.aws.toolkits.core.utils.WaiterUnrecoverableException
 import software.aws.toolkits.core.utils.Waiters.waitUntil
+import software.aws.toolkits.core.utils.error
 import software.aws.toolkits.core.utils.getLogger
+import software.aws.toolkits.core.utils.info
 import software.aws.toolkits.jetbrains.core.coroutines.EDT
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeModernizerManager
 import software.aws.toolkits.jetbrains.services.codemodernizer.CodeTransformTelemetryManager
@@ -172,22 +174,22 @@ suspend fun JobId.pollTransformationStatusAndPlan(
 
 suspend fun attemptLocalBuild(plan: TransformationPlan, jobId: JobId, project: Project) {
     val artifactId = getClientInstructionArtifactId(plan)
-    getLogger().info("Found artifactId: $artifactId")
+    getLogger().info { "Found artifactId: $artifactId" }
     if (artifactId != null) {
         val clientInstructionsPath = downloadClientInstructions(jobId, artifactId, project)
-        getLogger().info("Downloaded client instructions for job ${jobId.id} and artifact $artifactId at: $clientInstructionsPath")
+        getLogger().info { "Downloaded client instructions for job ${jobId.id} and artifact $artifactId at: $clientInstructionsPath" }
         processClientInstructions(clientInstructionsPath, jobId, artifactId, project)
-        getLogger().info("Finished processing client instructions for job ${jobId.id} and artifact $artifactId")
+        getLogger().info { "Finished processing client instructions for job ${jobId.id} and artifact $artifactId" }
     }
 }
 
 suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId, artifactId: String, project: Project) {
     var copyOfProjectSources = createTempDirectory("originalCopy_${jobId.id}_$artifactId", null).toPath()
-    getLogger().info("About to copy the original project ZIP to: $copyOfProjectSources")
+    getLogger().info { "About to copy the original project ZIP to: $copyOfProjectSources" }
     val originalProjectZip = CodeModernizerManager.getInstance(project).codeTransformationSession?.sessionContext?.originalUploadZipPath
     originalProjectZip?.let { unzipFile(it, copyOfProjectSources, isSqlMetadata = false, extractOnlySources = true) }
     copyOfProjectSources = copyOfProjectSources.resolve("sources") // where the user's source code is within the upload ZIP
-    getLogger().info("Copied and unzipped original project sources to: $copyOfProjectSources")
+    getLogger().info { "Copied and unzipped original project sources to: $copyOfProjectSources" }
 
     val targetDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(copyOfProjectSources.toFile())
         ?: throw RuntimeException("Cannot find copy of project sources directory")
@@ -217,16 +219,16 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
                     null,
                     null
                 ).execute()
-                getLogger().info("Successfully applied patch file at $clientInstructionsPath")
+                getLogger().info { "Successfully applied patch file at $clientInstructionsPath" }
 
                 val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(clientInstructionsPath.toFile())
                     ?: throw RuntimeException("Cannot find patch file at $clientInstructionsPath")
                 FileEditorManager.getInstance(project).openFile(virtualFile, true)
             } catch (e: Exception) {
-                getLogger().error(
+                getLogger().error {
                     "Error applying intermediate diff.patch for job ${jobId.id} and artifact $artifactId located at " +
                         "$clientInstructionsPath: $e"
-                )
+                }
             } finally {
                 runWriteAction {
                     ModuleManager.getInstance(project).disposeModule(tempModule)
@@ -236,21 +238,21 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
     }
 
     val (exitCode, buildOutput) = runClientSideBuild(targetDir, CodeModernizerManager.LOG, project)
-    getLogger().info("Ran client-side build with an exit code of $exitCode")
+    getLogger().info { "Ran client-side build with an exit code of $exitCode" }
     val uploadZip = createClientSideBuildUploadZip(exitCode, buildOutput)
-    getLogger().info("Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}")
+    getLogger().info { "Created client-side build result upload zip for job ${jobId.id} and artifact $artifactId: ${uploadZip.path}" }
     val uploadContext = UploadContext.fromTransformationUploadContext(
         TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build()
     )
     getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId")
     try {
         CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext)
-        getLogger().info("Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now")
+        getLogger().info { "Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now" }
         CodeModernizerManager.getInstance(project).codeTransformationSession?.resumeTransformation()
     } finally {
         uploadZip.deleteRecursively()
         copyOfProjectSources.toFile().deleteRecursively()
-        getLogger().info("Deleted copy of project sources and client-side build upload ZIP")
+        getLogger().info { "Deleted copy of project sources and client-side build upload ZIP" }
     }
     // switch back to Transformation Hub view
     runInEdt {
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
index c160f157b5b..ea19a954342 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformFileUtils.kt
@@ -198,7 +198,7 @@ fun parseXmlDependenciesReport(pathToXmlDependency: Path): DependencyUpdatesRepo
 
 fun validateCustomVersionsFile(file: VirtualFile): Boolean {
     if (!file.name.lowercase().endsWith(".yaml")) {
-        getLogger().error { "Custom versions file is not a YAML file: ${file.name}"}
+        getLogger().error { "Custom versions file is not a YAML file: ${file.name}" }
         return false
     }
     val fileContents = file.readText()
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
index 21bc2cf302d..37482669432 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerUtilsTest.kt
@@ -34,8 +34,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.getTableMap
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.parseBuildFile
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.pollTransformationStatusAndPlan
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.refreshToken
-import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateCustomVersionsFile
+import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
 import software.aws.toolkits.jetbrains.utils.notifyStickyWarn
 import software.aws.toolkits.jetbrains.utils.rules.addFileToModule
 import software.aws.toolkits.resources.message
From 7ebc0f8590468eb764b51552219f5a6a9162900e Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Tue, 29 Apr 2025 10:07:04 -0700
Subject: [PATCH 13/16] fix tests
---
 .../CodeWhispererCodeModernizerSessionTest.kt | 36 +++++++++++--------
 1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt
index 044cb72a757..72fef62a11e 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerSessionTest.kt
@@ -26,6 +26,7 @@ import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TemporaryFolder
+import org.mockito.ArgumentMatchers.nullable
 import org.mockito.Mockito.doReturn
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.spy
@@ -45,6 +46,7 @@ import software.amazon.awssdk.awscore.util.AwsHeader
 import software.amazon.awssdk.http.SdkHttpResponse
 import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlResponse
 import software.amazon.awssdk.services.codewhispererruntime.model.TransformationStatus
+import software.amazon.awssdk.services.codewhispererruntime.model.UploadContext
 import software.amazon.awssdk.services.ssooidc.model.SsoOidcException
 import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState
 import software.aws.toolkits.jetbrains.services.codemodernizer.model.CodeModernizerJobCompletedResult
@@ -410,12 +412,12 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
     fun `CodeModernizer can create modernization job`() = runTest {
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
+        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
         doNothing().whenever(clientAdaptorSpy).uploadArtifactToS3(any(), any(), any(), any(), any())
         doReturn(exampleStartCodeMigrationResponse).whenever(clientAdaptorSpy).startCodeModernization(any(), any(), any())
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.Started(jobId))
-        verify(clientAdaptorSpy, times(1)).createGumbyUploadUrl(any())
+        verify(clientAdaptorSpy, times(1)).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
         verify(clientAdaptorSpy, times(1)).startCodeModernization(any(), any(), any())
         verify(clientAdaptorSpy, times(1)).uploadArtifactToS3(any(), any(), any(), any(), any())
         verifyNoMoreInteractions(clientAdaptorSpy)
@@ -425,7 +427,7 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
     fun `CodeModernizer cannot upload payload due to already disposed`() = runTest {
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
+        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
         doAnswer { throw AlreadyDisposedException("mock exception") }.whenever(clientAdaptorSpy).uploadArtifactToS3(any(), any(), any(), any(), any())
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.Disposed)
@@ -436,7 +438,7 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
         setupConnection(BearerTokenAuthState.AUTHORIZED)
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doAnswer { throw SsoOidcException.builder().build() }.whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
+        doAnswer { throw SsoOidcException.builder().build() }.whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.CREDENTIALS_EXPIRED))
     }
@@ -454,8 +456,11 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
     fun `CodeModernizer cannot upload payload due to presigned url issue`() = runTest {
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
-        doAnswer { throw HttpRequests.HttpStatusException("mock error", 403, "mock url") }.whenever(testSessionSpy).uploadPayload(any())
+        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
+        doAnswer { throw HttpRequests.HttpStatusException("mock error", 403, "mock url") }.whenever(testSessionSpy).uploadPayload(
+            any(),
+            nullable(UploadContext::class.java)
+        )
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.PRESIGNED_URL_EXPIRED))
         verify(testSessionStateSpy, times(1)).putJobHistory(any(), eq(TransformationStatus.FAILED), any(), any())
@@ -466,8 +471,11 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
     fun `CodeModernizer cannot upload payload due to other status code`() = runTest {
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
-        doAnswer { throw HttpRequests.HttpStatusException("mock error", 407, "mock url") }.whenever(testSessionSpy).uploadPayload(any())
+        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
+        doAnswer { throw HttpRequests.HttpStatusException("mock error", 407, "mock url") }.whenever(testSessionSpy).uploadPayload(
+            any(),
+            nullable(UploadContext::class.java)
+        )
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.HTTP_ERROR(407)))
         verify(testSessionStateSpy, times(1)).putJobHistory(any(), eq(TransformationStatus.FAILED), any(), any())
@@ -478,7 +486,7 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
     fun `CodeModernizer cannot upload payload due to unknown client-side issue`() = runTest {
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
+        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
         doAnswer { throw Exception("mock client-side exception") }.whenever(clientAdaptorSpy).uploadArtifactToS3(any(), any(), any(), any(), any())
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.OTHER("mock client-side exception")))
@@ -490,8 +498,8 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
     fun `CodeModernizer cannot upload payload due to connection refused`() = runTest {
         doReturn(ZipCreationResult.Succeeded(File("./tst-resources/codemodernizer/test.txt")))
             .whenever(testSessionContextSpy).createZipWithModuleFiles(any())
-        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any())
-        doAnswer { throw ConnectException("mock exception") }.whenever(testSessionSpy).uploadPayload(any())
+        doReturn(exampleCreateUploadUrlResponse).whenever(clientAdaptorSpy).createGumbyUploadUrl(any(), nullable(UploadContext::class.java))
+        doAnswer { throw ConnectException("mock exception") }.whenever(testSessionSpy).uploadPayload(any(), nullable(UploadContext::class.java))
         val result = testSessionSpy.createModernizationJob(MavenCopyCommandsResult.Success(File("./mock/path/")))
         assertThat(result).isEqualTo(CodeModernizerStartJobResult.ZipUploadFailed(UploadFailureReason.CONNECTION_REFUSED))
         verify(testSessionStateSpy, times(1)).putJobHistory(any(), eq(TransformationStatus.FAILED), any(), any())
@@ -558,14 +566,14 @@ class CodeWhispererCodeModernizerSessionTest : CodeWhispererCodeModernizerTestBa
         val expectedSha256checksum: String =
             Base64.getEncoder().encodeToString(DigestUtils.sha256(FileInputStream(expectedFilePath.toAbsolutePath().toString())))
         clientAdaptorSpy.stub {
-            onGeneric { clientAdaptorSpy.createGumbyUploadUrl(any()) }
+            onGeneric { clientAdaptorSpy.createGumbyUploadUrl(any(), nullable(UploadContext::class.java)) }
                 .thenReturn(gumbyUploadUrlResponse)
         }
         wireMock.stubFor(put(urlEqualTo("/")).willReturn(aResponse().withStatus(200)))
-        testSessionSpy.uploadPayload(expectedFilePath.toFile())
+        testSessionSpy.uploadPayload(expectedFilePath.toFile(), null)
 
         val inOrder = inOrder(clientAdaptorSpy)
-        inOrder.verify(clientAdaptorSpy).createGumbyUploadUrl(eq(expectedSha256checksum))
+        inOrder.verify(clientAdaptorSpy).createGumbyUploadUrl(eq(expectedSha256checksum), nullable(UploadContext::class.java))
         inOrder.verify(clientAdaptorSpy).uploadArtifactToS3(
             eq(gumbyUploadUrlResponse.uploadUrl()),
             eq(expectedFilePath.toFile()),
From d986546d32eac5bc0379fffc2ccb824ffc8e872d Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Tue, 29 Apr 2025 12:15:05 -0700
Subject: [PATCH 14/16] fix tests again
---
 .../utils/CodeTransformApiUtils.kt            |  2 +-
 .../CodeWhispererCodeModernizerTest.kt        | 29 +++++++++++++++----
 2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
index a3f97a4aec6..6495508328b 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/utils/CodeTransformApiUtils.kt
@@ -244,7 +244,7 @@ suspend fun processClientInstructions(clientInstructionsPath: Path, jobId: JobId
     val uploadContext = UploadContext.fromTransformationUploadContext(
         TransformationUploadContext.builder().jobId(jobId.id).uploadArtifactType("ClientBuildResult").build()
     )
-    getLogger().info("About to call uploadPayload for job ${jobId.id} and artifact $artifactId")
+    getLogger().info { "About to call uploadPayload for job ${jobId.id} and artifact $artifactId" }
     try {
         CodeModernizerManager.getInstance(project).codeTransformationSession?.uploadPayload(uploadZip, uploadContext)
         getLogger().info { "Upload succeeded; about to call ResumeTransformation for job ${jobId.id} and artifact $artifactId now" }
diff --git a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
index f21c3e7ccd8..c5927c6d733 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codemodernizer/CodeWhispererCodeModernizerTest.kt
@@ -38,6 +38,7 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.downloadCli
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.filterOnlyParentFiles
 import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
 import software.aws.toolkits.telemetry.CodeTransformPreValidationError
+import java.io.ByteArrayOutputStream
 import java.io.FileOutputStream
 import java.util.zip.ZipEntry
 import java.util.zip.ZipOutputStream
@@ -160,8 +161,15 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() {
             DownloadArtifactResult.ParseZipFailure(
                 ParseZipFailureReason(TransformationDownloadArtifactType.LOGS, "Could not find build log")
             )
-        val mockDownloadResult = listOf()
-        doReturn(mockDownloadResult).whenever(clientAdaptorSpy)
+        val mockZipBytes = ByteArrayOutputStream().use { bos ->
+            ZipOutputStream(bos).use { zos ->
+                zos.putNextEntry(ZipEntry("some-other-file.txt"))
+                zos.write("mock content".toByteArray())
+                zos.closeEntry()
+            }
+            bos.toByteArray()
+        }
+        doReturn(listOf(mockZipBytes)).whenever(clientAdaptorSpy)
             .downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS)
         val result = handler.downloadArtifact(jobId, TransformationDownloadArtifactType.LOGS, false)
         verify(clientAdaptorSpy, times(1)).downloadExportResultArchive(jobId, null, TransformationDownloadArtifactType.LOGS)
@@ -172,10 +180,21 @@ class CodeWhispererCodeModernizerTest : CodeWhispererCodeModernizerTestBase() {
     fun `downloadClientInstructions downloads and extracts patch file`() = runBlocking {
         val jobId = JobId("test-job-id")
         val artifactId = "test-artifact-id"
-        val mockBytes = "mock content".toByteArray()
-        doReturn(mockBytes).whenever(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId)
+        val mockZipBytes = ByteArrayOutputStream().use { bos ->
+            ZipOutputStream(bos).use { zos ->
+                zos.putNextEntry(ZipEntry("diff.patch"))
+                zos.write("mock content".toByteArray())
+                zos.closeEntry()
+            }
+            bos.toByteArray()
+        }
+        doReturn(listOf(mockZipBytes)).whenever(clientAdaptorSpy).downloadExportResultArchive(
+            jobId,
+            artifactId,
+            TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS
+        )
         val result = downloadClientInstructions(jobId, artifactId, project)
-        verify(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId)
+        verify(clientAdaptorSpy).downloadExportResultArchive(jobId, artifactId, TransformationDownloadArtifactType.CLIENT_INSTRUCTIONS)
         assertEquals(result.fileName.toString(), "diff.patch")
     }
 
From 4fe84a66228f1790c0043e27a7fb0987304caae9 Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Thu, 1 May 2025 16:49:02 -0700
Subject: [PATCH 15/16] address comment
---
 .../codemodernizer/ideMaven/MavenRunnerUtils.kt  |   2 +-
 .../codemodernizer/ideMaven/TransformRunnable.kt |   4 +++-
 .../ElasticGumbyClientMavenSupport-1.0.jar       | Bin 0 -> 7657 bytes
 3 files changed, 4 insertions(+), 2 deletions(-)
 create mode 100644 plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
index 2168e00eb23..35ecb95564e 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/MavenRunnerUtils.kt
@@ -47,7 +47,7 @@ fun runClientSideBuild(targetDir: VirtualFile, logger: Logger, project: Project)
             FileEditorManager.getInstance(project).openFile(buildLogOutputVirtualFile, true)
         }
     }
-    return buildRunnable.exitCode to buildRunnable.getOutput().toString()
+    return buildRunnable.getExitCode() to buildRunnable.getOutput().toString()
 }
 
 fun runHilMavenCopyDependency(
diff --git a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt
index 7741306cb7c..cc5307b6062 100644
--- a/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt
+++ b/plugins/amazonq/codetransform/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codemodernizer/ideMaven/TransformRunnable.kt
@@ -4,13 +4,15 @@
 package software.aws.toolkits.jetbrains.services.codemodernizer.ideMaven
 
 class TransformRunnable : Runnable {
-    var exitCode: Int? = null
+    private var exitCode: Int? = null
     private var output: String? = null
 
     fun setExitCode(i: Int) {
         exitCode = i
     }
 
+    fun getExitCode(): Int? = exitCode
+
     override fun run() {
         // do nothing
     }
diff --git a/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar b/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar
new file mode 100644
index 0000000000000000000000000000000000000000..de2cf80be8ab941f2793236db8caab1fb4288c1e
GIT binary patch
literal 7657
zcmb_>1yoyW);3nOP~2S$MT>ip00lyEm*P$cZp8@>#a)U!4N_c+mg4TN#VJ~#^oP}%
zd*}9ke`jW`*;(i0&B}hBz0c0sZ<75e%E2Sx!oVOS!!*jIYs1_d+{5YKQ0@;PKvj(8
zrGgY2JdEOB9IJfb4oU7Ei0+Sj_@9nIF@={>02NhMpwuaFpkH2&g>@8Nj)iGxV7OYD
zeS&jkb8Qpu7qWZ&A5jtR*Tx{*zXkkPAB=za7}^?ofb0xi9e?Znkmdv9pWdc6hK^2_
z#^%npM()3bQvV)mY-4F^=k!~Kr~eUyt)Yvl-QReolI6qp?mvyZM=&rp{{@et1IWtM
z*a>K8XK7~Y=p+HMvAKT?OaV}YuS3l23AkB^Lidlh#+lkz?j
z>e6c|(f#BL+m3aN%)5loPgaPu-F6IMhswxuULXij=1r#Wd2I`FnqSQBwPnH8M})iQ
zy>)pD9t~oaSf*cI)BmKl*i_rf2-o@c`%5Ov3iiChumrn}kps%3HB4QIb~Xt)==eta
zB+K|!pb*dVqB`Qed3{XTcM;PoI^ypAF&`{=8)CV!(jJjPOm=s6*`$gzt+-pMjmYdm
zch6<&Qcq)IxXF{lLTuiCEY`U+N_eNZl)IBAQ*xb7=R5zZRC=XZL6Isi7y*Q*!
z!Waw-In?s8^qy@4TXRR}@@=h<5cG1?RNnA#NhlOqdFiC0Lp~Niks~;oVPeoruTn!S
zSqLeqbmLqaY1(k)>wJH^XHgh1x=Inuu$HnqDx7nqOBQ>yAFwj_5h?LoNVrnODEg$+
z#EO$z62@z{y4$;iAw1CmBfi=(Whov>K#zkkZs|ObqcWanL2)$Mu&gY%v5trrKxsWs
zz8vl@SI)jsV}AG=F>9Sso$xtYBNL%Vzj7!YF%?$1wyNi*z=~mz^w=Dkd5?`uPOZ|N
z0F6w``4t4|((bESu-MSfA|p|khz$l|grepzRvdWKL
zvuOEH0g>BHzHn$-dLSuSnjs12&yt-bn4x|5F*@eu+jlkjpa&H#Qv+`#`ay+bYqNX_R@G%S=WzdV(Z^a-DK}#o`8@W-rnf
zoW(o&0oexMT+o(TMGnPnwdVARvh|lS8ooPih-7rz6d-5Vpg)#xRrKRAMIXluPgP&V
z51h|UXLIr6$FXIOl7pX*j)nV#HaBE`z)FB%|GKf2tL(?u-Zx#n(qoxmdbF4eqVbyK#57o33<
z4oPUJi0_ki;gjG{@X!YbYaE>1m(`r+TWKjEv!O3HS)e7@`iNORapYdiQA_}u#I(Tj
z2BiC-3S3yvDxdXkGqxt*Cx|M22zSi_pz|1velS8P0CxppV=*>0JzPbTz
z25lSYg+%u>@yW<8=Zpdn%fSZB{`QYuzjpR(9s4KLVD
zyDulW@cUj^?r4lm4a$lsYE(QYA7{^wSj?JqBwQo30k;3gPr-%BO_u!YZcNG3OJ78%hhPEvYzJ9O-zu*={!1=b*>fa>DpTnEkK=!TDQ`h#<094iejTDnkmD`i$m==(fBB;u+hBfa5<>98M`OmgumQRwPz%=M}5(GS%1aR=ipWu5_NR&|AE$P_MZW-ClZ0-$$EQ
z>+B=yu+`jp~&sS7M^xFda*pO=N^A9mf9Ir|jh(rW(j%^3#}ON~n6TyZInn
zSe%)T%z}7I%z}e9iST}7`s1@H&?hNihG&=+`b5GeXCzp5K*=2SDNCmA#{(0J1;+Rt
zaGX+XXb3F51B6i-SjoI$je}_n!TiakhM7@vN<*AIAgqz=2%9GNE~UBsB-~SH=5}#d
z16km3->Cv&@zSTL0Ob{W^zcWCk>lJ4yX#iFjJ#wCnkB2x$&zwqvsvsIXr#vK2Nj6w
z%xKIyK8;niG;Dm#jdAOEt`gPTPZLeVC_uGWGZTss>{4(ZVqBn$gNW?{s(eYeMPR|U
z%`8i-W(^c$E{r9w#w>v^$GlX+qN
z4XUEO=i%2`nO}?gB&D4%L%;=((42q>PcaCqUBO-YVrS-AXYIn25yQB8$9|1tO8u<9UxiODsor&BCBCv6MXr16qfOTMs!`m~6uo6cnxRO{G7MEru%
z&`~G#zRVw%T*f
zF*Fd&ZWz^-)uGBQHp0}cL{_)zvelwbgm9^FJ|$0BFo`1EpsGuEGo&j3bTW^}cHMQu
zS&|RH91JaM0Fb+xp68hW;tq8X@PSrUm{F^&WUl?UdIi48yHF3ufpe3JRq{2hvEG+s
z<{MQpP8~uW6m*?2Ce&5D8T!r{8IRZWrwF>@7lDr?_@e6e+>j2}^JGcY{rf7w;?epM
zZ{jwtSjmnOEoB|{pJVfL2Hu?bLN0f&ByLAd{2R>=%#z$WO-$!)3%OHVq7>d%xKA$y
z2Xm#5oUkut4PP_%M|CYeCL|gP)Q--u)!
z6kN>(jpK1Q1fuGSl&F(v8Rmb*T2gxAh>qmQ;*`4WgE19Zxy*
z{)muhjyHr&k(yUvb6u(PJ*ELIdr#S>RytYRhC_VAM!&!v_VDNsDFJOvatuGST$f<@
zi#$RL{j6Jpu2U}wzJ-~X=~L@wbcdXAmBY&B6V_p=<=5|o)Mv%7K`5%YTEo>h3MZR-
znJq)>p2T-jz00y(2i|(|1<|J38ec!*_7}N~$Z8HLxnD2uU9}2n+ks7qYw1ELl;3>G
zgxJhQ=m@LpKI(>eC%Gbv_J~?sg+}?r2YFCQMVpav^54FWyNp=y-fj6rd>v;Jv-^Ql
zIm9RN=yMi|O%^s!L0}du`VZ=n)0<*`2{){^w*t4N?Ts460XHJou4F&_e&8kx>%uG2
z=4#;az|~F?^nIsEBPzNh`H{Qo<9v(V#&pras=&bRc(r5W$YYlG$Se|7JADo3+w}81
z{nzQ_we9to)`wQMZ4IWtb1j%T;lar748@;T!qkJ=&`7&4fgMkEb^FXuF7jw^|lXUZN
zw*bo38M&zbqZVh_g8c&urM#wm4Uh8|FPnr8r(fxw*lh5RH`?}e1HP=T<;qx)*Xq-<
zqA`vl96nX;!zZ1w^Qjr;rg
zBI0jwD&1wZKV03tbsq~*O|zx3JX#JfnV^iu)I3F9Qwtr
zG!096UeDo{U>kb`#?Ch`7&mt{H%F9|kdf@dORbM(a{}X0pwi$&mA_vYj&nxbq}Wzd
zInz8RXOcHxl1lobPBWRoUah7yFOn|zDsx>5>rfz-C)`Gq-TnIk)Pe&$RH2_E&ENlA
zO3`$^M-~fLV;uQgO&R^tizgnM%Ii{5!aGGL9*|8h<;sPzg?xJ6Dr|>EeMT(pS%dZ!
z?Wvlt0i9O~z-BRWH7V`Z7{_U>$)$zkZ8-k66f6ZW(NaSKh6?ASo1OQzR8T!hZme-Y
z(+rjUET4|#WJ0!5WM*@dY+O+8wt>$!@Xe^OgTq`OsXipAMiwcHFh_+z%}6U{hUNX4
z5nar{Q`_SB6s6_R4LQ)NNj@o16El?yYVdkC-liy&gfO0A`SZZ0U5~Ozye!P!U@z!c
z2f4XS3gu2OiV68672It?2Icg3D_Tox(mpMpLCX*Z+LYuiJ2OFztC`(H#8m>=JJfff
z*>cR}>#*KKEsBCL2aLMZn5CYm)sGZbn)X$Z(?8~1q%uHhn{8m8nG|}%oJ-VW6B1Pt
zbO;?m^yrn+S!VOIWay8t?{|2dy7S%qa045_TMld+SNeXz;ZfBJ)OT`53Rx5Q^6k
zXLUtLWyQ9-!c6rgC5ej32|@ER$7z;ltf?(X{UgJ(
zp6}tFH>3;+#PQ29|QTeg(owCGRn#eryfN$91Y@^at-$XIa%ABq$`+%8FPt!xD
zMnJ`4CRSF#_L3!Dy+owplNsG5jj+wsHl7_y}ReAAdo$r-D|W{r48K~n5$3oHl8O5|tnHC8-0bOzpKdWN(#7?Hn<`;Zb8
zyG&VNsMrZbdpdoL0xpJg<44DqXhK`V4hR(U|Avi)2Tis2r;m{p($3=j80s;N5ZQ`q
za5c^)k=xecgU^k3*G!jKWOv00&-b0Z!wOT)cApmG?T%yYQ$;Mk@O(T!p;4j9^N@m4
zv3O5Wwo5C#)P>T>{Yliz&thd4%r%XUJE{dfi3OqoVvK8AJ9r`vYqQpqa|UkKcXN(U
z6Jn8=Zk1}k(t+p{88qM==rBvmNxB-avV>nm!0K4!m3IyDc-RZFkkbtrcR2`FtZmNw
zX6UwL=3-pGCa4^@JNt@Z!q3pGx`k
zDlKY8c&CGL>N65s0`9zUVouDozY{`_@pD$nyLR-tb{4yKz}Ktf0>}DB+qRMm^P!`z
zn7NnW-lmz>G{QGeI6Oo-u3ckR%0?I4AgKEcYRpqHYc
zlM)qodJ{k66+!r&cJwPF2SGH>t3pXS5f(X{HwxA+amUO3i#=6u?@okEh?E#w8ed9`M*PHT{l
zrwW3OvH5ndJQb$&!ti83tG5T)-4E6sS>0@HOk0MG7NoE$Z4X*M_e-KRQcv2{bpEdr=)&EDiDDpfKJ-r}}iL2DhwQHQb-aY$je&+F<
zX*a3I5bSPP+VT2~oEUc75~*w>mcQkkk2$OvUjK4&LUaR3Q4SUk7ykb*w%pg^-Y{Vf
z#2%jiDC4iNU!|7^=LgI4W4u5A0s9vr=2wOX?|-U14|>Z_dkE}uzkJY2eusEaUw+yH
zBK3axS9Rrg*at1;FK*`8Bg&N85j926sQ~{`d9!$Myc(%>Fj${xy+br-pwf
z!jAl(C-V0h;;(Uj9mf3`N9n8b6e4d}l|AD^0lz-VW73CfwKKP^GKP>M1+xkJIh53JipaX>f
literal 0
HcmV?d00001
From 2e42f245ea4160487eb9c7d60003993e7e6d8bae Mon Sep 17 00:00:00 2001
From: David Hasani 
Date: Thu, 1 May 2025 16:50:43 -0700
Subject: [PATCH 16/16] remove jar
---
 .../ElasticGumbyClientMavenSupport-1.0.jar       | Bin 7657 -> 0 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar
diff --git a/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar b/plugins/amazonq/contrib/ElasticGumbyClientMavenSupport-1.0.jar
deleted file mode 100644
index de2cf80be8ab941f2793236db8caab1fb4288c1e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 7657
zcmb_>1yoyW);3nOP~2S$MT>ip00lyEm*P$cZp8@>#a)U!4N_c+mg4TN#VJ~#^oP}%
zd*}9ke`jW`*;(i0&B}hBz0c0sZ<75e%E2Sx!oVOS!!*jIYs1_d+{5YKQ0@;PKvj(8
zrGgY2JdEOB9IJfb4oU7Ei0+Sj_@9nIF@={>02NhMpwuaFpkH2&g>@8Nj)iGxV7OYD
zeS&jkb8Qpu7qWZ&A5jtR*Tx{*zXkkPAB=za7}^?ofb0xi9e?Znkmdv9pWdc6hK^2_
z#^%npM()3bQvV)mY-4F^=k!~Kr~eUyt)Yvl-QReolI6qp?mvyZM=&rp{{@et1IWtM
z*a>K8XK7~Y=p+HMvAKT?OaV}YuS3l23AkB^Lidlh#+lkz?j
z>e6c|(f#BL+m3aN%)5loPgaPu-F6IMhswxuULXij=1r#Wd2I`FnqSQBwPnH8M})iQ
zy>)pD9t~oaSf*cI)BmKl*i_rf2-o@c`%5Ov3iiChumrn}kps%3HB4QIb~Xt)==eta
zB+K|!pb*dVqB`Qed3{XTcM;PoI^ypAF&`{=8)CV!(jJjPOm=s6*`$gzt+-pMjmYdm
zch6<&Qcq)IxXF{lLTuiCEY`U+N_eNZl)IBAQ*xb7=R5zZRC=XZL6Isi7y*Q*!
z!Waw-In?s8^qy@4TXRR}@@=h<5cG1?RNnA#NhlOqdFiC0Lp~Niks~;oVPeoruTn!S
zSqLeqbmLqaY1(k)>wJH^XHgh1x=Inuu$HnqDx7nqOBQ>yAFwj_5h?LoNVrnODEg$+
z#EO$z62@z{y4$;iAw1CmBfi=(Whov>K#zkkZs|ObqcWanL2)$Mu&gY%v5trrKxsWs
zz8vl@SI)jsV}AG=F>9Sso$xtYBNL%Vzj7!YF%?$1wyNi*z=~mz^w=Dkd5?`uPOZ|N
z0F6w``4t4|((bESu-MSfA|p|khz$l|grepzRvdWKL
zvuOEH0g>BHzHn$-dLSuSnjs12&yt-bn4x|5F*@eu+jlkjpa&H#Qv+`#`ay+bYqNX_R@G%S=WzdV(Z^a-DK}#o`8@W-rnf
zoW(o&0oexMT+o(TMGnPnwdVARvh|lS8ooPih-7rz6d-5Vpg)#xRrKRAMIXluPgP&V
z51h|UXLIr6$FXIOl7pX*j)nV#HaBE`z)FB%|GKf2tL(?u-Zx#n(qoxmdbF4eqVbyK#57o33<
z4oPUJi0_ki;gjG{@X!YbYaE>1m(`r+TWKjEv!O3HS)e7@`iNORapYdiQA_}u#I(Tj
z2BiC-3S3yvDxdXkGqxt*Cx|M22zSi_pz|1velS8P0CxppV=*>0JzPbTz
z25lSYg+%u>@yW<8=Zpdn%fSZB{`QYuzjpR(9s4KLVD
zyDulW@cUj^?r4lm4a$lsYE(QYA7{^wSj?JqBwQo30k;3gPr-%BO_u!YZcNG3OJ78%hhPEvYzJ9O-zu*={!1=b*>fa>DpTnEkK=!TDQ`h#<094iejTDnkmD`i$m==(fBB;u+hBfa5<>98M`OmgumQRwPz%=M}5(GS%1aR=ipWu5_NR&|AE$P_MZW-ClZ0-$$EQ
z>+B=yu+`jp~&sS7M^xFda*pO=N^A9mf9Ir|jh(rW(j%^3#}ON~n6TyZInn
zSe%)T%z}7I%z}e9iST}7`s1@H&?hNihG&=+`b5GeXCzp5K*=2SDNCmA#{(0J1;+Rt
zaGX+XXb3F51B6i-SjoI$je}_n!TiakhM7@vN<*AIAgqz=2%9GNE~UBsB-~SH=5}#d
z16km3->Cv&@zSTL0Ob{W^zcWCk>lJ4yX#iFjJ#wCnkB2x$&zwqvsvsIXr#vK2Nj6w
z%xKIyK8;niG;Dm#jdAOEt`gPTPZLeVC_uGWGZTss>{4(ZVqBn$gNW?{s(eYeMPR|U
z%`8i-W(^c$E{r9w#w>v^$GlX+qN
z4XUEO=i%2`nO}?gB&D4%L%;=((42q>PcaCqUBO-YVrS-AXYIn25yQB8$9|1tO8u<9UxiODsor&BCBCv6MXr16qfOTMs!`m~6uo6cnxRO{G7MEru%
z&`~G#zRVw%T*f
zF*Fd&ZWz^-)uGBQHp0}cL{_)zvelwbgm9^FJ|$0BFo`1EpsGuEGo&j3bTW^}cHMQu
zS&|RH91JaM0Fb+xp68hW;tq8X@PSrUm{F^&WUl?UdIi48yHF3ufpe3JRq{2hvEG+s
z<{MQpP8~uW6m*?2Ce&5D8T!r{8IRZWrwF>@7lDr?_@e6e+>j2}^JGcY{rf7w;?epM
zZ{jwtSjmnOEoB|{pJVfL2Hu?bLN0f&ByLAd{2R>=%#z$WO-$!)3%OHVq7>d%xKA$y
z2Xm#5oUkut4PP_%M|CYeCL|gP)Q--u)!
z6kN>(jpK1Q1fuGSl&F(v8Rmb*T2gxAh>qmQ;*`4WgE19Zxy*
z{)muhjyHr&k(yUvb6u(PJ*ELIdr#S>RytYRhC_VAM!&!v_VDNsDFJOvatuGST$f<@
zi#$RL{j6Jpu2U}wzJ-~X=~L@wbcdXAmBY&B6V_p=<=5|o)Mv%7K`5%YTEo>h3MZR-
znJq)>p2T-jz00y(2i|(|1<|J38ec!*_7}N~$Z8HLxnD2uU9}2n+ks7qYw1ELl;3>G
zgxJhQ=m@LpKI(>eC%Gbv_J~?sg+}?r2YFCQMVpav^54FWyNp=y-fj6rd>v;Jv-^Ql
zIm9RN=yMi|O%^s!L0}du`VZ=n)0<*`2{){^w*t4N?Ts460XHJou4F&_e&8kx>%uG2
z=4#;az|~F?^nIsEBPzNh`H{Qo<9v(V#&pras=&bRc(r5W$YYlG$Se|7JADo3+w}81
z{nzQ_we9to)`wQMZ4IWtb1j%T;lar748@;T!qkJ=&`7&4fgMkEb^FXuF7jw^|lXUZN
zw*bo38M&zbqZVh_g8c&urM#wm4Uh8|FPnr8r(fxw*lh5RH`?}e1HP=T<;qx)*Xq-<
zqA`vl96nX;!zZ1w^Qjr;rg
zBI0jwD&1wZKV03tbsq~*O|zx3JX#JfnV^iu)I3F9Qwtr
zG!096UeDo{U>kb`#?Ch`7&mt{H%F9|kdf@dORbM(a{}X0pwi$&mA_vYj&nxbq}Wzd
zInz8RXOcHxl1lobPBWRoUah7yFOn|zDsx>5>rfz-C)`Gq-TnIk)Pe&$RH2_E&ENlA
zO3`$^M-~fLV;uQgO&R^tizgnM%Ii{5!aGGL9*|8h<;sPzg?xJ6Dr|>EeMT(pS%dZ!
z?Wvlt0i9O~z-BRWH7V`Z7{_U>$)$zkZ8-k66f6ZW(NaSKh6?ASo1OQzR8T!hZme-Y
z(+rjUET4|#WJ0!5WM*@dY+O+8wt>$!@Xe^OgTq`OsXipAMiwcHFh_+z%}6U{hUNX4
z5nar{Q`_SB6s6_R4LQ)NNj@o16El?yYVdkC-liy&gfO0A`SZZ0U5~Ozye!P!U@z!c
z2f4XS3gu2OiV68672It?2Icg3D_Tox(mpMpLCX*Z+LYuiJ2OFztC`(H#8m>=JJfff
z*>cR}>#*KKEsBCL2aLMZn5CYm)sGZbn)X$Z(?8~1q%uHhn{8m8nG|}%oJ-VW6B1Pt
zbO;?m^yrn+S!VOIWay8t?{|2dy7S%qa045_TMld+SNeXz;ZfBJ)OT`53Rx5Q^6k
zXLUtLWyQ9-!c6rgC5ej32|@ER$7z;ltf?(X{UgJ(
zp6}tFH>3;+#PQ29|QTeg(owCGRn#eryfN$91Y@^at-$XIa%ABq$`+%8FPt!xD
zMnJ`4CRSF#_L3!Dy+owplNsG5jj+wsHl7_y}ReAAdo$r-D|W{r48K~n5$3oHl8O5|tnHC8-0bOzpKdWN(#7?Hn<`;Zb8
zyG&VNsMrZbdpdoL0xpJg<44DqXhK`V4hR(U|Avi)2Tis2r;m{p($3=j80s;N5ZQ`q
za5c^)k=xecgU^k3*G!jKWOv00&-b0Z!wOT)cApmG?T%yYQ$;Mk@O(T!p;4j9^N@m4
zv3O5Wwo5C#)P>T>{Yliz&thd4%r%XUJE{dfi3OqoVvK8AJ9r`vYqQpqa|UkKcXN(U
z6Jn8=Zk1}k(t+p{88qM==rBvmNxB-avV>nm!0K4!m3IyDc-RZFkkbtrcR2`FtZmNw
zX6UwL=3-pGCa4^@JNt@Z!q3pGx`k
zDlKY8c&CGL>N65s0`9zUVouDozY{`_@pD$nyLR-tb{4yKz}Ktf0>}DB+qRMm^P!`z
zn7NnW-lmz>G{QGeI6Oo-u3ckR%0?I4AgKEcYRpqHYc
zlM)qodJ{k66+!r&cJwPF2SGH>t3pXS5f(X{HwxA+amUO3i#=6u?@okEh?E#w8ed9`M*PHT{l
zrwW3OvH5ndJQb$&!ti83tG5T)-4E6sS>0@HOk0MG7NoE$Z4X*M_e-KRQcv2{bpEdr=)&EDiDDpfKJ-r}}iL2DhwQHQb-aY$je&+F<
zX*a3I5bSPP+VT2~oEUc75~*w>mcQkkk2$OvUjK4&LUaR3Q4SUk7ykb*w%pg^-Y{Vf
z#2%jiDC4iNU!|7^=LgI4W4u5A0s9vr=2wOX?|-U14|>Z_dkE}uzkJY2eusEaUw+yH
zBK3axS9Rrg*at1;FK*`8Bg&N85j926sQ~{`d9!$Myc(%>Fj${xy+br-pwf
z!jAl(C-V0h;;(Uj9mf3`N9n8b6e4d}l|AD^0lz-VW73CfwKKP^GKP>M1+xkJIh53JipaX>f