girb 0.1.2 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/README.md +283 -129
- data/README_ja.md +280 -126
- data/lib/girb/ai_client.rb +209 -29
- data/lib/girb/auto_continue.rb +33 -0
- data/lib/girb/conversation_history.rb +8 -7
- data/lib/girb/debug_context_builder.rb +113 -0
- data/lib/girb/debug_integration.rb +426 -0
- data/lib/girb/debug_prompt_builder.rb +241 -0
- data/lib/girb/debug_session_history.rb +121 -0
- data/lib/girb/exception_capture.rb +4 -0
- data/lib/girb/girbrc_loader.rb +15 -9
- data/lib/girb/irb_integration.rb +233 -1
- data/lib/girb/prompt_builder.rb +156 -46
- data/lib/girb/session_persistence.rb +170 -0
- data/lib/girb/tools/continue_analysis.rb +45 -0
- data/lib/girb/tools/debug_session_history_tool.rb +132 -0
- data/lib/girb/tools/evaluate_code.rb +24 -3
- data/lib/girb/tools/run_debug_command.rb +49 -0
- data/lib/girb/tools/run_irb_debug_command.rb +58 -0
- data/lib/girb/tools/session_history_tool.rb +46 -8
- data/lib/girb/tools.rb +23 -2
- data/lib/girb/version.rb +1 -1
- data/lib/girb.rb +24 -7
- data/lib/irb/command/qq.rb +48 -6
- metadata +11 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Girb
|
|
6
|
+
module Tools
|
|
7
|
+
class RunDebugCommand < Base
|
|
8
|
+
class << self
|
|
9
|
+
def description
|
|
10
|
+
"Execute a debugger command. Use this tool whenever the user asks to step, continue, set breakpoints, or perform any debugger action. " \
|
|
11
|
+
"For conditional breakpoints, use 'if:' (with colon): e.g., 'break sample.rb:14 if: x == 1'."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def parameters
|
|
15
|
+
{
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
command: {
|
|
19
|
+
type: "string",
|
|
20
|
+
description: "The debugger command to execute. Examples: 'n', 's', 'c', 'finish', 'up', 'down', " \
|
|
21
|
+
"'break sample.rb:14', 'break sample.rb:14 if: x == 1', 'info locals', 'bt'"
|
|
22
|
+
},
|
|
23
|
+
auto_continue: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
description: "Set to true if you want to be re-invoked after the command executes " \
|
|
26
|
+
"to see the new state. Use this when you need to check variables or " \
|
|
27
|
+
"decide the next action after stepping/continuing."
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
required: ["command"]
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def available?
|
|
35
|
+
defined?(DEBUGGER__)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def execute(binding, command:, auto_continue: false)
|
|
40
|
+
Girb::DebugIntegration.add_pending_debug_command(command)
|
|
41
|
+
Girb::DebugIntegration.auto_continue = true if auto_continue
|
|
42
|
+
{ success: true, command: command, auto_continue: auto_continue,
|
|
43
|
+
message: auto_continue ?
|
|
44
|
+
"Command '#{command}' will be executed. You will be re-invoked with updated context." :
|
|
45
|
+
"Command '#{command}' will be executed after this response." }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Girb
|
|
6
|
+
module Tools
|
|
7
|
+
class RunIrbDebugCommand < Base
|
|
8
|
+
class << self
|
|
9
|
+
def name
|
|
10
|
+
"run_debug_command"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def description
|
|
14
|
+
"Execute a debug command in IRB. IRB integrates with debug gem, allowing step-by-step debugging. " \
|
|
15
|
+
"Use this when the user asks to step through code, set breakpoints, or navigate execution."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def parameters
|
|
19
|
+
{
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
command: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description: "The debug command to execute. Examples: 'next', 'step', 'continue', 'finish', " \
|
|
25
|
+
"'break sample.rb:14', 'break sample.rb:14 if: x == 1', 'info', 'backtrace'"
|
|
26
|
+
},
|
|
27
|
+
auto_continue: {
|
|
28
|
+
type: "boolean",
|
|
29
|
+
description: "Set to true to be re-invoked after the command executes to see the new state."
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
required: ["command"]
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def available?
|
|
37
|
+
# Available in IRB mode (not in active debug session)
|
|
38
|
+
# DEBUGGER__::SESSION indicates an active debug session
|
|
39
|
+
defined?(IRB) && !defined?(DEBUGGER__::SESSION)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def execute(binding, command:, auto_continue: false)
|
|
44
|
+
Girb::IrbIntegration.add_pending_irb_command(command)
|
|
45
|
+
Girb::AutoContinue.request! if auto_continue
|
|
46
|
+
|
|
47
|
+
{
|
|
48
|
+
success: true,
|
|
49
|
+
command: command,
|
|
50
|
+
auto_continue: auto_continue,
|
|
51
|
+
message: auto_continue ?
|
|
52
|
+
"Command '#{command}' will be executed. You will be re-invoked with updated context." :
|
|
53
|
+
"Command '#{command}' will be executed after this response."
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "base"
|
|
4
4
|
require_relative "../session_history"
|
|
5
|
+
require_relative "../conversation_history"
|
|
6
|
+
require_relative "../session_persistence"
|
|
5
7
|
|
|
6
8
|
module Girb
|
|
7
9
|
module Tools
|
|
@@ -12,7 +14,13 @@ module Girb
|
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
def description
|
|
15
|
-
"Get IRB session history
|
|
17
|
+
"Get IRB session history including AI conversations from previous sessions (if persisted). " \
|
|
18
|
+
"Can retrieve specific lines, line ranges, method definitions, AI conversation details, or full history."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def available?
|
|
22
|
+
# Only available in IRB mode, not in debug mode
|
|
23
|
+
!defined?(DEBUGGER__)
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
def parameters
|
|
@@ -146,21 +154,51 @@ module Girb
|
|
|
146
154
|
end
|
|
147
155
|
|
|
148
156
|
def list_ai_conversations
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
all_conversations = []
|
|
158
|
+
|
|
159
|
+
# 永続化されたセッションからの会話
|
|
160
|
+
persisted = get_persisted_conversations
|
|
161
|
+
all_conversations.concat(persisted)
|
|
162
|
+
|
|
163
|
+
# 現在のセッションの会話
|
|
164
|
+
current = SessionHistory.ai_conversations.map do |c|
|
|
151
165
|
{
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
line: c[:line_no],
|
|
167
|
+
question: c[:question],
|
|
168
|
+
response: c[:response] || "",
|
|
169
|
+
source: "current_session"
|
|
170
|
+
}
|
|
171
|
+
end
|
|
172
|
+
all_conversations.concat(current)
|
|
173
|
+
|
|
174
|
+
if all_conversations.any?
|
|
175
|
+
{
|
|
176
|
+
count: all_conversations.size,
|
|
177
|
+
conversations: all_conversations.map do |c|
|
|
178
|
+
response = c[:response] || ""
|
|
154
179
|
{
|
|
155
|
-
line: c[:
|
|
180
|
+
line: c[:line],
|
|
156
181
|
question: c[:question],
|
|
157
|
-
response_preview:
|
|
182
|
+
response_preview: response.length > 200 ? "#{response[0, 200]}..." : response,
|
|
183
|
+
source: c[:source] || "persisted"
|
|
158
184
|
}
|
|
159
185
|
end
|
|
160
186
|
}
|
|
161
187
|
else
|
|
162
|
-
{ message: "No AI conversations in
|
|
188
|
+
{ message: "No AI conversations in session history" }
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def get_persisted_conversations
|
|
193
|
+
conversations = []
|
|
194
|
+
ConversationHistory.messages.each do |msg|
|
|
195
|
+
if msg.role == "user"
|
|
196
|
+
conversations << { question: msg.content, source: "persisted" }
|
|
197
|
+
elsif msg.role == "model" && conversations.last && !conversations.last[:response]
|
|
198
|
+
conversations.last[:response] = msg.content
|
|
199
|
+
end
|
|
163
200
|
end
|
|
201
|
+
conversations
|
|
164
202
|
end
|
|
165
203
|
|
|
166
204
|
def get_ai_detail(line)
|
data/lib/girb/tools.rb
CHANGED
|
@@ -8,15 +8,36 @@ require_relative "tools/evaluate_code"
|
|
|
8
8
|
require_relative "tools/read_file"
|
|
9
9
|
require_relative "tools/find_file"
|
|
10
10
|
require_relative "tools/session_history_tool"
|
|
11
|
+
require_relative "tools/debug_session_history_tool"
|
|
11
12
|
require_relative "tools/environment_tools"
|
|
13
|
+
require_relative "tools/continue_analysis"
|
|
14
|
+
require_relative "tools/run_irb_debug_command"
|
|
12
15
|
|
|
13
16
|
module Girb
|
|
14
17
|
module Tools
|
|
15
|
-
|
|
18
|
+
# Shared tools available in both IRB and debug modes
|
|
19
|
+
SHARED_TOOLS = [InspectObject, GetSource, ListMethods, EvaluateCode, ReadFile, FindFile, GetCurrentDirectory].freeze
|
|
20
|
+
|
|
21
|
+
# IRB-only tools
|
|
22
|
+
IRB_TOOLS = [SessionHistoryTool, ContinueAnalysis, RunIrbDebugCommand].freeze
|
|
23
|
+
|
|
24
|
+
# Debug-only tools (RunDebugCommand is registered separately in DebugIntegration)
|
|
25
|
+
DEBUG_TOOLS = [DebugSessionHistoryTool].freeze
|
|
26
|
+
|
|
27
|
+
# All core tools (used for backward compatibility)
|
|
28
|
+
CORE_TOOLS = (SHARED_TOOLS + IRB_TOOLS + DEBUG_TOOLS).freeze
|
|
16
29
|
|
|
17
30
|
class << self
|
|
31
|
+
def registered_tools
|
|
32
|
+
@registered_tools ||= []
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def register(tool_class)
|
|
36
|
+
registered_tools << tool_class unless registered_tools.include?(tool_class)
|
|
37
|
+
end
|
|
38
|
+
|
|
18
39
|
def available_tools
|
|
19
|
-
tools = CORE_TOOLS.dup
|
|
40
|
+
tools = CORE_TOOLS.dup + registered_tools
|
|
20
41
|
|
|
21
42
|
# Rails tools are loaded conditionally
|
|
22
43
|
if defined?(Rails)
|
data/lib/girb/version.rb
CHANGED
data/lib/girb.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Girb
|
|
|
17
17
|
class ApiError < Error; end
|
|
18
18
|
|
|
19
19
|
class << self
|
|
20
|
-
attr_accessor :configuration
|
|
20
|
+
attr_accessor :configuration, :debug_session
|
|
21
21
|
|
|
22
22
|
def configure
|
|
23
23
|
self.configuration ||= Configuration.new
|
|
@@ -41,17 +41,34 @@ end
|
|
|
41
41
|
# Rails がロードされていたら Railtie を組み込む
|
|
42
42
|
require_relative "girb/railtie" if defined?(Rails::Railtie)
|
|
43
43
|
|
|
44
|
+
# debug gem がロードされていたら DebugIntegration を組み込む
|
|
45
|
+
if defined?(DEBUGGER__)
|
|
46
|
+
Girb.configure unless Girb.configuration
|
|
47
|
+
Girb::GirbrcLoader.load_girbrc
|
|
48
|
+
require_relative "girb/debug_integration"
|
|
49
|
+
Girb::DebugIntegration.setup
|
|
50
|
+
end
|
|
51
|
+
|
|
44
52
|
# binding.girb サポート
|
|
45
53
|
class Binding
|
|
46
|
-
def girb
|
|
54
|
+
def girb(show_code: true)
|
|
47
55
|
require "irb"
|
|
48
56
|
Girb.setup! unless defined?(IRB::Command::Qq)
|
|
49
57
|
|
|
50
|
-
#
|
|
51
|
-
|
|
58
|
+
# .girbrcを読み込む(プロバイダー設定)
|
|
59
|
+
Girb::GirbrcLoader.load_girbrc unless Girb.configuration&.provider
|
|
60
|
+
|
|
61
|
+
# キーバインドを再設定(IRBセッション開始前に確実に設定)
|
|
62
|
+
Girb::IrbIntegration.install_ai_keybinding
|
|
63
|
+
|
|
64
|
+
# 標準のbinding.irbと同じ方法でIRBを起動
|
|
65
|
+
IRB.setup(source_location[0], argv: []) unless IRB.initialized?
|
|
52
66
|
workspace = IRB::WorkSpace.new(self)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
STDOUT.print(workspace.code_around_binding) if show_code
|
|
68
|
+
|
|
69
|
+
binding_irb = IRB::Irb.new(workspace, from_binding: true)
|
|
70
|
+
binding_irb.context.irb_path = File.expand_path(source_location[0])
|
|
71
|
+
binding_irb.run(IRB.conf)
|
|
72
|
+
binding_irb.debug_break
|
|
56
73
|
end
|
|
57
74
|
end
|
data/lib/irb/command/qq.rb
CHANGED
|
@@ -12,17 +12,29 @@ module IRB
|
|
|
12
12
|
question = question.to_s.strip
|
|
13
13
|
if question.empty?
|
|
14
14
|
puts "[girb] Usage: qq \"your question here\""
|
|
15
|
+
puts "[girb] qq session clear - Clear current session"
|
|
16
|
+
puts "[girb] qq session list - List saved sessions"
|
|
15
17
|
return
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
puts "[girb] Or configure in your .irbrc:"
|
|
22
|
-
puts "[girb] Girb.configure { |c| c.gemini_api_key = 'your-key' }"
|
|
20
|
+
# セッション管理コマンド
|
|
21
|
+
if question.start_with?("session ")
|
|
22
|
+
handle_session_command(question.sub(/^session\s+/, ""))
|
|
23
23
|
return
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
unless Girb.configuration&.provider
|
|
27
|
+
puts "[girb] Error: No LLM provider configured."
|
|
28
|
+
puts "[girb] Install a provider gem and configure it:"
|
|
29
|
+
puts "[girb] gem install girb-ruby_llm"
|
|
30
|
+
puts "[girb] export GIRB_MODEL=gemini-2.5-flash"
|
|
31
|
+
puts "[girb] export GEMINI_API_KEY=your-key"
|
|
32
|
+
return
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# セッションが有効なら開始
|
|
36
|
+
Girb::IrbIntegration.start_session! if Girb::SessionPersistence.enabled?
|
|
37
|
+
|
|
26
38
|
current_binding = irb_context.workspace.binding
|
|
27
39
|
|
|
28
40
|
# AI質問を履歴に記録
|
|
@@ -41,13 +53,43 @@ module IRB
|
|
|
41
53
|
end
|
|
42
54
|
|
|
43
55
|
client = Girb::AiClient.new
|
|
44
|
-
client.ask(question, context, binding: current_binding, line_no: line_no)
|
|
56
|
+
client.ask(question, context, binding: current_binding, line_no: line_no, irb_context: irb_context)
|
|
45
57
|
rescue Girb::Error => e
|
|
46
58
|
puts "[girb] Error: #{e.message}"
|
|
47
59
|
rescue StandardError => e
|
|
48
60
|
puts "[girb] Error: #{e.message}"
|
|
49
61
|
puts e.backtrace.first(5).join("\n") if Girb.configuration&.debug
|
|
50
62
|
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def handle_session_command(cmd)
|
|
67
|
+
case cmd.strip
|
|
68
|
+
when "clear"
|
|
69
|
+
Girb::SessionPersistence.clear_session
|
|
70
|
+
when "list"
|
|
71
|
+
sessions = Girb::SessionPersistence.list_sessions
|
|
72
|
+
if sessions.empty?
|
|
73
|
+
puts "[girb] No saved sessions"
|
|
74
|
+
else
|
|
75
|
+
puts "[girb] Saved sessions:"
|
|
76
|
+
sessions.each do |s|
|
|
77
|
+
puts " - #{s[:id]} (#{s[:message_count]} messages, saved: #{s[:saved_at]})"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
when "status"
|
|
81
|
+
if Girb::SessionPersistence.current_session_id
|
|
82
|
+
puts "[girb] Current session: #{Girb::SessionPersistence.current_session_id}"
|
|
83
|
+
elsif Girb.debug_session
|
|
84
|
+
puts "[girb] Session configured: #{Girb.debug_session} (not started)"
|
|
85
|
+
else
|
|
86
|
+
puts "[girb] No session configured (use Girb.debug_session = 'name' to enable)"
|
|
87
|
+
end
|
|
88
|
+
else
|
|
89
|
+
puts "[girb] Unknown session command: #{cmd}"
|
|
90
|
+
puts "[girb] Available: clear, list, status"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
51
93
|
end
|
|
52
94
|
end
|
|
53
95
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: girb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- rira100000000
|
|
@@ -84,9 +84,14 @@ files:
|
|
|
84
84
|
- exe/girb
|
|
85
85
|
- lib/girb.rb
|
|
86
86
|
- lib/girb/ai_client.rb
|
|
87
|
+
- lib/girb/auto_continue.rb
|
|
87
88
|
- lib/girb/configuration.rb
|
|
88
89
|
- lib/girb/context_builder.rb
|
|
89
90
|
- lib/girb/conversation_history.rb
|
|
91
|
+
- lib/girb/debug_context_builder.rb
|
|
92
|
+
- lib/girb/debug_integration.rb
|
|
93
|
+
- lib/girb/debug_prompt_builder.rb
|
|
94
|
+
- lib/girb/debug_session_history.rb
|
|
90
95
|
- lib/girb/exception_capture.rb
|
|
91
96
|
- lib/girb/girbrc_loader.rb
|
|
92
97
|
- lib/girb/irb_integration.rb
|
|
@@ -94,8 +99,11 @@ files:
|
|
|
94
99
|
- lib/girb/providers/base.rb
|
|
95
100
|
- lib/girb/railtie.rb
|
|
96
101
|
- lib/girb/session_history.rb
|
|
102
|
+
- lib/girb/session_persistence.rb
|
|
97
103
|
- lib/girb/tools.rb
|
|
98
104
|
- lib/girb/tools/base.rb
|
|
105
|
+
- lib/girb/tools/continue_analysis.rb
|
|
106
|
+
- lib/girb/tools/debug_session_history_tool.rb
|
|
99
107
|
- lib/girb/tools/environment_tools.rb
|
|
100
108
|
- lib/girb/tools/evaluate_code.rb
|
|
101
109
|
- lib/girb/tools/find_file.rb
|
|
@@ -104,6 +112,8 @@ files:
|
|
|
104
112
|
- lib/girb/tools/list_methods.rb
|
|
105
113
|
- lib/girb/tools/rails_tools.rb
|
|
106
114
|
- lib/girb/tools/read_file.rb
|
|
115
|
+
- lib/girb/tools/run_debug_command.rb
|
|
116
|
+
- lib/girb/tools/run_irb_debug_command.rb
|
|
107
117
|
- lib/girb/tools/session_history_tool.rb
|
|
108
118
|
- lib/girb/version.rb
|
|
109
119
|
- lib/irb/command/qq.rb
|