sxn 0.2.2 → 0.2.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/Gemfile.lock +1 -1
- data/README.md +76 -8
- data/lib/sxn/CLI.rb +99 -4
- data/lib/sxn/commands/init.rb +136 -0
- data/lib/sxn/commands/sessions.rb +197 -7
- data/lib/sxn/commands/worktrees.rb +40 -5
- data/lib/sxn/core/config_manager.rb +17 -1
- data/lib/sxn/core/project_manager.rb +19 -2
- data/lib/sxn/core/rules_manager.rb +61 -3
- data/lib/sxn/core/session_config.rb +91 -0
- data/lib/sxn/core/session_manager.rb +21 -1
- data/lib/sxn/core/worktree_manager.rb +133 -7
- data/lib/sxn/core.rb +1 -0
- data/lib/sxn/errors.rb +10 -1
- data/lib/sxn/ui/prompt.rb +4 -0
- data/lib/sxn/version.rb +1 -1
- data/script/setup-hooks +52 -0
- data/sxn.gemspec +85 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30ceb6fb94a023b31e9b9c4c4354806a5343b7cefa8f1b43047011f86e3048cf
|
|
4
|
+
data.tar.gz: 071b888de74d9e284376acf2ed425a5a33ddf329ac01112bc3fbc65acc8dd363
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93cb3f85f80ccc13ffcc62662fa86bd0e8b7531105ab08dc49f0213744a858bbaf7fff8823c2d5358617704eeb5aae6f2264ba02f20e14c71003fd8e912136d4
|
|
7
|
+
data.tar.gz: fc1e076616d354218525d2d8ee6a6454a04dfd5d1db969f7032792c91ec1679605a4d0351573a57cd3b5af64c8d06fdecad1068b51dfd66bc2bea5c92bc52dfc
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,54 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.5] - 2025-11-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `sxn enter` command to quickly navigate to current session directory
|
|
12
|
+
- `sxn current enter` subcommand as alternative way to enter session
|
|
13
|
+
- `--path` option for `sxn current` to output only the session path
|
|
14
|
+
- `sxn shell` command to install shell integration (idempotent)
|
|
15
|
+
- Auto-detects shell type (bash/zsh)
|
|
16
|
+
- Installs `sxn-enter` function to shell config
|
|
17
|
+
- Supports `--uninstall` to remove integration
|
|
18
|
+
- Supports `--shell-type` to specify shell explicitly
|
|
19
|
+
|
|
20
|
+
## [0.2.4] - 2025-11-30
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- Interactive worktree wizard after session creation
|
|
24
|
+
- Prompts to add worktrees with descriptive explanations
|
|
25
|
+
- Supports adding multiple worktrees in sequence
|
|
26
|
+
- Explains branch options including remote tracking syntax
|
|
27
|
+
- `--skip-worktree` flag to bypass the wizard when creating sessions
|
|
28
|
+
- `--verbose` flag for worktree debugging with detailed git output
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- Sessions now automatically switch to newly created session (no need to run `sxn use` afterwards)
|
|
32
|
+
- Improved project manager to safely handle nil projects configuration
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
- Fixed test mocks for verbose parameter in worktree operations
|
|
36
|
+
- Fixed version spec to support semver pre-release format
|
|
37
|
+
|
|
38
|
+
## [0.2.3] - 2025-09-16
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
- Smart branch defaults: worktrees now use session name as default branch
|
|
42
|
+
- Remote branch tracking with `remote:` prefix syntax (e.g., `sxn worktree add project remote:origin/feature`)
|
|
43
|
+
- Automatic orphaned worktree recovery and cleanup
|
|
44
|
+
- Enhanced error messages with actionable suggestions
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
- Improved worktree creation logic to handle existing/orphaned states
|
|
48
|
+
- Better error handling for remote branch operations
|
|
49
|
+
- Updated CLI documentation with new branch options
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
- Orphaned worktree cleanup now works for both existing and missing directories
|
|
53
|
+
- Worktree creation properly handles branch conflicts
|
|
54
|
+
- Test suite compatibility with new worktree features
|
|
55
|
+
|
|
8
56
|
## [0.2.1] - 2025-01-20
|
|
9
57
|
|
|
10
58
|
### Fixed
|
|
@@ -53,5 +101,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
53
101
|
- Initial placeholder release
|
|
54
102
|
- Basic gem structure
|
|
55
103
|
|
|
104
|
+
[0.2.4]: https://github.com/idl3/sxn/compare/v0.2.3...v0.2.4
|
|
105
|
+
[0.2.3]: https://github.com/idl3/sxn/compare/v0.2.1...v0.2.3
|
|
106
|
+
[0.2.1]: https://github.com/idl3/sxn/compare/v0.2.0...v0.2.1
|
|
56
107
|
[0.2.0]: https://github.com/idl3/sxn/compare/v0.1.0...v0.2.0
|
|
57
108
|
[0.1.0]: https://github.com/idl3/sxn/releases/tag/v0.1.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# sxn
|
|
2
2
|
|
|
3
3
|
[](https://github.com/idl3/sxn/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.ruby-lang.org)
|
|
5
5
|
[](LICENSE.txt)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
sxn is a powerful session management tool for multi-repository development. It helps developers manage complex development environments with multiple git repositories, providing isolated workspaces, automatic project setup, and intelligent session management.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -38,7 +38,7 @@ gem install sxn
|
|
|
38
38
|
|
|
39
39
|
## Quick Start
|
|
40
40
|
|
|
41
|
-
### Initialize
|
|
41
|
+
### Initialize sxn in your workspace
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
sxn init
|
|
@@ -135,7 +135,7 @@ sxn rules apply my-app
|
|
|
135
135
|
|
|
136
136
|
## Configuration
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
sxn stores its configuration in `.sxn/config.yml` in your workspace:
|
|
139
139
|
|
|
140
140
|
```yaml
|
|
141
141
|
sessions_folder: .sxn-sessions
|
|
@@ -168,7 +168,7 @@ rules:
|
|
|
168
168
|
|
|
169
169
|
## Templates
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
sxn includes templates for common project types:
|
|
172
172
|
|
|
173
173
|
- **Rails**: CLAUDE.md, database.yml, session-info.md
|
|
174
174
|
- **JavaScript**: README.md, session-info.md
|
|
@@ -178,19 +178,87 @@ Templates use Liquid syntax and have access to session, project, and environment
|
|
|
178
178
|
|
|
179
179
|
## Development
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
### Setup
|
|
182
182
|
|
|
183
|
-
|
|
183
|
+
After cloning the repository, run:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
bundle install
|
|
187
|
+
./script/setup-hooks # Set up git hooks for automated checks
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Testing and Code Quality
|
|
191
|
+
|
|
192
|
+
**Important**: All code must pass tests and linting before being pushed to the repository.
|
|
193
|
+
|
|
194
|
+
#### Running Tests
|
|
184
195
|
|
|
185
196
|
```bash
|
|
186
197
|
# Run all tests
|
|
187
198
|
bundle exec rspec
|
|
188
199
|
|
|
200
|
+
# Run tests in parallel (faster)
|
|
201
|
+
bundle exec rake parallel:spec
|
|
202
|
+
|
|
203
|
+
# Run with coverage report
|
|
204
|
+
bundle exec rake parallel:spec_with_coverage
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Code Style
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Check code style
|
|
211
|
+
bundle exec rubocop
|
|
212
|
+
|
|
213
|
+
# Auto-fix code style issues
|
|
214
|
+
bundle exec rubocop -a
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Git Hooks
|
|
218
|
+
|
|
219
|
+
The project includes a pre-push hook that automatically runs RuboCop and RSpec before allowing pushes. To set it up:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
./script/setup-hooks
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
To bypass hooks in emergency situations (not recommended):
|
|
226
|
+
```bash
|
|
227
|
+
git push --no-verify
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Development Workflow
|
|
231
|
+
|
|
232
|
+
1. Make your changes
|
|
233
|
+
2. Run `bundle exec rubocop -a` to fix any style issues
|
|
234
|
+
3. Run `bundle exec rspec` to ensure tests pass
|
|
235
|
+
4. Commit your changes
|
|
236
|
+
5. Push (pre-push hooks will run automatically)
|
|
237
|
+
|
|
238
|
+
### Contributing
|
|
239
|
+
|
|
240
|
+
1. Fork the repository
|
|
241
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
242
|
+
3. Make your changes
|
|
243
|
+
4. Ensure tests pass and code style is correct
|
|
244
|
+
5. Commit your changes with meaningful commit messages
|
|
245
|
+
6. Push to the branch (`git push origin feature/amazing-feature`)
|
|
246
|
+
7. Open a Pull Request
|
|
247
|
+
|
|
248
|
+
### Additional Testing Options
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# Run all tests in parallel (recommended for speed)
|
|
252
|
+
bundle exec parallel_rspec spec/
|
|
253
|
+
|
|
254
|
+
# Run all tests sequentially
|
|
255
|
+
bundle exec rspec
|
|
256
|
+
|
|
189
257
|
# Run only unit tests
|
|
190
258
|
bundle exec rspec spec/unit
|
|
191
259
|
|
|
192
260
|
# Run with coverage
|
|
193
|
-
ENABLE_SIMPLECOV=true bundle exec
|
|
261
|
+
ENABLE_SIMPLECOV=true bundle exec parallel_rspec spec/
|
|
194
262
|
```
|
|
195
263
|
|
|
196
264
|
### Type Checking
|
data/lib/sxn/CLI.rb
CHANGED
|
@@ -41,8 +41,11 @@ module Sxn
|
|
|
41
41
|
desc "add SESSION_NAME", "Create a new session (shortcut for 'sxn sessions add')"
|
|
42
42
|
option :description, type: :string, aliases: "-d", desc: "Session description"
|
|
43
43
|
option :linear_task, type: :string, aliases: "-l", desc: "Linear task ID"
|
|
44
|
+
option :branch, type: :string, aliases: "-b", desc: "Default branch for worktrees"
|
|
44
45
|
def add(session_name)
|
|
45
|
-
Commands::Sessions.new
|
|
46
|
+
cmd = Commands::Sessions.new
|
|
47
|
+
cmd.options = options
|
|
48
|
+
cmd.add(session_name)
|
|
46
49
|
rescue Sxn::Error => e
|
|
47
50
|
handle_error(e)
|
|
48
51
|
end
|
|
@@ -62,10 +65,102 @@ module Sxn
|
|
|
62
65
|
handle_error(e)
|
|
63
66
|
end
|
|
64
67
|
|
|
65
|
-
desc "current", "Show current session (shortcut for 'sxn sessions current')"
|
|
68
|
+
desc "current [SUBCOMMAND]", "Show current session (shortcut for 'sxn sessions current')"
|
|
66
69
|
option :verbose, type: :boolean, aliases: "-v", desc: "Show detailed information"
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
option :path, type: :boolean, aliases: "-p", desc: "Output only the session path"
|
|
71
|
+
def current(subcommand = nil)
|
|
72
|
+
Commands::Sessions.new.current(subcommand)
|
|
73
|
+
rescue Sxn::Error => e
|
|
74
|
+
handle_error(e)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
desc "enter", "Enter current session directory (outputs cd command for shell eval)"
|
|
78
|
+
long_desc <<-LONGDESC
|
|
79
|
+
Outputs a cd command to navigate to the current session directory.
|
|
80
|
+
|
|
81
|
+
Usage with shell eval:
|
|
82
|
+
eval "$(sxn enter)"
|
|
83
|
+
|
|
84
|
+
Or install shell integration for easier use:
|
|
85
|
+
sxn shell
|
|
86
|
+
|
|
87
|
+
Then simply run:
|
|
88
|
+
sxn-enter
|
|
89
|
+
LONGDESC
|
|
90
|
+
def enter
|
|
91
|
+
Commands::Sessions.new.enter
|
|
92
|
+
rescue Sxn::Error => e
|
|
93
|
+
handle_error(e)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
desc "up", "Navigate to project root from session (outputs cd command for shell eval)"
|
|
97
|
+
long_desc <<-LONGDESC
|
|
98
|
+
Outputs a cd command to navigate to the project root from within a session.
|
|
99
|
+
|
|
100
|
+
The project root is determined from the .sxnrc file in the session directory,
|
|
101
|
+
which points back to the parent .sxn folder.
|
|
102
|
+
|
|
103
|
+
Usage with shell eval:
|
|
104
|
+
eval "$(sxn up)"
|
|
105
|
+
|
|
106
|
+
Or install shell integration for easier use:
|
|
107
|
+
sxn shell
|
|
108
|
+
|
|
109
|
+
Then simply run:
|
|
110
|
+
sxn-up
|
|
111
|
+
LONGDESC
|
|
112
|
+
def up
|
|
113
|
+
require "shellwords"
|
|
114
|
+
|
|
115
|
+
session_config = Sxn::Core::SessionConfig.find_from_path(Dir.pwd)
|
|
116
|
+
|
|
117
|
+
unless session_config
|
|
118
|
+
warn "Not in a session directory."
|
|
119
|
+
warn ""
|
|
120
|
+
warn "This command works when run from within a session folder."
|
|
121
|
+
warn "Session folders contain a .sxnrc file that points back to the project."
|
|
122
|
+
warn ""
|
|
123
|
+
warn "Tip: Add this function to your shell profile for easier navigation:"
|
|
124
|
+
warn ""
|
|
125
|
+
warn " sxn-up() { eval \"$(sxn up 2>/dev/null)\" || sxn up; }"
|
|
126
|
+
exit(1)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
project_root = session_config.project_root
|
|
130
|
+
|
|
131
|
+
unless project_root && File.directory?(project_root)
|
|
132
|
+
warn "Could not determine project root from .sxnrc"
|
|
133
|
+
warn "parent_sxn_path: #{session_config.parent_sxn_path || "nil"}"
|
|
134
|
+
exit(1)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Output the cd command for shell integration
|
|
138
|
+
puts "cd #{Shellwords.escape(project_root)}"
|
|
139
|
+
rescue Sxn::Error => e
|
|
140
|
+
handle_error(e)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
desc "shell", "Install shell integration (sxn-enter function)"
|
|
144
|
+
option :shell_type, type: :string, enum: %w[bash zsh auto], default: "auto",
|
|
145
|
+
desc: "Shell type (bash, zsh, or auto-detect)"
|
|
146
|
+
option :uninstall, type: :boolean, default: false, desc: "Remove shell integration"
|
|
147
|
+
long_desc <<-LONGDESC
|
|
148
|
+
Installs shell integration to your shell configuration file (.zshrc or .bashrc).
|
|
149
|
+
|
|
150
|
+
This adds the sxn-enter function which allows you to quickly navigate
|
|
151
|
+
to your current session directory.
|
|
152
|
+
|
|
153
|
+
The installation is idempotent - running it multiple times will not
|
|
154
|
+
add duplicate entries.
|
|
155
|
+
|
|
156
|
+
Examples:
|
|
157
|
+
sxn shell # Auto-detect shell and install
|
|
158
|
+
sxn shell --shell-type=zsh # Install for zsh specifically
|
|
159
|
+
sxn shell --uninstall # Remove shell integration
|
|
160
|
+
LONGDESC
|
|
161
|
+
map "shell" => :install_shell_wrapper
|
|
162
|
+
def install_shell_wrapper
|
|
163
|
+
Commands::Init.new.invoke(:install_shell, [], options)
|
|
69
164
|
rescue Sxn::Error => e
|
|
70
165
|
handle_error(e)
|
|
71
166
|
end
|
data/lib/sxn/commands/init.rb
CHANGED
|
@@ -8,6 +8,34 @@ module Sxn
|
|
|
8
8
|
class Init < Thor
|
|
9
9
|
include Thor::Actions
|
|
10
10
|
|
|
11
|
+
# Shell integration marker - used to identify sxn shell functions
|
|
12
|
+
SHELL_MARKER = "# sxn shell integration"
|
|
13
|
+
SHELL_MARKER_END = "# end sxn shell integration"
|
|
14
|
+
|
|
15
|
+
# Shell function that gets installed
|
|
16
|
+
SHELL_FUNCTION = <<~SHELL.freeze
|
|
17
|
+
#{SHELL_MARKER}
|
|
18
|
+
sxn-enter() {
|
|
19
|
+
local cmd
|
|
20
|
+
cmd="$(sxn enter 2>/dev/null)"
|
|
21
|
+
if [ $? -eq 0 ] && [ -n "$cmd" ]; then
|
|
22
|
+
eval "$cmd"
|
|
23
|
+
else
|
|
24
|
+
sxn enter
|
|
25
|
+
fi
|
|
26
|
+
}
|
|
27
|
+
sxn-up() {
|
|
28
|
+
local cmd
|
|
29
|
+
cmd="$(sxn up 2>/dev/null)"
|
|
30
|
+
if [ $? -eq 0 ] && [ -n "$cmd" ]; then
|
|
31
|
+
eval "$cmd"
|
|
32
|
+
else
|
|
33
|
+
sxn up
|
|
34
|
+
fi
|
|
35
|
+
}
|
|
36
|
+
#{SHELL_MARKER_END}
|
|
37
|
+
SHELL
|
|
38
|
+
|
|
11
39
|
desc "init [FOLDER]", "Initialize sxn in a project folder"
|
|
12
40
|
option :force, type: :boolean, desc: "Force initialization even if already initialized"
|
|
13
41
|
option :auto_detect, type: :boolean, default: true, desc: "Automatically detect and register projects"
|
|
@@ -55,8 +83,116 @@ module Sxn
|
|
|
55
83
|
end
|
|
56
84
|
end
|
|
57
85
|
|
|
86
|
+
desc "install_shell", "Install shell integration (sxn-enter function)"
|
|
87
|
+
option :shell_type, type: :string, enum: %w[bash zsh auto], default: "auto",
|
|
88
|
+
desc: "Shell type (bash, zsh, or auto-detect)"
|
|
89
|
+
option :uninstall, type: :boolean, default: false, desc: "Remove shell integration"
|
|
90
|
+
def install_shell
|
|
91
|
+
@ui.section("Shell Integration")
|
|
92
|
+
|
|
93
|
+
shell_type = detect_shell_type
|
|
94
|
+
rc_file = shell_rc_file(shell_type)
|
|
95
|
+
|
|
96
|
+
unless rc_file
|
|
97
|
+
@ui.error("Could not determine shell configuration file")
|
|
98
|
+
@ui.info("Supported shells: bash, zsh")
|
|
99
|
+
exit(1)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if options[:uninstall]
|
|
103
|
+
uninstall_shell_integration(rc_file, shell_type)
|
|
104
|
+
else
|
|
105
|
+
install_shell_integration(rc_file, shell_type)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
58
109
|
private
|
|
59
110
|
|
|
111
|
+
def detect_shell_type
|
|
112
|
+
shell_opt = options[:shell_type] || options[:shell] || "auto"
|
|
113
|
+
return shell_opt unless shell_opt == "auto"
|
|
114
|
+
|
|
115
|
+
# Check SHELL environment variable
|
|
116
|
+
current_shell = ENV.fetch("SHELL", "")
|
|
117
|
+
if current_shell.include?("zsh")
|
|
118
|
+
"zsh"
|
|
119
|
+
elsif current_shell.include?("bash")
|
|
120
|
+
"bash"
|
|
121
|
+
else
|
|
122
|
+
# Default to bash
|
|
123
|
+
"bash"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def shell_rc_file(shell_type)
|
|
128
|
+
home = Dir.home
|
|
129
|
+
case shell_type
|
|
130
|
+
when "zsh"
|
|
131
|
+
File.join(home, ".zshrc")
|
|
132
|
+
when "bash"
|
|
133
|
+
# Prefer .bashrc, fall back to .bash_profile on macOS
|
|
134
|
+
bashrc = File.join(home, ".bashrc")
|
|
135
|
+
bash_profile = File.join(home, ".bash_profile")
|
|
136
|
+
File.exist?(bashrc) ? bashrc : bash_profile
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def shell_integration_installed?(rc_file)
|
|
141
|
+
return false unless File.exist?(rc_file)
|
|
142
|
+
|
|
143
|
+
content = File.read(rc_file)
|
|
144
|
+
content.include?(SHELL_MARKER)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def install_shell_integration(rc_file, _shell_type)
|
|
148
|
+
if shell_integration_installed?(rc_file)
|
|
149
|
+
@ui.info("Shell integration already installed in #{rc_file}")
|
|
150
|
+
@ui.info("Use --uninstall to remove it first if you want to reinstall")
|
|
151
|
+
return
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Ensure rc file exists
|
|
155
|
+
FileUtils.touch(rc_file) unless File.exist?(rc_file)
|
|
156
|
+
|
|
157
|
+
# Append shell function
|
|
158
|
+
File.open(rc_file, "a") do |f|
|
|
159
|
+
f.puts "" # Add blank line before
|
|
160
|
+
f.puts SHELL_FUNCTION
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
@ui.success("Installed shell integration to #{rc_file}")
|
|
164
|
+
@ui.newline
|
|
165
|
+
@ui.info("The following functions were added:")
|
|
166
|
+
@ui.newline
|
|
167
|
+
puts " sxn-enter - Navigate to current session directory"
|
|
168
|
+
puts " sxn-up - Navigate to project root from session"
|
|
169
|
+
@ui.newline
|
|
170
|
+
@ui.recovery_suggestion("Run 'source #{rc_file}' or restart your shell to use them")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def uninstall_shell_integration(rc_file, _shell_type)
|
|
174
|
+
unless File.exist?(rc_file)
|
|
175
|
+
@ui.info("Shell configuration file not found: #{rc_file}")
|
|
176
|
+
return
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
unless shell_integration_installed?(rc_file)
|
|
180
|
+
@ui.info("Shell integration not installed in #{rc_file}")
|
|
181
|
+
return
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Read file and remove sxn block
|
|
185
|
+
content = File.read(rc_file)
|
|
186
|
+
# Remove the block between markers (including blank line before)
|
|
187
|
+
pattern = /\n?#{Regexp.escape(SHELL_MARKER)}.*?#{Regexp.escape(SHELL_MARKER_END)}\n?/m
|
|
188
|
+
new_content = content.gsub(pattern, "\n")
|
|
189
|
+
|
|
190
|
+
File.write(rc_file, new_content)
|
|
191
|
+
|
|
192
|
+
@ui.success("Removed shell integration from #{rc_file}")
|
|
193
|
+
@ui.recovery_suggestion("Run 'source #{rc_file}' or restart your shell")
|
|
194
|
+
end
|
|
195
|
+
|
|
60
196
|
def determine_sessions_folder(folder)
|
|
61
197
|
return folder if folder && !options[:quiet]
|
|
62
198
|
|