aidp 0.32.0 → 0.33.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 +4 -4
- data/lib/aidp/analyze/feature_analyzer.rb +322 -320
- data/lib/aidp/auto_update/coordinator.rb +97 -7
- data/lib/aidp/auto_update.rb +0 -12
- data/lib/aidp/cli/devcontainer_commands.rb +0 -5
- data/lib/aidp/cli.rb +2 -1
- data/lib/aidp/comment_consolidator.rb +78 -0
- data/lib/aidp/concurrency.rb +0 -3
- data/lib/aidp/config.rb +0 -1
- data/lib/aidp/config_paths.rb +71 -0
- data/lib/aidp/execute/work_loop_runner.rb +324 -15
- data/lib/aidp/harness/ai_filter_factory.rb +285 -0
- data/lib/aidp/harness/config_schema.rb +97 -1
- data/lib/aidp/harness/config_validator.rb +1 -1
- data/lib/aidp/harness/configuration.rb +61 -5
- data/lib/aidp/harness/filter_definition.rb +212 -0
- data/lib/aidp/harness/generated_filter_strategy.rb +197 -0
- data/lib/aidp/harness/output_filter.rb +50 -25
- data/lib/aidp/harness/output_filter_config.rb +129 -0
- data/lib/aidp/harness/provider_manager.rb +90 -2
- data/lib/aidp/harness/runner.rb +0 -11
- data/lib/aidp/harness/test_runner.rb +179 -41
- data/lib/aidp/harness/thinking_depth_manager.rb +16 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +0 -2
- data/lib/aidp/loader.rb +195 -0
- data/lib/aidp/metadata/compiler.rb +29 -17
- data/lib/aidp/metadata/query.rb +1 -1
- data/lib/aidp/metadata/scanner.rb +8 -1
- data/lib/aidp/metadata/tool_metadata.rb +13 -13
- data/lib/aidp/metadata/validator.rb +10 -0
- data/lib/aidp/metadata.rb +16 -0
- data/lib/aidp/pr_worktree_manager.rb +2 -2
- data/lib/aidp/provider_manager.rb +1 -7
- data/lib/aidp/setup/wizard.rb +279 -9
- data/lib/aidp/skills.rb +0 -5
- data/lib/aidp/storage/csv_storage.rb +3 -0
- data/lib/aidp/style_guide/selector.rb +360 -0
- data/lib/aidp/tooling_detector.rb +283 -16
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/change_request_processor.rb +152 -14
- data/lib/aidp/watch/repository_client.rb +41 -0
- data/lib/aidp/watch/runner.rb +29 -18
- data/lib/aidp/watch.rb +5 -7
- data/lib/aidp/workstream_cleanup.rb +0 -2
- data/lib/aidp/workstream_executor.rb +0 -4
- data/lib/aidp/worktree.rb +0 -1
- data/lib/aidp.rb +21 -106
- metadata +72 -36
- data/lib/aidp/config/paths.rb +0 -131
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "version_detector"
|
|
4
|
-
require_relative "checkpoint_store"
|
|
5
|
-
require_relative "update_logger"
|
|
6
|
-
require_relative "failure_tracker"
|
|
7
|
-
require_relative "update_policy"
|
|
8
|
-
require_relative "errors"
|
|
9
|
-
|
|
10
3
|
module Aidp
|
|
11
4
|
module AutoUpdate
|
|
12
5
|
# Facade for orchestrating the complete auto-update workflow
|
|
@@ -188,8 +181,105 @@ module Aidp
|
|
|
188
181
|
}
|
|
189
182
|
end
|
|
190
183
|
|
|
184
|
+
# Perform hot code reload without restarting the process
|
|
185
|
+
#
|
|
186
|
+
# This method performs a git pull and then uses Zeitwerk to reload
|
|
187
|
+
# all Ruby classes. Unlike initiate_update (which exits with code 75),
|
|
188
|
+
# this method keeps the process running.
|
|
189
|
+
#
|
|
190
|
+
# @param update_check [UpdateCheck] Update check result
|
|
191
|
+
# @return [Boolean] Whether reload was successful
|
|
192
|
+
# @raise [UpdateError] If updates are disabled or reload fails
|
|
193
|
+
def hot_reload_update(update_check = nil)
|
|
194
|
+
raise UpdateError, "Updates disabled by configuration" unless @policy.enabled
|
|
195
|
+
|
|
196
|
+
# Verify Zeitwerk loader is set up for reloading
|
|
197
|
+
unless Aidp::Loader.setup? && Aidp::Loader.reloading?
|
|
198
|
+
Aidp.log_warn("auto_update_coordinator", "hot_reload_not_available",
|
|
199
|
+
reason: "Zeitwerk loader not configured for reloading")
|
|
200
|
+
raise UpdateError, "Hot reloading not available. Loader must be configured with enable_reloading: true"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
update_check ||= check_for_update
|
|
204
|
+
return false unless update_check.should_update?
|
|
205
|
+
|
|
206
|
+
from_version = update_check.current_version
|
|
207
|
+
to_version = update_check.available_version
|
|
208
|
+
|
|
209
|
+
Aidp.log_info("auto_update_coordinator", "hot_reload_starting",
|
|
210
|
+
from_version: from_version,
|
|
211
|
+
to_version: to_version)
|
|
212
|
+
|
|
213
|
+
# Perform git pull
|
|
214
|
+
unless perform_git_pull
|
|
215
|
+
raise UpdateError, "Git pull failed"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Reload all classes using Zeitwerk
|
|
219
|
+
unless Aidp::Loader.reload!
|
|
220
|
+
@failure_tracker.record_failure
|
|
221
|
+
@update_logger.log_failure("Zeitwerk reload failed")
|
|
222
|
+
raise UpdateError, "Zeitwerk reload failed"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Log success
|
|
226
|
+
@update_logger.log_success(
|
|
227
|
+
from_version: from_version,
|
|
228
|
+
to_version: to_version
|
|
229
|
+
)
|
|
230
|
+
@failure_tracker.reset_on_success
|
|
231
|
+
|
|
232
|
+
Aidp.log_info("auto_update_coordinator", "hot_reload_complete",
|
|
233
|
+
from_version: from_version,
|
|
234
|
+
to_version: to_version)
|
|
235
|
+
|
|
236
|
+
true
|
|
237
|
+
rescue UpdateError
|
|
238
|
+
raise
|
|
239
|
+
rescue => e
|
|
240
|
+
@failure_tracker.record_failure
|
|
241
|
+
@update_logger.log_failure("Hot reload failed: #{e.message}")
|
|
242
|
+
Aidp.log_error("auto_update_coordinator", "hot_reload_failed",
|
|
243
|
+
error: e.message)
|
|
244
|
+
raise UpdateError, "Hot reload failed: #{e.message}"
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Check if hot reloading is available
|
|
248
|
+
# @return [Boolean]
|
|
249
|
+
def hot_reload_available?
|
|
250
|
+
Aidp::Loader.setup? && Aidp::Loader.reloading?
|
|
251
|
+
end
|
|
252
|
+
|
|
191
253
|
private
|
|
192
254
|
|
|
255
|
+
# Perform git pull to fetch latest code
|
|
256
|
+
# @return [Boolean] Whether pull was successful
|
|
257
|
+
def perform_git_pull
|
|
258
|
+
require "open3"
|
|
259
|
+
|
|
260
|
+
Aidp.log_debug("auto_update_coordinator", "git_pull_starting",
|
|
261
|
+
project_dir: @project_dir)
|
|
262
|
+
|
|
263
|
+
Dir.chdir(@project_dir) do
|
|
264
|
+
stdout, stderr, status = Open3.capture3("git", "pull", "--ff-only")
|
|
265
|
+
|
|
266
|
+
if status.success?
|
|
267
|
+
Aidp.log_info("auto_update_coordinator", "git_pull_success",
|
|
268
|
+
output: stdout.strip)
|
|
269
|
+
true
|
|
270
|
+
else
|
|
271
|
+
Aidp.log_error("auto_update_coordinator", "git_pull_failed",
|
|
272
|
+
stderr: stderr.strip,
|
|
273
|
+
exit_code: status.exitstatus)
|
|
274
|
+
false
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
rescue => e
|
|
278
|
+
Aidp.log_error("auto_update_coordinator", "git_pull_error",
|
|
279
|
+
error: e.message)
|
|
280
|
+
false
|
|
281
|
+
end
|
|
282
|
+
|
|
193
283
|
def build_checkpoint(current_state, target_version)
|
|
194
284
|
Checkpoint.new(
|
|
195
285
|
mode: current_state[:mode] || "watch",
|
data/lib/aidp/auto_update.rb
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "auto_update/errors"
|
|
4
|
-
require_relative "auto_update/update_policy"
|
|
5
|
-
require_relative "auto_update/update_check"
|
|
6
|
-
require_relative "auto_update/checkpoint"
|
|
7
|
-
require_relative "auto_update/bundler_adapter"
|
|
8
|
-
require_relative "auto_update/rubygems_api_adapter"
|
|
9
|
-
require_relative "auto_update/version_detector"
|
|
10
|
-
require_relative "auto_update/checkpoint_store"
|
|
11
|
-
require_relative "auto_update/update_logger"
|
|
12
|
-
require_relative "auto_update/failure_tracker"
|
|
13
|
-
require_relative "auto_update/coordinator"
|
|
14
|
-
|
|
15
3
|
module Aidp
|
|
16
4
|
# Auto-update functionality for Aidp in devcontainers
|
|
17
5
|
module AutoUpdate
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "../setup/devcontainer/parser"
|
|
4
|
-
require_relative "../setup/devcontainer/generator"
|
|
5
|
-
require_relative "../setup/devcontainer/port_manager"
|
|
6
|
-
require_relative "../setup/devcontainer/backup_manager"
|
|
7
|
-
require_relative "../message_display"
|
|
8
3
|
require "json"
|
|
9
4
|
require "yaml"
|
|
10
5
|
|
data/lib/aidp/cli.rb
CHANGED
|
@@ -8,6 +8,7 @@ require_relative "harness/ui/enhanced_tui"
|
|
|
8
8
|
require_relative "harness/ui/enhanced_workflow_selector"
|
|
9
9
|
require_relative "harness/enhanced_runner"
|
|
10
10
|
require_relative "cli/first_run_wizard"
|
|
11
|
+
require_relative "cli/issue_importer"
|
|
11
12
|
require_relative "rescue_logging"
|
|
12
13
|
require_relative "concurrency"
|
|
13
14
|
|
|
@@ -669,7 +670,7 @@ module Aidp
|
|
|
669
670
|
return
|
|
670
671
|
end
|
|
671
672
|
|
|
672
|
-
importer = IssueImporter.new
|
|
673
|
+
importer = Aidp::IssueImporter.new
|
|
673
674
|
issue_data = importer.import_issue(identifier)
|
|
674
675
|
|
|
675
676
|
if issue_data
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aidp
|
|
4
|
+
# Consolidates comments for GitHub issues and PRs by category
|
|
5
|
+
class CommentConsolidator
|
|
6
|
+
CATEGORY_HEADERS = {
|
|
7
|
+
progress: "## 🔄 Progress Report",
|
|
8
|
+
exceptions: "## 🚨 Exceptions and Errors",
|
|
9
|
+
completion: "## ✅ Completion Summary"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# @param repository_client [Aidp::Watch::RepositoryClient] GitHub repository client
|
|
13
|
+
# @param number [Integer] Issue or PR number
|
|
14
|
+
def initialize(repository_client:, number:)
|
|
15
|
+
@client = repository_client
|
|
16
|
+
@number = number
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Search for an existing comment by its category header
|
|
20
|
+
# @param category [Symbol] Comment category (:progress, :exceptions, :completion)
|
|
21
|
+
# @return [Hash, nil] Existing comment or nil if not found
|
|
22
|
+
def find_category_comment(category)
|
|
23
|
+
Aidp.log_debug("comment_consolidator", "searching_category_comment",
|
|
24
|
+
number: @number, category: category)
|
|
25
|
+
|
|
26
|
+
header = CATEGORY_HEADERS[category]
|
|
27
|
+
raise ArgumentError, "Invalid category: #{category}" unless header
|
|
28
|
+
|
|
29
|
+
comment = @client.find_comment(@number, header)
|
|
30
|
+
Aidp.log_debug("comment_consolidator", "find_category_comment_result",
|
|
31
|
+
found: !comment.nil?)
|
|
32
|
+
comment
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Update an existing category comment or create a new one
|
|
36
|
+
# @param category [Symbol] Comment category (:progress, :exceptions, :completion)
|
|
37
|
+
# @param new_content [String] New content to add to the comment
|
|
38
|
+
# @param append [Boolean] Whether to append or replace existing content
|
|
39
|
+
# @return [String] Result of comment operation (comment ID or response body)
|
|
40
|
+
def consolidate_comment(category:, new_content:, append: true)
|
|
41
|
+
Aidp.log_debug("comment_consolidator", "consolidating_comment", number: @number, category: category, append: append)
|
|
42
|
+
|
|
43
|
+
header = CATEGORY_HEADERS[category]
|
|
44
|
+
raise ArgumentError, "Invalid category: #{category}" unless header
|
|
45
|
+
|
|
46
|
+
existing_comment = find_category_comment(category)
|
|
47
|
+
|
|
48
|
+
content = if existing_comment && append
|
|
49
|
+
# Append new content with timestamp
|
|
50
|
+
existing_body = existing_comment[:body]
|
|
51
|
+
updated_body = if existing_body.include?(header)
|
|
52
|
+
existing_body.lines.first(1).join +
|
|
53
|
+
"### #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}\n\n" +
|
|
54
|
+
new_content + "\n\n" +
|
|
55
|
+
existing_body.lines[1..]&.join
|
|
56
|
+
else
|
|
57
|
+
# Reconstruct comment if header is missing
|
|
58
|
+
"#{header}\n\n### #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}\n\n" +
|
|
59
|
+
new_content + "\n\n" +
|
|
60
|
+
existing_body
|
|
61
|
+
end
|
|
62
|
+
updated_body
|
|
63
|
+
else
|
|
64
|
+
# Create new or replace content
|
|
65
|
+
"#{header}\n\n### #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}\n\n" + new_content
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Update or create comment
|
|
69
|
+
if existing_comment
|
|
70
|
+
Aidp.log_debug("comment_consolidator", "updating_existing_comment", comment_id: existing_comment[:id])
|
|
71
|
+
@client.update_comment(existing_comment[:id], content)
|
|
72
|
+
else
|
|
73
|
+
Aidp.log_debug("comment_consolidator", "creating_new_comment")
|
|
74
|
+
@client.post_comment(@number, content)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
data/lib/aidp/concurrency.rb
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "concurrent-ruby"
|
|
4
|
-
require_relative "concurrency/wait"
|
|
5
|
-
require_relative "concurrency/backoff"
|
|
6
|
-
require_relative "concurrency/exec"
|
|
7
4
|
|
|
8
5
|
module Aidp
|
|
9
6
|
# Concurrency utilities for deterministic waiting, retry/backoff, and executor management.
|
data/lib/aidp/config.rb
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Aidp
|
|
6
|
+
# Centralized path management for all AIDP internal files
|
|
7
|
+
# Ensures consistent file locations and prevents path-related bugs
|
|
8
|
+
module ConfigPaths
|
|
9
|
+
def self.aidp_dir(project_dir = Dir.pwd) = File.join(project_dir, ".aidp")
|
|
10
|
+
def self.config_file(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "aidp.yml")
|
|
11
|
+
def self.config_dir(project_dir = Dir.pwd) = aidp_dir(project_dir)
|
|
12
|
+
def self.progress_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "progress")
|
|
13
|
+
def self.execute_progress_file(project_dir = Dir.pwd) = File.join(progress_dir(project_dir), "execute.yml")
|
|
14
|
+
def self.analyze_progress_file(project_dir = Dir.pwd) = File.join(progress_dir(project_dir), "analyze.yml")
|
|
15
|
+
def self.harness_state_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "harness")
|
|
16
|
+
def self.harness_state_file(mode, project_dir = Dir.pwd) = File.join(harness_state_dir(project_dir), "#{mode}_state.json")
|
|
17
|
+
def self.providers_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "providers")
|
|
18
|
+
def self.provider_info_file(provider_name, project_dir = Dir.pwd) = File.join(providers_dir(project_dir), "#{provider_name}_info.yml")
|
|
19
|
+
def self.jobs_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "jobs")
|
|
20
|
+
def self.checkpoint_file(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "checkpoint.yml")
|
|
21
|
+
def self.checkpoint_history_file(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "checkpoint_history.jsonl")
|
|
22
|
+
def self.json_storage_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "json")
|
|
23
|
+
def self.model_cache_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "model_cache")
|
|
24
|
+
def self.work_loop_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "work_loop")
|
|
25
|
+
def self.logs_dir(project_dir = Dir.pwd) = File.join(aidp_dir(project_dir), "logs")
|
|
26
|
+
|
|
27
|
+
def self.config_exists?(project_dir = Dir.pwd)
|
|
28
|
+
File.exist?(config_file(project_dir))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.ensure_aidp_dir(project_dir = Dir.pwd)
|
|
32
|
+
dir = aidp_dir(project_dir)
|
|
33
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
34
|
+
dir
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.ensure_config_dir(project_dir = Dir.pwd)
|
|
38
|
+
ensure_aidp_dir(project_dir)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.ensure_progress_dir(project_dir = Dir.pwd)
|
|
42
|
+
dir = progress_dir(project_dir)
|
|
43
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
44
|
+
dir
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.ensure_harness_state_dir(project_dir = Dir.pwd)
|
|
48
|
+
dir = harness_state_dir(project_dir)
|
|
49
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
50
|
+
dir
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.ensure_providers_dir(project_dir = Dir.pwd)
|
|
54
|
+
dir = providers_dir(project_dir)
|
|
55
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
56
|
+
dir
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.ensure_jobs_dir(project_dir = Dir.pwd)
|
|
60
|
+
dir = jobs_dir(project_dir)
|
|
61
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
62
|
+
dir
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.ensure_json_storage_dir(project_dir = Dir.pwd)
|
|
66
|
+
dir = json_storage_dir(project_dir)
|
|
67
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
|
68
|
+
dir
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|