grok-cli-acp 0.1.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.
- package/.env.example +42 -0
- package/.github/workflows/ci.yml +30 -0
- package/.github/workflows/rust.yml +22 -0
- package/.grok/.env.example +85 -0
- package/.grok/COMPLETE_FIX_SUMMARY.md +466 -0
- package/.grok/ENV_CONFIG_GUIDE.md +173 -0
- package/.grok/QUICK_REFERENCE.md +180 -0
- package/.grok/README.md +104 -0
- package/.grok/TESTING_GUIDE.md +393 -0
- package/CHANGELOG.md +465 -0
- package/CODE_REVIEW_SUMMARY.md +414 -0
- package/COMPLETE_FIX_SUMMARY.md +415 -0
- package/CONFIGURATION.md +489 -0
- package/CONTEXT_FILES_GUIDE.md +419 -0
- package/CONTRIBUTING.md +55 -0
- package/CURSOR_POSITION_FIX.md +206 -0
- package/Cargo.toml +88 -0
- package/ERROR_HANDLING_REPORT.md +361 -0
- package/FINAL_FIX_SUMMARY.md +462 -0
- package/FIXES.md +37 -0
- package/FIXES_SUMMARY.md +87 -0
- package/GROK_API_MIGRATION_SUMMARY.md +111 -0
- package/LICENSE +22 -0
- package/MIGRATION_TO_GROK_API.md +223 -0
- package/README.md +504 -0
- package/REVIEW_COMPLETE.md +416 -0
- package/REVIEW_QUICK_REFERENCE.md +173 -0
- package/SECURITY.md +463 -0
- package/SECURITY_AUDIT.md +661 -0
- package/SETUP.md +287 -0
- package/TESTING_TOOLS.md +88 -0
- package/TESTING_TOOL_EXECUTION.md +239 -0
- package/TOOL_EXECUTION_FIX.md +491 -0
- package/VERIFICATION_CHECKLIST.md +419 -0
- package/docs/API.md +74 -0
- package/docs/CHAT_LOGGING.md +39 -0
- package/docs/CURSOR_FIX_DEMO.md +306 -0
- package/docs/ERROR_HANDLING_GUIDE.md +547 -0
- package/docs/FILE_OPERATIONS.md +449 -0
- package/docs/INTERACTIVE.md +401 -0
- package/docs/PROJECT_CREATION_GUIDE.md +570 -0
- package/docs/QUICKSTART.md +378 -0
- package/docs/QUICK_REFERENCE.md +691 -0
- package/docs/RELEASE_NOTES_0.1.2.md +240 -0
- package/docs/TOOLS.md +459 -0
- package/docs/TOOLS_QUICK_REFERENCE.md +210 -0
- package/docs/ZED_INTEGRATION.md +371 -0
- package/docs/extensions.md +464 -0
- package/docs/settings.md +293 -0
- package/examples/extensions/logging-hook/README.md +91 -0
- package/examples/extensions/logging-hook/extension.json +22 -0
- package/package.json +30 -0
- package/scripts/test_acp.py +252 -0
- package/scripts/test_acp.sh +143 -0
- package/scripts/test_acp_simple.sh +72 -0
- package/src/acp/mod.rs +741 -0
- package/src/acp/protocol.rs +323 -0
- package/src/acp/security.rs +298 -0
- package/src/acp/tools.rs +697 -0
- package/src/bin/banner_demo.rs +216 -0
- package/src/bin/docgen.rs +18 -0
- package/src/bin/installer.rs +217 -0
- package/src/cli/app.rs +310 -0
- package/src/cli/commands/acp.rs +721 -0
- package/src/cli/commands/chat.rs +485 -0
- package/src/cli/commands/code.rs +513 -0
- package/src/cli/commands/config.rs +394 -0
- package/src/cli/commands/health.rs +442 -0
- package/src/cli/commands/history.rs +421 -0
- package/src/cli/commands/mod.rs +14 -0
- package/src/cli/commands/settings.rs +1384 -0
- package/src/cli/mod.rs +166 -0
- package/src/config/mod.rs +2212 -0
- package/src/display/ascii_art.rs +139 -0
- package/src/display/banner.rs +289 -0
- package/src/display/components/input.rs +323 -0
- package/src/display/components/mod.rs +2 -0
- package/src/display/components/settings_list.rs +306 -0
- package/src/display/interactive.rs +1255 -0
- package/src/display/mod.rs +62 -0
- package/src/display/terminal.rs +42 -0
- package/src/display/tips.rs +316 -0
- package/src/grok_client_ext.rs +177 -0
- package/src/hooks/loader.rs +407 -0
- package/src/hooks/mod.rs +158 -0
- package/src/lib.rs +174 -0
- package/src/main.rs +65 -0
- package/src/mcp/client.rs +195 -0
- package/src/mcp/config.rs +20 -0
- package/src/mcp/mod.rs +6 -0
- package/src/mcp/protocol.rs +67 -0
- package/src/utils/auth.rs +41 -0
- package/src/utils/chat_logger.rs +568 -0
- package/src/utils/context.rs +390 -0
- package/src/utils/mod.rs +16 -0
- package/src/utils/network.rs +320 -0
- package/src/utils/rate_limiter.rs +166 -0
- package/src/utils/session.rs +73 -0
- package/src/utils/shell_permissions.rs +389 -0
- package/src/utils/telemetry.rs +41 -0
package/src/cli/app.rs
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
use anyhow::Result;
|
|
2
|
+
use clap::{Parser, Subcommand};
|
|
3
|
+
use std::path::PathBuf;
|
|
4
|
+
use tracing::{error, info};
|
|
5
|
+
|
|
6
|
+
use crate::config::{Config, ConfigSource};
|
|
7
|
+
use crate::display::banner::{BannerConfig, print_welcome_banner};
|
|
8
|
+
use crate::display::interactive::{InteractiveConfig, PromptStyle, start_interactive_mode};
|
|
9
|
+
use crate::utils::auth::{require_api_key, resolve_api_key};
|
|
10
|
+
use crate::utils::network::test_connectivity;
|
|
11
|
+
|
|
12
|
+
/// Grok CLI - Command-line interface for Grok AI
|
|
13
|
+
#[derive(Parser, Debug)]
|
|
14
|
+
#[command(author, version, about, long_about = None)]
|
|
15
|
+
pub struct Cli {
|
|
16
|
+
/// API key for authentication
|
|
17
|
+
#[arg(short, long, env = "GROK_API_KEY")]
|
|
18
|
+
pub api_key: Option<String>,
|
|
19
|
+
|
|
20
|
+
/// Config file path
|
|
21
|
+
#[arg(short, long)]
|
|
22
|
+
pub config: Option<PathBuf>,
|
|
23
|
+
|
|
24
|
+
/// Hide banner
|
|
25
|
+
#[arg(long)]
|
|
26
|
+
pub hide_banner: bool,
|
|
27
|
+
|
|
28
|
+
/// Model to use
|
|
29
|
+
#[arg(short, long)]
|
|
30
|
+
pub model: Option<String>,
|
|
31
|
+
|
|
32
|
+
#[command(subcommand)]
|
|
33
|
+
pub command: Option<Commands>,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[derive(Subcommand, Debug)]
|
|
37
|
+
pub enum Commands {
|
|
38
|
+
/// Chat with Grok AI
|
|
39
|
+
Chat {
|
|
40
|
+
/// The message to send
|
|
41
|
+
#[arg(required = true)]
|
|
42
|
+
message: Vec<String>,
|
|
43
|
+
|
|
44
|
+
/// Start an interactive chat session
|
|
45
|
+
#[arg(short, long)]
|
|
46
|
+
interactive: bool,
|
|
47
|
+
|
|
48
|
+
/// System prompt to use
|
|
49
|
+
#[arg(short, long)]
|
|
50
|
+
system: Option<String>,
|
|
51
|
+
|
|
52
|
+
/// Temperature for response generation (0.0 to 2.0)
|
|
53
|
+
#[arg(short, long, default_value = "0.7")]
|
|
54
|
+
temperature: f32,
|
|
55
|
+
|
|
56
|
+
/// Maximum tokens in response
|
|
57
|
+
#[arg(long, default_value = "4096")]
|
|
58
|
+
max_tokens: u32,
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/// Code-related operations
|
|
62
|
+
Code {
|
|
63
|
+
#[command(subcommand)]
|
|
64
|
+
action: crate::CodeAction,
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/// ACP (Agent Client Protocol) operations for Zed integration
|
|
68
|
+
Acp {
|
|
69
|
+
#[command(subcommand)]
|
|
70
|
+
action: crate::AcpAction,
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
/// Interactive chat mode
|
|
74
|
+
Interactive,
|
|
75
|
+
|
|
76
|
+
/// Send a single query
|
|
77
|
+
Query {
|
|
78
|
+
/// The question or prompt to send
|
|
79
|
+
#[arg(required = true)]
|
|
80
|
+
prompt: Vec<String>,
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/// Test network connectivity
|
|
84
|
+
TestNetwork {
|
|
85
|
+
/// Timeout in seconds
|
|
86
|
+
#[arg(short, long, default_value = "10")]
|
|
87
|
+
timeout: u64,
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/// Configuration management
|
|
91
|
+
Config {
|
|
92
|
+
#[command(subcommand)]
|
|
93
|
+
action: crate::ConfigAction,
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/// Settings management and configuration
|
|
97
|
+
Settings {
|
|
98
|
+
#[command(subcommand)]
|
|
99
|
+
action: crate::SettingsAction,
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/// Chat history management
|
|
103
|
+
History {
|
|
104
|
+
#[command(subcommand)]
|
|
105
|
+
action: crate::HistoryAction,
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/// Health check and diagnostics
|
|
109
|
+
Health {
|
|
110
|
+
/// Check API connectivity
|
|
111
|
+
#[arg(long)]
|
|
112
|
+
api: bool,
|
|
113
|
+
|
|
114
|
+
/// Check configuration
|
|
115
|
+
#[arg(long)]
|
|
116
|
+
config: bool,
|
|
117
|
+
|
|
118
|
+
/// Check all systems
|
|
119
|
+
#[arg(long)]
|
|
120
|
+
all: bool,
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/// Main application entry point
|
|
125
|
+
pub async fn run() -> Result<()> {
|
|
126
|
+
let cli = Cli::parse();
|
|
127
|
+
let config = if let Some(config_path) = &cli.config {
|
|
128
|
+
// Use explicit config path if provided
|
|
129
|
+
let path_str = config_path
|
|
130
|
+
.to_str()
|
|
131
|
+
.ok_or_else(|| anyhow::anyhow!("Invalid config path: contains non-UTF8 characters"))?;
|
|
132
|
+
Config::load(Some(path_str)).await?
|
|
133
|
+
} else {
|
|
134
|
+
// Use hierarchical loading: project → system → defaults
|
|
135
|
+
match Config::load_hierarchical().await {
|
|
136
|
+
Ok(cfg) => {
|
|
137
|
+
info!("✓ Configuration loaded successfully");
|
|
138
|
+
cfg
|
|
139
|
+
}
|
|
140
|
+
Err(e) => {
|
|
141
|
+
error!("Failed to load hierarchical configuration: {}", e);
|
|
142
|
+
error!("Falling back to default configuration");
|
|
143
|
+
Config {
|
|
144
|
+
config_source: Some(ConfigSource::Default),
|
|
145
|
+
..Config::default()
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Initialize telemetry
|
|
152
|
+
crate::utils::telemetry::init(config.telemetry.enabled, config.telemetry.log_file.clone());
|
|
153
|
+
|
|
154
|
+
// Resolve API key once
|
|
155
|
+
let api_key = resolve_api_key(cli.api_key.clone(), &config);
|
|
156
|
+
|
|
157
|
+
// Resolve model: CLI argument overrides config
|
|
158
|
+
let model = cli.model.as_deref().unwrap_or(&config.default_model);
|
|
159
|
+
|
|
160
|
+
// Show banner function
|
|
161
|
+
let show_banner_fn = || {
|
|
162
|
+
let banner_config = BannerConfig {
|
|
163
|
+
show_banner: true,
|
|
164
|
+
show_tips: true,
|
|
165
|
+
show_updates: true,
|
|
166
|
+
width: None,
|
|
167
|
+
};
|
|
168
|
+
print_welcome_banner(&banner_config);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
match &cli.command {
|
|
172
|
+
Some(Commands::Chat {
|
|
173
|
+
message,
|
|
174
|
+
interactive,
|
|
175
|
+
system,
|
|
176
|
+
temperature,
|
|
177
|
+
max_tokens,
|
|
178
|
+
}) => {
|
|
179
|
+
let api_key = require_api_key(api_key, cli.hide_banner, show_banner_fn);
|
|
180
|
+
crate::cli::commands::chat::handle_chat(crate::cli::commands::chat::ChatOptions {
|
|
181
|
+
message: message.clone(),
|
|
182
|
+
interactive: *interactive,
|
|
183
|
+
system: system.clone(),
|
|
184
|
+
temperature: *temperature,
|
|
185
|
+
max_tokens: *max_tokens,
|
|
186
|
+
api_key: &api_key,
|
|
187
|
+
model,
|
|
188
|
+
timeout_secs: config.timeout_secs,
|
|
189
|
+
max_retries: config.max_retries,
|
|
190
|
+
rate_limit_config: config.rate_limits,
|
|
191
|
+
})
|
|
192
|
+
.await?;
|
|
193
|
+
}
|
|
194
|
+
Some(Commands::Code { action }) => {
|
|
195
|
+
let api_key = require_api_key(api_key, cli.hide_banner, show_banner_fn);
|
|
196
|
+
crate::cli::commands::code::handle_code_action(
|
|
197
|
+
action.clone(),
|
|
198
|
+
&api_key,
|
|
199
|
+
model,
|
|
200
|
+
config.timeout_secs,
|
|
201
|
+
config.max_retries,
|
|
202
|
+
config.rate_limits,
|
|
203
|
+
)
|
|
204
|
+
.await?;
|
|
205
|
+
}
|
|
206
|
+
Some(Commands::Acp { action }) => {
|
|
207
|
+
crate::cli::commands::acp::handle_acp_action(action.clone(), &config).await?;
|
|
208
|
+
}
|
|
209
|
+
Some(Commands::Interactive) => {
|
|
210
|
+
let api_key = require_api_key(api_key, cli.hide_banner, show_banner_fn);
|
|
211
|
+
let interactive_config = InteractiveConfig {
|
|
212
|
+
show_banner: !cli.hide_banner,
|
|
213
|
+
show_tips: true,
|
|
214
|
+
show_status: true,
|
|
215
|
+
auto_save_session: false,
|
|
216
|
+
prompt_style: PromptStyle::Rich,
|
|
217
|
+
check_directory: true,
|
|
218
|
+
};
|
|
219
|
+
start_interactive_mode(&api_key, model, &config, interactive_config).await?;
|
|
220
|
+
}
|
|
221
|
+
Some(Commands::Query { prompt }) => {
|
|
222
|
+
let api_key = require_api_key(api_key, cli.hide_banner, show_banner_fn);
|
|
223
|
+
let query = prompt.join(" ");
|
|
224
|
+
|
|
225
|
+
if !cli.hide_banner {
|
|
226
|
+
show_banner_fn();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
info!("Sending query: {}", query);
|
|
230
|
+
crate::cli::commands::chat::handle_chat(crate::cli::commands::chat::ChatOptions {
|
|
231
|
+
message: vec![query],
|
|
232
|
+
interactive: false,
|
|
233
|
+
system: None,
|
|
234
|
+
temperature: 0.7,
|
|
235
|
+
max_tokens: 4096,
|
|
236
|
+
api_key: &api_key,
|
|
237
|
+
model,
|
|
238
|
+
timeout_secs: config.timeout_secs,
|
|
239
|
+
max_retries: config.max_retries,
|
|
240
|
+
rate_limit_config: config.rate_limits,
|
|
241
|
+
})
|
|
242
|
+
.await?;
|
|
243
|
+
}
|
|
244
|
+
Some(Commands::TestNetwork { timeout }) => {
|
|
245
|
+
if !cli.hide_banner {
|
|
246
|
+
show_banner_fn();
|
|
247
|
+
}
|
|
248
|
+
let timeout_duration = std::time::Duration::from_secs(*timeout);
|
|
249
|
+
match test_connectivity(timeout_duration).await {
|
|
250
|
+
Ok(duration) => {
|
|
251
|
+
println!("✓ Network connectivity test passed in {:?}", duration);
|
|
252
|
+
}
|
|
253
|
+
Err(e) => {
|
|
254
|
+
error!("Network connectivity test failed: {}", e);
|
|
255
|
+
return Err(e);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
Some(Commands::Config { action }) => {
|
|
260
|
+
if !cli.hide_banner {
|
|
261
|
+
show_banner_fn();
|
|
262
|
+
}
|
|
263
|
+
crate::cli::commands::config::handle_config_action(action.clone(), &config).await?;
|
|
264
|
+
}
|
|
265
|
+
Some(Commands::Settings { action }) => {
|
|
266
|
+
if !cli.hide_banner {
|
|
267
|
+
show_banner_fn();
|
|
268
|
+
}
|
|
269
|
+
crate::cli::commands::settings::handle_settings_action(action.clone(), &config).await?;
|
|
270
|
+
}
|
|
271
|
+
Some(Commands::History { action }) => {
|
|
272
|
+
if !cli.hide_banner {
|
|
273
|
+
show_banner_fn();
|
|
274
|
+
}
|
|
275
|
+
crate::cli::commands::history::handle_history_action(action.clone()).await?;
|
|
276
|
+
}
|
|
277
|
+
Some(Commands::Health {
|
|
278
|
+
api,
|
|
279
|
+
config: check_config,
|
|
280
|
+
all,
|
|
281
|
+
}) => {
|
|
282
|
+
let check_api = *api || *all;
|
|
283
|
+
let check_cfg = *check_config || *all;
|
|
284
|
+
crate::cli::commands::health::handle_health_check(
|
|
285
|
+
check_api,
|
|
286
|
+
check_cfg,
|
|
287
|
+
api_key.as_deref(),
|
|
288
|
+
&config,
|
|
289
|
+
model,
|
|
290
|
+
config.timeout_secs,
|
|
291
|
+
)
|
|
292
|
+
.await?;
|
|
293
|
+
}
|
|
294
|
+
None => {
|
|
295
|
+
// Default to interactive mode
|
|
296
|
+
let api_key = require_api_key(api_key, cli.hide_banner, show_banner_fn);
|
|
297
|
+
let interactive_config = InteractiveConfig {
|
|
298
|
+
show_banner: !cli.hide_banner,
|
|
299
|
+
show_tips: true,
|
|
300
|
+
show_status: true,
|
|
301
|
+
auto_save_session: false,
|
|
302
|
+
prompt_style: PromptStyle::Rich,
|
|
303
|
+
check_directory: true,
|
|
304
|
+
};
|
|
305
|
+
start_interactive_mode(&api_key, model, &config, interactive_config).await?;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
Ok(())
|
|
310
|
+
}
|