all_in_ruby 0.2.0 → 0.2.1
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 +5 -0
- data/lib/all_in_ruby/cli.rb +43 -34
- data/lib/all_in_ruby/installer.rb +16 -13
- data/lib/all_in_ruby/instruction.rb +7 -2
- data/lib/all_in_ruby/version.rb +1 -1
- data/lib/all_in_ruby.rb +0 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55c6359657b51756cdaf08ac451944c082a262648baacffd13b29149b232869e
|
|
4
|
+
data.tar.gz: b91ef1b9f442d440b060d4e3bdbcc59dbdcb4bfe63219dc8ce78f5cb9c33e629
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c09f7d78f6481e65f229894d95f378c77283493facc7d970e3b0323eb8ef48bb84a4d7409e1e8884c86d7cc6442d5cd95a7633505d43787d552e86c94660758
|
|
7
|
+
data.tar.gz: 40030931d424fc53f95edc456afcfc1a56fd3a27b0e82029d51b2c8b6a2603791f8d3a5626083664f9f25eccba8789c9f895d0f63628703e5dcfb589a15bb30b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.1 (2026-08-04)
|
|
4
|
+
|
|
5
|
+
- Require a complete instruction block when checking installation status, and preserve malformed or unrelated content when removing a later valid block
|
|
6
|
+
- Simplify the CLI and installer internals so command execution, reporting, dry runs, and result construction read more explicitly without changing their behavior
|
|
7
|
+
|
|
3
8
|
## 0.2.0 (2026-08-03)
|
|
4
9
|
|
|
5
10
|
- `install` and `uninstall` now back up any existing file before modifying it, writing a timestamped copy (`CLAUDE.md.20260802-153000.bak`) next to the original and listing the backups created at the end of the run. New files are not backed up. Pass `--no-backup` to skip, or `--dry-run` to preview which backups would be made
|
data/lib/all_in_ruby/cli.rb
CHANGED
|
@@ -41,39 +41,17 @@ module AllInRuby
|
|
|
41
41
|
return 1
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
agents = options[:agents].empty? ? Installer::AGENTS
|
|
44
|
+
agents = options[:agents].empty? ? Installer::AGENTS : options[:agents]
|
|
45
45
|
scopes = scopes_for(command, options[:scopes])
|
|
46
46
|
dry_run = options[:dry_run] && command != "status"
|
|
47
47
|
|
|
48
|
-
scope_results = scopes
|
|
49
|
-
results =
|
|
50
|
-
if command == "status"
|
|
51
|
-
@installer.status(agents: agents, scope: scope)
|
|
52
|
-
else
|
|
53
|
-
@installer.public_send(command, agents: agents, scope: scope, dry_run: dry_run, backup: options[:backup])
|
|
54
|
-
end
|
|
55
|
-
[scope, results]
|
|
56
|
-
end
|
|
57
|
-
|
|
48
|
+
scope_results = results_by_scope(command, agents:, scopes:, dry_run:, backup: options[:backup])
|
|
58
49
|
print_statuses(scope_results, dry_run ? DRY_RUN_LABELS : STATUS_LABELS)
|
|
59
50
|
|
|
60
51
|
results = scope_results.flat_map { |_scope, scope_result| scope_result }
|
|
61
|
-
results
|
|
62
|
-
next unless result.diff
|
|
63
|
-
|
|
64
|
-
@stdout.puts
|
|
65
|
-
@stdout.puts result.diff
|
|
66
|
-
end
|
|
67
|
-
|
|
52
|
+
print_diffs(results)
|
|
68
53
|
print_backups(results, dry_run)
|
|
69
|
-
|
|
70
|
-
if command == "install" && results.any? { |result| result.status == :manual }
|
|
71
|
-
@stdout.puts
|
|
72
|
-
@stdout.puts "Cursor has no global rules file. To apply the instruction globally,"
|
|
73
|
-
@stdout.puts "paste this into Cursor Settings > Rules:"
|
|
74
|
-
@stdout.puts
|
|
75
|
-
@stdout.puts Instruction.body
|
|
76
|
-
end
|
|
54
|
+
print_manual_instruction(command, results)
|
|
77
55
|
0
|
|
78
56
|
rescue OptionParser::ParseError => e
|
|
79
57
|
@stderr.puts e.message
|
|
@@ -87,16 +65,19 @@ module AllInRuby
|
|
|
87
65
|
def scopes_for(command, requested)
|
|
88
66
|
return requested.uniq unless requested.empty?
|
|
89
67
|
|
|
90
|
-
command == "status" ? Installer::SCOPES
|
|
68
|
+
command == "status" ? Installer::SCOPES : ["local"]
|
|
91
69
|
end
|
|
92
70
|
|
|
93
|
-
def
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
71
|
+
def results_by_scope(command, agents:, scopes:, dry_run:, backup:)
|
|
72
|
+
scopes.map do |scope|
|
|
73
|
+
results =
|
|
74
|
+
if command == "status"
|
|
75
|
+
@installer.status(agents: agents, scope: scope)
|
|
76
|
+
else
|
|
77
|
+
@installer.public_send(command, agents: agents, scope: scope, dry_run: dry_run, backup: backup)
|
|
78
|
+
end
|
|
79
|
+
[scope, results]
|
|
80
|
+
end
|
|
100
81
|
end
|
|
101
82
|
|
|
102
83
|
def print_statuses(scope_results, labels)
|
|
@@ -111,6 +92,34 @@ module AllInRuby
|
|
|
111
92
|
end
|
|
112
93
|
end
|
|
113
94
|
|
|
95
|
+
def print_diffs(results)
|
|
96
|
+
results.each do |result|
|
|
97
|
+
next unless result.diff
|
|
98
|
+
|
|
99
|
+
@stdout.puts
|
|
100
|
+
@stdout.puts result.diff
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def print_backups(results, dry_run)
|
|
105
|
+
backups = results.filter_map(&:backup)
|
|
106
|
+
return if backups.empty?
|
|
107
|
+
|
|
108
|
+
@stdout.puts
|
|
109
|
+
@stdout.puts(dry_run ? "Backups that would be created:" : "Backups created:")
|
|
110
|
+
backups.each { |backup| @stdout.puts " #{backup}" }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def print_manual_instruction(command, results)
|
|
114
|
+
return unless command == "install" && results.any? { |result| result.status == :manual }
|
|
115
|
+
|
|
116
|
+
@stdout.puts
|
|
117
|
+
@stdout.puts "Cursor has no global rules file. To apply the instruction globally,"
|
|
118
|
+
@stdout.puts "paste this into Cursor Settings > Rules:"
|
|
119
|
+
@stdout.puts
|
|
120
|
+
@stdout.puts Instruction.body
|
|
121
|
+
end
|
|
122
|
+
|
|
114
123
|
def build_parser(options)
|
|
115
124
|
OptionParser.new do |opts|
|
|
116
125
|
opts.banner = <<~BANNER
|
|
@@ -7,7 +7,7 @@ module AllInRuby
|
|
|
7
7
|
AGENTS = %w[claude codex opencode cursor].freeze
|
|
8
8
|
SCOPES = %w[local global].freeze
|
|
9
9
|
|
|
10
|
-
Result = Struct.new(:agent, :path, :status, :diff, :backup)
|
|
10
|
+
Result = Struct.new(:agent, :path, :status, :diff, :backup, keyword_init: true)
|
|
11
11
|
|
|
12
12
|
def initialize(root: Dir.pwd, home: Dir.home, env: ENV, clock: -> { Time.now })
|
|
13
13
|
@root = root
|
|
@@ -41,9 +41,9 @@ module AllInRuby
|
|
|
41
41
|
:already_installed
|
|
42
42
|
elsif content
|
|
43
43
|
new_content = content + separator_for(content) + Instruction.block
|
|
44
|
-
apply(path, content, new_content, :updated, dry_run
|
|
44
|
+
apply(path, content, new_content, :updated, dry_run:, backup:, planned:)
|
|
45
45
|
else
|
|
46
|
-
apply(path, nil, Instruction.block, :created, dry_run
|
|
46
|
+
apply(path, nil, Instruction.block, :created, dry_run:, backup:, planned:)
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
end
|
|
@@ -54,7 +54,7 @@ module AllInRuby
|
|
|
54
54
|
content = current_content(path, planned)
|
|
55
55
|
|
|
56
56
|
if content && Instruction.installed?(content)
|
|
57
|
-
apply(path, content, Instruction.remove(content), :removed, dry_run
|
|
57
|
+
apply(path, content, Instruction.remove(content), :removed, dry_run:, backup:, planned:)
|
|
58
58
|
else
|
|
59
59
|
:not_installed
|
|
60
60
|
end
|
|
@@ -92,17 +92,18 @@ module AllInRuby
|
|
|
92
92
|
# Returns [status, diff, backup]. A backup is made only when an existing
|
|
93
93
|
# file is modified (never on create); a dry run computes the name it would
|
|
94
94
|
# use so the preview can report it, but writes nothing.
|
|
95
|
-
def apply(path, old_content, new_content, status, dry_run
|
|
95
|
+
def apply(path, old_content, new_content, status, dry_run:, backup:, planned:)
|
|
96
96
|
backup_path = backup && old_content ? backup_path_for(path) : nil
|
|
97
|
+
|
|
97
98
|
if dry_run
|
|
98
99
|
planned[path] = new_content
|
|
99
|
-
[status, Diff.unified(old_content, new_content, path), backup_path]
|
|
100
|
-
else
|
|
101
|
-
FileUtils.cp(path, backup_path) if backup_path
|
|
102
|
-
FileUtils.mkdir_p(File.dirname(path)) unless old_content
|
|
103
|
-
File.write(path, new_content)
|
|
104
|
-
[status, nil, backup_path]
|
|
100
|
+
return [status, Diff.unified(old_content, new_content, path), backup_path]
|
|
105
101
|
end
|
|
102
|
+
|
|
103
|
+
FileUtils.cp(path, backup_path) if backup_path
|
|
104
|
+
FileUtils.mkdir_p(File.dirname(path)) unless old_content
|
|
105
|
+
File.write(path, new_content)
|
|
106
|
+
[status, nil, backup_path]
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
def backup_path_for(path)
|
|
@@ -112,8 +113,10 @@ module AllInRuby
|
|
|
112
113
|
def each_target(agents, scope)
|
|
113
114
|
agents.map do |agent|
|
|
114
115
|
path = path_for(agent, scope)
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
next Result.new(agent:, path:, status: :manual) unless path
|
|
117
|
+
|
|
118
|
+
status, diff, backup = yield(path)
|
|
119
|
+
Result.new(agent:, path:, status:, diff:, backup:)
|
|
117
120
|
end
|
|
118
121
|
end
|
|
119
122
|
end
|
|
@@ -22,6 +22,11 @@ module AllInRuby
|
|
|
22
22
|
MARKDOWN
|
|
23
23
|
|
|
24
24
|
BLOCK = "#{BEGIN_MARKER}\n#{BODY}#{END_MARKER}\n".freeze
|
|
25
|
+
BLOCK_PATTERN = /
|
|
26
|
+
#{Regexp.escape(BEGIN_MARKER)}
|
|
27
|
+
(?:(?!#{Regexp.escape(BEGIN_MARKER)}).)*?
|
|
28
|
+
#{Regexp.escape(END_MARKER)}\n?
|
|
29
|
+
/mx
|
|
25
30
|
|
|
26
31
|
def self.block
|
|
27
32
|
BLOCK
|
|
@@ -32,11 +37,11 @@ module AllInRuby
|
|
|
32
37
|
end
|
|
33
38
|
|
|
34
39
|
def self.installed?(content)
|
|
35
|
-
content.
|
|
40
|
+
content.match?(BLOCK_PATTERN)
|
|
36
41
|
end
|
|
37
42
|
|
|
38
43
|
def self.remove(content)
|
|
39
|
-
content.gsub(
|
|
44
|
+
content.gsub(BLOCK_PATTERN, "")
|
|
40
45
|
end
|
|
41
46
|
end
|
|
42
47
|
end
|
data/lib/all_in_ruby/version.rb
CHANGED
data/lib/all_in_ruby.rb
CHANGED