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.
- checksums.yaml +4 -4
- data/README.md +35 -0
- data/lib/aidp/analyze/tree_sitter_scan.rb +3 -0
- data/lib/aidp/cli/eval_command.rb +399 -0
- data/lib/aidp/cli/harness_command.rb +1 -1
- data/lib/aidp/cli/security_command.rb +416 -0
- data/lib/aidp/cli/tools_command.rb +6 -4
- data/lib/aidp/cli.rb +170 -3
- data/lib/aidp/concurrency/exec.rb +3 -0
- data/lib/aidp/config.rb +113 -0
- data/lib/aidp/config_paths.rb +20 -0
- data/lib/aidp/daemon/runner.rb +8 -4
- data/lib/aidp/errors.rb +134 -0
- data/lib/aidp/evaluations/context_capture.rb +205 -0
- data/lib/aidp/evaluations/evaluation_record.rb +114 -0
- data/lib/aidp/evaluations/evaluation_storage.rb +250 -0
- data/lib/aidp/evaluations.rb +23 -0
- data/lib/aidp/execute/async_work_loop_runner.rb +4 -1
- data/lib/aidp/execute/interactive_repl.rb +6 -2
- data/lib/aidp/execute/prompt_evaluator.rb +359 -0
- data/lib/aidp/execute/repl_macros.rb +100 -1
- data/lib/aidp/execute/work_loop_runner.rb +399 -47
- data/lib/aidp/execute/work_loop_state.rb +4 -1
- data/lib/aidp/execute/workflow_selector.rb +3 -0
- data/lib/aidp/harness/ai_decision_engine.rb +79 -0
- data/lib/aidp/harness/capability_registry.rb +2 -0
- data/lib/aidp/harness/condition_detector.rb +3 -0
- data/lib/aidp/harness/config_loader.rb +3 -0
- data/lib/aidp/harness/enhanced_runner.rb +14 -11
- data/lib/aidp/harness/error_handler.rb +3 -0
- data/lib/aidp/harness/provider_factory.rb +3 -0
- data/lib/aidp/harness/provider_manager.rb +6 -0
- data/lib/aidp/harness/runner.rb +5 -1
- data/lib/aidp/harness/state/persistence.rb +3 -0
- data/lib/aidp/harness/state_manager.rb +3 -0
- data/lib/aidp/harness/status_display.rb +28 -20
- data/lib/aidp/harness/thinking_depth_manager.rb +32 -32
- data/lib/aidp/harness/ui/enhanced_tui.rb +4 -0
- data/lib/aidp/harness/ui/enhanced_workflow_selector.rb +4 -0
- data/lib/aidp/harness/ui/error_handler.rb +3 -0
- data/lib/aidp/harness/ui/job_monitor.rb +4 -0
- data/lib/aidp/harness/ui/navigation/submenu.rb +2 -0
- data/lib/aidp/harness/ui/navigation/workflow_selector.rb +6 -0
- data/lib/aidp/harness/ui/spinner_helper.rb +3 -0
- data/lib/aidp/harness/ui/workflow_controller.rb +3 -0
- data/lib/aidp/harness/user_interface.rb +3 -0
- data/lib/aidp/loader.rb +2 -2
- data/lib/aidp/logger.rb +3 -0
- data/lib/aidp/message_display.rb +31 -0
- data/lib/aidp/pr_worktree_manager.rb +18 -6
- data/lib/aidp/provider_manager.rb +3 -0
- data/lib/aidp/providers/base.rb +2 -0
- data/lib/aidp/security/rule_of_two_enforcer.rb +210 -0
- data/lib/aidp/security/secrets_proxy.rb +328 -0
- data/lib/aidp/security/secrets_registry.rb +227 -0
- data/lib/aidp/security/trifecta_state.rb +220 -0
- data/lib/aidp/security/watch_mode_handler.rb +306 -0
- data/lib/aidp/security/work_loop_adapter.rb +277 -0
- data/lib/aidp/security.rb +56 -0
- data/lib/aidp/setup/wizard.rb +4 -2
- data/lib/aidp/version.rb +1 -1
- data/lib/aidp/watch/auto_merger.rb +274 -0
- data/lib/aidp/watch/auto_pr_processor.rb +125 -7
- data/lib/aidp/watch/build_processor.rb +16 -1
- data/lib/aidp/watch/change_request_processor.rb +680 -286
- data/lib/aidp/watch/ci_fix_processor.rb +262 -4
- data/lib/aidp/watch/feedback_collector.rb +191 -0
- data/lib/aidp/watch/hierarchical_pr_strategy.rb +256 -0
- data/lib/aidp/watch/implementation_verifier.rb +142 -1
- data/lib/aidp/watch/plan_generator.rb +70 -13
- data/lib/aidp/watch/plan_processor.rb +12 -5
- data/lib/aidp/watch/projects_processor.rb +286 -0
- data/lib/aidp/watch/repository_client.rb +861 -53
- data/lib/aidp/watch/review_processor.rb +33 -6
- data/lib/aidp/watch/runner.rb +51 -11
- data/lib/aidp/watch/state_store.rb +233 -0
- data/lib/aidp/watch/sub_issue_creator.rb +221 -0
- data/lib/aidp/workflows/guided_agent.rb +4 -0
- data/lib/aidp/workstream_executor.rb +3 -0
- data/lib/aidp/worktree.rb +61 -11
- data/lib/aidp/worktree_branch_manager.rb +347 -101
- data/templates/implementation/iterative_implementation.md +46 -3
- metadata +20 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4c9ad1d807359d816adfa79c71deb42fedce7158f782279366dffeee6b45179
|
|
4
|
+
data.tar.gz: 12bbe406911ad596b2b55dfa450a3841804e51417252fd9e3212a41ca0f4b88d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|