aidp 0.14.1 → 0.15.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 +46 -45
- data/lib/aidp/cli.rb +46 -38
- data/lib/aidp/debug_mixin.rb +34 -33
- data/lib/aidp/execute/agent_signal_parser.rb +46 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +5 -0
- data/lib/aidp/execute/checkpoint.rb +28 -5
- data/lib/aidp/execute/deterministic_unit.rb +254 -0
- data/lib/aidp/execute/interactive_repl.rb +7 -0
- data/lib/aidp/execute/steps.rb +1 -1
- data/lib/aidp/execute/work_loop_runner.rb +187 -30
- data/lib/aidp/execute/work_loop_unit_scheduler.rb +190 -0
- data/lib/aidp/harness/config_schema.rb +91 -1
- data/lib/aidp/harness/configuration.rb +60 -1
- data/lib/aidp/harness/enhanced_runner.rb +2 -0
- data/lib/aidp/harness/provider_info.rb +14 -4
- data/lib/aidp/harness/provider_manager.rb +64 -12
- data/lib/aidp/jobs/background_runner.rb +10 -3
- data/lib/aidp/logger.rb +10 -71
- data/lib/aidp/providers/base.rb +2 -0
- data/lib/aidp/providers/github_copilot.rb +12 -0
- data/lib/aidp/rescue_logging.rb +36 -0
- data/lib/aidp/setup/wizard.rb +42 -46
- data/lib/aidp/storage/csv_storage.rb +33 -7
- data/lib/aidp/storage/json_storage.rb +33 -10
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/workflows/guided_agent.rb +95 -22
- data/templates/implementation/simple_task.md +5 -0
- metadata +5 -2
- data/lib/aidp/debug_logger.rb +0 -195
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9a7dbc13b3136399f56fc64c00753506be8cbb35d5d3bf0f932799cc12a10504
|
|
4
|
+
data.tar.gz: 20afb73742ef4379f51fc05a9ae9cfb71ec95269856d79da0c0ce48c07c0aa39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 41837e458506b1dc31724b611d46792d446da2f9b0303a37ded28fddbb8f29cfbaeeb417fddc24a3f34a0ed40f5ef3b9d96bf6c827c548be92436ca5ead751c2
|
|
7
|
+
data.tar.gz: fd57d77e5f8a85c38b3343c4db7a96ec7764066c420e2810d650ef97b51b4d47461c6779d3d9d856baa6730e15a204708b0c0b151d2bc4c00b71d86df68f988d
|
data/README.md
CHANGED
|
@@ -20,11 +20,8 @@ aidp config --interactive
|
|
|
20
20
|
aidp init
|
|
21
21
|
# Creates LLM_STYLE_GUIDE.md, PROJECT_ANALYSIS.md, CODE_QUALITY_PLAN.md
|
|
22
22
|
|
|
23
|
-
# Start
|
|
24
|
-
aidp
|
|
25
|
-
|
|
26
|
-
# Or run in background
|
|
27
|
-
aidp execute --background
|
|
23
|
+
# Start Copilot interactive mode (default)
|
|
24
|
+
aidp
|
|
28
25
|
```
|
|
29
26
|
|
|
30
27
|
### First-Time Setup
|
|
@@ -58,16 +55,12 @@ AIDP implements **work loops** - an iterative execution pattern where AI agents
|
|
|
58
55
|
|
|
59
56
|
See [Work Loops Guide](docs/WORK_LOOPS_GUIDE.md) for details.
|
|
60
57
|
|
|
61
|
-
###
|
|
58
|
+
### Job Management
|
|
62
59
|
|
|
63
|
-
|
|
60
|
+
Monitor and control background jobs:
|
|
64
61
|
|
|
65
62
|
```bash
|
|
66
|
-
#
|
|
67
|
-
aidp execute --background
|
|
68
|
-
✓ Started background job: 20251005_235912_a1b2c3d4
|
|
69
|
-
|
|
70
|
-
# Monitor progress
|
|
63
|
+
# List and manage jobs
|
|
71
64
|
aidp jobs list # List all jobs
|
|
72
65
|
aidp jobs status <job_id> # Show job status
|
|
73
66
|
aidp jobs logs <job_id> --tail # View recent logs
|
|
@@ -102,17 +95,14 @@ aidp checkpoint history 20
|
|
|
102
95
|
|
|
103
96
|
## Command Reference
|
|
104
97
|
|
|
105
|
-
###
|
|
98
|
+
### Copilot Mode
|
|
106
99
|
|
|
107
100
|
```bash
|
|
108
|
-
#
|
|
109
|
-
aidp
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# Analyze mode - Analyze codebase
|
|
114
|
-
aidp analyze # Interactive analysis
|
|
115
|
-
aidp analyze --background # Background analysis
|
|
101
|
+
# Start interactive Copilot mode (default)
|
|
102
|
+
aidp # AI-guided workflow selection
|
|
103
|
+
|
|
104
|
+
# Copilot can perform both analysis and development based on your needs
|
|
105
|
+
# It will interactively help you choose the right approach
|
|
116
106
|
```
|
|
117
107
|
|
|
118
108
|
### Job Management
|
|
@@ -207,6 +197,21 @@ harness:
|
|
|
207
197
|
- "bundle exec rspec"
|
|
208
198
|
lint_commands:
|
|
209
199
|
- "bundle exec standardrb"
|
|
200
|
+
units:
|
|
201
|
+
deterministic:
|
|
202
|
+
- name: run_full_tests
|
|
203
|
+
command: "bundle exec rake spec"
|
|
204
|
+
enabled: false
|
|
205
|
+
next:
|
|
206
|
+
success: agentic
|
|
207
|
+
failure: decide_whats_next
|
|
208
|
+
- name: wait_for_github
|
|
209
|
+
type: "wait"
|
|
210
|
+
metadata:
|
|
211
|
+
interval_seconds: 60
|
|
212
|
+
defaults:
|
|
213
|
+
on_no_next_step: wait_for_github
|
|
214
|
+
fallback_agentic: decide_whats_next
|
|
210
215
|
|
|
211
216
|
providers:
|
|
212
217
|
claude:
|
|
@@ -329,40 +334,36 @@ The questions file is only created when the AI needs additional information beyo
|
|
|
329
334
|
### Standard Interactive Workflow
|
|
330
335
|
|
|
331
336
|
```bash
|
|
332
|
-
# Start
|
|
333
|
-
aidp
|
|
334
|
-
|
|
335
|
-
#
|
|
336
|
-
#
|
|
337
|
-
#
|
|
338
|
-
#
|
|
337
|
+
# Start Copilot mode (default)
|
|
338
|
+
aidp
|
|
339
|
+
|
|
340
|
+
# Copilot will guide you through:
|
|
341
|
+
# - Understanding your project goals
|
|
342
|
+
# - Selecting the right workflow (analysis, development, or both)
|
|
343
|
+
# - Answering questions about your requirements
|
|
344
|
+
# - Reviewing generated files (PRD, architecture, etc.)
|
|
345
|
+
# - Automatic execution with harness managing retries
|
|
339
346
|
```
|
|
340
347
|
|
|
341
|
-
###
|
|
348
|
+
### Project Analysis
|
|
342
349
|
|
|
343
350
|
```bash
|
|
344
|
-
#
|
|
345
|
-
aidp
|
|
346
|
-
✓ Started background job: 20251005_235912_a1b2c3d4
|
|
347
|
-
|
|
348
|
-
# Terminal 2: Watch progress in real-time
|
|
349
|
-
aidp checkpoint summary --watch
|
|
350
|
-
|
|
351
|
-
# Terminal 3: Monitor job status
|
|
352
|
-
aidp jobs status 20251005_235912_a1b2c3d4 --follow
|
|
351
|
+
# High-level project analysis and documentation
|
|
352
|
+
aidp init
|
|
353
353
|
|
|
354
|
-
#
|
|
355
|
-
|
|
356
|
-
|
|
354
|
+
# Creates:
|
|
355
|
+
# - LLM_STYLE_GUIDE.md
|
|
356
|
+
# - PROJECT_ANALYSIS.md
|
|
357
|
+
# - CODE_QUALITY_PLAN.md
|
|
357
358
|
```
|
|
358
359
|
|
|
359
|
-
###
|
|
360
|
+
### Progress Monitoring
|
|
360
361
|
|
|
361
362
|
```bash
|
|
362
|
-
#
|
|
363
|
-
aidp
|
|
363
|
+
# Watch progress in real-time
|
|
364
|
+
aidp checkpoint summary --watch
|
|
364
365
|
|
|
365
|
-
# Check
|
|
366
|
+
# Check job status
|
|
366
367
|
aidp jobs list
|
|
367
368
|
aidp checkpoint summary
|
|
368
369
|
```
|
data/lib/aidp/cli.rb
CHANGED
|
@@ -8,11 +8,13 @@ require_relative "harness/ui/enhanced_tui"
|
|
|
8
8
|
require_relative "harness/ui/enhanced_workflow_selector"
|
|
9
9
|
require_relative "harness/enhanced_runner"
|
|
10
10
|
require_relative "cli/first_run_wizard"
|
|
11
|
+
require_relative "rescue_logging"
|
|
11
12
|
|
|
12
13
|
module Aidp
|
|
13
14
|
# CLI interface for AIDP
|
|
14
15
|
class CLI
|
|
15
16
|
include Aidp::MessageDisplay
|
|
17
|
+
include Aidp::RescueLogging
|
|
16
18
|
|
|
17
19
|
# Simple options holder for instance methods (used in specs)
|
|
18
20
|
attr_accessor :options
|
|
@@ -126,6 +128,7 @@ module Aidp
|
|
|
126
128
|
{harness: {state: "unknown"}}
|
|
127
129
|
end
|
|
128
130
|
rescue => e
|
|
131
|
+
log_rescue(e, component: "cli", action: "fetch_harness_status", fallback: {harness: {state: "error"}}, mode: mode)
|
|
129
132
|
{harness: {state: "error", error: e.message}}
|
|
130
133
|
end
|
|
131
134
|
|
|
@@ -159,6 +162,10 @@ module Aidp
|
|
|
159
162
|
return 0
|
|
160
163
|
end
|
|
161
164
|
|
|
165
|
+
# Initialize logger from aidp.yml config
|
|
166
|
+
# Priority: ENV variable > aidp.yml > default (info)
|
|
167
|
+
setup_logging(Dir.pwd)
|
|
168
|
+
|
|
162
169
|
# Start the interactive TUI
|
|
163
170
|
display_message("AIDP initializing...", type: :info)
|
|
164
171
|
display_message(" Press Ctrl+C to stop\n", type: :highlight)
|
|
@@ -189,15 +196,15 @@ module Aidp
|
|
|
189
196
|
tui.start_display_loop
|
|
190
197
|
|
|
191
198
|
begin
|
|
192
|
-
#
|
|
193
|
-
|
|
199
|
+
# Copilot is now the default mode - no menu selection
|
|
200
|
+
# The guided workflow selector will internally choose appropriate mode
|
|
201
|
+
mode = :guided
|
|
194
202
|
|
|
195
203
|
# Get workflow configuration (no spinner - may wait for user input)
|
|
196
204
|
workflow_config = workflow_selector.select_workflow(harness_mode: false, mode: mode)
|
|
197
205
|
|
|
198
|
-
#
|
|
199
|
-
|
|
200
|
-
actual_mode = workflow_config[:mode] || mode
|
|
206
|
+
# Use the mode determined by the guided workflow selector
|
|
207
|
+
actual_mode = workflow_config[:mode] || :execute
|
|
201
208
|
|
|
202
209
|
# Pass workflow configuration to harness
|
|
203
210
|
harness_options = {
|
|
@@ -216,6 +223,7 @@ module Aidp
|
|
|
216
223
|
display_message("\n\n⏹️ Interrupted by user", type: :warning)
|
|
217
224
|
1
|
|
218
225
|
rescue => e
|
|
226
|
+
log_rescue(e, component: "cli", action: "run_harness", fallback: 1, mode: actual_mode)
|
|
219
227
|
display_message("\n❌ Error: #{e.message}", type: :error)
|
|
220
228
|
1
|
|
221
229
|
ensure
|
|
@@ -225,6 +233,29 @@ module Aidp
|
|
|
225
233
|
|
|
226
234
|
private
|
|
227
235
|
|
|
236
|
+
def setup_logging(project_dir)
|
|
237
|
+
# Load logging config from aidp.yml
|
|
238
|
+
config_path = File.join(project_dir, ".aidp", "aidp.yml")
|
|
239
|
+
logging_config = {}
|
|
240
|
+
|
|
241
|
+
if File.exist?(config_path)
|
|
242
|
+
require "yaml"
|
|
243
|
+
full_config = YAML.load_file(config_path)
|
|
244
|
+
logging_config = full_config["logging"] || full_config[:logging] || {}
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Set up logger with config (ENV variable AIDP_LOG_LEVEL takes precedence)
|
|
248
|
+
Aidp.setup_logger(project_dir, logging_config)
|
|
249
|
+
|
|
250
|
+
# Log initialization
|
|
251
|
+
Aidp.logger.info("cli", "AIDP starting", version: Aidp::VERSION, log_level: Aidp.logger.level)
|
|
252
|
+
rescue => e
|
|
253
|
+
log_rescue(e, component: "cli", action: "setup_logger", fallback: "default_config", project_dir: project_dir)
|
|
254
|
+
# If logging setup fails, continue with default logger
|
|
255
|
+
Aidp.setup_logger(project_dir, {})
|
|
256
|
+
Aidp.logger.warn("cli", "Failed to load logging config, using defaults", error: e.message)
|
|
257
|
+
end
|
|
258
|
+
|
|
228
259
|
def parse_options(args)
|
|
229
260
|
options = {}
|
|
230
261
|
|
|
@@ -234,8 +265,7 @@ module Aidp
|
|
|
234
265
|
opts.separator "AI Development Pipeline - Autonomous development workflow automation"
|
|
235
266
|
opts.separator ""
|
|
236
267
|
opts.separator "Commands:"
|
|
237
|
-
opts.separator "
|
|
238
|
-
opts.separator " execute [--background] Start execute mode workflow"
|
|
268
|
+
opts.separator " (no command) Start Copilot interactive mode (default)"
|
|
239
269
|
opts.separator " init Analyse project and bootstrap quality docs"
|
|
240
270
|
opts.separator " watch <issues_url> Run fully automatic watch mode"
|
|
241
271
|
opts.separator " status Show current system status"
|
|
@@ -271,9 +301,12 @@ module Aidp
|
|
|
271
301
|
|
|
272
302
|
opts.separator ""
|
|
273
303
|
opts.separator "Examples:"
|
|
274
|
-
opts.separator " # Start
|
|
275
|
-
opts.separator " aidp
|
|
276
|
-
opts.separator "
|
|
304
|
+
opts.separator " # Start interactive Copilot mode"
|
|
305
|
+
opts.separator " aidp"
|
|
306
|
+
opts.separator ""
|
|
307
|
+
opts.separator " # Project bootstrap"
|
|
308
|
+
opts.separator " aidp init # High-level analysis and docs"
|
|
309
|
+
opts.separator " aidp config --interactive # Configure providers"
|
|
277
310
|
opts.separator ""
|
|
278
311
|
opts.separator " # Monitor background jobs"
|
|
279
312
|
opts.separator " aidp jobs list # List all jobs"
|
|
@@ -284,20 +317,14 @@ module Aidp
|
|
|
284
317
|
opts.separator " aidp checkpoint summary --watch # Auto-refresh every 5s"
|
|
285
318
|
opts.separator " aidp checkpoint summary --watch --interval 10"
|
|
286
319
|
opts.separator ""
|
|
287
|
-
opts.separator " # Project bootstrap"
|
|
288
|
-
opts.separator " aidp init"
|
|
289
|
-
opts.separator " aidp config --interactive"
|
|
290
320
|
opts.separator " # Fully automatic orchestration"
|
|
291
|
-
opts.separator ""
|
|
292
321
|
opts.separator " aidp watch https://github.com/<org>/<repo>/issues"
|
|
293
322
|
opts.separator " aidp watch owner/repo --interval 120 --provider claude"
|
|
294
323
|
opts.separator ""
|
|
295
324
|
opts.separator " # Other commands"
|
|
296
325
|
opts.separator " aidp providers # Check provider health"
|
|
297
326
|
opts.separator " aidp providers info claude # Show detailed provider info"
|
|
298
|
-
opts.separator " aidp providers refresh # Refresh all provider info"
|
|
299
327
|
opts.separator " aidp mcp # Show MCP server dashboard"
|
|
300
|
-
opts.separator " aidp mcp check dash-api filesystem # Check provider eligibility"
|
|
301
328
|
opts.separator " aidp checkpoint history 20 # Show last 20 checkpoints"
|
|
302
329
|
opts.separator ""
|
|
303
330
|
opts.separator "For more information, visit: https://github.com/viamin/aidp"
|
|
@@ -311,7 +338,7 @@ module Aidp
|
|
|
311
338
|
# Determine if the invocation is a subcommand style call
|
|
312
339
|
def subcommand?(args)
|
|
313
340
|
return false if args.nil? || args.empty?
|
|
314
|
-
%w[status jobs kb harness
|
|
341
|
+
%w[status jobs kb harness providers checkpoint mcp issue config init watch].include?(args.first)
|
|
315
342
|
end
|
|
316
343
|
|
|
317
344
|
def run_subcommand(args)
|
|
@@ -321,8 +348,6 @@ module Aidp
|
|
|
321
348
|
when "jobs" then run_jobs_command(args)
|
|
322
349
|
when "kb" then run_kb_command(args)
|
|
323
350
|
when "harness" then run_harness_command(args)
|
|
324
|
-
when "execute" then run_execute_command(args)
|
|
325
|
-
when "analyze" then run_execute_command(args, mode: :analyze) # symmetry
|
|
326
351
|
when "providers" then run_providers_command(args)
|
|
327
352
|
when "checkpoint" then run_checkpoint_command(args)
|
|
328
353
|
when "mcp" then run_mcp_command(args)
|
|
@@ -699,6 +724,7 @@ module Aidp
|
|
|
699
724
|
table = TTY::Table.new header, table_rows
|
|
700
725
|
display_message(table.render(:basic), type: :info)
|
|
701
726
|
rescue => e
|
|
727
|
+
log_rescue(e, component: "cli", action: "display_provider_health", fallback: "error_message")
|
|
702
728
|
display_message("Failed to display provider health: #{e.message}", type: :error)
|
|
703
729
|
end
|
|
704
730
|
|
|
@@ -891,25 +917,6 @@ module Aidp
|
|
|
891
917
|
mode&.to_sym
|
|
892
918
|
end
|
|
893
919
|
|
|
894
|
-
def select_mode_interactive(tui)
|
|
895
|
-
mode_options = [
|
|
896
|
-
"🤖 Guided Workflow (Copilot) - AI helps you choose the right workflow",
|
|
897
|
-
"🔬 Analyze Mode - Analyze your codebase for insights and recommendations",
|
|
898
|
-
"🏗️ Execute Mode - Build new features with guided development workflow"
|
|
899
|
-
]
|
|
900
|
-
selected = tui.single_select("Welcome to AI Dev Pipeline! Choose your mode", mode_options, default: 1)
|
|
901
|
-
# Announce mode explicitly in headless contexts (handled internally otherwise)
|
|
902
|
-
if (defined?(RSpec) || ENV["RSPEC_RUNNING"]) && tui.respond_to?(:announce_mode)
|
|
903
|
-
tui.announce_mode(:guided) if selected == mode_options[0]
|
|
904
|
-
tui.announce_mode(:analyze) if selected == mode_options[1]
|
|
905
|
-
tui.announce_mode(:execute) if selected == mode_options[2]
|
|
906
|
-
end
|
|
907
|
-
return :guided if selected == mode_options[0]
|
|
908
|
-
return :analyze if selected == mode_options[1]
|
|
909
|
-
return :execute if selected == mode_options[2]
|
|
910
|
-
:analyze
|
|
911
|
-
end
|
|
912
|
-
|
|
913
920
|
def display_harness_result(result)
|
|
914
921
|
case result[:status]
|
|
915
922
|
when "completed"
|
|
@@ -1049,6 +1056,7 @@ module Aidp
|
|
|
1049
1056
|
)
|
|
1050
1057
|
runner.start
|
|
1051
1058
|
rescue ArgumentError => e
|
|
1059
|
+
log_rescue(e, component: "cli", action: "start_watch_command", fallback: "error_display")
|
|
1052
1060
|
display_message("❌ #{e.message}", type: :error)
|
|
1053
1061
|
end
|
|
1054
1062
|
|
data/lib/aidp/debug_mixin.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "debug_logger"
|
|
4
|
-
|
|
5
3
|
module Aidp
|
|
6
4
|
# Mixin module for easy debug integration across the codebase
|
|
7
5
|
module DebugMixin
|
|
@@ -27,7 +25,7 @@ module Aidp
|
|
|
27
25
|
|
|
28
26
|
# Shared logger instance across all classes using DebugMixin
|
|
29
27
|
def self.shared_logger
|
|
30
|
-
|
|
28
|
+
Aidp.logger
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
# Instance-level debug methods
|
|
@@ -56,7 +54,8 @@ module Aidp
|
|
|
56
54
|
def debug_log(message, level: :info, data: nil)
|
|
57
55
|
return unless debug_enabled?
|
|
58
56
|
|
|
59
|
-
debug_logger.log(
|
|
57
|
+
debug_logger.log(level, component_name, message, **data) if data
|
|
58
|
+
debug_logger.log(level, component_name, message) unless data
|
|
60
59
|
end
|
|
61
60
|
|
|
62
61
|
# Log command execution with debug details
|
|
@@ -65,30 +64,30 @@ module Aidp
|
|
|
65
64
|
|
|
66
65
|
command_str = [cmd, *args].join(" ")
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
debug_logger.info(component_name, "🔧 Executing command: #{command_str}")
|
|
69
68
|
|
|
70
69
|
if input
|
|
71
70
|
if input.is_a?(String) && input.length > 200
|
|
72
71
|
# If input is long, show first 100 chars and indicate it's truncated
|
|
73
|
-
|
|
72
|
+
debug_logger.info(component_name, "📝 Input (truncated): #{input[0..100]}...")
|
|
74
73
|
elsif input.is_a?(String) && File.exist?(input)
|
|
75
|
-
|
|
74
|
+
debug_logger.info(component_name, "📝 Input file: #{input}")
|
|
76
75
|
else
|
|
77
|
-
|
|
76
|
+
debug_logger.info(component_name, "📝 Input: #{input}")
|
|
78
77
|
end
|
|
79
78
|
end
|
|
80
79
|
|
|
81
80
|
if error && !error.empty?
|
|
82
|
-
|
|
81
|
+
debug_logger.error(component_name, "❌ Error output: #{error}")
|
|
83
82
|
end
|
|
84
83
|
|
|
85
84
|
if debug_verbose?
|
|
86
85
|
if output && !output.empty?
|
|
87
|
-
|
|
86
|
+
debug_logger.debug(component_name, "📤 Output: #{output}")
|
|
88
87
|
end
|
|
89
88
|
|
|
90
89
|
if exit_code
|
|
91
|
-
|
|
90
|
+
debug_logger.debug(component_name, "🏁 Exit code: #{exit_code}")
|
|
92
91
|
end
|
|
93
92
|
end
|
|
94
93
|
end
|
|
@@ -98,25 +97,15 @@ module Aidp
|
|
|
98
97
|
return unless debug_basic?
|
|
99
98
|
|
|
100
99
|
message = "🔄 #{action}: #{step_name}"
|
|
101
|
-
|
|
102
|
-
detail_str = details.map { |k, v| "#{k}=#{v}" }.join(", ")
|
|
103
|
-
message += " (#{detail_str})"
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
debug_log(message, level: :info, data: details)
|
|
100
|
+
debug_logger.info(component_name, message, **details)
|
|
107
101
|
end
|
|
108
102
|
|
|
109
103
|
# Log provider interaction
|
|
110
104
|
def debug_provider(provider_name, action, details = {})
|
|
111
105
|
return unless debug_basic?
|
|
112
106
|
|
|
113
|
-
message = "🤖 #{
|
|
114
|
-
|
|
115
|
-
detail_str = details.map { |k, v| "#{k}=#{v}" }.join(", ")
|
|
116
|
-
message += " (#{detail_str})"
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
debug_log(message, level: :info, data: details)
|
|
107
|
+
message = "🤖 #{action}"
|
|
108
|
+
debug_logger.info("provider_#{provider_name}", message, **details)
|
|
120
109
|
end
|
|
121
110
|
|
|
122
111
|
# Log error with debug context
|
|
@@ -124,10 +113,10 @@ module Aidp
|
|
|
124
113
|
return unless debug_basic?
|
|
125
114
|
|
|
126
115
|
error_message = "💥 Error: #{error.class.name}: #{error.message}"
|
|
127
|
-
|
|
116
|
+
debug_logger.error(component_name, error_message, error: error.class.name, **context)
|
|
128
117
|
|
|
129
118
|
if debug_verbose? && error.backtrace
|
|
130
|
-
|
|
119
|
+
debug_logger.debug(component_name, "📍 Backtrace: #{error.backtrace.first(5).join("\n")}")
|
|
131
120
|
end
|
|
132
121
|
end
|
|
133
122
|
|
|
@@ -136,12 +125,7 @@ module Aidp
|
|
|
136
125
|
return unless debug_verbose?
|
|
137
126
|
|
|
138
127
|
message = "⏱️ #{operation}: #{duration.round(2)}s"
|
|
139
|
-
|
|
140
|
-
detail_str = details.map { |k, v| "#{k}=#{v}" }.join(", ")
|
|
141
|
-
message += " (#{detail_str})"
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
debug_log(message, level: :info, data: {duration: duration, details: details})
|
|
128
|
+
debug_logger.debug(component_name, message, duration: duration, **details)
|
|
145
129
|
end
|
|
146
130
|
|
|
147
131
|
# Execute command with debug logging
|
|
@@ -151,7 +135,7 @@ module Aidp
|
|
|
151
135
|
command_str = [cmd, *args].join(" ")
|
|
152
136
|
start_time = Time.now
|
|
153
137
|
|
|
154
|
-
|
|
138
|
+
debug_logger.info(component_name, "🚀 Starting command execution: #{command_str}")
|
|
155
139
|
|
|
156
140
|
begin
|
|
157
141
|
# Configure printer based on streaming mode
|
|
@@ -190,5 +174,22 @@ module Aidp
|
|
|
190
174
|
raise
|
|
191
175
|
end
|
|
192
176
|
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
# Safely derive a component name for logging (memoized).
|
|
181
|
+
# Handles anonymous classes and modules gracefully.
|
|
182
|
+
def component_name
|
|
183
|
+
@component_name ||= begin
|
|
184
|
+
klass = self.class
|
|
185
|
+
name = klass.name
|
|
186
|
+
return "anonymous" unless name && !name.empty?
|
|
187
|
+
# Take the last constant segment, normalize to snake-ish lowercase
|
|
188
|
+
segment = name.split("::").last
|
|
189
|
+
segment.gsub(/([a-z\d])([A-Z])/, '\\1_\\2').downcase
|
|
190
|
+
rescue
|
|
191
|
+
"anonymous"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
193
194
|
end
|
|
194
195
|
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aidp
|
|
4
|
+
module Execute
|
|
5
|
+
module AgentSignalParser
|
|
6
|
+
def self.extract_next_unit(output)
|
|
7
|
+
return nil unless output
|
|
8
|
+
|
|
9
|
+
output.to_s.each_line do |line|
|
|
10
|
+
token = token_from_line(line)
|
|
11
|
+
next unless token
|
|
12
|
+
|
|
13
|
+
return normalize_token(token)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.normalize_token(raw)
|
|
20
|
+
return nil if raw.nil? || raw.empty?
|
|
21
|
+
|
|
22
|
+
token = raw.downcase.strip
|
|
23
|
+
token.gsub!(/\s+/, "_")
|
|
24
|
+
token.to_sym
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.token_from_line(line)
|
|
28
|
+
return nil unless line
|
|
29
|
+
|
|
30
|
+
trimmed = line.lstrip
|
|
31
|
+
separator_index = trimmed.index(":") || trimmed.index("=")
|
|
32
|
+
return nil unless separator_index
|
|
33
|
+
|
|
34
|
+
key = trimmed[0...separator_index].strip
|
|
35
|
+
value = trimmed[(separator_index + 1)..]&.strip
|
|
36
|
+
|
|
37
|
+
return nil unless key && value
|
|
38
|
+
return value if key.casecmp("next_unit").zero? || key.casecmp("next_step").zero?
|
|
39
|
+
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private_class_method :token_from_line
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "work_loop_runner"
|
|
4
4
|
require_relative "work_loop_state"
|
|
5
5
|
require_relative "instruction_queue"
|
|
6
|
+
require_relative "../rescue_logging"
|
|
6
7
|
|
|
7
8
|
module Aidp
|
|
8
9
|
module Execute
|
|
@@ -16,6 +17,8 @@ module Aidp
|
|
|
16
17
|
# - Stream output to main thread for display
|
|
17
18
|
# - Handle graceful cancellation with checkpoint save
|
|
18
19
|
class AsyncWorkLoopRunner
|
|
20
|
+
include Aidp::RescueLogging
|
|
21
|
+
|
|
19
22
|
attr_reader :state, :instruction_queue, :work_thread
|
|
20
23
|
|
|
21
24
|
def initialize(project_dir, provider_manager, config, options = {})
|
|
@@ -42,6 +45,7 @@ module Aidp
|
|
|
42
45
|
@work_thread = Thread.new do
|
|
43
46
|
run_async_loop
|
|
44
47
|
rescue => e
|
|
48
|
+
log_rescue(e, component: "async_work_loop_runner", action: "thread_execution", fallback: "error_state", step: @step_name)
|
|
45
49
|
@state.error!(e)
|
|
46
50
|
@state.append_output("Work loop error: #{e.message}", type: :error)
|
|
47
51
|
ensure
|
|
@@ -149,6 +153,7 @@ module Aidp
|
|
|
149
153
|
|
|
150
154
|
result
|
|
151
155
|
rescue => e
|
|
156
|
+
log_rescue(e, component: "async_work_loop_runner", action: "run_async_loop", fallback: "error_state", step: @step_name, iteration: @state.iteration)
|
|
152
157
|
@state.error!(e)
|
|
153
158
|
@state.append_output("Error in work loop: #{e.message}\n#{e.backtrace.first(3).join("\n")}", type: :error)
|
|
154
159
|
raise
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
require "yaml"
|
|
4
4
|
require "time"
|
|
5
5
|
require "json"
|
|
6
|
+
require "aidp/rescue_logging"
|
|
6
7
|
|
|
7
8
|
module Aidp
|
|
8
9
|
module Execute
|
|
9
10
|
# Manages periodic checkpoints during work loop execution
|
|
10
11
|
# Tracks progress metrics, code quality, and task completion
|
|
11
12
|
class Checkpoint
|
|
13
|
+
include Aidp::RescueLogging
|
|
14
|
+
|
|
12
15
|
attr_reader :project_dir, :checkpoint_file, :history_file
|
|
13
16
|
|
|
14
17
|
def initialize(project_dir)
|
|
@@ -104,7 +107,11 @@ module Aidp
|
|
|
104
107
|
end
|
|
105
108
|
|
|
106
109
|
total_lines
|
|
107
|
-
rescue
|
|
110
|
+
rescue => e
|
|
111
|
+
log_rescue(e,
|
|
112
|
+
component: "checkpoint",
|
|
113
|
+
action: "count_lines_of_code",
|
|
114
|
+
fallback: 0)
|
|
108
115
|
0
|
|
109
116
|
end
|
|
110
117
|
|
|
@@ -121,7 +128,11 @@ module Aidp
|
|
|
121
128
|
end
|
|
122
129
|
|
|
123
130
|
count
|
|
124
|
-
rescue
|
|
131
|
+
rescue => e
|
|
132
|
+
log_rescue(e,
|
|
133
|
+
component: "checkpoint",
|
|
134
|
+
action: "count_project_files",
|
|
135
|
+
fallback: 0)
|
|
125
136
|
0
|
|
126
137
|
end
|
|
127
138
|
|
|
@@ -134,7 +145,11 @@ module Aidp
|
|
|
134
145
|
|
|
135
146
|
coverage_ratio = (test_files.to_f / source_files * 100).round(2)
|
|
136
147
|
[coverage_ratio, 100].min
|
|
137
|
-
rescue
|
|
148
|
+
rescue => e
|
|
149
|
+
log_rescue(e,
|
|
150
|
+
component: "checkpoint",
|
|
151
|
+
action: "estimate_test_coverage",
|
|
152
|
+
fallback: 0)
|
|
138
153
|
0
|
|
139
154
|
end
|
|
140
155
|
|
|
@@ -173,7 +188,11 @@ module Aidp
|
|
|
173
188
|
offense_count = data["summary"]["offense_count"] || 0
|
|
174
189
|
# Simple scoring: fewer offenses = higher score
|
|
175
190
|
[100 - (offense_count / total_files.to_f * 10), 0].max.round(2)
|
|
176
|
-
rescue
|
|
191
|
+
rescue => e
|
|
192
|
+
log_rescue(e,
|
|
193
|
+
component: "checkpoint",
|
|
194
|
+
action: "run_rubocop_check",
|
|
195
|
+
fallback: nil)
|
|
177
196
|
nil
|
|
178
197
|
end
|
|
179
198
|
|
|
@@ -191,7 +210,11 @@ module Aidp
|
|
|
191
210
|
return 0 if total_tasks == 0
|
|
192
211
|
|
|
193
212
|
(completed_tasks.to_f / total_tasks * 100).round(2)
|
|
194
|
-
rescue
|
|
213
|
+
rescue => e
|
|
214
|
+
log_rescue(e,
|
|
215
|
+
component: "checkpoint",
|
|
216
|
+
action: "calculate_prd_task_progress",
|
|
217
|
+
fallback: 0)
|
|
195
218
|
0
|
|
196
219
|
end
|
|
197
220
|
|