ace-bundle 0.40.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.
- checksums.yaml +7 -0
- data/.ace-defaults/bundle/config.yml +28 -0
- data/.ace-defaults/bundle/presets/base.md +15 -0
- data/.ace-defaults/bundle/presets/code-review.md +61 -0
- data/.ace-defaults/bundle/presets/development.md +16 -0
- data/.ace-defaults/bundle/presets/documentation-review.md +52 -0
- data/.ace-defaults/bundle/presets/mixed-content-example.md +94 -0
- data/.ace-defaults/bundle/presets/project-context.md +79 -0
- data/.ace-defaults/bundle/presets/project.md +35 -0
- data/.ace-defaults/bundle/presets/section-example-simple.md +27 -0
- data/.ace-defaults/bundle/presets/security-review.md +53 -0
- data/.ace-defaults/bundle/presets/simple-project.md +43 -0
- data/.ace-defaults/bundle/presets/team.md +18 -0
- data/.ace-defaults/nav/protocols/wfi-sources/ace-bundle.yml +19 -0
- data/CHANGELOG.md +384 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/Rakefile +22 -0
- data/exe/ace-bundle +14 -0
- data/handbook/skills/as-bundle/SKILL.md +28 -0
- data/handbook/skills/as-onboard/SKILL.md +33 -0
- data/handbook/workflow-instructions/bundle.wf.md +111 -0
- data/handbook/workflow-instructions/onboard.wf.md +20 -0
- data/lib/ace/bundle/atoms/boundary_finder.rb +122 -0
- data/lib/ace/bundle/atoms/bundle_normalizer.rb +128 -0
- data/lib/ace/bundle/atoms/content_checker.rb +46 -0
- data/lib/ace/bundle/atoms/line_counter.rb +37 -0
- data/lib/ace/bundle/atoms/preset_list_formatter.rb +44 -0
- data/lib/ace/bundle/atoms/preset_validator.rb +69 -0
- data/lib/ace/bundle/atoms/section_validator.rb +215 -0
- data/lib/ace/bundle/atoms/typo_detector.rb +76 -0
- data/lib/ace/bundle/cli/commands/load.rb +347 -0
- data/lib/ace/bundle/cli.rb +26 -0
- data/lib/ace/bundle/models/bundle_data.rb +75 -0
- data/lib/ace/bundle/molecules/bundle_chunker.rb +280 -0
- data/lib/ace/bundle/molecules/bundle_file_writer.rb +269 -0
- data/lib/ace/bundle/molecules/bundle_merger.rb +248 -0
- data/lib/ace/bundle/molecules/preset_manager.rb +331 -0
- data/lib/ace/bundle/molecules/section_compressor.rb +249 -0
- data/lib/ace/bundle/molecules/section_formatter.rb +580 -0
- data/lib/ace/bundle/molecules/section_processor.rb +460 -0
- data/lib/ace/bundle/organisms/bundle_loader.rb +1436 -0
- data/lib/ace/bundle/organisms/pr_bundle_loader.rb +147 -0
- data/lib/ace/bundle/version.rb +7 -0
- data/lib/ace/bundle.rb +251 -0
- metadata +190 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/git"
|
|
4
|
+
|
|
5
|
+
module Ace
|
|
6
|
+
module Bundle
|
|
7
|
+
module Organisms
|
|
8
|
+
# Loads PR diff content into bundle
|
|
9
|
+
#
|
|
10
|
+
# Responsible for:
|
|
11
|
+
# - Normalizing PR references (string, array, hash formats)
|
|
12
|
+
# - Fetching diffs via Ace::Git::Molecules::PrMetadataFetcher
|
|
13
|
+
# - Integrating results into bundle sections
|
|
14
|
+
# - Error handling and surfacing
|
|
15
|
+
#
|
|
16
|
+
# @example Basic usage
|
|
17
|
+
# loader = PrBundleLoader.new(timeout: 60)
|
|
18
|
+
# loader.process(bundle, ["123", "owner/repo#456"])
|
|
19
|
+
#
|
|
20
|
+
class PrBundleLoader
|
|
21
|
+
# @param options [Hash] Configuration options
|
|
22
|
+
# @option options [Integer] :timeout Timeout for gh commands (default from ace-git config)
|
|
23
|
+
# @option options [Boolean] :debug Enable debug output
|
|
24
|
+
def initialize(options = {})
|
|
25
|
+
@timeout = options[:timeout] || Ace::Git.network_timeout
|
|
26
|
+
@debug = options[:debug] || false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Process PR references and add diffs to bundle
|
|
30
|
+
#
|
|
31
|
+
# @param bundle [Models::BundleData] Bundle to populate
|
|
32
|
+
# @param pr_refs [Array<String>, String, Hash, nil] PR reference(s)
|
|
33
|
+
# @return [Boolean] true if at least one diff was successfully fetched
|
|
34
|
+
def process(bundle, pr_refs)
|
|
35
|
+
normalized = normalize_pr_refs(pr_refs)
|
|
36
|
+
return false if normalized.empty?
|
|
37
|
+
|
|
38
|
+
processed_diffs = fetch_all_diffs(bundle, normalized)
|
|
39
|
+
successful_diffs = processed_diffs.select { |d| d[:success] }
|
|
40
|
+
|
|
41
|
+
if successful_diffs.empty?
|
|
42
|
+
surface_errors_to_content(bundle)
|
|
43
|
+
return false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
add_diffs_to_bundle(bundle, processed_diffs)
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Normalize PR refs to array, deduplicate, and remove empty/nil values
|
|
53
|
+
# Handles both string refs and hash refs (for future extensibility)
|
|
54
|
+
#
|
|
55
|
+
# @param pr_refs [String, Array, Hash, nil] PR reference(s)
|
|
56
|
+
# @return [Array<String>] Normalized, deduplicated PR refs
|
|
57
|
+
def normalize_pr_refs(pr_refs)
|
|
58
|
+
refs = pr_refs.is_a?(Array) ? pr_refs.flatten : [pr_refs]
|
|
59
|
+
refs.map do |ref|
|
|
60
|
+
case ref
|
|
61
|
+
when String then ref.strip
|
|
62
|
+
when Hash then ref[:number]&.to_s || ref["number"]&.to_s
|
|
63
|
+
else ref&.to_s
|
|
64
|
+
end
|
|
65
|
+
end.compact.reject(&:empty?).uniq
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Fetch diffs for all PR refs, recording errors in bundle metadata
|
|
69
|
+
#
|
|
70
|
+
# @param bundle [Models::BundleData] Bundle for error recording
|
|
71
|
+
# @param pr_refs [Array<String>] Normalized PR refs
|
|
72
|
+
# @return [Array<Hash>] Processed diff results
|
|
73
|
+
def fetch_all_diffs(bundle, pr_refs)
|
|
74
|
+
pr_refs.map do |pr_ref|
|
|
75
|
+
fetch_single_diff(bundle, pr_ref)
|
|
76
|
+
end.compact
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Fetch diff for a single PR reference
|
|
80
|
+
#
|
|
81
|
+
# @param bundle [Models::BundleData] Bundle for error recording
|
|
82
|
+
# @param pr_ref [String] Single PR reference
|
|
83
|
+
# @return [Hash, nil] Diff result or nil on skip
|
|
84
|
+
def fetch_single_diff(bundle, pr_ref)
|
|
85
|
+
result = Ace::Git::Molecules::PrMetadataFetcher.fetch_diff(pr_ref, timeout: @timeout)
|
|
86
|
+
|
|
87
|
+
if result[:success]
|
|
88
|
+
{
|
|
89
|
+
range: result[:source],
|
|
90
|
+
output: result[:diff],
|
|
91
|
+
success: true,
|
|
92
|
+
source: :pr
|
|
93
|
+
}
|
|
94
|
+
else
|
|
95
|
+
record_error(bundle, "PR fetch failed for '#{pr_ref}': #{result[:error]}")
|
|
96
|
+
{range: pr_range_identifier(pr_ref), output: "Error: #{result[:error]}", success: false, error: result[:error], source: :pr}
|
|
97
|
+
end
|
|
98
|
+
rescue Ace::Git::Error => e
|
|
99
|
+
# Catches all ace-git errors: GitError, GhNotInstalledError, GhAuthenticationError,
|
|
100
|
+
# PrNotFoundError, TimeoutError (all inherit from Ace::Git::Error)
|
|
101
|
+
record_error(bundle, "PR fetch failed for '#{pr_ref}': #{e.message}")
|
|
102
|
+
{range: pr_range_identifier(pr_ref), output: "Error: #{e.message}", success: false, error: e.message, source: :pr}
|
|
103
|
+
rescue ArgumentError => e
|
|
104
|
+
record_error(bundle, "Invalid PR identifier '#{pr_ref}': #{e.message}")
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Record error in bundle metadata
|
|
109
|
+
#
|
|
110
|
+
# @param bundle [Models::BundleData] Bundle to update
|
|
111
|
+
# @param message [String] Error message
|
|
112
|
+
def record_error(bundle, message)
|
|
113
|
+
bundle.metadata[:errors] ||= []
|
|
114
|
+
bundle.metadata[:errors] << message
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Generate standardized PR range identifier for error responses
|
|
118
|
+
# @param pr_ref [String] PR reference
|
|
119
|
+
# @return [String] Range identifier in "pr:ref" format
|
|
120
|
+
def pr_range_identifier(pr_ref)
|
|
121
|
+
"pr:#{pr_ref}"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Surface errors to content for callers who don't inspect metadata
|
|
125
|
+
#
|
|
126
|
+
# @param bundle [Models::BundleData] Bundle to update
|
|
127
|
+
def surface_errors_to_content(bundle)
|
|
128
|
+
return unless bundle.metadata[:errors]&.any?
|
|
129
|
+
|
|
130
|
+
error_notice = bundle.metadata[:errors].map { |e| "- #{e}" }.join("\n")
|
|
131
|
+
bundle.content = "**PR Fetch Errors:**\n#{error_notice}\n\n" + (bundle.content || "")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Add processed diffs to bundle's diffs section
|
|
135
|
+
#
|
|
136
|
+
# @param bundle [Models::BundleData] Bundle to update
|
|
137
|
+
# @param processed_diffs [Array<Hash>] Diff results to add
|
|
138
|
+
def add_diffs_to_bundle(bundle, processed_diffs)
|
|
139
|
+
bundle.sections ||= {}
|
|
140
|
+
bundle.sections["diffs"] ||= {title: "Diffs", _processed_diffs: []}
|
|
141
|
+
bundle.sections["diffs"][:_processed_diffs] ||= []
|
|
142
|
+
bundle.sections["diffs"][:_processed_diffs].concat(processed_diffs)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
data/lib/ace/bundle.rb
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/config"
|
|
4
|
+
require "ace/core"
|
|
5
|
+
require "ace/git"
|
|
6
|
+
require_relative "bundle/version"
|
|
7
|
+
|
|
8
|
+
# Define error hierarchy before loading components (they reference these classes)
|
|
9
|
+
module Ace
|
|
10
|
+
module Bundle
|
|
11
|
+
# Base error class for all ace-bundle errors
|
|
12
|
+
class Error < StandardError; end
|
|
13
|
+
|
|
14
|
+
# Raised when section validation fails
|
|
15
|
+
class SectionValidationError < Error; end
|
|
16
|
+
|
|
17
|
+
# Raised when preset loading fails
|
|
18
|
+
class PresetLoadError < Error; end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Main API
|
|
23
|
+
require_relative "bundle/organisms/bundle_loader"
|
|
24
|
+
require_relative "bundle/molecules/preset_manager"
|
|
25
|
+
require_relative "bundle/molecules/bundle_file_writer"
|
|
26
|
+
|
|
27
|
+
# CLI and commands
|
|
28
|
+
require_relative "bundle/cli"
|
|
29
|
+
|
|
30
|
+
module Ace
|
|
31
|
+
module Bundle
|
|
32
|
+
# Mutex for thread-safe config initialization
|
|
33
|
+
@config_mutex = Mutex.new
|
|
34
|
+
|
|
35
|
+
class << self
|
|
36
|
+
# Load bundle using preset
|
|
37
|
+
# @param preset_name [String] Name of the preset to load
|
|
38
|
+
# @param options [Hash] Additional options
|
|
39
|
+
# @return [Models::BundleData] Loaded bundle data
|
|
40
|
+
def load_preset(preset_name, options = {})
|
|
41
|
+
loader = Organisms::BundleLoader.new(options)
|
|
42
|
+
loader.load_preset(preset_name)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Load multiple presets and merge them
|
|
46
|
+
# @param preset_names [Array<String>] Names of presets to load
|
|
47
|
+
# @param options [Hash] Additional options
|
|
48
|
+
# @return [Models::BundleData] Merged bundle data
|
|
49
|
+
def load_multiple_presets(preset_names, options = {})
|
|
50
|
+
loader = Organisms::BundleLoader.new(options)
|
|
51
|
+
loader.load_multiple_presets(preset_names)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Inspect configuration of presets/files without loading files or executing commands
|
|
55
|
+
# @param inputs [Array<String>] Names of presets or paths to files to inspect
|
|
56
|
+
# @param options [Hash] Additional options
|
|
57
|
+
# @return [Models::BundleData] Configuration as YAML
|
|
58
|
+
def inspect_config(inputs, options = {})
|
|
59
|
+
loader = Organisms::BundleLoader.new(options)
|
|
60
|
+
loader.inspect_config(inputs)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# List available presets
|
|
64
|
+
# @return [Array<Hash>] List of available presets
|
|
65
|
+
def list_presets
|
|
66
|
+
manager = Molecules::PresetManager.new
|
|
67
|
+
manager.list_presets
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Load bundle from file
|
|
71
|
+
# @param path [String] Path to bundle file
|
|
72
|
+
# @param options [Hash] Additional options
|
|
73
|
+
# @return [Models::BundleData] Loaded bundle data
|
|
74
|
+
def load_file(path, options = {})
|
|
75
|
+
loader = Organisms::BundleLoader.new(options)
|
|
76
|
+
loader.load_file(path)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Load with auto-detection
|
|
80
|
+
# @param input [String] File path, inline YAML, or preset name
|
|
81
|
+
# @param options [Hash] Additional options
|
|
82
|
+
# @return [Models::BundleData] Loaded bundle data
|
|
83
|
+
def load_auto(input, options = {})
|
|
84
|
+
loader = Organisms::BundleLoader.new(options)
|
|
85
|
+
loader.load_auto(input)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Load multiple inputs and merge them
|
|
89
|
+
# @param inputs [Array<String>] Array of inputs to load
|
|
90
|
+
# @param options [Hash] Additional options
|
|
91
|
+
# @return [Models::BundleData] Merged bundle data
|
|
92
|
+
def load_multiple(inputs, options = {})
|
|
93
|
+
loader = Organisms::BundleLoader.new(options)
|
|
94
|
+
loader.load_multiple(inputs)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Load multiple inputs (presets and files) and merge them
|
|
98
|
+
# @param preset_names [Array<String>] Names of presets to load
|
|
99
|
+
# @param file_paths [Array<String>] Paths to configuration files
|
|
100
|
+
# @param options [Hash] Additional options
|
|
101
|
+
# @return [Models::BundleData] Merged bundle data
|
|
102
|
+
def load_multiple_inputs(preset_names, file_paths, options = {})
|
|
103
|
+
loader = Organisms::BundleLoader.new(options)
|
|
104
|
+
loader.load_multiple_inputs(preset_names, file_paths, options)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Write bundle output to file with optional chunking
|
|
108
|
+
# @param bundle [Models::BundleData] Bundle to write
|
|
109
|
+
# @param output_path [String] Output file path
|
|
110
|
+
# @param options [Hash] Additional options
|
|
111
|
+
# @return [Hash] Write result with success status
|
|
112
|
+
def write_output(bundle, output_path, options = {})
|
|
113
|
+
writer = Molecules::BundleFileWriter.new(
|
|
114
|
+
cache_dir: cache_dir,
|
|
115
|
+
max_lines: max_lines
|
|
116
|
+
)
|
|
117
|
+
writer.write_with_chunking(bundle, output_path, options)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Get configuration for ace-bundle
|
|
121
|
+
# Follows ADR-022: Configuration Default and Override Pattern
|
|
122
|
+
# Uses Ace::Support::Config.create() for configuration cascade resolution
|
|
123
|
+
# Thread-safe: uses mutex for initialization
|
|
124
|
+
# @return [Hash] merged configuration hash
|
|
125
|
+
# @example Get current configuration
|
|
126
|
+
# config = Ace::Bundle.config
|
|
127
|
+
# puts config["cache_dir"] # => ".ace-local/bundle"
|
|
128
|
+
def config
|
|
129
|
+
# Fast path: return cached config if already initialized
|
|
130
|
+
return @config if defined?(@config) && @config
|
|
131
|
+
|
|
132
|
+
# Thread-safe initialization
|
|
133
|
+
@config_mutex.synchronize do
|
|
134
|
+
@config ||= load_config
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Reset configuration cache (mainly for testing)
|
|
139
|
+
# Thread-safe: uses mutex to prevent race conditions
|
|
140
|
+
def reset_config!
|
|
141
|
+
@config_mutex.synchronize do
|
|
142
|
+
@config = nil
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# ---- Configuration Helper Methods (ADR-022 compliant) ----
|
|
147
|
+
# These read from config instead of using hardcoded constants
|
|
148
|
+
|
|
149
|
+
# Cache directory for bundle output files
|
|
150
|
+
# @return [String] Cache directory path (default: ".ace-local/bundle")
|
|
151
|
+
def cache_dir
|
|
152
|
+
config["cache_dir"] || ".ace-local/bundle"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Maximum lines per chunk before splitting output into multiple files
|
|
156
|
+
# @return [Integer] Max lines per chunk (default: 2000)
|
|
157
|
+
def max_lines
|
|
158
|
+
config["max_lines"] || 2_000
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Line count threshold for auto-format output mode
|
|
162
|
+
# When no explicit --output mode is specified:
|
|
163
|
+
# - Content below this threshold: displayed inline (stdout)
|
|
164
|
+
# - Content at or above this threshold: saved to cache file
|
|
165
|
+
# @return [Integer] Auto-format threshold in lines (default: 500, range: 10-10000)
|
|
166
|
+
def auto_format_threshold
|
|
167
|
+
threshold = config["auto_format_threshold"]
|
|
168
|
+
# Ensure valid integer within reasonable bounds (10-10000 lines)
|
|
169
|
+
# - Below 10: too aggressive, would cache almost everything
|
|
170
|
+
# - Above 10000: defeats the purpose of auto-format
|
|
171
|
+
return 500 unless threshold.is_a?(Integer) && threshold.between?(10, 10_000)
|
|
172
|
+
|
|
173
|
+
threshold
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Compressor configuration section from global/project config
|
|
177
|
+
# @return [Hash] compressor config (default: {})
|
|
178
|
+
def compressor_config
|
|
179
|
+
config["compressor"] || {}
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Default compressor source scope from config
|
|
183
|
+
# @return [String] source scope (default: "off")
|
|
184
|
+
def compressor_source_scope
|
|
185
|
+
compressor_config["source_scope"] || "off"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Default compressor mode from config
|
|
189
|
+
# @return [String] compressor mode (default: "exact")
|
|
190
|
+
def compressor_mode
|
|
191
|
+
compressor_config["mode"] || "exact"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
private
|
|
195
|
+
|
|
196
|
+
# Load configuration using Ace::Support::Config cascade
|
|
197
|
+
# Resolves gem defaults from .ace-defaults/ and user overrides from .ace/
|
|
198
|
+
# @return [Hash] Merged and transformed configuration
|
|
199
|
+
def load_config
|
|
200
|
+
gem_root = Gem.loaded_specs["ace-bundle"]&.gem_dir ||
|
|
201
|
+
File.expand_path("../..", __dir__)
|
|
202
|
+
|
|
203
|
+
resolver = Ace::Support::Config.create(
|
|
204
|
+
config_dir: ".ace",
|
|
205
|
+
defaults_dir: ".ace-defaults",
|
|
206
|
+
gem_path: gem_root
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# Resolve config for bundle namespace
|
|
210
|
+
config = resolver.resolve_namespace("bundle")
|
|
211
|
+
|
|
212
|
+
# Extract the bundle section for direct access
|
|
213
|
+
raw_config = config.data["bundle"] || config.data
|
|
214
|
+
normalize_keys(raw_config)
|
|
215
|
+
rescue Ace::Support::Config::YamlParseError => e
|
|
216
|
+
warn "ace-bundle: YAML syntax error in configuration"
|
|
217
|
+
warn " #{e.message}"
|
|
218
|
+
# Fall back to gem defaults
|
|
219
|
+
load_gem_defaults_fallback
|
|
220
|
+
rescue => e
|
|
221
|
+
warn "ace-bundle: Failed to load configuration: #{e.message}"
|
|
222
|
+
# Fall back to gem defaults
|
|
223
|
+
load_gem_defaults_fallback
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Load gem defaults directly as fallback when cascade resolution fails
|
|
227
|
+
# @return [Hash] Defaults hash or empty hash if defaults also fail
|
|
228
|
+
def load_gem_defaults_fallback
|
|
229
|
+
gem_root = Gem.loaded_specs["ace-bundle"]&.gem_dir ||
|
|
230
|
+
File.expand_path("../..", __dir__)
|
|
231
|
+
defaults_path = File.join(gem_root, ".ace-defaults", "bundle", "config.yml")
|
|
232
|
+
|
|
233
|
+
return {} unless File.exist?(defaults_path)
|
|
234
|
+
|
|
235
|
+
data = YAML.safe_load_file(defaults_path, permitted_classes: [Date], aliases: true) || {}
|
|
236
|
+
normalize_keys(data["bundle"] || data)
|
|
237
|
+
rescue
|
|
238
|
+
{} # Only return empty hash if even defaults fail to load
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Normalize hash keys to strings for consistent access
|
|
242
|
+
# @param hash [Hash] Hash with potentially mixed string/symbol keys
|
|
243
|
+
# @return [Hash] Hash with string keys
|
|
244
|
+
def normalize_keys(hash)
|
|
245
|
+
return {} unless hash.is_a?(Hash)
|
|
246
|
+
|
|
247
|
+
hash.transform_keys(&:to_s)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ace-bundle
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.40.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Michal Czyz
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ace-support-cli
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.3'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: ace-support-config
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.7'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0.7'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: ace-support-core
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0.24'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0.24'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: ace-support-fs
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.2'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0.2'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: ace-git
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0.11'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0.11'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: ace-support-nav
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0.18'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0.18'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: ace-compressor
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0.21'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0.21'
|
|
110
|
+
description: Assembles files, shell commands, and git diffs into a single bundled
|
|
111
|
+
file. Configured via presets or markdown frontmatter with protocol URL support (wfi://,
|
|
112
|
+
guide://, tmpl://, prompt://, task://). Output to stdout or cache, with optional
|
|
113
|
+
compression through ace-compressor.
|
|
114
|
+
email:
|
|
115
|
+
- mc@cs3b.com
|
|
116
|
+
executables:
|
|
117
|
+
- ace-bundle
|
|
118
|
+
extensions: []
|
|
119
|
+
extra_rdoc_files: []
|
|
120
|
+
files:
|
|
121
|
+
- ".ace-defaults/bundle/config.yml"
|
|
122
|
+
- ".ace-defaults/bundle/presets/base.md"
|
|
123
|
+
- ".ace-defaults/bundle/presets/code-review.md"
|
|
124
|
+
- ".ace-defaults/bundle/presets/development.md"
|
|
125
|
+
- ".ace-defaults/bundle/presets/documentation-review.md"
|
|
126
|
+
- ".ace-defaults/bundle/presets/mixed-content-example.md"
|
|
127
|
+
- ".ace-defaults/bundle/presets/project-context.md"
|
|
128
|
+
- ".ace-defaults/bundle/presets/project.md"
|
|
129
|
+
- ".ace-defaults/bundle/presets/section-example-simple.md"
|
|
130
|
+
- ".ace-defaults/bundle/presets/security-review.md"
|
|
131
|
+
- ".ace-defaults/bundle/presets/simple-project.md"
|
|
132
|
+
- ".ace-defaults/bundle/presets/team.md"
|
|
133
|
+
- ".ace-defaults/nav/protocols/wfi-sources/ace-bundle.yml"
|
|
134
|
+
- CHANGELOG.md
|
|
135
|
+
- LICENSE
|
|
136
|
+
- README.md
|
|
137
|
+
- Rakefile
|
|
138
|
+
- exe/ace-bundle
|
|
139
|
+
- handbook/skills/as-bundle/SKILL.md
|
|
140
|
+
- handbook/skills/as-onboard/SKILL.md
|
|
141
|
+
- handbook/workflow-instructions/bundle.wf.md
|
|
142
|
+
- handbook/workflow-instructions/onboard.wf.md
|
|
143
|
+
- lib/ace/bundle.rb
|
|
144
|
+
- lib/ace/bundle/atoms/boundary_finder.rb
|
|
145
|
+
- lib/ace/bundle/atoms/bundle_normalizer.rb
|
|
146
|
+
- lib/ace/bundle/atoms/content_checker.rb
|
|
147
|
+
- lib/ace/bundle/atoms/line_counter.rb
|
|
148
|
+
- lib/ace/bundle/atoms/preset_list_formatter.rb
|
|
149
|
+
- lib/ace/bundle/atoms/preset_validator.rb
|
|
150
|
+
- lib/ace/bundle/atoms/section_validator.rb
|
|
151
|
+
- lib/ace/bundle/atoms/typo_detector.rb
|
|
152
|
+
- lib/ace/bundle/cli.rb
|
|
153
|
+
- lib/ace/bundle/cli/commands/load.rb
|
|
154
|
+
- lib/ace/bundle/models/bundle_data.rb
|
|
155
|
+
- lib/ace/bundle/molecules/bundle_chunker.rb
|
|
156
|
+
- lib/ace/bundle/molecules/bundle_file_writer.rb
|
|
157
|
+
- lib/ace/bundle/molecules/bundle_merger.rb
|
|
158
|
+
- lib/ace/bundle/molecules/preset_manager.rb
|
|
159
|
+
- lib/ace/bundle/molecules/section_compressor.rb
|
|
160
|
+
- lib/ace/bundle/molecules/section_formatter.rb
|
|
161
|
+
- lib/ace/bundle/molecules/section_processor.rb
|
|
162
|
+
- lib/ace/bundle/organisms/bundle_loader.rb
|
|
163
|
+
- lib/ace/bundle/organisms/pr_bundle_loader.rb
|
|
164
|
+
- lib/ace/bundle/version.rb
|
|
165
|
+
homepage: https://github.com/cs3b/ace
|
|
166
|
+
licenses:
|
|
167
|
+
- MIT
|
|
168
|
+
metadata:
|
|
169
|
+
allowed_push_host: https://rubygems.org
|
|
170
|
+
homepage_uri: https://github.com/cs3b/ace
|
|
171
|
+
source_code_uri: https://github.com/cs3b/ace
|
|
172
|
+
changelog_uri: https://github.com/cs3b/ace/blob/main/ace-bundle/CHANGELOG.md
|
|
173
|
+
rdoc_options: []
|
|
174
|
+
require_paths:
|
|
175
|
+
- lib
|
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - ">="
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: 3.2.0
|
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '0'
|
|
186
|
+
requirements: []
|
|
187
|
+
rubygems_version: 3.6.9
|
|
188
|
+
specification_version: 4
|
|
189
|
+
summary: Assemble multiple sources into a single bundled file, with optional compression
|
|
190
|
+
test_files: []
|