@alexcrondon/tx 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
1
+ # lib/completions.sh — tx completions command
2
+
3
+ cmd_completions() {
4
+ cat << 'EOF'
5
+ # tx shell completions
6
+ _tx() {
7
+ local commands="config status serv tunnel db wt code nuke completions help"
8
+
9
+ if [ "$CURRENT" -eq 2 ]; then
10
+ compadd ${=commands}
11
+ return
12
+ fi
13
+
14
+ case "${words[2]}" in
15
+ config)
16
+ if [ "$CURRENT" -eq 3 ]; then
17
+ compadd port start url branch copy worktrees_dir code tunnel db auto_open init reset
18
+ elif [ "$CURRENT" -eq 4 ] && [ "${words[3]}" = "reset" ]; then
19
+ compadd user project
20
+ fi
21
+ ;;
22
+ serv)
23
+ if [ "$CURRENT" -eq 3 ]; then
24
+ compadd start stop restart open list log
25
+ else
26
+ compadd -- --open --front --port
27
+ fi
28
+ ;;
29
+ tunnel)
30
+ if [ "$CURRENT" -eq 3 ]; then
31
+ compadd start stop status
32
+ else
33
+ compadd -- --caffeinate
34
+ fi
35
+ ;;
36
+ db)
37
+ if [ "$CURRENT" -eq 3 ]; then
38
+ compadd start stop status log
39
+ fi
40
+ ;;
41
+ wt)
42
+ if [ "$CURRENT" -eq 3 ]; then
43
+ compadd add remove list clean
44
+ else
45
+ compadd -- --name --branch
46
+ fi
47
+ ;;
48
+ code)
49
+ if [ "$CURRENT" -eq 3 ]; then
50
+ compadd start attach
51
+ else
52
+ compadd -- --root --tunnel --name --branch --attach --caffeinate
53
+ fi
54
+ ;;
55
+ esac
56
+ }
57
+ compdef _tx tx
58
+ EOF
59
+ }
package/lib/config.sh ADDED
@@ -0,0 +1,174 @@
1
+ # lib/config.sh — tx config command
2
+
3
+ cmd_config() {
4
+ local subcommand="${1:-}"
5
+ shift 2>/dev/null || true
6
+
7
+ # tx config init
8
+ if [ "$subcommand" = "init" ]; then
9
+ _config_init
10
+ return $?
11
+ fi
12
+
13
+ # tx config reset [user|project]
14
+ if [ "$subcommand" = "reset" ]; then
15
+ local target="${1:-project}"
16
+ local file=""
17
+ case "$target" in
18
+ user) file="${HOME}/.txrc" ;;
19
+ project) file=".txrc" ;;
20
+ *)
21
+ echo "tx config reset: unknown target '$target'"
22
+ echo "Usage: tx config reset [user|project]"
23
+ return 1
24
+ ;;
25
+ esac
26
+ if [ ! -f "$file" ]; then
27
+ echo "No config file found: $file"
28
+ else
29
+ printf "Delete %s? [y/N] " "$file"
30
+ read -r answer
31
+ case "$answer" in
32
+ y|Y|yes|YES) rm -f "$file"; echo "Deleted $file" ;;
33
+ *) echo "Aborted." ;;
34
+ esac
35
+ fi
36
+ return 0
37
+ fi
38
+
39
+ # tx config (no args) — show current config
40
+ if [ -z "$subcommand" ]; then
41
+ echo "Configuration (user: ~/.txrc, project: .txrc)"
42
+ echo ""
43
+ for key in $TX_CONFIG_KEYS; do
44
+ local var scope
45
+ var=$(tx_config_var "$key")
46
+ scope=$(tx_config_scope "$key")
47
+ eval "local val=\$$var"
48
+ printf " %-15s %-8s %s\n" "$key" "($scope)" "$val"
49
+ done
50
+ return 0
51
+ fi
52
+
53
+ # tx config <key> <value>
54
+ local key="$subcommand"
55
+ local value="${1:-}"
56
+
57
+ if [ -z "$value" ]; then
58
+ # Show single key value
59
+ local var
60
+ var=$(tx_config_var "$key")
61
+ if [ -z "$var" ]; then
62
+ echo "Unknown config key: $key"
63
+ echo "Available keys: $TX_CONFIG_KEYS"
64
+ return 1
65
+ fi
66
+ eval "local val=\$$var"
67
+ echo "$val"
68
+ return 0
69
+ fi
70
+
71
+ local var scope file
72
+ var=$(tx_config_var "$key")
73
+ if [ -z "$var" ]; then
74
+ echo "Unknown config key: $key"
75
+ echo "Available keys: $TX_CONFIG_KEYS"
76
+ return 1
77
+ fi
78
+
79
+ scope=$(tx_config_scope "$key")
80
+ file=$(tx_config_file "$scope")
81
+ [ -f "$file" ] || touch "$file"
82
+
83
+ # --unset: remove the key from the config file, reverting to default
84
+ if [ "$value" = "--unset" ]; then
85
+ grep -v "^${var}=" "$file" > "$file.tmp" 2>/dev/null || true
86
+ mv "$file.tmp" "$file"
87
+ local default
88
+ default=$(tx_config_default "$key")
89
+ if [ -n "$default" ]; then
90
+ echo "Unset $key, reverted to default: $default ($scope: $file)"
91
+ else
92
+ echo "Unset $key ($scope: $file)"
93
+ fi
94
+ return 0
95
+ fi
96
+
97
+ # Update or append (grep+sed is unsafe with special chars, so delete+append)
98
+ grep -v "^${var}=" "$file" > "$file.tmp" 2>/dev/null || true
99
+ printf '%s="%s"\n' "$var" "$value" >> "$file.tmp"
100
+ mv "$file.tmp" "$file"
101
+
102
+ echo "Set $key = $value ($scope: $file)"
103
+ }
104
+
105
+ _config_init() {
106
+ echo "Initializing config — press Enter to keep default."
107
+ echo "User config: ~/.txrc | Project config: .txrc"
108
+ echo ""
109
+
110
+ for key in $TX_CONFIG_KEYS; do
111
+ local var scope file
112
+ var=$(tx_config_var "$key")
113
+ scope=$(tx_config_scope "$key")
114
+ file=$(tx_config_file "$scope")
115
+ eval "local default=\$$var"
116
+
117
+ if [ -n "$default" ]; then
118
+ printf " %s (%s) [%s]: " "$key" "$scope" "$default"
119
+ else
120
+ printf " %s (%s) (no default): " "$key" "$scope"
121
+ fi
122
+
123
+ read -r input
124
+ if [ -n "$input" ]; then
125
+ [ -f "$file" ] || touch "$file"
126
+ grep -v "^${var}=" "$file" > "$file.tmp" 2>/dev/null || true
127
+ printf '%s="%s"\n' "$var" "$input" >> "$file.tmp"
128
+ mv "$file.tmp" "$file"
129
+ fi
130
+ done
131
+
132
+ echo ""
133
+
134
+ # Offer to enable Claude Code sandbox for this project
135
+ printf " Enable Claude Code sandbox for this project? (y/N)\n"
136
+ printf " (This will modify .claude/settings.local.json in this repo)\n"
137
+ printf " > "
138
+ read -r sandbox_answer
139
+ case "$sandbox_answer" in
140
+ y|Y|yes|YES)
141
+ _config_enable_sandbox
142
+ ;;
143
+ esac
144
+
145
+ echo ""
146
+ echo "Done."
147
+ }
148
+
149
+ _config_enable_sandbox() {
150
+ local settings_dir=".claude"
151
+ local settings_file="$settings_dir/settings.local.json"
152
+
153
+ mkdir -p "$settings_dir"
154
+
155
+ if [ ! -f "$settings_file" ]; then
156
+ # Create new settings file with sandbox config
157
+ cat > "$settings_file" <<'SETTINGS'
158
+ {
159
+ "sandbox": {
160
+ "enabled": true,
161
+ "autoAllow": true
162
+ }
163
+ }
164
+ SETTINGS
165
+ echo " Created $settings_file with sandbox enabled."
166
+ elif grep -q '"sandbox"' "$settings_file" 2>/dev/null; then
167
+ echo " Sandbox already configured in $settings_file."
168
+ else
169
+ # Insert sandbox config after opening brace
170
+ sed '1s/{/{\'$'\n'" \"sandbox\": { \"enabled\": true, \"autoAllow\": true },/" "$settings_file" > "$settings_file.tmp"
171
+ mv "$settings_file.tmp" "$settings_file"
172
+ echo " Added sandbox config to $settings_file."
173
+ fi
174
+ }
package/lib/db.sh ADDED
@@ -0,0 +1,91 @@
1
+ # lib/db.sh — tx db command
2
+
3
+ TX_DB_PID_FILE="/tmp/tx-db.pid"
4
+ TX_DB_LOG_FILE="/tmp/tx-db.log"
5
+
6
+ cmd_db() {
7
+ local subcommand="${1:-status}"
8
+ shift 2>/dev/null || true
9
+
10
+ case "$subcommand" in
11
+ start) _db_start ;;
12
+ stop) _db_stop ;;
13
+ status) _db_status ;;
14
+ log) _db_log ;;
15
+ *)
16
+ echo "tx db: unknown subcommand '$subcommand'"
17
+ echo "Usage: tx db [start|stop|status|log]"
18
+ return 1
19
+ ;;
20
+ esac
21
+ }
22
+
23
+ _db_start() {
24
+ if [ -z "$TX_DB_CMD" ]; then
25
+ echo "No db command configured."
26
+ echo "Set one with: tx config db \"<command>\""
27
+ return 1
28
+ fi
29
+
30
+ # Check if already running
31
+ if [ -f "$TX_DB_PID_FILE" ]; then
32
+ local pid
33
+ pid=$(cat "$TX_DB_PID_FILE")
34
+ if tx_is_alive "$pid"; then
35
+ echo "Already running (PID $pid)."
36
+ return 1
37
+ else
38
+ rm -f "$TX_DB_PID_FILE"
39
+ fi
40
+ fi
41
+
42
+ echo "Starting: $TX_DB_CMD"
43
+ eval "$TX_DB_CMD" > "$TX_DB_LOG_FILE" 2>&1 &
44
+ echo $! > "$TX_DB_PID_FILE"
45
+ echo "Running (PID $!)."
46
+ }
47
+
48
+ _db_stop() {
49
+ if [ ! -f "$TX_DB_PID_FILE" ]; then
50
+ echo "Not running."
51
+ return 0
52
+ fi
53
+
54
+ local pid
55
+ pid=$(cat "$TX_DB_PID_FILE")
56
+ if tx_is_alive "$pid"; then
57
+ kill "$pid" 2>/dev/null || true
58
+ pkill -P "$pid" 2>/dev/null || true
59
+ echo "Stopped (PID $pid)."
60
+ else
61
+ echo "Not running (stale PID)."
62
+ fi
63
+ rm -f "$TX_DB_PID_FILE"
64
+ rm -f "$TX_DB_LOG_FILE"
65
+ }
66
+
67
+ _db_status() {
68
+ if [ ! -f "$TX_DB_PID_FILE" ]; then
69
+ echo "Not running."
70
+ return 0
71
+ fi
72
+
73
+ local pid
74
+ pid=$(cat "$TX_DB_PID_FILE")
75
+ if tx_is_alive "$pid"; then
76
+ echo "Running (PID $pid)"
77
+ echo "Command: $TX_DB_CMD"
78
+ else
79
+ echo "Not running (stale PID)."
80
+ rm -f "$TX_DB_PID_FILE"
81
+ fi
82
+ }
83
+
84
+ _db_log() {
85
+ if [ ! -f "$TX_DB_LOG_FILE" ]; then
86
+ echo "No log file. Is db running?"
87
+ return 1
88
+ fi
89
+
90
+ cat "$TX_DB_LOG_FILE"
91
+ }
package/lib/help.sh ADDED
@@ -0,0 +1,192 @@
1
+ # lib/help.sh — tx help command
2
+
3
+ _help_config() {
4
+ cat << 'EOF'
5
+ tx config — Manage configuration (user: ~/.txrc, project: .txrc)
6
+
7
+ Usage:
8
+ tx config Show current configuration
9
+ tx config <key> <value> Set a configuration value
10
+ tx config init Interactive setup (writes to appropriate file per key)
11
+ tx config reset [user|project] Delete config file (with confirmation)
12
+
13
+ Keys:
14
+ User (~/.txrc): code, tunnel, auto_open, db, auto_tmux
15
+ Project (.txrc): port, start, url, branch, copy, worktrees_dir
16
+ EOF
17
+ }
18
+
19
+ _help_serv() {
20
+ cat << 'EOF'
21
+ tx serv — Manage dev servers
22
+
23
+ Usage:
24
+ tx serv List all running servers (default)
25
+ tx serv start Start dev server (background by default)
26
+ tx serv start "<cmd>" Start with custom command
27
+ tx serv stop Stop server for current directory
28
+ tx serv stop all Stop all tx-managed servers
29
+ tx serv restart Restart server (same port)
30
+ tx serv open Open dev URL in browser
31
+ tx serv log Show server output log
32
+
33
+ Flags:
34
+ -o, --open Open browser after starting
35
+ -f, --front Run in foreground
36
+ -p, --port N Use specific port
37
+ EOF
38
+ }
39
+
40
+ _help_tunnel() {
41
+ cat << 'EOF'
42
+ tx tunnel — Manage SSH tunnels (ngrok)
43
+
44
+ Usage:
45
+ tx tunnel Show tunnel status (default)
46
+ tx tunnel start Start SSH tunnel
47
+ tx tunnel stop Stop SSH tunnel
48
+
49
+ Flags:
50
+ -c, --caffeinate Prevent sleep while tunnel is open
51
+ EOF
52
+ }
53
+
54
+ _help_db() {
55
+ cat << 'EOF'
56
+ tx db — Manage background db process (port-forward, etc.)
57
+
58
+ Usage:
59
+ tx db Show db process status (default)
60
+ tx db start Start configured db command in background
61
+ tx db stop Stop the db process
62
+ tx db log Show db process output
63
+ EOF
64
+ }
65
+
66
+ _help_wt() {
67
+ cat << 'EOF'
68
+ tx wt — Manage git worktrees
69
+
70
+ Usage:
71
+ tx wt List all worktrees (default)
72
+ tx wt add Create/reuse a git worktree
73
+ tx wt remove Remove a worktree (and its server)
74
+ tx wt clean Remove all worktrees
75
+
76
+ Flags:
77
+ -n, --name NAME Worktree name
78
+ -b, --branch BRANCH Branch to checkout (also used as worktree name if -n omitted, / → -)
79
+ -i, --install Run install command after creating worktree (TX_INSTALL_CMD)
80
+ EOF
81
+ }
82
+
83
+ _help_code() {
84
+ cat << 'EOF'
85
+ tx code — Launch code editors/agents (claude, tmux)
86
+
87
+ Usage:
88
+ tx code Launch in worktree (default), or repo root with -r
89
+ tx code attach [name] Attach to tmux session (interactive picker if no name)
90
+
91
+ Flags:
92
+ -r, --root Run in repo root instead of worktree
93
+ -t, --tunnel Launch in tmux session
94
+ -n, --name NAME Worktree/session name
95
+ -b, --branch BRANCH Branch to checkout (also used as worktree name, / → -)
96
+ -a, --attach Attach to existing session
97
+ -c, --caffeinate Prevent sleep
98
+ -i, --install Run install command after creating worktree (TX_INSTALL_CMD)
99
+ EOF
100
+ }
101
+
102
+ _help_nuke() {
103
+ cat << 'EOF'
104
+ tx nuke — Stop everything and remove all worktrees
105
+
106
+ Usage:
107
+ tx nuke Stop all servers, tunnels, db, remove worktrees (with confirmation)
108
+ EOF
109
+ }
110
+
111
+ _help_status() {
112
+ cat << 'EOF'
113
+ tx status — Show status of all managed processes
114
+
115
+ Usage:
116
+ tx status Show sessions, servers, tunnel, db, and worktree status
117
+
118
+ Sessions are listed globally (all tx tmux sessions across all projects).
119
+ EOF
120
+ }
121
+
122
+ _help_completions() {
123
+ cat << 'EOF'
124
+ tx completions — Output zsh completion script
125
+
126
+ Usage:
127
+ tx completions Print zsh completions (eval or source in .zshrc)
128
+ EOF
129
+ }
130
+
131
+ _help_overview() {
132
+ cat << 'EOF'
133
+ tx — modular CLI for isolated dev environments
134
+
135
+ Usage: tx [command] [subcommand] [flags]
136
+ (no command = status)
137
+
138
+ Commands:
139
+ config Manage project configuration (.txrc)
140
+ status Show status (default when no command given)
141
+ serv Manage dev servers (list by default)
142
+ tunnel Manage SSH tunnels (status by default)
143
+ db Manage background db process (status by default)
144
+ wt Manage git worktrees (list by default)
145
+ code Launch code editors/agents (claude, tmux)
146
+ nuke Stop everything and remove all worktrees
147
+ completions Output zsh completion script
148
+ help Show this help message
149
+
150
+ Run 'tx help <command>' for details on a specific command.
151
+
152
+ Examples:
153
+ tx Show status (default)
154
+ tx serv List running servers
155
+ tx serv start -o -p 3000 Start on port 3000, open browser
156
+ tx serv stop all Kill all dev servers
157
+ tx wt add -n hotfix Create worktree named "hotfix"
158
+ tx wt add -b fix/my-bug Create worktree fix-my-bug on branch fix/my-bug
159
+ tx code -b fix/my-bug Create worktree fix-my-bug on branch fix/my-bug
160
+ tx code -t Create worktree + launch in tmux session
161
+ tx code attach hotfix Reattach to tmux session
162
+ tx tunnel start -c Start SSH tunnel with caffeinate
163
+ tx config start "npm start" Set default start command
164
+ EOF
165
+ }
166
+
167
+ cmd_help() {
168
+ local command="${1:-}"
169
+
170
+ if [ -z "$command" ]; then
171
+ _help_overview
172
+ return 0
173
+ fi
174
+
175
+ case "$command" in
176
+ config) _help_config ;;
177
+ serv) _help_serv ;;
178
+ tunnel) _help_tunnel ;;
179
+ db) _help_db ;;
180
+ wt) _help_wt ;;
181
+ code) _help_code ;;
182
+ nuke) _help_nuke ;;
183
+ status) _help_status ;;
184
+ completions) _help_completions ;;
185
+ help) echo "Usage: tx help [command]" ;;
186
+ *)
187
+ echo "tx help: unknown command '$command'"
188
+ echo "Run 'tx help' for a list of commands."
189
+ return 1
190
+ ;;
191
+ esac
192
+ }
package/lib/nuke.sh ADDED
@@ -0,0 +1,58 @@
1
+ # lib/nuke.sh — tx nuke command
2
+
3
+ # Source dependencies
4
+ . "$TX_ROOT/lib/serv.sh"
5
+ . "$TX_ROOT/lib/tunnel.sh"
6
+ . "$TX_ROOT/lib/db.sh"
7
+ . "$TX_ROOT/lib/wt.sh"
8
+
9
+ cmd_nuke() {
10
+ printf "This will stop all services and remove all worktrees. Continue? [y/N] "
11
+ read -r answer
12
+ case "$answer" in
13
+ y|Y|yes|YES) ;;
14
+ *) echo "Aborted."; return 0 ;;
15
+ esac
16
+
17
+ echo "=== Stopping all servers ==="
18
+ _serv_stop "all"
19
+
20
+ echo ""
21
+ echo "=== Stopping tunnel ==="
22
+ _tunnel_stop
23
+
24
+ echo ""
25
+ echo "=== Stopping db ==="
26
+ _db_stop
27
+
28
+ echo ""
29
+ echo "=== Killing caffeinate ==="
30
+ local killed=0
31
+ if [ -f "/tmp/tx-tunnel-caff.pid" ]; then
32
+ local cpid
33
+ cpid=$(cat "/tmp/tx-tunnel-caff.pid")
34
+ kill "$cpid" 2>/dev/null || true
35
+ rm -f "/tmp/tx-tunnel-caff.pid"
36
+ killed=1
37
+ fi
38
+ pkill -f "caffeinate -dims" 2>/dev/null && killed=1 || true
39
+ [ "$killed" -eq 1 ] && echo "Stopped." || echo "Not running."
40
+
41
+ echo ""
42
+ echo "=== Killing tx tmux sessions ==="
43
+ local sessions
44
+ sessions=$(tx_list_sessions)
45
+ if [ -n "$sessions" ]; then
46
+ echo "$sessions" | while IFS= read -r s; do
47
+ local display
48
+ display=$(tx_display_name "$s")
49
+ tmux kill-session -t "$s" 2>/dev/null && echo "Killed: $display" || true
50
+ done
51
+ else
52
+ echo " (none)"
53
+ fi
54
+
55
+ echo ""
56
+ echo "=== Removing worktrees ==="
57
+ _wt_clean --yes
58
+ }