Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/actions/setup-cmux/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,14 @@ runs:
sudo apt-get install -y --no-install-recommends imagemagick
fi
convert --version | head -1
- name: Install ImageMagick (Windows)
if: inputs.install-imagemagick == 'true' && runner.os == 'Windows'
shell: powershell
run: |
if (Get-Command magick -ErrorAction SilentlyContinue) {
Write-Host "✅ ImageMagick already available"
} else {
Write-Host "📦 Installing ImageMagick..."
choco install -y imagemagick
}
magick --version | Select-Object -First 1
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,34 @@ jobs:
run: bun x electron-builder --linux --publish always
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

build-windows:
name: Build and Release Windows
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for git describe to find tags

- uses: ./.github/actions/setup-cmux
with:
install-imagemagick: true

- name: Install GNU Make (for build)
run: choco install -y make

- name: Verify tools
shell: bash
run: |
make --version
bun --version
magick --version | head -1

- name: Build application
run: bun run build

- name: Package and publish for Windows (.exe)
run: bun x electron-builder --win --publish always
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 changes: 17 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
# Branches reduce reproducibility - builds should fail fast with clear errors
# if dependencies are missing, not silently fall back to different behavior.

ifeq ($(OS),Windows_NT)
SHELL := /usr/bin/bash
else
SHELL := /bin/bash
endif
.SHELLFLAGS := -eu -o pipefail -c

# Enable parallel execution by default (only if user didn't specify -j)
ifeq (,$(filter -j%,$(MAKEFLAGS)))
MAKEFLAGS += -j
Expand Down Expand Up @@ -92,20 +99,21 @@ help: ## Show this help message

## Development
dev: node_modules/.installed build-main ## Start development server (Vite + tsgo watcher for 10x faster type checking)
@bun x concurrently -k \
"bun x concurrently \"$(TSGO) -w -p tsconfig.main.json\" \"bun x tsc-alias -w -p tsconfig.main.json\"" \
"vite"
@npx concurrently -k --raw \
"$(TSGO) -w -p tsconfig.main.json" \
"bun tsc-alias -w -p tsconfig.main.json" \
"bun x vite"

dev-server: node_modules/.installed build-main ## Start server mode with hot reload (backend :3000 + frontend :5173). Use VITE_HOST=0.0.0.0 BACKEND_HOST=0.0.0.0 for remote access
@echo "Starting dev-server..."
@echo " Backend (IPC/WebSocket): http://$(or $(BACKEND_HOST),localhost):$(or $(BACKEND_PORT),3000)"
@echo " Frontend (with HMR): http://$(or $(VITE_HOST),localhost):$(or $(VITE_PORT),5173)"
@echo ""
@echo "For remote access: make dev-server VITE_HOST=0.0.0.0 BACKEND_HOST=0.0.0.0"
@bun x concurrently -k \
"bun x concurrently \"$(TSGO) -w -p tsconfig.main.json\" \"bun x tsc-alias -w -p tsconfig.main.json\"" \
@npx concurrently -k \
"npx 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 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"
"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) bun x vite"



Expand Down Expand Up @@ -162,16 +170,16 @@ MAGICK_CMD := $(shell command -v magick 2>/dev/null || command -v convert 2>/dev
build/icon.png: docs/img/logo.webp
@echo "Generating Linux icon..."
@mkdir -p build
@$(MAGICK_CMD) docs/img/logo.webp -resize 512x512 build/icon.png
@"$(MAGICK_CMD)" docs/img/logo.webp -resize 512x512 build/icon.png

build/icon.icns: docs/img/logo.webp
@echo "Generating macOS icon..."
@mkdir -p build/icon.iconset
@for size in 16 32 64 128 256 512; do \
$(MAGICK_CMD) docs/img/logo.webp -resize $${size}x$${size} build/icon.iconset/icon_$${size}x$${size}.png; \
"$(MAGICK_CMD)" docs/img/logo.webp -resize $${size}x$${size} build/icon.iconset/icon_$${size}x$${size}.png; \
if [ $$size -le 256 ]; then \
double=$$((size * 2)); \
$(MAGICK_CMD) docs/img/logo.webp -resize $${double}x$${double} build/icon.iconset/icon_$${size}x$${size}@2x.png; \
"$(MAGICK_CMD)" docs/img/logo.webp -resize $${double}x$${double} build/icon.iconset/icon_$${size}x$${size}@2x.png; \
fi; \
done
@iconutil -c icns build/icon.iconset -o build/icon.icns
Expand Down
9 changes: 3 additions & 6 deletions bun.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "@coder/cmux",
Expand Down Expand Up @@ -70,7 +71,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"concurrently": "^8.2.0",
"concurrently": "^9.2.1",
"dotenv": "^17.2.3",
"electron": "^38.2.1",
"electron-builder": "^24.6.0",
Expand Down Expand Up @@ -1198,7 +1199,7 @@

"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],

"concurrently": ["concurrently@8.2.2", "", { "dependencies": { "chalk": "^4.1.2", "date-fns": "^2.30.0", "lodash": "^4.17.21", "rxjs": "^7.8.1", "shell-quote": "^1.8.1", "spawn-command": "0.0.2", "supports-color": "^8.1.1", "tree-kill": "^1.2.2", "yargs": "^17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg=="],
"concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="],

"confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="],

Expand Down Expand Up @@ -1316,8 +1317,6 @@

"data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="],

"date-fns": ["date-fns@2.30.0", "", { "dependencies": { "@babel/runtime": "^7.21.0" } }, "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw=="],

"dayjs": ["dayjs@1.11.18", "", {}, "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA=="],

"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
Expand Down Expand Up @@ -2572,8 +2571,6 @@

"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],

"spawn-command": ["spawn-command@0.0.2", "", {}, "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ=="],

"spawn-wrap": ["spawn-wrap@2.0.0", "", { "dependencies": { "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "which": "^2.0.1" } }, "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg=="],

"spawnd": ["spawnd@5.0.0", "", { "dependencies": { "exit": "^0.1.2", "signal-exit": "^3.0.3", "tree-kill": "^1.2.2", "wait-port": "^0.2.9" } }, "sha512-28+AJr82moMVWolQvlAIv3JcYDkjkFTEmfDc503wxrF5l2rQ3dFz6DpbXp3kD4zmgGGldfM4xM4v1sFj/ZaIOA=="],
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"concurrently": "^8.2.0",
"concurrently": "^9.2.1",
"dotenv": "^17.2.3",
"electron": "^38.2.1",
"electron-builder": "^24.6.0",
Expand Down Expand Up @@ -202,7 +202,9 @@
"artifactName": "${productName}-${version}-${arch}.${ext}"
},
"win": {
"target": "nsis"
"target": "nsis",
"icon": "build/icon.png",
"artifactName": "${productName}-${version}-${arch}.${ext}"
}
}
}
7 changes: 6 additions & 1 deletion src/components/NewWorkspaceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,12 @@ const NewWorkspaceModal: React.FC<NewWorkspaceModalProps> = ({
<code className="block break-all">
{runtimeMode === RUNTIME_MODE.SSH
? `${sshHost || "<host>"}:~/cmux/${branchName || "<branch-name>"}`
: `~/.cmux/src/${projectName}/${branchName || "<branch-name>"}`}
: (() => {
const isWindows = window.api?.platform === "win32";
const homePlaceholder = isWindows ? "%USERPROFILE%" : "~";
const sep = isWindows ? "\\" : "/";
return `${homePlaceholder}${sep}.cmux${sep}src${sep}${projectName}${sep}${branchName || "<branch-name>"}`;
})()}
</code>
</ModalInfo>

Expand Down
3 changes: 2 additions & 1 deletion src/runtime/SSHRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ import { getControlPath } from "./sshConnectionPool";
/**
* Shescape instance for bash shell escaping.
* Reused across all SSH runtime operations for performance.
* Shescape properly auto-detects win32 & linux shells, but fails on macOS.
*/
const shescape = new Shescape({ shell: "bash" });
const shescape = new Shescape({ shell: process.platform === "darwin" ? "bash" : true });

/**
* SSH Runtime Configuration
Expand Down
Loading