aidp 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/aidp/cli/devcontainer_commands.rb +501 -0
- data/lib/aidp/cli/issue_importer.rb +15 -3
- data/lib/aidp/cli.rb +91 -0
- data/lib/aidp/execute/prompt_manager.rb +16 -2
- data/lib/aidp/execute/runner.rb +10 -5
- data/lib/aidp/execute/work_loop_runner.rb +3 -3
- data/lib/aidp/harness/state/persistence.rb +12 -1
- data/lib/aidp/harness/state_manager.rb +13 -1
- data/lib/aidp/jobs/background_runner.rb +3 -1
- data/lib/aidp/logger.rb +41 -5
- data/lib/aidp/safe_directory.rb +87 -0
- data/lib/aidp/setup/devcontainer/backup_manager.rb +175 -0
- data/lib/aidp/setup/devcontainer/generator.rb +409 -0
- data/lib/aidp/setup/devcontainer/parser.rb +249 -0
- data/lib/aidp/setup/devcontainer/port_manager.rb +286 -0
- data/lib/aidp/setup/wizard.rb +145 -0
- data/lib/aidp/storage/csv_storage.rb +39 -2
- data/lib/aidp/storage/file_manager.rb +28 -3
- data/lib/aidp/storage/json_storage.rb +41 -2
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/guided_agent.rb +21 -46
- metadata +7 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
3
4
|
require_relative "../harness/provider_manager"
|
|
4
5
|
require_relative "../harness/provider_factory"
|
|
5
6
|
require_relative "../harness/config_manager"
|
|
@@ -32,7 +33,6 @@ module Aidp
|
|
|
32
33
|
@provider_manager = Aidp::Harness::ProviderManager.new(@config_manager, prompt: @prompt)
|
|
33
34
|
@conversation_history = []
|
|
34
35
|
@user_input = {}
|
|
35
|
-
@invalid_planning_responses = 0
|
|
36
36
|
@verbose = verbose
|
|
37
37
|
@debug_env = ENV["DEBUG"] == "1" || ENV["DEBUG"] == "2"
|
|
38
38
|
end
|
|
@@ -105,6 +105,7 @@ module Aidp
|
|
|
105
105
|
|
|
106
106
|
# Ask questions
|
|
107
107
|
question_response[:questions]&.each do |question|
|
|
108
|
+
puts "\n" + ("─" * 80) if iteration > 1 # Visual separator between Q&A pairs
|
|
108
109
|
answer = @prompt.ask(question)
|
|
109
110
|
@conversation_history << {role: "assistant", content: question}
|
|
110
111
|
@conversation_history << {role: "user", content: answer}
|
|
@@ -115,7 +116,8 @@ module Aidp
|
|
|
115
116
|
|
|
116
117
|
# Guard: break loop after 10 iterations to avoid infinite loop
|
|
117
118
|
if iteration >= 10
|
|
118
|
-
display_message("[
|
|
119
|
+
display_message("[WARNING] Planning loop exceeded 10 iterations. Provider may be returning generic responses.", type: :warning)
|
|
120
|
+
display_message("Continuing with the plan information gathered so far...", type: :info)
|
|
119
121
|
break
|
|
120
122
|
end
|
|
121
123
|
end
|
|
@@ -135,7 +137,7 @@ module Aidp
|
|
|
135
137
|
end
|
|
136
138
|
|
|
137
139
|
response = call_provider_for_analysis(system_prompt, user_prompt)
|
|
138
|
-
parsed =
|
|
140
|
+
parsed = parse_planning_response(response)
|
|
139
141
|
# Attach raw response for debug
|
|
140
142
|
parsed[:raw_response] = response
|
|
141
143
|
emit_verbose_raw_prompt(system_prompt, user_prompt, response)
|
|
@@ -375,53 +377,20 @@ module Aidp
|
|
|
375
377
|
json_match = response_text.match(/```json\s*(\{.*?\})\s*```/m) ||
|
|
376
378
|
response_text.match(/(\{.*\})/m)
|
|
377
379
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
rescue JSON::ParserError
|
|
381
|
-
{error: :invalid_format}
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
# Provides structured fallback sequence when provider keeps returning invalid planning JSON.
|
|
385
|
-
# After exceeding sequence length, switches to manual entry question.
|
|
386
|
-
def safe_parse_planning_response(response_text)
|
|
387
|
-
parsed = parse_planning_response(response_text)
|
|
388
|
-
return parsed unless parsed.is_a?(Hash) && parsed[:error] == :invalid_format
|
|
389
|
-
|
|
390
|
-
@invalid_planning_responses += 1
|
|
391
|
-
fallback_sequence = [
|
|
392
|
-
"Provide scope (key features) and primary users.",
|
|
393
|
-
"List 3-5 key functional requirements and any technical constraints.",
|
|
394
|
-
"Supply any non-functional requirements (performance/security) or type 'skip'."
|
|
395
|
-
]
|
|
396
|
-
|
|
397
|
-
if @invalid_planning_responses <= fallback_sequence.size
|
|
398
|
-
{complete: false, questions: [fallback_sequence[@invalid_planning_responses - 1]], reasoning: "Fallback due to invalid provider response (format)", error: :fallback}
|
|
399
|
-
else
|
|
400
|
-
display_message("[ERROR] Provider returned invalid planning JSON #{@invalid_planning_responses} times. Enter combined plan details manually.", type: :error)
|
|
401
|
-
{complete: false, questions: ["Enter plan details manually (features; users; requirements; constraints) or type 'skip'"], reasoning: "Manual recovery mode", error: :manual_recovery}
|
|
380
|
+
unless json_match
|
|
381
|
+
raise ConversationError, "Provider returned invalid format: no JSON found in response"
|
|
402
382
|
end
|
|
383
|
+
|
|
384
|
+
JSON.parse(json_match[1], symbolize_names: true)
|
|
385
|
+
rescue JSON::ParserError => e
|
|
386
|
+
raise ConversationError, "Provider returned invalid JSON: #{e.message}"
|
|
403
387
|
end
|
|
404
388
|
|
|
405
389
|
def update_plan_from_answer(plan, question, answer)
|
|
406
390
|
# Simple heuristic-based plan updates
|
|
407
391
|
# In a more sophisticated implementation, use AI to categorize answers
|
|
408
392
|
|
|
409
|
-
|
|
410
|
-
# by broader keyword heuristics (e.g., it contains the word 'users').
|
|
411
|
-
if question.start_with?("Enter plan details manually")
|
|
412
|
-
unless answer.strip.downcase == "skip"
|
|
413
|
-
parts = answer.split(/;|\|/).map(&:strip).reject(&:empty?)
|
|
414
|
-
features, users, requirements, constraints = parts
|
|
415
|
-
plan[:scope][:included] ||= []
|
|
416
|
-
plan[:scope][:included] << features if features
|
|
417
|
-
plan[:users][:personas] ||= []
|
|
418
|
-
plan[:users][:personas] << users if users
|
|
419
|
-
plan[:requirements][:functional] ||= []
|
|
420
|
-
plan[:requirements][:functional] << requirements if requirements
|
|
421
|
-
plan[:constraints][:technical] ||= []
|
|
422
|
-
plan[:constraints][:technical] << constraints if constraints
|
|
423
|
-
end
|
|
424
|
-
elsif question.downcase.include?("scope") || question.downcase.include?("include")
|
|
393
|
+
if question.downcase.include?("scope") || question.downcase.include?("include")
|
|
425
394
|
plan[:scope][:included] ||= []
|
|
426
395
|
plan[:scope][:included] << answer
|
|
427
396
|
elsif question.downcase.include?("user") || question.downcase.include?("who")
|
|
@@ -532,7 +501,9 @@ module Aidp
|
|
|
532
501
|
Generated by AIDP Plan & Execute workflow on #{Time.now.strftime("%Y-%m-%d")}
|
|
533
502
|
PRD
|
|
534
503
|
|
|
535
|
-
File.
|
|
504
|
+
docs_dir = File.join(@project_dir, "docs")
|
|
505
|
+
FileUtils.mkdir_p(docs_dir) unless Dir.exist?(docs_dir)
|
|
506
|
+
File.write(File.join(docs_dir, "prd.md"), prd_content)
|
|
536
507
|
end
|
|
537
508
|
|
|
538
509
|
def generate_nfr_from_plan(plan)
|
|
@@ -548,7 +519,9 @@ module Aidp
|
|
|
548
519
|
Generated by AIDP Plan & Execute workflow on #{Time.now.strftime("%Y-%m-%d")}
|
|
549
520
|
NFR
|
|
550
521
|
|
|
551
|
-
File.
|
|
522
|
+
docs_dir = File.join(@project_dir, "docs")
|
|
523
|
+
FileUtils.mkdir_p(docs_dir) unless Dir.exist?(docs_dir)
|
|
524
|
+
File.write(File.join(docs_dir, "nfrs.md"), nfr_content)
|
|
552
525
|
end
|
|
553
526
|
|
|
554
527
|
def generate_style_guide_from_plan(plan)
|
|
@@ -563,7 +536,9 @@ module Aidp
|
|
|
563
536
|
Generated by AIDP Plan & Execute workflow on #{Time.now.strftime("%Y-%m-%d")}
|
|
564
537
|
STYLE
|
|
565
538
|
|
|
566
|
-
File.
|
|
539
|
+
docs_dir = File.join(@project_dir, "docs")
|
|
540
|
+
FileUtils.mkdir_p(docs_dir) unless Dir.exist?(docs_dir)
|
|
541
|
+
File.write(File.join(docs_dir, "LLM_STYLE_GUIDE.md"), style_guide_content)
|
|
567
542
|
end
|
|
568
543
|
|
|
569
544
|
def format_hash_for_doc(hash)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aidp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bart Agapinan
|
|
@@ -245,6 +245,7 @@ files:
|
|
|
245
245
|
- lib/aidp/analyze/tree_sitter_grammar_loader.rb
|
|
246
246
|
- lib/aidp/analyze/tree_sitter_scan.rb
|
|
247
247
|
- lib/aidp/cli.rb
|
|
248
|
+
- lib/aidp/cli/devcontainer_commands.rb
|
|
248
249
|
- lib/aidp/cli/enhanced_input.rb
|
|
249
250
|
- lib/aidp/cli/first_run_wizard.rb
|
|
250
251
|
- lib/aidp/cli/issue_importer.rb
|
|
@@ -354,6 +355,11 @@ files:
|
|
|
354
355
|
- lib/aidp/providers/github_copilot.rb
|
|
355
356
|
- lib/aidp/providers/opencode.rb
|
|
356
357
|
- lib/aidp/rescue_logging.rb
|
|
358
|
+
- lib/aidp/safe_directory.rb
|
|
359
|
+
- lib/aidp/setup/devcontainer/backup_manager.rb
|
|
360
|
+
- lib/aidp/setup/devcontainer/generator.rb
|
|
361
|
+
- lib/aidp/setup/devcontainer/parser.rb
|
|
362
|
+
- lib/aidp/setup/devcontainer/port_manager.rb
|
|
357
363
|
- lib/aidp/setup/wizard.rb
|
|
358
364
|
- lib/aidp/skills.rb
|
|
359
365
|
- lib/aidp/skills/composer.rb
|