-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathai-code-claude-code.el
More file actions
132 lines (114 loc) · 5.27 KB
/
Copy pathai-code-claude-code.el
File metadata and controls
132 lines (114 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
;;; ai-code-claude-code.el --- Thin wrapper for Claude Code CLI -*- lexical-binding: t; -*-
;; Author: Kang Tu, Yoav Orot
;; SPDX-License-Identifier: Apache-2.0
;;; Commentary:
;;
;; Thin wrapper that reuses `ai-code-backends-infra' to run Claude Code CLI.
;; Provides interactive commands and aliases for the AI Code suite.
;; This is an alternative to the external claude-code.el package, using the
;; same terminal infrastructure as other backends (codex, gemini, grok, etc.).
;;
;;; Code:
(require 'ai-code-backends)
(require 'ai-code-backends-infra)
(require 'ai-code-mcp-agent)
(defvar ghostel-full-redraw)
(defgroup ai-code-claude-code nil
"Claude Code CLI integration via `ai-code-backends-infra'."
:group 'tools
:prefix "ai-code-claude-code-")
(defcustom ai-code-claude-code-program "claude"
"Path to the Claude Code CLI executable."
:type 'string
:group 'ai-code-claude-code)
(defcustom ai-code-claude-code-program-switches nil
"Command line switches to pass to Claude Code CLI on startup."
:type '(repeat string)
:group 'ai-code-claude-code)
(defcustom ai-code-claude-code-no-flicker nil
"Enable experimental flicker-free terminal renderer in Claude Code.
When non-nil, set CLAUDE_CODE_NO_FLICKER=1 which uses full-screen
redraw rendering. This can break vterm scrollback because the
screen-clearing sequences overwrite the scrollback buffer. Leave
nil unless you specifically need flicker-free rendering and do not
rely on scrolling back through terminal history."
:type 'boolean
:group 'ai-code-claude-code)
(defcustom ai-code-claude-code-multiline-input-sequence "\e\r"
"Terminal sequence used for multiline input in Claude Code sessions.
This mirrors the newline sequence Claude Code expects from `/terminal-setup'."
:type 'string
:group 'ai-code-claude-code)
(defconst ai-code-claude-code--session-prefix "claude"
"Session prefix used in Claude Code CLI buffer names.")
(defvar ai-code-claude-code--processes (make-hash-table :test 'equal)
"Hash table mapping Claude Code session keys to processes.")
;;;###autoload
(defun ai-code-claude-code (&optional arg)
"Start Claude Code using `ai-code-backends-infra' logic.
With prefix ARG, prompt for CLI args using
`ai-code-claude-code-program-switches' as the default input."
(interactive "P")
(ai-code-backends-infra--start-cli-session
(list :program ai-code-claude-code-program
:switches ai-code-claude-code-program-switches
:label "Claude Code"
:process-table ai-code-claude-code--processes
:session-prefix ai-code-claude-code--session-prefix
:escape-function #'ai-code-claude-code-send-escape
:env-vars (append (list "TERM_PROGRAM=emacs"
"FORCE_CODE_TERMINAL=true")
(when ai-code-claude-code-no-flicker
(list "CLAUDE_CODE_NO_FLICKER=1")))
:multiline-input-sequence ai-code-claude-code-multiline-input-sequence
:prepare-launch
(lambda (working-dir command)
(let* ((mcp-launch
(ai-code-mcp-agent-prepare-launch 'claude-code
working-dir
command))
(mcp-post-start-fn (plist-get mcp-launch :post-start-fn)))
(list
:command (plist-get mcp-launch :command)
:cleanup-fn (plist-get mcp-launch :cleanup-fn)
:post-start-fn
;; Preserve backend-specific rendering behavior while letting MCP
;; attach its own session metadata after the terminal is created.
(lambda (buffer process instance-name)
(with-current-buffer buffer
(if (eq ai-code-backends-infra-terminal-backend 'vterm)
(setq-local ai-code-backends-infra-strip-alternate-screen t)
(setq-local ai-code-backends-infra-strip-alternate-screen nil))
(when (eq ai-code-backends-infra-terminal-backend 'ghostel)
(setq-local ghostel-full-redraw t)))
(when mcp-post-start-fn
(funcall mcp-post-start-fn buffer process instance-name)))))))
arg))
;;;###autoload
(defun ai-code-claude-code-switch-to-buffer (&optional force-prompt)
"Switch to the Claude Code CLI buffer.
When FORCE-PROMPT is non-nil, prompt to select a session."
(interactive "P")
(ai-code-backends-infra--cli-switch-to-buffer
"Claude Code" ai-code-claude-code--session-prefix force-prompt))
;;;###autoload
(defun ai-code-claude-code-send-command (line)
"Send LINE to Claude Code CLI."
(interactive "sClaude Code> ")
(ai-code-backends-infra--cli-send-command
"Claude Code" ai-code-claude-code--session-prefix line))
;;;###autoload
(defun ai-code-claude-code-send-escape ()
"Send escape key to Claude Code CLI."
(interactive)
(ai-code-backends-infra--terminal-send-escape))
;;;###autoload
(defun ai-code-claude-code-resume (&optional arg)
"Resume a previous Claude Code CLI session.
With prefix ARG, prompt for additional CLI args."
(interactive "P")
(let ((ai-code-claude-code-program-switches
(append ai-code-claude-code-program-switches '("--resume"))))
(ai-code-claude-code arg)))
(provide 'ai-code-claude-code)
;;; ai-code-claude-code.el ends here