Skip to content

Commit e01d4d7

Browse files
authored
Merge branch 'feature/q-lsp-chat' into mcp
2 parents e8f31b4 + 66c340c commit e01d4d7

File tree

30 files changed

+505
-128
lines changed

30 files changed

+505
-128
lines changed

.changes/3.74.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"date" : "2025-06-05",
3+
"version" : "3.74",
4+
"entries" : [ {
5+
"type" : "feature",
6+
"description" : "Agentic coding experience: Amazon Q can now write code and run shell commands on your behalf"
7+
}, {
8+
"type" : "bugfix",
9+
"description" : "Support full Unicode range in inline chat panel on Windows"
10+
} ]
11+
}

.changes/next-release/bugfix-061149bd-c6ef-4c86-9f12-98e38fe3b576.json

Lines changed: 0 additions & 4 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# _3.74_ (2025-06-05)
2+
- **(Feature)** Agentic coding experience: Amazon Q can now write code and run shell commands on your behalf
3+
- **(Bug Fix)** Support full Unicode range in inline chat panel on Windows
4+
15
# _3.73_ (2025-05-29)
26
- **(Bug Fix)** /transform: handle InvalidGrantException properly when polling job status
37

buildspec/linuxTests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ phases:
4040
fi
4141
4242
- chmod +x gradlew
43-
- su codebuild-user -c "./gradlew -PideProfileName=$ALTERNATIVE_IDE_PROFILE_NAME check coverageReport --info --console plain --continue"
43+
- su codebuild-user -c "./gradlew -PideProfileName=$ALTERNATIVE_IDE_PROFILE_NAME check coverageReport --info --stacktrace --console plain --continue"
4444
- su codebuild-user -c "./gradlew -PideProfileName=$ALTERNATIVE_IDE_PROFILE_NAME buildPlugin"
4545
- VCS_COMMIT_ID="${CODEBUILD_RESOLVED_SOURCE_VERSION}"
4646
- CI_BUILD_URL=$(echo $CODEBUILD_BUILD_URL | sed 's/#/%23/g') # Encode `#` in the URL because otherwise the url is clipped in the Codecov.io site

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# Toolkit Version
5-
toolkitVersion=3.74-SNAPSHOT
5+
toolkitVersion=3.75-SNAPSHOT
66

77
# Publish Settings
88
publishToken=

plugins/amazonq/build.gradle.kts

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
4+
import com.fasterxml.jackson.databind.DeserializationFeature
5+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
6+
import de.undercouch.gradle.tasks.download.Download
7+
import org.jetbrains.intellij.platform.gradle.tasks.PrepareSandboxTask
58
import software.aws.toolkits.gradle.changelog.tasks.GeneratePluginChangeLog
6-
import software.aws.toolkits.gradle.intellij.IdeFlavor
7-
import software.aws.toolkits.gradle.intellij.IdeVersions
8-
import software.aws.toolkits.gradle.intellij.toolkitIntelliJ
99

1010
plugins {
1111
id("toolkit-publishing-conventions")
1212
id("toolkit-publish-root-conventions")
1313
id("toolkit-jvm-conventions")
1414
id("toolkit-testing")
15+
id("de.undercouch.download")
16+
}
17+
18+
buildscript {
19+
dependencies {
20+
classpath(libs.bundles.jackson)
21+
}
1522
}
1623

1724
val changelog = tasks.register<GeneratePluginChangeLog>("pluginChangeLog") {
@@ -51,3 +58,81 @@ tasks.check {
5158
}
5259
}
5360
}
61+
62+
val downloadFlareManifest by tasks.registering(Download::class) {
63+
src("https://aws-toolkit-language-servers.amazonaws.com/qAgenticChatServer/0/manifest.json")
64+
dest(layout.buildDirectory.file("flare/manifest.json"))
65+
onlyIfModified(true)
66+
useETag(true)
67+
}
68+
69+
data class FlareManifest(
70+
val versions: List<FlareVersion>,
71+
)
72+
73+
data class FlareVersion(
74+
val serverVersion: String,
75+
val thirdPartyLicenses: String,
76+
val targets: List<FlareTarget>,
77+
)
78+
79+
data class FlareTarget(
80+
val platform: String,
81+
val arch: String,
82+
val contents: List<FlareContent>
83+
)
84+
85+
data class FlareContent(
86+
val url: String,
87+
)
88+
89+
val downloadFlareArtifacts by tasks.registering(Download::class) {
90+
dependsOn(downloadFlareManifest)
91+
inputs.files(downloadFlareManifest)
92+
93+
val manifestFile = downloadFlareManifest.map { it.outputFiles.first() }
94+
val manifest = manifestFile.map { jacksonObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).readValue(it.readText(), FlareManifest::class.java) }
95+
96+
// use darwin-aarch64 because its the smallest and we're going to throw away everything platform specific
97+
val latest = manifest.map { it.versions.first() }
98+
val latestVersion = latest.map { it.serverVersion }
99+
val licensesUrl = latest.map { it.thirdPartyLicenses }
100+
val darwin = latest.map { it.targets.first { target -> target.platform == "darwin" && target.arch == "arm64" } }
101+
val contentUrls = darwin.map { it.contents.map { content -> content.url } }
102+
103+
val destination = layout.buildDirectory.dir(latestVersion.map { "flare/$it" })
104+
outputs.dir(destination)
105+
106+
src(contentUrls.zip(licensesUrl) { left, right -> left + right})
107+
dest(destination)
108+
onlyIfModified(true)
109+
useETag(true)
110+
}
111+
112+
val prepareBundledFlare by tasks.registering(Copy::class) {
113+
dependsOn(downloadFlareArtifacts)
114+
inputs.files(downloadFlareArtifacts)
115+
116+
val dest = layout.buildDirectory.dir("tmp/extractFlare")
117+
into(dest)
118+
from(downloadFlareArtifacts.map { it.outputFiles.filterNot { file -> file.name.endsWith(".zip") } })
119+
120+
doLast {
121+
copy {
122+
into(dest)
123+
includeEmptyDirs = false
124+
downloadFlareArtifacts.get().outputFiles.filter { it.name.endsWith(".zip") }.forEach {
125+
dest.get().file(it.parentFile.name).asFile.createNewFile()
126+
from(zipTree(it)) {
127+
include("*.js")
128+
include("*.txt")
129+
}
130+
}
131+
}
132+
}
133+
}
134+
135+
tasks.withType<PrepareSandboxTask>().configureEach {
136+
intoChild(intellijPlatform.projectName.map { "$it/flare" })
137+
.from(prepareBundledFlare)
138+
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/toolwindow/AmazonQPanel.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import software.aws.toolkits.jetbrains.isDeveloperMode
2525
import software.aws.toolkits.jetbrains.services.amazonq.apps.AmazonQAppInitContext
2626
import software.aws.toolkits.jetbrains.services.amazonq.apps.AppConnection
2727
import software.aws.toolkits.jetbrains.services.amazonq.commands.MessageTypeRegistry
28+
import software.aws.toolkits.jetbrains.services.amazonq.isQSupportedInThisVersion
2829
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
2930
import software.aws.toolkits.jetbrains.services.amazonq.lsp.artifacts.ArtifactManager
3031
import software.aws.toolkits.jetbrains.services.amazonq.lsp.flareChat.AsyncChatUiListener
@@ -42,6 +43,7 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeTest.auth.isCodeTestA
4243
import software.aws.toolkits.jetbrains.services.amazonqDoc.auth.isDocAvailable
4344
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.auth.isFeatureDevAvailable
4445
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.isCodeTransformAvailable
46+
import software.aws.toolkits.resources.message
4547
import java.util.concurrent.CompletableFuture
4648
import javax.swing.JButton
4749

@@ -102,6 +104,9 @@ class AmazonQPanel(val project: Project, private val scope: CoroutineScope) : Di
102104
webviewContainer.add(JBTextArea("JCEF not supported"))
103105
}
104106
browser.complete(null)
107+
} else if (!isQSupportedInThisVersion()) {
108+
webviewContainer.add(JBTextArea("${message("q.unavailable")}\n ${message("q.unavailable.node")}"))
109+
browser.complete(null)
105110
} else {
106111
val loadingPanel = JBLoadingPanel(null, this)
107112
val wrapper = Wrapper()

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/webview/BrowserConnector.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class BrowserConnector(
226226
)
227227

228228
val serializedEnrichmentParams = serializer.objectMapper.valueToTree<ObjectNode>(enrichmentParams)
229-
val chatParams: ObjectNode = (node as ObjectNode)
229+
val chatParams: ObjectNode = (node.params as ObjectNode)
230230
.setAll(serializedEnrichmentParams)
231231

232232
val tabId = requestFromUi.params.tabId
@@ -237,7 +237,7 @@ class BrowserConnector(
237237
val result = AmazonQLspService.executeIfRunning(project) { server ->
238238
encryptionManager = this.encryptionManager
239239

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

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/commands/ActionRegistrar.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ActionRegistrar {
2929

3030
fun reportMessageClick(command: EditorContextCommand, project: Project) {
3131
if (command == EditorContextCommand.GenerateUnitTests) {
32-
AsyncChatUiListener.notifyPartialMessageUpdate(Gson().toJson(TestCommandMessage()))
32+
AsyncChatUiListener.notifyPartialMessageUpdate(project, Gson().toJson(TestCommandMessage()))
3333
} else {
3434
// new agentic chat route
3535
ApplicationManager.getApplication().executeOnPooledThread {
@@ -45,7 +45,7 @@ class ActionRegistrar {
4545
val params = SendToPromptParams(selection = codeSelection, triggerType = TriggerType.CONTEXT_MENU)
4646
uiMessage = FlareUiMessage(command = SEND_TO_PROMPT, params = params)
4747
}
48-
AsyncChatUiListener.notifyPartialMessageUpdate(uiMessage)
48+
AsyncChatUiListener.notifyPartialMessageUpdate(project, uiMessage)
4949
}
5050
}
5151
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/cwc/commands/codescan/actions/ExplainCodeIssueAction.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package software.aws.toolkits.jetbrains.services.cwc.commands.codescan.actions
55

66
import com.intellij.openapi.actionSystem.ActionManager
7+
import com.intellij.openapi.actionSystem.ActionUpdateThread
78
import com.intellij.openapi.actionSystem.AnAction
89
import com.intellij.openapi.actionSystem.AnActionEvent
910
import com.intellij.openapi.actionSystem.DataKey
@@ -18,7 +19,14 @@ import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.SendT
1819
import software.aws.toolkits.jetbrains.services.amazonq.lsp.model.aws.chat.TriggerType
1920

2021
class ExplainCodeIssueAction : AnAction(), DumbAware {
22+
override fun getActionUpdateThread() = ActionUpdateThread.BGT
23+
24+
override fun update(e: AnActionEvent) {
25+
e.presentation.isEnabledAndVisible = e.project != null
26+
}
27+
2128
override fun actionPerformed(e: AnActionEvent) {
29+
val project = e.project ?: return
2230
val issueDataKey = DataKey.create<MutableMap<String, String>>("amazonq.codescan.explainissue")
2331
val issueContext = e.getData(issueDataKey) ?: return
2432

@@ -50,7 +58,7 @@ class ExplainCodeIssueAction : AnAction(), DumbAware {
5058
)
5159

5260
val uiMessage = FlareUiMessage(SEND_TO_PROMPT, params)
53-
AsyncChatUiListener.notifyPartialMessageUpdate(uiMessage)
61+
AsyncChatUiListener.notifyPartialMessageUpdate(project, uiMessage)
5462
}
5563
}
5664
}

0 commit comments

Comments
 (0)