aidp 0.13.0 → 0.14.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 +7 -0
- data/lib/aidp/cli/first_run_wizard.rb +28 -303
- data/lib/aidp/cli/issue_importer.rb +359 -0
- data/lib/aidp/cli.rb +151 -3
- data/lib/aidp/daemon/process_manager.rb +146 -0
- data/lib/aidp/daemon/runner.rb +232 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +216 -0
- data/lib/aidp/execute/future_work_backlog.rb +411 -0
- data/lib/aidp/execute/guard_policy.rb +246 -0
- data/lib/aidp/execute/instruction_queue.rb +131 -0
- data/lib/aidp/execute/interactive_repl.rb +335 -0
- data/lib/aidp/execute/repl_macros.rb +651 -0
- data/lib/aidp/execute/steps.rb +8 -0
- data/lib/aidp/execute/work_loop_runner.rb +322 -36
- data/lib/aidp/execute/work_loop_state.rb +162 -0
- data/lib/aidp/harness/config_schema.rb +88 -0
- data/lib/aidp/harness/configuration.rb +48 -1
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +2 -0
- data/lib/aidp/init/doc_generator.rb +256 -0
- data/lib/aidp/init/project_analyzer.rb +343 -0
- data/lib/aidp/init/runner.rb +83 -0
- data/lib/aidp/init.rb +5 -0
- data/lib/aidp/logger.rb +279 -0
- data/lib/aidp/setup/wizard.rb +777 -0
- data/lib/aidp/tooling_detector.rb +115 -0
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/build_processor.rb +282 -0
- data/lib/aidp/watch/plan_generator.rb +166 -0
- data/lib/aidp/watch/plan_processor.rb +83 -0
- data/lib/aidp/watch/repository_client.rb +243 -0
- data/lib/aidp/watch/runner.rb +93 -0
- data/lib/aidp/watch/state_store.rb +105 -0
- data/lib/aidp/watch.rb +9 -0
- data/lib/aidp.rb +14 -0
- data/templates/implementation/simple_task.md +36 -0
- metadata +26 -1
@@ -404,6 +404,55 @@ module Aidp
|
|
404
404
|
items: {
|
405
405
|
type: :string
|
406
406
|
}
|
407
|
+
},
|
408
|
+
guards: {
|
409
|
+
type: :hash,
|
410
|
+
required: false,
|
411
|
+
default: {
|
412
|
+
enabled: false
|
413
|
+
},
|
414
|
+
properties: {
|
415
|
+
enabled: {
|
416
|
+
type: :boolean,
|
417
|
+
required: false,
|
418
|
+
default: false
|
419
|
+
},
|
420
|
+
include_files: {
|
421
|
+
type: :array,
|
422
|
+
required: false,
|
423
|
+
default: [],
|
424
|
+
items: {
|
425
|
+
type: :string
|
426
|
+
}
|
427
|
+
},
|
428
|
+
exclude_files: {
|
429
|
+
type: :array,
|
430
|
+
required: false,
|
431
|
+
default: [],
|
432
|
+
items: {
|
433
|
+
type: :string
|
434
|
+
}
|
435
|
+
},
|
436
|
+
confirm_files: {
|
437
|
+
type: :array,
|
438
|
+
required: false,
|
439
|
+
default: [],
|
440
|
+
items: {
|
441
|
+
type: :string
|
442
|
+
}
|
443
|
+
},
|
444
|
+
max_lines_per_commit: {
|
445
|
+
type: :integer,
|
446
|
+
required: false,
|
447
|
+
min: 1,
|
448
|
+
max: 10000
|
449
|
+
},
|
450
|
+
bypass: {
|
451
|
+
type: :boolean,
|
452
|
+
required: false,
|
453
|
+
default: false
|
454
|
+
}
|
455
|
+
}
|
407
456
|
}
|
408
457
|
}
|
409
458
|
}
|
@@ -576,6 +625,45 @@ module Aidp
|
|
576
625
|
}
|
577
626
|
}
|
578
627
|
}
|
628
|
+
},
|
629
|
+
logging: {
|
630
|
+
type: :hash,
|
631
|
+
required: false,
|
632
|
+
default: {},
|
633
|
+
properties: {
|
634
|
+
level: {
|
635
|
+
type: :string,
|
636
|
+
required: false,
|
637
|
+
default: "info",
|
638
|
+
enum: ["debug", "info", "warn", "error"]
|
639
|
+
},
|
640
|
+
json: {
|
641
|
+
type: :boolean,
|
642
|
+
required: false,
|
643
|
+
default: false
|
644
|
+
},
|
645
|
+
max_size_mb: {
|
646
|
+
type: :integer,
|
647
|
+
required: false,
|
648
|
+
default: 10,
|
649
|
+
min: 1,
|
650
|
+
max: 100
|
651
|
+
},
|
652
|
+
max_backups: {
|
653
|
+
type: :integer,
|
654
|
+
required: false,
|
655
|
+
default: 5,
|
656
|
+
min: 1,
|
657
|
+
max: 20
|
658
|
+
},
|
659
|
+
max_age_days: {
|
660
|
+
type: :integer,
|
661
|
+
required: false,
|
662
|
+
default: 14,
|
663
|
+
min: 1,
|
664
|
+
max: 365
|
665
|
+
}
|
666
|
+
}
|
579
667
|
}
|
580
668
|
}.freeze
|
581
669
|
|
@@ -170,6 +170,41 @@ module Aidp
|
|
170
170
|
work_loop_config[:lint_commands] || []
|
171
171
|
end
|
172
172
|
|
173
|
+
# Get guards configuration
|
174
|
+
def guards_config
|
175
|
+
work_loop_config[:guards] || default_guards_config
|
176
|
+
end
|
177
|
+
|
178
|
+
# Check if guards are enabled
|
179
|
+
def guards_enabled?
|
180
|
+
guards_config[:enabled] == true
|
181
|
+
end
|
182
|
+
|
183
|
+
# Get include file patterns for guards
|
184
|
+
def guards_include_files
|
185
|
+
guards_config[:include_files] || []
|
186
|
+
end
|
187
|
+
|
188
|
+
# Get exclude file patterns for guards
|
189
|
+
def guards_exclude_files
|
190
|
+
guards_config[:exclude_files] || []
|
191
|
+
end
|
192
|
+
|
193
|
+
# Get files requiring confirmation for guards
|
194
|
+
def guards_confirm_files
|
195
|
+
guards_config[:confirm_files] || []
|
196
|
+
end
|
197
|
+
|
198
|
+
# Get max lines per commit for guards
|
199
|
+
def guards_max_lines_per_commit
|
200
|
+
guards_config[:max_lines_per_commit]
|
201
|
+
end
|
202
|
+
|
203
|
+
# Check if guards are bypassed
|
204
|
+
def guards_bypass?
|
205
|
+
guards_config[:bypass] == true
|
206
|
+
end
|
207
|
+
|
173
208
|
# Get provider priority
|
174
209
|
def provider_priority(provider_name)
|
175
210
|
provider_config(provider_name)[:priority] || 0
|
@@ -447,7 +482,19 @@ module Aidp
|
|
447
482
|
enabled: true,
|
448
483
|
max_iterations: 50,
|
449
484
|
test_commands: [],
|
450
|
-
lint_commands: []
|
485
|
+
lint_commands: [],
|
486
|
+
guards: default_guards_config
|
487
|
+
}
|
488
|
+
end
|
489
|
+
|
490
|
+
def default_guards_config
|
491
|
+
{
|
492
|
+
enabled: false,
|
493
|
+
include_files: [],
|
494
|
+
exclude_files: [],
|
495
|
+
confirm_files: [],
|
496
|
+
max_lines_per_commit: nil,
|
497
|
+
bypass: false
|
451
498
|
}
|
452
499
|
end
|
453
500
|
|
@@ -258,7 +258,9 @@ module Aidp
|
|
258
258
|
@user_input = result[:user_input]
|
259
259
|
|
260
260
|
# Return in the expected format
|
261
|
+
# IMPORTANT: Include the mode from guided agent result (usually :execute)
|
261
262
|
{
|
263
|
+
mode: result[:mode],
|
262
264
|
workflow_type: result[:workflow_type],
|
263
265
|
steps: result[:steps],
|
264
266
|
user_input: @user_input,
|
@@ -0,0 +1,256 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
module Aidp
|
7
|
+
module Init
|
8
|
+
# Creates project documentation artefacts based on the analyzer output. All
|
9
|
+
# documents are deterministic and tailored with repository insights.
|
10
|
+
class DocGenerator
|
11
|
+
OUTPUT_DIR = "docs"
|
12
|
+
STYLE_GUIDE_PATH = File.join(OUTPUT_DIR, "LLM_STYLE_GUIDE.md")
|
13
|
+
ANALYSIS_PATH = File.join(OUTPUT_DIR, "PROJECT_ANALYSIS.md")
|
14
|
+
QUALITY_PLAN_PATH = File.join(OUTPUT_DIR, "CODE_QUALITY_PLAN.md")
|
15
|
+
|
16
|
+
def initialize(project_dir = Dir.pwd)
|
17
|
+
@project_dir = project_dir
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate(analysis:, preferences: {})
|
21
|
+
ensure_output_directory
|
22
|
+
write_style_guide(analysis, preferences)
|
23
|
+
write_project_analysis(analysis)
|
24
|
+
write_quality_plan(analysis, preferences)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def ensure_output_directory
|
30
|
+
FileUtils.mkdir_p(File.join(@project_dir, OUTPUT_DIR))
|
31
|
+
end
|
32
|
+
|
33
|
+
def write_style_guide(analysis, preferences)
|
34
|
+
languages = format_list(analysis[:languages].keys)
|
35
|
+
frameworks = format_list(analysis[:frameworks])
|
36
|
+
test_frameworks = format_list(analysis[:test_frameworks])
|
37
|
+
key_dirs = format_list(analysis[:key_directories])
|
38
|
+
tooling = analysis[:tooling].keys.map { |tool| format_tool(tool) }.sort
|
39
|
+
|
40
|
+
adoption_note = if truthy?(preferences[:adopt_new_conventions])
|
41
|
+
"This project has opted to adopt new conventions recommended by aidp init. When in doubt, prefer the rules below over legacy patterns."
|
42
|
+
else
|
43
|
+
"Retain existing conventions when they do not conflict with the guidance below."
|
44
|
+
end
|
45
|
+
|
46
|
+
content = <<~GUIDE
|
47
|
+
# Project LLM Style Guide
|
48
|
+
|
49
|
+
> Generated automatically by `aidp init` on #{Time.now.utc.iso8601}.
|
50
|
+
>
|
51
|
+
> Detected languages: #{languages}
|
52
|
+
> Framework hints: #{frameworks.empty? ? "None detected" : frameworks}
|
53
|
+
> Primary test frameworks: #{test_frameworks.empty? ? "Unknown" : test_frameworks}
|
54
|
+
> Key directories: #{key_dirs.empty? ? "Standard structure" : key_dirs}
|
55
|
+
|
56
|
+
#{adoption_note}
|
57
|
+
|
58
|
+
## 1. Core Engineering Rules
|
59
|
+
- Prioritise readability and maintainability; extract objects or modules once business logic exceeds a few branches.
|
60
|
+
- Co-locate domain objects with their tests under the matching directory (e.g., `lib/` ↔ `spec/`).
|
61
|
+
- Remove dead code and feature flags that are no longer exercised; keep git history as the source of truth.
|
62
|
+
- Use small, composable services rather than bloated classes.
|
63
|
+
|
64
|
+
## 2. Naming & Structure
|
65
|
+
- Follow idiomatic naming for the detected languages (#{languages}); align files under #{key_dirs.empty? ? "the project root" : key_dirs}.
|
66
|
+
- Ensure top-level namespaces mirror the directory structure (e.g., `Aidp::Init` lives in `lib/aidp/init/`).
|
67
|
+
- Keep public APIs explicit with keyword arguments and descriptive method names.
|
68
|
+
|
69
|
+
## 3. Parameters & Data
|
70
|
+
- Limit positional arguments to three; prefer keyword arguments or value objects beyond that.
|
71
|
+
- Reuse shared data structures to capture configuration (YAML/JSON) instead of scattered constants.
|
72
|
+
- Validate incoming data at boundaries; rely on plain objects internally.
|
73
|
+
|
74
|
+
## 4. Error Handling
|
75
|
+
- Raise domain-specific errors; avoid using plain `StandardError` without context.
|
76
|
+
- Wrap external calls with rescuable adapters and surface actionable error messages.
|
77
|
+
- Log failures with relevant identifiers only—never entire payloads.
|
78
|
+
|
79
|
+
## 5. Testing Contracts
|
80
|
+
- Mirror production directory structure inside `#{preferred_test_dirs(analysis)}`.
|
81
|
+
- Keep tests independent; mock external services only at the boundary layers.
|
82
|
+
- Use the project's native assertions (#{test_frameworks.empty? ? "choose an appropriate framework" : test_frameworks}) and ensure every bug fix comes with a regression test.
|
83
|
+
|
84
|
+
## 6. Framework-Specific Guidelines
|
85
|
+
- Adopt the idioms of detected frameworks#{frameworks.empty? ? " once adopted." : " (#{frameworks})."}
|
86
|
+
- Keep controllers/handlers thin; delegate logic to service objects or interactors.
|
87
|
+
- Store shared UI or component primitives in a central folder to make reuse easier.
|
88
|
+
|
89
|
+
## 7. Dependencies & External Services
|
90
|
+
- Document every external integration inside `docs/` and keep credentials outside the repo.
|
91
|
+
- Use dependency injection for clients; avoid global state or singletons.
|
92
|
+
- When adding new gems or packages, document the rationale in `PROJECT_ANALYSIS.md`.
|
93
|
+
|
94
|
+
## 8. Build & Development
|
95
|
+
- Run linters before committing: #{tooling.empty? ? "add rubocop/eslint/flake8 as appropriate." : tooling.join(", ")}.
|
96
|
+
- Keep build scripts in `bin/` or `scripts/` and ensure they are idempotent.
|
97
|
+
- Prefer `mise` or language-specific version managers to keep toolchains aligned.
|
98
|
+
|
99
|
+
## 9. Performance
|
100
|
+
- Measure before optimising; add benchmarks for hotspots.
|
101
|
+
- Cache expensive computations when they are pure and repeatable.
|
102
|
+
- Review dependency load time; lazy-load optional components where possible.
|
103
|
+
|
104
|
+
## 10. Project-Specific Anti-Patterns
|
105
|
+
- Avoid sprawling God objects that mix persistence, business logic, and presentation.
|
106
|
+
- Resist ad-hoc shelling out; prefer library APIs with proper error handling.
|
107
|
+
- Do not bypass the agreed testing workflow—even for small fixes.
|
108
|
+
|
109
|
+
---
|
110
|
+
Generated from template `planning/generate_llm_style_guide.md` with repository-aware adjustments.
|
111
|
+
GUIDE
|
112
|
+
|
113
|
+
File.write(File.join(@project_dir, STYLE_GUIDE_PATH), content)
|
114
|
+
end
|
115
|
+
|
116
|
+
def write_project_analysis(analysis)
|
117
|
+
languages = format_language_breakdown(analysis[:languages])
|
118
|
+
frameworks = bullet_list(analysis[:frameworks], default: "_None detected_")
|
119
|
+
config_files = bullet_list(analysis[:config_files], default: "_No dedicated configuration files discovered_")
|
120
|
+
tooling = format_tooling_section(analysis[:tooling])
|
121
|
+
|
122
|
+
stats = analysis[:repo_stats]
|
123
|
+
stats_lines = [
|
124
|
+
"- Total files scanned: #{stats[:total_files]}",
|
125
|
+
"- Unique directories: #{stats[:total_directories]}",
|
126
|
+
"- Documentation folder present: #{stats[:docs_present] ? "Yes" : "No"}",
|
127
|
+
"- CI configuration present: #{stats[:has_ci_config] ? "Yes" : "No"}",
|
128
|
+
"- Containerisation assets: #{stats[:has_containerization] ? "Yes" : "No"}"
|
129
|
+
]
|
130
|
+
|
131
|
+
content = <<~ANALYSIS
|
132
|
+
# Project Analysis
|
133
|
+
|
134
|
+
Generated automatically by `aidp init` on #{Time.now.utc.iso8601}. This document summarises the repository structure to guide future autonomous work loops.
|
135
|
+
|
136
|
+
## Language & Framework Footprint
|
137
|
+
#{languages}
|
138
|
+
|
139
|
+
### Framework Signals
|
140
|
+
#{frameworks}
|
141
|
+
|
142
|
+
## Key Directories
|
143
|
+
#{bullet_list(analysis[:key_directories], default: "_No conventional application directories detected_")}
|
144
|
+
|
145
|
+
## Configuration & Tooling Files
|
146
|
+
#{config_files}
|
147
|
+
|
148
|
+
## Test & Quality Signals
|
149
|
+
#{bullet_list(analysis[:test_frameworks], prefix: "- Detected test suite: ", default: "_Unable to infer test suite_")}
|
150
|
+
|
151
|
+
## Local Quality Toolchain
|
152
|
+
#{tooling}
|
153
|
+
|
154
|
+
## Repository Stats
|
155
|
+
#{stats_lines.join("\n")}
|
156
|
+
|
157
|
+
---
|
158
|
+
Template inspiration: `analysis/analyze_repository.md`, `analysis/analyze_tests.md`.
|
159
|
+
ANALYSIS
|
160
|
+
|
161
|
+
File.write(File.join(@project_dir, ANALYSIS_PATH), content)
|
162
|
+
end
|
163
|
+
|
164
|
+
def write_quality_plan(analysis, preferences)
|
165
|
+
tooling = analysis[:tooling]
|
166
|
+
proactive = if truthy?(preferences[:stricter_linters])
|
167
|
+
"- Enable stricter linting rules and fail CI on offences.\n- Enforce formatting checks (`mise exec --` for consistent environments).\n"
|
168
|
+
else
|
169
|
+
"- Maintain current linting thresholds while documenting exceptions.\n"
|
170
|
+
end
|
171
|
+
|
172
|
+
migration = if truthy?(preferences[:migrate_styles])
|
173
|
+
"- Plan refactors to align legacy files with the new style guide.\n- Schedule incremental clean-up tasks to avoid large-batch rewrites.\n"
|
174
|
+
else
|
175
|
+
"- Keep legacy style deviations documented until dedicated refactors are scheduled.\n"
|
176
|
+
end
|
177
|
+
|
178
|
+
content = <<~PLAN
|
179
|
+
# Code Quality Plan
|
180
|
+
|
181
|
+
This plan captures the current tooling landscape and proposes next steps for keeping the codebase healthy. Generated by `aidp init` on #{Time.now.utc.iso8601}.
|
182
|
+
|
183
|
+
## Local Quality Toolchain
|
184
|
+
#{tooling.empty? ? "_No linting/formatting tools detected. Consider adding RuboCop, ESLint, or Prettier based on the primary language._" : format_tooling_table(tooling)}
|
185
|
+
|
186
|
+
## Immediate Actions
|
187
|
+
#{proactive}#{migration}- Document onboarding steps in `docs/` to ensure future contributors follow the agreed workflow.
|
188
|
+
|
189
|
+
## Long-Term Improvements
|
190
|
+
- Keep the style guide in sync with real-world code changes; regenerate with `aidp init` after major rewrites.
|
191
|
+
- Automate test and lint runs via CI (detected: #{analysis.dig(:repo_stats, :has_ci_config) ? "yes" : "no"}).
|
192
|
+
- Track flaky tests or unstable tooling in `PROJECT_ANALYSIS.md` under a “Health Log” section.
|
193
|
+
|
194
|
+
---
|
195
|
+
Based on templates: `analysis/analyze_static_code.md`, `analysis/analyze_tests.md`.
|
196
|
+
PLAN
|
197
|
+
|
198
|
+
File.write(File.join(@project_dir, QUALITY_PLAN_PATH), content)
|
199
|
+
end
|
200
|
+
|
201
|
+
def preferred_test_dirs(analysis)
|
202
|
+
detected = Array(analysis[:key_directories]).select { |dir| dir =~ /\b(spec|test|tests)\b/ }
|
203
|
+
detected.empty? ? "the chosen test directory" : detected.join(", ")
|
204
|
+
end
|
205
|
+
|
206
|
+
def format_list(values)
|
207
|
+
Array(values).join(", ")
|
208
|
+
end
|
209
|
+
|
210
|
+
def bullet_list(values, prefix: "- ", default: "_None_")
|
211
|
+
items = Array(values)
|
212
|
+
return default if items.empty?
|
213
|
+
|
214
|
+
items.map { |value| "#{prefix}#{value}" }.join("\n")
|
215
|
+
end
|
216
|
+
|
217
|
+
def format_language_breakdown(languages)
|
218
|
+
return "_No source files detected._" if languages.nil? || languages.empty?
|
219
|
+
|
220
|
+
total = languages.values.sum
|
221
|
+
languages.map do |language, weight|
|
222
|
+
percentage = total.zero? ? 0 : ((weight.to_f / total) * 100).round(2)
|
223
|
+
"- #{language}: #{percentage}% of codebase"
|
224
|
+
end.join("\n")
|
225
|
+
end
|
226
|
+
|
227
|
+
def format_tooling_table(tooling)
|
228
|
+
rows = tooling.map do |tool, evidence|
|
229
|
+
"| #{format_tool(tool)} | #{evidence.uniq.join(", ")} |"
|
230
|
+
end
|
231
|
+
header = "| Tool | Evidence |\n|------|----------|"
|
232
|
+
([header] + rows).join("\n")
|
233
|
+
end
|
234
|
+
|
235
|
+
def format_tooling_section(tooling)
|
236
|
+
return "_No tooling detected._" if tooling.nil? || tooling.empty?
|
237
|
+
|
238
|
+
header = "| Tool | Evidence |\n|------|----------|"
|
239
|
+
rows = tooling.map do |tool, evidence|
|
240
|
+
"| #{format_tool(tool)} | #{Array(evidence).uniq.join(", ")} |"
|
241
|
+
end
|
242
|
+
([header] + rows).join("\n")
|
243
|
+
end
|
244
|
+
|
245
|
+
def format_tool(tool)
|
246
|
+
tool.to_s.split("_").map(&:capitalize).join(" ")
|
247
|
+
end
|
248
|
+
|
249
|
+
def truthy?(value)
|
250
|
+
value == true || value.to_s.strip.casecmp("yes").zero?
|
251
|
+
rescue
|
252
|
+
false
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|