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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d97cff94f784545b96549c70d910e913bf19a7c94b908e45dae2a999c57e45b
4
- data.tar.gz: 170bf8fe45dbb081cad38ef69eb8a0f58b962d495ed300b3d58d3f78ef553462
3
+ metadata.gz: 9a7dbc13b3136399f56fc64c00753506be8cbb35d5d3bf0f932799cc12a10504
4
+ data.tar.gz: 20afb73742ef4379f51fc05a9ae9cfb71ec95269856d79da0c0ce48c07c0aa39
5
5
  SHA512:
6
- metadata.gz: a371614e261335e71b6e78cbe6d6410f26f03a4910e37e6b4102d3681fc9ef2abf617a8f4199b918f8efcdb43fc978a3eef9c1d04aa485297af90394bd34cbd8
7
- data.tar.gz: 549e21d089121d0212698307bd8ed520499452ad829ff70e8ca1dea7fd50b6c63db9be2a55d4b56c9c60d822703710e84f57f91354bad8892e7367347e6b7777
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 an interactive workflow
24
- aidp execute
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
- ### Background Execution
58
+ ### Job Management
62
59
 
63
- Run workflows in the background while monitoring progress from separate terminals:
60
+ Monitor and control background jobs:
64
61
 
65
62
  ```bash
66
- # Start in background
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
- ### Execution Modes
98
+ ### Copilot Mode
106
99
 
107
100
  ```bash
108
- # Execute mode - Build new features
109
- aidp execute # Interactive workflow selection
110
- aidp execute --background # Run in background
111
- aidp execute --background --follow # Start and follow logs
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 execute mode
333
- aidp execute
334
-
335
- # Select workflow type (e.g., "Full PRD to Implementation")
336
- # Answer any questions interactively
337
- # Review generated files (PRD, architecture, etc.)
338
- # Workflow runs automatically with harness managing retries
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
- ### Background Workflow with Monitoring
348
+ ### Project Analysis
342
349
 
343
350
  ```bash
344
- # Terminal 1: Start background execution
345
- aidp execute --background
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
- # Later: Check final results
355
- aidp checkpoint summary
356
- aidp jobs logs 20251005_235912_a1b2c3d4 --tail
354
+ # Creates:
355
+ # - LLM_STYLE_GUIDE.md
356
+ # - PROJECT_ANALYSIS.md
357
+ # - CODE_QUALITY_PLAN.md
357
358
  ```
358
359
 
359
- ### Quick Analysis
360
+ ### Progress Monitoring
360
361
 
361
362
  ```bash
362
- # Run analysis in background
363
- aidp analyze --background
363
+ # Watch progress in real-time
364
+ aidp checkpoint summary --watch
364
365
 
365
- # Check progress
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
- # First question: Choose mode
193
- mode = select_mode_interactive(tui)
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
- # For guided mode, use the mode determined by the guided workflow selector
199
- # Otherwise use the initially selected mode
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 " analyze [--background] Start analyze mode workflow"
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 background execution"
275
- opts.separator " aidp execute --background"
276
- opts.separator " aidp execute --background --follow # Start and follow logs"
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 execute analyze providers checkpoint mcp issue config init watch].include?(args.first)
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
 
@@ -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
- @shared_logger ||= Aidp::DebugLogger.new
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(message, level: level, data: data)
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
- debug_log("🔧 Executing command: #{command_str}", level: :info)
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
- debug_log("📝 Input (truncated): #{input[0..100]}...", level: :info)
72
+ debug_logger.info(component_name, "📝 Input (truncated): #{input[0..100]}...")
74
73
  elsif input.is_a?(String) && File.exist?(input)
75
- debug_log("📝 Input file: #{input}", level: :info)
74
+ debug_logger.info(component_name, "📝 Input file: #{input}")
76
75
  else
77
- debug_log("📝 Input: #{input}", level: :info)
76
+ debug_logger.info(component_name, "📝 Input: #{input}")
78
77
  end
79
78
  end
80
79
 
81
80
  if error && !error.empty?
82
- debug_log("❌ Error output: #{error}", level: :error)
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
- debug_log("📤 Output: #{output}", level: :info)
86
+ debug_logger.debug(component_name, "📤 Output: #{output}")
88
87
  end
89
88
 
90
89
  if exit_code
91
- debug_log("🏁 Exit code: #{exit_code}", level: :info)
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
- if details.any?
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 = "🤖 #{provider_name}: #{action}"
114
- if details.any?
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
- debug_log(error_message, level: :error, data: {error: error, context: context})
116
+ debug_logger.error(component_name, error_message, error: error.class.name, **context)
128
117
 
129
118
  if debug_verbose? && error.backtrace
130
- debug_log("📍 Backtrace: #{error.backtrace.first(5).join("\n")}", level: :error)
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
- if details.any?
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
- debug_log("🚀 Starting command execution: #{command_str}", level: :info)
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