diff --git a/README.md b/README.md index e5f78b4..5cc9c47 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# cmux-conjure +# cmuxup -> One command to conjure your terminal-first agentic workspace in [cmux](https://cmux.com). +> One command to cmuxup your terminal-first agentic workspace in [cmux](https://cmux.com). -`conjure` builds a full IDE-like layout in cmux using its **control socket API** — no AppleScript, no keystroke timing, reproducible every run. +`cmuxup` builds a full IDE-like layout in cmux using its **control socket API** — no AppleScript, no keystroke timing, reproducible every run. ``` ┌──────────────┬───────────────────────┐ @@ -21,7 +21,7 @@ ## Install ```bash -curl -fsSL https://raw.githubusercontent.com/ITZSHOAIB/cmux-conjure/main/install.sh | bash +curl -fsSL https://raw.githubusercontent.com/ITZSHOAIB/cmuxup/main/install.sh | bash ``` The interactive installer (powered by [gum](https://github.com/charmbracelet/gum)) will ask you to choose: @@ -38,10 +38,10 @@ It installs and configures: `lazygit`, `delta`, `helix`, `yazi`, `starship`, `zo ## Usage ```bash -conjure ~/my-project +cmuxup ~/my-project ``` -Open a new shell after installing, then run `conjure` from anywhere. +Open a new shell after installing, then run `cmuxup` from anywhere. ## What opens @@ -57,10 +57,10 @@ Open a new shell after installing, then run `conjure` from anywhere. Override any pane command without reinstalling: ```bash -CONJURE_MAIN_CMD="opencode" conjure ~/my-project -CONJURE_LG_CMD="tig" conjure ~/my-project -CONJURE_HX_CMD="nvim ." conjure ~/my-project -CONJURE_DEV_CMD="yarn dev" conjure ~/my-project +CMUXUP_MAIN_CMD="opencode" cmuxup ~/my-project +CMUXUP_LG_CMD="tig" cmuxup ~/my-project +CMUXUP_HX_CMD="nvim ." cmuxup ~/my-project +CMUXUP_DEV_CMD="yarn dev" cmuxup ~/my-project ``` ## Config templates @@ -80,11 +80,11 @@ All configs live in `templates/` and use `{{PLACEHOLDER}}` substitution. Edit th ## Non-interactive install (CI / scripting) ```bash -CONJURE_NON_INTERACTIVE=1 \ -CONJURE_THEME="Catppuccin Mocha" \ -CONJURE_FONT_SIZE=14 \ -CONJURE_AGENT=claude \ -CONJURE_EDITOR=helix \ +CMUXUP_NON_INTERACTIVE=1 \ +CMUXUP_THEME="Catppuccin Mocha" \ +CMUXUP_FONT_SIZE=14 \ +CMUXUP_AGENT=claude \ +CMUXUP_EDITOR=helix \ bash install.sh ``` diff --git a/bin/conjure b/bin/cmuxup similarity index 79% rename from bin/conjure rename to bin/cmuxup index c169d39..3ca9cf0 100755 --- a/bin/conjure +++ b/bin/cmuxup @@ -3,7 +3,7 @@ set -euo pipefail VERSION="0.1.0" -# conjure [/path/to/project] +# cmuxup [/path/to/project] # # Builds a terminal-first agentic IDE layout in cmux via its control socket. # No AppleScript, no keystroke timing — pure cmux socket API. @@ -16,14 +16,14 @@ VERSION="0.1.0" # └──────────────┴───────────────────────┘ # # Env overrides: -# CONJURE_MAIN_CMD default: claude -# CONJURE_LG_CMD default: lazygit -# CONJURE_HX_CMD default: hx . -# CONJURE_DEV_CMD default: (empty — just cd's into project) +# CMUXUP_MAIN_CMD default: claude +# CMUXUP_LG_CMD default: lazygit +# CMUXUP_HX_CMD default: hx . +# CMUXUP_DEV_CMD default: (empty — just cd's into project) usage() { cat </dev/null && pwd)"; then - echo "conjure: '${1:-$PWD}' is not a directory" >&2 + echo "cmuxup: '${1:-$PWD}' is not a directory" >&2 exit 1 fi NAME="$(basename "$PROJECT_DIR")" -MAIN_CMD="${CONJURE_MAIN_CMD:-claude}" -LG_CMD="${CONJURE_LG_CMD:-lazygit}" -HX_CMD="${CONJURE_HX_CMD:-hx .}" -DEV_CMD="${CONJURE_DEV_CMD:-}" +MAIN_CMD="${CMUXUP_MAIN_CMD:-claude}" +LG_CMD="${CMUXUP_LG_CMD:-lazygit}" +HX_CMD="${CMUXUP_HX_CMD:-hx .}" +DEV_CMD="${CMUXUP_DEV_CMD:-}" CMUX_BIN="$(command -v cmux 2>/dev/null || echo /Applications/cmux.app/Contents/Resources/bin/cmux)" cx() { "$CMUX_BIN" "$@"; } @@ -76,7 +76,7 @@ if ! cx ping >/dev/null 2>&1; then cx ping >/dev/null 2>&1 && break sleep 0.5 done - cx ping >/dev/null 2>&1 || { echo "conjure: cmux control socket not responding" >&2; exit 1; } + cx ping >/dev/null 2>&1 || { echo "cmuxup: cmux control socket not responding" >&2; exit 1; } fi # Parse the first "type:N" ref from stdin. @@ -98,7 +98,7 @@ _run_in() { # surface workspace command # 1. Create workspace; main pane launches the agent command. WS="$(cx new-workspace --name "$NAME" --cwd "$PROJECT_DIR" --command "$MAIN_CMD" --focus true | _ref workspace)" -[ -n "$WS" ] || { echo "conjure: failed to create cmux workspace" >&2; exit 1; } +[ -n "$WS" ] || { echo "cmuxup: failed to create cmux workspace" >&2; exit 1; } # 2. Identify the initial surface (the only one that exists right after creation). MAIN_SURFACE="$(cx tree --workspace "$WS" | _ref surface)" @@ -129,7 +129,7 @@ fi # 8. Return focus to the agent pane on the left. cx focus-panel --panel "$MAIN_SURFACE" --workspace "$WS" >/dev/null 2>&1 || true -echo "conjure: workspace '$NAME' ready ($WS)" +echo "cmuxup: workspace '$NAME' ready ($WS)" echo " left $MAIN_CMD" echo " right-top lazygit | helix (tabs)" echo " right-bottom dev terminal" diff --git a/install.sh b/install.sh index 4fa1d02..1d772bc 100644 --- a/install.sh +++ b/install.sh @@ -1,17 +1,17 @@ #!/usr/bin/env bash set -euo pipefail -# conjure-cmux installer -# Usage: curl -fsSL https://raw.githubusercontent.com/ITZSHOAIB/cmux-conjure/main/install.sh | bash +# cmuxup installer +# Usage: curl -fsSL https://raw.githubusercontent.com/ITZSHOAIB/cmuxup/main/install.sh | bash # Or: bash install.sh [--help] [--dry-run] # # Non-interactive mode (for CI / testing): -# CONJURE_NON_INTERACTIVE=1 skip all gum prompts, use env vars below -# CONJURE_THEME one of: "Catppuccin Mocha" | "TokyoNight Storm" | "Gruvbox Dark Hard" | "Kanagawa Wave" -# CONJURE_FONT_SIZE 13 | 14 | 15 -# CONJURE_AGENT claude | opencode | codex | none -# CONJURE_EDITOR helix | nvim | vim -# CONJURE_OVERWRITE 1 = overwrite existing configs without prompting +# CMUXUP_NON_INTERACTIVE=1 skip all gum prompts, use env vars below +# CMUXUP_THEME one of: "Catppuccin Mocha" | "TokyoNight Storm" | "Gruvbox Dark Hard" | "Kanagawa Wave" +# CMUXUP_FONT_SIZE 13 | 14 | 15 +# CMUXUP_AGENT claude | opencode | codex | none +# CMUXUP_EDITOR helix | nvim | vim +# CMUXUP_OVERWRITE 1 = overwrite existing configs without prompting SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" VERSION="0.1.0" @@ -21,18 +21,18 @@ usage() { cat </dev/null 2>&1; then gum confirm "Overwrite $dest?" || { _skip "$dest already exists"; return; } else - _skip "$dest already exists (use CONJURE_OVERWRITE=1 to overwrite)" + _skip "$dest already exists (use CMUXUP_OVERWRITE=1 to overwrite)" return fi fi @@ -121,7 +121,7 @@ if ! command -v brew >/dev/null 2>&1; then fi # Bootstrap gum for the interactive UI (skip in dry-run or non-interactive). -if [ "${CONJURE_NON_INTERACTIVE:-0}" != "1" ] && [ "$DRY_RUN" -eq 0 ]; then +if [ "${CMUXUP_NON_INTERACTIVE:-0}" != "1" ] && [ "$DRY_RUN" -eq 0 ]; then if ! command -v gum >/dev/null 2>&1; then echo "Installing gum for the interactive UI..." brew install gum >/dev/null 2>&1 @@ -130,17 +130,17 @@ fi # ── Gather choices ──────────────────────────────────────────────────────────── -if [ "${CONJURE_NON_INTERACTIVE:-0}" = "1" ] || [ "$DRY_RUN" -eq 1 ]; then - THEME="${CONJURE_THEME:-Catppuccin Mocha}" - FONT_SIZE="${CONJURE_FONT_SIZE:-14}" - AGENT="${CONJURE_AGENT:-claude}" - EDITOR_CHOICE="${CONJURE_EDITOR:-helix}" +if [ "${CMUXUP_NON_INTERACTIVE:-0}" = "1" ] || [ "$DRY_RUN" -eq 1 ]; then + THEME="${CMUXUP_THEME:-Catppuccin Mocha}" + FONT_SIZE="${CMUXUP_FONT_SIZE:-14}" + AGENT="${CMUXUP_AGENT:-claude}" + EDITOR_CHOICE="${CMUXUP_EDITOR:-helix}" else if command -v gum >/dev/null 2>&1; then gum style \ --border double --border-foreground 212 \ --padding "1 4" --margin "1 0" \ - --bold "cmux-conjure v${VERSION}" \ + --bold "cmuxup v${VERSION}" \ "Terminal-first agentic workspace for cmux" THEME="$(gum choose --header "Choose your theme:" \ @@ -190,7 +190,7 @@ _apply_template "$TEMPLATES/helix.toml" "${HOME}/.config/helix/config.t _apply_template "$TEMPLATES/lazygit.yml" "${HOME}/Library/Application Support/lazygit/config.yml" "$THEME" "$FONT_SIZE" "$DELTA_THEME" "$HELIX_THEME" _apply_template "$TEMPLATES/yazi.toml" "${HOME}/.config/yazi/yazi.toml" "$THEME" "$FONT_SIZE" "$DELTA_THEME" "$HELIX_THEME" _apply_template "$TEMPLATES/starship.toml" "${HOME}/.config/starship.toml" "$THEME" "$FONT_SIZE" "$DELTA_THEME" "$HELIX_THEME" -_apply_template "$TEMPLATES/gitconfig-delta.ini" "${TMPDIR:-/tmp}/conjure-gitdelta.ini" "$THEME" "$FONT_SIZE" "$DELTA_THEME" "$HELIX_THEME" +_apply_template "$TEMPLATES/gitconfig-delta.ini" "${TMPDIR:-/tmp}/cmuxup-gitdelta.ini" "$THEME" "$FONT_SIZE" "$DELTA_THEME" "$HELIX_THEME" # Merge delta git config (non-destructive: only sets keys not already present). if [ "$DRY_RUN" -eq 0 ]; then @@ -201,7 +201,7 @@ if [ "$DRY_RUN" -eq 0 ]; then section="" # We'll use git config --global directly. true - done < "${TMPDIR:-/tmp}/conjure-gitdelta.ini" + done < "${TMPDIR:-/tmp}/cmuxup-gitdelta.ini" git config --global core.pager "delta" git config --global interactive.diffFilter "delta --color-only" git config --global delta.navigate true @@ -218,30 +218,30 @@ fi # Write cmux.json settings if not already customized. CMUX_JSON="${HOME}/.config/cmux/cmux.json" if [ -f "$CMUX_JSON" ] && grep -q '"diffViewer"' "$CMUX_JSON" 2>/dev/null; then - _skip "cmux.json already has conjure settings" + _skip "cmux.json already has cmuxup settings" else _apply_template "$TEMPLATES/cmux-settings.jsonc" "$CMUX_JSON" "$THEME" "$FONT_SIZE" "$DELTA_THEME" "$HELIX_THEME" fi -# ── Install conjure command ──────────────────────────────────────────────────── +# ── Install cmuxup command ──────────────────────────────────────────────────── echo "" -_log "Installing conjure command..." +_log "Installing cmuxup command..." INSTALL_DIR="${HOME}/.local/bin" if [ "$DRY_RUN" -eq 1 ]; then - _dry "would install conjure to $INSTALL_DIR/conjure" + _dry "would install cmuxup to $INSTALL_DIR/cmuxup" else mkdir -p "$INSTALL_DIR" - cp "$SCRIPT_DIR/bin/conjure" "$INSTALL_DIR/conjure" - chmod +x "$INSTALL_DIR/conjure" - _ok "installed conjure to $INSTALL_DIR/conjure" + cp "$SCRIPT_DIR/bin/cmuxup" "$INSTALL_DIR/cmuxup" + chmod +x "$INSTALL_DIR/cmuxup" + _ok "installed cmuxup to $INSTALL_DIR/cmuxup" fi # ── Shell integration ───────────────────────────────────────────────────────── ZSHRC="${HOME}/.zshrc" SHELL_BLOCK=' -# ── cmux-conjure shell integration ────────────────────────────────────────── +# ── cmuxup shell integration ────────────────────────────────────────── export EDITOR="hx" export VISUAL="hx" eval "$(zoxide init zsh)" @@ -257,11 +257,11 @@ function y() { } alias lg="lazygit" alias e="hx" -# ── end cmux-conjure ─────────────────────────────────────────────────────────' +# ── end cmuxup ─────────────────────────────────────────────────────────' if [ "$DRY_RUN" -eq 1 ]; then _dry "would append shell integration to $ZSHRC" -elif grep -q "cmux-conjure shell integration" "$ZSHRC" 2>/dev/null; then +elif grep -q "cmuxup shell integration" "$ZSHRC" 2>/dev/null; then _skip "shell integration already in $ZSHRC" else echo "$SHELL_BLOCK" >> "$ZSHRC" @@ -271,10 +271,10 @@ fi # ── Done ────────────────────────────────────────────────────────────────────── echo "" -if command -v gum >/dev/null 2>&1 && [ "$DRY_RUN" -eq 0 ] && [ "${CONJURE_NON_INTERACTIVE:-0}" != "1" ]; then - gum style --foreground 212 --bold "conjure is ready." - gum style "Open a new shell and run: conjure ~/your-project" +if command -v gum >/dev/null 2>&1 && [ "$DRY_RUN" -eq 0 ] && [ "${CMUXUP_NON_INTERACTIVE:-0}" != "1" ]; then + gum style --foreground 212 --bold "cmuxup is ready." + gum style "Open a new shell and run: cmuxup ~/your-project" else - echo "conjure is ready." - echo "Open a new shell and run: conjure ~/your-project" + echo "cmuxup is ready." + echo "Open a new shell and run: cmuxup ~/your-project" fi diff --git a/templates/ghostty.config b/templates/ghostty.config index b0a21c3..8e53b9d 100644 --- a/templates/ghostty.config +++ b/templates/ghostty.config @@ -1,4 +1,4 @@ -# Ghostty terminal config — managed by cmux-conjure +# Ghostty terminal config — managed by cmuxup # Edit manually or re-run install.sh to regenerate. # After editing: cmux reload-config diff --git a/templates/helix.toml b/templates/helix.toml index 71d2c8b..f583221 100644 --- a/templates/helix.toml +++ b/templates/helix.toml @@ -1,4 +1,4 @@ -# Helix editor config — managed by cmux-conjure +# Helix editor config — managed by cmuxup theme = "{{HELIX_THEME}}" [editor] diff --git a/templates/lazygit.yml b/templates/lazygit.yml index 697e4a8..1207d81 100644 --- a/templates/lazygit.yml +++ b/templates/lazygit.yml @@ -1,4 +1,4 @@ -# lazygit config — managed by cmux-conjure +# lazygit config — managed by cmuxup git: paging: colorArg: always diff --git a/templates/yazi.toml b/templates/yazi.toml index 035f45e..97f66db 100644 --- a/templates/yazi.toml +++ b/templates/yazi.toml @@ -1,4 +1,4 @@ -# yazi file manager config — managed by cmux-conjure +# yazi file manager config — managed by cmuxup [mgr] ratio = [1, 3, 4] sort_by = "natural" diff --git a/test/conjure.bats b/test/cmuxup.bats similarity index 76% rename from test/conjure.bats rename to test/cmuxup.bats index 93eecdf..dba5843 100644 --- a/test/conjure.bats +++ b/test/cmuxup.bats @@ -1,10 +1,10 @@ #!/usr/bin/env bats -# Tests for bin/conjure — run with: bats test/conjure.bats +# Tests for bin/cmuxup — run with: bats test/cmuxup.bats -CONJURE="$BATS_TEST_DIRNAME/../bin/conjure" +CONJURE="$BATS_TEST_DIRNAME/../bin/cmuxup" setup() { - # Prepend mock cmux to PATH so conjure never touches the real cmux socket. + # Prepend mock cmux to PATH so cmuxup never touches the real cmux socket. export PATH="$BATS_TEST_DIRNAME/bin:$PATH" export CMUX_QUIET=1 # Clean up mock call log before each test. @@ -12,28 +12,28 @@ setup() { } # ── 1. --help ───────────────────────────────────────────────────────────────── -@test "conjure --help exits 0 and shows Usage" { +@test "cmuxup --help exits 0 and shows Usage" { run "$CONJURE" --help [ "$status" -eq 0 ] [[ "$output" == *"Usage"* ]] } # ── 2. --version ────────────────────────────────────────────────────────────── -@test "conjure --version exits 0 and prints a semver" { +@test "cmuxup --version exits 0 and prints a semver" { run "$CONJURE" --version [ "$status" -eq 0 ] [[ "$output" =~ [0-9]+\.[0-9]+\.[0-9]+ ]] } # ── 3. bad directory ────────────────────────────────────────────────────────── -@test "conjure /nonexistent exits 1 with error on stderr" { - run "$CONJURE" /this-does-not-exist-cmux-conjure +@test "cmuxup /nonexistent exits 1 with error on stderr" { + run "$CONJURE" /this-does-not-exist-cmuxup [ "$status" -eq 1 ] [[ "$stderr" == *"not a directory"* ]] || [[ "$output" == *"not a directory"* ]] } # ── 4. calls new-workspace with correct --cwd ───────────────────────────────── -@test "conjure calls cmux new-workspace with --cwd set to project dir" { +@test "cmuxup calls cmux new-workspace with --cwd set to project dir" { TMPDIR_PROJ="$(mktemp -d)" run "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] @@ -44,7 +44,7 @@ setup() { } # ── 5. calls new-split right ────────────────────────────────────────────────── -@test "conjure calls cmux new-split right for the git/editor pane" { +@test "cmuxup calls cmux new-split right for the git/editor pane" { TMPDIR_PROJ="$(mktemp -d)" run "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] @@ -53,7 +53,7 @@ setup() { } # ── 6. calls new-split down ─────────────────────────────────────────────────── -@test "conjure calls cmux new-split down for the dev terminal pane" { +@test "cmuxup calls cmux new-split down for the dev terminal pane" { TMPDIR_PROJ="$(mktemp -d)" run "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] @@ -62,7 +62,7 @@ setup() { } # ── 7. calls new-surface --pane for the helix tab ───────────────────────────── -@test "conjure calls cmux new-surface --type terminal --pane for helix tab" { +@test "cmuxup calls cmux new-surface --type terminal --pane for helix tab" { TMPDIR_PROJ="$(mktemp -d)" run "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] @@ -72,7 +72,7 @@ setup() { } # ── 8. renames both tabs ────────────────────────────────────────────────────── -@test "conjure renames tabs to lazygit and helix" { +@test "cmuxup renames tabs to lazygit and helix" { TMPDIR_PROJ="$(mktemp -d)" run "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] @@ -83,7 +83,7 @@ setup() { } # ── 9. sends commands via send + send-key Enter ─────────────────────────────── -@test "conjure sends commands to panes via cmux send and send-key Enter" { +@test "cmuxup sends commands to panes via cmux send and send-key Enter" { TMPDIR_PROJ="$(mktemp -d)" run "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] @@ -93,10 +93,10 @@ setup() { rm -rf "$TMPDIR_PROJ" } -# ── 10. CONJURE_MAIN_CMD override ───────────────────────────────────────────── -@test "CONJURE_MAIN_CMD env override is used instead of claude" { +# ── 10. CMUXUP_MAIN_CMD override ───────────────────────────────────────────── +@test "CMUXUP_MAIN_CMD env override is used instead of claude" { TMPDIR_PROJ="$(mktemp -d)" - run env CONJURE_MAIN_CMD="my-custom-agent" "$CONJURE" "$TMPDIR_PROJ" + run env CMUXUP_MAIN_CMD="my-custom-agent" "$CONJURE" "$TMPDIR_PROJ" [ "$status" -eq 0 ] grep -q "my-custom-agent" "${BATS_TMPDIR}/cmux_calls" rm -rf "$TMPDIR_PROJ" diff --git a/test/install.bats b/test/install.bats index cebe150..8c77968 100644 --- a/test/install.bats +++ b/test/install.bats @@ -4,11 +4,11 @@ INSTALL="$BATS_TEST_DIRNAME/../install.sh" setup() { - export CONJURE_NON_INTERACTIVE=1 - export CONJURE_THEME="Catppuccin Mocha" - export CONJURE_FONT_SIZE="14" - export CONJURE_AGENT="claude" - export CONJURE_EDITOR="helix" + export CMUXUP_NON_INTERACTIVE=1 + export CMUXUP_THEME="Catppuccin Mocha" + export CMUXUP_FONT_SIZE="14" + export CMUXUP_AGENT="claude" + export CMUXUP_EDITOR="helix" # Use an isolated HOME so we never touch the real ~/.gitconfig etc. export HOME="$(mktemp -d)" mkdir -p "$HOME/.local/bin" @@ -43,19 +43,19 @@ teardown() { rm "$TMPL" } -# ── 4. installs conjure to ~/.local/bin ─────────────────────────────────────── -@test "install.sh --dry-run reports it would install conjure to ~/.local/bin" { +# ── 4. installs cmuxup to ~/.local/bin ─────────────────────────────────────── +@test "install.sh --dry-run reports it would install cmuxup to ~/.local/bin" { run bash "$INSTALL" --dry-run [ "$status" -eq 0 ] # dry-run should mention the install path - [[ "$output" == *"local/bin"* ]] || [[ "$output" == *"conjure"* ]] + [[ "$output" == *"local/bin"* ]] || [[ "$output" == *"cmuxup"* ]] } # ── 5. does not overwrite existing ghostty config without confirmation ───────── @test "install.sh skips ghostty config when it already exists and not confirmed" { mkdir -p "$HOME/.config/ghostty" echo "existing-content" > "$HOME/.config/ghostty/config" - # Non-interactive mode with CONJURE_OVERWRITE unset should not overwrite. + # Non-interactive mode with CMUXUP_OVERWRITE unset should not overwrite. run bash "$INSTALL" --dry-run [ "$status" -eq 0 ] # File should still have original content.