Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dd2a1b6
fix(amazonq): Update text box border colors and light text colors (#5…
manodnyab Jun 2, 2025
0c79959
fix(amazonq): use user provided node runtime (#5768)
leigaol Jun 2, 2025
535b8e2
feat(amazonq): include minimal flare assets in plugin bundle (#5769)
rli Jun 2, 2025
6ef5842
feat(amazonq): fallback to bundled flare assets if cannot be download…
rli Jun 2, 2025
7426f29
Merge main into feature/q-lsp-chat
aws-toolkit-automation Jun 2, 2025
32aca78
Merge main into feature/q-lsp-chat
aws-toolkit-automation Jun 2, 2025
2cfbbb7
fix(amazonq): do not decode uri if `window/showDocument` is external …
rli Jun 2, 2025
44c37a0
fix(amazonq): make trust chain resolution optional for Q LSP (#5778)
rli Jun 2, 2025
ae4af35
fix(amazonq): cherry-pick changes to support `aws/chat/chatOptionsUpd…
rli Jun 3, 2025
2e70fc3
feat(amazonq): expose 'Manage Subscriptions' action for builder id pa…
rli Jun 3, 2025
4b83365
Revert "feat(amazonq): expose 'Manage Subscriptions' action for build…
rli Jun 3, 2025
2a178ce
Merge main into feature/q-lsp-chat
aws-toolkit-automation Jun 3, 2025
38e7369
Send active file in editor (#5783)
manodnyab Jun 4, 2025
5141320
Fix creation of prompts not opening files in the editor (#5781)
manodnyab Jun 4, 2025
69f1522
Update changelog (#5785)
manodnyab Jun 5, 2025
060a132
fix(amazonq): fix issue where chat messages get sent to all projects…
rli Jun 5, 2025
bc95823
fix(amazonq): add metrics for flare/node resolution (#5786)
rli Jun 5, 2025
a6d80b4
fix(amazonq): make q chat unavalable in IDE version 2024.2.1 (#5788)
samgst-amazon Jun 5, 2025
d9c199d
feat(amazonq): Agentic coding experience
manodnyab Jun 5, 2025
ea7c071
Updating version to 3.74
Jun 5, 2025
d6d032a
Updating SNAPSHOT version to 3.75-SNAPSHOT
Jun 5, 2025
7228af1
fix(amazonq): fix refresh button breaking chat history for tabs that …
samgst-amazon Jun 6, 2025
91f7eb3
Merge remote-tracking branch 'origin/main' into HEAD
rli Jun 6, 2025
3bea4ef
detekt
rli Jun 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changes/3.74.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"date" : "2025-06-05",
"version" : "3.74",
"entries" : [ {
"type" : "feature",
"description" : "Agentic coding experience: Amazon Q can now write code and run shell commands on your behalf"
}, {
"type" : "bugfix",
"description" : "Support full Unicode range in inline chat panel on Windows"
} ]
}

This file was deleted.

4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# _3.74_ (2025-06-05)
- **(Feature)** Agentic coding experience: Amazon Q can now write code and run shell commands on your behalf
- **(Bug Fix)** Support full Unicode range in inline chat panel on Windows

# _3.73_ (2025-05-29)
- **(Bug Fix)** /transform: handle InvalidGrantException properly when polling job status

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: Apache-2.0

# Toolkit Version
toolkitVersion=3.74-SNAPSHOT
toolkitVersion=3.75-SNAPSHOT

# Publish Settings
publishToken=
Expand Down
89 changes: 89 additions & 0 deletions plugins/amazonq/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import de.undercouch.gradle.tasks.download.Download
import org.jetbrains.intellij.platform.gradle.tasks.PrepareSandboxTask
import software.aws.toolkits.gradle.changelog.tasks.GeneratePluginChangeLog

plugins {
id("toolkit-publishing-conventions")
id("toolkit-publish-root-conventions")
id("toolkit-jvm-conventions")
id("toolkit-testing")
id("de.undercouch.download")
}

buildscript {
dependencies {
classpath(libs.bundles.jackson)
}
}

val changelog = tasks.register<GeneratePluginChangeLog>("pluginChangeLog") {
Expand Down Expand Up @@ -47,3 +58,81 @@ tasks.check {
}
}
}

val downloadFlareManifest by tasks.registering(Download::class) {
src("https://aws-toolkit-language-servers.amazonaws.com/qAgenticChatServer/0/manifest.json")
dest(layout.buildDirectory.file("flare/manifest.json"))
onlyIfModified(true)
useETag(true)
}

data class FlareManifest(
val versions: List<FlareVersion>,
)

data class FlareVersion(
val serverVersion: String,
val thirdPartyLicenses: String,
val targets: List<FlareTarget>,
)

data class FlareTarget(
val platform: String,
val arch: String,
val contents: List<FlareContent>
)

data class FlareContent(
val url: String,
)

val downloadFlareArtifacts by tasks.registering(Download::class) {
dependsOn(downloadFlareManifest)
inputs.files(downloadFlareManifest)

val manifestFile = downloadFlareManifest.map { it.outputFiles.first() }
val manifest = manifestFile.map { jacksonObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).readValue(it.readText(), FlareManifest::class.java) }

// use darwin-aarch64 because its the smallest and we're going to throw away everything platform specific
val latest = manifest.map { it.versions.first() }
val latestVersion = latest.map { it.serverVersion }
val licensesUrl = latest.map { it.thirdPartyLicenses }
val darwin = latest.map { it.targets.first { target -> target.platform == "darwin" && target.arch == "arm64" } }
val contentUrls = darwin.map { it.contents.map { content -> content.url } }

val destination = layout.buildDirectory.dir(latestVersion.map { "flare/$it" })
outputs.dir(destination)

src(contentUrls.zip(licensesUrl) { left, right -> left + right})
dest(destination)
onlyIfModified(true)
useETag(true)
}

val prepareBundledFlare by tasks.registering(Copy::class) {
dependsOn(downloadFlareArtifacts)
inputs.files(downloadFlareArtifacts)

val dest = layout.buildDirectory.dir("tmp/extractFlare")
into(dest)
from(downloadFlareArtifacts.map { it.outputFiles.filterNot { file -> file.name.endsWith(".zip") } })

doLast {
copy {
into(dest)
includeEmptyDirs = false
downloadFlareArtifacts.get().outputFiles.filter { it.name.endsWith(".zip") }.forEach {
dest.get().file(it.parentFile.name).asFile.createNewFile()
from(zipTree(it)) {
include("*.js")
include("*.txt")
}
}
}
}
}

tasks.withType<PrepareSandboxTask>().configureEach {
intoChild(intellijPlatform.projectName.map { "$it/flare" })
.from(prepareBundledFlare)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,25 @@ import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.util.messages.Topic
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.ChatCommunicationManager
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.CHAT_TAB_REMOVE
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindow
import software.aws.toolkits.resources.AmazonQBundle
import java.util.EventListener

class QRefreshPanelAction : DumbAwareAction(AmazonQBundle.message("amazonq.refresh.panel"), null, AllIcons.Actions.Refresh) {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return

// Notify LSP server about all open tabs being removed
val chatManager = ChatCommunicationManager.getInstance(project)
chatManager.getAllTabIds().forEach { tabId ->
AmazonQLspService.executeIfRunning(project) { server ->
rawEndpoint.notify(CHAT_TAB_REMOVE, mapOf("tabId" to tabId))
}
}

// recreate chat browser
AmazonQToolWindow.getInstance(project).disposeAndRecreate()
// recreate signin browser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import software.aws.toolkits.jetbrains.isDeveloperMode
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
import software.aws.toolkits.jetbrains.services.amazonq.apps.AppConnection
import software.aws.toolkits.jetbrains.services.amazonq.commands.MessageTypeRegistry
import software.aws.toolkits.jetbrains.services.amazonq.isQSupportedInThisVersion
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts.ArtifactManager
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AsyncChatUiListener
Expand All @@ -42,6 +43,7 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeTest.auth.isCodeTestA
import software.aws.toolkits.jetbrains.services.amazonqDoc.auth.isDocAvailable
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.auth.isFeatureDevAvailable
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTransformAvailable
import software.aws.toolkits.resources.message
import software.aws.toolkits.jetbrains.utils.isRunningOnRemoteBackend
import java.util.concurrent.CompletableFuture
import javax.swing.JButton
Expand Down Expand Up @@ -103,6 +105,9 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di
webviewContainer.add(JBTextArea("JCEF not supported"))
}
browser.complete(null)
} else if (!isQSupportedInThisVersion()) {
webviewContainer.add(JBTextArea("${message("q.unavailable")}\n ${message("q.unavailable.node")}"))
browser.complete(null)
} else {
val loadingPanel = if (isRunningOnRemoteBackend()) {
JBLoadingPanel(null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class BrowserConnector(
)

val serializedEnrichmentParams = serializer.objectMapper.valueToTree<ObjectNode>(enrichmentParams)
val chatParams: ObjectNode = (node as ObjectNode)
val chatParams: ObjectNode = (node.params as ObjectNode)
.setAll(serializedEnrichmentParams)

val tabId = requestFromUi.params.tabId
Expand All @@ -235,7 +235,7 @@ class BrowserConnector(
val result = AmazonQLspService.executeIfRunning(project) { server ->
encryptionManager = this.encryptionManager

val encryptedParams = EncryptedChatParams(this.encryptionManager.encrypt(chatParams.params), partialResultToken)
val encryptedParams = EncryptedChatParams(this.encryptionManager.encrypt(chatParams), partialResultToken)
rawEndpoint.request(SEND_CHAT_COMMAND_PROMPT, encryptedParams) as CompletableFuture<String>
} ?: (CompletableFuture.failedFuture(IllegalStateException("LSP Server not running")))

Expand Down Expand Up @@ -307,14 +307,19 @@ class BrowserConnector(
}

CHAT_TAB_ADD -> {
handleChat(AmazonQChatServer.tabAdd, node)
handleChat(AmazonQChatServer.tabAdd, node) { params, invoke ->
// Track the tab ID when a tab is added
chatCommunicationManager.addTabId(params.tabId)
invoke()
}
}

CHAT_TAB_REMOVE -> {
handleChat(AmazonQChatServer.tabRemove, node) { params, invoke ->
chatCommunicationManager.removePartialChatMessage(params.tabId)
cancelInflightRequests(params.tabId)

// Remove the tab ID from tracking when a tab is removed
chatCommunicationManager.removeTabId(params.tabId)
invoke()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ data class AmazonQTheme(
val defaultText: Color,
val inactiveText: Color,
val linkText: Color,
val lightText: Color,
val emptyText: Color,

val background: Color,
val border: Color,
Expand All @@ -31,6 +33,8 @@ data class AmazonQTheme(
val buttonBackground: Color,
val secondaryButtonForeground: Color,
val secondaryButtonBackground: Color,
val inputBorderFocused: Color,
val inputBorderUnfocused: Color,

val info: Color,
val success: Color,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum class CssVariable(
TextColorAlt("--mynah-color-text-alternate"),
TextColorStrong("--mynah-color-text-strong"),
TextColorWeak("--mynah-color-text-weak"),
TextColorLight("--mynah-color-light"),
TextColorLink("--mynah-color-text-link"),
TextColorInput("--mynah-color-text-input"),
TextColorDisabled("--mynah-color-text-disabled"),
Expand All @@ -27,6 +28,8 @@ enum class CssVariable(
ColorDeep("--mynah-color-deep"),
ColorDeepReverse("--mynah-color-deep-reverse"),
BorderDefault("--mynah-color-border-default"),
BorderFocused("--mynah-color-text-input-border-focused"),
BorderUnfocused("--mynah-color-text-input-border"),
InputBackground("--mynah-input-bg"),

SyntaxBackground("--mynah-color-syntax-bg"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ class EditorThemeAdapter {
editorString = currentScheme.foregroundColor(DefaultLanguageHighlighterColors.STRING),
editorProperty = currentScheme.foregroundColor(DefaultLanguageHighlighterColors.INSTANCE_FIELD),
editorClassName = currentScheme.foregroundColor(DefaultLanguageHighlighterColors.CLASS_NAME),
lightText = themeColor("TextField.inactiveForeground", default = 0xA8ADBD, darkDefault = 0x5A5D63),
emptyText = themeColor("TextField.inactiveForeground", default = 0xA8ADBD, darkDefault = 0x5A5D63),
inputBorderFocused = themeColor("ActionButton.focusedBorderColor", default = 0x4682FA, darkDefault = 0x3574f0),
inputBorderUnfocused = themeColor("TextField.borderColor", default = 0xEBECF0, darkDefault = 0x4E5157),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ class ThemeBrowserAdapter {
append(CssVariable.TextColorStrong, theme.textFieldForeground)
append(CssVariable.TextColorInput, theme.textFieldForeground)
append(CssVariable.TextColorLink, theme.linkText)
append(CssVariable.TextColorWeak, theme.inactiveText)
append(CssVariable.TextColorWeak, theme.emptyText)
append(CssVariable.TextColorLight, theme.emptyText)
append(CssVariable.TextColorDisabled, theme.inactiveText)

append(CssVariable.Background, bg)
append(CssVariable.BackgroundAlt, altBg)
append(CssVariable.CardBackground, bg)
append(CssVariable.CardBackgroundAlt, altBg)
append(CssVariable.BorderDefault, theme.border)
append(CssVariable.BorderFocused, theme.inputBorderFocused)
append(CssVariable.BorderUnfocused, theme.inputBorderUnfocused)
append(CssVariable.TabActive, theme.activeTab)

append(CssVariable.InputBackground, inputBg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class ActionRegistrar {

fun reportMessageClick(command: EditorContextCommand, project: Project) {
if (command == EditorContextCommand.GenerateUnitTests) {
AsyncChatUiListener.notifyPartialMessageUpdate(Gson().toJson(TestCommandMessage()))
AsyncChatUiListener.notifyPartialMessageUpdate(project, Gson().toJson(TestCommandMessage()))
} else {
// new agentic chat route
ApplicationManager.getApplication().executeOnPooledThread {
Expand All @@ -45,7 +45,7 @@ class ActionRegistrar {
val params = SendToPromptParams(selection = codeSelection, triggerType = TriggerType.CONTEXT_MENU)
uiMessage = FlareUiMessage(command = SEND_TO_PROMPT, params = params)
}
AsyncChatUiListener.notifyPartialMessageUpdate(uiMessage)
AsyncChatUiListener.notifyPartialMessageUpdate(project, uiMessage)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package software.aws.toolkits.jetbrains.services.cwc.commands.codescan.actions

import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.DataKey
Expand All @@ -18,7 +19,14 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendT
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TriggerType

class ExplainCodeIssueAction : AnAction(), DumbAware {
override fun getActionUpdateThread() = ActionUpdateThread.BGT

override fun update(e: AnActionEvent) {
e.presentation.isEnabledAndVisible = e.project != null
}

override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val issueDataKey = DataKey.create<MutableMap<String, String>>("amazonq.codescan.explainissue")
val issueContext = e.getData(issueDataKey) ?: return

Expand Down Expand Up @@ -50,7 +58,7 @@ class ExplainCodeIssueAction : AnAction(), DumbAware {
)

val uiMessage = FlareUiMessage(SEND_TO_PROMPT, params)
AsyncChatUiListener.notifyPartialMessageUpdate(uiMessage)
AsyncChatUiListener.notifyPartialMessageUpdate(project, uiMessage)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,21 @@ class CodeWhispererConfigurable(private val project: Project) :
.resizableColumn()
.align(Align.FILL)
}
row(message("amazonqFeatureDev.placeholder.node_runtime_path")) {
val fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFileDescriptor()
fileChooserDescriptor.isForcedToUseIdeaFileChooser = true

textFieldWithBrowseButton(fileChooserDescriptor = fileChooserDescriptor)
.bindText(
{ LspSettings.getInstance().getNodeRuntimePath().orEmpty() },
{ LspSettings.getInstance().setNodeRuntimePath(it) }
)
.applyToComponent {
emptyText.text = message("executableCommon.auto_managed")
}
.resizableColumn()
.align(Align.FILL)
}
}

group(message("aws.settings.codewhisperer.group.general")) {
Expand Down
9 changes: 9 additions & 0 deletions plugins/amazonq/shared/jetbrains-community/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,12 @@ dependencies {

testFixturesApi(testFixtures(project(":plugin-core:jetbrains-community")))
}

// hack because our test structure currently doesn't make complete sense
tasks.prepareTestSandbox {
val pluginXmlJar = project(":plugin-amazonq").tasks.jar

dependsOn(pluginXmlJar)
intoChild(intellijPlatform.projectName.map { "$it/lib" })
.from(pluginXmlJar)
}
Loading
Loading