aidp 0.17.1 ā 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/cli.rb +43 -2
- data/lib/aidp/config.rb +9 -14
- 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_schema.rb +305 -1
- data/lib/aidp/harness/configuration.rb +452 -0
- data/lib/aidp/harness/enhanced_runner.rb +7 -1
- data/lib/aidp/harness/provider_factory.rb +0 -2
- data/lib/aidp/harness/runner.rb +7 -1
- data/lib/aidp/harness/thinking_depth_manager.rb +335 -0
- 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/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 +19 -0
- data/lib/aidp/setup/wizard.rb +299 -4
- 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/repository_client.rb +2 -1
- 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 |  |