From e80177fa2d9ffe238ef6f09f9957c18b68a95c11 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:23:41 -0500 Subject: [PATCH 1/9] =?UTF-8?q?=F0=9F=A4=96=20refactor:=20rename=20cmux=20?= =?UTF-8?q?to=20mux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprehensive rename from cmux to mux across the entire codebase. ## Core Changes ### Directory Migration - Added `ensureMuxMigration()` to automatically migrate ~/.cmux → ~/.mux - Creates backward-compatible symlink ~/.cmux → ~/.mux - Called early in app startup to ensure seamless upgrade ### Constants & Paths - Renamed all path functions: getCmuxHome() → getMuxHome(), etc. - Updated base directory: .cmux → .mux - Updated environment variables: MUX_TEST_ROOT, MUX_DEVSERVER_PORT, etc. ### Configuration - Changed appId: com.cmux.app → com.mux.app (clean break) - Changed productName: cmux → mux - Updated package.json description - Kept repository URLs as github.com/coder/cmux (unchanged per plan) - Kept docs domain as cmux.io (unchanged per plan) ### Storage Keys (with migration) - mux_telemetry_enabled (migrates from cmux_telemetry_enabled) - mux_first_launch_complete (migrates from cmux_first_launch_complete) - Both keys check legacy values and migrate automatically ### Benchmarks - Renamed files: cmux_agent.py → mux_agent.py, etc. - Updated Python classes: CmuxAgent → MuxAgent, CmuxPayload → MuxPayload - Updated shell scripts and Jinja2 templates ### Documentation - Updated all markdown files in docs/ - Updated book.toml title - Updated GitHub Actions: setup-cmux → setup-mux - Updated workflow files to use new action name ### Source Code - Updated ~112 files with function calls, comments, strings - Updated UI strings: "Generated with cmux" → "Generated with mux" - Updated log messages and error strings - Updated test files and assertions ## Backward Compatibility Users upgrading from previous versions will: 1. Have ~/.cmux automatically moved to ~/.mux on first launch 2. Get symlink ~/.cmux → ~/.mux for old tools/scripts 3. Have localStorage keys migrated automatically 4. Experience no data loss or manual intervention needed ## VS Code Extension Excluded from this PR - will be updated in separate PR later. ## What Stays Unchanged - GitHub repository URLs (github.com/coder/cmux) - will update when repo renamed - Documentation domain (cmux.io) - keeping for now - VS Code extension references - separate PR _Generated with `mux`_ --- .../{setup-cmux => setup-mux}/action.yml | 2 +- .github/workflows/build.yml | 8 +- .github/workflows/chromatic.yml | 2 +- .github/workflows/ci.yml | 10 +- .github/workflows/publish-npm.yml | 2 +- .github/workflows/release.yml | 8 +- .github/workflows/terminal-bench.yml | 2 +- Makefile | 12 +-- README.md | 12 +-- benchmarks/terminal_bench/cmux-run.sh | 100 ------------------ benchmarks/terminal_bench/mux-run.sh | 100 ++++++++++++++++++ .../{cmux_agent.py => mux_agent.py} | 4 +- .../{cmux_agent_test.py => mux_agent_test.py} | 6 +- .../{cmux_payload.py => mux_payload.py} | 0 .../{cmux_setup.sh.j2 => mux_setup.sh.j2} | 16 +-- dev-app-update.yml | 2 +- docs/AGENTS.md | 20 ++-- docs/README.md | 6 +- docs/agentic-git-identity.md | 10 +- docs/benchmarking.md | 24 ++--- docs/book.toml | 6 +- docs/init-hooks.md | 6 +- docs/install.md | 16 +-- docs/instruction-files.md | 12 +-- docs/intro.md | 10 +- docs/keybinds.md | 2 +- docs/local.md | 6 +- docs/models.md | 10 +- docs/project-secrets.md | 6 +- docs/prompting-tips.md | 4 +- docs/ssh.md | 8 +- docs/system-prompt.md | 4 +- docs/telemetry.md | 10 +- docs/vim-mode.md | 2 +- docs/vscode-extension.md | 12 +-- docs/why-parallelize.md | 2 +- docs/workspaces.md | 6 +- flake.nix | 34 +++--- index.html | 2 +- package.json | 6 +- public/manifest.json | 4 +- scripts/check_pr_reviews.sh | 4 +- scripts/extract_pr_logs.sh | 2 +- src/App.tsx | 4 +- src/components/ChatInput.tsx | 4 +- .../Messages/ChatBarrier/RetryBarrier.tsx | 2 +- src/components/Messages/MessageWindow.tsx | 4 +- src/components/hooks/useGitBranchDetails.ts | 18 ++-- src/config.ts | 6 +- src/constants/paths.ts | 79 +++++++++----- src/debug/chatExtractors.ts | 16 +-- src/debug/costs.ts | 6 +- src/debug/git-status.ts | 6 +- src/debug/list-workspaces.ts | 4 +- src/debug/replay-history.ts | 12 +-- src/debug/send-message.ts | 12 +-- src/hooks/useStartHere.ts | 4 +- src/main-desktop.ts | 25 +++-- src/services/agentSession.ts | 4 +- src/services/aiService.ts | 30 +++--- src/services/historyService.test.ts | 88 +++++++-------- src/services/historyService.ts | 18 ++-- src/services/ipcMain.ts | 8 +- src/services/log.ts | 8 +- src/services/mock/mockScenarioPlayer.test.ts | 10 +- src/services/mock/mockScenarioPlayer.ts | 14 +-- src/services/partialService.test.ts | 14 +-- src/services/partialService.ts | 8 +- src/services/streamManager.ts | 16 +-- src/services/systemMessage.ts | 4 +- src/stores/WorkspaceConsumerManager.ts | 4 +- src/stores/WorkspaceStore.ts | 18 ++-- src/telemetry/client.ts | 20 +++- src/telemetry/lifecycle.ts | 24 +++-- src/types/ipc.ts | 18 ++-- src/types/message.ts | 38 +++---- src/types/providerOptions.ts | 6 +- src/types/stream.ts | 6 +- src/utils/ai/providerOptions.ts | 4 +- src/utils/chatCommands.ts | 6 +- src/utils/extensionMetadata.ts | 6 +- .../messages/StreamingMessageAggregator.ts | 30 +++--- .../messages/applyToolOutputRedaction.ts | 8 +- .../messages/modelMessageTransform.test.ts | 40 +++---- src/utils/messages/modelMessageTransform.ts | 18 ++-- src/utils/messages/recency.test.ts | 68 ++++++------ src/utils/messages/recency.ts | 4 +- src/utils/messages/retryEligibility.ts | 6 +- src/utils/messages/sanitizeToolInput.test.ts | 16 +-- src/utils/messages/sanitizeToolInput.ts | 6 +- src/utils/tokens/tokenStatsCalculator.test.ts | 14 +-- src/utils/tokens/tokenStatsCalculator.ts | 14 +-- src/utils/ui/pathAbbreviation.test.ts | 4 +- src/utils/ui/pathAbbreviation.ts | 2 +- static/splash.html | 4 +- tests/e2e/electronTest.ts | 28 ++--- tests/e2e/utils/ui.ts | 14 +-- tests/ipcMain/createWorkspace.test.ts | 12 +-- tests/ipcMain/forkWorkspace.test.ts | 6 +- tests/ipcMain/helpers.ts | 6 +- tests/ipcMain/initWorkspace.test.ts | 18 ++-- tests/ipcMain/ollama.test.ts | 4 +- tests/ipcMain/projectCreate.test.ts | 22 ++-- tests/ipcMain/resumeStream.test.ts | 4 +- tests/ipcMain/runtimeExecuteBash.test.ts | 2 +- tests/ipcMain/runtimeFileEditing.test.ts | 2 +- tests/ipcMain/sendMessage.test.ts | 14 +-- tests/ipcMain/setup.ts | 2 +- tests/ipcMain/truncate.test.ts | 26 ++--- tests/ipcMain/windowTitle.test.ts | 8 +- tests/runtime/ssh-fixture.ts | 10 +- tests/setup.ts | 4 +- vite.config.ts | 8 +- 113 files changed, 788 insertions(+), 730 deletions(-) rename .github/actions/{setup-cmux => setup-mux}/action.yml (99%) delete mode 100644 benchmarks/terminal_bench/cmux-run.sh create mode 100644 benchmarks/terminal_bench/mux-run.sh rename benchmarks/terminal_bench/{cmux_agent.py => mux_agent.py} (98%) rename benchmarks/terminal_bench/{cmux_agent_test.py => mux_agent_test.py} (91%) rename benchmarks/terminal_bench/{cmux_payload.py => mux_payload.py} (100%) rename benchmarks/terminal_bench/{cmux_setup.sh.j2 => mux_setup.sh.j2} (74%) diff --git a/.github/actions/setup-cmux/action.yml b/.github/actions/setup-mux/action.yml similarity index 99% rename from .github/actions/setup-cmux/action.yml rename to .github/actions/setup-mux/action.yml index 4c1fb0d65..6a248abfe 100644 --- a/.github/actions/setup-cmux/action.yml +++ b/.github/actions/setup-mux/action.yml @@ -1,4 +1,4 @@ -name: "Setup Cmux" +name: "Setup Mux" description: "Setup Bun and install dependencies with caching" inputs: install-imagemagick: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36053d970..72958a4ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux with: install-imagemagick: true @@ -72,7 +72,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux with: install-imagemagick: true @@ -99,7 +99,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - uses: ./.github/actions/build-vscode-extension @@ -107,6 +107,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: vscode-extension - path: vscode/cmux-*.vsix + path: vscode/mux-*.vsix retention-days: 30 if-no-files-found: error diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 04ca19c99..9ebda4142 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -19,7 +19,7 @@ jobs: with: fetch-depth: 0 # Required for Chromatic to track changes - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Generate version file run: ./scripts/generate-version.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ae56af8a..2c3b2a233 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Generate version file run: ./scripts/generate-version.sh @@ -76,7 +76,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Build worker files run: make build-main @@ -101,7 +101,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Check if Ollama is pre-installed id: check-ollama @@ -157,7 +157,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Install Playwright browsers run: bun x playwright install --with-deps @@ -183,7 +183,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Install system dependencies run: | diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 3dafaec9e..a42a22957 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -22,7 +22,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux with: install-imagemagick: "true" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd4e161d6..211edeea4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux with: install-imagemagick: true @@ -47,7 +47,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux with: install-imagemagick: true @@ -68,7 +68,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - uses: ./.github/actions/build-vscode-extension @@ -77,5 +77,5 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release upload ${{ github.event.release.tag_name }} \ - vscode/cmux-*.vsix \ + vscode/mux-*.vsix \ --clobber diff --git a/.github/workflows/terminal-bench.yml b/.github/workflows/terminal-bench.yml index 50cb87418..9f68ca0a7 100644 --- a/.github/workflows/terminal-bench.yml +++ b/.github/workflows/terminal-bench.yml @@ -87,7 +87,7 @@ jobs: with: fetch-depth: 0 # Required for git describe to find tags - - uses: ./.github/actions/setup-cmux + - uses: ./.github/actions/setup-mux - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/Makefile b/Makefile index 95306c148..4319dfd13 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Build System # ============ -# This Makefile orchestrates the cmux build process. +# This Makefile orchestrates the mux build process. # # Quick Start: # make help - Show all available targets @@ -110,7 +110,7 @@ dev-server: node_modules/.installed build-main ## Start server mode with hot rel @bun x concurrently -k \ "bun x concurrently \"$(TSGO) -w -p tsconfig.main.json\" \"bun x tsc-alias -w -p tsconfig.main.json\"" \ "bun x nodemon --watch dist/main.js --watch dist/main-server.js --delay 500ms --exec 'NODE_ENV=development node dist/main.js server --host $(or $(BACKEND_HOST),localhost) --port $(or $(BACKEND_PORT),3000)'" \ - "CMUX_VITE_HOST=$(or $(VITE_HOST),127.0.0.1) CMUX_VITE_PORT=$(or $(VITE_PORT),5173) VITE_BACKEND_URL=http://$(or $(BACKEND_HOST),localhost):$(or $(BACKEND_PORT),3000) vite" + "MUX_VITE_HOST=$(or $(VITE_HOST),127.0.0.1) MUX_VITE_PORT=$(or $(VITE_PORT),5173) VITE_BACKEND_URL=http://$(or $(BACKEND_HOST),localhost):$(or $(BACKEND_PORT),3000) vite" @@ -225,7 +225,7 @@ test-coverage: ## Run tests with coverage test-e2e: ## Run end-to-end tests @$(MAKE) build - @CMUX_E2E_LOAD_DIST=1 CMUX_E2E_SKIP_BUILD=1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 bun x playwright test --project=electron $(PLAYWRIGHT_ARGS) + @MUX_E2E_LOAD_DIST=1 MUX_E2E_SKIP_BUILD=1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 bun x playwright test --project=electron $(PLAYWRIGHT_ARGS) ## Distribution dist: build ## Build distributable packages @@ -308,7 +308,7 @@ chromatic: node_modules/.installed ## Run Chromatic for visual regression testin @bun x chromatic --exit-zero-on-changes ## Benchmarks -benchmark-terminal: ## Run Terminal-Bench with the cmux agent (use TB_DATASET/TB_SAMPLE_SIZE/TB_TIMEOUT/TB_ARGS to customize) +benchmark-terminal: ## Run Terminal-Bench with the mux agent (use TB_DATASET/TB_SAMPLE_SIZE/TB_TIMEOUT/TB_ARGS to customize) @TB_DATASET=$${TB_DATASET:-terminal-bench-core==0.1.1}; \ TB_TIMEOUT=$${TB_TIMEOUT:-1800}; \ CONCURRENCY_FLAG=$${TB_CONCURRENCY:+--n-concurrent $$TB_CONCURRENCY}; \ @@ -333,10 +333,10 @@ benchmark-terminal: ## Run Terminal-Bench with the cmux agent (use TB_DATASET/TB fi; \ echo "Using timeout: $$TB_TIMEOUT seconds"; \ echo "Running Terminal-Bench with dataset $$TB_DATASET"; \ - export CMUX_TIMEOUT_MS=$$((TB_TIMEOUT * 1000)); \ + export MUX_TIMEOUT_MS=$$((TB_TIMEOUT * 1000)); \ uvx terminal-bench run \ --dataset "$$TB_DATASET" \ - --agent-import-path benchmarks.terminal_bench.cmux_agent:CmuxAgent \ + --agent-import-path benchmarks.terminal_bench.mux_agent:CmuxAgent \ --global-agent-timeout-sec $$TB_TIMEOUT \ $$CONCURRENCY_FLAG \ $$LIVESTREAM_FLAG \ diff --git a/README.md b/README.md index 12b0563e4..ba7ea30dc 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@
-cmux logo +mux logo -# cmux - coding agent multiplexer +# mux - coding agent multiplexer [![CI](https://github.com/coder/cmux/actions/workflows/ci.yml/badge.svg)](https://github.com/coder/cmux/actions/workflows/ci.yml) [![Build](https://github.com/coder/cmux/actions/workflows/build.yml/badge.svg?event=merge_group)](https://github.com/coder/cmux/actions/workflows/build.yml?query=event:merge_group) @@ -11,7 +11,7 @@
-![cmux product screenshot](docs/img/product-hero.webp) +![mux product screenshot](docs/img/product-hero.webp) A desktop application for parallel agentic development. @@ -27,7 +27,7 @@ Here are some specific use cases we enable: - The stream will automatically resume after restarts or intermittent connection issues. If the model completes early we will show an indicator. - **A/B testing**: run multiple workspaces in parallel on the same problem but different approaches, abandon the bad ones. -- **Tangent exploration**: launch tangents in `cmux` away from main work +- **Tangent exploration**: launch tangents in `mux` away from main work @@ -39,11 +39,11 @@ Here are some specific use cases we enable: - **Multi-model** (`sonnet-4-*`, `gpt-5-*`, `opus-4-*`) - Ollama supported for local LLMs ([docs](https://cmux.io/models.html#ollama-local)) - OpenRouter supported for long-tail of LLMs ([docs](https://cmux.io/models.html#openrouter-cloud)) -- **VS Code Extension**: Jump into cmux workspaces directly from VS Code ([docs](https://cmux.io/vscode-extension.html)) +- **VS Code Extension**: Jump into mux workspaces directly from VS Code ([docs](https://cmux.io/vscode-extension.html)) - Supporting UI and keybinds for efficiently managing a suite of agents - Rich markdown outputs (mermaid diagrams, LaTeX, etc.) -cmux has a custom agent loop but much of the core UX is inspired by Claude Code. You'll find familiar features like Plan/Exec mode, vim inputs, `/compact` and new ones +mux has a custom agent loop but much of the core UX is inspired by Claude Code. You'll find familiar features like Plan/Exec mode, vim inputs, `/compact` and new ones like [opportunistic compaction](https://cmux.io/context-management.html) and [mode prompts](https://cmux.io/instruction-files.html#mode-prompts). **[Read the full documentation →](https://cmux.io)** diff --git a/benchmarks/terminal_bench/cmux-run.sh b/benchmarks/terminal_bench/cmux-run.sh deleted file mode 100644 index 379256e6a..000000000 --- a/benchmarks/terminal_bench/cmux-run.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -log() { - printf '[cmux-run] %s\n' "$1" -} - -fatal() { - printf '[cmux-run] ERROR: %s\n' "$1" >&2 - exit 1 -} - -instruction=${1:-} -if [[ -z "${instruction}" ]]; then - fatal "instruction argument is required" -fi - -export BUN_INSTALL="${BUN_INSTALL:-/root/.bun}" -export PATH="${BUN_INSTALL}/bin:${PATH}" - -CMUX_APP_ROOT="${CMUX_APP_ROOT:-/opt/cmux-app}" -CMUX_CONFIG_ROOT="${CMUX_CONFIG_ROOT:-/root/.cmux}" -CMUX_PROJECT_PATH="${CMUX_PROJECT_PATH:-}" -CMUX_PROJECT_CANDIDATES="${CMUX_PROJECT_CANDIDATES:-/workspace:/app:/workspaces:/root/project}" -CMUX_MODEL="${CMUX_MODEL:-anthropic:claude-sonnet-4-5}" -CMUX_TIMEOUT_MS="${CMUX_TIMEOUT_MS:-}" -CMUX_TRUNK="${CMUX_TRUNK:-main}" -CMUX_WORKSPACE_ID="${CMUX_WORKSPACE_ID:-cmux-bench}" -CMUX_THINKING_LEVEL="${CMUX_THINKING_LEVEL:-high}" -CMUX_MODE="${CMUX_MODE:-exec}" - -resolve_project_path() { - if [[ -n "${CMUX_PROJECT_PATH}" ]]; then - if [[ -d "${CMUX_PROJECT_PATH}" ]]; then - printf '%s\n' "${CMUX_PROJECT_PATH}" - return 0 - fi - fatal "CMUX_PROJECT_PATH=${CMUX_PROJECT_PATH} not found" - fi - - IFS=":" read -r -a candidates <<<"${CMUX_PROJECT_CANDIDATES}" - for candidate in "${candidates[@]}"; do - if [[ -d "${candidate}" ]]; then - printf '%s\n' "${candidate}" - return 0 - fi - done - - fatal "no project path located (searched ${CMUX_PROJECT_CANDIDATES})" -} - -ensure_git_repo() { - local project_path=$1 - - command -v git >/dev/null 2>&1 || return 0 - - if git -C "${project_path}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then - git -C "${project_path}" checkout "${CMUX_TRUNK}" 2>/dev/null || \ - git -C "${project_path}" checkout -b "${CMUX_TRUNK}" 2>/dev/null || true - return 0 - fi - - log "initialising git repository at ${project_path}" - git -C "${project_path}" init --initial-branch="${CMUX_TRUNK}" 2>/dev/null || \ - (git -C "${project_path}" init && git -C "${project_path}" checkout -B "${CMUX_TRUNK}") >/dev/null - git -C "${project_path}" config user.name "cmux-bench" - git -C "${project_path}" config user.email "bench@cmux.local" - git -C "${project_path}" add -A >/dev/null - git -C "${project_path}" commit -m "chore: initial snapshot" --allow-empty >/dev/null -} - -command -v bun >/dev/null 2>&1 || fatal "bun is not installed" -project_path=$(resolve_project_path) -ensure_git_repo "${project_path}" - -log "starting cmux agent session for ${project_path}" -cd "${CMUX_APP_ROOT}" - -cmd=(bun src/debug/agentSessionCli.ts - --config-root "${CMUX_CONFIG_ROOT}" - --project-path "${project_path}" - --workspace-path "${project_path}" - --workspace-id "${CMUX_WORKSPACE_ID}" - --model "${CMUX_MODEL}" - --mode "${CMUX_MODE}" - --json-streaming) - -if [[ -n "${CMUX_TIMEOUT_MS}" ]]; then - cmd+=(--timeout "${CMUX_TIMEOUT_MS}") -fi - -if [[ -n "${CMUX_THINKING_LEVEL}" ]]; then - cmd+=(--thinking-level "${CMUX_THINKING_LEVEL}") -fi - -# Terminal-bench enforces timeouts via --global-agent-timeout-sec -if ! printf '%s' "${instruction}" | "${cmd[@]}"; then - fatal "cmux agent session failed" -fi diff --git a/benchmarks/terminal_bench/mux-run.sh b/benchmarks/terminal_bench/mux-run.sh new file mode 100644 index 000000000..89e0ba4b0 --- /dev/null +++ b/benchmarks/terminal_bench/mux-run.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +set -euo pipefail + +log() { + printf '[mux-run] %s\n' "$1" +} + +fatal() { + printf '[mux-run] ERROR: %s\n' "$1" >&2 + exit 1 +} + +instruction=${1:-} +if [[ -z "${instruction}" ]]; then + fatal "instruction argument is required" +fi + +export BUN_INSTALL="${BUN_INSTALL:-/root/.bun}" +export PATH="${BUN_INSTALL}/bin:${PATH}" + +MUX_APP_ROOT="${MUX_APP_ROOT:-/opt/mux-app}" +MUX_CONFIG_ROOT="${MUX_CONFIG_ROOT:-/root/.mux}" +MUX_PROJECT_PATH="${MUX_PROJECT_PATH:-}" +MUX_PROJECT_CANDIDATES="${MUX_PROJECT_CANDIDATES:-/workspace:/app:/workspaces:/root/project}" +MUX_MODEL="${MUX_MODEL:-anthropic:claude-sonnet-4-5}" +MUX_TIMEOUT_MS="${MUX_TIMEOUT_MS:-}" +MUX_TRUNK="${MUX_TRUNK:-main}" +MUX_WORKSPACE_ID="${MUX_WORKSPACE_ID:-mux-bench}" +MUX_THINKING_LEVEL="${MUX_THINKING_LEVEL:-high}" +MUX_MODE="${MUX_MODE:-exec}" + +resolve_project_path() { + if [[ -n "${MUX_PROJECT_PATH}" ]]; then + if [[ -d "${MUX_PROJECT_PATH}" ]]; then + printf '%s\n' "${MUX_PROJECT_PATH}" + return 0 + fi + fatal "MUX_PROJECT_PATH=${MUX_PROJECT_PATH} not found" + fi + + IFS=":" read -r -a candidates <<<"${MUX_PROJECT_CANDIDATES}" + for candidate in "${candidates[@]}"; do + if [[ -d "${candidate}" ]]; then + printf '%s\n' "${candidate}" + return 0 + fi + done + + fatal "no project path located (searched ${MUX_PROJECT_CANDIDATES})" +} + +ensure_git_repo() { + local project_path=$1 + + command -v git >/dev/null 2>&1 || return 0 + + if git -C "${project_path}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then + git -C "${project_path}" checkout "${MUX_TRUNK}" 2>/dev/null || \ + git -C "${project_path}" checkout -b "${MUX_TRUNK}" 2>/dev/null || true + return 0 + fi + + log "initialising git repository at ${project_path}" + git -C "${project_path}" init --initial-branch="${MUX_TRUNK}" 2>/dev/null || \ + (git -C "${project_path}" init && git -C "${project_path}" checkout -B "${MUX_TRUNK}") >/dev/null + git -C "${project_path}" config user.name "mux-bench" + git -C "${project_path}" config user.email "bench@mux.local" + git -C "${project_path}" add -A >/dev/null + git -C "${project_path}" commit -m "chore: initial snapshot" --allow-empty >/dev/null +} + +command -v bun >/dev/null 2>&1 || fatal "bun is not installed" +project_path=$(resolve_project_path) +ensure_git_repo "${project_path}" + +log "starting mux agent session for ${project_path}" +cd "${MUX_APP_ROOT}" + +cmd=(bun src/debug/agentSessionCli.ts + --config-root "${MUX_CONFIG_ROOT}" + --project-path "${project_path}" + --workspace-path "${project_path}" + --workspace-id "${MUX_WORKSPACE_ID}" + --model "${MUX_MODEL}" + --mode "${MUX_MODE}" + --json-streaming) + +if [[ -n "${MUX_TIMEOUT_MS}" ]]; then + cmd+=(--timeout "${MUX_TIMEOUT_MS}") +fi + +if [[ -n "${MUX_THINKING_LEVEL}" ]]; then + cmd+=(--thinking-level "${MUX_THINKING_LEVEL}") +fi + +# Terminal-bench enforces timeouts via --global-agent-timeout-sec +if ! printf '%s' "${instruction}" | "${cmd[@]}"; then + fatal "mux agent session failed" +fi diff --git a/benchmarks/terminal_bench/cmux_agent.py b/benchmarks/terminal_bench/mux_agent.py similarity index 98% rename from benchmarks/terminal_bench/cmux_agent.py rename to benchmarks/terminal_bench/mux_agent.py index 2e9afe251..237e18f4e 100644 --- a/benchmarks/terminal_bench/cmux_agent.py +++ b/benchmarks/terminal_bench/mux_agent.py @@ -12,10 +12,10 @@ from terminal_bench.terminal.models import TerminalCommand from terminal_bench.terminal.tmux_session import TmuxSession -from .cmux_payload import build_app_archive, stage_payload +from .mux_payload import build_app_archive, stage_payload -class CmuxAgent(AbstractInstalledAgent): +class MuxAgent(AbstractInstalledAgent): """ Minimal Terminal-Bench adapter that installs cmux into the task container and forwards the benchmark instruction to the cmux headless runner. diff --git a/benchmarks/terminal_bench/cmux_agent_test.py b/benchmarks/terminal_bench/mux_agent_test.py similarity index 91% rename from benchmarks/terminal_bench/cmux_agent_test.py rename to benchmarks/terminal_bench/mux_agent_test.py index da4ecd089..c2040e5af 100644 --- a/benchmarks/terminal_bench/cmux_agent_test.py +++ b/benchmarks/terminal_bench/mux_agent_test.py @@ -4,7 +4,7 @@ import pytest -from .cmux_agent import CmuxAgent +from .mux_agent import MuxAgent @pytest.fixture(autouse=True) @@ -33,7 +33,7 @@ def _repo_root() -> Path: def test_env_defaults_are_normalized(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("CMUX_AGENT_REPO_ROOT", str(_repo_root())) - agent = CmuxAgent(model_name="anthropic/claude-sonnet-4-5") + agent = MuxAgent(model_name="anthropic/claude-sonnet-4-5") env = agent._env @@ -47,6 +47,6 @@ def test_timeout_must_be_numeric(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setenv("CMUX_AGENT_REPO_ROOT", str(_repo_root())) monkeypatch.setenv("CMUX_TIMEOUT_MS", "not-a-number") - agent = CmuxAgent() + agent = MuxAgent() with pytest.raises(ValueError): _ = agent._env diff --git a/benchmarks/terminal_bench/cmux_payload.py b/benchmarks/terminal_bench/mux_payload.py similarity index 100% rename from benchmarks/terminal_bench/cmux_payload.py rename to benchmarks/terminal_bench/mux_payload.py diff --git a/benchmarks/terminal_bench/cmux_setup.sh.j2 b/benchmarks/terminal_bench/mux_setup.sh.j2 similarity index 74% rename from benchmarks/terminal_bench/cmux_setup.sh.j2 rename to benchmarks/terminal_bench/mux_setup.sh.j2 index e9b879dd9..61ed08266 100644 --- a/benchmarks/terminal_bench/cmux_setup.sh.j2 +++ b/benchmarks/terminal_bench/mux_setup.sh.j2 @@ -3,7 +3,7 @@ set -euo pipefail log() { - printf '[cmux-setup] %s\n' "$1" + printf '[mux-setup] %s\n' "$1" } ensure_tool() { @@ -33,28 +33,28 @@ if ! command -v bun >/dev/null 2>&1; then curl -fsSL "${CMUX_BUN_INSTALL_URL:-https://bun.sh/install}" | bash fi -CMUX_APP_ROOT="${CMUX_APP_ROOT:-/opt/cmux-app}" -CMUX_CONFIG_ROOT="${CMUX_CONFIG_ROOT:-/root/.cmux}" +CMUX_APP_ROOT="${CMUX_APP_ROOT:-/opt/mux-app}" +CMUX_CONFIG_ROOT="${CMUX_CONFIG_ROOT:-/root/.mux}" CMUX_AGENT_VERSION="{{ version if version is not none else '' }}" rm -rf "${CMUX_APP_ROOT}" if [[ -n "${CMUX_AGENT_VERSION}" ]]; then : "${CMUX_AGENT_GIT_URL:?CMUX_AGENT_GIT_URL required when version is set}" - log "cloning cmux from ${CMUX_AGENT_GIT_URL} @ ${CMUX_AGENT_VERSION}" + log "cloning mux from ${CMUX_AGENT_GIT_URL} @ ${CMUX_AGENT_VERSION}" git clone --depth 1 --branch "${CMUX_AGENT_VERSION}" "${CMUX_AGENT_GIT_URL}" "${CMUX_APP_ROOT}" else - log "extracting cmux archive" + log "extracting mux archive" mkdir -p "${CMUX_APP_ROOT}" - tar -xzf "/installed-agent/cmux-app.tar.gz" -C "${CMUX_APP_ROOT}" + tar -xzf "/installed-agent/mux-app.tar.gz" -C "${CMUX_APP_ROOT}" fi cd "${CMUX_APP_ROOT}" -log "installing cmux dependencies via bun" +log "installing mux dependencies via bun" bun install --frozen-lockfile mkdir -p "${CMUX_CONFIG_ROOT}" -chmod +x /installed-agent/cmux-run.sh +chmod +x /installed-agent/mux-run.sh log "setup complete" diff --git a/dev-app-update.yml b/dev-app-update.yml index 496b7c6da..663a4d7bf 100644 --- a/dev-app-update.yml +++ b/dev-app-update.yml @@ -1,4 +1,4 @@ provider: github owner: coder -repo: cmux +repo: mux releaseType: release diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 25fa973a0..d5147e4e3 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -2,7 +2,7 @@ ## Project Context -- Project is named `cmux` +- Project is named `mux` - Electron + React desktop application for parallel agentic development - UX should be fast, responsive, and intuitive @@ -10,7 +10,7 @@ The project is in early development phase. Breaking changes of minor features are expected. Strive for backwards and forwards compatibility whenever possible on critical features. Users should be -able to upgrade, downgrade, upgrade between any two versions of cmux. +able to upgrade, downgrade, upgrade between any two versions of mux. Do not worry about migrations for breakage confined to the scope of the PR. ## AI-Generated Content Attribution @@ -18,7 +18,7 @@ Do not worry about migrations for breakage confined to the scope of the PR. When creating public operations (commits, PRs, issues), always include: - 🤖 emoji in the title -- "_Generated with `cmux`_" in the body (if applicable) +- "_Generated with `mux`_" in the body (if applicable) This ensures transparency about AI-generated contributions. @@ -124,9 +124,9 @@ Examples: - `src/preload.ts` - Preload script for IPC - `src/App.tsx` - Main React component - `src/config.ts` - Configuration management -- `~/.cmux/config.json` - User configuration file -- `~/.cmux/src//` - Local workspace directories (git worktrees) -- `~/.cmux/sessions//chat.jsonl` - Session chat histories +- `~/.mux/config.json` - User configuration file +- `~/.mux/src//` - Local workspace directories (git worktrees) +- `~/.mux/sessions//chat.jsonl` - Session chat histories ## Documentation Guidelines @@ -134,7 +134,7 @@ Examples: - **User-facing docs** → `./docs/` directory - **IMPORTANT**: Read `docs/README.md` first before writing user-facing documentation - - User docs are built with mdbook and deployed to https://cmux.io + - User docs are built with mdbook and deployed to https://mux.io - Must be added to `docs/SUMMARY.md` to appear in the docs - Use standard markdown + mermaid diagrams - **Developer docs** → inline with the code its documenting as comments. Consider them notes as notes to future Assistants to understand the logic more quickly. @@ -158,7 +158,7 @@ in `/tmp/ai-sdk-docs/**.mdx`. - Projects sidebar (left panel) - Workspaces (local uses git worktrees, SSH uses remote git clones) -- Configuration persisted to `~/.cmux/config.json` +- Configuration persisted to `~/.mux/config.json` ## Performance Patterns @@ -199,7 +199,7 @@ This project uses **Make** as the primary build orchestrator. See `Makefile` for - When refactoring, use `git mv` to preserve file history instead of rewriting files from scratch -**⚠️ NEVER kill the running cmux process** - The main cmux instance is used for active development. Use `make test` or `make typecheck` to verify changes instead of starting the app in test workspaces. +**⚠️ NEVER kill the running mux process** - The main mux instance is used for active development. Use `make test` or `make typecheck` to verify changes instead of starting the app in test workspaces. ## Testing @@ -490,7 +490,7 @@ The IPC layer is the boundary between backend and frontend. Follow these rules t - `bun run debug ui-messages --workspace ` - Show UI messages for a workspace - `bun run debug ui-messages --workspace --drop ` - Show messages with last n dropped -- Workspace names can be found in `~/.cmux/sessions/` +- Workspace names can be found in `~/.mux/sessions/` ## UX Guidelines diff --git a/docs/README.md b/docs/README.md index 1ab6cbf1e..d5e951e8e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -# cmux Documentation +# mux Documentation -This directory contains the source for cmux documentation built with [mdbook](https://rust-lang.github.io/mdBook/). +This directory contains the source for mux documentation built with [mdbook](https://rust-lang.github.io/mdBook/). ## Quick Start @@ -19,7 +19,7 @@ bun docs:watch - ✅ **Mermaid diagrams** - Add diagrams with ` ```mermaid ` code blocks - ✅ **Link checking** - Automatically validates all links during build -- ✅ **GitHub Pages** - Auto-deploys to https://cmux.io on push to main +- ✅ **GitHub Pages** - Auto-deploys to https://mux.io on push to main ## Structure diff --git a/docs/agentic-git-identity.md b/docs/agentic-git-identity.md index 2e60629ca..2b7934eae 100644 --- a/docs/agentic-git-identity.md +++ b/docs/agentic-git-identity.md @@ -1,6 +1,6 @@ # Agentic Git Identity -Configure cmux to use a separate Git identity for AI-generated commits, making it easy to distinguish between human and AI contributions. Reasons to use a separate identity include: +Configure mux to use a separate Git identity for AI-generated commits, making it easy to distinguish between human and AI contributions. Reasons to use a separate identity include: - Clear attribution - Preventing (accidental) destructive actions @@ -33,7 +33,7 @@ Classic tokens are easier to configure than fine-grained tokens for repository a 2. Go to [Settings → Developer settings → Personal access tokens → Tokens (classic)](https://github.com/settings/tokens) 3. Click "Generate new token (classic)" 4. Configure the token: - - **Note**: "cmux agent token" (or similar) + - **Note**: "mux agent token" (or similar) - **Expiration**: Choose based on your security preferences - **Scopes**: Select `repo` (Full control of private repositories) 5. Click "Generate token" @@ -41,9 +41,9 @@ Classic tokens are easier to configure than fine-grained tokens for repository a ## Step 3: Configure Git Identity -Add the Git identity environment variables as [Project Secrets](./project-secrets.md) in cmux: +Add the Git identity environment variables as [Project Secrets](./project-secrets.md) in mux: -1. Open cmux and find your project in the sidebar +1. Open mux and find your project in the sidebar 2. Click the 🔑 key icon to open the secrets modal 3. Add the following four secrets: - `GIT_AUTHOR_NAME` = `Your Name (Agent)` @@ -54,7 +54,7 @@ Add the Git identity environment variables as [Project Secrets](./project-secret These environment variables will be automatically injected when the agent runs Git commands in that project. -> **Note**: If you need the agent identity outside of cmux, you can alternatively set these as global environment variables in your shell configuration (`~/.zshrc`, `~/.bashrc`, etc.) +> **Note**: If you need the agent identity outside of mux, you can alternatively set these as global environment variables in your shell configuration (`~/.zshrc`, `~/.bashrc`, etc.) ## Step 4: Configure GitHub Authentication diff --git a/docs/benchmarking.md b/docs/benchmarking.md index 12a49ade1..54e7e4526 100644 --- a/docs/benchmarking.md +++ b/docs/benchmarking.md @@ -1,12 +1,12 @@ # Terminal Benchmarking -cmux ships with a headless adapter for [Terminal-Bench](https://www.tbench.ai/). The adapter runs the Electron backend without opening a window and exercises it through the same IPC paths we use in integration tests. This page documents how to launch benchmarks from the repository tree. +mux ships with a headless adapter for [Terminal-Bench](https://www.tbench.ai/). The adapter runs the Electron backend without opening a window and exercises it through the same IPC paths we use in integration tests. This page documents how to launch benchmarks from the repository tree. ## Prerequisites - Docker must be installed and running. Terminal-Bench executes each task inside a dedicated Docker container. - `uv` is available in the nix `devShell` (provided via `flake.nix`), or install it manually from . -- Standard provider API keys (e.g. `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`) should be exported so cmux can stream responses. +- Standard provider API keys (e.g. `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`) should be exported so mux can stream responses. Optional environment overrides: @@ -14,13 +14,13 @@ Optional environment overrides: | ---------------------- | --------------------------------------------------------- | -------------------------------------- | | `CMUX_AGENT_REPO_ROOT` | Path copied into each task container | repo root inferred from the agent file | | `CMUX_TRUNK` | Branch checked out when preparing the project | `main` | -| `CMUX_WORKSPACE_ID` | Workspace identifier used inside cmux | `cmux-bench` | +| `CMUX_WORKSPACE_ID` | Workspace identifier used inside mux | `mux-bench` | | `CMUX_MODEL` | Preferred model (supports `provider/model` syntax) | `anthropic/claude-sonnet-4-5` | | `CMUX_THINKING_LEVEL` | Optional reasoning level (`off`, `low`, `medium`, `high`) | `high` | | `CMUX_MODE` | Starting mode (`plan` or `exec`) | `exec` | | `CMUX_TIMEOUT_MS` | Optional stream timeout in milliseconds | no timeout | -| `CMUX_CONFIG_ROOT` | Location for cmux session data inside the container | `/root/.cmux` | -| `CMUX_APP_ROOT` | Path where the cmux sources are staged | `/opt/cmux-app` | +| `CMUX_CONFIG_ROOT` | Location for mux session data inside the container | `/root/.mux` | +| `CMUX_APP_ROOT` | Path where the mux sources are staged | `/opt/mux-app` | | `CMUX_PROJECT_PATH` | Explicit project directory inside the task container | auto-detected from common paths | ## Running Terminal-Bench @@ -32,18 +32,18 @@ All commands below should be run from the repository root. ```bash uvx terminal-bench run \ --dataset terminal-bench-core==0.1.1 \ - --agent-import-path benchmarks.terminal_bench.cmux_agent:CmuxAgent \ + --agent-import-path benchmarks.terminal_bench.mux_agent:MuxAgent \ --n-tasks 1 ``` -This downloads the Terminal-Bench runner, copies the cmux sources into the container, and validates the adapter against the first task only. Use this before attempting a full sweep. +This downloads the Terminal-Bench runner, copies the mux sources into the container, and validates the adapter against the first task only. Use this before attempting a full sweep. ### Full dataset ```bash uvx terminal-bench run \ --dataset terminal-bench-core==0.1.1 \ - --agent-import-path benchmarks.terminal_bench.cmux_agent:CmuxAgent + --agent-import-path benchmarks.terminal_bench.mux_agent:MuxAgent ``` Results (pass/fail, token usage, wall-clock) are printed at the end of the run. Terminal-Bench also writes per-task logs under the current working directory; review them when diagnosing failures. @@ -61,13 +61,13 @@ Use `TB_CONCURRENCY=` to control `--n-concurrent` (number of concurrently run ## How the Adapter Works -The adapter lives in `benchmarks/terminal_bench/cmux_agent.py`. For each task it: +The adapter lives in `benchmarks/terminal_bench/mux_agent.py`. For each task it: -1. Copies the cmux repository (package manifests + `src/`) into `/tmp/cmux-app` inside the container. +1. Copies the mux repository (package manifests + `src/`) into `/tmp/mux-app` inside the container. 2. Ensures Bun exists, then runs `bun install --frozen-lockfile`. -3. Launches `src/debug/agentSessionCli.ts` to prepare workspace metadata and stream the instruction, storing state under `CMUX_CONFIG_ROOT` (default `/root/.cmux`). +3. Launches `src/debug/agentSessionCli.ts` to prepare workspace metadata and stream the instruction, storing state under `CMUX_CONFIG_ROOT` (default `/root/.mux`). -`CMUX_MODEL` accepts either the cmux colon form (`anthropic:claude-sonnet-4-5`) or the Terminal-Bench slash form (`anthropic/claude-sonnet-4-5`); the adapter normalises whichever you provide. +`CMUX_MODEL` accepts either the mux colon form (`anthropic:claude-sonnet-4-5`) or the Terminal-Bench slash form (`anthropic/claude-sonnet-4-5`); the adapter normalises whichever you provide. ## Troubleshooting diff --git a/docs/book.toml b/docs/book.toml index b27fb6f19..e27b57ad3 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -3,7 +3,7 @@ authors = ["Ammar Bandukwala"] language = "en" multilingual = false src = "." -title = "cmux docs" +title = "mux docs" [build] build-dir = "book" @@ -20,8 +20,8 @@ command = "bun ../scripts/mdbook-shiki.ts" renderer = ["html"] [output.html] -git-repository-url = "https://github.com/coder/cmux" -edit-url-template = "https://github.com/coder/cmux/edit/main/docs/{path}" +git-repository-url = "https://github.com/coder/mux" +edit-url-template = "https://github.com/coder/mux/edit/main/docs/{path}" additional-js = ["mermaid.min.js", "mermaid-init.js", "theme/pagetoc.js", "theme/copy-buttons.js"] additional-css = ["theme/custom.css", "theme/pagetoc.css"] default-theme = "navy" diff --git a/docs/init-hooks.md b/docs/init-hooks.md index eedfbd6ee..4254cbabb 100644 --- a/docs/init-hooks.md +++ b/docs/init-hooks.md @@ -1,6 +1,6 @@ # Init Hooks -Add a `.cmux/init` executable script to your project root to run commands when creating new workspaces. +Add a `.mux/init` executable script to your project root to run commands when creating new workspaces. ## Example @@ -15,7 +15,7 @@ bun run build Make it executable: ```bash -chmod +x .cmux/init +chmod +x .mux/init ``` ## Behavior @@ -39,7 +39,7 @@ The init script runs in the workspace directory with the workspace's environment Init output appears in a banner at the top of the workspace. Click to expand/collapse the log. The banner shows: -- Script path (`.cmux/init`) +- Script path (`.mux/init`) - Status (running, success, or exit code on failure) - Full stdout/stderr output diff --git a/docs/install.md b/docs/install.md index 56a955950..9f7223527 100644 --- a/docs/install.md +++ b/docs/install.md @@ -4,14 +4,14 @@ ### Release Builds -Download pre-built binaries from [the releases page](https://github.com/coder/cmux/releases): +Download pre-built binaries from [the releases page](https://github.com/coder/mux/releases): - **macOS**: Signed and notarized DMG (separate builds for Intel/Apple Silicon) - **Linux**: AppImage ### Development Builds -Down pre-built binaries of `main` from [GitHub Actions](https://github.com/coder/cmux/actions/workflows/build.yml): +Down pre-built binaries of `main` from [GitHub Actions](https://github.com/coder/mux/actions/workflows/build.yml): - **macOS**: Signed and notarized DMG - `macos-dmg-x64` (Intel Macs) @@ -20,7 +20,7 @@ Down pre-built binaries of `main` from [GitHub Actions](https://github.com/coder To download: -1. Go to the [Build workflow](https://github.com/coder/cmux/actions/workflows/build.yml?query=event:merge_group) +1. Go to the [Build workflow](https://github.com/coder/mux/actions/workflows/build.yml?query=event:merge_group) 2. Click on the latest successful run 3. Scroll down to "Artifacts" section 4. Download the appropriate artifact for your platform @@ -33,7 +33,7 @@ To download: - Intel Mac: `macos-dmg-x64` - Apple Silicon: `macos-dmg-arm64` 2. Open the DMG file -3. Drag Cmux to Applications folder +3. Drag Mux to Applications folder 4. Open the app normally The app is code-signed and notarized by Apple, so it will open without security warnings. @@ -41,14 +41,14 @@ The app is code-signed and notarized by Apple, so it will open without security **Linux:** 1. Download the AppImage file -2. Make it executable: `chmod +x Cmux-*.AppImage` -3. Run it: `./Cmux-*.AppImage` +2. Make it executable: `chmod +x Mux-*.AppImage` +3. Run it: `./Mux-*.AppImage` ### Testing Pre-Release Builds ⚠️ **Note**: Only builds from the `main` branch are signed and notarized. If you're testing a build from a pull request or other branch, you'll need to bypass macOS Gatekeeper: 1. After installing, open Terminal -2. Run: `xattr -cr /Applications/Cmux.app` -3. Run: `codesign --force --deep --sign - /Applications/Cmux.app` +2. Run: `xattr -cr /Applications/Mux.app` +3. Run: `codesign --force --deep --sign - /Applications/Mux.app` 4. Now you can open the app normally diff --git a/docs/instruction-files.md b/docs/instruction-files.md index c9ea13e41..638be38ed 100644 --- a/docs/instruction-files.md +++ b/docs/instruction-files.md @@ -2,18 +2,18 @@ ## Overview -cmux layers instructions from two locations: +mux layers instructions from two locations: -1. `~/.cmux/AGENTS.md` (+ optional `AGENTS.local.md`) — global defaults +1. `~/.mux/AGENTS.md` (+ optional `AGENTS.local.md`) — global defaults 2. `/AGENTS.md` (+ optional `AGENTS.local.md`) — workspace-specific context -Priority within each location: `AGENTS.md` → `AGENT.md` → `CLAUDE.md` (first match wins). If the base file is found, cmux also appends `AGENTS.local.md` from the same directory when present. +Priority within each location: `AGENTS.md` → `AGENT.md` → `CLAUDE.md` (first match wins). If the base file is found, mux also appends `AGENTS.local.md` from the same directory when present. ## Mode Prompts > Use mode-specific sections to optimize context and customize the behavior specific modes. -cmux reads mode context from sections inside your instruction files. Add a heading titled: +mux reads mode context from sections inside your instruction files. Add a heading titled: - `Mode: ` (case-insensitive), at any heading level (`#` .. `######`) @@ -26,7 +26,7 @@ Rules: -Example (in either `~/.cmux/AGENTS.md` or `my-project/AGENTS.md`): +Example (in either `~/.mux/AGENTS.md` or `my-project/AGENTS.md`): ```markdown # General Instructions @@ -63,7 +63,7 @@ Customizing the `compact` mode is particularly useful for controlling what infor ## Practical layout ``` -~/.cmux/ +~/.mux/ AGENTS.md # Global instructions AGENTS.local.md # Personal tweaks (gitignored) diff --git a/docs/intro.md b/docs/intro.md index 2e8511e18..624359d2a 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,12 +1,12 @@ # Introduction -![cmux product screenshot](img/product-hero.webp) +![mux product screenshot](img/product-hero.webp) -**cmux** (Coding Agent Multiplexer) is a cross-platform desktop application for AI-assisted development with isolated workspace management. +**mux** (Coding Agent Multiplexer) is a cross-platform desktop application for AI-assisted development with isolated workspace management. -## What is cmux? +## What is mux? -cmux helps you work with multiple coding assistants more effectively via: +mux helps you work with multiple coding assistants more effectively via: - Isolated workspaces with central view on git status updates - Multi-model (`sonnet-4-*`, `gpt-5-*`, `opus-4-*`) support @@ -22,6 +22,6 @@ cmux helps you work with multiple coding assistants more effectively via: ## License -cmux is licensed under the [GNU Affero General Public License v3.0 (AGPL-3.0)](https://github.com/coder/cmux/blob/main/LICENSE). +mux is licensed under the [GNU Affero General Public License v3.0 (AGPL-3.0)](https://github.com/coder/mux/blob/main/LICENSE). Copyright (C) 2025 Coder Technologies, Inc. diff --git a/docs/keybinds.md b/docs/keybinds.md index 63d438e46..15b14339d 100644 --- a/docs/keybinds.md +++ b/docs/keybinds.md @@ -1,6 +1,6 @@ # Keyboard Shortcuts -cmux is designed to be keyboard-driven for maximum efficiency. All major actions have keyboard shortcuts. +mux is designed to be keyboard-driven for maximum efficiency. All major actions have keyboard shortcuts. > **Note**: This document should be kept in sync with `src/utils/ui/keybinds.ts`, which is the source of truth for keybind definitions. diff --git a/docs/local.md b/docs/local.md index cff83015c..a3e1c0008 100644 --- a/docs/local.md +++ b/docs/local.md @@ -10,13 +10,13 @@ It's important to note that a **worktree is not locked to a branch**. The agent ## Filesystem Layout -Local workspaces are stored in `~/.cmux/src//`. +Local workspaces are stored in `~/.mux/src//`. Example layout: ``` -~/.cmux/src/ - cmux-main/ +~/.mux/src/ + mux-main/ improved-auth-ux/ fix-ci-flakes/ ``` diff --git a/docs/models.md b/docs/models.md index 496c6c223..1b86079e4 100644 --- a/docs/models.md +++ b/docs/models.md @@ -4,7 +4,7 @@ See also: - [System Prompt](./system-prompt.md) -cmux supports multiple AI providers through its flexible provider architecture. +mux supports multiple AI providers through its flexible provider architecture. ### Supported Providers @@ -41,7 +41,7 @@ Access 300+ models from multiple providers through a single API: **Setup:** 1. Get your API key from [openrouter.ai](https://openrouter.ai/) -2. Add to `~/.cmux/providers.jsonc`: +2. Add to `~/.mux/providers.jsonc`: ```jsonc { @@ -53,7 +53,7 @@ Access 300+ models from multiple providers through a single API: **Provider Routing (Advanced):** -OpenRouter can route requests to specific infrastructure providers (Cerebras, Fireworks, Together, etc.). Configure provider preferences in `~/.cmux/providers.jsonc`: +OpenRouter can route requests to specific infrastructure providers (Cerebras, Fireworks, Together, etc.). Configure provider preferences in `~/.mux/providers.jsonc`: ```jsonc { @@ -117,7 +117,7 @@ Run models locally with Ollama. No API key required: **Custom Configuration** (optional): -By default, cmux connects to Ollama at `http://localhost:11434/api`. To use a remote instance or custom port, add to `~/.cmux/providers.jsonc`: +By default, mux connects to Ollama at `http://localhost:11434/api`. To use a remote instance or custom port, add to `~/.mux/providers.jsonc`: ```jsonc { @@ -129,7 +129,7 @@ By default, cmux connects to Ollama at `http://localhost:11434/api`. To use a re ### Provider Configuration -All providers are configured in `~/.cmux/providers.jsonc`. Example configurations: +All providers are configured in `~/.mux/providers.jsonc`. Example configurations: ```jsonc { diff --git a/docs/project-secrets.md b/docs/project-secrets.md index dde9f60ca..59e9721b5 100644 --- a/docs/project-secrets.md +++ b/docs/project-secrets.md @@ -1,6 +1,6 @@ # Project Secrets -Securely manage environment variables for your projects in cmux. Project secrets are automatically injected when the agent executes bash commands, making it easy to provide API keys, tokens, and other sensitive configuration. +Securely manage environment variables for your projects in mux. Project secrets are automatically injected when the agent executes bash commands, making it easy to provide API keys, tokens, and other sensitive configuration. ![Project Secrets Modal](./img/project-secrets.webp) @@ -9,7 +9,7 @@ Securely manage environment variables for your projects in cmux. Project secrets Project secrets are key-value pairs stored per project that are: - **Automatically injected** as environment variables when running bash commands -- **Stored outside repo** in `~/.cmux/secrets.json` +- **Stored outside repo** in `~/.mux/secrets.json` - **Project-scoped** - each project has its own set of secrets - **Workspace-inherited** - all workspaces in a project use the same secrets @@ -45,7 +45,7 @@ The agent doesn't need to explicitly reference secrets - they're available as re ### Storage -- Secrets are stored in `~/.cmux/config.json` +- Secrets are stored in `~/.mux/config.json` - **Stored in plaintext** - the config file is not encrypted - The config file has standard user-only file permissions diff --git a/docs/prompting-tips.md b/docs/prompting-tips.md index f7e7e7ec9..ecb77d6aa 100644 --- a/docs/prompting-tips.md +++ b/docs/prompting-tips.md @@ -1,6 +1,6 @@ # Prompting Tips -> Some tips and tricks from the cmux developers on getting the most out of your agents. +> Some tips and tricks from the mux developers on getting the most out of your agents. ## Persist lessons @@ -21,7 +21,7 @@ source comments in such files vs. expanding the global `AGENTS.md`. Agents thrive on TDD. Try to define their task in terms of what checks need to pass before they can claim success. -For cmux development, we have a [`wait_pr_checks.sh`](https://github.com/coder/cmux/blob/main/scripts/wait_pr_checks.sh) script +For mux development, we have a [`wait_pr_checks.sh`](https://github.com/coder/mux/blob/main/scripts/wait_pr_checks.sh) script that polls GitHub and ensures that: - There are no dirty changes diff --git a/docs/ssh.md b/docs/ssh.md index 918f62bc2..4cada96da 100644 --- a/docs/ssh.md +++ b/docs/ssh.md @@ -1,6 +1,6 @@ # SSH Workspaces -cmux supports using remote hosts over SSH for workspaces. When configured, all tool operations will +mux supports using remote hosts over SSH for workspaces. When configured, all tool operations will execute over SSH and the agent is securely isolated from your local machine. Our security architecture considers the remote machine potentially hostile. No keys or credentials are implicitly transferred there—just the git archive and [Project Secrets](./project-secrets.md). @@ -73,9 +73,9 @@ Host my-server ## Coder Workspaces If you're using [Coder Workspaces](https://coder.com/docs), you can use an existing Workspace -as a cmux agent host: +as a mux agent host: 1. Run `coder config-ssh` -2. Use `coder.` as your SSH host when creating a new cmux workspace +2. Use `coder.` as your SSH host when creating a new mux workspace -Note that in this approach we're multiplexing cmux workspaces onto a single Coder workspace. This avoids the compute provisioning overhead to enable rapid creation and deletion of workspaces. +Note that in this approach we're multiplexing mux workspaces onto a single Coder workspace. This avoids the compute provisioning overhead to enable rapid creation and deletion of workspaces. diff --git a/docs/system-prompt.md b/docs/system-prompt.md index a166ef2c6..8ca2d5879 100644 --- a/docs/system-prompt.md +++ b/docs/system-prompt.md @@ -1,6 +1,6 @@ # System Prompt -`cmux` is interested in supporting a variety of models at different levels of performance. +`mux` is interested in supporting a variety of models at different levels of performance. To that end, we're built on the [Vercel AI SDK](https://ai-sdk.dev/providers/ai-sdk-providers) which does most of the heavy lifting in creating a unified API for all models. @@ -12,7 +12,7 @@ Here's a snippet from `src/services/systemMessage.ts` which is our shared system ```typescript // The PRELUDE is intentionally minimal to not conflict with the user's instructions. -// cmux is designed to be model agnostic, and models have shown large inconsistency in how they +// mux is designed to be model agnostic, and models have shown large inconsistency in how they // follow instructions. const PRELUDE = ` diff --git a/docs/telemetry.md b/docs/telemetry.md index b5888d293..08063314e 100644 --- a/docs/telemetry.md +++ b/docs/telemetry.md @@ -1,6 +1,6 @@ # Telemetry -cmux collects anonymous usage telemetry to help us understand how the product is being used and improve it over time. +mux collects anonymous usage telemetry to help us understand how the product is being used and improve it over time. ## Privacy Policy @@ -8,7 +8,7 @@ cmux collects anonymous usage telemetry to help us understand how the product is - **No personal information**: We never collect usernames, project names, file paths, or code content - **Random IDs only**: Only randomly-generated workspace IDs are sent (impossible to trace back to you) - **No hashing**: We don't hash sensitive data because hashing is vulnerable to rainbow table attacks -- **Transparent data**: See exactly what data structures we send in [`src/telemetry/payload.ts`](https://github.com/coder/cmux/blob/main/src/telemetry/payload.ts) +- **Transparent data**: See exactly what data structures we send in [`src/telemetry/payload.ts`](https://github.com/coder/mux/blob/main/src/telemetry/payload.ts) ## What We Track @@ -54,8 +54,8 @@ Your preference is saved and persists across app restarts. For complete transparency, you can review the telemetry implementation: -- **Payload definitions**: [`src/telemetry/payload.ts`](https://github.com/coder/cmux/blob/main/src/telemetry/payload.ts) - All data structures we send -- **Client code**: [`src/telemetry/client.ts`](https://github.com/coder/cmux/blob/main/src/telemetry/client.ts) - How telemetry is sent -- **Privacy utilities**: [`src/telemetry/utils.ts`](https://github.com/coder/cmux/blob/main/src/telemetry/utils.ts) - Base-2 rounding and helpers +- **Payload definitions**: [`src/telemetry/payload.ts`](https://github.com/coder/mux/blob/main/src/telemetry/payload.ts) - All data structures we send +- **Client code**: [`src/telemetry/client.ts`](https://github.com/coder/mux/blob/main/src/telemetry/client.ts) - How telemetry is sent +- **Privacy utilities**: [`src/telemetry/utils.ts`](https://github.com/coder/mux/blob/main/src/telemetry/utils.ts) - Base-2 rounding and helpers The telemetry system includes debug logging that you can see in the developer console (View → Toggle Developer Tools). diff --git a/docs/vim-mode.md b/docs/vim-mode.md index 1dccffbae..87f4d1384 100644 --- a/docs/vim-mode.md +++ b/docs/vim-mode.md @@ -6,7 +6,7 @@ # Vim Mode -cmux includes a built-in Vim mode for the chat input, providing familiar Vim-style editing for power users. +mux includes a built-in Vim mode for the chat input, providing familiar Vim-style editing for power users. ## Enabling Vim Mode diff --git a/docs/vscode-extension.md b/docs/vscode-extension.md index bb98c7e9a..bb028a4e1 100644 --- a/docs/vscode-extension.md +++ b/docs/vscode-extension.md @@ -1,6 +1,6 @@ # VS Code Extension -The cmux VS Code extension allows you to easily pair with cmux during development. Our extension works with VS Code and Cursor. +The mux VS Code extension allows you to easily pair with mux during development. Our extension works with VS Code and Cursor. It's especially useful for completing the "last mile" of a task or establishing the initial architecture. @@ -8,10 +8,10 @@ It's especially useful for completing the "last mile" of a task or establishing The extension has a small initial surface area: a command to open a workspace. -![cmux VS Code extension screenshot](./img/vscode-ext.webp) +![mux VS Code extension screenshot](./img/vscode-ext.webp) 1. Press `Cmd+Shift+P` (or `Ctrl+Shift+P` on Windows/Linux) -2. Type "cmux: Open Workspace" +2. Type "mux: Open Workspace" - Optional: Set a custom keybinding in the Command Palette settings 3. Select your workspace 4. It opens in a new editor window @@ -22,7 +22,7 @@ The extension works with both local and SSH workspaces. ### Download -Download the latest `.vsix` file from the [GitHub releases page](https://github.com/coder/cmux/releases). +Download the latest `.vsix` file from the [GitHub releases page](https://github.com/coder/mux/releases). ### Install @@ -30,10 +30,10 @@ Download the latest `.vsix` file from the [GitHub releases page](https://github. ```bash # For VS Code -code --install-extension cmux-*.vsix +code --install-extension mux-*.vsix # For Cursor -cursor --install-extension cmux-*.vsix +cursor --install-extension mux-*.vsix ``` **From editor UI:** diff --git a/docs/why-parallelize.md b/docs/why-parallelize.md index 77c463335..857c67b92 100644 --- a/docs/why-parallelize.md +++ b/docs/why-parallelize.md @@ -10,4 +10,4 @@ Here are some specific use cases we enable: a subtle indicator when the model completes. - **A/B testing**: test a variety of approaches to the same problem, abandon the bad ones. -- **Tangent management**: launch tangents in `cmux` away from main work +- **Tangent management**: launch tangents in `mux` away from main work diff --git a/docs/workspaces.md b/docs/workspaces.md index 107f26890..93b62e76f 100644 --- a/docs/workspaces.md +++ b/docs/workspaces.md @@ -1,10 +1,10 @@ # Workspaces -Workspaces in cmux provide isolated development environments for parallel agent work. Each workspace maintains its own Git state, allowing you to explore different approaches, run multiple tasks simultaneously, or test changes without affecting your main repository. +Workspaces in mux provide isolated development environments for parallel agent work. Each workspace maintains its own Git state, allowing you to explore different approaches, run multiple tasks simultaneously, or test changes without affecting your main repository. ## Workspace Types -cmux supports two workspace backends: +mux supports two workspace backends: - **[Local Workspaces](./local.md)**: Use [git worktrees](https://git-scm.com/docs/git-worktree) on your local machine. Worktrees share the `.git` directory with your main repository while maintaining independent working changes. @@ -30,7 +30,7 @@ Here are a few practical approaches to reviewing changes from workspaces, depend - **Agent codes, commits, and pushes**: Ask agent to submit a PR and review changes in your git Web UI (GitHub, GitLab, etc.) - Also see: [Agentic Git Identity](./agentic-git-identity.md) - - This is the preferred approach for `cmux` development but requires additional care with repository security. + - This is the preferred approach for `mux` development but requires additional care with repository security. - **Agent codes and commits**: Review changes from the main repository via `git diff `, push changes when deemed acceptable. - **Agent codes**: Enter worktree (click Terminal icon in workspace top bar), run `git add -p` and progressively accept changes into a commit. diff --git a/flake.nix b/flake.nix index c8e22a2f2..d6135c64d 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "cmux - coder multiplexer"; + description = "mux - coder multiplexer"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; @@ -19,8 +19,8 @@ inherit system; }; - cmux = pkgs.stdenv.mkDerivation rec { - pname = "cmux"; + mux = pkgs.stdenv.mkDerivation rec { + pname = "mux"; version = self.rev or self.dirtyRev or "dev"; src = ./.; @@ -39,7 +39,7 @@ # Fetch dependencies in a separate fixed-output derivation offlineCache = pkgs.stdenvNoCC.mkDerivation { - name = "cmux-deps-${version}"; + name = "mux-deps-${version}"; inherit src; @@ -79,22 +79,22 @@ ''; buildPhase = '' - echo "Building cmux with make..." + echo "Building mux with make..." make build ''; installPhase = '' - mkdir -p $out/lib/cmux + mkdir -p $out/lib/mux mkdir -p $out/bin # Copy built files and runtime dependencies - cp -r dist $out/lib/cmux/ - cp -r node_modules $out/lib/cmux/ - cp package.json $out/lib/cmux/ + cp -r dist $out/lib/mux/ + cp -r node_modules $out/lib/mux/ + cp package.json $out/lib/mux/ # Create wrapper script - makeWrapper ${pkgs.electron}/bin/electron $out/bin/cmux \ - --add-flags "$out/lib/cmux/dist/main.js" \ + makeWrapper ${pkgs.electron}/bin/electron $out/bin/mux \ + --add-flags "$out/lib/mux/dist/main.js" \ --prefix PATH : ${ pkgs.lib.makeBinPath [ pkgs.git @@ -104,23 +104,23 @@ ''; meta = with pkgs.lib; { - description = "cmux - coder multiplexer"; - homepage = "https://github.com/coder/cmux"; + description = "mux - coder multiplexer"; + homepage = "https://github.com/coder/mux"; license = licenses.agpl3Only; platforms = platforms.linux ++ platforms.darwin; - mainProgram = "cmux"; + mainProgram = "mux"; }; }; in { - packages.default = cmux; - packages.cmux = cmux; + packages.default = mux; + packages.mux = mux; formatter = pkgs.nixfmt-rfc-style; apps.default = { type = "app"; - program = "${cmux}/bin/cmux"; + program = "${mux}/bin/mux"; }; devShells.default = pkgs.mkShell { diff --git a/index.html b/index.html index a6b02033b..2be5c48e7 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ - cmux - coder multiplexer + mux - coder multiplexer - +
Loading services...
coder multiplexer
diff --git a/tests/e2e/electronTest.ts b/tests/e2e/electronTest.ts index ac59f8993..dadd4169a 100644 --- a/tests/e2e/electronTest.ts +++ b/tests/e2e/electronTest.ts @@ -21,9 +21,9 @@ interface ElectronFixtures { } const appRoot = path.resolve(__dirname, "..", ".."); -const defaultTestRoot = path.join(appRoot, "tests", "e2e", "tmp", "cmux-root"); -const BASE_DEV_SERVER_PORT = Number(process.env.CMUX_E2E_DEVSERVER_PORT_BASE ?? "5173"); -const shouldLoadDist = process.env.CMUX_E2E_LOAD_DIST === "1"; +const defaultTestRoot = path.join(appRoot, "tests", "e2e", "tmp", "mux-root"); +const BASE_DEV_SERVER_PORT = Number(process.env.MUX_E2E_DEVSERVER_PORT_BASE ?? "5173"); +const shouldLoadDist = process.env.MUX_E2E_LOAD_DIST === "1"; const REQUIRED_DIST_FILES = [ path.join(appRoot, "dist", "index.html"), @@ -69,7 +69,7 @@ function sanitizeForPath(value: string): string { } function shouldSkipBuild(): boolean { - return process.env.CMUX_E2E_SKIP_BUILD === "1"; + return process.env.MUX_E2E_SKIP_BUILD === "1"; } function buildTarget(target: string): void { @@ -88,7 +88,7 @@ function buildTarget(target: string): void { export const electronTest = base.extend({ workspace: async ({}, use, testInfo) => { - const envRoot = process.env.CMUX_TEST_ROOT ?? ""; + const envRoot = process.env.MUX_TEST_ROOT ?? ""; const baseRoot = envRoot || defaultTestRoot; const uniqueTestId = testInfo.testId || testInfo.title || `test-${Date.now()}`; const testRoot = envRoot ? baseRoot : path.join(baseRoot, sanitizeForPath(uniqueTestId)); @@ -136,7 +136,7 @@ export const electronTest = base.extend({ ...process.env, NODE_ENV: "development", VITE_DISABLE_MERMAID: "1", - CMUX_VITE_PORT: String(devServerPort), + MUX_VITE_PORT: String(devServerPort), }, }); @@ -176,7 +176,7 @@ export const electronTest = base.extend({ try { let devHost = "127.0.0.1"; if (shouldStartDevServer) { - devHost = process.env.CMUX_DEVSERVER_HOST ?? "127.0.0.1"; + devHost = process.env.MUX_DEVSERVER_HOST ?? "127.0.0.1"; await waitForServerReady(`http://${devHost}:${devServerPort}`); const exitCode = devServer?.exitCode; if (exitCode !== null && exitCode !== undefined) { @@ -194,15 +194,15 @@ export const electronTest = base.extend({ } } electronEnv.ELECTRON_DISABLE_SECURITY_WARNINGS = "true"; - electronEnv.CMUX_MOCK_AI = electronEnv.CMUX_MOCK_AI ?? "1"; - electronEnv.CMUX_TEST_ROOT = configRoot; - electronEnv.CMUX_E2E = "1"; - electronEnv.CMUX_E2E_LOAD_DIST = shouldLoadDist ? "1" : "0"; + electronEnv.MUX_MOCK_AI = electronEnv.MUX_MOCK_AI ?? "1"; + electronEnv.MUX_TEST_ROOT = configRoot; + electronEnv.MUX_E2E = "1"; + electronEnv.MUX_E2E_LOAD_DIST = shouldLoadDist ? "1" : "0"; electronEnv.VITE_DISABLE_MERMAID = "1"; if (shouldStartDevServer) { - electronEnv.CMUX_DEVSERVER_PORT = String(devServerPort); - electronEnv.CMUX_DEVSERVER_HOST = devHost; + electronEnv.MUX_DEVSERVER_PORT = String(devServerPort); + electronEnv.MUX_DEVSERVER_HOST = devHost; electronEnv.NODE_ENV = electronEnv.NODE_ENV ?? "development"; } else { electronEnv.NODE_ENV = electronEnv.NODE_ENV ?? "production"; @@ -234,7 +234,7 @@ export const electronTest = base.extend({ await fsPromises.mkdir(videosDir, { recursive: true }); const orderedFiles = [...videoFiles].sort(); const baseName = sanitizeForPath( - testInfo.testId || testInfo.title || "cmux-e2e-video" + testInfo.testId || testInfo.title || "mux-e2e-video" ); for (const [index, file] of orderedFiles.entries()) { const ext = path.extname(file) || ".webm"; diff --git a/tests/e2e/utils/ui.ts b/tests/e2e/utils/ui.ts index a44ae0e46..9bce83ea1 100644 --- a/tests/e2e/utils/ui.ts +++ b/tests/e2e/utils/ui.ts @@ -186,12 +186,12 @@ export function createWorkspaceUI(page: Page, context: DemoProjectConfig): Works const win = window as unknown as { api: typeof window.api; - __cmuxStreamCapture?: Record; + __muxStreamCapture?: Record; }; const store = - win.__cmuxStreamCapture ?? - (win.__cmuxStreamCapture = Object.create(null) as Record); + win.__muxStreamCapture ?? + (win.__muxStreamCapture = Object.create(null) as Record); const existing = store[id]; if (existing) { existing.unsubscribe(); @@ -263,9 +263,9 @@ export function createWorkspaceUI(page: Page, context: DemoProjectConfig): Works type StreamCaptureEvent = { type: string }; type StreamCapture = { events: StreamCaptureEvent[] }; const win = window as unknown as { - __cmuxStreamCapture?: Record; + __muxStreamCapture?: Record; }; - const capture = win.__cmuxStreamCapture?.[id]; + const capture = win.__muxStreamCapture?.[id]; if (!capture) { return false; } @@ -295,9 +295,9 @@ export function createWorkspaceUI(page: Page, context: DemoProjectConfig): Works unsubscribe: () => void; }; const win = window as unknown as { - __cmuxStreamCapture?: Record; + __muxStreamCapture?: Record; }; - const store = win.__cmuxStreamCapture; + const store = win.__muxStreamCapture; const capture = store?.[id]; if (!capture) { return [] as StreamCaptureEvent[]; diff --git a/tests/ipcMain/createWorkspace.test.ts b/tests/ipcMain/createWorkspace.test.ts index 892f70ec7..3aa12ef99 100644 --- a/tests/ipcMain/createWorkspace.test.ts +++ b/tests/ipcMain/createWorkspace.test.ts @@ -37,7 +37,7 @@ const execAsync = promisify(exec); const TEST_TIMEOUT_MS = 60000; const INIT_HOOK_WAIT_MS = 1500; // Wait for async init hook completion (local runtime) const SSH_INIT_WAIT_MS = 7000; // SSH init includes sync + checkout + hook, takes longer -const CMUX_DIR = ".cmux"; +const MUX_DIR = ".mux"; const INIT_HOOK_FILENAME = "init"; // Event type constants @@ -104,9 +104,9 @@ function setupInitEventCapture(env: TestEnvironment): Array<{ channel: string; d * Create init hook file in git repo */ async function createInitHook(repoPath: string, hookContent: string): Promise { - const cmuxDir = path.join(repoPath, CMUX_DIR); - await fs.mkdir(cmuxDir, { recursive: true }); - const initHookPath = path.join(cmuxDir, INIT_HOOK_FILENAME); + const muxDir = path.join(repoPath, MUX_DIR); + await fs.mkdir(muxDir, { recursive: true }); + const initHookPath = path.join(muxDir, INIT_HOOK_FILENAME); await fs.writeFile(initHookPath, hookContent, { mode: 0o755 }); } @@ -366,7 +366,7 @@ describeIntegration("WORKSPACE_CREATE with both runtimes", () => { describe("Init hook execution", () => { test.concurrent( - "executes .cmux/init hook when present and streams logs", + "executes .mux/init hook when present and streams logs", async () => { const env = await createTestEnvironment(); const tempGitRepo = await createTempGitRepo(); @@ -878,7 +878,7 @@ exit 1 // Should be the original origin URL, not the bundle path expect(remoteUrl).toBe(originUrl); expect(remoteUrl).not.toContain(".bundle"); - expect(remoteUrl).not.toContain(".cmux-bundle"); + expect(remoteUrl).not.toContain(".mux-bundle"); } finally { await cleanup(); } diff --git a/tests/ipcMain/forkWorkspace.test.ts b/tests/ipcMain/forkWorkspace.test.ts index c818ba482..4ac28d335 100644 --- a/tests/ipcMain/forkWorkspace.test.ts +++ b/tests/ipcMain/forkWorkspace.test.ts @@ -16,7 +16,7 @@ import { } from "./helpers"; import { detectDefaultTrunkBranch } from "../../src/git"; import { HistoryService } from "../../src/services/historyService"; -import { createCmuxMessage } from "../../src/types/message"; +import { createMuxMessage } from "../../src/types/message"; // Skip all tests if TEST_INTEGRATION is not set const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; @@ -129,8 +129,8 @@ describeIntegration("IpcMain fork workspace integration tests", () => { const historyService = new HistoryService(env.config); const uniqueWord = `testword-${Date.now()}`; const historyMessages = [ - createCmuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), - createCmuxMessage("msg-2", "assistant", `I will remember the word "${uniqueWord}".`, {}), + createMuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), + createMuxMessage("msg-2", "assistant", `I will remember the word "${uniqueWord}".`, {}), ]; for (const msg of historyMessages) { diff --git a/tests/ipcMain/helpers.ts b/tests/ipcMain/helpers.ts index 08c305dcf..b7e9e2cac 100644 --- a/tests/ipcMain/helpers.ts +++ b/tests/ipcMain/helpers.ts @@ -676,7 +676,7 @@ export async function createTempGitRepo(): Promise { const execAsync = promisify(exec); // Use mkdtemp to avoid race conditions and ensure unique directory - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-test-repo-")); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-test-repo-")); // Use promisify(exec) for test setup - DisposableExec has issues in CI // TODO: Investigate why DisposableExec causes empty git output in CI @@ -756,7 +756,7 @@ export async function buildLargeHistory( } = {} ): Promise { const { HistoryService } = await import("../../src/services/historyService"); - const { createCmuxMessage } = await import("../../src/types/message"); + const { createMuxMessage } = await import("../../src/types/message"); // HistoryService only needs getSessionDir, so we can cast the partial config const historyService = new HistoryService(config as any); @@ -771,7 +771,7 @@ export async function buildLargeHistory( for (let i = 0; i < messageCount; i++) { const isUser = i % 2 === 0; const role = isUser ? "user" : "assistant"; - const message = createCmuxMessage(`history-msg-${i}`, role, largeText, {}); + const message = createMuxMessage(`history-msg-${i}`, role, largeText, {}); const result = await historyService.appendToHistory(workspaceId, message); if (!result.success) { diff --git a/tests/ipcMain/initWorkspace.test.ts b/tests/ipcMain/initWorkspace.test.ts index c639613e8..22ae08416 100644 --- a/tests/ipcMain/initWorkspace.test.ts +++ b/tests/ipcMain/initWorkspace.test.ts @@ -37,7 +37,7 @@ if (shouldRunIntegrationTests()) { } /** - * Create a temp git repo with a .cmux/init hook that writes to stdout/stderr and exits with a given code + * Create a temp git repo with a .mux/init hook that writes to stdout/stderr and exits with a given code */ async function createTempGitRepoWithInitHook(options: { exitCode: number; @@ -52,7 +52,7 @@ async function createTempGitRepoWithInitHook(options: { const execAsync = promisify(exec); // Use mkdtemp to avoid race conditions - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-test-init-hook-")); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-test-init-hook-")); // Initialize git repo await execAsync(`git init`, { cwd: tempDir }); @@ -63,12 +63,12 @@ async function createTempGitRepoWithInitHook(options: { cwd: tempDir, }); - // Create .cmux directory - const cmuxDir = path.join(tempDir, ".cmux"); - await fs.mkdir(cmuxDir, { recursive: true }); + // Create .mux directory + const muxDir = path.join(tempDir, ".mux"); + await fs.mkdir(muxDir, { recursive: true }); // Create init hook script - const hookPath = path.join(cmuxDir, "init"); + const hookPath = path.join(muxDir, "init"); let scriptContent: string; if (options.customScript) { @@ -152,7 +152,7 @@ describeIntegration("IpcMain workspace init hook integration tests", () => { const startEvent = initEvents.find((e) => isInitStart(e)); expect(startEvent).toBeDefined(); if (startEvent && isInitStart(startEvent)) { - // Hook path should be the project path (where .cmux/init exists) + // Hook path should be the project path (where .mux/init exists) expect(startEvent.hookPath).toBeTruthy(); } @@ -258,13 +258,13 @@ describeIntegration("IpcMain workspace init hook integration tests", () => { "should not emit meta events when no init hook exists", async () => { const env = await createTestEnvironment(); - // Create repo without .cmux/init hook + // Create repo without .mux/init hook const fs = await import("fs/promises"); const { exec } = await import("child_process"); const { promisify } = await import("util"); const execAsync = promisify(exec); - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-test-no-hook-")); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-test-no-hook-")); try { // Initialize git repo without hook diff --git a/tests/ipcMain/ollama.test.ts b/tests/ipcMain/ollama.test.ts index 0be4d83db..920c3e6f1 100644 --- a/tests/ipcMain/ollama.test.ts +++ b/tests/ipcMain/ollama.test.ts @@ -198,11 +198,11 @@ describeOllama("IpcMain Ollama integration tests", () => { const fileReadCall = toolCallStarts.find((e: any) => e.toolName === "file_read"); expect(fileReadCall).toBeDefined(); - // Verify response mentions README content (cmux heading or similar) + // Verify response mentions README content (mux heading or similar) const deltas = collector.getDeltas(); const responseText = extractTextFromEvents(deltas).toLowerCase(); - expect(responseText).toMatch(/cmux|readme|heading/i); + expect(responseText).toMatch(/mux|readme|heading/i); } finally { await cleanup(); } diff --git a/tests/ipcMain/projectCreate.test.ts b/tests/ipcMain/projectCreate.test.ts index 89e58d14a..57bb8dd4f 100644 --- a/tests/ipcMain/projectCreate.test.ts +++ b/tests/ipcMain/projectCreate.test.ts @@ -19,9 +19,9 @@ const describeIntegration = shouldRunIntegrationTests() ? describe : describe.sk describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should expand tilde in project path and create project", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); // Create a test directory in home directory - const testDirName = `cmux-test-tilde-${Date.now()}`; + const testDirName = `mux-test-tilde-${Date.now()}`; const homeProjectPath = path.join(os.homedir(), testDirName); await fs.mkdir(homeProjectPath, { recursive: true }); // Create .git directory to make it a valid git repo @@ -57,8 +57,8 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should reject non-existent project path", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); - const nonExistentPath = "/this/path/definitely/does/not/exist/cmux-test-12345"; + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); + const nonExistentPath = "/this/path/definitely/does/not/exist/mux-test-12345"; const result = await env.mockIpcRenderer.invoke(IPC_CHANNELS.PROJECT_CREATE, nonExistentPath); expect(result.success).toBe(false); @@ -70,8 +70,8 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should reject non-existent tilde path", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); - const nonExistentTildePath = "~/this-directory-should-not-exist-cmux-test-12345"; + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); + const nonExistentTildePath = "~/this-directory-should-not-exist-mux-test-12345"; const result = await env.mockIpcRenderer.invoke( IPC_CHANNELS.PROJECT_CREATE, nonExistentTildePath @@ -86,7 +86,7 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should reject file path (not a directory)", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); const testFile = path.join(tempProjectDir, "test-file.txt"); await fs.writeFile(testFile, "test content"); @@ -101,7 +101,7 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should reject directory without .git", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); const result = await env.mockIpcRenderer.invoke(IPC_CHANNELS.PROJECT_CREATE, tempProjectDir); @@ -114,7 +114,7 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should accept valid absolute path", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); // Create .git directory to make it a valid git repo await fs.mkdir(path.join(tempProjectDir, ".git")); @@ -134,7 +134,7 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should normalize paths with .. in them", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); // Create .git directory to make it a valid git repo await fs.mkdir(path.join(tempProjectDir, ".git")); @@ -156,7 +156,7 @@ describeIntegration("PROJECT_CREATE IPC Handler", () => { test.concurrent("should reject duplicate projects (same expanded path)", async () => { const env = await createTestEnvironment(); - const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-project-test-")); + const tempProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-project-test-")); // Create .git directory to make it a valid git repo await fs.mkdir(path.join(tempProjectDir, ".git")); diff --git a/tests/ipcMain/resumeStream.test.ts b/tests/ipcMain/resumeStream.test.ts index dc0b79e18..e71aeaaca 100644 --- a/tests/ipcMain/resumeStream.test.ts +++ b/tests/ipcMain/resumeStream.test.ts @@ -4,7 +4,7 @@ import { IPC_CHANNELS } from "../../src/constants/ipc-constants"; import type { Result } from "../../src/types/result"; import type { SendMessageError } from "../../src/types/errors"; import { HistoryService } from "../../src/services/historyService"; -import { createCmuxMessage } from "../../src/types/message"; +import { createMuxMessage } from "../../src/types/message"; // Skip all tests if TEST_INTEGRATION is not set const describeIntegration = shouldRunIntegrationTests() ? describe : describe.skip; @@ -148,7 +148,7 @@ describeIntegration("IpcMain resumeStream integration tests", () => { // Simulate post-compaction state: single assistant message with summary // The message promises to say a specific word next, allowing deterministic verification const verificationWord = "ELEPHANT"; - const summaryMessage = createCmuxMessage( + const summaryMessage = createMuxMessage( "compaction-summary-msg", "assistant", `I previously helped with a task. The conversation has been compacted for token efficiency. My next message will contain the word ${verificationWord} to confirm continuation works correctly.`, diff --git a/tests/ipcMain/runtimeExecuteBash.test.ts b/tests/ipcMain/runtimeExecuteBash.test.ts index 4bd8464dc..dcb99484e 100644 --- a/tests/ipcMain/runtimeExecuteBash.test.ts +++ b/tests/ipcMain/runtimeExecuteBash.test.ts @@ -247,7 +247,7 @@ describeIntegration("Runtime Bash Execution", () => { // Test command that pipes file through stdin-reading command (grep) // This would hang forever if stdin.close() was used instead of stdin.abort() - // Regression test for: https://github.com/coder/cmux/issues/503 + // Regression test for: https://github.com/coder/mux/issues/503 const startTime = Date.now(); const events = await sendMessageAndWait( env, diff --git a/tests/ipcMain/runtimeFileEditing.test.ts b/tests/ipcMain/runtimeFileEditing.test.ts index 037b8db36..13f29fc01 100644 --- a/tests/ipcMain/runtimeFileEditing.test.ts +++ b/tests/ipcMain/runtimeFileEditing.test.ts @@ -136,7 +136,7 @@ describeIntegration("Runtime File Editing Tools", () => { const createEvents = await sendMessageAndWait( env, workspaceId, - `Create a file called ${testFileName} with the content: "Hello from cmux file tools!"`, + `Create a file called ${testFileName} with the content: "Hello from mux file tools!"`, HAIKU_MODEL, FILE_TOOLS_ONLY, streamTimeout diff --git a/tests/ipcMain/sendMessage.test.ts b/tests/ipcMain/sendMessage.test.ts index 544ec8cda..10c7f55c2 100644 --- a/tests/ipcMain/sendMessage.test.ts +++ b/tests/ipcMain/sendMessage.test.ts @@ -1466,7 +1466,7 @@ These are general instructions that apply to all modes. "Test message with metadata", { model: "openai:gpt-4", // Valid format but provider not configured - will fail after storing message - cmuxMetadata: testMetadata, + muxMetadata: testMetadata, } ); @@ -1493,14 +1493,14 @@ These are general instructions that apply to all modes. // Verify metadata was preserved exactly as sent (black-box) expect(userMessage).toHaveProperty("metadata"); const metadata = (userMessage as any).metadata; - expect(metadata).toHaveProperty("cmuxMetadata"); - expect(metadata.cmuxMetadata).toEqual(testMetadata); + expect(metadata).toHaveProperty("muxMetadata"); + expect(metadata.muxMetadata).toEqual(testMetadata); // Verify structured fields are accessible - expect(metadata.cmuxMetadata.type).toBe("compaction-request"); - expect(metadata.cmuxMetadata.rawCommand).toBe("/compact -c continue working"); - expect(metadata.cmuxMetadata.parsed.continueMessage).toBe("continue working"); - expect(metadata.cmuxMetadata.parsed.maxOutputTokens).toBe(5000); + expect(metadata.muxMetadata.type).toBe("compaction-request"); + expect(metadata.muxMetadata.rawCommand).toBe("/compact -c continue working"); + expect(metadata.muxMetadata.parsed.continueMessage).toBe("continue working"); + expect(metadata.muxMetadata.parsed.maxOutputTokens).toBe(5000); } finally { await cleanup(); } diff --git a/tests/ipcMain/setup.ts b/tests/ipcMain/setup.ts index 0b221269b..bf984a3bb 100644 --- a/tests/ipcMain/setup.ts +++ b/tests/ipcMain/setup.ts @@ -52,7 +52,7 @@ function createMockBrowserWindow(): { */ export async function createTestEnvironment(): Promise { // Create temporary directory for test config - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-test-")); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-test-")); // Create config with temporary directory const config = new Config(tempDir); diff --git a/tests/ipcMain/truncate.test.ts b/tests/ipcMain/truncate.test.ts index 312631c95..1cd4aa3da 100644 --- a/tests/ipcMain/truncate.test.ts +++ b/tests/ipcMain/truncate.test.ts @@ -6,7 +6,7 @@ import { waitFor, } from "./helpers"; import { HistoryService } from "../../src/services/historyService"; -import { createCmuxMessage } from "../../src/types/message"; +import { createMuxMessage } from "../../src/types/message"; import type { DeleteMessage } from "../../src/types/ipc"; import { IPC_CHANNELS } from "../../src/constants/ipc-constants"; @@ -35,12 +35,12 @@ describeIntegration("IpcMain truncate integration tests", () => { // Create messages with a unique word in the first message const uniqueWord = `testword-${Date.now()}`; const messages = [ - createCmuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), - createCmuxMessage("msg-2", "assistant", "I will remember that word.", {}), - createCmuxMessage("msg-3", "user", "What is 2+2?", {}), - createCmuxMessage("msg-4", "assistant", "4", {}), - createCmuxMessage("msg-5", "user", "What is 3+3?", {}), - createCmuxMessage("msg-6", "assistant", "6", {}), + createMuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), + createMuxMessage("msg-2", "assistant", "I will remember that word.", {}), + createMuxMessage("msg-3", "user", "What is 2+2?", {}), + createMuxMessage("msg-4", "assistant", "4", {}), + createMuxMessage("msg-5", "user", "What is 3+3?", {}), + createMuxMessage("msg-6", "assistant", "6", {}), ]; // Append messages to history @@ -137,10 +137,10 @@ describeIntegration("IpcMain truncate integration tests", () => { // Prepopulate chat with messages (avoid API calls) const uniqueWord = `testword-${Date.now()}`; const messages = [ - createCmuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), - createCmuxMessage("msg-2", "assistant", "I will remember that word.", {}), - createCmuxMessage("msg-3", "user", "Tell me a fact about cats", {}), - createCmuxMessage("msg-4", "assistant", "Cats sleep 12-16 hours a day.", {}), + createMuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), + createMuxMessage("msg-2", "assistant", "I will remember that word.", {}), + createMuxMessage("msg-3", "user", "Tell me a fact about cats", {}), + createMuxMessage("msg-4", "assistant", "Cats sleep 12-16 hours a day.", {}), ]; // Append messages to history @@ -245,8 +245,8 @@ describeIntegration("IpcMain truncate integration tests", () => { // Prepopulate some history const uniqueWord = `testword-${Date.now()}`; const messages = [ - createCmuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), - createCmuxMessage("msg-2", "assistant", "I will remember that word.", {}), + createMuxMessage("msg-1", "user", `Remember this word: ${uniqueWord}`, {}), + createMuxMessage("msg-2", "assistant", "I will remember that word.", {}), ]; for (const msg of messages) { diff --git a/tests/ipcMain/windowTitle.test.ts b/tests/ipcMain/windowTitle.test.ts index faaab5c51..e3a63630e 100644 --- a/tests/ipcMain/windowTitle.test.ts +++ b/tests/ipcMain/windowTitle.test.ts @@ -16,12 +16,12 @@ describeIntegration("Window title IPC", () => { // Call setTitle via IPC await env.mockIpcRenderer.invoke( IPC_CHANNELS.WINDOW_SET_TITLE, - "test-workspace - test-project - cmux" + "test-workspace - test-project - mux" ); // Verify setTitle was called on the window expect(env.mockWindow.setTitle).toHaveBeenCalledWith( - "test-workspace - test-project - cmux" + "test-workspace - test-project - mux" ); } finally { await cleanupTestEnvironment(env); @@ -37,10 +37,10 @@ describeIntegration("Window title IPC", () => { try { // Set to default title - await env.mockIpcRenderer.invoke(IPC_CHANNELS.WINDOW_SET_TITLE, "cmux"); + await env.mockIpcRenderer.invoke(IPC_CHANNELS.WINDOW_SET_TITLE, "mux"); // Verify setTitle was called with default - expect(env.mockWindow.setTitle).toHaveBeenCalledWith("cmux"); + expect(env.mockWindow.setTitle).toHaveBeenCalledWith("mux"); } finally { await cleanupTestEnvironment(env); } diff --git a/tests/runtime/ssh-fixture.ts b/tests/runtime/ssh-fixture.ts index 5505c3d66..40acd7b98 100644 --- a/tests/runtime/ssh-fixture.ts +++ b/tests/runtime/ssh-fixture.ts @@ -48,7 +48,7 @@ export async function isDockerAvailable(): Promise { */ export async function startSSHServer(): Promise { // Create temp directory for SSH keys - const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "cmux-ssh-test-")); + const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "mux-ssh-test-")); try { // Generate ephemeral SSH key pair @@ -65,7 +65,7 @@ export async function startSSHServer(): Promise { "-N", "", // No passphrase "-C", - "cmux-test", + "mux-test", ]); // Read public key @@ -73,10 +73,10 @@ export async function startSSHServer(): Promise { // Build Docker image (use context directory for COPY commands) const dockerfilePath = path.join(__dirname, "ssh-server"); - await execCommand("docker", ["build", "-t", "cmux-ssh-test", dockerfilePath]); + await execCommand("docker", ["build", "-t", "mux-ssh-test", dockerfilePath]); // Generate unique container name to avoid conflicts - const containerName = `cmux-ssh-test-${crypto.randomBytes(8).toString("hex")}`; + const containerName = `mux-ssh-test-${crypto.randomBytes(8).toString("hex")}`; // Start container with dynamic port mapping // -p 0:22 tells Docker to assign a random available host port @@ -90,7 +90,7 @@ export async function startSSHServer(): Promise { "-e", `SSH_PUBLIC_KEY=${publicKey}`, "--rm", // Auto-remove on stop - "cmux-ssh-test", + "mux-ssh-test", ]); const containerId = runResult.stdout.trim(); diff --git a/tests/setup.ts b/tests/setup.ts index 13a4d1bc2..de015e3b4 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -28,13 +28,13 @@ if (typeof globalThis.File === "undefined") { // This eliminates ~10s initialization delay on first use if (process.env.TEST_INTEGRATION === "1") { // Store promise globally to ensure it blocks subsequent test execution - (globalThis as any).__cmuxPreloadPromise = (async () => { + (globalThis as any).__muxPreloadPromise = (async () => { const { preloadTestModules } = await import("./ipcMain/setup"); await preloadTestModules(); })(); // Add a global beforeAll to block until preload completes beforeAll(async () => { - await (globalThis as any).__cmuxPreloadPromise; + await (globalThis as any).__muxPreloadPromise; }, 30000); // 30s timeout for preload } diff --git a/vite.config.ts b/vite.config.ts index 0816c1d2b..33b0332fd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,9 +10,9 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); const disableMermaid = process.env.VITE_DISABLE_MERMAID === "1"; // Vite server configuration (for dev-server remote access) -const devServerHost = process.env.CMUX_VITE_HOST ?? "127.0.0.1"; // Secure by default -const devServerPort = Number(process.env.CMUX_VITE_PORT ?? "5173"); -const previewPort = Number(process.env.CMUX_VITE_PREVIEW_PORT ?? "4173"); +const devServerHost = process.env.MUX_VITE_HOST ?? "127.0.0.1"; // Secure by default +const devServerPort = Number(process.env.MUX_VITE_PORT ?? "5173"); +const previewPort = Number(process.env.MUX_VITE_PREVIEW_PORT ?? "4173"); const alias: Record = { "@": path.resolve(__dirname, "./src"), @@ -82,7 +82,7 @@ export default defineConfig(({ mode }) => ({ plugins: () => [topLevelAwait()], }, server: { - host: devServerHost, // Configurable via CMUX_VITE_HOST (defaults to 127.0.0.1 for security) + host: devServerHost, // Configurable via MUX_VITE_HOST (defaults to 127.0.0.1 for security) port: devServerPort, strictPort: true, allowedHosts: devServerHost === "0.0.0.0" ? undefined : ["localhost", "127.0.0.1"], From 70a2d910f3e9cd9b755772db2c6b311bc7c537dd Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:25:01 -0500 Subject: [PATCH 2/9] fix: preserve coder/cmux repo references in scripts The repository is still at coder/cmux, so scripts should reference that. --- scripts/check_pr_reviews.sh | 2 +- scripts/extract_pr_logs.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/check_pr_reviews.sh b/scripts/check_pr_reviews.sh index fd5fe9dfb..6cbb8537d 100755 --- a/scripts/check_pr_reviews.sh +++ b/scripts/check_pr_reviews.sh @@ -42,7 +42,7 @@ if [ -n "$UNRESOLVED" ]; then echo "To resolve a comment thread, use:" echo "$UNRESOLVED" | jq -r '" ./scripts/resolve_pr_comment.sh \(.thread_id)"' echo "" - echo "View PR: https://github.com/coder/mux/pull/$PR_NUMBER" + echo "View PR: https://github.com/coder/cmux/pull/$PR_NUMBER" exit 1 fi diff --git a/scripts/extract_pr_logs.sh b/scripts/extract_pr_logs.sh index 3ea5efbf2..3d9cfe49d 100755 --- a/scripts/extract_pr_logs.sh +++ b/scripts/extract_pr_logs.sh @@ -132,7 +132,7 @@ for JOB_ID in $JOB_IDS; do while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do # Use gh api to fetch logs (works for individual completed jobs even if run is in progress) - if gh api "/repos/coder/mux/actions/jobs/$JOB_ID/logs" 2>/dev/null; then + if gh api "/repos/coder/cmux/actions/jobs/$JOB_ID/logs" 2>/dev/null; then break else RETRY_COUNT=$((RETRY_COUNT + 1)) From 72baa9801eb73a5ec3d4704f5bcf16cc3328864f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:25:55 -0500 Subject: [PATCH 3/9] fix: correct repo name in GraphQL query Should be coder/cmux not coder/mux in the GraphQL query. --- scripts/check_pr_reviews.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check_pr_reviews.sh b/scripts/check_pr_reviews.sh index 6cbb8537d..4dcc7c4cc 100755 --- a/scripts/check_pr_reviews.sh +++ b/scripts/check_pr_reviews.sh @@ -15,7 +15,7 @@ PR_NUMBER="$1" # Query for unresolved review threads UNRESOLVED=$(gh api graphql -f query=" { - repository(owner: \"coder\", name: \"mux\") { + repository(owner: \"coder\", name: \"cmux\") { pullRequest(number: $PR_NUMBER) { reviewThreads(first: 100) { nodes { From 25aeb65a3a1229ab74b3fdef421a3ec9ec64924f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:28:00 -0500 Subject: [PATCH 4/9] fix: preserve cmux references for VS Code extension VS Code extension is excluded from this rename (separate PR later), so keep references to cmux-*.vsix in workflows. --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 72958a4ae..a1a14eb1a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -107,6 +107,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: vscode-extension - path: vscode/mux-*.vsix + path: vscode/cmux-*.vsix retention-days: 30 if-no-files-found: error diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 211edeea4..b59c0e9dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,5 +77,5 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh release upload ${{ github.event.release.tag_name }} \ - vscode/mux-*.vsix \ + vscode/cmux-*.vsix \ --clobber From 0bd1df4fda0ade0e1c1b51feaee51ded4cfea1cb Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:32:54 -0500 Subject: [PATCH 5/9] fix: update test expectations and comments for rename - Fixed splitAbbreviatedPath tests to use 'mux' instead of 'cmux' - Updated systemMessage comments to reference ~/.mux not ~/.cmux - Ran make fmt to fix formatting issues --- docs/benchmarking.md | 6 +++--- src/constants/paths.ts | 8 ++++---- src/services/mock/mockScenarioPlayer.ts | 5 +---- src/services/systemMessage.ts | 8 ++++---- src/telemetry/client.ts | 6 +++--- src/telemetry/lifecycle.ts | 4 ++-- src/utils/messages/recency.ts | 5 +---- src/utils/ui/pathAbbreviation.test.ts | 4 ++-- tests/ipcMain/windowTitle.test.ts | 4 +--- 9 files changed, 21 insertions(+), 29 deletions(-) diff --git a/docs/benchmarking.md b/docs/benchmarking.md index 54e7e4526..f1ab92df2 100644 --- a/docs/benchmarking.md +++ b/docs/benchmarking.md @@ -14,13 +14,13 @@ Optional environment overrides: | ---------------------- | --------------------------------------------------------- | -------------------------------------- | | `CMUX_AGENT_REPO_ROOT` | Path copied into each task container | repo root inferred from the agent file | | `CMUX_TRUNK` | Branch checked out when preparing the project | `main` | -| `CMUX_WORKSPACE_ID` | Workspace identifier used inside mux | `mux-bench` | +| `CMUX_WORKSPACE_ID` | Workspace identifier used inside mux | `mux-bench` | | `CMUX_MODEL` | Preferred model (supports `provider/model` syntax) | `anthropic/claude-sonnet-4-5` | | `CMUX_THINKING_LEVEL` | Optional reasoning level (`off`, `low`, `medium`, `high`) | `high` | | `CMUX_MODE` | Starting mode (`plan` or `exec`) | `exec` | | `CMUX_TIMEOUT_MS` | Optional stream timeout in milliseconds | no timeout | -| `CMUX_CONFIG_ROOT` | Location for mux session data inside the container | `/root/.mux` | -| `CMUX_APP_ROOT` | Path where the mux sources are staged | `/opt/mux-app` | +| `CMUX_CONFIG_ROOT` | Location for mux session data inside the container | `/root/.mux` | +| `CMUX_APP_ROOT` | Path where the mux sources are staged | `/opt/mux-app` | | `CMUX_PROJECT_PATH` | Explicit project directory inside the task container | auto-detected from common paths | ## Running Terminal-Bench diff --git a/src/constants/paths.ts b/src/constants/paths.ts index f9534b09d..2c5cc46b8 100644 --- a/src/constants/paths.ts +++ b/src/constants/paths.ts @@ -5,7 +5,7 @@ import { join } from "path"; /** * Migrate from .cmux to .mux directory structure. * Called on startup to ensure backward compatibility. - * + * * If .mux exists, nothing happens (already migrated). * If .cmux exists but .mux doesn't, moves .cmux → .mux and creates symlink. * This ensures old scripts/tools referencing ~/.cmux continue working. @@ -13,18 +13,18 @@ import { join } from "path"; export function ensureMuxMigration(): void { const oldPath = join(homedir(), ".cmux"); const newPath = join(homedir(), ".mux"); - + // If .mux exists, we're done (already migrated or fresh install) if (existsSync(newPath)) { return; } - + // If .cmux exists, move it and create symlink for backward compatibility if (existsSync(oldPath)) { renameSync(oldPath, newPath); symlinkSync(newPath, oldPath, "dir"); } - + // If neither exists, nothing to do (will be created on first use) } diff --git a/src/services/mock/mockScenarioPlayer.ts b/src/services/mock/mockScenarioPlayer.ts index e110e1b2e..4735cea5a 100644 --- a/src/services/mock/mockScenarioPlayer.ts +++ b/src/services/mock/mockScenarioPlayer.ts @@ -147,10 +147,7 @@ export class MockScenarioPlayer { this.activeStreams.delete(workspaceId); } - async play( - messages: MuxMessage[], - workspaceId: string - ): Promise> { + async play(messages: MuxMessage[], workspaceId: string): Promise> { const latest = messages[messages.length - 1]; if (!latest || latest.role !== "user") { return Err({ type: "unknown", raw: "Mock scenario expected a user message" }); diff --git a/src/services/systemMessage.ts b/src/services/systemMessage.ts index 1a63ab406..edea14668 100644 --- a/src/services/systemMessage.ts +++ b/src/services/systemMessage.ts @@ -7,7 +7,7 @@ import { getMuxHome } from "@/constants/paths"; // NOTE: keep this in sync with the docs/models.md file // The PRELUDE is intentionally minimal to not conflict with the user's instructions. -// cmux is designed to be model agnostic, and models have shown large inconsistency in how they +// mux is designed to be model agnostic, and models have shown large inconsistency in how they // follow instructions. const PRELUDE = ` @@ -45,8 +45,8 @@ You are in a git worktree at ${workspacePath} } /** - * Get the system directory where global cmux configuration lives. - * Users can place global AGENTS.md and .cmux/PLAN.md files here. + * Get the system directory where global mux configuration lives. + * Users can place global AGENTS.md and .mux/PLAN.md files here. */ function getSystemDirectory(): string { return getMuxHome(); @@ -56,7 +56,7 @@ function getSystemDirectory(): string { * Builds a system message for the AI model by combining instruction sources. * * Instruction layers: - * 1. Global: ~/.cmux/AGENTS.md (always included) + * 1. Global: ~/.mux/AGENTS.md (always included) * 2. Context: workspace/AGENTS.md OR project/AGENTS.md (workspace takes precedence) * 3. Mode: Extracts "Mode: " section from context then global (if mode provided) * diff --git a/src/telemetry/client.ts b/src/telemetry/client.ts index e27924e65..fe548e90c 100644 --- a/src/telemetry/client.ts +++ b/src/telemetry/client.ts @@ -55,13 +55,13 @@ const LEGACY_TELEMETRY_KEY = "cmux_telemetry_enabled"; */ export function isTelemetryEnabled(): boolean { if (typeof window === "undefined") return true; - + // Try new key first, then legacy key const stored = localStorage.getItem(TELEMETRY_ENABLED_KEY); if (stored !== null) { return stored === "true"; } - + // Migrate from legacy key if it exists const legacy = localStorage.getItem(LEGACY_TELEMETRY_KEY); if (legacy !== null) { @@ -69,7 +69,7 @@ export function isTelemetryEnabled(): boolean { localStorage.removeItem(LEGACY_TELEMETRY_KEY); return legacy === "true"; } - + return true; // Default to enabled } diff --git a/src/telemetry/lifecycle.ts b/src/telemetry/lifecycle.ts index d197cb362..a4fb04ab4 100644 --- a/src/telemetry/lifecycle.ts +++ b/src/telemetry/lifecycle.ts @@ -14,13 +14,13 @@ import { trackEvent, getBaseTelemetryProperties } from "./index"; function checkFirstLaunch(): boolean { const key = "mux_first_launch_complete"; const legacyKey = "cmux_first_launch_complete"; - + // Check new key first const hasLaunchedBefore = localStorage.getItem(key); if (hasLaunchedBefore) { return false; } - + // Migrate from legacy key if it exists const legacyValue = localStorage.getItem(legacyKey); if (legacyValue) { diff --git a/src/utils/messages/recency.ts b/src/utils/messages/recency.ts index 151b6a291..4de925c1b 100644 --- a/src/utils/messages/recency.ts +++ b/src/utils/messages/recency.ts @@ -10,10 +10,7 @@ import type { MuxMessage } from "@/types/message"; * * This eliminates race conditions where workspaces appear at bottom before messages load. */ -export function computeRecencyTimestamp( - messages: MuxMessage[], - createdAt?: string -): number | null { +export function computeRecencyTimestamp(messages: MuxMessage[], createdAt?: string): number | null { if (messages.length === 0 && !createdAt) { return null; } diff --git a/src/utils/ui/pathAbbreviation.test.ts b/src/utils/ui/pathAbbreviation.test.ts index 1c66ae7fb..13098c7f6 100644 --- a/src/utils/ui/pathAbbreviation.test.ts +++ b/src/utils/ui/pathAbbreviation.test.ts @@ -35,14 +35,14 @@ describe("abbreviatePath", () => { describe("splitAbbreviatedPath", () => { it("should split abbreviated path into directory and basename", () => { - expect(splitAbbreviatedPath("/U/a/P/c/cmux")).toEqual({ + expect(splitAbbreviatedPath("/U/a/P/c/mux")).toEqual({ dirPath: "/U/a/P/c/", basename: "mux", }); }); it("should handle paths without leading slash", () => { - expect(splitAbbreviatedPath("U/a/P/c/cmux")).toEqual({ + expect(splitAbbreviatedPath("U/a/P/c/mux")).toEqual({ dirPath: "U/a/P/c/", basename: "mux", }); diff --git a/tests/ipcMain/windowTitle.test.ts b/tests/ipcMain/windowTitle.test.ts index e3a63630e..865150726 100644 --- a/tests/ipcMain/windowTitle.test.ts +++ b/tests/ipcMain/windowTitle.test.ts @@ -20,9 +20,7 @@ describeIntegration("Window title IPC", () => { ); // Verify setTitle was called on the window - expect(env.mockWindow.setTitle).toHaveBeenCalledWith( - "test-workspace - test-project - mux" - ); + expect(env.mockWindow.setTitle).toHaveBeenCalledWith("test-workspace - test-project - mux"); } finally { await cleanupTestEnvironment(env); } From 4302ef5833efac6acc8112978ad0d5eb235feb53 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:37:16 -0500 Subject: [PATCH 6/9] fix: update test globalDir to use .mux instead of .cmux The globalDir in systemMessage tests was still using .cmux, which caused the global mode section fallback test to fail. --- src/services/systemMessage.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/systemMessage.test.ts b/src/services/systemMessage.test.ts index cff8e24c3..34f12e754 100644 --- a/src/services/systemMessage.test.ts +++ b/src/services/systemMessage.test.ts @@ -20,12 +20,12 @@ describe("buildSystemMessage", () => { tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "systemMessage-test-")); projectDir = path.join(tempDir, "project"); workspaceDir = path.join(tempDir, "workspace"); - globalDir = path.join(tempDir, ".cmux"); + globalDir = path.join(tempDir, ".mux"); await fs.mkdir(projectDir, { recursive: true }); await fs.mkdir(workspaceDir, { recursive: true }); await fs.mkdir(globalDir, { recursive: true }); - // Mock homedir to return our test directory (getSystemDirectory will append .cmux) + // Mock homedir to return our test directory (getSystemDirectory will append .mux) mockHomedir = spyOn(os, "homedir"); mockHomedir.mockReturnValue(tempDir); From c5c62c6e6c0b69eceb86d501f06732340eaba268 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:44:25 -0500 Subject: [PATCH 7/9] fix: update init hook paths and test metadata field names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changed .cmux/init → .mux/init in runtime code - Fixed test to use cmuxMetadata instead of muxMetadata (field name preserved for backward compat) --- src/runtime/LocalRuntime.ts | 4 ++-- src/runtime/SSHRuntime.ts | 6 +++--- src/runtime/initHook.ts | 2 +- .../StreamingMessageAggregator.init.test.ts | 2 +- tests/ipcMain/sendMessage.test.ts | 14 +++++++------- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/runtime/LocalRuntime.ts b/src/runtime/LocalRuntime.ts index e64c162ab..36099bb80 100644 --- a/src/runtime/LocalRuntime.ts +++ b/src/runtime/LocalRuntime.ts @@ -370,7 +370,7 @@ export class LocalRuntime implements Runtime { const { projectPath, workspacePath, initLogger } = params; try { - // Run .cmux/init hook if it exists + // Run .mux/init hook if it exists // Note: runInitHook calls logComplete() internally if hook exists const hookExists = await checkInitHookExists(projectPath); if (hookExists) { @@ -392,7 +392,7 @@ export class LocalRuntime implements Runtime { } /** - * Run .cmux/init hook if it exists and is executable + * Run .mux/init hook if it exists and is executable */ private async runInitHook( projectPath: string, diff --git a/src/runtime/SSHRuntime.ts b/src/runtime/SSHRuntime.ts index c35eb2e35..d11043d8e 100644 --- a/src/runtime/SSHRuntime.ts +++ b/src/runtime/SSHRuntime.ts @@ -706,7 +706,7 @@ export class SSHRuntime implements Runtime { } /** - * Run .cmux/init hook on remote machine if it exists + * Run .mux/init hook on remote machine if it exists */ private async runInitHook( projectPath: string, @@ -721,7 +721,7 @@ export class SSHRuntime implements Runtime { } // Construct hook path - expand tilde if present - const remoteHookPath = `${workspacePath}/.cmux/init`; + const remoteHookPath = `${workspacePath}/.mux/init`; initLogger.logStep(`Running init hook: ${remoteHookPath}`); // Expand tilde in hook path for execution @@ -888,7 +888,7 @@ export class SSHRuntime implements Runtime { } initLogger.logStep("Branch checked out successfully"); - // 3. Run .cmux/init hook if it exists + // 3. Run .mux/init hook if it exists // Note: runInitHook calls logComplete() internally if hook exists const hookExists = await checkInitHookExists(projectPath); if (hookExists) { diff --git a/src/runtime/initHook.ts b/src/runtime/initHook.ts index 401b71f00..c1864fe4e 100644 --- a/src/runtime/initHook.ts +++ b/src/runtime/initHook.ts @@ -4,7 +4,7 @@ import * as path from "path"; import type { InitLogger } from "./Runtime"; /** - * Check if .cmux/init hook exists and is executable + * Check if .mux/init hook exists and is executable * @param projectPath - Path to the project root * @returns true if hook exists and is executable, false otherwise */ diff --git a/src/utils/messages/StreamingMessageAggregator.init.test.ts b/src/utils/messages/StreamingMessageAggregator.init.test.ts index 2f72fec28..2a3fdfc8c 100644 --- a/src/utils/messages/StreamingMessageAggregator.init.test.ts +++ b/src/utils/messages/StreamingMessageAggregator.init.test.ts @@ -14,7 +14,7 @@ describe("Init display after cleanup changes", () => { // Simulate init start aggregator.handleMessage({ type: "init-start", - hookPath: "/test/.cmux/init", + hookPath: "/test/.mux/init", timestamp: Date.now(), }); diff --git a/tests/ipcMain/sendMessage.test.ts b/tests/ipcMain/sendMessage.test.ts index 10c7f55c2..544ec8cda 100644 --- a/tests/ipcMain/sendMessage.test.ts +++ b/tests/ipcMain/sendMessage.test.ts @@ -1466,7 +1466,7 @@ These are general instructions that apply to all modes. "Test message with metadata", { model: "openai:gpt-4", // Valid format but provider not configured - will fail after storing message - muxMetadata: testMetadata, + cmuxMetadata: testMetadata, } ); @@ -1493,14 +1493,14 @@ These are general instructions that apply to all modes. // Verify metadata was preserved exactly as sent (black-box) expect(userMessage).toHaveProperty("metadata"); const metadata = (userMessage as any).metadata; - expect(metadata).toHaveProperty("muxMetadata"); - expect(metadata.muxMetadata).toEqual(testMetadata); + expect(metadata).toHaveProperty("cmuxMetadata"); + expect(metadata.cmuxMetadata).toEqual(testMetadata); // Verify structured fields are accessible - expect(metadata.muxMetadata.type).toBe("compaction-request"); - expect(metadata.muxMetadata.rawCommand).toBe("/compact -c continue working"); - expect(metadata.muxMetadata.parsed.continueMessage).toBe("continue working"); - expect(metadata.muxMetadata.parsed.maxOutputTokens).toBe(5000); + expect(metadata.cmuxMetadata.type).toBe("compaction-request"); + expect(metadata.cmuxMetadata.rawCommand).toBe("/compact -c continue working"); + expect(metadata.cmuxMetadata.parsed.continueMessage).toBe("continue working"); + expect(metadata.cmuxMetadata.parsed.maxOutputTokens).toBe(5000); } finally { await cleanup(); } From 2e8b21bd33e88310b6e4e57e068cbb2e19ff6955 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 11:49:38 -0500 Subject: [PATCH 8/9] fix: update remaining .cmux references in initHook.ts The init hook path functions were still using .cmux instead of .mux, causing init hooks to not be found during workspace creation. --- src/runtime/initHook.ts | 4 ++-- src/services/initStateManager.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/initHook.ts b/src/runtime/initHook.ts index c1864fe4e..dfa762771 100644 --- a/src/runtime/initHook.ts +++ b/src/runtime/initHook.ts @@ -9,7 +9,7 @@ import type { InitLogger } from "./Runtime"; * @returns true if hook exists and is executable, false otherwise */ export async function checkInitHookExists(projectPath: string): Promise { - const hookPath = path.join(projectPath, ".cmux", "init"); + const hookPath = path.join(projectPath, ".mux", "init"); try { await fsPromises.access(hookPath, fs.constants.X_OK); @@ -23,7 +23,7 @@ export async function checkInitHookExists(projectPath: string): Promise * Get the init hook path for a project */ export function getInitHookPath(projectPath: string): string { - return path.join(projectPath, ".cmux", "init"); + return path.join(projectPath, ".mux", "init"); } /** diff --git a/src/services/initStateManager.ts b/src/services/initStateManager.ts index 368f41f42..3d90082f7 100644 --- a/src/services/initStateManager.ts +++ b/src/services/initStateManager.ts @@ -15,7 +15,7 @@ export interface TimedLine { /** * Persisted state for init hooks. - * Stored in ~/.cmux/sessions/{workspaceId}/init-status.json + * Stored in ~/.mux/sessions/{workspaceId}/init-status.json */ export interface InitStatus { status: "running" | "success" | "error"; From f933cc6f5f4445a56657fc34a66a1620717753e8 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 13 Nov 2025 12:08:24 -0500 Subject: [PATCH 9/9] refactor: rename ensureMuxMigration to migrateCmuxToMux - Renamed function for clarity - Added migration call to main-server.ts startup - Updated main-server.ts comments and command name --- src/constants/paths.ts | 2 +- src/main-desktop.ts | 4 ++-- src/main-server.ts | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/constants/paths.ts b/src/constants/paths.ts index 22e71e508..045a65818 100644 --- a/src/constants/paths.ts +++ b/src/constants/paths.ts @@ -10,7 +10,7 @@ import { join } from "path"; * If .cmux exists but .mux doesn't, moves .cmux → .mux and creates symlink. * This ensures old scripts/tools referencing ~/.cmux continue working. */ -export function ensureMuxMigration(): void { +export function migrateCmuxToMux(): void { const oldPath = join(homedir(), ".cmux"); const newPath = join(homedir(), ".mux"); diff --git a/src/main-desktop.ts b/src/main-desktop.ts index bac8cfa32..5c8017f2f 100644 --- a/src/main-desktop.ts +++ b/src/main-desktop.ts @@ -18,7 +18,7 @@ import type { Config } from "./config"; import type { IpcMain } from "./services/ipcMain"; import { VERSION } from "./version"; import { IPC_CHANNELS } from "./constants/ipc-constants"; -import { getMuxHome, ensureMuxMigration } from "./constants/paths"; +import { getMuxHome, migrateCmuxToMux } from "./constants/paths"; import { log } from "./services/log"; import { parseDebugUpdater } from "./utils/env"; import assert from "./utils/assert"; @@ -486,7 +486,7 @@ if (gotTheLock) { console.log("App ready, creating window..."); // Migrate from .cmux to .mux directory structure if needed - ensureMuxMigration(); + migrateCmuxToMux(); // Install React DevTools in development if (!app.isPackaged && installExtension && REACT_DEVELOPER_TOOLS) { diff --git a/src/main-server.ts b/src/main-server.ts index 4213375ed..77c44b58a 100644 --- a/src/main-server.ts +++ b/src/main-server.ts @@ -1,10 +1,11 @@ /** - * HTTP/WebSocket Server for cmux - * Allows accessing cmux backend from mobile devices + * HTTP/WebSocket Server for mux + * Allows accessing mux backend from mobile devices */ import { Config } from "./config"; import { IPC_CHANNELS } from "@/constants/ipc-constants"; import { IpcMain } from "./services/ipcMain"; +import { migrateCmuxToMux } from "./constants/paths"; import cors from "cors"; import type { BrowserWindow, IpcMain as ElectronIpcMain } from "electron"; import express from "express"; @@ -19,8 +20,8 @@ import { validateProjectPath } from "./utils/pathUtils"; const program = new Command(); program - .name("cmux-server") - .description("HTTP/WebSocket server for cmux - allows accessing cmux backend from mobile devices") + .name("mux-server") + .description("HTTP/WebSocket server for mux - allows accessing mux backend from mobile devices") .option("-h, --host ", "bind to specific host", "localhost") .option("-p, --port ", "bind to specific port", "3000") .option("--add-project ", "add and open project at the specified path (idempotent)") @@ -143,6 +144,9 @@ const httpIpcMain = new HttpIpcMainAdapter(app); // Initialize async services and register handlers (async () => { + // Migrate from .cmux to .mux directory structure if needed + migrateCmuxToMux(); + // Initialize config and IPC service const config = new Config(); const ipcMainService = new IpcMain(config);