patina-ai 0.23.0

Context orchestration for AI development - captures and evolves patterns over time
Documentation
//! Internal implementation for OpenCode adapter

use anyhow::Result;
use std::fs;
use std::path::{Path, PathBuf};

use crate::adapters::templates;
use crate::environment::Environment;

/// Path constants for OpenCode adapter
const ADAPTER_DIR: &str = ".opencode";
const CONTEXT_FILE: &str = "AGENTS.md";

/// Initialize OpenCode project structure
pub fn init_project(
    project_path: &Path,
    project_name: &str,
    environment: &Environment,
) -> Result<()> {
    // Copy templates from central location (~/.patina/adapters/opencode/templates/)
    templates::copy_to_project("opencode", project_path)?;

    // Generate context file in .opencode/
    let opencode_path = project_path.join(ADAPTER_DIR);
    let content = generate_minimal_context(project_name, environment);
    fs::write(opencode_path.join(CONTEXT_FILE), content)?;

    Ok(())
}

/// Get context file path
pub fn get_context_file_path(project_path: &Path) -> PathBuf {
    project_path.join(ADAPTER_DIR).join(CONTEXT_FILE)
}

/// Generate minimal context for OpenCode
fn generate_minimal_context(project_name: &str, environment: &Environment) -> String {
    let mut content = String::new();

    // Header
    content.push_str(&format!("# {project_name} - AI Agent Context\n\n"));
    content.push_str("Project context for OpenCode and AI agents.\n");
    content.push_str("See root `AGENTS.md` or `README.md` for project instructions.\n\n");

    // Environment
    content.push_str("## Environment\n\n");
    content.push_str(&format!(
        "- **Platform**: {} ({})\n",
        environment.os, environment.arch
    ));
    content.push_str(&format!("- **Directory**: {}\n", environment.current_dir));

    // Available tools
    let tools = ["cargo", "git", "docker", "python"];
    let available: Vec<_> = tools
        .iter()
        .filter_map(|&tool| {
            environment
                .tools
                .get(tool)
                .filter(|info| info.available)
                .map(|_| tool)
        })
        .collect();

    if !available.is_empty() {
        content.push_str(&format!("- **Tools**: {}\n", available.join(", ")));
    }
    content.push('\n');

    // Patterns
    content.push_str("## Patterns\n\n");
    content.push_str("See files in `layer/` directory for patterns and documentation.\n\n");

    // MCP Tools
    content.push_str("## MCP Tools (Use These!)\n\n");
    content.push_str("**`scry`** - Search codebase knowledge\n");
    content.push_str("- USE FIRST for any question about the code\n");
    content.push_str("- Searches indexed symbols, functions, git history, session learnings\n");
    content.push_str("- Example: \"how does authentication work?\"\n\n");
    content.push_str("**`context`** - Get project patterns\n");
    content.push_str("- USE to understand design rules before making changes\n");
    content.push_str("- Returns core patterns (eternal principles) and surface patterns (active architecture)\n\n");
    content.push_str(
        "💡 These tools search pre-indexed knowledge - faster than manual file exploration.\n\n",
    );

    // Footer
    content.push_str(&format!(
        "---\n*Generated by Patina v{} | Frontend: OpenCode*\n",
        env!("CARGO_PKG_VERSION")
    ));

    content
}