colgrep/install/
opencode.rs1use anyhow::{Context, Result};
2use colored::Colorize;
3use std::fs;
4use std::path::PathBuf;
5
6use super::SKILL_MD;
7
8const COLGREP_MARKER_START: &str = "<!-- COLGREP_START -->";
10const COLGREP_MARKER_END: &str = "<!-- COLGREP_END -->";
11
12fn get_opencode_dir() -> Result<PathBuf> {
14 let home = dirs::home_dir().context("Could not determine home directory")?;
15 Ok(home.join(".config").join("opencode"))
16}
17
18fn get_agents_md_path() -> Result<PathBuf> {
20 let opencode_dir = get_opencode_dir()?;
21 Ok(opencode_dir.join("AGENTS.md"))
22}
23
24fn add_to_agents_md() -> Result<()> {
26 let opencode_dir = get_opencode_dir()?;
27 fs::create_dir_all(&opencode_dir)?;
28
29 let agents_path = get_agents_md_path()?;
30
31 let mut content = if agents_path.exists() {
32 fs::read_to_string(&agents_path)?
33 } else {
34 String::from("# OpenCode Agent Tools\n\n")
35 };
36
37 if content.contains(COLGREP_MARKER_START) {
39 if let (Some(start), Some(end)) = (
41 content.find(COLGREP_MARKER_START),
42 content.find(COLGREP_MARKER_END),
43 ) {
44 let end_pos = end + COLGREP_MARKER_END.len();
45 content = format!("{}{}", &content[..start], &content[end_pos..]);
46 }
47 }
48
49 let colgrep_section = format!(
51 "{}\n{}\n{}\n",
52 COLGREP_MARKER_START, SKILL_MD, COLGREP_MARKER_END
53 );
54 content.push_str(&colgrep_section);
55
56 fs::write(&agents_path, content)?;
57 Ok(())
58}
59
60fn remove_from_agents_md() -> Result<()> {
62 let agents_path = get_agents_md_path()?;
63
64 if !agents_path.exists() {
65 return Ok(());
66 }
67
68 let content = fs::read_to_string(&agents_path)?;
69
70 if let (Some(start), Some(end)) = (
71 content.find(COLGREP_MARKER_START),
72 content.find(COLGREP_MARKER_END),
73 ) {
74 let end_pos = end + COLGREP_MARKER_END.len();
75 let new_content = format!("{}{}", &content[..start], &content[end_pos..]);
76
77 let cleaned = new_content.trim().to_string();
79
80 if cleaned.is_empty() || cleaned == "# OpenCode Agent Tools" {
81 fs::remove_file(&agents_path)?;
83 } else {
84 fs::write(&agents_path, format!("{}\n", cleaned))?;
85 }
86 }
87
88 Ok(())
89}
90
91pub fn install_opencode() -> Result<()> {
93 println!("Installing colgrep for OpenCode...");
94
95 add_to_agents_md()?;
97 let agents_path = get_agents_md_path()?;
98 println!(
99 "{} Added colgrep instructions to {}",
100 "✓".green(),
101 agents_path.display()
102 );
103
104 print_opencode_success();
105 Ok(())
106}
107
108pub fn uninstall_opencode() -> Result<()> {
110 println!("Uninstalling colgrep from OpenCode...");
111
112 remove_from_agents_md()?;
113 println!("{} Removed colgrep from AGENTS.md", "✓".green());
114
115 println!();
116 println!("{}", "Colgrep has been uninstalled from OpenCode.".green());
117 Ok(())
118}
119
120fn print_opencode_success() {
121 println!();
122 println!("{}", "═".repeat(70).cyan());
123 println!();
124 println!(
125 " {} {}",
126 "✓".green().bold(),
127 "COLGREP INSTALLED FOR OPENCODE".green().bold()
128 );
129 println!();
130 println!(
131 " {}",
132 "Colgrep is now available as a semantic search tool in OpenCode.".white()
133 );
134 println!();
135 println!(" {}", "Usage in OpenCode:".cyan().bold());
136 println!(
137 " {}",
138 "Use natural language to search your codebase.".white()
139 );
140 println!(" {}", "Example: \"find error handling logic\"".white());
141 println!();
142 println!(" {}", "To uninstall:".cyan().bold());
143 println!(" {}", "colgrep --uninstall-opencode".green());
144 println!();
145 println!("{}", "═".repeat(70).cyan());
146}