Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
76 kB · 1851 lines
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852;; -*- lexical-binding: t; -*-;; Aesthetic Computer Emacs Configuration, 2024.3.13.12.51
;; Debug logging - persistent location that survives container rebuilds(defvar ac-debug-log-file "/workspaces/aesthetic-computer/.emacs-logs/emacs-debug.log")(defvar ac-perf-log-file "/workspaces/aesthetic-computer/.emacs-logs/emacs-perf.log")(defvar ac-profile-log-file "/workspaces/aesthetic-computer/.emacs-logs/emacs-profile.log")(defvar ac--startup-time (current-time))(defvar ac--last-perf-time (current-time))
;; Boot progress tracking(defvar ac--boot-buffer-name "boot" "Name of the boot progress buffer.")(defvar ac--boot-step-count 0 "Current step number in boot sequence.")(defvar ac--boot-total-steps 14 "Total expected steps: artery, fishy, + 10 tabs + cdp + finalize.")(defvar ac--boot-start-time nil "Time when boot started.")
(defun ac-debug-log (message) "Log a debug message with timestamp." (with-temp-buffer (insert (format "[%s] %s\n" (format-time-string "%Y-%m-%d %H:%M:%S.%3N") message)) (append-to-file (point-min) (point-max) ac-debug-log-file)))
(defun ac-perf-log (label) "Log performance timing since startup and since last checkpoint." (let* ((now (current-time)) (total-ms (round (* 1000 (float-time (time-subtract now ac--startup-time))))) (delta-ms (round (* 1000 (float-time (time-subtract now ac--last-perf-time)))))) (setq ac--last-perf-time now) (with-temp-buffer (insert (format "[%s] PERF: %s | +%dms (total: %dms)\n" (format-time-string "%Y-%m-%d %H:%M:%S.%3N") label delta-ms total-ms)) (append-to-file (point-min) (point-max) ac-perf-log-file))))
(defun ac-perf-session-start () "Mark the start of a new Emacs session in perf log." (with-temp-buffer (insert (format "\n=== NEW SESSION: %s ===\n" (format-time-string "%Y-%m-%d %H:%M:%S"))) (append-to-file (point-min) (point-max) ac-perf-log-file)))
;;; ===================================================================;;; BOOT PROGRESS BUFFER;;; ===================================================================
(defface ac-boot-header-face '((t :foreground "#00ff00" :weight bold :height 1.3)) "Face for boot header.")
(defface ac-boot-step-pending-face '((t :foreground "#666666")) "Face for pending boot steps.")
(defface ac-boot-step-active-face '((t :foreground "#ffff00" :weight bold)) "Face for active boot step.")
(defface ac-boot-step-done-face '((t :foreground "#00ff00")) "Face for completed boot steps.")
(defface ac-boot-step-error-face '((t :foreground "#ff4444" :weight bold)) "Face for failed boot steps.")
(defface ac-boot-progress-face '((t :foreground "#00aaff")) "Face for progress bar.")
(defvar ac--boot-steps '(("artery" . "🩸 Artery dev server") ("status" . "📡 Status monitors") ("stripe" . "💳 Stripe listeners") ("chat" . "💬 Chat services") ("web 1/2" . "🌐 Web servers (1/2)") ("web 2/2" . "🌐 Web servers (2/2)") ("tests" . "🧪 Test runners") ("llm" . "🤖 LLM interface") ("mail" . "📬 Mail sync") ("signal" . "📶 Signal messenger") ("top" . "📊 System monitor") ("fishy" . "🐟 Fish shell") ("cdp" . "🔗 CDP tunnel") ("finalize" . "✨ Finalizing")) "Boot steps with descriptions.")
(defvar ac--boot-step-status (make-hash-table :test 'equal) "Hash table tracking status of each boot step: pending, active, done, error.")
(defun ac--boot-init () "Initialize the boot progress buffer." (setq ac--boot-start-time (current-time) ac--boot-step-count 0) (clrhash ac--boot-step-status) ;; Set all steps to pending (dolist (step ac--boot-steps) (puthash (car step) 'pending ac--boot-step-status)) ;; Create/get the boot buffer (let ((buf (get-buffer-create ac--boot-buffer-name))) (with-current-buffer buf (let ((inhibit-read-only t)) (erase-buffer) (ac--boot-render))) buf))
(defun ac--boot-render () "Render the boot progress buffer." (let ((inhibit-read-only t) (elapsed (if ac--boot-start-time (float-time (time-subtract (current-time) ac--boot-start-time)) 0))) (erase-buffer) (insert "\n") (insert (propertize " ╔══════════════════════════════════════════════════════════════╗\n" 'face 'ac-boot-header-face)) (insert (propertize " ║ 🚀 AESTHETIC COMPUTER BOOT SEQUENCE ║\n" 'face 'ac-boot-header-face)) (insert (propertize " ╚══════════════════════════════════════════════════════════════╝\n" 'face 'ac-boot-header-face)) (insert "\n") ;; Progress bar (let* ((pct (if (> ac--boot-total-steps 0) (/ (* 100.0 ac--boot-step-count) ac--boot-total-steps) 0)) (bar-width 50) (filled (round (* bar-width (/ pct 100.0)))) (empty (- bar-width filled))) (insert (format " Progress: [%s%s] %d%% (%.1fs)\n\n" (propertize (make-string filled ?█) 'face 'ac-boot-progress-face) (make-string empty ?░) (round pct) elapsed))) ;; Step list (insert " ─────────────────────────────────────────────────────────\n") (dolist (step ac--boot-steps) (let* ((step-id (car step)) (step-desc (cdr step)) (status (gethash step-id ac--boot-step-status 'pending)) (indicator (pcase status ('pending " ○") ('active " ●") ('done " ✓") ('error " ✗"))) (face (pcase status ('pending 'ac-boot-step-pending-face) ('active 'ac-boot-step-active-face) ('done 'ac-boot-step-done-face) ('error 'ac-boot-step-error-face)))) (insert (propertize (format "%s %s\n" indicator step-desc) 'face face)))) (insert " ─────────────────────────────────────────────────────────\n\n") ;; Status message (let ((active-step (cl-find 'active (hash-table-values ac--boot-step-status)))) (if active-step (let ((active-id (cl-find-if (lambda (k) (eq (gethash k ac--boot-step-status) 'active)) (hash-table-keys ac--boot-step-status)))) (insert (propertize (format " ⏳ Currently: %s...\n" (cdr (assoc active-id ac--boot-steps))) 'face 'ac-boot-step-active-face))) (if (= ac--boot-step-count ac--boot-total-steps) (insert (propertize " ✅ Boot complete!\n" 'face 'ac-boot-step-done-face)) (insert " ⏸ Waiting...\n")))) (insert "\n Press 'q' to close this buffer, 'g' to refresh\n") (goto-char (point-min))))
(defun ac--boot-update-step (step-id status) "Update STEP-ID to STATUS and refresh display." (puthash step-id status ac--boot-step-status) (when (eq status 'done) (setq ac--boot-step-count (1+ ac--boot-step-count))) ;; Also log it (ac-debug-log (format "BOOT: %s -> %s" step-id status)) ;; Update buffer if visible (when-let ((buf (get-buffer ac--boot-buffer-name))) (with-current-buffer buf (ac--boot-render)) ;; Force redisplay to show progress (redisplay t)))
(defun ac--boot-start-step (step-id) "Mark STEP-ID as active." (ac--boot-update-step step-id 'active))
(defun ac--boot-complete-step (step-id) "Mark STEP-ID as done." (ac--boot-update-step step-id 'done))
(defun ac--boot-error-step (step-id) "Mark STEP-ID as error." (ac--boot-update-step step-id 'error))
(defun ac-boot-show () "Show the boot progress buffer." (interactive) (let ((buf (get-buffer ac--boot-buffer-name))) (when buf (display-buffer buf '(display-buffer-pop-up-window)))))
(define-derived-mode ac-boot-mode special-mode "AC-Boot" "Mode for viewing boot progress." (setq buffer-read-only t) (local-set-key (kbd "g") (lambda () (interactive) (ac--boot-render))) (local-set-key (kbd "q") 'quit-window))
;;; ===================================================================;;; PROFILING & DIAGNOSTICS;;; ===================================================================
(defvar ac--profiling-active nil "Whether CPU profiling is currently running.")
(defun ac-profile-start () "Start CPU profiler and log to file." (interactive) (unless ac--profiling-active (profiler-start 'cpu) (setq ac--profiling-active t) (ac-debug-log "PROFILER: Started CPU profiling")))
(defun ac-profile-stop () "Stop profiler and write report to log file." (interactive) (when ac--profiling-active (let ((report (profiler-report-cpu))) (with-temp-buffer (insert (format "\n=== PROFILE REPORT: %s ===\n" (format-time-string "%Y-%m-%d %H:%M:%S"))) (profiler-report) (append-to-file (point-min) (point-max) ac-profile-log-file))) (profiler-stop) (setq ac--profiling-active nil) (ac-debug-log "PROFILER: Stopped, report written")))
(defun ac-profile-report () "Show profiler report interactively." (interactive) (profiler-report))
(defun ac-diagnose-eat () "Diagnose all eat terminal buffers - log their state." (interactive) (let ((eat-buffers (seq-filter (lambda (b) (with-current-buffer b (eq major-mode 'eat-mode))) (buffer-list)))) (ac-debug-log (format "DIAGNOSE: Found %d eat buffers" (length eat-buffers))) (dolist (buf eat-buffers) (with-current-buffer buf (let* ((proc (get-buffer-process buf)) (proc-status (if proc (process-status proc) 'no-process)) (buf-size (buffer-size))) (ac-debug-log (format " BUFFER: %s | size=%d | proc=%s" (buffer-name) buf-size proc-status))))) (message "Diagnosed %d eat buffers - see debug log" (length eat-buffers))))
(defun ac-diagnose-timers () "Log all active timers." (interactive) (ac-debug-log (format "DIAGNOSE: %d active timers" (length timer-list))) (dolist (timer timer-list) (ac-debug-log (format " TIMER: %s repeat=%s" (timer--function timer) (timer--repeat-delay timer)))) (message "Logged %d timers" (length timer-list)))
(defun ac-diagnose-processes () "Log all active processes." (interactive) (let ((procs (process-list))) (ac-debug-log (format "DIAGNOSE: %d active processes" (length procs))) (dolist (proc procs) (ac-debug-log (format " PROC: %s | status=%s | buffer=%s" (process-name proc) (process-status proc) (if (process-buffer proc) (buffer-name (process-buffer proc)) "none")))) (message "Logged %d processes" (length procs))))
(defun ac-diagnose-all () "Run all diagnostics." (interactive) (ac-debug-log "=== FULL DIAGNOSTIC START ===") (ac-diagnose-eat) (ac-diagnose-timers) (ac-diagnose-processes) (ac-debug-log "=== FULL DIAGNOSTIC END ===") (message "Full diagnostic complete - see .emacs-logs/emacs-debug.log"))
;; Keybindings for diagnostics(global-set-key (kbd "C-c d e") 'ac-diagnose-eat)(global-set-key (kbd "C-c d t") 'ac-diagnose-timers)(global-set-key (kbd "C-c d p") 'ac-diagnose-processes)(global-set-key (kbd "C-c d a") 'ac-diagnose-all)(global-set-key (kbd "C-c d s") 'ac-profile-start)(global-set-key (kbd "C-c d x") 'ac-profile-stop)(global-set-key (kbd "C-c d r") 'ac-profile-report)(global-set-key (kbd "C-c d b") 'ac-boot-show) ; Show boot progress
;;; --- MCP State Awareness Functions ---;; These functions provide structured state info for MCP tools
(defun ac-mcp-get-state () "Return comprehensive emacs state as JSON-friendly alist for MCP tools.Call this to get awareness of current buffers, tabs, and processes." (let* ((current-buf (current-buffer)) (current-buf-name (buffer-name current-buf)) (current-tab (alist-get 'name (tab-bar--current-tab))) (all-tabs (mapcar (lambda (tab) (alist-get 'name tab)) (tab-bar-tabs))) (eat-buffers (seq-filter (lambda (b) (with-current-buffer b (eq major-mode 'eat-mode))) (buffer-list))) (eat-info (mapcar (lambda (buf) (with-current-buffer buf (let* ((proc (get-buffer-process buf)) (proc-status (if proc (symbol-name (process-status proc)) "no-process"))) (list (cons 'name (buffer-name buf)) (cons 'process proc-status) (cons 'alive (and proc (process-live-p proc))))))) eat-buffers))) (list (cons 'currentBuffer current-buf-name) (cons 'currentTab current-tab) (cons 'allTabs all-tabs) (cons 'eatBuffers eat-info))))
(defun ac-mcp-get-buffer-state (buffer-name) "Get detailed state of a specific buffer for MCP tools.Returns nil if buffer doesn't exist, otherwise returns alist with:- exists: always t- mode: major mode name - process: process status or nil- alive: t if process is live- modified: t if buffer has unsaved changes- size: buffer character count" (if-let ((buf (get-buffer buffer-name))) (with-current-buffer buf (let* ((proc (get-buffer-process buf)) (proc-status (when proc (symbol-name (process-status proc))))) (list (cons 'exists t) (cons 'mode (symbol-name major-mode)) (cons 'process proc-status) (cons 'alive (and proc (process-live-p proc))) (cons 'modified (buffer-modified-p)) (cons 'size (buffer-size))))) nil))
(defun ac-mcp-get-eat-status (buffer-name) "Get status of an eat terminal buffer.Returns: 'running, 'exited, 'not-eat, or 'not-found" (if-let ((buf (get-buffer buffer-name))) (with-current-buffer buf (if (eq major-mode 'eat-mode) (let ((proc (get-buffer-process buf))) (cond ((not proc) 'exited) ((process-live-p proc) 'running) (t 'exited))) 'not-eat)) 'not-found))
(defun ac-mcp-format-state () "Return emacs state as formatted string for MCP tools." (let* ((state (ac-mcp-get-state)) (current-buf (alist-get 'currentBuffer state)) (current-tab (alist-get 'currentTab state)) (tabs (alist-get 'allTabs state)) (eats (alist-get 'eatBuffers state))) (format "Tab: %s | Buffer: %s | Tabs: [%s] | Terminals: %s" current-tab current-buf (mapconcat #'identity tabs ", ") (mapconcat (lambda (e) (format "%s(%s)" (alist-get 'name e) (if (alist-get 'alive e) "●" "○"))) eats ", "))))
(defun ac-mcp-ensure-buffer-ready (buffer-name &optional restart-fn) "Ensure buffer exists and is usable. Returns status symbol.If buffer has dead process and RESTART-FN is provided, calls it.Returns: 'ready, 'restarted, 'dead, or 'not-found" (if-let ((buf (get-buffer buffer-name))) (with-current-buffer buf (if (eq major-mode 'eat-mode) (let ((proc (get-buffer-process buf))) (cond ((and proc (process-live-p proc)) 'ready) (restart-fn (funcall restart-fn) 'restarted) (t 'dead))) 'ready)) 'not-found))
;;; --- Copilot Completion Notification ---;; Flash current terminal when Copilot response is done (called via MCP)
(defvar ac-notify-flash-active nil "Whether notification flash is currently active.")(defvar ac-notify-flash-timer nil "Timer for notification flashing.")(defvar ac-notify-flash-count 0 "Number of flash cycles completed.")(defvar ac-notify-original-bg nil "Original background color before flash.")(defvar ac-notify-flash-colors '("#1a3a1a" ; dark green "#3a1a3a" ; dark magenta "#1a1a3a" ; dark blue "#3a3a1a" ; dark yellow "#3a1a1a" ; dark red "#1a3a3a") ; dark cyan "Colors to cycle through during notification flash.")
(defun ac-notify-stop-flash () "Stop the notification flash and restore original background." (interactive) (when ac-notify-flash-timer (cancel-timer ac-notify-flash-timer) (setq ac-notify-flash-timer nil)) (setq ac-notify-flash-active nil) (setq ac-notify-flash-count 0) ;; Restore original background (when ac-notify-original-bg (set-face-background 'default ac-notify-original-bg) (setq ac-notify-original-bg nil)) ;; Force redisplay (redisplay t))
(defun ac-notify-do-flash () "Perform one flash cycle with rainbow colors." (when ac-notify-flash-active (setq ac-notify-flash-count (1+ ac-notify-flash-count)) ;; Alternate between flash colors and original (if (= (mod ac-notify-flash-count 2) 1) ;; Pick a color from the list, cycling through (let* ((color-idx (mod (/ ac-notify-flash-count 2) (length ac-notify-flash-colors))) (flash-color (nth color-idx ac-notify-flash-colors))) (set-face-background 'default flash-color)) (set-face-background 'default ac-notify-original-bg)) (redisplay t) ;; Continue flashing (setq ac-notify-flash-timer (run-at-time 0.25 nil #'ac-notify-do-flash))))
;; 🎯 Task State Management (for VS Code status bar integration)(defvar ac-task-state-file "/tmp/aesthetic-task-state.json" "Path to the task state file that VS Code watches.")
(defun ac-task-set (status &optional label progress) "Set the task state. STATUS can be: idle, working, done, error.LABEL is optional description text.PROGRESS is optional percentage (0-100).VS Code status bar will update to reflect this state." (let* ((timestamp (truncate (* 1000 (float-time)))) (state `((status . ,status) (label . ,(or label status)) (progress . ,(or progress (if (equal status "done") 100 0))) (timestamp . ,timestamp)))) (with-temp-file ac-task-state-file (insert (json-encode state))) (message "🎯 Task: %s - %s" status (or label ""))))
(defun ac-task-working (&optional label) "Set task status to working (yellow, spinning icon)." (interactive "sTask label: ") (ac-task-set "working" (or label "Working...")))
(defun ac-task-done (&optional label) "Set task status to done (green, flash effect)." (interactive "sTask label: ") (ac-task-set "done" (or label "Done!")))
(defun ac-task-error (&optional label) "Set task status to error (red)." (interactive "sTask label: ") (ac-task-set "error" (or label "Error")))
(defun ac-task-idle () "Clear task status (back to idle)." (interactive) (ac-task-set "idle" ""))
(defun ac-task-clear () "Remove the task state file entirely." (interactive) (when (file-exists-p ac-task-state-file) (delete-file ac-task-state-file) (message "🎯 Task state cleared")))
(defun ac-notify-done (&optional message) "Notify completion by flashing the current buffer background.Flash continues until user clicks or presses a key.Called by MCP tools at the end of each response.Also updates VS Code task status bar to 'done'." (interactive) (let ((msg (or message "Done"))) ;; Also signal artery-tui (for when viewing that tab) (with-temp-file "/tmp/ac-copilot-done" (insert "done")) ;; Update VS Code task status bar (ac-task-done msg) ;; Start flashing in current buffer (unless ac-notify-flash-active (setq ac-notify-original-bg (face-background 'default nil t)) (setq ac-notify-flash-active t) (setq ac-notify-flash-count 0) (ac-notify-do-flash) ;; Stop flash on any input (mouse or keyboard) (add-hook 'pre-command-hook #'ac-notify-stop-flash)) (message "🔔 %s" msg)))
(ac-perf-session-start)(ac-debug-log "=== Starting Emacs Configuration Load ===")(ac-perf-log "Config load started")
;; Performance settings(ac-debug-log "Setting performance options...")(setq native-comp-async-report-warnings-errors nil native-comp-deferred-compilation nil native-comp-jit-compilation nil ; Disable JIT native compilation native-comp-async-jobs-number 1 ; Limit async jobs if any do run native-comp-async-query-on-exit nil ; Don't query on exit comp-async-report-warnings-errors nil ; Suppress comp warnings comp-deferred-compilation nil ; Also disable via comp- prefix x-gtk-use-system-tooltips nil mac-option-modifier 'meta warning-minimum-level :emergency ;; Terminal/process output throttling read-process-output-max (* 16 1024) ; 16KB chunks instead of 64KB process-adaptive-read-buffering t ; Let emacs batch reads redisplay-dont-pause nil ; Allow redisplay interruption fast-but-imprecise-scrolling t ; Faster scroll in terminals bidi-inhibit-bpa t ; Disable bidi for terminals bidi-paragraph-direction 'left-to-right) ; No bidi scanning
;; Kill any runaway native comp processes on startup(when (fboundp 'native-comp-available-p) (advice-add 'native-compile-async :override (lambda (&rest _) nil))) ; Completely disable async native comp
(ac-debug-log "Performance settings loaded")(ac-perf-log "Performance settings loaded")
(global-set-key [C-down-mouse-1] 'ignore)
;; Tab bar(tab-bar-mode t)(setq tab-bar-new-tab-choice "*scratch*" tab-bar-hints t tab-bar-format '(tab-bar-format-tabs tab-bar-separator) tab-bar-close-button-show nil tab-line-tab-max-width 20)
;; Custom colored tab bar - each tab gets its own background color(defun ac-tab-bar-tab-name-format (tab i) "Format TAB name with custom colors based on tab name." (let* ((current-p (eq (car tab) 'current-tab)) (tab-name (alist-get 'name tab)) ;; Define colors for each tab type (bg . fg) (tab-colors '(("artery" . ("#8B0000" . "#FFFFFF")) ; Dark red ("status" . ("#006400" . "#FFFFFF")) ; Dark green ("stripe" . ("#4B0082" . "#FFFFFF")) ; Indigo ("chat" . ("#00008B" . "#FFFFFF")) ; Dark blue ("web 1/2" . ("#008B8B" . "#FFFFFF")) ; Dark cyan ("web 2/2" . ("#2F4F4F" . "#FFFFFF")) ; Dark slate gray ("tests" . ("#8B4513" . "#FFFFFF")) ; Saddle brown ("llm" . ("#5B2C83" . "#FFFFFF")) ; Deep purple ("signal" . ("#3A76F0" . "#FFFFFF")) ; Signal blue ("fishy" . ("#005F73" . "#FFFFFF")))) ; Deep teal (colors (or (cdr (assoc tab-name tab-colors)) '("#333333" . "#FFFFFF"))) ; Default dark gray (bg-color (car colors)) (fg-color (cdr colors)) ;; Make current tab brighter (face-spec (if current-p `(:background ,bg-color :foreground ,fg-color :weight bold :box (:line-width 2 :color "#FFFFFF")) `(:background ,bg-color :foreground ,fg-color :weight normal)))) (propertize (format " %d:%s " i tab-name) 'face face-spec)))
(setq tab-bar-tab-name-format-function #'ac-tab-bar-tab-name-format)
;; Display settings(setq scroll-step 1)(global-auto-revert-mode 1)(setq auto-revert-interval 5)(setq-default display-fill-column-indicator-column 80)(add-hook 'prog-mode-hook (lambda () (display-fill-column-indicator-mode 1)))
;; Line numbers(defun disable-line-numbers-in-modes () (when (or (derived-mode-p 'eshell-mode) (derived-mode-p 'eat-mode)) (display-line-numbers-mode -1)))
(defun ac-optimize-eat-terminal () "Disable heavy modes in eat terminal buffers for better performance." ;; Disable line numbers (display-line-numbers-mode -1) ;; Disable evil-mode (use emacs keybindings in terminals) (when (and (boundp 'evil-local-mode) (fboundp 'evil-local-mode)) (evil-local-mode -1)) ;; Disable origami (code folding not needed in terminal) (when (and (boundp 'origami-mode) (fboundp 'origami-mode)) (origami-mode -1)) ;; Disable yascroll (scrollbar causes rendering overhead) (when (and (boundp 'yascroll-bar-mode) (fboundp 'yascroll-bar-mode)) (yascroll-bar-mode -1)) ;; Disable fill column indicator (when (fboundp 'display-fill-column-indicator-mode) (display-fill-column-indicator-mode -1)))
;; Auto-scroll eat terminals to bottom on new output.;; Strategy: a single global idle timer scrolls all dirty visible buffers.;; The hook just marks buffers dirty (cheap hash-set op, no timer churn).;; This keeps overhead constant regardless of how many terminals produce output.(defvar ac--eat-dirty-bufs (make-hash-table :test 'eq) "Set of eat buffers that received output since last scroll.")
(defvar ac--eat-scroll-idle-timer nil "Single global idle timer for eat auto-scroll.")
(defun ac--eat-scroll-dirty () "Scroll all dirty eat buffers that have a visible window, then clear." (maphash (lambda (buf _) (when (buffer-live-p buf) (let ((window (get-buffer-window buf))) (when window (with-selected-window window (goto-char (point-max)) (recenter -1)))))) ac--eat-dirty-bufs) (clrhash ac--eat-dirty-bufs))
(defun ac-eat-auto-scroll () "Mark current eat buffer as needing scroll. Actual scroll happens on idle." (when (derived-mode-p 'eat-mode) (puthash (current-buffer) t ac--eat-dirty-bufs)))
;; Single idle timer — fires 0.5s after Emacs goes idle, repeats every 1s(with-eval-after-load 'eat (add-hook 'eat-update-hook #'ac-eat-auto-scroll) (setq ac--eat-scroll-idle-timer (run-with-idle-timer 0.5 t #'ac--eat-scroll-dirty)))
(add-hook 'eshell-mode-hook 'disable-line-numbers-in-modes)(add-hook 'eat-mode-hook 'disable-line-numbers-in-modes)(add-hook 'eat-mode-hook 'ac-optimize-eat-terminal)(add-hook 'image-mode-hook 'disable-line-numbers-in-modes)
;; Electric pairs(defun enable-electric-pairs () (setq-local electric-pair-pairs '((?\{ . ?\}) (?\( . ?\)) (?\[ . ?\]) (?' . ?') (?` . ?`))) (electric-pair-local-mode 1))(add-hook 'prog-mode-hook 'enable-electric-pairs)
;; Auto-save(auto-save-visited-mode 1)(add-hook 'before-save-hook 'delete-trailing-whitespace)
(defun auto-save-buffer () (when (or (derived-mode-p 'prog-mode) (derived-mode-p 'text-mode)) (save-buffer)))
(when (window-system) (defvar auto-save-throttle-timer nil) (defun throttled-auto-save () (when auto-save-throttle-timer (cancel-timer auto-save-throttle-timer)) (setq auto-save-throttle-timer (run-with-timer 3 nil #'auto-save-buffer))) (add-hook 'focus-out-hook 'auto-save-buffer))
;; Faces(custom-set-faces '(tab-bar ((t (:height 1.0)))) '(tab-bar-tab-inactive ((t (:inherit tab-bar-tab :inverse-video t)))))
;; UI settings(setq inhibit-startup-screen t eshell-banner-message "" initial-scratch-message nil)(global-display-line-numbers-mode)
;; Windows WSL(when (eq system-type 'windows-nt) (setq explicit-shell-file-name "C:/Windows/System32/bash.exe" shell-file-name explicit-shell-file-name) (setenv "SHELL" shell-file-name) (add-to-list 'exec-path "C:/Windows/System32"))
;; Mouse scrolling(global-set-key (kbd "<mouse-4>") (lambda () (interactive) (scroll-down 1)))(global-set-key (kbd "<mouse-5>") (lambda () (interactive) (scroll-up 1)))
;; Tab navigation(defun my-tab-next () (interactive) (tab-next))
(defun my-tab-previous () (interactive) (tab-previous))
(global-set-key (kbd "C-x <right>") 'my-tab-next)(global-set-key (kbd "C-x <left>") 'my-tab-previous)
;; GUI settings(when (display-graphic-p) (scroll-bar-mode -1) (fringe-mode 0))(setq-default scroll-bar-mode 'right)(menu-bar-mode -1)(tool-bar-mode -1)
;; Mouse and bell(xterm-mouse-mode 1)(defun track-mouse (e))(setq mouse-sel-mode t ring-bell-function 'ignore)
;; Backup directories(defvar my-backup-directory "~/.emacs.d/backups/")(unless (file-exists-p my-backup-directory) (make-directory my-backup-directory t))(setq backup-directory-alist `(("." . ,my-backup-directory)))
(defvar my-auto-save-directory "~/.emacs.d/auto-saves/")(unless (file-exists-p my-auto-save-directory) (make-directory my-auto-save-directory t))(setq auto-save-file-name-transforms `((".*" ,my-auto-save-directory t)))
(defvar my-lockfiles-directory "~/.emacs.d/lockfiles/")(unless (file-exists-p my-lockfiles-directory) (make-directory my-lockfiles-directory t))(setq lock-file-name-transforms `((".*" ,my-lockfiles-directory t)))
;; Editor behavior(setq-default indent-tabs-mode nil tab-width 2 truncate-lines t)(setq vc-follow-symlinks t)
(global-set-key (kbd "M-z") 'toggle-truncate-lines)(global-set-key (kbd "C-c z") 'toggle-truncate-lines)(global-set-key (kbd "C-=") 'text-scale-increase)(global-set-key (kbd "C--") 'text-scale-decrease)
(add-hook 'after-init-hook (lambda () (setq-default truncate-lines t)))
;; Package management(setq package-enable-at-startup nil)
;; Straight.el bootstrap with timeout(ac-debug-log "Starting straight.el bootstrap")(defvar bootstrap-version)(let ((bootstrap-file (expand-file-name "straight/repos/straight.el/bootstrap.el" (or (bound-and-true-p straight-base-dir) user-emacs-directory))) (bootstrap-version 7)) (unless (file-exists-p bootstrap-file) (ac-debug-log "Bootstrap file not found, downloading...") (condition-case err (with-timeout (10 (error "Bootstrap download timed out")) ; Reduced timeout (with-current-buffer (url-retrieve-synchronously "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el" 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (error (ac-debug-log (format "Failed to bootstrap straight.el: %s" err)) (message "Failed to bootstrap straight.el: %s" err)))) (when (file-exists-p bootstrap-file) (ac-debug-log "Loading bootstrap file") (load bootstrap-file nil 'nomessage)))
(setq straight-use-package-by-default t straight-vc-git-default-clone-depth 1 ; Shallow clones for faster setup straight-check-for-modifications '(check-on-save find-when-checking))
;; Auto-update packages in background (daemon only, not on client connect)(defun ac-update-packages-async () "Update all packages asynchronously in background subprocess." (ac-debug-log "Checking for package updates in background...") (let ((default-directory user-emacs-directory) (init-file (or user-init-file (expand-file-name "init.el" user-emacs-directory) (expand-file-name ".emacs" "~")))) (if (and init-file (file-exists-p init-file)) ;; Run in a subprocess so it doesn't block anything (start-process "straight-update" "*straight-update*" "emacs" "--batch" "-l" init-file "--eval" "(progn (straight-pull-all) (straight-rebuild-all))") (ac-debug-log "WARNING: Could not find init file for package update"))))
;; Manual update command(defun ac-update-packages () "Manually update all packages now." (interactive) (message "🔄 Updating packages...") (straight-pull-all) (straight-rebuild-all) (message "✅ All packages updated"))
;; Only check for updates during daemon startup, not on every client connection;; This prevents UI blocking when connecting emacsclient(when (daemonp) (run-with-timer 60 nil #'ac-update-packages-async))
(ac-debug-log "Straight.el configured, starting package loads")(ac-perf-log "Straight.el configured")
;; Completion(ac-debug-log "Loading vertico")(use-package vertico :init (vertico-mode))(ac-debug-log "Vertico loaded")(ac-perf-log "Vertico loaded")
(use-package savehist :init (savehist-mode))
;; Org-mode (temporarily disabled due to cloning issues);; (condition-case nil;; (progn;; (use-package org;; :defer t);; (global-set-key (kbd "C-c l") #'org-store-link);; (global-set-key (kbd "C-c a") #'org-agenda);; (global-set-key (kbd "C-c c") #'org-capture));; (error (message "Failed to load org-mode, continuing without it...")))
;; Enhanced completion(use-package emacs :init (defun crm-indicator (args) (cons (format "[CRM%s] %s" (replace-regexp-in-string "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" crm-separator) (car args)) (cdr args))) (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
(setq minibuffer-prompt-properties '(read-only t cursor-intangible t face minibuffer-prompt) enable-recursive-minibuffers t) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (setq read-extended-command-predicate #'command-completion-default-include-p))
(use-package orderless :init (setq completion-styles '(orderless basic) completion-category-defaults nil completion-category-overrides '((file (styles partial-completion)))))
(use-package marginalia :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) :init (marginalia-mode))
;;; ───────────────────────────────────────────────────────────────────;;; DISABLED/OPTIONAL PACKAGES;;; ───────────────────────────────────────────────────────────────────
;; Auto dark theme (commented out);; (when (window-system);; (use-package auto-dark);; (setq auto-dark-dark-theme 'wombat;; auto-dark-light-theme 'whiteboard);; (auto-dark-mode t))
;; Frame-specific configuration (commented out);; (when (display-graphic-p);; (add-hook 'after-make-frame-functions;; (lambda (frame);; Active packages(use-package yascroll :config (global-yascroll-bar-mode 1))
;; NOTE: origami.el has a defface bug that calls (face-attribute 'highlight :background);; at load time, which returns 'unspecified' in daemon mode (no frame).;; Defer loading until after a frame exists.(use-package origami :defer t :hook (server-after-make-frame . global-origami-mode))
(global-set-key (kbd "C-p") #'project-find-file)(global-set-key (kbd "C-x C-p") #'project-find-file)(global-set-key (kbd "M-p") #'project-find-file)
(setq js-indent-level 2)
(use-package s)(use-package dockerfile-mode)(use-package fish-mode)
(use-package prettier-js :hook (js-mode . prettier-js-mode) :bind ("C-c p" . prettier-js))
(use-package xclip :config (xclip-mode 1))
(defun my/xclip-set-selection (orig-fun type data) (let ((clipboard-command (format "fish -c 'clipboard %s'" (shell-quote-argument data)))) (start-process-shell-command "clipboard" nil clipboard-command)) (funcall orig-fun type data))
(advice-add 'xclip-set-selection :around #'my/xclip-set-selection)
;; Evil mode(use-package evil :config (evil-mode 1) (setq-default evil-shift-width 2) (dolist (state '(normal insert visual motion emacs)) (evil-define-key state 'global (kbd "C-p") 'project-find-file)))
(define-key evil-normal-state-map (kbd "C-u") 'evil-scroll-up)
(defun my/evil-quit () (interactive) (let ((current-buffer (current-buffer)) (is-last-tab (eq 1 (length (tab-bar-tabs)))) (is-last-window (eq 1 (length (window-list)))))
;; Close window if not the last window in tab (unless is-last-window (delete-window))
;; Kill buffer if not displayed elsewhere (unless (delq (selected-window) (get-buffer-window-list current-buffer nil t)) (kill-buffer current-buffer))
;; Optional: Close tab if last window but not last tab ;; (when (and is-last-window (not is-last-tab)) (if is-last-window (if is-last-tab (message "Cannot close last window of last tab") (tab-bar-close-tab)) (delete-window))))
(with-eval-after-load 'evil (evil-ex-define-cmd "q[uit]" 'my/evil-quit))
(unless (display-graphic-p) (use-package evil-terminal-cursor-changer) (require 'evil-terminal-cursor-changer) (evil-terminal-cursor-changer-activate))
;; Utilities(use-package restart-emacs)(setq restart-emacs-restore-frames t)
(global-set-key (kbd "C-c C-r") 'restart-emacs)(global-set-key (kbd "C-c C-o") 'browse-url-at-point)
;; Mail (Gmail via mbsync + mu4e)(defvar ac-maildir "~/.mail" "Local Maildir root used by mu4e.")
(defvar ac-mail-sync-command "mbsync ac-mail && mu index --quiet" "Command used to sync and index mail.")
(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e")
(use-package mu4e :straight nil :defer t :commands (mu4e mu4e-compose-new) :init (setq mu4e-maildir ac-maildir mu4e-get-mail-command ac-mail-sync-command mu4e-update-interval 300 mu4e-change-filenames-when-moving t mu4e-headers-auto-update t mu4e-view-show-addresses t mu4e-compose-format-flowed t mu4e-sent-folder "/[Gmail]/Sent Mail" mu4e-drafts-folder "/[Gmail]/Drafts" mu4e-trash-folder "/[Gmail]/Trash" mu4e-refile-folder "/[Gmail]/All Mail" mu4e-maildir-shortcuts '(("/INBOX" . ?i) ("/[Gmail]/Sent Mail" . ?s) ("/[Gmail]/Drafts" . ?d) ("/[Gmail]/Trash" . ?t))) :config (setq mail-user-agent 'mu4e-user-agent send-mail-function 'sendmail-send-it message-send-mail-function 'message-send-mail-with-sendmail sendmail-program (or (executable-find "msmtp") "/usr/sbin/msmtp") message-sendmail-f-is-evil t message-sendmail-extra-arguments '("--read-envelope-from" "--read-recipients")))
(defun ac-mail-sync () "Run mail sync + indexing asynchronously." (interactive) (async-shell-command ac-mail-sync-command "mail-sync"))
(defun ac-mail-open () "Open mu4e in a dedicated mail tab." (interactive) (if (and (fboundp 'ac--tab-exists-p) (ac--tab-exists-p "mail")) (tab-bar-switch-to-tab "mail") (tab-bar-new-tab) (tab-rename "mail")) (condition-case nil (mu4e) (error (message "mu4e not available — opening mail tab with blast tools only") (ac-mail-blast-preview))))
(global-set-key (kbd "C-c m") 'ac-mail-open)(global-set-key (kbd "C-c M-m") 'ac-mail-sync)
;; Main project directory (must be defined before any expand-file-name usage)(defvar ac--directory-path "~/aesthetic-computer")
;; Email Blast integration (artery/email-blast.mjs)(defvar ac-mail-blast-script (expand-file-name "artery/email-blast.mjs" ac--directory-path) "Path to the email blast script.")
(defun ac-mail-blast-preview () "Preview the email blast content in a buffer." (interactive) (let ((default-directory ac--directory-path) (buf (get-buffer-create "*ac-mail-blast*"))) (with-current-buffer buf (read-only-mode -1) (erase-buffer) (insert "── Aesthetic.Computer Email Blast ──\n\n") (insert "Commands (run with C-c M-b <key>):\n") (insert " p Preview email content\n") (insert " t Send test email (me@jas.life)\n") (insert " s Send blast (verified users)\n") (insert " r Resume interrupted blast\n") (insert " l List cached users\n\n") (insert "─────────────────────────────────────\n\n")) (switch-to-buffer buf) (shell-command (format "node %s --preview" (shell-quote-argument ac-mail-blast-script)) buf) (with-current-buffer buf (read-only-mode 1))))
(defun ac-mail-blast-test () "Send a test email to me@jas.life." (interactive) (let ((default-directory ac--directory-path)) (async-shell-command (format "node %s --test me@jas.life" (shell-quote-argument ac-mail-blast-script)) "*ac-mail-blast-test*")))
(defun ac-mail-blast-send () "Send email blast to verified users (with confirmation)." (interactive) (when (yes-or-no-p "Send email blast to all verified users? ") (let ((default-directory ac--directory-path)) (ac--ensure-mail-tab) (eat-exec (current-buffer) "blast" "node" nil (list ac-mail-blast-script "--send")))))
(defun ac-mail-blast-resume () "Resume an interrupted email blast." (interactive) (let ((default-directory ac--directory-path)) (ac--ensure-mail-tab) (eat-exec (current-buffer) "blast" "node" nil (list ac-mail-blast-script "--send" "--resume"))))
(defun ac-mail-blast-list () "List cached email blast users." (interactive) (let ((default-directory ac--directory-path)) (async-shell-command (format "node %s --list" (shell-quote-argument ac-mail-blast-script)) "*ac-mail-blast-list*")))
(defun ac--ensure-mail-tab () "Switch to or create the mail tab." (if (and (fboundp 'ac--tab-exists-p) (ac--tab-exists-p "mail")) (tab-bar-switch-to-tab "mail") (tab-bar-new-tab) (tab-rename "mail")))
;; Mail blast keybindings under C-c M-b prefix(define-prefix-command 'ac-mail-blast-map)(global-set-key (kbd "C-c M-b") 'ac-mail-blast-map)(define-key ac-mail-blast-map (kbd "p") 'ac-mail-blast-preview)(define-key ac-mail-blast-map (kbd "t") 'ac-mail-blast-test)(define-key ac-mail-blast-map (kbd "s") 'ac-mail-blast-send)(define-key ac-mail-blast-map (kbd "r") 'ac-mail-blast-resume)(define-key ac-mail-blast-map (kbd "l") 'ac-mail-blast-list)
;; Eat terminal - with performance optimizations for many terminals(use-package eat)(setq-default eat-shell "/usr/bin/fish" eat-term-name "xterm-256color")
;; Filter out unhandled OSC sequences (10/11/12 = fg/bg/cursor color);; These are sent by apps like Copilot CLI but eat doesn't handle them(defun ac--strip-osc-color-sequences (string) "Remove OSC 10/11/12 sequences that eat cannot process." ;; Simple pattern: ]10/11/12;... until whitespace (Copilot CLI sends malformed OSC) (replace-regexp-in-string "]1[012];[^[:space:]]+" "" string))
(defun ac--filter-eat-output (orig-fn process string) "Advice to filter unhandled OSC sequences before eat processes them." (funcall orig-fn process (ac--strip-osc-color-sequences string)))
(advice-add 'eat--filter :around #'ac--filter-eat-output)
;; Performance: Aggressively limit eat overhead for 16+ terminals(setq eat-enable-directory-tracking nil ; Reduces overhead eat-enable-shell-command-history nil ; We use fish history eat-enable-shell-prompt-annotation nil ; Reduces processing eat-show-title-on-mode-line nil ; We name buffers ourselves eat-term-scrollback-size 8192 ; 8KB - minimal scrollback eat-enable-auto-line-mode nil ; Keep in semi-char mode eat-minimum-latency 0.2 ; Batch output updates (200ms) eat-maximum-latency 0.5 ; Max batch delay (500ms) eat-enable-blinking-text nil ; Disable blinking eat-enable-mouse nil) ; Disable mouse support
;; Disable evil mode in artery buffer;; REMOVED: buffer-list-update-hook was causing performance issues;; The hook fired constantly with 16+ terminals causing CPU spike;; Just use eat-mode-hook with timer instead
;; Use eat-mode-hook with a timer to catch post-rename(add-hook 'eat-mode-hook (lambda () (run-with-timer 0.5 nil (lambda () (when (and (buffer-live-p (current-buffer)) (string-match-p "artery" (buffer-name))) (with-current-buffer (current-buffer) (when (and (boundp 'evil-mode) evil-mode) (evil-emacs-state))))))))
;; Eat tab integration (temporarily disabled for debugging);; (defun eat-tab-change (original-fun &rest args);; (interactive);; (let ((result (apply original-fun args)));; (run-with-idle-timer 0.1 nil;; (lambda ();; (when (and (selected-frame) (frame-live-p (selected-frame)));; (condition-case err;; (let ((current-tab-windows (window-list (selected-frame) 'never)));; (dolist (window current-tab-windows);; (when (and (windowp window) (window-live-p window));; (with-current-buffer (window-buffer window);; (when (eq major-mode 'eat-mode);; (with-selected-window window;; (end-of-buffer);; (when (bound-and-true-p evil-mode);; (evil-insert-state))))))));; (error nil)))));; result))
;; (with-eval-after-load 'eat;; (advice-add 'tab-bar-select-tab :around #'eat-tab-change))
(defun kill-eat-processes () (interactive) (dolist (buffer (buffer-list)) (with-current-buffer buffer (when (eq major-mode 'eat-mode) (eat-kill-process)))))
(add-hook 'kill-emacs-hook #'kill-eat-processes)
(defun ac-restart-fishy () "Restart fish process in the fishy buffer if it died." (interactive) (if-let ((buf (get-buffer "🐟-fishy"))) (with-current-buffer buf (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (eat-exec buf "fishy" "/usr/bin/fish" nil nil) (message "✅ Fish restarted in 🐟-fishy")) (message "No 🐟-fishy buffer found")))
(defun ac-restart-site () "Restart the site dev server (npm run site) in the 🌐-site buffer." (interactive) (if-let ((buf (get-buffer "🌐-site"))) (with-current-buffer buf (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (let ((default-directory ac--directory-path)) (eat-exec buf "🌐-site" "/usr/bin/fish" nil '("-c" "ac-site"))) (message "✅ Site dev server restarted")) (message "No 🌐-site buffer found - try switching to 'web 1/2' tab first")))
(defun ac-restart-session () "Restart the session server in the 📋-session buffer." (interactive) (if-let ((buf (get-buffer "📋-session"))) (with-current-buffer buf (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (let ((default-directory ac--directory-path)) (eat-exec buf "📋-session" "/usr/bin/fish" nil '("-c" "ac-session"))) (message "✅ Session server restarted")) (message "No 📋-session buffer found")))
(defun ac-restart-redis () "Restart redis in the 🔴-redis buffer." (interactive) (if-let ((buf (get-buffer "🔴-redis"))) (with-current-buffer buf (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (let ((default-directory ac--directory-path)) (eat-exec buf "🔴-redis" "/usr/bin/fish" nil '("-c" "ac-redis"))) (message "✅ Redis restarted")) (message "No 🔴-redis buffer found")))
(defun ac-restart-kidlisp () "Restart kidlisp test watcher in the 🧪-kidlisp buffer." (interactive) (if-let ((buf (get-buffer "🧪-kidlisp"))) (with-current-buffer buf (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (let ((default-directory ac--directory-path)) (eat-exec buf "🧪-kidlisp" "/usr/bin/fish" nil '("-c" "ac-kidlisp"))) (message "✅ KidLisp test watcher restarted")) (message "No 🧪-kidlisp buffer found")))
(defun ac-restart-buffer (buffer-name command) "Generic restart function for any AC terminal buffer.BUFFER-NAME is the full buffer name (e.g., \"🌐-site\").COMMAND is the ac- fish command to run (e.g., \"site\")." (if-let ((buf (get-buffer buffer-name))) (with-current-buffer buf (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (let ((default-directory ac--directory-path)) (eat-exec buf buffer-name "/usr/bin/fish" nil (list "-c" (format "ac-%s" command)))) (message "✅ %s restarted" buffer-name)) (message "Buffer %s not found" buffer-name)))
(defun ac--fishy-sentinel (process event) "Auto-restart fishy when process exits." (when (and (string-match-p "\\(finished\\|exited\\|killed\\)" event) (buffer-live-p (process-buffer process)) (string= (buffer-name (process-buffer process)) "🐟-fishy")) (run-with-timer 0.1 nil #'ac-restart-fishy)))
;; Hook into eat to watch fishy process(add-hook 'eat-mode-hook (lambda () (when (string= (buffer-name) "🐟-fishy") (run-with-timer 0.5 nil (lambda () (when-let ((proc (get-buffer-process "🐟-fishy"))) (set-process-sentinel proc #'ac--fishy-sentinel)))))))
;;; --- Aesthetic Computer Restart Functions ---
(defvar ac--tab-names '("artery" "status" "stripe" "chat" "web 1/2" "web 2/2" "tests" "llm" "mail" "signal" "top" "fishy") "List of all AC tab names.")
(defvar ac--buffer-prefixes '("🩸" "📡" "⚡" "🚇" "💳" "🎫" "🤖" "🧠" "⏰" "🌐" "📋" "🔴" "🔖" "🧪" "🔥" "📦") "Emoji prefixes used for AC buffers.")
(defun ac-kill-all () "Kill all AC processes, buffers, and tabs. Use before ac-restart." (interactive) (message "🛑 Killing all AC processes and buffers...") ;; 1. Stop artery bridge if running (when (and (boundp 'artery--process) artery--process (process-live-p artery--process)) (condition-case nil (artery-stop) (error nil))) ;; 2. Kill all eat processes first (sends SIGTERM) (kill-eat-processes) ;; 3. Kill all AC emoji-prefixed buffers (dolist (buffer (buffer-list)) (let ((name (buffer-name buffer))) (when (cl-some (lambda (prefix) (string-prefix-p prefix name)) ac--buffer-prefixes) (condition-case nil (progn ;; Kill any process attached to buffer (when (get-buffer-process buffer) (delete-process (get-buffer-process buffer))) (kill-buffer buffer)) (error nil))))) ;; 4. Kill artery-specific buffers (dolist (bufname '("🩸-artery" "🩸-daw-log" "🩸-bridge" "🩸-server" "*artery*" "*artery-daw*" "*artery-bridge*" "*artery-server*")) (when-let ((buf (get-buffer bufname))) (condition-case nil (progn (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (kill-buffer buf)) (error nil)))) ;; 5. Close all AC tabs except current, then close that (let ((current-tab (alist-get 'name (tab-bar--current-tab)))) ;; Close all other tabs first (dolist (tab-name ac--tab-names) (unless (string= tab-name current-tab) (condition-case nil (tab-bar-close-tab-by-name tab-name) (error nil)))) ;; Try to close current tab (might fail if it's the last one) (when (member current-tab ac--tab-names) (condition-case nil (tab-bar-close-tab) (error nil)))) ;; 6. Ensure we have at least scratch buffer (unless (get-buffer "*scratch*") (get-buffer-create "*scratch*")) (switch-to-buffer "*scratch*") (message "✅ All AC processes and buffers killed. Run M-x ac-restart to start fresh."))
(defun ac-restart (&optional target-tab) "Restart all AC tabs and processes from scratch.Optional TARGET-TAB specifies which tab to land on (default: artery)." (interactive) (let ((target (or target-tab "artery"))) (message "🔄 Restarting Aesthetic Computer...") ;; Kill everything first (ac-kill-all) ;; Wait a moment for processes to fully terminate (run-with-timer 1 nil (lambda (tgt) (message "🚀 Starting AC backend...") (aesthetic-backend tgt)) target)))
(defun ac-restart-artery () "Restart just the artery tab/process." (interactive) (message "🔄 Restarting artery...") ;; Stop artery bridge (when (and (boundp 'artery--process) artery--process) (condition-case nil (artery-stop) (error nil))) ;; Kill artery buffers (dolist (bufname '("🩸-artery" "🩸-daw-log" "🩸-bridge")) (when-let ((buf (get-buffer bufname))) (when (get-buffer-process buf) (delete-process (get-buffer-process buf))) (kill-buffer buf))) ;; Recreate artery tab (condition-case nil (tab-bar-close-tab-by-name "artery") (error nil)) (run-with-timer 0.5 nil (lambda () (tab-new) (tab-rename "artery") (let ((default-directory ac--directory-path)) (eat "fish -c 'ac-artery-dev'") (when (get-buffer "*eat*") (with-current-buffer "*eat*" (rename-buffer "🩸-artery" t) (eat-semi-char-mode) (when (and (boundp 'evil-mode) evil-mode) (evil-emacs-state))))) (message "✅ Artery restarted"))))
;; Keybindings for restart functions(global-set-key (kbd "C-c C-k") 'ac-kill-all)(global-set-key (kbd "C-c C-S-r") 'ac-restart)
;; Aesthetic functions(defun aesthetic () (interactive) (eshell) (insert "python3 -m http.server 8888") (eshell-send-input))
(setq confirm-kill-processes nil)
;; DISABLED: These hooks were causing CPU spikes with 16+ terminals;; Each terminal output triggers filter functions, overwhelming emacs;; Enable aggressive auto-scrolling for all shell/comint buffers(setq comint-scroll-to-bottom-on-input t comint-scroll-to-bottom-on-output t comint-move-point-for-output t comint-scroll-show-maximum-output t)
(add-hook 'comint-mode-hook (lambda () (setq-local scroll-conservatively 101)))
(add-hook 'shell-mode-hook (lambda () (setq-local scroll-conservatively 101)))
;; Main backend function(defvar ac--emoji-for-command '(("artery" . "🩸") ("status" . "📡") ("url" . "⚡") ("tunnel" . "🚇") ("agent" . "⚡") ("stripe-print" . "💳") ("stripe-ticket" . "🎫") ("chat-system" . "🤖") ("chat-sotce" . "🧠") ("chat-clock" . "⏰") ("site" . "🌐") ("session" . "📋") ("redis" . "🔴") ("bookmarks" . "🔖") ("kidlisp" . "🧪") ("oven" . "🔥") ("silo" . "🏗️") ("media" . "📦") ("llm" . "🤖") ("top" . "📊") ("mail" . "📬") ("signal" . "📶") ("crash-diary" . "💥") ("views" . "🖼️") ("boot" . "🚀")))
(defun ac--tab-exists-p (tab-name) "Check if a tab with TAB-NAME already exists." (cl-find tab-name (tab-bar-tabs) :key (lambda (tab) (alist-get 'name tab)) :test #'string=))
(defun ac--buffer-exists-p (buffer-name) "Check if a buffer with BUFFER-NAME already exists and has a live process." (when-let ((buf (get-buffer buffer-name))) (and (buffer-live-p buf) (or (get-buffer-process buf) (> (buffer-size buf) 0)))))
(cl-defun ac--create-split-tab (tab-name commands) "Create a new tab with split windows running the specified commands.Skips creation if tab already exists." ;; Guard: Skip if tab already exists (when (ac--tab-exists-p tab-name) (ac-debug-log (format "Tab '%s' already exists, skipping creation" tab-name)) (cl-return-from ac--create-split-tab nil)) (ac-debug-log (format "Creating tab: %s with commands: %s" tab-name commands)) (ac-perf-log (format "Creating tab: %s" tab-name)) (condition-case err (progn (tab-new) (tab-rename tab-name) (let ((default-directory ac--directory-path)) (delete-other-windows) ;; Calculate layout (let* ((window-height (window-height)) (min-height-per-window 8) (max-vertical-splits (/ window-height min-height-per-window)) (use-horizontal (< max-vertical-splits (length commands))) (cmd-index 0)) ;; Create windows and terminals - use eat-exec to avoid blocking (dolist (cmd commands) (unless (= cmd-index 0) (condition-case nil (if use-horizontal (progn (split-window-right) (other-window 1)) (progn (split-window-below) (other-window 1))) (error nil))) (let ((actual-cmd (cond ((string= cmd "bookmarks") "servers") ((string= cmd "llm") "llm-continue") ; Auto-resume last session (t cmd))) (buf-name (format "%s-%s" (or (cdr (assoc cmd ac--emoji-for-command)) "🔧") cmd))) (ac-debug-log (format "Running command: ac-%s" actual-cmd)) ;; Create eat buffer directly without blocking (condition-case err (let ((buf (generate-new-buffer buf-name))) (with-current-buffer buf (eat-mode) (eat-exec buf buf-name "/usr/bin/fish" nil (list "-c" (format "ac-%s" actual-cmd)))) (switch-to-buffer buf) ;; Yield to let Emacs process events (prevents freeze) (redisplay t)) (error (ac-debug-log (format "Error starting ac-%s in tab %s: %s" actual-cmd tab-name err))))) (setq cmd-index (1+ cmd-index))) (balance-windows) (other-window 1)))) (error (message "Error creating tab %s: %s" tab-name err))))
(defvar ac--startup-lock-file "/tmp/emacs-backend-startup.lock" "Lock file indicating aesthetic-backend is starting (crash monitor will be gentle).")
(defvar ac--backend-initializing nil "Whether aesthetic-backend is currently initializing.")
(defvar ac--backend-complete nil "Whether aesthetic-backend completed initialization.")
(defvar ac--backend-retry-count 0 "Number of aesthetic-backend retries attempted this session.")
(defvar ac--backend-max-retries 1 "Maximum number of aesthetic-backend retries.")
(cl-defun aesthetic-backend (target-tab) (interactive) (setq target-tab (or target-tab "artery")) ;; Prevent double-invocation race condition (when (and ac--backend-started ac--backend-complete) (ac-debug-log (format "aesthetic-backend already complete, switching to tab: %s" target-tab)) ;; Just switch to the requested tab if backend already running (run-with-timer 0.5 nil (lambda (target) (condition-case nil (when (member target '("artery" "fishy" "boot" "status" "stripe" "chat" "web 1/2" "web 2/2" "tests" "llm" "mail" "signal" "top")) (tab-bar-switch-to-tab target)) (error nil))) target-tab) (cl-return-from aesthetic-backend nil)) (when ac--backend-initializing (ac-debug-log "aesthetic-backend already initializing; skipping duplicate start") (cl-return-from aesthetic-backend nil)) (setq ac--backend-started t ac--backend-initializing t ac--backend-complete nil) ;; Initialize boot progress buffer (ac--boot-init) ;; Create startup lock file to tell crash monitor we're starting up ;; This prevents false "unresponsive" detection during heavy init (with-temp-file ac--startup-lock-file (insert (format "%s" (float-time)))) (ac-debug-log "Created startup lock file - crash monitor will wait") (ac-debug-log (format "Starting aesthetic-backend with target-tab: %s" target-tab)) (ac-perf-log "aesthetic-backend started") ;; Set environment variable to tell fish it's running inside Emacs (setenv "AC_EMACS_MODE" "t") ;; Prevent OSC color query responses from leaking (shows as "11;rgb:..." text) (setenv "COLORFGBG" "15;0") ;; Set up a watchdog timer to detect hangs (30 seconds) (run-with-timer 30 nil (lambda () (ac-debug-log "WARNING: aesthetic-backend has been running for 30+ seconds") (message "⚠️ Backend initialization taking longer than expected. Check .emacs-logs/")))
;; Clean up unwanted buffers before starting (with error handling) (condition-case nil (dolist (bufname '("*scratch*" "*Messages*" "*straight-process*" "*async-native-comp*")) (when-let ((buf (get-buffer bufname))) (dolist (win (get-buffer-window-list buf nil t)) (with-selected-window win (switch-to-buffer (other-buffer buf t)))) (kill-buffer buf))) (error nil))
;; Create artery tab FIRST - this is the primary tab (leftmost) (tab-rename "artery") (ac--boot-start-step "artery") (let ((default-directory ac--directory-path) (buf (or (get-buffer "🩸-artery") (generate-new-buffer "🩸-artery")))) (with-current-buffer buf (condition-case err (progn (unless (eq major-mode 'eat-mode) (eat-mode) (eat-exec buf "🩸-artery" "/usr/bin/fish" nil '("-c" "ac-artery-dev"))) (eat-semi-char-mode) (when (and (boundp 'evil-mode) evil-mode) (evil-emacs-state))) (error (ac-debug-log (format "Error starting artery eat buffer: %s" err)) (ac--boot-error-step "artery")))) (switch-to-buffer buf) (redisplay t)) (ac--boot-complete-step "artery")
;; Create boot tab SECOND - shows progress + crash diary after boot (tab-new) (tab-rename "boot") (let ((boot-buf (get-buffer ac--boot-buffer-name))) (when boot-buf (switch-to-buffer boot-buf) (ac-boot-mode) (redisplay t)))
;; Create all the split tabs with optimized delays (reduced from 500ms to 350ms) (let ((delay 0.5) (step-delay 0.35) ; Optimized: was 0.5 (tab-specs '(("status" ("url" "tunnel")) ("stripe" ("stripe-print" "stripe-ticket")) ("chat" ("chat-system" "chat-sotce" "chat-clock")) ("web 1/2" ("site" "session")) ("web 2/2" ("redis" "bookmarks" "oven" "silo" "media" "views")) ("tests" ("kidlisp")) ("llm" ("llm")) ("mail" ("mail")) ("signal" ("signal")) ("top" ("top"))))) (dolist (tab-spec tab-specs) (let ((tab-name (car tab-spec)) (commands (cadr tab-spec)) (current-delay delay)) (run-with-timer current-delay nil (lambda (name cmds) (ac--boot-start-step name) (condition-case err (progn (ac--create-split-tab name cmds) (ac--boot-complete-step name)) (error (ac-debug-log (format "Error creating tab %s: %s" name err)) (ac--boot-error-step name))) ;; Switch back to boot tab to show progress (when (ac--tab-exists-p "boot") (tab-bar-switch-to-tab "boot")) (redisplay t)) tab-name commands) (setq delay (+ delay step-delay)))))
;; Create fishy tab (tab bar position after other tabs) (run-with-timer 3.5 nil (lambda () (ac--boot-start-step "fishy") (unless (ac--tab-exists-p "fishy") (tab-new) (tab-rename "fishy") (let ((default-directory ac--directory-path) (buf (or (get-buffer "🐟-fishy") (generate-new-buffer "🐟-fishy")))) (with-current-buffer buf (condition-case err (progn (unless (eq major-mode 'eat-mode) (eat-mode) (eat-exec buf "🐟-fishy" "/usr/bin/fish" nil nil)) (eat-semi-char-mode) (when (and (boundp 'evil-mode) evil-mode) (evil-emacs-state))) (error (ac-debug-log (format "Error starting fishy eat buffer: %s" err)) (ac--boot-error-step "fishy")))) (switch-to-buffer buf) (redisplay t))) (ac--boot-complete-step "fishy") (tab-bar-switch-to-tab "boot")))
;; Calculate when tabs should be done (8 batch tabs * 0.35s = 2.8s + 0.5s initial = 3.3s, fishy at 3.5s) (let ((tabs-done-time 4.2)) ;; Start CDP tunnel after tabs (run-with-timer tabs-done-time nil (lambda () (ac--boot-start-step "cdp") (ac-start-cdp-tunnel-async) ;; CDP is async, mark done after a short delay (run-with-timer 1.0 nil (lambda () (ac--boot-complete-step "cdp"))))) ;; Finalize and switch to target tab (run-with-timer (+ tabs-done-time 1.5) nil (lambda (target) (ac--boot-start-step "finalize") ;; Remove startup lock (when (file-exists-p ac--startup-lock-file) (delete-file ac--startup-lock-file) (ac-debug-log "Removed startup lock - crash monitor now active")) (setq ac--backend-complete t ac--backend-initializing nil) (ac--boot-complete-step "finalize") (ac-perf-log "aesthetic-backend initialization complete") ;; Convert boot tab into crash diary (combined boot+crash) (run-with-timer 1.0 nil (lambda () (when (ac--tab-exists-p "boot") (tab-bar-switch-to-tab "boot") (let ((default-directory ac--directory-path) (buf (generate-new-buffer "💥-crash-diary"))) (with-current-buffer buf (condition-case err (progn (eat-mode) (eat-exec buf "💥-crash-diary" "/usr/bin/fish" nil '("-c" "ac-crash-diary"))) (error (ac-debug-log (format "Error starting crash diary: %s" err))))) (switch-to-buffer buf) (redisplay t))))) ;; Switch to target tab (run-with-timer 1.5 nil (lambda (tgt) (condition-case nil (when (member tgt '("artery" "fishy" "boot" "status" "stripe" "chat" "web 1/2" "web 2/2" "tests" "llm" "mail" "signal" "top")) (tab-bar-switch-to-tab tgt) (when (eq major-mode 'eat-mode) (goto-char (point-max))) (redisplay t)) (error nil))) target)) target-tab)
;; Retry logic (run-with-timer (+ tabs-done-time 3.0) nil (lambda (target) (when (and (not ac--backend-complete) (< ac--backend-retry-count ac--backend-max-retries)) (setq ac--backend-retry-count (1+ ac--backend-retry-count)) (ac-debug-log (format "Retrying aesthetic-backend (attempt %d)" ac--backend-retry-count)) (aesthetic-backend target))) target-tab)))
(defun ac-start-cdp-tunnel-async () "Start CDP tunnel to VS Code host in background (non-blocking)." (ac-debug-log "Starting CDP tunnel to host...") (let ((proc (start-process-shell-command "cdp-tunnel" nil "fish -c 'ac-cdp-tunnel' >/dev/null 2>&1"))) (when proc (set-process-sentinel proc (lambda (p e) (if (= 0 (process-exit-status p)) (ac-debug-log "CDP tunnel established") (ac-debug-log (format "CDP tunnel failed: %s" e))))))))
;;; ===================================================================;;; AUTO-START AESTHETIC-BACKEND ON FIRST TERMINAL FRAME;;; ===================================================================
(defvar ac--backend-started nil "Flag to ensure aesthetic-backend only runs once.")
(defun ac--backend-tabs-minimal-p () "Return t if minimal tabs are present (artery + fishy)." (and (ac--tab-exists-p "artery") (ac--tab-exists-p "fishy")))
(defun ac--ensure-backend (&optional reason) "Ensure aesthetic-backend is running; retries if needed.REASON is logged for debugging." (when (and (not ac--backend-initializing) (not (ac--backend-tabs-minimal-p)) (< ac--backend-retry-count ac--backend-max-retries)) (setq ac--backend-retry-count (1+ ac--backend-retry-count)) (ac-debug-log (format "Ensuring aesthetic-backend (attempt %d) reason=%s" ac--backend-retry-count (or reason "unknown"))) (aesthetic-backend "artery")))
(defun ac--maybe-start-backend (frame) "Start aesthetic-backend when first terminal frame connects." (when (and (not ac--backend-started) (not (display-graphic-p frame)) ; Terminal frame (frame-live-p frame)) ;; DON'T set flag here - let aesthetic-backend set it when it actually runs (ac-debug-log "First terminal frame detected, scheduling aesthetic-backend") ;; Delay to ensure frame is fully ready (run-with-timer 1 nil (lambda () (condition-case err (aesthetic-backend "artery") (error (message "Error starting aesthetic-backend: %s" err)))))))
;; Self-heal: if backend didn't start after daemon restart, try again once.(add-hook 'emacs-startup-hook (lambda () (run-with-timer 6 nil (lambda () (when (and (not ac--backend-started) (frame-live-p (selected-frame)) (<= (length (tab-bar-tabs)) 1)) (ac--ensure-backend "startup self-heal"))))))
;; Auto-start full backend on first terminal frame(add-hook 'after-make-frame-functions #'ac--maybe-start-backend)
(cl-defun aesthetic-backend-minimal () "Minimal version - start artery and fishy only. Use M-x aesthetic-backend for all tabs." (interactive) (ac-debug-log "Starting aesthetic-backend-minimal") (setenv "AC_EMACS_MODE" "t") ;; Start with artery in the first tab (tab-rename "artery") (let ((default-directory ac--directory-path)) (eat "fish -c 'ac-artery-dev'") (when (get-buffer "*eat*") (with-current-buffer "*eat*" (rename-buffer "🩸-artery" t) (eat-semi-char-mode)))) ;; Add fishy tab after 2 seconds (only if not already created) (run-with-timer 2 nil (lambda () (condition-case nil (unless (get-buffer "🐟-fishy") (tab-new) (tab-rename "fishy") (let ((default-directory ac--directory-path)) (eat "fish") (when (get-buffer "*eat*") (with-current-buffer "*eat*" (rename-buffer "🐟-fishy" t) (eat-semi-char-mode)))) ;; Switch back to artery (run-with-timer 1 nil (lambda () (tab-bar-switch-to-tab "artery")))) (error nil)))) (message "🚀 Artery started! Use M-x aesthetic-backend-full to load all tabs.") (ac-debug-log "aesthetic-backend-minimal complete"))
(cl-defun aesthetic-backend-full () "Load all remaining tabs (status, stripe, chat, web, tests, llm, top)." (interactive) (message "Loading additional tabs...") (dolist (tab-spec '(("status" ("url" "tunnel")) ("stripe" ("stripe-print" "stripe-ticket")) ("chat" ("chat-system" "chat-sotce" "chat-clock")) ("web 1/2" ("site" "session")) ("web 2/2" ("redis" "bookmarks" "oven" "silo" "media" "views")) ("tests" ("kidlisp")) ("llm" ("llm")) ("top" ("top")))) (let ((tab-name (car tab-spec)) (commands (cadr tab-spec))) (condition-case err (progn (ac--create-split-tab tab-name commands) (message "Created tab: %s" tab-name)) (error (message "Error creating tab %s: %s" tab-name err))))) (message "All tabs loaded!"))
;;; ===================================================================;;; END OF AESTHETIC COMPUTER EMACS CONFIGURATION;;; ===================================================================
(ac-debug-log "=== Emacs Configuration Load Complete ===")(ac-perf-log "Config load complete")