diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 892dbb8..f62f2d0 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -1380,52 +1380,25 @@ Do this when you edit your project view." ;; ================================================================= (use-package jsonnet-mode :ensure t) + +;; ================================================================= +;; Copilot (ugh) +;; ================================================================= +(use-package editorconfig :ensure) +(use-package jsonrpc :ensure) +;; (use-package copilot +;; :load-path (lambda () (expand-file-name "~/site-lisp/copilot")) +;; :after (editorconfig jsonrpc)) + ;; ================================================================= ;; Fish shell ;; ================================================================= (use-package fish-mode :ensure) ;; ================================================================= -;; AI Shit +;; gptel ;; ================================================================= -(use-package request :ensure) - -(use-package claude - :load-path "~/site-lisp/" - :custom - (claude-model "claude-3-7-sonnet-20250219") ;; Current model as of March 2025 - (claude-max-tokens 4000) - (claude-auto-display-results t) - :config - ;; If you want to add any custom tools, add them here - ;; (claude-register-tool - ;; '(:name "my_custom_tool" - ;; :description "A custom tool that does something specific" - ;; :parameters ((properties - ;; (param1 (title . "Parameter 1") - ;; (type . "string") - ;; (description . "Description of parameter 1")))))) - - ;; (claude-register-tool-handler - ;; "my_custom_tool" - ;; (lambda (parameters) - ;; ;; Your implementation here - ;; (format "Tool executed with param: %s" (cdr (assoc 'param1 parameters))))) - - ;; Enable the minor mode for keybindings - (claude-mode 1) - :bind (:map claude-mode-map - ;; You can customize the keybindings if you prefer different ones - ("C-c C-a a" . claude-prompt-and-send) ;; Add a custom binding - ;; Default bindings included by claude-mode: - ;; C-c C-a s - claude-send-region - ;; C-c C-a b - claude-send-buffer - ;; C-c C-a r - claude-code-review - ;; C-c C-a e - claude-explain-code - ;; C-c C-a c - claude-complete-code - ;; C-c C-a t - claude-send-with-tools - ;; C-c C-a l - claude-list-requested-tools - ;; C-c C-a p - claude-prompt-and-send - )) +(use-package gptel :ensure + :bind ("C-c RET" . gptel-send)) ;;; init.el ends here diff --git a/site-lisp/claude.el b/site-lisp/claude.el deleted file mode 100644 index e049d01..0000000 --- a/site-lisp/claude.el +++ /dev/null @@ -1,725 +0,0 @@ -;;; claude.el --- Integration with Claude AI assistant -*- lexical-binding: t -*- - -;; Author: John Doty ; mostly generated by claude.ai -;; Version: 1.0.0 -;; Package-Requires: ((emacs "27.1") (request "0.3.0") (json "1.5")) -;; Keywords: tools, ai, assistant -;; URL: https://git.d0ty.me/DeCarabas/claude-emacs - -;;; Commentary: -;; This package provides integration with the Claude AI assistant from Anthropic. -;; It includes basic functionality like sending text to Claude, as well as -;; code-specific features and tool use capabilities. - -;;; Code: - -(require 'request) -(require 'json) -(require 'auth-source) - -;;; Customization: - -(defgroup claude nil - "Integration with Claude AI assistant." - :group 'tools) - -(defcustom claude-model "claude-3-7-sonnet-20250219" - "Claude model to use." - :type 'string - :group 'claude) - -(defcustom claude-max-tokens 4000 - "Maximum number of tokens in Claude's response." - :type 'integer - :group 'claude) - -(defcustom claude-auto-display-results t - "If non-nil, automatically display Claude's responses." - :type 'boolean - :group 'claude) - -;;; Core functionality: - -(defvar claude-buffer-name "*Claude*" - "Name of the buffer for Claude interactions.") - -(defvar claude-last-request nil - "Store the last request data sent to Claude.") - -(defvar claude-response-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "q" 'quit-window) - (define-key map "r" 'claude-refresh-last-request) ;; We'll define this function later - map) - "Keymap for Claude response buffers.") - -(define-derived-mode claude-response-mode markdown-mode "Claude" - "Major mode for viewing Claude AI responses." - (use-local-map claude-response-mode-map) - ;; Enable visual line mode for word wrapping - (visual-line-mode 1) - ;; Make buffer read-only by default - (setq buffer-read-only t)) - - -(defun claude-get-api-key () - "Get Claude API key from auth-source." - (let ((auth-info (nth 0 (auth-source-search :host "anthropic.com" - :user "claude-api" - :require '(:secret) - :create t)))) - (if auth-info - (let ((secret (plist-get auth-info :secret))) - (if (functionp secret) - (funcall secret) - secret)) - (error "Claude API key not found in auth-source")))) - -(defun claude-ensure-buffer () - "Ensure the Claude buffer exists with proper formatting and keybindings." - (let ((buffer (get-buffer-create claude-buffer-name))) - (with-current-buffer buffer - (unless (eq major-mode 'claude-response-mode) - ;; Use our custom mode that has the q key binding - (if (fboundp 'markdown-mode) ;; Check if markdown-mode is available - (claude-response-mode) ;; Use our derived mode if markdown is available - ;; Fallback if markdown-mode isn't available - (special-mode) ;; special-mode also has the q key binding - (visual-line-mode 1)) - - ;; Set word-wrap and margins regardless of mode - (setq word-wrap t) - (setq left-margin-width 2 - right-margin-width 2))) - buffer)) - -(defun claude-send-message (prompt &optional system-prompt tools) - "Send PROMPT to Claude and display the response. -If SYSTEM-PROMPT is provided, include it in the request. -If TOOLS is provided, enable tool use." - (let ((data `((model . ,claude-model) - (max_tokens . ,claude-max-tokens) - (messages . [((role . "user") - (content . ,prompt))])))) - - ;; Add system prompt if provided - (when system-prompt - (setq data (append data `((system . ,system-prompt))))) - - ;; Add tools if provided - (when tools - (setq data (append data `((tools . ,tools) - (tool_choice . "auto"))))) - - ;; Store the request data for refresh functionality - (setq claude-last-request (list :prompt prompt - :system-prompt system-prompt - :tools tools)) - - ;; Display the buffer with a loading message - (let ((buffer (claude-ensure-buffer))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert "Sending request to Claude...\n\n"))) - (when claude-auto-display-results - (display-buffer buffer))) - - ;; Send request - (claude-send-request - data - (lambda (data) - (if tools - (claude-handle-tool-response data (claude-ensure-buffer)) - (claude-display-response data))) - (lambda (error-thrown) - (let ((buffer (claude-ensure-buffer))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert (format "Error: %s" error-thrown))))))))) - -(defun claude-extract-text-content (message) - "Extract text content from MESSAGE returned by the API." - (let ((content-items (cdr (assoc 'content message))) - (result "")) - (dolist (item content-items) - (let ((type (cdr (assoc 'type item)))) - (when (string= type "text") - (setq result (concat result (cdr (assoc 'text item)) "\n\n"))))) - result)) - -(defun claude-display-response (data) - "Display the response DATA from Claude with nice formatting." - (let ((content (cdr (assoc 'content data))) - (buffer (claude-ensure-buffer))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - ;; Clear the buffer - (erase-buffer) - - ;; Add a timestamp header - (insert (propertize - (format "Claude response at %s\n\n" - (format-time-string "%H:%M:%S")) - 'face 'font-lock-comment-face)) - - ;; Process content - (if (and content (arrayp content) (> (length content) 0)) - (dotimes (i (length content)) - (let* ((item (aref content i)) - (type (cdr (assoc 'type item)))) - (when (string= type "text") - (let ((text (cdr (assoc 'text item)))) - (insert text "\n\n"))))) - - ;; Handle unexpected response format - (insert (propertize "Unexpected response format from Claude API.\n" - 'face 'font-lock-warning-face)) - (insert "Response data: " (prin1-to-string data))) - - ;; Add helpful instructions at the bottom - (goto-char (point-max)) - (insert (propertize "\n──────────────────────────────────────\n" - 'face 'font-lock-comment-face)) - (insert (propertize "Press q to close this window\n" - 'face 'font-lock-comment-face)) - - ;; Return to the start of the buffer - (goto-char (point-min)))) - - ;; Only display the buffer if requested and not already visible - (when claude-auto-display-results - (unless (get-buffer-window buffer) - (display-buffer-other-window buffer))))) - -;; (defun claude-display-response (data) -;; "Display the response DATA from Claude." -;; (let* ((message (aref (cdr (assoc 'messages data)) 0)) -;; (content (claude-extract-text-content message)) -;; (buffer (claude-ensure-buffer))) -;; (with-current-buffer buffer -;; (let ((inhibit-read-only t)) -;; (erase-buffer) -;; (insert content) -;; (goto-char (point-min)))) -;; (when claude-auto-display-results -;; (display-buffer buffer)))) - -(defun claude-send-message (prompt &optional system-prompt tools) - "Send PROMPT to Claude and display the response. -If SYSTEM-PROMPT is provided, include it in the request. -If TOOLS is provided, enable tool use." - (let ((data `((model . ,claude-model) - (max_tokens . ,claude-max-tokens) - (messages . [((role . "user") - (content . ,prompt))])))) - - ;; Add system prompt if provided - (when system-prompt - (setq data (append data `((system . ,system-prompt))))) - - ;; Add tools if provided - (when tools - (setq data (append data `((tools . ,tools) - (tool_choice . "auto"))))) - - ;; Display the buffer with a loading message - (let ((buffer (claude-ensure-buffer))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert "Sending request to Claude...\n\n"))) - (when claude-auto-display-results - (display-buffer buffer))) - - ;; Send request - (claude-send-request - data - (lambda (data) - (if tools - (claude-handle-tool-response data (claude-ensure-buffer)) - (claude-display-response data))) - (lambda (error-thrown) - (let ((buffer (claude-ensure-buffer))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert (format "Error: %s" error-thrown))))))))) - -;;; Interactive commands: - -(defun claude-send-region (start end) - "Send the region between START and END to Claude and display the response." - (interactive "r") - (let ((prompt (buffer-substring-no-properties start end))) - (claude-send-message prompt))) - -(defun claude-send-buffer () - "Send the entire buffer to Claude." - (interactive) - (claude-send-region (point-min) (point-max))) - -(defun claude-code-review () - "Ask Claude to review the code in the current buffer." - (interactive) - (let ((code (buffer-substring-no-properties (point-min) (point-max)))) - (claude-send-message - (concat "Please review the following code and suggest improvements:\n\n```\n" - code "\n```")))) - -(defun claude-explain-code () - "Ask Claude to explain the selected code." - (interactive) - (if (use-region-p) - (let ((code (buffer-substring-no-properties (region-beginning) (region-end)))) - (claude-send-message - (concat "Please explain what this code does in detail:\n\n```\n" - code "\n```"))) - (message "No region selected"))) - -(defun claude-complete-code () - "Ask Claude to complete the code at point." - (interactive) - (let* ((buffer-text (buffer-substring-no-properties (point-min) (point-max))) - (cursor-pos (point)) - (text-before (buffer-substring-no-properties (point-min) cursor-pos)) - (text-after (buffer-substring-no-properties cursor-pos (point-max)))) - (claude-send-message - (concat "I'm writing code and need you to continue it from where the cursor is marked with [CURSOR]. Only provide the code that should replace [CURSOR], nothing else.\n\n```\n" - text-before "[CURSOR]" text-after "\n```")))) - -(defun claude-prompt-and-send () - "Prompt for input and send to Claude." - (interactive) - (let ((prompt (read-string "Ask Claude: "))) - (claude-send-message prompt))) - -(defun claude-refresh-last-request () - "Refresh the last Claude request by sending it again." - (interactive) - (if claude-last-request - (let ((prompt (plist-get claude-last-request :prompt)) - (system-prompt (plist-get claude-last-request :system-prompt)) - (tools (plist-get claude-last-request :tools))) - - ;; Display refreshing message - (let ((buffer (claude-ensure-buffer))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert "Refreshing last request to Claude...\n\n")))) - - ;; Re-send the same request - (claude-send-message prompt system-prompt tools) - (message "Refreshing Claude request...")) - (message "No previous Claude request to refresh"))) - -;;; Tool use functionality: - -(defvar claude-tools nil - "List of tool definitions available to Claude.") - -(defvar claude-tool-handlers (make-hash-table :test 'equal) - "Hash table of tool handlers, keyed by tool name.") - -(defvar claude-tool-requests nil - "List of tools that Claude has requested but aren't registered.") - -(defun claude-register-tool (tool-def) - "Register a tool definition for Claude to use. -TOOL-DEF should be a plist with :name, :description, and :parameters." - (add-to-list 'claude-tools tool-def t)) - -(defun claude-clear-tools () - "Clear all registered tools." - (setq claude-tools nil)) - -(defun claude-register-tool-handler (tool-name handler) - "Register a HANDLER function for TOOL-NAME. -The handler will be called with the parameters passed by Claude." - (puthash tool-name handler claude-tool-handlers)) - -(defun claude-execute-tool (tool-name parameters) - "Execute the tool with TOOL-NAME using PARAMETERS." - (let ((handler (gethash tool-name claude-tool-handlers))) - (if handler - (funcall handler parameters) - (format "Error: No handler registered for tool %s" tool-name)))) - -(defun claude-send-with-tools (prompt) - "Send PROMPT to Claude with tools enabled and handle the response." - (interactive "sPrompt: ") - (let ((tools-json (mapcar (lambda (tool) - `((name . ,(plist-get tool :name)) - (description . ,(plist-get tool :description)) - (parameters . ,(plist-get tool :parameters)))) - claude-tools))) - (claude-send-message prompt nil tools-json))) - -(defun claude-handle-tool-response (data buffer) - "Handle response DATA from Claude that may contain tool calls. -Display results in BUFFER." - (let ((message (aref (cdr (assoc 'messages data)) 0))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (let ((content-items (cdr (assoc 'content message)))) - (dolist (item content-items) - (let ((type (cdr (assoc 'type item)))) - (cond - ((string= type "text") - (insert (cdr (assoc 'text item)) "\n\n")) - ((string= type "tool_use") - (let* ((tool-use (cdr (assoc 'tool_use item))) - (tool-name (cdr (assoc 'name tool-use))) - (parameters (cdr (assoc 'parameters tool-use))) - (handler (gethash tool-name claude-tool-handlers))) - - ;; Check if we have this tool - (if handler - (let ((tool-result (claude-execute-tool tool-name parameters))) - (insert (format "Tool call: %s\n" tool-name)) - (insert (format "Parameters: %s\n" (json-encode parameters))) - (insert (format "Result: %s\n\n" tool-result)) - - ;; Send the tool result back to Claude - (claude-send-tool-result data tool-name tool-result)) - - ;; Tool not found - record the request and notify - (let ((description (format "Tool requested by Claude for task: %s" - (or (cdr (assoc 'description tool-use)) - "No description provided"))) - (param-structure (or (cdr (assoc 'parameter_structure tool-use)) - parameters))) - - ;; Record the tool request - (claude-request-tool tool-name description param-structure) - - ;; Notify Claude about missing tool - (insert (format "Tool requested: %s\n" tool-name)) - (insert (format "This tool is not currently available.\n")) - (insert "The request has been recorded. You can implement it with M-x claude-list-requested-tools.\n\n") - - ;; Send error message back to Claude - (let ((error-msg (format "The requested tool '%s' is not currently available. Would you like me to suggest an alternative approach?" tool-name))) - (claude-send-tool-result data tool-name error-msg)))))))))))))) - -(defun claude-send-tool-result (data tool-name tool-result) - "Send TOOL-RESULT for TOOL-NAME back to Claude based on the original DATA." - (let ((message-id (cdr (assoc 'id (aref (cdr (assoc 'messages data)) 0)))) - (tool-call-id (cdr (assoc 'id (cdr (assoc 'tool_use (aref (cdr (assoc 'content (aref (cdr (assoc 'messages data)) 0))) 0)))))) - (api-key (claude-get-api-key)) - (buffer (claude-ensure-buffer))) - - (request - "https://api.anthropic.com/v1/messages" - :type "POST" - :headers `(("Content-Type" . "application/json") - ("x-api-key" . ,api-key) - ("anthropic-version" . "2023-06-01")) - :data (json-encode - `((model . ,claude-model) - (max_tokens . ,claude-max-tokens) - (messages . ,(vconcat (cdr (assoc 'messages data)) - `[((role . "assistant") - (content . [((type . "tool_result") - (tool_result . ((tool_call_id . ,tool-call-id) - (content . ,tool-result))))]))])))) - :parser 'json-read - :success (cl-function - (lambda (&key data &allow-other-keys) - (claude-handle-tool-response data buffer))) - :error (cl-function - (lambda (&key error-thrown &allow-other-keys) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert (format "Error: %s" error-thrown))))))))) - -(defun claude-request-tool (tool-name description parameters) - "Record a request from Claude for a tool that isn't available." - (add-to-list 'claude-tool-requests - (list :name tool-name - :description description - :parameters parameters) - t)) - -(defun claude-list-requested-tools () - "Show all tools that Claude has requested but aren't registered." - (interactive) - (let ((buffer (get-buffer-create "*Claude Tool Requests*"))) - (with-current-buffer buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert "# Tools Requested by Claude\n\n") - (if claude-tool-requests - (dolist (tool claude-tool-requests) - (insert (format "## %s\n\n" (plist-get tool :name))) - (insert (format "Description: %s\n\n" (plist-get tool :description))) - (insert "Parameters:\n") - (let ((params (plist-get tool :parameters))) - (dolist (param params) - (insert (format "- %s: %s\n" - (car param) - (cdr (assoc 'description (cdr param))))))) - (insert "\n")) - (insert "No tools have been requested yet.\n")) - (insert "\nUse M-x claude-implement-requested-tool to implement one of these tools.\n"))) - (switch-to-buffer buffer))) - -(defun claude-implement-requested-tool (tool-name) - "Provide a template to implement a requested tool." - (interactive - (list (completing-read "Select tool to implement: " - (mapcar (lambda (tool) (plist-get tool :name)) - claude-tool-requests)))) - - (let* ((tool (car (cl-remove-if-not - (lambda (t) (string= (plist-get t :name) tool-name)) - claude-tool-requests))) - (name (plist-get tool :name)) - (description (plist-get tool :description)) - (parameters (plist-get tool :parameters)) - (buffer (get-buffer-create (format "*Implement Tool: %s*" name)))) - - (with-current-buffer buffer - (erase-buffer) - (emacs-lisp-mode) - (insert (format ";; Implementation template for tool: %s\n\n" name)) - (insert "(claude-register-tool\n") - (insert (format " '(:name \"%s\"\n" name)) - (insert (format " :description \"%s\"\n" description)) - (insert " :parameters ((properties\n") - - ;; Format parameters - (dolist (param parameters) - (let ((param-name (car param)) - (param-props (cdr param))) - (insert (format " (%s (title . \"%s\")\n" - param-name - (or (cdr (assoc 'title param-props)) param-name))) - (insert (format " (type . \"%s\")\n" - (or (cdr (assoc 'type param-props)) "string"))) - (insert (format " (description . \"%s\")))\n" - (or (cdr (assoc 'description param-props)) ""))))) - - (insert " )))\n\n") - (insert "(claude-register-tool-handler\n") - (insert (format " \"%s\"\n" name)) - (insert " (lambda (parameters)\n") - (insert " ;; Extract parameters\n") - - ;; Parameter extraction - (dolist (param parameters) - (let ((param-name (car param))) - (insert (format " (let ((%s (cdr (assoc '%s parameters))))\n" - param-name param-name)))) - - (insert " ;; Your implementation here\n") - (insert " ;; Return the result as a string or JSON-encodable object\n") - (insert " )))\n")) - - (switch-to-buffer buffer))) - -;;; Built-in tools: - -(defun claude-register-filesystem-tools () - "Register filesystem-related tools." - (interactive) - - ;; List directory contents - (claude-register-tool - '(:name "list_directory" - :description "List files and directories in a specified path" - :parameters ((properties - (path (title . "Path") - (type . "string") - (description . "Directory path to list")))))) - - (claude-register-tool-handler - "list_directory" - (lambda (parameters) - (let ((path (cdr (assoc 'path parameters)))) - (condition-case err - (let ((files (directory-files-and-attributes path t))) - (json-encode - (mapcar (lambda (file) - `((name . ,(file-name-nondirectory (car file))) - (type . ,(if (cadr file) "directory" "file")) - (size . ,(file-attribute-size (cdr file))))) - files))) - (error (format "Error listing directory: %s" (error-message-string err))))))) - - ;; Read file contents - (claude-register-tool - '(:name "read_file" - :description "Read the contents of a file" - :parameters ((properties - (path (title . "Path") - (type . "string") - (description . "Path to the file to read")))))) - - (claude-register-tool-handler - "read_file" - (lambda (parameters) - (let ((path (cdr (assoc 'path parameters)))) - (condition-case err - (with-temp-buffer - (insert-file-contents path) - (buffer-string)) - (error (format "Error reading file: %s" (error-message-string err))))))) - - ;; Write to file - (claude-register-tool - '(:name "write_file" - :description "Write content to a file" - :parameters ((properties - (path (title . "Path") - (type . "string") - (description . "Path to the file to write")) - (content (title . "Content") - (type . "string") - (description . "Content to write to the file")))))) - - (claude-register-tool-handler - "write_file" - (lambda (parameters) - (let ((path (cdr (assoc 'path parameters))) - (content (cdr (assoc 'content parameters)))) - (condition-case err - (progn - (with-temp-file path - (insert content)) - (format "Successfully wrote to %s" path)) - (error (format "Error writing to file: %s" (error-message-string err)))))))) - -(defun claude-register-emacs-tools () - "Register Emacs-specific tools." - (interactive) - - ;; List buffers - (claude-register-tool - '(:name "list_buffers" - :description "List all Emacs buffers" - :parameters ((properties ())))) - - (claude-register-tool-handler - "list_buffers" - (lambda (parameters) - (json-encode - (mapcar (lambda (buffer) - `((name . ,(buffer-name buffer)) - (file . ,(or (buffer-file-name buffer) "")) - (modified . ,(if (buffer-modified-p buffer) t :json-false)) - (size . ,(buffer-size buffer)))) - (buffer-list))))) - - ;; Get buffer content - (claude-register-tool - '(:name "get_buffer_content" - :description "Get the content of an Emacs buffer" - :parameters ((properties - (buffer_name (title . "Buffer Name") - (type . "string") - (description . "Name of the buffer to get content from")))))) - - (claude-register-tool-handler - "get_buffer_content" - (lambda (parameters) - (let ((buffer-name (cdr (assoc 'buffer_name parameters)))) - (if (get-buffer buffer-name) - (with-current-buffer buffer-name - (buffer-string)) - (format "Buffer '%s' not found" buffer-name))))) - - ;; List installed packages - (claude-register-tool - '(:name "list_packages" - :description "List installed Emacs packages" - :parameters ((properties ())))) - - (claude-register-tool-handler - "list_packages" - (lambda (parameters) - (require 'package) - (json-encode - (mapcar (lambda (pkg) - (let ((pkg-name (car pkg)) - (pkg-desc (cadr pkg))) - `((name . ,(symbol-name pkg-name)) - (version . ,(package-version-join - (package-desc-version pkg-desc))) - (status . ,(if (package-built-in-p pkg-name) - "built-in" - "installed"))))) - package-alist))))) - -(defun claude-register-shell-tools () - "Register shell command tool." - (interactive) - - ;; Run shell command - (claude-register-tool - '(:name "run_shell_command" - :description "Run a shell command and return its output" - :parameters ((properties - (command (title . "Command") - (type . "string") - (description . "Shell command to execute")))))) - - (claude-register-tool-handler - "run_shell_command" - (lambda (parameters) - (let ((command (cdr (assoc 'command parameters)))) - (condition-case err - (shell-command-to-string command) - (error (format "Error running command: %s" (error-message-string err)))))))) - -(defun claude-init-tools () - "Initialize all available tools." - (interactive) - (claude-clear-tools) - (claude-register-filesystem-tools) - (claude-register-emacs-tools) - ;; (claude-register-shell-tools) - ) - -;;; Keybindings: - -(defvar claude-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-a s") 'claude-send-region) - (define-key map (kbd "C-c C-a b") 'claude-send-buffer) - (define-key map (kbd "C-c C-a r") 'claude-code-review) - (define-key map (kbd "C-c C-a e") 'claude-explain-code) - (define-key map (kbd "C-c C-a c") 'claude-complete-code) - (define-key map (kbd "C-c C-a t") 'claude-send-with-tools) - (define-key map (kbd "C-c C-a l") 'claude-list-requested-tools) - (define-key map (kbd "C-c C-a p") 'claude-prompt-and-send) - map) - "Keymap for Claude mode.") - -;;;###autoload -(define-minor-mode claude-mode - "Toggle Claude mode. -With a prefix argument ARG, enable Claude mode if ARG is positive, -and disable it otherwise. If called from Lisp, enable the mode -if ARG is omitted or nil. - -Claude mode provides key bindings for interacting with the Claude AI assistant." - :init-value nil - :lighter " Claude" - :keymap claude-mode-map - :global t - (if claude-mode - (progn - (message "Claude mode enabled") - (claude-init-tools)) - (message "Claude mode disabled"))) - -;; Initialize tools on load -(claude-init-tools) - -(provide 'claude) -;;; claude.el ends here