diff --git a/README.org b/README.org index 14981d1d..918c875a 100644 --- a/README.org +++ b/README.org @@ -88,13 +88,7 @@ For Goose CLI, install [[https://block.github.io/goose/docs/getting-started/inst *** Cursor -For Cursor agent, install with: - -#+begin_src bash -npm install -g @blowmage/cursor-agent-acp -#+end_src - -See https://github.com/blowmage/cursor-agent-acp-npm for details. +For Cursor agent, install the official [[https://cursor.com/docs/cli/acp][Cursor CLI]] and ensure the `agent` executable is in PATH. *** Kiro CLI @@ -395,6 +389,48 @@ For API key authentication: (shell-command-to-string "source ~/.vibe/.env; echo $MISTRAL_API_KEY"))))) #+end_src +*** Cursor + +For login-based authentication (default): + +#+begin_src emacs-lisp +(setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :login t)) +#+end_src + +For API key authentication: + +#+begin_src emacs-lisp +;; With string +(setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :api-key "your-cursor-api-key-here")) + +;; With function +(setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication + :api-key (lambda () (auth-source-pass-get "secret" "cursor-api-key")))) +#+end_src + +For auth token authentication: + +#+begin_src emacs-lisp +;; With string +(setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :auth-token "your-cursor-auth-token")) + +;; With function +(setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication + :auth-token (lambda () (auth-source-pass-get "secret" "cursor-auth-token")))) +#+end_src + +For no authentication (when already authenticated via =agent login=): + +#+begin_src emacs-lisp +(setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :none t)) +#+end_src + *** Customizing Available Agents By default, =agent-shell= includes configurations for all supported agents (Claude Agent, Gemini CLI, Codex, Goose, Qwen Code, and Auggie). You can customize which agents are available through the =agent-shell-agent-configs= variable. diff --git a/agent-shell-cursor.el b/agent-shell-cursor.el index ee2d3c1c..da0955de 100644 --- a/agent-shell-cursor.el +++ b/agent-shell-cursor.el @@ -20,7 +20,11 @@ ;;; Commentary: ;; -;; This file includes Cursor-specific configurations. +;; This file includes Cursor-specific configurations using the official +;; Cursor CLI (agent acp) for ACP (Agent Client Protocol) communication. +;; +;; See https://cursor.com/docs/cli/acp for more information about +;; Cursor's official ACP implementation. ;; ;;; Code: @@ -36,8 +40,66 @@ (declare-function agent-shell--make-acp-client "agent-shell") (declare-function agent-shell--dwim "agent-shell") +(cl-defun agent-shell-cursor-make-authentication (&key api-key auth-token login none) + "Create Cursor authentication configuration. + +API-KEY is the Cursor API key string or function that returns it. +AUTH-TOKEN is the Cursor auth token string or function that returns it. +LOGIN when non-nil indicates to use cursor_login authentication. +NONE when non-nil indicates no authentication method is used. + +Only one of API-KEY, AUTH-TOKEN, LOGIN, or NONE should be provided." + (when (> (seq-count #'identity (list api-key auth-token login)) 1) + (error "Cannot specify multiple authentication methods - choose one")) + (unless (> (seq-count #'identity (list api-key auth-token login none)) 0) + (error "Must specify one of :api-key, :auth-token, :login, or :none")) + (cond + (api-key `((:api-key . ,api-key))) + (auth-token `((:auth-token . ,auth-token))) + (login `((:login . t))) + (none `((:none . t))))) + +(defcustom agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :login t) + "Configuration for Cursor authentication. + +For login-based authentication (default): + + (setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :login t)) + +For API key (string): + + (setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :api-key \"your-key\")) + +For API key (function): + + (setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :api-key (lambda () ...))) + +For auth token (string): + + (setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :auth-token \"your-token\")) + +For auth token (function): + + (setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :auth-token (lambda () ...))) + +For no authentication (already authenticated externally): + + (setq agent-shell-cursor-authentication + (agent-shell-cursor-make-authentication :none t)) + +When using :api-key or :auth-token, the corresponding environment +variable (CURSOR_API_KEY or CURSOR_AUTH_TOKEN) will be set automatically." + :type 'alist + :group 'agent-shell) + (defcustom agent-shell-cursor-acp-command - '("cursor-agent-acp") + '("agent" "acp") "Command and parameters for the Cursor agent client. The first element is the command name, and the rest are command parameters." @@ -49,7 +111,15 @@ The first element is the command name, and the rest are command parameters." "Environment variables for the Cursor agent client. This should be a list of environment variables to be used when -starting the Cursor agent process." +starting the Cursor agent process. + +Cursor CLI supports the following authentication environment variables: + - CURSOR_API_KEY: API key for authentication + - CURSOR_AUTH_TOKEN: Auth token for authentication + +These can be used for pre-authentication before the ACP session starts. +If not set, the authentication method specified in +`agent-shell-cursor-authentication' will be used." :type '(repeat string) :group 'agent-shell) @@ -67,7 +137,12 @@ Returns an agent configuration alist using `agent-shell-make-agent-config'." :welcome-function #'agent-shell-cursor--welcome-message :client-maker (lambda (buffer) (agent-shell-cursor-make-client :buffer buffer)) - :install-instructions "Install with: npm install -g @blowmage/cursor-agent-acp\nSee https://github.com/blowmage/cursor-agent-acp-npm for details.")) + :needs-authentication (not (map-elt agent-shell-cursor-authentication :none)) + :authenticate-request-maker (lambda () + (when (not (map-elt agent-shell-cursor-authentication :none)) + (acp-make-authenticate-request + :method-id "cursor_login"))) + :install-instructions "See https://cursor.com/docs/cli for installation.")) (defun agent-shell-cursor-start-agent () "Start an interactive Cursor agent shell." @@ -81,10 +156,29 @@ Returns an agent configuration alist using `agent-shell-make-agent-config'." (error "Missing required argument: :buffer")) (when (and (boundp 'agent-shell-cursor-command) agent-shell-cursor-command) (user-error "Please migrate to use agent-shell-cursor-acp-command and eval (setq agent-shell-cursor-command nil)")) - (agent-shell--make-acp-client :command (car agent-shell-cursor-acp-command) - :command-params (cdr agent-shell-cursor-acp-command) - :environment-variables agent-shell-cursor-environment - :context-buffer buffer)) + (let* ((api-key-value (map-elt agent-shell-cursor-authentication :api-key)) + (auth-token-value (map-elt agent-shell-cursor-authentication :auth-token)) + (env-vars-overrides + (cond + (api-key-value + (list (format "CURSOR_API_KEY=%s" + (if (functionp api-key-value) + (funcall api-key-value) + api-key-value)))) + (auth-token-value + (list (format "CURSOR_AUTH_TOKEN=%s" + (if (functionp auth-token-value) + (funcall auth-token-value) + auth-token-value)))) + ((map-elt agent-shell-cursor-authentication :login) + ;; Set empty API key to force login flow if not already authenticated + (list "CURSOR_API_KEY=")) + (t nil)))) + (agent-shell--make-acp-client :command (car agent-shell-cursor-acp-command) + :command-params (cdr agent-shell-cursor-acp-command) + :environment-variables (append env-vars-overrides + agent-shell-cursor-environment) + :context-buffer buffer))) (defun agent-shell-cursor--welcome-message (config) "Return Cursor welcome message using `shell-maker' CONFIG."