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,139 @@
1
+ //! ASCII art definitions for Grok CLI
2
+ //!
3
+ //! Contains various sizes of the Grok logo and related ASCII art
4
+
5
+ use colored::*;
6
+
7
+ /// Full Grok logo ASCII art (large version)
8
+ pub const GROK_LOGO_LARGE: &str = r#"
9
+ ░██████╗░██████╗░░█████╗░██╗░░██╗
10
+ ██╔════╝░██╔══██╗██╔══██╗██║░██╔╝
11
+ ██║░░██╗░██████╔╝██║░░██║█████═╝░
12
+ ██║░░╚██╗██╔══██╗██║░░██║██╔═██╗░
13
+ ╚██████╔╝██║░░██║╚█████╔╝██║░╚██╗
14
+ ░╚═════╝░╚═╝░░╚═╝░╚════╝░╚═╝░░╚═╝
15
+ "#;
16
+
17
+ /// Medium Grok logo ASCII art
18
+ pub const GROK_LOGO_MEDIUM: &str = r#"
19
+ ██████╗ ██████╗ ██████╗ ██╗ ██╗
20
+ ██╔════╝ ██╔══██╗██╔═══██╗██║ ██╔╝
21
+ ██║ ███╗██████╔╝██║ ██║█████╔╝
22
+ ██║ ██║██╔══██╗██║ ██║██╔═██╗
23
+ ╚██████╔╝██║ ██║╚██████╔╝██║ ██╗
24
+ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
25
+ "#;
26
+
27
+ /// Small Grok logo ASCII art
28
+ pub const GROK_LOGO_SMALL: &str = r#"
29
+ ▄████ ██▀███ ▒█████ ██ ▄█▀
30
+ ██▒ ▀█▒▓██ ▒ ██▒▒██▒ ██▒ ██▄█▒
31
+ ▒██░▄▄▄░▓██ ░▄█ ▒▒██░ ██▒▓███▄░
32
+ ░▓█ ██▓▒██▀▀█▄ ▒██ ██░▓██ █▄
33
+ ░▒▓███▀▒░██▓ ▒██▒░ ████▓▒░▒██▒ █▄
34
+ ░▒ ▒ ░ ▒▓ ░▒▓░░ ▒░▒░▒░ ▒ ▒▒ ▓▒
35
+ "#;
36
+
37
+ /// Tiny Grok logo ASCII art (single line)
38
+ pub const GROK_LOGO_TINY: &str = r#"GROK"#;
39
+
40
+ /// X.ai branding ASCII art
41
+ pub const X_AI_BRANDING: &str = r#"
42
+ ▄▀█ █ █▄▄ █▄█
43
+ █▄█ ▄ █ ▄ █▄█ █
44
+ "#;
45
+
46
+ /// Get the appropriate logo based on terminal width
47
+ pub fn get_logo_for_width(width: u16) -> &'static str {
48
+ if width >= 60 {
49
+ GROK_LOGO_LARGE
50
+ } else if width >= 45 {
51
+ GROK_LOGO_MEDIUM
52
+ } else if width >= 30 {
53
+ GROK_LOGO_SMALL
54
+ } else {
55
+ GROK_LOGO_TINY
56
+ }
57
+ }
58
+
59
+ /// Get the width of the ASCII art
60
+ pub fn get_logo_width(logo: &str) -> usize {
61
+ logo.lines()
62
+ .map(|line| line.trim_end().len())
63
+ .max()
64
+ .unwrap_or(0)
65
+ }
66
+
67
+ /// Print the Grok logo with gradient colors
68
+ pub fn print_grok_logo(width: u16) {
69
+ let logo = get_logo_for_width(width);
70
+ let lines: Vec<&str> = logo.lines().collect();
71
+
72
+ for (i, line) in lines.iter().enumerate() {
73
+ if line.trim().is_empty() {
74
+ continue;
75
+ }
76
+
77
+ // Apply gradient from blue to purple to pink
78
+ let colored_line = match i % 3 {
79
+ 0 => line.bright_blue(),
80
+ 1 => line.bright_magenta(),
81
+ _ => line.bright_cyan(),
82
+ };
83
+
84
+ println!("{}", colored_line);
85
+ }
86
+ }
87
+
88
+ /// Print X.ai branding
89
+ pub fn print_x_ai_branding() {
90
+ for line in X_AI_BRANDING.lines() {
91
+ if !line.trim().is_empty() {
92
+ println!("{}", line.bright_black());
93
+ }
94
+ }
95
+ }
96
+
97
+ /// Animated logo display (for fun startup effect)
98
+ pub fn print_animated_logo(width: u16) {
99
+ use std::{thread, time::Duration};
100
+
101
+ let logo = get_logo_for_width(width);
102
+ let lines: Vec<&str> = logo.lines().collect();
103
+
104
+ for (i, line) in lines.iter().enumerate() {
105
+ if line.trim().is_empty() {
106
+ continue;
107
+ }
108
+
109
+ // Apply gradient and print with small delay
110
+ let colored_line = match i % 3 {
111
+ 0 => line.bright_blue(),
112
+ 1 => line.bright_magenta(),
113
+ _ => line.bright_cyan(),
114
+ };
115
+
116
+ println!("{}", colored_line);
117
+ thread::sleep(Duration::from_millis(100));
118
+ }
119
+ }
120
+
121
+ #[cfg(test)]
122
+ mod tests {
123
+ use super::*;
124
+
125
+ #[test]
126
+ fn test_get_logo_for_width() {
127
+ assert_eq!(get_logo_for_width(80), GROK_LOGO_LARGE);
128
+ assert_eq!(get_logo_for_width(50), GROK_LOGO_MEDIUM);
129
+ assert_eq!(get_logo_for_width(35), GROK_LOGO_SMALL);
130
+ assert_eq!(get_logo_for_width(20), GROK_LOGO_TINY);
131
+ }
132
+
133
+ #[test]
134
+ fn test_get_logo_width() {
135
+ assert!(get_logo_width(GROK_LOGO_LARGE) > 0);
136
+ assert!(get_logo_width(GROK_LOGO_MEDIUM) > 0);
137
+ assert!(get_logo_width(GROK_LOGO_SMALL) > 0);
138
+ }
139
+ }
@@ -0,0 +1,289 @@
1
+ //! Banner display module for Grok CLI
2
+ //!
3
+ //! Handles startup banners, update notifications, and warning messages
4
+
5
+ use colored::*;
6
+ use std::io::{self, Write};
7
+
8
+ /// Banner types for different contexts
9
+ #[derive(Debug, Clone, PartialEq)]
10
+ pub enum BannerType {
11
+ /// Welcome/startup banner
12
+ Welcome,
13
+ /// Update notification
14
+ Update,
15
+ /// Warning message
16
+ Warning,
17
+ /// Error message
18
+ Error,
19
+ /// Information message
20
+ Info,
21
+ }
22
+
23
+ /// Banner configuration
24
+ #[derive(Debug, Clone)]
25
+ pub struct BannerConfig {
26
+ pub show_banner: bool,
27
+ pub show_tips: bool,
28
+ pub show_updates: bool,
29
+ pub width: Option<u16>,
30
+ }
31
+
32
+ impl Default for BannerConfig {
33
+ fn default() -> Self {
34
+ Self {
35
+ show_banner: true,
36
+ show_tips: true,
37
+ show_updates: true,
38
+ width: None,
39
+ }
40
+ }
41
+ }
42
+
43
+ /// Print a bordered banner with content
44
+ pub fn print_banner(title: &str, content: &[&str], banner_type: BannerType, width: Option<u16>) {
45
+ let term_width = width.unwrap_or(crate::display::get_terminal_size().0);
46
+ let banner_width = std::cmp::min(term_width - 4, 80); // Leave margin and cap at 80
47
+
48
+ let (border_color, title_color, content_color) = match banner_type {
49
+ BannerType::Welcome => (Color::Cyan, Color::BrightCyan, Color::White),
50
+ BannerType::Update => (Color::Green, Color::BrightGreen, Color::White),
51
+ BannerType::Warning => (Color::Yellow, Color::BrightYellow, Color::White),
52
+ BannerType::Error => (Color::Red, Color::BrightRed, Color::White),
53
+ BannerType::Info => (Color::Blue, Color::BrightBlue, Color::White),
54
+ };
55
+
56
+ // Top border
57
+ println!(
58
+ "{}",
59
+ format!("┌{}┐", "─".repeat(banner_width as usize - 2)).color(border_color)
60
+ );
61
+
62
+ // Title
63
+ if !title.is_empty() {
64
+ let title_line = format_banner_line(title, banner_width, true);
65
+ println!(
66
+ "{}{}{}",
67
+ "│".color(border_color),
68
+ title_line.color(title_color).bold(),
69
+ "│".color(border_color)
70
+ );
71
+
72
+ // Separator after title
73
+ println!(
74
+ "{}",
75
+ format!("├{}┤", "─".repeat(banner_width as usize - 2)).color(border_color)
76
+ );
77
+ }
78
+
79
+ // Content lines
80
+ for line in content {
81
+ if line.trim().is_empty() {
82
+ // Empty line
83
+ println!(
84
+ "{}{}{}",
85
+ "│".color(border_color),
86
+ " ".repeat(banner_width as usize - 2),
87
+ "│".color(border_color)
88
+ );
89
+ } else {
90
+ let content_line = format_banner_line(line, banner_width, false);
91
+ println!(
92
+ "{}{}{}",
93
+ "│".color(border_color),
94
+ content_line.color(content_color),
95
+ "│".color(border_color)
96
+ );
97
+ }
98
+ }
99
+
100
+ // Bottom border
101
+ println!(
102
+ "{}",
103
+ format!("└{}┘", "─".repeat(banner_width as usize - 2)).color(border_color)
104
+ );
105
+ println!(); // Extra line after banner
106
+ }
107
+
108
+ /// Format a line to fit within banner width with proper padding
109
+ fn format_banner_line(text: &str, width: u16, center: bool) -> String {
110
+ let content_width = width as usize - 4; // Account for borders and padding
111
+ let text = text.trim();
112
+
113
+ if text.len() > content_width {
114
+ // Truncate if too long
115
+ format!(
116
+ " {:<width$} ",
117
+ &text[..content_width],
118
+ width = content_width
119
+ )
120
+ } else if center {
121
+ // Center the text
122
+ let padding = (content_width - text.len()) / 2;
123
+ let right_padding = content_width - text.len() - padding;
124
+ format!(
125
+ " {}{}{} ",
126
+ " ".repeat(padding),
127
+ text,
128
+ " ".repeat(right_padding)
129
+ )
130
+ } else {
131
+ // Left align with padding
132
+ format!(" {:<width$} ", text, width = content_width)
133
+ }
134
+ }
135
+
136
+ /// Print welcome banner with logo and tips
137
+ pub fn print_welcome_banner(config: &BannerConfig) {
138
+ if !config.show_banner {
139
+ return;
140
+ }
141
+
142
+ let (width, _) = crate::display::get_terminal_size();
143
+
144
+ // Print logo first
145
+ crate::display::print_grok_logo(width);
146
+
147
+ // Print version
148
+ let version = env!("CARGO_PKG_VERSION");
149
+ let version_text = format!("v{}", version);
150
+ let padding = (width as usize - version_text.len()) / 2;
151
+ println!("{}{}", " ".repeat(padding), version_text.dimmed());
152
+ println!();
153
+
154
+ // Welcome message
155
+ if config.show_tips {
156
+ let content = vec![
157
+ "Tips for getting started:",
158
+ "1. Ask questions, edit files, or run commands.",
159
+ "2. Be specific for the best results.",
160
+ "3. /help for more information.",
161
+ ];
162
+
163
+ print_banner("", &content, BannerType::Welcome, config.width);
164
+ }
165
+ }
166
+
167
+ /// Print update notification banner
168
+ pub fn print_update_banner(current_version: &str, latest_version: &str, config: &BannerConfig) {
169
+ if !config.show_updates {
170
+ return;
171
+ }
172
+
173
+ let update_message = format!(
174
+ "Grok CLI update available! {} → {}",
175
+ current_version, latest_version
176
+ );
177
+ let content = vec![
178
+ &update_message,
179
+ "Please run: cargo install --git https://github.com/microtech/grok-cli",
180
+ ];
181
+
182
+ print_banner(
183
+ "Update Available",
184
+ &content,
185
+ BannerType::Update,
186
+ config.width,
187
+ );
188
+ }
189
+
190
+ /// Print warning banner
191
+ pub fn print_warning_banner(title: &str, message: &str, config: &BannerConfig) {
192
+ let content = vec![message];
193
+ print_banner(title, &content, BannerType::Warning, config.width);
194
+ }
195
+
196
+ /// Print directory recommendation banner
197
+ pub fn print_directory_recommendation(current_dir: &str, config: &BannerConfig) {
198
+ let home_message = "You are running Grok CLI in your home directory.".to_string();
199
+ let current_dir_message = format!("Current directory: {}", current_dir);
200
+ let content = vec![
201
+ &home_message,
202
+ "It is recommended to run in a project-specific directory.",
203
+ "",
204
+ &current_dir_message,
205
+ ];
206
+
207
+ print_banner(
208
+ "Directory Recommendation",
209
+ &content,
210
+ BannerType::Info,
211
+ config.width,
212
+ );
213
+ }
214
+
215
+ /// Print error banner
216
+ pub fn print_error_banner(title: &str, error: &str) {
217
+ let content = vec![error];
218
+ print_banner(title, &content, BannerType::Error, None);
219
+ }
220
+
221
+ /// Print a simple status line (like the bottom status bar in Gemini CLI)
222
+ pub fn print_status_line(
223
+ mode: &str,
224
+ model: &str,
225
+ context_used: Option<&str>,
226
+ directory: Option<&str>,
227
+ ) {
228
+ let (width, _) = crate::display::get_terminal_size();
229
+
230
+ let mut status_parts = vec![mode.to_string()];
231
+
232
+ if let Some(dir) = directory {
233
+ status_parts.push(format!("📁 {}", dir));
234
+ }
235
+
236
+ status_parts.push(format!("🤖 {}", model));
237
+
238
+ if let Some(context) = context_used {
239
+ status_parts.push(format!("📊 {}", context));
240
+ }
241
+
242
+ let status_line = status_parts.join(" | ");
243
+ let padding = if width as usize > status_line.len() {
244
+ width as usize - status_line.len()
245
+ } else {
246
+ 0
247
+ };
248
+
249
+ print!("{}", " ".repeat(padding));
250
+ println!("{}", status_line.dimmed());
251
+ }
252
+
253
+ /// Clear the current line and move cursor to beginning
254
+ pub fn clear_current_line() {
255
+ print!("\r\x1b[K");
256
+ io::stdout().flush().unwrap_or(());
257
+ }
258
+
259
+ /// Print a simple progress indicator
260
+ pub fn print_progress_dots(count: usize) {
261
+ clear_current_line();
262
+ print!("Thinking{}", ".".repeat((count % 4) + 1));
263
+ io::stdout().flush().unwrap_or(());
264
+ }
265
+
266
+ #[cfg(test)]
267
+ mod tests {
268
+ use super::*;
269
+
270
+ #[test]
271
+ fn test_format_banner_line() {
272
+ let result = format_banner_line("Hello", 20, false);
273
+ assert!(result.starts_with(" Hello"));
274
+ assert_eq!(result.len(), 18); // 20 - 2 for padding chars
275
+
276
+ let result = format_banner_line("Hello", 20, true);
277
+ assert!(result.contains("Hello"));
278
+ assert_eq!(result.len(), 18);
279
+ }
280
+
281
+ #[test]
282
+ fn test_banner_config_default() {
283
+ let config = BannerConfig::default();
284
+ assert!(config.show_banner);
285
+ assert!(config.show_tips);
286
+ assert!(config.show_updates);
287
+ assert!(config.width.is_none());
288
+ }
289
+ }