diff --git a/.icons/aider.svg b/.icons/aider.svg new file mode 100644 index 00000000..44e064ff --- /dev/null +++ b/.icons/aider.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aider/README.md b/aider/README.md new file mode 100644 index 00000000..ce26e71f --- /dev/null +++ b/aider/README.md @@ -0,0 +1,304 @@ +--- +display_name: Aider +description: Run Aider AI pair programming in your workspace +icon: ../.icons/aider.svg +maintainer_github: coder +verified: true +tags: [agent, aider] +--- + +# Aider + +Run [Aider](https://aider.chat) AI pair programming in your workspace. This module installs Aider and provides a persistent session using screen or tmux. + +```tf +module "aider" { + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id +} +``` + +## Features + +- **Interactive Parameter Selection**: Choose your AI provider, model, and configuration options when creating the workspace +- **Multiple AI Providers**: Supports Anthropic (Claude), OpenAI, DeepSeek, GROQ, and OpenRouter +- **Persistent Sessions**: Uses screen (default) or tmux to keep Aider running in the background +- **Optional Dependencies**: Install Playwright for web page scraping and PortAudio for voice coding +- **Project Integration**: Works with any project directory, including Git repositories +- **Browser UI**: Use Aider in your browser with a modern web interface instead of the terminal +- **Non-Interactive Mode**: Automatically processes tasks when provided via the `CODER_MCP_AIDER_TASK_PROMPT` environment variable + +## Module Parameters + +| Parameter | Description | Type | Default | +| ---------------------------------- | -------------------------------------------------------------------------- | -------- | ------------------- | +| `agent_id` | The ID of a Coder agent (required) | `string` | - | +| `folder` | The folder to run Aider in | `string` | `/home/coder` | +| `install_aider` | Whether to install Aider | `bool` | `true` | +| `aider_version` | The version of Aider to install | `string` | `"latest"` | +| `use_screen` | Whether to use screen for running Aider in the background | `bool` | `true` | +| `use_tmux` | Whether to use tmux instead of screen for running Aider in the background | `bool` | `false` | +| `session_name` | Name for the persistent session (screen or tmux) | `string` | `"aider"` | +| `order` | Position of the app in the UI presentation | `number` | `null` | +| `icon` | The icon to use for the app | `string` | `"/icon/aider.svg"` | +| `experiment_report_tasks` | Whether to enable task reporting | `bool` | `true` | +| `experiment_task_conventions` | Custom conventions for task reporting to be written to CONVENTIONS.md | `string` | See default in code | +| `experiment_pre_install_script` | Custom script to run before installing Aider | `string` | `null` | +| `experiment_post_install_script` | Custom script to run after installing Aider | `string` | `null` | +| `experiment_additional_extensions` | Additional extensions configuration in YAML format to append to the config | `string` | `null` | + +## Usage Examples + +### Basic setup + +```tf +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" +} +``` + +This basic setup will: + +- Install Aider in the workspace +- Create a persistent screen session named "aider" +- Enable task reporting (configures Aider to report tasks to Coder MCP) + +### With tmux instead of screen + +```tf +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" + use_tmux = true +} +``` + +### With API key via environment variables + +```tf +variable "anthropic_api_key" { + type = string + description = "Anthropic API key" + sensitive = true +} + +variable "anthropic_model" { + type = string + description = "Anthropic Model" + default = "sonnet" +} + +resource "coder_agent" "main" { + # ... +} + +# Set API key and model using coder_env resource +resource "coder_env" "anthropic" { + agent_id = coder_agent.example.id + name = "ANTHROPIC_API_KEY" + value = var.anthropic_api_key +} + +resource "coder_env" "aider_model" { + agent_id = coder_agent.example.id + name = "AIDER_MODEL" + value = var.anthropic_model +} + +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" +} +``` + +### Adding Custom Extensions (Experimental) + +You can extend Aider's capabilities by adding custom extensions: + +```tf +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" + + experiment_pre_install_script = <<-EOT + pip install some-custom-dependency + EOT + + experiment_additional_extensions = <<-EOT + custom-extension: + args: [] + cmd: custom-extension-command + description: A custom extension for Aider + enabled: true + envs: {} + name: custom-extension + timeout: 300 + type: stdio + EOT +} +``` + +Note: The indentation in the heredoc is preserved, so you can write the YAML naturally. + +## Task Reporting (Experimental) + +> This functionality is in early access as of Coder v2.21 and is still evolving. +> For now, we recommend testing it in a demo or staging environment, +> rather than deploying to production +> +> Learn more in [the Coder documentation](https://coder.com/docs/tutorials/ai-agents) +> +> Join our [Discord channel](https://discord.gg/coder) or +> [contact us](https://coder.com/contact) to get help or share feedback. + +Your workspace must have either `screen` or `tmux` installed to use this. + +Task reporting is **enabled by default** in this module, allowing you to: + +- Send an initial prompt to Aider during workspace creation +- Monitor task progress in the Coder UI +- Use the `coder_parameter` resource to collect prompts from users + +### Setting up Task Reporting + +To use task reporting effectively: + +1. Add the Coder Login module to your template +2. Configure the necessary environment variables to pass the task prompt and status slug +3. Optionally add a coder_parameter to collect prompts from users + +Here's a complete example: + +```tf +module "coder-login" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/coder-login/coder" + version = "1.0.15" + agent_id = coder_agent.example.id +} + +variable "anthropic_api_key" { + type = string + description = "Anthropic API key" + sensitive = true +} + +variable "anthropic_model" { + type = string + description = "Anthropic Model" + default = "sonnet" +} + +data "coder_parameter" "ai_prompt" { + type = "string" + name = "AI Prompt" + default = "" + description = "Write a prompt for Aider" + mutable = true + ephemeral = true +} + +# Configure environment variables for API key, model and task prompt +resource "coder_env" "anthropic" { + agent_id = coder_agent.example.id + name = "ANTHROPIC_API_KEY" + value = var.anthropic_api_key +} + +resource "coder_env" "aider_model" { + agent_id = coder_agent.example.id + name = "AIDER_MODEL" + value = var.anthropic_model +} + +resource "coder_env" "task_prompt" { + agent_id = coder_agent.example.id + name = "CODER_MCP_AIDER_TASK_PROMPT" + value = data.coder_parameter.ai_prompt.value +} + +resource "coder_env" "app_status" { + agent_id = coder_agent.example.id + name = "CODER_MCP_APP_STATUS_SLUG" + value = "aider" +} + +module "aider" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/modules/aider/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + folder = "/home/coder" +} +``` + +When a task prompt is provided, the module automatically: + +1. Executes the task during workspace creation using the `--message` and `--yes-always` flags +2. Creates a flag file to prevent duplicate execution if the Aider button is clicked later +3. Logs task output to `$HOME/.aider.log` for reference + +If you want to disable task reporting, set `experiment_report_tasks = false` in your module configuration. + +## Using Aider in Your Workspace + +After the workspace starts, Aider will be installed and configured according to your parameters. A persistent session will automatically be started during workspace creation. + +### Session Options + +You can run Aider in three different ways: + +1. **Direct Mode**: Aider starts directly in the specified folder when you click the app button + + - Simple setup without persistent context + - Suitable for quick coding sessions + +2. **Screen Mode** (Default): Run Aider in a screen session that persists across connections + + - Session name: "aider" (or configured via `session_name`) + +3. **Tmux Mode**: Run Aider in a tmux session instead of screen + - Set `use_tmux = true` to enable + - Session name: "aider" (or configured via `session_name`) + +Persistent sessions (screen/tmux) allow you to: + +- Disconnect and reconnect without losing context +- Run Aider in the background while doing other work +- Switch between terminal and browser interfaces + +### Available AI Providers and Models + +| Provider | Available Models | API Key Source | +| -------------- | ----------------------------------- | ----------------------------------------------------------- | +| **Anthropic** | Claude 3.7 Sonnet, Claude 3.7 Haiku | [console.anthropic.com](https://console.anthropic.com/) | +| **OpenAI** | o3-mini, o1, GPT-4o | [platform.openai.com](https://platform.openai.com/api-keys) | +| **DeepSeek** | DeepSeek R1, DeepSeek Chat V3 | [platform.deepseek.com](https://platform.deepseek.com/) | +| **GROQ** | Mixtral, Llama 3 | [console.groq.com](https://console.groq.com/keys) | +| **OpenRouter** | OpenRouter | [openrouter.ai](https://openrouter.ai/keys) | + +For a complete and up-to-date list of supported LLMs and models, please refer to the [Aider LLM documentation](https://aider.chat/docs/llms.html) and the [Aider LLM Leaderboards](https://aider.chat/docs/leaderboards.html) which show performance comparisons across different models. + +## Troubleshooting + +If you encounter issues: + +1. **Screen/Tmux issues**: If you can't reconnect to your session, check if the session exists with `screen -list` or `tmux list-sessions` +2. **API key issues**: Ensure you've entered the correct API key for your selected provider +3. **Browser mode issues**: If the browser interface doesn't open, check that you're accessing it from a machine that can reach your Coder workspace + +For more information on using Aider, see the [Aider documentation](https://aider.chat/docs/). diff --git a/aider/main.test.ts b/aider/main.test.ts new file mode 100644 index 00000000..8130ab87 --- /dev/null +++ b/aider/main.test.ts @@ -0,0 +1,144 @@ +import { describe, expect, it } from "bun:test"; +import { + execContainer, + findResourceInstance, + runContainer, + runTerraformApply, + runTerraformInit, + testRequiredVariables, + type TerraformState, +} from "../test"; + +// Executes the coder script after installing bash (required for the script) +const executeScriptInContainerWithBash = async ( + state: TerraformState, + image = "alpine", + extraCommands = "", +): Promise<{ + exitCode: number; + stdout: string[]; + stderr: string[]; +}> => { + const instance = findResourceInstance(state, "coder_script"); + const id = await runContainer(image); + + await execContainer(id, [ + "sh", + "-c", + ` + apk add --no-cache bash + mkdir -p /home/coder/bin + touch /home/coder/.aider.log + ${extraCommands} + `, + ]); + + const resp = await execContainer(id, [ + "bash", + "-c", + ` + # Source any environment variables that might have been set + if [ -f /tmp/env_vars.sh ]; then + source /tmp/env_vars.sh + fi + + # Run the script + ${instance.script} + `, + ]); + const stdout = resp.stdout.trim().split("\n"); + const stderr = resp.stderr.trim().split("\n"); + return { + exitCode: resp.exitCode, + stdout, + stderr, + }; +}; + +describe("aider", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, { + agent_id: "foo", + }); + + it("installs aider with default settings", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + }); + + const output = await executeScriptInContainerWithBash(state); + + expect(output.stdout).toContain("Setting up Aider AI pair programming..."); + }); + + it("configures task reporting when enabled", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + experiment_report_tasks: true, + }); + + const output = await executeScriptInContainerWithBash(state); + + expect(output.stdout).toContain( + "Configuring Aider to report tasks via Coder MCP...", + ); + }); + + it("passes aider cmd with correct flags when prompt is provided", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + }); + + const testPrompt = "Add a hello world function"; + + const output = await executeScriptInContainerWithBash( + state, + "alpine", + `echo 'export CODER_MCP_AIDER_TASK_PROMPT="${testPrompt}"' > /tmp/env_vars.sh`, + ); + + const instance = findResourceInstance(state, "coder_script"); + + expect( + instance.script.includes( + "aider --architect --yes-always --read CONVENTIONS.md --message", + ), + ).toBe(true); + + expect( + instance.script.includes( + '--message \\"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\\"', + ), + ).toBe(true); + + expect( + instance.script.includes('export CODER_MCP_APP_STATUS_SLUG=\\"aider\\"'), + ).toBe(true); + + expect( + output.stdout.some((line) => + line.includes("Running Aider with message in screen session"), + ), + ).toBe(true); + + expect( + output.stdout.some((line) => + line.includes("Creating ~/.screenrc and adding multiuser settings"), + ), + ).toBe(true); + }); + + it("executes pre and post install scripts", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + experiment_pre_install_script: "echo 'Pre-install script executed'", + experiment_post_install_script: "echo 'Post-install script executed'", + }); + + const output = await executeScriptInContainerWithBash(state); + + expect(output.stdout).toContain("Running pre-install script..."); + expect(output.stdout).toContain("Running post-install script..."); + }); +}); diff --git a/aider/main.tf b/aider/main.tf new file mode 100644 index 00000000..5f46cea3 --- /dev/null +++ b/aider/main.tf @@ -0,0 +1,420 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.17" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} + +variable "icon" { + type = string + description = "The icon to use for the app." + default = "/icon/aider.svg" +} + +variable "folder" { + type = string + description = "The folder to run Aider in." + default = "/home/coder" +} + +variable "install_aider" { + type = bool + description = "Whether to install Aider." + default = true +} + +variable "aider_version" { + type = string + description = "The version of Aider to install." + default = "latest" +} + +variable "use_screen" { + type = bool + description = "Whether to use screen for running Aider in the background" + default = true +} + +variable "use_tmux" { + type = bool + description = "Whether to use tmux instead of screen for running Aider in the background" + default = false +} + +variable "session_name" { + type = string + description = "Name for the persistent session (screen or tmux)" + default = "aider" +} + +variable "experiment_report_tasks" { + type = bool + description = "Whether to enable task reporting." + default = true +} + +variable "experiment_task_conventions" { + type = string + description = "Custom conventions for task reporting to be written to CONVENTIONS.md" + default = <<-EOT +# Aider Coding Conventions + +## Task Reporting Requirements + +As you work on tasks, you MUST follow these task reporting conventions: + +1. ALWAYS report the status of each task to Coder before and after your steps. +2. Use the following format for reporting tasks: + ``` + TASK: [brief description of what you're doing] + STATUS: [one of: "started", "in progress", "done", "failed"] + ``` + +3. Send a task report in these specific situations: + - When you BEGIN working on a task + - When you make SIGNIFICANT PROGRESS on a task + - When you COMPLETE a task successfully + - When you ENCOUNTER AN ERROR or cannot complete a task + +4. Example sequence of task reporting: + ``` + TASK: Setting up project structure + STATUS: started + + [Your work and discussion here] + + TASK: Setting up project structure + STATUS: in progress + + [More work and discussion] + + TASK: Setting up project structure + STATUS: done + + TASK: Implementing feature X + STATUS: started + ``` + +5. Always include a brief but descriptive task name that clearly identifies what you're working on. + +These conventions ensure that Coder can properly track task status in the UI. +EOT +} + +variable "experiment_pre_install_script" { + type = string + description = "Custom script to run before installing Aider." + default = null +} + +variable "experiment_post_install_script" { + type = string + description = "Custom script to run after installing Aider." + default = null +} + +variable "experiment_additional_extensions" { + type = string + description = "Additional extensions configuration in YAML format to append to the config." + default = null +} + +locals { + base_extensions = <<-EOT +coder: + args: + - exp + - mcp + - server + cmd: coder + description: Report ALL tasks and statuses (in progress, done, failed) you are working on. + enabled: true + envs: + CODER_MCP_APP_STATUS_SLUG: aider + name: Coder + timeout: 3000 + type: stdio +developer: + display_name: Developer + enabled: true + name: developer + timeout: 300 + type: builtin +EOT + + formatted_base = " ${replace(trimspace(local.base_extensions), "\n", "\n ")}" + additional_extensions = var.experiment_additional_extensions != null ? "\n ${replace(trimspace(var.experiment_additional_extensions), "\n", "\n ")}" : "" + + combined_extensions = <<-EOT +extensions: +${local.formatted_base}${local.additional_extensions} +EOT + + encoded_pre_install_script = var.experiment_pre_install_script != null ? base64encode(var.experiment_pre_install_script) : "" + encoded_post_install_script = var.experiment_post_install_script != null ? base64encode(var.experiment_post_install_script) : "" +} + +# Install and Initialize Aider +resource "coder_script" "aider" { + agent_id = var.agent_id + display_name = "Aider" + icon = "/icon/aider.svg" + script = <<-EOT + #!/bin/bash + set -e + + command_exists() { + command -v "$1" >/dev/null 2>&1 + } + + echo "Setting up Aider AI pair programming..." + + mkdir -p "${var.folder}" + + if [ "$(uname)" = "Linux" ]; then + echo "Checking dependencies for Linux..." + + if [ "${var.use_tmux}" = "true" ]; then + if ! command_exists tmux; then + echo "Installing tmux for persistent sessions..." + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq tmux + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y -q tmux + else + echo "Warning: Unable to install tmux on this system." + fi + else + echo "tmux is already installed, skipping installation." + fi + elif [ "${var.use_screen}" = "true" ]; then + if ! command_exists screen; then + echo "Installing screen for persistent sessions..." + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq screen + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y -q screen + else + echo "Warning: Unable to install screen on this system." + fi + else + echo "screen is already installed, skipping installation." + fi + fi + else + echo "This module currently only supports Linux workspaces." + exit 1 + fi + + if [ -n "${local.encoded_pre_install_script}" ]; then + echo "Running pre-install script..." + echo "${local.encoded_pre_install_script}" | base64 -d > /tmp/pre_install.sh + chmod +x /tmp/pre_install.sh + /tmp/pre_install.sh + fi + + if [ "${var.install_aider}" = "true" ]; then + echo "Installing Aider..." + + if ! command_exists python3 || ! command_exists pip3; then + echo "Installing Python dependencies required for Aider..." + if command -v apt-get >/dev/null 2>&1; then + sudo apt-get update -qq + sudo apt-get install -y -qq python3-pip python3-venv + elif command -v dnf >/dev/null 2>&1; then + sudo dnf install -y -q python3-pip python3-virtualenv + else + echo "Warning: Unable to install Python on this system." + fi + else + echo "Python is already installed, skipping installation." + fi + + if ! command_exists aider; then + curl -LsSf https://aider.chat/install.sh | sh + fi + + if [ -f "$HOME/.bashrc" ]; then + if ! grep -q 'export PATH="$HOME/bin:$PATH"' "$HOME/.bashrc"; then + echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc" + fi + fi + + if [ -f "$HOME/.zshrc" ]; then + if ! grep -q 'export PATH="$HOME/bin:$PATH"' "$HOME/.zshrc"; then + echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.zshrc" + fi + fi + + fi + + if [ -n "${local.encoded_post_install_script}" ]; then + echo "Running post-install script..." + echo "${local.encoded_post_install_script}" | base64 -d > /tmp/post_install.sh + chmod +x /tmp/post_install.sh + /tmp/post_install.sh + fi + + if [ "${var.experiment_report_tasks}" = "true" ]; then + echo "Configuring Aider to report tasks via Coder MCP..." + + mkdir -p "$HOME/.config/aider" + + cat > "$HOME/.config/aider/config.yml" << EOL +${trimspace(local.combined_extensions)} +EOL + echo "Added Coder MCP extension to Aider config.yml" + + mkdir -p "${var.folder}" + cat > "${var.folder}/CONVENTIONS.md" << 'CONVENTIONS_EOF' +${var.experiment_task_conventions} +CONVENTIONS_EOF + echo "Created CONVENTIONS.md file with task reporting instructions" + fi + + echo "Starting persistent Aider session..." + + touch "$HOME/.aider.log" + + export LANG=en_US.UTF-8 + export LC_ALL=en_US.UTF-8 + + export PATH="$HOME/bin:$PATH" + + if [ "${var.use_tmux}" = "true" ]; then + if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]; then + echo "Running Aider with message in tmux session..." + tmux new-session -d -s ${var.session_name} -c ${var.folder} "echo \"Starting Aider with app status slug: aider\"; export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --architect --yes-always --read CONVENTIONS.md --message \"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\"" + echo "Aider task started in tmux session '${var.session_name}'. Check the UI for progress." + else + tmux new-session -d -s ${var.session_name} -c ${var.folder} "echo \"Starting Aider with app status slug: aider\"; export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --read CONVENTIONS.md" + echo "Tmux session '${var.session_name}' started. Access it by clicking the Aider button." + fi + else + if [ -n "$CODER_MCP_AIDER_TASK_PROMPT" ]; then + echo "Running Aider with message in screen session..." + + if [ ! -f "$HOME/.screenrc" ]; then + echo "Creating ~/.screenrc and adding multiuser settings..." + echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc" + fi + + if ! grep -q "^multiuser on$" "$HOME/.screenrc"; then + echo "Adding 'multiuser on' to ~/.screenrc..." + echo "multiuser on" >> "$HOME/.screenrc" + fi + + if ! grep -q "^acladd $(whoami)$" "$HOME/.screenrc"; then + echo "Adding 'acladd $(whoami)' to ~/.screenrc..." + echo "acladd $(whoami)" >> "$HOME/.screenrc" + fi + + screen -U -dmS ${var.session_name} bash -c " + cd ${var.folder} + export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\" + export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\" + export CODER_MCP_APP_STATUS_SLUG=\"aider\" + echo \"Starting Aider with app status slug: aider\" + aider --architect --yes-always --read CONVENTIONS.md --message \"Report each step to Coder. Your task: $CODER_MCP_AIDER_TASK_PROMPT\" + /bin/bash + " + + echo "Aider task started in screen session '${var.session_name}'. Check the UI for progress." + else + + if [ ! -f "$HOME/.screenrc" ]; then + echo "Creating ~/.screenrc and adding multiuser settings..." + echo -e "multiuser on\nacladd $(whoami)" > "$HOME/.screenrc" + fi + + if ! grep -q "^multiuser on$" "$HOME/.screenrc"; then + echo "Adding 'multiuser on' to ~/.screenrc..." + echo "multiuser on" >> "$HOME/.screenrc" + fi + + if ! grep -q "^acladd $(whoami)$" "$HOME/.screenrc"; then + echo "Adding 'acladd $(whoami)' to ~/.screenrc..." + echo "acladd $(whoami)" >> "$HOME/.screenrc" + fi + + screen -U -dmS ${var.session_name} bash -c " + cd ${var.folder} + export PATH=\"$HOME/bin:$HOME/.local/bin:$PATH\" + export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\" + export CODER_MCP_APP_STATUS_SLUG=\"aider\" + echo \"Starting Aider with app status slug: aider\" + aider --read CONVENTIONS.md + /bin/bash + " + echo "Screen session '${var.session_name}' started. Access it by clicking the Aider button." + fi + fi + + echo "Aider setup complete!" + EOT + run_on_start = true +} + +# Aider CLI app +resource "coder_app" "aider_cli" { + agent_id = var.agent_id + slug = "aider" + display_name = "Aider" + icon = var.icon + command = <<-EOT + #!/bin/bash + set -e + + export PATH="$HOME/bin:$HOME/.local/bin:$PATH" + + export CODER_MCP_APP_STATUS_SLUG="aider" + + export LANG=en_US.UTF-8 + export LC_ALL=en_US.UTF-8 + + if [ "${var.use_tmux}" = "true" ]; then + if tmux has-session -t ${var.session_name} 2>/dev/null; then + echo "Attaching to existing Aider tmux session..." + tmux setenv -t ${var.session_name} CODER_MCP_APP_STATUS_SLUG "aider" + tmux attach-session -t ${var.session_name} + else + echo "Starting new Aider tmux session..." + tmux new-session -s ${var.session_name} -c ${var.folder} "export ANTHROPIC_API_KEY=\"$ANTHROPIC_API_KEY\"; export CODER_MCP_APP_STATUS_SLUG=\"aider\"; aider --read CONVENTIONS.md; exec bash" + fi + elif [ "${var.use_screen}" = "true" ]; then + if ! screen -list | grep -q "${var.session_name}"; then + echo "Error: No existing Aider session found. Please wait for the script to start it." + exit 1 + fi + export CODER_MCP_APP_STATUS_SLUG="aider" + screen -xRR ${var.session_name} + else + cd "${var.folder}" + echo "Starting Aider directly..." + export CODER_MCP_APP_STATUS_SLUG="aider" + aider --read CONVENTIONS.md + fi + EOT + order = var.order +}