cc-sessions
Довідник конкретних emacsclient --eval рецептів для керування сесіями claude-code-ide.el з
«Мажордома» (чи будь-якої іншої сесії з доступом до цього самого Emacs-сервера). Принципи (чому саме
так) — у majordom.md; тут — лише готові виклики.
КРИТИЧНО: єдина безпечна команда старту — claude-code-ide-start
claude-code-ide-continue, claude-code-ide-resume і старий claude-code-ide (усі без аргументів) —
НІКОЛИ не викликай напряму headless. Кожна з них, коли для каталогу вже є активна сесія, викликає
блокуючий (read-string "Instance name (empty for auto): "), що зависає назавжди без живого
користувача за клавіатурою (підтверджено емпірично на всіх трьох). Єдиний виняток — інтерактивний
M-x людиною напряму.
claude-code-ide-start (сигнатура (&optional instance-name continue resume)) покриває всі три
випадки одним викликом, що НІКОЛИ не питає ім'я інтерактивно:
;; звичайний старт нової розмови
(let ((default-directory "/home/eugine/job/<проект>/")
(claude-code-ide-cli-extra-flags "--remote-control <проект>"))
(claude-code-ide-start "<ім'я-або-nil>"))
;; замість claude-code-ide-continue
(claude-code-ide-start "<ім'я-або-nil>" t nil)
;; замість claude-code-ide-resume (відкриває інтерактивний picker УСЕРЕДИНІ термінала claude,
;; не через Emacs-мінібуфер — сам виклик не блокує emacsclient)
(claude-code-ide-start "<ім'я-або-nil>" nil t)
instance-name (1-й аргумент) nil ⇒ авто-номер (vedmid-2, vedmid-3...). Задавай його явно лише
коли користувач сам назвав мету/ім'я нової копії — якщо неясно, запитай користувача, не вигадуй сама.
Перед стартом: перевір наявний стан
(mapcar (lambda (b) (list (buffer-name b) (and (get-buffer-process b) (process-status (get-buffer-process b)))))
(seq-filter (lambda (b) (string-match-p "claude-code\\[<проект>" (buffer-name b))) (buffer-list)))
- Немає активної сесії →
(claude-code-ide-start nil t nil)(підхопить останню розмову проєкту, якcontinue). - Є активна сесія → НІКОЛИ не зупиняй її «для перезапуску». Піднімай ДОДАТКОВУ копію тим самим
claude-code-ide-start(зresume=t, якщо мета — обрати конкретну стару розмову, чи без — нова розмова поруч).
Після старту: підтверди remote-control реальним пошуком у буфері
Відсутність зависання ще НЕ доводить, що --remote-control подіяв (епізод: забула прапорець —
сесія піднялась чисто, але лишилась не-remote).
(with-current-buffer "*claude-code[<проект>]*"
(save-excursion (goto-char (point-min))
(if (search-forward "remote-control" nil t) "FOUND" "NOT FOUND")))
Якщо NOT FOUND — не завжди помилка: перевір повний вміст буфера (buffer-substring-no-properties (point-min) (point-max)), рядок може бути поза межами того, що відрендерилось, чи (для великих
сесій) поза видимим скролбеком eat — сам термінал зберігає лише недавню історію, не всю розмову.
Зупинка сесії: спершу вимкни query-on-exit, тоді stop
claude-code-ide-stop сам по собі безпечний і НЕ залежить від того, чи сесія мала remote-control.
Але звичайний Emacs-запит Buffer "..." has a running process; kill it? спливає АСИНХРОННО (у
process-sentinel, вже ПІСЛЯ того, як claude-code-ide-stop повернувся) — тож let-обгортка навколо
самого виклику не рятує. Вимикай прапорець на процесі ЗАЗДАЛЕГІДЬ, окремим викликом:
(let ((proc (get-buffer-process "*claude-code[<проект>]*")))
(when proc (set-process-query-on-exit-flag proc nil)))
(with-current-buffer "*claude-code[<проект>]*" (claude-code-ide-stop))
Якщо для каталогу кілька копій (vedmid, vedmid:2, vedmid:masazh...) — виклич claude-code-ide-stop
у контексті САМЕ того буфера (with-current-buffer), не через default-directory: повідомлення
підтвердить, яку саме зупинила ("Stopping Claude Code vedmid:masazh...").
Якщо запит усе ж проскочив і завис (ps aux | grep emacsclient показує застряглий процес) — НІКОЛИ
не намагайся розблокувати сама (жодних повторних --eval, жодних сигналів до emacs) — проси
користувача відповісти в живому Emacs. Див. emacs.md для повного контексту цієї небезпеки.
Навігація в інтерактивних picker'ах (resume-список, permission-запити)
Список сесій (resume) і меню підтвердження дозволів рендеряться ВСЕРЕДИНІ термінала (не через
Emacs-мінібуфер) — керуються звичайними ANSI-послідовностями через сирий process-send-string, не
через emacsclient --eval елісп-виклики:
(process-send-string (get-buffer-process "*claude-code[<проект>]*") "\e[B") ; стрілка вниз
(process-send-string (get-buffer-process "*claude-code[<проект>]*") "\e[A") ; стрілка вгору
(process-send-string (get-buffer-process "*claude-code[<проект>]*") "\e[6~") ; Page Down
(process-send-string (get-buffer-process "*claude-code[<проект>]*") "\r") ; Enter (підтвердити)
Після кожного надісланого натискання перечитай вміст буфера (buffer-substring-no-properties), щоб
побачити нову позицію курсора (❯) і заголовок (N of M), перш ніж рухатись далі чи підтверджувати —
не рухайся навмання кілька кроків без перевірки. Числові клавіші ("3") для прямого вибору пункту
меню підтвердження НЕ підтверджено робочими — навігація стрілками + Enter надійніша.
Перемикання permission-mode (Shift+Tab) — інша річ, не auto-accept
Статус-рядок термінала (⏸ manual mode on, ⏵⏵ accept edits on, ⏸ plan mode on, ⏵⏵ auto mode on) керується виключно самим бінарником claude — Emacs про це нічого не знає. Цикл (Shift+Tab,
чотири стани): manual → accept edits → plan → auto → manual.
(process-send-string (get-buffer-process "*claude-code[<проект>]*") "\e[Z")
Перемикання ІНОДІ саме викликає проміжний запит підтвердження інструмента (Do you want to proceed?) — обирай пункт "Yes, and switch to auto mode" через навігацію стрілками (не цифрою) +
Enter, якщо мета — саме повернутись в auto.
claude-code-ide-toggle-auto-accept — окрема Emacs-функція, не той самий стан
Не плутати з циклом permission-mode вище. Ця функція перемикає лише елісп-прапорець на структурі
сесії й впливає ЛИШЕ на MCP-інструмент openDiff (пропозиція ediff-перегляду перед збереженням
файлу): ON → ediff не показується, файл зберігається одразу (FILE_SAVED); OFF → звичайний
ediff. Статус-рядок термінала НЕ змінюється цим викликом.
(with-current-buffer "*claude-code[<проект>]*" (claude-code-ide-toggle-auto-accept))
Показати вміст буфера користувачу «ніби він дивиться»
(with-current-buffer "*claude-code[<проект>]*" (buffer-substring-no-properties (point-min) (point-max)))
Для великих сесій обрізай ((max (point-min) (- (point-max) N)) (point-max)) — повний вміст може бути
мегабайтним, хоча видимий скролбек eat завжди обмежений (реально відрендерена частина не росте
безмежно).