From aaefee78de2486bf563404c8f605aed21c8532af Mon Sep 17 00:00:00 2001 From: ThanhNguyxn Date: Fri, 30 Jan 2026 17:12:02 +0700 Subject: [PATCH 1/3] fix(signal): preserve case for group IDs (base64 is case-sensitive) fix(windows): add shell option for spawn on Windows to fix npm ENOENT Fixes #4537, Fixes #4557 --- src/channels/plugins/normalize/signal.ts | 8 +++++--- src/process/exec.ts | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/channels/plugins/normalize/signal.ts b/src/channels/plugins/normalize/signal.ts index c8ff17da6..9750dba5e 100644 --- a/src/channels/plugins/normalize/signal.ts +++ b/src/channels/plugins/normalize/signal.ts @@ -8,21 +8,23 @@ export function normalizeSignalMessagingTarget(raw: string): string | undefined if (!normalized) return undefined; const lower = normalized.toLowerCase(); if (lower.startsWith("group:")) { + // Preserve case for group IDs - base64 is case-sensitive const id = normalized.slice("group:".length).trim(); - return id ? `group:${id}`.toLowerCase() : undefined; + return id ? `group:${id}` : undefined; } if (lower.startsWith("username:")) { const id = normalized.slice("username:".length).trim(); - return id ? `username:${id}`.toLowerCase() : undefined; + return id ? `username:${id.toLowerCase()}` : undefined; } if (lower.startsWith("u:")) { const id = normalized.slice("u:".length).trim(); - return id ? `username:${id}`.toLowerCase() : undefined; + return id ? `username:${id.toLowerCase()}` : undefined; } if (lower.startsWith("uuid:")) { const id = normalized.slice("uuid:".length).trim(); return id ? id.toLowerCase() : undefined; } + // Phone numbers and other targets can be lowercased return normalized.toLowerCase(); } diff --git a/src/process/exec.ts b/src/process/exec.ts index 44f8b2ce0..0e8397c64 100644 --- a/src/process/exec.ts +++ b/src/process/exec.ts @@ -85,6 +85,7 @@ export async function runCommandWithTimeout( cwd, env: resolvedEnv, windowsVerbatimArguments, + shell: process.platform === "win32", }); // Spawn with inherited stdin (TTY) so tools like `pi` stay interactive when needed. return await new Promise((resolve, reject) => { From 59f6fc37485b1055f2d5cc516df68b54cc6747c4 Mon Sep 17 00:00:00 2001 From: ThanhNguyxn Date: Fri, 30 Jan 2026 22:36:49 +0700 Subject: [PATCH 2/3] fix(exec): scope Windows shell to npm/pnpm/yarn/npx --- src/process/exec.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/process/exec.ts b/src/process/exec.ts index 0e8397c64..d77af40ef 100644 --- a/src/process/exec.ts +++ b/src/process/exec.ts @@ -80,12 +80,15 @@ export async function runCommandWithTimeout( } const stdio = resolveCommandStdio({ hasInput, preferInherit: true }); + const cmdTool = path.parse(argv[0] ?? "").name; + const needsShell = + process.platform === "win32" && ["npm", "pnpm", "yarn", "npx"].includes(cmdTool); const child = spawn(argv[0], argv.slice(1), { stdio, cwd, env: resolvedEnv, windowsVerbatimArguments, - shell: process.platform === "win32", + shell: needsShell, }); // Spawn with inherited stdin (TTY) so tools like `pi` stay interactive when needed. return await new Promise((resolve, reject) => { From 37e43c8f7f5bf623764ae77be2da6f49e87f7f27 Mon Sep 17 00:00:00 2001 From: ThanhNguyxn Date: Fri, 30 Jan 2026 22:56:50 +0700 Subject: [PATCH 3/3] ci: skip submodule update when no .gitmodules --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 885d87fcb..a2abe26ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,10 @@ jobs: - name: Checkout submodules (retry) run: | set -euo pipefail + if [ ! -f .gitmodules ]; then + echo "No .gitmodules found; skipping submodule update." + exit 0 + fi git submodule sync --recursive for attempt in 1 2 3 4 5; do if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then @@ -101,6 +105,10 @@ jobs: - name: Checkout submodules (retry) run: | set -euo pipefail + if [ ! -f .gitmodules ]; then + echo "No .gitmodules found; skipping submodule update." + exit 0 + fi git submodule sync --recursive for attempt in 1 2 3 4 5; do if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then @@ -217,6 +225,10 @@ jobs: - name: Checkout submodules (retry) run: | set -euo pipefail + if [ ! -f .gitmodules ]; then + echo "No .gitmodules found; skipping submodule update." + exit 0 + fi git submodule sync --recursive for attempt in 1 2 3 4 5; do if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then @@ -293,6 +305,10 @@ jobs: - name: Checkout submodules (retry) run: | set -euo pipefail + if [ ! -f .gitmodules ]; then + echo "No .gitmodules found; skipping submodule update." + exit 0 + fi git submodule sync --recursive for attempt in 1 2 3 4 5; do if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then @@ -389,6 +405,10 @@ jobs: - name: Checkout submodules (retry) run: | set -euo pipefail + if [ ! -f .gitmodules ]; then + echo "No .gitmodules found; skipping submodule update." + exit 0 + fi git submodule sync --recursive for attempt in 1 2 3 4 5; do if git -c protocol.version=2 submodule update --init --force --depth=1 --recursive; then