aidp 0.26.0 → 0.28.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 +89 -0
- data/lib/aidp/cli/checkpoint_command.rb +198 -0
- data/lib/aidp/cli/config_command.rb +71 -0
- data/lib/aidp/cli/enhanced_input.rb +2 -0
- data/lib/aidp/cli/first_run_wizard.rb +8 -7
- data/lib/aidp/cli/harness_command.rb +102 -0
- data/lib/aidp/cli/jobs_command.rb +3 -3
- data/lib/aidp/cli/mcp_dashboard.rb +4 -3
- data/lib/aidp/cli/models_command.rb +661 -0
- data/lib/aidp/cli/providers_command.rb +223 -0
- data/lib/aidp/cli.rb +45 -464
- data/lib/aidp/config.rb +54 -0
- data/lib/aidp/daemon/runner.rb +2 -2
- data/lib/aidp/debug_mixin.rb +25 -10
- data/lib/aidp/execute/agent_signal_parser.rb +22 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +2 -1
- data/lib/aidp/execute/checkpoint_display.rb +38 -37
- data/lib/aidp/execute/interactive_repl.rb +2 -1
- data/lib/aidp/execute/prompt_manager.rb +4 -4
- data/lib/aidp/execute/repl_macros.rb +2 -2
- data/lib/aidp/execute/steps.rb +94 -1
- data/lib/aidp/execute/work_loop_runner.rb +238 -19
- data/lib/aidp/execute/workflow_selector.rb +4 -27
- data/lib/aidp/firewall/provider_requirements_collector.rb +262 -0
- data/lib/aidp/harness/ai_decision_engine.rb +35 -2
- data/lib/aidp/harness/config_manager.rb +5 -10
- data/lib/aidp/harness/config_schema.rb +8 -0
- data/lib/aidp/harness/configuration.rb +40 -2
- data/lib/aidp/harness/enhanced_runner.rb +25 -19
- data/lib/aidp/harness/error_handler.rb +23 -73
- data/lib/aidp/harness/model_cache.rb +269 -0
- data/lib/aidp/harness/model_discovery_service.rb +259 -0
- data/lib/aidp/harness/model_registry.rb +201 -0
- data/lib/aidp/harness/provider_factory.rb +11 -2
- data/lib/aidp/harness/runner.rb +5 -0
- data/lib/aidp/harness/state_manager.rb +0 -7
- data/lib/aidp/harness/thinking_depth_manager.rb +202 -7
- data/lib/aidp/harness/ui/enhanced_tui.rb +8 -18
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +0 -18
- data/lib/aidp/harness/ui/progress_display.rb +6 -2
- data/lib/aidp/harness/user_interface.rb +0 -58
- data/lib/aidp/init/runner.rb +7 -2
- data/lib/aidp/message_display.rb +0 -46
- data/lib/aidp/planning/analyzers/feedback_analyzer.rb +365 -0
- data/lib/aidp/planning/builders/agile_plan_builder.rb +387 -0
- data/lib/aidp/planning/builders/project_plan_builder.rb +193 -0
- data/lib/aidp/planning/generators/gantt_generator.rb +190 -0
- data/lib/aidp/planning/generators/iteration_plan_generator.rb +392 -0
- data/lib/aidp/planning/generators/legacy_research_planner.rb +473 -0
- data/lib/aidp/planning/generators/marketing_report_generator.rb +348 -0
- data/lib/aidp/planning/generators/mvp_scope_generator.rb +310 -0
- data/lib/aidp/planning/generators/user_test_plan_generator.rb +373 -0
- data/lib/aidp/planning/generators/wbs_generator.rb +259 -0
- data/lib/aidp/planning/mappers/persona_mapper.rb +163 -0
- data/lib/aidp/planning/parsers/document_parser.rb +141 -0
- data/lib/aidp/planning/parsers/feedback_data_parser.rb +252 -0
- data/lib/aidp/provider_manager.rb +8 -32
- data/lib/aidp/providers/adapter.rb +2 -4
- data/lib/aidp/providers/aider.rb +264 -0
- data/lib/aidp/providers/anthropic.rb +206 -121
- data/lib/aidp/providers/base.rb +123 -3
- data/lib/aidp/providers/capability_registry.rb +0 -1
- data/lib/aidp/providers/codex.rb +75 -70
- data/lib/aidp/providers/cursor.rb +87 -59
- data/lib/aidp/providers/gemini.rb +57 -60
- data/lib/aidp/providers/github_copilot.rb +19 -66
- data/lib/aidp/providers/kilocode.rb +35 -80
- data/lib/aidp/providers/opencode.rb +35 -80
- data/lib/aidp/setup/wizard.rb +555 -8
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +211 -30
- data/lib/aidp/watch/change_request_processor.rb +128 -14
- data/lib/aidp/watch/ci_fix_processor.rb +103 -37
- data/lib/aidp/watch/ci_log_extractor.rb +258 -0
- data/lib/aidp/watch/github_state_extractor.rb +177 -0
- data/lib/aidp/watch/implementation_verifier.rb +284 -0
- data/lib/aidp/watch/plan_generator.rb +95 -52
- data/lib/aidp/watch/plan_processor.rb +7 -6
- data/lib/aidp/watch/repository_client.rb +245 -17
- data/lib/aidp/watch/review_processor.rb +100 -19
- data/lib/aidp/watch/reviewers/base_reviewer.rb +1 -1
- data/lib/aidp/watch/runner.rb +181 -29
- data/lib/aidp/watch/state_store.rb +22 -1
- data/lib/aidp/workflows/definitions.rb +147 -0
- data/lib/aidp/workflows/guided_agent.rb +3 -3
- data/lib/aidp/workstream_cleanup.rb +245 -0
- data/lib/aidp/worktree.rb +19 -0
- data/templates/aidp-development.yml.example +2 -2
- data/templates/aidp-production.yml.example +3 -3
- data/templates/aidp.yml.example +57 -0
- data/templates/implementation/generate_tdd_specs.md +213 -0
- data/templates/implementation/iterative_implementation.md +122 -0
- data/templates/planning/agile/analyze_feedback.md +183 -0
- data/templates/planning/agile/generate_iteration_plan.md +179 -0
- data/templates/planning/agile/generate_legacy_research_plan.md +171 -0
- data/templates/planning/agile/generate_marketing_report.md +162 -0
- data/templates/planning/agile/generate_mvp_scope.md +127 -0
- data/templates/planning/agile/generate_user_test_plan.md +143 -0
- data/templates/planning/agile/ingest_feedback.md +174 -0
- data/templates/planning/assemble_project_plan.md +113 -0
- data/templates/planning/assign_personas.md +108 -0
- data/templates/planning/create_tasks.md +52 -6
- data/templates/planning/generate_gantt.md +86 -0
- data/templates/planning/generate_wbs.md +85 -0
- data/templates/planning/initialize_planning_mode.md +70 -0
- data/templates/skills/README.md +2 -2
- data/templates/skills/marketing_strategist/SKILL.md +279 -0
- data/templates/skills/product_manager/SKILL.md +177 -0
- data/templates/skills/ruby_aidp_planning/SKILL.md +497 -0
- data/templates/skills/ruby_rspec_tdd/SKILL.md +514 -0
- data/templates/skills/ux_researcher/SKILL.md +222 -0
- metadata +47 -1
data/lib/aidp/config.rb
CHANGED
|
@@ -156,6 +156,27 @@ module Aidp
|
|
|
156
156
|
search_paths: [],
|
|
157
157
|
default_provider_filter: true,
|
|
158
158
|
enable_custom_skills: true
|
|
159
|
+
},
|
|
160
|
+
waterfall: {
|
|
161
|
+
enabled: true,
|
|
162
|
+
docs_directory: ".aidp/docs",
|
|
163
|
+
generate_decisions_md: true,
|
|
164
|
+
gantt_format: "mermaid",
|
|
165
|
+
wbs_phases: [
|
|
166
|
+
"Requirements",
|
|
167
|
+
"Design",
|
|
168
|
+
"Implementation",
|
|
169
|
+
"Testing",
|
|
170
|
+
"Deployment"
|
|
171
|
+
],
|
|
172
|
+
effort_estimation: {
|
|
173
|
+
method: "llm_relative",
|
|
174
|
+
units: "story_points"
|
|
175
|
+
},
|
|
176
|
+
persona_assignment: {
|
|
177
|
+
method: "zfc_automatic",
|
|
178
|
+
allow_parallel: true
|
|
179
|
+
}
|
|
159
180
|
}
|
|
160
181
|
}.freeze
|
|
161
182
|
|
|
@@ -246,6 +267,24 @@ module Aidp
|
|
|
246
267
|
symbolize_keys(skills_section)
|
|
247
268
|
end
|
|
248
269
|
|
|
270
|
+
# Get waterfall configuration
|
|
271
|
+
def self.waterfall_config(project_dir = Dir.pwd)
|
|
272
|
+
config = load_harness_config(project_dir)
|
|
273
|
+
waterfall_section = config[:waterfall] || config["waterfall"] || {}
|
|
274
|
+
|
|
275
|
+
# Convert string keys to symbols for consistency
|
|
276
|
+
symbolize_keys(waterfall_section)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Get agile configuration
|
|
280
|
+
def self.agile_config(project_dir = Dir.pwd)
|
|
281
|
+
config = load_harness_config(project_dir)
|
|
282
|
+
agile_section = config[:agile] || config["agile"] || {}
|
|
283
|
+
|
|
284
|
+
# Convert string keys to symbols for consistency
|
|
285
|
+
symbolize_keys(agile_section)
|
|
286
|
+
end
|
|
287
|
+
|
|
249
288
|
# Check if configuration file exists
|
|
250
289
|
def self.config_exists?(project_dir = Dir.pwd)
|
|
251
290
|
ConfigPaths.config_exists?(project_dir)
|
|
@@ -280,6 +319,15 @@ module Aidp
|
|
|
280
319
|
max_tokens: 50_000,
|
|
281
320
|
default_flags: []
|
|
282
321
|
}
|
|
322
|
+
},
|
|
323
|
+
agile: {
|
|
324
|
+
mvp_first: true,
|
|
325
|
+
feedback_loops: true,
|
|
326
|
+
auto_iteration: false,
|
|
327
|
+
research_enabled: true,
|
|
328
|
+
marketing_enabled: true,
|
|
329
|
+
legacy_analysis: true,
|
|
330
|
+
personas: ["product_manager", "ux_researcher", "architect", "senior_developer", "qa_engineer", "devops_engineer", "tech_writer", "marketing_strategist"]
|
|
283
331
|
}
|
|
284
332
|
}
|
|
285
333
|
|
|
@@ -337,6 +385,12 @@ module Aidp
|
|
|
337
385
|
merged[:thinking] = symbolize_keys(thinking_section)
|
|
338
386
|
end
|
|
339
387
|
|
|
388
|
+
# Deep merge waterfall config
|
|
389
|
+
if config[:waterfall] || config["waterfall"]
|
|
390
|
+
waterfall_section = config[:waterfall] || config["waterfall"]
|
|
391
|
+
merged[:waterfall] = merged[:waterfall].merge(symbolize_keys(waterfall_section))
|
|
392
|
+
end
|
|
393
|
+
|
|
340
394
|
merged
|
|
341
395
|
end
|
|
342
396
|
|
data/lib/aidp/daemon/runner.rb
CHANGED
|
@@ -10,11 +10,11 @@ module Aidp
|
|
|
10
10
|
# Main daemon runner for background mode execution
|
|
11
11
|
# Manages work loops, watch mode, and IPC communication
|
|
12
12
|
class Runner
|
|
13
|
-
def initialize(project_dir, config, options = {})
|
|
13
|
+
def initialize(project_dir, config, options = {}, process_manager: nil)
|
|
14
14
|
@project_dir = project_dir
|
|
15
15
|
@config = config
|
|
16
16
|
@options = options
|
|
17
|
-
@process_manager = ProcessManager.new(project_dir)
|
|
17
|
+
@process_manager = process_manager || ProcessManager.new(project_dir)
|
|
18
18
|
@running = false
|
|
19
19
|
@work_loop_runner = nil
|
|
20
20
|
@watch_runner = nil
|
data/lib/aidp/debug_mixin.rb
CHANGED
|
@@ -78,7 +78,9 @@ module Aidp
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
if error && !error.empty?
|
|
81
|
-
|
|
81
|
+
# Filter out benign sandbox debug messages from Claude CLI
|
|
82
|
+
filtered_error = filter_benign_errors(error)
|
|
83
|
+
debug_logger.error(component_name, "❌ Error output: #{filtered_error}") unless filtered_error.empty?
|
|
82
84
|
end
|
|
83
85
|
|
|
84
86
|
if debug_verbose?
|
|
@@ -130,7 +132,7 @@ module Aidp
|
|
|
130
132
|
end
|
|
131
133
|
|
|
132
134
|
# Execute command with debug logging
|
|
133
|
-
def debug_execute_command(cmd, args: [], input: nil, timeout: nil,
|
|
135
|
+
def debug_execute_command(cmd, args: [], input: nil, timeout: nil, **options)
|
|
134
136
|
require "tty-command"
|
|
135
137
|
|
|
136
138
|
command_str = [cmd, *args].join(" ")
|
|
@@ -139,14 +141,7 @@ module Aidp
|
|
|
139
141
|
debug_logger.info(component_name, "🚀 Starting command execution: #{command_str}")
|
|
140
142
|
|
|
141
143
|
begin
|
|
142
|
-
|
|
143
|
-
if streaming
|
|
144
|
-
# Use progress printer for real-time output
|
|
145
|
-
cmd_obj = TTY::Command.new(printer: :progress)
|
|
146
|
-
debug_log("📺 Streaming mode enabled - showing real-time output", level: :info)
|
|
147
|
-
else
|
|
148
|
-
cmd_obj = TTY::Command.new(printer: :null) # Disable TTY::Command's own output
|
|
149
|
-
end
|
|
144
|
+
cmd_obj = TTY::Command.new(printer: :null) # Disable TTY::Command's own output
|
|
150
145
|
|
|
151
146
|
# Prepare input
|
|
152
147
|
input_data = nil
|
|
@@ -178,6 +173,26 @@ module Aidp
|
|
|
178
173
|
|
|
179
174
|
private
|
|
180
175
|
|
|
176
|
+
# Filter out benign error messages that don't indicate real failures
|
|
177
|
+
def filter_benign_errors(error)
|
|
178
|
+
return "" if error.nil?
|
|
179
|
+
|
|
180
|
+
# List of string patterns for benign messages to filter out
|
|
181
|
+
# Using simple string matching to avoid ReDoS vulnerabilities
|
|
182
|
+
benign_substrings = [
|
|
183
|
+
"[SandboxDebug]",
|
|
184
|
+
"Seccomp filtering not available",
|
|
185
|
+
"allowAllUnixSockets mode"
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
lines = error.lines
|
|
189
|
+
filtered_lines = lines.reject do |line|
|
|
190
|
+
benign_substrings.any? { |substring| line.include?(substring) }
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
filtered_lines.join
|
|
194
|
+
end
|
|
195
|
+
|
|
181
196
|
# Safely derive a component name for logging (memoized).
|
|
182
197
|
# Handles anonymous classes and modules gracefully.
|
|
183
198
|
def component_name
|
|
@@ -36,6 +36,28 @@ module Aidp
|
|
|
36
36
|
tasks
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# Parse task status update signals from agent output
|
|
40
|
+
# Returns array of status update hashes with task_id, status, and optional reason
|
|
41
|
+
# Pattern: Update task: task_id_here status: done|in_progress|pending|abandoned [reason: "reason"]
|
|
42
|
+
def self.parse_task_status_updates(output)
|
|
43
|
+
return [] unless output
|
|
44
|
+
|
|
45
|
+
updates = []
|
|
46
|
+
# Pattern matches: Update task: task_123_abc status: done
|
|
47
|
+
# Or: Update task: task_123_abc status: abandoned reason: "No longer needed"
|
|
48
|
+
pattern = /Update\s+task:\s*(\S+)\s+status:\s*(done|in_progress|pending|abandoned)(?:\s+reason:\s*"([^"]+)")?/i
|
|
49
|
+
|
|
50
|
+
output.to_s.scan(pattern).each do |task_id, status, reason|
|
|
51
|
+
updates << {
|
|
52
|
+
task_id: task_id.strip,
|
|
53
|
+
status: status.downcase.to_sym,
|
|
54
|
+
reason: reason&.strip
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
updates
|
|
59
|
+
end
|
|
60
|
+
|
|
39
61
|
def self.normalize_token(raw)
|
|
40
62
|
return nil if raw.nil? || raw.empty?
|
|
41
63
|
|
|
@@ -27,6 +27,7 @@ module Aidp
|
|
|
27
27
|
@config = config
|
|
28
28
|
@options = options
|
|
29
29
|
@cancel_timeout = options[:cancel_timeout] || 5 # seconds to wait for graceful shutdown
|
|
30
|
+
@sync_runner_class = options[:sync_runner_class] || WorkLoopRunner
|
|
30
31
|
@state = WorkLoopState.new
|
|
31
32
|
@instruction_queue = InstructionQueue.new
|
|
32
33
|
@work_thread = nil
|
|
@@ -133,7 +134,7 @@ module Aidp
|
|
|
133
134
|
# Main async execution loop
|
|
134
135
|
def run_async_loop
|
|
135
136
|
# Create synchronous runner (runs in this thread)
|
|
136
|
-
@sync_runner =
|
|
137
|
+
@sync_runner = @sync_runner_class.new(
|
|
137
138
|
@project_dir,
|
|
138
139
|
@provider_manager,
|
|
139
140
|
@config,
|
|
@@ -8,17 +8,18 @@ module Aidp
|
|
|
8
8
|
class CheckpointDisplay
|
|
9
9
|
include Aidp::MessageDisplay
|
|
10
10
|
|
|
11
|
-
def initialize
|
|
11
|
+
def initialize(prompt: nil)
|
|
12
12
|
@pastel = Pastel.new
|
|
13
|
+
@prompt = prompt || TTY::Prompt.new
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
# Display a checkpoint during work loop iteration
|
|
16
17
|
def display_checkpoint(checkpoint_data, show_details: false)
|
|
17
18
|
return unless checkpoint_data
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
@prompt.say("")
|
|
21
|
+
@prompt.say(@pastel.bold("📊 Checkpoint - Iteration #{checkpoint_data[:iteration]}"))
|
|
22
|
+
@prompt.say(@pastel.dim("─" * 60))
|
|
22
23
|
|
|
23
24
|
display_metrics(checkpoint_data[:metrics])
|
|
24
25
|
display_status(checkpoint_data[:status])
|
|
@@ -27,52 +28,52 @@ module Aidp
|
|
|
27
28
|
display_trends(checkpoint_data[:trends]) if checkpoint_data[:trends]
|
|
28
29
|
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
@prompt.say(@pastel.dim("─" * 60))
|
|
32
|
+
@prompt.say("")
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
# Display progress summary with trends
|
|
35
36
|
def display_progress_summary(summary)
|
|
36
37
|
return unless summary
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
@prompt.say("")
|
|
40
|
+
@prompt.say(@pastel.bold("📈 Progress Summary"))
|
|
41
|
+
@prompt.say(@pastel.dim("=" * 60))
|
|
41
42
|
|
|
42
43
|
current = summary[:current]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
@prompt.say("Step: #{@pastel.cyan(current[:step_name])}")
|
|
45
|
+
@prompt.say("Iteration: #{current[:iteration]}")
|
|
46
|
+
@prompt.say("Status: #{format_status(current[:status])}")
|
|
47
|
+
@prompt.say("")
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
@prompt.say(@pastel.bold("Current Metrics:"))
|
|
49
50
|
display_metrics(current[:metrics])
|
|
50
51
|
|
|
51
52
|
if summary[:trends]
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
@prompt.say("")
|
|
54
|
+
@prompt.say(@pastel.bold("Trends:"))
|
|
54
55
|
display_trends(summary[:trends])
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
if summary[:quality_score]
|
|
58
|
-
|
|
59
|
+
@prompt.say("")
|
|
59
60
|
display_quality_score(summary[:quality_score])
|
|
60
61
|
end
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
@prompt.say(@pastel.dim("=" * 60))
|
|
64
|
+
@prompt.say("")
|
|
64
65
|
end
|
|
65
66
|
|
|
66
67
|
# Display checkpoint history as a table
|
|
67
68
|
def display_checkpoint_history(history, limit: 10)
|
|
68
69
|
return if history.empty?
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
@prompt.say("")
|
|
72
|
+
@prompt.say(@pastel.bold("📜 Checkpoint History (Last #{[limit, history.size].min})"))
|
|
73
|
+
@prompt.say(@pastel.dim("=" * 80))
|
|
73
74
|
|
|
74
75
|
# Table header
|
|
75
|
-
|
|
76
|
+
@prompt.say(format_table_row([
|
|
76
77
|
"Iteration",
|
|
77
78
|
"Time",
|
|
78
79
|
"LOC",
|
|
@@ -80,15 +81,15 @@ module Aidp
|
|
|
80
81
|
"Quality",
|
|
81
82
|
"PRD Progress",
|
|
82
83
|
"Status"
|
|
83
|
-
], header: true)
|
|
84
|
-
|
|
84
|
+
], header: true))
|
|
85
|
+
@prompt.say(@pastel.dim("-" * 80))
|
|
85
86
|
|
|
86
87
|
# Table rows
|
|
87
88
|
history.last(limit).each do |checkpoint|
|
|
88
89
|
metrics = checkpoint[:metrics]
|
|
89
90
|
timestamp = Time.parse(checkpoint[:timestamp]).strftime("%H:%M:%S")
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
@prompt.say(format_table_row([
|
|
92
93
|
checkpoint[:iteration].to_s,
|
|
93
94
|
timestamp,
|
|
94
95
|
metrics[:lines_of_code].to_s,
|
|
@@ -96,11 +97,11 @@ module Aidp
|
|
|
96
97
|
"#{metrics[:code_quality]}%",
|
|
97
98
|
"#{metrics[:prd_task_progress]}%",
|
|
98
99
|
format_status(checkpoint[:status])
|
|
99
|
-
])
|
|
100
|
+
]))
|
|
100
101
|
end
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
@prompt.say(@pastel.dim("=" * 80))
|
|
104
|
+
@prompt.say("")
|
|
104
105
|
end
|
|
105
106
|
|
|
106
107
|
# Display inline progress indicator (for work loop)
|
|
@@ -124,15 +125,15 @@ module Aidp
|
|
|
124
125
|
private
|
|
125
126
|
|
|
126
127
|
def display_metrics(metrics)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
@prompt.say(" Lines of Code: #{@pastel.yellow(metrics[:lines_of_code].to_s)}")
|
|
129
|
+
@prompt.say(" Test Coverage: #{format_percentage_with_color(metrics[:test_coverage])}")
|
|
130
|
+
@prompt.say(" Code Quality: #{format_percentage_with_color(metrics[:code_quality])}")
|
|
131
|
+
@prompt.say(" PRD Task Progress: #{format_percentage_with_color(metrics[:prd_task_progress])}")
|
|
132
|
+
@prompt.say(" File Count: #{metrics[:file_count]}")
|
|
132
133
|
end
|
|
133
134
|
|
|
134
135
|
def display_status(status)
|
|
135
|
-
|
|
136
|
+
@prompt.say(" Overall Status: #{format_status(status)}")
|
|
136
137
|
end
|
|
137
138
|
|
|
138
139
|
def format_status(status)
|
|
@@ -156,7 +157,7 @@ module Aidp
|
|
|
156
157
|
arrow = trend_arrow(trend_data[:direction])
|
|
157
158
|
change = format_change(trend_data[:change], trend_data[:change_percent])
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
@prompt.say(" #{metric_name}: #{arrow} #{change}")
|
|
160
161
|
end
|
|
161
162
|
end
|
|
162
163
|
|
|
@@ -185,7 +186,7 @@ module Aidp
|
|
|
185
186
|
:red
|
|
186
187
|
end
|
|
187
188
|
|
|
188
|
-
|
|
189
|
+
@prompt.say(" Quality Score: #{@pastel.send(color, "#{score.round(2)}%")}")
|
|
189
190
|
end
|
|
190
191
|
|
|
191
192
|
def format_percentage(value)
|
|
@@ -29,6 +29,7 @@ module Aidp
|
|
|
29
29
|
@config = config
|
|
30
30
|
@options = options
|
|
31
31
|
@prompt = options[:prompt] || TTY::Prompt.new
|
|
32
|
+
@async_runner_class = options[:async_runner_class] || AsyncWorkLoopRunner
|
|
32
33
|
@async_runner = nil
|
|
33
34
|
@repl_macros = ReplMacros.new
|
|
34
35
|
@output_display_thread = nil
|
|
@@ -38,7 +39,7 @@ module Aidp
|
|
|
38
39
|
|
|
39
40
|
# Start work loop and enter interactive REPL
|
|
40
41
|
def start_work_loop(step_name, step_spec, context = {})
|
|
41
|
-
@async_runner =
|
|
42
|
+
@async_runner = @async_runner_class.new(
|
|
42
43
|
@project_dir,
|
|
43
44
|
@provider_manager,
|
|
44
45
|
@config,
|
|
@@ -17,20 +17,20 @@ module Aidp
|
|
|
17
17
|
|
|
18
18
|
attr_reader :optimizer, :last_optimization_stats
|
|
19
19
|
|
|
20
|
-
def initialize(project_dir, config: nil)
|
|
20
|
+
def initialize(project_dir, config: nil, optimizer: nil)
|
|
21
21
|
@project_dir = project_dir
|
|
22
22
|
@aidp_dir = File.join(project_dir, ".aidp")
|
|
23
23
|
@prompt_path = File.join(@aidp_dir, PROMPT_FILENAME)
|
|
24
24
|
@archive_dir = File.join(project_dir, ARCHIVE_DIR)
|
|
25
25
|
@config = config
|
|
26
|
-
@optimizer =
|
|
26
|
+
@optimizer = optimizer
|
|
27
27
|
@last_optimization_stats = nil
|
|
28
28
|
|
|
29
29
|
# Ensure .aidp directory exists
|
|
30
30
|
FileUtils.mkdir_p(@aidp_dir)
|
|
31
31
|
|
|
32
|
-
# Initialize optimizer if enabled
|
|
33
|
-
if config&.respond_to?(:prompt_optimization_enabled?) && config.prompt_optimization_enabled?
|
|
32
|
+
# Initialize optimizer if enabled and not provided
|
|
33
|
+
if @optimizer.nil? && config&.respond_to?(:prompt_optimization_enabled?) && config.prompt_optimization_enabled?
|
|
34
34
|
@optimizer = Aidp::PromptOptimization::Optimizer.new(
|
|
35
35
|
project_dir: project_dir,
|
|
36
36
|
config: config.prompt_optimization_config
|
|
@@ -1777,8 +1777,8 @@ module Aidp
|
|
|
1777
1777
|
lines << "Legend: → current, ↑ max allowed"
|
|
1778
1778
|
lines << ""
|
|
1779
1779
|
|
|
1780
|
-
# Show current model selection
|
|
1781
|
-
current_model = manager.select_model_for_tier
|
|
1780
|
+
# Show current model selection (using harness default provider)
|
|
1781
|
+
current_model = manager.select_model_for_tier(provider: config.default_provider)
|
|
1782
1782
|
if current_model
|
|
1783
1783
|
provider, model_name, model_data = current_model
|
|
1784
1784
|
lines << "Current Model: #{provider}/#{model_name}"
|
data/lib/aidp/execute/steps.rb
CHANGED
|
@@ -121,12 +121,20 @@ module Aidp
|
|
|
121
121
|
},
|
|
122
122
|
# New implementation step for actual development work
|
|
123
123
|
"16_IMPLEMENTATION" => {
|
|
124
|
-
"templates" => ["implementation/
|
|
124
|
+
"templates" => ["implementation/iterative_implementation.md"], # Multi-step feature implementation with task decomposition
|
|
125
125
|
"description" => "Execute Implementation Tasks",
|
|
126
126
|
"outs" => ["implementation_log.md"],
|
|
127
127
|
"gate" => false,
|
|
128
128
|
"implementation" => true # Special step that runs development tasks
|
|
129
129
|
},
|
|
130
|
+
# Test-Driven Development (TDD) - Optional step for any workflow
|
|
131
|
+
"17_TDD_SPECIFICATION" => {
|
|
132
|
+
"templates" => ["implementation/generate_tdd_specs.md"],
|
|
133
|
+
"description" => "Generate TDD test specifications (write tests first)",
|
|
134
|
+
"outs" => ["docs/tdd_specifications.md", "spec/**/*_spec.rb"],
|
|
135
|
+
"gate" => false,
|
|
136
|
+
"interactive" => false
|
|
137
|
+
},
|
|
130
138
|
# Simple task execution - for one-off commands and simple fixes
|
|
131
139
|
"99_SIMPLE_TASK" => {
|
|
132
140
|
"templates" => ["implementation/simple_task.md"],
|
|
@@ -134,6 +142,91 @@ module Aidp
|
|
|
134
142
|
"outs" => [],
|
|
135
143
|
"gate" => false,
|
|
136
144
|
"simple" => true # Special step for simple, focused tasks
|
|
145
|
+
},
|
|
146
|
+
# Generic planning and project management steps (usable in any workflow)
|
|
147
|
+
"18_WBS" => {
|
|
148
|
+
"templates" => ["planning/generate_wbs.md"],
|
|
149
|
+
"description" => "Generate Work Breakdown Structure with phases and tasks",
|
|
150
|
+
"outs" => [".aidp/docs/WBS.md"],
|
|
151
|
+
"gate" => false
|
|
152
|
+
},
|
|
153
|
+
"19_GANTT_CHART" => {
|
|
154
|
+
"templates" => ["planning/generate_gantt.md"],
|
|
155
|
+
"description" => "Generate Gantt chart with timeline and critical path",
|
|
156
|
+
"outs" => [".aidp/docs/GANTT.md"],
|
|
157
|
+
"gate" => false
|
|
158
|
+
},
|
|
159
|
+
"20_PERSONA_ASSIGNMENT" => {
|
|
160
|
+
"templates" => ["planning/assign_personas.md"],
|
|
161
|
+
"description" => "Assign tasks to personas/roles using AI (ZFC)",
|
|
162
|
+
"outs" => [".aidp/docs/persona_map.yml"],
|
|
163
|
+
"gate" => false
|
|
164
|
+
},
|
|
165
|
+
"21_PROJECT_PLAN_ASSEMBLY" => {
|
|
166
|
+
"templates" => ["planning/assemble_project_plan.md"],
|
|
167
|
+
"description" => "Assemble complete project plan from all artifacts",
|
|
168
|
+
"outs" => [".aidp/docs/PROJECT_PLAN.md"],
|
|
169
|
+
"gate" => false
|
|
170
|
+
},
|
|
171
|
+
# Planning mode initialization (supports ingestion vs generation workflows)
|
|
172
|
+
"22_PLANNING_MODE_INIT" => {
|
|
173
|
+
"templates" => ["planning/initialize_planning_mode.md"],
|
|
174
|
+
"description" => "Initialize planning mode (ingestion of existing docs vs generation from scratch)",
|
|
175
|
+
"outs" => [".aidp/docs/.planning_mode"],
|
|
176
|
+
"gate" => true,
|
|
177
|
+
"interactive" => true
|
|
178
|
+
},
|
|
179
|
+
# Agile planning steps
|
|
180
|
+
"23_MVP_SCOPE" => {
|
|
181
|
+
"skill" => "product_manager",
|
|
182
|
+
"templates" => ["planning/agile/generate_mvp_scope.md"],
|
|
183
|
+
"description" => "Define MVP scope with must-have and nice-to-have features",
|
|
184
|
+
"outs" => [".aidp/docs/MVP_SCOPE.md"],
|
|
185
|
+
"gate" => false,
|
|
186
|
+
"interactive" => true
|
|
187
|
+
},
|
|
188
|
+
"24_USER_TEST_PLAN" => {
|
|
189
|
+
"skill" => "ux_researcher",
|
|
190
|
+
"templates" => ["planning/agile/generate_user_test_plan.md"],
|
|
191
|
+
"description" => "Generate user testing plan with recruitment and survey templates",
|
|
192
|
+
"outs" => [".aidp/docs/USER_TEST_PLAN.md"],
|
|
193
|
+
"gate" => false
|
|
194
|
+
},
|
|
195
|
+
"25_MARKETING_REPORT" => {
|
|
196
|
+
"skill" => "marketing_strategist",
|
|
197
|
+
"templates" => ["planning/agile/generate_marketing_report.md"],
|
|
198
|
+
"description" => "Generate marketing report with key messages and differentiators",
|
|
199
|
+
"outs" => [".aidp/docs/MARKETING_REPORT.md"],
|
|
200
|
+
"gate" => false
|
|
201
|
+
},
|
|
202
|
+
"26_INGEST_FEEDBACK" => {
|
|
203
|
+
"skill" => "ux_researcher",
|
|
204
|
+
"templates" => ["planning/agile/ingest_feedback.md"],
|
|
205
|
+
"description" => "Ingest user feedback data (CSV, JSON, markdown)",
|
|
206
|
+
"outs" => [".aidp/docs/feedback_data.json"],
|
|
207
|
+
"gate" => false,
|
|
208
|
+
"interactive" => true
|
|
209
|
+
},
|
|
210
|
+
"27_ANALYZE_FEEDBACK" => {
|
|
211
|
+
"skill" => "ux_researcher",
|
|
212
|
+
"templates" => ["planning/agile/analyze_feedback.md"],
|
|
213
|
+
"description" => "Analyze user feedback with AI-powered insights",
|
|
214
|
+
"outs" => [".aidp/docs/USER_FEEDBACK_ANALYSIS.md"],
|
|
215
|
+
"gate" => false
|
|
216
|
+
},
|
|
217
|
+
"28_ITERATION_PLAN" => {
|
|
218
|
+
"skill" => "product_manager",
|
|
219
|
+
"templates" => ["planning/agile/generate_iteration_plan.md"],
|
|
220
|
+
"description" => "Generate next iteration plan based on feedback",
|
|
221
|
+
"outs" => [".aidp/docs/NEXT_ITERATION_PLAN.md"],
|
|
222
|
+
"gate" => false
|
|
223
|
+
},
|
|
224
|
+
"29_LEGACY_RESEARCH_PLAN" => {
|
|
225
|
+
"skill" => "ux_researcher",
|
|
226
|
+
"templates" => ["planning/agile/generate_legacy_research_plan.md"],
|
|
227
|
+
"description" => "Generate user research plan for existing codebase",
|
|
228
|
+
"outs" => [".aidp/docs/LEGACY_USER_RESEARCH_PLAN.md"],
|
|
229
|
+
"gate" => false
|
|
137
230
|
}
|
|
138
231
|
}.freeze
|
|
139
232
|
end
|