Add new cursor-cli module
- Create separate cursor-cli module instead of modifying existing cursor module - Add AgentAPI integration for web interface and CLI support - Support both interactive and non-interactive modes - Include installation and start scripts for cursor-agent - Comprehensive documentation with CLI usage examples - Add tests for CLI functionality - Configure interactive mode with text output Co-authored-by: matifali <10648092+matifali@users.noreply.github.com>
This commit is contained in:
parent
142167f9c0
commit
6677432df7
167
registry/coder/modules/cursor-cli/README.md
Normal file
167
registry/coder/modules/cursor-cli/README.md
Normal file
@ -0,0 +1,167 @@
|
||||
---
|
||||
display_name: Cursor CLI
|
||||
description: Run Cursor CLI agent in your workspace
|
||||
icon: ../../../../.icons/cursor.svg
|
||||
verified: true
|
||||
tags: [cli, cursor, ai, agent]
|
||||
---
|
||||
|
||||
# Cursor CLI
|
||||
|
||||
Run the [Cursor CLI](https://docs.cursor.com/en/cli/overview) agent in your workspace for terminal-based AI coding assistance.
|
||||
|
||||
```tf
|
||||
module "cursor-cli" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/cursor-cli/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder"
|
||||
}
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- You must add the [Coder Login](https://registry.coder.com/modules/coder-login) module to your template
|
||||
|
||||
## Features
|
||||
|
||||
- **CLI Agent**: Terminal-based AI coding assistant with interactive and non-interactive modes
|
||||
- **AgentAPI Integration**: Web interface for CLI interactions
|
||||
- **Interactive Mode**: Conversational sessions with text output
|
||||
- **Non-Interactive Mode**: Automation-friendly for scripts and CI pipelines
|
||||
- **Session Management**: List, resume, and manage coding sessions
|
||||
- **Model Selection**: Support for multiple AI models (GPT-5, Claude, etc.)
|
||||
- **MCP Support**: Model Context Protocol for extended functionality
|
||||
- **Rules System**: Custom agent behavior configuration
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic setup
|
||||
|
||||
```tf
|
||||
module "coder-login" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/coder-login/coder"
|
||||
version = "1.0.15"
|
||||
agent_id = coder_agent.example.id
|
||||
}
|
||||
|
||||
module "cursor-cli" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/cursor-cli/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder/project"
|
||||
install_cursor_cli = true
|
||||
install_agentapi = true
|
||||
}
|
||||
```
|
||||
|
||||
### CLI only (no web interface)
|
||||
|
||||
```tf
|
||||
module "cursor-cli" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/cursor-cli/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
folder = "/home/coder/project"
|
||||
install_cursor_cli = true
|
||||
install_agentapi = false
|
||||
}
|
||||
```
|
||||
|
||||
### With custom pre-install script
|
||||
|
||||
```tf
|
||||
module "cursor-cli" {
|
||||
count = data.coder_workspace.me.start_count
|
||||
source = "registry.coder.com/coder/cursor-cli/coder"
|
||||
version = "1.0.0"
|
||||
agent_id = coder_agent.example.id
|
||||
|
||||
pre_install_script = <<-EOT
|
||||
# Install additional dependencies
|
||||
npm install -g typescript
|
||||
EOT
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Web Interface
|
||||
|
||||
1. Click the "Cursor CLI" button to access the web interface
|
||||
2. Start interactive sessions with text output
|
||||
|
||||
### Terminal Usage
|
||||
|
||||
```bash
|
||||
# Interactive mode (default)
|
||||
cursor-agent
|
||||
|
||||
# Interactive mode with initial prompt
|
||||
cursor-agent "refactor the auth module to use JWT tokens"
|
||||
|
||||
# Non-interactive mode with text output
|
||||
cursor-agent -p "find and fix performance issues" --output-format text
|
||||
|
||||
# Use specific model
|
||||
cursor-agent -p "add error handling" --model "gpt-5"
|
||||
|
||||
# Session management
|
||||
cursor-agent ls # List all previous chats
|
||||
cursor-agent resume # Resume latest conversation
|
||||
cursor-agent --resume="chat-id" # Resume specific conversation
|
||||
```
|
||||
|
||||
### Interactive Mode Features
|
||||
|
||||
- Conversational sessions with the agent
|
||||
- Review proposed changes before applying
|
||||
- Real-time guidance and steering
|
||||
- Text-based output optimized for terminal use
|
||||
- Session persistence and resumption
|
||||
|
||||
### Non-Interactive Mode Features
|
||||
|
||||
- Automation-friendly for scripts and CI pipelines
|
||||
- Direct prompt execution with text output
|
||||
- Model selection support
|
||||
- Git integration for change reviews
|
||||
|
||||
## Configuration
|
||||
|
||||
The module supports the same configuration options as the Cursor CLI:
|
||||
|
||||
- **MCP (Model Context Protocol)**: Automatically detects `mcp.json` configuration
|
||||
- **Rules System**: Supports `.cursor/rules` directory for custom agent behavior
|
||||
- **Environment Variables**: Respects Cursor CLI environment settings
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
The module creates log files in the workspace's `~/.cursor-cli-module` directory. Check these files if you encounter issues:
|
||||
|
||||
```bash
|
||||
# Check installation logs
|
||||
cat ~/.cursor-cli-module/install.log
|
||||
|
||||
# Check runtime logs
|
||||
cat ~/.cursor-cli-module/runtime.log
|
||||
|
||||
# Verify Cursor CLI installation
|
||||
cursor-agent --help
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Cursor CLI not found**: Ensure `install_cursor_cli = true` or install manually:
|
||||
|
||||
```bash
|
||||
curl https://cursor.com/install -fsS | bash
|
||||
```
|
||||
|
||||
2. **Permission issues**: Check that the installation script has proper permissions
|
||||
|
||||
3. **Path issues**: The module automatically adds Cursor CLI to PATH, but you may need to restart your shell
|
||||
80
registry/coder/modules/cursor-cli/main.test.ts
Normal file
80
registry/coder/modules/cursor-cli/main.test.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import {
|
||||
runTerraformApply,
|
||||
runTerraformInit,
|
||||
testRequiredVariables,
|
||||
} from "~test";
|
||||
|
||||
describe("cursor-cli", async () => {
|
||||
await runTerraformInit(import.meta.dir);
|
||||
|
||||
testRequiredVariables(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
});
|
||||
|
||||
it("default output with CLI enabled", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
});
|
||||
|
||||
// Check that AgentAPI module is created
|
||||
const agentapi_module = state.resources.find(
|
||||
(res) => res.type === "module" && res.name === "agentapi",
|
||||
);
|
||||
expect(agentapi_module).not.toBeNull();
|
||||
});
|
||||
|
||||
it("adds custom folder", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
folder: "/foo/bar",
|
||||
});
|
||||
|
||||
// Check that AgentAPI module is created with custom folder
|
||||
const agentapi_module = state.resources.find(
|
||||
(res) => res.type === "module" && res.name === "agentapi",
|
||||
);
|
||||
expect(agentapi_module).not.toBeNull();
|
||||
});
|
||||
|
||||
it("expect order to be set", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
order: "22",
|
||||
});
|
||||
|
||||
// Check that AgentAPI module is created
|
||||
const agentapi_module = state.resources.find(
|
||||
(res) => res.type === "module" && res.name === "agentapi",
|
||||
);
|
||||
expect(agentapi_module).not.toBeNull();
|
||||
});
|
||||
|
||||
it("disables CLI installation", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
install_cursor_cli: "false",
|
||||
install_agentapi: "false",
|
||||
});
|
||||
|
||||
// AgentAPI module should still exist but with install_agentapi = false
|
||||
const agentapi_module = state.resources.find(
|
||||
(res) => res.type === "module" && res.name === "agentapi",
|
||||
);
|
||||
expect(agentapi_module).not.toBeNull();
|
||||
});
|
||||
|
||||
it("enables only CLI without web interface", async () => {
|
||||
const state = await runTerraformApply(import.meta.dir, {
|
||||
agent_id: "foo",
|
||||
install_cursor_cli: "true",
|
||||
install_agentapi: "false",
|
||||
});
|
||||
|
||||
// AgentAPI module should exist but with install_agentapi = false
|
||||
const agentapi_module = state.resources.find(
|
||||
(res) => res.type === "module" && res.name === "agentapi",
|
||||
);
|
||||
expect(agentapi_module).not.toBeNull();
|
||||
});
|
||||
});
|
||||
119
registry/coder/modules/cursor-cli/main.tf
Normal file
119
registry/coder/modules/cursor-cli/main.tf
Normal file
@ -0,0 +1,119 @@
|
||||
terraform {
|
||||
required_version = ">= 1.0"
|
||||
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">= 2.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 "group" {
|
||||
type = string
|
||||
description = "The name of a group that this app belongs to."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "icon" {
|
||||
type = string
|
||||
description = "The icon to use for the app."
|
||||
default = "/icon/cursor.svg"
|
||||
}
|
||||
|
||||
variable "folder" {
|
||||
type = string
|
||||
description = "The folder to run Cursor CLI in."
|
||||
default = "/home/coder"
|
||||
}
|
||||
|
||||
variable "install_cursor_cli" {
|
||||
type = bool
|
||||
description = "Whether to install Cursor CLI."
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "install_agentapi" {
|
||||
type = bool
|
||||
description = "Whether to install AgentAPI."
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "agentapi_version" {
|
||||
type = string
|
||||
description = "The version of AgentAPI to install."
|
||||
default = "v0.3.3"
|
||||
}
|
||||
|
||||
variable "subdomain" {
|
||||
type = bool
|
||||
description = "Whether to use a subdomain for AgentAPI."
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "pre_install_script" {
|
||||
type = string
|
||||
description = "Custom script to run before installing Cursor CLI."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "post_install_script" {
|
||||
type = string
|
||||
description = "Custom script to run after installing Cursor CLI."
|
||||
default = null
|
||||
}
|
||||
|
||||
locals {
|
||||
app_slug = "cursor-cli"
|
||||
install_script = file("${path.module}/scripts/install.sh")
|
||||
start_script = file("${path.module}/scripts/start.sh")
|
||||
module_dir_name = ".cursor-cli-module"
|
||||
}
|
||||
|
||||
module "agentapi" {
|
||||
source = "registry.coder.com/coder/agentapi/coder"
|
||||
version = "1.1.0"
|
||||
|
||||
agent_id = var.agent_id
|
||||
web_app_slug = local.app_slug
|
||||
web_app_order = var.order
|
||||
web_app_group = var.group
|
||||
web_app_icon = var.icon
|
||||
web_app_display_name = "Cursor CLI"
|
||||
cli_app_slug = "${local.app_slug}-terminal"
|
||||
cli_app_display_name = "Cursor CLI Terminal"
|
||||
module_dir_name = local.module_dir_name
|
||||
install_agentapi = var.install_agentapi
|
||||
agentapi_version = var.agentapi_version
|
||||
agentapi_subdomain = var.subdomain
|
||||
pre_install_script = var.pre_install_script
|
||||
post_install_script = var.post_install_script
|
||||
start_script = local.start_script
|
||||
install_script = <<-EOT
|
||||
#!/bin/bash
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh
|
||||
chmod +x /tmp/install.sh
|
||||
|
||||
ARG_FOLDER='${var.folder}' \
|
||||
ARG_INSTALL='${var.install_cursor_cli}' \
|
||||
/tmp/install.sh
|
||||
EOT
|
||||
}
|
||||
45
registry/coder/modules/cursor-cli/scripts/install.sh
Normal file
45
registry/coder/modules/cursor-cli/scripts/install.sh
Normal file
@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to check if a command exists
|
||||
command_exists() {
|
||||
command -v "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
set -o nounset
|
||||
|
||||
echo "--------------------------------"
|
||||
echo "folder: $ARG_FOLDER"
|
||||
echo "install: $ARG_INSTALL"
|
||||
echo "--------------------------------"
|
||||
|
||||
set +o nounset
|
||||
|
||||
if [ "${ARG_INSTALL}" = "true" ]; then
|
||||
echo "Installing Cursor CLI..."
|
||||
|
||||
# Install Cursor CLI using the official installer
|
||||
curl https://cursor.com/install -fsS | bash
|
||||
|
||||
# Add cursor-agent to PATH if not already there
|
||||
if ! command_exists cursor-agent; then
|
||||
echo 'export PATH="$HOME/.cursor/bin:$PATH"' >> "$HOME/.bashrc"
|
||||
echo 'export PATH="$HOME/.cursor/bin:$PATH"' >> "$HOME/.zshrc" 2> /dev/null || true
|
||||
export PATH="$HOME/.cursor/bin:$PATH"
|
||||
fi
|
||||
|
||||
echo "Cursor CLI installed"
|
||||
else
|
||||
echo "Skipping Cursor CLI installation"
|
||||
fi
|
||||
|
||||
# Verify installation
|
||||
if command_exists cursor-agent; then
|
||||
CURSOR_CMD=cursor-agent
|
||||
elif [ -f "$HOME/.cursor/bin/cursor-agent" ]; then
|
||||
CURSOR_CMD="$HOME/.cursor/bin/cursor-agent"
|
||||
else
|
||||
echo "Warning: Cursor CLI is not installed or not found in PATH. Please enable install_cursor_cli or install it manually."
|
||||
echo "You can install it manually with: curl https://cursor.com/install -fsS | bash"
|
||||
fi
|
||||
|
||||
echo "Cursor CLI setup complete"
|
||||
45
registry/coder/modules/cursor-cli/scripts/start.sh
Normal file
45
registry/coder/modules/cursor-cli/scripts/start.sh
Normal file
@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to check if a command exists
|
||||
command_exists() {
|
||||
command -v "$1" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Set working directory
|
||||
if [ -n "${ARG_FOLDER:-}" ] && [ -d "${ARG_FOLDER}" ]; then
|
||||
cd "${ARG_FOLDER}" || {
|
||||
echo "Warning: Could not change to directory ${ARG_FOLDER}, using current directory"
|
||||
}
|
||||
fi
|
||||
|
||||
# Find cursor-agent command
|
||||
if command_exists cursor-agent; then
|
||||
CURSOR_CMD=cursor-agent
|
||||
elif [ -f "$HOME/.cursor/bin/cursor-agent" ]; then
|
||||
CURSOR_CMD="$HOME/.cursor/bin/cursor-agent"
|
||||
else
|
||||
echo "Error: Cursor CLI is not installed. Please enable install_cursor_cli or install it manually."
|
||||
echo "You can install it manually with: curl https://cursor.com/install -fsS | bash"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting Cursor CLI in $(pwd)"
|
||||
echo "Interactive mode with text output enabled"
|
||||
echo "Available commands:"
|
||||
echo " - Start interactive session: cursor-agent"
|
||||
echo " - Non-interactive mode: cursor-agent -p 'your prompt here'"
|
||||
echo " - With specific model: cursor-agent -p 'prompt' --model 'gpt-5'"
|
||||
echo " - Text output format: cursor-agent -p 'prompt' --output-format text"
|
||||
echo " - List sessions: cursor-agent ls"
|
||||
echo " - Resume session: cursor-agent resume"
|
||||
echo ""
|
||||
|
||||
# Configure for interactive mode with text output
|
||||
# If no arguments provided, start in interactive mode
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Starting interactive session..."
|
||||
exec "$CURSOR_CMD"
|
||||
else
|
||||
# Pass through all arguments for custom usage
|
||||
exec "$CURSOR_CMD" "$@"
|
||||
fi
|
||||
Loading…
x
Reference in New Issue
Block a user