aidp 0.1.0 → 0.3.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.
data/lib/aidp/util.rb ADDED
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Aidp
6
+ # Utility functions shared between execute and analyze modes
7
+ class Util
8
+ def self.which(cmd)
9
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
10
+ ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
11
+ exts.each do |ext|
12
+ exe = File.join(path, "#{cmd}#{ext}")
13
+ return exe if File.executable?(exe) && !File.directory?(exe)
14
+ end
15
+ end
16
+ nil
17
+ end
18
+
19
+ def self.ensure_dirs(output_files, project_dir)
20
+ output_files.each do |file|
21
+ dir = File.dirname(File.join(project_dir, file))
22
+ FileUtils.mkdir_p(dir) unless dir == "."
23
+ end
24
+ end
25
+
26
+ def self.safe_file_write(path, content)
27
+ FileUtils.mkdir_p(File.dirname(path))
28
+ File.write(path, content)
29
+ end
30
+
31
+ def self.project_root?(dir = Dir.pwd)
32
+ File.exist?(File.join(dir, ".git")) ||
33
+ File.exist?(File.join(dir, "package.json")) ||
34
+ File.exist?(File.join(dir, "Gemfile")) ||
35
+ File.exist?(File.join(dir, "pom.xml")) ||
36
+ File.exist?(File.join(dir, "build.gradle"))
37
+ end
38
+ end
39
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aidp
4
- module Shared
5
- VERSION = "0.1.0"
6
- end
4
+ VERSION = "0.3.0"
7
5
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "digest"
5
+
6
+ module Aidp
7
+ # Workspace management utilities
8
+ class Workspace
9
+ def self.current
10
+ Dir.pwd
11
+ end
12
+
13
+ def self.ensure_project_root
14
+ unless Aidp::Util.project_root?
15
+ raise "Not in a project root directory. Please run from a directory with .git, package.json, Gemfile, etc."
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/aidp.rb CHANGED
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Shared modules
4
- require "aidp/shared/version"
5
- require "aidp/shared/config"
6
- require "aidp/shared/workspace"
7
- require "aidp/shared/util"
8
- require "aidp/shared/cli"
9
- require "aidp/shared/project_detector"
10
- require "aidp/shared/sync"
11
- require "aidp/shared/providers/base"
12
- require "aidp/shared/providers/cursor"
13
- require "aidp/shared/providers/anthropic"
14
- require "aidp/shared/providers/gemini"
15
- require "aidp/shared/providers/macos_ui"
4
+ require "aidp/version"
5
+ require "aidp/config"
6
+ require "aidp/workspace"
7
+ require "aidp/util"
8
+ require "aidp/cli"
9
+ require "aidp/project_detector"
10
+ require "aidp/sync"
11
+ require "aidp/providers/base"
12
+ require "aidp/providers/cursor"
13
+ require "aidp/providers/anthropic"
14
+ require "aidp/providers/gemini"
15
+ require "aidp/providers/macos_ui"
16
16
 
17
17
  # Execute mode modules
18
18
  require "aidp/execute/steps"
@@ -49,5 +49,5 @@ require "aidp/analyze/performance_optimizer"
49
49
  require "aidp/analyze/error_handler"
50
50
 
51
51
  module Aidp
52
- VERSION = Aidp::Shared::VERSION
52
+ class Error < StandardError; end
53
53
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aidp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-08-16 00:00:00.000000000 Z
10
+ date: 2025-08-18 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: colorize
@@ -69,16 +69,22 @@ dependencies:
69
69
  name: sqlite3
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '1.6'
75
+ - - "<"
76
+ - !ruby/object:Gem::Version
77
+ version: '3.0'
75
78
  type: :runtime
76
79
  prerelease: false
77
80
  version_requirements: !ruby/object:Gem::Requirement
78
81
  requirements:
79
- - - "~>"
82
+ - - ">="
80
83
  - !ruby/object:Gem::Version
81
84
  version: '1.6'
85
+ - - "<"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.0'
82
88
  - !ruby/object:Gem::Dependency
83
89
  name: thor
84
90
  requirement: !ruby/object:Gem::Requirement
@@ -191,8 +197,9 @@ dependencies:
191
197
  - - "~>"
192
198
  - !ruby/object:Gem::Version
193
199
  version: '1.0'
194
- description: Portable CLI to run a markdown-based AI dev workflow without copying
195
- prompts into projects.
200
+ description: The AI-Dev-Pipeline (AIDP) CLI provides a powerful, markdown-driven workflow
201
+ for software development. It supports in-depth project analysis to understand existing
202
+ codebases and an execution mode to systematically implement new features.
196
203
  email:
197
204
  - bart@sonic.next
198
205
  executables:
@@ -231,21 +238,21 @@ files:
231
238
  - lib/aidp/analyze/storage.rb
232
239
  - lib/aidp/analyze/tool_configuration.rb
233
240
  - lib/aidp/analyze/tool_modernization.rb
241
+ - lib/aidp/cli.rb
242
+ - lib/aidp/config.rb
234
243
  - lib/aidp/execute/progress.rb
235
244
  - lib/aidp/execute/runner.rb
236
245
  - lib/aidp/execute/steps.rb
237
- - lib/aidp/shared/cli.rb
238
- - lib/aidp/shared/config.rb
239
- - lib/aidp/shared/project_detector.rb
240
- - lib/aidp/shared/providers/anthropic.rb
241
- - lib/aidp/shared/providers/base.rb
242
- - lib/aidp/shared/providers/cursor.rb
243
- - lib/aidp/shared/providers/gemini.rb
244
- - lib/aidp/shared/providers/macos_ui.rb
245
- - lib/aidp/shared/sync.rb
246
- - lib/aidp/shared/util.rb
247
- - lib/aidp/shared/version.rb
248
- - lib/aidp/shared/workspace.rb
246
+ - lib/aidp/project_detector.rb
247
+ - lib/aidp/providers/anthropic.rb
248
+ - lib/aidp/providers/base.rb
249
+ - lib/aidp/providers/cursor.rb
250
+ - lib/aidp/providers/gemini.rb
251
+ - lib/aidp/providers/macos_ui.rb
252
+ - lib/aidp/sync.rb
253
+ - lib/aidp/util.rb
254
+ - lib/aidp/version.rb
255
+ - lib/aidp/workspace.rb
249
256
  - templates/ANALYZE/01_REPOSITORY_ANALYSIS.md
250
257
  - templates/ANALYZE/02_ARCHITECTURE_ANALYSIS.md
251
258
  - templates/ANALYZE/03_TEST_ANALYSIS.md
@@ -277,7 +284,7 @@ files:
277
284
  - templates/EXECUTE/13_DELIVERY_ROLLOUT.md
278
285
  - templates/EXECUTE/14_DOCS_PORTAL.md
279
286
  - templates/EXECUTE/15_POST_RELEASE.md
280
- homepage: https://github.com/viamin/ai-scaffold
287
+ homepage: https://github.com/viamin/aidp
281
288
  licenses:
282
289
  - MIT
283
290
  metadata: {}
@@ -297,5 +304,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
297
304
  requirements: []
298
305
  rubygems_version: 3.6.2
299
306
  specification_version: 4
300
- summary: AI Dev Pipeline CLI that drives prompts via Cursor/Claude/Gemini
307
+ summary: A CLI for AI-driven software development, from analysis to execution.
301
308
  test_files: []
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "thor"
4
-
5
- module Aidp
6
- module Shared
7
- # CLI interface for both execute and analyze modes
8
- class CLI < Thor
9
- desc "execute [STEP]", "Run execute mode step(s)"
10
- option :force, type: :boolean, desc: "Force execution even if dependencies are not met"
11
- option :rerun, type: :boolean, desc: "Re-run a completed step"
12
- def execute(project_dir = Dir.pwd, step_name = nil, custom_options = {})
13
- if step_name
14
- runner = Aidp::Execute::Runner.new(project_dir)
15
- # Merge Thor options with custom options
16
- all_options = options.merge(custom_options)
17
- runner.run_step(step_name, all_options)
18
- else
19
- puts "Available execute steps:"
20
- Aidp::Execute::Steps::SPEC.keys.each { |step| puts " - #{step}" }
21
- progress = Aidp::Execute::Progress.new(project_dir)
22
- next_step = progress.next_step
23
- {status: "success", message: "Available steps listed", next_step: next_step}
24
- end
25
- end
26
-
27
- desc "analyze [STEP]", "Run analyze mode step(s)"
28
- option :force, type: :boolean, desc: "Force execution even if dependencies are not met"
29
- option :rerun, type: :boolean, desc: "Re-run a completed step"
30
- def analyze(project_dir = Dir.pwd, step_name = nil, custom_options = {})
31
- if step_name
32
- runner = Aidp::Analyze::Runner.new(project_dir)
33
- # Merge Thor options with custom options
34
- all_options = options.merge(custom_options)
35
- runner.run_step(step_name, all_options)
36
- else
37
- puts "Available analyze steps:"
38
- Aidp::Analyze::Steps::SPEC.keys.each { |step| puts " - #{step}" }
39
- progress = Aidp::Analyze::Progress.new(project_dir)
40
- next_step = progress.next_step
41
- {status: "success", message: "Available steps listed", next_step: next_step,
42
- completed_steps: progress.completed_steps}
43
- end
44
- end
45
-
46
- desc "analyze-approve STEP", "Approve a completed analyze gate step"
47
- def analyze_approve(project_dir = Dir.pwd, step_name = nil)
48
- progress = Aidp::Analyze::Progress.new(project_dir)
49
- progress.mark_step_completed(step_name)
50
- puts "✅ Approved analyze step: #{step_name}"
51
- {status: "success", step: step_name}
52
- end
53
-
54
- desc "analyze-reset", "Reset analyze mode progress"
55
- def analyze_reset(project_dir = Dir.pwd)
56
- progress = Aidp::Analyze::Progress.new(project_dir)
57
- progress.reset
58
- puts "🔄 Reset analyze mode progress"
59
- {status: "success", message: "Progress reset"}
60
- end
61
-
62
- desc "execute-approve STEP", "Approve a completed execute gate step"
63
- def execute_approve(project_dir = Dir.pwd, step_name = nil)
64
- progress = Aidp::Execute::Progress.new(project_dir)
65
- progress.mark_step_completed(step_name)
66
- puts "✅ Approved execute step: #{step_name}"
67
- {status: "success", step: step_name}
68
- end
69
-
70
- desc "execute-reset", "Reset execute mode progress"
71
- def execute_reset(project_dir = Dir.pwd)
72
- progress = Aidp::Execute::Progress.new(project_dir)
73
- progress.reset
74
- puts "🔄 Reset execute mode progress"
75
- {status: "success", message: "Progress reset"}
76
- end
77
-
78
- # Backward compatibility aliases
79
- desc "approve STEP", "Approve a completed execute gate step (alias for execute-approve)"
80
- def approve(project_dir = Dir.pwd, step_name = nil)
81
- execute_approve(project_dir, step_name)
82
- end
83
-
84
- desc "reset", "Reset execute mode progress (alias for execute-reset)"
85
- def reset(project_dir = Dir.pwd)
86
- execute_reset(project_dir)
87
- end
88
-
89
- desc "status", "Show current progress for both modes"
90
- def status
91
- puts "\n📊 AI Dev Pipeline Status"
92
- puts "=" * 50
93
-
94
- # Execute mode status
95
- execute_progress = Aidp::Execute::Progress.new(Dir.pwd)
96
- puts "\n🔧 Execute Mode:"
97
- Aidp::Execute::Steps::SPEC.keys.each do |step|
98
- status = execute_progress.step_completed?(step) ? "✅" : "⏳"
99
- puts " #{status} #{step}"
100
- end
101
-
102
- # Analyze mode status
103
- analyze_progress = Aidp::Analyze::Progress.new(Dir.pwd)
104
- puts "\n🔍 Analyze Mode:"
105
- Aidp::Analyze::Steps::SPEC.keys.each do |step|
106
- status = analyze_progress.step_completed?(step) ? "✅" : "⏳"
107
- puts " #{status} #{step}"
108
- end
109
- end
110
-
111
- desc "version", "Show version information"
112
- def version
113
- puts "Aidp version #{Aidp::Shared::VERSION}"
114
- end
115
- end
116
- end
117
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "yaml"
4
-
5
- module Aidp
6
- module Shared
7
- # Configuration management for both execute and analyze modes
8
- class Config
9
- def self.load(project_dir = Dir.pwd)
10
- config_file = File.join(project_dir, ".aidp.yml")
11
- if File.exist?(config_file)
12
- YAML.load_file(config_file) || {}
13
- else
14
- {}
15
- end
16
- end
17
-
18
- def self.templates_root
19
- File.join(Dir.pwd, "templates")
20
- end
21
-
22
- def self.analyze_templates_root
23
- File.join(Dir.pwd, "templates", "ANALYZE")
24
- end
25
-
26
- def self.execute_templates_root
27
- File.join(Dir.pwd, "templates", "EXECUTE")
28
- end
29
-
30
- def self.common_templates_root
31
- File.join(Dir.pwd, "templates", "COMMON")
32
- end
33
- end
34
- end
35
- end
@@ -1,119 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
- require "yaml"
5
-
6
- module Aidp
7
- module Shared
8
- # Detects project type, language, framework, and other characteristics
9
- class ProjectDetector
10
- attr_reader :project_dir
11
-
12
- def initialize(project_dir = Dir.pwd)
13
- @project_dir = project_dir
14
- end
15
-
16
- def detect
17
- {
18
- language: detect_language,
19
- framework: detect_framework,
20
- build_system: detect_build_system,
21
- package_manager: detect_package_manager,
22
- static_analysis_tools: detect_static_analysis_tools,
23
- test_framework: detect_test_framework,
24
- database: detect_database,
25
- deployment: detect_deployment
26
- }
27
- end
28
-
29
- private
30
-
31
- def detect_language
32
- return "ruby" if File.exist?(File.join(@project_dir, "Gemfile"))
33
- return "javascript" if File.exist?(File.join(@project_dir, "package.json"))
34
- return "python" if File.exist?(File.join(@project_dir, "requirements.txt")) || File.exist?(File.join(@project_dir, "pyproject.toml"))
35
- return "java" if File.exist?(File.join(@project_dir, "pom.xml")) || File.exist?(File.join(@project_dir, "build.gradle"))
36
- return "go" if File.exist?(File.join(@project_dir, "go.mod"))
37
- return "rust" if File.exist?(File.join(@project_dir, "Cargo.toml"))
38
- return "csharp" if File.exist?(File.join(@project_dir, "*.csproj"))
39
- "unknown"
40
- end
41
-
42
- def detect_framework
43
- case detect_language
44
- when "ruby"
45
- return "rails" if File.exist?(File.join(@project_dir, "config", "application.rb"))
46
- return "sinatra" if File.exist?(File.join(@project_dir, "app.rb")) && File.read(File.join(@project_dir, "app.rb")).include?("Sinatra")
47
- when "javascript"
48
- return "react" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("react")
49
- return "vue" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("vue")
50
- return "angular" if File.exist?(File.join(@project_dir, "angular.json"))
51
- return "express" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("express")
52
- when "python"
53
- return "django" if File.exist?(File.join(@project_dir, "manage.py"))
54
- return "flask" if File.exist?(File.join(@project_dir, "app.py")) && File.read(File.join(@project_dir, "app.py")).include?("Flask")
55
- when "java"
56
- return "spring" if File.exist?(File.join(@project_dir, "pom.xml")) && File.read(File.join(@project_dir, "pom.xml")).include?("spring-boot")
57
- end
58
- "unknown"
59
- end
60
-
61
- def detect_build_system
62
- return "maven" if File.exist?(File.join(@project_dir, "pom.xml"))
63
- return "gradle" if File.exist?(File.join(@project_dir, "build.gradle"))
64
- return "npm" if File.exist?(File.join(@project_dir, "package.json"))
65
- return "bundler" if File.exist?(File.join(@project_dir, "Gemfile"))
66
- return "pip" if File.exist?(File.join(@project_dir, "requirements.txt"))
67
- return "cargo" if File.exist?(File.join(@project_dir, "Cargo.toml"))
68
- return "go" if File.exist?(File.join(@project_dir, "go.mod"))
69
- "unknown"
70
- end
71
-
72
- def detect_package_manager
73
- detect_build_system
74
- end
75
-
76
- def detect_static_analysis_tools
77
- tools = []
78
- tools << "rubocop" if File.exist?(File.join(@project_dir, ".rubocop.yml"))
79
- tools << "eslint" if File.exist?(File.join(@project_dir, ".eslintrc"))
80
- tools << "flake8" if File.exist?(File.join(@project_dir, ".flake8"))
81
- tools << "checkstyle" if File.exist?(File.join(@project_dir, "checkstyle.xml"))
82
- tools << "clippy" if File.exist?(File.join(@project_dir, "Cargo.toml"))
83
- tools
84
- end
85
-
86
- def detect_test_framework
87
- case detect_language
88
- when "ruby"
89
- return "rspec" if File.exist?(File.join(@project_dir, "spec"))
90
- return "minitest" if File.exist?(File.join(@project_dir, "test"))
91
- when "javascript"
92
- return "jest" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("jest")
93
- return "mocha" if File.exist?(File.join(@project_dir, "package.json")) && File.read(File.join(@project_dir, "package.json")).include?("mocha")
94
- when "python"
95
- return "pytest" if File.exist?(File.join(@project_dir, "pytest.ini"))
96
- return "unittest" if Dir.exist?(File.join(@project_dir, "tests"))
97
- when "java"
98
- return "junit" if File.exist?(File.join(@project_dir, "src", "test"))
99
- end
100
- "unknown"
101
- end
102
-
103
- def detect_database
104
- return "postgresql" if File.exist?(File.join(@project_dir, "config", "database.yml")) && File.read(File.join(@project_dir, "config", "database.yml")).include?("postgresql")
105
- return "mysql" if File.exist?(File.join(@project_dir, "config", "database.yml")) && File.read(File.join(@project_dir, "config", "database.yml")).include?("mysql")
106
- return "sqlite" if File.exist?(File.join(@project_dir, "config", "database.yml")) && File.read(File.join(@project_dir, "config", "database.yml")).include?("sqlite")
107
- "unknown"
108
- end
109
-
110
- def detect_deployment
111
- return "docker" if File.exist?(File.join(@project_dir, "Dockerfile"))
112
- return "kubernetes" if File.exist?(File.join(@project_dir, "k8s")) || File.exist?(File.join(@project_dir, "kubernetes"))
113
- return "heroku" if File.exist?(File.join(@project_dir, "Procfile"))
114
- return "aws" if File.exist?(File.join(@project_dir, "serverless.yml")) || File.exist?(File.join(@project_dir, "template.yaml"))
115
- "unknown"
116
- end
117
- end
118
- end
119
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module Aidp
6
- module Shared
7
- module Providers
8
- class Anthropic < Base
9
- def self.available?
10
- !!Aidp::Shared::Util.which("claude")
11
- end
12
-
13
- def name = "anthropic"
14
-
15
- def send(prompt:, session: nil)
16
- raise "claude CLI not available" unless self.class.available?
17
-
18
- # Use Claude CLI for non-interactive mode
19
- cmd = ["claude", "compose", "--prompt", prompt]
20
- system(*cmd)
21
- :ok
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Aidp
4
- module Shared
5
- module Providers
6
- class Base
7
- def name = raise(NotImplementedError)
8
-
9
- # Send a composed prompt string to the provider.
10
- # Return :ok when command completed successfully,
11
- # Return :interactive when starting an interactive session (for gate steps),
12
- # or return a string if we captured output and the caller should write to a file.
13
- def send(prompt:, session: nil) = raise(NotImplementedError)
14
- end
15
- end
16
- end
17
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "open3"
4
- require "timeout"
5
- require_relative "base"
6
- require_relative "../util"
7
-
8
- module Aidp
9
- module Shared
10
- module Providers
11
- class Cursor < Base
12
- def self.available?
13
- !!Aidp::Shared::Util.which("cursor-agent")
14
- end
15
-
16
- def name = "cursor"
17
-
18
- def send(prompt:, session: nil)
19
- raise "cursor-agent not available" unless self.class.available?
20
-
21
- # Always use non-interactive mode with -p flag
22
- cmd = ["cursor-agent", "-p"]
23
- puts "📝 Sending prompt to cursor-agent"
24
-
25
- # Enable debug output if requested
26
- if ENV["AIDP_DEBUG"]
27
- puts "🔍 Debug mode enabled - showing cursor-agent output"
28
- end
29
-
30
- # Setup logging if log file is specified
31
- log_file = ENV["AIDP_LOG_FILE"]
32
- if log_file
33
- puts "📝 Logging to: #{log_file}"
34
- end
35
-
36
- Open3.popen3(*cmd) do |stdin, stdout, stderr, wait|
37
- # Send the prompt to stdin
38
- stdin.puts prompt
39
- stdin.close
40
-
41
- # Log the prompt if debugging
42
- if ENV["AIDP_DEBUG"] || log_file
43
- prompt_log = "📝 Sending prompt to cursor-agent:\n#{prompt}"
44
- puts prompt_log if ENV["AIDP_DEBUG"]
45
- File.write(log_file, "#{Time.now.iso8601} #{prompt_log}\n", mode: "a") if log_file
46
- end
47
-
48
- # Handle debug output and logging
49
- if ENV["AIDP_DEBUG"] || log_file
50
- # Start threads to capture and display output in real-time
51
- stdout_thread = Thread.new do
52
- stdout.each_line do |line|
53
- output = "📤 cursor-agent: #{line.chomp}"
54
- puts output if ENV["AIDP_DEBUG"]
55
- File.write(log_file, "#{Time.now.iso8601} #{output}\n", mode: "a") if log_file
56
- end
57
- end
58
-
59
- stderr_thread = Thread.new do
60
- stderr.each_line do |line|
61
- output = "❌ cursor-agent error: #{line.chomp}"
62
- puts output if ENV["AIDP_DEBUG"]
63
- File.write(log_file, "#{Time.now.iso8601} #{output}\n", mode: "a") if log_file
64
- end
65
- end
66
- end
67
-
68
- # Wait for completion with a reasonable timeout
69
- begin
70
- Timeout.timeout(300) do # 5 minutes timeout
71
- result = wait.value
72
-
73
- # Stop debug threads
74
- if ENV["AIDP_DEBUG"]
75
- stdout_thread&.kill
76
- stderr_thread&.kill
77
- end
78
-
79
- return :ok if result.success?
80
- raise "cursor-agent failed with exit code #{result.exitstatus}"
81
- end
82
- rescue Timeout::Error
83
- # Stop debug threads
84
- if ENV["AIDP_DEBUG"]
85
- stdout_thread&.kill
86
- stderr_thread&.kill
87
- end
88
-
89
- # Kill the process if it's taking too long
90
- begin
91
- Process.kill("TERM", wait.pid)
92
- rescue
93
- nil
94
- end
95
- raise Timeout::Error, "cursor-agent timed out after 5 minutes"
96
- end
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "base"
4
-
5
- module Aidp
6
- module Shared
7
- module Providers
8
- class Gemini < Base
9
- def self.available?
10
- !!Aidp::Shared::Util.which("gemini")
11
- end
12
-
13
- def name = "gemini"
14
-
15
- def send(prompt:, session: nil)
16
- raise "gemini CLI not available" unless self.class.available?
17
-
18
- # Use Gemini CLI for non-interactive mode
19
- cmd = ["gemini", "chat", "--prompt", prompt]
20
- system(*cmd)
21
- :ok
22
- end
23
- end
24
- end
25
- end
26
- end