openclacky 0.5.6 → 0.6.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 +43 -0
- data/docs/ui2-architecture.md +124 -0
- data/lib/clacky/agent.rb +245 -340
- data/lib/clacky/agent_config.rb +1 -7
- data/lib/clacky/cli.rb +156 -397
- data/lib/clacky/client.rb +68 -36
- data/lib/clacky/gitignore_parser.rb +26 -12
- data/lib/clacky/model_pricing.rb +6 -2
- data/lib/clacky/session_manager.rb +6 -2
- data/lib/clacky/tools/glob.rb +65 -9
- data/lib/clacky/tools/grep.rb +4 -120
- data/lib/clacky/tools/run_project.rb +5 -0
- data/lib/clacky/tools/safe_shell.rb +49 -13
- data/lib/clacky/tools/shell.rb +1 -49
- data/lib/clacky/tools/web_fetch.rb +2 -2
- data/lib/clacky/tools/web_search.rb +38 -26
- data/lib/clacky/ui2/README.md +214 -0
- data/lib/clacky/ui2/components/base_component.rb +163 -0
- data/lib/clacky/ui2/components/common_component.rb +89 -0
- data/lib/clacky/ui2/components/inline_input.rb +187 -0
- data/lib/clacky/ui2/components/input_area.rb +1029 -0
- data/lib/clacky/ui2/components/message_component.rb +76 -0
- data/lib/clacky/ui2/components/output_area.rb +112 -0
- data/lib/clacky/ui2/components/todo_area.rb +137 -0
- data/lib/clacky/ui2/components/tool_component.rb +106 -0
- data/lib/clacky/ui2/components/welcome_banner.rb +93 -0
- data/lib/clacky/ui2/layout_manager.rb +331 -0
- data/lib/clacky/ui2/line_editor.rb +201 -0
- data/lib/clacky/ui2/screen_buffer.rb +238 -0
- data/lib/clacky/ui2/theme_manager.rb +68 -0
- data/lib/clacky/ui2/themes/base_theme.rb +99 -0
- data/lib/clacky/ui2/themes/hacker_theme.rb +56 -0
- data/lib/clacky/ui2/themes/minimal_theme.rb +50 -0
- data/lib/clacky/ui2/ui_controller.rb +720 -0
- data/lib/clacky/ui2/view_renderer.rb +160 -0
- data/lib/clacky/ui2.rb +37 -0
- data/lib/clacky/utils/file_ignore_helper.rb +126 -0
- data/lib/clacky/version.rb +1 -1
- data/lib/clacky.rb +1 -6
- metadata +38 -6
- data/lib/clacky/ui/banner.rb +0 -155
- data/lib/clacky/ui/enhanced_prompt.rb +0 -786
- data/lib/clacky/ui/formatter.rb +0 -209
- data/lib/clacky/ui/statusbar.rb +0 -96
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../line_editor"
|
|
4
|
+
|
|
5
|
+
module Clacky
|
|
6
|
+
module UI2
|
|
7
|
+
module Components
|
|
8
|
+
# InlineInput provides inline input for confirmations and simple prompts
|
|
9
|
+
# Renders at the end of output area, not at fixed bottom position
|
|
10
|
+
class InlineInput
|
|
11
|
+
include LineEditor
|
|
12
|
+
|
|
13
|
+
attr_reader :prompt, :default_value
|
|
14
|
+
|
|
15
|
+
def initialize(prompt: "", default: nil)
|
|
16
|
+
initialize_line_editor
|
|
17
|
+
@prompt = prompt
|
|
18
|
+
@default_value = default
|
|
19
|
+
@active = false
|
|
20
|
+
@result_queue = nil
|
|
21
|
+
@paste_counter = 0
|
|
22
|
+
@paste_placeholders = {}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Activate inline input and wait for user input
|
|
26
|
+
# @return [String] User input
|
|
27
|
+
def collect
|
|
28
|
+
@active = true
|
|
29
|
+
@result_queue = Queue.new
|
|
30
|
+
# Don't set default as initial text - start empty
|
|
31
|
+
@result_queue.pop
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Check if active
|
|
35
|
+
def active?
|
|
36
|
+
@active
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Handle keyboard input
|
|
40
|
+
# @param key [Symbol, String] Key input
|
|
41
|
+
# @return [Hash] Result with action
|
|
42
|
+
def handle_key(key)
|
|
43
|
+
return { action: nil } unless @active
|
|
44
|
+
|
|
45
|
+
case key
|
|
46
|
+
when Hash
|
|
47
|
+
if key[:type] == :rapid_input
|
|
48
|
+
# Handle multi-line paste with placeholder
|
|
49
|
+
pasted_text = key[:text]
|
|
50
|
+
pasted_lines = pasted_text.split(/\r\n|\r|\n/)
|
|
51
|
+
|
|
52
|
+
if pasted_lines.size > 1
|
|
53
|
+
# Multi-line paste - use placeholder
|
|
54
|
+
@paste_counter += 1
|
|
55
|
+
placeholder = "[##{@paste_counter} Paste Text]"
|
|
56
|
+
@paste_placeholders[placeholder] = pasted_text
|
|
57
|
+
insert_text(placeholder)
|
|
58
|
+
else
|
|
59
|
+
# Single line - insert directly
|
|
60
|
+
insert_text(pasted_text)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
{ action: :update }
|
|
64
|
+
when :enter
|
|
65
|
+
handle_enter
|
|
66
|
+
when :backspace
|
|
67
|
+
backspace
|
|
68
|
+
{ action: :update }
|
|
69
|
+
when :delete
|
|
70
|
+
delete_char
|
|
71
|
+
{ action: :update }
|
|
72
|
+
when :left_arrow, :ctrl_b
|
|
73
|
+
cursor_left
|
|
74
|
+
{ action: :update }
|
|
75
|
+
when :right_arrow, :ctrl_f
|
|
76
|
+
cursor_right
|
|
77
|
+
{ action: :update }
|
|
78
|
+
when :home, :ctrl_a
|
|
79
|
+
cursor_home
|
|
80
|
+
{ action: :update }
|
|
81
|
+
when :end, :ctrl_e
|
|
82
|
+
cursor_end
|
|
83
|
+
{ action: :update }
|
|
84
|
+
when :ctrl_k
|
|
85
|
+
kill_to_end
|
|
86
|
+
{ action: :update }
|
|
87
|
+
when :ctrl_u
|
|
88
|
+
kill_to_start
|
|
89
|
+
{ action: :update }
|
|
90
|
+
when :ctrl_w
|
|
91
|
+
kill_word
|
|
92
|
+
{ action: :update }
|
|
93
|
+
when :shift_tab
|
|
94
|
+
handle_shift_tab
|
|
95
|
+
when :ctrl_c
|
|
96
|
+
handle_cancel
|
|
97
|
+
when :escape
|
|
98
|
+
handle_cancel
|
|
99
|
+
else
|
|
100
|
+
if key.is_a?(String) && key.length >= 1 && key.ord >= 32
|
|
101
|
+
insert_char(key)
|
|
102
|
+
{ action: :update }
|
|
103
|
+
else
|
|
104
|
+
{ action: nil }
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Render inline input with prompt and cursor
|
|
110
|
+
# @return [String] Rendered line (may wrap to multiple lines)
|
|
111
|
+
def render
|
|
112
|
+
line = render_line_with_cursor
|
|
113
|
+
full_text = "#{@prompt}#{line}"
|
|
114
|
+
|
|
115
|
+
# Calculate terminal width and check if wrapping is needed
|
|
116
|
+
width = TTY::Screen.width
|
|
117
|
+
visible_text = strip_ansi_codes(full_text)
|
|
118
|
+
display_width = calculate_display_width(visible_text)
|
|
119
|
+
|
|
120
|
+
# If no wrapping needed, return as is
|
|
121
|
+
return full_text if display_width <= width
|
|
122
|
+
|
|
123
|
+
# Otherwise, wrap the input (prompt on first line, continuation indented)
|
|
124
|
+
prompt_width = calculate_display_width(strip_ansi_codes(@prompt))
|
|
125
|
+
available_width = width - prompt_width
|
|
126
|
+
|
|
127
|
+
# For simplicity, just return full text and let terminal handle wrapping
|
|
128
|
+
# InlineInput is typically short, so natural wrapping should be fine
|
|
129
|
+
full_text
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Get cursor column position
|
|
133
|
+
# @return [Integer] Column position
|
|
134
|
+
def cursor_col
|
|
135
|
+
cursor_column(@prompt)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Deactivate inline input
|
|
139
|
+
def deactivate
|
|
140
|
+
@active = false
|
|
141
|
+
@result_queue = nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
def handle_enter
|
|
147
|
+
result = expand_placeholders(current_line)
|
|
148
|
+
# If empty and has default, use default
|
|
149
|
+
result = @default_value.to_s if result.empty? && @default_value
|
|
150
|
+
|
|
151
|
+
queue = @result_queue
|
|
152
|
+
deactivate
|
|
153
|
+
queue&.push(result)
|
|
154
|
+
|
|
155
|
+
{ action: :submit, result: result }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def expand_placeholders(text)
|
|
159
|
+
super(text, @paste_placeholders)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def handle_cancel
|
|
163
|
+
queue = @result_queue
|
|
164
|
+
deactivate
|
|
165
|
+
queue&.push(nil)
|
|
166
|
+
|
|
167
|
+
{ action: :cancel }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def handle_shift_tab
|
|
171
|
+
# Auto-confirm as yes (or use default if it's true)
|
|
172
|
+
result = if @default_value == true || @default_value.to_s.downcase == "yes"
|
|
173
|
+
@default_value.to_s
|
|
174
|
+
else
|
|
175
|
+
"yes"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
queue = @result_queue
|
|
179
|
+
deactivate
|
|
180
|
+
queue&.push(result)
|
|
181
|
+
|
|
182
|
+
{ action: :toggle_mode }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|