From bc915481f6b55c5d52956043183b62a34fefd180 Mon Sep 17 00:00:00 2001 From: Corwin Marsh Date: Wed, 20 May 2026 11:18:38 -0700 Subject: [PATCH] Remove legacy rename aliases --- README.md | 38 +-- bin/opencode-tmux | 13 - coding-agents-tmux.tmux | 266 ++++++++------------ docs/remove-legacy-name-plan.md | 49 ++++ docs/rename-coding-agents-tmux-migration.md | 225 ++--------------- docs/rename-coding-agents-tmux.md | 8 +- opencode-tmux.tmux | 6 - package-lock.json | 3 +- package.json | 3 +- plugin/coding-agents-tmux.ts | 3 - plugin/opencode-tmux.ts | 1 - plugin/pi-tmux.ts | 1 - scripts/shfmt.mjs | 1 - scripts/sync-tmux-plugin.sh | 12 +- src/cli.ts | 19 +- src/cli/render.ts | 36 +-- src/core/claude.ts | 6 +- src/core/codex.ts | 6 +- src/core/opencode.ts | 23 +- src/core/pi.ts | 6 +- src/naming.ts | 39 +-- test/cli.test.ts | 41 +-- test/codex.test.ts | 87 +++---- test/opencode.test.ts | 65 ++--- test/pi-plugin.test.ts | 13 +- test/pi.test.ts | 36 +-- test/plugin.test.ts | 42 +--- test/render.test.ts | 6 +- test/tmux-plugin-rename.test.ts | 36 +-- test/tmux.test.ts | 2 +- 30 files changed, 338 insertions(+), 754 deletions(-) delete mode 100755 bin/opencode-tmux create mode 100644 docs/remove-legacy-name-plan.md delete mode 100755 opencode-tmux.tmux delete mode 100644 plugin/opencode-tmux.ts diff --git a/README.md b/README.md index 2d0b9d9..f25c220 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,7 @@ Today the strongest runtime support is still for `opencode`, and the project als ## Rename status -This project is being renamed from `opencode-tmux` to `coding-agents-tmux`. - -In this update: - -- **preferred public name:** `coding-agents-tmux` -- **temporary compatibility aliases:** `opencode-tmux`, `@opencode-tmux-*`, and `OPENCODE_TMUX_*` - -The legacy names still work for now, but they are transition aliases and are not intended to stay forever. +This project was previously named `opencode-tmux`. The current public name is `coding-agents-tmux`. ## Install @@ -79,27 +72,18 @@ Requirements: With the recommended settings above, the tmux plugin manages the bundled `opencode` plugin, the Pi extension, and the Codex and Claude hook installs for you. -It installs the bundled `opencode` plugin by creating these symlinks: +It installs the bundled `opencode` plugin at: ```text ~/.config/opencode/plugins/coding-agents-tmux.ts -~/.config/opencode/plugins/opencode-tmux.ts ``` -The new path is preferred. The legacy path is kept as a temporary compatibility alias. - That plugin publishes normalized session state files under: ```text ~/.local/state/coding-agents-tmux/plugin-state ``` -The runtime also continues reading legacy state under: - -```text -~/.local/state/opencode-tmux/plugin-state -``` - On first install, the tmux plugin also bootstraps the CLI runtime dependencies inside: ```text @@ -112,24 +96,12 @@ It also installs or updates the bundled Pi extension under: ~/.pi/agent/extensions/coding-agents-tmux/index.ts ``` -The legacy extension path is also kept during the transition: - -```text -~/.pi/agent/extensions/opencode-tmux/index.ts -``` - That extension publishes normalized Pi state files under: ```text ~/.local/state/coding-agents-tmux/pi-state ``` -The runtime also continues reading legacy Pi state under: - -```text -~/.local/state/opencode-tmux/pi-state -``` - It also installs or updates Codex hook integration under: ```text @@ -290,8 +262,6 @@ set -ag status-right " #[fg=colour81]󰚩 #[default]#{@coding-agents-tmux-status `manual` mode is the default. `#{E:@catppuccin_status_agents}` gives Catppuccin users a native-looking module, `#{@coding-agents-tmux-status-inline-format}` gives other themes a tone-aware inline segment, and `#{@coding-agents-tmux-status-text}` gives a plain live summary text export for fully custom wrappers. `append` mode restores the old behavior and appends automatically. -`@catppuccin_status_opencode` still works as a compatibility alias for now. - ## Configuration Available tmux options: @@ -323,8 +293,6 @@ Available tmux options: - `@coding-agents-tmux-status-color-waiting` tmux color for waiting state, default `colour196` - `@coding-agents-tmux-status-color-unknown` tmux color for unknown/none state, default `colour244` -Legacy `@opencode-tmux-*` tmux options still work for now as transition aliases. - ## Providers Recommended provider: @@ -484,5 +452,3 @@ Useful commands: ./bin/coding-agents-tmux status --provider plugin --style tmux ./bin/coding-agents-tmux tmux-config --provider plugin ``` - -The legacy `./bin/opencode-tmux` alias still works for now during the rename transition. diff --git a/bin/opencode-tmux b/bin/opencode-tmux deleted file mode 100755 index b90e7ec..0000000 --- a/bin/opencode-tmux +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -CLI="$CURRENT_DIR/bin/coding-agents-tmux" - -if [ ! -f "$CLI" ]; then - printf 'opencode-tmux: missing CLI alias target at %s\n' "$CLI" >&2 - exit 1 -fi - -exec "$CLI" "$@" diff --git a/coding-agents-tmux.tmux b/coding-agents-tmux.tmux index f39cacd..318e4da 100755 --- a/coding-agents-tmux.tmux +++ b/coding-agents-tmux.tmux @@ -16,43 +16,6 @@ get_tmux_option() { fi } -get_tmux_option_alias() { - local preferred_option="$1" - local legacy_option="$2" - local default_value="$3" - local value - - value="$(tmux show-option -gqv "$preferred_option")" - if [ -n "$value" ]; then - printf '%s' "$value" - return - fi - - value="$(tmux show-option -gqv "$legacy_option")" - if [ -n "$value" ]; then - printf '%s' "$value" - else - printf '%s' "$default_value" - fi -} - -set_tmux_option_alias() { - local preferred_option="$1" - local legacy_option="$2" - local value="$3" - - tmux set-option -gq "$preferred_option" "$value" - tmux set-option -gq "$legacy_option" "$value" -} - -unset_tmux_option_alias() { - local preferred_option="$1" - local legacy_option="$2" - - tmux set-option -gu "$preferred_option" - tmux set-option -gu "$legacy_option" -} - shell_escape() { printf "'%s'" "${1//\'/\'\\\'\'}" } @@ -111,21 +74,21 @@ configure_catppuccin_status_module() { local module if [ -z "$text_segment" ] || ! catppuccin_loaded; then - unset_tmux_option_alias '@catppuccin_agents_icon' '@catppuccin_opencode_icon' - unset_tmux_option_alias '@catppuccin_agents_color' '@catppuccin_opencode_color' - unset_tmux_option_alias '@catppuccin_agents_text' '@catppuccin_opencode_text' - unset_tmux_option_alias '@catppuccin_status_agents_icon_fg' '@catppuccin_status_opencode_icon_fg' - unset_tmux_option_alias '@catppuccin_status_agents_icon_bg' '@catppuccin_status_opencode_icon_bg' - unset_tmux_option_alias '@catppuccin_status_agents_text_fg' '@catppuccin_status_opencode_text_fg' - unset_tmux_option_alias '@catppuccin_status_agents_text_bg' '@catppuccin_status_opencode_text_bg' - unset_tmux_option_alias '@catppuccin_status_agents' '@catppuccin_status_opencode' + tmux set-option -gu '@catppuccin_agents_icon' + tmux set-option -gu '@catppuccin_agents_color' + tmux set-option -gu '@catppuccin_agents_text' + tmux set-option -gu '@catppuccin_status_agents_icon_fg' + tmux set-option -gu '@catppuccin_status_agents_icon_bg' + tmux set-option -gu '@catppuccin_status_agents_text_fg' + tmux set-option -gu '@catppuccin_status_agents_text_bg' + tmux set-option -gu '@catppuccin_status_agents' return fi - set_tmux_option_alias '@catppuccin_agents_icon' '@catppuccin_opencode_icon' "$prefix " + tmux set-option -gq '@catppuccin_agents_icon' "$prefix " accent_format="#{?#{==:#{E:@coding-agents-tmux-status-tone},waiting},$waiting_color,#{?#{==:#{E:@coding-agents-tmux-status-tone},idle},$idle_color,#{?#{==:#{E:@coding-agents-tmux-status-tone},unknown},$unknown_color,$accent_color}}}" - set_tmux_option_alias '@catppuccin_agents_color' '@catppuccin_opencode_color' "$accent_format" - set_tmux_option_alias '@catppuccin_agents_text' '@catppuccin_opencode_text' "$text_segment" + tmux set-option -gq '@catppuccin_agents_color' "$accent_format" + tmux set-option -gq '@catppuccin_agents_text' "$text_segment" left_separator="$(tmux show-option -gqv @catppuccin_status_left_separator)" right_separator="$(tmux show-option -gqv @catppuccin_status_right_separator)" @@ -148,17 +111,17 @@ configure_catppuccin_status_module() { connect_style='' fi - set_tmux_option_alias '@catppuccin_status_agents_icon_fg' '@catppuccin_status_opencode_icon_fg' "$theme_crust" - set_tmux_option_alias '@catppuccin_status_agents_icon_bg' '@catppuccin_status_opencode_icon_bg' "$accent_format" - set_tmux_option_alias '@catppuccin_status_agents_text_fg' '@catppuccin_status_opencode_text_fg' "$theme_fg" - set_tmux_option_alias '@catppuccin_status_agents_text_bg' '@catppuccin_status_opencode_text_bg' "$module_text_bg" + tmux set-option -gq '@catppuccin_status_agents_icon_fg' "$theme_crust" + tmux set-option -gq '@catppuccin_status_agents_icon_bg' "$accent_format" + tmux set-option -gq '@catppuccin_status_agents_text_fg' "$theme_fg" + tmux set-option -gq '@catppuccin_status_agents_text_bg' "$module_text_bg" module="#[fg=#{E:@catppuccin_status_agents_icon_bg},nobold,nounderscore,noitalics]$connect_style$left_separator" module="$module#[fg=#{E:@catppuccin_status_agents_icon_fg},bg=#{E:@catppuccin_status_agents_icon_bg}]${prefix} " module="$module$middle_separator" module="$module#[fg=#{E:@catppuccin_status_agents_text_fg},bg=#{E:@catppuccin_status_agents_text_bg}] #{E:@catppuccin_agents_text}" module="$module#[fg=#{E:@catppuccin_status_agents_text_bg}]$connect_style$right_separator" - set_tmux_option_alias '@catppuccin_status_agents' '@catppuccin_status_opencode' "$module" + tmux set-option -gq '@catppuccin_status_agents' "$module" } remove_status_segment() { @@ -235,20 +198,6 @@ normalize_toggle() { esac } -tmux_option_alias_is_set() { - local preferred_option="$1" - local legacy_option="$2" - local value - - value="$(tmux show-option -gqv "$preferred_option")" - if [ -n "$value" ]; then - return 0 - fi - - value="$(tmux show-option -gqv "$legacy_option")" - [ -n "$value" ] -} - normalize_auto_install_value() { local value lowered value="${1// /}" @@ -293,14 +242,13 @@ unbind_key_if_set() { } store_bound_key() { - local preferred_option_name="$1" - local legacy_option_name="$2" - local key="$3" + local option_name="$1" + local key="$2" if [ -n "$key" ]; then - set_tmux_option_alias "$preferred_option_name" "$legacy_option_name" "$key" + tmux set-option -gq "$option_name" "$key" else - unset_tmux_option_alias "$preferred_option_name" "$legacy_option_name" + tmux set-option -gu "$option_name" fi } @@ -374,9 +322,9 @@ install_cli_dependencies() { local install_command if [ -f "$CURRENT_DIR/package-lock.json" ] && command -v npm >/dev/null 2>&1; then - install_command="npm ci --omit=dev" + install_command="npm ci --omit=dev --ignore-scripts" elif command -v npm >/dev/null 2>&1; then - install_command="npm install --omit=dev" + install_command="npm install --omit=dev --ignore-scripts" else tmux display-message "coding-agents-tmux: npm is required to install CLI dependencies" return 1 @@ -404,12 +352,10 @@ install_opencode_plugin() { config_root="${XDG_CONFIG_HOME:-$HOME/.config}" plugin_dir="$config_root/opencode/plugins" plugin_target="$plugin_dir/coding-agents-tmux.ts" - legacy_plugin_target="$plugin_dir/opencode-tmux.ts" mkdir -p "$plugin_dir" ln -sfn "$plugin_source" "$plugin_target" - ln -sfn "$plugin_source" "$legacy_plugin_target" - set_tmux_option_alias '@coding-agents-tmux-plugin-path' '@opencode-tmux-plugin-path' "$plugin_target" + tmux set-option -gq '@coding-agents-tmux-plugin-path' "$plugin_target" } install_codex_hooks() { @@ -425,7 +371,7 @@ install_claude_hooks() { } install_pi_extension() { - local extension_source pi_dir extension_dir extension_target legacy_extension_dir legacy_extension_target existing_target installed_changed + local extension_source pi_dir extension_dir extension_target existing_target installed_changed extension_source="$CURRENT_DIR/plugin/pi-tmux.ts" @@ -437,8 +383,6 @@ install_pi_extension() { pi_dir="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}" extension_dir="$pi_dir/extensions/coding-agents-tmux" extension_target="$extension_dir/index.ts" - legacy_extension_dir="$pi_dir/extensions/opencode-tmux" - legacy_extension_target="$legacy_extension_dir/index.ts" existing_target="$(readlink "$extension_target" 2>/dev/null || true)" installed_changed='off' @@ -447,10 +391,8 @@ install_pi_extension() { fi mkdir -p "$extension_dir" - mkdir -p "$legacy_extension_dir" ln -sfn "$extension_source" "$extension_target" - ln -sfn "$extension_source" "$legacy_extension_target" - set_tmux_option_alias '@coding-agents-tmux-pi-extension-path' '@opencode-tmux-pi-extension-path' "$extension_target" + tmux set-option -gq '@coding-agents-tmux-pi-extension-path' "$extension_target" if [ "$installed_changed" = 'on' ]; then tmux display-message "coding-agents-tmux: Pi extension installed; restart Pi sessions to load it" @@ -461,18 +403,18 @@ main() { local menu_key popup_key waiting_menu_key waiting_popup_key provider server_map popup_filter popup_width popup_height popup_title status_enabled status_style status_position status_option status_interval status_mode install_plugin install_codex install_pi install_claude auto_install_value status_text_segment status_inline_segment status_tone_segment status_refresh_command local status_prefix status_color_neutral status_color_busy status_color_waiting status_color_idle status_color_unknown local previous_status_segment previous_status_option previous_menu_key previous_popup_key previous_waiting_menu_key previous_waiting_popup_key - menu_key="$(normalize_binding_key "$(get_tmux_option_alias '@coding-agents-tmux-menu-key' '@opencode-tmux-menu-key' 'O')")" - popup_key="$(normalize_binding_key "$(get_tmux_option_alias '@coding-agents-tmux-popup-key' '@opencode-tmux-popup-key' 'P')")" - waiting_menu_key="$(normalize_binding_key "$(get_tmux_option_alias '@coding-agents-tmux-waiting-menu-key' '@opencode-tmux-waiting-menu-key' 'W')")" - waiting_popup_key="$(normalize_binding_key "$(get_tmux_option_alias '@coding-agents-tmux-waiting-popup-key' '@opencode-tmux-waiting-popup-key' 'C-w')")" - provider="$(get_tmux_option_alias '@coding-agents-tmux-provider' '@opencode-tmux-provider' 'plugin')" - server_map="$(get_tmux_option_alias '@coding-agents-tmux-server-map' '@opencode-tmux-server-map' '')" - popup_filter="$(get_tmux_option_alias '@coding-agents-tmux-popup-filter' '@opencode-tmux-popup-filter' 'all')" - popup_width="$(get_tmux_option_alias '@coding-agents-tmux-popup-width' '@opencode-tmux-popup-width' '100%')" - popup_height="$(get_tmux_option_alias '@coding-agents-tmux-popup-height' '@opencode-tmux-popup-height' '100%')" - popup_title="$(get_tmux_option_alias '@coding-agents-tmux-popup-title' '@opencode-tmux-popup-title' 'Coding Agent Sessions')" - if tmux_option_alias_is_set '@coding-agents-tmux-auto-install' '@opencode-tmux-auto-install'; then - auto_install_value="$(normalize_auto_install_value "$(get_tmux_option_alias '@coding-agents-tmux-auto-install' '@opencode-tmux-auto-install' '')")" + menu_key="$(normalize_binding_key "$(get_tmux_option '@coding-agents-tmux-menu-key' 'O')")" + popup_key="$(normalize_binding_key "$(get_tmux_option '@coding-agents-tmux-popup-key' 'P')")" + waiting_menu_key="$(normalize_binding_key "$(get_tmux_option '@coding-agents-tmux-waiting-menu-key' 'W')")" + waiting_popup_key="$(normalize_binding_key "$(get_tmux_option '@coding-agents-tmux-waiting-popup-key' 'C-w')")" + provider="$(get_tmux_option '@coding-agents-tmux-provider' 'plugin')" + server_map="$(get_tmux_option '@coding-agents-tmux-server-map' '')" + popup_filter="$(get_tmux_option '@coding-agents-tmux-popup-filter' 'all')" + popup_width="$(get_tmux_option '@coding-agents-tmux-popup-width' '100%')" + popup_height="$(get_tmux_option '@coding-agents-tmux-popup-height' '100%')" + popup_title="$(get_tmux_option '@coding-agents-tmux-popup-title' 'Coding Agent Sessions')" + if [ -n "$(tmux show-option -gqv '@coding-agents-tmux-auto-install')" ]; then + auto_install_value="$(normalize_auto_install_value "$(get_tmux_option '@coding-agents-tmux-auto-install' '')")" case "$auto_install_value" in auto) @@ -511,28 +453,28 @@ main() { ;; esac else - install_plugin="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-opencode-plugin' '@opencode-tmux-install-opencode-plugin' 'on')")" - install_codex="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-codex-hooks' '@opencode-tmux-install-codex-hooks' 'on')")" - install_pi="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-pi-extension' '@opencode-tmux-install-pi-extension' 'on')")" - install_claude="$(normalize_toggle "$(get_tmux_option_alias '@coding-agents-tmux-install-claude-hooks' '@opencode-tmux-install-claude-hooks' 'off')")" - fi - status_enabled="$(get_tmux_option_alias '@coding-agents-tmux-status' '@opencode-tmux-status' 'on')" - status_style="$(get_tmux_option_alias '@coding-agents-tmux-status-style' '@opencode-tmux-status-style' 'tmux')" - status_position="$(get_tmux_option_alias '@coding-agents-tmux-status-position' '@opencode-tmux-status-position' 'right')" - status_mode="$(normalize_status_mode "$(get_tmux_option_alias '@coding-agents-tmux-status-mode' '@opencode-tmux-status-mode' 'manual')")" - status_interval="$(get_tmux_option_alias '@coding-agents-tmux-status-interval' '@opencode-tmux-status-interval' '0')" - status_prefix="$(get_tmux_option_alias '@coding-agents-tmux-status-prefix' '@opencode-tmux-status-prefix' '󰚩')" - status_color_neutral="$(get_tmux_option_alias '@coding-agents-tmux-status-color-neutral' '@opencode-tmux-status-color-neutral' 'colour252')" - status_color_busy="$(get_tmux_option_alias '@coding-agents-tmux-status-color-busy' '@opencode-tmux-status-color-busy' 'colour220')" - status_color_waiting="$(get_tmux_option_alias '@coding-agents-tmux-status-color-waiting' '@opencode-tmux-status-color-waiting' 'colour196')" - status_color_idle="$(get_tmux_option_alias '@coding-agents-tmux-status-color-idle' '@opencode-tmux-status-color-idle' 'colour70')" - status_color_unknown="$(get_tmux_option_alias '@coding-agents-tmux-status-color-unknown' '@opencode-tmux-status-color-unknown' 'colour244')" - previous_status_segment="$(get_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' '')" - previous_status_option="$(get_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-right')" - previous_menu_key="$(get_tmux_option_alias '@coding-agents-tmux-bound-menu-key' '@opencode-tmux-bound-menu-key' '')" - previous_popup_key="$(get_tmux_option_alias '@coding-agents-tmux-bound-popup-key' '@opencode-tmux-bound-popup-key' '')" - previous_waiting_menu_key="$(get_tmux_option_alias '@coding-agents-tmux-bound-waiting-menu-key' '@opencode-tmux-bound-waiting-menu-key' '')" - previous_waiting_popup_key="$(get_tmux_option_alias '@coding-agents-tmux-bound-waiting-popup-key' '@opencode-tmux-bound-waiting-popup-key' '')" + install_plugin="$(normalize_toggle "$(get_tmux_option '@coding-agents-tmux-install-opencode-plugin' 'on')")" + install_codex="$(normalize_toggle "$(get_tmux_option '@coding-agents-tmux-install-codex-hooks' 'on')")" + install_pi="$(normalize_toggle "$(get_tmux_option '@coding-agents-tmux-install-pi-extension' 'on')")" + install_claude="$(normalize_toggle "$(get_tmux_option '@coding-agents-tmux-install-claude-hooks' 'off')")" + fi + status_enabled="$(get_tmux_option '@coding-agents-tmux-status' 'on')" + status_style="$(get_tmux_option '@coding-agents-tmux-status-style' 'tmux')" + status_position="$(get_tmux_option '@coding-agents-tmux-status-position' 'right')" + status_mode="$(normalize_status_mode "$(get_tmux_option '@coding-agents-tmux-status-mode' 'manual')")" + status_interval="$(get_tmux_option '@coding-agents-tmux-status-interval' '0')" + status_prefix="$(get_tmux_option '@coding-agents-tmux-status-prefix' '󰚩')" + status_color_neutral="$(get_tmux_option '@coding-agents-tmux-status-color-neutral' 'colour252')" + status_color_busy="$(get_tmux_option '@coding-agents-tmux-status-color-busy' 'colour220')" + status_color_waiting="$(get_tmux_option '@coding-agents-tmux-status-color-waiting' 'colour196')" + status_color_idle="$(get_tmux_option '@coding-agents-tmux-status-color-idle' 'colour70')" + status_color_unknown="$(get_tmux_option '@coding-agents-tmux-status-color-unknown' 'colour244')" + previous_status_segment="$(get_tmux_option '@coding-agents-tmux-status-segment' '')" + previous_status_option="$(get_tmux_option '@coding-agents-tmux-status-option' 'status-right')" + previous_menu_key="$(get_tmux_option '@coding-agents-tmux-bound-menu-key' '')" + previous_popup_key="$(get_tmux_option '@coding-agents-tmux-bound-popup-key' '')" + previous_waiting_menu_key="$(get_tmux_option '@coding-agents-tmux-bound-waiting-menu-key' '')" + previous_waiting_popup_key="$(get_tmux_option '@coding-agents-tmux-bound-waiting-popup-key' '')" status_option="$(normalize_status_option "$status_position")" if [ ! -f "$CURRENT_DIR/bin/coding-agents-tmux" ]; then @@ -631,10 +573,10 @@ main() { tmux bind-key "$waiting_popup_key" display-popup -E -w "$popup_width" -h "$popup_height" -T "$popup_title (Waiting)" "$waiting_switch_command" fi - store_bound_key '@coding-agents-tmux-bound-menu-key' '@opencode-tmux-bound-menu-key' "$menu_key" - store_bound_key '@coding-agents-tmux-bound-popup-key' '@opencode-tmux-bound-popup-key' "$popup_key" - store_bound_key '@coding-agents-tmux-bound-waiting-menu-key' '@opencode-tmux-bound-waiting-menu-key' "$waiting_menu_key" - store_bound_key '@coding-agents-tmux-bound-waiting-popup-key' '@opencode-tmux-bound-waiting-popup-key' "$waiting_popup_key" + store_bound_key '@coding-agents-tmux-bound-menu-key' "$menu_key" + store_bound_key '@coding-agents-tmux-bound-popup-key' "$popup_key" + store_bound_key '@coding-agents-tmux-bound-waiting-menu-key' "$waiting_menu_key" + store_bound_key '@coding-agents-tmux-bound-waiting-popup-key' "$waiting_popup_key" if [ -n "$previous_status_segment" ]; then remove_status_segment "$previous_status_option" "$previous_status_segment" @@ -647,58 +589,58 @@ main() { status_inline_segment="#($status_inline_command)" status_tone_segment="#($status_tone_command)" tmux set-option -g status-interval "$status_interval" - set_tmux_option_alias '@coding-agents-tmux-status-format' '@opencode-tmux-status-format' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-text' '@opencode-tmux-status-text' "$status_text_segment" - set_tmux_option_alias '@coding-agents-tmux-status-inline-format' '@opencode-tmux-status-inline-format' "$status_inline_segment" - set_tmux_option_alias '@coding-agents-tmux-status-tone' '@opencode-tmux-status-tone' "$status_tone_segment" + tmux set-option -gq '@coding-agents-tmux-status-format' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-text' "$status_text_segment" + tmux set-option -gq '@coding-agents-tmux-status-inline-format' "$status_inline_segment" + tmux set-option -gq '@coding-agents-tmux-status-tone' "$status_tone_segment" configure_catppuccin_status_module "$status_text_segment" "$status_prefix" "$status_color_busy" "$status_color_waiting" "$status_color_idle" "$status_color_unknown" configure_status_hooks "$status_refresh_command" tmux refresh-client -S >/dev/null 2>&1 || true if [ "$status_mode" = "append" ]; then append_status_segment "$status_option" "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' "$status_option" - elif replace_status_placeholder "$status_option" "$current_status_segment" '#{E:@coding-agents-tmux-status-format}' '#{@coding-agents-tmux-status-format}' '#{E:@opencode-tmux-status-format}' '#{@opencode-tmux-status-format}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' "$status_option" - elif replace_status_placeholder "$status_option" "$status_text_segment" '#{E:@coding-agents-tmux-status-text}' '#{@coding-agents-tmux-status-text}' '#{E:@opencode-tmux-status-text}' '#{@opencode-tmux-status-text}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' "$status_option" - elif replace_status_placeholder "$status_option" "$status_inline_segment" '#{E:@coding-agents-tmux-status-inline-format}' '#{@coding-agents-tmux-status-inline-format}' '#{E:@opencode-tmux-status-inline-format}' '#{@opencode-tmux-status-inline-format}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' "$status_option" - elif [ "$status_option" = "status-right" ] && replace_status_placeholder 'status-left' "$current_status_segment" '#{E:@coding-agents-tmux-status-format}' '#{@coding-agents-tmux-status-format}' '#{E:@opencode-tmux-status-format}' '#{@opencode-tmux-status-format}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-left' - elif [ "$status_option" = "status-right" ] && replace_status_placeholder 'status-left' "$status_text_segment" '#{E:@coding-agents-tmux-status-text}' '#{@coding-agents-tmux-status-text}' '#{E:@opencode-tmux-status-text}' '#{@opencode-tmux-status-text}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-left' - elif [ "$status_option" = "status-right" ] && replace_status_placeholder 'status-left' "$status_inline_segment" '#{E:@coding-agents-tmux-status-inline-format}' '#{@coding-agents-tmux-status-inline-format}' '#{E:@opencode-tmux-status-inline-format}' '#{@opencode-tmux-status-inline-format}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-left' - elif [ "$status_option" = "status-left" ] && replace_status_placeholder 'status-right' "$current_status_segment" '#{E:@coding-agents-tmux-status-format}' '#{@coding-agents-tmux-status-format}' '#{E:@opencode-tmux-status-format}' '#{@opencode-tmux-status-format}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-right' - elif [ "$status_option" = "status-left" ] && replace_status_placeholder 'status-right' "$status_text_segment" '#{E:@coding-agents-tmux-status-text}' '#{@coding-agents-tmux-status-text}' '#{E:@opencode-tmux-status-text}' '#{@opencode-tmux-status-text}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-right' - elif [ "$status_option" = "status-left" ] && replace_status_placeholder 'status-right' "$status_inline_segment" '#{E:@coding-agents-tmux-status-inline-format}' '#{@coding-agents-tmux-status-inline-format}' '#{E:@opencode-tmux-status-inline-format}' '#{@opencode-tmux-status-inline-format}'; then - set_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' "$current_status_segment" - set_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' 'status-right' + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' "$status_option" + elif replace_status_placeholder "$status_option" "$current_status_segment" '#{E:@coding-agents-tmux-status-format}' '#{@coding-agents-tmux-status-format}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' "$status_option" + elif replace_status_placeholder "$status_option" "$status_text_segment" '#{E:@coding-agents-tmux-status-text}' '#{@coding-agents-tmux-status-text}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' "$status_option" + elif replace_status_placeholder "$status_option" "$status_inline_segment" '#{E:@coding-agents-tmux-status-inline-format}' '#{@coding-agents-tmux-status-inline-format}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' "$status_option" + elif [ "$status_option" = "status-right" ] && replace_status_placeholder 'status-left' "$current_status_segment" '#{E:@coding-agents-tmux-status-format}' '#{@coding-agents-tmux-status-format}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' 'status-left' + elif [ "$status_option" = "status-right" ] && replace_status_placeholder 'status-left' "$status_text_segment" '#{E:@coding-agents-tmux-status-text}' '#{@coding-agents-tmux-status-text}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' 'status-left' + elif [ "$status_option" = "status-right" ] && replace_status_placeholder 'status-left' "$status_inline_segment" '#{E:@coding-agents-tmux-status-inline-format}' '#{@coding-agents-tmux-status-inline-format}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' 'status-left' + elif [ "$status_option" = "status-left" ] && replace_status_placeholder 'status-right' "$current_status_segment" '#{E:@coding-agents-tmux-status-format}' '#{@coding-agents-tmux-status-format}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' 'status-right' + elif [ "$status_option" = "status-left" ] && replace_status_placeholder 'status-right' "$status_text_segment" '#{E:@coding-agents-tmux-status-text}' '#{@coding-agents-tmux-status-text}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' 'status-right' + elif [ "$status_option" = "status-left" ] && replace_status_placeholder 'status-right' "$status_inline_segment" '#{E:@coding-agents-tmux-status-inline-format}' '#{@coding-agents-tmux-status-inline-format}'; then + tmux set-option -gq '@coding-agents-tmux-status-segment' "$current_status_segment" + tmux set-option -gq '@coding-agents-tmux-status-option' 'status-right' else - unset_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' - unset_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' + tmux set-option -gu '@coding-agents-tmux-status-segment' + tmux set-option -gu '@coding-agents-tmux-status-option' fi else clear_status_hooks - unset_tmux_option_alias '@coding-agents-tmux-status-format' '@opencode-tmux-status-format' - unset_tmux_option_alias '@coding-agents-tmux-status-text' '@opencode-tmux-status-text' - unset_tmux_option_alias '@coding-agents-tmux-status-inline-format' '@opencode-tmux-status-inline-format' - unset_tmux_option_alias '@coding-agents-tmux-status-tone' '@opencode-tmux-status-tone' + tmux set-option -gu '@coding-agents-tmux-status-format' + tmux set-option -gu '@coding-agents-tmux-status-text' + tmux set-option -gu '@coding-agents-tmux-status-inline-format' + tmux set-option -gu '@coding-agents-tmux-status-tone' configure_catppuccin_status_module '' "$status_prefix" "$status_color_busy" "$status_color_waiting" "$status_color_idle" "$status_color_unknown" - unset_tmux_option_alias '@coding-agents-tmux-status-segment' '@opencode-tmux-status-segment' - unset_tmux_option_alias '@coding-agents-tmux-status-option' '@opencode-tmux-status-option' + tmux set-option -gu '@coding-agents-tmux-status-segment' + tmux set-option -gu '@coding-agents-tmux-status-option' fi } diff --git a/docs/remove-legacy-name-plan.md b/docs/remove-legacy-name-plan.md new file mode 100644 index 0000000..7d629ee --- /dev/null +++ b/docs/remove-legacy-name-plan.md @@ -0,0 +1,49 @@ +# Remove legacy rename aliases plan + +## Goal + +Finish the public rename so `coding-agents-tmux` is the only documented and user-facing project name, except for one short README note that tells existing users the former name and that compatibility aliases may exist during the transition. + +## Current target state + +- README uses only `coding-agents-tmux` in install, setup, configuration, status, and CLI examples. +- Migration details move out of the README and stay in historical release/migration docs only while they are useful. +- Runtime compatibility aliases have been removed for the next release. +- Tests cover only the current public names. + +## What is already done + +- README title, install snippet, tmux options, status examples, and CLI examples prefer `coding-agents-tmux`. +- README no longer lists legacy plugin/state/extension paths outside the rename note. +- Canonical tmux entrypoint, package metadata, OpenCode plugin file, Pi extension path, state root, env vars, and tmux options have new-name support. + +## Left to do + +### Documentation + +- [x] Keep only the short rename note in `README.md`; avoid adding legacy examples elsewhere in the README. +- [x] Keep `docs/rename-coding-agents-tmux-migration.md` in the repo as historical migration notes and update it as needed. +- [x] Update `docs/rename-coding-agents-tmux.md` after each cleanup milestone so it reflects current status instead of the original transition plan. +- [x] Audit all docs for accidental legacy-name promotion before release. Current legacy references are confined to README rename note, historical implementation/migration plans, and compatibility-context notes. + +### Runtime cleanup + +- [x] Decide the deprecation window for legacy CLI, env-var, tmux-option, state-dir, plugin-path, and extension-path aliases: remove them in the next release. +- [x] Decide whether legacy alias usage should emit runtime warnings before removal: no warnings needed because aliases are being removed in the next release. +- [x] Pick the exact release boundary for removing alias support: the next release is the removal boundary. +- [x] Remove legacy aliases only after the communicated transition window. + +### Validation + +- [x] Run `npm test`. +- [x] Run `npm run typecheck`. +- [x] Run `npm run lint`. +- [x] Run `npm run shell:check`. +- [x] Run `npm run fmt:check`. +- [x] Verify TPM install/reload with the renamed repo and entrypoint. + +## Release note checklist + +- [x] State that the main README now documents only the new public surfaces. +- [x] Link existing users to the migration guide or release notes if legacy aliases are still supported. +- [x] Clearly state whether aliases are supported, deprecated with warnings, or removed in that release. diff --git a/docs/rename-coding-agents-tmux-migration.md b/docs/rename-coding-agents-tmux-migration.md index 73b1f4f..598be93 100644 --- a/docs/rename-coding-agents-tmux-migration.md +++ b/docs/rename-coding-agents-tmux-migration.md @@ -1,17 +1,10 @@ # Migration guide: `opencode-tmux` → `coding-agents-tmux` -This release renames the project from **`opencode-tmux`** to **`coding-agents-tmux`**. +This project was renamed from **`opencode-tmux`** to **`coding-agents-tmux`**. -The goal is to make the public name match the current scope of the project: +The current release removes the old public aliases. Existing users should update configs and scripts to the new names before upgrading. -- `opencode` -- `codex` -- `pi` -- mixed-agent discovery, switching, popup navigation, and status summaries in tmux - -## What changed - -The new preferred public names are: +## Current public names - **repo / product name:** `coding-agents-tmux` - **CLI:** `coding-agents-tmux` @@ -23,57 +16,30 @@ The new preferred public names are: - **Pi extension dir:** `~/.pi/agent/extensions/coding-agents-tmux/` - **bundled OpenCode plugin symlink:** `~/.config/opencode/plugins/coding-agents-tmux.ts` -## What still works for now - -The old names are still supported in this transition release: - -- `opencode-tmux` CLI -- `@opencode-tmux-*` tmux options -- `OPENCODE_TMUX_*` env vars -- legacy Catppuccin module export `@catppuccin_status_opencode` -- legacy state under `~/.local/state/opencode-tmux/` -- legacy tmux entrypoint `opencode-tmux.tmux` -- legacy Pi extension path `~/.pi/agent/extensions/opencode-tmux/` -- legacy OpenCode plugin symlink `~/.config/opencode/plugins/opencode-tmux.ts` - -These are **temporary compatibility aliases**, not the long-term preferred interface. - -## Compatibility guarantees in this release +## Removed legacy aliases -This release is designed so that existing users can upgrade without their setup breaking immediately. +The following legacy aliases are no longer installed or read by the current release: -Current behavior: - -- runtime readers accept both old and new state roots -- the tmux plugin accepts both old and new tmux option names -- the CLI/runtime accept both old and new env var names -- the old CLI wrapper forwards to the new CLI -- the new tmux/plugin install flow creates new preferred paths and keeps legacy compatibility links in place +- old CLI name +- old tmux option prefix +- old env var prefix +- old Catppuccin status module export +- old state root +- old tmux entrypoint filename +- old Pi extension path +- old OpenCode plugin symlink ## Recommended migration ### 1. Update your tmux plugin reference -Preferred TPM entry: - ```tmux set -g @plugin 'corwinm/coding-agents-tmux' ``` -If you already had the plugin installed before the rename, update your TPM entry to the new repo slug so your local config matches the current docs and release notes. - -### 2. Update your tmux option names - -Before: - -```tmux -set -g @opencode-tmux-provider 'plugin' -set -g @opencode-tmux-menu-key 'O' -set -g @opencode-tmux-popup-key 'P' -set -g @opencode-tmux-status 'on' -``` +### 2. Update tmux option names -After: +Use the `@coding-agents-tmux-*` prefix: ```tmux set -g @coding-agents-tmux-provider 'plugin' @@ -84,15 +50,6 @@ set -g @coding-agents-tmux-status 'on' ### 3. Update CLI invocations and scripts -Before: - -```bash -opencode-tmux list -./bin/opencode-tmux status --provider plugin -``` - -After: - ```bash coding-agents-tmux list ./bin/coding-agents-tmux status --provider plugin @@ -100,163 +57,19 @@ coding-agents-tmux list ### 4. Update env vars if you set them explicitly -Examples: - -Before: - -```bash -export OPENCODE_TMUX_STATE_DIR=/tmp/opencode-state -export OPENCODE_TMUX_PI_STATE_DIR=/tmp/pi-state -export OPENCODE_TMUX_SERVER_MAP='{"work:1.0":"http://127.0.0.1:4096"}' -``` - -After: - ```bash export CODING_AGENTS_TMUX_STATE_DIR=/tmp/opencode-state export CODING_AGENTS_TMUX_PI_STATE_DIR=/tmp/pi-state export CODING_AGENTS_TMUX_SERVER_MAP='{"work:1.0":"http://127.0.0.1:4096"}' ``` -### 5. Update the Catppuccin module name if you use manual mode - -If you manually place the module in `status-left` or `status-right`, update the exported name. - -Before: - -```tmux -set -ag status-right "#{E:@catppuccin_status_opencode}" -``` - -After: +### 5. Update Catppuccin manual-mode status usage ```tmux +set -g @coding-agents-tmux-status-mode 'manual' set -ag status-right "#{E:@catppuccin_status_agents}" ``` -The old `@catppuccin_status_opencode` export still works as a compatibility alias for now. - -### 6. Reload tmux and restart agent sessions if needed - -After changing plugin config or bundled integration paths: - -```tmux -prefix + I -``` - -Or: - -```bash -tmux source-file ~/.tmux.conf -``` - -Then restart any running `opencode`, `codex`, or `pi` sessions if you need them to pick up newly installed plugin or extension links. - -## Path migration notes - -### State directories - -Preferred new root: - -```text -~/.local/state/coding-agents-tmux/ -``` - -Legacy root still read during the transition: - -```text -~/.local/state/opencode-tmux/ -``` - -### OpenCode plugin symlink - -Preferred path: - -```text -~/.config/opencode/plugins/coding-agents-tmux.ts -``` - -Legacy compatibility path also created for now: - -```text -~/.config/opencode/plugins/opencode-tmux.ts -``` - -### Pi extension path - -Preferred path: - -```text -~/.pi/agent/extensions/coding-agents-tmux/index.ts -``` - -Legacy compatibility path also created for now: - -```text -~/.pi/agent/extensions/opencode-tmux/index.ts -``` - -## Deprecation plan - -Legacy names are being kept only to make the rename less disruptive. - -The intent is: - -1. prefer new names immediately -2. keep old names working during the transition window -3. remove old aliases in a later cleanup or major release - -This means you should treat the following as deprecated now: - -- `opencode-tmux` -- `@opencode-tmux-*` -- `OPENCODE_TMUX_*` -- legacy install paths that still include `opencode-tmux` - -## Release notes summary - -### Highlights - -- renamed the package and public product name to `coding-agents-tmux` -- added `coding-agents-tmux` as the primary CLI wrapper -- added `coding-agents-tmux.tmux` as the new public tmux entrypoint -- added `@coding-agents-tmux-*` tmux option aliases -- added `CODING_AGENTS_TMUX_*` env var aliases -- switched generated tmux config snippets to the new name -- updated install paths to prefer `coding-agents-tmux` -- renamed the Catppuccin module export to `@catppuccin_status_agents` -- kept old names as temporary compatibility aliases - -### Upgrade impact - -- low for existing users in the short term -- recommended follow-up is to rename config, scripts, and env vars to the new names soon - -## Quick copy-paste migration example - -```tmux -set -g @plugin 'corwinm/coding-agents-tmux' -set -g @coding-agents-tmux-provider 'plugin' -set -g @coding-agents-tmux-menu-key 'O' -set -g @coding-agents-tmux-popup-key 'P' -set -g @coding-agents-tmux-waiting-menu-key 'W' -set -g @coding-agents-tmux-waiting-popup-key 'C-w' -set -g @coding-agents-tmux-status 'on' -set -g @coding-agents-tmux-status-style 'tmux' -set -g @coding-agents-tmux-status-position 'right' -set -g @coding-agents-tmux-status-interval '0' -``` - -## Questions you may still have - -### Do I need to rename everything immediately? - -No. The old names still work in this release. - -### Should I keep using the old names? - -No. They are still supported only to ease the transition. - -### Will the old names stay forever? +### 6. Move any manually managed state or integration paths -No. The project intends to remove them in a later cleanup release after users have had time to migrate. +If you manually created state files, plugin links, or Pi extension links under the old name, move or recreate them under the current paths listed above. diff --git a/docs/rename-coding-agents-tmux.md b/docs/rename-coding-agents-tmux.md index c59a3fb..b10b2b0 100644 --- a/docs/rename-coding-agents-tmux.md +++ b/docs/rename-coding-agents-tmux.md @@ -445,9 +445,12 @@ Mitigation: ## Remaining implementation decisions -- [ ] Decide the deprecation window to communicate for legacy CLI/env/tmux-option aliases. +Tracked in `docs/remove-legacy-name-plan.md`. + +- [ ] Decide the deprecation window to communicate for legacy CLI/env/tmux-option/state/path aliases. - [ ] Decide whether to emit runtime warnings when legacy names are used, or only document the deprecation. - [ ] Decide the exact release boundary for removing the legacy aliases. +- [ ] Verify TPM install/reload still works with the renamed repo and entrypoint. ## Success criteria @@ -494,3 +497,6 @@ The rename is successful when: - 2026-04-14: Re-validated the rename work with `npm test`, `npm run typecheck`, `npm run lint`, `npm run shell:check`, and `npm run fmt:check` after restoring dev dependencies with `npm ci`. - 2026-04-14: Audited the remaining markdown docs, updated `PLAN.md`, `TASKS.md`, and the Pi support plan for the new public name where practical, and added `docs/rename-coding-agents-tmux-migration.md` as a dedicated migration and release-notes guide. - 2026-04-16: Renamed the Catppuccin manual-mode status export from `@catppuccin_status_opencode` to `@catppuccin_status_agents`, kept the legacy export as a compatibility alias, and updated the README plus migration guide to call out the change explicitly. +- 2026-05-20: Trimmed README legacy-name details so install/configuration/CLI docs only show the new public surfaces outside the short rename note, and added `docs/remove-legacy-name-plan.md` to track the remaining alias cleanup decisions and validation work. +- 2026-05-20: Decided the next release is the removal boundary for legacy aliases, removed runtime/path/CLI/tmux/env compatibility aliases, updated tests and migration guidance for the new-name-only behavior, and revalidated with the standard automated checks. +- 2026-05-20: Verified the renamed tmux plugin install/reload path manually via `scripts/sync-tmux-plugin.sh --reload --bootstrap`; production bootstrap now skips dev-only lifecycle scripts with `--ignore-scripts` so omitted Husky dev dependencies do not break tmux-managed installs. diff --git a/opencode-tmux.tmux b/opencode-tmux.tmux deleted file mode 100755 index f286f94..0000000 --- a/opencode-tmux.tmux +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "$CURRENT_DIR/coding-agents-tmux.tmux" "$@" diff --git a/package-lock.json b/package-lock.json index 7e7b619..9be2758 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,7 @@ "commander": "^14.0.3" }, "bin": { - "coding-agents-tmux": "bin/coding-agents-tmux", - "opencode-tmux": "bin/opencode-tmux" + "coding-agents-tmux": "bin/coding-agents-tmux" }, "devDependencies": { "@types/node": "^25.3.5", diff --git a/package.json b/package.json index a65cea4..eaa0796 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,7 @@ "url": "git+https://github.com/corwinm/coding-agents-tmux.git" }, "bin": { - "coding-agents-tmux": "bin/coding-agents-tmux", - "opencode-tmux": "bin/opencode-tmux" + "coding-agents-tmux": "bin/coding-agents-tmux" }, "type": "module", "scripts": { diff --git a/plugin/coding-agents-tmux.ts b/plugin/coding-agents-tmux.ts index f5b70ba..3e040c3 100644 --- a/plugin/coding-agents-tmux.ts +++ b/plugin/coding-agents-tmux.ts @@ -5,7 +5,6 @@ import { join } from "node:path"; const STATE_DIR = process.env.CODING_AGENTS_TMUX_STATE_DIR ?? - process.env.OPENCODE_TMUX_STATE_DIR ?? join( process.env.XDG_STATE_HOME ?? join(homedir(), ".local", "state"), "coding-agents-tmux", @@ -422,5 +421,3 @@ export const CodingAgentsTmuxPlugin = async ({ directory, project, client }: Plu }, }; }; - -export const OpencodeTmuxPlugin = CodingAgentsTmuxPlugin; diff --git a/plugin/opencode-tmux.ts b/plugin/opencode-tmux.ts deleted file mode 100644 index a2a9583..0000000 --- a/plugin/opencode-tmux.ts +++ /dev/null @@ -1 +0,0 @@ -export { CodingAgentsTmuxPlugin, OpencodeTmuxPlugin } from "./coding-agents-tmux.ts"; diff --git a/plugin/pi-tmux.ts b/plugin/pi-tmux.ts index 33800d0..9d6c3ce 100644 --- a/plugin/pi-tmux.ts +++ b/plugin/pi-tmux.ts @@ -23,7 +23,6 @@ interface PiExtensionAPI { const STATE_DIR = process.env.CODING_AGENTS_TMUX_PI_STATE_DIR ?? - process.env.OPENCODE_TMUX_PI_STATE_DIR ?? join( process.env.XDG_STATE_HOME ?? join(homedir(), ".local", "state"), "coding-agents-tmux", diff --git a/scripts/shfmt.mjs b/scripts/shfmt.mjs index 37f2bec..09043a0 100644 --- a/scripts/shfmt.mjs +++ b/scripts/shfmt.mjs @@ -7,7 +7,6 @@ import { format } from "@wasm-fmt/shfmt/node"; const repoRoot = path.resolve(import.meta.dirname, ".."); const defaultFiles = [ "bin/coding-agents-tmux", - "bin/opencode-tmux", "scripts/sync-tmux-plugin.sh", "scripts/tmux-menu-switch.sh", "scripts/tmux-popup-switch.sh", diff --git a/scripts/sync-tmux-plugin.sh b/scripts/sync-tmux-plugin.sh index fe6e093..fee3923 100755 --- a/scripts/sync-tmux-plugin.sh +++ b/scripts/sync-tmux-plugin.sh @@ -3,8 +3,8 @@ set -euo pipefail CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -TARGET_DIR="${CODING_AGENTS_TMUX_PLUGIN_DIR:-${OPENCODE_TMUX_PLUGIN_DIR:-$HOME/.tmux/plugins/coding-agents-tmux}}" -TMUX_CONF="${CODING_AGENTS_TMUX_TMUX_CONF:-${OPENCODE_TMUX_TMUX_CONF:-$HOME/.tmux.conf}}" +TARGET_DIR="${CODING_AGENTS_TMUX_PLUGIN_DIR:-$HOME/.tmux/plugins/coding-agents-tmux}" +TMUX_CONF="${CODING_AGENTS_TMUX_TMUX_CONF:-$HOME/.tmux.conf}" RELOAD=0 BOOTSTRAP=0 @@ -27,19 +27,15 @@ run_bootstrap() { fi if [ -f "$TARGET_DIR/package-lock.json" ]; then - npm ci --omit=dev --prefix "$TARGET_DIR" + npm ci --omit=dev --ignore-scripts --prefix "$TARGET_DIR" else - npm install --omit=dev --prefix "$TARGET_DIR" + npm install --omit=dev --ignore-scripts --prefix "$TARGET_DIR" fi } reload_tmux() { local plugin_entrypoint="$TARGET_DIR/coding-agents-tmux.tmux" - if [ ! -f "$plugin_entrypoint" ]; then - plugin_entrypoint="$TARGET_DIR/opencode-tmux.tmux" - fi - if ! command -v tmux >/dev/null 2>&1; then printf 'coding-agents-tmux: tmux is not installed; skipping reload\n' return diff --git a/src/cli.ts b/src/cli.ts index e9c2607..26e5aee 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -780,19 +780,14 @@ export function getTmuxConfigPath(file: string | undefined): string { } export function updateTmuxConfig(existing: string, snippet: string): string { - const markerPairs = [ - ["# >>> coding-agents-tmux >>>", "# <<< coding-agents-tmux <<<"], - ["# >>> opencode-tmux >>>", "# <<< opencode-tmux <<<"], - ] as const; - - for (const [startMarker, endMarker] of markerPairs) { - const blockPattern = new RegExp( - `${escapeRegExp(startMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`, - ); + const startMarker = "# >>> coding-agents-tmux >>>"; + const endMarker = "# <<< coding-agents-tmux <<<"; + const blockPattern = new RegExp( + `${escapeRegExp(startMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`, + ); - if (blockPattern.test(existing)) { - return existing.replace(blockPattern, snippet); - } + if (blockPattern.test(existing)) { + return existing.replace(blockPattern, snippet); } return `${existing.trimEnd()}${existing.trimEnd() ? "\n\n" : ""}${snippet}\n`; diff --git a/src/cli/render.ts b/src/cli/render.ts index eaf01b8..6d17c9c 100644 --- a/src/cli/render.ts +++ b/src/cli/render.ts @@ -1,4 +1,4 @@ -import { getEnvAliasValue } from "../naming.ts"; +import { getEnvValue } from "../naming.ts"; import type { InspectResult, PaneRuntimeSummary } from "../types.ts"; type StatusStyle = "plain" | "tmux"; @@ -6,36 +6,16 @@ type StatusStyle = "plain" | "tmux"; type StatusTone = "neutral" | "busy" | "waiting" | "idle" | "unknown"; const statusToneColors: Record = { - neutral: - getEnvAliasValue( - "CODING_AGENTS_TMUX_STATUS_COLOR_NEUTRAL", - "OPENCODE_TMUX_STATUS_COLOR_NEUTRAL", - ) ?? "colour252", - busy: - getEnvAliasValue("CODING_AGENTS_TMUX_STATUS_COLOR_BUSY", "OPENCODE_TMUX_STATUS_COLOR_BUSY") ?? - "colour220", - waiting: - getEnvAliasValue( - "CODING_AGENTS_TMUX_STATUS_COLOR_WAITING", - "OPENCODE_TMUX_STATUS_COLOR_WAITING", - ) ?? "colour196", - idle: - getEnvAliasValue("CODING_AGENTS_TMUX_STATUS_COLOR_IDLE", "OPENCODE_TMUX_STATUS_COLOR_IDLE") ?? - "colour70", - unknown: - getEnvAliasValue( - "CODING_AGENTS_TMUX_STATUS_COLOR_UNKNOWN", - "OPENCODE_TMUX_STATUS_COLOR_UNKNOWN", - ) ?? "colour244", + neutral: getEnvValue("CODING_AGENTS_TMUX_STATUS_COLOR_NEUTRAL") ?? "colour252", + busy: getEnvValue("CODING_AGENTS_TMUX_STATUS_COLOR_BUSY") ?? "colour220", + waiting: getEnvValue("CODING_AGENTS_TMUX_STATUS_COLOR_WAITING") ?? "colour196", + idle: getEnvValue("CODING_AGENTS_TMUX_STATUS_COLOR_IDLE") ?? "colour70", + unknown: getEnvValue("CODING_AGENTS_TMUX_STATUS_COLOR_UNKNOWN") ?? "colour244", }; -const statusPrefix = - getEnvAliasValue("CODING_AGENTS_TMUX_STATUS_PREFIX", "OPENCODE_TMUX_STATUS_PREFIX") ?? "󰚩"; +const statusPrefix = getEnvValue("CODING_AGENTS_TMUX_STATUS_PREFIX") ?? "󰚩"; const statusShowPrefix = !["0", "false", "no", "off"].includes( - ( - getEnvAliasValue("CODING_AGENTS_TMUX_STATUS_SHOW_PREFIX", "OPENCODE_TMUX_STATUS_SHOW_PREFIX") ?? - "on" - ).toLowerCase(), + (getEnvValue("CODING_AGENTS_TMUX_STATUS_SHOW_PREFIX") ?? "on").toLowerCase(), ); const columns = [ diff --git a/src/core/claude.ts b/src/core/claude.ts index 21c2783..60c1ef9 100644 --- a/src/core/claude.ts +++ b/src/core/claude.ts @@ -188,8 +188,7 @@ export function getClaudeSettingsPath(): string { export function getClaudeStateDir(): string { return getPreferredStateDir({ - preferredEnv: "CODING_AGENTS_TMUX_CLAUDE_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_CLAUDE_STATE_DIR", + env: "CODING_AGENTS_TMUX_CLAUDE_STATE_DIR", subdirectory: "claude-state", }); } @@ -466,8 +465,7 @@ export async function persistClaudeHookState(rawInput: string): Promise { export function readClaudeStates(): ClaudeStateFile[] { return getStateDirCandidates({ - preferredEnv: "CODING_AGENTS_TMUX_CLAUDE_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_CLAUDE_STATE_DIR", + env: "CODING_AGENTS_TMUX_CLAUDE_STATE_DIR", subdirectory: "claude-state", }) .filter((stateDir) => existsSync(stateDir)) diff --git a/src/core/codex.ts b/src/core/codex.ts index 00bea12..fc5b90d 100644 --- a/src/core/codex.ts +++ b/src/core/codex.ts @@ -64,8 +64,7 @@ function normalizeEnvValue(value: string | undefined): string | null { export function getCodexStateDir(): string { return getPreferredStateDir({ - preferredEnv: "CODING_AGENTS_TMUX_CODEX_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_CODEX_STATE_DIR", + env: "CODING_AGENTS_TMUX_CODEX_STATE_DIR", subdirectory: "codex-state", }); } @@ -284,8 +283,7 @@ export async function persistCodexHookState(rawInput: string): Promise { export function readCodexStateEntries(): CodexStateEntry[] { return getStateDirCandidates({ - preferredEnv: "CODING_AGENTS_TMUX_CODEX_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_CODEX_STATE_DIR", + env: "CODING_AGENTS_TMUX_CODEX_STATE_DIR", subdirectory: "codex-state", }) .filter((stateDir) => existsSync(stateDir)) diff --git a/src/core/opencode.ts b/src/core/opencode.ts index c9d0b79..61314a5 100644 --- a/src/core/opencode.ts +++ b/src/core/opencode.ts @@ -13,7 +13,7 @@ import { attachRuntimeWithPi } from "./pi.ts"; import { capturePanePreview } from "./tmux.ts"; import { PRIMARY_CLI_NAME, - getEnvAliasValue, + getEnvValue, getPreferredStateDir, getStateDirCandidates, } from "../naming.ts"; @@ -152,8 +152,7 @@ function getOpencodeDbPath(): string { function getPluginStateDir(): string { return getPreferredStateDir({ - preferredEnv: "CODING_AGENTS_TMUX_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_STATE_DIR", + env: "CODING_AGENTS_TMUX_STATE_DIR", subdirectory: "plugin-state", }); } @@ -312,8 +311,7 @@ function toPluginSessionMatch(state: PluginStateFile): SessionMatch | null { function readPluginStates(): PluginStateFile[] { return getStateDirCandidates({ - preferredEnv: "CODING_AGENTS_TMUX_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_STATE_DIR", + env: "CODING_AGENTS_TMUX_STATE_DIR", subdirectory: "plugin-state", }) .filter((stateDir) => existsSync(stateDir)) @@ -754,7 +752,7 @@ function normalizeServerMapSource(value: string | undefined): string | null { return value.trim(); } - return getEnvAliasValue("CODING_AGENTS_TMUX_SERVER_MAP", "OPENCODE_TMUX_SERVER_MAP") ?? null; + return getEnvValue("CODING_AGENTS_TMUX_SERVER_MAP") ?? null; } function parseServerMap(value: string | undefined): Record { @@ -1212,10 +1210,7 @@ function classifyCodexPreview( } function getCodexBusyGraceMs(): number { - const value = getEnvAliasValue( - "CODING_AGENTS_TMUX_CODEX_BUSY_GRACE_MS", - "OPENCODE_TMUX_CODEX_BUSY_GRACE_MS", - ); + const value = getEnvValue("CODING_AGENTS_TMUX_CODEX_BUSY_GRACE_MS"); if (!value) { return 3000; @@ -1530,23 +1525,23 @@ export function getRuntimeProviderHelpText(): string { "", "Plugin state:", ` Default path: ${getPluginStateDir()}`, - " Override with CODING_AGENTS_TMUX_STATE_DIR or OPENCODE_TMUX_STATE_DIR.", + " Override with CODING_AGENTS_TMUX_STATE_DIR.", "", "Codex hook state:", ` Default path: ${getCodexStateDir()}`, - " Override with CODING_AGENTS_TMUX_CODEX_STATE_DIR or OPENCODE_TMUX_CODEX_STATE_DIR.", + " Override with CODING_AGENTS_TMUX_CODEX_STATE_DIR.", ` Generate hooks.json with: ${PRIMARY_CLI_NAME} codex-hooks-template`, "", "Claude hook state:", ` Default path: ${getClaudeStateDir()}`, - " Override with CODING_AGENTS_TMUX_CLAUDE_STATE_DIR or OPENCODE_TMUX_CLAUDE_STATE_DIR.", + " Override with CODING_AGENTS_TMUX_CLAUDE_STATE_DIR.", ` Generate settings hooks with: ${PRIMARY_CLI_NAME} claude-hooks-template`, ` Install global Claude hooks with: ${PRIMARY_CLI_NAME} install-claude`, "", "Server map:", " Pass --server-map with a JSON object or a path to a JSON file.", ' Example: {"work:1.2":"http://127.0.0.1:4096"}', - " You can also set CODING_AGENTS_TMUX_SERVER_MAP or OPENCODE_TMUX_SERVER_MAP with the same value.", + " You can also set CODING_AGENTS_TMUX_SERVER_MAP with the same value.", ].join("\n"); } diff --git a/src/core/pi.ts b/src/core/pi.ts index 3368f6f..58eaa0d 100644 --- a/src/core/pi.ts +++ b/src/core/pi.ts @@ -70,16 +70,14 @@ function pickNewerPiState(current: PiStateFile | undefined, candidate: PiStateFi export function getPiStateDir(): string { return getPreferredStateDir({ - preferredEnv: "CODING_AGENTS_TMUX_PI_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_PI_STATE_DIR", + env: "CODING_AGENTS_TMUX_PI_STATE_DIR", subdirectory: "pi-state", }); } function readPiStates(): PiStateFile[] { return getStateDirCandidates({ - preferredEnv: "CODING_AGENTS_TMUX_PI_STATE_DIR", - legacyEnv: "OPENCODE_TMUX_PI_STATE_DIR", + env: "CODING_AGENTS_TMUX_PI_STATE_DIR", subdirectory: "pi-state", }) .filter((stateDir) => existsSync(stateDir)) diff --git a/src/naming.ts b/src/naming.ts index 76d866c..2f5d3d2 100644 --- a/src/naming.ts +++ b/src/naming.ts @@ -2,50 +2,27 @@ import { homedir } from "node:os"; import { join } from "node:path"; export const PRODUCT_SLUG = "coding-agents-tmux"; -export const LEGACY_PRODUCT_SLUG = "opencode-tmux"; export const PRIMARY_CLI_NAME = "coding-agents-tmux"; -export const LEGACY_CLI_NAME = "opencode-tmux"; -export function getEnvAliasValue(...names: string[]): string | undefined { - for (const name of names) { - const value = process.env[name]; - - if (value && value.trim()) { - return value.trim(); - } - } - - return undefined; +export function getEnvValue(name: string): string | undefined { + const value = process.env[name]; + return value && value.trim() ? value.trim() : undefined; } export function getStateHome(): string { return process.env.XDG_STATE_HOME ?? join(homedir(), ".local", "state"); } -export function getPreferredStateDir(input: { - preferredEnv: string; - legacyEnv: string; - subdirectory: string; -}): string { - return ( - getEnvAliasValue(input.preferredEnv, input.legacyEnv) ?? - join(getStateHome(), PRODUCT_SLUG, input.subdirectory) - ); +export function getPreferredStateDir(input: { env: string; subdirectory: string }): string { + return getEnvValue(input.env) ?? join(getStateHome(), PRODUCT_SLUG, input.subdirectory); } -export function getStateDirCandidates(input: { - preferredEnv: string; - legacyEnv: string; - subdirectory: string; -}): string[] { - const explicitDir = getEnvAliasValue(input.preferredEnv, input.legacyEnv); +export function getStateDirCandidates(input: { env: string; subdirectory: string }): string[] { + const explicitDir = getEnvValue(input.env); if (explicitDir) { return [explicitDir]; } - return [ - join(getStateHome(), PRODUCT_SLUG, input.subdirectory), - join(getStateHome(), LEGACY_PRODUCT_SLUG, input.subdirectory), - ]; + return [join(getStateHome(), PRODUCT_SLUG, input.subdirectory)]; } diff --git a/test/cli.test.ts b/test/cli.test.ts index c75a475..c0ea541 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -26,7 +26,7 @@ import type { } from "../src/types.ts"; const BIN_PATH = join(process.cwd(), "bin", "coding-agents-tmux"); -const LEGACY_BIN_PATH = join(process.cwd(), "bin", "opencode-tmux"); +const LEGACY_BIN_PATH = join(process.cwd(), "bin", "coding-agents-tmux"); function setEnv(updates: Record): () => void { const previous = new Map(); @@ -52,7 +52,7 @@ function setEnv(updates: Record): () => void { } function createPluginStateDir(states: Record[]): string { - const root = mkdtempSync(join(tmpdir(), "opencode-tmux-cli-state-")); + const root = mkdtempSync(join(tmpdir(), "coding-agents-tmux-cli-state-")); states.forEach((state, index) => { writeFileSync(join(root, `state-${index + 1}.json`), JSON.stringify(state), "utf8"); @@ -62,7 +62,7 @@ function createPluginStateDir(states: Record[]): string { } function installFakeTmux(script: string): { pathEntry: string; logPath: string } { - const dir = mkdtempSync(join(tmpdir(), "opencode-tmux-cli-tmux-")); + const dir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-cli-tmux-")); const tmuxPath = join(dir, "tmux"); const logPath = join(dir, "tmux.log"); const resolvedScript = script.replaceAll("__LOG_PATH__", logPath); @@ -290,9 +290,9 @@ test("getTmuxConfigPath and updateTmuxConfig choose defaults, append, and replac [ "set -g mouse on", "", - "# >>> opencode-tmux >>>", + "# >>> coding-agents-tmux >>>", "old config", - "# <<< opencode-tmux <<<", + "# <<< coding-agents-tmux <<<", "", ].join("\n"), snippet, @@ -383,7 +383,7 @@ test("CLI help and tmux-config work through the entrypoint script", async () => assert.match(configResult.stdoutText, /--waiting/); }); -test("legacy opencode-tmux CLI alias still works", async () => { +test("coding-agents-tmux CLI entrypoint works", async () => { const result = await runCommand([LEGACY_BIN_PATH, "--help"]); assert.equal(result.exitCode, 0); @@ -391,7 +391,7 @@ test("legacy opencode-tmux CLI alias still works", async () => { }); test("CLI install-tmux writes and replaces a marked config block", async () => { - const dir = mkdtempSync(join(tmpdir(), "opencode-tmux-cli-test-")); + const dir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-cli-test-")); const filePath = join(dir, "tmux.conf"); const firstRun = await runCommand([BIN_PATH, "install-tmux", "--file", filePath]); const secondRun = await runCommand([ @@ -413,7 +413,7 @@ test("CLI install-tmux writes and replaces a marked config block", async () => { }); test("CLI install-codex writes Codex config and hooks files", async () => { - const codexHome = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-home-")); + const codexHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-home-")); const restoreEnv = setEnv({ CODEX_HOME: codexHome }); try { @@ -474,7 +474,7 @@ exit 1 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, }); try { @@ -528,7 +528,7 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const codexStateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const codexStateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); writeFileSync( join(codexStateDir, "pane.json"), JSON.stringify({ @@ -548,7 +548,7 @@ exit 1 ); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: codexStateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: codexStateDir, }); try { @@ -618,7 +618,7 @@ exit 0 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, TMUX: "1", }); @@ -664,7 +664,7 @@ exit 1 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, TMUX: "1", }); @@ -768,7 +768,16 @@ exit 1 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: mkdtempSync( + join(tmpdir(), "coding-agents-tmux-empty-codex-state-"), + ), + CODING_AGENTS_TMUX_PI_STATE_DIR: mkdtempSync( + join(tmpdir(), "coding-agents-tmux-empty-pi-state-"), + ), + CODING_AGENTS_TMUX_CLAUDE_STATE_DIR: mkdtempSync( + join(tmpdir(), "coding-agents-tmux-empty-claude-state-"), + ), }); try { @@ -867,7 +876,7 @@ exit 1 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, TMUX: "1", }); @@ -930,7 +939,7 @@ exit 1 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, TMUX: "1", }); diff --git a/test/codex.test.ts b/test/codex.test.ts index 8adff0f..f577b4e 100644 --- a/test/codex.test.ts +++ b/test/codex.test.ts @@ -71,7 +71,7 @@ function setEnv(updates: Record): () => void { } function installFakeTmux(script: string): { pathEntry: string } { - const dir = mkdtempSync(join(tmpdir(), "opencode-tmux-fake-tmux-")); + const dir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-fake-tmux-")); const scriptPath = join(dir, "tmux"); writeFileSync( @@ -88,7 +88,7 @@ ${script} test("buildCodexHooksTemplate emits all hook events with the ingest command", () => { const template = JSON.parse( - buildCodexHooksTemplate("/tmp/opencode-tmux/bin/opencode-tmux codex-hook-state"), + buildCodexHooksTemplate("/tmp/coding-agents-tmux/bin/coding-agents-tmux codex-hook-state"), ) as { hooks: Record }>>; }; @@ -102,14 +102,14 @@ test("buildCodexHooksTemplate emits all hook events with the ingest command", () ]); assert.equal( template.hooks.Stop?.[0]?.hooks[0]?.command, - "/tmp/opencode-tmux/bin/opencode-tmux codex-hook-state", + "/tmp/coding-agents-tmux/bin/coding-agents-tmux codex-hook-state", ); }); test("persistCodexHookState classifies multiple-choice prompts as waiting-question", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const restoreEnv = setEnv({ - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, TMUX_PANE: undefined, }); @@ -133,7 +133,7 @@ test("persistCodexHookState classifies multiple-choice prompts as waiting-questi } }); -test("readCodexStates supports new env aliases and both default state roots", () => { +test("readCodexStates supports env override and default state root", () => { const preferredStateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); writeFileSync( join(preferredStateDir, "preferred.json"), @@ -149,7 +149,6 @@ test("readCodexStates supports new env aliases and both default state roots", () ); const explicitEnvRestore = setEnv({ CODING_AGENTS_TMUX_CODEX_STATE_DIR: preferredStateDir, - OPENCODE_TMUX_CODEX_STATE_DIR: undefined, }); try { @@ -160,9 +159,7 @@ test("readCodexStates supports new env aliases and both default state roots", () const stateHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-home-")); const preferredRoot = join(stateHome, "coding-agents-tmux", "codex-state"); - const legacyRoot = join(stateHome, "opencode-tmux", "codex-state"); mkdirSync(preferredRoot, { recursive: true }); - mkdirSync(legacyRoot, { recursive: true }); writeFileSync( join(preferredRoot, "preferred.json"), JSON.stringify({ @@ -175,28 +172,15 @@ test("readCodexStates supports new env aliases and both default state roots", () updatedAt: 200, }), ); - writeFileSync( - join(legacyRoot, "legacy.json"), - JSON.stringify({ - version: 1, - target: "work:1.2", - directory: "/tmp/codex-root-legacy", - title: "Legacy Root Codex Session", - status: "waiting-input", - activity: "busy", - updatedAt: 300, - }), - ); const restoreEnv = setEnv({ XDG_STATE_HOME: stateHome, CODING_AGENTS_TMUX_CODEX_STATE_DIR: undefined, - OPENCODE_TMUX_CODEX_STATE_DIR: undefined, }); try { const titles = readCodexStates().map((state) => state.title); - assert.deepEqual(titles, ["Preferred Root Codex Session", "Legacy Root Codex Session"]); + assert.deepEqual(titles, ["Preferred Root Codex Session"]); } finally { restoreEnv(); } @@ -227,7 +211,7 @@ test("updateCodexHooks merges managed hooks without dropping existing user hooks hooks: [ { type: "command", - command: "/old/opencode-tmux codex-hook-state", + command: "/old/coding-agents-tmux codex-hook-state", statusMessage: "Updating Codex tmux state", }, ], @@ -241,7 +225,7 @@ test("updateCodexHooks merges managed hooks without dropping existing user hooks null, 2, ), - "/new/opencode-tmux codex-hook-state", + "/new/coding-agents-tmux codex-hook-state", ), ) as { hooks: Record }>>; @@ -249,7 +233,10 @@ test("updateCodexHooks merges managed hooks without dropping existing user hooks assert.equal(updated.hooks.Stop?.length, 2); assert.equal(updated.hooks.Stop?.[0]?.hooks[0]?.command, "python3 ~/.codex/custom-stop.py"); - assert.equal(updated.hooks.Stop?.[1]?.hooks[0]?.command, "/new/opencode-tmux codex-hook-state"); + assert.equal( + updated.hooks.Stop?.[1]?.hooks[0]?.command, + "/new/coding-agents-tmux codex-hook-state", + ); assert.deepEqual(Object.keys(updated.hooks), [ "Stop", "SessionStart", @@ -260,11 +247,13 @@ test("updateCodexHooks merges managed hooks without dropping existing user hooks }); test("installCodexIntegration writes config.toml and hooks.json under CODEX_HOME", () => { - const codexHome = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-home-")); + const codexHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-home-")); const restoreEnv = setEnv({ CODEX_HOME: codexHome }); try { - const result = installCodexIntegration("/tmp/opencode-tmux/bin/opencode-tmux codex-hook-state"); + const result = installCodexIntegration( + "/tmp/coding-agents-tmux/bin/coding-agents-tmux codex-hook-state", + ); const config = readFileSync(result.configPath, "utf8"); const hooks = readFileSync(result.hooksPath, "utf8"); @@ -291,10 +280,10 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -328,10 +317,10 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -362,7 +351,7 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); writeFileSync( join(stateDir, "pane.json"), JSON.stringify({ @@ -381,7 +370,7 @@ exit 1 ); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -413,7 +402,7 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); writeFileSync( join(stateDir, "pane.json"), JSON.stringify({ @@ -432,7 +421,7 @@ exit 1 ); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -465,7 +454,7 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); writeFileSync( join(stateDir, "pane.json"), JSON.stringify({ @@ -484,7 +473,7 @@ exit 1 ); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -515,7 +504,7 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); writeFileSync( join(stateDir, "pane.json"), JSON.stringify({ @@ -534,8 +523,8 @@ exit 1 ); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, - OPENCODE_TMUX_CODEX_BUSY_GRACE_MS: "3000", + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_BUSY_GRACE_MS: "3000", }); try { @@ -568,10 +557,10 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -599,10 +588,10 @@ fi printf 'unexpected args: %s\n' "$*" >&2 exit 1 `); - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -623,7 +612,7 @@ exit 1 }); test("Codex runtime does not borrow another pane's hook state by directory alone", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const fakeTmux = installFakeTmux(` if [ "$1" = "capture-pane" ]; then printf '╭──────────────────────────────────────────────╮\n' @@ -655,7 +644,7 @@ exit 1 ); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, }); try { @@ -672,9 +661,9 @@ exit 1 }); test("persistCodexHookState records waiting-input and attachRuntimeToPanes prefers hook state", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-codex-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-codex-state-")); const restoreEnv = setEnv({ - OPENCODE_TMUX_CODEX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_CODEX_STATE_DIR: stateDir, TMUX_PANE: undefined, }); diff --git a/test/opencode.test.ts b/test/opencode.test.ts index 8e3f53f..fa174c5 100644 --- a/test/opencode.test.ts +++ b/test/opencode.test.ts @@ -69,7 +69,7 @@ function setEnv(updates: Record): () => void { } function createPluginStateDir(states: Record[]): string { - const root = mkdtempSync(join(tmpdir(), "opencode-tmux-plugin-state-")); + const root = mkdtempSync(join(tmpdir(), "coding-agents-tmux-plugin-state-")); states.forEach((state, index) => { writeFileSync(join(root, `state-${index + 1}.json`), JSON.stringify(state), "utf8"); @@ -79,7 +79,7 @@ function createPluginStateDir(states: Record[]): string { } function createSqliteDataHome(): { dataHome: string; databasePath: string } { - const dataHome = mkdtempSync(join(tmpdir(), "opencode-tmux-data-home-")); + const dataHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-data-home-")); const opencodeDir = join(dataHome, "opencode"); mkdirSync(opencodeDir, { recursive: true }); return { @@ -137,7 +137,7 @@ function getSummary(summaries: PaneRuntimeSummary[], index: number): PaneRuntime return summary; } -test("plugin provider matches panes by target, pane id, and legacy directory state", async () => { +test("plugin provider matches panes by target, pane id, and directory state", async () => { const pluginStateDir = createPluginStateDir([ { target: "work:1.0", @@ -164,7 +164,7 @@ test("plugin provider matches panes by target, pane id, and legacy directory sta updatedAt: 300, }, ]); - const restoreEnv = setEnv({ OPENCODE_TMUX_STATE_DIR: pluginStateDir }); + const restoreEnv = setEnv({ CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir }); try { const panes = [ @@ -210,7 +210,7 @@ test("plugin provider uses safe descendant heuristics and leaves ambiguous panes updatedAt: 300, }, ]); - const restoreEnv = setEnv({ OPENCODE_TMUX_STATE_DIR: pluginStateDir }); + const restoreEnv = setEnv({ CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir }); try { const panes = [ @@ -231,7 +231,7 @@ test("plugin provider uses safe descendant heuristics and leaves ambiguous panes test("sqlite provider classifies exact matches across idle, waiting, running, and unfinished steps", async () => { const { dataHome, databasePath } = createSqliteDataHome(); - const restoreEnv = setEnv({ XDG_DATA_HOME: dataHome, OPENCODE_TMUX_STATE_DIR: undefined }); + const restoreEnv = setEnv({ XDG_DATA_HOME: dataHome, CODING_AGENTS_TMUX_STATE_DIR: undefined }); const database = initializeSqliteDatabase(databasePath); try { @@ -337,7 +337,7 @@ test("sqlite provider classifies exact matches across idle, waiting, running, an test("sqlite provider uses descendant heuristics only when they are unambiguous", async () => { const { dataHome, databasePath } = createSqliteDataHome(); - const restoreEnv = setEnv({ XDG_DATA_HOME: dataHome, OPENCODE_TMUX_STATE_DIR: undefined }); + const restoreEnv = setEnv({ XDG_DATA_HOME: dataHome, CODING_AGENTS_TMUX_STATE_DIR: undefined }); const database = initializeSqliteDatabase(databasePath); try { @@ -410,7 +410,7 @@ test("sqlite provider uses descendant heuristics only when they are unambiguous" }); test("server provider parses inline and file-backed maps and normalizes endpoints", async () => { - const mapFile = join(mkdtempSync(join(tmpdir(), "opencode-tmux-server-map-")), "map.json"); + const mapFile = join(mkdtempSync(join(tmpdir(), "coding-agents-tmux-server-map-")), "map.json"); writeFileSync(mapFile, JSON.stringify({ "work:1.1": "http://127.0.0.1:4097/" }), "utf8"); const responses = new Map([ @@ -465,23 +465,12 @@ test("server provider parses inline and file-backed maps and normalizes endpoint }); test("describeServerMapInput falls back to env when no explicit value is provided", () => { - const restoreEnv = setEnv({ OPENCODE_TMUX_SERVER_MAP: '{"work:1.0":"http://127.0.0.1:4096"}' }); - - try { - assert.equal(describeServerMapInput(undefined), '{"work:1.0":"http://127.0.0.1:4096"}'); - } finally { - restoreEnv(); - } -}); - -test("describeServerMapInput prefers the new CODING_AGENTS_TMUX_SERVER_MAP alias", () => { const restoreEnv = setEnv({ - CODING_AGENTS_TMUX_SERVER_MAP: '{"work:1.2":"http://127.0.0.1:5096"}', - OPENCODE_TMUX_SERVER_MAP: '{"work:1.0":"http://127.0.0.1:4096"}', + CODING_AGENTS_TMUX_SERVER_MAP: '{"work:1.0":"http://127.0.0.1:4096"}', }); try { - assert.equal(describeServerMapInput(undefined), '{"work:1.2":"http://127.0.0.1:5096"}'); + assert.equal(describeServerMapInput(undefined), '{"work:1.0":"http://127.0.0.1:4096"}'); } finally { restoreEnv(); } @@ -507,9 +496,9 @@ test("runtime provider helpers expose provider docs, template output, and valida }); assert.match(helpText, /Runtime providers:/); assert.match(helpText, /plugin Use opencode plugin state files only/); - assert.match(helpText, /Override with CODING_AGENTS_TMUX_STATE_DIR or OPENCODE_TMUX_STATE_DIR/); + assert.match(helpText, /Override with CODING_AGENTS_TMUX_STATE_DIR\./); assert.match(helpText, /Generate hooks\.json with: coding-agents-tmux codex-hooks-template/); - assert.match(helpText, /CODING_AGENTS_TMUX_SERVER_MAP or OPENCODE_TMUX_SERVER_MAP/); + assert.match(helpText, /CODING_AGENTS_TMUX_SERVER_MAP with the same value/); assert.match(helpText, /Codex hook state:/); await assert.rejects( attachRuntimeToPanes([createDiscoveredPane()], { provider: "bogus" as never }), @@ -517,7 +506,7 @@ test("runtime provider helpers expose provider docs, template output, and valida ); }); -test("plugin state supports new env aliases and both default state roots", async () => { +test("plugin state supports env override and default state root", async () => { const preferredStateDir = createPluginStateDir([ { target: "work:1.0", @@ -530,7 +519,6 @@ test("plugin state supports new env aliases and both default state roots", async ]); const explicitEnvRestore = setEnv({ CODING_AGENTS_TMUX_STATE_DIR: preferredStateDir, - OPENCODE_TMUX_STATE_DIR: undefined, }); try { @@ -547,9 +535,7 @@ test("plugin state supports new env aliases and both default state roots", async const stateHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-state-home-")); const preferredRoot = join(stateHome, "coding-agents-tmux", "plugin-state"); - const legacyRoot = join(stateHome, "opencode-tmux", "plugin-state"); mkdirSync(preferredRoot, { recursive: true }); - mkdirSync(legacyRoot, { recursive: true }); writeFileSync( join(preferredRoot, "preferred.json"), JSON.stringify({ @@ -561,35 +547,18 @@ test("plugin state supports new env aliases and both default state roots", async updatedAt: 300, }), ); - writeFileSync( - join(legacyRoot, "legacy.json"), - JSON.stringify({ - target: "work:1.2", - directory: "/tmp/legacy-root", - title: "Legacy Root Session", - status: "waiting-input", - activity: "busy", - updatedAt: 400, - }), - ); const restoreEnv = setEnv({ XDG_STATE_HOME: stateHome, CODING_AGENTS_TMUX_STATE_DIR: undefined, - OPENCODE_TMUX_STATE_DIR: undefined, }); try { const summaries = await attachRuntimeToPanes( - [ - createDiscoveredPane({ target: "work:1.1", currentPath: "/tmp/preferred-root" }), - createDiscoveredPane({ target: "work:1.2", currentPath: "/tmp/legacy-root", paneIndex: 2 }), - ], + [createDiscoveredPane({ target: "work:1.1", currentPath: "/tmp/preferred-root" })], { provider: "plugin" }, ); assert.equal(getRuntime(getSummary(summaries, 0)).session?.title, "Preferred Root Session"); - assert.equal(getRuntime(getSummary(summaries, 1)).session?.title, "Legacy Root Session"); - assert.equal(getRuntime(getSummary(summaries, 1)).status, "waiting-input"); } finally { restoreEnv(); } @@ -626,8 +595,8 @@ test("codex panes use a coarse command-backed runtime classification", async () }); test("sqlite provider reports a missing database as unknown runtime detail", async () => { - const dataHome = mkdtempSync(join(tmpdir(), "opencode-tmux-missing-db-")); - const restoreEnv = setEnv({ XDG_DATA_HOME: dataHome, OPENCODE_TMUX_STATE_DIR: undefined }); + const dataHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-missing-db-")); + const restoreEnv = setEnv({ XDG_DATA_HOME: dataHome, CODING_AGENTS_TMUX_STATE_DIR: undefined }); try { const summaries = await attachRuntimeToPanes([createDiscoveredPane()], { provider: "sqlite" }); @@ -673,7 +642,7 @@ test("auto provider keeps plugin matches and falls back to sqlite when server st ]); const { dataHome, databasePath } = createSqliteDataHome(); const restoreEnv = setEnv({ - OPENCODE_TMUX_STATE_DIR: pluginStateDir, + CODING_AGENTS_TMUX_STATE_DIR: pluginStateDir, XDG_DATA_HOME: dataHome, }); const database = initializeSqliteDatabase(databasePath); diff --git a/test/pi-plugin.test.ts b/test/pi-plugin.test.ts index 7b0fcd6..d6df738 100644 --- a/test/pi-plugin.test.ts +++ b/test/pi-plugin.test.ts @@ -34,7 +34,7 @@ function setEnv(updates: Record): () => void { } function installFakeTmux(script: string): { pathEntry: string; logPath: string } { - const dir = mkdtempSync(join(tmpdir(), "opencode-tmux-pi-plugin-fake-tmux-")); + const dir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-plugin-fake-tmux-")); const tmuxPath = join(dir, "tmux"); const logPath = join(dir, "tmux.log"); const resolvedScript = script.replaceAll("__LOG_PATH__", logPath); @@ -70,7 +70,7 @@ function readOnlyStateFile(stateDir: string): Record { } test("Pi plugin refreshes tmux clients after writing state", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-pi-plugin-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-plugin-state-")); const fakeTmux = installFakeTmux(` if [ "$1" = "display-message" ]; then printf 'work:1.1\n' @@ -85,7 +85,7 @@ exit 1 `); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_PI_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir, TMUX_PANE: "%42", }); @@ -124,11 +124,10 @@ exit 1 } }); -test("Pi plugin supports CODING_AGENTS_TMUX_PI_STATE_DIR as a state dir alias", async () => { +test("Pi plugin supports CODING_AGENTS_TMUX_PI_STATE_DIR as a state dir override", async () => { const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-plugin-state-")); const restoreEnv = setEnv({ CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir, - OPENCODE_TMUX_PI_STATE_DIR: undefined, TMUX_PANE: undefined, }); @@ -166,7 +165,7 @@ test("Pi plugin supports CODING_AGENTS_TMUX_PI_STATE_DIR as a state dir alias", }); test("Pi plugin refreshes tmux clients after removing state on shutdown", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-pi-plugin-state-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-plugin-state-")); const fakeTmux = installFakeTmux(` if [ "$1" = "display-message" ]; then printf 'work:1.1\n' @@ -181,7 +180,7 @@ exit 1 `); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_PI_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir, TMUX_PANE: "%42", }); diff --git a/test/pi.test.ts b/test/pi.test.ts index 80f5f9d..0e98526 100644 --- a/test/pi.test.ts +++ b/test/pi.test.ts @@ -63,7 +63,7 @@ function setEnv(updates: Record): () => void { } function createPiStateDir(states: Record[]): string { - const root = mkdtempSync(join(tmpdir(), "opencode-tmux-pi-state-")); + const root = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-state-")); states.forEach((state, index) => { writeFileSync(join(root, `state-${index + 1}.json`), JSON.stringify(state), "utf8"); @@ -73,7 +73,7 @@ function createPiStateDir(states: Record[]): string { } function installFakeTmux(script: string): { pathEntry: string } { - const dir = mkdtempSync(join(tmpdir(), "opencode-tmux-pi-fake-tmux-")); + const dir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-fake-tmux-")); const tmuxPath = join(dir, "tmux"); writeFileSync( @@ -89,7 +89,7 @@ ${script} return { pathEntry: dir }; } -test("Pi runtime supports new env aliases and both default state roots", async () => { +test("Pi runtime supports env override and default state root", async () => { const preferredStateDir = createPiStateDir([ { target: "work:1.0", @@ -102,7 +102,6 @@ test("Pi runtime supports new env aliases and both default state roots", async ( ]); const explicitEnvRestore = setEnv({ CODING_AGENTS_TMUX_PI_STATE_DIR: preferredStateDir, - OPENCODE_TMUX_PI_STATE_DIR: undefined, }); try { @@ -118,9 +117,7 @@ test("Pi runtime supports new env aliases and both default state roots", async ( const stateHome = mkdtempSync(join(tmpdir(), "coding-agents-tmux-pi-state-home-")); const preferredRoot = join(stateHome, "coding-agents-tmux", "pi-state"); - const legacyRoot = join(stateHome, "opencode-tmux", "pi-state"); mkdirSync(preferredRoot, { recursive: true }); - mkdirSync(legacyRoot, { recursive: true }); writeFileSync( join(preferredRoot, "preferred.json"), JSON.stringify({ @@ -132,21 +129,9 @@ test("Pi runtime supports new env aliases and both default state roots", async ( updatedAt: 200, }), ); - writeFileSync( - join(legacyRoot, "legacy.json"), - JSON.stringify({ - target: "work:1.2", - directory: "/tmp/pi-root-legacy", - title: "Legacy Root Pi Session", - status: "waiting-input", - activity: "busy", - updatedAt: 300, - }), - ); const restoreEnv = setEnv({ XDG_STATE_HOME: stateHome, CODING_AGENTS_TMUX_PI_STATE_DIR: undefined, - OPENCODE_TMUX_PI_STATE_DIR: undefined, }); try { @@ -157,18 +142,11 @@ test("Pi runtime supports new env aliases and both default state roots", async ( currentPath: "/tmp/pi-root-preferred", paneIndex: 1, }), - createDiscoveredPiPane({ - target: "work:1.2", - currentPath: "/tmp/pi-root-legacy", - paneIndex: 2, - }), ], { provider: "plugin" }, ); assert.equal(summaries[0]?.runtime?.session?.title, "Preferred Root Pi Session"); - assert.equal(summaries[1]?.runtime?.session?.title, "Legacy Root Pi Session"); - assert.equal(summaries[1]?.runtime?.status, "waiting-input"); } finally { restoreEnv(); } @@ -201,7 +179,7 @@ test("Pi runtime matches panes by target, pane id, and unique cwd fallback", asy updatedAt: 300, }, ]); - const restoreEnv = setEnv({ OPENCODE_TMUX_PI_STATE_DIR: stateDir }); + const restoreEnv = setEnv({ CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir }); try { const summaries = await attachRuntimeToPanes([ @@ -250,7 +228,7 @@ exit 1 ]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_PI_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir, }); try { @@ -281,7 +259,7 @@ exit 1 const stateDir = createPiStateDir([]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_PI_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir, }); try { @@ -309,7 +287,7 @@ exit 1 const stateDir = createPiStateDir([]); const restoreEnv = setEnv({ PATH: `${fakeTmux.pathEntry}:${process.env.PATH ?? ""}`, - OPENCODE_TMUX_PI_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_PI_STATE_DIR: stateDir, }); try { diff --git a/test/plugin.test.ts b/test/plugin.test.ts index 554d782..88cbc36 100644 --- a/test/plugin.test.ts +++ b/test/plugin.test.ts @@ -42,14 +42,10 @@ async function loadPlugin() { return import(`../plugin/coding-agents-tmux.ts?test=${Math.random()}`); } -async function loadLegacyPluginAlias() { - return import(`../plugin/opencode-tmux.ts?test=${Math.random()}`); -} - test("plugin preserves waiting state for ambiguous session.status heartbeats", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-plugin-test-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-plugin-test-")); const restoreEnv = setEnv({ - OPENCODE_TMUX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_STATE_DIR: stateDir, TMUX: undefined, TMUX_PANE: undefined, }); @@ -74,11 +70,10 @@ test("plugin preserves waiting state for ambiguous session.status heartbeats", a } }); -test("plugin supports CODING_AGENTS_TMUX_STATE_DIR as a state dir alias", async () => { +test("plugin supports CODING_AGENTS_TMUX_STATE_DIR as a state dir override", async () => { const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-plugin-test-")); const restoreEnv = setEnv({ CODING_AGENTS_TMUX_STATE_DIR: stateDir, - OPENCODE_TMUX_STATE_DIR: undefined, TMUX: undefined, TMUX_PANE: undefined, }); @@ -101,37 +96,10 @@ test("plugin supports CODING_AGENTS_TMUX_STATE_DIR as a state dir alias", async } }); -test("legacy plugin filename still re-exports the plugin", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-plugin-legacy-test-")); - const restoreEnv = setEnv({ - CODING_AGENTS_TMUX_STATE_DIR: stateDir, - OPENCODE_TMUX_STATE_DIR: undefined, - TMUX: undefined, - TMUX_PANE: undefined, - }); - - try { - const { OpencodeTmuxPlugin } = await loadLegacyPluginAlias(); - const plugin = await OpencodeTmuxPlugin({ - directory: "/tmp/project", - project: { name: "Project" }, - client: { app: { log: async () => null } }, - }); - - await plugin.event({ event: { type: "session.idle", timeUpdated: 100 } }); - - const state = readOnlyStateFile(stateDir); - assert.equal(state.status, "idle"); - assert.equal(state.title, "Project"); - } finally { - restoreEnv(); - } -}); - test("plugin switches back to running when session.status explicitly reports busy after a reply", async () => { - const stateDir = mkdtempSync(join(tmpdir(), "opencode-tmux-plugin-test-")); + const stateDir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-plugin-test-")); const restoreEnv = setEnv({ - OPENCODE_TMUX_STATE_DIR: stateDir, + CODING_AGENTS_TMUX_STATE_DIR: stateDir, TMUX: undefined, TMUX_PANE: undefined, }); diff --git a/test/render.test.ts b/test/render.test.ts index 2bade32..0a6a334 100644 --- a/test/render.test.ts +++ b/test/render.test.ts @@ -33,7 +33,7 @@ function createPane(overrides: Partial = {}): TmuxPane { paneId: overrides.paneId ?? `%${paneIndex + 1}`, paneTitle: overrides.paneTitle ?? "OpenCode", currentCommand: overrides.currentCommand ?? "opencode", - currentPath: overrides.currentPath ?? "/Users/corwin/Developer/opencode-tmux", + currentPath: overrides.currentPath ?? "/Users/corwin/Developer/coding-agents-tmux", isActive: overrides.isActive ?? false, tty: overrides.tty ?? "/dev/ttys001", target: overrides.target ?? `${sessionName}:${windowIndex}.${paneIndex}`, @@ -291,7 +291,7 @@ test("renderCompactPaneList prints tab-separated rows", () => { assert.equal( renderCompactPaneList([pane]), - "work:1.0\tidle\tidle\tplugin-exact\t1\tSession Title\tOpenCode\t/Users/corwin/Developer/opencode-tmux", + "work:1.0\tidle\tidle\tplugin-exact\t1\tSession Title\tOpenCode\t/Users/corwin/Developer/coding-agents-tmux", ); assert.equal(renderCompactPaneList([]), ""); }); @@ -308,7 +308,7 @@ test("renderCompactPaneList falls back to unmatched and untitled labels", () => assert.equal( renderCompactPaneList([pane]), - "work:1.1\tunknown\tunknown\tunmapped\t0\t(unmatched)\t(untitled)\t/Users/corwin/Developer/opencode-tmux", + "work:1.1\tunknown\tunknown\tunmapped\t0\t(unmatched)\t(untitled)\t/Users/corwin/Developer/coding-agents-tmux", ); }); diff --git a/test/tmux-plugin-rename.test.ts b/test/tmux-plugin-rename.test.ts index a186a11..72b933e 100644 --- a/test/tmux-plugin-rename.test.ts +++ b/test/tmux-plugin-rename.test.ts @@ -70,7 +70,7 @@ exit 0 chmodSync(npmPath, 0o755); } -test("coding-agents-tmux.tmux prefers new tmux option aliases over legacy names", async () => { +test("coding-agents-tmux.tmux reads renamed tmux options", async () => { const fakeTmux = installFakeTmux(` log_path='__LOG_PATH__' option="\${!#}" @@ -81,7 +81,7 @@ show-option) @coding-agents-tmux-menu-key) printf 'N\n' ;; - @opencode-tmux-menu-key) + @coding-agents-tmux-menu-key) printf 'O\n' ;; @coding-agents-tmux-status) @@ -113,7 +113,7 @@ exit 1 } }); -test("coding-agents-tmux.tmux installs new and legacy plugin integration paths", async () => { +test("coding-agents-tmux.tmux installs renamed plugin integration paths", async () => { const fakeTmux = installFakeTmux(` log_path='__LOG_PATH__' option="\${!#}" @@ -149,31 +149,17 @@ exit 1 try { const result = await runCommand([join(process.cwd(), "coding-agents-tmux.tmux")]); - const newPluginPath = join(configHome, "opencode", "plugins", "coding-agents-tmux.ts"); - const legacyPluginPath = join(configHome, "opencode", "plugins", "opencode-tmux.ts"); - const newPiExtensionPath = join(piHome, "extensions", "coding-agents-tmux", "index.ts"); - const legacyPiExtensionPath = join(piHome, "extensions", "opencode-tmux", "index.ts"); + const pluginPath = join(configHome, "opencode", "plugins", "coding-agents-tmux.ts"); + const piExtensionPath = join(piHome, "extensions", "coding-agents-tmux", "index.ts"); assert.equal(result.exitCode, 0); assert.equal(result.stderrText.trim(), ""); - assert.ok(existsSync(newPluginPath)); - assert.ok(existsSync(legacyPluginPath)); - assert.ok(existsSync(newPiExtensionPath)); - assert.ok(existsSync(legacyPiExtensionPath)); - assert.ok(lstatSync(newPluginPath).isSymbolicLink()); - assert.ok(lstatSync(legacyPluginPath).isSymbolicLink()); - assert.ok(lstatSync(newPiExtensionPath).isSymbolicLink()); - assert.ok(lstatSync(legacyPiExtensionPath).isSymbolicLink()); - assert.equal( - readlinkSync(newPluginPath), - join(process.cwd(), "plugin", "coding-agents-tmux.ts"), - ); - assert.equal( - readlinkSync(legacyPluginPath), - join(process.cwd(), "plugin", "coding-agents-tmux.ts"), - ); - assert.equal(readlinkSync(newPiExtensionPath), join(process.cwd(), "plugin", "pi-tmux.ts")); - assert.equal(readlinkSync(legacyPiExtensionPath), join(process.cwd(), "plugin", "pi-tmux.ts")); + assert.ok(existsSync(pluginPath)); + assert.ok(existsSync(piExtensionPath)); + assert.ok(lstatSync(pluginPath).isSymbolicLink()); + assert.ok(lstatSync(piExtensionPath).isSymbolicLink()); + assert.equal(readlinkSync(pluginPath), join(process.cwd(), "plugin", "coding-agents-tmux.ts")); + assert.equal(readlinkSync(piExtensionPath), join(process.cwd(), "plugin", "pi-tmux.ts")); } finally { restoreEnv(); } diff --git a/test/tmux.test.ts b/test/tmux.test.ts index 35e5a63..faccbff 100644 --- a/test/tmux.test.ts +++ b/test/tmux.test.ts @@ -62,7 +62,7 @@ function setEnv(updates: Record): () => void { } function installFakeTmux(script: string): { pathEntry: string; logPath: string } { - const dir = mkdtempSync(join(tmpdir(), "opencode-tmux-fake-tmux-")); + const dir = mkdtempSync(join(tmpdir(), "coding-agents-tmux-fake-tmux-")); const tmuxPath = join(dir, "tmux"); const logPath = join(dir, "tmux.log"); const resolvedScript = script.replaceAll("__LOG_PATH__", logPath);