From ff8f46a38d1050d398d67b5f2e3519b3fc944d9b Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Nov 2025 18:14:53 +0100 Subject: [PATCH 1/6] fix: change cmux npm package to mux --- registry/coder/modules/cmux/README.md | 22 +++---- registry/coder/modules/cmux/main.test.ts | 12 ++-- registry/coder/modules/cmux/main.tf | 24 ++++---- registry/coder/modules/cmux/run.sh | 77 ++++++++++++++---------- 4 files changed, 73 insertions(+), 62 deletions(-) diff --git a/registry/coder/modules/cmux/README.md b/registry/coder/modules/cmux/README.md index c1ced2831..a379f3031 100644 --- a/registry/coder/modules/cmux/README.md +++ b/registry/coder/modules/cmux/README.md @@ -8,13 +8,13 @@ tags: [ai, agents, development, multiplexer] # cmux -Automatically install and run [cmux](https://github.com/coder/cmux) in a Coder workspace. By default, the module installs `@coder/cmux@latest` from npm (with a fallback to downloading the npm tarball if npm is unavailable). cmux is a desktop application for parallel agentic development that enables developers to run multiple AI agents simultaneously across isolated cmux workspaces. +Automatically install and run mux in a Coder workspace. By default, the module installs `mux@next` from npm (with a fallback to downloading the npm tarball if npm is unavailable). mux is a desktop application for parallel agentic development that enables developers to run multiple AI agents simultaneously across isolated workspaces. ```tf module "cmux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cmux/coder" - version = "1.0.2" + version = "1.1.0" agent_id = coder_agent.example.id } ``` @@ -22,7 +22,7 @@ module "cmux" { ## Features - **Parallel Agent Execution**: Run multiple AI agents simultaneously on different tasks -- **Cmux Workspace Isolation**: Each agent works in its own isolated environment +- **Mux Workspace Isolation**: Each agent works in its own isolated environment - **Git Divergence Visualization**: Track changes across different cmux agent workspaces - **Long-Running Processes**: Resume AI work after interruptions - **Cost Tracking**: Monitor API usage across agents @@ -35,7 +35,7 @@ module "cmux" { module "cmux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cmux/coder" - version = "1.0.2" + version = "1.1.0" agent_id = coder_agent.example.id } ``` @@ -46,7 +46,7 @@ module "cmux" { module "cmux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cmux/coder" - version = "1.0.2" + version = "1.1.0" agent_id = coder_agent.example.id # Default is "latest"; set to a specific version to pin install_version = "0.4.0" @@ -59,7 +59,7 @@ module "cmux" { module "cmux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cmux/coder" - version = "1.0.2" + version = "1.1.0" agent_id = coder_agent.example.id port = 8080 } @@ -67,13 +67,13 @@ module "cmux" { ### Use Cached Installation -Run an existing copy of cmux if found, otherwise install from npm: +Run an existing copy of mux if found, otherwise install from npm: ```tf module "cmux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cmux/coder" - version = "1.0.2" + version = "1.1.0" agent_id = coder_agent.example.id use_cached = true } @@ -81,13 +81,13 @@ module "cmux" { ### Skip Install -Run without installing from the network (requires cmux to be pre-installed): +Run without installing from the network (requires mux to be pre-installed): ```tf module "cmux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cmux/coder" - version = "1.0.2" + version = "1.1.0" agent_id = coder_agent.example.id install = false } @@ -101,4 +101,4 @@ module "cmux" { - cmux is currently in preview and you may encounter bugs - Requires internet connectivity for agent operations (unless `install` is set to false) -- Installs `@coder/cmux` from npm by default (falls back to the npm tarball if npm is unavailable) +- Installs `mux@next` from npm by default (falls back to the npm tarball if npm is unavailable) diff --git a/registry/coder/modules/cmux/main.test.ts b/registry/coder/modules/cmux/main.test.ts index 5ff42c3f0..7ec1bcf6f 100644 --- a/registry/coder/modules/cmux/main.test.ts +++ b/registry/coder/modules/cmux/main.test.ts @@ -6,7 +6,7 @@ import { testRequiredVariables, } from "~test"; -describe("cmux", async () => { +describe("mux", async () => { await runTerraformInit(import.meta.dir); testRequiredVariables(import.meta.dir, { @@ -31,8 +31,8 @@ describe("cmux", async () => { expect(output.exitCode).toBe(0); const expectedLines = [ "📥 npm not found; downloading tarball from npm registry...", - "🥳 cmux has been installed in /tmp/cmux", - "🚀 Starting cmux server on port 4000...", + "🥳 mux has been installed in /tmp/cmux", + "🚀 Starting mux server on port 4000...", "Check logs at /tmp/cmux.log!", ]; for (const line of expectedLines) { @@ -54,9 +54,9 @@ describe("cmux", async () => { expect(output.exitCode).toBe(0); const expectedLines = [ - "📦 Installing @coder/cmux via npm into /tmp/cmux...", - "🥳 cmux has been installed in /tmp/cmux", - "🚀 Starting cmux server on port 4000...", + "📦 Installing mux via npm into /tmp/cmux...", + "🥳 mux has been installed in /tmp/cmux", + "🚀 Starting mux server on port 4000...", "Check logs at /tmp/cmux.log!", ]; for (const line of expectedLines) { diff --git a/registry/coder/modules/cmux/main.tf b/registry/coder/modules/cmux/main.tf index 37ec52021..be5f818d6 100644 --- a/registry/coder/modules/cmux/main.tf +++ b/registry/coder/modules/cmux/main.tf @@ -17,38 +17,38 @@ variable "agent_id" { variable "port" { type = number - description = "The port to run cmux on." + description = "The port to run mux on." default = 4000 } variable "display_name" { type = string - description = "The display name for the cmux application." - default = "cmux" + description = "The display name for the mux application." + default = "mux" } variable "slug" { type = string - description = "The slug for the cmux application." - default = "cmux" + description = "The slug for the mux application." + default = "mux" } variable "install_prefix" { type = string - description = "The prefix to install cmux to." + description = "The prefix to install mux to." default = "/tmp/cmux" } variable "log_path" { type = string - description = "The path for cmux logs." + description = "The path for mux logs." default = "/tmp/cmux.log" } variable "install_version" { type = string - description = "The version of cmux to install." - default = "latest" + description = "The version or dist-tag of mux to install." + default = "next" } variable "share" { @@ -74,13 +74,13 @@ variable "group" { variable "install" { type = bool - description = "Install cmux from the network (npm or tarball). If false, run without installing (requires a pre-installed cmux)." + description = "Install mux from the network (npm or tarball). If false, run without installing (requires a pre-installed mux)." default = true } variable "use_cached" { type = bool - description = "Use cached copy of cmux if present; otherwise install from npm" + description = "Use cached copy of mux if present; otherwise install from npm" default = false } @@ -109,7 +109,7 @@ variable "open_in" { resource "coder_script" "cmux" { agent_id = var.agent_id - display_name = "cmux" + display_name = "mux" icon = "/icon/cmux.svg" script = templatefile("${path.module}/run.sh", { VERSION : var.install_version, diff --git a/registry/coder/modules/cmux/run.sh b/registry/coder/modules/cmux/run.sh index 23656f8f7..43bb80f58 100644 --- a/registry/coder/modules/cmux/run.sh +++ b/registry/coder/modules/cmux/run.sh @@ -2,7 +2,7 @@ BOLD='\033[0;1m' RESET='\033[0m' -CMUX_BINARY="${INSTALL_PREFIX}/cmux" +CMUX_BINARY="${INSTALL_PREFIX}/mux" function run_cmux() { local port_value @@ -10,7 +10,7 @@ function run_cmux() { if [ -z "$port_value" ]; then port_value="4000" fi - echo "🚀 Starting cmux server on port $port_value..." + echo "🚀 Starting mux server on port $port_value..." echo "Check logs at ${LOG_PATH}!" PORT="$port_value" "$CMUX_BINARY" server --port "$port_value" > "${LOG_PATH}" 2>&1 & } @@ -18,48 +18,51 @@ function run_cmux() { # Check if cmux is already installed for offline mode if [ "${OFFLINE}" = true ]; then if [ -f "$CMUX_BINARY" ]; then - echo "🥳 Found a copy of cmux" + echo "🥳 Found a copy of mux" run_cmux exit 0 fi - echo "❌ Failed to find a copy of cmux" + echo "❌ Failed to find a copy of mux" exit 1 fi # If there is no cached install OR we don't want to use a cached install if [ ! -f "$CMUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then - printf "$${BOLD}Installing cmux from npm...\n" + printf "$${BOLD}Installing mux from npm...\n" # Clean up from other install (in case install prefix changed). if [ -n "$CODER_SCRIPT_BIN_DIR" ] && [ -e "$CODER_SCRIPT_BIN_DIR/cmux" ]; then rm "$CODER_SCRIPT_BIN_DIR/cmux" fi + if [ -n "$CODER_SCRIPT_BIN_DIR" ] && [ -e "$CODER_SCRIPT_BIN_DIR/mux" ]; then + rm "$CODER_SCRIPT_BIN_DIR/mux" + fi mkdir -p "$(dirname "$CMUX_BINARY")" if command -v npm > /dev/null 2>&1; then - echo "📦 Installing @coder/cmux via npm into ${INSTALL_PREFIX}..." + echo "📦 Installing mux via npm into ${INSTALL_PREFIX}..." NPM_WORKDIR="${INSTALL_PREFIX}/npm" mkdir -p "$NPM_WORKDIR" cd "$NPM_WORKDIR" || exit 1 if [ ! -f package.json ]; then echo '{}' > package.json fi - PKG="@coder/cmux" + PKG="mux" if [ -z "${VERSION}" ] || [ "${VERSION}" = "latest" ]; then PKG_SPEC="$PKG@latest" else PKG_SPEC="$PKG@${VERSION}" fi if ! npm install --no-audit --no-fund --omit=dev "$PKG_SPEC"; then - echo "❌ Failed to install @coder/cmux via npm" + echo "❌ Failed to install mux via npm" exit 1 fi # Determine the installed binary path BIN_DIR="$NPM_WORKDIR/node_modules/.bin" - CANDIDATE="$BIN_DIR/cmux" + CANDIDATE="$BIN_DIR/mux" if [ ! -f "$CANDIDATE" ]; then - echo "❌ Could not locate cmux binary after npm install" + echo "❌ Could not locate mux binary after npm install" exit 1 fi chmod +x "$CANDIDATE" || true @@ -67,16 +70,19 @@ if [ ! -f "$CMUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then else echo "📥 npm not found; downloading tarball from npm registry..." VERSION_TO_USE="${VERSION}" - if [ -z "$VERSION_TO_USE" ] || [ "$VERSION_TO_USE" = "latest" ]; then - # Try to determine the latest version - META_URL="https://registry.npmjs.org/@coder/cmux/latest" - VERSION_TO_USE="$(curl -fsSL "$META_URL" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p' | head -n1)" - if [ -z "$VERSION_TO_USE" ]; then - echo "❌ Could not determine latest version for @coder/cmux" - exit 1 - fi + if [ -z "$VERSION_TO_USE" ]; then + VERSION_TO_USE="next" fi - TARBALL_URL="https://registry.npmjs.org/@coder/cmux/-/cmux-$VERSION_TO_USE.tgz" + META_URL="https://registry.npmjs.org/mux/$VERSION_TO_USE" + RESOLVED_VERSION="$(curl -fsSL "$META_URL" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p' | head -n1)" + if [ -n "$RESOLVED_VERSION" ]; then + VERSION_TO_USE="$RESOLVED_VERSION" + fi + if [ -z "$VERSION_TO_USE" ]; then + echo "❌ Could not determine version for mux" + exit 1 + fi + TARBALL_URL="https://registry.npmjs.org/mux/-/mux-$VERSION_TO_USE.tgz" TMP_DIR="$(mktemp -d)" TAR_PATH="$TMP_DIR/cmux.tgz" if ! curl -fsSL "$TARBALL_URL" -o "$TAR_PATH"; then @@ -91,18 +97,18 @@ if [ ! -f "$CMUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then fi CANDIDATE="" # Common locations - if [ -f "$TMP_DIR/package/bin/cmux" ]; then - CANDIDATE="$TMP_DIR/package/bin/cmux" - elif [ -f "$TMP_DIR/package/bin/cmux.js" ]; then - CANDIDATE="$TMP_DIR/package/bin/cmux.js" - elif [ -f "$TMP_DIR/package/bin/cmux.mjs" ]; then - CANDIDATE="$TMP_DIR/package/bin/cmux.mjs" + if [ -f "$TMP_DIR/package/bin/mux" ]; then + CANDIDATE="$TMP_DIR/package/bin/mux" + elif [ -f "$TMP_DIR/package/bin/mux.js" ]; then + CANDIDATE="$TMP_DIR/package/bin/mux.js" + elif [ -f "$TMP_DIR/package/bin/mux.mjs" ]; then + CANDIDATE="$TMP_DIR/package/bin/mux.mjs" else # Try to read package.json bin field if [ -f "$TMP_DIR/package/package.json" ]; then BIN_PATH=$(sed -n 's/.*"bin"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$TMP_DIR/package/package.json" | head -n1) if [ -z "$BIN_PATH" ]; then - BIN_PATH=$(sed -n '/"bin"[[:space:]]*:[[:space:]]*{/,/}/p' "$TMP_DIR/package/package.json" | sed -n 's/.*"cmux"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1) + BIN_PATH=$(sed -n '/"bin"[[:space:]]*:[[:space:]]*{/,/}/p' "$TMP_DIR/package/package.json" | sed -n 's/.*"mux"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1) fi if [ -n "$BIN_PATH" ] && [ -f "$TMP_DIR/package/$BIN_PATH" ]; then CANDIDATE="$TMP_DIR/package/$BIN_PATH" @@ -110,11 +116,11 @@ if [ ! -f "$CMUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then fi # Fallback: search for plausible filenames if [ -z "$CANDIDATE" ] || [ ! -f "$CANDIDATE" ]; then - CANDIDATE=$(find "$TMP_DIR/package" -maxdepth 4 -type f \( -name "cmux" -o -name "cmux.js" -o -name "cmux.mjs" -o -name "cmux.cjs" \) | head -n1) + CANDIDATE=$(find "$TMP_DIR/package" -maxdepth 4 -type f \( -name "mux" -o -name "mux.js" -o -name "mux.mjs" -o -name "mux.cjs" \) | head -n1) fi fi if [ -z "$CANDIDATE" ] || [ ! -f "$CANDIDATE" ]; then - echo "❌ Could not locate cmux binary in tarball" + echo "❌ Could not locate mux binary in tarball" rm -rf "$TMP_DIR" exit 1 fi @@ -123,13 +129,18 @@ if [ ! -f "$CMUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then rm -rf "$TMP_DIR" fi - printf "🥳 cmux has been installed in ${INSTALL_PREFIX}\n\n" + printf "🥳 mux has been installed in ${INSTALL_PREFIX}\n\n" fi -# Make cmux available in PATH if CODER_SCRIPT_BIN_DIR is set -if [ -n "$CODER_SCRIPT_BIN_DIR" ] && [ ! -e "$CODER_SCRIPT_BIN_DIR/cmux" ]; then - ln -s "$CMUX_BINARY" "$CODER_SCRIPT_BIN_DIR/cmux" +# Make mux available in PATH if CODER_SCRIPT_BIN_DIR is set (and cmux for compatibility) +if [ -n "$CODER_SCRIPT_BIN_DIR" ]; then + if [ ! -e "$CODER_SCRIPT_BIN_DIR/mux" ]; then + ln -s "$CMUX_BINARY" "$CODER_SCRIPT_BIN_DIR/mux" + fi + if [ ! -e "$CODER_SCRIPT_BIN_DIR/cmux" ]; then + ln -s "$CMUX_BINARY" "$CODER_SCRIPT_BIN_DIR/cmux" + fi fi -# Start cmux +# Start mux run_cmux From 733876c99bce8225047027d2ae8e910c5b913fa5 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:10:17 +0100 Subject: [PATCH 2/6] fix: migrated from cmux to mux --- .icons/{cmux.svg => mux.svg} | 0 registry/coder/modules/cmux/run.sh | 146 -------------- .../coder/modules/{cmux => mux}/README.md | 46 ++--- .../coder/modules/{cmux => mux}/main.test.ts | 10 +- registry/coder/modules/{cmux => mux}/main.tf | 14 +- .../cmux.tftest.hcl => mux/mux.tftest.hcl} | 6 +- registry/coder/modules/mux/run.sh | 190 ++++++++++++++++++ 7 files changed, 230 insertions(+), 182 deletions(-) rename .icons/{cmux.svg => mux.svg} (100%) delete mode 100644 registry/coder/modules/cmux/run.sh rename registry/coder/modules/{cmux => mux}/README.md (75%) rename registry/coder/modules/{cmux => mux}/main.test.ts (87%) rename registry/coder/modules/{cmux => mux}/main.tf (95%) rename registry/coder/modules/{cmux/cmux.tftest.hcl => mux/mux.tftest.hcl} (89%) create mode 100644 registry/coder/modules/mux/run.sh diff --git a/.icons/cmux.svg b/.icons/mux.svg similarity index 100% rename from .icons/cmux.svg rename to .icons/mux.svg diff --git a/registry/coder/modules/cmux/run.sh b/registry/coder/modules/cmux/run.sh deleted file mode 100644 index 43bb80f58..000000000 --- a/registry/coder/modules/cmux/run.sh +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env bash - -BOLD='\033[0;1m' -RESET='\033[0m' -CMUX_BINARY="${INSTALL_PREFIX}/mux" - -function run_cmux() { - local port_value - port_value="${PORT}" - if [ -z "$port_value" ]; then - port_value="4000" - fi - echo "🚀 Starting mux server on port $port_value..." - echo "Check logs at ${LOG_PATH}!" - PORT="$port_value" "$CMUX_BINARY" server --port "$port_value" > "${LOG_PATH}" 2>&1 & -} - -# Check if cmux is already installed for offline mode -if [ "${OFFLINE}" = true ]; then - if [ -f "$CMUX_BINARY" ]; then - echo "🥳 Found a copy of mux" - run_cmux - exit 0 - fi - echo "❌ Failed to find a copy of mux" - exit 1 -fi - -# If there is no cached install OR we don't want to use a cached install -if [ ! -f "$CMUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then - printf "$${BOLD}Installing mux from npm...\n" - - # Clean up from other install (in case install prefix changed). - if [ -n "$CODER_SCRIPT_BIN_DIR" ] && [ -e "$CODER_SCRIPT_BIN_DIR/cmux" ]; then - rm "$CODER_SCRIPT_BIN_DIR/cmux" - fi - if [ -n "$CODER_SCRIPT_BIN_DIR" ] && [ -e "$CODER_SCRIPT_BIN_DIR/mux" ]; then - rm "$CODER_SCRIPT_BIN_DIR/mux" - fi - - mkdir -p "$(dirname "$CMUX_BINARY")" - - if command -v npm > /dev/null 2>&1; then - echo "📦 Installing mux via npm into ${INSTALL_PREFIX}..." - NPM_WORKDIR="${INSTALL_PREFIX}/npm" - mkdir -p "$NPM_WORKDIR" - cd "$NPM_WORKDIR" || exit 1 - if [ ! -f package.json ]; then - echo '{}' > package.json - fi - PKG="mux" - if [ -z "${VERSION}" ] || [ "${VERSION}" = "latest" ]; then - PKG_SPEC="$PKG@latest" - else - PKG_SPEC="$PKG@${VERSION}" - fi - if ! npm install --no-audit --no-fund --omit=dev "$PKG_SPEC"; then - echo "❌ Failed to install mux via npm" - exit 1 - fi - # Determine the installed binary path - BIN_DIR="$NPM_WORKDIR/node_modules/.bin" - CANDIDATE="$BIN_DIR/mux" - if [ ! -f "$CANDIDATE" ]; then - echo "❌ Could not locate mux binary after npm install" - exit 1 - fi - chmod +x "$CANDIDATE" || true - ln -sf "$CANDIDATE" "$CMUX_BINARY" - else - echo "📥 npm not found; downloading tarball from npm registry..." - VERSION_TO_USE="${VERSION}" - if [ -z "$VERSION_TO_USE" ]; then - VERSION_TO_USE="next" - fi - META_URL="https://registry.npmjs.org/mux/$VERSION_TO_USE" - RESOLVED_VERSION="$(curl -fsSL "$META_URL" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p' | head -n1)" - if [ -n "$RESOLVED_VERSION" ]; then - VERSION_TO_USE="$RESOLVED_VERSION" - fi - if [ -z "$VERSION_TO_USE" ]; then - echo "❌ Could not determine version for mux" - exit 1 - fi - TARBALL_URL="https://registry.npmjs.org/mux/-/mux-$VERSION_TO_USE.tgz" - TMP_DIR="$(mktemp -d)" - TAR_PATH="$TMP_DIR/cmux.tgz" - if ! curl -fsSL "$TARBALL_URL" -o "$TAR_PATH"; then - echo "❌ Failed to download tarball: $TARBALL_URL" - rm -rf "$TMP_DIR" - exit 1 - fi - if ! tar -xzf "$TAR_PATH" -C "$TMP_DIR"; then - echo "❌ Failed to extract tarball" - rm -rf "$TMP_DIR" - exit 1 - fi - CANDIDATE="" - # Common locations - if [ -f "$TMP_DIR/package/bin/mux" ]; then - CANDIDATE="$TMP_DIR/package/bin/mux" - elif [ -f "$TMP_DIR/package/bin/mux.js" ]; then - CANDIDATE="$TMP_DIR/package/bin/mux.js" - elif [ -f "$TMP_DIR/package/bin/mux.mjs" ]; then - CANDIDATE="$TMP_DIR/package/bin/mux.mjs" - else - # Try to read package.json bin field - if [ -f "$TMP_DIR/package/package.json" ]; then - BIN_PATH=$(sed -n 's/.*"bin"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$TMP_DIR/package/package.json" | head -n1) - if [ -z "$BIN_PATH" ]; then - BIN_PATH=$(sed -n '/"bin"[[:space:]]*:[[:space:]]*{/,/}/p' "$TMP_DIR/package/package.json" | sed -n 's/.*"mux"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1) - fi - if [ -n "$BIN_PATH" ] && [ -f "$TMP_DIR/package/$BIN_PATH" ]; then - CANDIDATE="$TMP_DIR/package/$BIN_PATH" - fi - fi - # Fallback: search for plausible filenames - if [ -z "$CANDIDATE" ] || [ ! -f "$CANDIDATE" ]; then - CANDIDATE=$(find "$TMP_DIR/package" -maxdepth 4 -type f \( -name "mux" -o -name "mux.js" -o -name "mux.mjs" -o -name "mux.cjs" \) | head -n1) - fi - fi - if [ -z "$CANDIDATE" ] || [ ! -f "$CANDIDATE" ]; then - echo "❌ Could not locate mux binary in tarball" - rm -rf "$TMP_DIR" - exit 1 - fi - cp "$CANDIDATE" "$CMUX_BINARY" - chmod +x "$CMUX_BINARY" || true - rm -rf "$TMP_DIR" - fi - - printf "🥳 mux has been installed in ${INSTALL_PREFIX}\n\n" -fi - -# Make mux available in PATH if CODER_SCRIPT_BIN_DIR is set (and cmux for compatibility) -if [ -n "$CODER_SCRIPT_BIN_DIR" ]; then - if [ ! -e "$CODER_SCRIPT_BIN_DIR/mux" ]; then - ln -s "$CMUX_BINARY" "$CODER_SCRIPT_BIN_DIR/mux" - fi - if [ ! -e "$CODER_SCRIPT_BIN_DIR/cmux" ]; then - ln -s "$CMUX_BINARY" "$CODER_SCRIPT_BIN_DIR/cmux" - fi -fi - -# Start mux -run_cmux diff --git a/registry/coder/modules/cmux/README.md b/registry/coder/modules/mux/README.md similarity index 75% rename from registry/coder/modules/cmux/README.md rename to registry/coder/modules/mux/README.md index a379f3031..9bd85e20c 100644 --- a/registry/coder/modules/cmux/README.md +++ b/registry/coder/modules/mux/README.md @@ -1,20 +1,20 @@ --- -display_name: cmux +display_name: mux description: Coding Agent Multiplexer - Run multiple AI agents in parallel -icon: ../../../../.icons/cmux.svg +icon: ../../../../.icons/mux.svg verified: false tags: [ai, agents, development, multiplexer] --- -# cmux +# mux Automatically install and run mux in a Coder workspace. By default, the module installs `mux@next` from npm (with a fallback to downloading the npm tarball if npm is unavailable). mux is a desktop application for parallel agentic development that enables developers to run multiple AI agents simultaneously across isolated workspaces. ```tf -module "cmux" { +module "mux" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/cmux/coder" - version = "1.1.0" + source = "registry.coder.com/coder/mux/coder" + version = "1.0.0" agent_id = coder_agent.example.id } ``` @@ -23,7 +23,7 @@ module "cmux" { - **Parallel Agent Execution**: Run multiple AI agents simultaneously on different tasks - **Mux Workspace Isolation**: Each agent works in its own isolated environment -- **Git Divergence Visualization**: Track changes across different cmux agent workspaces +- **Git Divergence Visualization**: Track changes across different mux agent workspaces - **Long-Running Processes**: Resume AI work after interruptions - **Cost Tracking**: Monitor API usage across agents @@ -32,10 +32,10 @@ module "cmux" { ### Basic Usage ```tf -module "cmux" { +module "mux" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/cmux/coder" - version = "1.1.0" + source = "registry.coder.com/coder/mux/coder" + version = "1.0.0" agent_id = coder_agent.example.id } ``` @@ -43,10 +43,10 @@ module "cmux" { ### Pin Version ```tf -module "cmux" { +module "mux" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/cmux/coder" - version = "1.1.0" + source = "registry.coder.com/coder/mux/coder" + version = "1.0.0" agent_id = coder_agent.example.id # Default is "latest"; set to a specific version to pin install_version = "0.4.0" @@ -56,10 +56,10 @@ module "cmux" { ### Custom Port ```tf -module "cmux" { +module "mux" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/cmux/coder" - version = "1.1.0" + source = "registry.coder.com/coder/mux/coder" + version = "1.0.0" agent_id = coder_agent.example.id port = 8080 } @@ -70,10 +70,10 @@ module "cmux" { Run an existing copy of mux if found, otherwise install from npm: ```tf -module "cmux" { +module "mux" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/cmux/coder" - version = "1.1.0" + source = "registry.coder.com/coder/mux/coder" + version = "1.0.0" agent_id = coder_agent.example.id use_cached = true } @@ -84,10 +84,10 @@ module "cmux" { Run without installing from the network (requires mux to be pre-installed): ```tf -module "cmux" { +module "mux" { count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/cmux/coder" - version = "1.1.0" + source = "registry.coder.com/coder/mux/coder" + version = "1.0.0" agent_id = coder_agent.example.id install = false } @@ -99,6 +99,6 @@ module "cmux" { ## Notes -- cmux is currently in preview and you may encounter bugs +- mux is currently in preview and you may encounter bugs - Requires internet connectivity for agent operations (unless `install` is set to false) - Installs `mux@next` from npm by default (falls back to the npm tarball if npm is unavailable) diff --git a/registry/coder/modules/cmux/main.test.ts b/registry/coder/modules/mux/main.test.ts similarity index 87% rename from registry/coder/modules/cmux/main.test.ts rename to registry/coder/modules/mux/main.test.ts index 7ec1bcf6f..efc00460d 100644 --- a/registry/coder/modules/cmux/main.test.ts +++ b/registry/coder/modules/mux/main.test.ts @@ -31,9 +31,9 @@ describe("mux", async () => { expect(output.exitCode).toBe(0); const expectedLines = [ "📥 npm not found; downloading tarball from npm registry...", - "🥳 mux has been installed in /tmp/cmux", + "🥳 mux has been installed in /tmp/mux", "🚀 Starting mux server on port 4000...", - "Check logs at /tmp/cmux.log!", + "Check logs at /tmp/mux.log!", ]; for (const line of expectedLines) { expect(output.stdout).toContain(line); @@ -54,10 +54,10 @@ describe("mux", async () => { expect(output.exitCode).toBe(0); const expectedLines = [ - "📦 Installing mux via npm into /tmp/cmux...", - "🥳 mux has been installed in /tmp/cmux", + "📦 Installing mux via npm into /tmp/mux...", + "🥳 mux has been installed in /tmp/mux", "🚀 Starting mux server on port 4000...", - "Check logs at /tmp/cmux.log!", + "Check logs at /tmp/mux.log!", ]; for (const line of expectedLines) { expect(output.stdout).toContain(line); diff --git a/registry/coder/modules/cmux/main.tf b/registry/coder/modules/mux/main.tf similarity index 95% rename from registry/coder/modules/cmux/main.tf rename to registry/coder/modules/mux/main.tf index be5f818d6..f76e046cf 100644 --- a/registry/coder/modules/cmux/main.tf +++ b/registry/coder/modules/mux/main.tf @@ -36,13 +36,13 @@ variable "slug" { variable "install_prefix" { type = string description = "The prefix to install mux to." - default = "/tmp/cmux" + default = "/tmp/mux" } variable "log_path" { type = string description = "The path for mux logs." - default = "/tmp/cmux.log" + default = "/tmp/mux.log" } variable "install_version" { @@ -107,10 +107,10 @@ variable "open_in" { } } -resource "coder_script" "cmux" { +resource "coder_script" "mux" { agent_id = var.agent_id display_name = "mux" - icon = "/icon/cmux.svg" + icon = "/icon/mux.svg" script = templatefile("${path.module}/run.sh", { VERSION : var.install_version, PORT : var.port, @@ -129,12 +129,12 @@ resource "coder_script" "cmux" { } } -resource "coder_app" "cmux" { +resource "coder_app" "mux" { agent_id = var.agent_id slug = var.slug display_name = var.display_name url = "http://localhost:${var.port}" - icon = "/icon/cmux.svg" + icon = "/icon/mux.svg" subdomain = var.subdomain share = var.share order = var.order @@ -147,3 +147,5 @@ resource "coder_app" "cmux" { threshold = 6 } } + + diff --git a/registry/coder/modules/cmux/cmux.tftest.hcl b/registry/coder/modules/mux/mux.tftest.hcl similarity index 89% rename from registry/coder/modules/cmux/cmux.tftest.hcl rename to registry/coder/modules/mux/mux.tftest.hcl index 3b831b373..c403d377d 100644 --- a/registry/coder/modules/cmux/cmux.tftest.hcl +++ b/registry/coder/modules/mux/mux.tftest.hcl @@ -16,7 +16,7 @@ run "install_false_and_use_cached_conflict" { } expect_failures = [ - resource.coder_script.cmux + resource.coder_script.mux ] } @@ -29,7 +29,7 @@ run "custom_port" { } assert { - condition = resource.coder_app.cmux.url == "http://localhost:8080" + condition = resource.coder_app.mux.url == "http://localhost:8080" error_message = "coder_app URL must use the configured port" } } @@ -62,3 +62,5 @@ run "use_cached_only_success" { use_cached = true } } + + diff --git a/registry/coder/modules/mux/run.sh b/registry/coder/modules/mux/run.sh new file mode 100644 index 000000000..503b68106 --- /dev/null +++ b/registry/coder/modules/mux/run.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash + +BOLD='\033[0;1m' +RESET='\033[0m' +MUX_BINARY="${INSTALL_PREFIX}/mux" + +function run_mux() { + local port_value + port_value="${PORT}" + if [ -z "$port_value" ]; then + port_value="4000" + fi + echo "🚀 Starting mux server on port $port_value..." + echo "Check logs at ${LOG_PATH}!" + PORT="$port_value" "$MUX_BINARY" server --port "$port_value" > "${LOG_PATH}" 2>&1 & +} + +# Check if mux is already installed for offline mode +if [ "${OFFLINE}" = true ]; then + if [ -f "$MUX_BINARY" ]; then + echo "🥳 Found a copy of mux" + run_mux + exit 0 + fi + echo "❌ Failed to find a copy of mux" + exit 1 +fi + +# If there is no cached install OR we don't want to use a cached install +if [ ! -f "$MUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then + printf "$${BOLD}Installing mux from npm...\n" + + # Clean up from other install (in case install prefix changed). + if [ -n "$CODER_SCRIPT_BIN_DIR" ] && [ -e "$CODER_SCRIPT_BIN_DIR/mux" ]; then + rm "$CODER_SCRIPT_BIN_DIR/mux" + fi + + mkdir -p "$(dirname "$MUX_BINARY")" + + if command -v npm > /dev/null 2>&1; then + echo "📦 Installing mux via npm into ${INSTALL_PREFIX}..." + NPM_WORKDIR="${INSTALL_PREFIX}/npm" + mkdir -p "$NPM_WORKDIR" + cd "$NPM_WORKDIR" || exit 1 + if [ ! -f package.json ]; then + echo '{}' > package.json + fi + PKG="mux" + if [ -z "${VERSION}" ] || [ "${VERSION}" = "latest" ]; then + PKG_SPEC="$PKG@latest" + else + PKG_SPEC="$PKG@${VERSION}" + fi + if ! npm install --no-audit --no-fund --omit=dev "$PKG_SPEC"; then + echo "❌ Failed to install mux via npm" + exit 1 + fi + # Determine the installed binary path + BIN_DIR="$NPM_WORKDIR/node_modules/.bin" + CANDIDATE="$BIN_DIR/mux" + if [ ! -f "$CANDIDATE" ]; then + echo "❌ Could not locate mux binary after npm install" + exit 1 + fi + chmod +x "$CANDIDATE" || true + ln -sf "$CANDIDATE" "$MUX_BINARY" + else + echo "📥 npm not found; downloading tarball from npm registry..." + VERSION_TO_USE="${VERSION}" + if [ -z "$VERSION_TO_USE" ]; then + VERSION_TO_USE="next" + fi + META_URL="https://registry.npmjs.org/mux/$VERSION_TO_USE" + META_JSON="$(curl -fsSL "$META_URL" || true)" + if [ -z "$META_JSON" ]; then + echo "❌ Failed to fetch npm metadata: $META_URL" + exit 1 + fi + # Normalize JSON to a single line for robust pattern matching across environments + META_ONE_LINE="$(printf "%s" "$META_JSON" | tr -d '\n' || true)" + if [ -z "$META_ONE_LINE" ]; then + META_ONE_LINE="$META_JSON" + fi + # Try to extract tarball URL directly from metadata (prefer Node if available for robust JSON parsing) + TARBALL_URL="" + if command -v node >/dev/null 2>&1; then + TARBALL_URL="$(printf "%s" "$META_JSON" | node -e 'try{const fs=require("fs");const data=JSON.parse(fs.readFileSync(0,"utf8"));if(data&&data.dist&&data.dist.tarball){console.log(data.dist.tarball);}}catch(e){}')" + fi + # sed-based fallback + if [ -z "$TARBALL_URL" ]; then + TARBALL_URL="$(printf "%s" "$META_ONE_LINE" | sed -n 's/.*\"tarball\":\"\\([^\"]*\\)\".*/\\1/p' | head -n1)" + fi + # Fallback: resolve version then construct tarball URL + if [ -z "$TARBALL_URL" ]; then + RESOLVED_VERSION="" + if command -v node >/dev/null 2>&1; then + RESOLVED_VERSION="$(printf "%s" "$META_JSON" | node -e 'try{const fs=require("fs");const data=JSON.parse(fs.readFileSync(0,"utf8"));if(data&&data.version){console.log(data.version);}}catch(e){}')" + fi + if [ -z "$RESOLVED_VERSION" ]; then + RESOLVED_VERSION="$(printf "%s" "$META_ONE_LINE" | sed -n 's/.*\"version\":\"\\([^\"]*\\)\".*/\\1/p' | head -n1)" + fi + if [ -z "$RESOLVED_VERSION" ]; then + RESOLVED_VERSION="$(printf "%s" "$META_ONE_LINE" | grep -o '\"version\":\"[^\"]*\"' | head -n1 | cut -d '\"' -f4)" + fi + if [ -n "$RESOLVED_VERSION" ]; then + VERSION_TO_USE="$RESOLVED_VERSION" + fi + if [ -z "$VERSION_TO_USE" ]; then + echo "❌ Could not determine version for mux" + exit 1 + fi + TARBALL_URL="https://registry.npmjs.org/mux/-/mux-$VERSION_TO_USE.tgz" + fi + TMP_DIR="$(mktemp -d)" + TAR_PATH="$TMP_DIR/mux.tgz" + if ! curl -fsSL "$TARBALL_URL" -o "$TAR_PATH"; then + echo "❌ Failed to download tarball: $TARBALL_URL" + rm -rf "$TMP_DIR" + exit 1 + fi + if ! tar -xzf "$TAR_PATH" -C "$TMP_DIR"; then + echo "❌ Failed to extract tarball" + rm -rf "$TMP_DIR" + exit 1 + fi + CANDIDATE="" + BIN_PATH="" + # Prefer reading bin path from package.json + if [ -f "$TMP_DIR/package/package.json" ]; then + if command -v node >/dev/null 2>&1; then + BIN_PATH="$(node -e 'try{const fs=require("fs");const p=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));let bp=typeof p.bin==="string"?p.bin:(p.bin&&p.bin.mux);if(bp){console.log(bp)}}catch(e){}' "$TMP_DIR/package/package.json")" + fi + if [ -z "$BIN_PATH" ]; then + # sed fallbacks (handle both string and object forms) + BIN_PATH=$(sed -n 's/.*\"bin\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p' "$TMP_DIR/package/package.json" | head -n1) + if [ -z "$BIN_PATH" ]; then + BIN_PATH=$(sed -n '/\"bin\"[[:space:]]*:[[:space:]]*{/,/}/p' "$TMP_DIR/package/package.json" | sed -n 's/.*\"mux\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p' | head -n1) + fi + fi + if [ -n "$BIN_PATH" ] && [ -f "$TMP_DIR/package/$BIN_PATH" ]; then + CANDIDATE="$TMP_DIR/package/$BIN_PATH" + fi + fi + # Fallback: check common locations + if [ -z "$CANDIDATE" ]; then + if [ -f "$TMP_DIR/package/bin/mux" ]; then + CANDIDATE="$TMP_DIR/package/bin/mux" + elif [ -f "$TMP_DIR/package/bin/mux.js" ]; then + CANDIDATE="$TMP_DIR/package/bin/mux.js" + elif [ -f "$TMP_DIR/package/bin/mux.mjs" ]; then + CANDIDATE="$TMP_DIR/package/bin/mux.mjs" + fi + fi + # Fallback: search for plausible filenames + if [ -z "$CANDIDATE" ] || [ ! -f "$CANDIDATE" ]; then + CANDIDATE=$(find "$TMP_DIR/package" -maxdepth 4 -type f \( -name "mux" -o -name "mux.js" -o -name "mux.mjs" -o -name "mux.cjs" -o -name "main.js" \) | head -n1) + fi + if [ -z "$CANDIDATE" ] || [ ! -f "$CANDIDATE" ]; then + echo "❌ Could not locate mux binary in tarball" + rm -rf "$TMP_DIR" + exit 1 + fi + # Copy entire package to installation directory to preserve relative imports + DEST_DIR="${INSTALL_PREFIX}/.mux-package" + rm -rf "$DEST_DIR" + mkdir -p "$DEST_DIR" + cp -R "$TMP_DIR/package/." "$DEST_DIR/" + # Create/refresh launcher symlink + if [ -n "$BIN_PATH" ] && [ -f "$DEST_DIR/$BIN_PATH" ]; then + ln -sf "$DEST_DIR/$BIN_PATH" "$MUX_BINARY" + chmod +x "$DEST_DIR/$BIN_PATH" || true + else + ln -sf "$DEST_DIR/$(basename "$CANDIDATE")" "$MUX_BINARY" + chmod +x "$DEST_DIR/$(basename "$CANDIDATE")" || true + fi + rm -rf "$TMP_DIR" + fi + + printf "🥳 mux has been installed in ${INSTALL_PREFIX}\n\n" +fi + +# Make mux available in PATH if CODER_SCRIPT_BIN_DIR is set +if [ -n "$CODER_SCRIPT_BIN_DIR" ]; then + if [ ! -e "$CODER_SCRIPT_BIN_DIR/mux" ]; then + ln -s "$MUX_BINARY" "$CODER_SCRIPT_BIN_DIR/mux" + fi +fi + +# Start mux +run_mux From 7561637f934b4ebc5ce19db44e742aea8e9d049c Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:36:00 +0100 Subject: [PATCH 3/6] fix: fmt --- registry/coder/modules/mux/run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/registry/coder/modules/mux/run.sh b/registry/coder/modules/mux/run.sh index 503b68106..b48b03131 100644 --- a/registry/coder/modules/mux/run.sh +++ b/registry/coder/modules/mux/run.sh @@ -83,7 +83,7 @@ if [ ! -f "$MUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then fi # Try to extract tarball URL directly from metadata (prefer Node if available for robust JSON parsing) TARBALL_URL="" - if command -v node >/dev/null 2>&1; then + if command -v node > /dev/null 2>&1; then TARBALL_URL="$(printf "%s" "$META_JSON" | node -e 'try{const fs=require("fs");const data=JSON.parse(fs.readFileSync(0,"utf8"));if(data&&data.dist&&data.dist.tarball){console.log(data.dist.tarball);}}catch(e){}')" fi # sed-based fallback @@ -93,7 +93,7 @@ if [ ! -f "$MUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then # Fallback: resolve version then construct tarball URL if [ -z "$TARBALL_URL" ]; then RESOLVED_VERSION="" - if command -v node >/dev/null 2>&1; then + if command -v node > /dev/null 2>&1; then RESOLVED_VERSION="$(printf "%s" "$META_JSON" | node -e 'try{const fs=require("fs");const data=JSON.parse(fs.readFileSync(0,"utf8"));if(data&&data.version){console.log(data.version);}}catch(e){}')" fi if [ -z "$RESOLVED_VERSION" ]; then @@ -127,7 +127,7 @@ if [ ! -f "$MUX_BINARY" ] || [ "${USE_CACHED}" != true ]; then BIN_PATH="" # Prefer reading bin path from package.json if [ -f "$TMP_DIR/package/package.json" ]; then - if command -v node >/dev/null 2>&1; then + if command -v node > /dev/null 2>&1; then BIN_PATH="$(node -e 'try{const fs=require("fs");const p=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));let bp=typeof p.bin==="string"?p.bin:(p.bin&&p.bin.mux);if(bp){console.log(bp)}}catch(e){}' "$TMP_DIR/package/package.json")" fi if [ -z "$BIN_PATH" ]; then From a29533599bc8e8066030453a3e1bc0b4663b8428 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Nov 2025 22:02:19 +0100 Subject: [PATCH 4/6] fix: add handling for add-project --- registry/coder/modules/mux/main.tf | 7 +++++++ registry/coder/modules/mux/run.sh | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/mux/main.tf b/registry/coder/modules/mux/main.tf index f76e046cf..08c70aab6 100644 --- a/registry/coder/modules/mux/main.tf +++ b/registry/coder/modules/mux/main.tf @@ -45,6 +45,12 @@ variable "log_path" { default = "/tmp/mux.log" } +variable "add-project" { + type = string + description = "Path to add/open as a project in mux (idempotent)." + default = "" +} + variable "install_version" { type = string description = "The version or dist-tag of mux to install." @@ -115,6 +121,7 @@ resource "coder_script" "mux" { VERSION : var.install_version, PORT : var.port, LOG_PATH : var.log_path, + ADD_PROJECT : var.add-project, INSTALL_PREFIX : var.install_prefix, OFFLINE : !var.install, USE_CACHED : var.use_cached, diff --git a/registry/coder/modules/mux/run.sh b/registry/coder/modules/mux/run.sh index b48b03131..931cdcb5b 100644 --- a/registry/coder/modules/mux/run.sh +++ b/registry/coder/modules/mux/run.sh @@ -10,9 +10,15 @@ function run_mux() { if [ -z "$port_value" ]; then port_value="4000" fi + # Build args for mux + local args + args=(server --port "$port_value") + if [ -n "${ADD_PROJECT}" ]; then + args+=( --add-project "${ADD_PROJECT}") + fi echo "🚀 Starting mux server on port $port_value..." echo "Check logs at ${LOG_PATH}!" - PORT="$port_value" "$MUX_BINARY" server --port "$port_value" > "${LOG_PATH}" 2>&1 & + PORT="$port_value" "$MUX_BINARY" "${args[@]}" > "${LOG_PATH}" 2>&1 & } # Check if mux is already installed for offline mode From 930576900770a0610874d1a5557e668d8368abfc Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Nov 2025 22:59:23 +0100 Subject: [PATCH 5/6] fix: fmt --- registry/coder/modules/mux/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/mux/run.sh b/registry/coder/modules/mux/run.sh index 931cdcb5b..97ed65683 100644 --- a/registry/coder/modules/mux/run.sh +++ b/registry/coder/modules/mux/run.sh @@ -14,7 +14,7 @@ function run_mux() { local args args=(server --port "$port_value") if [ -n "${ADD_PROJECT}" ]; then - args+=( --add-project "${ADD_PROJECT}") + args+=(--add-project "${ADD_PROJECT}") fi echo "🚀 Starting mux server on port $port_value..." echo "Check logs at ${LOG_PATH}!" From 62a052888031fe322755149d38893a797dd7f6bf Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Mon, 10 Nov 2025 23:06:16 +0100 Subject: [PATCH 6/6] fix: fmt & test --- registry/coder/modules/mux/run.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/mux/run.sh b/registry/coder/modules/mux/run.sh index 97ed65683..c202a9ee0 100644 --- a/registry/coder/modules/mux/run.sh +++ b/registry/coder/modules/mux/run.sh @@ -10,15 +10,14 @@ function run_mux() { if [ -z "$port_value" ]; then port_value="4000" fi - # Build args for mux - local args - args=(server --port "$port_value") + # Build args for mux (POSIX-compatible, avoid bash arrays) + set -- server --port "$port_value" if [ -n "${ADD_PROJECT}" ]; then - args+=(--add-project "${ADD_PROJECT}") + set -- "$@" --add-project "${ADD_PROJECT}" fi echo "🚀 Starting mux server on port $port_value..." echo "Check logs at ${LOG_PATH}!" - PORT="$port_value" "$MUX_BINARY" "${args[@]}" > "${LOG_PATH}" 2>&1 & + PORT="$port_value" "$MUX_BINARY" "$@" > "${LOG_PATH}" 2>&1 & } # Check if mux is already installed for offline mode