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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
//! Simple banner demo to showcase Grok CLI visual features
|
|
2
|
+
//!
|
|
3
|
+
//! This binary demonstrates the ASCII art, banners, and visual elements
|
|
4
|
+
//! without requiring API keys or interactive input.
|
|
5
|
+
|
|
6
|
+
use crate::banner::print_banner;
|
|
7
|
+
use crate::banner::BannerType;
|
|
8
|
+
use colored::*;
|
|
9
|
+
use std::env;
|
|
10
|
+
|
|
11
|
+
// Import the display modules from the main grok-cli crate
|
|
12
|
+
use grok_cli::display::*;
|
|
13
|
+
|
|
14
|
+
fn main() {
|
|
15
|
+
println!(
|
|
16
|
+
"{}",
|
|
17
|
+
"🎪 Grok CLI Visual Features Demo".bright_cyan().bold()
|
|
18
|
+
);
|
|
19
|
+
println!("{}", "─".repeat(60).dimmed());
|
|
20
|
+
println!();
|
|
21
|
+
|
|
22
|
+
// Get terminal size
|
|
23
|
+
let (width, height) = get_terminal_size();
|
|
24
|
+
println!(
|
|
25
|
+
"{}",
|
|
26
|
+
format!("Terminal: {}×{} characters", width, height).dimmed()
|
|
27
|
+
);
|
|
28
|
+
println!();
|
|
29
|
+
|
|
30
|
+
// Demo 1: ASCII Art Logo
|
|
31
|
+
println!("{}", "1. ASCII Art Logo (Adaptive)".bright_blue().bold());
|
|
32
|
+
print_grok_logo(width);
|
|
33
|
+
println!();
|
|
34
|
+
|
|
35
|
+
// Demo 2: Welcome Banner
|
|
36
|
+
println!("{}", "2. Welcome Banner".bright_green().bold());
|
|
37
|
+
let banner_config = BannerConfig {
|
|
38
|
+
show_banner: true,
|
|
39
|
+
show_tips: true,
|
|
40
|
+
show_updates: true,
|
|
41
|
+
width: Some(width),
|
|
42
|
+
};
|
|
43
|
+
print_welcome_banner(&banner_config);
|
|
44
|
+
|
|
45
|
+
// Demo 3: Different Banner Types
|
|
46
|
+
println!("{}", "3. Banner Variations".bright_magenta().bold());
|
|
47
|
+
|
|
48
|
+
// Info banner
|
|
49
|
+
let info_content = vec![
|
|
50
|
+
"This is an information banner",
|
|
51
|
+
"It shows helpful system messages",
|
|
52
|
+
"Like configuration status or tips",
|
|
53
|
+
];
|
|
54
|
+
print_banner(
|
|
55
|
+
"System Information",
|
|
56
|
+
&info_content,
|
|
57
|
+
BannerType::Info,
|
|
58
|
+
Some(width),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Directory recommendation (simulated)
|
|
62
|
+
if env::current_dir()
|
|
63
|
+
.map(|d| {
|
|
64
|
+
d.file_name().and_then(|n| n.to_str()).unwrap_or("") == "Users"
|
|
65
|
+
|| d.file_name()
|
|
66
|
+
.and_then(|n| n.to_str())
|
|
67
|
+
.unwrap_or("")
|
|
68
|
+
.contains("home")
|
|
69
|
+
})
|
|
70
|
+
.unwrap_or(false)
|
|
71
|
+
{
|
|
72
|
+
print_directory_recommendation(
|
|
73
|
+
&env::current_dir().unwrap().display().to_string(),
|
|
74
|
+
&banner_config,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Demo 4: Color Scheme
|
|
79
|
+
println!("{}", "4. Color Scheme".bright_yellow().bold());
|
|
80
|
+
println!();
|
|
81
|
+
|
|
82
|
+
let color_examples = vec![
|
|
83
|
+
(
|
|
84
|
+
"🔵 Primary (Blue)",
|
|
85
|
+
"Grok branding and main headers",
|
|
86
|
+
Color::BrightBlue,
|
|
87
|
+
),
|
|
88
|
+
(
|
|
89
|
+
"🟢 Success (Green)",
|
|
90
|
+
"Successful operations and confirmations",
|
|
91
|
+
Color::BrightGreen,
|
|
92
|
+
),
|
|
93
|
+
(
|
|
94
|
+
"🟡 Warning (Yellow)",
|
|
95
|
+
"Warnings and important notices",
|
|
96
|
+
Color::BrightYellow,
|
|
97
|
+
),
|
|
98
|
+
(
|
|
99
|
+
"🔴 Error (Red)",
|
|
100
|
+
"Errors and critical issues",
|
|
101
|
+
Color::BrightRed,
|
|
102
|
+
),
|
|
103
|
+
(
|
|
104
|
+
"🟣 Accent (Magenta)",
|
|
105
|
+
"Interactive elements and highlights",
|
|
106
|
+
Color::BrightMagenta,
|
|
107
|
+
),
|
|
108
|
+
("🔄 Info (Cyan)", "Information and tips", Color::BrightCyan),
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
for (label, description, color) in color_examples {
|
|
112
|
+
println!(" {} - {}", label.color(color), description);
|
|
113
|
+
}
|
|
114
|
+
println!();
|
|
115
|
+
|
|
116
|
+
// Demo 5: Logo Size Variations
|
|
117
|
+
println!("{}", "5. Logo Adaptability".bright_cyan().bold());
|
|
118
|
+
println!();
|
|
119
|
+
|
|
120
|
+
let sizes = vec![
|
|
121
|
+
(80, "Large (80+ columns)"),
|
|
122
|
+
(50, "Medium (45+ columns)"),
|
|
123
|
+
(35, "Small (30+ columns)"),
|
|
124
|
+
(20, "Tiny (<30 columns)"),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
for (test_width, description) in sizes {
|
|
128
|
+
println!("{}: {}", "Testing".dimmed(), description);
|
|
129
|
+
print_grok_logo(test_width);
|
|
130
|
+
println!("{}", "─".repeat(40).dimmed());
|
|
131
|
+
println!();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Demo 6: Status Information
|
|
135
|
+
println!("{}", "6. Status Display".bright_white().bold());
|
|
136
|
+
println!();
|
|
137
|
+
|
|
138
|
+
println!(
|
|
139
|
+
" {} API Key: {}",
|
|
140
|
+
"🔑".bright_yellow(),
|
|
141
|
+
"✓ Configured".bright_green()
|
|
142
|
+
);
|
|
143
|
+
println!(" {} Model: {}", "🤖".bright_blue(), "grok-3".bright_cyan());
|
|
144
|
+
println!(
|
|
145
|
+
" {} Network: {}",
|
|
146
|
+
"🌐".bright_green(),
|
|
147
|
+
"✓ Connected".bright_green()
|
|
148
|
+
);
|
|
149
|
+
println!(
|
|
150
|
+
" {} Features: {}",
|
|
151
|
+
"⚡".bright_magenta(),
|
|
152
|
+
"All systems ready".bright_white()
|
|
153
|
+
);
|
|
154
|
+
println!();
|
|
155
|
+
|
|
156
|
+
// Demo 7: Tips Display
|
|
157
|
+
println!("{}", "7. Helpful Tips".bright_green().bold());
|
|
158
|
+
let tips_content = vec![
|
|
159
|
+
"💡 Use 'grok chat \"your question\"' for quick answers",
|
|
160
|
+
"💻 Try 'grok code explain file.rs' for code analysis",
|
|
161
|
+
"🔧 Run 'grok health --all' for system diagnostics",
|
|
162
|
+
"⚙️ Configure with 'grok config show' and 'grok config set'",
|
|
163
|
+
"🎭 Enable Zed integration with 'grok acp server'",
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for tip in tips_content {
|
|
167
|
+
println!(" {}", tip);
|
|
168
|
+
}
|
|
169
|
+
println!();
|
|
170
|
+
|
|
171
|
+
// Demo 8: Feature Summary
|
|
172
|
+
let features = [
|
|
173
|
+
"✨ Beautiful ASCII art with adaptive sizing",
|
|
174
|
+
"🎨 Professional color scheme throughout",
|
|
175
|
+
"📱 Responsive design for any terminal width",
|
|
176
|
+
"🔔 Contextual banners and notifications",
|
|
177
|
+
"💬 Rich interactive prompts (when working)",
|
|
178
|
+
"📊 Comprehensive health monitoring",
|
|
179
|
+
"⚙️ Advanced configuration management",
|
|
180
|
+
"🚀 Starlink-optimized networking",
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
let feature_banner_content: Vec<&str> = features.to_vec();
|
|
184
|
+
print_banner(
|
|
185
|
+
"Enhanced Features",
|
|
186
|
+
&feature_banner_content,
|
|
187
|
+
BannerType::Welcome,
|
|
188
|
+
Some(width),
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// Conclusion
|
|
192
|
+
println!("{}", "🎉 Demo Complete!".bright_green().bold());
|
|
193
|
+
println!();
|
|
194
|
+
println!("{}", "The Grok CLI now features:".bright_white());
|
|
195
|
+
println!(
|
|
196
|
+
"• {} that rivals modern AI CLI tools",
|
|
197
|
+
"Visual polish".bright_cyan()
|
|
198
|
+
);
|
|
199
|
+
println!(
|
|
200
|
+
"• {} for any terminal environment",
|
|
201
|
+
"Adaptive interface".bright_blue()
|
|
202
|
+
);
|
|
203
|
+
println!(
|
|
204
|
+
"• {} with helpful guidance",
|
|
205
|
+
"User-friendly experience".bright_green()
|
|
206
|
+
);
|
|
207
|
+
println!(
|
|
208
|
+
"• {} for professional use",
|
|
209
|
+
"Production-ready code".bright_magenta()
|
|
210
|
+
);
|
|
211
|
+
println!();
|
|
212
|
+
println!(
|
|
213
|
+
"{}",
|
|
214
|
+
"Ready for interactive mode once the input loop is fixed! 🚀".bright_yellow()
|
|
215
|
+
);
|
|
216
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
use clap::CommandFactory;
|
|
2
|
+
use clap_markdown::MarkdownOptions;
|
|
3
|
+
use grok_cli::cli::app::Cli;
|
|
4
|
+
use std::fs;
|
|
5
|
+
use std::path::PathBuf;
|
|
6
|
+
|
|
7
|
+
fn main() {
|
|
8
|
+
let out_dir = PathBuf::from("docs");
|
|
9
|
+
if !out_dir.exists() {
|
|
10
|
+
fs::create_dir_all(&out_dir).expect("Failed to create docs directory");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let markdown = clap_markdown::help_markdown::<Cli>();
|
|
14
|
+
let out_path = out_dir.join("CLI_REFERENCE.md");
|
|
15
|
+
|
|
16
|
+
fs::write(&out_path, markdown).expect("Failed to write CLI_REFERENCE.md");
|
|
17
|
+
println!("Generated CLI documentation at {:?}", out_path);
|
|
18
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
use colored::*;
|
|
2
|
+
use std::env;
|
|
3
|
+
use std::fs;
|
|
4
|
+
use std::io::{self, Write};
|
|
5
|
+
use std::path::{Path, PathBuf};
|
|
6
|
+
use std::process::Command;
|
|
7
|
+
|
|
8
|
+
#[cfg(windows)]
|
|
9
|
+
use winreg::RegKey;
|
|
10
|
+
#[cfg(windows)]
|
|
11
|
+
use winreg::enums::*;
|
|
12
|
+
|
|
13
|
+
fn find_project_root() -> Option<PathBuf> {
|
|
14
|
+
let mut current = env::current_dir().ok()?;
|
|
15
|
+
loop {
|
|
16
|
+
if current.join("Cargo.toml").exists() {
|
|
17
|
+
return Some(current);
|
|
18
|
+
}
|
|
19
|
+
if !current.pop() {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
None
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fn main() {
|
|
27
|
+
println!("{}", "Grok CLI Installer for Windows 11".green().bold());
|
|
28
|
+
println!("=======================================");
|
|
29
|
+
|
|
30
|
+
if !cfg!(windows) {
|
|
31
|
+
eprintln!("{}", "This installer is designed for Windows only.".red());
|
|
32
|
+
std::process::exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[cfg(windows)]
|
|
36
|
+
install_windows();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#[cfg(windows)]
|
|
40
|
+
fn install_windows() {
|
|
41
|
+
let root_dir = find_project_root().expect("Failed to find project root (Cargo.toml not found)");
|
|
42
|
+
|
|
43
|
+
// 1. Build the release binary
|
|
44
|
+
println!("{}", "Building release binary...".cyan());
|
|
45
|
+
let status = Command::new("cargo")
|
|
46
|
+
.current_dir(&root_dir)
|
|
47
|
+
.args(["build", "--release", "--bin", "grok"])
|
|
48
|
+
.status()
|
|
49
|
+
.expect("Failed to execute cargo build");
|
|
50
|
+
|
|
51
|
+
if !status.success() {
|
|
52
|
+
eprintln!("{}", "Build failed. Aborting installation.".red());
|
|
53
|
+
std::process::exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Define paths
|
|
57
|
+
let local_app_data = env::var("LOCALAPPDATA").expect("LOCALAPPDATA not set");
|
|
58
|
+
let install_dir = PathBuf::from(&local_app_data).join("grok-cli").join("bin");
|
|
59
|
+
let exe_name = "grok.exe";
|
|
60
|
+
let target_exe = install_dir.join(exe_name);
|
|
61
|
+
|
|
62
|
+
let source_exe = root_dir.join("target").join("release").join(exe_name);
|
|
63
|
+
|
|
64
|
+
if !source_exe.exists() {
|
|
65
|
+
eprintln!(
|
|
66
|
+
"{} {}",
|
|
67
|
+
"Source binary not found at:".red(),
|
|
68
|
+
source_exe.display()
|
|
69
|
+
);
|
|
70
|
+
std::process::exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 3. Create directory
|
|
74
|
+
if !install_dir.exists() {
|
|
75
|
+
println!("Creating installation directory: {}", install_dir.display());
|
|
76
|
+
fs::create_dir_all(&install_dir).expect("Failed to create installation directory");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 4. Copy binary
|
|
80
|
+
println!("Copying binary to {}", target_exe.display());
|
|
81
|
+
fs::copy(&source_exe, &target_exe).expect("Failed to copy binary");
|
|
82
|
+
|
|
83
|
+
// 5. Update PATH
|
|
84
|
+
println!("{}", "Updating PATH environment variable...".cyan());
|
|
85
|
+
update_path(&install_dir);
|
|
86
|
+
|
|
87
|
+
// 6. Create Start Menu Shortcut
|
|
88
|
+
println!("{}", "Creating Start Menu shortcut...".cyan());
|
|
89
|
+
create_shortcut(&target_exe);
|
|
90
|
+
|
|
91
|
+
// 7. Setup Configuration
|
|
92
|
+
println!("{}", "Setting up configuration...".cyan());
|
|
93
|
+
setup_config();
|
|
94
|
+
|
|
95
|
+
println!("\n{}", "Installation Complete!".green().bold());
|
|
96
|
+
println!("Please restart your terminal to use the 'grok' command.");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
#[cfg(windows)]
|
|
100
|
+
fn setup_config() {
|
|
101
|
+
let config_dir = dirs::config_dir()
|
|
102
|
+
.expect("Failed to get config directory")
|
|
103
|
+
.join("grok-cli");
|
|
104
|
+
|
|
105
|
+
if !config_dir.exists()
|
|
106
|
+
&& let Err(e) = fs::create_dir_all(&config_dir)
|
|
107
|
+
{
|
|
108
|
+
eprintln!("Failed to create config directory: {}", e);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
let config_file = config_dir.join("config.toml");
|
|
113
|
+
if !config_file.exists() {
|
|
114
|
+
println!("Configuration file not found at: {}", config_file.display());
|
|
115
|
+
print!("Do you want to set up your Grok API Key now? [Y/n]: ");
|
|
116
|
+
io::stdout().flush().unwrap_or_default();
|
|
117
|
+
|
|
118
|
+
let mut input = String::new();
|
|
119
|
+
if io::stdin().read_line(&mut input).is_ok() {
|
|
120
|
+
let input = input.trim().to_lowercase();
|
|
121
|
+
if input != "n" && input != "no" {
|
|
122
|
+
print!("Enter your X API Key: ");
|
|
123
|
+
io::stdout().flush().unwrap_or_default();
|
|
124
|
+
let mut key = String::new();
|
|
125
|
+
if io::stdin().read_line(&mut key).is_ok() {
|
|
126
|
+
let key = key.trim();
|
|
127
|
+
if !key.is_empty() {
|
|
128
|
+
let config_content = format!(
|
|
129
|
+
r#"# Grok CLI Configuration
|
|
130
|
+
|
|
131
|
+
# X API Key
|
|
132
|
+
api_key = "{}"
|
|
133
|
+
|
|
134
|
+
# Default Model
|
|
135
|
+
default_model = "grok-3"
|
|
136
|
+
|
|
137
|
+
# Network Configuration
|
|
138
|
+
[network]
|
|
139
|
+
starlink_optimizations = true
|
|
140
|
+
health_monitoring = true
|
|
141
|
+
"#,
|
|
142
|
+
key
|
|
143
|
+
);
|
|
144
|
+
if let Err(e) = fs::write(&config_file, config_content) {
|
|
145
|
+
eprintln!("Failed to write config file: {}", e);
|
|
146
|
+
} else {
|
|
147
|
+
println!("Configuration saved to {}", config_file.display());
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
println!("Skipping API key setup (empty key provided).");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
println!(
|
|
157
|
+
"Configuration file already exists at: {}",
|
|
158
|
+
config_file.display()
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#[cfg(windows)]
|
|
164
|
+
fn update_path(install_dir: &Path) {
|
|
165
|
+
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
|
166
|
+
let env_key = hkcu
|
|
167
|
+
.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)
|
|
168
|
+
.expect("Failed to open Environment registry key");
|
|
169
|
+
|
|
170
|
+
let current_path: String = env_key.get_value("Path").unwrap_or_default();
|
|
171
|
+
let install_path_str = install_dir.to_string_lossy();
|
|
172
|
+
|
|
173
|
+
// Simple check to avoid duplicates (case-insensitive check would be better but this is a start)
|
|
174
|
+
if !current_path.contains(&*install_path_str) {
|
|
175
|
+
let new_path = if current_path.is_empty() {
|
|
176
|
+
install_path_str.to_string()
|
|
177
|
+
} else {
|
|
178
|
+
format!("{};{}", current_path, install_path_str)
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
env_key
|
|
182
|
+
.set_value("Path", &new_path)
|
|
183
|
+
.expect("Failed to update Path");
|
|
184
|
+
println!("Added {} to PATH.", install_path_str);
|
|
185
|
+
} else {
|
|
186
|
+
println!("Path already configured.");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#[cfg(windows)]
|
|
191
|
+
fn create_shortcut(target_exe: &Path) {
|
|
192
|
+
let roaming = env::var("APPDATA").expect("APPDATA not set");
|
|
193
|
+
let start_menu = PathBuf::from(roaming)
|
|
194
|
+
.join("Microsoft")
|
|
195
|
+
.join("Windows")
|
|
196
|
+
.join("Start Menu")
|
|
197
|
+
.join("Programs")
|
|
198
|
+
.join("Grok CLI.lnk");
|
|
199
|
+
|
|
200
|
+
// PowerShell script to create shortcut
|
|
201
|
+
let script = format!(
|
|
202
|
+
"$WS = New-Object -ComObject WScript.Shell; $SC = $WS.CreateShortcut('{}'); $SC.TargetPath = '{}'; $SC.Save()",
|
|
203
|
+
start_menu.display(),
|
|
204
|
+
target_exe.display()
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
let status = Command::new("powershell")
|
|
208
|
+
.args(["-NoProfile", "-Command", &script])
|
|
209
|
+
.status()
|
|
210
|
+
.expect("Failed to create shortcut");
|
|
211
|
+
|
|
212
|
+
if status.success() {
|
|
213
|
+
println!("Shortcut created at: {}", start_menu.display());
|
|
214
|
+
} else {
|
|
215
|
+
eprintln!("{}", "Failed to create Start Menu shortcut.".yellow());
|
|
216
|
+
}
|
|
217
|
+
}
|