aidp 0.33.0 → 0.34.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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -0
  3. data/lib/aidp/analyze/tree_sitter_scan.rb +3 -0
  4. data/lib/aidp/cli/eval_command.rb +399 -0
  5. data/lib/aidp/cli/harness_command.rb +1 -1
  6. data/lib/aidp/cli/security_command.rb +416 -0
  7. data/lib/aidp/cli/tools_command.rb +6 -4
  8. data/lib/aidp/cli.rb +170 -3
  9. data/lib/aidp/concurrency/exec.rb +3 -0
  10. data/lib/aidp/config.rb +113 -0
  11. data/lib/aidp/config_paths.rb +20 -0
  12. data/lib/aidp/daemon/runner.rb +8 -4
  13. data/lib/aidp/errors.rb +134 -0
  14. data/lib/aidp/evaluations/context_capture.rb +205 -0
  15. data/lib/aidp/evaluations/evaluation_record.rb +114 -0
  16. data/lib/aidp/evaluations/evaluation_storage.rb +250 -0
  17. data/lib/aidp/evaluations.rb +23 -0
  18. data/lib/aidp/execute/async_work_loop_runner.rb +4 -1
  19. data/lib/aidp/execute/interactive_repl.rb +6 -2
  20. data/lib/aidp/execute/prompt_evaluator.rb +359 -0
  21. data/lib/aidp/execute/repl_macros.rb +100 -1
  22. data/lib/aidp/execute/work_loop_runner.rb +399 -47
  23. data/lib/aidp/execute/work_loop_state.rb +4 -1
  24. data/lib/aidp/execute/workflow_selector.rb +3 -0
  25. data/lib/aidp/harness/ai_decision_engine.rb +79 -0
  26. data/lib/aidp/harness/capability_registry.rb +2 -0
  27. data/lib/aidp/harness/condition_detector.rb +3 -0
  28. data/lib/aidp/harness/config_loader.rb +3 -0
  29. data/lib/aidp/harness/enhanced_runner.rb +14 -11
  30. data/lib/aidp/harness/error_handler.rb +3 -0
  31. data/lib/aidp/harness/provider_factory.rb +3 -0
  32. data/lib/aidp/harness/provider_manager.rb +6 -0
  33. data/lib/aidp/harness/runner.rb +5 -1
  34. data/lib/aidp/harness/state/persistence.rb +3 -0
  35. data/lib/aidp/harness/state_manager.rb +3 -0
  36. data/lib/aidp/harness/status_display.rb +28 -20
  37. data/lib/aidp/harness/thinking_depth_manager.rb +32 -32
  38. data/lib/aidp/harness/ui/enhanced_tui.rb +4 -0
  39. data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +4 -0
  40. data/lib/aidp/harness/ui/error_handler.rb +3 -0
  41. data/lib/aidp/harness/ui/job_monitor.rb +4 -0
  42. data/lib/aidp/harness/ui/navigation/submenu.rb +2 -0
  43. data/lib/aidp/harness/ui/navigation/workflow_selector.rb +6 -0
  44. data/lib/aidp/harness/ui/spinner_helper.rb +3 -0
  45. data/lib/aidp/harness/ui/workflow_controller.rb +3 -0
  46. data/lib/aidp/harness/user_interface.rb +3 -0
  47. data/lib/aidp/loader.rb +2 -2
  48. data/lib/aidp/logger.rb +3 -0
  49. data/lib/aidp/message_display.rb +31 -0
  50. data/lib/aidp/pr_worktree_manager.rb +18 -6
  51. data/lib/aidp/provider_manager.rb +3 -0
  52. data/lib/aidp/providers/base.rb +2 -0
  53. data/lib/aidp/security/rule_of_two_enforcer.rb +210 -0
  54. data/lib/aidp/security/secrets_proxy.rb +328 -0
  55. data/lib/aidp/security/secrets_registry.rb +227 -0
  56. data/lib/aidp/security/trifecta_state.rb +220 -0
  57. data/lib/aidp/security/watch_mode_handler.rb +306 -0
  58. data/lib/aidp/security/work_loop_adapter.rb +277 -0
  59. data/lib/aidp/security.rb +56 -0
  60. data/lib/aidp/setup/wizard.rb +4 -2
  61. data/lib/aidp/version.rb +1 -1
  62. data/lib/aidp/watch/auto_merger.rb +274 -0
  63. data/lib/aidp/watch/auto_pr_processor.rb +125 -7
  64. data/lib/aidp/watch/build_processor.rb +16 -1
  65. data/lib/aidp/watch/change_request_processor.rb +680 -286
  66. data/lib/aidp/watch/ci_fix_processor.rb +262 -4
  67. data/lib/aidp/watch/feedback_collector.rb +191 -0
  68. data/lib/aidp/watch/hierarchical_pr_strategy.rb +256 -0
  69. data/lib/aidp/watch/implementation_verifier.rb +142 -1
  70. data/lib/aidp/watch/plan_generator.rb +70 -13
  71. data/lib/aidp/watch/plan_processor.rb +12 -5
  72. data/lib/aidp/watch/projects_processor.rb +286 -0
  73. data/lib/aidp/watch/repository_client.rb +861 -53
  74. data/lib/aidp/watch/review_processor.rb +33 -6
  75. data/lib/aidp/watch/runner.rb +51 -11
  76. data/lib/aidp/watch/state_store.rb +233 -0
  77. data/lib/aidp/watch/sub_issue_creator.rb +221 -0
  78. data/lib/aidp/workflows/guided_agent.rb +4 -0
  79. data/lib/aidp/workstream_executor.rb +3 -0
  80. data/lib/aidp/worktree.rb +61 -11
  81. data/lib/aidp/worktree_branch_manager.rb +347 -101
  82. data/templates/implementation/iterative_implementation.md +46 -3
  83. metadata +20 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e0f9ea4164fa6ae0228b03ec99af6a60a03c60fbde12103b4b06211c11236e3
4
- data.tar.gz: 180c772109f7598583881b207ef5d55bd098c13e46e3bd4c0616bfd333b54185
3
+ metadata.gz: c4c9ad1d807359d816adfa79c71deb42fedce7158f782279366dffeee6b45179
4
+ data.tar.gz: 12bbe406911ad596b2b55dfa450a3841804e51417252fd9e3212a41ca0f4b88d
5
5
  SHA512:
6
- metadata.gz: 19ec209b57133e5dd6c67ad8979e4feb268d567baa3e0044b41b7390587e732009b922d62b77e5a07dfeb2dbb901b997e91a9b1b9fe47dab6349b6de937bfd9d
7
- data.tar.gz: b5e721ed8596e489f62720e4ac299403c2b1467f7a43a87233146c2091033feda55de9efc648c2f0835d1b829a82a79115b3e05c82a560886660b6bb727711bf
6
+ metadata.gz: aabaf9b483b9031e2180a6b1dd9c9d94c7c24bcd6a67a7baf45a6b3bb97d48abbde29295b80a58a0f1d5ed3bfb37290f01acc463fa87004da2323a4e8c3dc44a
7
+ data.tar.gz: 720a3d31ee8b827312db11ac85c08cd212caf7da566a30678be88f4e0a56cd46c895b3b6f0027fcf2d2b85b1bfe5c4935c6a8593f1f97d480ea736a4871ca2bc
data/README.md CHANGED
@@ -224,6 +224,41 @@ Analyze existing codebase and create user research plan:
224
224
 
225
225
  See [Agile Development Mode Guide](docs/AGILE_MODE_GUIDE.md) for complete documentation.
226
226
 
227
+ ### GitHub Projects V2 Integration
228
+
229
+ AIDP integrates with GitHub Projects V2 for hierarchical issue management and automated PR workflows:
230
+
231
+ ```bash
232
+ # Start watch mode with projects integration
233
+ aidp watch owner/repo
234
+
235
+ # Issues with aidp-plan label are automatically:
236
+ # 1. Analyzed for complexity
237
+ # 2. Broken into sub-issues (if large)
238
+ # 3. Linked to your GitHub Project
239
+ # 4. Implemented with hierarchical PRs
240
+ ```
241
+
242
+ **Key Features:**
243
+
244
+ - **Hierarchical Planning** - Large issues automatically decomposed into manageable sub-issues
245
+ - **Project Board Sync** - Issues and status automatically synced to GitHub Projects V2
246
+ - **Sub-Issue PRs** - Each sub-issue gets its own PR targeting the parent branch
247
+ - **Auto-Merge** - Sub-issue PRs auto-merge when CI passes
248
+ - **Parent PR Aggregation** - Parent PR shows all completed work for final review
249
+
250
+ **Branch Strategy:**
251
+
252
+ ```text
253
+ main
254
+ └── aidp/parent-123-feature
255
+ ├── aidp/sub-123-124-component-a
256
+ ├── aidp/sub-123-125-component-b
257
+ └── aidp/sub-123-126-component-c
258
+ ```
259
+
260
+ See [GitHub Projects Guide](docs/GITHUB_PROJECTS.md) for complete documentation.
261
+
227
262
  ### Job Management
228
263
 
229
264
  Monitor and control background jobs:
@@ -14,6 +14,9 @@ module Aidp
14
14
  class TreeSitterScan
15
15
  include Aidp::MessageDisplay
16
16
 
17
+ # Expose state for testability
18
+ attr_accessor :symbols, :imports, :calls, :metrics, :seams, :hotspots, :tests, :cycles
19
+
17
20
  def initialize(root: Dir.pwd, kb_dir: ".aidp/kb", langs: %w[ruby], threads: Etc.nprocessors, prompt: TTY::Prompt.new)
18
21
  @root = File.expand_path(root)
19
22
  @kb_dir = File.expand_path(kb_dir, @root)
@@ -0,0 +1,399 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tty-prompt"
4
+ require "tty-table"
5
+ require_relative "../evaluations"
6
+ require_relative "../message_display"
7
+
8
+ module Aidp
9
+ class CLI
10
+ # Command handler for `aidp eval` subcommand
11
+ #
12
+ # Provides commands for managing evaluations:
13
+ # - list: List recent evaluations
14
+ # - view <id>: View details of a specific evaluation
15
+ # - stats: Show evaluation statistics
16
+ # - add <rating>: Add a new evaluation
17
+ # - clear: Clear all evaluation data
18
+ #
19
+ # Usage:
20
+ # aidp eval list
21
+ # aidp eval list --rating good
22
+ # aidp eval view eval_20241115_123456_abc1
23
+ # aidp eval stats
24
+ # aidp eval add good "Great output"
25
+ # aidp eval clear --force
26
+ class EvalCommand
27
+ include Aidp::MessageDisplay
28
+
29
+ def initialize(prompt: TTY::Prompt.new, storage: nil, project_dir: nil)
30
+ @prompt = prompt
31
+ @project_dir = project_dir || Dir.pwd
32
+ @storage = storage || Aidp::Evaluations::EvaluationStorage.new(project_dir: @project_dir)
33
+
34
+ Aidp.log_debug("eval_command", "initialize", project_dir: @project_dir)
35
+ end
36
+
37
+ # Main entry point for eval subcommands
38
+ def run(args)
39
+ sub = args.shift || "list"
40
+
41
+ case sub
42
+ when "list"
43
+ run_list_command(args)
44
+ when "view"
45
+ run_view_command(args)
46
+ when "stats"
47
+ run_stats_command
48
+ when "add"
49
+ run_add_command(args)
50
+ when "watch"
51
+ run_watch_command(args)
52
+ when "clear"
53
+ run_clear_command(args)
54
+ else
55
+ display_usage
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def run_list_command(args)
62
+ Aidp.log_debug("eval_command", "list", args: args)
63
+
64
+ options = parse_list_options(args)
65
+ evaluations = @storage.list(
66
+ limit: options[:limit],
67
+ rating: options[:rating],
68
+ target_type: options[:target_type]
69
+ )
70
+
71
+ if evaluations.empty?
72
+ display_message("No evaluations found.", type: :info)
73
+ return
74
+ end
75
+
76
+ display_evaluations_table(evaluations)
77
+ end
78
+
79
+ def run_view_command(args)
80
+ id = args.shift
81
+ unless id
82
+ display_message("Error: Please provide an evaluation ID", type: :error)
83
+ display_message("Usage: aidp eval view <evaluation_id>", type: :info)
84
+ return
85
+ end
86
+
87
+ Aidp.log_debug("eval_command", "view", id: id)
88
+
89
+ record = @storage.load(id)
90
+ unless record
91
+ display_message("Evaluation not found: #{id}", type: :error)
92
+ return
93
+ end
94
+
95
+ display_evaluation_details(record)
96
+ end
97
+
98
+ def run_stats_command
99
+ Aidp.log_debug("eval_command", "stats")
100
+
101
+ stats = @storage.stats
102
+
103
+ display_message("", type: :info)
104
+ display_message("Evaluation Statistics", type: :highlight)
105
+ display_message("=" * 50, type: :muted)
106
+ display_message("", type: :info)
107
+
108
+ display_message("Total evaluations: #{stats[:total]}", type: :info)
109
+ display_message("", type: :info)
110
+
111
+ display_message("By rating:", type: :info)
112
+ display_rating_bar(" Good", stats[:by_rating][:good], stats[:total], :green)
113
+ display_rating_bar(" Neutral", stats[:by_rating][:neutral], stats[:total], :yellow)
114
+ display_rating_bar(" Bad", stats[:by_rating][:bad], stats[:total], :red)
115
+
116
+ if stats[:by_target_type]&.any?
117
+ display_message("", type: :info)
118
+ display_message("By target type:", type: :info)
119
+ stats[:by_target_type].each do |type, count|
120
+ display_message(" #{type || "unspecified"}: #{count}", type: :muted)
121
+ end
122
+ end
123
+
124
+ if stats[:first_evaluation]
125
+ display_message("", type: :info)
126
+ display_message("First evaluation: #{format_timestamp(stats[:first_evaluation])}", type: :muted)
127
+ display_message("Last evaluation: #{format_timestamp(stats[:last_evaluation])}", type: :muted)
128
+ end
129
+
130
+ display_message("", type: :info)
131
+ end
132
+
133
+ def run_add_command(args)
134
+ # Check for watch mode options
135
+ watch_opts = extract_watch_options(args)
136
+
137
+ rating = args.shift
138
+ comment = args.join(" ").strip
139
+ comment = nil if comment.empty?
140
+
141
+ unless rating
142
+ display_message("Error: Please provide a rating (good, neutral, or bad)", type: :error)
143
+ display_message("Usage: aidp eval add <rating> [comment]", type: :info)
144
+ display_message(" aidp eval add --watch <type> <repo> <number> <rating> [comment]", type: :info)
145
+ return
146
+ end
147
+
148
+ Aidp.log_debug("eval_command", "add", rating: rating, has_comment: !comment.nil?, watch: watch_opts)
149
+
150
+ begin
151
+ context_capture = Aidp::Evaluations::ContextCapture.new(project_dir: @project_dir)
152
+
153
+ if watch_opts[:enabled]
154
+ context = context_capture.capture_watch(
155
+ repo: watch_opts[:repo],
156
+ number: watch_opts[:number],
157
+ processor_type: watch_opts[:type]
158
+ )
159
+ target_type = watch_opts[:type]
160
+ target_id = "#{watch_opts[:repo]}##{watch_opts[:number]}"
161
+ else
162
+ context = context_capture.capture_minimal
163
+ target_type = nil
164
+ target_id = nil
165
+ end
166
+
167
+ record = Aidp::Evaluations::EvaluationRecord.new(
168
+ rating: rating,
169
+ comment: comment,
170
+ target_type: target_type,
171
+ target_id: target_id,
172
+ context: context
173
+ )
174
+
175
+ result = @storage.store(record)
176
+
177
+ if result[:success]
178
+ display_message("Evaluation recorded: #{record.id}", type: :success)
179
+ display_message(" Rating: #{rating_with_emoji(record.rating)}", type: :info)
180
+ display_message(" Target: #{target_type} (#{target_id})", type: :info) if target_type
181
+ display_message(" Comment: #{record.comment}", type: :muted) if record.comment
182
+ else
183
+ display_message("Failed to store evaluation: #{result[:error]}", type: :error)
184
+ end
185
+ rescue ArgumentError => e
186
+ display_message("Error: #{e.message}", type: :error)
187
+ end
188
+ end
189
+
190
+ def run_watch_command(args)
191
+ # aidp eval watch <plan|review|build|ci_fix|change_request> <repo> <number> <rating> [comment]
192
+ processor_type = args.shift
193
+ repo = args.shift
194
+ number = args.shift&.to_i
195
+ rating = args.shift
196
+ comment = args.join(" ").strip
197
+ comment = nil if comment.empty?
198
+
199
+ unless processor_type && repo && number && rating
200
+ display_message("Error: Missing required arguments", type: :error)
201
+ display_message("Usage: aidp eval watch <type> <repo> <number> <rating> [comment]", type: :info)
202
+ display_message("", type: :info)
203
+ display_message("Types: plan, review, build, ci_fix, change_request", type: :info)
204
+ display_message("Example: aidp eval watch plan owner/repo 123 good \"Clear plan\"", type: :muted)
205
+ return
206
+ end
207
+
208
+ Aidp.log_debug("eval_command", "watch",
209
+ processor_type: processor_type, repo: repo, number: number, rating: rating)
210
+
211
+ begin
212
+ context_capture = Aidp::Evaluations::ContextCapture.new(project_dir: @project_dir)
213
+ context = context_capture.capture_watch(
214
+ repo: repo,
215
+ number: number,
216
+ processor_type: processor_type
217
+ )
218
+
219
+ record = Aidp::Evaluations::EvaluationRecord.new(
220
+ rating: rating,
221
+ comment: comment,
222
+ target_type: processor_type,
223
+ target_id: "#{repo}##{number}",
224
+ context: context
225
+ )
226
+
227
+ result = @storage.store(record)
228
+
229
+ if result[:success]
230
+ display_message("Watch evaluation recorded: #{record.id}", type: :success)
231
+ display_message(" Rating: #{rating_with_emoji(record.rating)}", type: :info)
232
+ display_message(" Type: #{processor_type}", type: :info)
233
+ display_message(" Target: #{repo}##{number}", type: :info)
234
+ display_message(" Comment: #{record.comment}", type: :muted) if record.comment
235
+ else
236
+ display_message("Failed to store evaluation: #{result[:error]}", type: :error)
237
+ end
238
+ rescue ArgumentError => e
239
+ display_message("Error: #{e.message}", type: :error)
240
+ end
241
+ end
242
+
243
+ def run_clear_command(args)
244
+ force = args.include?("--force")
245
+
246
+ unless force
247
+ confirm = @prompt.yes?("Are you sure you want to clear all evaluation data?")
248
+ return unless confirm
249
+ end
250
+
251
+ Aidp.log_debug("eval_command", "clear", force: force)
252
+
253
+ result = @storage.clear
254
+
255
+ if result[:success]
256
+ display_message("Cleared #{result[:count]} evaluation(s).", type: :success)
257
+ else
258
+ display_message("Failed to clear evaluations: #{result[:error]}", type: :error)
259
+ end
260
+ end
261
+
262
+ def parse_list_options(args)
263
+ options = {limit: 20, rating: nil, target_type: nil}
264
+
265
+ args.each_with_index do |arg, i|
266
+ case arg
267
+ when "--limit", "-n"
268
+ options[:limit] = args[i + 1].to_i if args[i + 1]
269
+ when "--rating", "-r"
270
+ options[:rating] = args[i + 1] if args[i + 1]
271
+ when "--type", "-t"
272
+ options[:target_type] = args[i + 1] if args[i + 1]
273
+ end
274
+ end
275
+
276
+ options
277
+ end
278
+
279
+ def extract_watch_options(args)
280
+ options = {enabled: false, type: nil, repo: nil, number: nil}
281
+
282
+ watch_idx = args.index("--watch")
283
+ return options unless watch_idx
284
+
285
+ # Remove --watch and extract following arguments
286
+ args.delete_at(watch_idx)
287
+
288
+ # Expect: --watch <type> <repo> <number>
289
+ if args[watch_idx] && args[watch_idx + 1] && args[watch_idx + 2]
290
+ options[:enabled] = true
291
+ options[:type] = args.delete_at(watch_idx)
292
+ options[:repo] = args.delete_at(watch_idx)
293
+ options[:number] = args.delete_at(watch_idx).to_i
294
+ end
295
+
296
+ options
297
+ end
298
+
299
+ def display_evaluations_table(evaluations)
300
+ header = ["ID", "Rating", "Target", "Comment", "Created"]
301
+
302
+ rows = evaluations.map do |eval|
303
+ [
304
+ truncate(eval.id, 25),
305
+ rating_with_emoji(eval.rating),
306
+ eval.target_type || "-",
307
+ truncate(eval.comment || "-", 30),
308
+ format_timestamp(eval.created_at)
309
+ ]
310
+ end
311
+
312
+ table = TTY::Table.new(header: header, rows: rows)
313
+ @prompt.say(table.render(:unicode, padding: [0, 1]))
314
+ end
315
+
316
+ def display_evaluation_details(record)
317
+ display_message("", type: :info)
318
+ display_message("Evaluation Details", type: :highlight)
319
+ display_message("=" * 50, type: :muted)
320
+ display_message("", type: :info)
321
+
322
+ display_message("ID: #{record.id}", type: :info)
323
+ display_message("Rating: #{rating_with_emoji(record.rating)}", type: :info)
324
+ display_message("Comment: #{record.comment || "(none)"}", type: :info)
325
+ display_message("Target Type: #{record.target_type || "(none)"}", type: :info)
326
+ display_message("Target ID: #{record.target_id || "(none)"}", type: :info)
327
+ display_message("Created: #{format_timestamp(record.created_at)}", type: :info)
328
+
329
+ if record.context&.any?
330
+ display_message("", type: :info)
331
+ display_message("Context:", type: :highlight)
332
+ display_context(record.context)
333
+ end
334
+
335
+ display_message("", type: :info)
336
+ end
337
+
338
+ def display_context(context, indent: 2)
339
+ prefix = " " * indent
340
+ context.each do |key, value|
341
+ if value.is_a?(Hash)
342
+ display_message("#{prefix}#{key}:", type: :muted)
343
+ display_context(value, indent: indent + 2)
344
+ elsif value.is_a?(Array)
345
+ display_message("#{prefix}#{key}: #{value.join(", ")}", type: :muted)
346
+ else
347
+ display_message("#{prefix}#{key}: #{value}", type: :muted)
348
+ end
349
+ end
350
+ end
351
+
352
+ def display_rating_bar(label, count, total, color)
353
+ percentage = (total > 0) ? (count.to_f / total * 100).round(1) : 0
354
+ bar_width = (total > 0) ? (count.to_f / total * 20).round : 0
355
+ bar = "#" * bar_width + "-" * (20 - bar_width)
356
+
357
+ display_message("#{label}: [#{bar}] #{count} (#{percentage}%)", type: :info)
358
+ end
359
+
360
+ def rating_with_emoji(rating)
361
+ case rating
362
+ when "good" then "good (+)"
363
+ when "neutral" then "neutral (~)"
364
+ when "bad" then "bad (-)"
365
+ else rating
366
+ end
367
+ end
368
+
369
+ def truncate(str, max_length)
370
+ return str if str.nil? || str.length <= max_length
371
+ str[0, max_length - 3] + "..."
372
+ end
373
+
374
+ def format_timestamp(timestamp)
375
+ return "-" unless timestamp
376
+ Time.parse(timestamp).strftime("%Y-%m-%d %H:%M")
377
+ rescue
378
+ timestamp.to_s[0, 16]
379
+ end
380
+
381
+ def display_usage
382
+ display_message("Usage: aidp eval <list|view|stats|add|watch|clear>", type: :info)
383
+ display_message("", type: :info)
384
+ display_message("Commands:", type: :info)
385
+ display_message(" list [options] - List recent evaluations", type: :info)
386
+ display_message(" --limit, -n <N> - Limit results (default: 20)", type: :muted)
387
+ display_message(" --rating, -r <rating> - Filter by rating", type: :muted)
388
+ display_message(" --type, -t <type> - Filter by target type", type: :muted)
389
+ display_message(" view <id> - View evaluation details", type: :info)
390
+ display_message(" stats - Show evaluation statistics", type: :info)
391
+ display_message(" add <rating> [comment] - Add a new evaluation", type: :info)
392
+ display_message(" watch <type> <repo> <number> <rating> [comment]", type: :info)
393
+ display_message(" - Rate a watch mode output", type: :info)
394
+ display_message(" Types: plan, review, build, ci_fix, change_request", type: :muted)
395
+ display_message(" clear [--force] - Clear all evaluation data", type: :info)
396
+ end
397
+ end
398
+ end
399
+ end
@@ -58,7 +58,7 @@ module Aidp
58
58
 
59
59
  # Build a runner to access state manager
60
60
  runner = @runner_class.new(@project_dir, mode.to_sym, {})
61
- state_manager = runner.instance_variable_get(:@state_manager)
61
+ state_manager = runner.state_manager
62
62
  state_manager.reset_all if state_manager.respond_to?(:reset_all)
63
63
  display_message("✅ Reset harness state for #{mode} mode", type: :success)
64
64
  end