aidp 0.17.0 → 0.18.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/README.md +69 -0
- data/lib/aidp/analyze/kb_inspector.rb +2 -3
- data/lib/aidp/analyze/progress.rb +5 -10
- data/lib/aidp/cli/mcp_dashboard.rb +1 -1
- data/lib/aidp/cli.rb +64 -29
- data/lib/aidp/config.rb +9 -14
- data/lib/aidp/execute/progress.rb +5 -8
- data/lib/aidp/execute/prompt_manager.rb +128 -1
- data/lib/aidp/execute/repl_macros.rb +555 -0
- data/lib/aidp/execute/work_loop_runner.rb +108 -1
- data/lib/aidp/harness/ai_decision_engine.rb +376 -0
- data/lib/aidp/harness/capability_registry.rb +273 -0
- data/lib/aidp/harness/config_loader.rb +2 -2
- data/lib/aidp/harness/config_schema.rb +305 -1
- data/lib/aidp/harness/configuration.rb +452 -0
- data/lib/aidp/harness/enhanced_runner.rb +23 -8
- data/lib/aidp/harness/error_handler.rb +12 -5
- data/lib/aidp/harness/provider_factory.rb +0 -2
- data/lib/aidp/harness/provider_manager.rb +4 -19
- data/lib/aidp/harness/runner.rb +9 -3
- data/lib/aidp/harness/state/persistence.rb +9 -10
- data/lib/aidp/harness/state/workflow_state.rb +3 -2
- data/lib/aidp/harness/state_manager.rb +33 -97
- data/lib/aidp/harness/status_display.rb +22 -12
- data/lib/aidp/harness/thinking_depth_manager.rb +335 -0
- data/lib/aidp/harness/ui/enhanced_tui.rb +3 -4
- data/lib/aidp/harness/user_interface.rb +11 -6
- data/lib/aidp/harness/zfc_condition_detector.rb +395 -0
- data/lib/aidp/init/devcontainer_generator.rb +274 -0
- data/lib/aidp/init/runner.rb +37 -10
- data/lib/aidp/init.rb +1 -0
- data/lib/aidp/jobs/background_runner.rb +7 -1
- data/lib/aidp/logger.rb +1 -1
- data/lib/aidp/message_display.rb +9 -2
- data/lib/aidp/prompt_optimization/context_composer.rb +286 -0
- data/lib/aidp/prompt_optimization/optimizer.rb +335 -0
- data/lib/aidp/prompt_optimization/prompt_builder.rb +309 -0
- data/lib/aidp/prompt_optimization/relevance_scorer.rb +256 -0
- data/lib/aidp/prompt_optimization/source_code_fragmenter.rb +308 -0
- data/lib/aidp/prompt_optimization/style_guide_indexer.rb +240 -0
- data/lib/aidp/prompt_optimization/template_indexer.rb +250 -0
- data/lib/aidp/provider_manager.rb +0 -2
- data/lib/aidp/providers/anthropic.rb +20 -1
- data/lib/aidp/providers/base.rb +4 -4
- data/lib/aidp/providers/codex.rb +1 -1
- data/lib/aidp/providers/cursor.rb +1 -1
- data/lib/aidp/providers/gemini.rb +1 -1
- data/lib/aidp/providers/github_copilot.rb +1 -1
- data/lib/aidp/providers/opencode.rb +1 -1
- data/lib/aidp/setup/wizard.rb +299 -4
- data/lib/aidp/skills/wizard/prompter.rb +2 -2
- data/lib/aidp/utils/devcontainer_detector.rb +166 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +72 -6
- data/lib/aidp/watch/plan_generator.rb +1 -1
- data/lib/aidp/watch/repository_client.rb +15 -10
- data/lib/aidp/workflows/guided_agent.rb +2 -312
- data/lib/aidp/workstream_executor.rb +8 -2
- data/lib/aidp.rb +0 -1
- data/templates/aidp.yml.example +128 -0
- metadata +14 -2
- data/lib/aidp/providers/macos_ui.rb +0 -102
|
@@ -275,6 +275,24 @@ module Aidp
|
|
|
275
275
|
usage: "/skill <list|show|use> [args]",
|
|
276
276
|
example: "/skill list",
|
|
277
277
|
handler: method(:cmd_skill)
|
|
278
|
+
},
|
|
279
|
+
"/tools" => {
|
|
280
|
+
description: "Manage available tools (coverage, testing, etc.)",
|
|
281
|
+
usage: "/tools <show|coverage|test> [subcommand]",
|
|
282
|
+
example: "/tools show",
|
|
283
|
+
handler: method(:cmd_tools)
|
|
284
|
+
},
|
|
285
|
+
"/thinking" => {
|
|
286
|
+
description: "Manage thinking depth tier for model selection",
|
|
287
|
+
usage: "/thinking <show|set|max|reset> [tier]",
|
|
288
|
+
example: "/thinking show",
|
|
289
|
+
handler: method(:cmd_thinking)
|
|
290
|
+
},
|
|
291
|
+
"/prompt" => {
|
|
292
|
+
description: "Inspect and control prompt optimization",
|
|
293
|
+
usage: "/prompt <explain|stats|expand|reset>",
|
|
294
|
+
example: "/prompt explain",
|
|
295
|
+
handler: method(:cmd_prompt)
|
|
278
296
|
}
|
|
279
297
|
}
|
|
280
298
|
end
|
|
@@ -1489,6 +1507,543 @@ module Aidp
|
|
|
1489
1507
|
}
|
|
1490
1508
|
end
|
|
1491
1509
|
end
|
|
1510
|
+
|
|
1511
|
+
# /tools command - manage available tools
|
|
1512
|
+
def cmd_tools(args)
|
|
1513
|
+
Aidp.log_debug("repl_macros", "Executing /tools command", args: args)
|
|
1514
|
+
|
|
1515
|
+
subcommand = args[0]&.downcase
|
|
1516
|
+
|
|
1517
|
+
case subcommand
|
|
1518
|
+
when "show"
|
|
1519
|
+
cmd_tools_show
|
|
1520
|
+
when "coverage"
|
|
1521
|
+
cmd_tools_coverage(args[1..])
|
|
1522
|
+
when "test"
|
|
1523
|
+
cmd_tools_test(args[1..])
|
|
1524
|
+
else
|
|
1525
|
+
{
|
|
1526
|
+
success: false,
|
|
1527
|
+
message: "Usage: /tools <command> [args]\n\nCommands:\n show - Show configured tools and their status\n coverage - Run coverage analysis and show delta\n test <type> - Run interactive tests (web, cli, desktop)\n\nExamples:\n /tools show\n /tools coverage\n /tools test web",
|
|
1528
|
+
action: :none
|
|
1529
|
+
}
|
|
1530
|
+
end
|
|
1531
|
+
end
|
|
1532
|
+
|
|
1533
|
+
def cmd_tools_show
|
|
1534
|
+
require_relative "../harness/configuration"
|
|
1535
|
+
|
|
1536
|
+
begin
|
|
1537
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1538
|
+
|
|
1539
|
+
output = ["📊 Configured Tools\n", "=" * 50]
|
|
1540
|
+
|
|
1541
|
+
# Coverage tools
|
|
1542
|
+
if config.coverage_enabled?
|
|
1543
|
+
output << "\n🔍 Coverage:"
|
|
1544
|
+
output << " Tool: #{config.coverage_tool || "not specified"}"
|
|
1545
|
+
output << " Command: #{config.coverage_run_command || "not specified"}"
|
|
1546
|
+
output << " Report paths: #{config.coverage_report_paths.join(", ")}" if config.coverage_report_paths.any?
|
|
1547
|
+
output << " Fail on drop: #{config.coverage_fail_on_drop? ? "yes" : "no"}"
|
|
1548
|
+
output << " Minimum coverage: #{config.coverage_minimum || "not set"}%" if config.coverage_minimum
|
|
1549
|
+
else
|
|
1550
|
+
output << "\n🔍 Coverage: disabled"
|
|
1551
|
+
end
|
|
1552
|
+
|
|
1553
|
+
# VCS configuration
|
|
1554
|
+
output << "\n\n🗂️ Version Control:"
|
|
1555
|
+
output << " Tool: #{config.vcs_tool}"
|
|
1556
|
+
output << " Behavior: #{config.vcs_behavior}"
|
|
1557
|
+
output << " Conventional commits: #{config.conventional_commits? ? "yes" : "no"}"
|
|
1558
|
+
|
|
1559
|
+
# Interactive testing
|
|
1560
|
+
if config.interactive_testing_enabled?
|
|
1561
|
+
output << "\n\n🎯 Interactive Testing:"
|
|
1562
|
+
output << " App type: #{config.interactive_testing_app_type}"
|
|
1563
|
+
tools = config.interactive_testing_tools
|
|
1564
|
+
if tools.any?
|
|
1565
|
+
tools.each do |category, category_tools|
|
|
1566
|
+
output << " #{category.to_s.capitalize}:"
|
|
1567
|
+
category_tools.each do |tool_name, tool_config|
|
|
1568
|
+
next unless tool_config[:enabled]
|
|
1569
|
+
output << " • #{tool_name}: enabled"
|
|
1570
|
+
output << " Run: #{tool_config[:run]}" if tool_config[:run]
|
|
1571
|
+
output << " Specs: #{tool_config[:specs_dir]}" if tool_config[:specs_dir]
|
|
1572
|
+
end
|
|
1573
|
+
end
|
|
1574
|
+
else
|
|
1575
|
+
output << " No tools configured"
|
|
1576
|
+
end
|
|
1577
|
+
else
|
|
1578
|
+
output << "\n\n🎯 Interactive Testing: disabled"
|
|
1579
|
+
end
|
|
1580
|
+
|
|
1581
|
+
# Model families
|
|
1582
|
+
output << "\n\n🤖 Model Families:"
|
|
1583
|
+
config.configured_providers.each do |provider|
|
|
1584
|
+
family = config.model_family(provider)
|
|
1585
|
+
output << " #{provider}: #{family}"
|
|
1586
|
+
end
|
|
1587
|
+
|
|
1588
|
+
{
|
|
1589
|
+
success: true,
|
|
1590
|
+
message: output.join("\n"),
|
|
1591
|
+
action: :none
|
|
1592
|
+
}
|
|
1593
|
+
rescue => e
|
|
1594
|
+
Aidp.log_error("repl_macros", "Failed to show tools", error: e.message)
|
|
1595
|
+
{
|
|
1596
|
+
success: false,
|
|
1597
|
+
message: "Failed to load tool configuration: #{e.message}",
|
|
1598
|
+
action: :none
|
|
1599
|
+
}
|
|
1600
|
+
end
|
|
1601
|
+
end
|
|
1602
|
+
|
|
1603
|
+
def cmd_tools_coverage(args)
|
|
1604
|
+
require_relative "../harness/configuration"
|
|
1605
|
+
|
|
1606
|
+
begin
|
|
1607
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1608
|
+
|
|
1609
|
+
unless config.coverage_enabled?
|
|
1610
|
+
return {
|
|
1611
|
+
success: false,
|
|
1612
|
+
message: "Coverage is not enabled. Run 'aidp config --interactive' to configure coverage.",
|
|
1613
|
+
action: :none
|
|
1614
|
+
}
|
|
1615
|
+
end
|
|
1616
|
+
|
|
1617
|
+
unless config.coverage_run_command
|
|
1618
|
+
return {
|
|
1619
|
+
success: false,
|
|
1620
|
+
message: "Coverage run command not configured. Run 'aidp config --interactive' to set it up.",
|
|
1621
|
+
action: :none
|
|
1622
|
+
}
|
|
1623
|
+
end
|
|
1624
|
+
|
|
1625
|
+
Aidp.log_debug("repl_macros", "Running coverage", command: config.coverage_run_command)
|
|
1626
|
+
|
|
1627
|
+
{
|
|
1628
|
+
success: true,
|
|
1629
|
+
message: "Running coverage with: #{config.coverage_run_command}\n(Coverage execution to be implemented in work loop)",
|
|
1630
|
+
action: :run_coverage,
|
|
1631
|
+
data: {
|
|
1632
|
+
command: config.coverage_run_command,
|
|
1633
|
+
tool: config.coverage_tool,
|
|
1634
|
+
report_paths: config.coverage_report_paths
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
rescue => e
|
|
1638
|
+
Aidp.log_error("repl_macros", "Failed to run coverage", error: e.message)
|
|
1639
|
+
{
|
|
1640
|
+
success: false,
|
|
1641
|
+
message: "Failed to run coverage: #{e.message}",
|
|
1642
|
+
action: :none
|
|
1643
|
+
}
|
|
1644
|
+
end
|
|
1645
|
+
end
|
|
1646
|
+
|
|
1647
|
+
def cmd_tools_test(args)
|
|
1648
|
+
require_relative "../harness/configuration"
|
|
1649
|
+
|
|
1650
|
+
test_type = args[0]&.downcase
|
|
1651
|
+
|
|
1652
|
+
begin
|
|
1653
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1654
|
+
|
|
1655
|
+
unless config.interactive_testing_enabled?
|
|
1656
|
+
return {
|
|
1657
|
+
success: false,
|
|
1658
|
+
message: "Interactive testing is not enabled. Run 'aidp config --interactive' to configure it.",
|
|
1659
|
+
action: :none
|
|
1660
|
+
}
|
|
1661
|
+
end
|
|
1662
|
+
|
|
1663
|
+
unless test_type
|
|
1664
|
+
return {
|
|
1665
|
+
success: false,
|
|
1666
|
+
message: "Usage: /tools test <type>\n\nTypes: web, cli, desktop\n\nExample: /tools test web",
|
|
1667
|
+
action: :none
|
|
1668
|
+
}
|
|
1669
|
+
end
|
|
1670
|
+
|
|
1671
|
+
unless %w[web cli desktop].include?(test_type)
|
|
1672
|
+
return {
|
|
1673
|
+
success: false,
|
|
1674
|
+
message: "Invalid test type: #{test_type}. Must be one of: web, cli, desktop",
|
|
1675
|
+
action: :none
|
|
1676
|
+
}
|
|
1677
|
+
end
|
|
1678
|
+
|
|
1679
|
+
tools = config.interactive_testing_tools.dig(test_type.to_sym)
|
|
1680
|
+
unless tools&.any? { |_, t| t[:enabled] }
|
|
1681
|
+
return {
|
|
1682
|
+
success: false,
|
|
1683
|
+
message: "No #{test_type} testing tools configured. Run 'aidp config --interactive' to set them up.",
|
|
1684
|
+
action: :none
|
|
1685
|
+
}
|
|
1686
|
+
end
|
|
1687
|
+
|
|
1688
|
+
enabled_tools = tools.select { |_, t| t[:enabled] }
|
|
1689
|
+
tool_list = enabled_tools.map { |name, cfg| " • #{name}: #{cfg[:run] || "no command"}" }.join("\n")
|
|
1690
|
+
|
|
1691
|
+
Aidp.log_debug("repl_macros", "Running interactive tests", type: test_type, tools: enabled_tools.keys)
|
|
1692
|
+
|
|
1693
|
+
{
|
|
1694
|
+
success: true,
|
|
1695
|
+
message: "Running #{test_type} tests:\n#{tool_list}\n(Test execution to be implemented in work loop)",
|
|
1696
|
+
action: :run_interactive_tests,
|
|
1697
|
+
data: {
|
|
1698
|
+
test_type: test_type,
|
|
1699
|
+
tools: enabled_tools
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
rescue => e
|
|
1703
|
+
Aidp.log_error("repl_macros", "Failed to run interactive tests", error: e.message)
|
|
1704
|
+
{
|
|
1705
|
+
success: false,
|
|
1706
|
+
message: "Failed to run interactive tests: #{e.message}",
|
|
1707
|
+
action: :none
|
|
1708
|
+
}
|
|
1709
|
+
end
|
|
1710
|
+
end
|
|
1711
|
+
|
|
1712
|
+
# Command: /thinking
|
|
1713
|
+
def cmd_thinking(args)
|
|
1714
|
+
subcommand = args[0]
|
|
1715
|
+
|
|
1716
|
+
case subcommand
|
|
1717
|
+
when "show"
|
|
1718
|
+
cmd_thinking_show
|
|
1719
|
+
when "set"
|
|
1720
|
+
cmd_thinking_set(args[1])
|
|
1721
|
+
when "max"
|
|
1722
|
+
cmd_thinking_max(args[1])
|
|
1723
|
+
when "reset"
|
|
1724
|
+
cmd_thinking_reset
|
|
1725
|
+
else
|
|
1726
|
+
{
|
|
1727
|
+
success: false,
|
|
1728
|
+
message: "Unknown subcommand: #{subcommand}\nUsage: /thinking <show|set|max|reset> [tier]",
|
|
1729
|
+
action: :none
|
|
1730
|
+
}
|
|
1731
|
+
end
|
|
1732
|
+
rescue => e
|
|
1733
|
+
Aidp.log_error("repl_macros", "Failed to execute thinking command", error: e.message)
|
|
1734
|
+
{
|
|
1735
|
+
success: false,
|
|
1736
|
+
message: "Failed to execute thinking command: #{e.message}",
|
|
1737
|
+
action: :none
|
|
1738
|
+
}
|
|
1739
|
+
end
|
|
1740
|
+
|
|
1741
|
+
# Subcommand: /thinking show
|
|
1742
|
+
def cmd_thinking_show
|
|
1743
|
+
require_relative "../harness/configuration"
|
|
1744
|
+
require_relative "../harness/thinking_depth_manager"
|
|
1745
|
+
|
|
1746
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1747
|
+
manager = Aidp::Harness::ThinkingDepthManager.new(config, root_dir: @project_dir)
|
|
1748
|
+
|
|
1749
|
+
lines = []
|
|
1750
|
+
lines << "Thinking Depth Configuration:"
|
|
1751
|
+
lines << ""
|
|
1752
|
+
lines << "Current Tier: #{manager.current_tier}"
|
|
1753
|
+
lines << "Default Tier: #{manager.default_tier}"
|
|
1754
|
+
lines << "Max Tier: #{manager.max_tier}"
|
|
1755
|
+
lines << ""
|
|
1756
|
+
|
|
1757
|
+
# Show all available tiers
|
|
1758
|
+
require_relative "../harness/capability_registry"
|
|
1759
|
+
lines << "Available Tiers:"
|
|
1760
|
+
Aidp::Harness::CapabilityRegistry::VALID_TIERS.each do |tier|
|
|
1761
|
+
marker = if tier == manager.current_tier
|
|
1762
|
+
"→"
|
|
1763
|
+
elsif tier == manager.max_tier
|
|
1764
|
+
"↑"
|
|
1765
|
+
else
|
|
1766
|
+
" "
|
|
1767
|
+
end
|
|
1768
|
+
lines << " #{marker} #{tier}"
|
|
1769
|
+
end
|
|
1770
|
+
lines << ""
|
|
1771
|
+
lines << "Legend: → current, ↑ max allowed"
|
|
1772
|
+
lines << ""
|
|
1773
|
+
|
|
1774
|
+
# Show current model selection
|
|
1775
|
+
current_model = manager.select_model_for_tier
|
|
1776
|
+
if current_model
|
|
1777
|
+
provider, model_name, model_data = current_model
|
|
1778
|
+
lines << "Current Model: #{provider}/#{model_name}"
|
|
1779
|
+
lines << " Tier: #{model_data["tier"]}" if model_data["tier"]
|
|
1780
|
+
lines << " Context Window: #{model_data["context_window"]}" if model_data["context_window"]
|
|
1781
|
+
else
|
|
1782
|
+
lines << "Current Model: (none selected)"
|
|
1783
|
+
end
|
|
1784
|
+
|
|
1785
|
+
lines << ""
|
|
1786
|
+
lines << "Provider Switching: #{config.allow_provider_switch_for_tier? ? "enabled" : "disabled"}"
|
|
1787
|
+
|
|
1788
|
+
# Show escalation config
|
|
1789
|
+
escalation = config.escalation_config
|
|
1790
|
+
lines << ""
|
|
1791
|
+
lines << "Escalation Settings:"
|
|
1792
|
+
lines << " Fail Attempts Threshold: #{escalation[:on_fail_attempts]}"
|
|
1793
|
+
if escalation[:on_complexity_threshold]&.any?
|
|
1794
|
+
lines << " Complexity Thresholds:"
|
|
1795
|
+
escalation[:on_complexity_threshold].each do |key, value|
|
|
1796
|
+
lines << " #{key}: #{value}"
|
|
1797
|
+
end
|
|
1798
|
+
end
|
|
1799
|
+
|
|
1800
|
+
{
|
|
1801
|
+
success: true,
|
|
1802
|
+
message: lines.join("\n"),
|
|
1803
|
+
action: :display
|
|
1804
|
+
}
|
|
1805
|
+
end
|
|
1806
|
+
|
|
1807
|
+
# Subcommand: /thinking set <tier>
|
|
1808
|
+
def cmd_thinking_set(tier)
|
|
1809
|
+
unless tier
|
|
1810
|
+
return {
|
|
1811
|
+
success: false,
|
|
1812
|
+
message: "Usage: /thinking set <tier>\nTiers: mini, standard, thinking, pro, max",
|
|
1813
|
+
action: :none
|
|
1814
|
+
}
|
|
1815
|
+
end
|
|
1816
|
+
|
|
1817
|
+
require_relative "../harness/configuration"
|
|
1818
|
+
require_relative "../harness/thinking_depth_manager"
|
|
1819
|
+
|
|
1820
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1821
|
+
manager = Aidp::Harness::ThinkingDepthManager.new(config, root_dir: @project_dir)
|
|
1822
|
+
|
|
1823
|
+
old_tier = manager.current_tier
|
|
1824
|
+
manager.current_tier = tier
|
|
1825
|
+
|
|
1826
|
+
{
|
|
1827
|
+
success: true,
|
|
1828
|
+
message: "Thinking tier changed: #{old_tier} → #{tier}\nMax tier: #{manager.max_tier}",
|
|
1829
|
+
action: :tier_changed
|
|
1830
|
+
}
|
|
1831
|
+
rescue ArgumentError => e
|
|
1832
|
+
{
|
|
1833
|
+
success: false,
|
|
1834
|
+
message: "Invalid tier: #{e.message}\nValid tiers: mini, standard, thinking, pro, max",
|
|
1835
|
+
action: :none
|
|
1836
|
+
}
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
# Subcommand: /thinking max <tier>
|
|
1840
|
+
def cmd_thinking_max(tier)
|
|
1841
|
+
unless tier
|
|
1842
|
+
return {
|
|
1843
|
+
success: false,
|
|
1844
|
+
message: "Usage: /thinking max <tier>\nTiers: mini, standard, thinking, pro, max",
|
|
1845
|
+
action: :none
|
|
1846
|
+
}
|
|
1847
|
+
end
|
|
1848
|
+
|
|
1849
|
+
require_relative "../harness/configuration"
|
|
1850
|
+
require_relative "../harness/thinking_depth_manager"
|
|
1851
|
+
|
|
1852
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1853
|
+
manager = Aidp::Harness::ThinkingDepthManager.new(config, root_dir: @project_dir)
|
|
1854
|
+
|
|
1855
|
+
old_max = manager.max_tier
|
|
1856
|
+
manager.max_tier = tier
|
|
1857
|
+
|
|
1858
|
+
{
|
|
1859
|
+
success: true,
|
|
1860
|
+
message: "Max tier changed: #{old_max} → #{tier}\nCurrent tier: #{manager.current_tier}",
|
|
1861
|
+
action: :max_tier_changed
|
|
1862
|
+
}
|
|
1863
|
+
rescue ArgumentError => e
|
|
1864
|
+
{
|
|
1865
|
+
success: false,
|
|
1866
|
+
message: "Invalid tier: #{e.message}\nValid tiers: mini, standard, thinking, pro, max",
|
|
1867
|
+
action: :none
|
|
1868
|
+
}
|
|
1869
|
+
end
|
|
1870
|
+
|
|
1871
|
+
# Subcommand: /thinking reset
|
|
1872
|
+
def cmd_thinking_reset
|
|
1873
|
+
require_relative "../harness/configuration"
|
|
1874
|
+
require_relative "../harness/thinking_depth_manager"
|
|
1875
|
+
|
|
1876
|
+
config = Aidp::Harness::Configuration.new(@project_dir)
|
|
1877
|
+
manager = Aidp::Harness::ThinkingDepthManager.new(config, root_dir: @project_dir)
|
|
1878
|
+
|
|
1879
|
+
old_tier = manager.current_tier
|
|
1880
|
+
manager.reset_to_default
|
|
1881
|
+
|
|
1882
|
+
{
|
|
1883
|
+
success: true,
|
|
1884
|
+
message: "Thinking tier reset: #{old_tier} → #{manager.current_tier}\nEscalation count cleared",
|
|
1885
|
+
action: :tier_reset
|
|
1886
|
+
}
|
|
1887
|
+
end
|
|
1888
|
+
|
|
1889
|
+
# Command: /prompt - Inspect and control prompt optimization
|
|
1890
|
+
def cmd_prompt(args)
|
|
1891
|
+
subcommand = args[0]
|
|
1892
|
+
|
|
1893
|
+
case subcommand
|
|
1894
|
+
when "explain"
|
|
1895
|
+
cmd_prompt_explain
|
|
1896
|
+
when "stats"
|
|
1897
|
+
cmd_prompt_stats
|
|
1898
|
+
when "expand"
|
|
1899
|
+
cmd_prompt_expand(args[1])
|
|
1900
|
+
when "reset"
|
|
1901
|
+
cmd_prompt_reset
|
|
1902
|
+
else
|
|
1903
|
+
{
|
|
1904
|
+
success: false,
|
|
1905
|
+
message: "Unknown subcommand: #{subcommand}\nUsage: /prompt <explain|stats|expand|reset>",
|
|
1906
|
+
action: :none
|
|
1907
|
+
}
|
|
1908
|
+
end
|
|
1909
|
+
rescue => e
|
|
1910
|
+
Aidp.log_error("repl_macros", "Failed to execute prompt command", error: e.message)
|
|
1911
|
+
{
|
|
1912
|
+
success: false,
|
|
1913
|
+
message: "Failed to execute prompt command: #{e.message}",
|
|
1914
|
+
action: :none
|
|
1915
|
+
}
|
|
1916
|
+
end
|
|
1917
|
+
|
|
1918
|
+
# Subcommand: /prompt explain
|
|
1919
|
+
# Shows which fragments were selected for the current prompt and why
|
|
1920
|
+
def cmd_prompt_explain
|
|
1921
|
+
require_relative "prompt_manager"
|
|
1922
|
+
|
|
1923
|
+
prompt_manager = PromptManager.new(@project_dir, config: load_config)
|
|
1924
|
+
|
|
1925
|
+
unless prompt_manager.optimization_enabled?
|
|
1926
|
+
return {
|
|
1927
|
+
success: false,
|
|
1928
|
+
message: "Prompt optimization is not enabled. Check your .aidp/config.yml:\n" \
|
|
1929
|
+
"prompt_optimization:\n enabled: true",
|
|
1930
|
+
action: :none
|
|
1931
|
+
}
|
|
1932
|
+
end
|
|
1933
|
+
|
|
1934
|
+
unless prompt_manager.last_optimization_stats
|
|
1935
|
+
return {
|
|
1936
|
+
success: false,
|
|
1937
|
+
message: "No optimization performed yet. Prompt optimization will be used on the next work loop iteration.",
|
|
1938
|
+
action: :none
|
|
1939
|
+
}
|
|
1940
|
+
end
|
|
1941
|
+
|
|
1942
|
+
report = prompt_manager.optimization_report
|
|
1943
|
+
{
|
|
1944
|
+
success: true,
|
|
1945
|
+
message: report,
|
|
1946
|
+
action: :show_optimization_report
|
|
1947
|
+
}
|
|
1948
|
+
end
|
|
1949
|
+
|
|
1950
|
+
# Subcommand: /prompt stats
|
|
1951
|
+
# Shows overall optimizer statistics across all runs
|
|
1952
|
+
def cmd_prompt_stats
|
|
1953
|
+
require_relative "prompt_manager"
|
|
1954
|
+
|
|
1955
|
+
prompt_manager = PromptManager.new(@project_dir, config: load_config)
|
|
1956
|
+
|
|
1957
|
+
unless prompt_manager.optimization_enabled?
|
|
1958
|
+
return {
|
|
1959
|
+
success: false,
|
|
1960
|
+
message: "Prompt optimization is not enabled.",
|
|
1961
|
+
action: :none
|
|
1962
|
+
}
|
|
1963
|
+
end
|
|
1964
|
+
|
|
1965
|
+
stats = prompt_manager.optimizer_stats
|
|
1966
|
+
unless stats
|
|
1967
|
+
return {
|
|
1968
|
+
success: false,
|
|
1969
|
+
message: "No optimization statistics available.",
|
|
1970
|
+
action: :none
|
|
1971
|
+
}
|
|
1972
|
+
end
|
|
1973
|
+
|
|
1974
|
+
lines = []
|
|
1975
|
+
lines << "# Prompt Optimizer Statistics"
|
|
1976
|
+
lines << ""
|
|
1977
|
+
lines << "- **Total Runs**: #{stats[:runs_count]}"
|
|
1978
|
+
lines << "- **Total Fragments Indexed**: #{stats[:total_fragments_indexed]}"
|
|
1979
|
+
lines << "- **Total Fragments Selected**: #{stats[:total_fragments_selected]}"
|
|
1980
|
+
lines << "- **Total Fragments Excluded**: #{stats[:total_fragments_excluded]}"
|
|
1981
|
+
lines << "- **Total Tokens Used**: #{stats[:total_tokens_used]}"
|
|
1982
|
+
lines << "- **Average Fragments/Run**: #{stats[:average_fragments_selected]}"
|
|
1983
|
+
lines << "- **Average Budget Utilization**: #{stats[:average_budget_utilization]}%"
|
|
1984
|
+
lines << "- **Average Optimization Time**: #{stats[:average_optimization_time_ms]}ms"
|
|
1985
|
+
|
|
1986
|
+
{
|
|
1987
|
+
success: true,
|
|
1988
|
+
message: lines.join("\n"),
|
|
1989
|
+
action: :show_optimizer_stats
|
|
1990
|
+
}
|
|
1991
|
+
end
|
|
1992
|
+
|
|
1993
|
+
# Subcommand: /prompt expand <fragment_id>
|
|
1994
|
+
# Adds a specific omitted fragment to the next prompt
|
|
1995
|
+
def cmd_prompt_expand(fragment_id)
|
|
1996
|
+
unless fragment_id
|
|
1997
|
+
return {
|
|
1998
|
+
success: false,
|
|
1999
|
+
message: "Usage: /prompt expand <fragment_id>\nUse /prompt explain to see available fragments",
|
|
2000
|
+
action: :none
|
|
2001
|
+
}
|
|
2002
|
+
end
|
|
2003
|
+
|
|
2004
|
+
# For now, this is a placeholder - full implementation would:
|
|
2005
|
+
# 1. Look up the fragment by ID
|
|
2006
|
+
# 2. Add it to an override list
|
|
2007
|
+
# 3. Include it in the next prompt generation
|
|
2008
|
+
{
|
|
2009
|
+
success: true,
|
|
2010
|
+
message: "Fragment expansion not yet implemented.\n" \
|
|
2011
|
+
"This will be available in a future update to manually include excluded fragments.",
|
|
2012
|
+
action: :feature_not_implemented
|
|
2013
|
+
}
|
|
2014
|
+
end
|
|
2015
|
+
|
|
2016
|
+
# Subcommand: /prompt reset
|
|
2017
|
+
# Clears optimizer cache and resets to default behavior
|
|
2018
|
+
def cmd_prompt_reset
|
|
2019
|
+
require_relative "prompt_manager"
|
|
2020
|
+
|
|
2021
|
+
prompt_manager = PromptManager.new(@project_dir, config: load_config)
|
|
2022
|
+
|
|
2023
|
+
unless prompt_manager.optimization_enabled?
|
|
2024
|
+
return {
|
|
2025
|
+
success: false,
|
|
2026
|
+
message: "Prompt optimization is not enabled.",
|
|
2027
|
+
action: :none
|
|
2028
|
+
}
|
|
2029
|
+
end
|
|
2030
|
+
|
|
2031
|
+
prompt_manager.optimizer.clear_cache
|
|
2032
|
+
|
|
2033
|
+
{
|
|
2034
|
+
success: true,
|
|
2035
|
+
message: "Optimizer cache cleared. Next prompt will use fresh indexing.",
|
|
2036
|
+
action: :optimizer_reset
|
|
2037
|
+
}
|
|
2038
|
+
end
|
|
2039
|
+
|
|
2040
|
+
private
|
|
2041
|
+
|
|
2042
|
+
# Load configuration for prompt commands
|
|
2043
|
+
def load_config
|
|
2044
|
+
require_relative "../harness/configuration"
|
|
2045
|
+
Aidp::Harness::Configuration.new(@project_dir)
|
|
2046
|
+
end
|
|
1492
2047
|
end
|
|
1493
2048
|
end
|
|
1494
2049
|
end
|
|
@@ -46,7 +46,7 @@ module Aidp
|
|
|
46
46
|
@project_dir = project_dir
|
|
47
47
|
@provider_manager = provider_manager
|
|
48
48
|
@config = config
|
|
49
|
-
@prompt_manager = PromptManager.new(project_dir)
|
|
49
|
+
@prompt_manager = PromptManager.new(project_dir, config: config)
|
|
50
50
|
@test_runner = Aidp::Harness::TestRunner.new(project_dir, config)
|
|
51
51
|
@checkpoint = Checkpoint.new(project_dir)
|
|
52
52
|
@checkpoint_display = CheckpointDisplay.new
|
|
@@ -343,6 +343,16 @@ module Aidp
|
|
|
343
343
|
|
|
344
344
|
# Create initial PROMPT.md with all context
|
|
345
345
|
def create_initial_prompt(step_spec, context)
|
|
346
|
+
# Try intelligent prompt optimization first (ZFC-powered)
|
|
347
|
+
if @prompt_manager.optimization_enabled?
|
|
348
|
+
if create_optimized_prompt(step_spec, context)
|
|
349
|
+
return
|
|
350
|
+
end
|
|
351
|
+
# Fallback to traditional prompt on optimization failure
|
|
352
|
+
display_message(" ⚠️ Prompt optimization failed, using traditional approach", type: :warning)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Traditional prompt building (fallback or when optimization disabled)
|
|
346
356
|
template_content = load_template(step_spec["templates"]&.first)
|
|
347
357
|
prd_content = load_prd
|
|
348
358
|
style_guide = load_style_guide
|
|
@@ -364,6 +374,103 @@ module Aidp
|
|
|
364
374
|
display_message(" Created PROMPT.md (#{initial_prompt.length} chars)", type: :info)
|
|
365
375
|
end
|
|
366
376
|
|
|
377
|
+
# Create prompt using intelligent optimization (Zero Framework Cognition)
|
|
378
|
+
# Selects only the most relevant fragments from style guide, templates, and code
|
|
379
|
+
def create_optimized_prompt(step_spec, context)
|
|
380
|
+
user_input = format_user_input(context[:user_input])
|
|
381
|
+
|
|
382
|
+
# Infer task type from step name
|
|
383
|
+
task_type = infer_task_type(step_spec, user_input)
|
|
384
|
+
|
|
385
|
+
# Extract affected files from context or PRD
|
|
386
|
+
affected_files = extract_affected_files(context, user_input)
|
|
387
|
+
|
|
388
|
+
# Build task context for optimizer
|
|
389
|
+
task_context = {
|
|
390
|
+
task_type: task_type,
|
|
391
|
+
description: build_task_description(user_input, context),
|
|
392
|
+
affected_files: affected_files,
|
|
393
|
+
step_name: @step_name,
|
|
394
|
+
tags: extract_tags(user_input, step_spec)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
# Use optimizer to create prompt
|
|
398
|
+
success = @prompt_manager.write_optimized(
|
|
399
|
+
task_context,
|
|
400
|
+
include_metadata: @config.prompt_log_fragments?
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
if success
|
|
404
|
+
stats = @prompt_manager.last_optimization_stats
|
|
405
|
+
display_message(" ✨ Created optimized PROMPT.md", type: :success)
|
|
406
|
+
display_message(" Selected: #{stats.selected_count} fragments, Excluded: #{stats.excluded_count}", type: :info)
|
|
407
|
+
display_message(" Tokens: #{stats.total_tokens} (#{stats.budget_utilization.round(1)}% of budget)", type: :info)
|
|
408
|
+
display_message(" Avg relevance: #{(stats.average_score * 100).round(1)}%", type: :info)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
success
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
# Infer task type from step name and context
|
|
415
|
+
def infer_task_type(step_spec, user_input)
|
|
416
|
+
step_name = @step_name.to_s.downcase
|
|
417
|
+
input_lower = user_input.to_s.downcase
|
|
418
|
+
|
|
419
|
+
return :test if step_name.include?("test") || input_lower.include?("test")
|
|
420
|
+
return :bugfix if step_name.include?("fix") || input_lower.include?("fix") || input_lower.include?("bug")
|
|
421
|
+
return :refactor if step_name.include?("refactor") || input_lower.include?("refactor")
|
|
422
|
+
return :analysis if step_name.include?("analyz") || step_name.include?("review")
|
|
423
|
+
|
|
424
|
+
:feature # Default to feature
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# Extract files that will be affected by this work
|
|
428
|
+
def extract_affected_files(context, user_input)
|
|
429
|
+
files = []
|
|
430
|
+
|
|
431
|
+
# From user input (e.g., "update lib/user.rb")
|
|
432
|
+
user_input&.scan(/[\w\/]+\.rb/)&.each do |file|
|
|
433
|
+
files << file
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
# From deterministic outputs
|
|
437
|
+
context[:deterministic_outputs]&.each do |output|
|
|
438
|
+
if output[:output_path]&.end_with?(".rb")
|
|
439
|
+
files << output[:output_path]
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
files.uniq
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# Build task description from context
|
|
447
|
+
def build_task_description(user_input, context)
|
|
448
|
+
parts = []
|
|
449
|
+
parts << user_input if user_input && !user_input.empty?
|
|
450
|
+
parts << context[:previous_agent_summary] if context[:previous_agent_summary]
|
|
451
|
+
parts.join("\n\n")
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Extract relevant tags from input and spec
|
|
455
|
+
def extract_tags(user_input, step_spec)
|
|
456
|
+
tags = []
|
|
457
|
+
input_lower = user_input.to_s.downcase
|
|
458
|
+
|
|
459
|
+
# Common tags from content
|
|
460
|
+
tags << "testing" if input_lower.include?("test")
|
|
461
|
+
tags << "security" if input_lower.include?("security") || input_lower.include?("auth")
|
|
462
|
+
tags << "api" if input_lower.include?("api") || input_lower.include?("endpoint")
|
|
463
|
+
tags << "database" if input_lower.include?("database") || input_lower.include?("migration")
|
|
464
|
+
tags << "performance" if input_lower.include?("performance") || input_lower.include?("optim")
|
|
465
|
+
|
|
466
|
+
# Tags from step spec
|
|
467
|
+
if step_spec["tags"]
|
|
468
|
+
tags.concat(Array(step_spec["tags"]))
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
tags.uniq
|
|
472
|
+
end
|
|
473
|
+
|
|
367
474
|
def build_initial_prompt_content(template:, prd:, style_guide:, user_input:, step_name:, deterministic_outputs:, previous_agent_summary:)
|
|
368
475
|
parts = []
|
|
369
476
|
|