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
data/lib/aidp/setup/wizard.rb
CHANGED
|
@@ -6,15 +6,7 @@ require "yaml"
|
|
|
6
6
|
require "time"
|
|
7
7
|
require "fileutils"
|
|
8
8
|
require "json"
|
|
9
|
-
|
|
10
|
-
require_relative "../util"
|
|
11
|
-
require_relative "../config/paths"
|
|
12
|
-
require_relative "../harness/capability_registry"
|
|
13
|
-
require_relative "provider_registry"
|
|
14
|
-
require_relative "devcontainer/parser"
|
|
15
|
-
require_relative "devcontainer/generator"
|
|
16
|
-
require_relative "devcontainer/port_manager"
|
|
17
|
-
require_relative "devcontainer/backup_manager"
|
|
9
|
+
require "ostruct"
|
|
18
10
|
|
|
19
11
|
module Aidp
|
|
20
12
|
module Setup
|
|
@@ -57,6 +49,7 @@ module Aidp
|
|
|
57
49
|
configure_artifacts
|
|
58
50
|
configure_nfrs
|
|
59
51
|
configure_logging
|
|
52
|
+
configure_auto_update
|
|
60
53
|
configure_modes
|
|
61
54
|
configure_devcontainer
|
|
62
55
|
|
|
@@ -493,6 +486,7 @@ module Aidp
|
|
|
493
486
|
prompt.say("-" * 40)
|
|
494
487
|
|
|
495
488
|
configure_work_loop_limits
|
|
489
|
+
configure_output_filtering
|
|
496
490
|
configure_test_commands
|
|
497
491
|
configure_linting
|
|
498
492
|
configure_watch_patterns
|
|
@@ -515,6 +509,216 @@ module Aidp
|
|
|
515
509
|
set([:work_loop, :max_iterations], max_iterations)
|
|
516
510
|
end
|
|
517
511
|
|
|
512
|
+
def configure_output_filtering
|
|
513
|
+
prompt.say("\nš Output filtering configuration")
|
|
514
|
+
prompt.say(" Reduces token consumption by filtering test/lint output")
|
|
515
|
+
existing = get([:work_loop, :output_filtering]) || {}
|
|
516
|
+
|
|
517
|
+
return unless prompt.yes?("Configure output filtering?", default: false)
|
|
518
|
+
|
|
519
|
+
enabled = prompt.yes?(
|
|
520
|
+
"Enable output filtering?",
|
|
521
|
+
default: existing.fetch(:enabled, true)
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
unless enabled
|
|
525
|
+
set([:work_loop, :output_filtering], {enabled: false})
|
|
526
|
+
return
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# Test output mode
|
|
530
|
+
test_mode_choices = [
|
|
531
|
+
["Full (no filtering)", "full"],
|
|
532
|
+
["Failures only (recommended for iterations)", "failures_only"],
|
|
533
|
+
["Minimal (summary + locations only)", "minimal"]
|
|
534
|
+
]
|
|
535
|
+
test_mode_default = existing[:test_mode] || "full"
|
|
536
|
+
test_mode_default_label = test_mode_choices.find { |label, value| value == test_mode_default }&.first
|
|
537
|
+
|
|
538
|
+
test_mode = prompt.select("Test output mode:", default: test_mode_default_label) do |menu|
|
|
539
|
+
test_mode_choices.each { |label, value| menu.choice label, value }
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
# Lint output mode
|
|
543
|
+
lint_mode_choices = test_mode_choices
|
|
544
|
+
lint_mode_default = existing[:lint_mode] || "full"
|
|
545
|
+
lint_mode_default_label = lint_mode_choices.find { |label, value| value == lint_mode_default }&.first
|
|
546
|
+
|
|
547
|
+
lint_mode = prompt.select("Lint output mode:", default: lint_mode_default_label) do |menu|
|
|
548
|
+
lint_mode_choices.each { |label, value| menu.choice label, value }
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# Max output lines
|
|
552
|
+
test_max_lines = ask_with_default(
|
|
553
|
+
"Maximum test output lines",
|
|
554
|
+
(existing[:test_max_lines] || 500).to_s
|
|
555
|
+
) { |value| value.to_i }
|
|
556
|
+
|
|
557
|
+
lint_max_lines = ask_with_default(
|
|
558
|
+
"Maximum lint output lines",
|
|
559
|
+
(existing[:lint_max_lines] || 300).to_s
|
|
560
|
+
) { |value| value.to_i }
|
|
561
|
+
|
|
562
|
+
# Context configuration
|
|
563
|
+
include_context = prompt.yes?(
|
|
564
|
+
"Include context lines around failures?",
|
|
565
|
+
default: existing.fetch(:include_context, true)
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
context_lines = if include_context
|
|
569
|
+
ask_with_default(
|
|
570
|
+
"Number of context lines",
|
|
571
|
+
(existing[:context_lines] || 3).to_s
|
|
572
|
+
) { |value| value.to_i }
|
|
573
|
+
else
|
|
574
|
+
0
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
set([:work_loop, :output_filtering], {
|
|
578
|
+
enabled: true,
|
|
579
|
+
test_mode: test_mode,
|
|
580
|
+
lint_mode: lint_mode,
|
|
581
|
+
test_max_lines: test_max_lines,
|
|
582
|
+
lint_max_lines: lint_max_lines,
|
|
583
|
+
include_context: include_context,
|
|
584
|
+
context_lines: context_lines
|
|
585
|
+
})
|
|
586
|
+
|
|
587
|
+
prompt.ok("ā
Output filtering configured")
|
|
588
|
+
|
|
589
|
+
# Offer to generate AI-powered filter definitions
|
|
590
|
+
configure_filter_generation
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def configure_filter_generation
|
|
594
|
+
prompt.say("\nš¤ AI-Generated Filter Definitions")
|
|
595
|
+
prompt.say(" Generate custom filters for your test/lint tools (one-time AI call)")
|
|
596
|
+
|
|
597
|
+
return unless prompt.yes?("Generate filter definitions for your tools?", default: false)
|
|
598
|
+
|
|
599
|
+
# Collect configured commands
|
|
600
|
+
commands_to_filter = collect_commands_for_filtering
|
|
601
|
+
if commands_to_filter.empty?
|
|
602
|
+
prompt.warn("ā ļø No test or lint commands configured. Configure them first.")
|
|
603
|
+
return
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
prompt.say("\nš Commands detected:")
|
|
607
|
+
commands_to_filter.each do |cmd|
|
|
608
|
+
prompt.say(" ⢠#{cmd[:name]}: #{cmd[:command]}")
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
# Check if AI provider is configured
|
|
612
|
+
primary_provider = get([:harness, :default_provider])
|
|
613
|
+
unless primary_provider
|
|
614
|
+
prompt.warn("ā ļø No AI provider configured. Configure providers first.")
|
|
615
|
+
return
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
# Let user select which commands to generate filters for
|
|
619
|
+
prompt.say("\nš” Use ā/ā arrows to navigate, SPACE to select/deselect, ENTER to confirm")
|
|
620
|
+
selected = prompt.multi_select("Select commands to generate filters for:") do |menu|
|
|
621
|
+
commands_to_filter.each do |cmd|
|
|
622
|
+
menu.choice "#{cmd[:name]} (#{cmd[:command]})", cmd
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
return if selected.empty?
|
|
627
|
+
|
|
628
|
+
# Generate filter definitions
|
|
629
|
+
filter_definitions = {}
|
|
630
|
+
factory = create_filter_factory
|
|
631
|
+
|
|
632
|
+
selected.each do |cmd|
|
|
633
|
+
prompt.say("\nā³ Generating filter for #{cmd[:name]}...")
|
|
634
|
+
Aidp.log_info("setup_wizard", "generating_filter_definition",
|
|
635
|
+
tool_name: cmd[:name], command: cmd[:command])
|
|
636
|
+
|
|
637
|
+
begin
|
|
638
|
+
definition = factory.generate_from_command(
|
|
639
|
+
tool_command: cmd[:command],
|
|
640
|
+
project_dir: project_dir,
|
|
641
|
+
tier: "mini"
|
|
642
|
+
)
|
|
643
|
+
|
|
644
|
+
filter_definitions[cmd[:key]] = definition.to_h
|
|
645
|
+
prompt.ok(" ā
Generated filter for #{cmd[:name]}")
|
|
646
|
+
Aidp.log_info("setup_wizard", "filter_definition_generated",
|
|
647
|
+
tool_name: cmd[:name],
|
|
648
|
+
pattern_count: definition.summary_patterns.size)
|
|
649
|
+
rescue => e
|
|
650
|
+
prompt.warn(" ā ļø Failed to generate filter for #{cmd[:name]}: #{e.message}")
|
|
651
|
+
Aidp.log_error("setup_wizard", "filter_generation_failed",
|
|
652
|
+
tool_name: cmd[:name], error: e.message)
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
if filter_definitions.any?
|
|
657
|
+
set([:work_loop, :output_filtering, :filter_definitions], filter_definitions)
|
|
658
|
+
prompt.ok("\nā
Generated #{filter_definitions.size} filter definition(s)")
|
|
659
|
+
prompt.say(" These filters will be applied deterministically (no AI calls at runtime)")
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def collect_commands_for_filtering
|
|
664
|
+
commands = []
|
|
665
|
+
|
|
666
|
+
# Test commands
|
|
667
|
+
test_config = get([:work_loop, :test]) || {}
|
|
668
|
+
if test_config[:unit] && !test_config[:unit].start_with?("echo")
|
|
669
|
+
commands << {
|
|
670
|
+
key: "unit_test",
|
|
671
|
+
name: "Unit Tests",
|
|
672
|
+
command: test_config[:unit],
|
|
673
|
+
type: :test
|
|
674
|
+
}
|
|
675
|
+
end
|
|
676
|
+
if test_config[:integration] && !test_config[:integration].to_s.empty? && !test_config[:integration].start_with?("echo")
|
|
677
|
+
commands << {
|
|
678
|
+
key: "integration_test",
|
|
679
|
+
name: "Integration Tests",
|
|
680
|
+
command: test_config[:integration],
|
|
681
|
+
type: :test
|
|
682
|
+
}
|
|
683
|
+
end
|
|
684
|
+
if test_config[:e2e] && !test_config[:e2e].to_s.empty? && !test_config[:e2e].start_with?("echo")
|
|
685
|
+
commands << {
|
|
686
|
+
key: "e2e_test",
|
|
687
|
+
name: "E2E Tests",
|
|
688
|
+
command: test_config[:e2e],
|
|
689
|
+
type: :test
|
|
690
|
+
}
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
# Lint commands
|
|
694
|
+
lint_config = get([:work_loop, :lint]) || {}
|
|
695
|
+
if lint_config[:command] && !lint_config[:command].start_with?("echo")
|
|
696
|
+
commands << {
|
|
697
|
+
key: "lint",
|
|
698
|
+
name: "Linter",
|
|
699
|
+
command: lint_config[:command],
|
|
700
|
+
type: :lint
|
|
701
|
+
}
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
commands
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
def create_filter_factory
|
|
708
|
+
# Build a minimal configuration for the factory
|
|
709
|
+
config = build_harness_config_for_factory
|
|
710
|
+
Aidp::Harness::AIFilterFactory.new(config)
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
def build_harness_config_for_factory
|
|
714
|
+
# Create a minimal config object that the factory needs
|
|
715
|
+
OpenStruct.new(
|
|
716
|
+
default_provider: get([:harness, :default_provider]),
|
|
717
|
+
providers: get([:providers]) || {},
|
|
718
|
+
thinking_tiers: get([:thinking, :tiers])
|
|
719
|
+
)
|
|
720
|
+
end
|
|
721
|
+
|
|
518
722
|
def configure_test_commands
|
|
519
723
|
existing = get([:work_loop, :test]) || {}
|
|
520
724
|
|
|
@@ -1007,6 +1211,72 @@ module Aidp
|
|
|
1007
1211
|
})
|
|
1008
1212
|
end
|
|
1009
1213
|
|
|
1214
|
+
def configure_auto_update
|
|
1215
|
+
prompt.say("\nā»ļø Auto-update configuration")
|
|
1216
|
+
prompt.say("-" * 40)
|
|
1217
|
+
|
|
1218
|
+
existing = get([:auto_update]) || {}
|
|
1219
|
+
enabled = prompt.yes?(
|
|
1220
|
+
"Enable auto-update for watch mode?",
|
|
1221
|
+
default: existing.fetch(:enabled, false)
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1224
|
+
if enabled
|
|
1225
|
+
policy_choices = [
|
|
1226
|
+
["Off (manual updates)", "off"],
|
|
1227
|
+
["Patch updates", "patch"],
|
|
1228
|
+
["Minor updates", "minor"],
|
|
1229
|
+
["Major updates", "major"],
|
|
1230
|
+
["Exact version only", "exact"]
|
|
1231
|
+
]
|
|
1232
|
+
policy_default = existing[:policy] || "minor"
|
|
1233
|
+
policy_default_label = policy_choices.find { |label, value| value == policy_default }&.first
|
|
1234
|
+
policy = prompt.select("Auto-update policy:", default: policy_default_label) do |menu|
|
|
1235
|
+
policy_choices.each { |label, value| menu.choice(label, value) }
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
allow_prerelease = prompt.yes?(
|
|
1239
|
+
"Allow prerelease versions?",
|
|
1240
|
+
default: existing.fetch(:allow_prerelease, false)
|
|
1241
|
+
)
|
|
1242
|
+
|
|
1243
|
+
interval_default = (existing[:check_interval_seconds] || 3600).to_s
|
|
1244
|
+
interval = ask_with_default(
|
|
1245
|
+
"Check interval (seconds, 300-86400)",
|
|
1246
|
+
interval_default
|
|
1247
|
+
) { |value| value.to_i }
|
|
1248
|
+
|
|
1249
|
+
supervisor_choices = [
|
|
1250
|
+
["None (manual restart)", "none"],
|
|
1251
|
+
["supervisord (recommended)", "supervisord"],
|
|
1252
|
+
["s6", "s6"],
|
|
1253
|
+
["runit", "runit"]
|
|
1254
|
+
]
|
|
1255
|
+
supervisor_default = existing[:supervisor] || "none"
|
|
1256
|
+
supervisor_default_label = supervisor_choices.find { |label, value| value == supervisor_default }&.first
|
|
1257
|
+
|
|
1258
|
+
supervisor = prompt.select("Update supervisor:", default: supervisor_default_label) do |menu|
|
|
1259
|
+
supervisor_choices.each { |label, value| menu.choice(label, value) }
|
|
1260
|
+
end
|
|
1261
|
+
|
|
1262
|
+
max_failures = ask_with_default(
|
|
1263
|
+
"Max consecutive update failures before backoff",
|
|
1264
|
+
(existing[:max_consecutive_failures] || 3).to_s
|
|
1265
|
+
) { |value| value.to_i }
|
|
1266
|
+
|
|
1267
|
+
set([:auto_update], {
|
|
1268
|
+
enabled: true,
|
|
1269
|
+
policy: policy,
|
|
1270
|
+
allow_prerelease: allow_prerelease,
|
|
1271
|
+
check_interval_seconds: interval,
|
|
1272
|
+
supervisor: supervisor,
|
|
1273
|
+
max_consecutive_failures: max_failures
|
|
1274
|
+
})
|
|
1275
|
+
else
|
|
1276
|
+
set([:auto_update], {enabled: false, policy: "off"})
|
|
1277
|
+
end
|
|
1278
|
+
end
|
|
1279
|
+
|
|
1010
1280
|
def configure_modes
|
|
1011
1281
|
prompt.say("\nš Operational modes")
|
|
1012
1282
|
prompt.say("-" * 40)
|
data/lib/aidp/skills.rb
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "skills/skill"
|
|
4
|
-
require_relative "skills/loader"
|
|
5
|
-
require_relative "skills/registry"
|
|
6
|
-
require_relative "skills/composer"
|
|
7
|
-
|
|
8
3
|
module Aidp
|
|
9
4
|
# Skills subsystem for managing agent personas and capabilities
|
|
10
5
|
#
|