ace-support-core 0.29.3 → 0.29.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/.ace-defaults/README.md +16 -0
- data/CHANGELOG.md +11 -0
- data/README.md +3 -3
- data/lib/ace/core/version.rb +1 -1
- metadata +4 -9
- data/exe/ace-framework +0 -13
- data/lib/ace/core/cli.rb +0 -192
- data/lib/ace/core/models/config_templates.rb +0 -87
- data/lib/ace/core/organisms/config_diff.rb +0 -187
- data/lib/ace/core/organisms/config_initializer.rb +0 -125
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a6b708c53652bcab306f9ac32f767818083c2ec3d8d08c250765d333b27f7eee
|
|
4
|
+
data.tar.gz: 1761a2ed810b94d59636b52455ca38bef56eceb58b7b752ebeb4199fd7db35fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7ad2edbaca8fae8c51cfd934608b6e5b7c087764626515ddb1c0a4913d436a4b63f41d5ed07b6670f7c4d6f4d70eecbc01e5ccf0bd47f9ea3a3c8a9c582c8894
|
|
7
|
+
data.tar.gz: 2e968110a915140fb18dd5dc8de8044e19c80c6a1b71bc774b146f0b7dc23657873952fd748334906ceb7a188769e8379f441e5359ae79157bc16892b84049dd
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# .ace Configuration
|
|
2
|
+
|
|
3
|
+
This directory contains local ACE configuration for your project.
|
|
4
|
+
These starter files are intentionally generic so you can tailor them to your own codebase.
|
|
5
|
+
|
|
6
|
+
## First Steps
|
|
7
|
+
|
|
8
|
+
1. Review `.ace/bundle/presets/project.md` and replace TODO placeholders.
|
|
9
|
+
2. Optionally use `.ace/bundle/presets/project-base.md` for lightweight context loading.
|
|
10
|
+
3. Run `ace-bundle project` to verify the preset loads successfully.
|
|
11
|
+
4. Use `ace-task status` to inspect and manage your project task queue.
|
|
12
|
+
|
|
13
|
+
## Notes
|
|
14
|
+
|
|
15
|
+
- Re-run `ace-config init --force` to refresh files from gem defaults.
|
|
16
|
+
- Keep project-specific guidance in your local `.ace/` files.
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.29.5] - 2026-03-31
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Migrated config CLI ownership to `ace-support-config` by removing `ace-framework` packaging/runtime surfaces from `ace-support-core` and updating package docs/default guidance to reference `ace-config`.
|
|
14
|
+
|
|
15
|
+
## [0.29.4] - 2026-03-29
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Added a shipped `.ace-defaults/README.md` scaffold so `ace-framework init` generates `.ace/README.md` for newly initialized projects.
|
|
19
|
+
- Updated bootstrap configuration guidance and examples to current `ace-task` CLI usage and documented generated `project`/`project-base` presets.
|
|
20
|
+
|
|
10
21
|
## [0.29.3] - 2026-03-29
|
|
11
22
|
|
|
12
23
|
### Technical
|
data/README.md
CHANGED
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
> Works with: Claude Code, Codex CLI, OpenCode, Gemini CLI, pi-agent, and more.
|
|
16
16
|
|
|
17
|
-
`ace-support-core` centralizes configuration loading, environment handling, and shared runtime behavior used by support libraries. It delegates config resolution through [ace-support-config](../ace-support-config) and exposes stable orchestration points that other `ace-support-*` gems build on.
|
|
17
|
+
`ace-support-core` centralizes configuration loading, environment handling, and shared runtime behavior used by support libraries. It delegates config resolution through [ace-support-config](../ace-support-config) and exposes stable orchestration points that other `ace-support-*` gems build on.
|
|
18
18
|
|
|
19
19
|
## How It Works
|
|
20
20
|
|
|
21
21
|
1. Provide a shared bootstrap path for config, env, and runtime context so every `ace-support-*` gem starts from the same foundation.
|
|
22
22
|
2. Delegate cascaded configuration resolution through [ace-support-config](../ace-support-config) so packages inherit project, user, and gem-level defaults automatically.
|
|
23
|
-
3.
|
|
23
|
+
3. Provide shared runtime/config primitives consumed by `ace-support-config`, which owns the `ace-config` CLI.
|
|
24
24
|
|
|
25
25
|
## Use Cases
|
|
26
26
|
|
|
@@ -31,4 +31,4 @@
|
|
|
31
31
|
**Keep support libraries composable** - build package-specific features on top of stable core contracts that provide predictable runtime behavior.
|
|
32
32
|
|
|
33
33
|
---
|
|
34
|
-
[Configuration overview](docs/config.md) | [`ace-
|
|
34
|
+
[Configuration overview](docs/config.md) | [`ace-config` usage](../ace-support-config/docs/usage.md) | Part of [ACE](https://github.com/cs3b/ace)
|
data/lib/ace/core/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-support-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.29.
|
|
4
|
+
version: 0.29.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-04-01 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-support-config
|
|
@@ -56,17 +56,16 @@ description: Foundational infrastructure gem providing configuration cascade res
|
|
|
56
56
|
gem following ace-support-* pattern for infrastructure components.
|
|
57
57
|
email:
|
|
58
58
|
- mc@cs3b.com
|
|
59
|
-
executables:
|
|
60
|
-
- ace-framework
|
|
59
|
+
executables: []
|
|
61
60
|
extensions: []
|
|
62
61
|
extra_rdoc_files: []
|
|
63
62
|
files:
|
|
63
|
+
- ".ace-defaults/README.md"
|
|
64
64
|
- ".ace-defaults/core/settings.yml"
|
|
65
65
|
- CHANGELOG.md
|
|
66
66
|
- LICENSE
|
|
67
67
|
- README.md
|
|
68
68
|
- Rakefile
|
|
69
|
-
- exe/ace-framework
|
|
70
69
|
- lib/ace/core.rb
|
|
71
70
|
- lib/ace/core/atoms/command_executor.rb
|
|
72
71
|
- lib/ace/core/atoms/config_summary.rb
|
|
@@ -75,18 +74,14 @@ files:
|
|
|
75
74
|
- lib/ace/core/atoms/glob_expander.rb
|
|
76
75
|
- lib/ace/core/atoms/process_terminator.rb
|
|
77
76
|
- lib/ace/core/atoms/template_parser.rb
|
|
78
|
-
- lib/ace/core/cli.rb
|
|
79
77
|
- lib/ace/core/cli/config_summary_mixin.rb
|
|
80
78
|
- lib/ace/core/config_discovery.rb
|
|
81
79
|
- lib/ace/core/errors.rb
|
|
82
|
-
- lib/ace/core/models/config_templates.rb
|
|
83
80
|
- lib/ace/core/molecules/env_loader.rb
|
|
84
81
|
- lib/ace/core/molecules/file_aggregator.rb
|
|
85
82
|
- lib/ace/core/molecules/frontmatter_free_policy.rb
|
|
86
83
|
- lib/ace/core/molecules/output_formatter.rb
|
|
87
84
|
- lib/ace/core/molecules/prompt_cache_manager.rb
|
|
88
|
-
- lib/ace/core/organisms/config_diff.rb
|
|
89
|
-
- lib/ace/core/organisms/config_initializer.rb
|
|
90
85
|
- lib/ace/core/organisms/environment_manager.rb
|
|
91
86
|
- lib/ace/core/version.rb
|
|
92
87
|
homepage: https://github.com/cs3b/ace
|
data/exe/ace-framework
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "ace/core"
|
|
5
|
-
require "ace/core/cli"
|
|
6
|
-
|
|
7
|
-
# Start FrameworkCLI (separate from Ace::Core::CLI module which is ace-support-cli infrastructure)
|
|
8
|
-
begin
|
|
9
|
-
Ace::Core::FrameworkCLI.start(ARGV)
|
|
10
|
-
rescue Ace::Support::Cli::Error => e
|
|
11
|
-
warn e.message
|
|
12
|
-
exit(e.exit_code)
|
|
13
|
-
end
|
data/lib/ace/core/cli.rb
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "optparse"
|
|
4
|
-
require_relative "organisms/config_initializer"
|
|
5
|
-
require_relative "organisms/config_diff"
|
|
6
|
-
require_relative "models/config_templates"
|
|
7
|
-
|
|
8
|
-
module Ace
|
|
9
|
-
module Core
|
|
10
|
-
# Framework CLI for ace-framework binary.
|
|
11
|
-
# Uses a separate class name to avoid collision with Ace::Core::CLI module
|
|
12
|
-
# (which provides shared CLI infrastructure).
|
|
13
|
-
class FrameworkCLI
|
|
14
|
-
def self.start(argv)
|
|
15
|
-
new.run(argv)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def run(argv)
|
|
19
|
-
return show_help if argv.empty?
|
|
20
|
-
|
|
21
|
-
command = argv.shift
|
|
22
|
-
|
|
23
|
-
case command
|
|
24
|
-
when "init"
|
|
25
|
-
run_init(argv)
|
|
26
|
-
when "diff"
|
|
27
|
-
run_diff(argv)
|
|
28
|
-
when "list"
|
|
29
|
-
run_list(argv)
|
|
30
|
-
when "version", "--version"
|
|
31
|
-
show_version
|
|
32
|
-
when "help", "--help", "-h"
|
|
33
|
-
show_help
|
|
34
|
-
else
|
|
35
|
-
puts "Unknown command: #{command}"
|
|
36
|
-
puts ""
|
|
37
|
-
show_help
|
|
38
|
-
exit 1
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
private
|
|
43
|
-
|
|
44
|
-
def run_init(argv)
|
|
45
|
-
options = {}
|
|
46
|
-
|
|
47
|
-
parser = OptionParser.new do |opts|
|
|
48
|
-
opts.banner = <<~BANNER.chomp
|
|
49
|
-
NAME
|
|
50
|
-
ace-framework init - Initialize configuration for ace-* gems
|
|
51
|
-
|
|
52
|
-
USAGE
|
|
53
|
-
ace-framework init [GEM] [OPTIONS]
|
|
54
|
-
|
|
55
|
-
OPTIONS
|
|
56
|
-
BANNER
|
|
57
|
-
opts.on("--force", "Overwrite existing files") { options[:force] = true }
|
|
58
|
-
opts.on("--dry-run", "Show what would be done") { options[:dry_run] = true }
|
|
59
|
-
opts.on("--global", "Use ~/.ace instead of ./.ace") { options[:global] = true }
|
|
60
|
-
opts.on("--verbose", "Show verbose output") { options[:verbose] = true }
|
|
61
|
-
opts.on("-h", "--help", "Show this help") {
|
|
62
|
-
puts opts
|
|
63
|
-
exit
|
|
64
|
-
}
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
parser.parse!(argv)
|
|
68
|
-
gem_name = argv.shift
|
|
69
|
-
|
|
70
|
-
initializer = ConfigInitializer.new(**options)
|
|
71
|
-
|
|
72
|
-
if gem_name
|
|
73
|
-
initializer.init_gem(gem_name)
|
|
74
|
-
else
|
|
75
|
-
initializer.init_all
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def run_diff(argv)
|
|
80
|
-
options = {}
|
|
81
|
-
|
|
82
|
-
parser = OptionParser.new do |opts|
|
|
83
|
-
opts.banner = <<~BANNER.chomp
|
|
84
|
-
NAME
|
|
85
|
-
ace-framework diff - Compare configs with examples
|
|
86
|
-
|
|
87
|
-
USAGE
|
|
88
|
-
ace-framework diff [GEM] [OPTIONS]
|
|
89
|
-
|
|
90
|
-
OPTIONS
|
|
91
|
-
BANNER
|
|
92
|
-
opts.on("--global", "Compare global configs") { options[:global] = true }
|
|
93
|
-
opts.on("--local", "Compare local configs (default)") { options[:local] = true }
|
|
94
|
-
opts.on("--file PATH", "Compare specific file") { |f| options[:file] = f }
|
|
95
|
-
opts.on("--one-line", "One-line summary per file") { options[:one_line] = true }
|
|
96
|
-
opts.on("-h", "--help", "Show this help") {
|
|
97
|
-
puts opts
|
|
98
|
-
exit
|
|
99
|
-
}
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
parser.parse!(argv)
|
|
103
|
-
gem_name = argv.shift
|
|
104
|
-
|
|
105
|
-
differ = ConfigDiff.new(**options)
|
|
106
|
-
|
|
107
|
-
if gem_name
|
|
108
|
-
differ.diff_gem(gem_name)
|
|
109
|
-
else
|
|
110
|
-
differ.run
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def run_list(argv)
|
|
115
|
-
verbose = false
|
|
116
|
-
|
|
117
|
-
parser = OptionParser.new do |opts|
|
|
118
|
-
opts.banner = <<~BANNER.chomp
|
|
119
|
-
NAME
|
|
120
|
-
ace-framework list - List available ace-* gems with example configs
|
|
121
|
-
|
|
122
|
-
USAGE
|
|
123
|
-
ace-framework list [OPTIONS]
|
|
124
|
-
|
|
125
|
-
OPTIONS
|
|
126
|
-
BANNER
|
|
127
|
-
opts.on("--verbose", "Show detailed information") { verbose = true }
|
|
128
|
-
opts.on("-h", "--help", "Show this help") {
|
|
129
|
-
puts opts
|
|
130
|
-
exit
|
|
131
|
-
}
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
parser.parse!(argv)
|
|
135
|
-
|
|
136
|
-
puts "Available ace-* gems with example configurations:\n\n"
|
|
137
|
-
|
|
138
|
-
if ConfigTemplates.all_gems.empty?
|
|
139
|
-
puts "No ace-* gems with example configurations found."
|
|
140
|
-
return
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
ConfigTemplates.all_gems.each do |gem_name|
|
|
144
|
-
info = ConfigTemplates.gem_info[gem_name]
|
|
145
|
-
source_label = case info[:source]
|
|
146
|
-
when :local then "[local]"
|
|
147
|
-
when :gem then "[gem]"
|
|
148
|
-
when :both then "[local+gem]"
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
puts " #{gem_name} #{source_label}"
|
|
152
|
-
|
|
153
|
-
if verbose
|
|
154
|
-
puts " Path: #{info[:path]}"
|
|
155
|
-
puts " Gem: #{info[:gem_path]}" if info[:gem_path]
|
|
156
|
-
example_dir = ConfigTemplates.example_dir_for(gem_name)
|
|
157
|
-
if example_dir && File.exist?(example_dir)
|
|
158
|
-
example_files = Dir.glob("#{example_dir}/**/*").reject { |f| File.directory?(f) }
|
|
159
|
-
puts " Example files: #{example_files.size}"
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
puts "\nUse 'ace-framework init [GEM]' to initialize a specific gem's configuration"
|
|
165
|
-
puts "Use 'ace-framework init' to initialize all configurations"
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def show_version
|
|
169
|
-
puts "ace-framework #{Ace::Core::VERSION}"
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def show_help
|
|
173
|
-
puts <<~HELP
|
|
174
|
-
NAME
|
|
175
|
-
ace-framework - Configuration management for ace-* gems
|
|
176
|
-
|
|
177
|
-
USAGE
|
|
178
|
-
ace-framework COMMAND [OPTIONS]
|
|
179
|
-
|
|
180
|
-
COMMANDS
|
|
181
|
-
init [GEM] Initialize configuration for specific gem or all
|
|
182
|
-
diff [GEM] Compare configs with examples
|
|
183
|
-
list List available ace-* gems with example configs
|
|
184
|
-
version Show version
|
|
185
|
-
help Show this help
|
|
186
|
-
|
|
187
|
-
Run 'ace-framework COMMAND --help' for more information on a command.
|
|
188
|
-
HELP
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "pathname"
|
|
4
|
-
require "rubygems"
|
|
5
|
-
|
|
6
|
-
module Ace
|
|
7
|
-
module Core
|
|
8
|
-
class ConfigTemplates
|
|
9
|
-
class << self
|
|
10
|
-
def all_gems
|
|
11
|
-
gem_info.keys.sort
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def gem_exists?(gem_name)
|
|
15
|
-
gem_info.key?(gem_name)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def example_dir_for(gem_name)
|
|
19
|
-
info = gem_info[gem_name]
|
|
20
|
-
return nil unless info
|
|
21
|
-
|
|
22
|
-
# Prefer local path for development
|
|
23
|
-
path = (info[:source] == :gem) ? info[:path] : (info[:path] || info[:gem_path])
|
|
24
|
-
resolve_defaults_dir(path)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def gem_info
|
|
28
|
-
@gem_info ||= build_gem_info
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def build_gem_info
|
|
32
|
-
gems = {}
|
|
33
|
-
|
|
34
|
-
# 1. Look in the parent directory (monorepo/development)
|
|
35
|
-
parent_dir = File.expand_path("../../../../../../", __FILE__)
|
|
36
|
-
Dir.glob("#{parent_dir}/ace-*").each do |dir|
|
|
37
|
-
next unless File.directory?(dir)
|
|
38
|
-
gem_name = File.basename(dir)
|
|
39
|
-
if has_example_dir?(dir)
|
|
40
|
-
gems[gem_name] = {source: :local, path: dir}
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# 2. Look for installed RubyGems
|
|
45
|
-
begin
|
|
46
|
-
Gem::Specification.each do |spec|
|
|
47
|
-
next unless spec.name.start_with?("ace-")
|
|
48
|
-
|
|
49
|
-
gem_path = spec.gem_dir
|
|
50
|
-
if has_example_dir?(gem_path)
|
|
51
|
-
if gems.key?(spec.name)
|
|
52
|
-
gems[spec.name][:source] = :both
|
|
53
|
-
gems[spec.name][:gem_path] = gem_path
|
|
54
|
-
else
|
|
55
|
-
gems[spec.name] = {source: :gem, path: gem_path}
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
rescue
|
|
60
|
-
# If we can't access installed gems, just use local ones
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
gems
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def docs_file_for(gem_name)
|
|
67
|
-
info = gem_info[gem_name]
|
|
68
|
-
return nil unless info
|
|
69
|
-
|
|
70
|
-
# Prefer local path for development
|
|
71
|
-
path = (info[:source] == :gem) ? info[:path] : (info[:path] || info[:gem_path])
|
|
72
|
-
File.join(path, "docs", "config.md")
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
private
|
|
76
|
-
|
|
77
|
-
def resolve_defaults_dir(gem_path)
|
|
78
|
-
File.join(gem_path, ".ace-defaults")
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def has_example_dir?(gem_dir)
|
|
82
|
-
Dir.exist?(File.join(gem_dir, ".ace-defaults"))
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "open3"
|
|
4
|
-
require "pathname"
|
|
5
|
-
require_relative "../models/config_templates"
|
|
6
|
-
|
|
7
|
-
module Ace
|
|
8
|
-
module Core
|
|
9
|
-
class ConfigDiff
|
|
10
|
-
def initialize(global: false, file: nil, one_line: false)
|
|
11
|
-
@global = global
|
|
12
|
-
@file = file
|
|
13
|
-
@one_line = one_line
|
|
14
|
-
@diffs = []
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def run
|
|
18
|
-
if @file
|
|
19
|
-
diff_file(@file)
|
|
20
|
-
else
|
|
21
|
-
diff_all_configs
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
print_results
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def diff_gem(gem_name)
|
|
28
|
-
# Normalize gem name (support both "ace-bundle" and "bundle")
|
|
29
|
-
gem_name = gem_name.start_with?("ace-") ? gem_name : "ace-#{gem_name}"
|
|
30
|
-
|
|
31
|
-
unless ConfigTemplates.gem_exists?(gem_name)
|
|
32
|
-
puts "Error: Gem '#{gem_name}' not found or has no example configurations"
|
|
33
|
-
exit 1
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
diff_gem_configs(gem_name)
|
|
37
|
-
print_results
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def config_directory
|
|
43
|
-
@global ? File.expand_path("~/.ace") : ".ace"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def diff_all_configs
|
|
47
|
-
ConfigTemplates.all_gems.each do |gem_name|
|
|
48
|
-
diff_gem_configs(gem_name)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def diff_gem_configs(gem_name)
|
|
53
|
-
source_dir = ConfigTemplates.example_dir_for(gem_name)
|
|
54
|
-
|
|
55
|
-
return unless source_dir && File.exist?(source_dir)
|
|
56
|
-
|
|
57
|
-
Dir.glob("#{source_dir}/**/*").each do |source_file|
|
|
58
|
-
next if File.directory?(source_file)
|
|
59
|
-
|
|
60
|
-
relative_path = Pathname.new(source_file).relative_path_from(Pathname.new(source_dir))
|
|
61
|
-
target_file = File.join(config_directory, relative_path.to_s)
|
|
62
|
-
|
|
63
|
-
compare_files(source_file, target_file, gem_name)
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def diff_file(file_path)
|
|
68
|
-
# Determine which gem this file belongs to
|
|
69
|
-
if file_path.start_with?(config_directory)
|
|
70
|
-
relative_path = Pathname.new(file_path).relative_path_from(Pathname.new(config_directory))
|
|
71
|
-
parts = relative_path.to_s.split(File::SEPARATOR)
|
|
72
|
-
|
|
73
|
-
if parts.any?
|
|
74
|
-
config_subdir = parts.first
|
|
75
|
-
gem_name = "ace-#{config_subdir}"
|
|
76
|
-
|
|
77
|
-
if ConfigTemplates.gem_exists?(gem_name)
|
|
78
|
-
source_dir = ConfigTemplates.example_dir_for(gem_name)
|
|
79
|
-
relative_file = parts[1..-1].join(File::SEPARATOR)
|
|
80
|
-
source_file = File.join(source_dir, relative_file)
|
|
81
|
-
|
|
82
|
-
if File.exist?(source_file)
|
|
83
|
-
compare_files(source_file, file_path, gem_name)
|
|
84
|
-
else
|
|
85
|
-
puts "No example file found for #{file_path}"
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
else
|
|
90
|
-
puts "File #{file_path} is not in a configuration directory"
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def compare_files(source_file, target_file, gem_name)
|
|
95
|
-
@diffs << if !File.exist?(target_file)
|
|
96
|
-
{
|
|
97
|
-
gem: gem_name,
|
|
98
|
-
file: target_file,
|
|
99
|
-
status: :missing,
|
|
100
|
-
source: source_file
|
|
101
|
-
}
|
|
102
|
-
elsif files_differ?(source_file, target_file)
|
|
103
|
-
{
|
|
104
|
-
gem: gem_name,
|
|
105
|
-
file: target_file,
|
|
106
|
-
status: :different,
|
|
107
|
-
source: source_file,
|
|
108
|
-
diff_output: get_diff_output(source_file, target_file)
|
|
109
|
-
}
|
|
110
|
-
else
|
|
111
|
-
{
|
|
112
|
-
gem: gem_name,
|
|
113
|
-
file: target_file,
|
|
114
|
-
status: :same,
|
|
115
|
-
source: source_file
|
|
116
|
-
}
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def files_differ?(file1, file2)
|
|
121
|
-
File.read(file1) != File.read(file2)
|
|
122
|
-
rescue
|
|
123
|
-
true
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def get_diff_output(source_file, target_file)
|
|
127
|
-
# Use system diff command
|
|
128
|
-
output, _status = Open3.capture2("diff", "-u", target_file, source_file)
|
|
129
|
-
output
|
|
130
|
-
rescue
|
|
131
|
-
"Unable to generate diff"
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def print_results
|
|
135
|
-
if @one_line
|
|
136
|
-
print_one_line_summary
|
|
137
|
-
else
|
|
138
|
-
print_detailed_diffs
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def print_one_line_summary
|
|
143
|
-
@diffs.each do |diff|
|
|
144
|
-
case diff[:status]
|
|
145
|
-
when :missing
|
|
146
|
-
puts "MISSING: #{diff[:file]}"
|
|
147
|
-
when :different
|
|
148
|
-
puts "CHANGED: #{diff[:file]}"
|
|
149
|
-
when :same
|
|
150
|
-
puts "SAME: #{diff[:file]}" if @verbose
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
puts "\nSummary:"
|
|
155
|
-
puts " Missing: #{@diffs.count { |d| d[:status] == :missing }}"
|
|
156
|
-
puts " Changed: #{@diffs.count { |d| d[:status] == :different }}"
|
|
157
|
-
puts " Same: #{@diffs.count { |d| d[:status] == :same }}"
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
def print_detailed_diffs
|
|
161
|
-
missing = @diffs.select { |d| d[:status] == :missing }
|
|
162
|
-
changed = @diffs.select { |d| d[:status] == :different }
|
|
163
|
-
|
|
164
|
-
if missing.any?
|
|
165
|
-
puts "Missing configuration files:"
|
|
166
|
-
missing.each do |diff|
|
|
167
|
-
puts " #{diff[:file]}"
|
|
168
|
-
puts " -> Example: #{diff[:source]}"
|
|
169
|
-
end
|
|
170
|
-
puts
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
if changed.any?
|
|
174
|
-
puts "Changed configuration files:"
|
|
175
|
-
changed.each do |diff|
|
|
176
|
-
puts "\n#{diff[:file]}:"
|
|
177
|
-
puts diff[:diff_output]
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
if missing.empty? && changed.empty?
|
|
182
|
-
puts "All configuration files match the examples."
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "fileutils"
|
|
4
|
-
require "pathname"
|
|
5
|
-
require_relative "../models/config_templates"
|
|
6
|
-
|
|
7
|
-
module Ace
|
|
8
|
-
module Core
|
|
9
|
-
class ConfigInitializer
|
|
10
|
-
def initialize(force: false, dry_run: false, global: false, verbose: false)
|
|
11
|
-
@force = force
|
|
12
|
-
@dry_run = dry_run
|
|
13
|
-
@global = global
|
|
14
|
-
@verbose = verbose
|
|
15
|
-
@copied_files = []
|
|
16
|
-
@skipped_files = []
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def init_all
|
|
20
|
-
puts "Initializing all ace-* gem configurations..." if @verbose
|
|
21
|
-
|
|
22
|
-
ConfigTemplates.all_gems.each do |gem_name|
|
|
23
|
-
init_gem(gem_name)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
print_summary
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def init_gem(gem_name)
|
|
30
|
-
gem_name = normalize_gem_name(gem_name)
|
|
31
|
-
|
|
32
|
-
unless ConfigTemplates.gem_exists?(gem_name)
|
|
33
|
-
puts "Warning: No configuration found for #{gem_name}"
|
|
34
|
-
return
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
puts "\nInitializing #{gem_name}..." if @verbose
|
|
38
|
-
|
|
39
|
-
source_dir = ConfigTemplates.example_dir_for(gem_name)
|
|
40
|
-
target_dir = target_directory
|
|
41
|
-
|
|
42
|
-
unless File.exist?(source_dir)
|
|
43
|
-
puts "Warning: No .ace-defaults directory found for #{gem_name}"
|
|
44
|
-
return
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Show config docs on first run if config is missing
|
|
48
|
-
show_config_docs_if_needed(gem_name, target_dir)
|
|
49
|
-
|
|
50
|
-
# Copy files from .ace-defaults to .ace
|
|
51
|
-
copy_config_files(source_dir, target_dir, gem_name)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
private
|
|
55
|
-
|
|
56
|
-
def normalize_gem_name(name)
|
|
57
|
-
# Handle both "ace-core" and "core" formats
|
|
58
|
-
name.start_with?("ace-") ? name : "ace-#{name}"
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def target_directory
|
|
62
|
-
@global ? File.expand_path("~/.ace") : ".ace"
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def show_config_docs_if_needed(gem_name, target_dir)
|
|
66
|
-
# Check if any config files exist for this gem
|
|
67
|
-
config_subdir = gem_name.sub("ace-", "")
|
|
68
|
-
|
|
69
|
-
# Look for any existing config files in the expected location
|
|
70
|
-
existing_configs = Dir.glob("#{target_dir}/#{config_subdir}/**/*").reject { |f| File.directory?(f) }
|
|
71
|
-
|
|
72
|
-
# Only show docs if this is the first time (no existing config)
|
|
73
|
-
if existing_configs.empty? && !@dry_run
|
|
74
|
-
docs_file = ConfigTemplates.docs_file_for(gem_name)
|
|
75
|
-
if File.exist?(docs_file)
|
|
76
|
-
puts "\n#{File.read(docs_file)}\n"
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def copy_config_files(source_dir, target_dir, gem_name)
|
|
82
|
-
Dir.glob("#{source_dir}/**/*").each do |source_file|
|
|
83
|
-
next if File.directory?(source_file)
|
|
84
|
-
|
|
85
|
-
# Calculate relative path from source_dir
|
|
86
|
-
relative_path = Pathname.new(source_file).relative_path_from(Pathname.new(source_dir))
|
|
87
|
-
|
|
88
|
-
# Build target path - files already include their subdirectory
|
|
89
|
-
target_file = File.join(target_dir, relative_path.to_s)
|
|
90
|
-
|
|
91
|
-
copy_file(source_file, target_file)
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def copy_file(source, target)
|
|
96
|
-
if File.exist?(target) && !@force
|
|
97
|
-
@skipped_files << target
|
|
98
|
-
puts " Skipped: #{target} (already exists)" if @verbose
|
|
99
|
-
return
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
if @dry_run
|
|
103
|
-
puts " Would copy: #{source} -> #{target}"
|
|
104
|
-
else
|
|
105
|
-
FileUtils.mkdir_p(File.dirname(target))
|
|
106
|
-
FileUtils.cp(source, target)
|
|
107
|
-
@copied_files << target
|
|
108
|
-
puts " Copied: #{target}" if @verbose
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def print_summary
|
|
113
|
-
return if @dry_run
|
|
114
|
-
|
|
115
|
-
puts "\nConfiguration initialization complete:"
|
|
116
|
-
puts " Files copied: #{@copied_files.size}"
|
|
117
|
-
puts " Files skipped: #{@skipped_files.size}"
|
|
118
|
-
|
|
119
|
-
if @skipped_files.any? && !@force
|
|
120
|
-
puts "\nUse --force to overwrite existing files"
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|