From c2e40030503343d43dbcf63e109d0656017c9ef8 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 14:33:07 -0700 Subject: [PATCH 01/11] support al2 --- packages/amazonq/src/extension.ts | 6 +--- .../core/src/shared/lsp/utils/platform.ts | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/amazonq/src/extension.ts b/packages/amazonq/src/extension.ts index ffcbf333762..fa7623ed1eb 100644 --- a/packages/amazonq/src/extension.ts +++ b/packages/amazonq/src/extension.ts @@ -43,7 +43,6 @@ import { registerCommands } from './commands' import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat' import { activate as activateAmazonqLsp } from './lsp/activation' import { activate as activateInlineCompletion } from './app/inline/activation' -import { isAmazonInternalOs } from 'aws-core-vscode/shared' export const amazonQContextPrefix = 'amazonq' @@ -120,10 +119,7 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is } // This contains every lsp agnostic things (auth, security scan, code scan) await activateCodeWhisperer(extContext as ExtContext) - if ( - (Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) && - !isAmazonInternalOs() - ) { + if (Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) { // start the Amazon Q LSP for internal users first await activateAmazonqLsp(context) } diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index 5d96ef496f4..b1c4275a2e4 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -7,7 +7,7 @@ import { ToolkitError } from '../../errors' import { Logger } from '../../logger/logger' import { ChildProcess } from '../../utilities/processUtils' import { waitUntil } from '../../utilities/timeoutUtils' -import { isDebugInstance } from '../../vscode/env' +import { isAmazonInternalOs, isDebugInstance } from '../../vscode/env' export function getNodeExecutableName(): string { return process.platform === 'win32' ? 'node.exe' : 'node' @@ -26,12 +26,23 @@ function getEncryptionInit(key: Buffer): string { return JSON.stringify(request) + '\n' } +const al2Config = { + path: '/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2', + args: ['--library-path', '/opt/vsc-sysroot/lib64'], +} + /** * Checks that we can actually run the `node` executable and execute code with it. */ export async function validateNodeExe(nodePath: string, lsp: string, args: string[], logger: Logger) { // Check that we can start `node` by itself. - const proc = new ChildProcess(nodePath, ['-e', 'console.log("ok " + process.version)'], { logging: 'no' }) + const proc = new ChildProcess( + isAmazonInternalOs() ? al2Config.path : nodePath, + isAmazonInternalOs() + ? [...al2Config.args, nodePath, '-e', 'console.log("ok " + process.version)'] + : ['-e', 'console.log("ok " + process.version)'], + { logging: 'no' } + ) const r = await proc.run() const ok = r.exitCode === 0 && r.stdout.includes('ok') if (!ok) { @@ -41,7 +52,12 @@ export async function validateNodeExe(nodePath: string, lsp: string, args: strin } // Check that we can start `node …/lsp.js --stdio …`. - const lspProc = new ChildProcess(nodePath, [lsp, ...args], { logging: 'no' }) + const lspProc = new ChildProcess( + isAmazonInternalOs() ? al2Config.path : nodePath, + isAmazonInternalOs() ? [...al2Config.args, nodePath, lsp, ...args] : [lsp, ...args], + { logging: 'no' } + ) + try { // Start asynchronously (it never stops; we need to stop it below). lspProc.run().catch((e) => logger.error('failed to run: %s', lspProc.toString(false, true))) @@ -89,8 +105,11 @@ export function createServerOptions({ if (isDebugInstance()) { args.unshift('--inspect=6080') } - const lspProcess = new ChildProcess(executable, args) - + const lspProcess = new ChildProcess( + isAmazonInternalOs() ? al2Config.path : executable, + isAmazonInternalOs() ? [...al2Config.args, executable, ...args] : args, + { logging: 'no' } + ) // this is a long running process, awaiting it will never resolve void lspProcess.run() From e58211c3a4e4b5a76af040b19197e6bc547241f7 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 14:51:16 -0700 Subject: [PATCH 02/11] feedback --- .../core/src/shared/lsp/utils/platform.ts | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index b1c4275a2e4..82a5da65c46 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -26,23 +26,25 @@ function getEncryptionInit(key: Buffer): string { return JSON.stringify(request) + '\n' } +// use dynamic linking to let node binary +// pick up GLIBC >= 2.28 const al2Config = { path: '/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2', args: ['--library-path', '/opt/vsc-sysroot/lib64'], } - +function createNodeProcess(nodePath: string, args: string[]) { + return new ChildProcess( + isAmazonInternalOs() ? al2Config.path : nodePath, + isAmazonInternalOs() ? [...al2Config.args, nodePath, ...args] : [...args], + { logging: 'no' } + ) +} /** * Checks that we can actually run the `node` executable and execute code with it. */ export async function validateNodeExe(nodePath: string, lsp: string, args: string[], logger: Logger) { // Check that we can start `node` by itself. - const proc = new ChildProcess( - isAmazonInternalOs() ? al2Config.path : nodePath, - isAmazonInternalOs() - ? [...al2Config.args, nodePath, '-e', 'console.log("ok " + process.version)'] - : ['-e', 'console.log("ok " + process.version)'], - { logging: 'no' } - ) + const proc = createNodeProcess(nodePath, ['-e', 'console.log("ok")']) const r = await proc.run() const ok = r.exitCode === 0 && r.stdout.includes('ok') if (!ok) { @@ -52,11 +54,7 @@ export async function validateNodeExe(nodePath: string, lsp: string, args: strin } // Check that we can start `node …/lsp.js --stdio …`. - const lspProc = new ChildProcess( - isAmazonInternalOs() ? al2Config.path : nodePath, - isAmazonInternalOs() ? [...al2Config.args, nodePath, lsp, ...args] : [lsp, ...args], - { logging: 'no' } - ) + const lspProc = createNodeProcess(nodePath, [lsp, ...args]) try { // Start asynchronously (it never stops; we need to stop it below). @@ -105,11 +103,7 @@ export function createServerOptions({ if (isDebugInstance()) { args.unshift('--inspect=6080') } - const lspProcess = new ChildProcess( - isAmazonInternalOs() ? al2Config.path : executable, - isAmazonInternalOs() ? [...al2Config.args, executable, ...args] : args, - { logging: 'no' } - ) + const lspProcess = createNodeProcess(executable, args) // this is a long running process, awaiting it will never resolve void lspProcess.run() From 0ae577c9d56a2af11001080f828795e81120483f Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 14:57:17 -0700 Subject: [PATCH 03/11] version --- packages/core/src/shared/lsp/utils/platform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index 82a5da65c46..a506297f1cb 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -44,7 +44,7 @@ function createNodeProcess(nodePath: string, args: string[]) { */ export async function validateNodeExe(nodePath: string, lsp: string, args: string[], logger: Logger) { // Check that we can start `node` by itself. - const proc = createNodeProcess(nodePath, ['-e', 'console.log("ok")']) + const proc = createNodeProcess(nodePath, ['-e', 'console.log("ok " + process.version)']) const r = await proc.run() const ok = r.exitCode === 0 && r.stdout.includes('ok') if (!ok) { From 20925f52f89ec1fd84044accc562412d795c1d5b Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 17:49:14 -0700 Subject: [PATCH 04/11] clean --- packages/amazonq/src/extension.ts | 8 ++++- packages/amazonq/src/lsp/client.ts | 32 ++++++++++++++++--- .../core/src/shared/lsp/utils/platform.ts | 21 +++--------- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/packages/amazonq/src/extension.ts b/packages/amazonq/src/extension.ts index fa7623ed1eb..5ae9e397119 100644 --- a/packages/amazonq/src/extension.ts +++ b/packages/amazonq/src/extension.ts @@ -33,6 +33,7 @@ import { maybeShowMinVscodeWarning, Experiments, isSageMaker, + isAmazonInternalOs, } from 'aws-core-vscode/shared' import { ExtStartUpSources } from 'aws-core-vscode/telemetry' import { VSCODE_EXTENSION_ID } from 'aws-core-vscode/utils' @@ -43,6 +44,7 @@ import { registerCommands } from './commands' import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat' import { activate as activateAmazonqLsp } from './lsp/activation' import { activate as activateInlineCompletion } from './app/inline/activation' +import { hasGlibcPatch } from './lsp/client' export const amazonQContextPrefix = 'amazonq' @@ -119,8 +121,12 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is } // This contains every lsp agnostic things (auth, security scan, code scan) await activateCodeWhisperer(extContext as ExtContext) - if (Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) { + if ( + (Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) && + (!isAmazonInternalOs() || (await hasGlibcPatch())) + ) { // start the Amazon Q LSP for internal users first + // for AL2, start LSP if glibc patch is found await activateAmazonqLsp(context) } if (!Experiments.instance.get('amazonqLSPInline', false)) { diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index d813370cb0b..06d7288df0d 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -6,6 +6,7 @@ import vscode, { env, version } from 'vscode' import * as nls from 'vscode-nls' import * as crypto from 'crypto' +import * as path from 'path' import { LanguageClient, LanguageClientOptions, RequestType, State } from 'vscode-languageclient' import { InlineCompletionManager } from '../app/inline/completion' import { AmazonQLspAuth, encryptionKey, notificationTypes } from './auth' @@ -32,14 +33,21 @@ import { getLogger, undefinedIfEmpty, getOptOutPreference, + isAmazonInternalOs, + fs, } from 'aws-core-vscode/shared' import { activate } from './chat/activation' import { AmazonQResourcePaths } from './lspInstaller' import { ConfigSection, isValidConfigSection, toAmazonQLSPLogLevel } from './config' +import { chmodSync } from 'fs' const localize = nls.loadMessageBundle() const logger = getLogger('amazonqLsp.lspClient') +export async function hasGlibcPatch(): Promise { + return await fs.exists('/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2') +} + export async function startLanguageServer( extensionContext: vscode.ExtensionContext, resourcePaths: AmazonQResourcePaths @@ -55,6 +63,25 @@ export async function startLanguageServer( '--pre-init-encryption', '--set-credentials-encryption-key', ] + + const documentSelector = [{ scheme: 'file', language: '*' }] + + const clientId = 'amazonq' + const traceServerEnabled = Settings.instance.isSet(`${clientId}.trace.server`) + + // apply the GLIBC 2.28 path to node js runtime binary + if (isAmazonInternalOs() && (await hasGlibcPatch())) { + const nodeWrapper = ` + #! /bin/bash + exec /opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2 --library-path /opt/vsc-sysroot/lib64 ${resourcePaths.node} "$@" + ` + const nodeWrapperPath = path.join(path.dirname(resourcePaths.node), 'node-wrapper') + await fs.writeFile(nodeWrapperPath, nodeWrapper) + chmodSync(nodeWrapperPath, 0o755) + resourcePaths.node = nodeWrapperPath + getLogger('amazonqLsp').info(`Patched node runtime with GLIBC to ${resourcePaths.node}`) + } + const serverOptions = createServerOptions({ encryptionKey, executable: resourcePaths.node, @@ -62,11 +89,6 @@ export async function startLanguageServer( execArgv: argv, }) - const documentSelector = [{ scheme: 'file', language: '*' }] - - const clientId = 'amazonq' - const traceServerEnabled = Settings.instance.isSet(`${clientId}.trace.server`) - await validateNodeExe(resourcePaths.node, resourcePaths.lsp, argv, logger) // Options to control the language client diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index a506297f1cb..fc761fabd5f 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -7,7 +7,7 @@ import { ToolkitError } from '../../errors' import { Logger } from '../../logger/logger' import { ChildProcess } from '../../utilities/processUtils' import { waitUntil } from '../../utilities/timeoutUtils' -import { isAmazonInternalOs, isDebugInstance } from '../../vscode/env' +import { isDebugInstance } from '../../vscode/env' export function getNodeExecutableName(): string { return process.platform === 'win32' ? 'node.exe' : 'node' @@ -26,25 +26,12 @@ function getEncryptionInit(key: Buffer): string { return JSON.stringify(request) + '\n' } -// use dynamic linking to let node binary -// pick up GLIBC >= 2.28 -const al2Config = { - path: '/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2', - args: ['--library-path', '/opt/vsc-sysroot/lib64'], -} -function createNodeProcess(nodePath: string, args: string[]) { - return new ChildProcess( - isAmazonInternalOs() ? al2Config.path : nodePath, - isAmazonInternalOs() ? [...al2Config.args, nodePath, ...args] : [...args], - { logging: 'no' } - ) -} /** * Checks that we can actually run the `node` executable and execute code with it. */ export async function validateNodeExe(nodePath: string, lsp: string, args: string[], logger: Logger) { // Check that we can start `node` by itself. - const proc = createNodeProcess(nodePath, ['-e', 'console.log("ok " + process.version)']) + const proc = new ChildProcess(nodePath, ['-e', 'console.log("ok " + process.version)'], { logging: 'no' }) const r = await proc.run() const ok = r.exitCode === 0 && r.stdout.includes('ok') if (!ok) { @@ -54,7 +41,7 @@ export async function validateNodeExe(nodePath: string, lsp: string, args: strin } // Check that we can start `node …/lsp.js --stdio …`. - const lspProc = createNodeProcess(nodePath, [lsp, ...args]) + const lspProc = new ChildProcess(nodePath, [lsp, ...args]) try { // Start asynchronously (it never stops; we need to stop it below). @@ -103,7 +90,7 @@ export function createServerOptions({ if (isDebugInstance()) { args.unshift('--inspect=6080') } - const lspProcess = createNodeProcess(executable, args) + const lspProcess = new ChildProcess(executable, args) // this is a long running process, awaiting it will never resolve void lspProcess.run() From d78b731a060029a1e85ed5691e09611f6ea08e16 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 17:50:18 -0700 Subject: [PATCH 05/11] clean up --- packages/core/src/shared/lsp/utils/platform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index fc761fabd5f..fa2e36a34b9 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -41,7 +41,7 @@ export async function validateNodeExe(nodePath: string, lsp: string, args: strin } // Check that we can start `node …/lsp.js --stdio …`. - const lspProc = new ChildProcess(nodePath, [lsp, ...args]) + const lspProc = new ChildProcess(nodePath, [lsp, ...args], { logging: 'no' }) try { // Start asynchronously (it never stops; we need to stop it below). From 44d04b34ec2c37322217c562863e0fd650f11c7e Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 17:51:57 -0700 Subject: [PATCH 06/11] minimize changes --- packages/core/src/shared/lsp/utils/platform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index fa2e36a34b9..5d96ef496f4 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -42,7 +42,6 @@ export async function validateNodeExe(nodePath: string, lsp: string, args: strin // Check that we can start `node …/lsp.js --stdio …`. const lspProc = new ChildProcess(nodePath, [lsp, ...args], { logging: 'no' }) - try { // Start asynchronously (it never stops; we need to stop it below). lspProc.run().catch((e) => logger.error('failed to run: %s', lspProc.toString(false, true))) @@ -91,6 +90,7 @@ export function createServerOptions({ args.unshift('--inspect=6080') } const lspProcess = new ChildProcess(executable, args) + // this is a long running process, awaiting it will never resolve void lspProcess.run() From bd8140cebb9716049e052ef7376abcce9cd86bf1 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 17:53:11 -0700 Subject: [PATCH 07/11] change log --- .../Bug Fix-534a4369-a0e1-4789-9f55-fa172b9fb93f.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages/amazonq/.changes/next-release/Bug Fix-534a4369-a0e1-4789-9f55-fa172b9fb93f.json diff --git a/packages/amazonq/.changes/next-release/Bug Fix-534a4369-a0e1-4789-9f55-fa172b9fb93f.json b/packages/amazonq/.changes/next-release/Bug Fix-534a4369-a0e1-4789-9f55-fa172b9fb93f.json new file mode 100644 index 00000000000..59ee9d3498e --- /dev/null +++ b/packages/amazonq/.changes/next-release/Bug Fix-534a4369-a0e1-4789-9f55-fa172b9fb93f.json @@ -0,0 +1,4 @@ +{ + "type": "Bug Fix", + "description": "Enable Amazon Q LSP in AL2 instances" +} From 0c18b2c3f4f2538e44c521740a31db71f3b97216 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Wed, 30 Apr 2025 19:38:41 -0700 Subject: [PATCH 08/11] lint --- packages/amazonq/src/lsp/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 06d7288df0d..2cc201a802b 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -39,7 +39,7 @@ import { import { activate } from './chat/activation' import { AmazonQResourcePaths } from './lspInstaller' import { ConfigSection, isValidConfigSection, toAmazonQLSPLogLevel } from './config' -import { chmodSync } from 'fs' +import { chmodSync } from 'fs' // eslint-disable-line no-restricted-imports const localize = nls.loadMessageBundle() const logger = getLogger('amazonqLsp.lspClient') From deb8bc921b944a9757892c89024ecedaff91f5a4 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Thu, 1 May 2025 09:40:08 -0700 Subject: [PATCH 09/11] chmod --- packages/amazonq/src/lsp/client.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 2cc201a802b..648097ec9e8 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -39,7 +39,6 @@ import { import { activate } from './chat/activation' import { AmazonQResourcePaths } from './lspInstaller' import { ConfigSection, isValidConfigSection, toAmazonQLSPLogLevel } from './config' -import { chmodSync } from 'fs' // eslint-disable-line no-restricted-imports const localize = nls.loadMessageBundle() const logger = getLogger('amazonqLsp.lspClient') @@ -77,7 +76,7 @@ export async function startLanguageServer( ` const nodeWrapperPath = path.join(path.dirname(resourcePaths.node), 'node-wrapper') await fs.writeFile(nodeWrapperPath, nodeWrapper) - chmodSync(nodeWrapperPath, 0o755) + await fs.chmod(nodeWrapperPath, 0o755) resourcePaths.node = nodeWrapperPath getLogger('amazonqLsp').info(`Patched node runtime with GLIBC to ${resourcePaths.node}`) } From 746378d609810acc3a6b5782126aab2781dc49bb Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Thu, 1 May 2025 10:48:37 -0700 Subject: [PATCH 10/11] up --- packages/amazonq/src/lsp/client.ts | 23 ++++++++----------- packages/core/src/amazonq/lsp/lspClient.ts | 4 ++-- .../core/src/shared/lsp/utils/platform.ts | 16 ++++++++----- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 648097ec9e8..676152cc075 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -6,7 +6,6 @@ import vscode, { env, version } from 'vscode' import * as nls from 'vscode-nls' import * as crypto from 'crypto' -import * as path from 'path' import { LanguageClient, LanguageClientOptions, RequestType, State } from 'vscode-languageclient' import { InlineCompletionManager } from '../app/inline/completion' import { AmazonQLspAuth, encryptionKey, notificationTypes } from './auth' @@ -67,28 +66,26 @@ export async function startLanguageServer( const clientId = 'amazonq' const traceServerEnabled = Settings.instance.isSet(`${clientId}.trace.server`) - + let executable: string[] = [] // apply the GLIBC 2.28 path to node js runtime binary if (isAmazonInternalOs() && (await hasGlibcPatch())) { - const nodeWrapper = ` - #! /bin/bash - exec /opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2 --library-path /opt/vsc-sysroot/lib64 ${resourcePaths.node} "$@" - ` - const nodeWrapperPath = path.join(path.dirname(resourcePaths.node), 'node-wrapper') - await fs.writeFile(nodeWrapperPath, nodeWrapper) - await fs.chmod(nodeWrapperPath, 0o755) - resourcePaths.node = nodeWrapperPath - getLogger('amazonqLsp').info(`Patched node runtime with GLIBC to ${resourcePaths.node}`) + executable = [ + '/opt/vsc-sysroot/lib64/ld-linux-x86-64.so.2', + '--library-path', + '/opt/vsc-sysroot/lib64', + resourcePaths.node, + ] + getLogger('amazonqLsp').info(`Patched node runtime with GLIBC to ${executable}`) } const serverOptions = createServerOptions({ encryptionKey, - executable: resourcePaths.node, + executable: executable, serverModule, execArgv: argv, }) - await validateNodeExe(resourcePaths.node, resourcePaths.lsp, argv, logger) + await validateNodeExe(executable, resourcePaths.lsp, argv, logger) // Options to control the language client const clientOptions: LanguageClientOptions = { diff --git a/packages/core/src/amazonq/lsp/lspClient.ts b/packages/core/src/amazonq/lsp/lspClient.ts index b992fef2fe3..bd671af0a39 100644 --- a/packages/core/src/amazonq/lsp/lspClient.ts +++ b/packages/core/src/amazonq/lsp/lspClient.ts @@ -255,7 +255,7 @@ export async function activate(extensionContext: ExtensionContext, resourcePaths const serverOptions = createServerOptions({ encryptionKey: key, - executable: resourcePaths.node, + executable: [resourcePaths.node], serverModule, // TODO(jmkeyes): we always use the debug options...? execArgv: debugOptions.execArgv, @@ -263,7 +263,7 @@ export async function activate(extensionContext: ExtensionContext, resourcePaths const documentSelector = [{ scheme: 'file', language: '*' }] - await validateNodeExe(resourcePaths.node, resourcePaths.lsp, debugOptions.execArgv, logger) + await validateNodeExe([resourcePaths.node], resourcePaths.lsp, debugOptions.execArgv, logger) // Options to control the language client const clientOptions: LanguageClientOptions = { diff --git a/packages/core/src/shared/lsp/utils/platform.ts b/packages/core/src/shared/lsp/utils/platform.ts index 5d96ef496f4..7db40ffdf30 100644 --- a/packages/core/src/shared/lsp/utils/platform.ts +++ b/packages/core/src/shared/lsp/utils/platform.ts @@ -29,9 +29,12 @@ function getEncryptionInit(key: Buffer): string { /** * Checks that we can actually run the `node` executable and execute code with it. */ -export async function validateNodeExe(nodePath: string, lsp: string, args: string[], logger: Logger) { +export async function validateNodeExe(nodePath: string[], lsp: string, args: string[], logger: Logger) { + const bin = nodePath[0] // Check that we can start `node` by itself. - const proc = new ChildProcess(nodePath, ['-e', 'console.log("ok " + process.version)'], { logging: 'no' }) + const proc = new ChildProcess(bin, [...nodePath.slice(1), '-e', 'console.log("ok " + process.version)'], { + logging: 'no', + }) const r = await proc.run() const ok = r.exitCode === 0 && r.stdout.includes('ok') if (!ok) { @@ -41,7 +44,7 @@ export async function validateNodeExe(nodePath: string, lsp: string, args: strin } // Check that we can start `node …/lsp.js --stdio …`. - const lspProc = new ChildProcess(nodePath, [lsp, ...args], { logging: 'no' }) + const lspProc = new ChildProcess(bin, [...nodePath.slice(1), lsp, ...args], { logging: 'no' }) try { // Start asynchronously (it never stops; we need to stop it below). lspProc.run().catch((e) => logger.error('failed to run: %s', lspProc.toString(false, true))) @@ -80,16 +83,17 @@ export function createServerOptions({ execArgv, }: { encryptionKey: Buffer - executable: string + executable: string[] serverModule: string execArgv: string[] }) { return async () => { - const args = [serverModule, ...execArgv] + const bin = executable[0] + const args = [...executable.slice(1), serverModule, ...execArgv] if (isDebugInstance()) { args.unshift('--inspect=6080') } - const lspProcess = new ChildProcess(executable, args) + const lspProcess = new ChildProcess(bin, args) // this is a long running process, awaiting it will never resolve void lspProcess.run() From ae87b1b68466a1644b63dc74845b1ed4f98d0814 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Thu, 1 May 2025 10:50:24 -0700 Subject: [PATCH 11/11] z --- packages/amazonq/src/lsp/client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/amazonq/src/lsp/client.ts b/packages/amazonq/src/lsp/client.ts index 676152cc075..40f1cabb060 100644 --- a/packages/amazonq/src/lsp/client.ts +++ b/packages/amazonq/src/lsp/client.ts @@ -76,6 +76,8 @@ export async function startLanguageServer( resourcePaths.node, ] getLogger('amazonqLsp').info(`Patched node runtime with GLIBC to ${executable}`) + } else { + executable = [resourcePaths.node] } const serverOptions = createServerOptions({