openclacky 0.6.1 → 0.6.2

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: 9c052d03a1c67251ddb1310bd82b4d1bbee0129716f4e0f2ec664dfdf3b52ced
4
- data.tar.gz: 1d04af0f03f0e03e5ef41a312b2074a8b53a57d2fc9b38f95e73fe3baed3ffd4
3
+ metadata.gz: 84e359dab8c2113e7b9160f92eadff62872bce2a1c1713abee9a2cbf4cac80b1
4
+ data.tar.gz: 604a48aaa45cf5bc79667e9fbd0792626aa578b65d7d0a8b06c5548759d3de39
5
5
  SHA512:
6
- metadata.gz: 6a78384406082c30a41e3546b145230276532567664e2fcf2d6de579a7765966d9ce837629c24b1e35e27f5b9a60b7e1337d6f95981665f74cc99cdee52773ef
7
- data.tar.gz: 6da58385006861fcb511c56febf1a0c81d5f30825354e3610201ea2b4c53a29f0d65fd41cf89447c9347c396de4dadb77f7139e4a69d19d0f5debcc986e5536f
6
+ metadata.gz: 8c037ed1835e6295338b3136795d8be58ad3ae3654d6174c85cc7b05e237094fa8a39c96ec26c16106c6ff2ef382f7e5c88aca8b01da7e0b891ec438c579fd17
7
+ data.tar.gz: ebdd5c9a65cd21fdc7fb47743f3c6b9b5ce9fd0552fabb1a0a1c02554da8c91b9464718e1fd01f5dc18593740c22377ca67e132fd5c4ab67183166a878b039b7
data/CHANGELOG.md CHANGED
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.2] - 2026-01-30
11
+
12
+ ### Added
13
+ - `--theme` CLI option to switch UI themes (hacker, minimal)
14
+ - Support for reading binary files (with 5MB limit)
15
+ - Cost color coding for better visibility
16
+ - Install script for easier installation
17
+ - New command handling improvements
18
+
19
+ ### Improved
20
+ - User input style enhancements
21
+ - Tool execution output simplification
22
+ - Thinking mode output improvements
23
+ - Diff format display with cleaner line numbers
24
+ - Terminal resize handling
25
+
26
+ ### Fixed
27
+ - BadQuotedString parsing error
28
+ - Token counting for every new task
29
+ - Shell output max characters limit
30
+ - Inline input cursor positioning
31
+ - Compress message display (now hidden)
32
+
33
+ ### Removed
34
+ - Redundant output components for cleaner architecture
35
+
10
36
  ## [0.6.1] - 2026-01-29
11
37
 
12
38
  ### Added
data/README.md CHANGED
@@ -18,19 +18,36 @@ OpenClacky = Lovable + Supabase
18
18
 
19
19
  ## Installation
20
20
 
21
- Install the gem by executing:
21
+ ### Quick Install (Recommended)
22
+
23
+ **One-line installation** (auto-detects your system):
22
24
 
23
25
  ```bash
24
- gem install openclacky
26
+ curl -sSL https://raw.githubusercontent.com/clacky-ai/open-clacky/main/scripts/install.sh | bash
25
27
  ```
26
28
 
27
- Or add it to your Gemfile:
29
+ This script will:
30
+ - Check your Ruby version
31
+ - Install via Homebrew (macOS) if available
32
+ - Install via RubyGems if Ruby >= 3.1.0 is installed
33
+ - Guide you to install Ruby if needed
34
+
35
+ ### Method 1: Homebrew (macOS/Linux)
36
+
37
+ **Best for macOS users** - Automatically handles Ruby dependencies:
28
38
 
29
39
  ```bash
30
- bundle add openclacky
40
+ brew tap clacky-ai/openclacky
41
+ brew install openclacky
31
42
  ```
32
43
 
33
- For development from source:
44
+ ### Method 2: RubyGems (If you already have Ruby >= 3.1.0)
45
+
46
+ ```bash
47
+ gem install openclacky
48
+ ```
49
+
50
+ ### Method 3: From Source (For Development)
34
51
 
35
52
  ```bash
36
53
  git clone https://github.com/clacky-ai/open-clacky.git
@@ -39,6 +56,22 @@ bundle install
39
56
  bin/clacky
40
57
  ```
41
58
 
59
+ ### System Requirements
60
+
61
+ - **Ruby**: >= 3.1.0 (automatically handled by Homebrew)
62
+ - **OS**: macOS, Linux, or Windows (WSL)
63
+
64
+ ### Uninstallation
65
+
66
+ ```bash
67
+ # Quick uninstall
68
+ curl -sSL https://raw.githubusercontent.com/clacky-ai/open-clacky/main/scripts/uninstall.sh | bash
69
+
70
+ # Or manually
71
+ brew uninstall openclacky # If installed via Homebrew
72
+ gem uninstall openclacky # If installed via gem
73
+ ```
74
+
42
75
  ## Configuration
43
76
 
44
77
  Before using Clacky, you need to configure your settings:
@@ -60,32 +93,6 @@ clacky config show
60
93
 
61
94
  ## Usage
62
95
 
63
- ### Interactive Chat Mode
64
-
65
- Start an interactive chat session:
66
-
67
- ```bash
68
- clacky chat
69
- ```
70
-
71
- Type your messages and press Enter. Type `exit` or `quit` to end the session.
72
-
73
- ### Single Message Mode
74
-
75
- Send a single message and get a response:
76
-
77
- ```bash
78
- clacky chat "What is Ruby?"
79
- ```
80
-
81
- ### Specify Model
82
-
83
- You can specify which model to use (overrides config):
84
-
85
- ```bash
86
- clacky chat --model=gpt-4 "Hello!"
87
- ```
88
-
89
96
  ### AI Agent Mode (Interactive)
90
97
 
91
98
  Run an autonomous AI agent in interactive mode. The agent can use tools to complete tasks and runs in a continuous loop, allowing you to have multi-turn conversations with tool use capabilities.
@@ -103,22 +110,10 @@ clacky agent --mode=auto_approve
103
110
  # Work in a specific project directory
104
111
  clacky agent --path /path/to/project
105
112
 
106
- # Limit tools available to the agent
107
- clacky agent --tools file_reader glob grep
108
- ```
109
-
110
- The agent will:
111
- 1. Complete each task using its React (Reason-Act-Observe) cycle
112
- 2. Show you the results
113
- 3. Wait for your next instruction
114
- 4. Maintain conversation context across tasks
115
- 5. Type 'exit' or 'quit' to end the session
116
-
117
113
  #### Permission Modes
118
114
 
119
- - `confirm_all` (default) - Confirm every tool use
120
- - `confirm_edits` - Auto-approve read-only tools, confirm edits
121
115
  - `auto_approve` - Automatically execute all tools (use with caution)
116
+ - `confirm_safes` - Auto-approve read-only tools, confirm edits
122
117
  - `plan_only` - Generate plan without executing
123
118
 
124
119
  #### Agent Options
@@ -126,9 +121,6 @@ The agent will:
126
121
  ```bash
127
122
  --path PATH # Project directory (defaults to current directory)
128
123
  --mode MODE # Permission mode
129
- --tools TOOL1 TOOL2 # Allowed tools (or "all")
130
- --max-iterations N # Maximum iterations (default: 50)
131
- --max-cost N # Maximum cost in USD (default: 5.0)
132
124
  --verbose # Show detailed output
133
125
  ```
134
126
 
@@ -138,30 +130,17 @@ The agent includes intelligent cost control features:
138
130
 
139
131
  - **Automatic Message Compression**: When conversation history grows beyond 100 messages, the agent automatically compresses older messages into a summary, keeping only the system prompt and the most recent 20 messages. This dramatically reduces token costs for long-running tasks (achieves ~60% compression ratio).
140
132
 
141
- - **Configurable Limits**:
142
- - `max_iterations`: Maximum number of agent loops (default: 200)
143
- - `max_cost_usd`: Maximum total cost in USD (default: $5.00)
144
- - `timeout_seconds`: Maximum execution time (default: none)
145
-
146
133
  - **Compression Settings**:
147
134
  - `enable_compression`: Enable/disable automatic compression (default: true)
148
135
  - `keep_recent_messages`: Number of recent messages to preserve (default: 20)
149
136
  - Compression triggers at: ~100 messages (keep_recent_messages + 80)
150
137
 
151
- Example with custom limits:
152
- ```bash
153
- clacky agent --max-iterations=100 --max-cost=10.0 --verbose
154
- ```
155
-
156
138
  ### List Available Tools
157
139
 
158
140
  View all built-in tools:
159
141
 
160
142
  ```bash
161
143
  clacky tools
162
-
163
- # Filter by category
164
- clacky tools --category file_system
165
144
  ```
166
145
 
167
146
  #### Built-in Tools
@@ -173,14 +152,12 @@ clacky tools --category file_system
173
152
  - **glob** - Find files by pattern matching
174
153
  - **grep** - Search file contents with regex
175
154
  - **shell** - Execute shell commands
176
- - **calculator** - Perform mathematical calculations
177
155
  - **web_search** - Search the web for information
178
156
  - **web_fetch** - Fetch and parse web page content
179
157
 
180
158
  ### Available Commands
181
159
 
182
160
  ```bash
183
- clacky chat [MESSAGE] # Start a chat or send a single message
184
161
  clacky agent [MESSAGE] # Run autonomous agent with tool use
185
162
  clacky tools # List available tools
186
163
  clacky config set # Set your API key
@@ -191,19 +168,6 @@ clacky help # Show help information
191
168
 
192
169
  ## Examples
193
170
 
194
- ### Chat Examples
195
-
196
- ```bash
197
- # Quick question
198
- clacky chat "Explain closures in Ruby"
199
-
200
- # Start interactive session
201
- clacky chat
202
-
203
- # Check version
204
- clacky version
205
- ```
206
-
207
171
  ### Agent Examples
208
172
 
209
173
  ```bash
@@ -214,25 +178,12 @@ clacky agent
214
178
  # > Now add more items to the TODO list
215
179
  # > exit
216
180
 
217
- # Start with initial task, then continue
218
- clacky agent "Add a .gitignore file for Ruby projects"
219
- # After completing, agent waits for next task
220
- # > List all Ruby files
221
- # > Count lines in each file
222
- # > exit
223
-
224
181
  # Auto-approve mode for trusted operations
225
182
  clacky agent --mode=auto_approve --path ~/my-project
226
183
  # > Count all lines of code
227
184
  # > Create a summary report
228
185
  # > exit
229
186
 
230
- # Use specific tools only in interactive mode
231
- clacky agent --tools file_reader glob grep
232
- # > Find all TODO comments
233
- # > Search for FIXME comments
234
- # > exit
235
-
236
187
  # Using TODO manager for complex tasks
237
188
  clacky agent "Implement a new feature with user authentication"
238
189
  # Agent will:
@@ -0,0 +1,96 @@
1
+ # Homebrew Formula for OpenClacky
2
+
3
+ This directory contains the Homebrew formula for OpenClacky.
4
+
5
+ ## For Maintainers: Publishing to Homebrew Tap
6
+
7
+ ### One-time Setup
8
+
9
+ 1. Create a GitHub repository named `homebrew-openclacky` (must start with `homebrew-`)
10
+ 2. Push this formula to the repository
11
+
12
+ ```bash
13
+ # In your GitHub account, create: homebrew-openclacky
14
+ git clone https://github.com/YOUR_USERNAME/homebrew-openclacky.git
15
+ cd homebrew-openclacky
16
+ cp /path/to/openclacky/homebrew/openclacky.rb ./Formula/openclacky.rb
17
+ git add Formula/openclacky.rb
18
+ git commit -m "Add openclacky formula"
19
+ git push origin main
20
+ ```
21
+
22
+ ### Update Formula for New Release
23
+
24
+ When you release a new version:
25
+
26
+ 1. Download the new gem and calculate SHA256:
27
+ ```bash
28
+ VERSION=0.6.1
29
+ wget https://rubygems.org/downloads/openclacky-${VERSION}.gem
30
+ shasum -a 256 openclacky-${VERSION}.gem
31
+ ```
32
+
33
+ 2. Update the formula in `homebrew-openclacky` repository:
34
+ - Update `url` with new version
35
+ - Update `sha256` with calculated hash
36
+ - Commit and push
37
+
38
+ 3. Users can then upgrade:
39
+ ```bash
40
+ brew update
41
+ brew upgrade openclacky
42
+ ```
43
+
44
+ ## For Users: Installation
45
+
46
+ ```bash
47
+ # Add the tap (one-time)
48
+ brew tap YOUR_USERNAME/openclacky
49
+
50
+ # Install
51
+ brew install openclacky
52
+
53
+ # Or in one command
54
+ brew install YOUR_USERNAME/openclacky/openclacky
55
+ ```
56
+
57
+ ## Testing the Formula Locally
58
+
59
+ ```bash
60
+ # Install from local formula
61
+ brew install --build-from-source ./homebrew/openclacky.rb
62
+
63
+ # Or test without installing
64
+ brew test ./homebrew/openclacky.rb
65
+ ```
66
+
67
+ ## Automation Script
68
+
69
+ For easier updates, use this script:
70
+
71
+ ```bash
72
+ #!/bin/bash
73
+ # update_formula.sh
74
+
75
+ VERSION=$1
76
+ if [ -z "$VERSION" ]; then
77
+ echo "Usage: ./update_formula.sh VERSION"
78
+ exit 1
79
+ fi
80
+
81
+ # Download gem
82
+ wget https://rubygems.org/downloads/openclacky-${VERSION}.gem -O /tmp/openclacky.gem
83
+
84
+ # Calculate SHA256
85
+ SHA256=$(shasum -a 256 /tmp/openclacky.gem | cut -d' ' -f1)
86
+
87
+ # Update formula
88
+ sed -i '' "s|url \".*\"|url \"https://rubygems.org/downloads/openclacky-${VERSION}.gem\"|" openclacky.rb
89
+ sed -i '' "s|sha256 \".*\"|sha256 \"${SHA256}\"|" openclacky.rb
90
+
91
+ echo "Formula updated to version ${VERSION}"
92
+ echo "SHA256: ${SHA256}"
93
+ echo "Don't forget to commit and push to homebrew-openclacky repository!"
94
+
95
+ rm /tmp/openclacky.gem
96
+ ```
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Openclacky < Formula
4
+ desc "Command-line interface for AI models with autonomous agent capabilities"
5
+ homepage "https://github.com/clacky-ai/open-clacky"
6
+ url "https://rubygems.org/downloads/openclacky-0.6.1.gem"
7
+ sha256 "" # Will be updated when gem is published
8
+ license "MIT"
9
+
10
+ depends_on "ruby@3.3"
11
+
12
+ def install
13
+ ENV["GEM_HOME"] = libexec
14
+ system "gem", "install", cached_download, "--no-document"
15
+
16
+ # Create wrapper scripts
17
+ (bin/"openclacky").write_env_script libexec/"bin/openclacky", GEM_HOME: ENV["GEM_HOME"]
18
+ (bin/"clacky").write_env_script libexec/"bin/clacky", GEM_HOME: ENV["GEM_HOME"]
19
+ end
20
+
21
+ test do
22
+ assert_match "openclacky version #{version}", shell_output("#{bin}/openclacky version")
23
+ end
24
+ end
data/lib/clacky/agent.rb CHANGED
@@ -4,8 +4,8 @@ require "securerandom"
4
4
  require "json"
5
5
  require "tty-prompt"
6
6
  require "set"
7
- require "base64"
8
7
  require_relative "utils/arguments_parser"
8
+ require_relative "utils/file_processor"
9
9
 
10
10
  module Clacky
11
11
  class Agent
@@ -137,7 +137,7 @@ module Clacky
137
137
  user_messages = @messages.select do |m|
138
138
  m[:role] == "user" && !m[:system_injected]
139
139
  end
140
-
140
+
141
141
  # Extract text content from the last N user messages
142
142
  user_messages.last(limit).map do |msg|
143
143
  extract_text_from_content(msg[:content])
@@ -163,10 +163,11 @@ module Clacky
163
163
  def run(user_input, images: [])
164
164
  @start_time = Time.now
165
165
  @task_cost_source = :estimated # Reset for new task
166
- @previous_total_tokens = 0 # Reset token tracking for new task
166
+ # Note: Do NOT reset @previous_total_tokens here - it should maintain the value from the last iteration
167
+ # across tasks to correctly calculate delta tokens in each iteration
167
168
  @task_start_iterations = @iterations # Track starting iterations for this task
168
169
  @task_start_cost = @total_cost # Track starting cost for this task
169
-
170
+
170
171
  # Track cache stats for current task
171
172
  @task_cache_stats = {
172
173
  cache_creation_input_tokens: 0,
@@ -538,7 +539,7 @@ module Clacky
538
539
  denial_message += ": #{confirmation[:feedback]}"
539
540
  end
540
541
  @ui&.show_warning(denial_message)
541
-
542
+
542
543
  denied = true
543
544
  user_feedback = confirmation[:feedback]
544
545
  feedback = user_feedback if user_feedback
@@ -666,7 +667,7 @@ module Clacky
666
667
  # Check if the command is a slow command
667
668
  command = args[:command] || args['command']
668
669
  return false unless command
669
-
670
+
670
671
  # List of slow command patterns
671
672
  slow_patterns = [
672
673
  /bundle\s+(install|exec\s+rspec|exec\s+rake)/,
@@ -679,7 +680,7 @@ module Clacky
679
680
  /pytest/,
680
681
  /jest/
681
682
  ]
682
-
683
+
683
684
  slow_patterns.any? { |pattern| command.match?(pattern) }
684
685
  when 'web_fetch', 'web_search'
685
686
  true # Network operations can be slow
@@ -692,11 +693,7 @@ module Clacky
692
693
  private def build_tool_progress_message(tool_name, args)
693
694
  case tool_name.to_s.downcase
694
695
  when 'shell', 'safe_shell'
695
- command = args[:command] || args['command']
696
- # Extract the main command for display
697
- cmd_parts = command.to_s.split
698
- main_cmd = cmd_parts.first(2).join(' ')
699
- "Running #{main_cmd}"
696
+ "Running command"
700
697
  when 'web_fetch'
701
698
  "Fetching web page"
702
699
  when 'web_search'
@@ -755,15 +752,15 @@ module Clacky
755
752
  @cache_stats[:raw_api_usage_samples] << raw_api_usage
756
753
  @cache_stats[:raw_api_usage_samples] = @cache_stats[:raw_api_usage_samples].last(3)
757
754
  end
758
-
755
+
759
756
  # Track cache usage for current task
760
757
  if @task_cache_stats
761
758
  @task_cache_stats[:total_requests] += 1
762
-
759
+
763
760
  if usage[:cache_creation_input_tokens]
764
761
  @task_cache_stats[:cache_creation_input_tokens] += usage[:cache_creation_input_tokens]
765
762
  end
766
-
763
+
767
764
  if usage[:cache_read_input_tokens]
768
765
  @task_cache_stats[:cache_read_input_tokens] += usage[:cache_read_input_tokens]
769
766
  @task_cache_stats[:cache_hit_requests] += 1
@@ -957,7 +954,8 @@ module Clacky
957
954
 
958
955
  {
959
956
  role: "user",
960
- content: "[SYSTEM] " + summary_text
957
+ content: "[SYSTEM] " + summary_text,
958
+ system_injected: true
961
959
  }
962
960
  end
963
961
 
@@ -1200,10 +1198,10 @@ module Clacky
1200
1198
  def build_result(status, error: nil)
1201
1199
  # Calculate iterations for current task only
1202
1200
  task_iterations = @iterations - (@task_start_iterations || 0)
1203
-
1201
+
1204
1202
  # Calculate cost for current task only
1205
1203
  task_cost = @total_cost - (@task_start_cost || 0)
1206
-
1204
+
1207
1205
  {
1208
1206
  status: status,
1209
1207
  session_id: @session_id,
@@ -1257,64 +1255,13 @@ module Clacky
1257
1255
  content << { type: "text", text: text } unless text.nil? || text.empty?
1258
1256
 
1259
1257
  images.each do |image_path|
1260
- image_url = image_path_to_data_url(image_path)
1258
+ image_url = Utils::FileProcessor.image_path_to_data_url(image_path)
1261
1259
  content << { type: "image_url", image_url: { url: image_url } }
1262
1260
  end
1263
1261
 
1264
1262
  content
1265
1263
  end
1266
1264
 
1267
- # Convert image file path to base64 data URL
1268
- # @param path [String] File path to image
1269
- # @return [String] base64 data URL (e.g., "data:image/png;base64,...")
1270
- def image_path_to_data_url(path)
1271
- unless File.exist?(path)
1272
- raise ArgumentError, "Image file not found: #{path}"
1273
- end
1274
-
1275
- # Read file as binary
1276
- image_data = File.binread(path)
1277
-
1278
- # Detect MIME type from file extension or content
1279
- mime_type = detect_image_mime_type(path, image_data)
1280
-
1281
- # Encode to base64
1282
- base64_data = Base64.strict_encode64(image_data)
1283
-
1284
- "data:#{mime_type};base64,#{base64_data}"
1285
- end
1286
1265
 
1287
- # Detect image MIME type
1288
- # @param path [String] File path
1289
- # @param data [String] Binary image data
1290
- # @return [String] MIME type (e.g., "image/png")
1291
- def detect_image_mime_type(path, data)
1292
- # Try to detect from file extension first
1293
- ext = File.extname(path).downcase
1294
- case ext
1295
- when ".png"
1296
- "image/png"
1297
- when ".jpg", ".jpeg"
1298
- "image/jpeg"
1299
- when ".gif"
1300
- "image/gif"
1301
- when ".webp"
1302
- "image/webp"
1303
- else
1304
- # Try to detect from file signature (magic bytes)
1305
- if data.start_with?("\x89PNG".b)
1306
- "image/png"
1307
- elsif data.start_with?("\xFF\xD8\xFF".b)
1308
- "image/jpeg"
1309
- elsif data.start_with?("GIF87a".b) || data.start_with?("GIF89a".b)
1310
- "image/gif"
1311
- elsif data.start_with?("RIFF".b) && data[8..11] == "WEBP".b
1312
- "image/webp"
1313
- else
1314
- # Default to png if unknown
1315
- "image/png"
1316
- end
1317
- end
1318
- end
1319
1266
  end
1320
1267
  end
data/lib/clacky/cli.rb CHANGED
@@ -32,6 +32,10 @@ module Clacky
32
32
  confirm_edits - Auto-approve read-only tools, confirm edits
33
33
  plan_only - Generate plan without executing
34
34
 
35
+ UI themes:
36
+ hacker - Matrix/hacker-style with bracket symbols (default)
37
+ minimal - Clean, simple symbols
38
+
35
39
  Session management:
36
40
  -c, --continue - Continue the most recent session for this directory
37
41
  -l, --list - List recent sessions
@@ -42,6 +46,8 @@ module Clacky
42
46
  LONGDESC
43
47
  option :mode, type: :string, default: "confirm_safes",
44
48
  desc: "Permission mode: auto_approve, confirm_safes, confirm_edits, plan_only"
49
+ option :theme, type: :string, default: "hacker",
50
+ desc: "UI theme: hacker, minimal (default: hacker)"
45
51
  option :verbose, type: :boolean, aliases: "-v", default: false, desc: "Show detailed output"
46
52
  option :path, type: :string, desc: "Project directory path (defaults to current directory)"
47
53
  option :continue, type: :boolean, aliases: "-c", desc: "Continue most recent session"
@@ -127,6 +133,80 @@ module Clacky
127
133
  end
128
134
  end
129
135
 
136
+ desc "new PROJECT_NAME", "Create a new Rails project from the official template"
137
+ long_desc <<-LONGDESC
138
+ Create a new Rails project from the official template.
139
+
140
+ This command will:
141
+ 1. Clone the template from git@github.com:clacky-ai/rails-template-7x-starter.git
142
+ 2. Change into the project directory
143
+ 3. Run bin/setup to install dependencies and configure the project
144
+
145
+ Example:
146
+ $ clacky new my_rails_app
147
+ LONGDESC
148
+ def new(project_name = nil)
149
+ unless project_name
150
+ say "Error: Project name is required.", :red
151
+ say "Usage: clacky new <project_name>", :yellow
152
+ exit 1
153
+ end
154
+
155
+ # Validate project name
156
+ unless project_name.match?(/^[a-zA-Z][a-zA-Z0-9_-]*$/)
157
+ say "Error: Invalid project name. Use only letters, numbers, underscores, and hyphens.", :red
158
+ exit 1
159
+ end
160
+
161
+ template_repo = "git@github.com:clacky-ai/rails-template-7x-starter.git"
162
+ current_dir = Dir.pwd
163
+ target_dir = File.join(current_dir, project_name)
164
+
165
+ # Check if target directory already exists
166
+ if Dir.exist?(target_dir)
167
+ say "Error: Directory '#{project_name}' already exists.", :red
168
+ exit 1
169
+ end
170
+
171
+ say "Creating new Rails project: #{project_name}", :green
172
+
173
+ # Clone the template repository
174
+ say "\nšŸ“¦ Cloning template repository...", :cyan
175
+ clone_command = "git clone #{template_repo} #{project_name}"
176
+
177
+ clone_result = system(clone_command)
178
+
179
+ unless clone_result
180
+ say "\nāŒ Failed to clone repository. Please check your git configuration and network connection.", :red
181
+ exit 1
182
+ end
183
+
184
+ say "āœ“ Repository cloned successfully", :green
185
+
186
+ # Run bin/setup
187
+ say "\nāš™ļø Running bin/setup...", :cyan
188
+
189
+ Dir.chdir(target_dir)
190
+
191
+ setup_command = "./bin/setup"
192
+
193
+ setup_result = system(setup_command)
194
+
195
+ Dir.chdir(current_dir)
196
+
197
+ unless setup_result
198
+ say "\nāŒ Failed to run bin/setup. Please check the setup script for errors.", :red
199
+ say "You can try running it manually:", :yellow
200
+ say " cd #{project_name} && ./bin/setup", :cyan
201
+ exit 1
202
+ end
203
+
204
+ say "\nāœ… Project '#{project_name}' created successfully!", :green
205
+ say "\nNext steps:", :green
206
+ say " cd #{project_name}", :cyan
207
+ say " clacky agent", :cyan
208
+ end
209
+
130
210
  desc "price", "Show pricing information for AI models"
131
211
  def price
132
212
  say "\nšŸ’° Model Pricing Information\n\n", :green
@@ -300,11 +380,20 @@ module Clacky
300
380
 
301
381
  # Run agent with UI2 split-screen interface
302
382
  def run_agent_with_ui2(agent, working_dir, agent_config, initial_message = nil, session_manager = nil, client = nil, is_session_load: false)
383
+ # Validate theme
384
+ theme_name = options[:theme] || "hacker"
385
+ available_themes = UI2::ThemeManager.available_themes.map(&:to_s)
386
+ unless available_themes.include?(theme_name)
387
+ say "Error: Unknown theme '#{theme_name}'. Available themes: #{available_themes.join(', ')}", :red
388
+ exit 1
389
+ end
390
+
303
391
  # Create UI2 controller with configuration
304
392
  ui_controller = UI2::UIController.new(
305
393
  working_dir: working_dir,
306
394
  mode: agent_config.permission_mode.to_s,
307
- model: agent_config.model
395
+ model: agent_config.model,
396
+ theme: theme_name
308
397
  )
309
398
 
310
399
  # Inject UI into agent