Function: claude-code-ide--create-terminal-session

claude-code-ide--create-terminal-session is a natively compiled function defined in claude-code-ide.el.

Signature

(claude-code-ide--create-terminal-session BUFFER-NAME WORKING-DIR PORT CONTINUE RESUME SESSION-ID)

Documentation

Create a new terminal session for Claude Code.

BUFFER-NAME is the name for the terminal buffer. WORKING-DIR is the working directory. PORT is the MCP server port. CONTINUE is whether to continue the most recent conversation. RESUME is whether to resume a previous conversation. SESSION-ID is the unique identifier for this session.

Returns a cons cell of (buffer . process) on success. Signals an error if terminal fails to initialize.

Source Code

;; Defined in /nix/store/yjvbhwl7p6zrbw9xlnni7y4hra8sa3pl-emacs-packages-deps/share/emacs/site-lisp/claude-code-ide.el
(defun claude-code-ide--create-terminal-session (buffer-name working-dir port continue resume session-id)
  "Create a new terminal session for Claude Code.
BUFFER-NAME is the name for the terminal buffer.
WORKING-DIR is the working directory.
PORT is the MCP server port.
CONTINUE is whether to continue the most recent conversation.
RESUME is whether to resume a previous conversation.
SESSION-ID is the unique identifier for this session.

Returns a cons cell of (buffer . process) on success.
Signals an error if terminal fails to initialize."
  ;; Ensure terminal backend is available before proceeding
  (claude-code-ide--terminal-ensure-backend)
  (let* ((claude-cmd (claude-code-ide--build-claude-command continue resume session-id))
         (default-directory working-dir)
         (env-vars (append (list (format "CLAUDE_CODE_SSE_PORT=%d" port)
                                 "TERM_PROGRAM=emacs"
                                 "FORCE_CODE_TERMINAL=true")
                           (when claude-code-ide-no-flicker
                             (list "CLAUDE_CODE_NO_FLICKER=1")))))
    ;; Log the command for debugging
    (claude-code-ide-debug "Starting Claude with command: %s" claude-cmd)
    (claude-code-ide-debug "Working directory: %s" working-dir)
    (claude-code-ide-debug "Environment: CLAUDE_CODE_SSE_PORT=%d" port)
    (claude-code-ide-debug "Session ID: %s" session-id)
    (claude-code-ide-debug "Terminal backend: %s" claude-code-ide-terminal-backend)

    ;; A buffer created here is unowned until this function returns: the
    ;; session's buffer slot is still nil, so the caller's error path could
    ;; never reap it.  Track it and destroy it if construction fails.
    (let ((created-buffer nil))
      (condition-case err
          (cond
           ;; vterm backend
           ((eq claude-code-ide-terminal-backend 'vterm)
            (let* ((vterm-buffer-name buffer-name)
                   ;; Set vterm-shell to run Claude directly
                   (vterm-shell claude-cmd)
                   ;; vterm uses vterm-environment for passing env vars
                   (vterm-environment (append env-vars vterm-environment)))
              ;; Create vterm buffer without switching to it
              (let ((buffer (save-window-excursion
                              (vterm vterm-buffer-name))))
                (setq created-buffer buffer)
                ;; Check if vterm successfully created a buffer
                (unless buffer
                  (error "Failed to create vterm buffer.  Please ensure vterm is properly installed and compiled"))
                ;; Configure vterm buffer for optimal performance
                (with-current-buffer buffer
                  (claude-code-ide--configure-vterm-buffer))
                ;; Get the process that vterm created
                (let ((process (get-buffer-process buffer)))
                  (unless process
                    (error "Failed to get vterm process.  The vterm module may not be compiled correctly"))
                  ;; Check if buffer is still alive
                  (unless (buffer-live-p buffer)
                    (error "Vterm buffer was killed during initialization"))
                  (cons buffer process)))))

           ;; eat backend
           ((eq claude-code-ide-terminal-backend 'eat)
            (let* ((buffer (get-buffer-create buffer-name))
                   (eat-term-name "xterm-256color")
                   ;; Parse command string into program and args
                   (cmd-parts (claude-code-ide--parse-command-string claude-cmd))
                   (program (car cmd-parts))
                   (args (cdr cmd-parts)))
              (setq created-buffer buffer)
              (with-current-buffer buffer
                ;; Set up eat mode
                (unless (eq major-mode 'eat-mode)
                  (eat-mode))
                ;; Configure position preservation if enabled
                (when claude-code-ide-eat-preserve-position
                  (setq-local eat--synchronize-scroll-function
                              #'claude-code-ide--terminal-position-keeper))
                ;; Prepend our env vars to the buffer-local process-environment
                (setq-local process-environment
                            (append env-vars process-environment))
                (eat-exec buffer buffer-name program nil args)
                ;; Get the process
                (let ((process (get-buffer-process buffer)))
                  (unless process
                    (error "Failed to create eat process.  Please ensure eat is properly installed"))
                  (cons buffer process)))))

           ;; ghostel backend
           ((eq claude-code-ide-terminal-backend 'ghostel)
            (let* ((cmd-parts (claude-code-ide--parse-command-string claude-cmd))
                   (program (claude-code-ide--resolve-program (car cmd-parts)))
                   (args (cdr cmd-parts))
                   (buffer nil))
              (when-let* ((stale-buffer (get-buffer buffer-name)))
                ;; A buffer with a live session backpointer is a running sibling
                ;; instance, not a stale leftover — never kill it.
                (when (claude-code-ide--buffer-session stale-buffer)
                  (error "Buffer %s already belongs to a running Claude Code instance"
                         buffer-name))
                (kill-buffer stale-buffer))
              (setq buffer (get-buffer-create buffer-name))
              (setq created-buffer buffer)
              (unless (buffer-live-p buffer)
                (error "Failed to create ghostel buffer.  Please ensure ghostel is properly installed"))
              (with-current-buffer buffer
                (setq default-directory working-dir)
                (claude-code-ide--disable-ghostel-title-tracking)
                ;; Let `claude-code-ide--cleanup-session' be the single place that
                ;; kills the buffer.  Otherwise ghostel's sentinel kills the buffer
                ;; first, firing `kill-buffer-hook' → cleanup-session, and then our
                ;; wrapping sentinel runs cleanup-session a second time.
                (setq-local ghostel-kill-buffer-on-exit nil)
                (let* ((process-environment (append env-vars process-environment))
                       (process (ghostel-exec buffer program args)))
                  ;; `ghostel-exec' switches the buffer into `ghostel-mode', which
                  ;; resets buffer-local variables.
                  (claude-code-ide--disable-ghostel-title-tracking)
                  (setq-local ghostel-kill-buffer-on-exit nil)
                  ;; `ghostel-mode-hook' has run by now, so if `evil-ghostel-mode'
                  ;; is enabled it has already seeded `evil-ghostel--escape-mode'
                  ;; from the global default; override it for this buffer only.
                  (claude-code-ide--apply-ghostel-evil-escape)
                  (unless process
                    (error "Failed to create ghostel process.  Please ensure ghostel is properly installed"))
                  ;; Chain ghostel's own sentinel so its buffer-local timers,
                  ;; focus-change hook, and `ghostel-exit-functions' still run
                  ;; when `claude-code-ide--start-session' installs its own
                  ;; sentinel on top.  Without this, ghostel teardown is skipped.
                  (process-put process 'claude-code-ide--ghostel-sentinel
                               (process-sentinel process))
                  (cons buffer process)))))

           (t
            (error "Unknown terminal backend: %s" claude-code-ide-terminal-backend)))
        ((error quit)
         (when (and created-buffer (buffer-live-p created-buffer))
           (when-let* ((process (get-buffer-process created-buffer)))
             (ignore-errors (delete-process process)))
           (let ((kill-buffer-hook nil)
                 (kill-buffer-query-functions nil))
             (ignore-errors (kill-buffer created-buffer))))
         (signal (car err) (cdr err)))))))