Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
# SPDX-License-Identifier: Apache-2.0

.DEFAULT_GOAL := help
.PHONY: help install-linux install-linux-dry-run uninstall-linux
.PHONY: help install-linux install-linux-dry-run uninstall-linux install-macos install-macos-dry-run uninstall-macos

help:
@echo "install-linux Install the systemd user service and Codex profile"
@echo "install-linux-dry-run Preview installation without changes"
@echo "uninstall-linux Remove the service and Codex profile"
@echo "install-macos Install the background server"
@echo "install-macos-dry-run Preview installation without changes"
@echo "uninstall-macos Remove the LaunchAgents and Codex profile"

## Install the Switchyard background server as a systemd user service.
install-linux:
Expand All @@ -20,3 +23,15 @@ install-linux-dry-run:
## Remove the systemd user service, the sy Codex profile, and the codex alias.
uninstall-linux:
@scripts/linux/uninstall.sh

## Install the Switchyard background server for this user.
install-macos:
@scripts/macos/install.sh

## Print what install-macos would do, without changing anything.
install-macos-dry-run:
@scripts/macos/install.sh --dry-run

## Remove the LaunchAgent, the sy Codex profile, and the codex alias.
uninstall-macos:
@scripts/macos/uninstall.sh
117 changes: 117 additions & 0 deletions scripts/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

SY_HOME="${SY_HOME:-$HOME/.switchyard}"
SY_PORT="${SY_PORT:-4123}"
CODEX_DIR="${CODEX_HOME:-$HOME/.codex}"
# Both installers use Codex's standalone profile file for the CLI.
CODEX_PROFILE_CONFIG="$CODEX_DIR/sy.config.toml"
ALIAS_START="# >>> switchyard codex alias >>>"
ALIAS_END="# <<< switchyard codex alias <<<"

say() { printf '%s\n' "$*"; }
step() { printf '\n==> %s\n' "$*"; }

strip_block() {
local path="$1" start="$2" end="$3" label="${4:-the switchyard block}"
if [[ ! -f "$path" ]] || ! grep -qF "$start" "$path"; then
return 1
fi
if ! grep -qF "$end" "$path"; then
say " $path has no end marker for $label; not editing it" >&2
return 1
fi
if (( DRY_RUN )); then
say " would remove $label from $path"
return 0
fi
local temp
temp="$(mktemp)"
awk -v start="$start" -v end="$end" '
index($0, start) { skipping = 1 }
!skipping { print }
index($0, end) { skipping = 0 }
END { if (skipping) exit 1 }
' "$path" > "$temp"
cat "$temp" > "$path"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
rm -f "$temp"
say " removed $label from $path"
return 0
}

run() {
if (( DRY_RUN )); then
say " would run: $*"
else
"$@"
fi
}

write_once() {
local path="$1"
if [[ -f "$path" ]]; then
say " keeping existing $path"
cat >/dev/null
return
fi
if (( DRY_RUN )); then
say " would create $path"
cat >/dev/null
else
mkdir -p "$(dirname "$path")"
cat > "$path"
say " created $path"
fi
}

write_with_backup() {
local path="$1"
if (( DRY_RUN )); then
[[ -f "$path" ]] && say " would back up $path"
say " would write $path"
cat >/dev/null
return
fi
mkdir -p "$(dirname "$path")"
local incoming
incoming="$(mktemp)"
cat > "$incoming"
if [[ -f "$path" ]] && cmp -s "$incoming" "$path"; then
say " $path is already up to date"
rm -f "$incoming"
return
fi
if [[ -f "$path" ]]; then
local backup
backup="$path.switchyard-backup.$(date +%Y%m%d%H%M%S)"
cp "$path" "$backup"
say " backed up $path to $backup"
fi
cat "$incoming" > "$path"
rm -f "$incoming"
say " wrote $path"
}

write_always() {
local path="$1"
if (( DRY_RUN )); then
say " would write $path"
cat >/dev/null
else
mkdir -p "$(dirname "$path")"
cat > "$path"
say " wrote $path"
fi
}

remove_file() {
local path="$1"
if [[ ! -e "$path" ]]; then
say " nothing to remove at $path"
elif (( DRY_RUN )); then
say " would delete $path"
else
rm -f "$path"
say " deleted $path"
fi
}
43 changes: 2 additions & 41 deletions scripts/linux/common.sh
Original file line number Diff line number Diff line change
@@ -1,47 +1,8 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Paths, markers, and helpers shared by install.sh and uninstall.sh.
# The markers must match between the two, which is why they live here.
# shellcheck source=scripts/common.sh
source "$(dirname "${BASH_SOURCE[0]}")/../common.sh"

SY_HOME="${SY_HOME:-$HOME/.switchyard}"
SY_PORT="${SY_PORT:-4123}"
SERVICE_NAME="switchyard.service"
SYSTEMD_USER_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
CODEX_DIR="${CODEX_HOME:-$HOME/.codex}"
# Since Codex 0.134.0, `--profile sy` reads sy.config.toml and fails if
# config.toml still has [profiles.sy].
CODEX_PROFILE_CONFIG="$CODEX_DIR/sy.config.toml"
ALIAS_START="# >>> switchyard codex alias >>>"
ALIAS_END="# <<< switchyard codex alias <<<"

say() { printf '%s\n' "$*"; }
step() { printf '\n==> %s\n' "$*"; }

# Deletes the marked block, inclusive, leaving the rest of the file alone.
strip_block() {
local path="$1" start="$2" end="$3" label="${4:-the switchyard block}"
if [[ ! -f "$path" ]] || ! grep -qF "$start" "$path"; then
return 1
fi
if ! grep -qF "$end" "$path"; then
say " $path has no end marker for $label; not editing it" >&2
return 1
fi
if (( DRY_RUN )); then
say " would remove $label from $path"
return 0
fi
local temp
temp="$(mktemp)"
awk -v start="$start" -v end="$end" '
index($0, start) { skipping = 1 }
!skipping { print }
index($0, end) { skipping = 0 }
END { if (skipping) exit 1 }
' "$path" > "$temp"
cat "$temp" > "$path"
rm -f "$temp"
say " removed $label from $path"
return 0
}
69 changes: 0 additions & 69 deletions scripts/linux/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,75 +34,6 @@ if [[ ! "$SY_PORT" =~ ^[0-9]+$ ]]; then
exit 1
fi

# Runs a command, or prints it when dry running.
run() {
if (( DRY_RUN )); then
say " would run: $*"
else
"$@"
fi
}

# Writes stdin to a file, leaving an existing file untouched.
write_once() {
local path="$1"
if [[ -f "$path" ]]; then
say " keeping existing $path"
cat >/dev/null
return
fi
if (( DRY_RUN )); then
say " would create $path"
cat >/dev/null
else
mkdir -p "$(dirname "$path")"
cat > "$path"
say " created $path"
fi
}

# Writes stdin to a file, keeping any existing version as a timestamped backup.
write_with_backup() {
local path="$1"
if (( DRY_RUN )); then
[[ -f "$path" ]] && say " would back up $path"
say " would write $path"
cat >/dev/null
return
fi
mkdir -p "$(dirname "$path")"
local incoming
incoming="$(mktemp)"
cat > "$incoming"
if [[ -f "$path" ]] && cmp -s "$incoming" "$path"; then
say " $path is already up to date"
rm -f "$incoming"
return
fi
if [[ -f "$path" ]]; then
local backup
backup="$path.switchyard-backup.$(date +%Y%m%d%H%M%S)"
cp "$path" "$backup"
say " backed up $path to $backup"
fi
cat "$incoming" > "$path"
rm -f "$incoming"
say " wrote $path"
}

# Writes stdin to a file, replacing it. Used only for files this script owns.
write_always() {
local path="$1"
if (( DRY_RUN )); then
say " would write $path"
cat >/dev/null
else
mkdir -p "$(dirname "$path")"
cat > "$path"
say " wrote $path"
fi
}

if [[ "$(uname -s)" != "Linux" ]]; then
say "This installer is for Linux only." >&2
exit 1
Expand Down
13 changes: 0 additions & 13 deletions scripts/linux/uninstall.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,6 @@ esac
# shellcheck source=scripts/linux/common.sh
source "$SCRIPT_DIR/common.sh"

# Deletes a file this script owns.
remove_file() {
local path="$1"
if [[ ! -e "$path" ]]; then
say " nothing to remove at $path"
elif (( DRY_RUN )); then
say " would delete $path"
else
rm -f "$path"
say " deleted $path"
fi
}

step "Removing the sy Codex profile"
remove_file "$CODEX_PROFILE_CONFIG"

Expand Down
26 changes: 26 additions & 0 deletions scripts/macos/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Paths, markers, and helpers shared by install.sh and uninstall.sh.
# The markers must match between the two, which is why they live here.

# shellcheck source=scripts/common.sh
source "$(dirname "${BASH_SOURCE[0]}")/../common.sh"

SERVER_LABEL="com.nvidia.switchyard.server"
LAUNCH_AGENTS="$HOME/Library/LaunchAgents"
CODEX_CONFIG="$CODEX_DIR/config.toml"
# Codex reads `--profile sy` from its own file next to config.toml. A
# [profiles.sy] table in config.toml is rejected outright as legacy config.
# Codex.app ignores profiles entirely, so it gets a whole config.toml with the
# routing inlined. Keep the generated file beside the original for reference.
CODEX_SWITCHYARD_CONFIG="$CODEX_DIR/config.sy.toml"
CODEX_DIRECT_CONFIG="$CODEX_DIR/config.toml.direct"
PROFILE_START="# >>> switchyard sy profile >>>"
PROFILE_END="# <<< switchyard sy profile <<<"

codex_config_uses_switchyard() {
local path="$1"
[[ -f "$path" ]] || return 1
grep -Fq '[model_providers.sy]' "$path"
}
Loading
Loading