jules-ruby 0.0.67

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/.jules/bolt.md +4 -0
  3. data/.rubocop.yml +51 -0
  4. data/AGENTS.md +250 -0
  5. data/CHANGELOG.md +20 -0
  6. data/CONTRIBUTING.md +82 -0
  7. data/LICENSE +21 -0
  8. data/README.md +330 -0
  9. data/Rakefile +70 -0
  10. data/SECURITY.md +41 -0
  11. data/assets/banner.png +0 -0
  12. data/bin/jules-ruby +7 -0
  13. data/jules-ruby.gemspec +43 -0
  14. data/lib/jules-ruby/cli/activities.rb +142 -0
  15. data/lib/jules-ruby/cli/banner.rb +113 -0
  16. data/lib/jules-ruby/cli/base.rb +38 -0
  17. data/lib/jules-ruby/cli/interactive/activity_renderer.rb +81 -0
  18. data/lib/jules-ruby/cli/interactive/session_creator.rb +112 -0
  19. data/lib/jules-ruby/cli/interactive/session_manager.rb +285 -0
  20. data/lib/jules-ruby/cli/interactive/source_manager.rb +65 -0
  21. data/lib/jules-ruby/cli/interactive.rb +48 -0
  22. data/lib/jules-ruby/cli/prompts.rb +184 -0
  23. data/lib/jules-ruby/cli/sessions.rb +185 -0
  24. data/lib/jules-ruby/cli/sources.rb +72 -0
  25. data/lib/jules-ruby/cli.rb +127 -0
  26. data/lib/jules-ruby/client.rb +130 -0
  27. data/lib/jules-ruby/configuration.rb +20 -0
  28. data/lib/jules-ruby/errors.rb +35 -0
  29. data/lib/jules-ruby/models/activity.rb +137 -0
  30. data/lib/jules-ruby/models/artifact.rb +78 -0
  31. data/lib/jules-ruby/models/github_branch.rb +17 -0
  32. data/lib/jules-ruby/models/github_repo.rb +31 -0
  33. data/lib/jules-ruby/models/plan.rb +23 -0
  34. data/lib/jules-ruby/models/plan_step.rb +25 -0
  35. data/lib/jules-ruby/models/pull_request.rb +23 -0
  36. data/lib/jules-ruby/models/session.rb +111 -0
  37. data/lib/jules-ruby/models/source.rb +23 -0
  38. data/lib/jules-ruby/models/source_context.rb +35 -0
  39. data/lib/jules-ruby/resources/activities.rb +76 -0
  40. data/lib/jules-ruby/resources/base.rb +27 -0
  41. data/lib/jules-ruby/resources/sessions.rb +125 -0
  42. data/lib/jules-ruby/resources/sources.rb +61 -0
  43. data/lib/jules-ruby/version.rb +5 -0
  44. data/lib/jules-ruby.rb +43 -0
  45. data/mise.toml +2 -0
  46. metadata +232 -0
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JulesRuby
4
+ module Resources
5
+ class Activities < Base
6
+ # List activities for a session
7
+ #
8
+ # @param session_name [String] The session name (e.g., "sessions/123") or just the ID
9
+ # @param page_token [String, nil] Token for pagination
10
+ # @param page_size [Integer, nil] Number of results per page
11
+ # @return [Hash] Response with :activities array and :next_page_token
12
+ def list(session_name, page_token: nil, page_size: nil)
13
+ path = "#{normalize_session_path(session_name)}/activities"
14
+ params = {
15
+ pageToken: page_token,
16
+ pageSize: page_size
17
+ }.compact
18
+
19
+ response = get(path, params: params)
20
+
21
+ {
22
+ activities: (response['activities'] || []).map { |a| Models::Activity.new(a) },
23
+ next_page_token: response['nextPageToken']
24
+ }
25
+ end
26
+
27
+ # Get a specific activity by name
28
+ #
29
+ # @param name [String] The full activity name (e.g., "sessions/123/activities/abc")
30
+ # @return [Models::Activity] The activity object
31
+ def find(name)
32
+ path = name.start_with?('/') ? name : "/#{name}"
33
+ response = get(path)
34
+ Models::Activity.new(response)
35
+ end
36
+
37
+ # List all activities for a session with automatic pagination
38
+ #
39
+ # @param session_name [String] The session name or ID
40
+ # @yield [Models::Activity] Each activity
41
+ # @return [Enumerator] If no block given
42
+ def each(session_name, &block)
43
+ return enum_for(:each, session_name) unless block_given?
44
+
45
+ page_token = nil
46
+ loop do
47
+ result = list(session_name, page_token: page_token)
48
+ result[:activities].each(&block)
49
+
50
+ page_token = result[:next_page_token]
51
+ break if page_token.nil? || page_token.empty?
52
+ end
53
+ end
54
+
55
+ # Get all activities for a session as an array
56
+ #
57
+ # @param session_name [String] The session name or ID
58
+ # @return [Array<Models::Activity>]
59
+ def all(session_name)
60
+ each(session_name).to_a
61
+ end
62
+
63
+ private
64
+
65
+ def normalize_session_path(name)
66
+ if name.start_with?('sessions/')
67
+ "/#{name}"
68
+ elsif name.start_with?('/sessions/')
69
+ name
70
+ else
71
+ "/sessions/#{name}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JulesRuby
4
+ module Resources
5
+ class Base
6
+ attr_reader :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ private
13
+
14
+ def get(path, params: {})
15
+ client.get(path, params: params)
16
+ end
17
+
18
+ def post(path, body: {})
19
+ client.post(path, body: body)
20
+ end
21
+
22
+ def delete(path)
23
+ client.delete(path)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JulesRuby
4
+ module Resources
5
+ class Sessions < Base
6
+ # List all sessions
7
+ #
8
+ # @param page_token [String, nil] Token for pagination
9
+ # @param page_size [Integer, nil] Number of results per page
10
+ # @return [Hash] Response with :sessions array and :next_page_token
11
+ def list(page_token: nil, page_size: nil)
12
+ params = {
13
+ pageToken: page_token,
14
+ pageSize: page_size
15
+ }.compact
16
+
17
+ response = get('/sessions', params: params)
18
+
19
+ {
20
+ sessions: (response['sessions'] || []).map { |s| Models::Session.new(s) },
21
+ next_page_token: response['nextPageToken']
22
+ }
23
+ end
24
+
25
+ # Get a specific session by name or ID
26
+ #
27
+ # @param name [String] The session name (e.g., "sessions/123") or just the ID
28
+ # @return [Models::Session] The session object
29
+ def find(name)
30
+ path = normalize_session_path(name)
31
+ response = get(path)
32
+ Models::Session.new(response)
33
+ end
34
+
35
+ # Create a new session
36
+ #
37
+ # @param prompt [String] The prompt to start the session with
38
+ # @param source_context [Hash] The source context (use SourceContext.build helper)
39
+ # @param title [String, nil] Optional title for the session
40
+ # @param require_plan_approval [Boolean, nil] If true, plans require explicit approval
41
+ # @param automation_mode [String, nil] e.g., "AUTO_CREATE_PR"
42
+ # @return [Models::Session] The created session
43
+ def create(prompt:, source_context:, title: nil, require_plan_approval: nil, automation_mode: nil)
44
+ body = {
45
+ 'prompt' => prompt,
46
+ 'sourceContext' => source_context
47
+ }
48
+
49
+ body['title'] = title if title
50
+ body['requirePlanApproval'] = require_plan_approval unless require_plan_approval.nil?
51
+ body['automationMode'] = automation_mode if automation_mode
52
+
53
+ response = post('/sessions', body: body)
54
+ Models::Session.new(response)
55
+ end
56
+
57
+ # Approve the current plan for a session
58
+ #
59
+ # @param session_name [String] The session name (e.g., "sessions/123") or just the ID
60
+ # @return [Models::Session] The updated session
61
+ def approve_plan(session_name)
62
+ path = "#{normalize_session_path(session_name)}:approvePlan"
63
+ response = post(path, body: {})
64
+ Models::Session.new(response)
65
+ end
66
+
67
+ # Send a message to a session
68
+ #
69
+ # @param session_name [String] The session name (e.g., "sessions/123") or just the ID
70
+ # @param prompt [String] The message to send
71
+ # @return [Models::Session] The updated session
72
+ def send_message(session_name, prompt:)
73
+ path = "#{normalize_session_path(session_name)}:sendMessage"
74
+ response = post(path, body: { 'prompt' => prompt })
75
+ Models::Session.new(response)
76
+ end
77
+
78
+ # Delete a session
79
+ #
80
+ # @param session_name [String] The session name (e.g., "sessions/123") or just the ID
81
+ # @return [void]
82
+ def destroy(session_name)
83
+ path = normalize_session_path(session_name)
84
+ delete(path)
85
+ nil
86
+ end
87
+
88
+ # List all sessions with automatic pagination
89
+ #
90
+ # @yield [Models::Session] Each session
91
+ # @return [Enumerator] If no block given
92
+ def each(&block)
93
+ return enum_for(:each) unless block_given?
94
+
95
+ page_token = nil
96
+ loop do
97
+ result = list(page_token: page_token)
98
+ result[:sessions].each(&block)
99
+
100
+ page_token = result[:next_page_token]
101
+ break if page_token.nil? || page_token.empty?
102
+ end
103
+ end
104
+
105
+ # Get all sessions as an array
106
+ #
107
+ # @return [Array<Models::Session>]
108
+ def all
109
+ each.to_a
110
+ end
111
+
112
+ private
113
+
114
+ def normalize_session_path(name)
115
+ if name.start_with?('sessions/')
116
+ "/#{name}"
117
+ elsif name.start_with?('/sessions/')
118
+ name
119
+ else
120
+ "/sessions/#{name}"
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JulesRuby
4
+ module Resources
5
+ class Sources < Base
6
+ # List all available sources (connected repositories)
7
+ #
8
+ # @param page_token [String, nil] Token for pagination
9
+ # @param page_size [Integer, nil] Number of results per page
10
+ # @return [Hash] Response with :sources array and :next_page_token
11
+ def list(page_token: nil, page_size: nil)
12
+ params = {
13
+ pageToken: page_token,
14
+ pageSize: page_size
15
+ }.compact
16
+
17
+ response = get('/sources', params: params)
18
+
19
+ {
20
+ sources: (response['sources'] || []).map { |s| Models::Source.new(s) },
21
+ next_page_token: response['nextPageToken']
22
+ }
23
+ end
24
+
25
+ # Get a specific source by name
26
+ #
27
+ # @param name [String] The full resource name (e.g., "sources/github/owner/repo")
28
+ # @return [Models::Source] The source object
29
+ def find(name)
30
+ # Ensure the name has the correct format
31
+ path = name.start_with?('/') ? name : "/#{name}"
32
+ response = get(path)
33
+ Models::Source.new(response)
34
+ end
35
+
36
+ # List all sources with automatic pagination
37
+ #
38
+ # @yield [Models::Source] Each source
39
+ # @return [Enumerator] If no block given
40
+ def each(&block)
41
+ return enum_for(:each) unless block_given?
42
+
43
+ page_token = nil
44
+ loop do
45
+ result = list(page_token: page_token)
46
+ result[:sources].each(&block)
47
+
48
+ page_token = result[:next_page_token]
49
+ break if page_token.nil? || page_token.empty?
50
+ end
51
+ end
52
+
53
+ # Get all sources as an array
54
+ #
55
+ # @return [Array<Models::Source>]
56
+ def all
57
+ each.to_a
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JulesRuby
4
+ VERSION = '0.1.0'
5
+ end
data/lib/jules-ruby.rb ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dotenv'
4
+ Dotenv.load
5
+
6
+ require_relative 'jules-ruby/version'
7
+ require_relative 'jules-ruby/configuration'
8
+ require_relative 'jules-ruby/errors'
9
+ require_relative 'jules-ruby/client'
10
+
11
+ # Models
12
+ require_relative 'jules-ruby/models/github_repo'
13
+ require_relative 'jules-ruby/models/github_branch'
14
+ require_relative 'jules-ruby/models/source'
15
+ require_relative 'jules-ruby/models/source_context'
16
+ require_relative 'jules-ruby/models/session'
17
+ require_relative 'jules-ruby/models/pull_request'
18
+ require_relative 'jules-ruby/models/plan'
19
+ require_relative 'jules-ruby/models/plan_step'
20
+ require_relative 'jules-ruby/models/artifact'
21
+ require_relative 'jules-ruby/models/activity'
22
+
23
+ # Resources
24
+ require_relative 'jules-ruby/resources/base'
25
+ require_relative 'jules-ruby/resources/sources'
26
+ require_relative 'jules-ruby/resources/sessions'
27
+ require_relative 'jules-ruby/resources/activities'
28
+
29
+ module JulesRuby
30
+ class << self
31
+ attr_accessor :configuration
32
+
33
+ def configure
34
+ self.configuration ||= Configuration.new
35
+ yield(configuration) if block_given?
36
+ configuration
37
+ end
38
+
39
+ def reset_configuration!
40
+ self.configuration = Configuration.new
41
+ end
42
+ end
43
+ end
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = 'latest'
metadata ADDED
@@ -0,0 +1,232 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jules-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.67
5
+ platform: ruby
6
+ authors:
7
+ - Taylor Weibley
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: async-http
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.75'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.75'
26
+ - !ruby/object:Gem::Dependency
27
+ name: dotenv
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: thor
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.3'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.3'
54
+ - !ruby/object:Gem::Dependency
55
+ name: tty-prompt
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.23'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.23'
68
+ - !ruby/object:Gem::Dependency
69
+ name: tty-spinner
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.9'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.9'
82
+ - !ruby/object:Gem::Dependency
83
+ name: pastel
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.8'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.8'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rspec
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '3.0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: webmock
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '3.0'
117
+ type: :development
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: rubocop
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '1.0'
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.0'
138
+ - !ruby/object:Gem::Dependency
139
+ name: simplecov
140
+ requirement: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '0.22'
145
+ type: :development
146
+ prerelease: false
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '0.22'
152
+ description: A Ruby gem for interacting with the Jules API to programmatically create
153
+ and manage asynchronous coding tasks.
154
+ email:
155
+ - tweibley@gmail.com
156
+ executables:
157
+ - jules-ruby
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - ".jules/bolt.md"
162
+ - ".rubocop.yml"
163
+ - AGENTS.md
164
+ - CHANGELOG.md
165
+ - CONTRIBUTING.md
166
+ - LICENSE
167
+ - README.md
168
+ - Rakefile
169
+ - SECURITY.md
170
+ - assets/banner.png
171
+ - bin/jules-ruby
172
+ - jules-ruby.gemspec
173
+ - lib/jules-ruby.rb
174
+ - lib/jules-ruby/cli.rb
175
+ - lib/jules-ruby/cli/activities.rb
176
+ - lib/jules-ruby/cli/banner.rb
177
+ - lib/jules-ruby/cli/base.rb
178
+ - lib/jules-ruby/cli/interactive.rb
179
+ - lib/jules-ruby/cli/interactive/activity_renderer.rb
180
+ - lib/jules-ruby/cli/interactive/session_creator.rb
181
+ - lib/jules-ruby/cli/interactive/session_manager.rb
182
+ - lib/jules-ruby/cli/interactive/source_manager.rb
183
+ - lib/jules-ruby/cli/prompts.rb
184
+ - lib/jules-ruby/cli/sessions.rb
185
+ - lib/jules-ruby/cli/sources.rb
186
+ - lib/jules-ruby/client.rb
187
+ - lib/jules-ruby/configuration.rb
188
+ - lib/jules-ruby/errors.rb
189
+ - lib/jules-ruby/models/activity.rb
190
+ - lib/jules-ruby/models/artifact.rb
191
+ - lib/jules-ruby/models/github_branch.rb
192
+ - lib/jules-ruby/models/github_repo.rb
193
+ - lib/jules-ruby/models/plan.rb
194
+ - lib/jules-ruby/models/plan_step.rb
195
+ - lib/jules-ruby/models/pull_request.rb
196
+ - lib/jules-ruby/models/session.rb
197
+ - lib/jules-ruby/models/source.rb
198
+ - lib/jules-ruby/models/source_context.rb
199
+ - lib/jules-ruby/resources/activities.rb
200
+ - lib/jules-ruby/resources/base.rb
201
+ - lib/jules-ruby/resources/sessions.rb
202
+ - lib/jules-ruby/resources/sources.rb
203
+ - lib/jules-ruby/version.rb
204
+ - mise.toml
205
+ homepage: https://github.com/tweibley/jules-ruby
206
+ licenses:
207
+ - MIT
208
+ metadata:
209
+ homepage_uri: https://github.com/tweibley/jules-ruby
210
+ source_code_uri: https://github.com/tweibley/jules-ruby
211
+ changelog_uri: https://github.com/tweibley/jules-ruby/blob/main/CHANGELOG.md
212
+ bug_tracker_uri: https://github.com/tweibley/jules-ruby/issues
213
+ documentation_uri: https://github.com/tweibley/jules-ruby#readme
214
+ rubygems_mfa_required: 'true'
215
+ rdoc_options: []
216
+ require_paths:
217
+ - lib
218
+ required_ruby_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: 3.0.0
223
+ required_rubygems_version: !ruby/object:Gem::Requirement
224
+ requirements:
225
+ - - ">="
226
+ - !ruby/object:Gem::Version
227
+ version: '0'
228
+ requirements: []
229
+ rubygems_version: 3.6.7
230
+ specification_version: 4
231
+ summary: Ruby CLI for the Jules API
232
+ test_files: []