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.
Files changed (100) hide show
  1. package/.env.example +42 -0
  2. package/.github/workflows/ci.yml +30 -0
  3. package/.github/workflows/rust.yml +22 -0
  4. package/.grok/.env.example +85 -0
  5. package/.grok/COMPLETE_FIX_SUMMARY.md +466 -0
  6. package/.grok/ENV_CONFIG_GUIDE.md +173 -0
  7. package/.grok/QUICK_REFERENCE.md +180 -0
  8. package/.grok/README.md +104 -0
  9. package/.grok/TESTING_GUIDE.md +393 -0
  10. package/CHANGELOG.md +465 -0
  11. package/CODE_REVIEW_SUMMARY.md +414 -0
  12. package/COMPLETE_FIX_SUMMARY.md +415 -0
  13. package/CONFIGURATION.md +489 -0
  14. package/CONTEXT_FILES_GUIDE.md +419 -0
  15. package/CONTRIBUTING.md +55 -0
  16. package/CURSOR_POSITION_FIX.md +206 -0
  17. package/Cargo.toml +88 -0
  18. package/ERROR_HANDLING_REPORT.md +361 -0
  19. package/FINAL_FIX_SUMMARY.md +462 -0
  20. package/FIXES.md +37 -0
  21. package/FIXES_SUMMARY.md +87 -0
  22. package/GROK_API_MIGRATION_SUMMARY.md +111 -0
  23. package/LICENSE +22 -0
  24. package/MIGRATION_TO_GROK_API.md +223 -0
  25. package/README.md +504 -0
  26. package/REVIEW_COMPLETE.md +416 -0
  27. package/REVIEW_QUICK_REFERENCE.md +173 -0
  28. package/SECURITY.md +463 -0
  29. package/SECURITY_AUDIT.md +661 -0
  30. package/SETUP.md +287 -0
  31. package/TESTING_TOOLS.md +88 -0
  32. package/TESTING_TOOL_EXECUTION.md +239 -0
  33. package/TOOL_EXECUTION_FIX.md +491 -0
  34. package/VERIFICATION_CHECKLIST.md +419 -0
  35. package/docs/API.md +74 -0
  36. package/docs/CHAT_LOGGING.md +39 -0
  37. package/docs/CURSOR_FIX_DEMO.md +306 -0
  38. package/docs/ERROR_HANDLING_GUIDE.md +547 -0
  39. package/docs/FILE_OPERATIONS.md +449 -0
  40. package/docs/INTERACTIVE.md +401 -0
  41. package/docs/PROJECT_CREATION_GUIDE.md +570 -0
  42. package/docs/QUICKSTART.md +378 -0
  43. package/docs/QUICK_REFERENCE.md +691 -0
  44. package/docs/RELEASE_NOTES_0.1.2.md +240 -0
  45. package/docs/TOOLS.md +459 -0
  46. package/docs/TOOLS_QUICK_REFERENCE.md +210 -0
  47. package/docs/ZED_INTEGRATION.md +371 -0
  48. package/docs/extensions.md +464 -0
  49. package/docs/settings.md +293 -0
  50. package/examples/extensions/logging-hook/README.md +91 -0
  51. package/examples/extensions/logging-hook/extension.json +22 -0
  52. package/package.json +30 -0
  53. package/scripts/test_acp.py +252 -0
  54. package/scripts/test_acp.sh +143 -0
  55. package/scripts/test_acp_simple.sh +72 -0
  56. package/src/acp/mod.rs +741 -0
  57. package/src/acp/protocol.rs +323 -0
  58. package/src/acp/security.rs +298 -0
  59. package/src/acp/tools.rs +697 -0
  60. package/src/bin/banner_demo.rs +216 -0
  61. package/src/bin/docgen.rs +18 -0
  62. package/src/bin/installer.rs +217 -0
  63. package/src/cli/app.rs +310 -0
  64. package/src/cli/commands/acp.rs +721 -0
  65. package/src/cli/commands/chat.rs +485 -0
  66. package/src/cli/commands/code.rs +513 -0
  67. package/src/cli/commands/config.rs +394 -0
  68. package/src/cli/commands/health.rs +442 -0
  69. package/src/cli/commands/history.rs +421 -0
  70. package/src/cli/commands/mod.rs +14 -0
  71. package/src/cli/commands/settings.rs +1384 -0
  72. package/src/cli/mod.rs +166 -0
  73. package/src/config/mod.rs +2212 -0
  74. package/src/display/ascii_art.rs +139 -0
  75. package/src/display/banner.rs +289 -0
  76. package/src/display/components/input.rs +323 -0
  77. package/src/display/components/mod.rs +2 -0
  78. package/src/display/components/settings_list.rs +306 -0
  79. package/src/display/interactive.rs +1255 -0
  80. package/src/display/mod.rs +62 -0
  81. package/src/display/terminal.rs +42 -0
  82. package/src/display/tips.rs +316 -0
  83. package/src/grok_client_ext.rs +177 -0
  84. package/src/hooks/loader.rs +407 -0
  85. package/src/hooks/mod.rs +158 -0
  86. package/src/lib.rs +174 -0
  87. package/src/main.rs +65 -0
  88. package/src/mcp/client.rs +195 -0
  89. package/src/mcp/config.rs +20 -0
  90. package/src/mcp/mod.rs +6 -0
  91. package/src/mcp/protocol.rs +67 -0
  92. package/src/utils/auth.rs +41 -0
  93. package/src/utils/chat_logger.rs +568 -0
  94. package/src/utils/context.rs +390 -0
  95. package/src/utils/mod.rs +16 -0
  96. package/src/utils/network.rs +320 -0
  97. package/src/utils/rate_limiter.rs +166 -0
  98. package/src/utils/session.rs +73 -0
  99. package/src/utils/shell_permissions.rs +389 -0
  100. package/src/utils/telemetry.rs +41 -0
@@ -0,0 +1,442 @@
1
+ //! Health check command handler for grok-cli
2
+ //!
3
+ //! Handles health checking operations including API connectivity tests,
4
+ //! configuration validation, and system diagnostics.
5
+
6
+ use anyhow::{Result, anyhow};
7
+ use colored::*;
8
+ use std::time::{Duration, Instant};
9
+
10
+ use crate::GrokClient;
11
+ use crate::cli::{create_spinner, print_error, print_info, print_success, print_warning};
12
+ use crate::config::Config;
13
+ use crate::utils::network::{detect_starlink_connection, test_connectivity};
14
+
15
+ /// Handle health check commands
16
+ pub async fn handle_health_check(
17
+ check_api: bool,
18
+ check_config: bool,
19
+ api_key: Option<&str>,
20
+ config: &Config,
21
+ model: &str,
22
+ timeout_secs: u64,
23
+ ) -> Result<()> {
24
+ println!("{}", "🏥 Grok CLI Health Check".cyan().bold());
25
+ println!();
26
+
27
+ let mut checks_passed = 0;
28
+ let mut total_checks = 0;
29
+ let mut warnings = Vec::new();
30
+
31
+ // Always run basic system checks
32
+ println!("{}", "System Checks:".green().bold());
33
+
34
+ // Check configuration file
35
+ total_checks += 1;
36
+ let config_file_status = check_config_file().await;
37
+ match config_file_status {
38
+ Ok(()) => {
39
+ print_success("Configuration file found and readable");
40
+ checks_passed += 1;
41
+ }
42
+ Err(e) => {
43
+ print_error(&format!("Configuration file issue: {}", e));
44
+ warnings.push("Configuration file may need to be initialized".to_string());
45
+ }
46
+ }
47
+
48
+ // Check environment variables
49
+ total_checks += 1;
50
+ let env_status = check_environment();
51
+ match env_status {
52
+ Ok(env_info) => {
53
+ print_success(&format!("Environment: {}", env_info));
54
+ checks_passed += 1;
55
+ }
56
+ Err(e) => {
57
+ print_warning(&format!("Environment check: {}", e));
58
+ checks_passed += 1; // Not critical
59
+ }
60
+ }
61
+
62
+ // Check network connectivity
63
+ total_checks += 1;
64
+ println!();
65
+ println!("{}", "Network Checks:".green().bold());
66
+
67
+ let spinner = create_spinner("Testing basic connectivity...");
68
+ let connectivity_result = test_connectivity(Duration::from_secs(5)).await;
69
+ spinner.finish_and_clear();
70
+
71
+ match connectivity_result {
72
+ Ok(latency) => {
73
+ print_success(&format!("Network connectivity OK (latency: {:?})", latency));
74
+ checks_passed += 1;
75
+
76
+ if latency > Duration::from_millis(1000) {
77
+ warnings.push(
78
+ "High network latency detected - consider Starlink optimizations".to_string(),
79
+ );
80
+ }
81
+ }
82
+ Err(e) => {
83
+ print_error(&format!("Network connectivity failed: {}", e));
84
+ warnings.push("Network issues may affect API calls".to_string());
85
+ }
86
+ }
87
+
88
+ // Check for Starlink connection
89
+ total_checks += 1;
90
+ let starlink_spinner = create_spinner("Detecting network type...");
91
+ let is_starlink = detect_starlink_connection().await;
92
+ starlink_spinner.finish_and_clear();
93
+
94
+ if is_starlink {
95
+ print_info("Detected possible Starlink satellite connection");
96
+ if config.network.starlink_optimizations {
97
+ print_success("Starlink optimizations are enabled");
98
+ } else {
99
+ print_warning("Consider enabling Starlink optimizations");
100
+ warnings.push("Enable Starlink optimizations with: grok config set network.starlink_optimizations true".to_string());
101
+ }
102
+ checks_passed += 1;
103
+ } else {
104
+ print_info("Standard internet connection detected");
105
+ checks_passed += 1;
106
+ }
107
+
108
+ // Configuration validation if requested
109
+ if check_config {
110
+ println!();
111
+ println!("{}", "Configuration Validation:".green().bold());
112
+
113
+ total_checks += 1;
114
+ match config.validate() {
115
+ Ok(()) => {
116
+ print_success("Configuration is valid");
117
+ checks_passed += 1;
118
+ }
119
+ Err(e) => {
120
+ print_error(&format!("Configuration validation failed: {}", e));
121
+ }
122
+ }
123
+
124
+ // Check specific configuration values
125
+ total_checks += 1;
126
+ if config.api_key.is_some() {
127
+ print_success("API key is configured");
128
+ checks_passed += 1;
129
+ } else {
130
+ print_warning("No API key configured");
131
+ warnings.push("Set API key with: grok config set api_key YOUR_API_KEY".to_string());
132
+ }
133
+
134
+ total_checks += 1;
135
+ if config.acp.enabled {
136
+ print_info("ACP (Zed integration) is enabled");
137
+ checks_passed += 1;
138
+ } else {
139
+ print_info("ACP is disabled");
140
+ checks_passed += 1;
141
+ }
142
+ }
143
+
144
+ // API connectivity test if requested
145
+ if check_api {
146
+ println!();
147
+ println!("{}", "API Connectivity:".green().bold());
148
+
149
+ if let Some(key) = api_key {
150
+ total_checks += 2;
151
+
152
+ // Test API key validity
153
+ let api_spinner = create_spinner("Testing Grok API connection...");
154
+ let client_result = GrokClient::with_settings(key, timeout_secs, 3)
155
+ .map(|client| client.with_rate_limits(config.rate_limits));
156
+
157
+ match client_result {
158
+ Ok(client) => {
159
+ let test_result = client.test_connection().await;
160
+ api_spinner.finish_and_clear();
161
+
162
+ match test_result {
163
+ Ok(()) => {
164
+ print_success("Grok API connection successful");
165
+ checks_passed += 2;
166
+ }
167
+ Err(e) => {
168
+ print_error(&format!("Grok API connection failed: {}", e));
169
+
170
+ // Provide specific error guidance
171
+ let error_msg = e.to_string().to_lowercase();
172
+ if error_msg.contains("authentication") || error_msg.contains("401") {
173
+ warnings.push(
174
+ "Check your API key - it may be invalid or expired".to_string(),
175
+ );
176
+ } else if error_msg.contains("timeout") || error_msg.contains("network")
177
+ {
178
+ warnings.push(
179
+ "Network connectivity issues - check your internet connection"
180
+ .to_string(),
181
+ );
182
+ } else if error_msg.contains("rate limit") || error_msg.contains("429")
183
+ {
184
+ warnings
185
+ .push("API rate limit exceeded - try again later".to_string());
186
+ }
187
+ }
188
+ }
189
+ }
190
+ Err(e) => {
191
+ api_spinner.finish_and_clear();
192
+ print_error(&format!("Failed to create API client: {}", e));
193
+ }
194
+ }
195
+
196
+ // Test model availability
197
+ match GrokClient::with_settings(key, timeout_secs, 3)
198
+ .map(|client| client.with_rate_limits(config.rate_limits))
199
+ {
200
+ Ok(client) => {
201
+ let models_spinner = create_spinner("Checking model availability...");
202
+ let models_result = client.list_models().await;
203
+ models_spinner.finish_and_clear();
204
+
205
+ match models_result {
206
+ Ok(models) => {
207
+ if models.contains(&model.to_string()) {
208
+ print_success(&format!("Model '{}' is available", model));
209
+ } else {
210
+ print_warning(&format!("Model '{}' may not be available", model));
211
+ print_info(&format!("Available models: {}", models.join(", ")));
212
+ }
213
+ }
214
+ Err(e) => {
215
+ print_warning(&format!("Could not check model availability: {}", e));
216
+ }
217
+ }
218
+ }
219
+ Err(_) => {
220
+ // Already handled above
221
+ }
222
+ }
223
+ } else {
224
+ print_warning("No API key provided - skipping API tests");
225
+ warnings.push("Provide API key to test API connectivity".to_string());
226
+ }
227
+ }
228
+
229
+ // Performance diagnostics
230
+ println!();
231
+ println!("{}", "Performance Diagnostics:".green().bold());
232
+
233
+ total_checks += 1;
234
+ let perf_result = run_performance_diagnostics(config).await;
235
+ match perf_result {
236
+ Ok(diagnostics) => {
237
+ print_success("Performance diagnostics completed");
238
+ display_performance_results(&diagnostics);
239
+ checks_passed += 1;
240
+ }
241
+ Err(e) => {
242
+ print_warning(&format!("Performance diagnostics failed: {}", e));
243
+ }
244
+ }
245
+
246
+ // Summary
247
+ println!();
248
+ println!("{}", "Health Check Summary:".cyan().bold());
249
+ println!("{}", "─".repeat(50));
250
+
251
+ let success_rate = if total_checks > 0 {
252
+ (checks_passed as f64 / total_checks as f64) * 100.0
253
+ } else {
254
+ 100.0
255
+ };
256
+
257
+ let status_color = if success_rate >= 90.0 {
258
+ "green"
259
+ } else if success_rate >= 70.0 {
260
+ "yellow"
261
+ } else {
262
+ "red"
263
+ };
264
+
265
+ match status_color {
266
+ "green" => println!(
267
+ "Status: {} ({:.0}%)",
268
+ "✓ HEALTHY".green().bold(),
269
+ success_rate
270
+ ),
271
+ "yellow" => println!(
272
+ "Status: {} ({:.0}%)",
273
+ "⚠ WARNING".yellow().bold(),
274
+ success_rate
275
+ ),
276
+ "red" => println!(
277
+ "Status: {} ({:.0}%)",
278
+ "✗ UNHEALTHY".red().bold(),
279
+ success_rate
280
+ ),
281
+ _ => unreachable!(),
282
+ }
283
+
284
+ println!("Checks passed: {}/{}", checks_passed, total_checks);
285
+
286
+ if !warnings.is_empty() {
287
+ println!();
288
+ println!("{}", "Recommendations:".yellow().bold());
289
+ for (i, warning) in warnings.iter().enumerate() {
290
+ println!(" {}. {}", i + 1, warning);
291
+ }
292
+ }
293
+
294
+ println!();
295
+ if success_rate >= 90.0 {
296
+ print_success("System is healthy and ready to use!");
297
+ } else if success_rate >= 70.0 {
298
+ print_warning("System has minor issues but should work");
299
+ } else {
300
+ print_error("System has significant issues that need attention");
301
+ return Err(anyhow!(
302
+ "Health check failed with {:.0}% success rate",
303
+ success_rate
304
+ ));
305
+ }
306
+
307
+ Ok(())
308
+ }
309
+
310
+ /// Check if configuration file exists and is readable
311
+ async fn check_config_file() -> Result<()> {
312
+ let config_path = Config::default_config_path()?;
313
+
314
+ if !config_path.exists() {
315
+ return Err(anyhow!("Configuration file not found at {:?}", config_path));
316
+ }
317
+
318
+ // Try to load the config to ensure it's valid
319
+ Config::load(None).await?;
320
+
321
+ Ok(())
322
+ }
323
+
324
+ /// Check environment variables and system information
325
+ fn check_environment() -> Result<String> {
326
+ let mut env_info = Vec::new();
327
+
328
+ // Check OS
329
+ env_info.push(format!("OS: {}", std::env::consts::OS));
330
+
331
+ // Check if running in terminal
332
+ if std::io::IsTerminal::is_terminal(&std::io::stdout()) {
333
+ env_info.push("Terminal: Yes".to_string());
334
+ } else {
335
+ env_info.push("Terminal: No (piped/redirected)".to_string());
336
+ }
337
+
338
+ // Check for NO_COLOR environment variable
339
+ if std::env::var("NO_COLOR").is_ok() {
340
+ env_info.push("Colors: Disabled (NO_COLOR set)".to_string());
341
+ } else {
342
+ env_info.push("Colors: Enabled".to_string());
343
+ }
344
+
345
+ // Check for relevant environment variables
346
+ let mut env_vars = Vec::new();
347
+ if std::env::var("GROK_API_KEY").is_ok() {
348
+ env_vars.push("GROK_API_KEY");
349
+ }
350
+ if std::env::var("X_API_KEY").is_ok() {
351
+ env_vars.push("X_API_KEY");
352
+ }
353
+ if std::env::var("GROK_MODEL").is_ok() {
354
+ env_vars.push("GROK_MODEL");
355
+ }
356
+
357
+ if !env_vars.is_empty() {
358
+ env_info.push(format!("Env vars: {}", env_vars.join(", ")));
359
+ }
360
+
361
+ Ok(env_info.join(", "))
362
+ }
363
+
364
+ /// Performance diagnostics data
365
+ struct PerformanceDiagnostics {
366
+ memory_usage: u64,
367
+ startup_time: Duration,
368
+ config_load_time: Duration,
369
+ }
370
+
371
+ /// Run performance diagnostics
372
+ async fn run_performance_diagnostics(_config: &Config) -> Result<PerformanceDiagnostics> {
373
+ let start_time = Instant::now();
374
+
375
+ // Measure config reload time
376
+ let config_start = Instant::now();
377
+ Config::load(None).await?;
378
+ let config_load_time = config_start.elapsed();
379
+
380
+ // Estimate memory usage (simplified)
381
+ let memory_usage = estimate_memory_usage();
382
+
383
+ let startup_time = start_time.elapsed();
384
+
385
+ Ok(PerformanceDiagnostics {
386
+ memory_usage,
387
+ startup_time,
388
+ config_load_time,
389
+ })
390
+ }
391
+
392
+ /// Display performance diagnostic results
393
+ fn display_performance_results(diagnostics: &PerformanceDiagnostics) {
394
+ println!(" Memory usage: ~{} KB", diagnostics.memory_usage / 1024);
395
+ println!(" Config load time: {:?}", diagnostics.config_load_time);
396
+ println!(" Startup time: {:?}", diagnostics.startup_time);
397
+
398
+ // Performance warnings
399
+ if diagnostics.config_load_time > Duration::from_millis(100) {
400
+ print_warning("Configuration loading is slow");
401
+ }
402
+
403
+ if diagnostics.memory_usage > 50 * 1024 * 1024 {
404
+ // 50MB
405
+ print_warning("High memory usage detected");
406
+ }
407
+ }
408
+
409
+ /// Estimate current memory usage (simplified approach)
410
+ fn estimate_memory_usage() -> u64 {
411
+ // This is a simplified estimation
412
+ // In a real implementation, you might use system-specific APIs
413
+ // to get actual memory usage
414
+ 10 * 1024 * 1024 // Estimate 10MB base usage
415
+ }
416
+
417
+ #[cfg(test)]
418
+ mod tests {
419
+ use super::*;
420
+
421
+ #[test]
422
+ fn test_check_environment() {
423
+ let result = check_environment();
424
+ assert!(result.is_ok());
425
+ let env_info = result.unwrap();
426
+ assert!(env_info.contains("OS:"));
427
+ }
428
+
429
+ #[test]
430
+ fn test_estimate_memory_usage() {
431
+ let memory = estimate_memory_usage();
432
+ assert!(memory > 0);
433
+ }
434
+
435
+ #[tokio::test]
436
+ async fn test_performance_diagnostics() {
437
+ let config = Config::default();
438
+ let result = run_performance_diagnostics(&config).await;
439
+ // This test might fail if config loading fails, but that's expected
440
+ // in a test environment without proper setup
441
+ }
442
+ }