aidp 0.9.3 → 0.9.5

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: 9d0c7cc3b04a5bf072473bc3b2ea145fd89ab30e6109cdf3954a8a5d6fa047d1
4
- data.tar.gz: 42a9693c97e90762f7d6ae7522a4a3e53ed39a317288bdc115a6f7bf4db476fc
3
+ metadata.gz: 12e70b298f80b189c33c7db0a67027086a8441a4fdd5c0ae45045b491c5ca825
4
+ data.tar.gz: 1f6445fd7ed137c78e4c6000aac0418d15d00856beea9db9afd4d843aad11b4a
5
5
  SHA512:
6
- metadata.gz: 215e1ceef3aa14003503244236a3669e3f7ddf1e2c3d11ceabd22b9aa059909e20577d08b79032b11fd5625645cecb2d76734029bdf929b8de579738d6d1e795
7
- data.tar.gz: c72d937cd6d1e166491f829f650118588944968062ac69ff41294b462304887829370baa2daf7601db068fd1ab6697c0e234f7dca63f85f6e900edf04122aca6
6
+ metadata.gz: 5fab5f97f7874314f0991cd75260175b7aab803d199bb25ab1223fae0d280a7b6a97a11ff160d90b5bc263fc312bc64bb3c95c32e34e31d960c8ab7a403a8778
7
+ data.tar.gz: 9bf30d28286d09e7d25bb23bd3109e422e91518f7e46113949ed27a87cc722046dc8cfd881f00279c6f849173a6a9f4c503d07b519d7cd7ca53d7cd53a71cf67
data/README.md CHANGED
@@ -76,15 +76,15 @@ The TUI automatically switches providers when:
76
76
  # aidp.yml
77
77
  providers:
78
78
  claude:
79
- type: "api"
79
+ type: "usage_based"
80
80
  api_key: "${AIDP_CLAUDE_API_KEY}"
81
81
  max_tokens: 100000
82
82
  gemini:
83
- type: "api"
83
+ type: "usage_based"
84
84
  api_key: "${AIDP_GEMINI_API_KEY}"
85
85
  max_tokens: 50000
86
86
  cursor:
87
- type: "package"
87
+ type: "subscription"
88
88
  ```
89
89
 
90
90
  ### Environment Variables
@@ -10,10 +10,10 @@ module Aidp
10
10
  class FirstRunWizard
11
11
  TEMPLATES_DIR = File.expand_path(File.join(__dir__, "..", "..", "..", "templates"))
12
12
 
13
- def self.ensure_config(project_dir, input: $stdin, output: $stdout, non_interactive: false)
13
+ def self.ensure_config(project_dir, input: $stdin, output: $stdout, non_interactive: false, prompt: TTY::Prompt.new)
14
14
  return true if Aidp::Config.config_exists?(project_dir)
15
15
 
16
- wizard = new(project_dir, input: input, output: output)
16
+ wizard = new(project_dir, input: input, output: output, prompt: prompt)
17
17
 
18
18
  if non_interactive || !input.tty? || !output.tty?
19
19
  # Non-interactive environment - create minimal config silently
@@ -25,8 +25,8 @@ module Aidp
25
25
  wizard.run
26
26
  end
27
27
 
28
- def self.setup_config(project_dir, input: $stdin, output: $stdout, non_interactive: false)
29
- wizard = new(project_dir, input: input, output: output)
28
+ def self.setup_config(project_dir, input: $stdin, output: $stdout, non_interactive: false, prompt: TTY::Prompt.new)
29
+ wizard = new(project_dir, input: input, output: output, prompt: prompt)
30
30
 
31
31
  if non_interactive || !input.tty? || !output.tty?
32
32
  # Non-interactive environment - skip setup
@@ -37,11 +37,11 @@ module Aidp
37
37
  wizard.run_setup_config
38
38
  end
39
39
 
40
- def initialize(project_dir, input: $stdin, output: $stdout)
40
+ def initialize(project_dir, input: $stdin, output: $stdout, prompt: TTY::Prompt.new)
41
41
  @project_dir = project_dir
42
42
  @input = input
43
43
  @output = output
44
- @prompt = TTY::Prompt.new
44
+ @prompt = prompt
45
45
  end
46
46
 
47
47
  def run
@@ -49,11 +49,8 @@ module Aidp
49
49
  loop do
50
50
  choice = ask_choice
51
51
  case choice
52
- when "1" then return finish(write_minimal_config(@project_dir))
53
- when "2" then return finish(copy_template("aidp-development.yml.example"))
54
- when "3" then return finish(copy_template("aidp-production.yml.example"))
55
- when "4" then return finish(write_example_config(@project_dir))
56
- when "5" then return finish(run_custom)
52
+ when "1" then return finish(write_quick_config(@project_dir))
53
+ when "2" then return finish(run_custom)
57
54
  when "q", "Q" then @output.puts("Exiting without creating configuration.")
58
55
  return false
59
56
  else
@@ -92,19 +89,14 @@ module Aidp
92
89
 
93
90
  def ask_choice
94
91
  @output.puts "Choose a configuration style:" unless @asking
95
- @output.puts <<~MENU
96
- 1) Minimal (single provider: cursor)
97
- 2) Development template (multiple providers, safe defaults)
98
- 3) Production template (full features, review required)
99
- 4) Full example (verbose example config)
100
- 5) Custom (interactive prompts)
101
- q) Quit
102
- MENU
103
- @output.print "Enter choice [1]: "
104
- @output.flush
105
- ans = @input.gets&.strip
106
- ans = "1" if ans.nil? || ans.empty?
107
- ans
92
+
93
+ options = {
94
+ "Quick setup (cursor + macos, no API keys needed)" => "1",
95
+ "Custom setup (choose your own providers and settings)" => "2",
96
+ "Quit" => "q"
97
+ }
98
+
99
+ @prompt.select("Select an option:", options, default: "Quick setup (cursor + macos, no API keys needed)")
108
100
  end
109
101
 
110
102
  def finish(path)
@@ -133,16 +125,41 @@ module Aidp
133
125
  dest = File.join(project_dir, "aidp.yml")
134
126
  return dest if File.exist?(dest)
135
127
  data = {
136
- harness: {
137
- max_retries: 2,
138
- default_provider: "cursor",
139
- fallback_providers: ["cursor"],
140
- no_api_keys_required: false
128
+ "harness" => {
129
+ "max_retries" => 2,
130
+ "default_provider" => "cursor",
131
+ "fallback_providers" => ["cursor"],
132
+ "no_api_keys_required" => false
133
+ },
134
+ "providers" => {
135
+ "cursor" => {
136
+ "type" => "subscription",
137
+ "default_flags" => []
138
+ }
139
+ }
140
+ }
141
+ File.write(dest, YAML.dump(data))
142
+ dest
143
+ end
144
+
145
+ def write_quick_config(project_dir)
146
+ dest = File.join(project_dir, "aidp.yml")
147
+ return dest if File.exist?(dest)
148
+ data = {
149
+ "harness" => {
150
+ "max_retries" => 2,
151
+ "default_provider" => "cursor",
152
+ "fallback_providers" => ["macos"],
153
+ "no_api_keys_required" => true
141
154
  },
142
- providers: {
143
- cursor: {
144
- type: "package",
145
- default_flags: []
155
+ "providers" => {
156
+ "cursor" => {
157
+ "type" => "subscription",
158
+ "default_flags" => []
159
+ },
160
+ "macos" => {
161
+ "type" => "usage_based",
162
+ "default_flags" => []
146
163
  }
147
164
  }
148
165
  }
@@ -252,6 +269,12 @@ module Aidp
252
269
  # Convert existing provider config to string keys
253
270
  converted_provider = {}
254
271
  existing_provider.each { |k, v| converted_provider[k.to_s] = v }
272
+ # Ensure the type is correct (fix old "package" and "api" types)
273
+ if converted_provider["type"] == "package"
274
+ converted_provider["type"] = "subscription"
275
+ elsif converted_provider["type"] == "api"
276
+ converted_provider["type"] = "usage_based"
277
+ end
255
278
  provider_section[prov] = converted_provider
256
279
  else
257
280
  provider_section[prov] = {"type" => (prov == "cursor") ? "subscription" : "usage_based", "default_flags" => []}
@@ -6,9 +6,9 @@ module Aidp
6
6
  module Execute
7
7
  # Handles interactive workflow selection and project setup
8
8
  class WorkflowSelector
9
- def initialize
9
+ def initialize(prompt: TTY::Prompt.new)
10
10
  @user_input = {}
11
- @prompt = TTY::Prompt.new
11
+ @prompt = prompt
12
12
  end
13
13
 
14
14
  # Main entry point for interactive workflow selection
@@ -47,7 +47,7 @@ module Aidp
47
47
  harness_config[:no_api_keys_required]
48
48
  end
49
49
 
50
- # Get provider type (api, package, etc.)
50
+ # Get provider type (usage_based, subscription, etc.)
51
51
  def provider_type(provider_name)
52
52
  provider_config(provider_name)[:type] || "unknown"
53
53
  end
@@ -7,8 +7,8 @@ module Aidp
7
7
  # Simple, focused user interface for collecting feedback
8
8
  # Replaces the bloated UserInterface with minimal, clean code
9
9
  class SimpleUserInterface
10
- def initialize
11
- @prompt = TTY::Prompt.new
10
+ def initialize(prompt: TTY::Prompt.new)
11
+ @prompt = prompt
12
12
  end
13
13
 
14
14
  # Main method - collect responses for questions
@@ -18,15 +18,17 @@ module Aidp
18
18
  class InputError < TUIError; end
19
19
  class DisplayError < TUIError; end
20
20
 
21
- def initialize
21
+ def initialize(prompt: TTY::Prompt.new)
22
22
  @cursor = TTY::Cursor
23
23
  @screen = TTY::Screen
24
24
  @pastel = Pastel.new
25
- @prompt = TTY::Prompt.new
25
+ @prompt = prompt
26
+
26
27
  # Headless (non-interactive) detection for test/CI environments:
27
28
  # - RSpec defined or RSPEC_RUNNING env set
28
29
  # - STDIN not a TTY (captured by PTY/tmux harness)
29
30
  @headless = !!(defined?(RSpec) || ENV["RSPEC_RUNNING"] || $stdin.nil? || !$stdin.tty?)
31
+
30
32
  @current_mode = nil
31
33
  @workflow_active = false
32
34
  @current_step = nil
@@ -47,32 +49,6 @@ module Aidp
47
49
  restore_screen
48
50
  end
49
51
 
50
- # Job monitoring methods
51
- def add_job(job_id, job_data)
52
- @jobs[job_id] = {
53
- id: job_id,
54
- name: job_data[:name] || job_id,
55
- status: job_data[:status] || :pending,
56
- progress: job_data[:progress] || 0,
57
- started_at: Time.now,
58
- message: job_data[:message] || "",
59
- provider: job_data[:provider] || "unknown"
60
- }
61
- @jobs_visible = true
62
- end
63
-
64
- def update_job(job_id, updates)
65
- return unless @jobs[job_id]
66
-
67
- @jobs[job_id].merge!(updates)
68
- @jobs[job_id][:updated_at] = Time.now
69
- end
70
-
71
- def remove_job(job_id)
72
- @jobs.delete(job_id)
73
- @jobs_visible = @jobs.any?
74
- end
75
-
76
52
  # Input methods using TTY::Prompt only - no background threads
77
53
  def get_user_input(prompt = "💬 You: ")
78
54
  @prompt.ask(prompt)
@@ -31,9 +31,9 @@ module Aidp
31
31
  urgent: "Urgent"
32
32
  }.freeze
33
33
 
34
- def initialize(ui_components = {})
34
+ def initialize(ui_components = {}, prompt: TTY::Prompt.new)
35
35
  super()
36
- @prompt = TTY::Prompt.new
36
+ @prompt = prompt
37
37
  @pastel = Pastel.new
38
38
  @status_manager = ui_components[:status_manager] || StatusManager.new
39
39
  @frame_manager = ui_components[:frame_manager] || FrameManager.new
@@ -17,9 +17,9 @@ module Aidp
17
17
  class InvalidMenuError < MenuError; end
18
18
  class NavigationError < MenuError; end
19
19
 
20
- def initialize(ui_components = {})
20
+ def initialize(ui_components = {}, prompt: nil)
21
21
  super()
22
- @prompt = ui_components[:prompt] || TTY::Prompt.new
22
+ @prompt = prompt || ui_components[:prompt] || TTY::Prompt.new
23
23
  @pastel = Pastel.new
24
24
  @formatter = ui_components[:formatter] || MenuFormatter.new
25
25
  @state_manager = ui_components[:state_manager] || MenuState.new
@@ -28,9 +28,9 @@ module Aidp
28
28
  }
29
29
  }.freeze
30
30
 
31
- def initialize(ui_components = {})
31
+ def initialize(ui_components = {}, prompt: nil)
32
32
  super()
33
- @prompt = ui_components[:prompt] || TTY::Prompt.new
33
+ @prompt = prompt || ui_components[:prompt] || TTY::Prompt.new
34
34
  @pastel = Pastel.new
35
35
  @formatter = ui_components[:formatter] || WorkflowFormatter.new
36
36
  @state_manager = ui_components[:state_manager]
@@ -12,9 +12,9 @@ module Aidp
12
12
  class ValidationError < QuestionError; end
13
13
  class CollectionError < QuestionError; end
14
14
 
15
- def initialize(ui_components = {})
15
+ def initialize(ui_components = {}, prompt: nil)
16
16
  super()
17
- @prompt = ui_components[:prompt] || TTY::Prompt.new
17
+ @prompt = prompt || ui_components[:prompt] || TTY::Prompt.new
18
18
  @validator = ui_components[:validator] || QuestionValidator.new
19
19
  end
20
20
 
@@ -6,10 +6,10 @@ module Aidp
6
6
  module Harness
7
7
  # Handles user interaction and feedback collection
8
8
  class UserInterface
9
- def initialize
9
+ def initialize(prompt: TTY::Prompt.new)
10
10
  @input_history = []
11
11
  @file_selection_enabled = false
12
- @prompt = TTY::Prompt.new
12
+ @prompt = prompt
13
13
  @control_mutex = Mutex.new
14
14
  @pause_requested = false
15
15
  @stop_requested = false
data/lib/aidp/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aidp
4
- VERSION = "0.9.3"
4
+ VERSION = "0.9.5"
5
5
  end
data/templates/README.md CHANGED
@@ -102,7 +102,7 @@ The `harness` section controls the overall behavior of the harness system:
102
102
 
103
103
  The `providers` section defines individual provider settings:
104
104
 
105
- - `type`: Provider type (package, api, passthrough)
105
+ - `type`: Provider type (subscription, usage_based, passthrough)
106
106
  - `priority`: Provider priority (higher = more preferred)
107
107
  - `models`: Available models for the provider
108
108
  - `features`: Provider capabilities
@@ -172,9 +172,9 @@ time_based:
172
172
 
173
173
  ## Provider Types
174
174
 
175
- ### Package Providers
175
+ ### Subscription Providers
176
176
 
177
- - **Type**: `package`
177
+ - **Type**: `subscription`
178
178
  - **Pricing**: Fixed monthly/yearly subscription
179
179
  - **Examples**: Cursor Pro
180
180
  - **Configuration**: No API keys needed
@@ -110,8 +110,8 @@ harness:
110
110
  # Provider configurations
111
111
  providers:
112
112
  # Cursor provider (primary for development)
113
- cursor:
114
- type: "package"
113
+ cursor:
114
+ type: "subscription"
115
115
  priority: 1
116
116
  default_flags: []
117
117
 
@@ -227,8 +227,8 @@ providers:
227
227
  max_redirects: 5
228
228
 
229
229
  # Cursor provider (fallback)
230
- cursor:
231
- type: "package"
230
+ cursor:
231
+ type: "subscription"
232
232
  priority: 2
233
233
  default_flags: []
234
234
 
@@ -125,7 +125,7 @@ harness:
125
125
 
126
126
  # Provider configurations
127
127
  providers:
128
- # Cursor provider (package-based)
128
+ # Cursor provider (subscription-based)
129
129
  cursor:
130
130
  type: "subscription" # subscription, usage_based, or passthrough
131
131
  priority: 1 # Provider priority (higher = more preferred)
@@ -188,7 +188,7 @@ providers:
188
188
 
189
189
  # Cost tracking
190
190
  cost:
191
- input_cost_per_token: 0.0 # Package-based pricing
191
+ input_cost_per_token: 0.0 # Subscription-based pricing
192
192
  output_cost_per_token: 0.0
193
193
  fixed_cost_per_request: 0.0
194
194
  currency: "USD"
@@ -426,8 +426,8 @@ providers:
426
426
  # metrics_interval: 60
427
427
 
428
428
  # Provider types explained:
429
- # - "package": Uses package-based pricing (e.g., Cursor Pro)
430
- # - "api": Uses API-based pricing with token limits
429
+ # - "subscription": Uses subscription-based pricing (e.g., Cursor Pro)
430
+ # - "usage_based": Uses API-based pricing with token limits
431
431
  # - "passthrough": Uses underlying service (user manages API keys)
432
432
 
433
433
  # Environment-specific configurations
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aidp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan