From c43185309694dac11501a7c8b1b78bbba390aa52 Mon Sep 17 00:00:00 2001 From: xingjie zhou Date: Tue, 17 Mar 2026 22:33:14 +0800 Subject: [PATCH 1/2] fix(acpx): read ACPX_PINNED_VERSION from package.json instead of hardcoding The hardcoded ACPX_PINNED_VERSION ("0.1.16") falls out of sync with the bundled acpx version in package.json every release, causing ACP runtime to be marked unavailable due to version mismatch (see #43997). --- extensions/acpx/src/config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/acpx/src/config.ts b/extensions/acpx/src/config.ts index d6bfb3a44db..db2d77a11fa 100644 --- a/extensions/acpx/src/config.ts +++ b/extensions/acpx/src/config.ts @@ -9,7 +9,6 @@ export type AcpxPermissionMode = (typeof ACPX_PERMISSION_MODES)[number]; export const ACPX_NON_INTERACTIVE_POLICIES = ["deny", "fail"] as const; export type AcpxNonInteractivePermissionPolicy = (typeof ACPX_NON_INTERACTIVE_POLICIES)[number]; -export const ACPX_PINNED_VERSION = "0.1.16"; export const ACPX_VERSION_ANY = "any"; const ACPX_BIN_NAME = process.platform === "win32" ? "acpx.cmd" : "acpx"; @@ -33,6 +32,8 @@ export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): stri } export const ACPX_PLUGIN_ROOT = resolveAcpxPluginRoot(); +const pluginPkg = JSON.parse(fs.readFileSync(path.join(ACPX_PLUGIN_ROOT, "package.json"), "utf8")); +export const ACPX_PINNED_VERSION: string = pluginPkg.dependencies.acpx; export const ACPX_BUNDLED_BIN = path.join(ACPX_PLUGIN_ROOT, "node_modules", ".bin", ACPX_BIN_NAME); export function buildAcpxLocalInstallCommand(version: string = ACPX_PINNED_VERSION): string { return `npm install --omit=dev --no-save acpx@${version}`; From aef2c45381a0d53af593f4b5af85d8be0e221500 Mon Sep 17 00:00:00 2001 From: xingjie zhou Date: Wed, 18 Mar 2026 10:02:57 +0800 Subject: [PATCH 2/2] Validate and sanitize ACPX version retrieval Add validation for acpx version from package.json --- extensions/acpx/src/config.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/acpx/src/config.ts b/extensions/acpx/src/config.ts index db2d77a11fa..8786a7fc272 100644 --- a/extensions/acpx/src/config.ts +++ b/extensions/acpx/src/config.ts @@ -33,7 +33,13 @@ export function resolveAcpxPluginRoot(moduleUrl: string = import.meta.url): stri export const ACPX_PLUGIN_ROOT = resolveAcpxPluginRoot(); const pluginPkg = JSON.parse(fs.readFileSync(path.join(ACPX_PLUGIN_ROOT, "package.json"), "utf8")); -export const ACPX_PINNED_VERSION: string = pluginPkg.dependencies.acpx; +const acpxVersion: unknown = pluginPkg?.dependencies?.acpx; +if (typeof acpxVersion !== "string" || acpxVersion.trim() === "") { + throw new Error( + `Could not read acpx version from ${path.join(ACPX_PLUGIN_ROOT, "package.json")} — expected a non-empty string at dependencies.acpx` + ); +} +export const ACPX_PINNED_VERSION: string = acpxVersion.replace(/^[^0-9]*/, ""); export const ACPX_BUNDLED_BIN = path.join(ACPX_PLUGIN_ROOT, "node_modules", ".bin", ACPX_BIN_NAME); export function buildAcpxLocalInstallCommand(version: string = ACPX_PINNED_VERSION): string { return `npm install --omit=dev --no-save acpx@${version}`;