diff --git a/.config/cursor/cursor-rules.yaml b/.config/cursor/cursor-rules.yaml deleted file mode 100644 index ca229e7..0000000 --- a/.config/cursor/cursor-rules.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# Global preferences for Cursor editor -preferences: - telemetry: false - autoUpdate: true - -include: - - ~/.config/cursor/generated/tools.yaml - -# Preferred languages and frameworks -languages: - preferred: - - rust - - python - - typescript - optional: - - bash - tags: - rust: - - backend - - systems - python: - - backend - - scripting - typescript: - - frontend - -frontend_frameworks: - - next.js (typescript) - - react native - -backend_frameworks: - - flask (python) - - actix-web (rust) - -project_structure: - source_dir: src - test_dir: tests - infra_dirs: - docker: docker/ - optional: - k8s: k8s/ - terraform: infra/terraform/ - doc_dirs: - design_docs: architecture/ - markdown: project/ - prefers_monorepo: false - prefers_submodules: true - -scaffolding: - tool: kickstart - config_path: ~/.config/kickstart/config.yaml diff --git a/.config/cursor/generated/tools.yaml b/.config/cursor/generated/tools.yaml deleted file mode 100644 index f740df2..0000000 --- a/.config/cursor/generated/tools.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# Placeholder for tool configuration generated by automation -# This file will be overwritten automatically. -tools: [] diff --git a/.dircolors b/.dircolors deleted file mode 100644 index fe2240c..0000000 --- a/.dircolors +++ /dev/null @@ -1,713 +0,0 @@ -# core {{{1 -BLK 38;5;68 -CAPABILITY 38;5;17 -CHR 38;5;113;1 -DIR 38;5;1 -DOOR 38;5;127 -EXEC 35;5;210 -FIFO 38;5;126 -FILE 0 -LINK target -MULTIHARDLINK 38;5;222;1 -NORMAL 0 -ORPHAN 48;5;196;38;5;232;1 -OTHER_WRITABLE 38;5;220;1 -SETGID 48;5;3;38;5;0 -SETUID 38;5;220;1;3;100;1 -SOCK 38;5;197 -STICKY 38;5;86;48;5;234 -STICKY_OTHER_WRITABLE 48;5;235;38;5;139;3 - -*LS_COLORS 38;5;89;38;5;197;1;3;4;7 # :-) -# }}} -# documents {{{1 -*README 38;5;220;1 -*README.rst 38;5;220;1 -*README.md 38;5;220;1 -*LICENSE 38;5;220;1 -*COPYING 38;5;220;1 -*INSTALL 38;5;220;1 -*COPYRIGHT 38;5;220;1 -*AUTHORS 38;5;220;1 -*HISTORY 38;5;220;1 -*CONTRIBUTORS 38;5;220;1 -*PATENTS 38;5;220;1 -*VERSION 38;5;220;1 -*NOTICE 38;5;220;1 -*CHANGES 38;5;220;1 -.log 38;5;190 -# plain-text {{{2 -.txt 38;5;253 -# markup {{{2 -.etx 38;5;184 -.info 38;5;184 -.markdown 38;5;184 -.md 38;5;184 -.mkd 38;5;184 -.nfo 38;5;184 -.pod 38;5;184 -.rst 38;5;184 -.tex 38;5;184 -.textile 38;5;184 -# key-value, non-relational data {{{2 -.bib 38;5;178 -.json 38;5;178 -.msg 38;5;178 -.pgn 38;5;178 -.rss 38;5;178 -.xml 38;5;178 -.yaml 38;5;178 -.yml 38;5;178 -.RData 38;5;178 -.rdata 38;5;178 -# }}} -# binary {{{2 -.cbr 38;5;141 -.cbz 38;5;141 -.chm 38;5;141 -.djvu 38;5;141 -.pdf 38;5;141 -.PDF 38;5;141 -.mobi 38;5;141 -.epub 38;5;141 -# words {{{3 -.docm 38;5;111;4 -.doc 38;5;111 -.docx 38;5;111 -.eps 38;5;111 -.ps 38;5;111 -.odb 38;5;111 -.odt 38;5;111 -.rtf 38;5;111 -# presentation {{{3 -.odp 38;5;166 -.pps 38;5;166 -.ppt 38;5;166 -.pptx 38;5;166 -# Powerpoint show -.ppts 38;5;166 -# Powerpoint with enabled macros -.pptxm 38;5;166;4 -# Powerpoint show with enabled macros -.pptsm 38;5;166;4 -# spreadsheet {{{3 -.csv 38;5;78 -# Open document spreadsheet -.ods 38;5;112 -.xla 38;5;76 -# Excel spreadsheet -.xls 38;5;112 -.xlsx 38;5;112 -# Excel spreadsheet with macros -.xlsxm 38;5;112;4 -# Excel module -.xltm 38;5;73;4 -.xltx 38;5;73 -# }}} -# }}} -# configs {{{2 -*cfg 1 -*conf 1 -*rc 1 -.ini 1 -.plist 1 -# vim -.viminfo 1 -# cisco VPN client configuration -.pcf 1 -# }}} -# }}} -# code {{{1 -# version control {{{2 -.git 38;5;197 -.gitignore 38;5;240 -.gitattributes 38;5;240 -.gitmodules 38;5;240 - -# shell {{{2 -.awk 38;5;172 -.bash 38;5;172 -.sed 38;5;172 -.sh 38;5;172 -.zsh 38;5;172 -.vim 38;5;172 - -# interpreted {{{2 -.ahk 38;5;41 -# python -.py 38;5;41 -.ipynb 38;5;41 -# ruby -.rb 38;5;41 -.gemspec 38;5;41 -# perl -.pl 38;5;208 -.PL 38;5;160 -.t 38;5;114 -# sql -.msql 38;5;222 -.mysql 38;5;222 -.pgsql 38;5;222 -.sql 38;5;222 -# Tool Command Language -.tcl 38;5;64;1 -# R language -.r 38;5;49 -.R 38;5;49 -# GrADS script -.gs 38;5;81 -# Clojure -.clj 38;5;41 -.cljs 38;5;41 -.cljc 38;5;41 -# Clojure gorilla REPL worksheet -.cljw 38;5;41 -# Scala -.scala 38;5;41 -# Dart -.dart 38;5;51 - -# compiled {{{2 -# -# assembly language -.asm 38;5;81 -# LISP -.cl 38;5;81 -.lisp 38;5;81 -# lua -.lua 38;5;81 -# Moonscript -.moon 38;5;81 -# C -.c 38;5;81 -.C 38;5;81 -.h 38;5;110 -.H 38;5;110 -.tcc 38;5;110 -# C++ -.c++ 38;5;81 -.h++ 38;5;110 -.hpp 38;5;110 -.hxx 38;5;110 -.ii 38;5;110 -# method file for Objective C -.M 38;5;110 -.m 38;5;110 -# Csharp -.cc 38;5;81 -.cs 38;5;81 -.cp 38;5;81 -.cpp 38;5;81 -.cxx 38;5;81 -# Crystal -.cr 38;5;81 -# Google golang -.go 38;5;81 -# fortran -.f 38;5;81 -.F 38;5;81 -.for 38;5;81 -.ftn 38;5;81 -.f90 38;5;81 -.F90 38;5;81 -.f95 38;5;81 -.F95 38;5;81 -.f03 38;5;81 -.F03 38;5;81 -.f08 38;5;81 -.F08 38;5;81 -# Nim -.nim 38;5;81 -.nimble 38;5;81 -# pascal -.s 38;5;110 -.S 38;5;110 -# Rust -.rs 38;5;81 -# Swift -.swift 38;5;219 -# ? -.sx 38;5;81 -# Vala -.vala 38;5;81 -.vapi 38;5;81 -# interface file in GHC - https://github.com/trapd00r/LS_COLORS/pull/9 -.hi 38;5;110 -# haskell -.hs 38;5;81 -.lhs 38;5;81 - -# binaries {{{2 -# compiled apps for interpreted languages -.pyc 38;5;240 -# }}} -# orchestration {{{2 -.tf 38;5;168 -.tfstate 38;5;168 -.tfvars 38;5;168 -# orchestration 2}}} -# html {{{2 -.css 38;5;125;1 -.less 38;5;125;1 -.sass 38;5;125;1 -.scss 38;5;125;1 -.htm 38;5;125;1 -.html 38;5;125;1 -.jhtm 38;5;125;1 -.mht 38;5;125;1 -.eml 38;5;125;1 -.mustache 38;5;125;1 -# }}} -# java {{{2 -.coffee 38;5;074;1 -.java 38;5;074;1 -.js 38;5;074;1 -.mjs 38;5;074;1 -.jsm 38;5;074;1 -.jsm 38;5;074;1 -.jsp 38;5;074;1 -# }}} -# php {{{2 -.php 38;5;81 -# CakePHP view scripts and helpers -.ctp 38;5;81 -# Twig template engine -.twig 38;5;81 -# }}} -# vb/a {{{2 -.vb 38;5;81 -.vba 38;5;81 -.vbs 38;5;81 -# 2}}} -# Build stuff {{{2 -*Dockerfile 38;5;155 -.dockerignore 38;5;240 -*Makefile 38;5;155 -*MANIFEST 38;5;243 -*pm_to_blib 38;5;240 -# ruby rake -.rake 38;5;155 -# automake -.am 38;5;242 -.in 38;5;242 -.hin 38;5;242 -.scan 38;5;242 -.m4 38;5;242 -.old 38;5;242 -.out 38;5;242 -.SKIP 38;5;244 -# }}} -# patch files {{{2 -.diff 48;5;197;38;5;232 -.patch 48;5;197;38;5;232;1 -#}}} -# graphics {{{1 -.bmp 38;5;97 -.tiff 38;5;97 -.tif 38;5;97 -.TIFF 38;5;97 -.cdr 38;5;97 -.flif 38;5;97 -.gif 38;5;97 -.ico 38;5;97 -.jpeg 38;5;97 -.JPG 38;5;97 -.jpg 38;5;97 -.nth 38;5;97 -.png 38;5;97 -.psd 38;5;97 -.xpm 38;5;97 -.webp 38;5;97 -# }}} -# vector {{{1 -.ai 38;5;99 -.eps 38;5;99 -.epsf 38;5;99 -.drw 38;5;99 -.ps 38;5;99 -.svg 38;5;99 -# }}} -# video {{{1 -.avi 38;5;114 -.divx 38;5;114 -.IFO 38;5;114 -.m2v 38;5;114 -.m4v 38;5;114 -.mkv 38;5;114 -.MOV 38;5;114 -.mov 38;5;114 -.mp4 38;5;114 -.mpeg 38;5;114 -.mpg 38;5;114 -.ogm 38;5;114 -.rmvb 38;5;114 -.sample 38;5;114 -.wmv 38;5;114 - # mobile/streaming {{{2 -.3g2 38;5;115 -.3gp 38;5;115 -.gp3 38;5;115 -.webm 38;5;115 -.gp4 38;5;115 -.asf 38;5;115 -.flv 38;5;115 -.ts 38;5;115 -.ogv 38;5;115 -.f4v 38;5;115 - # }}} - # lossless {{{2 -.VOB 38;5;115;1 -.vob 38;5;115;1 -# }}} -# audio {{{1 -.3ga 38;5;137;1 -.S3M 38;5;137;1 -.aac 38;5;137;1 -.au 38;5;137;1 -.dat 38;5;137;1 -.dts 38;5;137;1 -.fcm 38;5;137;1 -.m4a 38;5;137;1 -.mid 38;5;137;1 -.midi 38;5;137;1 -.mod 38;5;137;1 -.mp3 38;5;137;1 -.mp4a 38;5;137;1 -.oga 38;5;137;1 -.ogg 38;5;137;1 -.opus 38;5;137;1 -.s3m 38;5;137;1 -.sid 38;5;137;1 -.wma 38;5;137;1 -# lossless -.ape 38;5;136;1 -.aiff 38;5;136;1 -.cda 38;5;136;1 -.flac 38;5;136;1 -.alac 38;5;136;1 -.midi 38;5;136;1 -.pcm 38;5;136;1 -.wav 38;5;136;1 -.wv 38;5;136;1 -.wvc 38;5;136;1 - -# }}} -# fonts {{{1 -.afm 38;5;66 -.fon 38;5;66 -.fnt 38;5;66 -.pfb 38;5;66 -.pfm 38;5;66 -.ttf 38;5;66 -.otf 38;5;66 -# postscript fonts -.PFA 38;5;66 -.pfa 38;5;66 -# }}} -# archives {{{1 -.7z 38;5;40 -.a 38;5;40 -.arj 38;5;40 -.bz2 38;5;40 -.cpio 38;5;40 -.gz 38;5;40 -.lrz 38;5;40 -.lz 38;5;40 -.lzma 38;5;40 -.lzo 38;5;40 -.rar 38;5;40 -.s7z 38;5;40 -.sz 38;5;40 -.tar 38;5;40 -.tgz 38;5;40 -.xz 38;5;40 -.z 38;5;40 -.Z 38;5;40 -.zip 38;5;40 -.zipx 38;5;40 -.zoo 38;5;40 -.zpaq 38;5;40 -.zz 38;5;40 - # packaged apps {{{2 -.apk 38;5;215 -.deb 38;5;215 -.rpm 38;5;215 -.jad 38;5;215 -.jar 38;5;215 -.cab 38;5;215 -.pak 38;5;215 -.pk3 38;5;215 -.vdf 38;5;215 -.vpk 38;5;215 -.bsp 38;5;215 -.dmg 38;5;215 - # }}} - # segments from 0 to three digits after first extension letter {{{2 -.r[0-9]{0,2} 38;5;239 -.zx[0-9]{0,2} 38;5;239 -.z[0-9]{0,2} 38;5;239 -# partial files -.part 38;5;239 - # }}} -# partition images {{{2 -.dmg 38;5;124 -.iso 38;5;124 -.bin 38;5;124 -.nrg 38;5;124 -.qcow 38;5;124 -.sparseimage 38;5;124 -.toast 38;5;124 -.vcd 38;5;124 -.vmdk 38;5;124 -# }}} -# databases {{{2 -.accdb 38;5;60 -.accde 38;5;60 -.accdr 38;5;60 -.accdt 38;5;60 -.db 38;5;60 -.fmp12 38;5;60 -.fp7 38;5;60 -.localstorage 38;5;60 -.mdb 38;5;60 -.mde 38;5;60 -.sqlite 38;5;60 -.typelib 38;5;60 -# NetCDF database -.nc 38;5;60 -# }}} -# tempfiles {{{1 -# undo files -.pacnew 38;5;33 -.un~ 38;5;241 -.orig 38;5;241 -# backups -.BUP 38;5;241 -.bak 38;5;241 -.o 38;5;241 # *nix Object file (shared libraries, core dumps etc) -*core 38;5;241 # Linux user core dump file (from /proc/sys/kernel/core_pattern) -.rlib 38;5;241 # Static rust library -# temporary files -.swp 38;5;244 -.swo 38;5;244 -.tmp 38;5;244 -.sassc 38;5;244 -# state files -.pid 38;5;248 -.state 38;5;248 -*lockfile 38;5;248 -*lock 38;5;248 -# error logs -.err 38;5;160;1 -.error 38;5;160;1 -.stderr 38;5;160;1 -# state dumps -.aria2 38;5;241 -.dump 38;5;241 -.stackdump 38;5;241 -.zcompdump 38;5;241 -.zwc 38;5;241 -# tcpdump, network traffic capture -.pcap 38;5;29 -.cap 38;5;29 -.dmp 38;5;29 -# macOS -.DS_Store 38;5;239 -.localized 38;5;239 -.CFUserTextEncoding 38;5;239 -# }}} -# hosts {{{1 -# /etc/hosts.{deny,allow} -.allow 38;5;112 -.deny 38;5;196 -# }}} -# systemd {{{1 -# http://www.freedesktop.org/software/systemd/man/systemd.unit.html -.service 38;5;45 -*@.service 38;5;45 -.socket 38;5;45 -.swap 38;5;45 -.device 38;5;45 -.mount 38;5;45 -.automount 38;5;45 -.target 38;5;45 -.path 38;5;45 -.timer 38;5;45 -.snapshot 38;5;45 -# }}} -# metadata {{{1 -.application 38;5;116 -.cue 38;5;116 -.description 38;5;116 -.directory 38;5;116 -.m3u 38;5;116 -.m3u8 38;5;116 -.md5 38;5;116 -.properties 38;5;116 -.sfv 38;5;116 -.srt 38;5;116 -.sub 38;5;116 -.theme 38;5;116 -.torrent 38;5;116 -.urlview 38;5;116 -# }}} -# encrypted data {{{1 -.asc 38;5;192;3 -.bfe 38;5;192;3 -.enc 38;5;192;3 -.gpg 38;5;192;3 -.signature 38;5;192;3 -.sig 38;5;192;3 -.p12 38;5;192;3 -.pem 38;5;192;3 -.pgp 38;5;192;3 -.asc 38;5;192;3 -.enc 38;5;192;3 -.sig 38;5;192;3 -.p7s 38;5;192;3 -# 1}}} -# emulators {{{1 -.32x 38;5;213 -.cdi 38;5;213 -.fm2 38;5;213 -.rom 38;5;213 -.sav 38;5;213 -.st 38;5;213 - # atari -.a00 38;5;213 -.a52 38;5;213 -.A64 38;5;213 -.a64 38;5;213 -.a78 38;5;213 -.adf 38;5;213 -.atr 38;5;213 - # nintendo -.gb 38;5;213 -.gba 38;5;213 -.gbc 38;5;213 -.gel 38;5;213 -.gg 38;5;213 -.ggl 38;5;213 -.ipk 38;5;213 # Nintendo (DS Packed Images) -.j64 38;5;213 -.nds 38;5;213 -.nes 38;5;213 - # Sega -.sms 38;5;213 -# }}} -# unsorted {{{1 -# -# Portable Object Translation for GNU Gettext -.pot 38;5;7 -# CAD files for printed circuit boards -.pcb 38;5;7 -# groff (rendering app for texinfo) -.mm 38;5;7 -# perldoc -.pod 38;5;7 -# GIMP files -.gbr 38;5;7 -.scm 38;5;7 -.xcf 38;5;7 -# printer spool file -.spl 38;5;7 -# RStudio project file -.Rproj 38;5;11 -# Nokia Symbian OS files -.sis 38;5;7 - -.1p 38;5;7 -.3p 38;5;7 -.cnc 38;5;7 -.def 38;5;7 -.ex 38;5;7 -.example 38;5;7 -.feature 38;5;7 -.ger 38;5;7 -.map 38;5;7 -.mf 38;5;7 -.mfasl 38;5;7 -.mi 38;5;7 -.mtx 38;5;7 -.pc 38;5;7 -.pi 38;5;7 -.plt 38;5;7 -.pm 38;5;7 -.rdf 38;5;7 -.ru 38;5;7 -.sch 38;5;7 -.sty 38;5;7 -.sug 38;5;7 -.t 38;5;7 -.tdy 38;5;7 -.tfm 38;5;7 -.tfnt 38;5;7 -.tg 38;5;7 -.vcard 38;5;7 -.vcf 38;5;7 -.xln 38;5;7 -# AppCode files -.iml 38;5;166 -# Xcode files -.xcconfig 1 -.entitlements 1 -.strings 1 -.storyboard 38;5;196 -.xcsettings 1 -.xib 38;5;208 -# }}} -# termcap {{{1 -TERM ansi -TERM color-xterm -TERM con132x25 -TERM con132x30 -TERM con132x43 -TERM con132x60 -TERM con80x25 -TERM con80x28 -TERM con80x30 -TERM con80x43 -TERM con80x50 -TERM con80x60 -TERM cons25 -TERM console -TERM cygwin -TERM dtterm -TERM Eterm -TERM eterm-color -TERM gnome -TERM gnome-256color -TERM jfbterm -TERM konsole -TERM kterm -TERM linux -TERM linux-c -TERM mach-color -TERM mlterm -TERM putty -TERM rxvt -TERM rxvt-256color -TERM rxvt-cygwin -TERM rxvt-cygwin-native -TERM rxvt-unicode -TERM rxvt-unicode-256color -TERM rxvt-unicode256 -TERM screen -TERM screen-256color -TERM screen-256color-bce -TERM screen-bce -TERM screen-w -TERM screen.linux -TERM screen.rxvt -TERM terminator -TERM vt100 -TERM xterm -TERM xterm-16color -TERM xterm-256color -TERM xterm-88color -TERM xterm-color -TERM xterm-debian -TERM xterm-kitty -# }}} - -# vim: ft=dircolors:fdm=marker:et:sw=2: diff --git a/.dircolors-catpuccin b/.dircolors-catpuccin deleted file mode 100644 index ca467d1..0000000 --- a/.dircolors-catpuccin +++ /dev/null @@ -1,32 +0,0 @@ -# ~/.catppuccin-mocho.dircolors - -# File types -di 38;5;117 # directory = sky blue -ln 38;5;153 # symlink = lavender -so 38;5;217 # socket = flamingo -pi 38;5;229 # pipe = yellow -ex 38;5;114 # executable = green -bd 38;5;174 # block special = maroon -cd 38;5;174 # character special = maroon -su 38;5;204 # setuid file = red -sg 38;5;204 # setgid file = red -tw 38;5;204 # sticky other writable = red -ow 38;5;204 # other writable = red -st 38;5;204 # sticky = red -mi 38;5;204 # missing file = red -or 38;5;204 # orphaned symlink = red - -# Extensions -*.rs 38;5;153 # Rust files = lavender -*.py 38;5;153 # Python files = lavender -*.sh 38;5;114 # Shell scripts = green -*.toml 38;5;229 # TOML = yellow -*.yaml 38;5;229 # YAML = yellow -*.yml 38;5;229 # YAML = yellow -*.md 38;5;218 # Markdown = pink -*.txt 38;5;218 # Text = pink -*.log 38;5;229 # Logs = yellow -*.json 38;5;229 # JSON = yellow - -# Special cases -Makefile 38;5;216 diff --git a/.gitconfig b/.gitconfig deleted file mode 100644 index 30a4f90..0000000 --- a/.gitconfig +++ /dev/null @@ -1,19 +0,0 @@ -[user] - name=Jean-Michel Bouchard - email=jim@polarcoordinates.org -[github] - user=woud420 -[color] - ui = auto -[alias] - st = status -sb - lg = log --stat - diff-master = !echo "diff master...origin/master:" && git diff master...origin/master --stat && echo "" && echo "diff origin/master...master:" && git diff origin/master...master --stat - - cm = commit -m - ca = commit --amend - rb = !git fetch && git rebase && git st - cl = !git reset --hard && git clean -df && git st - - up = !git submodule update --init && git st - submodules-to-master = submodule foreach "git fetch && git checkout master && git rebase" diff --git a/.github/workflows/test-install.yml b/.github/workflows/test-install.yml new file mode 100644 index 0000000..3278ff7 --- /dev/null +++ b/.github/workflows/test-install.yml @@ -0,0 +1,335 @@ +name: Test install.sh + +on: + push: + branches: [master, "feature/*", "fix/*", "converge/*"] + pull_request: + branches: [master] + +jobs: + # Fast syntax/parse checks that don't need install.sh + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Shell syntax check (bash -n) + run: | + echo "=== Checking shell configs ===" + bash -n common/shell/.bashrc && echo "PASS: .bashrc" + bash -n common/shell/.bashrc.server && echo "PASS: .bashrc.server" + + echo "=== Checking shell functions ===" + fail=0 + for f in common/shell-functions/*.sh; do + bash -n "$f" && echo "PASS: $(basename $f)" || { echo "FAIL: $(basename $f)"; fail=1; } + done + + echo "=== Checking scripts ===" + for f in scripts/*.sh; do + bash -n "$f" && echo "PASS: $(basename $f)" || { echo "FAIL: $(basename $f)"; fail=1; } + done + exit $fail + + - name: Zsh syntax check + run: | + sudo apt-get update && sudo apt-get install -y zsh + zsh -n common/shell/.zshrc && echo "PASS: .zshrc" + + - name: ShellCheck + uses: ludeeus/action-shellcheck@master + with: + scandir: ./common/shell-functions + severity: error + + - name: Git config parse check + run: | + git config --file common/git/.gitconfig --list > /dev/null + echo "PASS: .gitconfig parses ($(git config --file common/git/.gitconfig --get-regexp '^alias\.' | wc -l) aliases found)" + + - name: Vim CoC settings JSON validation + run: | + python3 -c "import json; json.load(open('.vim/coc-settings.json'))" && echo "PASS: coc-settings.json" + + - name: install.sh syntax check + run: | + bash -n install.sh && echo "PASS: install.sh" + + - name: Installer smoke test (temp HOME) + run: ./scripts/test-install.sh + + test-arch: + runs-on: ubuntu-latest + needs: lint + container: + image: archlinux:latest + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + pacman -Syu --noconfirm + pacman -S --noconfirm base-devel git zsh vim fzf sudo kitty \ + ttf-firacode-nerd python nodejs npm curl + + - name: Create test user + run: | + useradd -m -s /bin/zsh testuser + echo "testuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + + - name: Run install.sh + shell: bash + run: | + cp -r "$GITHUB_WORKSPACE" /home/testuser/dotfiles + chown -R testuser:testuser /home/testuser/dotfiles + su testuser -c "cd /home/testuser/dotfiles && DOTFILES_FULL_INSTALL=1 ./install.sh --no-packages 2>&1" | tee /tmp/install.log + + - name: Verify file deployments (copies, never symlinks) + run: | + su testuser -c ' + set -e + echo "=== Copied configs ===" + for f in .bashrc .zshrc .bash_profile .gitconfig .gnu_aliases .dircolors; do + test -f ~/$f && ! test -L ~/$f && echo "PASS: $f (copied)" || { echo "FAIL: $f"; exit 1; } + done + for f in .vim/vimrc .vim/plugins.vim .vim/mappings.vim .vim/settings.vim; do + test -f ~/$f && ! test -L ~/$f && echo "PASS: $f (copied)" || { echo "FAIL: $f"; exit 1; } + done + ls ~/.config/shell-functions/*.sh > /dev/null && echo "PASS: shell-functions deployed" + + echo "=== Kitty ===" + test -f ~/.config/kitty/kitty.conf && echo "PASS: kitty.conf" + test -f ~/.config/kitty/current-theme.conf && echo "PASS: current-theme.conf" + + echo "=== Arch desktop configs ===" + for f in .config/sway/config .config/waybar/config .config/gtk-3.0/settings.ini .config/gtk-4.0/settings.ini; do + test -f ~/$f && echo "PASS: $f" || { echo "FAIL: $f"; exit 1; } + done + + echo "=== AI context ===" + test -f ~/AGENTS.md && echo "PASS: AGENTS.md" + test -f ~/MACHINE.md && echo "PASS: MACHINE.md" + + echo "=== Audit log ===" + ls ~/.dotfiles-backup-*/install-audit.tsv > /dev/null && echo "PASS: install audit written" + ' + + - name: Validate Kitty config (headless parse) + run: | + su testuser -c ' + kitty +runpy " + import sys + from kitty.config import load_config + bad = [] + opts = load_config(\"$HOME/.config/kitty/kitty.conf\", accumulate_bad_lines=bad) + if bad: + for b in bad: + print(f\"ERROR line {b.number}: {b.line!r} -> {b.exception}\") + sys.exit(1) + print(f\"PASS: kitty.conf parsed\") + print(f\" font_family: {opts.font_family}\") + " + ' + + - name: Verify Arch kitty theme is personal-pink overlay + run: | + su testuser -c ' + grep -q "personal-pink" ~/.config/kitty/current-theme.conf && echo "PASS: personal-pink overlay applied" || { echo "FAIL: personal-pink marker missing"; exit 1; } + grep -qi "background[^_]*#2A1E2E" ~/.config/kitty/current-theme.conf && echo "PASS: plum background" || { echo "FAIL: expected #2A1E2E background"; exit 1; } + ' + + - name: Verify font installed and resolved + run: | + fc-list -q "FiraCode Nerd Font" && echo "PASS: FiraCode Nerd Font installed" || { echo "FAIL: font not found"; exit 1; } + + - name: Validate Vim config (headless load) + run: | + su testuser -c ' + curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ + https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + + output=$(vim -e -N -u ~/.vim/vimrc --not-a-term -c "qa!" 2>&1) + rc=$? + if [ $rc -eq 0 ]; then + echo "PASS: vimrc loaded without errors" + else + echo "FAIL: vimrc load errors:" + echo "$output" + exit 1 + fi + ' + + - name: Validate git config + run: | + su testuser -c ' + git config --file ~/.gitconfig --list > /dev/null 2>&1 && echo "PASS: .gitconfig" || { echo "FAIL: .gitconfig"; exit 1; } + echo " $(git config --file ~/.gitconfig --get-regexp "^alias\." | wc -l) git aliases loaded" + ' + + - name: Collect evidence + if: always() + run: | + mkdir -p /tmp/evidence + chmod 777 /tmp/evidence + cp /tmp/install.log /tmp/evidence/ 2>/dev/null || true + su testuser -c ' + ls -la ~/.bashrc ~/.zshrc ~/.gitconfig 2>&1 > /tmp/evidence/report.txt + head -10 ~/.config/kitty/current-theme.conf >> /tmp/evidence/report.txt 2>&1 + ls ~/.config/sway ~/.config/waybar >> /tmp/evidence/report.txt 2>&1 + ' + + - name: Upload evidence + if: always() + uses: actions/upload-artifact@v4 + with: + name: evidence-arch + path: /tmp/evidence/ + + test-debian: + runs-on: ubuntu-latest + needs: lint + container: + image: debian:bookworm + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + apt-get update + apt-get install -y git zsh vim sudo curl python3 fontconfig + + - name: Create test user + run: | + useradd -m -s /bin/zsh testuser + echo "testuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + + - name: Run install.sh + shell: bash + run: | + cp -r "$GITHUB_WORKSPACE" /home/testuser/dotfiles + chown -R testuser:testuser /home/testuser/dotfiles + su testuser -c "cd /home/testuser/dotfiles && DOTFILES_FULL_INSTALL=1 ./install.sh --no-packages 2>&1" | tee /tmp/install.log + + - name: Verify file deployments (copies, never symlinks) + run: | + su testuser -c ' + set -e + for f in .bashrc .zshrc .gitconfig .gnu_aliases .dircolors; do + test -f ~/$f && ! test -L ~/$f && echo "PASS: $f (copied)" || { echo "FAIL: $f"; exit 1; } + done + + echo "=== Kitty ===" + test -f ~/.config/kitty/kitty.conf && echo "PASS: kitty.conf" + test -f ~/.config/kitty/current-theme.conf && echo "PASS: current-theme.conf" + grep -q "Catppuccin-Mocha" ~/.config/kitty/current-theme.conf && echo "PASS: Catppuccin Mocha theme" + ! grep -q "personal-pink" ~/.config/kitty/current-theme.conf && echo "PASS: no personal-pink leak on non-arch" + + echo "=== No desktop configs on non-arch ===" + ! test -e ~/.config/sway && echo "PASS: sway config not installed" + + echo "=== AI context ===" + test -f ~/AGENTS.md && echo "PASS: AGENTS.md" + test -f ~/MACHINE.md && echo "PASS: MACHINE.md" + ' + + - name: Validate shell configs + run: | + su testuser -c ' + bash -n ~/.bashrc && echo "PASS: .bashrc syntax" + zsh -n ~/.zshrc && echo "PASS: .zshrc syntax" + for f in ~/.config/shell-functions/*.sh; do + bash -n "$f" && echo "PASS: $(basename $f)" || { echo "FAIL: $(basename $f)"; exit 1; } + done + ' + + - name: Validate Vim config + run: | + su testuser -c ' + curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ + https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + vim -e -N -u ~/.vim/vimrc --not-a-term -c "qa!" 2>&1 + [ $? -eq 0 ] && echo "PASS: vimrc loaded" || { echo "FAIL: vimrc errors"; exit 1; } + ' + + - name: Validate git config + run: | + su testuser -c ' + git config --file ~/.gitconfig --list > /dev/null 2>&1 && echo "PASS: .gitconfig" || { echo "FAIL"; exit 1; } + ' + + - name: Collect evidence + if: always() + run: | + mkdir -p /tmp/evidence + chmod 777 /tmp/evidence + cp /tmp/install.log /tmp/evidence/ 2>/dev/null || true + su testuser -c ' + ls -la ~/.bashrc ~/.zshrc ~/.gitconfig 2>&1 > /tmp/evidence/report.txt + head -10 ~/.config/kitty/current-theme.conf >> /tmp/evidence/report.txt 2>&1 + ' + + - name: Upload evidence + if: always() + uses: actions/upload-artifact@v4 + with: + name: evidence-debian + path: /tmp/evidence/ + + test-macos: + runs-on: macos-latest + needs: lint + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: brew install vim + + - name: Run install.sh + shell: bash + run: | + ./install.sh --no-packages 2>&1 | tee /tmp/install.log + + - name: Verify file deployments (copies, never symlinks) + run: | + set -e + for f in .bashrc .zshrc .gitconfig .gnu_aliases .dircolors; do + test -f ~/$f && ! test -L ~/$f && echo "PASS: $f (copied)" || { echo "FAIL: $f"; exit 1; } + done + + echo "=== Kitty ===" + test -f ~/.config/kitty/kitty.conf && echo "PASS: kitty.conf" + test -f ~/.config/kitty/current-theme.conf && echo "PASS: current-theme.conf" + grep -q "Catppuccin-Mocha" ~/.config/kitty/current-theme.conf && echo "PASS: macOS Catppuccin Mocha theme" + ! grep -q "personal-pink" ~/.config/kitty/current-theme.conf && echo "PASS: no personal-pink leak on macOS" + grep -q "FiraCode" ~/.config/kitty/kitty.conf && echo "PASS: FiraCode font (macOS)" + + echo "=== AI context ===" + test -f ~/AGENTS.md && echo "PASS: AGENTS.md" + test -f ~/MACHINE.md && echo "PASS: MACHINE.md" + + - name: Validate Vim config + run: | + curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ + https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + output=$(vim -e -N -u ~/.vim/vimrc --not-a-term -c "qa!" 2>&1) + [ $? -eq 0 ] && echo "PASS: vimrc loaded" || { echo "FAIL: $output"; exit 1; } + + - name: Validate git config + run: | + git config --file ~/.gitconfig --list > /dev/null 2>&1 && echo "PASS: .gitconfig" || { echo "FAIL"; exit 1; } + echo " $(git config --file ~/.gitconfig --get-regexp '^alias\.' | wc -l) git aliases loaded" + + - name: Collect evidence + if: always() + run: | + mkdir -p /tmp/evidence + cp /tmp/install.log /tmp/evidence/ 2>/dev/null || true + ls -la ~/.bashrc ~/.zshrc ~/.gitconfig > /tmp/evidence/report.txt 2>&1 + head -10 ~/.config/kitty/current-theme.conf >> /tmp/evidence/report.txt 2>&1 + + - name: Upload evidence + if: always() + uses: actions/upload-artifact@v4 + with: + name: evidence-macos + path: /tmp/evidence/ diff --git a/.gitignore b/.gitignore index dde2be2..63936bb 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,6 @@ __pycache__/ .DS_Store # Cursor generated configuration -.config/cursor/generated/ + +# Generated AI context (machine-specific, not versioned) +**/ai-context/machine-state.md diff --git a/.tmux.conf b/.tmux.conf deleted file mode 100644 index a952ebb..0000000 --- a/.tmux.conf +++ /dev/null @@ -1,213 +0,0 @@ -# Set prefix key to c-f instead of default c-b -unbind C-b -set -g prefix C-f -bind C-f send-prefix - -# toogle last window by hitting again C-f -bind-key C-f last-window - -# if multiple clients are attached to the same window, maximize it to the -# bigger one -set-window-option -g aggressive-resize - -# Start windows and pane numbering with index 1 instead of 0 -set -g base-index 1 -setw -g pane-base-index 1 - -# re-number windows when one is closed -set -g renumber-windows on - -# word separators for automatic word selection -setw -g word-separators ' @"=()[]_-:,.' -setw -ag word-separators "'" - -# Show times longer than supposed -set -g display-panes-time 2000 - -# tmux messages are displayed for 4 seconds -set -g display-time 4000 - -# Split horiziontal and vertical splits, instead of % and " -# Also open them in the same directory -bind-key v split-window -h -c '#{pane_current_path}' -bind-key s split-window -v -c '#{pane_current_path}' - -# Pressing Ctrl+Shift+Left (will move the current window to the left. Similarly -# right. No need to use the modifier (C-b). -#bind-key -n C-S-Left swap-window -t -1 -#bind-key -n C-S-Right swap-window -t +1 - -bind-key -n C-S-Left swap-window -t -1 -bind-key -n C-S-Right swap-window -t +1 - -# Source file -unbind r -bind r source-file ~/.tmux.conf \; display "Reloaded!" - -# Use vim keybindings in copy mode -setw -g mode-keys vi - -# Update default binding of `Enter` and `Space to also use copy-pipe -unbind -T copy-mode-vi Enter -unbind -T copy-mode-vi Space - -bind-key -T edit-mode-vi Up send-keys -X history-up -bind-key -T edit-mode-vi Down send-keys -X history-down - -# setup 'v' to begin selection as in Vim -bind-key -T copy-mode-vi 'v' send-keys -X begin-selection - -# copy text with `y` in copy mode -# bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel\; run "tmux save -|pbcopy >/dev/null 2>&1" -bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel - -# copy text with mouse selection without pressing any key -bind-key -T copy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel\; run "tmux save -|pbcopy >/dev/null 2>&1" -# bind-key -T copy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel - -# focus events enabled for terminals that support them -set -g focus-events on - -# Sync panes (Send input to all panes in the window). When enabled, pane -# borders become red as an indication. -bind C-s if -F '#{pane_synchronized}' \ - 'setw synchronize-panes off; \ - setw pane-active-border-style fg=colour63,bg=default; \ - setw pane-border-format " #P "' \ - 'setw synchronize-panes on; \ - setw pane-active-border-style fg=red; \ - setw pane-border-format " #P - Pane Synchronization ON "' - -# Faster command sequence -set -s escape-time 0 - -# Have a very large history -set -g history-limit 1000000 - -# Mouse mode on -set -g terminal-overrides 'xterm*:smcup@:rmcup@' -set -g mouse on - -# Set title -set -g set-titles on -set -g set-titles-string "#T" - -# Equally resize all panes -bind-key = select-layout even-horizontal -bind-key | select-layout even-vertical - -# Resize panes -bind-key J resize-pane -D 10 -bind-key K resize-pane -U 10 -bind-key H resize-pane -L 10 -bind-key L resize-pane -R 10 - -# Select panes -# NOTE(arslan): See to prevent cycling https://github.com/tmux/tmux/issues/1158 -bind-key j select-pane -D -bind-key k select-pane -U -bind-key h select-pane -L -bind-key l select-pane -R - -# Disable confirm before killing -bind-key x kill-pane - -# This tmux statusbar config was created by tmuxline.vim -# on Wed, 25 Nov 2015 -set -g status "on" -set -g status-bg "colour236" -set -g status-justify "left" -set -g status-position "bottom" -set -g status-left-length "100" -set -g status-left-style "none" -set -g status-right-length "100" -set -g status-style "none" -set -g status-left "#{prefix_highlight}#[fg=colour22,bg=colour148,bold] #S #[fg=colour148,bg=colour236,nobold,nounderscore,noitalics]" -set -g status-right "#[fg=colour240,bg=colour236,nobold,nounderscore,noitalics]#[fg=colour250,bg=colour240] %Y-%m-%d %H:%M #[fg=colour252,bg=colour240,nobold,nounderscore,noitalics]#[fg=colour241,bg=colour252] #h " - -set -g pane-active-border-style "fg=colour148" -set -g pane-border-style "fg=colour240" - -set -g message-command-style "fg=colour231" -set -g message-style "bg=colour240,fg=colour231" -set -g message-command-style "bg=colour240" - -setw -g window-status-style "fg=colour245" -setw -g window-status-style "none" -setw -g window-status-activity-style "bg=colour236" -setw -g window-status-activity-style "none" -setw -g window-status-activity-style "fg=colour148" -setw -g window-status-separator "" -setw -g window-status-style "bg=colour236" -setw -g window-status-format "#[fg=colour245,bg=colour236] #I #[fg=colour245,bg=colour236]#W " -setw -g window-status-current-format "#[fg=colour236,bg=colour240,nobold,nounderscore,noitalics]#[fg=colour231,bg=colour240] #I #[fg=colour231,bg=colour240]#{?window_zoomed_flag,#[fg=green][],}#W #[fg=colour240,bg=colour236,nobold,nounderscore,noitalics]" - -# List of plugins -# see this https://github.com/tmux-plugins/tpm to installation -set -g @plugin 'tmux-plugins/tpm' -set -g @plugin 'tmux-plugins/tmux-open' -set -g @plugin 'tmux-plugins/tmux-yank' -set -g @plugin 'tmux-plugins/tmux-prefix-highlight' - -# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) -run '~/.tmux/plugins/tpm/tpm' - -######## Alacritty + Tmux key integration ######### -# First of all, Alacritty can send hex codes for shortcuts you define. So for -# example you can send a hex code for the shortcut "c-f v" which in my case -# opens a vertical pane (see setting above). The hex code for this combination -# is: 0x06 0x76. There are many cases to find it out. One of them is the tool -# 'xxd' - -# If you run "xxd -psd" and hit "c-f v" and then enter and finally c-c to exit -# , it outputs the following: -# -# $ xxd -psd -# ^Fv -# 06760a^C -# -# What matters is the sequence 06760a^C where: -# -# 06 -> c-f -# 76 -> v -# 0a -> return -# ^C -> c-c -# -# From here, we know that 0x06 0x76 corresponds to "c-f v". -# -# Next step is to add a line to 'key_binding' setting in Alacritty: -# -# - { key: D, mods: Command, chars: "\x06\x76" } -# -# That's it! The followings are the ones that I'm using: -# -# key_bindings: -# - { key: D, mods: Command, chars: "\x06\x76" } -# - { key: D, mods: Command|Shift, chars: "\x06\x73" } -# - { key: W, mods: Command, chars: "\x06\x78" } -# - { key: H, mods: Command, chars: "\x06\x68" } -# - { key: J, mods: Command, chars: "\x06\x6a" } -# - { key: K, mods: Command, chars: "\x06\x6b" } -# - { key: L, mods: Command, chars: "\x06\x6c" } -# - { key: T, mods: Command, chars: "\x06\x63" } -# - { key: Key1, mods: Command, chars: "\x06\x31" } -# - { key: Key2, mods: Command, chars: "\x06\x32" } -# - { key: Key3, mods: Command, chars: "\x06\x33" } -# - { key: Key4, mods: Command, chars: "\x06\x34" } -# - { key: Key5, mods: Command, chars: "\x06\x35" } -# - { key: Key6, mods: Command, chars: "\x06\x36" } -# - { key: Key7, mods: Command, chars: "\x06\x37" } -# - { key: Key8, mods: Command, chars: "\x06\x38" } -# - { key: Key9, mods: Command, chars: "\x06\x39" } -# - { key: Left, mods: Command, chars: "\x06\x48" } -# - { key: Down, mods: Command, chars: "\x06\x4a" } -# - { key: Up, mods: Command, chars: "\x06\x4b" } -# - { key: Right, mods: Command, chars: "\x06\x4c" } -# -# Finally, inside the iTerm2 Key settings, I'm adding just various shortcuts, -# such as cmd-j, cmd-left, etc.. , select the option "send hex code" and the -# enter the hex code which I want to be executed, hence the tmux sequence. So -# when I press CMD + d in iterm, I send the sequence 0x06 0x76, -# which tmux inteprets it as opening a new pane. -############################################### - diff --git a/.vim/coc-settings.json b/.vim/coc-settings.json index bbdf511..aa9f1bc 100644 --- a/.vim/coc-settings.json +++ b/.vim/coc-settings.json @@ -42,4 +42,4 @@ "coc.preferences.formatOnSaveFiletypes": ["python", "javascript", "typescript", "json", "jsonc", "yaml", "rust"], "coc.preferences.colorSupport": true -} \ No newline at end of file +} diff --git a/.vim/plugins.vim b/.vim/plugins.vim index 85baf33..99140bd 100644 --- a/.vim/plugins.vim +++ b/.vim/plugins.vim @@ -8,7 +8,7 @@ endif call plug#begin('~/.vim/plugged') " Polyglot configuration (must be before plugin load) -let g:polyglot_disabled = ['csv'] +let g:polyglot_disabled = ['csv', 'typescript'] " disable heavy yats TS syntax " UI Enhancements Plug 'vim-airline/vim-airline' @@ -21,6 +21,13 @@ Plug 'junegunn/fzf.vim' " Syntax & Language Support Plug 'sheerun/vim-polyglot' +" Lightweight TypeScript/TSX syntax to avoid polyglot/yats slowness on larger files +Plug 'leafgarland/typescript-vim' +Plug 'peitalin/vim-jsx-typescript' Plug 'neoclide/coc.nvim', {'branch': 'release'} +if has('nvim') + Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'} +endif + call plug#end() diff --git a/.vim/settings/appearance.vim b/.vim/settings/appearance.vim index 7ebdcd4..59df65a 100644 --- a/.vim/settings/appearance.vim +++ b/.vim/settings/appearance.vim @@ -6,7 +6,7 @@ set laststatus=2 " Catppuccin theme settings let g:catppuccin_flavour = 'mocha' " latte, frappe, macchiato, mocha -colorscheme catppuccin_mocha +silent! colorscheme catppuccin_mocha " let g:airline_extensions = ['branch'] " let g:airline_extensions = ['branch', 'hunks', 'whitespace'] diff --git a/.vim/settings/coc-settings.vim b/.vim/settings/coc-settings.vim index 9691088..2ae9d73 100644 --- a/.vim/settings/coc-settings.vim +++ b/.vim/settings/coc-settings.vim @@ -82,4 +82,4 @@ nnoremap p :CocListResume " Additional useful commands command! -nargs=0 Format :call CocActionAsync('format') -command! -nargs=0 OR :call CocActionAsync('runCommand', 'editor.action.organizeImport') \ No newline at end of file +command! -nargs=0 OR :call CocActionAsync('runCommand', 'editor.action.organizeImport') diff --git a/.vim/settings/fzf-settings.vim b/.vim/settings/fzf-settings.vim index b6e2166..21fb14d 100644 --- a/.vim/settings/fzf-settings.vim +++ b/.vim/settings/fzf-settings.vim @@ -58,7 +58,7 @@ nnoremap g :RG nnoremap G :RG nnoremap / :Lines -" Vim operations +" Vim operations nnoremap c :call FzfCommands() nnoremap h :Helptags nnoremap m :Marks @@ -102,13 +102,13 @@ function! RipgrepFzf(query, fullscreen) " - Binary file exclusions from g:rg_binary_extensions " - Pipe through awk to shorten paths (keep last 2 components) let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case --binary -g "!*.{' . g:rg_binary_extensions . '}" -- %s | awk -F: ''{split($1,a,"/"); if(length(a)>2) $1="[..]/"a[length(a)-1]"/"a[length(a)]; else $1=$1; printf "%%s:%%s:%%s:%%s\n", $1, $2, $3, substr($0,index($0,$4))}'' || true' - + " Start with empty results let initial_command = 'echo ""' - + " Only run ripgrep when query is non-empty let reload_command = 'if [ -n "{q}" ]; then ' . printf(command_fmt, '{q}') . '; else echo ""; fi' - + " FZF options: " --phony: Don't run initial command on every keystroke " --bind change:reload: Re-run command when input changes @@ -179,4 +179,4 @@ function! s:execute_command_directly(cmd) catch echo "Command failed: " . cmd endtry -endfunction \ No newline at end of file +endfunction diff --git a/.vim/settings/keybindings.vim b/.vim/settings/keybindings.vim index 06780f6..05605e9 100644 --- a/.vim/settings/keybindings.vim +++ b/.vim/settings/keybindings.vim @@ -1,3 +1,3 @@ " ===== Leader Key Configuration ===== " Set leader key to space for easy access -let mapleader = " " \ No newline at end of file +let mapleader = " " diff --git a/.vim/settings/performance.vim b/.vim/settings/performance.vim index c32bd59..c0f3c9a 100644 --- a/.vim/settings/performance.vim +++ b/.vim/settings/performance.vim @@ -3,7 +3,9 @@ " Display performance set lazyredraw " Don't redraw screen during macros/scripts -set ttyfast " Indicates fast terminal connection +if exists('+ttyfast') + set ttyfast " Indicates fast terminal connection +endif set scrolljump=5 " Jump 5 lines when cursor moves off screen set sidescroll=1 " Minimal horizontal scrolling @@ -25,4 +27,4 @@ set noswapfile " Disable swap files (use version control instead) " Note: nobackup and nowritebackup are set in settings.vim for CoC " CoC performance optimization -let g:coc_disable_startup_warning = 1 " Skip CoC startup warnings \ No newline at end of file +let g:coc_disable_startup_warning = 1 " Skip CoC startup warnings diff --git a/.vim/settings/treesitter.vim b/.vim/settings/treesitter.vim new file mode 100644 index 0000000..df3950b --- /dev/null +++ b/.vim/settings/treesitter.vim @@ -0,0 +1,43 @@ +" ===== Neovim Tree-sitter Configuration ===== +" Phase 1 keeps Vimscript as the main configuration language while adding +" Neovim's parser-based highlighting where available. + +if !has('nvim') + finish +endif + +lua << EOF +local ok, configs = pcall(require, "nvim-treesitter.configs") +if not ok then + return +end + +configs.setup({ + ensure_installed = { + "bash", + "css", + "dockerfile", + "go", + "html", + "javascript", + "json", + "lua", + "markdown", + "python", + "rust", + "terraform", + "toml", + "tsx", + "typescript", + "vim", + "yaml", + }, + highlight = { + enable = true, + additional_vim_regex_highlighting = false, + }, + indent = { + enable = true, + }, +}) +EOF diff --git a/.vim/settings/ui-features.vim b/.vim/settings/ui-features.vim new file mode 100644 index 0000000..82d8720 --- /dev/null +++ b/.vim/settings/ui-features.vim @@ -0,0 +1,162 @@ +" ===== Custom UI Features ===== +" This file contains custom UI enhancements like floating windows and popups + +" Define custom highlight groups for popups (Catppuccin Mocha inspired) +augroup PopupHighlights + autocmd! + " Main popup background - darker for contrast + autocmd ColorScheme * highlight RegisterPopup guibg=#1e1e2e guifg=#cdd6f4 ctermbg=234 ctermfg=252 + " Border - subtle blue accent + autocmd ColorScheme * highlight RegisterPopupBorder guibg=#313244 guifg=#89b4fa ctermbg=236 ctermfg=117 + " Alternative styles you can try: + " Darker with green accent: + " autocmd ColorScheme * highlight RegisterPopup guibg=#11111b guifg=#a6e3a1 + " autocmd ColorScheme * highlight RegisterPopupBorder guifg=#a6e3a1 + " Purple accent: + " autocmd ColorScheme * highlight RegisterPopup guibg=#181825 guifg=#cba6f7 + " autocmd ColorScheme * highlight RegisterPopupBorder guifg=#cba6f7 +augroup END + +" Show registers in a floating window (upper right corner) +" Requires Vim 8.2+ with popup support +function! ShowRegistersPopup() + " Check if popups are supported + if !has('popupwin') + echo "Popup windows require Vim 8.2+" + return + endif + + " Get register contents + let reg_output = execute('registers') + let reg_lines = split(reg_output, '\n') + + " Create custom highlight groups for the popup + highlight RegisterPopup guibg=#1e1e2e guifg=#cdd6f4 ctermbg=234 ctermfg=252 + highlight RegisterPopupBorder guibg=#313244 guifg=#89b4fa ctermbg=236 ctermfg=117 + + " Create popup in upper right corner + let popup_id = popup_create(reg_lines, { + \ 'pos': 'topright', + \ 'line': 1, + \ 'col': &columns - 2, + \ 'minwidth': 30, + \ 'maxwidth': 40, + \ 'maxheight': 15, + \ 'border': [1, 1, 1, 1], + \ 'borderchars': ['─', '│', '─', '│', '╭', '╮', '╯', '╰'], + \ 'title': ' 📋 Registers ', + \ 'close': 'click', + \ 'padding': [1, 2, 1, 2], + \ 'highlight': 'RegisterPopup', + \ 'borderhighlight': ['RegisterPopupBorder'], + \ 'scrollbar': 1, + \ 'mapping': 0, + \ 'time': 10000, + \ 'moved': 'any' + \ }) + + " Allow closing with Esc + call popup_filter_menu(popup_id, 'ShowRegistersFilter') +endfunction + +" Filter function to handle Esc key +function! ShowRegistersFilter(id, key) + if a:key == "\" + call popup_close(a:id) + return 1 + endif + return 0 +endfunction + +" Alternative: Show registers in a preview window (works in older Vim) +function! ShowRegistersPreview() + " Save current window + let curr_win = winnr() + + " Create small window in upper right + topleft 10vnew + wincmd L + vertical resize 35 + + " Set window properties + setlocal previewwindow + setlocal buftype=nofile + setlocal bufhidden=delete + setlocal noswapfile + setlocal nowrap + setlocal nonumber + setlocal norelativenumber + + " Insert register content + put =execute('registers') + normal! gg + + " Map q and Esc to close + nnoremap q :close + nnoremap :close + + " Return to original window + execute curr_win . 'wincmd w' +endfunction + +" ===== Key Mappings ===== + +" Show registers popup +nnoremap r :call ShowRegistersPopup() + +" Quick register access with visual feedback +" Shows registers when pressing " in normal mode +" (uncomment if you want this behavior) +" nnoremap " :call ShowRegistersPopup()" + +" ===== Additional UI Features ===== + +" Show marks in a floating window +function! ShowMarksPopup() + if !has('popupwin') + echo "Popup windows require Vim 8.2+" + return + endif + + let marks_output = execute('marks') + let marks_lines = split(marks_output, '\n') + + call popup_create(marks_lines, { + \ 'pos': 'center', + \ 'minwidth': 40, + \ 'maxheight': 20, + \ 'border': [], + \ 'title': ' 🔖 Marks ', + \ 'close': 'click', + \ 'padding': [0, 1, 0, 1], + \ }) +endfunction + +" Show buffer list in a floating window +function! ShowBuffersPopup() + if !has('popupwin') + echo "Popup windows require Vim 8.2+" + return + endif + + let buffers_output = execute('ls') + let buffer_lines = split(buffers_output, '\n') + + call popup_create(buffer_lines, { + \ 'pos': 'topleft', + \ 'line': 2, + \ 'col': 5, + \ 'minwidth': 50, + \ 'maxheight': 15, + \ 'border': [], + \ 'title': ' 📁 Buffers ', + \ 'close': 'click', + \ 'padding': [0, 1, 0, 1], + \ }) +endfunction + +" Optional: Auto-show registers on " press (commented out by default) +" augroup RegisterPreview +" autocmd! +" autocmd CmdlineEnter : if getcmdtype() == '"' | call ShowRegistersPopup() | endif +" augroup END \ No newline at end of file diff --git a/.vim/vimrc b/.vim/vimrc index 8828bbc..16b6133 100644 --- a/.vim/vimrc +++ b/.vim/vimrc @@ -5,7 +5,9 @@ " Essential encoding settings (must be first) set encoding=utf-8 set fileencoding=utf-8 -set termencoding=utf-8 +if exists('+termencoding') + set termencoding=utf-8 +endif set termguicolors " 1. Plugins - Load all plugins first (includes plugin-specific settings) @@ -17,23 +19,32 @@ source ~/.vim/settings/appearance.vim " 3. Performance - Speed optimizations (early for best effect) source ~/.vim/settings/performance.vim -" 4. Key mappings - Basic vim keybindings +" 4. Neovim-only syntax engine support +if has('nvim') && filereadable(expand('~/.vim/settings/treesitter.vim')) + source ~/.vim/settings/treesitter.vim +endif + +" 5. Key mappings - Basic vim keybindings source ~/.vim/mappings.vim -" 5. Extra keybindings - Leader key and custom bindings +" 6. Extra keybindings - Leader key and custom bindings source ~/.vim/settings/keybindings.vim -" 6. CoC LSP - Language server configuration (after basic settings) +" 6b. UI features - popups etc. (self-guarded for vim/nvim differences) +if filereadable(expand('~/.vim/settings/ui-features.vim')) + source ~/.vim/settings/ui-features.vim +endif + +" 7. CoC LSP - Language server configuration (after basic settings) source ~/.vim/settings/coc-settings.vim -" 7. FZF - Fuzzy finder configuration (after keybindings) +" 8. FZF - Fuzzy finder configuration (after keybindings) source ~/.vim/settings/fzf-settings.vim -" 8. General settings - Search, behavior, etc. (loaded last) +" 9. General settings - Search, behavior, etc. (loaded last) source ~/.vim/settings.vim " Give the highlighter more time but cap per-line work set redrawtime=10000 set synmaxcol=300 " don't try to highlight beyond column 300 syntax sync minlines=128 " don't rescan the entire file from top - diff --git a/.zshrc b/.zshrc deleted file mode 100644 index b10fbdc..0000000 --- a/.zshrc +++ /dev/null @@ -1,158 +0,0 @@ -# Make sure autocomplete works properly -autoload -Uz compinit -compinit - -# Load colors -autoload -Uz colors && colors -setopt prompt_subst - -# Git branch info setup -autoload -Uz vcs_info -precmd() { vcs_info } -zstyle ':vcs_info:*' enable git -zstyle ':vcs_info:git:*' formats ' %b' - -ROSEWATER='%F{#f5e0dc}' -MAUVE='%F{#cba6f7}' -TEAL='%F{#94e2d5}' -PEACH='%F{#fab387}' -SOFT_GRAY='%F{#6c7086}' -RESET='%f%k' - -BUBBLE_BG='%{%K{#f5e0dc}%}' -BUBBLE_FG='%{%F{#1e1e2e}%}' - -function kube_prompt() { - local context=$(kubectl config current-context 2>/dev/null) - if [ -n "$context" ]; then - echo "(k8s:$context)" - fi -} - -function pretty_git() { - # Don't forget the space at the end of the echo - [[ -n "${vcs_info_msg_0_}" ]] && echo "${vcs_info_msg_0_} " -} - -# Custom function to show 🏡 if in home -function pretty_pwd() { - case "$PWD" in - "$HOME") - echo "🏡" - ;; - "$HOME/Documents") - echo "📄" - ;; - "$HOME/Downloads") - echo "📁" - ;; - "$HOME/Pictures") - echo "🖼️" - ;; - "$HOME/Music") - echo "🎵" - ;; - "$HOME/Desktop") - echo "🖥️" - ;; - "$HOME/workspace") - echo "💻" - ;; - *) - echo "%~" - ;; - esac - #if [[ "$PWD" == "$HOME" ]]; then - # echo "🏡" - #else - # echo "%~" - #fi -} - -# Dynamic time color based on hour -function dynamic_time_prompt() { - local hour=$(date +%H) - local color icon - - if (( hour >= 6 && hour < 12 )); then - color=$PEACH - icon='☀️' - elif (( hour >= 12 && hour < 18 )); then - color=$TEAL - icon='☀️' - elif (( hour >= 18 && hour < 21 )); then - color=$MAUVE - icon='🌙' - else - color=$SOFT_GRAY - icon='🌙' - fi - - echo "%{$color%}%*%{$RESET%}" -} - -function build_prompt() { - local GIT_INFO="$(pretty_git)" - local PWD_INFO="$(pretty_pwd)" - - PROMPT="⭐ ${MAUVE}[${ROSEWATER}%n${MAUVE}@${TEAL}${PWD_INFO}${MAUVE}] ${PEACH}${GIT_INFO}${RESET}➔ " -} - -precmd_functions+=(build_prompt) - -function build_rprompt() { - RPROMPT="$(dynamic_time_prompt)" -} - -precmd_functions+=(build_rprompt) - -source ~/.gnu_aliases - -# Soft pastel fzf colors -export FZF_DEFAULT_OPTS=" - --color=fg:#cdd6f4,bg:#1e1e2e,hl:#f38ba8 - --color=fg+:#f5e0dc,bg+:#313244,hl+:#fab387 - --color=info:#89b4fa,prompt:#94e2d5,pointer:#f5c2e7 - --color=marker:#a6e3a1,spinner:#b4befe,header:#cba6f7 - --layout=reverse - --border -" -[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh - -# Load custom shell functions -for f in ~/.config/shell-functions/*.sh; do - source "$f" -done - -function kctx() { - local selected - selected=$(kubectl config get-contexts -o name | \ - fzf --prompt="Select context > " \ - --height=40% \ - --layout=reverse \ - --border \ - --ansi) - - if [[ -n "$selected" ]]; then - kubectl config use-context "$selected" - else - echo "No context selected." - fi -} - -function git-ch() { - local branch - branch=$(git branch --sort=-committerdate | sed 's/* //' | sed 's/^[[:space:]]*//' | \ - fzf --prompt="Checkout branch > " \ - --height=40% \ - --layout=reverse \ - --border) - if [[ -n "$branch" ]]; then - git checkout "$branch" - fi -} - -alias kc=kctx -alias gch="git-ch" - -export PATH="/opt/homebrew/bin:$PATH" diff --git a/COC-EXAMPLES.md b/COC-EXAMPLES.md deleted file mode 100644 index a1568e1..0000000 --- a/COC-EXAMPLES.md +++ /dev/null @@ -1,205 +0,0 @@ -# CoC.nvim Examples & Usage Guide - -## Installation - -After updating vim plugins with `:PlugInstall`, CoC extensions will auto-install based on the languages you use. - -## Key Bindings Reference - -| Key | Action | Example | -|-----|--------|---------| -| `gd` | Go to definition | Jump to where a function is defined | -| `gy` | Go to type definition | See the type/interface definition | -| `gi` | Go to implementation | Find where interface is implemented | -| `gr` | Find references | See all places using this symbol | -| `K` | Show documentation | View function docs in popup | -| `[c` / `]c` | Previous/Next diagnostic | Navigate errors/warnings | -| `rn` | Rename symbol | Rename across entire project | -| `ca` | Code actions | Quick fixes and refactoring | -| `f` | Format selection | Auto-format code | -| `qf` | Quick fix | Auto-fix current line | -| `d` | Show documentation | Alternative to K | -| `` | Next completion | Navigate suggestions | -| `` | Accept completion | Confirm selected suggestion | - -## Language-Specific Examples - -### Python - -```python -# 1. Auto-completion -import requ| # Press Tab → suggests 'requests' - -# 2. Type information -def calculate(x: int, y: int) -> int: - return x + y - -result = calculate(10, 20) # Hover with K shows: "(x: int, y: int) -> int" - -# 3. Go to definition (gd) -from mymodule import helper_function -helper_function() # Press gd → jumps to mymodule.py - -# 4. Find all references (gr) -my_variable = 42 # Press gr → shows all uses of my_variable - -# 5. Quick fixes (ca) -undefined_func() # Shows: "Import 'undefined_func' from module" - -# 6. Auto-imports -Path(|) # Type and accept → adds "from pathlib import Path" -``` - -### JavaScript/TypeScript - -```javascript -// 1. Auto-import on completion -const data = fetchData| // Tab → completes and adds import - -// 2. Type checking -const num: number = "string" // Red underline, [g to see error - -// 3. Rename symbol (rn) -const oldName = 5; // Rename to 'newName' everywhere - -// 4. Extract to function (ca) -// Select code block → Extract to function/variable - -// 5. Organize imports (:OR) -import { b, a } from './utils'; // :OR → sorts imports - -// 6. JSDoc completion -/** - * @par| // Completes to @param - */ -``` - -### Rust - -```rust -// 1. Type inference -let mut vec = Vec::new(); -vec.push(42); // K shows: Vec - -// 2. Error explanations -let x: &str = 123; // Hover shows detailed error - -// 3. Auto-derive -#[derive(|)] // Suggests: Debug, Clone, PartialEq, etc. - -// 4. Import suggestions -HashMap::new() // ca → Import HashMap - -// 5. Inline hints -// Shows parameter names and types inline -``` - -### YAML (Docker, K8s) - -```yaml -# 1. Schema validation -apiVersion: apps/v1 -kind: Deployment -spec: - replicas: "three" # Error: should be number - -# 2. Auto-completion -image: | # Suggests from Docker Hub - -# 3. Hover documentation -command: | # K shows field documentation -``` - -### Shell/Bash - -```bash -# 1. Shellcheck integration -if [ $var == "test" ] # Warning: use [[ ]] or quote $var - -# 2. Command completion -git che| # Suggests: checkout, cherry-pick - -# 3. Variable tracking -MY_VAR="hello" -echo $MY_V| # Completes to MY_VAR -``` - -## Common Workflows - -### 1. Fix All Errors in File -```vim -:CocDiagnostics " See all problems -[g " Go to first error -qf " Quick fix -]g " Next error -qf " Fix it -" Repeat... -``` - -### 2. Refactor a Function -```vim -" 1. Place cursor on function name -" 2. rn to rename -" 3. Type new name -" 4. Enter to apply everywhere -``` - -### 3. Add Missing Imports -```vim -:OR " Organize and add imports -" or -ca " On undefined symbol -``` - -### 4. Format on Save -```vim -:w " Automatically formats supported files -" or manually: -:Format " Format entire file -``` - -### 5. Jump Through Code -```vim -gd " Go to definition - " Jump back -gr " Find all usages - " Follow tag -``` - -## Troubleshooting - -### Check CoC Status -```vim -:CocInfo " See CoC status and logs -:CocList extensions " Manage extensions -:checkhealth " Overall vim health -``` - -### Install Missing Language Servers -```vim -:CocInstall coc-python " Python -:CocInstall coc-tsserver " JS/TS -:CocInstall coc-rust-analyzer " Rust -``` - -### Common Issues - -1. **No completions appearing** - - Check `:CocInfo` for errors - - Ensure language server is installed - - Try `:CocRestart` - -2. **Slow performance** - - Exclude large folders in coc-settings.json - - Disable unused extensions - -3. **Format on save not working** - - Check file type is in `formatOnSaveFiletypes` - - Install formatter (prettier, black, etc.) - -## Tips - -- Use `:CocCommand` to see all available commands -- `` is typically `\` unless remapped -- CoC works best with vim 8.1+ or neovim -- Language servers need to be installed separately (npm, pip, etc.) \ No newline at end of file diff --git a/Makefile b/Makefile index 9909f2f..5b448a7 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ -.PHONY: all help install install-minimal install-no-packages backup-bash brew-sync clean-backup legacy +.PHONY: all help install install-minimal install-no-packages install-dry-run install-copy install-git-hooks check test-install check-editor brew-sync clean-backup .ONESHELL: SHELL = /bin/bash DOTFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) OS := $(shell uname -s | tr '[:upper:]' '[:lower:]') -# Main install targets using new universal installer +# Main install targets using the universal installer all: install install: $(DOTFILE_DIR)/install.sh @@ -22,102 +22,30 @@ install-dry-run: install-copy: $(DOTFILE_DIR)/install.sh --copy -# Legacy OS-specific targets (kept for compatibility) -legacy: $(OS) -linux: apt flatpak git-init stow-linux git-installs profile-source font-cache -darwin: brew brew-upgrade git-init stow-darwin git-installs profile-source +check: test-install + bash -n $(DOTFILE_DIR)/install.sh + bash -n $(DOTFILE_DIR)/scripts/check-editor-parity.sh + bash -n $(DOTFILE_DIR)/scripts/test-install.sh +test-install: + $(DOTFILE_DIR)/scripts/test-install.sh -apt: - $(info You may be prompted for super-user privleges:) - xargs -a linux/debian/packages.list sudo apt-get install -y +check-editor: + $(DOTFILE_DIR)/scripts/check-editor-parity.sh -darwin: brew - softwareupdate -aiR - -brew: /usr/local/Homebrew/bin/brew - -brew bundle --file=$(DOTFILE_DIR)/darwin/Brewfile +install-git-hooks: + mkdir -p $(HOME)/.config/git/hooks + for hook in $(DOTFILE_DIR)/common/git/hooks/*; do \ + if [[ -f "$$hook" && "$$(basename "$$hook")" != "README.md" ]]; then \ + cp -f "$$hook" "$(HOME)/.config/git/hooks/$$(basename "$$hook")"; \ + chmod +x "$(HOME)/.config/git/hooks/$$(basename "$$hook")"; \ + fi; \ + done + git config --global core.hooksPath "~/.config/git/hooks" brew-sync: brew bundle dump --force --file=$(DOTFILE_DIR)/darwin/Brewfile -brew-upgrade: - if brew upgrade ; then brew cleanup ; fi; - -/usr/local/Homebrew/bin/brews: - { \ - set -e ;\ - if hash brew 2> /dev/null; then \ - echo "Brew is already installed."; \ - else \ - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"; \ - fi ;\ - } - -flatpak: - sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo - -font-cache: - $(info Resetting system font-cache) - $(shell fc-cache -f) - -git-init: - git submodule update --init --recursive - -git-installs: python-dev nodejs-dev - -python-dev: $(HOME)/.pyenv venv-wrapper -nodejs-dev: $(HOME)/.nodenv $(HOME)/.nodenv/plugins/node-build - -$(HOME)/.nodenv: - git clone https://github.com/nodenv/nodenv.git $(HOME)/.nodenv - $(shell cd $HOME/.nodenv && src/configure && make -C src) - -$(HOME)/.nodenv/plugins/node-build: - git clone https://github.com/nodenv/node-build.git $(HOME)/.nodenv/plugins/node-build - -$(HOME)/.pyenv: - git clone https://github.com/pyenv/pyenv.git $(HOME)/.pyenv - -venv-wrapper: - pip3 install --user -U virtualenvwrapper virtualenv - -profile-source: - source $(HOME)/.bash_profile - -backup-bash: - $(DOTFILE_DIR)/bash_backup.sh - -stow-common: backup-bash - stow -d common -t ~ bash - stow -d common -t ~ shell - stow -d common -t ~ git - stow -d common -t ~/.config htop - stow -d common -t ~/.config shell-functions - -stow-darwin: stow-common - stow -d darwin -t ~/.config kitty - -stow-linux: stow-common - stow -d linux/common -t ~/.config kitty - -stow: stow-$(OS) - -link: backup-bash - ln -fs bash/.bash_aliases $(HOME)/.bash_aliases - ln -fs bash/.bash_logout $(HOME)/.bash_logout - ln -fs bash/.bash_profile $(HOME)/.bash_profile - ln -fs bash/.bashrc $(HOME)/.bashrc - ln -fs bash/.curlrc $(HOME)/.curlrc - ln -fs bin/bin $(HOME)/bin - -unlink: - unlink $(HOME)/.bash_aliases - unlink $(HOME)/.bash_logout - unlink $(HOME)/.bash_profile - unlink $(HOME)/.bashrc - unlink $(HOME)/.curlrc - # Cleanup clean-backup: @echo "Removing old backup directories..." @@ -127,17 +55,20 @@ clean-backup: help: @echo "Dotfiles Installation Options:" @echo "" - @echo " make install # Full installation with symlinks (recommended)" - @echo " make install-minimal # Minimal config for servers/containers" + @echo " make install # Full installation with regular file copies" + @echo " make install-minimal # Minimal config for servers/containers" @echo " make install-no-packages # Install configs only, skip packages" - @echo " make install-copy # Copy files instead of symlinks" - @echo " make install-dry-run # Show what would be installed" + @echo " make install-dry-run # Show what would be installed" + @echo " make install-git-hooks # Install personal global Git hooks only" @echo "" - @echo "Advanced:" - @echo " make legacy # Use legacy OS-specific installation" - @echo " make clean-backup # Remove old backup directories (30+ days)" - @echo " make brew-sync # Update Brewfile with current packages" + @echo "Checks:" + @echo " make check # Lint installer scripts + run smoke test" + @echo " make test-install # Run the installer against a temp HOME" + @echo " make check-editor # Verify vim/nvim behavior parity" + @echo "" + @echo "Maintenance:" + @echo " make brew-sync # Update Brewfile with current packages" + @echo " make clean-backup # Remove old backup directories (30+ days)" @echo "" @echo "Direct script usage:" @echo " ./install.sh --help # Show all script options" - diff --git a/README.md b/README.md index 6b66d1e..9a30e78 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Personal dotfiles for macOS and Linux with modular shell functions, git workflow ```bash # Clone and install -git clone https://github.com/yourusername/dotfiles.git ~/workspace/projects/dotfiles +git clone https://github.com/woud420/dotfiles.git ~/workspace/projects/dotfiles cd ~/workspace/projects/dotfiles ./install.sh @@ -31,11 +31,11 @@ make install-dry-run # Preview changes ### Remote Installation ```bash -# One-liner for remote servers -curl -fsSL https://raw.githubusercontent.com/yourusername/dotfiles/main/install.sh | bash -s -- --minimal +# Minimal quick-install (shallow-clones the repo and copies server configs) +curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/scripts/quick-install.sh | bash -# SSH with dotfiles -ssh user@host 'bash -s' < install.sh --minimal +# Or clone and run the full installer +git clone https://github.com/woud420/dotfiles.git && cd dotfiles && ./install.sh --minimal ``` ## 📁 Directory Structure @@ -69,11 +69,18 @@ dotfiles/ | `.bash_profile` | `~/.bash_profile` | Bash profile (sources .bashrc) | | `.bashrc.server` | `~/.bashrc` | Conservative bash config for servers (minimal mode) | | `.gitconfig` | `~/.gitconfig` | Git aliases and fuzzy commands | +| `commit-template.md` | `~/.config/git/commit-template.md` | Default structured git commit template | | `.gitignore_global` | `~/.config/git/ignore` | Global git ignores | | `.gnu_aliases` | `~/.gnu_aliases` | GNU coreutils aliases for macOS | | `.dircolors` | `~/.dircolors` | Directory colors | +| `common/git/hooks/*` | `~/.config/git/hooks/*` | Personal global Git hooks | +| `common/ssh/config` | `~/.ssh/config.dotfiles` | Shared SSH defaults (Include'd from `~/.ssh/config`) | | `kitty.conf` | `~/.config/kitty/kitty.conf` | Kitty terminal config | | `htoprc` | `~/.config/htop/htoprc` | htop configuration | +| `.vim/*` | `~/.vim/` | Vim config, settings, and CoC settings | +| `common/nvim/init.vim` | `~/.config/nvim/init.vim` | Neovim bridge to the Vim config | +| `.vim/coc-settings.json` | `~/.vim/` and `~/.config/nvim/` | CoC LSP settings (both editors) | +| `scripts/sudo-askpass.sh` | `~/.local/bin/sudo-askpass` | GUI sudo prompt helper | ### Shell Functions @@ -81,13 +88,17 @@ All shell functions are installed to `~/.config/shell-functions/`: | File | Purpose | Key Commands | |------|---------|--------------| -| `kubectl-aliases.sh` | Kubernetes shortcuts | `k get p`, `kgpw`, `kdp`, `kshp` | -| `git-aliases.sh` | Git shortcuts | `g`, `gs`, `gaa`, `gcm`, `gp` | -| `git.sh` | Git workflow functions | `git-ch()`, `git-log()`, `git-add()` | -| `ssh.sh` | SSH helpers | `sshdot`, `sshconf`, `ssht` | -| `docker.sh` | Docker helpers | `dex`, `dlog`, `dclean` | -| `utils.sh` | Utilities | `mkcd`, `extract`, `backup` | -| `fuzzy-vim.sh` | Vim with fzf | `v` (fuzzy file open) | +| `editor.sh` | Editor defaults | `vi`, `vim`, `vimdiff` use Neovim when available | +| `which.sh` | Command lookup | Includes shell aliases and functions | +| `sudo.sh` | GUI sudo prompts | Exports `SUDO_ASKPASS` (use `sudo -A`) | +| `macos-clipboard.sh` | Clipboard parity | `pbcopy`/`pbpaste` on Linux (wl-clipboard) | +| `kubectl-aliases.sh` | Kubernetes | `k` (kubectl); `kctx` lives in the shell rc files | + +The remaining function files (`git.sh`, `git-aliases.sh`, `docker.sh`, +`docker-aliases.sh`, `k8s.sh`, `ssh.sh`, `utils.sh`, `fuzzy-vim.sh`, +`modern-tools-aliases.sh`, `secrets.sh`, `system-aliases.sh`) are currently +**disabled stubs** - kept in place so they can be restored incrementally +without breaking installs. ### Git Aliases (in .gitconfig) @@ -104,29 +115,19 @@ git lg # Pretty log with graph ### Kubectl Aliases ```bash -# Quick shortcuts k # kubectl -kgp # kubectl get pods -kgpw # kubectl get pods -o wide -kdp # kubectl describe pod -klf # kubectl logs -f - -# Functions -kshp # Shell into first pod matching pattern -klp # Logs from first pod matching pattern kctx # Switch context with fzf -kns # Switch namespace with fzf ``` ## 📦 Packages ### macOS (Homebrew) -Core tools: `awscli`, `bash`, `coreutils`, `git`, `fzf`, `fd`, `ripgrep`, `htop`, `tree`, `wget` +Core tools: `awscli`, `bash`, `coreutils`, `git`, `fzf`, `fd`, `ripgrep`, `htop`, `neovim`, `tree`, `wget` Development: `node`, `python`, `rust`, `poetry`, `virtualenv` Kubernetes: `kubernetes-cli`, `helm`, `k9s`, `eksctl`, `minikube` -Infrastructure: `terraform`, `terraformer`, `tflint` -Apps: `docker`, `docker-desktop`, `slack`, `spotify` +Infrastructure: `terraformer`, `tflint` +Apps: `docker-desktop` (bundles the docker CLI), `slack`, `spotify` ### Linux @@ -151,11 +152,10 @@ Example prompt: ``` ### Fuzzy Everything -- **File search**: `v` to open files with vim - **Git branches**: `git ch` for interactive checkout - **Git commits**: `git flog` to browse history - **Git staging**: `git fadd` to stage files -- **Kubernetes**: `kctx`/`kns` for context/namespace switching +- **Kubernetes**: `kctx` for context switching ### GNU Tools on macOS Automatically aliases GNU versions to replace BSD utilities: @@ -176,6 +176,23 @@ To clean old backups (30+ days): make clean-backup ``` +## 🧭 Machine Convergence + +`install.sh` is the single entry point for every machine. It detects the OS +and distribution and installs the right layer on top of `common/`: + +- macOS: `darwin/` (Brewfile, kitty) +- Linux: `linux//` packages plus, on Arch, the full desktop + configuration under `linux/arch/.config/` (Sway, Waybar, GTK, kitty theme + overlays) + +Installs are always copies (never symlinks) with path-preserving backups and +an audit log. Preview any run with `./install.sh --dry-run`. + +This converges personal interactive machines on Zsh, Kitty, and Neovim while +keeping Bash available as a fallback. The history of this effort is recorded +in `docs/machine-convergence-plan.md`. + ## 🐳 Container Usage The installer auto-detects container environments and uses minimal mode: @@ -195,10 +212,45 @@ The installer automatically detects: ## 🔧 Customization ### Local Overrides -Create `~/.bashrc.local` or `~/.zshrc.local` for machine-specific configs. +Machine-specific config lives outside the repo and survives reinstalls: + +- `~/.bashrc.local` / `~/.zshrc.local` - sourced at the end of the shell configs +- `~/.gitconfig.local` - included last by `.gitconfig`, so identity or + tool-appended blocks (e.g. git-ai) win over the shared config +- `~/.ssh/config` - your own host entries stay first; the shared defaults are + pulled in via `Include ~/.ssh/config.dotfiles`. Note the shared defaults set + `ForwardAgent yes` globally - convenient across personal machines, but scope + it per-host in a local block if you ssh to hosts you don't control. + +### Personal Git Hooks -### Memory Management -The installer respects `CLAUDE.md` files for project-specific context. +The installed `.gitconfig` sets `core.hooksPath = ~/.config/git/hooks`. +Installed hooks are intentionally general and local-only: + +- `pre-commit` runs repo hooks like `.husky/pre-commit` first, then blocks + likely secrets, conflict markers, oversized files, and generated-looking + files (lockfiles allowlisted; override with `JM_ALLOW_GENERATED_EDITS=1`). +- `pre-push` runs repo hooks first, then an explicit repo check when configured. + +```bash +JM_GIT_HOOKS=0 git commit ... # Skip personal hooks once +git config jm.hooks.runRepoHooks false # Don't run repo-controlled hooks in an untrusted clone +git config jm.hooks.prePushCommand "make check" +make install-git-hooks # Install only the hooks +``` + +### Minimal mode +`--minimal` (auto-enabled in containers) installs the server bashrc and core +configs only: it skips packages, vim/nvim plugins, desktop configs, the +sudo-askpass helper, and AI context files, but still installs terminal +(kitty/htop) configs. + +### AI Context +The installer copies `common/ai-context/` files into place: +`~/AGENTS.md` and an OS-specific `~/MACHINE.md`; `~/.claude/CLAUDE.md` is +only seeded when absent (an existing customized one is left alone). +Machine state snapshots are generated on demand with +`scripts/refresh-machine-state.sh`. ## 📚 Requirements @@ -221,4 +273,3 @@ The installer respects `CLAUDE.md` files for project-specific context. # View installer help ./install.sh --help ``` - diff --git a/bash/16bit.colors b/bash/16bit.colors deleted file mode 100644 index afc6827..0000000 --- a/bash/16bit.colors +++ /dev/null @@ -1,515 +0,0 @@ -# Based on https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit -local S1="\[\033[38;5;1m\]" #000000 -local S2="\[\033[38;5;2m\]" #800000 -local S3="\[\033[38;5;3m\]" #008000 -local S4="\[\033[38;5;4m\]" #808000 -local S5="\[\033[38;5;5m\]" #000080 -local S6="\[\033[38;5;6m\]" #800080 -local S7="\[\033[38;5;7m\]" #008080 -local S8="\[\033[38;5;8m\]" #c0c0c0 -local S9="\[\033[38;5;9m\]" #808080 -local S10="\[\033[38;5;10m\]" #ff0000 -local S11="\[\033[38;5;11m\]" #00ff00 -local S12="\[\033[38;5;12m\]" #ffff00 -local S13="\[\033[38;5;13m\]" #0000ff -local S14="\[\033[38;5;14m\]" #ff00ff -local S15="\[\033[38;5;15m\]" #00ffff -local S16="\[\033[38;5;16m\]" #ffffff -local S17="\[\033[38;5;17m\]" #000000 -local S18="\[\033[38;5;18m\]" #00005f -local S19="\[\033[38;5;19m\]" #000087 -local S20="\[\033[38;5;20m\]" #0000af -local S21="\[\033[38;5;21m\]" #0000d7 -local S22="\[\033[38;5;22m\]" #0000ff -local S23="\[\033[38;5;23m\]" #005f00 -local S24="\[\033[38;5;24m\]" #005f5f -local S25="\[\033[38;5;25m\]" #005f87 -local S26="\[\033[38;5;26m\]" #005faf -local S27="\[\033[38;5;27m\]" #005fd7 -local S28="\[\033[38;5;28m\]" #005fff -local SA9="\[\033[38;5;29m\]" #008700 -local S30="\[\033[38;5;30m\]" #00875f -local S31="\[\033[38;5;31m\]" #008787 -local S32="\[\033[38;5;32m\]" #0087af -local S33="\[\033[38;5;33m\]" #0087d7 -local S34="\[\033[38;5;34m\]" #0087ff -local S35="\[\033[38;5;35m\]" #00af00 -local S36="\[\033[38;5;36m\]" #00af5f -local S37="\[\033[38;5;37m\]" #00af87 -local S38="\[\033[38;5;38m\]" #00afaf -local S38="\[\033[38;5;39m\]" #00afd7 -local S40="\[\033[38;5;40m\]" #00afff -local S41="\[\033[38;5;41m\]" #00d700 -local S42="\[\033[38;5;42m\]" #00d75f -local S43="\[\033[38;5;43m\]" #00d787 -local S44="\[\033[38;5;44m\]" #00d7af -local S45="\[\033[38;5;45m\]" #00d7d7 -local S46="\[\033[38;5;46m\]" #00d7ff -local S47="\[\033[38;5;47m\]" #00ff00 -local S48="\[\033[38;5;48m\]" #00ff5f -local S49="\[\033[38;5;49m\]" #00ff87 -local S50="\[\033[38;5;50m\]" #00ffaf -local S51="\[\033[38;5;51m\]" #00ffd7 -local S52="\[\033[38;5;52m\]" #00ffff -local S53="\[\033[38;5;53m\]" #5f0000 -local S54="\[\033[38;5;54m\]" #5f005f -local S55="\[\033[38;5;55m\]" #5f0087 -local S56="\[\033[38;5;56m\]" #5f00af -local S57="\[\033[38;5;57m\]" #5f00d7 -local S58="\[\033[38;5;58m\]" #5f00ff -local S59="\[\033[38;5;59m\]" #5f5f00 -local S60="\[\033[38;5;60m\]" #5f5f5f -local S61="\[\033[38;5;61m\]" #5f5f87 -local S62="\[\033[38;5;62m\]" #5f5faf -local S63="\[\033[38;5;63m\]" #5f5fd7 -local S64="\[\033[38;5;64m\]" #5f5fff -local S65="\[\033[38;5;65m\]" #5f8700 -local S66="\[\033[38;5;66m\]" #5f875f -local S67="\[\033[38;5;67m\]" #5f8787 -local S68="\[\033[38;5;68m\]" #5f87af -local S69="\[\033[38;5;69m\]" #5f87d7 -local S70="\[\033[38;5;70m\]" #5f87ff -local S71="\[\033[38;5;71m\]" #5faf00 -local S72="\[\033[38;5;72m\]" #5faf5f -local S73="\[\033[38;5;73m\]" #5faf87 -local S74="\[\033[38;5;74m\]" #5fafaf -local S75="\[\033[38;5;75m\]" #5fafd7 -local S76="\[\033[38;5;76m\]" #5fafff -local S77="\[\033[38;5;77m\]" #5fd700 -local S78="\[\033[38;5;78m\]" #5fd75f -local S79="\[\033[38;5;79m\]" #5fd787 -local S80="\[\033[38;5;80m\]" #5fd7af -local S81="\[\033[38;5;81m\]" #5fd7d7 -local S82="\[\033[38;5;82m\]" #5fd7ff -local S83="\[\033[38;5;83m\]" #5fff00 -local S84="\[\033[38;5;84m\]" #5fff5f -local S85="\[\033[38;5;85m\]" #5fff87 -local S86="\[\033[38;5;86m\]" #5fffaf -local S87="\[\033[38;5;87m\]" #5fffd7 -local S88="\[\033[38;5;88m\]" #5fffff -local S89="\[\033[38;5;89m\]" #870000 -local S90="\[\033[38;5;90m\]" #87005f -local S91="\[\033[38;5;91m\]" #870087 -local S92="\[\033[38;5;92m\]" #8700af -local S93="\[\033[38;5;93m\]" #8700d7 -local S94="\[\033[38;5;94m\]" #8700ff -local S95="\[\033[38;5;95m\]" #875f00 -local S96="\[\033[38;5;96m\]" #875f5f -local S97="\[\033[38;5;97m\]" #875f87 -local S98="\[\033[38;5;98m\]" #875faf -local S99="\[\033[38;5;99m\]" #875fd7 -local S100="\[\033[38;5;100m\]" #875fff -local S101="\[\033[38;5;101m\]" #878700 -local S102="\[\033[38;5;102m\]" #87875f -local S103="\[\033[38;5;103m\]" #878787 -local S104="\[\033[38;5;104m\]" #8787af -local S105="\[\033[38;5;105m\]" #8787d7 -local S106="\[\033[38;5;106m\]" #8787ff -local S107="\[\033[38;5;107m\]" #87af00 -local S108="\[\033[38;5;108m\]" #87af5f -local S109="\[\033[38;5;109m\]" #87af87 -local S110="\[\033[38;5;110m\]" #87afaf -local S111="\[\033[38;5;111m\]" #87afd7 -local S112="\[\033[38;5;112m\]" #87afff -local S113="\[\033[38;5;113m\]" #87d700 -local S114="\[\033[38;5;114m\]" #87d75f -local S115="\[\033[38;5;115m\]" #87d787 -local S116="\[\033[38;5;116m\]" #87d7af -local S117="\[\033[38;5;117m\]" #87d7d7 -local S118="\[\033[38;5;118m\]" #87d7ff -local S119="\[\033[38;5;119m\]" #87ff00 -local S120="\[\033[38;5;120m\]" #87ff5f -local S121="\[\033[38;5;121m\]" #87ff87 -local S122="\[\033[38;5;122m\]" #87ffaf -local S123="\[\033[38;5;123m\]" #87ffd7 -local S124="\[\033[38;5;124m\]" #87ffff -local S125="\[\033[38;5;125m\]" #af0000 -local S126="\[\033[38;5;126m\]" #af005f -local S127="\[\033[38;5;127m\]" #af0087 -local S128="\[\033[38;5;128m\]" #af00af -local S129="\[\033[38;5;129m\]" #af00d7 -local S130="\[\033[38;5;130m\]" #af00ff -local S131="\[\033[38;5;131m\]" #af5f00 -local S132="\[\033[38;5;132m\]" #af5f5f -local S133="\[\033[38;5;133m\]" #af5f87 -local S134="\[\033[38;5;134m\]" #af5faf -local S135="\[\033[38;5;135m\]" #af5fd7 -local S136="\[\033[38;5;136m\]" #af5fff -local S137="\[\033[38;5;137m\]" #af8700 -local S138="\[\033[38;5;138m\]" #af875f -local S139="\[\033[38;5;139m\]" #af8787 -local S140="\[\033[38;5;140m\]" #af87af -local S141="\[\033[38;5;141m\]" #af87d7 -local S142="\[\033[38;5;142m\]" #af87ff -local S143="\[\033[38;5;143m\]" #afaf00 -local S144="\[\033[38;5;144m\]" #afaf5f -local S145="\[\033[38;5;145m\]" #afaf87 -local S146="\[\033[38;5;146m\]" #afafaf -local S147="\[\033[38;5;147m\]" #afafd7 -local S148="\[\033[38;5;148m\]" #afafff -local S149="\[\033[38;5;149m\]" #afd700 -local S150="\[\033[38;5;150m\]" #afd75f -local S151="\[\033[38;5;151m\]" #afd787 -local S152="\[\033[38;5;152m\]" #afd7af -local S153="\[\033[38;5;153m\]" #afd7d7 -local S154="\[\033[38;5;154m\]" #afd7ff -local S155="\[\033[38;5;155m\]" #afff00 -local S156="\[\033[38;5;156m\]" #afff5f -local S157="\[\033[38;5;157m\]" #afff87 -local S158="\[\033[38;5;158m\]" #afffaf -local S159="\[\033[38;5;159m\]" #afffd7 -local S160="\[\033[38;5;160m\]" #afffff -local S161="\[\033[38;5;161m\]" #d70000 -local S162="\[\033[38;5;162m\]" #d7005f -local S163="\[\033[38;5;163m\]" #d70087 -local S164="\[\033[38;5;164m\]" #d700af -local S165="\[\033[38;5;165m\]" #d700d7 -local S166="\[\033[38;5;166m\]" #d700ff -local S167="\[\033[38;5;167m\]" #d75f00 -local S168="\[\033[38;5;168m\]" #d75f5f -local S169="\[\033[38;5;169m\]" #d75f87 -local S170="\[\033[38;5;170m\]" #d75faf -local S171="\[\033[38;5;171m\]" #d75fd7 -local S172="\[\033[38;5;172m\]" #d75fff -local S173="\[\033[38;5;173m\]" #d78700 -local S174="\[\033[38;5;174m\]" #d7875f -local S175="\[\033[38;5;175m\]" #d78787 -local S176="\[\033[38;5;176m\]" #d787af -local S177="\[\033[38;5;177m\]" #d787d7 -local S178="\[\033[38;5;178m\]" #d787ff -local S179="\[\033[38;5;179m\]" #d7af00 -local S180="\[\033[38;5;180m\]" #d7af5f -local S181="\[\033[38;5;181m\]" #d7af87 -local S182="\[\033[38;5;182m\]" #d7afaf -local S183="\[\033[38;5;183m\]" #d7afd7 -local S184="\[\033[38;5;184m\]" #d7afff -local S185="\[\033[38;5;185m\]" #d7d700 -local S186="\[\033[38;5;186m\]" #d7d75f -local S187="\[\033[38;5;187m\]" #d7d787 -local S188="\[\033[38;5;188m\]" #d7d7af -local S189="\[\033[38;5;189m\]" #d7d7d7 -local S190="\[\033[38;5;190m\]" #d7d7ff -local S191="\[\033[38;5;191m\]" #d7ff00 -local S192="\[\033[38;5;192m\]" #d7ff5f -local S193="\[\033[38;5;193m\]" #d7ff87 -local S194="\[\033[38;5;194m\]" #d7ffaf -local S195="\[\033[38;5;195m\]" #d7ffd7 -local S196="\[\033[38;5;196m\]" #d7ffff -local S197="\[\033[38;5;197m\]" #ff0000 -local S198="\[\033[38;5;198m\]" #ff005f -local S199="\[\033[38;5;199m\]" #ff0087 -local S200="\[\033[38;5;200m\]" #ff00af -local S201="\[\033[38;5;201m\]" #ff00d7 -local S202="\[\033[38;5;202m\]" #ff00ff -local S203="\[\033[38;5;203m\]" #ff5f00 -local S204="\[\033[38;5;204m\]" #ff5f5f -local S205="\[\033[38;5;205m\]" #ff5f87 -local S206="\[\033[38;5;206m\]" #ff5faf -local S207="\[\033[38;5;207m\]" #ff5fd7 -local S208="\[\033[38;5;208m\]" #ff5fff -local S209="\[\033[38;5;209m\]" #ff8700 -local S210="\[\033[38;5;210m\]" #ff875f -local S211="\[\033[38;5;211m\]" #ff8787 -local S212="\[\033[38;5;212m\]" #ff87af -local S213="\[\033[38;5;213m\]" #ff87d7 -local S214="\[\033[38;5;214m\]" #ff87ff -local S215="\[\033[38;5;215m\]" #ffaf00 -local S216="\[\033[38;5;216m\]" #ffaf5f -local S217="\[\033[38;5;217m\]" #ffaf87 -local S218="\[\033[38;5;218m\]" #ffafaf -local S219="\[\033[38;5;219m\]" #ffafd7 -local S220="\[\033[38;5;220m\]" #ffafff -local S221="\[\033[38;5;221m\]" #ffd700 -local S222="\[\033[38;5;222m\]" #ffd75f -local S223="\[\033[38;5;223m\]" #ffd787 -local S224="\[\033[38;5;224m\]" #ffd7af -local S225="\[\033[38;5;225m\]" #ffd7d7 -local S226="\[\033[38;5;226m\]" #ffd7ff -local S227="\[\033[38;5;227m\]" #ffff00 -local S228="\[\033[38;5;228m\]" #ffff5f -local S229="\[\033[38;5;229m\]" #ffff87 -local S230="\[\033[38;5;230m\]" #ffffaf -local S231="\[\033[38;5;231m\]" #ffffd7 -local S232="\[\033[38;5;232m\]" #ffffff -local S233="\[\033[38;5;233m\]" #080808 -local S234="\[\033[38;5;234m\]" #121212 -local S235="\[\033[38;5;235m\]" #1c1c1c -local S236="\[\033[38;5;236m\]" #262626 -local S237="\[\033[38;5;237m\]" #303030 -local S238="\[\033[38;5;238m\]" #3a3a3a -local S239="\[\033[38;5;239m\]" #444444 -local S240="\[\033[38;5;240m\]" #4e4e4e -local S241="\[\033[38;5;241m\]" #585858 -local S242="\[\033[38;5;242m\]" #626262 -local S243="\[\033[38;5;243m\]" #6c6c6c -local S244="\[\033[38;5;244m\]" #767676 -local S245="\[\033[38;5;245m\]" #808080 -local S246="\[\033[38;5;246m\]" #8a8a8a -local S247="\[\033[38;5;247m\]" #949494 -local S248="\[\033[38;5;248m\]" #9e9e9e -local S249="\[\033[38;5;249m\]" #a8a8a8 -local S250="\[\033[38;5;250m\]" #b2b2b2 -local S251="\[\033[38;5;251m\]" #bcbcbc -local S252="\[\033[38;5;252m\]" #c6c6c6 -local S253="\[\033[38;5;253m\]" #d0d0d0 -local S254="\[\033[38;5;254m\]" #dadada -local S255="\[\033[38;5;255m\]" #e4e4e4 -local S256="\[\033[38;5;256m\]" #eeeeee - -# background -local BG1="\[\033[48;5;1m\]" -local BG2="\[\033[48;5;2m\]" -local BG3="\[\033[48;5;3m\]" -local BG4="\[\033[48;5;4m\]" -local BG5="\[\033[48;5;5m\]" -local BG6="\[\033[48;5;6m\]" -local BG7="\[\033[48;5;7m\]" -local BG8="\[\033[48;5;8m\]" -local BG9="\[\033[48;5;9m\]" -local BG10="\[\033[48;5;10m\]" -local BG11="\[\033[48;5;11m\]" -local BG12="\[\033[48;5;12m\]" -local BG13="\[\033[48;5;13m\]" -local BG14="\[\033[48;5;14m\]" -local BG15="\[\033[48;5;15m\]" -local BG16="\[\033[48;5;16m\]" -local BG17="\[\033[48;5;17m\]" -local BG18="\[\033[48;5;18m\]" -local BG19="\[\033[48;5;19m\]" -local BG20="\[\033[48;5;20m\]" -local BG21="\[\033[48;5;21m\]" -local BG22="\[\033[48;5;22m\]" -local BG23="\[\033[48;5;23m\]" -local BG24="\[\033[48;5;24m\]" -local BG25="\[\033[48;5;25m\]" -local BG26="\[\033[48;5;26m\]" -local BG27="\[\033[48;5;27m\]" -local BG28="\[\033[48;5;28m\]" -local BGA9="\[\033[48;5;29m\]" -local BG30="\[\033[48;5;30m\]" -local BG31="\[\033[48;5;31m\]" -local BG32="\[\033[48;5;32m\]" -local BG33="\[\033[48;5;33m\]" -local BG34="\[\033[48;5;34m\]" -local BG35="\[\033[48;5;35m\]" -local BG36="\[\033[48;5;36m\]" -local BG37="\[\033[48;5;37m\]" -local BG38="\[\033[48;5;38m\]" -local BG38="\[\033[48;5;39m\]" -local BG40="\[\033[48;5;40m\]" -local BG41="\[\033[48;5;41m\]" -local BG42="\[\033[48;5;42m\]" -local BG43="\[\033[48;5;43m\]" -local BG44="\[\033[48;5;44m\]" -local BG45="\[\033[48;5;45m\]" -local BG46="\[\033[48;5;46m\]" -local BG47="\[\033[48;5;47m\]" -local BG48="\[\033[48;5;48m\]" -local BG49="\[\033[48;5;49m\]" -local BG50="\[\033[48;5;50m\]" -local BG51="\[\033[48;5;51m\]" -local BG52="\[\033[48;5;52m\]" -local BG53="\[\033[48;5;53m\]" -local BG54="\[\033[48;5;54m\]" -local BG55="\[\033[48;5;55m\]" -local BG56="\[\033[48;5;56m\]" -local BG57="\[\033[48;5;57m\]" -local BG58="\[\033[48;5;58m\]" -local BG59="\[\033[48;5;59m\]" -local BG60="\[\033[48;5;60m\]" -local BG61="\[\033[48;5;61m\]" -local BG62="\[\033[48;5;62m\]" -local BG63="\[\033[48;5;63m\]" -local BG64="\[\033[48;5;64m\]" -local BG65="\[\033[48;5;65m\]" -local BG66="\[\033[48;5;66m\]" -local BG67="\[\033[48;5;67m\]" -local BG68="\[\033[48;5;68m\]" -local BG69="\[\033[48;5;69m\]" -local BG70="\[\033[48;5;70m\]" -local BG71="\[\033[48;5;71m\]" -local BG72="\[\033[48;5;72m\]" -local BG73="\[\033[48;5;73m\]" -local BG74="\[\033[48;5;74m\]" -local BG75="\[\033[48;5;75m\]" -local BG76="\[\033[48;5;76m\]" -local BG77="\[\033[48;5;77m\]" -local BG78="\[\033[48;5;78m\]" -local BG79="\[\033[48;5;79m\]" -local BG80="\[\033[48;5;80m\]" -local BG81="\[\033[48;5;81m\]" -local BG82="\[\033[48;5;82m\]" -local BG83="\[\033[48;5;83m\]" -local BG84="\[\033[48;5;84m\]" -local BG85="\[\033[48;5;85m\]" -local BG86="\[\033[48;5;86m\]" -local BG87="\[\033[48;5;87m\]" -local BG88="\[\033[48;5;88m\]" -local BG89="\[\033[48;5;89m\]" -local BG90="\[\033[48;5;90m\]" -local BG91="\[\033[48;5;91m\]" -local BG92="\[\033[48;5;92m\]" -local BG93="\[\033[48;5;93m\]" -local BG94="\[\033[48;5;94m\]" -local BG95="\[\033[48;5;95m\]" -local BG96="\[\033[48;5;96m\]" -local BG97="\[\033[48;5;97m\]" -local BG98="\[\033[48;5;98m\]" -local BG99="\[\033[48;5;99m\]" -local BG100="\[\033[48;5;100m\]" -local BG101="\[\033[48;5;101m\]" -local BG102="\[\033[48;5;102m\]" -local BG103="\[\033[48;5;103m\]" -local BG104="\[\033[48;5;104m\]" -local BG105="\[\033[48;5;105m\]" -local BG106="\[\033[48;5;106m\]" -local BG107="\[\033[48;5;107m\]" -local BG108="\[\033[48;5;108m\]" -local BG109="\[\033[48;5;109m\]" -local BG110="\[\033[48;5;110m\]" -local BG111="\[\033[48;5;111m\]" -local BG112="\[\033[48;5;112m\]" -local BG113="\[\033[48;5;113m\]" -local BG114="\[\033[48;5;114m\]" -local BG115="\[\033[48;5;115m\]" -local BG116="\[\033[48;5;116m\]" -local BG117="\[\033[48;5;117m\]" -local BG118="\[\033[48;5;118m\]" -local BG119="\[\033[48;5;119m\]" -local BG120="\[\033[48;5;120m\]" -local BG121="\[\033[48;5;121m\]" -local BG122="\[\033[48;5;122m\]" -local BG123="\[\033[48;5;123m\]" -local BG124="\[\033[48;5;124m\]" -local BG125="\[\033[48;5;125m\]" -local BG126="\[\033[48;5;126m\]" -local BG127="\[\033[48;5;127m\]" -local BG128="\[\033[48;5;128m\]" -local BG129="\[\033[48;5;129m\]" -local BG130="\[\033[48;5;130m\]" -local BG131="\[\033[48;5;131m\]" -local BG132="\[\033[48;5;132m\]" -local BG133="\[\033[48;5;133m\]" -local BG134="\[\033[48;5;134m\]" -local BG135="\[\033[48;5;135m\]" -local BG136="\[\033[48;5;136m\]" -local BG137="\[\033[48;5;137m\]" -local BG138="\[\033[48;5;138m\]" -local BG139="\[\033[48;5;139m\]" -local BG140="\[\033[48;5;140m\]" -local BG141="\[\033[48;5;141m\]" -local BG142="\[\033[48;5;142m\]" -local BG143="\[\033[48;5;143m\]" -local BG144="\[\033[48;5;144m\]" -local BG145="\[\033[48;5;145m\]" -local BG146="\[\033[48;5;146m\]" -local BG147="\[\033[48;5;147m\]" -local BG148="\[\033[48;5;148m\]" -local BG149="\[\033[48;5;149m\]" -local BG150="\[\033[48;5;150m\]" -local BG151="\[\033[48;5;151m\]" -local BG152="\[\033[48;5;152m\]" -local BG153="\[\033[48;5;153m\]" -local BG154="\[\033[48;5;154m\]" -local BG155="\[\033[48;5;155m\]" -local BG156="\[\033[48;5;156m\]" -local BG157="\[\033[48;5;157m\]" -local BG158="\[\033[48;5;158m\]" -local BG159="\[\033[48;5;159m\]" -local BG160="\[\033[48;5;160m\]" -local BG161="\[\033[48;5;161m\]" -local BG162="\[\033[48;5;162m\]" -local BG163="\[\033[48;5;163m\]" -local BG164="\[\033[48;5;164m\]" -local BG165="\[\033[48;5;165m\]" -local BG166="\[\033[48;5;166m\]" -local BG167="\[\033[48;5;167m\]" -local BG168="\[\033[48;5;168m\]" -local BG169="\[\033[48;5;169m\]" -local BG170="\[\033[48;5;170m\]" -local BG171="\[\033[48;5;171m\]" -local BG172="\[\033[48;5;172m\]" -local BG173="\[\033[48;5;173m\]" -local BG174="\[\033[48;5;174m\]" -local BG175="\[\033[48;5;175m\]" -local BG176="\[\033[48;5;176m\]" -local BG177="\[\033[48;5;177m\]" -local BG178="\[\033[48;5;178m\]" -local BG179="\[\033[48;5;179m\]" -local BG180="\[\033[48;5;180m\]" -local BG181="\[\033[48;5;181m\]" -local BG182="\[\033[48;5;182m\]" -local BG183="\[\033[48;5;183m\]" -local BG184="\[\033[48;5;184m\]" -local BG185="\[\033[48;5;185m\]" -local BG186="\[\033[48;5;186m\]" -local BG187="\[\033[48;5;187m\]" -local BG188="\[\033[48;5;188m\]" -local BG189="\[\033[48;5;189m\]" -local BG190="\[\033[48;5;190m\]" -local BG191="\[\033[48;5;191m\]" -local BG192="\[\033[48;5;192m\]" -local BG193="\[\033[48;5;193m\]" -local BG194="\[\033[48;5;194m\]" -local BG195="\[\033[48;5;195m\]" -local BG196="\[\033[48;5;196m\]" -local BG197="\[\033[48;5;197m\]" -local BG198="\[\033[48;5;198m\]" -local BG199="\[\033[48;5;199m\]" -local BG200="\[\033[48;5;200m\]" -local BG201="\[\033[48;5;201m\]" -local BG202="\[\033[48;5;202m\]" -local BG203="\[\033[48;5;203m\]" -local BG204="\[\033[48;5;204m\]" -local BG205="\[\033[48;5;205m\]" -local BG206="\[\033[48;5;206m\]" -local BG207="\[\033[48;5;207m\]" -local BG208="\[\033[48;5;208m\]" -local BG209="\[\033[48;5;209m\]" -local BG210="\[\033[48;5;210m\]" -local BG211="\[\033[48;5;211m\]" -local BG212="\[\033[48;5;212m\]" -local BG213="\[\033[48;5;213m\]" -local BG214="\[\033[48;5;214m\]" -local BG215="\[\033[48;5;215m\]" -local BG216="\[\033[48;5;216m\]" -local BG217="\[\033[48;5;217m\]" -local BG218="\[\033[48;5;218m\]" -local BG219="\[\033[48;5;219m\]" -local BG220="\[\033[48;5;220m\]" -local BG221="\[\033[48;5;221m\]" -local BG222="\[\033[48;5;222m\]" -local BG223="\[\033[48;5;223m\]" -local BG224="\[\033[48;5;224m\]" -local BG225="\[\033[48;5;225m\]" -local BG226="\[\033[48;5;226m\]" -local BG227="\[\033[48;5;227m\]" -local BG228="\[\033[48;5;228m\]" -local BG229="\[\033[48;5;229m\]" -local BG230="\[\033[48;5;230m\]" -local BG231="\[\033[48;5;231m\]" -local BG232="\[\033[48;5;232m\]" -local BG233="\[\033[48;5;233m\]" -local BG234="\[\033[48;5;234m\]" -local BG235="\[\033[48;5;235m\]" -local BG236="\[\033[48;5;236m\]" -local BG237="\[\033[48;5;237m\]" -local BG238="\[\033[48;5;238m\]" -local BG239="\[\033[48;5;239m\]" -local BG240="\[\033[48;5;240m\]" -local BG241="\[\033[48;5;241m\]" -local BG242="\[\033[48;5;242m\]" -local BG243="\[\033[48;5;243m\]" -local BG244="\[\033[48;5;244m\]" -local BG245="\[\033[48;5;245m\]" -local BG246="\[\033[48;5;246m\]" -local BG247="\[\033[48;5;247m\]" -local BG248="\[\033[48;5;248m\]" -local BG249="\[\033[48;5;249m\]" -local BG250="\[\033[48;5;250m\]" -local BG251="\[\033[48;5;251m\]" -local BG252="\[\033[48;5;252m\]" -local BG253="\[\033[48;5;253m\]" -local BG254="\[\033[48;5;254m\]" -local BG255="\[\033[48;5;255m\]" -local BG256="\[\033[48;5;256m\]" diff --git a/bash/16bit.colors.bak b/bash/16bit.colors.bak deleted file mode 100644 index eba441e..0000000 --- a/bash/16bit.colors.bak +++ /dev/null @@ -1,515 +0,0 @@ -# Based on https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit -local S1="\[\033[38;5;1m\]" -local S2="\[\033[38;5;2m\]" -local S3="\[\033[38;5;3m\]" -local S4="\[\033[38;5;4m\]" -local S5="\[\033[38;5;5m\]" -local S6="\[\033[38;5;6m\]" -local S7="\[\033[38;5;7m\]" -local S8="\[\033[38;5;8m\]" -local S9="\[\033[38;5;9m\]" -local S10="\[\033[38;5;10m\]" -local S11="\[\033[38;5;11m\]" -local S12="\[\033[38;5;12m\]" -local S13="\[\033[38;5;13m\]" -local S14="\[\033[38;5;14m\]" -local S15="\[\033[38;5;15m\]" -local S16="\[\033[38;5;16m\]" -local S17="\[\033[38;5;17m\]" -local S18="\[\033[38;5;18m\]" -local S19="\[\033[38;5;19m\]" -local S20="\[\033[38;5;20m\]" -local S21="\[\033[38;5;21m\]" -local S22="\[\033[38;5;22m\]" -local S23="\[\033[38;5;23m\]" -local S24="\[\033[38;5;24m\]" -local S25="\[\033[38;5;25m\]" -local S26="\[\033[38;5;26m\]" -local S27="\[\033[38;5;27m\]" -local S28="\[\033[38;5;28m\]" -local SA9="\[\033[38;5;29m\]" -local S30="\[\033[38;5;30m\]" -local S31="\[\033[38;5;31m\]" -local S32="\[\033[38;5;32m\]" -local S33="\[\033[38;5;33m\]" -local S34="\[\033[38;5;34m\]" -local S35="\[\033[38;5;35m\]" -local S36="\[\033[38;5;36m\]" -local S37="\[\033[38;5;37m\]" -local S38="\[\033[38;5;38m\]" -local S38="\[\033[38;5;39m\]" -local S40="\[\033[38;5;40m\]" -local S41="\[\033[38;5;41m\]" -local S42="\[\033[38;5;42m\]" -local S43="\[\033[38;5;43m\]" -local S44="\[\033[38;5;44m\]" -local S45="\[\033[38;5;45m\]" -local S46="\[\033[38;5;46m\]" -local S47="\[\033[38;5;47m\]" -local S48="\[\033[38;5;48m\]" -local S49="\[\033[38;5;49m\]" -local S50="\[\033[38;5;50m\]" -local S51="\[\033[38;5;51m\]" -local S52="\[\033[38;5;52m\]" -local S53="\[\033[38;5;53m\]" -local S54="\[\033[38;5;54m\]" -local S55="\[\033[38;5;55m\]" -local S56="\[\033[38;5;56m\]" -local S57="\[\033[38;5;57m\]" -local S58="\[\033[38;5;58m\]" -local S59="\[\033[38;5;59m\]" -local S60="\[\033[38;5;60m\]" -local S61="\[\033[38;5;61m\]" -local S62="\[\033[38;5;62m\]" -local S63="\[\033[38;5;63m\]" -local S64="\[\033[38;5;64m\]" -local S65="\[\033[38;5;65m\]" -local S66="\[\033[38;5;66m\]" -local S67="\[\033[38;5;67m\]" -local S68="\[\033[38;5;68m\]" -local S69="\[\033[38;5;69m\]" -local S70="\[\033[38;5;70m\]" -local S71="\[\033[38;5;71m\]" -local S72="\[\033[38;5;72m\]" -local S73="\[\033[38;5;73m\]" -local S74="\[\033[38;5;74m\]" -local S75="\[\033[38;5;75m\]" -local S76="\[\033[38;5;76m\]" -local S77="\[\033[38;5;77m\]" -local S78="\[\033[38;5;78m\]" -local S79="\[\033[38;5;79m\]" -local S80="\[\033[38;5;80m\]" -local S81="\[\033[38;5;81m\]" -local S82="\[\033[38;5;82m\]" -local S83="\[\033[38;5;83m\]" -local S84="\[\033[38;5;84m\]" -local S85="\[\033[38;5;85m\]" -local S86="\[\033[38;5;86m\]" -local S87="\[\033[38;5;87m\]" -local S88="\[\033[38;5;88m\]" -local S89="\[\033[38;5;89m\]" -local S90="\[\033[38;5;90m\]" -local S91="\[\033[38;5;91m\]" -local S92="\[\033[38;5;92m\]" -local S93="\[\033[38;5;93m\]" -local S94="\[\033[38;5;94m\]" -local S95="\[\033[38;5;95m\]" -local S96="\[\033[38;5;96m\]" -local S97="\[\033[38;5;97m\]" -local S98="\[\033[38;5;98m\]" -local S99="\[\033[38;5;99m\]" -local S100="\[\033[38;5;100m\]" -local S101="\[\033[38;5;101m\]" -local S102="\[\033[38;5;102m\]" -local S103="\[\033[38;5;103m\]" -local S104="\[\033[38;5;104m\]" -local S105="\[\033[38;5;105m\]" -local S106="\[\033[38;5;106m\]" -local S107="\[\033[38;5;107m\]" -local S108="\[\033[38;5;108m\]" -local S109="\[\033[38;5;109m\]" -local S110="\[\033[38;5;110m\]" -local S111="\[\033[38;5;111m\]" -local S112="\[\033[38;5;112m\]" -local S113="\[\033[38;5;113m\]" -local S114="\[\033[38;5;114m\]" -local S115="\[\033[38;5;115m\]" -local S116="\[\033[38;5;116m\]" -local S117="\[\033[38;5;117m\]" -local S118="\[\033[38;5;118m\]" -local S119="\[\033[38;5;119m\]" -local S120="\[\033[38;5;120m\]" -local S121="\[\033[38;5;121m\]" -local S122="\[\033[38;5;122m\]" -local S123="\[\033[38;5;123m\]" -local S124="\[\033[38;5;124m\]" -local S125="\[\033[38;5;125m\]" -local S126="\[\033[38;5;126m\]" -local S127="\[\033[38;5;127m\]" -local S128="\[\033[38;5;128m\]" -local S129="\[\033[38;5;129m\]" -local S130="\[\033[38;5;130m\]" -local S131="\[\033[38;5;131m\]" -local S132="\[\033[38;5;132m\]" -local S133="\[\033[38;5;133m\]" -local S134="\[\033[38;5;134m\]" -local S135="\[\033[38;5;135m\]" -local S136="\[\033[38;5;136m\]" -local S137="\[\033[38;5;137m\]" -local S138="\[\033[38;5;138m\]" -local S139="\[\033[38;5;139m\]" -local S140="\[\033[38;5;140m\]" -local S141="\[\033[38;5;141m\]" -local S142="\[\033[38;5;142m\]" -local S143="\[\033[38;5;143m\]" -local S144="\[\033[38;5;144m\]" -local S145="\[\033[38;5;145m\]" -local S146="\[\033[38;5;146m\]" -local S147="\[\033[38;5;147m\]" -local S148="\[\033[38;5;148m\]" -local S149="\[\033[38;5;149m\]" -local S150="\[\033[38;5;150m\]" -local S151="\[\033[38;5;151m\]" -local S152="\[\033[38;5;152m\]" -local S153="\[\033[38;5;153m\]" -local S154="\[\033[38;5;154m\]" -local S155="\[\033[38;5;155m\]" -local S156="\[\033[38;5;156m\]" -local S157="\[\033[38;5;157m\]" -local S158="\[\033[38;5;158m\]" -local S159="\[\033[38;5;159m\]" -local S160="\[\033[38;5;160m\]" -local S161="\[\033[38;5;161m\]" -local S162="\[\033[38;5;162m\]" -local S163="\[\033[38;5;163m\]" -local S164="\[\033[38;5;164m\]" -local S165="\[\033[38;5;165m\]" -local S166="\[\033[38;5;166m\]" -local S167="\[\033[38;5;167m\]" -local S168="\[\033[38;5;168m\]" -local S169="\[\033[38;5;169m\]" -local S170="\[\033[38;5;170m\]" -local S171="\[\033[38;5;171m\]" -local S172="\[\033[38;5;172m\]" -local S173="\[\033[38;5;173m\]" -local S174="\[\033[38;5;174m\]" -local S175="\[\033[38;5;175m\]" -local S176="\[\033[38;5;176m\]" -local S177="\[\033[38;5;177m\]" -local S178="\[\033[38;5;178m\]" -local S179="\[\033[38;5;179m\]" -local S180="\[\033[38;5;180m\]" -local S181="\[\033[38;5;181m\]" -local S182="\[\033[38;5;182m\]" -local S183="\[\033[38;5;183m\]" -local S184="\[\033[38;5;184m\]" -local S185="\[\033[38;5;185m\]" -local S186="\[\033[38;5;186m\]" -local S187="\[\033[38;5;187m\]" -local S188="\[\033[38;5;188m\]" -local S189="\[\033[38;5;189m\]" -local S190="\[\033[38;5;190m\]" -local S191="\[\033[38;5;191m\]" -local S192="\[\033[38;5;192m\]" -local S193="\[\033[38;5;193m\]" -local S194="\[\033[38;5;194m\]" -local S195="\[\033[38;5;195m\]" -local S196="\[\033[38;5;196m\]" -local S197="\[\033[38;5;197m\]" -local S198="\[\033[38;5;198m\]" -local S199="\[\033[38;5;199m\]" -local S200="\[\033[38;5;200m\]" -local S201="\[\033[38;5;201m\]" -local S202="\[\033[38;5;202m\]" -local S203="\[\033[38;5;203m\]" -local S204="\[\033[38;5;204m\]" -local S205="\[\033[38;5;205m\]" -local S206="\[\033[38;5;206m\]" -local S207="\[\033[38;5;207m\]" -local S208="\[\033[38;5;208m\]" -local S209="\[\033[38;5;209m\]" -local S210="\[\033[38;5;210m\]" -local S211="\[\033[38;5;211m\]" -local S212="\[\033[38;5;212m\]" -local S213="\[\033[38;5;213m\]" -local S214="\[\033[38;5;214m\]" -local S215="\[\033[38;5;215m\]" -local S216="\[\033[38;5;216m\]" -local S217="\[\033[38;5;217m\]" -local S218="\[\033[38;5;218m\]" -local S219="\[\033[38;5;219m\]" -local S220="\[\033[38;5;220m\]" -local S221="\[\033[38;5;221m\]" -local S222="\[\033[38;5;222m\]" -local S223="\[\033[38;5;223m\]" -local S224="\[\033[38;5;224m\]" -local S225="\[\033[38;5;225m\]" -local S226="\[\033[38;5;226m\]" -local S227="\[\033[38;5;227m\]" -local S228="\[\033[38;5;228m\]" -local S229="\[\033[38;5;229m\]" -local S230="\[\033[38;5;230m\]" -local S231="\[\033[38;5;231m\]" -local S232="\[\033[38;5;232m\]" -local S233="\[\033[38;5;233m\]" -local S234="\[\033[38;5;234m\]" -local S235="\[\033[38;5;235m\]" -local S236="\[\033[38;5;236m\]" -local S237="\[\033[38;5;237m\]" -local S238="\[\033[38;5;238m\]" -local S239="\[\033[38;5;239m\]" -local S240="\[\033[38;5;240m\]" -local S241="\[\033[38;5;241m\]" -local S242="\[\033[38;5;242m\]" -local S243="\[\033[38;5;243m\]" -local S244="\[\033[38;5;244m\]" -local S245="\[\033[38;5;245m\]" -local S246="\[\033[38;5;246m\]" -local S247="\[\033[38;5;247m\]" -local S248="\[\033[38;5;248m\]" -local S249="\[\033[38;5;249m\]" -local S250="\[\033[38;5;250m\]" -local S251="\[\033[38;5;251m\]" -local S252="\[\033[38;5;252m\]" -local S253="\[\033[38;5;253m\]" -local S254="\[\033[38;5;254m\]" -local S255="\[\033[38;5;255m\]" -local S256="\[\033[38;5;256m\]" - -# background -local BG1="\[\033[48;5;1m\]" -local BG2="\[\033[48;5;2m\]" -local BG3="\[\033[48;5;3m\]" -local BG4="\[\033[48;5;4m\]" -local BG5="\[\033[48;5;5m\]" -local BG6="\[\033[48;5;6m\]" -local BG7="\[\033[48;5;7m\]" -local BG8="\[\033[48;5;8m\]" -local BG9="\[\033[48;5;9m\]" -local BG10="\[\033[48;5;10m\]" -local BG11="\[\033[48;5;11m\]" -local BG12="\[\033[48;5;12m\]" -local BG13="\[\033[48;5;13m\]" -local BG14="\[\033[48;5;14m\]" -local BG15="\[\033[48;5;15m\]" -local BG16="\[\033[48;5;16m\]" -local BG17="\[\033[48;5;17m\]" -local BG18="\[\033[48;5;18m\]" -local BG19="\[\033[48;5;19m\]" -local BG20="\[\033[48;5;20m\]" -local BG21="\[\033[48;5;21m\]" -local BG22="\[\033[48;5;22m\]" -local BG23="\[\033[48;5;23m\]" -local BG24="\[\033[48;5;24m\]" -local BG25="\[\033[48;5;25m\]" -local BG26="\[\033[48;5;26m\]" -local BG27="\[\033[48;5;27m\]" -local BG28="\[\033[48;5;28m\]" -local BGA9="\[\033[48;5;29m\]" -local BG30="\[\033[48;5;30m\]" -local BG31="\[\033[48;5;31m\]" -local BG32="\[\033[48;5;32m\]" -local BG33="\[\033[48;5;33m\]" -local BG34="\[\033[48;5;34m\]" -local BG35="\[\033[48;5;35m\]" -local BG36="\[\033[48;5;36m\]" -local BG37="\[\033[48;5;37m\]" -local BG38="\[\033[48;5;38m\]" -local BG38="\[\033[48;5;39m\]" -local BG40="\[\033[48;5;40m\]" -local BG41="\[\033[48;5;41m\]" -local BG42="\[\033[48;5;42m\]" -local BG43="\[\033[48;5;43m\]" -local BG44="\[\033[48;5;44m\]" -local BG45="\[\033[48;5;45m\]" -local BG46="\[\033[48;5;46m\]" -local BG47="\[\033[48;5;47m\]" -local BG48="\[\033[48;5;48m\]" -local BG49="\[\033[48;5;49m\]" -local BG50="\[\033[48;5;50m\]" -local BG51="\[\033[48;5;51m\]" -local BG52="\[\033[48;5;52m\]" -local BG53="\[\033[48;5;53m\]" -local BG54="\[\033[48;5;54m\]" -local BG55="\[\033[48;5;55m\]" -local BG56="\[\033[48;5;56m\]" -local BG57="\[\033[48;5;57m\]" -local BG58="\[\033[48;5;58m\]" -local BG59="\[\033[48;5;59m\]" -local BG60="\[\033[48;5;60m\]" -local BG61="\[\033[48;5;61m\]" -local BG62="\[\033[48;5;62m\]" -local BG63="\[\033[48;5;63m\]" -local BG64="\[\033[48;5;64m\]" -local BG65="\[\033[48;5;65m\]" -local BG66="\[\033[48;5;66m\]" -local BG67="\[\033[48;5;67m\]" -local BG68="\[\033[48;5;68m\]" -local BG69="\[\033[48;5;69m\]" -local BG70="\[\033[48;5;70m\]" -local BG71="\[\033[48;5;71m\]" -local BG72="\[\033[48;5;72m\]" -local BG73="\[\033[48;5;73m\]" -local BG74="\[\033[48;5;74m\]" -local BG75="\[\033[48;5;75m\]" -local BG76="\[\033[48;5;76m\]" -local BG77="\[\033[48;5;77m\]" -local BG78="\[\033[48;5;78m\]" -local BG79="\[\033[48;5;79m\]" -local BG80="\[\033[48;5;80m\]" -local BG81="\[\033[48;5;81m\]" -local BG82="\[\033[48;5;82m\]" -local BG83="\[\033[48;5;83m\]" -local BG84="\[\033[48;5;84m\]" -local BG85="\[\033[48;5;85m\]" -local BG86="\[\033[48;5;86m\]" -local BG87="\[\033[48;5;87m\]" -local BG88="\[\033[48;5;88m\]" -local BG89="\[\033[48;5;89m\]" -local BG90="\[\033[48;5;90m\]" -local BG91="\[\033[48;5;91m\]" -local BG92="\[\033[48;5;92m\]" -local BG93="\[\033[48;5;93m\]" -local BG94="\[\033[48;5;94m\]" -local BG95="\[\033[48;5;95m\]" -local BG96="\[\033[48;5;96m\]" -local BG97="\[\033[48;5;97m\]" -local BG98="\[\033[48;5;98m\]" -local BG99="\[\033[48;5;99m\]" -local BG100="\[\033[48;5;100m\]" -local BG101="\[\033[48;5;101m\]" -local BG102="\[\033[48;5;102m\]" -local BG103="\[\033[48;5;103m\]" -local BG104="\[\033[48;5;104m\]" -local BG105="\[\033[48;5;105m\]" -local BG106="\[\033[48;5;106m\]" -local BG107="\[\033[48;5;107m\]" -local BG108="\[\033[48;5;108m\]" -local BG109="\[\033[48;5;109m\]" -local BG110="\[\033[48;5;110m\]" -local BG111="\[\033[48;5;111m\]" -local BG112="\[\033[48;5;112m\]" -local BG113="\[\033[48;5;113m\]" -local BG114="\[\033[48;5;114m\]" -local BG115="\[\033[48;5;115m\]" -local BG116="\[\033[48;5;116m\]" -local BG117="\[\033[48;5;117m\]" -local BG118="\[\033[48;5;118m\]" -local BG119="\[\033[48;5;119m\]" -local BG120="\[\033[48;5;120m\]" -local BG121="\[\033[48;5;121m\]" -local BG122="\[\033[48;5;122m\]" -local BG123="\[\033[48;5;123m\]" -local BG124="\[\033[48;5;124m\]" -local BG125="\[\033[48;5;125m\]" -local BG126="\[\033[48;5;126m\]" -local BG127="\[\033[48;5;127m\]" -local BG128="\[\033[48;5;128m\]" -local BG129="\[\033[48;5;129m\]" -local BG130="\[\033[48;5;130m\]" -local BG131="\[\033[48;5;131m\]" -local BG132="\[\033[48;5;132m\]" -local BG133="\[\033[48;5;133m\]" -local BG134="\[\033[48;5;134m\]" -local BG135="\[\033[48;5;135m\]" -local BG136="\[\033[48;5;136m\]" -local BG137="\[\033[48;5;137m\]" -local BG138="\[\033[48;5;138m\]" -local BG139="\[\033[48;5;139m\]" -local BG140="\[\033[48;5;140m\]" -local BG141="\[\033[48;5;141m\]" -local BG142="\[\033[48;5;142m\]" -local BG143="\[\033[48;5;143m\]" -local BG144="\[\033[48;5;144m\]" -local BG145="\[\033[48;5;145m\]" -local BG146="\[\033[48;5;146m\]" -local BG147="\[\033[48;5;147m\]" -local BG148="\[\033[48;5;148m\]" -local BG149="\[\033[48;5;149m\]" -local BG150="\[\033[48;5;150m\]" -local BG151="\[\033[48;5;151m\]" -local BG152="\[\033[48;5;152m\]" -local BG153="\[\033[48;5;153m\]" -local BG154="\[\033[48;5;154m\]" -local BG155="\[\033[48;5;155m\]" -local BG156="\[\033[48;5;156m\]" -local BG157="\[\033[48;5;157m\]" -local BG158="\[\033[48;5;158m\]" -local BG159="\[\033[48;5;159m\]" -local BG160="\[\033[48;5;160m\]" -local BG161="\[\033[48;5;161m\]" -local BG162="\[\033[48;5;162m\]" -local BG163="\[\033[48;5;163m\]" -local BG164="\[\033[48;5;164m\]" -local BG165="\[\033[48;5;165m\]" -local BG166="\[\033[48;5;166m\]" -local BG167="\[\033[48;5;167m\]" -local BG168="\[\033[48;5;168m\]" -local BG169="\[\033[48;5;169m\]" -local BG170="\[\033[48;5;170m\]" -local BG171="\[\033[48;5;171m\]" -local BG172="\[\033[48;5;172m\]" -local BG173="\[\033[48;5;173m\]" -local BG174="\[\033[48;5;174m\]" -local BG175="\[\033[48;5;175m\]" -local BG176="\[\033[48;5;176m\]" -local BG177="\[\033[48;5;177m\]" -local BG178="\[\033[48;5;178m\]" -local BG179="\[\033[48;5;179m\]" -local BG180="\[\033[48;5;180m\]" -local BG181="\[\033[48;5;181m\]" -local BG182="\[\033[48;5;182m\]" -local BG183="\[\033[48;5;183m\]" -local BG184="\[\033[48;5;184m\]" -local BG185="\[\033[48;5;185m\]" -local BG186="\[\033[48;5;186m\]" -local BG187="\[\033[48;5;187m\]" -local BG188="\[\033[48;5;188m\]" -local BG189="\[\033[48;5;189m\]" -local BG190="\[\033[48;5;190m\]" -local BG191="\[\033[48;5;191m\]" -local BG192="\[\033[48;5;192m\]" -local BG193="\[\033[48;5;193m\]" -local BG194="\[\033[48;5;194m\]" -local BG195="\[\033[48;5;195m\]" -local BG196="\[\033[48;5;196m\]" -local BG197="\[\033[48;5;197m\]" -local BG198="\[\033[48;5;198m\]" -local BG199="\[\033[48;5;199m\]" -local BG200="\[\033[48;5;200m\]" -local BG201="\[\033[48;5;201m\]" -local BG202="\[\033[48;5;202m\]" -local BG203="\[\033[48;5;203m\]" -local BG204="\[\033[48;5;204m\]" -local BG205="\[\033[48;5;205m\]" -local BG206="\[\033[48;5;206m\]" -local BG207="\[\033[48;5;207m\]" -local BG208="\[\033[48;5;208m\]" -local BG209="\[\033[48;5;209m\]" -local BG210="\[\033[48;5;210m\]" -local BG211="\[\033[48;5;211m\]" -local BG212="\[\033[48;5;212m\]" -local BG213="\[\033[48;5;213m\]" -local BG214="\[\033[48;5;214m\]" -local BG215="\[\033[48;5;215m\]" -local BG216="\[\033[48;5;216m\]" -local BG217="\[\033[48;5;217m\]" -local BG218="\[\033[48;5;218m\]" -local BG219="\[\033[48;5;219m\]" -local BG220="\[\033[48;5;220m\]" -local BG221="\[\033[48;5;221m\]" -local BG222="\[\033[48;5;222m\]" -local BG223="\[\033[48;5;223m\]" -local BG224="\[\033[48;5;224m\]" -local BG225="\[\033[48;5;225m\]" -local BG226="\[\033[48;5;226m\]" -local BG227="\[\033[48;5;227m\]" -local BG228="\[\033[48;5;228m\]" -local BG229="\[\033[48;5;229m\]" -local BG230="\[\033[48;5;230m\]" -local BG231="\[\033[48;5;231m\]" -local BG232="\[\033[48;5;232m\]" -local BG233="\[\033[48;5;233m\]" -local BG234="\[\033[48;5;234m\]" -local BG235="\[\033[48;5;235m\]" -local BG236="\[\033[48;5;236m\]" -local BG237="\[\033[48;5;237m\]" -local BG238="\[\033[48;5;238m\]" -local BG239="\[\033[48;5;239m\]" -local BG240="\[\033[48;5;240m\]" -local BG241="\[\033[48;5;241m\]" -local BG242="\[\033[48;5;242m\]" -local BG243="\[\033[48;5;243m\]" -local BG244="\[\033[48;5;244m\]" -local BG245="\[\033[48;5;245m\]" -local BG246="\[\033[48;5;246m\]" -local BG247="\[\033[48;5;247m\]" -local BG248="\[\033[48;5;248m\]" -local BG249="\[\033[48;5;249m\]" -local BG250="\[\033[48;5;250m\]" -local BG251="\[\033[48;5;251m\]" -local BG252="\[\033[48;5;252m\]" -local BG253="\[\033[48;5;253m\]" -local BG254="\[\033[48;5;254m\]" -local BG255="\[\033[48;5;255m\]" -local BG256="\[\033[48;5;256m\]" diff --git a/bash/4bit.colors b/bash/4bit.colors deleted file mode 100644 index 71b5a76..0000000 --- a/bash/4bit.colors +++ /dev/null @@ -1,31 +0,0 @@ -local NONE="\[\033[0m\]" # unsets color to term's fg color - -# regular colors -local K="\[\033[0;30m\]" # black -local R="\[\033[0;31m\]" # red -local G="\[\033[0;32m\]" # green -local Y="\[\033[0;33m\]" # yellow -local B="\[\033[0;34m\]" # blue -local M="\[\033[0;35m\]" # magenta -local C="\[\033[0;36m\]" # cyan -local W="\[\033[0;37m\]" # white - -# emphasized (bolded) colors -local EMK="\[\033[1;30m\]" -local EMR="\[\033[1;31m\]" -local EMG="\[\033[1;32m\]" -local EMY="\[\033[1;33m\]" -local EMB="\[\033[1;34m\]" -local EMM="\[\033[1;35m\]" -local EMC="\[\033[1;36m\]" -local EMW="\[\033[1;37m\]" - -# background colors -local BGK="\[\033[40m\]" -local BGR="\[\033[41m\]" -local BGG="\[\033[42m\]" -local BGY="\[\033[43m\]" -local BGB="\[\033[44m\]" -local BGM="\[\033[45m\]" -local BGC="\[\033[46m\]" -local BGW="\[\033[47m\]" diff --git a/bash/escape_functions.default b/bash/escape_functions.default deleted file mode 100644 index d71cb91..0000000 --- a/bash/escape_functions.default +++ /dev/null @@ -1 +0,0 @@ -local ESC_SEQ_START ="\[\033[" diff --git a/bash/hex b/bash/hex deleted file mode 100644 index 4f9a4f5..0000000 --- a/bash/hex +++ /dev/null @@ -1,257 +0,0 @@ - -#000000 -#800000 -#008000 -#808000 -#000080 -#800080 -#008080 -#c0c0c0 -#808080 -#ff0000 -#00ff00 -#ffff00 -#0000ff -#ff00ff -#00ffff -#ffffff -#000000 -#00005f -#000087 -#0000af -#0000d7 -#0000ff -#005f00 -#005f5f -#005f87 -#005faf -#005fd7 -#005fff -#008700 -#00875f -#008787 -#0087af -#0087d7 -#0087ff -#00af00 -#00af5f -#00af87 -#00afaf -#00afd7 -#00afff -#00d700 -#00d75f -#00d787 -#00d7af -#00d7d7 -#00d7ff -#00ff00 -#00ff5f -#00ff87 -#00ffaf -#00ffd7 -#00ffff -#5f0000 -#5f005f -#5f0087 -#5f00af -#5f00d7 -#5f00ff -#5f5f00 -#5f5f5f -#5f5f87 -#5f5faf -#5f5fd7 -#5f5fff -#5f8700 -#5f875f -#5f8787 -#5f87af -#5f87d7 -#5f87ff -#5faf00 -#5faf5f -#5faf87 -#5fafaf -#5fafd7 -#5fafff -#5fd700 -#5fd75f -#5fd787 -#5fd7af -#5fd7d7 -#5fd7ff -#5fff00 -#5fff5f -#5fff87 -#5fffaf -#5fffd7 -#5fffff -#870000 -#87005f -#870087 -#8700af -#8700d7 -#8700ff -#875f00 -#875f5f -#875f87 -#875faf -#875fd7 -#875fff -#878700 -#87875f -#878787 -#8787af -#8787d7 -#8787ff -#87af00 -#87af5f -#87af87 -#87afaf -#87afd7 -#87afff -#87d700 -#87d75f -#87d787 -#87d7af -#87d7d7 -#87d7ff -#87ff00 -#87ff5f -#87ff87 -#87ffaf -#87ffd7 -#87ffff -#af0000 -#af005f -#af0087 -#af00af -#af00d7 -#af00ff -#af5f00 -#af5f5f -#af5f87 -#af5faf -#af5fd7 -#af5fff -#af8700 -#af875f -#af8787 -#af87af -#af87d7 -#af87ff -#afaf00 -#afaf5f -#afaf87 -#afafaf -#afafd7 -#afafff -#afd700 -#afd75f -#afd787 -#afd7af -#afd7d7 -#afd7ff -#afff00 -#afff5f -#afff87 -#afffaf -#afffd7 -#afffff -#d70000 -#d7005f -#d70087 -#d700af -#d700d7 -#d700ff -#d75f00 -#d75f5f -#d75f87 -#d75faf -#d75fd7 -#d75fff -#d78700 -#d7875f -#d78787 -#d787af -#d787d7 -#d787ff -#d7af00 -#d7af5f -#d7af87 -#d7afaf -#d7afd7 -#d7afff -#d7d700 -#d7d75f -#d7d787 -#d7d7af -#d7d7d7 -#d7d7ff -#d7ff00 -#d7ff5f -#d7ff87 -#d7ffaf -#d7ffd7 -#d7ffff -#ff0000 -#ff005f -#ff0087 -#ff00af -#ff00d7 -#ff00ff -#ff5f00 -#ff5f5f -#ff5f87 -#ff5faf -#ff5fd7 -#ff5fff -#ff8700 -#ff875f -#ff8787 -#ff87af -#ff87d7 -#ff87ff -#ffaf00 -#ffaf5f -#ffaf87 -#ffafaf -#ffafd7 -#ffafff -#ffd700 -#ffd75f -#ffd787 -#ffd7af -#ffd7d7 -#ffd7ff -#ffff00 -#ffff5f -#ffff87 -#ffffaf -#ffffd7 -#ffffff -#080808 -#121212 -#1c1c1c -#262626 -#303030 -#3a3a3a -#444444 -#4e4e4e -#585858 -#626262 -#6c6c6c -#767676 -#808080 -#8a8a8a -#949494 -#9e9e9e -#a8a8a8 -#b2b2b2 -#bcbcbc -#c6c6c6 -#d0d0d0 -#dadada -#e4e4e4 -#eeeeee diff --git a/bash/prompt b/bash/prompt deleted file mode 100644 index 202da4d..0000000 --- a/bash/prompt +++ /dev/null @@ -1,82 +0,0 @@ -# Fancy PWD display function -## The home directory (HOME) is replaced with a ~ -## The last pwdmaxlen characters of the PWD are displayed -## Leading partial directory names are striped off -## /home/me/stuff -> ~/stuff if USER=me -## /usr/share/big_dir_name -> ../share/big_dir_name if pwdmaxlen=20 -## -## Source: WOLFMAN'S color bash promt - - -## ARRANGE $PWD AND STORE IT IN $NEW_PWD -bash_prompt_command() { - # How many characters of the $PWD should be kept - local pwdmaxlen=25 - - # Indicate that there has been dir truncation - local trunc_symbol=".." - - # Store local dir - local dir=${PWD##*/} - - # Which length to use - pwdmaxlen=$(( ( pwdmaxlen < ${#dir} ) ? ${#dir} : pwdmaxlen )) - - NEW_PWD=${PWD/#$HOME/\~} - - local pwdoffset=$(( ${#NEW_PWD} - pwdmaxlen )) - - # Generate name - if [ ${pwdoffset} -gt "0" ] - then - NEW_PWD=${NEW_PWD:$pwdoffset:$pwdmaxlen} - NEW_PWD=${trunc_symbol}/${NEW_PWD#*/} - fi -} - - -## COLORIZE -bash_prompt() { - case $TERM in - xterm*|rxvt*) - local TITLEBAR="\[\033]0;\u:${NEW_PWD}\007\]" - ;; - *) - local TITLEBAR="" - ;; - esac - local NONE="\[\033[0m\]" # unsets color to term's fg color - - source ~/.bash/4bit.colors - source ~/.bash/16bit.colors - - local UC=$S111 # user's color - local HC=$S222 # host color - local PC="\[\033[38;2;255;155;135m\]" - [ $UID -eq "0" ] && UC=$R # root's color - - - PS1="$TITLEBAR ${EMK}[${UC}\u${EMG}@${HC}\h ${PC}\${NEW_PWD}${EMK}]${EMC}\\$ ${S139}" - - - # without colors: PS1="[\u@\h \${NEW_PWD}]\\$ " - # extra backslash in front of \$ to make bash colorize the prompt - - # for terminal line coloring, leaving the rest standard - none="$(tput sgr0)" - trap 'echo -ne "${none}"' DEBUG -} - - -## Bash provides an environment variable called PROMPT_COMMAND. -## The contents of this variable are executed as a regular Bash command -## just before Bash displays a prompt. -## We want it to call our own command to truncate PWD and store it in NEW_PWD -PROMPT_COMMAND=bash_prompt_command - -## Call bash_promnt only once, then unset it (not needed any more) -## It will set $PS1 with colors and relative to $NEW_PWD, -## which gets updated by $PROMT_COMMAND on behalf of the terminal -bash_prompt -unset bash_prompt -## EOF diff --git a/common/README.md b/common/README.md index 4eba887..e18fce9 100644 --- a/common/README.md +++ b/common/README.md @@ -8,4 +8,4 @@ This directory contains configurations that work across all operating systems. - Git configuration - Editor configs (vim, etc.) - GNU tool aliases -- Color schemes and themes \ No newline at end of file +- Color schemes and themes diff --git a/common/ai-context/AGENTS.md b/common/ai-context/AGENTS.md new file mode 100644 index 0000000..52a5c9b --- /dev/null +++ b/common/ai-context/AGENTS.md @@ -0,0 +1,55 @@ +# Agent Context + +This file provides context for AI coding assistants (Codex, Copilot, Claude, etc.). + +## Developer Profile + +- Works across multiple organizations — treat each project independently +- Uses multiple AI tools depending on task requirements + +## Tech Stack + +### Languages (preference order) +1. Rust - backend, systems, CLI tools +2. Python - backend, scripting, automation +3. TypeScript - frontend applications +4. Bash - simple scripts only + +### Frameworks +- Frontend: Next.js (TypeScript), React Native +- Backend: Flask (Python), Actix-web (Rust) + +### Infrastructure +- Containers: Docker, Docker Compose +- Orchestration: Kubernetes +- IaC: Terraform +- Package managers: pacman, Homebrew, apt (depending on OS) + +## Code Style Guidelines + +- Concise over verbose +- Explicit over clever +- No premature abstractions +- Comments only when logic isn't obvious +- Error handling at boundaries, not everywhere +- Tests in `tests/`, source in `src/` + +## Project Structure + +Preferred layout: +``` +src/ - source code +tests/ - tests +docker/ - container configs +k8s/ - kubernetes manifests +infra/ - terraform and other IaC +architecture/ - design docs +``` + +Prefers git submodules over monorepos. + +## Communication + +- Direct responses, no filler +- OS-specific commands only (no multi-platform alternatives unless asked) +- Honest feedback over false validation diff --git a/common/ai-context/CLAUDE.md b/common/ai-context/CLAUDE.md new file mode 100644 index 0000000..7f41fd1 --- /dev/null +++ b/common/ai-context/CLAUDE.md @@ -0,0 +1,42 @@ +# Claude Code Context + +## Machine Context + +Two files describe the current machine: +- `~/MACHINE.md` — static: what this machine is *for*, preferences, paths +- a generated state snapshot in the dotfiles repo under `/ai-context/machine-state.md` + (refresh with `scripts/refresh-machine-state.sh`) + +If you need current system info, run commands directly or refresh the snapshot. + +## General Preferences + +I work across multiple organizations. Treat each project independently — don't carry assumptions between repos or contexts. + +## Languages & Frameworks + +**Preferred stack:** +- Rust (backend, systems, CLI) +- Python (backend, scripting) +- TypeScript (frontend) +- Bash (simple automation only) + +**Frameworks:** Next.js, React Native, Flask, Actix-web + +## Project Conventions + +- Source in `src/`, tests in `tests/` +- Git submodules over monorepos +- Infrastructure in `docker/`, `k8s/`, `infra/terraform/` + +## How to Work With Me + +- Be direct. No fluff, no excessive caveats. +- Give me commands for my current OS only (check MACHINE.md). +- Don't over-engineer. Minimal viable solution first. +- If I'm wrong, tell me. I value correction over validation. +- Skip emojis unless I use them first. + +## Dotfiles + +My dotfiles repo is github.com/woud420/dotfiles (checked out under `~/workspace/`, exact path varies per machine). If you need to understand my shell setup, git aliases, or tooling, look there. diff --git a/common/ai-context/context.md b/common/ai-context/context.md new file mode 100644 index 0000000..d5da779 --- /dev/null +++ b/common/ai-context/context.md @@ -0,0 +1,65 @@ +# Developer Context + +## About Me + +I work across multiple organizations and contexts. Do not assume knowledge or patterns from one project apply to another. Each project should be treated independently. + +I use multiple AI assistants (Claude, Codex, Copilot, etc.) depending on the task. Keep responses practical and tool-agnostic. + +## Languages (in order of preference) + +1. **Rust** - backend, systems programming, CLI tools +2. **Python** - backend services, scripting, automation +3. **TypeScript** - frontend, full-stack when needed +4. **Bash** - scripting, automation (keep it simple) + +## Frameworks + +| Domain | Preferred | +|--------|-----------| +| Frontend | Next.js (TypeScript), React Native | +| Backend (Python) | Flask | +| Backend (Rust) | Actix-web | + +## Project Structure Preferences + +``` +project/ +├── src/ # Source code +├── tests/ # Tests +├── docker/ # Docker configs +├── k8s/ # Kubernetes manifests (if applicable) +├── infra/terraform/ # Infrastructure as code +├── architecture/ # Design documents +└── project/ # Project documentation +``` + +- Prefer **git submodules** over monorepos +- Keep infrastructure separate from application code +- Tests live in `tests/`, not alongside source + +## Coding Style + +- Be concise. Avoid over-engineering. +- No unnecessary abstractions for one-time operations +- Error handling only where it matters (system boundaries, external APIs) +- Comments only when logic isn't self-evident +- Prefer explicit over clever + +## Tools I Use + +- **Package managers**: pacman (Arch), Homebrew (macOS), apt (Debian/Ubuntu) +- **Containers**: Docker, Docker Compose +- **Orchestration**: Kubernetes (kubectl, k9s, helm) +- **Infrastructure**: Terraform +- **Shell**: zsh with custom functions +- **Editor**: Neovim, Cursor +- **Terminal**: Kitty +- **Search**: fzf, ripgrep, fd + +## Communication Preferences + +- Be direct. Skip pleasantries and excessive caveats. +- When I'm on a specific OS, give me commands for that OS only. +- Don't pad responses with alternatives unless I ask. +- If something is wrong, say so. I prefer correction over false agreement. diff --git a/common/bash/16bit.colors.bak b/common/bash/16bit.colors.bak deleted file mode 100644 index eba441e..0000000 --- a/common/bash/16bit.colors.bak +++ /dev/null @@ -1,515 +0,0 @@ -# Based on https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit -local S1="\[\033[38;5;1m\]" -local S2="\[\033[38;5;2m\]" -local S3="\[\033[38;5;3m\]" -local S4="\[\033[38;5;4m\]" -local S5="\[\033[38;5;5m\]" -local S6="\[\033[38;5;6m\]" -local S7="\[\033[38;5;7m\]" -local S8="\[\033[38;5;8m\]" -local S9="\[\033[38;5;9m\]" -local S10="\[\033[38;5;10m\]" -local S11="\[\033[38;5;11m\]" -local S12="\[\033[38;5;12m\]" -local S13="\[\033[38;5;13m\]" -local S14="\[\033[38;5;14m\]" -local S15="\[\033[38;5;15m\]" -local S16="\[\033[38;5;16m\]" -local S17="\[\033[38;5;17m\]" -local S18="\[\033[38;5;18m\]" -local S19="\[\033[38;5;19m\]" -local S20="\[\033[38;5;20m\]" -local S21="\[\033[38;5;21m\]" -local S22="\[\033[38;5;22m\]" -local S23="\[\033[38;5;23m\]" -local S24="\[\033[38;5;24m\]" -local S25="\[\033[38;5;25m\]" -local S26="\[\033[38;5;26m\]" -local S27="\[\033[38;5;27m\]" -local S28="\[\033[38;5;28m\]" -local SA9="\[\033[38;5;29m\]" -local S30="\[\033[38;5;30m\]" -local S31="\[\033[38;5;31m\]" -local S32="\[\033[38;5;32m\]" -local S33="\[\033[38;5;33m\]" -local S34="\[\033[38;5;34m\]" -local S35="\[\033[38;5;35m\]" -local S36="\[\033[38;5;36m\]" -local S37="\[\033[38;5;37m\]" -local S38="\[\033[38;5;38m\]" -local S38="\[\033[38;5;39m\]" -local S40="\[\033[38;5;40m\]" -local S41="\[\033[38;5;41m\]" -local S42="\[\033[38;5;42m\]" -local S43="\[\033[38;5;43m\]" -local S44="\[\033[38;5;44m\]" -local S45="\[\033[38;5;45m\]" -local S46="\[\033[38;5;46m\]" -local S47="\[\033[38;5;47m\]" -local S48="\[\033[38;5;48m\]" -local S49="\[\033[38;5;49m\]" -local S50="\[\033[38;5;50m\]" -local S51="\[\033[38;5;51m\]" -local S52="\[\033[38;5;52m\]" -local S53="\[\033[38;5;53m\]" -local S54="\[\033[38;5;54m\]" -local S55="\[\033[38;5;55m\]" -local S56="\[\033[38;5;56m\]" -local S57="\[\033[38;5;57m\]" -local S58="\[\033[38;5;58m\]" -local S59="\[\033[38;5;59m\]" -local S60="\[\033[38;5;60m\]" -local S61="\[\033[38;5;61m\]" -local S62="\[\033[38;5;62m\]" -local S63="\[\033[38;5;63m\]" -local S64="\[\033[38;5;64m\]" -local S65="\[\033[38;5;65m\]" -local S66="\[\033[38;5;66m\]" -local S67="\[\033[38;5;67m\]" -local S68="\[\033[38;5;68m\]" -local S69="\[\033[38;5;69m\]" -local S70="\[\033[38;5;70m\]" -local S71="\[\033[38;5;71m\]" -local S72="\[\033[38;5;72m\]" -local S73="\[\033[38;5;73m\]" -local S74="\[\033[38;5;74m\]" -local S75="\[\033[38;5;75m\]" -local S76="\[\033[38;5;76m\]" -local S77="\[\033[38;5;77m\]" -local S78="\[\033[38;5;78m\]" -local S79="\[\033[38;5;79m\]" -local S80="\[\033[38;5;80m\]" -local S81="\[\033[38;5;81m\]" -local S82="\[\033[38;5;82m\]" -local S83="\[\033[38;5;83m\]" -local S84="\[\033[38;5;84m\]" -local S85="\[\033[38;5;85m\]" -local S86="\[\033[38;5;86m\]" -local S87="\[\033[38;5;87m\]" -local S88="\[\033[38;5;88m\]" -local S89="\[\033[38;5;89m\]" -local S90="\[\033[38;5;90m\]" -local S91="\[\033[38;5;91m\]" -local S92="\[\033[38;5;92m\]" -local S93="\[\033[38;5;93m\]" -local S94="\[\033[38;5;94m\]" -local S95="\[\033[38;5;95m\]" -local S96="\[\033[38;5;96m\]" -local S97="\[\033[38;5;97m\]" -local S98="\[\033[38;5;98m\]" -local S99="\[\033[38;5;99m\]" -local S100="\[\033[38;5;100m\]" -local S101="\[\033[38;5;101m\]" -local S102="\[\033[38;5;102m\]" -local S103="\[\033[38;5;103m\]" -local S104="\[\033[38;5;104m\]" -local S105="\[\033[38;5;105m\]" -local S106="\[\033[38;5;106m\]" -local S107="\[\033[38;5;107m\]" -local S108="\[\033[38;5;108m\]" -local S109="\[\033[38;5;109m\]" -local S110="\[\033[38;5;110m\]" -local S111="\[\033[38;5;111m\]" -local S112="\[\033[38;5;112m\]" -local S113="\[\033[38;5;113m\]" -local S114="\[\033[38;5;114m\]" -local S115="\[\033[38;5;115m\]" -local S116="\[\033[38;5;116m\]" -local S117="\[\033[38;5;117m\]" -local S118="\[\033[38;5;118m\]" -local S119="\[\033[38;5;119m\]" -local S120="\[\033[38;5;120m\]" -local S121="\[\033[38;5;121m\]" -local S122="\[\033[38;5;122m\]" -local S123="\[\033[38;5;123m\]" -local S124="\[\033[38;5;124m\]" -local S125="\[\033[38;5;125m\]" -local S126="\[\033[38;5;126m\]" -local S127="\[\033[38;5;127m\]" -local S128="\[\033[38;5;128m\]" -local S129="\[\033[38;5;129m\]" -local S130="\[\033[38;5;130m\]" -local S131="\[\033[38;5;131m\]" -local S132="\[\033[38;5;132m\]" -local S133="\[\033[38;5;133m\]" -local S134="\[\033[38;5;134m\]" -local S135="\[\033[38;5;135m\]" -local S136="\[\033[38;5;136m\]" -local S137="\[\033[38;5;137m\]" -local S138="\[\033[38;5;138m\]" -local S139="\[\033[38;5;139m\]" -local S140="\[\033[38;5;140m\]" -local S141="\[\033[38;5;141m\]" -local S142="\[\033[38;5;142m\]" -local S143="\[\033[38;5;143m\]" -local S144="\[\033[38;5;144m\]" -local S145="\[\033[38;5;145m\]" -local S146="\[\033[38;5;146m\]" -local S147="\[\033[38;5;147m\]" -local S148="\[\033[38;5;148m\]" -local S149="\[\033[38;5;149m\]" -local S150="\[\033[38;5;150m\]" -local S151="\[\033[38;5;151m\]" -local S152="\[\033[38;5;152m\]" -local S153="\[\033[38;5;153m\]" -local S154="\[\033[38;5;154m\]" -local S155="\[\033[38;5;155m\]" -local S156="\[\033[38;5;156m\]" -local S157="\[\033[38;5;157m\]" -local S158="\[\033[38;5;158m\]" -local S159="\[\033[38;5;159m\]" -local S160="\[\033[38;5;160m\]" -local S161="\[\033[38;5;161m\]" -local S162="\[\033[38;5;162m\]" -local S163="\[\033[38;5;163m\]" -local S164="\[\033[38;5;164m\]" -local S165="\[\033[38;5;165m\]" -local S166="\[\033[38;5;166m\]" -local S167="\[\033[38;5;167m\]" -local S168="\[\033[38;5;168m\]" -local S169="\[\033[38;5;169m\]" -local S170="\[\033[38;5;170m\]" -local S171="\[\033[38;5;171m\]" -local S172="\[\033[38;5;172m\]" -local S173="\[\033[38;5;173m\]" -local S174="\[\033[38;5;174m\]" -local S175="\[\033[38;5;175m\]" -local S176="\[\033[38;5;176m\]" -local S177="\[\033[38;5;177m\]" -local S178="\[\033[38;5;178m\]" -local S179="\[\033[38;5;179m\]" -local S180="\[\033[38;5;180m\]" -local S181="\[\033[38;5;181m\]" -local S182="\[\033[38;5;182m\]" -local S183="\[\033[38;5;183m\]" -local S184="\[\033[38;5;184m\]" -local S185="\[\033[38;5;185m\]" -local S186="\[\033[38;5;186m\]" -local S187="\[\033[38;5;187m\]" -local S188="\[\033[38;5;188m\]" -local S189="\[\033[38;5;189m\]" -local S190="\[\033[38;5;190m\]" -local S191="\[\033[38;5;191m\]" -local S192="\[\033[38;5;192m\]" -local S193="\[\033[38;5;193m\]" -local S194="\[\033[38;5;194m\]" -local S195="\[\033[38;5;195m\]" -local S196="\[\033[38;5;196m\]" -local S197="\[\033[38;5;197m\]" -local S198="\[\033[38;5;198m\]" -local S199="\[\033[38;5;199m\]" -local S200="\[\033[38;5;200m\]" -local S201="\[\033[38;5;201m\]" -local S202="\[\033[38;5;202m\]" -local S203="\[\033[38;5;203m\]" -local S204="\[\033[38;5;204m\]" -local S205="\[\033[38;5;205m\]" -local S206="\[\033[38;5;206m\]" -local S207="\[\033[38;5;207m\]" -local S208="\[\033[38;5;208m\]" -local S209="\[\033[38;5;209m\]" -local S210="\[\033[38;5;210m\]" -local S211="\[\033[38;5;211m\]" -local S212="\[\033[38;5;212m\]" -local S213="\[\033[38;5;213m\]" -local S214="\[\033[38;5;214m\]" -local S215="\[\033[38;5;215m\]" -local S216="\[\033[38;5;216m\]" -local S217="\[\033[38;5;217m\]" -local S218="\[\033[38;5;218m\]" -local S219="\[\033[38;5;219m\]" -local S220="\[\033[38;5;220m\]" -local S221="\[\033[38;5;221m\]" -local S222="\[\033[38;5;222m\]" -local S223="\[\033[38;5;223m\]" -local S224="\[\033[38;5;224m\]" -local S225="\[\033[38;5;225m\]" -local S226="\[\033[38;5;226m\]" -local S227="\[\033[38;5;227m\]" -local S228="\[\033[38;5;228m\]" -local S229="\[\033[38;5;229m\]" -local S230="\[\033[38;5;230m\]" -local S231="\[\033[38;5;231m\]" -local S232="\[\033[38;5;232m\]" -local S233="\[\033[38;5;233m\]" -local S234="\[\033[38;5;234m\]" -local S235="\[\033[38;5;235m\]" -local S236="\[\033[38;5;236m\]" -local S237="\[\033[38;5;237m\]" -local S238="\[\033[38;5;238m\]" -local S239="\[\033[38;5;239m\]" -local S240="\[\033[38;5;240m\]" -local S241="\[\033[38;5;241m\]" -local S242="\[\033[38;5;242m\]" -local S243="\[\033[38;5;243m\]" -local S244="\[\033[38;5;244m\]" -local S245="\[\033[38;5;245m\]" -local S246="\[\033[38;5;246m\]" -local S247="\[\033[38;5;247m\]" -local S248="\[\033[38;5;248m\]" -local S249="\[\033[38;5;249m\]" -local S250="\[\033[38;5;250m\]" -local S251="\[\033[38;5;251m\]" -local S252="\[\033[38;5;252m\]" -local S253="\[\033[38;5;253m\]" -local S254="\[\033[38;5;254m\]" -local S255="\[\033[38;5;255m\]" -local S256="\[\033[38;5;256m\]" - -# background -local BG1="\[\033[48;5;1m\]" -local BG2="\[\033[48;5;2m\]" -local BG3="\[\033[48;5;3m\]" -local BG4="\[\033[48;5;4m\]" -local BG5="\[\033[48;5;5m\]" -local BG6="\[\033[48;5;6m\]" -local BG7="\[\033[48;5;7m\]" -local BG8="\[\033[48;5;8m\]" -local BG9="\[\033[48;5;9m\]" -local BG10="\[\033[48;5;10m\]" -local BG11="\[\033[48;5;11m\]" -local BG12="\[\033[48;5;12m\]" -local BG13="\[\033[48;5;13m\]" -local BG14="\[\033[48;5;14m\]" -local BG15="\[\033[48;5;15m\]" -local BG16="\[\033[48;5;16m\]" -local BG17="\[\033[48;5;17m\]" -local BG18="\[\033[48;5;18m\]" -local BG19="\[\033[48;5;19m\]" -local BG20="\[\033[48;5;20m\]" -local BG21="\[\033[48;5;21m\]" -local BG22="\[\033[48;5;22m\]" -local BG23="\[\033[48;5;23m\]" -local BG24="\[\033[48;5;24m\]" -local BG25="\[\033[48;5;25m\]" -local BG26="\[\033[48;5;26m\]" -local BG27="\[\033[48;5;27m\]" -local BG28="\[\033[48;5;28m\]" -local BGA9="\[\033[48;5;29m\]" -local BG30="\[\033[48;5;30m\]" -local BG31="\[\033[48;5;31m\]" -local BG32="\[\033[48;5;32m\]" -local BG33="\[\033[48;5;33m\]" -local BG34="\[\033[48;5;34m\]" -local BG35="\[\033[48;5;35m\]" -local BG36="\[\033[48;5;36m\]" -local BG37="\[\033[48;5;37m\]" -local BG38="\[\033[48;5;38m\]" -local BG38="\[\033[48;5;39m\]" -local BG40="\[\033[48;5;40m\]" -local BG41="\[\033[48;5;41m\]" -local BG42="\[\033[48;5;42m\]" -local BG43="\[\033[48;5;43m\]" -local BG44="\[\033[48;5;44m\]" -local BG45="\[\033[48;5;45m\]" -local BG46="\[\033[48;5;46m\]" -local BG47="\[\033[48;5;47m\]" -local BG48="\[\033[48;5;48m\]" -local BG49="\[\033[48;5;49m\]" -local BG50="\[\033[48;5;50m\]" -local BG51="\[\033[48;5;51m\]" -local BG52="\[\033[48;5;52m\]" -local BG53="\[\033[48;5;53m\]" -local BG54="\[\033[48;5;54m\]" -local BG55="\[\033[48;5;55m\]" -local BG56="\[\033[48;5;56m\]" -local BG57="\[\033[48;5;57m\]" -local BG58="\[\033[48;5;58m\]" -local BG59="\[\033[48;5;59m\]" -local BG60="\[\033[48;5;60m\]" -local BG61="\[\033[48;5;61m\]" -local BG62="\[\033[48;5;62m\]" -local BG63="\[\033[48;5;63m\]" -local BG64="\[\033[48;5;64m\]" -local BG65="\[\033[48;5;65m\]" -local BG66="\[\033[48;5;66m\]" -local BG67="\[\033[48;5;67m\]" -local BG68="\[\033[48;5;68m\]" -local BG69="\[\033[48;5;69m\]" -local BG70="\[\033[48;5;70m\]" -local BG71="\[\033[48;5;71m\]" -local BG72="\[\033[48;5;72m\]" -local BG73="\[\033[48;5;73m\]" -local BG74="\[\033[48;5;74m\]" -local BG75="\[\033[48;5;75m\]" -local BG76="\[\033[48;5;76m\]" -local BG77="\[\033[48;5;77m\]" -local BG78="\[\033[48;5;78m\]" -local BG79="\[\033[48;5;79m\]" -local BG80="\[\033[48;5;80m\]" -local BG81="\[\033[48;5;81m\]" -local BG82="\[\033[48;5;82m\]" -local BG83="\[\033[48;5;83m\]" -local BG84="\[\033[48;5;84m\]" -local BG85="\[\033[48;5;85m\]" -local BG86="\[\033[48;5;86m\]" -local BG87="\[\033[48;5;87m\]" -local BG88="\[\033[48;5;88m\]" -local BG89="\[\033[48;5;89m\]" -local BG90="\[\033[48;5;90m\]" -local BG91="\[\033[48;5;91m\]" -local BG92="\[\033[48;5;92m\]" -local BG93="\[\033[48;5;93m\]" -local BG94="\[\033[48;5;94m\]" -local BG95="\[\033[48;5;95m\]" -local BG96="\[\033[48;5;96m\]" -local BG97="\[\033[48;5;97m\]" -local BG98="\[\033[48;5;98m\]" -local BG99="\[\033[48;5;99m\]" -local BG100="\[\033[48;5;100m\]" -local BG101="\[\033[48;5;101m\]" -local BG102="\[\033[48;5;102m\]" -local BG103="\[\033[48;5;103m\]" -local BG104="\[\033[48;5;104m\]" -local BG105="\[\033[48;5;105m\]" -local BG106="\[\033[48;5;106m\]" -local BG107="\[\033[48;5;107m\]" -local BG108="\[\033[48;5;108m\]" -local BG109="\[\033[48;5;109m\]" -local BG110="\[\033[48;5;110m\]" -local BG111="\[\033[48;5;111m\]" -local BG112="\[\033[48;5;112m\]" -local BG113="\[\033[48;5;113m\]" -local BG114="\[\033[48;5;114m\]" -local BG115="\[\033[48;5;115m\]" -local BG116="\[\033[48;5;116m\]" -local BG117="\[\033[48;5;117m\]" -local BG118="\[\033[48;5;118m\]" -local BG119="\[\033[48;5;119m\]" -local BG120="\[\033[48;5;120m\]" -local BG121="\[\033[48;5;121m\]" -local BG122="\[\033[48;5;122m\]" -local BG123="\[\033[48;5;123m\]" -local BG124="\[\033[48;5;124m\]" -local BG125="\[\033[48;5;125m\]" -local BG126="\[\033[48;5;126m\]" -local BG127="\[\033[48;5;127m\]" -local BG128="\[\033[48;5;128m\]" -local BG129="\[\033[48;5;129m\]" -local BG130="\[\033[48;5;130m\]" -local BG131="\[\033[48;5;131m\]" -local BG132="\[\033[48;5;132m\]" -local BG133="\[\033[48;5;133m\]" -local BG134="\[\033[48;5;134m\]" -local BG135="\[\033[48;5;135m\]" -local BG136="\[\033[48;5;136m\]" -local BG137="\[\033[48;5;137m\]" -local BG138="\[\033[48;5;138m\]" -local BG139="\[\033[48;5;139m\]" -local BG140="\[\033[48;5;140m\]" -local BG141="\[\033[48;5;141m\]" -local BG142="\[\033[48;5;142m\]" -local BG143="\[\033[48;5;143m\]" -local BG144="\[\033[48;5;144m\]" -local BG145="\[\033[48;5;145m\]" -local BG146="\[\033[48;5;146m\]" -local BG147="\[\033[48;5;147m\]" -local BG148="\[\033[48;5;148m\]" -local BG149="\[\033[48;5;149m\]" -local BG150="\[\033[48;5;150m\]" -local BG151="\[\033[48;5;151m\]" -local BG152="\[\033[48;5;152m\]" -local BG153="\[\033[48;5;153m\]" -local BG154="\[\033[48;5;154m\]" -local BG155="\[\033[48;5;155m\]" -local BG156="\[\033[48;5;156m\]" -local BG157="\[\033[48;5;157m\]" -local BG158="\[\033[48;5;158m\]" -local BG159="\[\033[48;5;159m\]" -local BG160="\[\033[48;5;160m\]" -local BG161="\[\033[48;5;161m\]" -local BG162="\[\033[48;5;162m\]" -local BG163="\[\033[48;5;163m\]" -local BG164="\[\033[48;5;164m\]" -local BG165="\[\033[48;5;165m\]" -local BG166="\[\033[48;5;166m\]" -local BG167="\[\033[48;5;167m\]" -local BG168="\[\033[48;5;168m\]" -local BG169="\[\033[48;5;169m\]" -local BG170="\[\033[48;5;170m\]" -local BG171="\[\033[48;5;171m\]" -local BG172="\[\033[48;5;172m\]" -local BG173="\[\033[48;5;173m\]" -local BG174="\[\033[48;5;174m\]" -local BG175="\[\033[48;5;175m\]" -local BG176="\[\033[48;5;176m\]" -local BG177="\[\033[48;5;177m\]" -local BG178="\[\033[48;5;178m\]" -local BG179="\[\033[48;5;179m\]" -local BG180="\[\033[48;5;180m\]" -local BG181="\[\033[48;5;181m\]" -local BG182="\[\033[48;5;182m\]" -local BG183="\[\033[48;5;183m\]" -local BG184="\[\033[48;5;184m\]" -local BG185="\[\033[48;5;185m\]" -local BG186="\[\033[48;5;186m\]" -local BG187="\[\033[48;5;187m\]" -local BG188="\[\033[48;5;188m\]" -local BG189="\[\033[48;5;189m\]" -local BG190="\[\033[48;5;190m\]" -local BG191="\[\033[48;5;191m\]" -local BG192="\[\033[48;5;192m\]" -local BG193="\[\033[48;5;193m\]" -local BG194="\[\033[48;5;194m\]" -local BG195="\[\033[48;5;195m\]" -local BG196="\[\033[48;5;196m\]" -local BG197="\[\033[48;5;197m\]" -local BG198="\[\033[48;5;198m\]" -local BG199="\[\033[48;5;199m\]" -local BG200="\[\033[48;5;200m\]" -local BG201="\[\033[48;5;201m\]" -local BG202="\[\033[48;5;202m\]" -local BG203="\[\033[48;5;203m\]" -local BG204="\[\033[48;5;204m\]" -local BG205="\[\033[48;5;205m\]" -local BG206="\[\033[48;5;206m\]" -local BG207="\[\033[48;5;207m\]" -local BG208="\[\033[48;5;208m\]" -local BG209="\[\033[48;5;209m\]" -local BG210="\[\033[48;5;210m\]" -local BG211="\[\033[48;5;211m\]" -local BG212="\[\033[48;5;212m\]" -local BG213="\[\033[48;5;213m\]" -local BG214="\[\033[48;5;214m\]" -local BG215="\[\033[48;5;215m\]" -local BG216="\[\033[48;5;216m\]" -local BG217="\[\033[48;5;217m\]" -local BG218="\[\033[48;5;218m\]" -local BG219="\[\033[48;5;219m\]" -local BG220="\[\033[48;5;220m\]" -local BG221="\[\033[48;5;221m\]" -local BG222="\[\033[48;5;222m\]" -local BG223="\[\033[48;5;223m\]" -local BG224="\[\033[48;5;224m\]" -local BG225="\[\033[48;5;225m\]" -local BG226="\[\033[48;5;226m\]" -local BG227="\[\033[48;5;227m\]" -local BG228="\[\033[48;5;228m\]" -local BG229="\[\033[48;5;229m\]" -local BG230="\[\033[48;5;230m\]" -local BG231="\[\033[48;5;231m\]" -local BG232="\[\033[48;5;232m\]" -local BG233="\[\033[48;5;233m\]" -local BG234="\[\033[48;5;234m\]" -local BG235="\[\033[48;5;235m\]" -local BG236="\[\033[48;5;236m\]" -local BG237="\[\033[48;5;237m\]" -local BG238="\[\033[48;5;238m\]" -local BG239="\[\033[48;5;239m\]" -local BG240="\[\033[48;5;240m\]" -local BG241="\[\033[48;5;241m\]" -local BG242="\[\033[48;5;242m\]" -local BG243="\[\033[48;5;243m\]" -local BG244="\[\033[48;5;244m\]" -local BG245="\[\033[48;5;245m\]" -local BG246="\[\033[48;5;246m\]" -local BG247="\[\033[48;5;247m\]" -local BG248="\[\033[48;5;248m\]" -local BG249="\[\033[48;5;249m\]" -local BG250="\[\033[48;5;250m\]" -local BG251="\[\033[48;5;251m\]" -local BG252="\[\033[48;5;252m\]" -local BG253="\[\033[48;5;253m\]" -local BG254="\[\033[48;5;254m\]" -local BG255="\[\033[48;5;255m\]" -local BG256="\[\033[48;5;256m\]" diff --git a/common/git/.gitconfig b/common/git/.gitconfig index 09473cf..f703fed 100644 --- a/common/git/.gitconfig +++ b/common/git/.gitconfig @@ -5,6 +5,10 @@ user=woud420 [color] ui = auto +[commit] + template = ~/.config/git/commit-template.md +[url "git@github.com:"] + insteadOf = https://github.com/ [alias] st = status -sb lg = log --stat @@ -74,4 +78,15 @@ else \ git log --oneline; \ fi; \ - }; f" \ No newline at end of file + }; f" +[filter "lfs"] + clean = git-lfs clean -- %f + smudge = git-lfs smudge -- %f + process = git-lfs filter-process + required = true +[core] + hooksPath = ~/.config/git/hooks +# Machine-local overrides (identity, tool-appended blocks like git-ai trace2). +# Values here win because git reads includes last. +[include] + path = ~/.gitconfig.local diff --git a/common/git/.gitignore_global b/common/git/.gitignore_global index 1e58af4..66d62f8 100644 --- a/common/git/.gitignore_global +++ b/common/git/.gitignore_global @@ -1 +1 @@ -**/.claude/settings.local.json \ No newline at end of file +**/.claude/settings.local.json diff --git a/common/git/commit-template.md b/common/git/commit-template.md new file mode 100644 index 0000000..f080fc6 --- /dev/null +++ b/common/git/commit-template.md @@ -0,0 +1,13 @@ + + +Primary changes: +- + +Reviewer walkthrough: +- + +Correctness and invariants: +- + +Testing and QA: +- diff --git a/common/git/hooks/README.md b/common/git/hooks/README.md new file mode 100644 index 0000000..f6b2344 --- /dev/null +++ b/common/git/hooks/README.md @@ -0,0 +1,43 @@ +# Git Hooks + +These are personal, global Git hooks installed through `core.hooksPath`. + +## Behavior + +- `pre-commit` + - preserves repo-local `.husky/pre-commit`, `.githooks/pre-commit`, and `.git/hooks/pre-commit.local`; + - blocks likely secret files; + - blocks large staged files over 10 MiB by default; + - blocks conflict markers; + - blocks generated-looking files unless `JM_ALLOW_GENERATED_EDITS=1` + (common lockfiles like `Cargo.lock`/`yarn.lock` are allowlisted). + +- `pre-push` + - preserves repo-local `.husky/pre-push`, `.githooks/pre-push`, and `.git/hooks/pre-push.local`; + - runs `git config jm.hooks.prePushCommand` when set; + - runs `scripts/pre-push-check` when executable; + - can auto-run `make check`, package `ci`, package `check`, or package `test` when `JM_GIT_HOOKS_AUTO_PRE_PUSH=1`. + +## Escapes + +- Repo-hook delegation runs repo-controlled code; disable it for untrusted + clones with `git config jm.hooks.runRepoHooks false` (add `--global` to + flip the default and re-enable per trusted repo). +- Disable all personal hooks for one command: `JM_GIT_HOOKS=0 git commit ...` +- Alternate skip flag: `SKIP_JM_HOOKS=1 git commit ...` +- Allow intentional generated output: `JM_ALLOW_GENERATED_EDITS=1 git commit ...` +- Adjust large file limit: `JM_GIT_HOOKS_MAX_BYTES=20971520 git commit ...` + +## Repo-specific checks + +Prefer an explicit local command: + +```bash +git config jm.hooks.prePushCommand "make check" +``` + +Or add an executable script: + +```bash +scripts/pre-push-check +``` diff --git a/common/git/hooks/pre-commit b/common/git/hooks/pre-commit new file mode 100755 index 0000000..b4571f3 --- /dev/null +++ b/common/git/hooks/pre-commit @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${JM_GIT_HOOKS:-1}" == "0" || "${SKIP_JM_HOOKS:-0}" == "1" ]]; then + echo "[jm-hooks] pre-commit skipped by environment" + exit 0 +fi + +repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)" +if [[ -z "$repo_root" ]]; then + exit 0 +fi + +cd "$repo_root" + +# Repo hooks are repo-controlled code. Delegation is on by default so tools +# like husky keep working, but can be disabled for untrusted clones with +# git config jm.hooks.runRepoHooks false (or --global to flip the default) +repo_hooks_trusted() { + # --type=bool normalizes 0/no/off/false; unset or garbage stays trusted + [[ "$(git config --type=bool --get jm.hooks.runRepoHooks 2>/dev/null || echo true)" != "false" ]] +} + +run_repo_hook() { + local hook_path="$1" + if [[ -f "$hook_path" ]]; then + if ! repo_hooks_trusted; then + echo "[jm-hooks] skipping repo hook (jm.hooks.runRepoHooks=false): $hook_path" + return 0 + fi + echo "[jm-hooks] running repo hook: $hook_path" + if [[ -x "$hook_path" ]]; then + "$hook_path" + else + bash "$hook_path" + fi + fi +} + +staged_files=() +while IFS= read -r -d '' f; do + staged_files+=("$f") +done < <(git diff --cached --name-only -z --diff-filter=ACMR) +if [[ "${#staged_files[@]}" -eq 0 ]]; then + exit 0 +fi + +# Preserve common repo-local hook systems even when global core.hooksPath is set. +run_repo_hook ".husky/pre-commit" +run_repo_hook ".githooks/pre-commit" +run_repo_hook ".git/hooks/pre-commit.local" + +failures=0 +max_bytes="${JM_GIT_HOOKS_MAX_BYTES:-10485760}" + +is_secret_path() { + local path="$1" + local base + base="$(basename -- "$path")" + + case "$base" in + .env.example|.env.sample|.env.template|.envrc.example) + return 1 + ;; + .env|.env.*|*.pem|*.key|*.p12|*.pfx|*.p8|*.jks|*.keystore|.netrc|.pgpass|credentials.json|service-account*.json) + return 0 + ;; + id_rsa|id_dsa|id_ecdsa|id_ed25519|id_ecdsa_sk|id_ed25519_sk) + return 0 + ;; + esac + + return 1 +} + +is_generated_blob() { + local path="$1" + local base head_blob + base="$(basename -- "$path")" + + # Lockfiles carry generated-by headers but are meant to be committed. + case "$base" in + *.lock|package-lock.json|yarn.lock|bun.lock|bun.lockb|Pipfile.lock|go.sum|flake.lock) + return 1 + ;; + esac + + # Capture instead of piping into grep -q: an early-exiting grep SIGPIPEs + # the producer, and under pipefail that reads as "no match" on big files. + head_blob="$(git show ":$path" 2>/dev/null | sed -n '1,60p')" || true + grep -Eiq '(do not edit|automatically generated|auto-generated|generated by)' <<<"$head_blob" +} + +has_conflict_markers() { + local path="$1" + local markers + # Single full-input grep (no -q): early-exiting greps SIGPIPE git show, + # which pipefail turns into a silent pass on files larger than the pipe + # buffer. -I treats binary files as non-matching. + markers="$(git show ":$path" 2>/dev/null | grep -InE '^(<<<<<<< |=======$|>>>>>>> )')" || return 1 + # Require a real <<<<<<< marker; bare ======= lines are common as + # heading underlines in plain text and only mean a conflict alongside one. + grep -qE '^[0-9]+:<<<<<<< ' <<<"$markers" || return 1 + printf '%s\n' "$markers" +} + +for file in "${staged_files[@]}"; do + if is_secret_path "$file"; then + echo "[jm-hooks] blocked likely secret file: $file" + echo " Rename to an example/template file or commit with SKIP_JM_HOOKS=1 if intentional." + failures=1 + fi + + if size="$(git cat-file -s ":$file" 2>/dev/null)"; then + if [[ "$size" -gt "$max_bytes" ]]; then + echo "[jm-hooks] blocked oversized staged file: $file (${size} bytes)" + echo " Limit is ${max_bytes} bytes. Use Git LFS or SKIP_JM_HOOKS=1 if intentional." + failures=1 + fi + fi + + if [[ "${JM_ALLOW_GENERATED_EDITS:-0}" != "1" ]] && is_generated_blob "$file"; then + echo "[jm-hooks] staged generated-looking file: $file" + echo " Regenerate from source and set JM_ALLOW_GENERATED_EDITS=1 only when this output is expected." + failures=1 + fi + + if conflict_output="$(has_conflict_markers "$file" || true)" && [[ -n "$conflict_output" ]]; then + echo "[jm-hooks] conflict markers in staged file: $file" + echo "$conflict_output" + failures=1 + fi +done + +if [[ "$failures" -ne 0 ]]; then + echo "[jm-hooks] pre-commit failed" + exit 1 +fi + +echo "[jm-hooks] pre-commit passed" diff --git a/common/git/hooks/pre-push b/common/git/hooks/pre-push new file mode 100755 index 0000000..944c9ce --- /dev/null +++ b/common/git/hooks/pre-push @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ "${JM_GIT_HOOKS:-1}" == "0" || "${SKIP_JM_HOOKS:-0}" == "1" ]]; then + echo "[jm-hooks] pre-push skipped by environment" + exit 0 +fi + +repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)" +if [[ -z "$repo_root" ]]; then + exit 0 +fi + +cd "$repo_root" + +# See pre-commit: disable repo-hook delegation for untrusted clones with +# git config jm.hooks.runRepoHooks false +repo_hooks_trusted() { + # --type=bool normalizes 0/no/off/false; unset or garbage stays trusted + [[ "$(git config --type=bool --get jm.hooks.runRepoHooks 2>/dev/null || echo true)" != "false" ]] +} + +run_repo_hook() { + local hook_path="$1" + shift + if [[ -f "$hook_path" ]]; then + if ! repo_hooks_trusted; then + echo "[jm-hooks] skipping repo hook (jm.hooks.runRepoHooks=false): $hook_path" + return 0 + fi + echo "[jm-hooks] running repo hook: $hook_path" + if [[ -x "$hook_path" ]]; then + "$hook_path" "$@" + else + bash "$hook_path" "$@" + fi + return 0 + fi + return 1 +} + +# Preserve common repo-local hook systems even when global core.hooksPath is set. +if [[ -f ".husky/pre-push" ]]; then + run_repo_hook ".husky/pre-push" "$@" +fi +if [[ -f ".githooks/pre-push" ]]; then + run_repo_hook ".githooks/pre-push" "$@" +fi +if [[ -f ".git/hooks/pre-push.local" ]]; then + run_repo_hook ".git/hooks/pre-push.local" "$@" +fi + +configured_command="$(git config --get jm.hooks.prePushCommand || true)" +if [[ -n "$configured_command" ]]; then + echo "[jm-hooks] running configured pre-push command: $configured_command" + bash -lc "$configured_command" + exit 0 +fi + +if [[ -x "scripts/pre-push-check" ]]; then + echo "[jm-hooks] running scripts/pre-push-check" + scripts/pre-push-check + exit 0 +fi + +if [[ "${JM_GIT_HOOKS_AUTO_PRE_PUSH:-0}" == "1" ]]; then + if [[ -f Makefile ]] && grep -Eq '^check:' Makefile; then + echo "[jm-hooks] running make check" + make check + exit 0 + fi + + if [[ -f package.json ]] && command -v python3 >/dev/null 2>&1; then + script_name="$(python3 - <<'PY' +import json +from pathlib import Path + +try: + package = json.loads(Path("package.json").read_text()) +except Exception: + raise SystemExit(0) + +scripts = package.get("scripts", {}) +for name in ("ci", "check", "test"): + if name in scripts: + print(name) + break +PY +)" + if [[ -n "$script_name" ]]; then + if command -v bun >/dev/null 2>&1 && [[ -f bun.lock || -f bun.lockb ]]; then + echo "[jm-hooks] running bun run $script_name" + bun run "$script_name" + exit 0 + elif command -v npm >/dev/null 2>&1; then + echo "[jm-hooks] running npm run $script_name" + npm run "$script_name" + exit 0 + fi + fi + fi +fi + +echo "[jm-hooks] pre-push passed; no repo-specific check configured" +echo " Set 'git config jm.hooks.prePushCommand \"make check\"' or JM_GIT_HOOKS_AUTO_PRE_PUSH=1 to run checks." diff --git a/common/nvim/init.vim b/common/nvim/init.vim new file mode 100644 index 0000000..ccaaf16 --- /dev/null +++ b/common/nvim/init.vim @@ -0,0 +1,10 @@ +" Neovim compatibility bridge. +" Keep editor behavior in the existing Vimscript config and load it from Neovim. + +set runtimepath^=~/.vim +set runtimepath+=~/.vim/after +let &packpath = &runtimepath + +let g:coc_config_home = expand('~/.config/nvim') + +source ~/.vim/vimrc diff --git a/common/shell-functions/README.md b/common/shell-functions/README.md index a925174..5b37bd2 100644 --- a/common/shell-functions/README.md +++ b/common/shell-functions/README.md @@ -1,98 +1,26 @@ # Shell Functions & Aliases -This directory contains organized shell functions and aliases grouped by tool and purpose. +Sourced by both bash and zsh from `~/.config/shell-functions/` (the installer +copies every `*.sh` file here). -## 📂 Files Overview +## Active -### Core Function Files -- **`fuzzy-vim.sh`** - Enhanced vim wrapper with fuzzy file selection -- **`ssh.sh`** - SSH and remote connection helpers -- **`git.sh`** - Advanced git workflow functions -- **`k8s.sh`** - Kubernetes management functions -- **`docker.sh`** - Docker container management functions -- **`utils.sh`** - General utility functions +| File | Purpose | +|------|---------| +| `editor.sh` | `vi`/`vim`/`vimdiff` and `EDITOR`/`VISUAL` use Neovim when available | +| `which.sh` | Shell-aware `which` that also reports aliases and functions | +| `sudo.sh` | Exports `SUDO_ASKPASS` (rofi GUI prompt via `sudo -A`) when the helper is installed | +| `macos-clipboard.sh` | `pbcopy`/`pbpaste` parity on Linux (wl-clipboard) | +| `kubectl-aliases.sh` | `k` alias for kubectl (`kctx` lives in the shell rc files) | -### Alias Files -- **`kubectl-aliases.sh`** - Kubectl short aliases (`k get p`, `kgpw`, etc.) -- **`git-aliases.sh`** - Git short aliases (`g`, `gs`, `gc`, etc.) -- **`docker-aliases.sh`** - Docker short aliases (`d`, `dc`, `dr`, etc.) -- **`system-aliases.sh`** - System and file operation aliases -- **`modern-tools-aliases.sh`** - Modern CLI tool replacements +## Disabled stubs -## 🚀 Key Features +The remaining files are deliberately kept as ~90-byte disabled stubs so they +can be restored incrementally without breaking installs: -### Git Integration -**Git Config Aliases** (in `.gitconfig`): -```bash -git ch # Fuzzy branch checkout with preview -git flog # Interactive log browser -git fadd # Select files to stage with preview -git llog # Fuzzy search through commits -``` +`git.sh`, `git-aliases.sh`, `docker.sh`, `docker-aliases.sh`, `k8s.sh`, +`ssh.sh`, `utils.sh`, `fuzzy-vim.sh`, `modern-tools-aliases.sh`, +`secrets.sh`, `system-aliases.sh` -**Shell Aliases** (complement git config): -```bash -g # git -gs # git status -gaa # git add . -gcm "message" # git commit -m "message" -gp # git push -``` - -### Kubectl Power Aliases -```bash -# Resource shortcuts -k get p # kubectl get pods -kgpw # kubectl get pods -o wide -kgpy # kubectl get pods -o yaml -kdp # kubectl describe pod -klf # kubectl logs -f - -# Quick operations -kshp pattern # Shell into first pod matching pattern -klp pattern # Logs from first pod matching pattern -krestart deploy # Restart deployment -``` - -Your dotfiles are now fully updated with: - -## ✅ **Updated Structure:** - -**Git Config (.gitconfig):** -- ✅ Added `git ch` - Fuzzy branch checkout with fzf fallback -- ✅ Added `git flog` - Interactive log browser -- ✅ Added `git fadd` - Fuzzy file staging -- ✅ Added `git llog` - Fuzzy commit search -- ✅ Kept all your existing aliases (`st`, `lg`, `cm`, etc.) - -**Shell Functions (shell-functions/):** -- ✅ All functions moved to `~/.config/shell-functions/` as you wanted -- ✅ Kubectl aliases (`k get p`, `kgpw`, etc.) -- ✅ Git shell aliases (`g`, `gs`, `gp`, etc.) -- ✅ Docker aliases (`d`, `dc`, `dr`, etc.) -- ✅ SSH helpers (`sshdot`, `ssht`, etc.) -- ✅ System utilities and modern tool replacements - -**Installation Scripts:** -- ✅ Updated to copy all shell-functions -- ✅ Remote installation handles new structure - -## 🎯 **Usage:** - -```bash -# Git workflows -git ch # Fuzzy branch select -git fadd # Interactive file staging -git flog # Browse commits -g st # Quick status (shell alias) - -# Kubernetes -k get p # kubectl get pods -kgpw # kubectl get pods -o wide -kctx # Switch context with fzf - -# Remote servers -sshdot user@host # SSH with dotfiles auto-install -``` - -Everything is backward compatible and your existing workflow stays the same! \ No newline at end of file +Restoring one means replacing the stub's body and confirming `bash -n` and +`zsh -n` pass (CI runs ShellCheck at error severity over this directory). diff --git a/common/shell-functions/docker-aliases.sh b/common/shell-functions/docker-aliases.sh index 4d2a9dd..476ec01 100644 --- a/common/shell-functions/docker-aliases.sh +++ b/common/shell-functions/docker-aliases.sh @@ -1,4 +1,4 @@ #!/bin/bash # Docker aliases (disabled) -# Docker functionality disabled to avoid conflicts \ No newline at end of file +# Docker functionality disabled to avoid conflicts diff --git a/common/shell-functions/docker.sh b/common/shell-functions/docker.sh index fbedf40..d24d510 100644 --- a/common/shell-functions/docker.sh +++ b/common/shell-functions/docker.sh @@ -1,4 +1,4 @@ #!/bin/bash # Docker functions (disabled) -# Docker functionality disabled to avoid conflicts \ No newline at end of file +# Docker functionality disabled to avoid conflicts diff --git a/common/shell-functions/editor.sh b/common/shell-functions/editor.sh new file mode 100644 index 0000000..20f7e58 --- /dev/null +++ b/common/shell-functions/editor.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +if command -v nvim >/dev/null 2>&1; then + export EDITOR=nvim + export VISUAL=nvim + alias vi='nvim' + alias vim='nvim' + alias vimdiff='nvim -d' +fi diff --git a/common/shell-functions/fuzzy-vim.sh b/common/shell-functions/fuzzy-vim.sh index d7dbb44..28189c8 100644 --- a/common/shell-functions/fuzzy-vim.sh +++ b/common/shell-functions/fuzzy-vim.sh @@ -1,4 +1,4 @@ #!/bin/bash # Fuzzy vim (disabled) -# Fuzzy vim functionality disabled - keeping minimal setup \ No newline at end of file +# Fuzzy vim functionality disabled - keeping minimal setup diff --git a/common/shell-functions/git-aliases.sh b/common/shell-functions/git-aliases.sh index c183876..fa32188 100644 --- a/common/shell-functions/git-aliases.sh +++ b/common/shell-functions/git-aliases.sh @@ -1,4 +1,4 @@ #!/bin/bash # Git aliases (disabled) -# Git functionality disabled - keeping minimal setup \ No newline at end of file +# Git functionality disabled - keeping minimal setup diff --git a/common/shell-functions/git.sh b/common/shell-functions/git.sh index 610327c..9068f52 100644 --- a/common/shell-functions/git.sh +++ b/common/shell-functions/git.sh @@ -1,4 +1,4 @@ #!/bin/bash # Git functions (disabled) -# Git functionality disabled - keeping minimal setup \ No newline at end of file +# Git functionality disabled - keeping minimal setup diff --git a/common/shell-functions/k8s.sh b/common/shell-functions/k8s.sh index 6d9a688..874f666 100644 --- a/common/shell-functions/k8s.sh +++ b/common/shell-functions/k8s.sh @@ -1,4 +1,4 @@ #!/bin/bash # K8s functions (disabled) -# K8s functionality disabled - keeping minimal setup \ No newline at end of file +# K8s functionality disabled - keeping minimal setup diff --git a/common/shell-functions/kubectl-aliases.sh b/common/shell-functions/kubectl-aliases.sh index 6d23b2f..6fd5aa2 100644 --- a/common/shell-functions/kubectl-aliases.sh +++ b/common/shell-functions/kubectl-aliases.sh @@ -7,4 +7,4 @@ if ! command -v kubectl >/dev/null 2>&1; then fi # Core kubectl alias -alias k='kubectl' \ No newline at end of file +alias k='kubectl' diff --git a/common/shell-functions/macos-clipboard.sh b/common/shell-functions/macos-clipboard.sh new file mode 100644 index 0000000..bfdfc3f --- /dev/null +++ b/common/shell-functions/macos-clipboard.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# macOS-compatible clipboard commands for Linux shells. +# On macOS, leave the real pbcopy/pbpaste commands untouched. +if [ "$(uname -s 2>/dev/null)" = "Linux" ]; then + if ! command -v pbcopy >/dev/null 2>&1; then + pbcopy() { + wl-copy "$@" + } + fi + + if ! command -v pbpaste >/dev/null 2>&1; then + pbpaste() { + wl-paste "$@" + } + fi +fi diff --git a/common/shell-functions/modern-tools-aliases.sh b/common/shell-functions/modern-tools-aliases.sh index 31a3da7..743fb1c 100644 --- a/common/shell-functions/modern-tools-aliases.sh +++ b/common/shell-functions/modern-tools-aliases.sh @@ -1,4 +1,4 @@ #!/bin/bash # Modern tools aliases (disabled) -# Modern tools functionality disabled - keeping minimal setup \ No newline at end of file +# Modern tools functionality disabled - keeping minimal setup diff --git a/common/shell-functions/secrets.sh b/common/shell-functions/secrets.sh index 197fcf9..d1e3729 100644 --- a/common/shell-functions/secrets.sh +++ b/common/shell-functions/secrets.sh @@ -1,4 +1,4 @@ #!/bin/bash # Secrets functions (disabled) -# Secrets functionality disabled - keeping minimal setup \ No newline at end of file +# Secrets functionality disabled - keeping minimal setup diff --git a/common/shell-functions/ssh.sh b/common/shell-functions/ssh.sh index 87921f0..3c6d151 100644 --- a/common/shell-functions/ssh.sh +++ b/common/shell-functions/ssh.sh @@ -1,4 +1,4 @@ #!/bin/bash # SSH functions (disabled) -# SSH functionality disabled - keeping minimal setup \ No newline at end of file +# SSH functionality disabled - keeping minimal setup diff --git a/common/shell-functions/sudo.sh b/common/shell-functions/sudo.sh new file mode 100644 index 0000000..02f50c1 --- /dev/null +++ b/common/shell-functions/sudo.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# Sudo askpass for GUI password prompts (used by Claude CLI, etc.) +# The installer copies scripts/sudo-askpass.sh to ~/.local/bin/sudo-askpass, +# so this works regardless of where the dotfiles repo is checked out. +if [[ -x "$HOME/.local/bin/sudo-askpass" ]]; then + export SUDO_ASKPASS="$HOME/.local/bin/sudo-askpass" +fi diff --git a/common/shell-functions/system-aliases.sh b/common/shell-functions/system-aliases.sh index e30d848..779e2c7 100644 --- a/common/shell-functions/system-aliases.sh +++ b/common/shell-functions/system-aliases.sh @@ -1,4 +1,4 @@ #!/bin/bash # System aliases (disabled) -# System functionality disabled - keeping minimal setup \ No newline at end of file +# System functionality disabled - keeping minimal setup diff --git a/common/shell-functions/utils.sh b/common/shell-functions/utils.sh index a7fafb9..71ee591 100644 --- a/common/shell-functions/utils.sh +++ b/common/shell-functions/utils.sh @@ -1,4 +1,4 @@ #!/bin/bash # Utils functions (disabled) -# Utils functionality disabled - keeping minimal setup \ No newline at end of file +# Utils functionality disabled - keeping minimal setup diff --git a/common/shell-functions/which.sh b/common/shell-functions/which.sh new file mode 100644 index 0000000..5a08927 --- /dev/null +++ b/common/shell-functions/which.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +which() { + local show_all=false + if [ "${1:-}" = "-a" ]; then + show_all=true + shift + fi + + if [ "$#" -eq 0 ]; then + printf 'usage: which [-a] command ...\n' >&2 + return 2 + fi + + if [ -n "${ZSH_VERSION:-}" ]; then + if [ "$show_all" = true ]; then + whence -a "$@" + else + whence "$@" + fi + else + if [ "$show_all" = true ]; then + type -a "$@" + return + fi + + local name kind alias_output alias_value path + for name in "$@"; do + kind="$(type -t "$name" 2>/dev/null || true)" + case "$kind" in + alias) + alias_output="$(alias "$name")" + alias_value="${alias_output#alias "$name"=}" + alias_value="${alias_value#\'}" + alias_value="${alias_value%\'}" + printf '%s\n' "$alias_value" + ;; + file) + type -P "$name" + ;; + function|builtin|keyword) + printf '%s is a shell %s\n' "$name" "$kind" + ;; + *) + path="$(command -v "$name" 2>/dev/null || true)" + if [ -n "$path" ]; then + printf '%s\n' "$path" + else + return 1 + fi + ;; + esac + done + fi +} diff --git a/common/shell/.bash_profile b/common/shell/.bash_profile index ede0c94..8a0fc60 100644 --- a/common/shell/.bash_profile +++ b/common/shell/.bash_profile @@ -6,8 +6,13 @@ if [ -f ~/.bashrc ]; then fi # User specific environment and startup programs -export EDITOR=vim -export VISUAL=vim +if command -v nvim >/dev/null 2>&1; then + export EDITOR=nvim + export VISUAL=nvim +else + export EDITOR=vim + export VISUAL=vim +fi # Set PATH so it includes user's private bin if it exists if [ -d "$HOME/bin" ] ; then @@ -19,4 +24,4 @@ if [ -d "$HOME/.local/bin" ] ; then fi export PATH -. "$HOME/.local/bin/env" +[ -f "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env" diff --git a/common/shell/.bashrc b/common/shell/.bashrc index a16f740..a3abfa1 100644 --- a/common/shell/.bashrc +++ b/common/shell/.bashrc @@ -80,8 +80,14 @@ pretty_pwd() { echo "💻" ;; *) - # For bash, use \w for relative path - echo "\w" + case "$PWD" in + "$HOME"/*) + printf '~/%s\n' "${PWD#"$HOME"/}" + ;; + *) + printf '%s\n' "$PWD" + ;; + esac ;; esac } @@ -108,8 +114,8 @@ dynamic_time_prompt() { build_prompt() { local GIT_INFO=$(parse_git_branch) # Note: In bash, we need to escape the $ in the function call - PS1="⭐ ${MAUVE}[${ROSEWATER}\u${MAUVE}@${TEAL}\$(pretty_pwd)${MAUVE}]${PEACH}${GIT_INFO}${RESET} ➔ " - + PS1="⭐ \[${MAUVE}\][\[${ROSEWATER}\]\u\[${MAUVE}\]@\[${TEAL}\]\$(pretty_pwd)\[${MAUVE}\]]\[${PEACH}\]${GIT_INFO}\[${RESET}\] ➔ " + # Optional: Add time to right side of prompt (requires special handling in bash) # For simpler setup, we'll skip the right prompt } @@ -135,6 +141,22 @@ export FZF_DEFAULT_OPTS=" # Source FZF if available [ -f ~/.fzf.bash ] && source ~/.fzf.bash +# PATH helper - prevents duplicates +path_prepend() { + local dir + for dir in "$@"; do + [[ -d "$dir" ]] || continue + case ":$PATH:" in + *":$dir:"*) ;; + *) PATH="$dir:$PATH" ;; + esac + done +} + +path_prepend "/usr/local/bin" "/usr/local/sbin" "/opt/homebrew/bin" \ + "$HOME/bin" "$HOME/.local/bin" "$HOME/.cargo/bin" "$HOME/.git-ai/bin" +export PATH + # Load custom shell functions if [ -d ~/.config/shell-functions ]; then for f in ~/.config/shell-functions/*.sh; do @@ -142,13 +164,6 @@ if [ -d ~/.config/shell-functions ]; then done fi -# Add local bin to PATH if exists -[ -d "$HOME/bin" ] && PATH="$HOME/bin:$PATH" -[ -d "$HOME/.local/bin" ] && PATH="$HOME/.local/bin:$PATH" - -# Export PATH -export PATH - # Enable color support for ls and grep if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" @@ -171,11 +186,33 @@ alias mv='mv -i' # Make less more friendly for non-text input files [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" -# Source shell functions -for func in ~/.config/shell-functions/*.sh; do - [ -r "$func" ] && source "$func" -done +# mise (version manager for Python, Node, etc.) +if command -v mise >/dev/null 2>&1; then + eval "$(mise activate bash)" +fi + +# kubectl context switcher with fzf +kctx() { + local selected + selected=$(kubectl config get-contexts -o name | \ + fzf --prompt="Select context > " \ + --height=40% \ + --layout=reverse \ + --border \ + --ansi) + + if [[ -n "$selected" ]]; then + kubectl config use-context "$selected" + else + echo "No context selected." + fi +} # Source local secrets (if exists) [ -f ~/.env.secrets ] && source ~/.env.secrets -. "$HOME/.local/bin/env" +[ -f "$HOME/.local/bin/env" ] && . "$HOME/.local/bin/env" + +# Machine-local overrides - kept out of the repo, survives reinstalls +if [ -f "$HOME/.bashrc.local" ]; then + . "$HOME/.bashrc.local" +fi diff --git a/common/shell/.bashrc.server b/common/shell/.bashrc.server index c531fda..88e2fde 100644 --- a/common/shell/.bashrc.server +++ b/common/shell/.bashrc.server @@ -41,7 +41,7 @@ else fi # Simple prompt without emoji -PS1="${GREEN}\u${RESET}@${BLUE}\h${RESET}:${CYAN}\w${RESET}${YELLOW}\$(parse_git_branch)${RESET}\$ " +PS1="\[${GREEN}\]\u\[${RESET}\]@\[${BLUE}\]\h\[${RESET}\]:\[${CYAN}\]\w\[${RESET}\]\[${YELLOW}\]\$(parse_git_branch)\[${RESET}\]\$ " # Load GNU aliases if available if [ -f ~/.gnu_aliases ]; then @@ -100,8 +100,16 @@ alias ....='cd ../../..' export PATH # Set default editor -export EDITOR=vim -export VISUAL=vim +if command -v nvim >/dev/null 2>&1; then + export EDITOR=nvim + export VISUAL=nvim + alias vi='nvim' + alias vim='nvim' + alias vimdiff='nvim -d' +else + export EDITOR=vim + export VISUAL=vim +fi # Enable programmable completion features if ! shopt -oq posix; then @@ -110,4 +118,9 @@ if ! shopt -oq posix; then elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi -fi \ No newline at end of file +fi + +# Machine-local overrides - kept out of the repo, survives reinstalls +if [ -f "$HOME/.bashrc.local" ]; then + . "$HOME/.bashrc.local" +fi diff --git a/common/shell/.dircolors b/common/shell/.dircolors index a20008b..ca467d1 100644 --- a/common/shell/.dircolors +++ b/common/shell/.dircolors @@ -29,4 +29,4 @@ or 38;5;204 # orphaned symlink = red *.json 38;5;229 # JSON = yellow # Special cases -Makefile 38;5;216 \ No newline at end of file +Makefile 38;5;216 diff --git a/common/shell/.gnu_aliases b/common/shell/.gnu_aliases index 055b551..fe5476d 100644 --- a/common/shell/.gnu_aliases +++ b/common/shell/.gnu_aliases @@ -21,12 +21,14 @@ if [ "$(uname -s)" = "Darwin" ]; then safe_alias grep 'ggrep' fallback 'grep' safe_alias xargs 'gxargs' fallback 'xargs' safe_alias tar 'gtar' fallback 'tar' - safe_alias which 'gwhich' fallback 'which' safe_alias make 'gmake' fallback 'make' safe_alias dircolors 'gdircolors' fallback 'dircolors' - # If dircolors is available, eval LS_COLORS - if command -v dircolors >/dev/null 2>&1; then + # If a real dircolors binary is available, eval LS_COLORS (command -v would + # match the alias above even when no binary exists on macOS) + if command -v gdircolors >/dev/null 2>&1; then + eval "$(gdircolors -b ~/.dircolors)" + elif [ -x /usr/bin/dircolors ] || [ -x /bin/dircolors ]; then eval "$(dircolors -b ~/.dircolors)" fi fi diff --git a/common/shell/.zshrc b/common/shell/.zshrc index 6f5f34d..928e766 100644 --- a/common/shell/.zshrc +++ b/common/shell/.zshrc @@ -5,10 +5,11 @@ compinit # Load colors autoload -Uz colors && colors setopt prompt_subst +PROMPT_EOL_MARK='' # Git branch info setup autoload -Uz vcs_info -precmd() { +precmd() { vcs_info # Set tab title to show current directory (last 2 path components) print -Pn "\e]0;%2~\a" @@ -39,7 +40,7 @@ function kube_prompt() { echo "(k8s:$context)" fi } - + function pretty_git() { # Don't forget the space at the end of the echo [[ -n "${vcs_info_msg_0_}" ]] && echo "${vcs_info_msg_0_} " @@ -129,14 +130,11 @@ path_prepend() { done } -path_prepend "/usr/local/bin" "/usr/local/sbin" "$HOME/bin" "$HOME/.cargo/bin" +path_prepend "/opt/homebrew/bin" "/usr/local/bin" "/usr/local/sbin" "$HOME/bin" "$HOME/.local/bin" "$HOME/.cargo/bin" "$HOME/.git-ai/bin" -if [[ -d "$HOME/.pyenv" ]]; then - export PYENV_ROOT="$HOME/.pyenv" - path_prepend "$PYENV_ROOT/bin" - if command -v pyenv >/dev/null 2>&1; then - eval "$(pyenv init -)" - fi +# mise (version manager for Python, Node, etc.) +if command -v mise >/dev/null 2>&1; then + eval "$(mise activate zsh)" fi [[ -r "$HOME/.gnu_aliases" ]] && source "$HOME/.gnu_aliases" @@ -153,7 +151,7 @@ export FZF_DEFAULT_OPTS=" [ -f ~/.fzf.zsh ] && source ~/.fzf.zsh # Load custom shell functions -for f in ~/.config/shell-functions/*.sh; do +for f in ~/.config/shell-functions/*.sh(N); do [[ -r "$f" ]] && source "$f" done @@ -176,5 +174,15 @@ function kctx() { # Source local secrets (if exists) [[ -f ~/.env.secrets ]] && source ~/.env.secrets -export PATH="/opt/homebrew/bin:$PATH" -. "$HOME/.local/bin/env" +[[ -f "$HOME/.local/bin/env" ]] && . "$HOME/.local/bin/env" + +if [[ -d "$HOME/.bun" ]]; then + export BUN_INSTALL="$HOME/.bun" + path_prepend "$BUN_INSTALL/bin" + [[ -s "$BUN_INSTALL/_bun" ]] && source "$BUN_INSTALL/_bun" +fi + +# Machine-local overrides - kept out of the repo, survives reinstalls +if [[ -f "$HOME/.zshrc.local" ]]; then + . "$HOME/.zshrc.local" +fi diff --git a/common/ssh/config b/common/ssh/config index 23a27d7..3654923 100644 --- a/common/ssh/config +++ b/common/ssh/config @@ -1,29 +1,14 @@ -# SSH config with automatic dotfile deployment +# IgnoreUnknown keeps macOS-only options harmless on Linux openssh +IgnoreUnknown UseKeychain -# Example host with automatic dotfile setup -# Host myserver -# HostName example.com -# User myuser -# RemoteCommand bash -c "curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/scripts/quick-install.sh | bash && exec bash" -# RequestTTY yes - -# For all hosts - send local environment variables Host * - # Send your local terminal type - SendEnv TERM - SendEnv LANG LC_* - - # Keep connections alive - ServerAliveInterval 60 - ServerAliveCountMax 3 - - # Reuse connections - ControlMaster auto - ControlPath ~/.ssh/sockets/%r@%h:%p - ControlPersist 600 - - # Faster connections - Compression yes - - # Forward agent for git operations - ForwardAgent yes \ No newline at end of file + AddKeysToAgent yes + UseKeychain yes + ForwardAgent yes + ServerAliveInterval 60 + ServerAliveCountMax 5 + +Host github.com + HostName github.com + User git + IdentityFile ~/.ssh/github-id-rsa diff --git a/common/themes/custom-purple.conf b/common/themes/custom-purple.conf new file mode 100644 index 0000000..d84e71e --- /dev/null +++ b/common/themes/custom-purple.conf @@ -0,0 +1,77 @@ +# vim:ft=kitty + +## name: Custom Purple (Sway Desktop Match) +## author: local +## blurb: Warm purple/burgundy theme matching Sway, Waybar, Rofi, and Mako + + +# The basic colors +foreground #d0d0d0 +background #221820 +selection_foreground #221820 +selection_background #9d5a7f + +# Cursor colors +cursor #d0d0d0 +cursor_text_color #221820 + +# URL underline color when hovering with mouse +url_color #9d5a7f + +# Kitty window border colors +active_border_color #9d5a7f +inactive_border_color #4a3844 +bell_border_color #d68787 + +# OS Window titlebar colors +wayland_titlebar_color system +macos_titlebar_color system + +# Tab bar colors +active_tab_foreground #221820 +active_tab_background #9d5a7f +inactive_tab_foreground #d0d0d0 +inactive_tab_background #2a1f27 +tab_bar_background #1a1218 + +# Colors for marks (marked text in the terminal) +mark1_foreground #221820 +mark1_background #9d5a7f +mark2_foreground #221820 +mark2_background #6b4456 +mark3_foreground #221820 +mark3_background #87b8a8 + +# The 16 terminal colors + +# black +color0 #2a1f27 +color8 #4a3844 + +# red +color1 #d68787 +color9 #e09898 + +# green +color2 #a3be8c +color10 #b5d4a1 + +# yellow +color3 #d4a373 +color11 #e0b98a + +# blue +color4 #8a9fc5 +color12 #a0b3d4 + +# magenta +color5 #9d5a7f +color13 #b87a9d + +# cyan +color6 #87b8a8 +color14 #a0ccbb + +# white +color7 #d0d0d0 +color15 #e8e8e8 diff --git a/config/htop/htoprc b/config/htop/htoprc deleted file mode 100644 index 7a663a2..0000000 --- a/config/htop/htoprc +++ /dev/null @@ -1,57 +0,0 @@ -# Beware! This file is rewritten by htop when settings are changed in the interface. -# The parser is also very primitive, and not human-friendly. -htop_version=3.4.1 -config_reader_min_version=3 -fields=0 48 17 18 38 39 2 46 47 49 1 -hide_kernel_threads=1 -hide_userland_threads=0 -hide_running_in_container=0 -shadow_other_users=0 -show_thread_names=0 -show_program_path=1 -highlight_base_name=0 -highlight_deleted_exe=1 -shadow_distribution_path_prefix=0 -highlight_megabytes=1 -highlight_threads=1 -highlight_changes=0 -highlight_changes_delay_secs=5 -find_comm_in_cmdline=1 -strip_exe_from_cmdline=1 -header_layout=two_50_50 -header_margin=1 -screen_tabs=1 -detailed_cpu_time=0 -cpu_count_from_one=0 -update_process_names=0 -account_guest_in_cpu_meter=0 -color_scheme=0 -enable_mouse=1 -delay=15 -hide_function_bar=0 -header_text=0 -left_meters=AllCPUs Memory Swap -left_meter_modes=1 1 1 -right_meters=Tasks LoadAverage Uptime -right_meter_modes=2 2 2 -tree_sort_key=0 -tree_sort_direction=1 -tree_view=0 -tree_view_always_by_pid=0 -all_branches_collapsed=0 -screen:Main=PID USER PRIORITY NICE M_VIRT M_RESIDENT M_SHARE STATE PERCENT_CPU PERCENT_MEM TIME Command -.sort_key=PERCENT_CPU -.tree_sort_key=PID -.tree_view=0 -.tree_view_always_by_pid=0 -.sort_direction=1 -.tree_sort_direction=1 -.all_branches_collapsed=0 -screen:I/O=PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command -.sort_key=IO_RATE -.tree_sort_key=PID -.tree_view=0 -.tree_view_always_by_pid=0 -.sort_direction=-1 -.tree_sort_direction=1 -.all_branches_collapsed=0 \ No newline at end of file diff --git a/config/kitty.conf b/config/kitty.conf deleted file mode 100644 index 0210e11..0000000 --- a/config/kitty.conf +++ /dev/null @@ -1,52 +0,0 @@ -# vim:fileencoding=utf-8 -# macOS-specific Kitty configuration - -# BEGIN_KITTY_THEME -include current-theme.conf -# END_KITTY_THEME - -font_family FiraCode Nerd Font -font_size 12.5 -macos_option_as_alt left -shell_integration disabled - -cursor_shape beam -cursor_blink_interval 0.6 ease-in-out -background_opacity 0.95 -enable_audio_bell no - -# Scrollback -scrollback_lines 5000 - -# Performance -sync_to_monitor yes -repaint_delay 5 - -# Clipboard -copy_on_select clipboard - -# Terminal title -window_alert_on_bell yes -tab_bar_edge bottom -tab_bar_style powerline -active_tab_font_style bold -inactive_tab_font_style normal -tab_switch_strategy previous - -# macOS Keyboard shortcuts (cmd+) -map cmd+q quit -map cmd+n new_os_window -map cmd+enter new_window -map cmd+t new_tab -map cmd+w close_tab -map cmd+arrow_right next_tab -map cmd+arrow_left previous_tab -map cmd+plus change_font_size all +1.0 -map cmd+minus change_font_size all -1.0 -map cmd+0 change_font_size all 0 -map cmd+f toggle_fullscreen -map cmd+ctrl+l clear_terminal to_cursor_scroll active - -# Word navigation with Option+Arrow keys -map alt+left send_text all \x1b\x62 -map alt+right send_text all \x1b\x66 diff --git a/config/kitty.conf.bak b/config/kitty.conf.bak deleted file mode 100644 index e9b5ddd..0000000 --- a/config/kitty.conf.bak +++ /dev/null @@ -1,2718 +0,0 @@ -# vim:fileencoding=utf-8:foldmethod=marker - -# BEGIN_KITTY_THEME -# Catppuccin-Frappe -include current-theme.conf -# END_KITTY_THEME - -#: Fonts {{{ - -#: kitty has very powerful font management. You can configure -#: individual font faces and even specify special fonts for particular -#: characters. - -# font_family monospace -# bold_font auto -# italic_font auto -# bold_italic_font auto - -#: You can specify different fonts for the bold/italic/bold-italic -#: variants. The easiest way to select fonts is to run the `kitten -#: choose-fonts` command which will present a nice UI for you to -#: select the fonts you want with previews and support for selecting -#: variable fonts and font features. If you want to learn to select -#: fonts manually, read the font specification syntax -#: . - -# font_size 11.0 - -#: Font size (in pts). - -# force_ltr no - -#: kitty does not support BIDI (bidirectional text), however, for RTL -#: scripts, words are automatically displayed in RTL. That is to say, -#: in an RTL script, the words "HELLO WORLD" display in kitty as -#: "WORLD HELLO", and if you try to select a substring of an RTL- -#: shaped string, you will get the character that would be there had -#: the string been LTR. For example, assuming the Hebrew word ירושלים, -#: selecting the character that on the screen appears to be ם actually -#: writes into the selection buffer the character י. kitty's default -#: behavior is useful in conjunction with a filter to reverse the word -#: order, however, if you wish to manipulate RTL glyphs, it can be -#: very challenging to work with, so this option is provided to turn -#: it off. Furthermore, this option can be used with the command line -#: program GNU FriBidi -#: to get BIDI support, because it will force kitty to always treat -#: the text as LTR, which FriBidi expects for terminals. - -# symbol_map - -#: E.g. symbol_map U+E0A0-U+E0A3,U+E0C0-U+E0C7 PowerlineSymbols - -#: Map the specified Unicode codepoints to a particular font. Useful -#: if you need special rendering for some symbols, such as for -#: Powerline. Avoids the need for patched fonts. Each Unicode code -#: point is specified in the form `U+`. You -#: can specify multiple code points, separated by commas and ranges -#: separated by hyphens. This option can be specified multiple times. -#: The syntax is:: - -#: symbol_map codepoints Font Family Name - -# narrow_symbols - -#: E.g. narrow_symbols U+E0A0-U+E0A3,U+E0C0-U+E0C7 1 - -#: Usually, for Private Use Unicode characters and some symbol/dingbat -#: characters, if the character is followed by one or more spaces, -#: kitty will use those extra cells to render the character larger, if -#: the character in the font has a wide aspect ratio. Using this -#: option you can force kitty to restrict the specified code points to -#: render in the specified number of cells (defaulting to one cell). -#: This option can be specified multiple times. The syntax is:: - -#: narrow_symbols codepoints [optionally the number of cells] - -# disable_ligatures never - -#: Choose how you want to handle multi-character ligatures. The -#: default is to always render them. You can tell kitty to not render -#: them when the cursor is over them by using cursor to make editing -#: easier, or have kitty never render them at all by using always, if -#: you don't like them. The ligature strategy can be set per-window -#: either using the kitty remote control facility or by defining -#: shortcuts for it in kitty.conf, for example:: - -#: map alt+1 disable_ligatures_in active always -#: map alt+2 disable_ligatures_in all never -#: map alt+3 disable_ligatures_in tab cursor - -#: Note that this refers to programming ligatures, typically -#: implemented using the calt OpenType feature. For disabling general -#: ligatures, use the font_features option. - -# font_features - -#: E.g. font_features none - -#: Choose exactly which OpenType features to enable or disable. Note -#: that for the main fonts, features can be specified when selecting -#: the font using the choose-fonts kitten. This setting is useful for -#: fallback fonts. - -#: Some fonts might have features worthwhile in a terminal. For -#: example, Fira Code includes a discretionary feature, zero, which in -#: that font changes the appearance of the zero (0), to make it more -#: easily distinguishable from Ø. Fira Code also includes other -#: discretionary features known as Stylistic Sets which have the tags -#: ss01 through ss20. - -#: For the exact syntax to use for individual features, see the -#: HarfBuzz documentation . - -#: Note that this code is indexed by PostScript name, and not the font -#: family. This allows you to define very precise feature settings; -#: e.g. you can disable a feature in the italic font but not in the -#: regular font. - -#: On Linux, font features are first read from the FontConfig database -#: and then this option is applied, so they can be configured in a -#: single, central place. - -#: To get the PostScript name for a font, use the `fc-scan file.ttf` -#: command on Linux or the `Font Book tool on macOS -#: `__. - -#: Enable alternate zero and oldstyle numerals:: - -#: font_features FiraCode-Retina +zero +onum - -#: Enable only alternate zero in the bold font:: - -#: font_features FiraCode-Bold +zero - -#: Disable the normal ligatures, but keep the calt feature which (in -#: this font) breaks up monotony:: - -#: font_features TT2020StyleB-Regular -liga +calt - -#: In conjunction with force_ltr, you may want to disable Arabic -#: shaping entirely, and only look at their isolated forms if they -#: show up in a document. You can do this with e.g.:: - -#: font_features UnifontMedium +isol -medi -fina -init - -# modify_font - -#: Modify font characteristics such as the position or thickness of -#: the underline and strikethrough. The modifications can have the -#: suffix px for pixels or % for percentage of original value. No -#: suffix means use pts. For example:: - -#: modify_font underline_position -2 -#: modify_font underline_thickness 150% -#: modify_font strikethrough_position 2px - -#: Additionally, you can modify the size of the cell in which each -#: font glyph is rendered and the baseline at which the glyph is -#: placed in the cell. For example:: - -#: modify_font cell_width 80% -#: modify_font cell_height -2px -#: modify_font baseline 3 - -#: Note that modifying the baseline will automatically adjust the -#: underline and strikethrough positions by the same amount. -#: Increasing the baseline raises glyphs inside the cell and -#: decreasing it lowers them. Decreasing the cell size might cause -#: rendering artifacts, so use with care. - -# box_drawing_scale 0.001, 1, 1.5, 2 - -#: The sizes of the lines used for the box drawing Unicode characters. -#: These values are in pts. They will be scaled by the monitor DPI to -#: arrive at a pixel value. There must be four values corresponding to -#: thin, normal, thick, and very thick lines. - -# undercurl_style thin-sparse - -#: The style with which undercurls are rendered. This option takes the -#: form (thin|thick)-(sparse|dense). Thin and thick control the -#: thickness of the undercurl. Sparse and dense control how often the -#: curl oscillates. With sparse the curl will peak once per character, -#: with dense twice. Changing this option dynamically via reloading -#: the config or remote control is undefined. - -# underline_exclusion 1 - -#: By default kitty renders gaps in underlines when they overlap with -#: descenders (the parts of letters below the baseline, such as for y, -#: q, p etc.). This option controls the thickness of the gaps. It can -#: be either a unitless number in which case it is a fraction of the -#: underline thickness as specified in the font or it can have a -#: suffix of px for pixels or pt for points. Set to zero to disable -#: the gaps. Changing this option dynamically via reloading the config -#: or remote control is undefined. - -# text_composition_strategy platform - -#: Control how kitty composites text glyphs onto the background color. -#: The default value of platform tries for text rendering as close to -#: "native" for the platform kitty is running on as possible. - -#: A value of legacy uses the old (pre kitty 0.28) strategy for how -#: glyphs are composited. This will make dark text on light -#: backgrounds look thicker and light text on dark backgrounds -#: thinner. It might also make some text appear like the strokes are -#: uneven. - -#: You can fine tune the actual contrast curve used for glyph -#: composition by specifying up to two space-separated numbers for -#: this setting. - -#: The first number is the gamma adjustment, which controls the -#: thickness of dark text on light backgrounds. Increasing the value -#: will make text appear thicker. The default value for this is 1.0 on -#: Linux and 1.7 on macOS. Valid values are 0.01 and above. The result -#: is scaled based on the luminance difference between the background -#: and the foreground. Dark text on light backgrounds receives the -#: full impact of the curve while light text on dark backgrounds is -#: affected very little. - -#: The second number is an additional multiplicative contrast. It is -#: percentage ranging from 0 to 100. The default value is 0 on Linux -#: and 30 on macOS. - -#: If you wish to achieve similar looking thickness in light and dark -#: themes, a good way to experiment is start by setting the value to -#: 1.0 0 and use a dark theme. Then adjust the second parameter until -#: it looks good. Then switch to a light theme and adjust the first -#: parameter until the perceived thickness matches the dark theme. - -# text_fg_override_threshold 0 - -#: A setting to prevent low contrast between foreground and background -#: colors. Useful when working with applications that use colors that -#: do not contrast well with your preferred color scheme. The default -#: value is 0, which means no color overriding is performed. There are -#: two modes of operation: - -#: A value with the suffix ratio represents the minimum accepted -#: contrast ratio between the foreground and background color. -#: Possible values range from 0.0 ratio to 21.0 ratio. For example, to -#: meet WCAG level AA -#: -#: a value of 4.5 ratio can be provided. The algorithm is implemented -#: using HSLuv which enables it to change the -#: perceived lightness of a color just as much as needed without -#: really changing its hue and saturation. - -#: A value with the suffix % represents the minimum accepted -#: difference in luminance between the foreground and background -#: color, below which kitty will override the foreground color. It is -#: percentage ranging from 0 % to 100 %. If the difference in -#: luminance of the foreground and background is below this threshold, -#: the foreground color will be set to white if the background is dark -#: or black if the background is light. - -#: WARNING: Some programs use characters (such as block characters) -#: for graphics display and may expect to be able to set the -#: foreground and background to the same color (or similar colors). If -#: you see unexpected stripes, dots, lines, incorrect color, no color -#: where you expect color, or any kind of graphic display problem try -#: setting text_fg_override_threshold to 0 to see if this is the cause -#: of the problem or consider using the ratio mode of operation -#: described above instead of the % mode of operation. - -#: }}} - -#: Text cursor customization {{{ - -# cursor #cccccc - -#: Default text cursor color. If set to the special value none the -#: cursor will be rendered with a "reverse video" effect. Its color -#: will be the color of the text in the cell it is over and the text -#: will be rendered with the background color of the cell. Note that -#: if the program running in the terminal sets a cursor color, this -#: takes precedence. Also, the cursor colors are modified if the cell -#: background and foreground colors have very low contrast. Note that -#: some themes set this value, so if you want to override it, place -#: your value after the lines where the theme file is included. - -# cursor_text_color #111111 - -#: The color of text under the cursor. If you want it rendered with -#: the background color of the cell underneath instead, use the -#: special keyword: `background`. Note that if cursor is set to none -#: then this option is ignored. Note that some themes set this value, -#: so if you want to override it, place your value after the lines -#: where the theme file is included. - -# cursor_shape block - -#: The cursor shape can be one of block, beam, underline. Note that -#: when reloading the config this will be changed only if the cursor -#: shape has not been set by the program running in the terminal. This -#: sets the default cursor shape, applications running in the terminal -#: can override it. In particular, shell integration -#: in kitty sets -#: the cursor shape to beam at shell prompts. You can avoid this by -#: setting shell_integration to no-cursor. - -# cursor_shape_unfocused hollow - -#: Defines the text cursor shape when the OS window is not focused. -#: The unfocused cursor shape can be one of block, beam, underline, -#: hollow and unchanged (leave the cursor shape as it is). - -# cursor_beam_thickness 1.5 - -#: The thickness of the beam cursor (in pts). - -# cursor_underline_thickness 2.0 - -#: The thickness of the underline cursor (in pts). - -# cursor_blink_interval -1 - -#: The interval to blink the cursor (in seconds). Set to zero to -#: disable blinking. Negative values mean use system default. Note -#: that the minimum interval will be limited to repaint_delay. You can -#: also animate the cursor blink by specifying an easing function. For -#: example, setting this to option to 0.5 ease-in-out will cause the -#: cursor blink to be animated over a second, in the first half of the -#: second it will go from opaque to transparent and then back again -#: over the next half. You can specify different easing functions for -#: the two halves, for example: -1 linear ease-out. kitty supports all -#: the CSS easing functions . Note that turning on animations -#: uses extra power as it means the screen is redrawn multiple times -#: per blink interval. See also, cursor_stop_blinking_after. - -# cursor_stop_blinking_after 15.0 - -#: Stop blinking cursor after the specified number of seconds of -#: keyboard inactivity. Set to zero to never stop blinking. - -# cursor_trail 0 - -#: Set this to a value larger than zero to enable a "cursor trail" -#: animation. This is an animation that shows a "trail" following the -#: movement of the text cursor. It makes it easy to follow large -#: cursor jumps and makes for a cool visual effect of the cursor -#: zooming around the screen. The actual value of this option controls -#: when the animation is triggered. It is a number of milliseconds. -#: The trail animation only follows cursors that have stayed in their -#: position for longer than the specified number of milliseconds. This -#: prevents trails from appearing for cursors that rapidly change -#: their positions during UI updates in complex applications. See -#: cursor_trail_decay to control the animation speed and -#: cursor_trail_start_threshold to control when a cursor trail is -#: started. - -# cursor_trail_decay 0.1 0.4 - -#: Controls the decay times for the cursor trail effect when the -#: cursor_trail is enabled. This option accepts two positive float -#: values specifying the fastest and slowest decay times in seconds. -#: The first value corresponds to the fastest decay time (minimum), -#: and the second value corresponds to the slowest decay time -#: (maximum). The second value must be equal to or greater than the -#: first value. Smaller values result in a faster decay of the cursor -#: trail. Adjust these values to control how quickly the cursor trail -#: fades away. - -# cursor_trail_start_threshold 2 - -#: Set the distance threshold for starting the cursor trail. This -#: option accepts a positive integer value that represents the minimum -#: number of cells the cursor must move before the trail is started. -#: When the cursor moves less than this threshold, the trail is -#: skipped, reducing unnecessary cursor trail animation. - -#: }}} - -#: Scrollback {{{ - -# scrollback_lines 2000 - -#: Number of lines of history to keep in memory for scrolling back. -#: Memory is allocated on demand. Negative numbers are (effectively) -#: infinite scrollback. Note that using very large scrollback is not -#: recommended as it can slow down performance of the terminal and -#: also use large amounts of RAM. Instead, consider using -#: scrollback_pager_history_size. Note that on config reload if this -#: is changed it will only affect newly created windows, not existing -#: ones. - -# scrollback_indicator_opacity 1.0 - -#: The opacity of the scrollback indicator which is a small colored -#: rectangle that moves along the right hand side of the window as you -#: scroll, indicating what fraction you have scrolled. The default is -#: one which means fully opaque, aka visible. Set to a value between -#: zero and one to make the indicator less visible. - -# scrollback_pager less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER - -#: Program with which to view scrollback in a new window. The -#: scrollback buffer is passed as STDIN to this program. If you change -#: it, make sure the program you use can handle ANSI escape sequences -#: for colors and text formatting. INPUT_LINE_NUMBER in the command -#: line above will be replaced by an integer representing which line -#: should be at the top of the screen. Similarly CURSOR_LINE and -#: CURSOR_COLUMN will be replaced by the current cursor position or -#: set to 0 if there is no cursor, for example, when showing the last -#: command output. - -# scrollback_pager_history_size 0 - -#: Separate scrollback history size (in MB), used only for browsing -#: the scrollback buffer with pager. This separate buffer is not -#: available for interactive scrolling but will be piped to the pager -#: program when viewing scrollback buffer in a separate window. The -#: current implementation stores the data in UTF-8, so approximately -#: 10000 lines per megabyte at 100 chars per line, for pure ASCII, -#: unformatted text. A value of zero or less disables this feature. -#: The maximum allowed size is 4GB. Note that on config reload if this -#: is changed it will only affect newly created windows, not existing -#: ones. - -# scrollback_fill_enlarged_window no - -#: Fill new space with lines from the scrollback buffer after -#: enlarging a window. - -# wheel_scroll_multiplier 5.0 - -#: Multiplier for the number of lines scrolled by the mouse wheel. -#: Note that this is only used for low precision scrolling devices, -#: not for high precision scrolling devices on platforms such as macOS -#: and Wayland. Use negative numbers to change scroll direction. See -#: also wheel_scroll_min_lines. - -# wheel_scroll_min_lines 1 - -#: The minimum number of lines scrolled by the mouse wheel. The scroll -#: multiplier wheel_scroll_multiplier only takes effect after it -#: reaches this number. Note that this is only used for low precision -#: scrolling devices like wheel mice that scroll by very small amounts -#: when using the wheel. With a negative number, the minimum number of -#: lines will always be added. - -# touch_scroll_multiplier 1.0 - -#: Multiplier for the number of lines scrolled by a touchpad. Note -#: that this is only used for high precision scrolling devices on -#: platforms such as macOS and Wayland. Use negative numbers to change -#: scroll direction. - -#: }}} - -#: Mouse {{{ - -# mouse_hide_wait 3.0 - -#: Hide mouse cursor after the specified number of seconds of the -#: mouse not being used. Set to zero to disable mouse cursor hiding. -#: Set to a negative value to hide the mouse cursor immediately when -#: typing text. Disabled by default on macOS as getting it to work -#: robustly with the ever-changing sea of bugs that is Cocoa is too -#: much effort. - -# url_color #0087bd -# url_style curly - -#: The color and style for highlighting URLs on mouse-over. url_style -#: can be one of: none, straight, double, curly, dotted, dashed. - -# open_url_with default - -#: The program to open clicked URLs. The special value default will -#: first look for any URL handlers defined via the open_actions -#: facility and if non -#: are found, it will use the Operating System's default URL handler -#: (open on macOS and xdg-open on Linux). - -# url_prefixes file ftp ftps gemini git gopher http https irc ircs kitty mailto news sftp ssh - -#: The set of URL prefixes to look for when detecting a URL under the -#: mouse cursor. - -# detect_urls yes - -#: Detect URLs under the mouse. Detected URLs are highlighted with an -#: underline and the mouse cursor becomes a hand over them. Even if -#: this option is disabled, URLs are still clickable. See also the -#: underline_hyperlinks option to control how hyperlinks (as opposed -#: to plain text URLs) are displayed. - -# url_excluded_characters - -#: Additional characters to be disallowed from URLs, when detecting -#: URLs under the mouse cursor. By default, all characters that are -#: legal in URLs are allowed. Additionally, newlines are allowed (but -#: stripped). This is to accommodate programs such as mutt that add -#: hard line breaks even for continued lines. \n can be added to this -#: option to disable this behavior. Special characters can be -#: specified using backslash escapes, to specify a backslash use a -#: double backslash. - -# show_hyperlink_targets no - -#: When the mouse hovers over a terminal hyperlink, show the actual -#: URL that will be activated when the hyperlink is clicked. - -# underline_hyperlinks hover - -#: Control how hyperlinks are underlined. They can either be -#: underlined on mouse hover, always (i.e. permanently underlined) or -#: never which means that kitty will not apply any underline styling -#: to hyperlinks. Note that the value of always only applies to real -#: (OSC 8) hyperlinks not text that is detected to be a URL on mouse -#: hover. Uses the url_style and url_color settings for the underline -#: style. Note that reloading the config and changing this value -#: to/from always will only affect text subsequently received by -#: kitty. - -# copy_on_select no - -#: Copy to clipboard or a private buffer on select. With this set to -#: clipboard, selecting text with the mouse will cause the text to be -#: copied to clipboard. Useful on platforms such as macOS that do not -#: have the concept of primary selection. You can instead specify a -#: name such as a1 to copy to a private kitty buffer. Map a shortcut -#: with the paste_from_buffer action to paste from this private -#: buffer. For example:: - -#: copy_on_select a1 -#: map shift+cmd+v paste_from_buffer a1 - -#: Note that copying to the clipboard is a security risk, as all -#: programs, including websites open in your browser can read the -#: contents of the system clipboard. - -# clear_selection_on_clipboard_loss no - -#: When the contents of the clipboard no longer reflect the current -#: selection, clear it. This is primarily useful on platforms such as -#: Linux where selecting text automatically copies it to a special -#: "primary selection" clipboard or if you have copy_on_select set to -#: clipboard. - -#: Note that on macOS the system does not provide notifications when -#: the clipboard owner is changed, so there, copying to clipboard in a -#: non-kitty application will not clear selections even if -#: copy_on_select is enabled. - -# paste_actions quote-urls-at-prompt,confirm - -#: A comma separated list of actions to take when pasting text into -#: the terminal. The supported paste actions are: - -#: quote-urls-at-prompt: -#: If the text being pasted is a URL and the cursor is at a shell prompt, -#: automatically quote the URL (needs shell_integration). -#: replace-dangerous-control-codes -#: Replace dangerous control codes from pasted text, without confirmation. -#: replace-newline -#: Replace the newline character from pasted text, without confirmation. -#: confirm: -#: Confirm the paste if the text to be pasted contains any terminal control codes -#: as this can be dangerous, leading to code execution if the shell/program running -#: in the terminal does not properly handle these. -#: confirm-if-large -#: Confirm the paste if it is very large (larger than 16KB) as pasting -#: large amounts of text into shells can be very slow. -#: filter: -#: Run the filter_paste() function from the file paste-actions.py in -#: the kitty config directory on the pasted text. The text returned by the -#: function will be actually pasted. -#: no-op: -#: Has no effect. - -# strip_trailing_spaces never - -#: Remove spaces at the end of lines when copying to clipboard. A -#: value of smart will do it when using normal selections, but not -#: rectangle selections. A value of always will always do it. - -# select_by_word_characters @-./_~?&=%+# - -#: Characters considered part of a word when double clicking. In -#: addition to these characters any character that is marked as an -#: alphanumeric character in the Unicode database will be matched. - -# select_by_word_characters_forward - -#: Characters considered part of a word when extending the selection -#: forward on double clicking. In addition to these characters any -#: character that is marked as an alphanumeric character in the -#: Unicode database will be matched. - -#: If empty (default) select_by_word_characters will be used for both -#: directions. - -# click_interval -1.0 - -#: The interval between successive clicks to detect double/triple -#: clicks (in seconds). Negative numbers will use the system default -#: instead, if available, or fallback to 0.5. - -# focus_follows_mouse no - -#: Set the active window to the window under the mouse when moving the -#: mouse around. On macOS, this will also cause the OS Window under -#: the mouse to be focused automatically when the mouse enters it. - -# pointer_shape_when_grabbed arrow - -#: The shape of the mouse pointer when the program running in the -#: terminal grabs the mouse. - -# default_pointer_shape beam - -#: The default shape of the mouse pointer. - -# pointer_shape_when_dragging beam crosshair - -#: The default shape of the mouse pointer when dragging across text. -#: The optional second value sets the shape when dragging in -#: rectangular selection mode. - -#: Mouse actions {{{ - -#: Mouse buttons can be mapped to perform arbitrary actions. The -#: syntax is: - -#: .. code-block:: none - -#: mouse_map button-name event-type modes action - -#: Where button-name is one of left, middle, right, b1 ... b8 with -#: added keyboard modifiers. For example: ctrl+shift+left refers to -#: holding the Ctrl+Shift keys while clicking with the left mouse -#: button. The value b1 ... b8 can be used to refer to up to eight -#: buttons on a mouse. - -#: event-type is one of press, release, doublepress, triplepress, -#: click, doubleclick. modes indicates whether the action is performed -#: when the mouse is grabbed by the program running in the terminal, -#: or not. The values are grabbed or ungrabbed or a comma separated -#: combination of them. grabbed refers to when the program running in -#: the terminal has requested mouse events. Note that the click and -#: double click events have a delay of click_interval to disambiguate -#: from double and triple presses. - -#: You can run kitty with the kitty --debug-input command line option -#: to see mouse events. See the builtin actions below to get a sense -#: of what is possible. - -#: If you want to unmap a button, map it to nothing. For example, to -#: disable opening of URLs with a plain click:: - -#: mouse_map left click ungrabbed - -#: See all the mappable actions including mouse actions here -#: . - -#: .. note:: -#: Once a selection is started, releasing the button that started it will -#: automatically end it and no release event will be dispatched. - -# clear_all_mouse_actions no - -#: Remove all mouse action definitions up to this point. Useful, for -#: instance, to remove the default mouse actions. - -#: Click the link under the mouse or move the cursor - -# mouse_map left click ungrabbed mouse_handle_click selection link prompt - -#:: First check for a selection and if one exists do nothing. Then -#:: check for a link under the mouse cursor and if one exists, click -#:: it. Finally check if the click happened at the current shell -#:: prompt and if so, move the cursor to the click location. Note -#:: that this requires shell integration -#:: to work. - -#: Click the link under the mouse or move the cursor even when grabbed - -# mouse_map shift+left click grabbed,ungrabbed mouse_handle_click selection link prompt - -#:: Same as above, except that the action is performed even when the -#:: mouse is grabbed by the program running in the terminal. - -#: Click the link under the mouse cursor - -# mouse_map ctrl+shift+left release grabbed,ungrabbed mouse_handle_click link - -#:: Variant with Ctrl+Shift is present because the simple click based -#:: version has an unavoidable delay of click_interval, to -#:: disambiguate clicks from double clicks. - -#: Discard press event for link click - -# mouse_map ctrl+shift+left press grabbed discard_event - -#:: Prevent this press event from being sent to the program that has -#:: grabbed the mouse, as the corresponding release event is used to -#:: open a URL. - -#: Paste from the primary selection - -# mouse_map middle release ungrabbed paste_from_selection - -#: Start selecting text - -# mouse_map left press ungrabbed mouse_selection normal - -#: Start selecting text in a rectangle - -# mouse_map ctrl+alt+left press ungrabbed mouse_selection rectangle - -#: Select a word - -# mouse_map left doublepress ungrabbed mouse_selection word - -#: Select a line - -# mouse_map left triplepress ungrabbed mouse_selection line - -#: Select line from point - -# mouse_map ctrl+alt+left triplepress ungrabbed mouse_selection line_from_point - -#:: Select from the clicked point to the end of the line. If you -#:: would like to select the word at the point and then extend to the -#:: rest of the line, change `line_from_point` to -#:: `word_and_line_from_point`. - -#: Extend the current selection - -# mouse_map right press ungrabbed mouse_selection extend - -#:: If you want only the end of the selection to be moved instead of -#:: the nearest boundary, use move-end instead of extend. - -#: Paste from the primary selection even when grabbed - -# mouse_map shift+middle release ungrabbed,grabbed paste_selection -# mouse_map shift+middle press grabbed discard_event - -#: Start selecting text even when grabbed - -# mouse_map shift+left press ungrabbed,grabbed mouse_selection normal - -#: Start selecting text in a rectangle even when grabbed - -# mouse_map ctrl+shift+alt+left press ungrabbed,grabbed mouse_selection rectangle - -#: Select a word even when grabbed - -# mouse_map shift+left doublepress ungrabbed,grabbed mouse_selection word - -#: Select a line even when grabbed - -# mouse_map shift+left triplepress ungrabbed,grabbed mouse_selection line - -#: Select line from point even when grabbed - -# mouse_map ctrl+shift+alt+left triplepress ungrabbed,grabbed mouse_selection line_from_point - -#:: Select from the clicked point to the end of the line even when -#:: grabbed. If you would like to select the word at the point and -#:: then extend to the rest of the line, change `line_from_point` to -#:: `word_and_line_from_point`. - -#: Extend the current selection even when grabbed - -# mouse_map shift+right press ungrabbed,grabbed mouse_selection extend - -#: Show clicked command output in pager - -# mouse_map ctrl+shift+right press ungrabbed mouse_show_command_output - -#:: Requires shell integration -#:: to work. - -#: }}} - -#: }}} - -#: Performance tuning {{{ - -# repaint_delay 10 - -#: Delay between screen updates (in milliseconds). Decreasing it, -#: increases frames-per-second (FPS) at the cost of more CPU usage. -#: The default value yields ~100 FPS which is more than sufficient for -#: most uses. Note that to actually achieve 100 FPS, you have to -#: either set sync_to_monitor to no or use a monitor with a high -#: refresh rate. Also, to minimize latency when there is pending input -#: to be processed, this option is ignored. - -# input_delay 3 - -#: Delay before input from the program running in the terminal is -#: processed (in milliseconds). Note that decreasing it will increase -#: responsiveness, but also increase CPU usage and might cause flicker -#: in full screen programs that redraw the entire screen on each loop, -#: because kitty is so fast that partial screen updates will be drawn. -#: This setting is ignored when the input buffer is almost full. - -# sync_to_monitor yes - -#: Sync screen updates to the refresh rate of the monitor. This -#: prevents screen tearing -#: when scrolling. -#: However, it limits the rendering speed to the refresh rate of your -#: monitor. With a very high speed mouse/high keyboard repeat rate, -#: you may notice some slight input latency. If so, set this to no. - -#: }}} - -#: Terminal bell {{{ - -# enable_audio_bell yes - -#: The audio bell. Useful to disable it in environments that require -#: silence. - -# visual_bell_duration 0.0 - -#: The visual bell duration (in seconds). Flash the screen when a bell -#: occurs for the specified number of seconds. Set to zero to disable. -#: The flash is animated, fading in and out over the specified -#: duration. The easing function used for the fading can be -#: controlled. For example, 2.0 linear will casuse the flash to fade -#: in and out linearly. The default if unspecified is to use ease-in- -#: out which fades slowly at the start, middle and end. You can -#: specify different easing functions for the fade-in and fade-out -#: parts, like this: 2.0 ease-in linear. kitty supports all the CSS -#: easing functions . - -# visual_bell_color none - -#: The color used by visual bell. Set to none will fall back to -#: selection background color. If you feel that the visual bell is too -#: bright, you can set it to a darker color. - -# window_alert_on_bell yes - -#: Request window attention on bell. Makes the dock icon bounce on -#: macOS or the taskbar flash on Linux. - -# bell_on_tab "🔔 " - -#: Some text or a Unicode symbol to show on the tab if a window in the -#: tab that does not have focus has a bell. If you want to use leading -#: or trailing spaces, surround the text with quotes. See -#: tab_title_template for how this is rendered. - -#: For backwards compatibility, values of yes, y and true are -#: converted to the default bell symbol and no, n, false and none are -#: converted to the empty string. - -# command_on_bell none - -#: Program to run when a bell occurs. The environment variable -#: KITTY_CHILD_CMDLINE can be used to get the program running in the -#: window in which the bell occurred. - -# bell_path none - -#: Path to a sound file to play as the bell sound. If set to none, the -#: system default bell sound is used. Must be in a format supported by -#: the operating systems sound API, such as WAV or OGA on Linux -#: (libcanberra) or AIFF, MP3 or WAV on macOS (NSSound). - -# linux_bell_theme __custom - -#: The XDG Sound Theme kitty will use to play the bell sound. Defaults -#: to the custom theme name specified in the XDG Sound theme -#: specification , falling back to the default -#: freedesktop theme if it does not exist. To change your sound theme -#: desktop wide, create -#: :file:~/.local/share/sounds/__custom/index.theme` with the -#: contents: - -#: [Sound Theme] - -#: Inherits=name-of-the-sound-theme-you-want-to-use - -#: Replace name-of-the-sound-theme-you-want-to-use with the actual -#: theme name. Now all compliant applications should use sounds from -#: this theme. - -#: }}} - -#: Window layout {{{ - -# remember_window_size yes -# initial_window_width 640 -# initial_window_height 400 - -#: If enabled, the OS Window size will be remembered so that new -#: instances of kitty will have the same size as the previous -#: instance. If disabled, the OS Window will initially have size -#: configured by initial_window_width/height, in pixels. You can use a -#: suffix of "c" on the width/height values to have them interpreted -#: as number of cells instead of pixels. - -# enabled_layouts * - -#: The enabled window layouts. A comma separated list of layout names. -#: The special value all means all layouts. The first listed layout -#: will be used as the startup layout. Default configuration is all -#: layouts in alphabetical order. For a list of available layouts, see -#: the layouts . - -# window_resize_step_cells 2 -# window_resize_step_lines 2 - -#: The step size (in units of cell width/cell height) to use when -#: resizing kitty windows in a layout with the shortcut -#: start_resizing_window. The cells value is used for horizontal -#: resizing, and the lines value is used for vertical resizing. - -# window_border_width 0.5pt - -#: The width of window borders. Can be either in pixels (px) or pts -#: (pt). Values in pts will be rounded to the nearest number of pixels -#: based on screen resolution. If not specified, the unit is assumed -#: to be pts. Note that borders are displayed only when more than one -#: window is visible. They are meant to separate multiple windows. - -# draw_minimal_borders yes - -#: Draw only the minimum borders needed. This means that only the -#: borders that separate the window from a neighbor are drawn. Note -#: that setting a non-zero window_margin_width overrides this and -#: causes all borders to be drawn. - -# window_margin_width 0 - -#: The window margin (in pts) (blank area outside the border). A -#: single value sets all four sides. Two values set the vertical and -#: horizontal sides. Three values set top, horizontal and bottom. Four -#: values set top, right, bottom and left. - -# single_window_margin_width -1 - -#: The window margin to use when only a single window is visible (in -#: pts). Negative values will cause the value of window_margin_width -#: to be used instead. A single value sets all four sides. Two values -#: set the vertical and horizontal sides. Three values set top, -#: horizontal and bottom. Four values set top, right, bottom and left. - -# window_padding_width 0 - -#: The window padding (in pts) (blank area between the text and the -#: window border). A single value sets all four sides. Two values set -#: the vertical and horizontal sides. Three values set top, horizontal -#: and bottom. Four values set top, right, bottom and left. - -# single_window_padding_width -1 - -#: The window padding to use when only a single window is visible (in -#: pts). Negative values will cause the value of window_padding_width -#: to be used instead. A single value sets all four sides. Two values -#: set the vertical and horizontal sides. Three values set top, -#: horizontal and bottom. Four values set top, right, bottom and left. - -# placement_strategy center - -#: When the window size is not an exact multiple of the cell size, the -#: cell area of the terminal window will have some extra padding on -#: the sides. You can control how that padding is distributed with -#: this option. Using a value of center means the cell area will be -#: placed centrally. A value of top-left means the padding will be -#: only at the bottom and right edges. The value can be one of: top- -#: left, top, top-right, left, center, right, bottom-left, bottom, -#: bottom-right. - -# active_border_color #00ff00 - -#: The color for the border of the active window. Set this to none to -#: not draw borders around the active window. - -# inactive_border_color #cccccc - -#: The color for the border of inactive windows. - -# bell_border_color #ff5a00 - -#: The color for the border of inactive windows in which a bell has -#: occurred. - -# inactive_text_alpha 1.0 - -#: Fade the text in inactive windows by the specified amount (a number -#: between zero and one, with zero being fully faded). - -# hide_window_decorations no - -#: Hide the window decorations (title-bar and window borders) with -#: yes. On macOS, titlebar-only and titlebar-and-corners can be used -#: to only hide the titlebar and the rounded corners. Whether this -#: works and exactly what effect it has depends on the window -#: manager/operating system. Note that the effects of changing this -#: option when reloading config are undefined. When using titlebar- -#: only, it is useful to also set window_margin_width and -#: placement_strategy to prevent the rounded corners from clipping -#: text. Or use titlebar-and-corners. - -# window_logo_path none - -#: Path to a logo image. Must be in PNG/JPEG/WEBP/GIF/TIFF/BMP format. -#: Relative paths are interpreted relative to the kitty config -#: directory. The logo is displayed in a corner of every kitty window. -#: The position is controlled by window_logo_position. Individual -#: windows can be configured to have different logos either using the -#: launch action or the remote control -#: facility. - -# window_logo_position bottom-right - -#: Where to position the window logo in the window. The value can be -#: one of: top-left, top, top-right, left, center, right, bottom-left, -#: bottom, bottom-right. - -# window_logo_alpha 0.5 - -#: The amount the logo should be faded into the background. With zero -#: being fully faded and one being fully opaque. - -# window_logo_scale 0 - -#: The percentage (0-100] of the window size to which the logo should -#: scale. Using a single number means the logo is scaled to that -#: percentage of the shortest window dimension, while preserving -#: aspect ratio of the logo image. - -#: Using two numbers means the width and height of the logo are scaled -#: to the respective percentage of the window's width and height. - -#: Using zero as the percentage disables scaling in that dimension. A -#: single zero (the default) disables all scaling of the window logo. - -# resize_debounce_time 0.1 0.5 - -#: The time to wait (in seconds) before asking the program running in -#: kitty to resize and redraw the screen during a live resize of the -#: OS window, when no new resize events have been received, i.e. when -#: resizing is either paused or finished. On platforms such as macOS, -#: where the operating system sends events corresponding to the start -#: and end of a live resize, the second number is used for redraw- -#: after-pause since kitty can distinguish between a pause and end of -#: resizing. On such systems the first number is ignored and redraw is -#: immediate after end of resize. On other systems only the first -#: number is used so that kitty is "ready" quickly after the end of -#: resizing, while not also continuously redrawing, to save energy. - -# resize_in_steps no - -#: Resize the OS window in steps as large as the cells, instead of -#: with the usual pixel accuracy. Combined with initial_window_width -#: and initial_window_height in number of cells, this option can be -#: used to keep the margins as small as possible when resizing the OS -#: window. Note that this does not currently work on Wayland. - -# visual_window_select_characters 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ - -#: The list of characters for visual window selection. For example, -#: for selecting a window to focus on with focus_visible_window. The -#: value should be a series of unique numbers or alphabets, case -#: insensitive, from the set 0-9A-Z\-=[];',./\\`. Specify your -#: preference as a string of characters. - -# confirm_os_window_close -1 - -#: Ask for confirmation when closing an OS window or a tab with at -#: least this number of kitty windows in it by window manager (e.g. -#: clicking the window close button or pressing the operating system -#: shortcut to close windows) or by the close_tab action. A value of -#: zero disables confirmation. This confirmation also applies to -#: requests to quit the entire application (all OS windows, via the -#: quit action). Negative values are converted to positive ones, -#: however, with shell_integration enabled, using negative values -#: means windows sitting at a shell prompt are not counted, only -#: windows where some command is currently running. You can also have -#: backgrounded jobs prevent closing, by adding count-background to -#: the setting, for example: -1 count-background. Note that if you -#: want confirmation when closing individual windows, you can map the -#: close_window_with_confirmation action. - -#: }}} - -#: Tab bar {{{ - -# tab_bar_edge bottom - -#: The edge to show the tab bar on, top or bottom. - -# tab_bar_margin_width 0.0 - -#: The margin to the left and right of the tab bar (in pts). - -# tab_bar_margin_height 0.0 0.0 - -#: The margin above and below the tab bar (in pts). The first number -#: is the margin between the edge of the OS Window and the tab bar. -#: The second number is the margin between the tab bar and the -#: contents of the current tab. - -# tab_bar_style fade - -#: The tab bar style, can be one of: - -#: fade -#: Each tab's edges fade into the background color. (See also tab_fade) -#: slant -#: Tabs look like the tabs in a physical file. -#: separator -#: Tabs are separated by a configurable separator. (See also -#: tab_separator) -#: powerline -#: Tabs are shown as a continuous line with "fancy" separators. -#: (See also tab_powerline_style) -#: custom -#: A user-supplied Python function called draw_tab is loaded from the file -#: tab_bar.py in the kitty config directory. For examples of how to -#: write such a function, see the functions named draw_tab_with_* in -#: kitty's source code: kitty/tab_bar.py. See also -#: this discussion -#: for examples from kitty users. -#: hidden -#: The tab bar is hidden. If you use this, you might want to create -#: a mapping for the select_tab action which presents you with a list of -#: tabs and allows for easy switching to a tab. - -# tab_bar_align left - -#: The horizontal alignment of the tab bar, can be one of: left, -#: center, right. - -# tab_bar_min_tabs 2 - -#: The minimum number of tabs that must exist before the tab bar is -#: shown. - -# tab_switch_strategy previous - -#: The algorithm to use when switching to a tab when the current tab -#: is closed. The default of previous will switch to the last used -#: tab. A value of left will switch to the tab to the left of the -#: closed tab. A value of right will switch to the tab to the right of -#: the closed tab. A value of last will switch to the right-most tab. - -# tab_fade 0.25 0.5 0.75 1 - -#: Control how each tab fades into the background when using fade for -#: the tab_bar_style. Each number is an alpha (between zero and one) -#: that controls how much the corresponding cell fades into the -#: background, with zero being no fade and one being full fade. You -#: can change the number of cells used by adding/removing entries to -#: this list. - -# tab_separator " ┇" - -#: The separator between tabs in the tab bar when using separator as -#: the tab_bar_style. - -# tab_powerline_style angled - -#: The powerline separator style between tabs in the tab bar when -#: using powerline as the tab_bar_style, can be one of: angled, -#: slanted, round. - -# tab_activity_symbol none - -#: Some text or a Unicode symbol to show on the tab if a window in the -#: tab that does not have focus has some activity. If you want to use -#: leading or trailing spaces, surround the text with quotes. See -#: tab_title_template for how this is rendered. - -# tab_title_max_length 0 - -#: The maximum number of cells that can be used to render the text in -#: a tab. A value of zero means that no limit is applied. - -# tab_title_template "{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{tab.last_focused_progress_percent}{title}" - -#: A template to render the tab title. The default just renders the -#: title with optional symbols for bell and activity. If you wish to -#: include the tab-index as well, use something like: {index}:{title}. -#: Useful if you have shortcuts mapped for goto_tab N. If you prefer -#: to see the index as a superscript, use {sup.index}. All data -#: available is: - -#: title -#: The current tab title. -#: index -#: The tab index usable with goto_tab N goto_tab shortcuts. -#: layout_name -#: The current layout name. -#: num_windows -#: The number of windows in the tab. -#: num_window_groups -#: The number of window groups (a window group is a window and all of its overlay windows) in the tab. -#: tab.active_wd -#: The working directory of the currently active window in the tab -#: (expensive, requires syscall). Use tab.active_oldest_wd to get -#: the directory of the oldest foreground process rather than the newest. -#: tab.active_exe -#: The name of the executable running in the foreground of the currently -#: active window in the tab (expensive, requires syscall). Use -#: tab.active_oldest_exe for the oldest foreground process. -#: max_title_length -#: The maximum title length available. -#: keyboard_mode -#: The name of the current keyboard mode or the empty string if no keyboard mode is active. -#: tab.last_focused_progress_percent -#: If a command running in a window reports the progress for a task, show this progress as a percentage -#: from the most recently focused window in the tab. Empty string if no progress is reported. -#: tab.progress_percent -#: If a command running in a window reports the progress for a task, show this progress as a percentage -#: from all windows in the tab, averaged. Empty string is no progress is reported. - -#: Note that formatting is done by Python's string formatting -#: machinery, so you can use, for instance, {layout_name[:2].upper()} -#: to show only the first two letters of the layout name, upper-cased. -#: If you want to style the text, you can use styling directives, for -#: example: -#: `{fmt.fg.red}red{fmt.fg.tab}normal{fmt.bg._00FF00}greenbg{fmt.bg.tab}`. -#: Similarly, for bold and italic: -#: `{fmt.bold}bold{fmt.nobold}normal{fmt.italic}italic{fmt.noitalic}`. -#: The 256 eight terminal colors can be used as `fmt.fg.color0` -#: through `fmt.fg.color255`. Note that for backward compatibility, if -#: {bell_symbol} or {activity_symbol} are not present in the template, -#: they are prepended to it. - -# active_tab_title_template none - -#: Template to use for active tabs. If not specified falls back to -#: tab_title_template. - -# active_tab_foreground #000 -# active_tab_background #eee -# active_tab_font_style bold-italic -# inactive_tab_foreground #444 -# inactive_tab_background #999 -# inactive_tab_font_style normal - -#: Tab bar colors and styles. - -# tab_bar_background none - -#: Background color for the tab bar. Defaults to using the terminal -#: background color. - -# tab_bar_margin_color none - -#: Color for the tab bar margin area. Defaults to using the terminal -#: background color for margins above and below the tab bar. For side -#: margins the default color is chosen to match the background color -#: of the neighboring tab. - -#: }}} - -#: Color scheme {{{ - -# foreground #dddddd -# background #000000 - -#: The foreground and background colors. - -# background_opacity 1.0 - -#: The opacity of the background. A number between zero and one, where -#: one is opaque and zero is fully transparent. This will only work if -#: supported by the OS (for instance, when using a compositor under -#: X11). Note that it only sets the background color's opacity in -#: cells that have the same background color as the default terminal -#: background, so that things like the status bar in vim, powerline -#: prompts, etc. still look good. But it means that if you use a color -#: theme with a background color in your editor, it will not be -#: rendered as transparent. Instead you should change the default -#: background color in your kitty config and not use a background -#: color in the editor color scheme. Or use the escape codes to set -#: the terminals default colors in a shell script to launch your -#: editor. See also transparent_background_colors. Be aware that using -#: a value less than 1.0 is a (possibly significant) performance hit. -#: When using a low value for this setting, it is desirable that you -#: set the background color to a color the matches the general color -#: of the desktop background, for best text rendering. Note that to -#: workaround window managers not doing gamma-corrected blending kitty -#: makes background_opacity non-linear which means, especially for -#: light backgrounds you might need to make the value much lower than -#: you expect to get good results, see 6218 -#: for details. - -#: If you want to dynamically change transparency of windows, set -#: dynamic_background_opacity to yes (this is off by default as it has -#: a performance cost). Changing this option when reloading the config -#: will only work if dynamic_background_opacity was enabled in the -#: original config. - -# background_blur 0 - -#: Set to a positive value to enable background blur (blurring of the -#: visuals behind a transparent window) on platforms that support it. -#: Only takes effect when background_opacity is less than one. On -#: macOS, this will also control the blur radius (amount of blurring). -#: Setting it to too high a value will cause severe performance issues -#: and/or rendering artifacts. Usually, values up to 64 work well. -#: Note that this might cause performance issues, depending on how the -#: platform implements it, so use with care. Currently supported on -#: macOS and KDE. - -# background_image none - -#: Path to a background image. Must be in PNG/JPEG/WEBP/TIFF/GIF/BMP -#: format. - -# background_image_layout tiled - -#: Whether to tile, scale or clamp the background image. The value can -#: be one of tiled, mirror-tiled, scaled, clamped, centered or -#: cscaled. The scaled and cscaled values scale the image to the -#: window size, with cscaled preserving the image aspect ratio. - -# background_image_linear no - -#: When background image is scaled, whether linear interpolation -#: should be used. - -# transparent_background_colors - -#: A space separated list of upto 7 colors, with opacity. When the -#: background color of a cell matches one of these colors, it is -#: rendered semi-transparent using the specified opacity. - -#: Useful in more complex UIs like editors where you could want more -#: than a single background color to be rendered as transparent, for -#: instance, for a cursor highlight line background or a highlighted -#: block. Terminal applications can set this color using The kitty -#: color control escape code. - -#: The syntax for specifying colors is: color@opacity, where the -#: @opacity part is optional. When unspecified, the value of -#: background_opacity is used. For example:: - -#: transparent_background_colors red@0.5 #00ff00@0.3 - -# dynamic_background_opacity no - -#: Allow changing of the background_opacity dynamically, using either -#: keyboard shortcuts (increase_background_opacity and -#: decrease_background_opacity) or the remote control facility. -#: Changing this option by reloading the config is not supported. - -# background_tint 0.0 - -#: How much to tint the background image by the background color. This -#: option makes it easier to read the text. Tinting is done using the -#: current background color for each window. This option applies only -#: if background_opacity is set and transparent windows are supported -#: or background_image is set. - -# background_tint_gaps 1.0 - -#: How much to tint the background image at the window gaps by the -#: background color, after applying background_tint. Since this is -#: multiplicative with background_tint, it can be used to lighten the -#: tint over the window gaps for a *separated* look. - -# dim_opacity 0.4 - -#: How much to dim text that has the DIM/FAINT attribute set. One -#: means no dimming and zero means fully dimmed (i.e. invisible). - -# selection_foreground #000000 -# selection_background #fffacd - -#: The foreground and background colors for text selected with the -#: mouse. Setting both of these to none will cause a "reverse video" -#: effect for selections, where the selection will be the cell text -#: color and the text will become the cell background color. Setting -#: only selection_foreground to none will cause the foreground color -#: to be used unchanged. Note that these colors can be overridden by -#: the program running in the terminal. - -#: The color table {{{ - -#: The 256 terminal colors. There are 8 basic colors, each color has a -#: dull and bright version, for the first 16 colors. You can set the -#: remaining 240 colors as color16 to color255. - -# color0 #000000 -# color8 #767676 - -#: black - -# color1 #cc0403 -# color9 #f2201f - -#: red - -# color2 #19cb00 -# color10 #23fd00 - -#: green - -# color3 #cecb00 -# color11 #fffd00 - -#: yellow - -# color4 #0d73cc -# color12 #1a8fff - -#: blue - -# color5 #cb1ed1 -# color13 #fd28ff - -#: magenta - -# color6 #0dcdcd -# color14 #14ffff - -#: cyan - -# color7 #dddddd -# color15 #ffffff - -#: white - -# mark1_foreground black - -#: Color for marks of type 1 - -# mark1_background #98d3cb - -#: Color for marks of type 1 (light steel blue) - -# mark2_foreground black - -#: Color for marks of type 2 - -# mark2_background #f2dcd3 - -#: Color for marks of type 1 (beige) - -# mark3_foreground black - -#: Color for marks of type 3 - -# mark3_background #f274bc - -#: Color for marks of type 3 (violet) - -#: }}} - -#: }}} - -#: Advanced {{{ - -# shell . - -#: The shell program to execute. The default value of . means to use -#: the value of of the SHELL environment variable or if unset, -#: whatever shell is set as the default shell for the current user. -#: Note that on macOS if you change this, you might need to add -#: --login and --interactive to ensure that the shell starts in -#: interactive mode and reads its startup rc files. Environment -#: variables are expanded in this setting. - -# editor . - -#: The terminal based text editor (such as vim or nano) to use when -#: editing the kitty config file or similar tasks. - -#: The default value of . means to use the environment variables -#: VISUAL and EDITOR in that order. If these variables aren't set, -#: kitty will run your shell ($SHELL -l -i -c env) to see if your -#: shell startup rc files set VISUAL or EDITOR. If that doesn't work, -#: kitty will cycle through various known editors (vim, emacs, etc.) -#: and take the first one that exists on your system. - -# close_on_child_death no - -#: Close the window when the child process (usually the shell) exits. -#: With the default value no, the terminal will remain open when the -#: child exits as long as there are still other processes outputting -#: to the terminal (for example disowned or backgrounded processes). -#: When enabled with yes, the window will close as soon as the child -#: process exits. Note that setting it to yes means that any -#: background processes still using the terminal can fail silently -#: because their stdout/stderr/stdin no longer work. - -# remote_control_password - -#: Allow other programs to control kitty using passwords. This option -#: can be specified multiple times to add multiple passwords. If no -#: passwords are present kitty will ask the user for permission if a -#: program tries to use remote control with a password. A password can -#: also *optionally* be associated with a set of allowed remote -#: control actions. For example:: - -#: remote_control_password "my passphrase" get-colors set-colors focus-window focus-tab - -#: Only the specified actions will be allowed when using this -#: password. Glob patterns can be used too, for example:: - -#: remote_control_password "my passphrase" set-tab-* resize-* - -#: To get a list of available actions, run:: - -#: kitten @ --help - -#: A set of actions to be allowed when no password is sent can be -#: specified by using an empty password. For example:: - -#: remote_control_password "" *-colors - -#: Finally, the path to a python module can be specified that provides -#: a function is_cmd_allowed that is used to check every remote -#: control command. For example:: - -#: remote_control_password "my passphrase" my_rc_command_checker.py - -#: Relative paths are resolved from the kitty configuration directory. -#: See rc_custom_auth for details. - -# allow_remote_control no - -#: Allow other programs to control kitty. If you turn this on, other -#: programs can control all aspects of kitty, including sending text -#: to kitty windows, opening new windows, closing windows, reading the -#: content of windows, etc. Note that this even works over SSH -#: connections. The default setting of no prevents any form of remote -#: control. The meaning of the various values are: - -#: password -#: Remote control requests received over both the TTY device and the socket -#: are confirmed based on passwords, see remote_control_password. - -#: socket-only -#: Remote control requests received over a socket are accepted -#: unconditionally. Requests received over the TTY are denied. -#: See listen_on. - -#: socket -#: Remote control requests received over a socket are accepted -#: unconditionally. Requests received over the TTY are confirmed based on -#: password. - -#: no -#: Remote control is completely disabled. - -#: yes -#: Remote control requests are always accepted. - -# listen_on none - -#: Listen to the specified socket for remote control connections. Note -#: that this will apply to all kitty instances. It can be overridden -#: by the kitty --listen-on command line option. For UNIX sockets, -#: such as unix:${TEMP}/mykitty or unix:@mykitty (on Linux). -#: Environment variables are expanded and relative paths are resolved -#: with respect to the temporary directory. If {kitty_pid} is present, -#: then it is replaced by the PID of the kitty process, otherwise the -#: PID of the kitty process is appended to the value, with a hyphen. -#: For TCP sockets such as tcp:localhost:0 a random port is always -#: used even if a non-zero port number is specified. See the help for -#: kitty --listen-on for more details. Note that this will be ignored -#: unless allow_remote_control is set to either: yes, socket or -#: socket-only. Changing this option by reloading the config is not -#: supported. - -# env - -#: Specify the environment variables to be set in all child processes. -#: Using the name with an equal sign (e.g. env VAR=) will set it to -#: the empty string. Specifying only the name (e.g. env VAR) will -#: remove the variable from the child process' environment. Note that -#: environment variables are expanded recursively, for example:: - -#: env VAR1=a -#: env VAR2=${HOME}/${VAR1}/b - -#: The value of VAR2 will be /a/b. - -# filter_notification - -#: Specify rules to filter out notifications sent by applications -#: running in kitty. Can be specified multiple times to create -#: multiple filter rules. A rule specification is of the form -#: field:regexp. A filter rule can match on any of the fields: title, -#: body, app, type. The special value of all filters out all -#: notifications. Rules can be combined using Boolean operators. Some -#: examples:: - -#: filter_notification title:hello or body:"abc.*def" -#: # filter out notification from vim except for ones about updates, (?i) -#: # makes matching case insensitive. -#: filter_notification app:"[ng]?vim" and not body:"(?i)update" -#: # filter out all notifications -#: filter_notification all - -#: The field app is the name of the application sending the -#: notification and type is the type of the notification. Not all -#: applications will send these fields, so you can also match on the -#: title and body of the notification text. More sophisticated -#: programmatic filtering and custom actions on notifications can be -#: done by creating a notifications.py file in the kitty config -#: directory (~/.config/kitty). An annotated sample is available -#: . - -# watcher - -#: Path to python file which will be loaded for watchers -#: . Can be -#: specified more than once to load multiple watchers. The watchers -#: will be added to every kitty window. Relative paths are resolved -#: relative to the kitty config directory. Note that reloading the -#: config will only affect windows created after the reload. - -# exe_search_path - -#: Control where kitty finds the programs to run. The default search -#: order is: First search the system wide PATH, then ~/.local/bin and -#: ~/bin. If still not found, the PATH defined in the login shell -#: after sourcing all its startup files is tried. Finally, if present, -#: the PATH specified by the env option is tried. - -#: This option allows you to prepend, append, or remove paths from -#: this search order. It can be specified multiple times for multiple -#: paths. A simple path will be prepended to the search order. A path -#: that starts with the + sign will be append to the search order, -#: after ~/bin above. A path that starts with the - sign will be -#: removed from the entire search order. For example:: - -#: exe_search_path /some/prepended/path -#: exe_search_path +/some/appended/path -#: exe_search_path -/some/excluded/path - -# update_check_interval 24 - -#: The interval to periodically check if an update to kitty is -#: available (in hours). If an update is found, a system notification -#: is displayed informing you of the available update. The default is -#: to check every 24 hours, set to zero to disable. Update checking is -#: only done by the official binary builds. Distro packages or source -#: builds do not do update checking. Changing this option by reloading -#: the config is not supported. - -# startup_session none - -#: Path to a session file to use for all kitty instances. Can be -#: overridden by using the kitty --session =none command line option -#: for individual instances. See sessions -#: in the kitty -#: documentation for details. Note that relative paths are interpreted -#: with respect to the kitty config directory. Environment variables -#: in the path are expanded. Changing this option by reloading the -#: config is not supported. Note that if kitty is invoked with command -#: line arguments specifying a command to run, this option is ignored. - -# clipboard_control write-clipboard write-primary read-clipboard-ask read-primary-ask - -#: Allow programs running in kitty to read and write from the -#: clipboard. You can control exactly which actions are allowed. The -#: possible actions are: write-clipboard, read-clipboard, write- -#: primary, read-primary, read-clipboard-ask, read-primary-ask. The -#: default is to allow writing to the clipboard and primary selection -#: and to ask for permission when a program tries to read from the -#: clipboard. Note that disabling the read confirmation is a security -#: risk as it means that any program, even the ones running on a -#: remote server via SSH can read your clipboard. See also -#: clipboard_max_size. - -# clipboard_max_size 512 - -#: The maximum size (in MB) of data from programs running in kitty -#: that will be stored for writing to the system clipboard. A value of -#: zero means no size limit is applied. See also clipboard_control. - -# file_transfer_confirmation_bypass - -#: The password that can be supplied to the file transfer kitten -#: to skip the -#: transfer confirmation prompt. This should only be used when -#: initiating transfers from trusted computers, over trusted networks -#: or encrypted transports, as it allows any programs running on the -#: remote machine to read/write to the local filesystem, without -#: permission. - -# allow_hyperlinks yes - -#: Process hyperlink escape sequences (OSC 8). If disabled OSC 8 -#: escape sequences are ignored. Otherwise they become clickable -#: links, that you can click with the mouse or by using the hints -#: kitten . The -#: special value of ask means that kitty will ask before opening the -#: link when clicked. - -# shell_integration enabled - -#: Enable shell integration on supported shells. This enables features -#: such as jumping to previous prompts, browsing the output of the -#: previous command in a pager, etc. on supported shells. Set to -#: disabled to turn off shell integration, completely. It is also -#: possible to disable individual features, set to a space separated -#: list of these values: no-rc, no-cursor, no-title, no-cwd, no- -#: prompt-mark, no-complete, no-sudo. See Shell integration -#: for details. - -# allow_cloning ask - -#: Control whether programs running in the terminal can request new -#: windows to be created. The canonical example is clone-in-kitty -#: . -#: By default, kitty will ask for permission for each clone request. -#: Allowing cloning unconditionally gives programs running in the -#: terminal (including over SSH) permission to execute arbitrary code, -#: as the user who is running the terminal, on the computer that the -#: terminal is running on. - -# clone_source_strategies venv,conda,env_var,path - -#: Control what shell code is sourced when running clone-in-kitty in -#: the newly cloned window. The supported strategies are: - -#: venv -#: Source the file $VIRTUAL_ENV/bin/activate. This is used by the -#: Python stdlib venv module and allows cloning venvs automatically. -#: conda -#: Run conda activate $CONDA_DEFAULT_ENV. This supports the virtual -#: environments created by conda. -#: env_var -#: Execute the contents of the environment variable -#: KITTY_CLONE_SOURCE_CODE with eval. -#: path -#: Source the file pointed to by the environment variable -#: KITTY_CLONE_SOURCE_PATH. - -#: This option must be a comma separated list of the above values. -#: Only the first valid match, in the order specified, is sourced. - -# notify_on_cmd_finish never - -#: Show a desktop notification when a long-running command finishes -#: (needs shell_integration). The possible values are: - -#: never -#: Never send a notification. - -#: unfocused -#: Only send a notification when the window does not have keyboard focus. - -#: invisible -#: Only send a notification when the window both is unfocused and not visible -#: to the user, for example, because it is in an inactive tab or its OS window -#: is not currently visible (on platforms that support OS window visibility querying -#: this considers an OS Window visible iff it is active). - -#: always -#: Always send a notification, regardless of window state. - -#: There are two optional arguments: - -#: First, the minimum duration for what is considered a long running -#: command. The default is 5 seconds. Specify a second argument to set -#: the duration. For example: invisible 15. Do not set the value too -#: small, otherwise a command that launches a new OS Window and exits -#: will spam a notification. - -#: Second, the action to perform. The default is notify. The possible -#: values are: - -#: notify -#: Send a desktop notification. The subsequent arguments are optional and specify when -#: the notification is automatically cleared. The set of possible events when the notification is -#: cleared are: focus and next. focus means that when the notification -#: policy is unfocused or invisible the notification is automatically cleared -#: when the window regains focus. The value of next means that the previous notification -#: is cleared when the next notification is shown. The default when no arguments are specified -#: is: focus next. - -#: bell -#: Ring the terminal bell. - -#: command -#: Run a custom command. All subsequent arguments are the cmdline to run. - -#: Some more examples:: - -#: # Send a notification when a command takes more than 5 seconds in an unfocused window -#: notify_on_cmd_finish unfocused -#: # Send a notification when a command takes more than 10 seconds in a invisible window -#: notify_on_cmd_finish invisible 10.0 -#: # Ring a bell when a command takes more than 10 seconds in a invisible window -#: notify_on_cmd_finish invisible 10.0 bell -#: # Run 'notify-send' when a command takes more than 10 seconds in a invisible window -#: # Here %c is replaced by the current command line and %s by the job exit code -#: notify_on_cmd_finish invisible 10.0 command notify-send "job finished with status: %s" %c -#: # Do not clear previous notification when next command finishes or window regains focus -#: notify_on_cmd_finish invisible 5.0 notify - -# term xterm-kitty - -#: The value of the TERM environment variable to set. Changing this -#: can break many terminal programs, only change it if you know what -#: you are doing, not because you read some advice on "Stack Overflow" -#: to change it. The TERM variable is used by various programs to get -#: information about the capabilities and behavior of the terminal. If -#: you change it, depending on what programs you run, and how -#: different the terminal you are changing it to is, various things -#: from key-presses, to colors, to various advanced features may not -#: work. Changing this option by reloading the config will only affect -#: newly created windows. - -# terminfo_type path - -#: The value of the TERMINFO environment variable to set. This -#: variable is used by programs running in the terminal to search for -#: terminfo databases. The default value of path causes kitty to set -#: it to a filesystem location containing the kitty terminfo database. -#: A value of direct means put the entire database into the env var -#: directly. This can be useful when connecting to containers, for -#: example. But, note that not all software supports this. A value of -#: none means do not touch the variable. - -# forward_stdio no - -#: Forward STDOUT and STDERR of the kitty process to child processes. -#: This is useful for debugging as it allows child processes to print -#: to kitty's STDOUT directly. For example, echo hello world -#: >&$KITTY_STDIO_FORWARDED in a shell will print to the parent -#: kitty's STDOUT. Sets the KITTY_STDIO_FORWARDED=fdnum environment -#: variable so child processes know about the forwarding. Note that on -#: macOS this prevents the shell from being run via the login utility -#: so getlogin() will not work in programs run in this session. - -# menu_map - -#: Specify entries for various menus in kitty. Currently only the -#: global menubar on macOS is supported. For example:: - -#: menu_map global "Actions::Launch something special" launch --hold --type=os-window sh -c "echo hello world" - -#: This will create a menu entry named "Launch something special" in -#: an "Actions" menu in the macOS global menubar. Sub-menus can be -#: created by adding more levels separated by the :: characters. - -#: }}} - -#: OS specific tweaks {{{ - -# wayland_titlebar_color system - -#: The color of the kitty window's titlebar on Wayland systems with -#: client side window decorations such as GNOME. A value of system -#: means to use the default system colors, a value of background means -#: to use the background color of the currently active kitty window -#: and finally you can use an arbitrary color, such as #12af59 or red. - -# macos_titlebar_color system - -#: The color of the kitty window's titlebar on macOS. A value of -#: system means to use the default system color, light or dark can -#: also be used to set it explicitly. A value of background means to -#: use the background color of the currently active window and finally -#: you can use an arbitrary color, such as #12af59 or red. WARNING: -#: This option works by using a hack when arbitrary color (or -#: background) is configured, as there is no proper Cocoa API for it. -#: It sets the background color of the entire window and makes the -#: titlebar transparent. As such it is incompatible with -#: background_opacity. If you want to use both, you are probably -#: better off just hiding the titlebar with hide_window_decorations. - -# macos_option_as_alt no - -#: Use the Option key as an Alt key on macOS. With this set to no, -#: kitty will use the macOS native Option+Key to enter Unicode -#: character behavior. This will break any Alt+Key keyboard shortcuts -#: in your terminal programs, but you can use the macOS Unicode input -#: technique. You can use the values: left, right or both to use only -#: the left, right or both Option keys as Alt, instead. Note that -#: kitty itself always treats Option the same as Alt. This means you -#: cannot use this option to configure different kitty shortcuts for -#: Option+Key vs. Alt+Key. Also, any kitty shortcuts using -#: Option/Alt+Key will take priority, so that any such key presses -#: will not be passed to terminal programs running inside kitty. -#: Changing this option by reloading the config is not supported. - -# macos_hide_from_tasks no - -#: Hide the kitty window from running tasks on macOS (⌘+Tab and the -#: Dock). Changing this option by reloading the config is not -#: supported. - -# macos_quit_when_last_window_closed no - -#: Have kitty quit when all the top-level windows are closed on macOS. -#: By default, kitty will stay running, even with no open windows, as -#: is the expected behavior on macOS. - -# macos_window_resizable yes - -#: Disable this if you want kitty top-level OS windows to not be -#: resizable on macOS. - -# macos_thicken_font 0 - -#: Draw an extra border around the font with the given width, to -#: increase legibility at small font sizes on macOS. For example, a -#: value of 0.75 will result in rendering that looks similar to sub- -#: pixel antialiasing at common font sizes. Note that in modern kitty, -#: this option is obsolete (although still supported). Consider using -#: text_composition_strategy instead. - -# macos_traditional_fullscreen no - -#: Use the macOS traditional full-screen transition, that is faster, -#: but less pretty. - -# macos_show_window_title_in all - -#: Control where the window title is displayed on macOS. A value of -#: window will show the title of the currently active window at the -#: top of the macOS window. A value of menubar will show the title of -#: the currently active window in the macOS global menu bar, making -#: use of otherwise wasted space. A value of all will show the title -#: in both places, and none hides the title. See -#: macos_menubar_title_max_length for how to control the length of the -#: title in the menu bar. - -# macos_menubar_title_max_length 0 - -#: The maximum number of characters from the window title to show in -#: the macOS global menu bar. Values less than one means that there is -#: no maximum limit. - -# macos_custom_beam_cursor no - -#: Use a custom mouse cursor for macOS that is easier to see on both -#: light and dark backgrounds. Nowadays, the default macOS cursor -#: already comes with a white border. WARNING: this might make your -#: mouse cursor invisible on dual GPU machines. Changing this option -#: by reloading the config is not supported. - -# macos_colorspace srgb - -#: The colorspace in which to interpret terminal colors. The default -#: of srgb will cause colors to match those seen in web browsers. The -#: value of default will use whatever the native colorspace of the -#: display is. The value of displayp3 will use Apple's special -#: snowflake display P3 color space, which will result in over -#: saturated (brighter) colors with some color shift. Reloading -#: configuration will change this value only for newly created OS -#: windows. - -# linux_display_server auto - -#: Choose between Wayland and X11 backends. By default, an appropriate -#: backend based on the system state is chosen automatically. Set it -#: to x11 or wayland to force the choice. Changing this option by -#: reloading the config is not supported. - -# wayland_enable_ime yes - -#: Enable Input Method Extension on Wayland. This is typically used -#: for inputting text in East Asian languages. However, its -#: implementation in Wayland is often buggy and introduces latency -#: into the input loop, so disable this if you know you dont need it. -#: Changing this option by reloading the config is not supported, it -#: will not have any effect. - -#: }}} - -#: Keyboard shortcuts {{{ - -#: Keys are identified simply by their lowercase Unicode characters. -#: For example: a for the A key, [ for the left square bracket key, -#: etc. For functional keys, such as Enter or Escape, the names are -#: present at Functional key definitions -#: . -#: For modifier keys, the names are ctrl (control, ⌃), shift (⇧), alt -#: (opt, option, ⌥), super (cmd, command, ⌘). - -#: Simple shortcut mapping is done with the map directive. For full -#: details on advanced mapping including modal and per application -#: maps, see mapping . Some -#: quick examples to illustrate common tasks:: - -#: # unmap a keyboard shortcut, passing it to the program running in kitty -#: map kitty_mod+space -#: # completely ignore a keyboard event -#: map ctrl+alt+f1 discard_event -#: # combine multiple actions -#: map kitty_mod+e combine : new_window : next_layout -#: # multi-key shortcuts -#: map ctrl+x>ctrl+y>z action - -#: The full list of actions that can be mapped to key presses is -#: available here . - -# kitty_mod ctrl+shift - -#: Special modifier key alias for default shortcuts. You can change -#: the value of this option to alter all default shortcuts that use -#: kitty_mod. - -# clear_all_shortcuts no - -#: Remove all shortcut definitions up to this point. Useful, for -#: instance, to remove the default shortcuts. - -# action_alias - -#: E.g. action_alias launch_tab launch --type=tab --cwd=current - -#: Define action aliases to avoid repeating the same options in -#: multiple mappings. Aliases can be defined for any action and will -#: be expanded recursively. For example, the above alias allows you to -#: create mappings to launch a new tab in the current working -#: directory without duplication:: - -#: map f1 launch_tab vim -#: map f2 launch_tab emacs - -#: Similarly, to alias kitten invocation:: - -#: action_alias hints kitten hints --hints-offset=0 - -# kitten_alias - -#: E.g. kitten_alias hints hints --hints-offset=0 - -#: Like action_alias above, but specifically for kittens. Generally, -#: prefer to use action_alias. This option is a legacy version, -#: present for backwards compatibility. It causes all invocations of -#: the aliased kitten to be substituted. So the example above will -#: cause all invocations of the hints kitten to have the --hints- -#: offset=0 option applied. - -#: Clipboard {{{ - -#: Copy to clipboard - -# map kitty_mod+c copy_to_clipboard -# map cmd+c copy_to_clipboard - -#:: There is also a copy_or_interrupt action that can be optionally -#:: mapped to Ctrl+C. It will copy only if there is a selection and -#:: send an interrupt otherwise. Similarly, -#:: copy_and_clear_or_interrupt will copy and clear the selection or -#:: send an interrupt if there is no selection. - -#: Paste from clipboard - -# map kitty_mod+v paste_from_clipboard -# map cmd+v paste_from_clipboard - -#: Paste from selection - -# map kitty_mod+s paste_from_selection -# map shift+insert paste_from_selection - -#: Pass selection to program - -# map kitty_mod+o pass_selection_to_program - -#:: You can also pass the contents of the current selection to any -#:: program with pass_selection_to_program. By default, the system's -#:: open program is used, but you can specify your own, the selection -#:: will be passed as a command line argument to the program. For -#:: example:: - -#:: map kitty_mod+o pass_selection_to_program firefox - -#:: You can pass the current selection to a terminal program running -#:: in a new kitty window, by using the @selection placeholder:: - -#:: map kitty_mod+y new_window less @selection - -#: }}} - -#: Scrolling {{{ - -#: Scroll line up - -# map kitty_mod+up scroll_line_up -# map kitty_mod+k scroll_line_up -# map opt+cmd+page_up scroll_line_up -# map cmd+up scroll_line_up - -#: Scroll line down - -# map kitty_mod+down scroll_line_down -# map kitty_mod+j scroll_line_down -# map opt+cmd+page_down scroll_line_down -# map cmd+down scroll_line_down - -#: Scroll page up - -# map kitty_mod+page_up scroll_page_up -# map cmd+page_up scroll_page_up - -#: Scroll page down - -# map kitty_mod+page_down scroll_page_down -# map cmd+page_down scroll_page_down - -#: Scroll to top - -# map kitty_mod+home scroll_home -# map cmd+home scroll_home - -#: Scroll to bottom - -# map kitty_mod+end scroll_end -# map cmd+end scroll_end - -#: Scroll to previous shell prompt - -# map kitty_mod+z scroll_to_prompt -1 - -#:: Use a parameter of 0 for scroll_to_prompt to scroll to the last -#:: jumped to or the last clicked position. Requires shell -#:: integration -#:: to work. - -#: Scroll to next shell prompt - -# map kitty_mod+x scroll_to_prompt 1 - -#: Browse scrollback buffer in pager - -# map kitty_mod+h show_scrollback - -#:: You can pipe the contents of the current screen and history -#:: buffer as STDIN to an arbitrary program using launch --stdin- -#:: source. For example, the following opens the scrollback buffer in -#:: less in an overlay window:: - -#:: map f1 launch --stdin-source=@screen_scrollback --stdin-add-formatting --type=overlay less +G -R - -#:: For more details on piping screen and buffer contents to external -#:: programs, see launch . - -#: Browse output of the last shell command in pager - -# map kitty_mod+g show_last_command_output - -#:: You can also define additional shortcuts to get the command -#:: output. For example, to get the first command output on screen:: - -#:: map f1 show_first_command_output_on_screen - -#:: To get the command output that was last accessed by a keyboard -#:: action or mouse action:: - -#:: map f1 show_last_visited_command_output - -#:: You can pipe the output of the last command run in the shell -#:: using the launch action. For example, the following opens the -#:: output in less in an overlay window:: - -#:: map f1 launch --stdin-source=@last_cmd_output --stdin-add-formatting --type=overlay less +G -R - -#:: To get the output of the first command on the screen, use -#:: @first_cmd_output_on_screen. To get the output of the last jumped -#:: to command, use @last_visited_cmd_output. - -#:: Requires shell integration -#:: to work. - -#: }}} - -#: Window management {{{ - -#: New window - -# map kitty_mod+enter new_window -# map cmd+enter new_window - -#:: You can open a new kitty window running an arbitrary program, for -#:: example:: - -#:: map kitty_mod+y launch mutt - -#:: You can open a new window with the current working directory set -#:: to the working directory of the current window using:: - -#:: map ctrl+alt+enter launch --cwd=current - -#:: You can open a new window that is allowed to control kitty via -#:: the kitty remote control facility with launch --allow-remote- -#:: control. Any programs running in that window will be allowed to -#:: control kitty. For example:: - -#:: map ctrl+enter launch --allow-remote-control some_program - -#:: You can open a new window next to the currently active window or -#:: as the first window, with:: - -#:: map ctrl+n launch --location=neighbor -#:: map ctrl+f launch --location=first - -#:: For more details, see launch -#:: . - -#: New OS window - -# map kitty_mod+n new_os_window -# map cmd+n new_os_window - -#:: Works like new_window above, except that it opens a top-level OS -#:: window. In particular you can use new_os_window_with_cwd to open -#:: a window with the current working directory. - -#: Close window - -# map kitty_mod+w close_window -# map shift+cmd+d close_window - -#: Next window - -# map kitty_mod+] next_window - -#: Previous window - -# map kitty_mod+[ previous_window - -#: Move window forward - -# map kitty_mod+f move_window_forward - -#: Move window backward - -# map kitty_mod+b move_window_backward - -#: Move window to top - -# map kitty_mod+` move_window_to_top - -#: Start resizing window - -# map kitty_mod+r start_resizing_window -# map cmd+r start_resizing_window - -#: First window - -# map kitty_mod+1 first_window -# map cmd+1 first_window - -#: Second window - -# map kitty_mod+2 second_window -# map cmd+2 second_window - -#: Third window - -# map kitty_mod+3 third_window -# map cmd+3 third_window - -#: Fourth window - -# map kitty_mod+4 fourth_window -# map cmd+4 fourth_window - -#: Fifth window - -# map kitty_mod+5 fifth_window -# map cmd+5 fifth_window - -#: Sixth window - -# map kitty_mod+6 sixth_window -# map cmd+6 sixth_window - -#: Seventh window - -# map kitty_mod+7 seventh_window -# map cmd+7 seventh_window - -#: Eighth window - -# map kitty_mod+8 eighth_window -# map cmd+8 eighth_window - -#: Ninth window - -# map kitty_mod+9 ninth_window -# map cmd+9 ninth_window - -#: Tenth window - -# map kitty_mod+0 tenth_window - -#: Visually select and focus window - -# map kitty_mod+f7 focus_visible_window - -#:: Display overlay numbers and alphabets on the window, and switch -#:: the focus to the window when you press the key. When there are -#:: only two windows, the focus will be switched directly without -#:: displaying the overlay. You can change the overlay characters and -#:: their order with option visual_window_select_characters. - -#: Visually swap window with another - -# map kitty_mod+f8 swap_with_window - -#:: Works like focus_visible_window above, but swaps the window. - -#: }}} - -#: Tab management {{{ - -#: Next tab - -# map kitty_mod+right next_tab -# map shift+cmd+] next_tab -# map ctrl+tab next_tab - -#: Previous tab - -# map kitty_mod+left previous_tab -# map shift+cmd+[ previous_tab -# map ctrl+shift+tab previous_tab - -#: New tab - -# map kitty_mod+t new_tab -# map cmd+t new_tab - -#: Close tab - -# map kitty_mod+q close_tab -# map cmd+w close_tab - -#: Close OS window - -# map shift+cmd+w close_os_window - -#: Move tab forward - -# map kitty_mod+. move_tab_forward - -#: Move tab backward - -# map kitty_mod+, move_tab_backward - -#: Set tab title - -# map kitty_mod+alt+t set_tab_title -# map shift+cmd+i set_tab_title - - -#: You can also create shortcuts to go to specific tabs, with 1 being -#: the first tab, 2 the second tab and -1 being the previously active -#: tab, -2 being the tab active before the previously active tab and -#: so on. Any number larger than the number of tabs goes to the last -#: tab and any number less than the number of previously used tabs in -#: the history goes to the oldest previously used tab in the history:: - -#: map ctrl+alt+1 goto_tab 1 -#: map ctrl+alt+2 goto_tab 2 - -#: Just as with new_window above, you can also pass the name of -#: arbitrary commands to run when using new_tab and new_tab_with_cwd. -#: Finally, if you want the new tab to open next to the current tab -#: rather than at the end of the tabs list, use:: - -#: map ctrl+t new_tab !neighbor [optional cmd to run] -#: }}} - -#: Layout management {{{ - -#: Next layout - -# map kitty_mod+l next_layout - - -#: You can also create shortcuts to switch to specific layouts:: - -#: map ctrl+alt+t goto_layout tall -#: map ctrl+alt+s goto_layout stack - -#: Similarly, to switch back to the previous layout:: - -#: map ctrl+alt+p last_used_layout - -#: There is also a toggle_layout action that switches to the named -#: layout or back to the previous layout if in the named layout. -#: Useful to temporarily "zoom" the active window by switching to the -#: stack layout:: - -#: map ctrl+alt+z toggle_layout stack -#: }}} - -#: Font sizes {{{ - -#: You can change the font size for all top-level kitty OS windows at -#: a time or only the current one. - -#: Increase font size - -# map kitty_mod+equal change_font_size all +2.0 -# map kitty_mod+plus change_font_size all +2.0 -# map kitty_mod+kp_add change_font_size all +2.0 -# map cmd+plus change_font_size all +2.0 -# map cmd+equal change_font_size all +2.0 -# map shift+cmd+equal change_font_size all +2.0 - -#: Decrease font size - -# map kitty_mod+minus change_font_size all -2.0 -# map kitty_mod+kp_subtract change_font_size all -2.0 -# map cmd+minus change_font_size all -2.0 -# map shift+cmd+minus change_font_size all -2.0 - -#: Reset font size - -# map kitty_mod+backspace change_font_size all 0 -# map cmd+0 change_font_size all 0 - - -#: To setup shortcuts for specific font sizes:: - -#: map kitty_mod+f6 change_font_size all 10.0 - -#: To setup shortcuts to change only the current OS window's font -#: size:: - -#: map kitty_mod+f6 change_font_size current 10.0 -#: }}} - -#: Select and act on visible text {{{ - -#: Use the hints kitten to select text and either pass it to an -#: external program or insert it into the terminal or copy it to the -#: clipboard. - -#: Open URL - -# map kitty_mod+e open_url_with_hints - -#:: Open a currently visible URL using the keyboard. The program used -#:: to open the URL is specified in open_url_with. - -#: Insert selected path - -# map kitty_mod+p>f kitten hints --type path --program - - -#:: Select a path/filename and insert it into the terminal. Useful, -#:: for instance to run git commands on a filename output from a -#:: previous git command. - -#: Open selected path - -# map kitty_mod+p>shift+f kitten hints --type path - -#:: Select a path/filename and open it with the default open program. - -#: Insert selected line - -# map kitty_mod+p>l kitten hints --type line --program - - -#:: Select a line of text and insert it into the terminal. Useful for -#:: the output of things like: `ls -1`. - -#: Insert selected word - -# map kitty_mod+p>w kitten hints --type word --program - - -#:: Select words and insert into terminal. - -#: Insert selected hash - -# map kitty_mod+p>h kitten hints --type hash --program - - -#:: Select something that looks like a hash and insert it into the -#:: terminal. Useful with git, which uses SHA1 hashes to identify -#:: commits. - -#: Open the selected file at the selected line - -# map kitty_mod+p>n kitten hints --type linenum - -#:: Select something that looks like filename:linenum and open it in -#:: your default editor at the specified line number. - -#: Open the selected hyperlink - -# map kitty_mod+p>y kitten hints --type hyperlink - -#:: Select a hyperlink (i.e. a URL that has been marked as such by -#:: the terminal program, for example, by `ls --hyperlink=auto`). - - -#: The hints kitten has many more modes of operation that you can map -#: to different shortcuts. For a full description see hints kitten -#: . -#: }}} - -#: Miscellaneous {{{ - -#: Show documentation - -# map kitty_mod+f1 show_kitty_doc overview - -#: Toggle fullscreen - -# map kitty_mod+f11 toggle_fullscreen -# map ctrl+cmd+f toggle_fullscreen - -#: Toggle maximized - -# map kitty_mod+f10 toggle_maximized - -#: Toggle macOS secure keyboard entry - -# map opt+cmd+s toggle_macos_secure_keyboard_entry - -#: Unicode input - -# map kitty_mod+u kitten unicode_input -# map ctrl+cmd+space kitten unicode_input - -#: Edit config file - -# map kitty_mod+f2 edit_config_file -# map cmd+, edit_config_file - -#: Open the kitty command shell - -# map kitty_mod+escape kitty_shell window - -#:: Open the kitty shell in a new window / tab / overlay / os_window -#:: to control kitty using commands. - -#: Increase background opacity - -# map kitty_mod+a>m set_background_opacity +0.1 - -#: Decrease background opacity - -# map kitty_mod+a>l set_background_opacity -0.1 - -#: Make background fully opaque - -# map kitty_mod+a>1 set_background_opacity 1 - -#: Reset background opacity - -# map kitty_mod+a>d set_background_opacity default - -#: Reset the terminal - -# map kitty_mod+delete clear_terminal reset active -# map opt+cmd+r clear_terminal reset active - -#:: You can create shortcuts to clear/reset the terminal. For -#:: example:: - -#:: # Reset the terminal -#:: map f1 clear_terminal reset active -#:: # Clear the terminal screen by erasing all contents -#:: map f1 clear_terminal clear active -#:: # Clear the terminal scrollback by erasing it -#:: map f1 clear_terminal scrollback active -#:: # Scroll the contents of the screen into the scrollback -#:: map f1 clear_terminal scroll active -#:: # Clear everything on screen up to the line with the cursor or the start of the current prompt (needs shell integration) -#:: map f1 clear_terminal to_cursor active -#:: # Same as above except cleared lines are moved into scrollback -#:: map f1 clear_terminal to_cursor_scroll active - -#:: If you want to operate on all kitty windows instead of just the -#:: current one, use all instead of active. - -#:: Some useful functions that can be defined in the shell rc files -#:: to perform various kinds of clearing of the current window: - -#:: .. code-block:: sh - -#:: clear-only-screen() { -#:: printf "\e[H\e[2J" -#:: } - -#:: clear-screen-and-scrollback() { -#:: printf "\e[H\e[3J" -#:: } - -#:: clear-screen-saving-contents-in-scrollback() { -#:: printf "\e[H\e[22J" -#:: } - -#:: For instance, using these escape codes, it is possible to remap -#:: Ctrl+L to both scroll the current screen contents into the -#:: scrollback buffer and clear the screen, instead of just clearing -#:: the screen. For ZSH, in ~/.zshrc, add: - -#:: .. code-block:: zsh - -#:: ctrl_l() { -#:: builtin print -rn -- $'\r\e[0J\e[H\e[22J' >"$TTY" -#:: builtin zle .reset-prompt -#:: builtin zle -R -#:: } -#:: zle -N ctrl_l -#:: bindkey '^l' ctrl_l - -#:: Alternatively, you can just add map ctrl+l clear_terminal -#:: to_cursor_scroll active to kitty.conf which works with no changes -#:: to the shell rc files, but only clears up to the prompt, it does -#:: not clear any text at the prompt itself. - -#: Clear to start - -# map cmd+k clear_terminal to_cursor active - -#: Clear scrollback - -# map option+cmd+k clear_terminal scrollback active - -#: Clear screen - -# map cmd+ctrl+l clear_terminal to_cursor_scroll active - -#: Reload kitty.conf - -# map kitty_mod+f5 load_config_file -# map ctrl+cmd+, load_config_file - -#:: Reload kitty.conf, applying any changes since the last time it -#:: was loaded. Note that a handful of options cannot be dynamically -#:: changed and require a full restart of kitty. Particularly, when -#:: changing shortcuts for actions located on the macOS global menu -#:: bar, a full restart is needed. You can also map a keybinding to -#:: load a different config file, for example:: - -#:: map f5 load_config /path/to/alternative/kitty.conf - -#:: Note that all options from the original kitty.conf are discarded, -#:: in other words the new configuration *replace* the old ones. - -#: Debug kitty configuration - -# map kitty_mod+f6 debug_config -# map opt+cmd+, debug_config - -#:: Show details about exactly what configuration kitty is running -#:: with and its host environment. Useful for debugging issues. - -#: Send arbitrary text on key presses - -#:: E.g. map ctrl+shift+alt+h send_text all Hello World - -#:: You can tell kitty to send arbitrary (UTF-8) encoded text to the -#:: client program when pressing specified shortcut keys. For -#:: example:: - -#:: map ctrl+alt+a send_text all Special text - -#:: This will send "Special text" when you press the Ctrl+Alt+A key -#:: combination. The text to be sent decodes ANSI C escapes -#:: so you can use escapes like \e to send control -#:: codes or \u21fb to send Unicode characters (or you can just input -#:: the Unicode characters directly as UTF-8 text). You can use -#:: `kitten show-key` to get the key escape codes you want to -#:: emulate. - -#:: The first argument to send_text is the keyboard modes in which to -#:: activate the shortcut. The possible values are normal, -#:: application, kitty or a comma separated combination of them. The -#:: modes normal and application refer to the DECCKM cursor key mode -#:: for terminals, and kitty refers to the kitty extended keyboard -#:: protocol. The special value all means all of them. - -#:: Some more examples:: - -#:: # Output a word and move the cursor to the start of the line (like typing and pressing Home) -#:: map ctrl+alt+a send_text normal Word\e[H -#:: map ctrl+alt+a send_text application Word\eOH -#:: # Run a command at a shell prompt (like typing the command and pressing Enter) -#:: map ctrl+alt+a send_text normal,application some command with arguments\r - -#: Open kitty Website - -# map shift+cmd+/ open_url https://sw.kovidgoyal.net/kitty/ - -#: Hide macOS kitty application - -# map cmd+h hide_macos_app - -#: Hide macOS other applications - -# map opt+cmd+h hide_macos_other_apps - -#: Minimize macOS window - -# map cmd+m minimize_macos_window - -#: Quit kitty - -# map cmd+q quit - -#: }}} - -#: }}} diff --git a/config/shell-functions/fuzzy-vim.sh b/config/shell-functions/fuzzy-vim.sh deleted file mode 100644 index f1bb864..0000000 --- a/config/shell-functions/fuzzy-vim.sh +++ /dev/null @@ -1,44 +0,0 @@ -# Smart fuzzy vim wrapper (Bash + Zsh compatible) -vim() { - if [[ $# -eq 0 ]]; then - # Check if fzf exists - if ! command -v fzf >/dev/null 2>&1; then - echo "fzf not found, opening normal vim..." >&2 - command vim - return - fi - - # List of directories to ignore - local ignore_dirs=(".git" "node_modules" "vendor" "venv" ".cache") - - # If fd exists, use it. Otherwise fallback to find - if command -v fd >/dev/null 2>&1; then - local fd_cmd="fd --type f" - for dir in "${ignore_dirs[@]}"; do - fd_cmd+=" --exclude $dir" - done - local file=$(eval "$fd_cmd" | fzf --height 40% --reverse --border) - else - local find_cmd="find ." - for dir in "${ignore_dirs[@]}"; do - find_cmd+=" -path \"*/$dir/*\" -prune -o" - done - find_cmd+=" -type f -print" - local file=$(eval "$find_cmd" 2>/dev/null | fzf --height 40% --reverse --border) - fi - - if [[ -n "$file" ]]; then - command vim "$file" - fi - else - command vim "$@" - fi -} - -# 🛡 Fix: Preserve vim autocompletion behavior -if [[ -n "$ZSH_VERSION" ]]; then - compdef _vim vim -elif [[ -n "$BASH_VERSION" ]]; then - complete -o default -o bashdefault vim -fi - diff --git a/config/themes/diff-frappe.conf b/config/themes/diff-frappe.conf deleted file mode 100644 index bac699c..0000000 --- a/config/themes/diff-frappe.conf +++ /dev/null @@ -1,50 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Diff Frappé -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/diff-frappe.conf -## blurb: Soothing pastel theme for the high-spirited! - -# text -foreground #c6d0f5 -# base -background #303446 -# subtext0 -title_fg #a5adce - -# mantle -title_bg #292c3c -margin_bg #292c3c - -# subtext1 -margin_fg #a5adce -# mantle -filler_bg #292c3c - -# 30% red, 70% base -removed_bg #684b59 -# 50% red, 50% base -highlight_removed_bg #8c5b65 -# 40% red, 60% base -removed_margin_bg #79535f - -# 30% green, 70% base -added_bg #54635a -# 50% green, 50% base -highlight_added_bg #6b8368 -# 40% green, 60% base -added_margin_bg #79535f - -# mantle -hunk_margin_bg #292c3c -hunk_bg #292c3c - -# 40% yellow, 60% base -search_bg #796f64 -# text -search_fg #c6d0f5 -# 30% sky, 70% base -select_bg #506373 -# text -select_fg #c6d0f5 diff --git a/config/themes/diff-latte.conf b/config/themes/diff-latte.conf deleted file mode 100644 index f1f00b3..0000000 --- a/config/themes/diff-latte.conf +++ /dev/null @@ -1,50 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Diff Latte -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/diff-latte.conf -## blurb: Soothing pastel theme for the high-spirited! - -# text -foreground #4c4f69 -# base -background #eff1f5 -# subtext0 -title_fg #6c6f85 - -# mantle -title_bg #e6e9ef -margin_bg #e6e9ef - -# subtext1 -margin_fg #5c5f77 -# mantle -filler_bg #e6e9ef - -# 30% red, 70% base -removed_bg #e6adbc -# 50% red, 50% base -highlight_removed_bg #e08097 -# 40% red, 60% base -removed_margin_bg #e397aa - -# 30% green, 70% base -added_bg #bad8b8 -# 50% green, 50% base -highlight_added_bg #97c890 -# 40% green, 60% base -added_margin_bg #e397aa - -# mantle -hunk_margin_bg #e6e9ef -hunk_bg #e6e9ef - -# 40% yellow, 60% base -search_bg #e8ca9f -# text -search_fg #4c4f69 -# 30% sky, 70% base -select_bg #a8daf0 -# text -select_fg #4c4f69 diff --git a/config/themes/diff-macchiato.conf b/config/themes/diff-macchiato.conf deleted file mode 100644 index f590b8e..0000000 --- a/config/themes/diff-macchiato.conf +++ /dev/null @@ -1,50 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Diff Macchiato -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/diff-macchiato.conf -## blurb: Soothing pastel theme for the high-spirited! - -# text -foreground #cad3f5 -# base -background #24273a -# subtext0 -title_fg #a5adcb - -# mantle -title_bg #1e2030 -margin_bg #1e2030 - -# subtext1 -margin_fg #a5adcb -# mantle -filler_bg #1e2030 - -# 30% red, 70% base -removed_bg #614455 -# 50% red, 50% base -highlight_removed_bg #895768 -# 40% red, 60% base -removed_margin_bg #754d5f - -# 30% green, 70% base -added_bg #4b5d55 -# 50% green, 50% base -highlight_added_bg #658068 -# 40% green, 60% base -added_margin_bg #754d5f - -# mantle -hunk_margin_bg #1e2030 -hunk_bg #1e2030 - -# 40% yellow, 60% base -search_bg #756c63 -# text -search_fg #cad3f5 -# 30% sky, 70% base -select_bg #455c6d -# text -select_fg #cad3f5 diff --git a/config/themes/diff-mocha.conf b/config/themes/diff-mocha.conf deleted file mode 100644 index b627460..0000000 --- a/config/themes/diff-mocha.conf +++ /dev/null @@ -1,50 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Diff Mocha -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/diff-mocha.conf -## blurb: Soothing pastel theme for the high-spirited! - -# text -foreground #cdd6f4 -# base -background #1e1e2e -# subtext0 -title_fg #a6adc8 - -# mantle -title_bg #181825 -margin_bg #181825 - -# subtext1 -margin_fg #a6adc8 -# mantle -filler_bg #181825 - -# 30% red, 70% base -removed_bg #5e3f53 -# 50% red, 50% base -highlight_removed_bg #89556b -# 40% red, 60% base -removed_margin_bg #734a5f - -# 30% green, 70% base -added_bg #475a51 -# 50% green, 50% base -highlight_added_bg #628168 -# 40% green, 60% base -added_margin_bg #734a5f - -# mantle -hunk_margin_bg #181825 -hunk_bg #181825 - -# 40% yellow, 60% base -search_bg #766c62 -# text -search_fg #cdd6f4 -# 30% sky, 70% base -select_bg #3e5767 -# text -select_fg #cdd6f4 diff --git a/config/themes/frappe.conf b/config/themes/frappe.conf deleted file mode 100644 index a785bce..0000000 --- a/config/themes/frappe.conf +++ /dev/null @@ -1,80 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Frappé -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/frappe.conf -## blurb: Soothing pastel theme for the high-spirited! - - - -# The basic colors -foreground #c6d0f5 -background #303446 -selection_foreground #303446 -selection_background #f2d5cf - -# Cursor colors -cursor #f2d5cf -cursor_text_color #303446 - -# URL underline color when hovering with mouse -url_color #f2d5cf - -# Kitty window border colors -active_border_color #babbf1 -inactive_border_color #737994 -bell_border_color #e5c890 - -# OS Window titlebar colors -wayland_titlebar_color system -macos_titlebar_color system - -# Tab bar colors -active_tab_foreground #232634 -active_tab_background #ca9ee6 -inactive_tab_foreground #c6d0f5 -inactive_tab_background #292c3c -tab_bar_background #232634 - -# Colors for marks (marked text in the terminal) -mark1_foreground #303446 -mark1_background #babbf1 -mark2_foreground #303446 -mark2_background #ca9ee6 -mark3_foreground #303446 -mark3_background #85c1dc - -# The 16 terminal colors - -# black -color0 #51576d -color8 #626880 - -# red -color1 #e78284 -color9 #e78284 - -# green -color2 #a6d189 -color10 #a6d189 - -# yellow -color3 #e5c890 -color11 #e5c890 - -# blue -color4 #8caaee -color12 #8caaee - -# magenta -color5 #f4b8e4 -color13 #f4b8e4 - -# cyan -color6 #81c8be -color14 #81c8be - -# white -color7 #b5bfe2 -color15 #a5adce diff --git a/config/themes/latte.conf b/config/themes/latte.conf deleted file mode 100644 index 31c37bc..0000000 --- a/config/themes/latte.conf +++ /dev/null @@ -1,80 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Latte -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/latte.conf -## blurb: Soothing pastel theme for the high-spirited! - - - -# The basic colors -foreground #4c4f69 -background #eff1f5 -selection_foreground #eff1f5 -selection_background #dc8a78 - -# Cursor colors -cursor #dc8a78 -cursor_text_color #eff1f5 - -# URL underline color when hovering with mouse -url_color #dc8a78 - -# Kitty window border colors -active_border_color #7287fd -inactive_border_color #9ca0b0 -bell_border_color #df8e1d - -# OS Window titlebar colors -wayland_titlebar_color system -macos_titlebar_color system - -# Tab bar colors -active_tab_foreground #eff1f5 -active_tab_background #8839ef -inactive_tab_foreground #4c4f69 -inactive_tab_background #9ca0b0 -tab_bar_background #bcc0cc - -# Colors for marks (marked text in the terminal) -mark1_foreground #eff1f5 -mark1_background #7287fd -mark2_foreground #eff1f5 -mark2_background #8839ef -mark3_foreground #eff1f5 -mark3_background #209fb5 - -# The 16 terminal colors - -# black -color0 #5c5f77 -color8 #6c6f85 - -# red -color1 #d20f39 -color9 #d20f39 - -# green -color2 #40a02b -color10 #40a02b - -# yellow -color3 #df8e1d -color11 #df8e1d - -# blue -color4 #1e66f5 -color12 #1e66f5 - -# magenta -color5 #ea76cb -color13 #ea76cb - -# cyan -color6 #179299 -color14 #179299 - -# white -color7 #acb0be -color15 #bcc0cc diff --git a/config/themes/macchiato.conf b/config/themes/macchiato.conf deleted file mode 100644 index 21c31bb..0000000 --- a/config/themes/macchiato.conf +++ /dev/null @@ -1,80 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Macchiato -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/macchiato.conf -## blurb: Soothing pastel theme for the high-spirited! - - - -# The basic colors -foreground #cad3f5 -background #24273a -selection_foreground #24273a -selection_background #f4dbd6 - -# Cursor colors -cursor #f4dbd6 -cursor_text_color #24273a - -# URL underline color when hovering with mouse -url_color #f4dbd6 - -# Kitty window border colors -active_border_color #b7bdf8 -inactive_border_color #6e738d -bell_border_color #eed49f - -# OS Window titlebar colors -wayland_titlebar_color system -macos_titlebar_color system - -# Tab bar colors -active_tab_foreground #181926 -active_tab_background #c6a0f6 -inactive_tab_foreground #cad3f5 -inactive_tab_background #1e2030 -tab_bar_background #181926 - -# Colors for marks (marked text in the terminal) -mark1_foreground #24273a -mark1_background #b7bdf8 -mark2_foreground #24273a -mark2_background #c6a0f6 -mark3_foreground #24273a -mark3_background #7dc4e4 - -# The 16 terminal colors - -# black -color0 #494d64 -color8 #5b6078 - -# red -color1 #ed8796 -color9 #ed8796 - -# green -color2 #a6da95 -color10 #a6da95 - -# yellow -color3 #eed49f -color11 #eed49f - -# blue -color4 #8aadf4 -color12 #8aadf4 - -# magenta -color5 #f5bde6 -color13 #f5bde6 - -# cyan -color6 #8bd5ca -color14 #8bd5ca - -# white -color7 #b8c0e0 -color15 #a5adcb diff --git a/config/themes/mocha.conf b/config/themes/mocha.conf deleted file mode 100644 index f37adf9..0000000 --- a/config/themes/mocha.conf +++ /dev/null @@ -1,80 +0,0 @@ -# vim:ft=kitty - -## name: Catppuccin Kitty Mocha -## author: Catppuccin Org -## license: MIT -## upstream: https://github.com/catppuccin/kitty/blob/main/themes/mocha.conf -## blurb: Soothing pastel theme for the high-spirited! - - - -# The basic colors -foreground #cdd6f4 -background #1e1e2e -selection_foreground #1e1e2e -selection_background #f5e0dc - -# Cursor colors -cursor #f5e0dc -cursor_text_color #1e1e2e - -# URL underline color when hovering with mouse -url_color #f5e0dc - -# Kitty window border colors -active_border_color #b4befe -inactive_border_color #6c7086 -bell_border_color #f9e2af - -# OS Window titlebar colors -wayland_titlebar_color system -macos_titlebar_color system - -# Tab bar colors -active_tab_foreground #11111b -active_tab_background #cba6f7 -inactive_tab_foreground #cdd6f4 -inactive_tab_background #181825 -tab_bar_background #11111b - -# Colors for marks (marked text in the terminal) -mark1_foreground #1e1e2e -mark1_background #b4befe -mark2_foreground #1e1e2e -mark2_background #cba6f7 -mark3_foreground #1e1e2e -mark3_background #74c7ec - -# The 16 terminal colors - -# black -color0 #45475a -color8 #585b70 - -# red -color1 #f38ba8 -color9 #f38ba8 - -# green -color2 #a6e3a1 -color10 #a6e3a1 - -# yellow -color3 #f9e2af -color11 #f9e2af - -# blue -color4 #89b4fa -color12 #89b4fa - -# magenta -color5 #f5c2e7 -color13 #f5c2e7 - -# cyan -color6 #94e2d5 -color14 #94e2d5 - -# white -color7 #bac2de -color15 #a6adc8 diff --git a/darwin/Brewfile b/darwin/Brewfile index 2f87b79..3ab3f6e 100644 --- a/darwin/Brewfile +++ b/darwin/Brewfile @@ -1,41 +1,68 @@ +brew "argon2" brew "awscli" +brew "python@3.13" +brew "azure-cli" brew "bash" brew "bat" brew "binutils" +brew "cmake" brew "coreutils" brew "diffutils" +brew "doppler" +brew "duckdb" brew "eksctl" brew "fd" +brew "ffmpeg" brew "findutils" brew "fzf" brew "gawk" +brew "gcc" +brew "gh" brew "git" brew "gnu-sed" brew "gnu-tar" brew "gnu-which" +brew "go" +brew "go-task" brew "grep" brew "gzip" -brew "hashicorp/tap/terraform" brew "helm" +brew "helmfile" brew "htop" brew "k9s" brew "kubernetes-cli" +brew "kustomize" +brew "libb64" brew "libpq" brew "make" brew "minikube" +brew "mypy" +brew "neovim" brew "node" +brew "ollama" brew "poetry" +brew "ripgrep" +brew "rtk" brew "rust" +brew "rustup" brew "terraformer" brew "tflint" brew "tree" +brew "universal-ctags" brew "virtualenv" brew "vite" brew "wget" - -# Casks -cask "docker" +brew "whisper-cpp" +brew "wireguard-tools" +cask "bunch" +cask "claude-code@latest" cask "docker-desktop" cask "font-noto-color-emoji" +cask "gcloud-cli" cask "slack" cask "spotify" +cask "superwhisper" +cargo "sqlx-cli" +cargo "worker-build" +npm "@openai/codex" +cask "font-fira-code-nerd-font" diff --git a/darwin/README.md b/darwin/README.md index d856164..2b348df 100644 --- a/darwin/README.md +++ b/darwin/README.md @@ -6,4 +6,4 @@ This directory contains configurations specific to macOS systems. - `Brewfile` - Homebrew packages and casks - Kitty terminal configs with macOS-specific keybindings (cmd+) -- System preferences and defaults \ No newline at end of file +- System preferences and defaults diff --git a/darwin/ai-context/machine.md b/darwin/ai-context/machine.md new file mode 100644 index 0000000..de2cd48 --- /dev/null +++ b/darwin/ai-context/machine.md @@ -0,0 +1,35 @@ +# Machine: MacBook + +## System + +- **OS**: macOS +- **Package manager**: Homebrew +- **Shell**: zsh +- **Terminal**: Kitty + +## Primary Use + +- Personal projects +- Mobile development (React Native, iOS) +- General development + +## Package Installation + +```bash +# Homebrew +brew install + +# Cask (GUI apps) +brew install --cask +``` + +## Paths + +- Dotfiles: `~/workspace/dotfiles` +- Projects: `~/workspace/` + +## Notes + +- Uses GNU coreutils via Homebrew (aliased to replace BSD tools) +- Catppuccin theme +- Brewfile in dotfiles for reproducible setup diff --git a/docs/convergence/combined-plan.md b/docs/convergence/combined-plan.md new file mode 100644 index 0000000..27090c6 --- /dev/null +++ b/docs/convergence/combined-plan.md @@ -0,0 +1,450 @@ +> **Status (2026-07):** historical/archived. This is the negotiated two-agent +> plan that the convergence executed; the decisions that superseded parts of it +> are listed in the status header of `docs/machine-convergence-plan.md`. The +> planned backup-restore deliverable was descoped - restores are manual from +> the path-preserving `~/.dotfiles-backup-*` directories using the audit log. + +# Combined Dotfiles Convergence Plan + +## Agreement + +Codex and Claude agree on the convergence model: + +> Shared tooling behavior should converge in common config. Platform and machine +> presentation should remain intentionally different. + +The merged dotfiles repo should work for the macOS MacBook Pro, the Linux +`jm-home-box`, and future machines without forcing one machine's visual identity +onto another. + +## Source Branches + +- `feature/personal-laptop-combined`: current macOS laptop branch. Treat as + authoritative for recent macOS package state, copy-only installer behavior, + Neovim defaulting, shell updates, and test additions. +- `origin/fix/jm-home-box`: current Linux `jm-home-box` branch. Treat as + authoritative for Arch/Linux package state, Sway/SwayFX visuals, Linux machine + state, and Linux convergence tooling. +- `feature/ai-context`: inspect as an input for machine-state and AI-context + infrastructure. Bring forward useful structure if it fits the final + `machines/` model. +- `feature/add-linux-box`: historical Linux input only. Use for context if a + file exists there that explains a current Linux choice. + +## Core Rules + +1. Shared behavior lives in `common/`. +2. macOS-specific configuration lives in `darwin/`. +3. Linux-specific configuration lives in `linux/`. +4. Machine facts and selected profiles live in `machines//`. +5. Visual identity remains platform or machine specific. +6. Installer behavior must use regular copied files, not symlinks. +7. Installer behavior must preserve path-aware backups and an audit log. +8. Neovim is the target editor when available. +9. `vi`, `vim`, and `vimdiff` should use Neovim when available. +10. `EDITOR` and `VISUAL` should prefer `nvim` when available. +11. `which` should be shell-aware and should see aliases. Do not alias `which` + to `gwhich`. +12. Do not copy local daemon sockets, local runtime state, or installer comments + into shared dotfiles. +13. Do not create a MacBook machine profile unless there are true machine facts + that cannot live in `darwin/` or `common/`. +14. Current installed state on the MacBook Pro and `jm-home-box` is part of the + source of truth. Capture and classify that state before merging branches or + applying installs. + +## Proposed Final Layout + +```text +. +├── common/ +│ ├── bin/ +│ │ └── dotfiles +│ ├── git/ +│ │ ├── .gitconfig +│ │ ├── .gitignore_global +│ │ └── commit-template.md +│ ├── nvim/ +│ │ └── init.vim +│ ├── shell/ +│ │ ├── .bash_profile +│ │ ├── .bashrc +│ │ ├── .bashrc.server +│ │ ├── .gnu_aliases +│ │ └── .zshrc +│ ├── shell-functions/ +│ │ ├── editor.sh +│ │ ├── which.sh +│ │ └── ... +│ ├── ssh/ +│ └── themes/ +├── darwin/ +│ ├── Brewfile +│ ├── kitty.conf +│ └── README.md +├── linux/ +│ ├── arch/ +│ │ ├── packages.list +│ │ ├── ai-context/ +│ │ └── .config/sway/ +│ ├── common/ +│ │ └── kitty.conf +│ └── README.md +├── machines/ +│ └── jm-home-box/ +│ └── machine.toml +├── scripts/ +├── install.sh +├── Makefile +└── README.md +``` + +Potential later addition: + +```text +.agents/ +├── AGENTS.md +├── RTK.md +└── skills/ +``` + +Agent behavior should be shared by default. Do not add machine-specific +`AGENTS.md` files unless a machine truly needs different agent operating rules. + +## Merge Strategy + +Use `feature/personal-laptop-combined` as the practical base because it already +contains the current copy-only installer, audit/test behavior, Neovim defaulting, +and macOS state. + +Then merge `origin/fix/jm-home-box` and preserve Linux-specific files in their +proper layer. + +### Phase 0: Capture Current Installed State + +Before merging or applying anything, capture current reality on both machines in +read-only mode. + +MacBook Pro snapshot: + +- Current dotfiles repo branch, status, remotes, and recent log. +- Managed file checksums and file types. +- Symlink-vs-regular-file audit for managed targets. +- Current Homebrew bundle dump. +- Shell/editor behavior: `type vim`, `which vim`, `which -a vim`, `EDITOR`, + `VISUAL`, `vim --version`, and `nvim --version`. +- Local-only drift such as `git-ai` PATH edits or Git trace2 sockets. + +`jm-home-box` snapshot: + +- Current dotfiles repo branch, status, remotes, and recent log. +- Managed file checksums and file types. +- Symlink-vs-regular-file audit for managed targets. +- Current Arch package state or package list. +- Shell/editor behavior: `type vim`, `which vim`, `which -a vim`, `EDITOR`, + `VISUAL`, `vim --version`, and `nvim --version`. +- Machine-state files. +- Sway, SwayFX, Kitty, theme, and visual state. +- Local-only drift and generated/runtime state. + +Save snapshots outside the repo working tree under timestamped paths, for +example: + +```text +/private/tmp/dotfiles-state-/ +~/convo/dotfiles/state-/ +``` + +Classify every observed drift item before merge work: + +- Shared behavior. +- Platform-specific config. +- Machine-specific facts or visuals. +- Local runtime state. +- Stale/generated artifact. +- Needs human decision. + +Only after this classification should branch merging or installer testing begin. + +Order of work: + +1. Start from clean worktrees on both machines. +2. Capture current installed state on both machines. +3. Classify drift before editing. +4. Fetch all remotes. +5. Create a convergence branch from `feature/personal-laptop-combined`. +6. Inspect `feature/ai-context` for reusable machine-state structure. +7. Merge `origin/fix/jm-home-box`. +8. Resolve conflicts by category, not by blindly picking one side. +9. Run narrow verification after each category. +10. Run full verification on macOS and Linux. +11. Commit the convergence. +12. Push the convergence branch for review. + +## Conflict Resolution Rules + +### Shared Shell + +Files: + +- `common/shell/.zshrc` +- `common/shell/.bashrc` +- `common/shell/.bash_profile` +- `common/shell/.bashrc.server` +- `common/shell/.gnu_aliases` +- `common/shell-functions/*.sh` + +Keep: + +- Guarded portable PATH logic. +- `rtk` conventions where installed. +- `~/.git-ai/bin` only as guarded PATH support, not installer comments. +- `PROMPT_EOL_MARK=''`. +- Shared aliases/functions where the underlying tools exist on both platforms. +- `editor.sh` for `nvim` defaulting. +- `which.sh` for shell-aware lookup. + +Avoid: + +- Hardcoded local daemon paths. +- Platform package-manager aliases that are not guarded. +- Reintroducing `which -> gwhich`. + +### Editor + +Files: + +- `.vim/vimrc` +- `.vim/plugins.vim` +- `.vim/mappings.vim` +- `.vim/settings/*.vim` +- `.vim/coc-settings.json` +- `common/nvim/init.vim` +- `scripts/check-editor-parity.sh` +- `scripts/editor-parity.vim` + +Make Vim-to-Neovim audit a named step: + +1. Compare Vim and Neovim config entry points. +2. Inventory plugins in `.vim/plugins.vim`. +3. Inventory mappings in `.vim/mappings.vim` and `.vim/settings/keybindings.vim`. +4. Inventory settings in `.vim/settings/*.vim`. +5. Guard Vim-only settings so Neovim loads cleanly. +6. Confirm keybindings and editor behavior are identical across machines. +7. Run editor parity checks. + +Neovim is the target editor. Vim config may remain as compatibility/source +material, but new shared editor behavior should converge toward Neovim. + +### Git + +Files: + +- `common/git/.gitconfig` +- `common/git/.gitignore_global` +- `common/git/commit-template.md` + +Keep: + +- Commit template. +- Shared Git aliases. +- Portable GitHub HTTPS-to-SSH rewrite if the user wants that globally. + +Exclude: + +- Local Git trace2 daemon socket paths. +- Machine-local Git runtime state. + +### Terminal and Visuals + +Files: + +- `darwin/kitty.conf` +- `linux/common/kitty.conf` +- `common/themes/*.conf` +- `linux/arch/.config/sway/config` +- `linux/arch/.config/sway/assets/*` + +Keep: + +- macOS Kitty visual identity in `darwin/`. +- Linux pinkish Sway/SwayFX identity in `linux/` and `machines/jm-home-box/`. +- Shared themes only when they are genuinely reusable assets. + +Avoid: + +- Making Linux look like macOS. +- Making macOS look like Linux. +- Moving visual choices into global shared config. + +### Package Management + +Files: + +- `darwin/Brewfile` +- `linux/arch/packages.list` +- other Linux package lists +- `machines/jm-home-box/machine.toml` + +Keep package files platform specific. + +Tools expected to be aligned where possible: + +- `git` +- `nvim` +- `fzf` +- `ripgrep` +- `fd` +- `bat` +- `kitty` +- `rtk` +- `node` + +Do not add macOS casks to Linux package lists. Do not remove Linux packages just +because they do not exist in the Brewfile. + +### Installer + +Files: + +- `install.sh` +- `Makefile` +- `scripts/test-install.sh` + +Keep: + +- Copy-only install behavior. +- No symlink default. +- Path-preserving backups. +- Audit log. +- Platform detection. +- Minimal/container/remote modes where supported. +- Tests proving no symlink install behavior. + +If jm-home-box has Linux-specific install logic, preserve the behavior but adapt +it to copy-only semantics. + +### Scripts + +Create a script classification table during the merge. + +Categories: + +- Shared-safe. +- macOS-only. +- Linux-only. +- `jm-home-box` specific. +- Obsolete/superseded. +- Needs review. + +Do not move scripts solely for tidiness in the first convergence. Move scripts +only when needed to prevent wrong-machine execution or to make machine scope +explicit. + +Include `common/bin/dotfiles` in the inventory and classify it as either a shared +helper or a machine-convergence helper. + +### Skills and Agents + +Inspect: + +- `.agents/skills/` +- `.claude/skills/` +- any symlink or copy relationship between them + +Classify skills as: + +- Shared default behavior. +- Platform specific. +- Machine specific. +- Experimental. + +Do not add machine-specific `AGENTS.md` files by default. Machine specs should +describe facts and roles, not agent behavior. + +## Required Verification + +Run on macOS: + +```bash +make check +make check-editor +zsh -n common/shell/.zshrc +bash -n common/shell/.bashrc +bash -n install.sh +git diff --check +``` + +Run on Linux: + +```bash +make check +make check-editor +zsh -n common/shell/.zshrc +bash -n common/shell/.bashrc +bash -n install.sh +git diff --check +``` + +If a source branch lacks `make check`, use the closest available checks and add +or port the shared `make check` target during convergence. + +Manual behavior checks: + +```bash +source ~/.zshrc +type vim +which vim +which -a vim +vim --version +nvim --version +echo "$EDITOR" +echo "$VISUAL" +``` + +Expected: + +- `vim` is an alias to `nvim` when Neovim exists. +- `which vim` reports `nvim`. +- `which -a vim` shows the alias result and system fallback if present. +- `EDITOR` and `VISUAL` prefer `nvim`. + +Install checks: + +- Installed files are regular files. +- Installed files are not symlinks. +- Existing files are backed up before replacement. +- Backup paths preserve target structure. +- Audit log records mkdir, backup, remove, and copy actions. + +## Open Decisions + +1. Should GitHub HTTPS-to-SSH rewrite be global for all machines? +2. Should `git-ai` PATH support remain shared or move to an optional tool + snippet? +3. Should jm-home-box convergence scripts remain in top-level `scripts/`, or + move under `machines/jm-home-box/` later? +4. Should `.agents/` be added as part of this convergence, or handled as a + follow-up? +5. Should theme selection become explicitly profile-driven, while keeping + current visual files in place? + +## Success Criteria + +The convergence is complete when: + +- The convergence branch contains useful work from both source branches. +- Current installed state was captured on both machines before merge/install + work. +- Observed drift was classified as shared behavior, platform config, machine + facts/visuals, local runtime state, stale/generated artifact, or human + decision. +- MacBook command-line behavior remains consistent with current laptop branch. +- jm-home-box Linux visuals and Sway/SwayFX setup are preserved. +- Neovim behavior is shared. +- Shell aliases/functions are consistent where portable. +- Installer remains copy-only, backed up, and audited. +- Scripts are classified by scope. +- Skills/agents are inventoried if present. +- Verification passes on macOS and Linux. +- Remaining platform-only differences are documented and intentional. diff --git a/docs/convergence/conversation-for-plan.md b/docs/convergence/conversation-for-plan.md new file mode 100644 index 0000000..79d87f7 --- /dev/null +++ b/docs/convergence/conversation-for-plan.md @@ -0,0 +1,4 @@ +{"author":"codex","message":"I have read both planning files and I propose this convergence strategy.\n\nShared behavior should be unified in common/: Neovim as the default editor when available; vi/vim/vimdiff routing to nvim; EDITOR/VISUAL preferring nvim; shell-aware which; shared Git aliases and commit template; rtk conventions; and an installer that uses regular copies, path-preserving backups, and an audit log.\n\nMachine and platform identity should remain separate: macOS package/app choices in darwin/Brewfile, Arch/Linux package choices in linux/arch/packages.list, jm-home-box hardware/state facts in machines/jm-home-box/, macOS Kitty visuals in darwin/, Linux Kitty/Sway/SwayFX pink visual identity in linux/ and machine profile files. We should not make Linux look like macOS or macOS look like Linux.\n\nFor the merge order, I recommend starting from feature/personal-laptop-combined because it already has the copy-only installer, audit/test work, current macOS state, and Neovim defaults. Then merge origin/fix/jm-home-box and preserve Linux-specific package/state/visual files. Conflict resolution should favor shared portable behavior in common/, platform-specific files in darwin/ or linux/, and machine facts in machines/.\n\nI think the final combined plan should include: final layout, merge order, conflict-resolution rules, verification on macOS and Linux, explicit no-symlink/no-local-daemon-state constraints, and open decisions around git-ai PATH, GitHub HTTPS-to-SSH rewrite, agents, and where jm-home-box convergence scripts should live.\n\nClaude, do you agree with this framing? If not, please propose concrete changes. If yes, please say so and add any missing merge rules you think are necessary before we write combined-plan.md.\n"} +{"author":"claude","message":"I agree with the core framing — three-layer model (common/, platform, machine), personal-laptop-combined as the merge base, copy-only installer, nvim everywhere. A few concrete additions I think we need before we write the combined plan:\n\n1. SKILLS LAYER: Neither plan fully accounts for .agents/skills/ (or .claude/skills/ symlink). The jm-home-box branch already has this structure. We should classify skills explicitly: machine-agnostic (kickstart, code-review, deep-research, run, verify, etc.) stay in .agents/skills/ and work on both machines; machine-specific ones (archlinux-update-system is Linux-only, anything brew-dependent is mac-only) get a note in their frontmatter but still live in the same directory. The install.sh should copy .agents/ on both platforms.\n\n2. VIM→NVIM PORT AUDIT MUST BE A NAMED STEP: Saying 'nvim as default' is not enough. Before the merge, someone needs to diff .vim/settings/keybindings.vim + .vim/mappings.vim against common/nvim/init.vim across both branches and produce an explicit list of unported bindings and plugins. This audit should happen in step 3 of the merge, before any install.sh work, so we know exactly what needs to go into common/nvim/init.vim. I'd call this step 'nvim parity audit and port.'\n\n3. SCRIPTS CLASSIFICATION: We should include a table in the combined plan. From what I can see across branches: shared-safe are check-editor-parity.sh, editor-parity.vim, minimal-bashrc.sh, test-install.sh, quick-install.sh, ssh-copy-dotfiles.sh; linux-only are sudo-askpass.sh and dotfiles.py (Arch convergence tooling); mac-oriented is update_cursor_tools.py. The combined plan should say which scripts get installed by default and which are run-on-demand.\n\n4. FEATURE/AI-CONTEXT: Your plan and mine both omit the feature/ai-context branch, which added machine-state context files and a pacman hook. The jm-home-box branch appears to have absorbed this already (linux/arch/ai-context/ exists there). The combined plan should confirm this is already folded in and not a separate merge step.\n\n5. COMMON/BIN/: The jm-home-box branch has common/bin/dotfiles (a helper binary/script). This should appear in the final layout explicitly, not just implied by common/.\n\n6. NO MACHINES/ ENTRY FOR MBP: User has one MBP now. No machines/jm-mbp/ needed. The darwin/ layer is sufficient. We should state this explicitly so no one adds a spurious machine file later.\n\nIf you agree with these six additions, I think we have a complete combined plan and I'm ready to write combined-plan.md. Or propose changes to any of these."} +{"author":"codex","message":"I agree with Claude's six additions and consider them necessary for the combined plan.\n\nRefinements to incorporate into combined-plan.md:\n\n1. Skills/agents layer: include .agents/skills or .claude/skills in the inventory if present, but treat agent behavior as shared default behavior unless a machine truly needs different operating rules. Do not create machine-specific AGENTS.md by default.\n\n2. Named Vim-to-Neovim audit: make this an explicit merge step, not just a desired end state. The audit should compare .vim/vimrc, .vim/plugins.vim, .vim/mappings.vim, .vim/settings/*.vim, .vim/coc-settings.json, and common/nvim/init.vim, then list any plugins, settings, and keybindings that still need to be ported or guarded.\n\n3. Scripts classification: include a table classifying scripts as shared-safe, macOS-only, Linux-only, jm-home-box-specific, obsolete, or needs-review. Do not move scripts solely for tidiness during the first convergence unless the move is needed to prevent wrong-machine execution.\n\n4. feature/ai-context: include it as a branch/input to inspect for machine-state and AI-context infrastructure. Bring forward useful machine-state structure if it does not conflict with the cleaner machines/ model.\n\n5. common/bin: include common/bin/dotfiles in the final layout and classify whether it is a shared helper or machine-convergence helper.\n\n6. No MBP machine profile for now: the MacBook can be represented by darwin/ plus shared common/ defaults. Only add machines// when there are true machine facts, roles, hazards, or profile selections that cannot live cleanly in platform config.\n\nWith those additions, I agree we have consensus. The combined plan should now be written as the agreed plan, with the core principle preserved: shared tooling behavior converges, platform and machine presentation remain intentionally different.\n\n\nAdditional consensus update based on user feedback:\n\nReopening one point based on the user's feedback: our combined plan is missing an explicit state-capture-first phase.\n\nThe problem is not just branch convergence. The current installed state on both machines is part of the source of truth. Before merging or applying anything, the plan should require read-only snapshots of the MacBook Pro and jm-home-box current reality.\n\nI propose adding this as Phase 0:\n\n1. Capture current MBP state: dotfiles branch/status/log, managed file checksums and file types, symlink-vs-regular-file audit, Homebrew bundle dump, shell/editor behavior, and local-only drift such as git-ai PATH or trace2 sockets.\n2. Capture current jm-home-box state: dotfiles branch/status/log, managed file checksums and file types, symlink-vs-regular-file audit, Arch package list or pacman state, shell/editor behavior, machine-state files, Sway/Kitty visual state, and local-only drift.\n3. Save snapshots outside the repo working tree, under timestamped paths.\n4. Classify drift before merging: shared behavior, platform-specific config, machine-specific facts/visuals, local runtime state, stale/generated artifacts, or needs human decision.\n5. Only after that classification should we merge branches or run installer tests.\n\nThis changes the execution strategy from \"merge branches, then install\" to \"capture current reality, classify drift, merge branches, test in temp homes, then apply carefully.\"\n\nClaude, do you agree this Phase 0 should be added to combined-plan.md as a required first phase? If yes, please say so explicitly and add any missing details. If no, please explain the concrete alternative.\n"} +{"author":"claude","message":"Confirmed — we have consensus. Codex's refinements align exactly with my additions. Combined-plan.md has been written and reflects the agreed plan. One item to add that came up in conversation with the user: we need an explicit revert strategy. The combined plan should include: (a) the convergence branch never merges to master until verified on both machines — source branches remain intact as machine-level rollback; (b) the installer's backup mechanism is the file-level revert; (c) a make restore-backup or install.sh --restore target that reads the audit log and reverses every copy operation should be a required deliverable of the installer work, tested before declaring the merge done. I'll add this to combined-plan.md now."} diff --git a/docs/convergence/plan-claude.md b/docs/convergence/plan-claude.md new file mode 100644 index 0000000..1cdc53c --- /dev/null +++ b/docs/convergence/plan-claude.md @@ -0,0 +1,104 @@ +# Dotfiles Unification Research Prompt + +You are analyzing a dotfiles repository (~/workspace/dotfiles) to produce a +concrete merge plan. The goal: one coherent dotfiles setup that works across +two machine classes — a Linux Arch desktop (jm-home-box, pinkish/swayfx +aesthetic) and a macOS MBP (personal-laptop-combined, its own visual identity) +— while sharing everything that should be shared. + +## Branches to analyze (in rough chronological order, newest = ground truth) + +- master — baseline +- feature/add-linux-box — early Arch config attempt +- feature/ai-context — AI context file infra +- feature/personal-laptop — MBP snapshot (older) +- feature/personal-laptop-combined — MBP current state (ground truth for mac) +- fix/jm-home-box — Linux box current state (ground truth for linux) + +For each branch, read the following files if they exist and note what's in them: + - common/shell/.zshrc, common/shell/.bashrc + - common/shell-functions/*.sh (all of them) + - common/nvim/init.vim, .vim/vimrc + - .vim/settings/keybindings.vim, .vim/mappings.vim + - .vim/plugins.vim + - config/kitty.conf, darwin/kitty.conf, linux/common/kitty.conf + - linux/arch/.config/sway/config + - darwin/Brewfile + - linux/arch/packages.list + - machines/jm-home-box/machine.toml + - install.sh + - Makefile + - scripts/*.sh, scripts/*.py + - .agents/skills/ or .claude/skills/ (if present) + - common/git/.gitconfig + +## What to extract per file category + +**Shell (aliases + functions)** +- List every alias and function defined in each branch's shell-functions/ +- Flag: exists on both? Linux-only? Mac-only? Diverged (same name, different impl)? + +**Editor (vim → nvim migration)** +- The user wants to move fully to nvim. Compare .vim/vimrc vs common/nvim/init.vim + across branches. What plugins, keybindings, and settings exist in vim that + are NOT yet in nvim? What's already been ported? +- Identify the full keybinding set from .vim/settings/keybindings.vim and + .vim/mappings.vim on both branches. The goal is these must be identical in nvim + across both machines. + +**Terminal / visual** +- Note what theme/colors each branch uses for kitty. Do NOT propose changing them. +- Note what's sway-specific (Linux only) vs what's kitty config that could be shared. + +**Scripts** +- List every script in scripts/ across branches. Classify: shared-safe, linux-only, + mac-only, or obsolete/superseded. + +**Skills** +- List any agent skills found. Classify: machine-agnostic, linux-only, mac-only. + +**Package management** +- darwin/Brewfile (mac), linux/arch/packages.list and machines/jm-home-box/machine.toml (linux) +- Identify tools present on both that should be kept in sync (same version + expectations, same purpose — e.g. fzf, ripgrep, git, nvim, kitty). + +**Install script** +- Compare install.sh across branches. What does it do on each? Does it handle + both platforms or is it platform-specific? + +## Constraints to respect + +1. Do not touch visual/color config (kitty themes, sway colors, pink aesthetic on linux). +2. nvim is the target editor. vim config should be read for what needs porting, not preserved. +3. Keybindings in nvim must be identical on both machines. +4. Aliases must be identical where the underlying tool exists on both platforms. + Where a tool is platform-specific (e.g. brew, pacman, sway), the alias is + machine-scoped — note it but don't try to unify it. +5. The common/ directory is the right place for shared config. + darwin/ and linux/ are the right place for platform-specific config. + +## Output format + +Produce a structured merge plan with these sections: + +### 1. Branch timeline summary +What changed when, which branch is newest/authoritative per area. + +### 2. Shared config inventory +Table: file/category | linux state | mac state | diverged? | merge action + +### 3. vim → nvim porting gaps +Exact list of keybindings, plugins, and settings in vim that aren't in nvim yet. + +### 4. File layout proposal +Proposed final directory structure showing where each config lives +(common/ vs darwin/ vs linux/arch/ vs machines/). + +### 5. Ordered merge steps +Concrete sequence: what to merge first (low-risk shared shell functions), +what to do last (install.sh unification). Flag anything that needs a human +decision before proceeding. + +### 6. Open questions for the user +Anything ambiguous — tools that exist on one machine but not the other, +diverged aliases with different semantics, skills that could go either way. diff --git a/docs/convergence/plan-codex.md b/docs/convergence/plan-codex.md new file mode 100644 index 0000000..42d32d6 --- /dev/null +++ b/docs/convergence/plan-codex.md @@ -0,0 +1,474 @@ +# Dotfiles Unification Plan - Codex + +## Purpose + +Unify the macOS laptop branch and the Linux jm-home-box branch into one default +dotfiles repository that feels consistent to use everywhere, while preserving +machine-specific visuals and platform-specific system configuration. + +Target branches: + +- `feature/personal-laptop-combined`: current macOS laptop branch and current + source of recent Neovim, copy-install, Brewfile, and shell updates. +- `fix/jm-home-box`: current Linux jm-home-box branch and current source of + Arch, Sway, machine-state, and Linux visual configuration. + +Core rule: + +> Common tooling behavior belongs in shared config. Visual identity and +> platform/machine facts belong in platform or machine profiles. + +## Desired Outcome + +The default branch should work on: + +- The MacBook Pro. +- The Linux jm-home-box. +- Future machines with minimal new machine-specific metadata. + +The user experience should be consistent for: + +- Editor commands: `vi`, `vim`, `vimdiff`, `EDITOR`, and `VISUAL`. +- Neovim behavior, plugins, and keybindings. +- Shell aliases and functions where the underlying tools exist. +- `rtk` command conventions. +- Git aliases and commit template. +- Installer behavior, especially regular copied files, no symlinks, backups, + and audit logs. + +The user experience may remain machine-specific for: + +- Kitty theme choice and colors. +- Sway/SwayFX visuals. +- Linux desktop assets. +- macOS application/cask choices. +- Arch package choices. +- Machine role, hardware facts, and known local hazards. + +## Non-Negotiable Constraints + +1. Do not reintroduce symlink-based installation. +2. Installed dotfiles must be regular copied files. +3. Installer must create path-preserving backups before replacing files. +4. Installer must write an auditable install log. +5. Neovim is the target editor when available. +6. `vi`, `vim`, and `vimdiff` should use Neovim when available. +7. `which` must be shell-aware and must see aliases. Do not alias `which` to + `gwhich`. +8. Do not copy local daemon/socket paths into shared config. +9. Do not flatten Linux and macOS visuals into one global theme. +10. Do not stage unrelated changes during the merge. + +## Proposed Final Layout + +```text +. +├── common/ +│ ├── git/ +│ │ ├── .gitconfig +│ │ ├── .gitignore_global +│ │ └── commit-template.md +│ ├── nvim/ +│ │ └── init.vim +│ ├── shell/ +│ │ ├── .bash_profile +│ │ ├── .bashrc +│ │ ├── .bashrc.server +│ │ ├── .gnu_aliases +│ │ └── .zshrc +│ ├── shell-functions/ +│ │ ├── editor.sh +│ │ ├── which.sh +│ │ └── ... +│ ├── themes/ +│ └── ssh/ +├── darwin/ +│ ├── Brewfile +│ ├── kitty.conf +│ └── README.md +├── linux/ +│ ├── arch/ +│ │ ├── packages.list +│ │ ├── ai-context/ +│ │ └── .config/sway/ +│ ├── common/ +│ │ └── kitty.conf +│ └── README.md +├── machines/ +│ └── jm-home-box/ +│ └── machine.toml +├── scripts/ +├── install.sh +├── Makefile +└── README.md +``` + +Potential future addition: + +```text +.agents/ +├── AGENTS.md +├── RTK.md +└── skills/ +``` + +Do not add machine-specific `AGENTS.md` files unless a machine truly needs +different agent behavior. Machine files should describe facts and role, not +agent operating style. + +## Merge Model + +Use a three-layer model: + +1. Shared behavior layer: `common/`, `.vim/`, `common/nvim/`, shared scripts, + Git config, shell functions, Make targets, install logic. +2. Platform layer: `darwin/`, `linux/`, platform package files, platform + terminal config. +3. Machine layer: `machines//`, hardware/state/role metadata and selected + profile facts. + +When branches conflict: + +- Prefer `common/` only for behavior that should feel identical everywhere. +- Prefer `darwin/` for Homebrew, macOS Kitty config, and macOS-specific setup. +- Prefer `linux/` for Arch packages, Sway, Linux Kitty config, and Linux desktop + setup. +- Prefer `machines/jm-home-box/` for jm-home-box state and inventory. +- Prefer the newest tested installer behavior from the laptop branch where it + enforces copy-only installs, backups, and audit logs. +- Preserve jm-home-box visuals from the Linux branch. + +## Area-by-Area Plan + +### 1. Shell Entry Points + +Files: + +- `common/shell/.zshrc` +- `common/shell/.bashrc` +- `common/shell/.bash_profile` +- `common/shell/.bashrc.server` +- `common/shell/.gnu_aliases` + +Desired result: + +- Shared prompt/tool behavior lives in `common/shell`. +- `rtk` is available through normal PATH behavior where installed. +- `~/.git-ai/bin` may be added through a guarded path check, not as a hardcoded + installer comment. +- zsh `PROMPT_EOL_MARK=''` is okay as shared behavior. +- Homebrew PATH belongs in common shell only as guarded macOS-safe path logic. +- Platform-specific package manager aliases should either be guarded or moved + to platform-specific shell snippets if they become numerous. + +Conflict rule: + +- Keep the shell setup that is guarded and portable. +- Remove local installer comments and absolute local daemon state. + +### 2. Shell Functions and Aliases + +Files: + +- `common/shell-functions/*.sh` + +Desired result: + +- `editor.sh` sets `EDITOR` and `VISUAL` to `nvim` when available and aliases + `vi`, `vim`, and `vimdiff` to Neovim. +- `which.sh` provides shell-aware lookup. It must report aliases in zsh/bash. +- Shared aliases should behave the same on both machines where possible. +- Platform-only aliases must be guarded by command availability or split later + into platform snippets. + +Conflict rule: + +- If the same alias/function exists on both branches with different behavior, + keep the version that is command-availability guarded and less destructive. +- Keep Linux-only workflow helpers only when guarded or clearly placed in Linux + config. + +### 3. Editor: Vim to Neovim + +Files: + +- `.vim/vimrc` +- `.vim/plugins.vim` +- `.vim/mappings.vim` +- `.vim/settings/*.vim` +- `.vim/coc-settings.json` +- `common/nvim/init.vim` +- `scripts/check-editor-parity.sh` +- `scripts/editor-parity.vim` + +Desired result: + +- Neovim is the default editor on both machines. +- `common/nvim/init.vim` bridges to existing Vim config where appropriate. +- Vim-only options are guarded so Neovim does not error. +- Keybindings must be identical across machines. +- Editor parity test must pass for both Vim and Neovim config load. + +Conflict rule: + +- Treat Vim config as source compatibility data, not as the long-term target. +- If Linux branch has editor improvements not in the laptop branch, port them + into the shared Neovim/Vim-compatible layer. +- Do not create a Linux-only editor behavior unless it depends on Linux-only + external tooling. + +### 4. Git + +Files: + +- `common/git/.gitconfig` +- `common/git/.gitignore_global` +- `common/git/commit-template.md` + +Desired result: + +- Commit template is shared. +- Git aliases are shared. +- GitHub HTTPS-to-SSH rewrite can be shared if desired. +- Do not include machine-local Git trace2 socket config. + +Conflict rule: + +- Keep portable Git behavior in `common/git/.gitconfig`. +- Exclude local daemon endpoints and temporary experiments. + +### 5. Terminal and Visual Identity + +Files: + +- `darwin/kitty.conf` +- `linux/common/kitty.conf` +- `common/themes/*.conf` +- `linux/arch/.config/sway/config` +- `linux/arch/.config/sway/assets/*` + +Desired result: + +- macOS keeps its own Kitty visual feel. +- jm-home-box keeps its pinkish Linux/Sway visual identity. +- Shared themes can remain in `common/themes`, but selection is platform or + machine-specific. +- Do not force one visual theme onto all machines. + +Conflict rule: + +- Preserve Linux visual files from `fix/jm-home-box`. +- Preserve macOS visual files from `feature/personal-laptop-combined`. +- Only deduplicate purely identical theme assets. + +### 6. Package Management + +Files: + +- `darwin/Brewfile` +- `linux/arch/packages.list` +- other Linux package lists +- `machines/jm-home-box/machine.toml` + +Desired result: + +- macOS packages stay in `darwin/Brewfile`. +- Arch packages stay in `linux/arch/packages.list`. +- Machine state stays in `machines/jm-home-box/machine.toml` or machine-state + docs. +- Shared tool expectations are documented, not forced through one package file. + +Tools that should exist on both where possible: + +- `git` +- `nvim` +- `fzf` +- `ripgrep` +- `fd` +- `bat` +- `kitty` +- `rtk` +- `node` +- shellcheck-compatible shell scripts if available + +Conflict rule: + +- Do not remove Linux package changes from jm-home-box just because they do not + appear in Brewfile. +- Do not add macOS casks to Linux package lists. + +### 7. Installer + +Files: + +- `install.sh` +- `scripts/test-install.sh` +- `Makefile` + +Desired result: + +- One installer supports macOS, Linux, remote, container, and minimal modes. +- Installer uses copies only. +- Installer backs up targets before replacing. +- Installer writes audit logs. +- Installer copies shared config from `common/`. +- Installer copies platform-specific config from `darwin/` or `linux/` based on + OS. +- Installer can eventually read machine metadata, but should not require it for + normal install. + +Conflict rule: + +- Prefer the copy-only audited installer. +- Preserve Linux-specific install functionality if it exists, but adapt it to + copy-only semantics. +- Never reintroduce stow/symlink behavior as default. + +### 8. Scripts + +Files: + +- `scripts/*.sh` +- `scripts/*.py` + +Desired result: + +- Shared verification scripts stay in `scripts/`. +- Linux-only machine convergence scripts can stay under `scripts/` if named + clearly, or move later under `machines/jm-home-box/scripts/`. +- Script names should make scope obvious. + +Conflict rule: + +- Keep scripts needed for current verification. +- Do not delete jm-home-box convergence tooling unless it is superseded and the + replacement is tested. + +## Ordered Merge Steps + +1. Start from a clean worktree. +2. Fetch all remotes. +3. Create or choose a convergence branch from the intended future default base. +4. Merge `feature/personal-laptop-combined`. +5. Merge `origin/fix/jm-home-box`. +6. Resolve conflicts in this order: + - Git config and commit template. + - Shell entry points. + - Shell functions. + - Vim/Neovim. + - Package lists. + - Terminal/visual config. + - Installer and Makefile. + - Scripts. +7. After each conflict category, run the narrow checks for that category. +8. Run full verification before commit. +9. Commit the convergence with a detailed message. +10. Push the convergence branch and compare against both source branches. + +## Verification Checklist + +Required checks on macOS: + +```bash +make check +make check-editor +zsh -n common/shell/.zshrc +bash -n common/shell/.bashrc +bash -n install.sh +git diff --check +``` + +Required checks on Linux: + +```bash +make check +make check-editor +zsh -n common/shell/.zshrc +bash -n common/shell/.bashrc +bash -n install.sh +git diff --check +``` + +If `make check` does not exist on a source branch, use the closest available +checks and add/port `make check` during convergence. + +Manual behavior checks: + +```bash +source ~/.zshrc +type vim +which vim +which -a vim +vim --version +nvim --version +echo "$EDITOR" +echo "$VISUAL" +``` + +Expected behavior: + +- `vim` is an alias to `nvim` when Neovim exists. +- `which vim` reports `nvim`. +- `which -a vim` shows alias result and system fallback if present. +- `EDITOR` and `VISUAL` prefer `nvim`. + +Install checks: + +- Installed files are regular files, not symlinks. +- Existing files are backed up. +- Backup paths preserve target structure. +- Audit log records mkdir, backup, remove, and copy actions. + +## Human Decisions Needed + +1. Should GitHub HTTPS-to-SSH rewrite be global for all machines? +2. Should `git-ai` PATH support remain shared, or move to an optional tool + snippet? +3. Should jm-home-box convergence scripts remain in top-level `scripts/`, or + move under `machines/jm-home-box/` later? +4. Should `.agents/` be added in this merge, or handled as a separate follow-up? +5. Should common themes remain in `common/themes`, or should theme selection be + explicitly profile-driven? + +## Recommended First Merge Strategy + +Use `feature/personal-laptop-combined` as the practical base because it already +has: + +- Recent copy-only installer behavior. +- Audit log and backup behavior. +- Neovim defaulting and editor parity checks. +- Current MacBook Brewfile and shell updates. + +Then merge `origin/fix/jm-home-box` into it and preserve Linux-specific files +where they belong. + +Expected conflict hotspots: + +- `Makefile` +- `install.sh` +- `common/nvim/init.vim` +- `common/shell/.zshrc` +- `common/shell/.bashrc` +- `common/git/.gitconfig` +- `darwin/Brewfile` +- Linux package/state files +- Kitty/Sway visual files + +Resolution principle: + +> Shared tool behavior should converge. Platform and machine presentation +> should remain intentionally different. + +## Final Success Criteria + +The merge is successful when: + +- A clean branch contains both source branches' useful work. +- MacBook install behavior remains unchanged or improved. +- jm-home-box Linux visuals and Sway setup are preserved. +- Neovim behavior is shared. +- Shell aliases/functions are consistent where portable. +- Installer is copy-only, backed up, and audited. +- The branch passes verification on at least one Mac and one Linux machine. +- Any remaining platform-only differences are documented and intentional. diff --git a/docs/machine-convergence-plan.md b/docs/machine-convergence-plan.md new file mode 100644 index 0000000..5e5916f --- /dev/null +++ b/docs/machine-convergence-plan.md @@ -0,0 +1,114 @@ +> **Status (2026-07):** historical. The convergence happened on +> `converge/jm-home-box-laptop`; decisions that supersede parts of this plan: +> `install.sh` is the single install tool (`scripts/dotfiles.py` and +> `machines//` were removed), per-machine visual identity is handled +> by the Arch-only overlay in `linux/arch/.config/kitty/`, and machine-local +> runtime state lives in `~/.bashrc.local` / `~/.zshrc.local` / +> `~/.gitconfig.local` rather than the repo. The negotiated two-agent plan this +> executed is archived in `docs/convergence/combined-plan.md`. + +# Machine Convergence Plan + +Goal: keep the same daily capabilities and muscle memory across `jm-home-box`, +the personal MBP, and the Charlie Labs MBP while preserving machine/style +differences where they are intentional. + +## Branch Model + +- `fix/jm-home-box`: capture and normalize this Arch machine first. +- `fix/personal-mbp`: capture the personal MacBook Pro state. +- `fix/charlie-mbp`: capture the Charlie Labs MacBook Pro state. +- `feat/converge-three-machines`: merge the three inventories into a durable + shared model. + +The `fix/` branches are inventory and cleanup branches. They should not +become permanent configuration silos. + +## Configuration Model + +- `common/`: shared behavior and source-of-truth configs. +- `darwin/`: macOS package lists and platform adapters. +- `linux/`: Linux package lists and platform adapters. +- `machines//`: machine identity, role, and explicit deltas. +- `common/bin/`: executable commands shared by every shell. + +Interactive machines should converge on: + +- Kitty for terminal behavior. +- Zsh for the rich interactive shell. +- Bash as a minimal fallback for servers, containers, and recovery. +- Neovim as the editor target, with Vim kept as fallback. +- 1Password CLI/app integration for secrets and SSH where possible. + +## Copy Deployment + +Managed dotfiles should be copied into place, not symlinked. The repository +remains the source of truth, and drift is detected by comparing live files with +repo sources. + +Current workflow: + +```bash +make dotfiles-doctor +make dotfiles-dry-run +make dotfiles-backup +make dotfiles-install +make dotfiles-diff-live +``` + +`scripts/dotfiles.py` owns the copy-based workflow: + +- backs up managed live files before changes +- copies files into place +- writes `~/.local/share/dotfiles/install-manifest.json` +- reports changed, missing, or symlinked managed files +- checks expected local tools with `doctor` + +## jm-home-box State + +This machine is the first convergence branch. + +Done: + +- Added `machines/jm-home-box/machine.toml`. +- Converted managed live dotfiles from symlinks to real copied files. +- Added backup/install/diff/doctor tooling. +- Added Neovim phase-1 entrypoint that preserves the existing Vim config. +- Added guarded Tree-sitter config for Neovim. +- Fixed copied Linux Kitty theme include. +- Verified `dotfiles diff-live` is clean. + +Still expected locally: + +- Install `zsh`. +- Install `neovim`. +- Test Zsh before making it the login shell. +- Run Neovim plugin install and Tree-sitter setup after `nvim` exists. + +## MBP Capture Plan + +On each MBP: + +1. Create the matching `fix/` branch. +2. Add `machines//machine.toml`. +3. Capture package state: + `brew bundle dump --force --file machines//Brewfile.current`. +4. Capture current shell/editor/terminal state. +5. Run the copy workflow in dry-run mode first. +6. Compare differences against `fix/jm-home-box`. +7. Move shared behavior into `common/`; keep platform differences in `darwin/` + or `linux/`; keep identity differences in `machines//`. + +## Comparison Rules + +Classify every difference as one of: + +- shared behavior +- platform adapter +- machine identity +- style +- obsolete drift + +Only shared behavior belongs in `common/`. Machine identity should be explicit, +small, and documented. + diff --git a/docs/reference/color-linux-box.md b/docs/reference/color-linux-box.md new file mode 100644 index 0000000..f2a4221 --- /dev/null +++ b/docs/reference/color-linux-box.md @@ -0,0 +1,44 @@ +> **Status (2026-07):** historical example of container-based theme derivation. +> `scripts/dotfiles.py` and `machines/` were removed; the shipped theme is the +> Arch-only overlay in `linux/arch/.config/kitty/` (#2A1E2E). + +# Terminal background proposal — jm-home-box + +## Color recommendation + +`#181420` — a deep pink-leaning mantle. + +Why this over the current `#000000`: + +- Pure black is harsh and flattens the `background_opacity 0.95` nuance in `linux/common/kitty.conf`. +- It clashes with the Catppuccin Mocha pastel accents already in `common/themes/current-theme.conf`: + - rosewater cursor `#F5E0DC` + - mauve active tab `#CBA6F7` + - pink `#F5C2E7` +- `#181420` is essentially Catppuccin's `mantle` (`#181825`) nudged warm/rose to match the `style = "personal-pink"` identity declared in `machines/jm-home-box/machine.toml`. +- Stays clearly distinct from the `#11111B` tab bar so panel layering still reads. + +## Alternatives + +| Hex | Feel | +| --------- | ------------------------------------------------------------------- | +| `#1E1825` | Warmer base, brighter — closest to original Mocha brightness | +| `#15101A` | More dramatic, deeper warm-rose dark | +| `#11111B` | Catppuccin crust — official deepest, but merges into the tab bar | + +## Machine-only scope plan + +The current installer (`scripts/dotfiles.py`) copies `common/themes/*.conf` to every machine — no override path exists. + +Proposed change: + +1. Add `machines/jm-home-box/themes/current-theme.conf` containing the warm-rose background override. +2. In `scripts/dotfiles.py`, after the existing `add_glob(entries, "common/themes/*.conf", "~/.config/kitty", "kitty")`, add a gated copy of `machines//themes/*.conf` so machine-specific themes win. +3. Revert the uncommitted `#000000` edit in: + - `common/themes/current-theme.conf` + - `config/current-theme.conf` (stale mirror, unused by current installer) + so the upstream Mocha background is restored for any other machine. + +## Tradeoff + +Adds a small piece of machinery to the installer (one `add_glob` call gated on the directory existing) — minor scope creep, but it's the right hook for the per-machine deltas the convergence plan in `docs/machine-convergence-plan.md` already anticipates ("machine identity" classification). diff --git a/git/.gitconfig b/git/.gitconfig deleted file mode 100644 index 0cc7ab0..0000000 --- a/git/.gitconfig +++ /dev/null @@ -1,19 +0,0 @@ -[user] - name=Jean-Michel Bouchard - email=jim@polarcoordinates.org -[github] - user=woud420 -[color] - ui = auto -[alias] - st = status -sb - lg = log --stat - diff-master = !echo "diff master...origin/master:" && git diff master...origin/master --stat && echo "" && echo "diff origin/master...master:" && git diff origin/master...master --stat - - cm = commit -m - ca = commit --amend - rb = !git fetch && git rebase && git st - cl = !git reset --hard && git clean -df && git st - - up = !git submodule update --init && git st - submodules-to-master = submodule foreach "git fetch && git checkout master && git rebase" \ No newline at end of file diff --git a/git/.gitignore_global b/git/.gitignore_global deleted file mode 100644 index 1e58af4..0000000 --- a/git/.gitignore_global +++ /dev/null @@ -1 +0,0 @@ -**/.claude/settings.local.json \ No newline at end of file diff --git a/install.sh b/install.sh index 8aa7835..b8d2b7c 100755 --- a/install.sh +++ b/install.sh @@ -8,18 +8,20 @@ # 2. Package Installation (optional) # 3. Configuration Installation: # - Shell configs (foundation) -# - Git configuration -# - Shell functions & aliases +# - Git configuration + personal git hooks +# - Shared SSH defaults (via Include) +# - Shell functions & sudo-askpass helper # - Terminal configs (kitty, htop) -# - Vim setup (plugins, LSP, themes) +# - Linux desktop configs (sway/waybar/gtk, arch only) +# - Vim/Neovim setup (plugins, CoC compilation) # - Optional tools (fzf, etc.) +# - AI context files (CLAUDE.md, AGENTS.md, MACHINE.md) # # Features: # - Auto-detects OS and environment (local/remote/container) -# - Creates backups before changes -# - Supports both symlinks and file copying +# - Creates backups before changes (path-preserving, with an audit log) +# - Installs regular file copies, not symlinks # - Compiles CoC.nvim automatically -# - Installs language servers and tools set -e @@ -35,10 +37,11 @@ NC='\033[0m' # No Color # Configuration DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BACKUP_DIR="$HOME/.dotfiles-backup-$(date +%Y%m%d_%H%M%S)" +AUDIT_LOG="" +INSTALL_ARGS="$*" MINIMAL_MODE=false INSTALL_PACKAGES=true DRY_RUN=false -COPY_MODE=false # Parse arguments while [[ $# -gt 0 ]]; do @@ -56,7 +59,7 @@ while [[ $# -gt 0 ]]; do shift ;; --copy) - COPY_MODE=true + # Historical no-op: copied files are now the only install mode. shift ;; -h|--help) @@ -64,7 +67,7 @@ while [[ $# -gt 0 ]]; do echo " --minimal Install minimal config (no fancy tools)" echo " --no-packages Skip package installation" echo " --dry-run Show what would be done without doing it" - echo " --copy Copy files instead of creating symlinks" + echo " --copy No-op; files are always copied" echo " -h, --help Show this help" exit 0 ;; @@ -96,6 +99,52 @@ log_step() { echo -e "${PURPLE}[STEP]${NC} $1" } +init_audit() { + if [[ "$DRY_RUN" == "true" ]] || [[ -n "$AUDIT_LOG" ]]; then + return + fi + + mkdir -p "$BACKUP_DIR" + AUDIT_LOG="$BACKUP_DIR/install-audit.tsv" + { + printf '# dotfiles install audit\n' + printf '# started_at\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" + printf '# dotfiles_dir\t%s\n' "$DOTFILES_DIR" + printf '# args\t%s\n' "$INSTALL_ARGS" + printf 'timestamp\taction\tsource\ttarget\tdetail\n' + } > "$AUDIT_LOG" +} + +audit_action() { + local action="$1" + local source="${2:-}" + local target="${3:-}" + local detail="${4:-}" + + if [[ "$DRY_RUN" == "true" ]]; then + return + fi + + init_audit + printf '%s\t%s\t%s\t%s\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$action" "$source" "$target" "$detail" >> "$AUDIT_LOG" +} + +backup_path_for() { + local file="$1" + local relative + + case "$file" in + "$HOME"/*) + relative="${file#"$HOME"/}" + ;; + *) + relative="absolute/${file#/}" + ;; + esac + + printf '%s/files/%s' "$BACKUP_DIR" "$relative" +} + # OS Detection detect_os() { if [[ "$OSTYPE" == "darwin"* ]]; then @@ -115,7 +164,7 @@ detect_os() { OS="unknown" DISTRO="unknown" fi - + log_info "Detected OS: $OS, Distribution: $DISTRO" } @@ -123,8 +172,12 @@ detect_os() { detect_environment() { if [[ -f /.dockerenv ]] || [[ -n "$CONTAINER" ]]; then ENVIRONMENT="container" - MINIMAL_MODE=true - log_info "Container environment detected, enabling minimal mode" + if [[ -n "${DOTFILES_FULL_INSTALL:-}" ]]; then + log_info "Container detected, but DOTFILES_FULL_INSTALL is set; keeping full install" + else + MINIMAL_MODE=true + log_info "Container environment detected, enabling minimal mode" + fi elif [[ -n "$SSH_CONNECTION" ]] || [[ -n "$SSH_CLIENT" ]]; then ENVIRONMENT="remote" log_info "Remote SSH session detected" @@ -144,7 +197,7 @@ install_packages_macos() { log_info "Would install Homebrew" fi fi - + log_step "Installing packages from Brewfile..." if [[ "$DRY_RUN" == "false" ]]; then brew bundle --file="$DOTFILES_DIR/darwin/Brewfile" || log_warning "Some packages failed to install" @@ -155,7 +208,7 @@ install_packages_macos() { install_packages_linux() { local package_list="" - + case "$DISTRO" in ubuntu|debian) package_list="$DOTFILES_DIR/linux/debian/packages.list" @@ -173,7 +226,7 @@ install_packages_linux() { if [[ "$DRY_RUN" == "false" ]]; then log_step "Installing packages from $package_list..." # Filter comments and empty lines, then install - grep -v '^#' "$package_list" | grep -v '^$' | xargs sudo pacman -S --noconfirm + grep -v '^#' "$package_list" | grep -v '^$' | xargs sudo pacman -S --needed --noconfirm || log_warning "Some packages failed to install" else log_info "Would install packages from $package_list with pacman" fi @@ -206,60 +259,78 @@ install_packages_linux() { esac } -# Backup existing files +# Backup existing files (path-preserving: mirrors directory structure under BACKUP_DIR) backup_file() { local file="$1" if [[ -f "$file" ]] || [[ -L "$file" ]]; then if [[ "$DRY_RUN" == "false" ]]; then - mkdir -p "$BACKUP_DIR" - cp -L "$file" "$BACKUP_DIR/$(basename "$file")" 2>/dev/null || true - log_info "Backed up $file to $BACKUP_DIR" + local backup_path + backup_path="$(backup_path_for "$file")" + mkdir -p "$(dirname "$backup_path")" + if [[ -e "$backup_path" ]] || [[ -L "$backup_path" ]]; then + audit_action "backup-skip" "$file" "$backup_path" "existing backup retained" + else + cp -a "$file" "$backup_path" + audit_action "backup" "$file" "$backup_path" "existing target preserved" + log_info "Backed up $file to $backup_path" + fi else - log_info "Would backup: $file" + log_info "Would backup: $file -> $(backup_path_for "$file")" fi fi } -# Create symlink or copy file -create_symlink() { +# Replace any symlinked ancestor of a target path that resolves into the +# repo checkout with a real directory. Without this, a legacy symlink like +# ~/.vim -> repo/.vim would make install_file delete the REPO's file and +# then copy the source onto itself. +materialize_target_dir() { + local dir="$1" + local ancestor="$dir" + local chain=() + while [[ "$ancestor" != "$HOME" && "$ancestor" != "/" && -n "$ancestor" ]]; do + chain+=("$ancestor") + ancestor="$(dirname "$ancestor")" + done + # Check from the top down so the outermost symlink is replaced first + local i seg resolved + for (( i=${#chain[@]}-1; i>=0; i-- )); do + seg="${chain[$i]}" + if [[ -L "$seg" ]]; then + resolved="$(cd "$seg" 2>/dev/null && pwd -P || true)" + case "$resolved" in + "$DOTFILES_DIR"|"$DOTFILES_DIR"/*) + log_warning "Replacing legacy symlink into the repo: $seg -> $resolved" + rm -f "$seg" + mkdir -p "$seg" + audit_action "unlink" "$resolved" "$seg" "replaced repo symlink with real directory" + ;; + esac + fi + done +} + +# Install a regular copied file +install_file() { local source="$1" local target="$2" local target_dir="$(dirname "$target")" - + if [[ "$DRY_RUN" == "false" ]]; then # Create target directory if it doesn't exist + materialize_target_dir "$target_dir" mkdir -p "$target_dir" - + audit_action "mkdir" "" "$target_dir" "ensure target directory" + # Remove existing file/link - [[ -e "$target" ]] || [[ -L "$target" ]] && rm -f "$target" - - if [[ "$COPY_MODE" == "true" ]]; then - # Copy file - cp "$source" "$target" - log_success "Copied $source -> $target" - else - # Create symlink - ln -sf "$source" "$target" - log_success "Linked $source -> $target" - fi - else - if [[ "$COPY_MODE" == "true" ]]; then - log_info "Would copy: $source -> $target" - else - log_info "Would link: $source -> $target" + if [[ -e "$target" ]] || [[ -L "$target" ]]; then + backup_file "$target" + rm -f "$target" + audit_action "remove" "" "$target" "replace existing target" fi - fi -} -copy_file() { - local source="$1" - local target="$2" - local target_dir - target_dir="$(dirname "$target")" - - if [[ "$DRY_RUN" == "false" ]]; then - mkdir -p "$target_dir" cp -f "$source" "$target" + audit_action "copy" "$source" "$target" "regular file copy" log_success "Copied $source -> $target" else log_info "Would copy: $source -> $target" @@ -269,83 +340,158 @@ copy_file() { # Install shell configurations install_shell_configs() { log_step "Installing shell configurations..." - + # Determine which shell config to use if [[ "$MINIMAL_MODE" == "true" ]]; then backup_file "$HOME/.bashrc" - create_symlink "$DOTFILES_DIR/common/shell/.bashrc.server" "$HOME/.bashrc" + install_file "$DOTFILES_DIR/common/shell/.bashrc.server" "$HOME/.bashrc" else # Install both bash and zsh configs backup_file "$HOME/.bashrc" backup_file "$HOME/.zshrc" backup_file "$HOME/.bash_profile" - create_symlink "$DOTFILES_DIR/common/shell/.bashrc" "$HOME/.bashrc" - create_symlink "$DOTFILES_DIR/common/shell/.zshrc" "$HOME/.zshrc" - create_symlink "$DOTFILES_DIR/common/shell/.bash_profile" "$HOME/.bash_profile" + install_file "$DOTFILES_DIR/common/shell/.bashrc" "$HOME/.bashrc" + install_file "$DOTFILES_DIR/common/shell/.zshrc" "$HOME/.zshrc" + install_file "$DOTFILES_DIR/common/shell/.bash_profile" "$HOME/.bash_profile" fi - + # GNU aliases and dircolors backup_file "$HOME/.gnu_aliases" backup_file "$HOME/.dircolors" - copy_file "$DOTFILES_DIR/common/shell/.gnu_aliases" "$HOME/.gnu_aliases" - copy_file "$DOTFILES_DIR/common/shell/.dircolors" "$HOME/.dircolors" + install_file "$DOTFILES_DIR/common/shell/.gnu_aliases" "$HOME/.gnu_aliases" + install_file "$DOTFILES_DIR/common/shell/.dircolors" "$HOME/.dircolors" } # Install git configuration install_git_config() { log_step "Installing git configuration..." - + backup_file "$HOME/.gitconfig" - create_symlink "$DOTFILES_DIR/common/git/.gitconfig" "$HOME/.gitconfig" + install_file "$DOTFILES_DIR/common/git/.gitconfig" "$HOME/.gitconfig" # Global gitignore - mkdir -p "$HOME/.config/git" - create_symlink "$DOTFILES_DIR/common/git/.gitignore_global" "$HOME/.config/git/ignore" + install_file "$DOTFILES_DIR/common/git/.gitignore_global" "$HOME/.config/git/ignore" + install_file "$DOTFILES_DIR/common/git/commit-template.md" "$HOME/.config/git/commit-template.md" +} + +# Install personal global Git hooks +install_git_hooks() { + log_step "Installing personal git hooks..." + + local hooks_src="$DOTFILES_DIR/common/git/hooks" + local hooks_dest="$HOME/.config/git/hooks" + + if [[ ! -d "$hooks_src" ]]; then + log_warning "Git hooks source not found: $hooks_src" + return + fi + + if [[ "$DRY_RUN" == "false" ]]; then + mkdir -p "$hooks_dest" + for hook_file in "$hooks_src"/*; do + if [[ -f "$hook_file" && "$(basename "$hook_file")" != "README.md" ]]; then + install_file "$hook_file" "$hooks_dest/$(basename "$hook_file")" + chmod +x "$hooks_dest/$(basename "$hook_file")" + fi + done + # core.hooksPath is set by the installed ~/.gitconfig + log_success "Installed git hooks to $hooks_dest" + else + log_info "Would install hooks from $hooks_src to $hooks_dest" + fi +} + +# Install shared SSH config without clobbering machine-local host entries: +# the shared file lands at ~/.ssh/config.dotfiles and is Include'd from +# ~/.ssh/config, so per-machine hosts keep precedence. +install_ssh_config() { + local src="$DOTFILES_DIR/common/ssh/config" + [[ -f "$src" ]] || return 0 + + log_step "Installing shared SSH config..." + if [[ "$DRY_RUN" == "false" ]]; then + mkdir -p "$HOME/.ssh" + chmod 700 "$HOME/.ssh" + install_file "$src" "$HOME/.ssh/config.dotfiles" + chmod 600 "$HOME/.ssh/config.dotfiles" + if [[ ! -f "$HOME/.ssh/config" ]] || ! grep -q 'config\.dotfiles' "$HOME/.ssh/config"; then + backup_file "$HOME/.ssh/config" + # Prepend: an Include after a Host block would only apply to that + # host, and IgnoreUnknown must be parsed before any UseKeychain. + { + printf '# Shared dotfiles SSH defaults\nInclude ~/.ssh/config.dotfiles\n\n' + [[ -f "$HOME/.ssh/config" ]] && cat "$HOME/.ssh/config" + } > "$HOME/.ssh/config.tmp$$" + mv "$HOME/.ssh/config.tmp$$" "$HOME/.ssh/config" + chmod 600 "$HOME/.ssh/config" + audit_action "prepend" "$src" "$HOME/.ssh/config" "Include directive" + fi + else + log_info "Would copy: common/ssh/config -> ~/.ssh/config.dotfiles (Include'd from ~/.ssh/config)" + fi } # Install shell functions install_shell_functions() { log_step "Installing shell functions..." - + if [[ "$DRY_RUN" == "false" ]]; then mkdir -p "$HOME/.config/shell-functions" - # Copy all shell function files for func_file in "$DOTFILES_DIR/common/shell-functions/"*.sh; do if [[ -f "$func_file" ]]; then - copy_file "$func_file" "$HOME/.config/shell-functions/$(basename "$func_file")" + install_file "$func_file" "$HOME/.config/shell-functions/$(basename "$func_file")" fi done else - log_info "Would install shell functions to ~/.config/shell-functions/" + for func_file in "$DOTFILES_DIR/common/shell-functions/"*.sh; do + if [[ -f "$func_file" ]]; then + log_info "Would copy: $func_file -> ~/.config/shell-functions/$(basename "$func_file")" + fi + done + fi + + # GUI sudo askpass helper at a stable path (sudo.sh points SUDO_ASKPASS here) + if [[ "$MINIMAL_MODE" == "true" ]]; then + log_info "Minimal mode: skipping sudo-askpass helper" + elif [[ "$DRY_RUN" == "false" ]]; then + install_file "$DOTFILES_DIR/scripts/sudo-askpass.sh" "$HOME/.local/bin/sudo-askpass" + chmod +x "$HOME/.local/bin/sudo-askpass" + else + log_info "Would copy: scripts/sudo-askpass.sh -> ~/.local/bin/sudo-askpass" fi } # Install terminal configuration install_terminal_config() { log_step "Installing terminal configuration..." - + # Kitty config based on OS (using hard copies for kitty to work properly) - mkdir -p "$HOME/.config/kitty" + if [[ "$DRY_RUN" == "false" ]]; then + audit_action "mkdir" "" "$HOME/.config/kitty" "ensure kitty config directory" + fi if [[ "$DRY_RUN" == "false" ]]; then if [[ "$OS" == "macos" ]]; then - backup_file "$HOME/.config/kitty/kitty.conf" - cp "$DOTFILES_DIR/darwin/kitty.conf" "$HOME/.config/kitty/kitty.conf" - log_success "Copied darwin/kitty.conf -> ~/.config/kitty/kitty.conf" + install_file "$DOTFILES_DIR/darwin/kitty.conf" "$HOME/.config/kitty/kitty.conf" else - backup_file "$HOME/.config/kitty/kitty.conf" - cp "$DOTFILES_DIR/linux/common/kitty.conf" "$HOME/.config/kitty/kitty.conf" - log_success "Copied linux/common/kitty.conf -> ~/.config/kitty/kitty.conf" + install_file "$DOTFILES_DIR/linux/common/kitty.conf" "$HOME/.config/kitty/kitty.conf" fi - + # Copy themes for theme_file in "$DOTFILES_DIR/common/themes/"*.conf; do if [[ -f "$theme_file" ]]; then - cp "$theme_file" "$HOME/.config/kitty/$(basename "$theme_file")" - log_success "Copied $(basename "$theme_file") -> ~/.config/kitty/" + install_file "$theme_file" "$HOME/.config/kitty/$(basename "$theme_file")" fi done + + # Arch-specific theme overrides (e.g. personal-pink plum background) + if [[ "$DISTRO" == "arch" || "$DISTRO" == "manjaro" ]]; then + for theme_file in "$DOTFILES_DIR/linux/arch/.config/kitty/"*.conf; do + [[ -f "$theme_file" ]] || continue + install_file "$theme_file" "$HOME/.config/kitty/$(basename "$theme_file")" + done + fi else if [[ "$OS" == "macos" ]]; then log_info "Would copy: darwin/kitty.conf -> ~/.config/kitty/kitty.conf" @@ -353,60 +499,197 @@ install_terminal_config() { log_info "Would copy: linux/common/kitty.conf -> ~/.config/kitty/kitty.conf" fi log_info "Would copy kitty themes to ~/.config/kitty/" + if [[ "$DISTRO" == "arch" || "$DISTRO" == "manjaro" ]]; then + log_info "Would apply Arch kitty overrides from linux/arch/.config/kitty/ to ~/.config/kitty/" + fi fi - + # htop config - mkdir -p "$HOME/.config/htop" - create_symlink "$DOTFILES_DIR/common/htop/htoprc" "$HOME/.config/htop/htoprc" + install_file "$DOTFILES_DIR/common/htop/htoprc" "$HOME/.config/htop/htoprc" } -# Install vim configuration +# Install Linux desktop configurations (sway, waybar, gtk, rofi, mako, ...) +# Copies everything under linux/arch/.config/ into ~/.config/ preserving +# relative paths, so new tool configs are picked up without listing them here. +install_desktop_configs() { + if [[ "$DISTRO" != "arch" && "$DISTRO" != "manjaro" ]] || [[ "$MINIMAL_MODE" == "true" ]]; then + return 0 + fi + + log_step "Installing Arch desktop configurations..." + + local desktop_root="$DOTFILES_DIR/linux/arch/.config" + local src rel + while IFS= read -r -d '' src; do + rel="${src#$desktop_root/}" + # kitty files are applied as theme overlays by install_terminal_config + [[ "$rel" == kitty/* ]] && continue + install_file "$src" "$HOME/.config/$rel" + done < <(find "$desktop_root" -type f -print0 | sort -z) +} + +# Compile CoC.nvim after plugin installation (shared by vim + nvim paths) +compile_coc_nvim() { + if [[ ! -d "$HOME/.vim/plugged/coc.nvim" ]]; then + if grep -q "coc.nvim" "$HOME/.vim/plugins.vim" 2>/dev/null; then + log_warning "coc.nvim requested by plugins.vim but not installed; run :PlugInstall manually" + fi + return 0 + fi + + if [[ ! -f "$HOME/.vim/plugged/coc.nvim/package.json" ]]; then + log_warning "coc.nvim present but incomplete (no package.json); rerun :PlugInstall" + return 0 + fi + + log_step "Compiling CoC.nvim..." + if ! command -v npm >/dev/null 2>&1; then + log_warning "npm not found. CoC.nvim needs manual compilation: cd ~/.vim/plugged/coc.nvim && npm install" + return 0 + fi + + # The subshell is the if-condition so a build failure cannot trip set -e + if ( + cd "$HOME/.vim/plugged/coc.nvim" || exit 0 + + if [[ -f package-lock.json || -f npm-shrinkwrap.json ]]; then + npm ci + else + npm install + fi + ); then + log_success "CoC.nvim compiled successfully" + else + log_warning "CoC.nvim compilation failed. Retry manually: cd ~/.vim/plugged/coc.nvim && npm install" + fi +} + +# Install vim + nvim configuration install_vim_config() { log_step "Installing vim configuration..." - - # Create .vim directory and symlink config files + if [[ "$DRY_RUN" == "false" ]]; then mkdir -p "$HOME/.vim/settings" - - # Link vim configuration files - create_symlink "$DOTFILES_DIR/.vim/vimrc" "$HOME/.vim/vimrc" - create_symlink "$DOTFILES_DIR/.vim/plugins.vim" "$HOME/.vim/plugins.vim" - create_symlink "$DOTFILES_DIR/.vim/mappings.vim" "$HOME/.vim/mappings.vim" - create_symlink "$DOTFILES_DIR/.vim/settings.vim" "$HOME/.vim/settings.vim" - create_symlink "$DOTFILES_DIR/.vim/coc-settings.json" "$HOME/.vim/coc-settings.json" - - # Link settings directory files - for settings_file in "$DOTFILES_DIR/.vim/settings/"*.vim; do - if [[ -f "$settings_file" ]]; then - create_symlink "$settings_file" "$HOME/.vim/settings/$(basename "$settings_file")" - fi - done - else - log_info "Would install vim configuration" - return fi - - # Install vim plugins if vim is available - if command -v vim >/dev/null 2>&1; then + + # install_file handles dry-run logging itself + install_file "$DOTFILES_DIR/.vim/vimrc" "$HOME/.vim/vimrc" + install_file "$DOTFILES_DIR/.vim/plugins.vim" "$HOME/.vim/plugins.vim" + install_file "$DOTFILES_DIR/.vim/mappings.vim" "$HOME/.vim/mappings.vim" + install_file "$DOTFILES_DIR/.vim/settings.vim" "$HOME/.vim/settings.vim" + install_file "$DOTFILES_DIR/.vim/coc-settings.json" "$HOME/.vim/coc-settings.json" + + for settings_file in "$DOTFILES_DIR/.vim/settings/"*.vim; do + if [[ -f "$settings_file" ]]; then + install_file "$settings_file" "$HOME/.vim/settings/$(basename "$settings_file")" + fi + done + + if [[ "$MINIMAL_MODE" == "true" ]]; then + log_info "Minimal mode: skipping vim plugin installation" + return 0 + fi + + # Install vim plugins. When nvim is present the neovim step handles this + # (same ~/.vim/plugged); headless plain vim needs a pty to run vim-plug. + if command -v nvim >/dev/null 2>&1; then + log_info "nvim present; plugins are installed by the neovim step" + elif command -v vim >/dev/null 2>&1; then log_step "Installing vim plugins..." if [[ "$DRY_RUN" == "false" ]]; then - vim +PlugInstall +qall - - # Compile CoC.nvim if it was installed - if [[ -d "$HOME/.vim/plugged/coc.nvim" ]]; then - log_step "Compiling CoC.nvim..." - if command -v npm >/dev/null 2>&1; then - (cd "$HOME/.vim/plugged/coc.nvim" && npm ci) - log_success "CoC.nvim compiled successfully" - else - log_warning "npm not found. CoC.nvim needs manual compilation: cd ~/.vim/plugged/coc.nvim && npm ci" - fi + seed_vim_plug + # vim-plug needs a real terminal: ex mode (-e/-es) aborts with E31 + # and installs nothing, so allocate a pty via script(1). + if command -v script >/dev/null 2>&1; then + run_vim_in_pty vim -N -u "$HOME/.vim/vimrc" -c 'PlugInstall --sync' -c 'qa!' \ + || log_warning "vim plugin install failed; run :PlugInstall manually" + else + vim -e -N -u "$HOME/.vim/vimrc" --not-a-term -c 'PlugInstall --sync' -c 'qa!' /dev/null 2>&1; then + local cmd + printf -v cmd '%q ' "$@" + script -qec "$cmd" /dev/null /dev/null 2>&1 + else + script -q /dev/null "$@" /dev/null 2>&1 + fi +} + +# Compare installed plugin dirs against what plugins.vim declares. +report_plug_count() { + local expected installed + expected="$(grep -c "^Plug '" "$HOME/.vim/plugins.vim" 2>/dev/null || echo 0)" + installed="$(ls -1 "$HOME/.vim/plugged" 2>/dev/null | wc -l | tr -d ' ')" + if [[ "$installed" -ge "$expected" && "$expected" -gt 0 ]]; then + log_success "vim plugins installed ($installed/$expected)" else - log_warning "vim not found. Skipping plugin installation." + log_warning "only $installed of $expected vim plugins installed; run :PlugInstall manually" + fi +} + +# Install neovim configuration +install_neovim_config() { + log_step "Installing neovim configuration..." + + if [[ "$DRY_RUN" == "false" ]]; then + mkdir -p "$HOME/.config/nvim" + + backup_file "$HOME/.config/nvim/init.vim" + backup_file "$HOME/.config/nvim/coc-settings.json" + + install_file "$DOTFILES_DIR/common/nvim/init.vim" "$HOME/.config/nvim/init.vim" + install_file "$DOTFILES_DIR/.vim/coc-settings.json" "$HOME/.config/nvim/coc-settings.json" + else + log_info "Would copy: common/nvim/init.vim -> ~/.config/nvim/init.vim" + log_info "Would copy: .vim/coc-settings.json -> ~/.config/nvim/coc-settings.json" + if [[ "$MINIMAL_MODE" == "false" ]]; then + log_info "Would install neovim plugins and compile CoC.nvim" + fi + return + fi + + if [[ "$MINIMAL_MODE" == "true" ]]; then + log_info "Minimal mode: skipping neovim plugin installation" + return 0 + fi + + if command -v nvim >/dev/null 2>&1; then + log_step "Installing neovim plugins..." + seed_vim_plug + nvim --headless +PlugInstall +qall /dev/null 2>&1; then + if ! command -v fzf >/dev/null 2>&1 && [[ ! -d "$HOME/.fzf" ]]; then log_info "Installing fzf..." if [[ "$DRY_RUN" == "false" ]]; then - git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf - ~/.fzf/install --bin --no-update-rc --no-key-bindings --no-completion + if git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf; then + ~/.fzf/install --bin --no-update-rc --no-key-bindings --no-completion || log_warning "fzf install script failed" + else + log_warning "fzf clone failed; skipping" + fi else log_info "Would install fzf" fi fi } +# Install AI context files (CLAUDE.md, MACHINE.md, AGENTS.md) +install_ai_context() { + if [[ "$MINIMAL_MODE" == "true" ]]; then + log_info "Minimal mode: skipping AI context files" + return 0 + fi + + log_step "Installing AI context files..." + + # ~/.claude/CLAUDE.md is often user-curated (e.g. custom includes); + # only seed it when absent instead of clobbering it on every install. + local claude_src="$DOTFILES_DIR/common/ai-context/CLAUDE.md" + if [[ -f "$claude_src" ]]; then + if [[ -f "$HOME/.claude/CLAUDE.md" ]] && ! cmp -s "$claude_src" "$HOME/.claude/CLAUDE.md"; then + log_info "Keeping existing ~/.claude/CLAUDE.md (differs from repo version; merge manually if wanted)" + else + install_file "$claude_src" "$HOME/.claude/CLAUDE.md" + fi + fi + + # AGENTS.md -> ~/AGENTS.md (for Codex/Copilot compatibility) + local agents_src="$DOTFILES_DIR/common/ai-context/AGENTS.md" + if [[ -f "$agents_src" ]]; then + install_file "$agents_src" "$HOME/AGENTS.md" + fi + + # OS-specific machine.md -> ~/MACHINE.md + local machine_src="" + case "$DISTRO" in + arch|manjaro) + machine_src="$DOTFILES_DIR/linux/arch/ai-context/machine.md" + ;; + ubuntu|debian) + machine_src="$DOTFILES_DIR/linux/debian/ai-context/machine.md" + ;; + rhel|centos|fedora) + machine_src="$DOTFILES_DIR/linux/fedora/ai-context/machine.md" + ;; + alpine) + machine_src="$DOTFILES_DIR/linux/alpine/ai-context/machine.md" + ;; + darwin|macos) + machine_src="$DOTFILES_DIR/darwin/ai-context/machine.md" + ;; + esac + + if [[ -n "$machine_src" && -f "$machine_src" ]]; then + install_file "$machine_src" "$HOME/MACHINE.md" + fi + + # Machine state snapshots are generated on demand, not at install time: + # DOTFILES_DIR=$DOTFILES_DIR scripts/refresh-machine-state.sh +} + # Main installation function main() { echo -e "${CYAN}" @@ -439,14 +779,14 @@ main() { echo "║ Universal Unix/Linux/macOS ║" echo "╚══════════════════════════════════════════════════════════════╝" echo -e "${NC}" - + detect_os detect_environment - + if [[ "$DRY_RUN" == "true" ]]; then log_warning "DRY RUN MODE - No changes will be made" fi - + # Install packages if requested if [[ "$INSTALL_PACKAGES" == "true" ]] && [[ "$MINIMAL_MODE" == "false" ]]; then case "$OS" in @@ -463,35 +803,42 @@ main() { else log_info "Skipping package installation" fi - + # Install configurations in dependency order install_shell_configs # 1. Shell configs (.bashrc, .zshrc) - foundation install_git_config # 2. Git configuration (.gitconfig) + install_git_hooks # 2b. Personal global Git hooks + install_ssh_config # 2c. Shared SSH defaults (via Include) install_shell_functions # 3. Shell functions (depends on shell configs) install_terminal_config # 4. Terminal configs (kitty, htop) - install_vim_config # 5. Vim setup (plugins, settings, CoC compilation) - install_optional_tools # 6. Optional tools (fzf, etc.) - last + install_desktop_configs # 5. Linux desktop configs (sway/waybar/gtk) - arch only + install_vim_config # 6. Vim setup (plugins, settings, CoC compilation) + install_neovim_config # 7. Neovim bridge to Vim config + install_optional_tools # 8. Optional tools (fzf, etc.) - last + install_ai_context # 9. AI context files (CLAUDE.md, AGENTS.md, MACHINE.md) echo -e "${GREEN}" echo "╔══════════════════════════════════════════════════════════════╗" echo "║ Installation Complete! ║" echo "╚══════════════════════════════════════════════════════════════╝" echo -e "${NC}" - + if [[ -d "$BACKUP_DIR" ]]; then log_info "Backups saved to: $BACKUP_DIR" + if [[ -n "$AUDIT_LOG" ]]; then + log_info "Audit log: $AUDIT_LOG" + fi fi - + log_info "Please run: source ~/.bashrc (or source ~/.zshrc)" - + if [[ "$MINIMAL_MODE" == "false" ]]; then echo log_info "Try these new commands:" echo " git ch # Fuzzy branch checkout" echo " git fadd # Interactive file staging" echo " git flog # Browse commits" - echo " k get p # kubectl get pods" - echo " sshdot user@host # SSH with dotfiles" + echo " kctx # Switch kubectl context with fzf" fi } diff --git a/linux/README.md b/linux/README.md index f0be892..daca448 100644 --- a/linux/README.md +++ b/linux/README.md @@ -15,4 +15,4 @@ Each distro directory may contain: - Package lists (apt, pacman, dnf) - System service configs - X11/Wayland configs -- Distribution-specific shell configurations \ No newline at end of file +- Distribution-specific shell configurations diff --git a/linux/alpine/ai-context/machine.md b/linux/alpine/ai-context/machine.md new file mode 100644 index 0000000..851ab49 --- /dev/null +++ b/linux/alpine/ai-context/machine.md @@ -0,0 +1,41 @@ +# Machine: Alpine Linux + +## System + +- **OS**: Alpine Linux +- **Package manager**: apk +- **Shell**: zsh +- **Terminal**: Kitty + +## Primary Use + +- Lightweight container and development environment +- General development + +## Package Installation + +```bash +# System packages +sudo apk add + +# Search for packages +apk search + +# Remove packages +sudo apk del + +# Update package index +sudo apk update +``` + +## Paths + +- Dotfiles: `~/workspace/dotfiles` +- Projects: `~/workspace/` + +## Notes + +- Uses musl libc instead of glibc (some binaries may need static builds or compatibility layers) +- Uses OpenRC for service management (not systemd) +- Minimal base system; BusyBox provides core utilities by default +- Modern CLI tools: ripgrep, fd, bat diff --git a/linux/alpine/packages.list b/linux/alpine/packages.list index f73f670..02fb20d 100644 --- a/linux/alpine/packages.list +++ b/linux/alpine/packages.list @@ -15,5 +15,6 @@ py3-virtualenv tmux tree vim +neovim wget zsh \ No newline at end of file diff --git a/linux/arch/.config/gtk-3.0/gtk.css b/linux/arch/.config/gtk-3.0/gtk.css new file mode 100644 index 0000000..4db69a5 --- /dev/null +++ b/linux/arch/.config/gtk-3.0/gtk.css @@ -0,0 +1,279 @@ +/* + * Local GTK polish for Sway/kitty/mako. + * Nordic-darker remains the base theme; these rules bend GTK dialogs toward + * the desktop palette used by Sway, Waybar, mako, and kitty. + */ + +@define-color jm_bg #221820; +@define-color jm_bg_deep #18121a; +@define-color jm_bg_soft #2a1e2e; +@define-color jm_surface #332635; +@define-color jm_surface_raised #4a3844; +@define-color jm_accent #9d5a7f; +@define-color jm_accent_soft #6b4456; +@define-color jm_text #d0d0d0; +@define-color jm_text_bright #cdd6f4; +@define-color jm_muted #8a8a8a; +@define-color jm_urgent #d68787; + +window, +dialog, +messagedialog, +filechooser, +filechooserdialog { + background-color: @jm_bg_soft; + color: @jm_text; +} + +decoration { + border: 2px solid @jm_accent; + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55); +} + +headerbar, +headerbar.titlebar, +.titlebar { + background-image: none; + background-color: @jm_bg; + color: @jm_text_bright; + border-bottom: 1px solid @jm_accent_soft; + box-shadow: none; +} + +headerbar label, +.titlebar label { + color: @jm_text_bright; +} + +toolbar, +actionbar, +revealer > box, +filechooser .view, +filechooser placessidebar, +filechooser placessidebar list, +filechooser stack, +filechooser paned, +filechooserdialog .background, +dialog .background { + background-color: @jm_bg_soft; + color: @jm_text; +} + +filechooser paned > separator, +paned > separator, +separator { + background-color: @jm_accent_soft; + color: @jm_accent_soft; + min-width: 1px; + min-height: 1px; +} + +placessidebar { + background-color: @jm_bg; + border-right: 1px solid @jm_accent_soft; +} + +placessidebar row, +list row, +treeview.view, +treeview.view row, +.view { + background-color: @jm_bg; + color: @jm_text; +} + +placessidebar row:hover, +list row:hover, +treeview.view row:hover, +.view:hover { + background-color: @jm_surface; + color: @jm_text_bright; +} + +placessidebar row:selected, +list row:selected, +treeview.view:selected, +treeview.view row:selected, +.view:selected, +.view:selected:focus { + background-color: @jm_accent_soft; + color: @jm_text_bright; +} + +treeview.view header button { + background-image: none; + background-color: @jm_bg_soft; + color: @jm_text; + border-color: @jm_accent_soft; +} + +entry, +spinbutton, +combobox box button.combo, +filechooser entry, +searchbar entry { + background-image: none; + background-color: @jm_bg; + color: @jm_text_bright; + border: 1px solid @jm_accent_soft; + border-radius: 6px; + box-shadow: none; +} + +entry:focus, +spinbutton:focus, +combobox box button.combo:focus { + border-color: @jm_accent; + box-shadow: 0 0 0 1px alpha(@jm_accent, 0.65); +} + +dialog button, +dialog button.flat, +dialog button.image-button, +dialog button.text-button, +messagedialog button, +filechooser button, +filechooser button.flat, +filechooser button.image-button, +filechooser button.text-button, +filechooserdialog button, +filechooserdialog button.flat, +filechooserdialog button.image-button, +filechooserdialog button.text-button, +popover button, +headerbar button, +.titlebar button { + background-image: none; + background-color: @jm_surface; + color: @jm_text; + border: 1px solid @jm_accent_soft; + border-radius: 6px; + box-shadow: none; + text-shadow: none; +} + +dialog button:hover, +dialog button.flat:hover, +dialog button.image-button:hover, +dialog button.text-button:hover, +messagedialog button:hover, +filechooser button:hover, +filechooser button.flat:hover, +filechooser button.image-button:hover, +filechooser button.text-button:hover, +filechooserdialog button:hover, +filechooserdialog button.flat:hover, +filechooserdialog button.image-button:hover, +filechooserdialog button.text-button:hover, +popover button:hover, +headerbar button:hover, +.titlebar button:hover { + background-color: @jm_surface_raised; + color: @jm_text_bright; + border-color: @jm_accent; +} + +dialog button:active, +dialog button:checked, +dialog button.suggested-action, +dialog button.suggested-action:hover, +messagedialog button:active, +messagedialog button:checked, +messagedialog button.suggested-action, +messagedialog button.suggested-action:hover, +filechooser button:active, +filechooser button:checked, +filechooser button.suggested-action, +filechooser button.suggested-action:hover, +filechooserdialog button:active, +filechooserdialog button:checked, +filechooserdialog button.suggested-action, +filechooserdialog button.suggested-action:hover { + background-color: @jm_accent; + color: @jm_text_bright; + border-color: @jm_accent; +} + +dialog button.destructive-action, +dialog button.destructive-action:hover, +messagedialog button.destructive-action, +messagedialog button.destructive-action:hover, +filechooser button.destructive-action, +filechooser button.destructive-action:hover, +filechooserdialog button.destructive-action, +filechooserdialog button.destructive-action:hover { + background-color: @jm_urgent; + color: @jm_bg_deep; + border-color: @jm_urgent; +} + +pathbar button, +filechooser #pathbarbox button { + background-color: @jm_bg; + color: @jm_text; + border-color: transparent; +} + +pathbar button:hover, +filechooser #pathbarbox button:hover { + background-color: @jm_surface; + color: @jm_text_bright; + border-color: @jm_accent_soft; +} + +scrollbar trough { + background-color: @jm_bg; +} + +scrollbar slider { + background-color: @jm_accent_soft; + border-radius: 6px; + min-width: 6px; + min-height: 6px; +} + +scrollbar slider:hover { + background-color: @jm_accent; +} + +popover, +menu, +menuitem, +.context-menu { + background-color: @jm_bg; + color: @jm_text; + border-color: @jm_accent_soft; +} + +menuitem:hover, +menuitem:selected { + background-color: @jm_surface_raised; + color: @jm_text_bright; +} + +tooltip, +.tooltip { + background-color: @jm_bg; + color: @jm_text; + border: 2px solid @jm_accent; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); +} + +tooltip *, +.tooltip * { + background-color: transparent; + color: @jm_text; +} + +selection, +dialog *:selected, +filechooser *:selected, +filechooserdialog *:selected { + background-color: @jm_accent; + color: @jm_text_bright; +} + +NautilusWindow { + background-color: transparent; +} diff --git a/linux/arch/.config/gtk-3.0/settings.ini b/linux/arch/.config/gtk-3.0/settings.ini new file mode 100644 index 0000000..a303bbb --- /dev/null +++ b/linux/arch/.config/gtk-3.0/settings.ini @@ -0,0 +1,5 @@ +[Settings] +gtk-theme-name=Nordic-darker +gtk-icon-theme-name=Adwaita +gtk-font-name=FiraCode Nerd Font 10 +gtk-application-prefer-dark-theme=true diff --git a/linux/arch/.config/gtk-4.0/gtk.css b/linux/arch/.config/gtk-4.0/gtk.css new file mode 100644 index 0000000..88514a7 --- /dev/null +++ b/linux/arch/.config/gtk-4.0/gtk.css @@ -0,0 +1,126 @@ +/* + * GTK4 companion to the GTK3 Sway/kitty/mako polish. + * The Firefox portal file chooser is GTK3 today, but these variables keep + * newer GTK apps visually aligned. + */ + +@define-color jm_bg #221820; +@define-color jm_bg_deep #18121a; +@define-color jm_bg_soft #2a1e2e; +@define-color jm_surface #332635; +@define-color jm_surface_raised #4a3844; +@define-color jm_accent #9d5a7f; +@define-color jm_accent_soft #6b4456; +@define-color jm_text #d0d0d0; +@define-color jm_text_bright #cdd6f4; +@define-color jm_muted #8a8a8a; +@define-color jm_urgent #d68787; + +window, +dialog, +filechooser, +dialog.background, +filechooser.background { + background: @jm_bg_soft; + color: @jm_text; +} + +headerbar, +.titlebar { + background: @jm_bg; + color: @jm_text_bright; + border-bottom: 1px solid @jm_accent_soft; + box-shadow: none; +} + +entry, +searchbar entry, +spinbutton, +dropdown button { + background: @jm_bg_deep; + color: @jm_text_bright; + border: 1px solid @jm_accent_soft; + border-radius: 6px; + box-shadow: none; +} + +entry:focus, +spinbutton:focus { + border-color: @jm_accent; + box-shadow: 0 0 0 1px alpha(@jm_accent, 0.65); +} + +dialog button, +filechooser button, +popover button, +headerbar button, +.titlebar button { + background: @jm_surface; + color: @jm_text; + border: 1px solid @jm_accent_soft; + border-radius: 6px; + box-shadow: none; + text-shadow: none; +} + +dialog button:hover, +filechooser button:hover, +popover button:hover, +headerbar button:hover, +.titlebar button:hover { + background: @jm_surface_raised; + color: @jm_text_bright; + border-color: @jm_accent; +} + +dialog button:checked, +dialog button:active, +dialog button.suggested-action, +filechooser button:checked, +filechooser button:active, +filechooser button.suggested-action { + background: @jm_accent; + color: @jm_text_bright; + border-color: @jm_accent; +} + +list, +listview, +columnview, +treeexpander, +row, +placessidebar { + background: @jm_bg; + color: @jm_text; +} + +row:hover { + background: @jm_surface; + color: @jm_text_bright; +} + +row:selected { + background: @jm_accent_soft; + color: @jm_text_bright; +} + +scrollbar trough { + background: @jm_bg; +} + +scrollbar slider { + background: @jm_accent_soft; + border-radius: 6px; +} + +scrollbar slider:hover { + background: @jm_accent; +} + +popover, +popover contents, +tooltip { + background: @jm_bg; + color: @jm_text; + border-color: @jm_accent_soft; +} diff --git a/linux/arch/.config/gtk-4.0/settings.ini b/linux/arch/.config/gtk-4.0/settings.ini new file mode 100644 index 0000000..a303bbb --- /dev/null +++ b/linux/arch/.config/gtk-4.0/settings.ini @@ -0,0 +1,5 @@ +[Settings] +gtk-theme-name=Nordic-darker +gtk-icon-theme-name=Adwaita +gtk-font-name=FiraCode Nerd Font 10 +gtk-application-prefer-dark-theme=true diff --git a/config/current-theme.conf b/linux/arch/.config/kitty/current-theme.conf similarity index 78% rename from config/current-theme.conf rename to linux/arch/.config/kitty/current-theme.conf index 2533db7..e3f47e8 100644 --- a/config/current-theme.conf +++ b/linux/arch/.config/kitty/current-theme.conf @@ -1,16 +1,21 @@ # vim:ft=kitty -## name: Catppuccin-Mocha +## name: Catppuccin-Mocha (personal-pink) ## author: Pocco81 (https://github.com/Pocco81) ## license: MIT ## upstream: https://github.com/catppuccin/kitty/blob/main/mocha.conf ## blurb: Soothing pastel theme for the high-spirited! +## +## Arch (jm-home-box) override: matches machine.toml style = "personal-pink". +## Only the background is customized to a dark plum that coordinates with the +## Sway purple/pink accent (#9d5a7f). Stock Catppuccin-Mocha base is #1E1E2E. +## Applied over common/themes/current-theme.conf by install.sh on Arch. # The basic colors foreground #CDD6F4 -background #1E1E2E +background #2A1E2E selection_foreground #1E1E2E selection_background #F5E0DC diff --git a/linux/arch/.config/mako/config b/linux/arch/.config/mako/config new file mode 100644 index 0000000..35947e2 --- /dev/null +++ b/linux/arch/.config/mako/config @@ -0,0 +1,33 @@ +# Mako notification daemon config - Purple theme + +# General appearance +font=FiraCode Nerd Font 10 +background-color=#221820 +text-color=#d0d0d0 +border-size=2 +border-radius=16 +padding=15 +margin=10 + +# Position and behavior +sort=-time +layer=overlay +default-timeout=5000 +ignore-timeout=1 +width=400 +height=150 + +# Icons +icon-path=/usr/share/icons/Adwaita +max-icon-size=48 + +# Urgency levels +[urgency=low] +border-color=#626262 + +[urgency=normal] +border-color=#9d5a7f + +[urgency=high] +border-color=#d68787 +default-timeout=0 diff --git a/linux/arch/.config/rofi/config.rasi b/linux/arch/.config/rofi/config.rasi new file mode 100644 index 0000000..c635d43 --- /dev/null +++ b/linux/arch/.config/rofi/config.rasi @@ -0,0 +1,3 @@ +configuration { +} +@theme "~/.config/rofi/theme.rasi" diff --git a/linux/arch/.config/rofi/theme.rasi b/linux/arch/.config/rofi/theme.rasi new file mode 100644 index 0000000..90f8369 --- /dev/null +++ b/linux/arch/.config/rofi/theme.rasi @@ -0,0 +1,96 @@ +/** + * Rofi Theme - Matching your purple/dark Waybar theme + */ + +* { + bg-main: #221820; + bg-dark: #6b4456; + bg-selected: #9d5a7f; + fg-main: #d0d0d0; + fg-dim: #626262; + border-color: #9d5a7f; + + background-color: transparent; + text-color: @fg-main; + font: "Noto Sans 11"; +} + +window { + background-color: @bg-main; + border: 2px solid; + border-color: @border-color; + border-radius: 16px; + padding: 15px; + width: 600px; +} + +mainbox { + background-color: transparent; + children: [inputbar, listview]; + spacing: 10px; +} + +inputbar { + background-color: transparent; + border: 0px 0px 1px 0px solid; + border-color: @border-color; + padding: 12px 15px; + children: [prompt, entry]; + spacing: 10px; +} + +prompt { + text-color: @border-color; + font: "Noto Sans Bold 11"; +} + +entry { + text-color: @fg-main; + placeholder: ""; + placeholder-color: @fg-dim; +} + +listview { + background-color: transparent; + lines: 8; + spacing: 4px; + scrollbar: false; + cycle: true; +} + +element { + background-color: transparent; + text-color: @fg-main; + border-radius: 8px; + padding: 8px 12px; +} + +element-icon { + size: 24px; + margin: 0px 10px 0px 0px; +} + +element-text { + background-color: transparent; + text-color: inherit; +} + +element selected { + background-color: @bg-selected; + text-color: @fg-main; +} + +element normal.normal { + background-color: transparent; + text-color: @fg-main; +} + +element alternate.normal { + background-color: transparent; + text-color: @fg-main; +} + +element selected.normal { + background-color: @bg-selected; + text-color: @fg-main; +} diff --git a/linux/arch/.config/sway/assets/Sway_Wallpaper_Blue_1920x1080.png b/linux/arch/.config/sway/assets/Sway_Wallpaper_Blue_1920x1080.png new file mode 100644 index 0000000..034f004 Binary files /dev/null and b/linux/arch/.config/sway/assets/Sway_Wallpaper_Blue_1920x1080.png differ diff --git a/linux/arch/.config/sway/assets/beautiful-morning-4k-3840x2160.jpg b/linux/arch/.config/sway/assets/beautiful-morning-4k-3840x2160.jpg new file mode 100644 index 0000000..60ad0ea Binary files /dev/null and b/linux/arch/.config/sway/assets/beautiful-morning-4k-3840x2160.jpg differ diff --git a/linux/arch/.config/sway/assets/fishing-boat-sunrise-hd-4k.png b/linux/arch/.config/sway/assets/fishing-boat-sunrise-hd-4k.png new file mode 100644 index 0000000..f72fbed Binary files /dev/null and b/linux/arch/.config/sway/assets/fishing-boat-sunrise-hd-4k.png differ diff --git a/linux/arch/.config/sway/assets/focused.png b/linux/arch/.config/sway/assets/focused.png new file mode 100644 index 0000000..4487206 Binary files /dev/null and b/linux/arch/.config/sway/assets/focused.png differ diff --git a/linux/arch/.config/sway/assets/focused_inactive.png b/linux/arch/.config/sway/assets/focused_inactive.png new file mode 100644 index 0000000..0c7ddd2 Binary files /dev/null and b/linux/arch/.config/sway/assets/focused_inactive.png differ diff --git a/linux/arch/.config/sway/assets/unfocused.png b/linux/arch/.config/sway/assets/unfocused.png new file mode 100644 index 0000000..0c7ddd2 Binary files /dev/null and b/linux/arch/.config/sway/assets/unfocused.png differ diff --git a/linux/arch/.config/sway/assets/urgent.png b/linux/arch/.config/sway/assets/urgent.png new file mode 100644 index 0000000..87f6fca Binary files /dev/null and b/linux/arch/.config/sway/assets/urgent.png differ diff --git a/linux/arch/.config/sway/config b/linux/arch/.config/sway/config new file mode 100644 index 0000000..8605a46 --- /dev/null +++ b/linux/arch/.config/sway/config @@ -0,0 +1,314 @@ +set $mod Mod4 + +input * { + xkb_layout us,ca + xkb_options altwin:super_win +} + +# Home row direction keys, like vim +set $left h +set $down j +set $up k +set $right l +# Your preferred terminal emulator +set $term kitty +# Your preferred application launcher +# Note: pass the final command to swaymsg so that the resulting window can be opened +# on the original workspace that the command was run on. +#set $menu wofi --hide-scroll --show run | xargs swaymsg exec -- +#set $menu wofi -c ~/.config/wofi/config -s ~/.config/wofi/style.css -I +set $menu rofi -show drun +set $ssh-menu rofi -show ssh +### Output configuration +# +# Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/) +#output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill +set $wallpaper ~/.config/sway/assets/beautiful-morning-4k-3840x2160.jpg +output * mode 3440x1440@165Hz bg $wallpaper fill +# +# Example configuration: +# +# output * resolution 1920x1080 position 0,0 +# +# You can get the names of your outputs by running: swaymsg -t get_outputs + +### Idle configuration +# +# Example configuration: +# +# exec swayidle -w \ + # timeout 300 'swaylock --clock --datestr "%d.%m.%Y" --indicator -ef -i "assets/beautiful-morning-4k-3840x2160.jpg"' \ + # timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \ + +### Input configuration +# +# Example configuration: +# +# input "2:14:SynPS/2_Synaptics_TouchPad" { +# dwt enabled +# tap enabled +# natural_scroll enabled +# middle_emulation enabled +# } +# +# You can get the names of your inputs by running: swaymsg -t get_inputs +# Read `man 5 sway-input` for more information about this section. + +### Key bindings +# +# Basics: +# + # Start a terminal + bindsym --to-code $mod+Return workspace number 1, exec $term + bindsym --to-code $mod+KP_Enter workspace number 1, exec $term + + # Kill focused window + bindsym $mod+q kill + + # Screenshot + bindsym $mod+Ctrl+Shift+3 exec sh -c 'grim -g "$(slurp)" - | wl-copy' + + # Start your launcher + bindsym $mod+space exec $menu + bindsym $mod+Ctrl+d exec $menu + + # Window switcher (like macOS Cmd+Tab) + bindsym $mod+Tab exec rofi -show window + + # Clipboard history + bindsym $mod+Ctrl+p exec cliphist list | rofi -dmenu | cliphist decode | wl-copy + + # macOS-style app editing shortcuts + bindsym --no-repeat $mod+c exec ~/.config/sway/scripts/macos-edit copy + bindsym --no-repeat $mod+v exec ~/.config/sway/scripts/macos-edit paste + + # SSH windows + bindsym $mod+Shift+q exec $ssh-menu + + # Volume controls + bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5% + bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5% + bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle + bindsym XF86AudioMicMute exec pactl set-source-mute @DEFAULT_SOURCE@ toggle + + # Media controls + bindsym XF86AudioPlay exec playerctl play-pause + bindsym XF86AudioNext exec playerctl next + bindsym XF86AudioPrev exec playerctl previous + + # Drag floating windows by holding down $mod and left mouse button. + # Resize them with right mouse button + $mod. + # Despite the name, also works for non-floating windows. + # Change normal to inverse to use left mouse button for resizing and right + # mouse button for dragging. + floating_modifier $mod normal + + # Prevent accidental wheel-click paste while scrolling. + bindsym --whole-window button2 nop + bindsym --whole-window --release button2 nop + + # Reload the configuration file + bindsym $mod+Shift+c reload + + + # Exit sway (logs you out of your Wayland session) + bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit' +# +# Moving around: +# + # Move your focus around + bindsym $mod+$left focus left + bindsym $mod+$down focus down + bindsym $mod+$up focus up + bindsym $mod+$right focus right + # Or use $mod+[up|down|left|right] + bindsym $mod+Left focus left + bindsym $mod+Down focus down + bindsym $mod+Up focus up + bindsym $mod+Right focus right + + # Move the focused window with the same, but add Shift + bindsym $mod+Shift+$left move left + bindsym $mod+Shift+$down move down + bindsym $mod+Shift+$up move up + bindsym $mod+Shift+$right move right + # Ditto, with arrow keys + bindsym $mod+Shift+Left move left + bindsym $mod+Shift+Down move down + bindsym $mod+Shift+Up move up + bindsym $mod+Shift+Right move right +# +# Workspaces: +# +set $ws1 "1" +set $ws2 "2" +set $ws3 "3" +set $ws4 "4" +set $ws5 "5" + + # Switch to workspace + bindsym --to-code $mod+1 workspace number $ws1 + bindsym --to-code $mod+2 workspace number $ws2 + bindsym --to-code $mod+3 workspace number $ws3 + bindsym --to-code $mod+4 workspace number $ws4 + bindsym --to-code $mod+5 workspace number $ws5 + # Move focused container to workspace + bindsym --to-code $mod+Shift+1 move container to workspace number $ws1 + bindsym --to-code $mod+Shift+2 move container to workspace number $ws2 + bindsym --to-code $mod+Shift+3 move container to workspace number $ws3 + bindsym --to-code $mod+Shift+4 move container to workspace number $ws4 + bindsym --to-code $mod+Shift+5 move container to workspace number $ws5 + # Note: workspaces can have any name you want, not just numbers. + # We just use 1-10 as the default. +# +# Layout stuff: +# + # You can "split" the current object of your focus with + # $mod+b or $mod+Shift+v, for horizontal and vertical splits + # respectively. + bindsym $mod+Shift+b splith + bindsym $mod+Shift+v splitv + + # Switch the current container between different layout styles + bindsym $mod+Ctrl+s layout stacking + bindsym $mod+Ctrl+w layout tabbed + # bindsym $mod+e layout toggle split # Disabled - using for file manager + + # Make the current focus fullscreen + bindsym $mod+Ctrl+f fullscreen + + # File managers + bindsym $mod+e exec thunar + bindsym $mod+Shift+r exec kitty ranger + + # Toggle the current focus between tiling and floating mode + bindsym $mod+Shift+space floating toggle + + # Swap focus between the tiling area and the floating area + bindsym $mod+Ctrl+space focus mode_toggle + + # Move focus to the parent container + bindsym $mod+Ctrl+a focus parent +# +# Scratchpad: +# + # Sway has a "scratchpad", which is a bag of holding for windows. + # You can send windows there and get them back later. + + # Move the currently focused window to the scratchpad + bindsym $mod+Ctrl+Shift+minus move scratchpad + + # Show the next scratchpad window or hide the focused scratchpad window. + # If there are multiple scratchpad windows, this command cycles through them. + bindsym $mod+Ctrl+minus scratchpad show +# +# Resizing containers: +# +mode "resize" { + # left will shrink the containers width + # right will grow the containers width + # up will shrink the containers height + # down will grow the containers height + bindsym $left resize shrink width 10px + bindsym $down resize grow height 10px + bindsym $up resize shrink height 10px + bindsym $right resize grow width 10px + + # Ditto, with arrow keys + bindsym Left resize shrink width 10px + bindsym Down resize grow height 10px + bindsym Up resize shrink height 10px + bindsym Right resize grow width 10px + + # Return to default mode + bindsym Return mode "default" + bindsym Escape mode "default" +} +bindsym $mod+Ctrl+r mode "resize" + +# Assignment of apps +bindsym $mod+Shift+f exec firefox +bindsym $mod+Shift+s exec steam + +# Workspace assignments +assign [app_id="firefox"] $ws2 +assign [class="^Firefox$"] $ws2 +assign [class="^Slack$"] $ws3 +assign [class="^Steam$"] $ws4 + +# pavucontrol floating +for_window [app_id="pavucontrol" title=".*"] floating enabled, resize set width 1000px height 400px, move position 750 px 750 px + +# GTK portal file pickers, e.g. Firefox open/save dialogs +for_window [app_id="xdg-desktop-portal-gtk"] floating enabled, resize set width 1400px height 900px, move position center, opacity 0.96 + +# Unity Assign +for_window [class="^Unity$" title="^Starting Unity...$"] floating enabled +for_window [class="^Unity$" title="^Hold On$"] floating enabled +for_window [class="^Unity$" title="^Preparing Package$"] floating enabled +for_window [class="^Unity$" title="^Importing Package$"] floating enabled + +# opacity terminals +# for_window [app_id="Alacritty"] opacity 75% + +# https://github.com/ValveSoftware/steam-for-linux/issues/1040 +for_window [class="^Steam$" title=".*"] floating enabled +for_window [class="^Steam$" title="^Friends$"] floating enabled +for_window [class="^Steam$" title="Steam - News"] floating enabled +for_window [class="^Steam$" title=".* - Chat"] floating enabled +for_window [class="^Steam$" title="^Settings$"] floating enabled +for_window [class="^Steam$" title=".* - event started"] floating enabled +for_window [class="^Steam$" title=".* CD key"] floating enabled +for_window [class="^Steam$" title="^Steam - Self Updater$"] floating enabled +for_window [class="^Steam$" title="^Screenshot Uploader$"] floating enabled +for_window [class="^Steam$" title="^Steam Guard - Computer Authorization Required$"] floating enabled +for_window [class="^Steam$" title="^Friends$"] floating enabled +for_window [title="^Steam Keyboard$"] floating enabled + +# font +font pango:Noto Mono Regular 9 + +gaps inner 28 +gaps outer -8 + +# Window borders +default_border pixel 4 +default_floating_border pixel 4 +hide_edge_borders none + +# Border colors (softer purple accent) +# class border background text indicator child_border +client.focused #9d5a7f #9d5a7f #d0d0d0 #9d5a7f #9d5a7f +client.focused_inactive #626262 #1c1c1c #626262 #1c1c1c #1c1c1c +client.unfocused #4a3844 #4a3844 #8a8a8a #4a3844 #4a3844 +client.urgent #d68787 #d68787 #1c1c1c #d68787 #d68787 + +# SwayFX effects +corner_radius 10 +shadows enable +shadow_blur_radius 20 +shadow_color #00000099 +layer_effects "waybar" blur enable; shadows enable; corner_radius 10 + +# Dim inactive windows slightly +default_dim_inactive 0.15 +dim_inactive_colors.unfocused #000000FF +dim_inactive_colors.urgent #900000FF + +# sway-borders (disabled - package removed) +# border_images.focused ~/.config/sway/assets/focused.png +# border_images.focused_inactive ~/.config/sway/assets/focused_inactive.png +# border_images.unfocused ~/.config/sway/assets/unfocused.png +# border_images.urgent ~/.config/sway/assets/urgent.png + +# XWayland configuration for GPU access +xwayland enable + +# Autostart +exec_always systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE +exec_always dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE +exec mako +exec_always ~/.config/waybar/waybar.sh +exec wl-paste --watch cliphist store + +include /etc/sway/config.d/* diff --git a/linux/arch/.config/sway/scripts/macos-edit b/linux/arch/.config/sway/scripts/macos-edit new file mode 100755 index 0000000..2b14c50 --- /dev/null +++ b/linux/arch/.config/sway/scripts/macos-edit @@ -0,0 +1,25 @@ +#!/usr/bin/env sh + +focused_app=$( + swaymsg -t get_tree | + jq -r '.. | objects | select(.focused? == true) | .app_id // .window_properties.class // ""' | + head -n 1 +) + +case "$1:$focused_app" in + copy:kitty) + exec wtype -M ctrl -M shift -k c -m shift -m ctrl + ;; + paste:kitty) + exec wtype -M ctrl -M shift -k v -m shift -m ctrl + ;; + copy:*) + exec wtype -M ctrl -k c -m ctrl + ;; + paste:*) + exec wtype -M ctrl -k v -m ctrl + ;; + *) + exit 64 + ;; +esac diff --git a/linux/arch/.config/waybar/config b/linux/arch/.config/waybar/config new file mode 100644 index 0000000..ef8709d --- /dev/null +++ b/linux/arch/.config/waybar/config @@ -0,0 +1,184 @@ +{ + "layer": "bottom", + "position": "top", + "height": 54, + + "modules-left": ["custom/app-launcher", "sway/workspaces", "sway/mode"], + + "modules-center": ["custom/launch-firefox", + "custom/launch-slack", + "custom/launch-spotify", + "custom/launch-steam" + ], + + "modules-right": ["tray", "pulseaudio", "custom/system-graph", "custom/storage", "custom/storage-workspace", "custom/docker", "custom/k8s", "clock"], + + "sway/mode": { + "format": " {}" + }, + + "sway/workspaces": { + "all-outputs": false, + "disable-scroll": true, + "format": "{icon}", + "format-icons": { + "1": "", + "2": "", + "3": " ", + "4": "", + }, + "persistent-workspaces" : { + "1" : [], + "2" : [], + "3" : [], + "4" : [], + } + }, + "sway/window": { + "max-length": 80, + "tooltip": false + }, + "cpu": { + "interval": 10, + "format": "{load} {usage}%" + }, + "memory": { + "interval": 30, + "format": "{}% ", + "max-length": 10 + }, + "clock": { + "format": "{:%a %d %b %H:%M}", + "tooltip": false + }, + "network": { + "format": "{icon}", + "format-alt": "{ipaddr}/{cidr} {icon}", + "format-alt-click": "click-right", + "format-icons": { + "wifi": ["", "" ,""], + "ethernet": ["NET"], + "disconnected": [""] + }, + "on-click": "notify-send `nmcli device` --icon=dialog-information", + "tooltip": false + }, + "custom/app-launcher": { + "format": "", + "on-click": "rofi -show drun -eh 2 &" + }, + "custom/launch-firefox": { + "format": "", + "on-click": "firefox", + "tooltip": false + }, + "custom/launch-spotify": { + "format": "", + "on-click": "spotify", + "tooltip": false + }, + "custom/launch-slack": { + "format": "", + "on-click": "slack -s", + "tooltip": false + }, + "custom/launch-steam": { + "format": "", + "on-click": "steam", + "tooltip": false + }, + "custom/launch-thunderbird": { + "format": "", + "on-click": "thunderbird" + }, + "pulseaudio": { + "format": "{icon}", + "format-alt": "{volume} {icon}", + "format-alt-click": "click-right", + "format-muted": "", + "format-icons": { + "phone": [" ", " ", " ", " "], + "default": ["", "", "", ""] + }, + "scroll-step": 10, + "on-click": "if pgrep pavucontrol ; then pkill pavucontrol; else pavucontrol; fi", + "tooltip": false + }, + "custom/spotify": { + "interval": 1, + "return-type": "json", + "exec": "~/.config/waybar/modules/spotify.sh", + "exec-if": "pgrep spotify", + "escape": true + }, + "custom/storage": { + "format": "{} ", + "format-alt": "{percentage}% ", + "format-alt-click": "click-right", + "return-type": "json", + "interval": 60, + "exec": "~/.config/waybar/modules/storage.sh" + }, + "custom/weather": { + "format": "{}", + "format-alt": "{alt}: {}", + "format-alt-click": "click-right", + "interval": 1800, + "return-type": "json", + "exec": "~/.config/waybar/modules/weather.sh", + "exec-if": "ping wttr.in -c1" + }, + "idle_inhibitor": { + "format": "{icon}", + "format-icons": { + "activated": "", + "deactivated": "" + }, + "tooltip": false + }, + "custom/mail": { + "format": "", + "format-alt": "{alt} ", + "format-alt-click": "click-right", + "interval": 60, + "return-type": "json", + "exec": "~/.config/waybar/modules/mail.py", + "tooltip": false + }, + "tray": { + "icon-size": 16, + "spacing": 10 + }, + "custom/storage-workspace": { + "format": "🗄️ {}", + "format-alt": "🗄️ {percentage}%", + "format-alt-click": "click-right", + "return-type": "json", + "interval": 60, + "exec": "~/.config/waybar/modules/storage-workspace.sh", + "tooltip": true + }, + "custom/system-graph": { + "format": "{}", + "return-type": "json", + "interval": 2, + "exec": "~/.config/waybar/modules/system-graph.sh", + "tooltip": true + }, + "custom/docker": { + "format": "{}", + "return-type": "json", + "interval": 30, + "exec": "~/.config/waybar/modules/docker.py", + "exec-if": "pgrep -x dockerd", + "tooltip": true + }, + "custom/k8s": { + "format": "{}", + "return-type": "json", + "interval": 30, + "exec": "~/.config/waybar/modules/k8s.py", + "exec-if": "sh -c 'command -v kubectl >/dev/null && kubectl config current-context >/dev/null 2>&1'", + "tooltip": true + } +} diff --git a/linux/arch/.config/waybar/modules/docker.py b/linux/arch/.config/waybar/modules/docker.py new file mode 100755 index 0000000..37faf0c --- /dev/null +++ b/linux/arch/.config/waybar/modules/docker.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +import json +import subprocess + +def run_command(cmd): + """Run a shell command and return output""" + try: + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5) + return result.stdout.strip() + except: + return "" + +def get_docker_info(): + """Get Docker container information""" + running = run_command("docker ps -q 2>/dev/null | wc -l") + total = run_command("docker ps -aq 2>/dev/null | wc -l") + + # Get container names for tooltip + containers = run_command("docker ps --format '{{.Names}}' 2>/dev/null") + + try: + running = int(running) if running else 0 + total = int(total) if total else 0 + except: + running, total = 0, 0 + + return { + "running": running, + "total": total, + "containers": containers.split('\n') if containers else [] + } + +def main(): + docker_info = get_docker_info() + + # Build display text + text = f"🐳 {docker_info['running']}" + + # Build detailed tooltip + tooltip_lines = [f"Docker: {docker_info['running']}/{docker_info['total']} running"] + + if docker_info['containers']: + tooltip_lines.append("\nRunning containers:") + for container in docker_info['containers'][:10]: # Limit to 10 + tooltip_lines.append(f" • {container}") + if len(docker_info['containers']) > 10: + tooltip_lines.append(f" ... and {len(docker_info['containers']) - 10} more") + else: + tooltip_lines.append("No containers running") + + tooltip = "\n".join(tooltip_lines) + + output = { + "text": text, + "tooltip": tooltip + } + + print(json.dumps(output)) + +if __name__ == "__main__": + main() diff --git a/linux/arch/.config/waybar/modules/k8s.py b/linux/arch/.config/waybar/modules/k8s.py new file mode 100755 index 0000000..94c6a95 --- /dev/null +++ b/linux/arch/.config/waybar/modules/k8s.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 + +import json +import subprocess +from collections import defaultdict + +def run_command(cmd): + """Run a shell command and return output""" + try: + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5) + return result.stdout.strip() + except: + return "" + +def get_k8s_info(): + """Get Kubernetes context and detailed pod/app information""" + context = run_command("kubectl config current-context 2>/dev/null") + + if not context: + return None + + # Get namespace list + namespaces_raw = run_command("kubectl get namespaces --no-headers -o custom-columns=':metadata.name' 2>/dev/null") + namespaces = [ns.strip() for ns in namespaces_raw.split('\n') if ns.strip()] + + # Get all pods with namespace and status + pods_raw = run_command("kubectl get pods --all-namespaces -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase' --no-headers 2>/dev/null") + + # Parse pods by namespace + pods_by_namespace = defaultdict(lambda: {"running": [], "pending": [], "failed": []}) + total_running = 0 + total_pending = 0 + total_failed = 0 + + for line in pods_raw.split('\n'): + if not line.strip(): + continue + parts = line.split() + if len(parts) >= 3: + namespace, pod_name, status = parts[0], parts[1], parts[2] + + if status == "Running": + pods_by_namespace[namespace]["running"].append(pod_name) + total_running += 1 + elif status == "Pending": + pods_by_namespace[namespace]["pending"].append(pod_name) + total_pending += 1 + elif status in ["Failed", "Error", "CrashLoopBackOff"]: + pods_by_namespace[namespace]["failed"].append(pod_name) + total_failed += 1 + + # Get node info + nodes_ready = run_command("kubectl get nodes --no-headers 2>/dev/null | grep -c ' Ready'") + try: + nodes = int(nodes_ready) if nodes_ready else 0 + except: + nodes = 0 + + # Get deployments for better app understanding + deployments_raw = run_command("kubectl get deployments --all-namespaces -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,READY:.status.readyReplicas,TOTAL:.status.replicas' --no-headers 2>/dev/null") + deployments = [] + for line in deployments_raw.split('\n'): + if not line.strip(): + continue + parts = line.split() + if len(parts) >= 4: + deployments.append({ + "namespace": parts[0], + "name": parts[1], + "ready": parts[2] if parts[2] != '' else '0', + "total": parts[3] if parts[3] != '' else '0' + }) + + return { + "context": context, + "namespaces": namespaces, + "pods_by_namespace": dict(pods_by_namespace), + "pods_running": total_running, + "pods_pending": total_pending, + "pods_failed": total_failed, + "nodes": nodes, + "deployments": deployments + } + +def main(): + k8s_info = get_k8s_info() + + if not k8s_info: + output = { + "text": "☸ -", + "tooltip": "Kubernetes: No context" + } + print(json.dumps(output)) + return + + # Build display text (context shown in tooltip only) + text = f"☸ {k8s_info['pods_running']}" + + # Skip default Kubernetes namespaces + system_namespaces = {'default', 'kube-system', 'kube-public', 'kube-node-lease', 'ingress-nginx'} + + # Build detailed tooltip + tooltip_lines = [ + f"Context: {k8s_info['context']}", + f"Nodes: {k8s_info['nodes']}", + "" + ] + + # Show deployments if any (excluding system namespaces) + custom_deployments = [d for d in k8s_info['deployments'] if d['namespace'] not in system_namespaces] + + if custom_deployments: + tooltip_lines.append("Deployments:") + for dep in custom_deployments[:10]: # Limit to 10 + tooltip_lines.append(f" {dep['namespace']}/{dep['name']}: {dep['ready']}/{dep['total']}") + if len(custom_deployments) > 10: + tooltip_lines.append(f" ... and {len(custom_deployments) - 10} more") + tooltip_lines.append("") + + # Show pods grouped by namespace (only non-empty, non-system ones) + tooltip_lines.append("Namespaces:") + active_namespaces = 0 + for ns in k8s_info['namespaces']: + # Skip system namespaces + if ns in system_namespaces: + continue + + pods = k8s_info['pods_by_namespace'].get(ns, {"running": [], "pending": [], "failed": []}) + running_count = len(pods['running']) + pending_count = len(pods['pending']) + failed_count = len(pods['failed']) + + status_parts = [] + if running_count > 0: + status_parts.append(f"{running_count} running") + if pending_count > 0: + status_parts.append(f"{pending_count} pending") + if failed_count > 0: + status_parts.append(f"{failed_count} failed") + + if status_parts: + tooltip_lines.append(f" {ns}: {', '.join(status_parts)}") + active_namespaces += 1 + + if active_namespaces == 0: + tooltip_lines.append(" (no custom namespaces)") + + # Add totals at bottom + tooltip_lines.append("") + tooltip_lines.append(f"Total: {k8s_info['pods_running']} running") + if k8s_info['pods_pending'] > 0: + tooltip_lines.append(f" {k8s_info['pods_pending']} pending") + if k8s_info['pods_failed'] > 0: + tooltip_lines.append(f" {k8s_info['pods_failed']} failed") + + tooltip = "\n".join(tooltip_lines) + + # Add CSS class if there are issues + css_class = "" + if k8s_info['pods_failed'] > 0: + css_class = "critical" + elif k8s_info['pods_pending'] > 0: + css_class = "warning" + + output = { + "text": text, + "tooltip": tooltip, + "class": css_class + } + + print(json.dumps(output)) + +if __name__ == "__main__": + main() diff --git a/linux/arch/.config/waybar/modules/mail.py b/linux/arch/.config/waybar/modules/mail.py new file mode 100755 index 0000000..abc36ec --- /dev/null +++ b/linux/arch/.config/waybar/modules/mail.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +import os +import imaplib + +import mailsecrets + +def getmails(username, password, server): + imap = imaplib.IMAP4_SSL(server, 993) + imap.login(username, password) + imap.select('INBOX') + ustatus, uresponse = imap.uid('search', None, 'UNSEEN') + if ustatus == 'OK': + unread_msg_nums = uresponse[0].split() + else: + unread_msg_nums = [] + + fstatus, fresponse = imap.uid('search', None, 'FLAGGED') + if fstatus == 'OK': + flagged_msg_nums = fresponse[0].split() + else: + flagged_msg_nums = [] + + return [len(unread_msg_nums), len(flagged_msg_nums)] + +ping = os.system("ping " + mailsecrets.server + " -c1 > /dev/null 2>&1") +if ping == 0: + mails = getmails(mailsecrets.username, mailsecrets.password, mailsecrets.server) + text = '' + alt = '' + + if mails[0] > 0: + text = alt = str(mails[0]) + if mails[1] > 0: + alt = str(mails[1]) + "  " + alt + else: + exit(1) + + print('{"text":"' + text + '", "alt": "' + alt + '"}') + +else: + exit(1) diff --git a/linux/arch/.config/waybar/modules/spotify.sh b/linux/arch/.config/waybar/modules/spotify.sh new file mode 100755 index 0000000..3da3be4 --- /dev/null +++ b/linux/arch/.config/waybar/modules/spotify.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +class=$(playerctl metadata --player=spotify --format '{{lc(status)}}' 2>/dev/null) +icon="" + +if [[ $class == "playing" ]]; then + info=$(playerctl metadata --player=spotify --format '{{artist}} - {{title}}') + if [[ ${#info} -gt 40 ]]; then + info=$(echo "$info" | cut -c1-40)"..." + fi + text=$info +elif [[ $class == "paused" ]]; then + text="$icon paused" +elif [[ $class == "stopped" ]]; then + text="$icon stopped" +fi + +echo -e "{\"text\":\""$text"\", \"class\":\""$class"\"}" diff --git a/linux/arch/.config/waybar/modules/storage-workspace.sh b/linux/arch/.config/waybar/modules/storage-workspace.sh new file mode 100755 index 0000000..f77c86b --- /dev/null +++ b/linux/arch/.config/waybar/modules/storage-workspace.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +mount="$HOME/workspace" +warning=80 +critical=90 + +# Exit quietly (module hides) when the workspace mount does not exist +[ -d "$mount" ] || exit 1 + +df -h -P -l "$mount" | awk -v warning=$warning -v critical=$critical ' +NR==2 { + text=$4 + tooltip="Workspace: "$2" total, "$3" used, "$4" free ("$5")" + use=$5 +} +END { + if (use == "") { exit 1 } + class="" + gsub(/%$/,"",use) + if (use > critical) { + class="critical" + } else if (use > warning) { + class="warning" + } + print "{\"text\":\""text"\", \"percentage\":"use",\"tooltip\":\""tooltip"\", \"class\":\""class"\"}" +} +' diff --git a/linux/arch/.config/waybar/modules/storage.sh b/linux/arch/.config/waybar/modules/storage.sh new file mode 100755 index 0000000..77902e3 --- /dev/null +++ b/linux/arch/.config/waybar/modules/storage.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +mount="/" +warning=80 +critical=90 + +df -h -P -l "$mount" | awk -v warning=$warning -v critical=$critical ' +/\/.*/ { + text=$4 + tooltip="Root: "$2" total, "$3" used, "$4" free ("$5")" + use=$5 + exit 0 +} +END { + class="" + gsub(/%$/,"",use) + if (use > critical) { + class="critical" + } else if (use > warning) { + class="warning" + } + print "{\"text\":\""text"\", \"percentage\":"use",\"tooltip\":\""tooltip"\", \"class\":\""class"\"}" +} +' diff --git a/linux/arch/.config/waybar/modules/system-graph.sh b/linux/arch/.config/waybar/modules/system-graph.sh new file mode 100755 index 0000000..6d817bc --- /dev/null +++ b/linux/arch/.config/waybar/modules/system-graph.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Simple CPU + Memory display with load indicators + +# Get current CPU usage +cpu_usage=$(top -bn2 -d 0.5 | grep "Cpu(s)" | tail -1 | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}') +cpu_int=$(printf "%.0f" "$cpu_usage") + +# Get current memory usage +mem_usage=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}') + +# Choose icon based on CPU load +if [ $cpu_int -lt 25 ]; then + cpu_icon="" +elif [ $cpu_int -lt 50 ]; then + cpu_icon="" +elif [ $cpu_int -lt 75 ]; then + cpu_icon="" +else + cpu_icon="" +fi + +# Simple compact display +text="${cpu_int}% ${mem_usage}%" +tooltip="CPU: ${cpu_int}%\nMemory: ${mem_usage}%" + +echo "{\"text\":\"$text\", \"tooltip\":\"$tooltip\"}" diff --git a/linux/arch/.config/waybar/modules/weather.sh b/linux/arch/.config/waybar/modules/weather.sh new file mode 100755 index 0000000..303e938 --- /dev/null +++ b/linux/arch/.config/waybar/modules/weather.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +cachedir=~/.cache/rbn +cachefile=${0##*/}-$1 + +if [ ! -d $cachedir ]; then + mkdir -p $cachedir +fi + +if [ ! -f $cachedir/$cachefile ]; then + touch $cachedir/$cachefile +fi + +# Save current IFS +SAVEIFS=$IFS +# Change IFS to new line. +IFS=$'\n' + +cacheage=$(($(date +%s) - $(stat -c '%Y' "$cachedir/$cachefile"))) +if [ $cacheage -gt 1740 ] || [ ! -s $cachedir/$cachefile ]; then + data=($(curl -s https://en.wttr.in/$1\?0qnT 2>&1)) + echo ${data[0]} | cut -f1 -d, > $cachedir/$cachefile + echo ${data[1]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile + echo ${data[2]} | sed -E 's/^.{15}//' >> $cachedir/$cachefile +fi + +weather=($(cat $cachedir/$cachefile)) + +# Restore IFSClear +IFS=$SAVEIFS + +temperature=$(echo ${weather[2]} | sed -E 's/([[:digit:]]+)\.\./\1 to /g') + +#echo ${weather[1]##*,} + +# https://fontawesome.com/icons?s=solid&c=weather +case $(echo ${weather[1]##*,} | tr '[:upper:]' '[:lower:]') in +"clear" | "sunny") + condition="" + ;; +"partly cloudy") + condition="" + ;; +"cloudy") + condition="" + ;; +"overcast") + condition="" + ;; +"mist" | "fog" | "freezing fog") + condition="" + ;; +"patchy rain possible" | "patchy light drizzle" | "light drizzle" | "patchy light rain" | "light rain" | "light rain shower" | "rain") + condition="" + ;; +"moderate rain at times" | "moderate rain" | "heavy rain at times" | "heavy rain" | "moderate or heavy rain shower" | "torrential rain shower" | "rain shower") + condition="" + ;; +"patchy snow possible" | "patchy sleet possible" | "patchy freezing drizzle possible" | "freezing drizzle" | "heavy freezing drizzle" | "light freezing rain" | "moderate or heavy freezing rain" | "light sleet" | "ice pellets" | "light sleet showers" | "moderate or heavy sleet showers") + condition="" + ;; +"blowing snow" | "moderate or heavy sleet" | "patchy light snow" | "light snow" | "light snow showers") + condition="" + ;; +"blizzard" | "patchy moderate snow" | "moderate snow" | "patchy heavy snow" | "heavy snow" | "moderate or heavy snow with thunder" | "moderate or heavy snow showers") + condition="" + ;; +"thundery outbreaks possible" | "patchy light rain with thunder" | "moderate or heavy rain with thunder" | "patchy light snow with thunder") + condition="" + ;; +*) + condition="" + echo -e "{\"text\":\""$condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" + ;; +esac + +#echo $temp $condition + +echo -e "{\"text\":\""$temperature $condition"\", \"alt\":\""${weather[0]}"\", \"tooltip\":\""${weather[0]}: $temperature ${weather[1]}"\"}" diff --git a/linux/arch/.config/waybar/style.css b/linux/arch/.config/waybar/style.css new file mode 100644 index 0000000..698c017 --- /dev/null +++ b/linux/arch/.config/waybar/style.css @@ -0,0 +1,124 @@ +* { + border: none; + font-family: Helvetica, Sans; + margin: 2.5px; + font-family: Helvetica, Sans; +} + +window { + color: rgba(217, 216, 216, 1); +} + +window#waybar { + background: transparent; +} + +#workspaces { + margin-left: 10px; + font-size: 10px; + background:#843656; + border-radius: 10px 10px 10px 10px; +} + +#workspaces format { + font-size: 20px; +} + +#workspaces button { + padding: 0 10px; + font-size: 20px; + background: transparent; + background-color: transparent; + border: none; + box-shadow: none; + text-shadow: none; + color: rgba(217, 216, 216, 0.4); +} + +#workspaces button.visible, +#workspaces button.focused { + background: transparent; + background-color: transparent; + box-shadow: none; + text-shadow: none; +} + +#workspaces button:hover, +#workspaces button:active { + background: #6b4456; + background-color: #6b4456; + box-shadow: none; + text-shadow: none; +} + +#workspaces button.visible { + color: rgba(217, 216, 216, 1); +} + +#workspaces button.focused { + border-top: 3px solid rgba(217, 216, 216, 1); + border-bottom: 3px solid rgba(217, 216, 216, 0); +} + +#workspaces button.urgent { + color: rgba(238, 46, 36, 1); +} + +.modules-center { + min-width: 25px; +} + +#custom-app-launcher { + border-radius: 10px 10px 10px 10px; + background:#6b4456; +} + +#custom-launch-firefox, #custom-launch-spotify, #custom-launch-slack, #custom-launch-steam { + font-size: 14px; + margin: 0px 6px 0px 10px; + min-width: 25px; +} + +.modules-right { + border-radius: 20px 20px 20px 20px; + background: #6b4456; +} + +#mode, #cpu, #memory, #network, #pulseaudio, #idle_inhibitor, #custom-storage, #custom-spotify, #custom-weather, #custom-mail, #custom-docker, #custom-k8s, #custom-storage-workspace, #custom-system-graph { + margin: 0px 6px 0px 10px; + min-width: 25px; +} + +#tray * { + margin: 0 10px; +} + +#clock { + margin: 0px 16px 0px 10px; + min-width: 140px; +} + +#custom-storage.warning { + color: rgba(255, 210, 4, 1); +} + +#custom-storage.critical { + color: rgba(238, 46, 36, 1); +} + +/* Tooltip styling to match purple theme */ +tooltip { + background: #221820; + border: 2px solid #9d5a7f; + border-radius: 12px; + color: #d0d0d0; + padding: 12px 16px; + font-family: FiraCode Nerd Font, monospace; + font-size: 10px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); +} + +tooltip label { + color: #d0d0d0; + font-family: FiraCode Nerd Font, monospace; +} diff --git a/linux/arch/.config/waybar/waybar.sh b/linux/arch/.config/waybar/waybar.sh new file mode 100755 index 0000000..720620c --- /dev/null +++ b/linux/arch/.config/waybar/waybar.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +# Terminate already running bar instances +killall -q waybar + +# Wait until the processes have been shut down +while pgrep -x waybar >/dev/null; do sleep 1; done + +# Launch main +waybar diff --git a/linux/arch/README.md b/linux/arch/README.md new file mode 100644 index 0000000..e4683c3 --- /dev/null +++ b/linux/arch/README.md @@ -0,0 +1,98 @@ +# Arch Linux Desktop Configuration + +This directory contains configuration files for my Arch Linux desktop setup. + +## System Info +- **Window Manager**: SwayFX 0.5.3 (Wayland compositor with rounded corners and effects) +- **Status Bar**: Waybar with custom modules +- **Terminal**: Kitty with FiraCode Nerd Font +- **Launcher**: Rofi +- **Notifications**: Mako +- **Theme**: Purple/dark color scheme + +## What's Included + +### Sway/SwayFX Configuration +- **Location**: `.config/sway/config` +- **Features**: + - 10px rounded corners on windows + - Window shadows and blur effects + - 4px purple borders (#9d5a7f) + - 28px inner gaps, -8px outer gaps + - Workspace assignments (Firefox→2, Slack→3, Steam→4) + - Custom keybindings + +### Waybar +- **Location**: `.config/waybar/` +- **Modules**: + - Docker container monitoring (`modules/docker.py`) + - Kubernetes cluster info (`modules/k8s.py`) - filters out system namespaces + - CPU/Memory usage display + - Dual drive monitoring (root + workspace drive) + - Custom app launchers (Firefox, Slack, Spotify, Steam) +- **Theme**: Purple/dark (#6b4456 backgrounds, #9d5a7f accents) +- **Font**: FiraCode Nerd Font 10px for tooltips + +### Kitty Terminal +- **Location**: `.config/kitty/current-theme.conf` (Arch-only theme overlay) +- The base config comes from `linux/common/kitty.conf` (installed to + `~/.config/kitty/kitty.conf`); this overlay applies the personal-pink + palette on top: + - Background: #2A1E2E (plum) + - Accent: #9d5a7f + - Font: FiraCode Nerd Font + +### Rofi Launcher +- **Location**: `.config/rofi/theme.rasi` +- **Theme**: Purple/dark matching system colors +- **Border radius**: 16px rounded corners + +### Mako Notifications +- **Location**: `.config/mako/config` +- **Theme**: Purple borders, dark background +- **Font**: FiraCode Nerd Font 10px +- **Border radius**: 16px + +## Installation + +1. **Prerequisites**: + ```bash + sudo pacman -S waybar kitty rofi mako grim slurp \ + firefox spotify-launcher steam + + # AUR (pacman cannot install these; use an AUR helper) + paru -S swayfx slack-desktop nordic-theme + ``` + +2. **Install configs** (from the dotfiles root - configs are copied, never + symlinked; packages come from `linux/arch/packages.list`): + ```bash + ./install.sh + ``` + +3. **Reload Sway**: + ```bash + swaymsg reload + ``` + +4. **(Optional) auto-refresh the AI machine-state snapshot on package changes** + (the installer deliberately does not enable this; it writes into the repo): + ```bash + sed -e "s|__DOTFILES_DIR__|$PWD|" -e "s|__DOTFILES_USER__|$USER|" \ + linux/arch/hooks/90-refresh-ai-context.hook \ + | sudo tee /etc/pacman.d/hooks/90-refresh-ai-context.hook + ``` + +## Color Scheme + +- **Primary Purple**: `#9d5a7f` (borders, accents) +- **Dark Purple-Gray**: `#6b4456` (waybar backgrounds) +- **Background**: `#221820` (pink-gray tint) +- **Text**: `#d0d0d0` (light gray) +- **Unfocused**: `#4a3844` (dark purple-gray) + +## Notes + +- Waybar tooltips use FiraCode Nerd Font for consistency +- Docker and Kubernetes modules require respective CLIs installed +- All configs use rounded corners (10-16px) for visual consistency diff --git a/linux/arch/ai-context/machine.md b/linux/arch/ai-context/machine.md new file mode 100644 index 0000000..0bfe633 --- /dev/null +++ b/linux/arch/ai-context/machine.md @@ -0,0 +1,36 @@ +# Machine: Arch Linux Workstation + +## System + +- **OS**: Arch Linux +- **Package manager**: pacman (AUR: yay) +- **Shell**: zsh +- **Display**: Wayland (Sway) +- **Terminal**: Kitty + +## Primary Use + +- Personal projects +- LLC work +- Development environment + +## Package Installation + +```bash +# System packages +sudo pacman -S + +# AUR packages +yay -S +``` + +## Paths + +- Dotfiles: `~/workspace/dotfiles` +- Projects: `~/workspace/` + +## Notes + +- Uses Sway window manager with Waybar +- Catppuccin Mocha theme across terminal and applications +- Modern CLI tools: ripgrep, fd, bat, exa diff --git a/linux/arch/hooks/90-refresh-ai-context.hook b/linux/arch/hooks/90-refresh-ai-context.hook new file mode 100644 index 0000000..77f4480 --- /dev/null +++ b/linux/arch/hooks/90-refresh-ai-context.hook @@ -0,0 +1,11 @@ +[Trigger] +Operation = Install +Operation = Upgrade +Operation = Remove +Type = Package +Target = * + +[Action] +Description = Refreshing AI context machine state... +When = PostTransaction +Exec = /usr/bin/runuser -u __DOTFILES_USER__ -- __DOTFILES_DIR__/scripts/refresh-machine-state.sh diff --git a/linux/arch/packages.list b/linux/arch/packages.list index 2e552f5..08a3b72 100644 --- a/linux/arch/packages.list +++ b/linux/arch/packages.list @@ -13,7 +13,21 @@ gzip htop jq kitty +linux-headers +nvidia-open +nvidia-utils +wl-clipboard +wtype +waybar +ttf-firacode-nerd +rofi +mako +grim +slurp +cliphist +playerctl make +neovim nodejs npm python @@ -28,11 +42,14 @@ wget zsh # Modern alternatives bat -exa -delta +eza +git-delta dust procs bottom httpie yq -neofetch \ No newline at end of file + +# AUR (install with an AUR helper, e.g. paru -S; pacman cannot install these) +# swayfx +# nordic-theme (GTK theme referenced by gtk settings.ini) diff --git a/linux/common/kitty.conf b/linux/common/kitty.conf index d5965dd..14fc548 100644 --- a/linux/common/kitty.conf +++ b/linux/common/kitty.conf @@ -2,7 +2,7 @@ # Linux-specific Kitty configuration # BEGIN_KITTY_THEME -include ../../common/themes/current-theme.conf +include current-theme.conf # END_KITTY_THEME font_family FiraCode Nerd Font @@ -32,7 +32,24 @@ active_tab_font_style bold inactive_tab_font_style normal tab_switch_strategy previous -# Linux Keyboard shortcuts (ctrl+shift+) +# Keyboard shortcuts (macOS-style super+ with ctrl+shift+ fallbacks) +map super+c copy_to_clipboard +map super+v paste_from_clipboard +map super+q quit +map super+n new_os_window +map super+enter new_window +map super+t new_tab +map super+w close_tab +map super+right next_tab +map super+left previous_tab +map super+plus change_font_size all +1.0 +map super+equal change_font_size all +1.0 +map super+minus change_font_size all -1.0 +map super+0 change_font_size all 0 +map f11 toggle_fullscreen +map super+l clear_terminal to_cursor_scroll active + +# ctrl+shift fallbacks map ctrl+shift+q quit map ctrl+shift+n new_os_window map ctrl+shift+enter new_window @@ -43,5 +60,4 @@ map ctrl+shift+left previous_tab map ctrl+shift+plus change_font_size all +1.0 map ctrl+shift+minus change_font_size all -1.0 map ctrl+shift+0 change_font_size all 0 -map f11 toggle_fullscreen -map ctrl+shift+l clear_terminal to_cursor_scroll active \ No newline at end of file +map ctrl+shift+l clear_terminal to_cursor_scroll active diff --git a/linux/debian/ai-context/machine.md b/linux/debian/ai-context/machine.md new file mode 100644 index 0000000..8559d14 --- /dev/null +++ b/linux/debian/ai-context/machine.md @@ -0,0 +1,37 @@ +# Machine: Debian Linux + +## System + +- **OS**: Debian GNU/Linux +- **Package manager**: apt +- **Shell**: zsh +- **Terminal**: Kitty + +## Primary Use + +- Server and development environment +- General development + +## Package Installation + +```bash +# System packages +sudo apt update && sudo apt install + +# Search for packages +apt search + +# Remove packages +sudo apt remove +``` + +## Paths + +- Dotfiles: `~/workspace/dotfiles` +- Projects: `~/workspace/` + +## Notes + +- Uses systemd for service management +- Stable release cycle; backports available for newer packages +- Modern CLI tools: ripgrep, fd-find, bat (binary names may differ from upstream: `fdfind`, `batcat`) diff --git a/linux/debian/packages.list b/linux/debian/packages.list index 40fabbd..369a0ef 100644 --- a/linux/debian/packages.list +++ b/linux/debian/packages.list @@ -23,5 +23,6 @@ ripgrep tmux tree vim +neovim wget zsh \ No newline at end of file diff --git a/linux/fedora/ai-context/machine.md b/linux/fedora/ai-context/machine.md new file mode 100644 index 0000000..03991da --- /dev/null +++ b/linux/fedora/ai-context/machine.md @@ -0,0 +1,41 @@ +# Machine: Fedora Linux + +## System + +- **OS**: Fedora Linux +- **Package manager**: dnf +- **Shell**: zsh +- **Terminal**: Kitty + +## Primary Use + +- Development environment +- General development + +## Package Installation + +```bash +# System packages +sudo dnf install + +# Search for packages +dnf search + +# Remove packages +sudo dnf remove + +# Enable COPR repos (community packages) +sudo dnf copr enable / +``` + +## Paths + +- Dotfiles: `~/workspace/dotfiles` +- Projects: `~/workspace/` + +## Notes + +- Uses systemd for service management +- SELinux enabled by default +- Rapid release cycle with recent upstream packages +- Modern CLI tools: ripgrep, fd-find, bat diff --git a/linux/fedora/packages.list b/linux/fedora/packages.list index 5974d5c..5fc5640 100644 --- a/linux/fedora/packages.list +++ b/linux/fedora/packages.list @@ -25,6 +25,7 @@ cargo tmux tree vim +neovim wget zsh # Modern alternatives diff --git a/prompt-results/audit-log.md b/prompt-results/audit-log.md deleted file mode 100644 index 20e9844..0000000 --- a/prompt-results/audit-log.md +++ /dev/null @@ -1,516 +0,0 @@ -# Cursor Rules - Language-Agnostic Project Standards - -## Overview - -This document defines the standardized patterns, conventions, and architectural principles for all projects based on the audit-log-service example. These rules ensure consistency, maintainability, and scalability across different technology stacks. The project it was generated off of was in Go. - -## 1. Modularity & Structure - -### Directory Layout - -``` -project-root/ -├── src/ # Main source code -│ ├── api/ # Business logic layer -│ ├── handler/ # HTTP/transport layer handlers -│ ├── model/ # Data models and entities -│ │ ├── dao/ # Data Access Objects -│ │ ├── dto/ # Data Transfer Objects -│ │ │ ├── request/ # Request DTOs -│ │ │ └── response/ # Response DTOs -│ │ ├── entities/ # Core domain entities -│ │ └── repository/ # Repository interfaces -│ ├── modules/ # Dependency injection modules -│ ├── routes/ # Route definitions -│ ├── service/ # Business services -│ └── errors/ # Error definitions -├── test/ # Test files -│ ├── unit/ # Unit tests (mirror src structure) -│ └── integration/ # Integration tests -├── cmd/ # Application entry points -├── scripts/ # Utility scripts -├── examples/ # Example data and configurations -├── bin/ # Build artifacts -├── docs/ # Documentation -│ └── architecture/ # Architecture documentation -├── docker-compose.yml # Service orchestration -├── Dockerfile # Container definition -├── Makefile # Build and development commands -├── README.md # Project overview -└── .gitignore # Version control exclusions -``` - -### Naming Conventions - -#### Files and Directories -- **snake_case** for file names: `audit_handler.go`, `user_service.py` -- **kebab-case** for directories: `load-test-env/`, `test-data/` -- **PascalCase** for class/struct files: `AuditEvent.java`, `UserModel.cs` - -#### Code Elements -- **PascalCase** for public interfaces, classes, and structs -- **camelCase** for methods, functions, and variables -- **UPPER_SNAKE_CASE** for constants and environment variables -- **snake_case** for database fields and API parameters - -#### Layer-Specific Naming -- **DAO**: `{Entity}DAO` (e.g., `UserDAO`, `AuditDAO`) -- **Repository**: `{Entity}Repository` (e.g., `UserRepository`) -- **Service**: `{Entity}Service` (e.g., `UserService`) -- **Handler**: `{Entity}Handler` (e.g., `UserHandler`) -- **DTO**: `{Entity}{Request|Response}` (e.g., `UserRequest`, `UserResponse`) - -## 2. Build & Dev Tooling - -### Makefile Structure - -Every project must include a comprehensive Makefile with these standard targets: - -```makefile -# Core Development -build # Build the application -run # Run the application locally -test # Run all tests -test-unit # Run unit tests only -test-integration # Run integration tests only -test-coverage # Generate coverage report - -# Docker Operations -docker-up # Start all services -docker-down # Stop all services -docker-build # Build container image - -# Data Management -ingest # Load test data -clear-data # Clear test data - -# Code Quality -lint # Run linting tools -format # Format code -clean # Clean build artifacts - -# Help -help # Show available commands -``` - -### Scripts Directory - -Maintain a `scripts/` directory with utility scripts: - -- **Data Management**: `ingest-data.sh`, `clear-data.sh` -- **Testing**: `run-tests.sh`, `load-test.py` -- **Infrastructure**: `setup-env.sh`, `deploy.sh` -- **Development**: `generate-test-data.py`, `validate-schema.py` - -### Docker Configuration - -#### docker-compose.yml Requirements -- **Service Health Checks**: Every service must include health checks -- **Environment Variables**: Use `.env` files for configuration -- **Network Isolation**: Define custom networks for service communication -- **Volume Management**: Persistent data storage with named volumes -- **Resource Limits**: Define memory and CPU constraints - -#### Dockerfile Best Practices -- **Multi-stage builds** for production optimization -- **Non-root user** for security -- **Layer caching** optimization -- **Health check** instructions -- **Environment-specific** configurations - -## 3. Documentation & Metadata - -### Required Documentation Files - -#### README.md Structure -```markdown -# Project Name - -Brief description of the project and its purpose. - -## Features -- Key feature 1 -- Key feature 2 - -## Quick Start -### Prerequisites -### Installation -### Usage - -## API Documentation -### Endpoints -### Examples - -## Architecture -### Components -### Data Flow - -## Development -### Project Structure -### Available Commands -### Testing - -## Configuration -### Environment Variables -### Service Configuration - -## Production Considerations -### Performance -### Security -### Monitoring -``` - -#### Architecture Documentation (`docs/architecture/`) - -Required files: -- `system-overview.md` - High-level system architecture -- `data-flow.md` - Data flow diagrams -- `api-design.md` - API design principles -- `deployment.md` - Deployment architecture -- `security.md` - Security considerations - -### Mermaid Diagrams - -Include these diagram types in architecture documentation: - -```mermaid -# System Architecture -graph TB - Client[Client] --> API[API Layer] - API --> Service[Service Layer] - Service --> Repository[Repository Layer] - Repository --> Database[(Database)] - -# Data Flow -sequenceDiagram - participant C as Client - participant A as API - participant S as Service - participant R as Repository - participant D as Database - - C->>A: Request - A->>S: Process - S->>R: Query - R->>D: Execute - D-->>R: Result - R-->>S: Data - S-->>A: Response - A-->>C: Response -``` - -## 4. Testing Strategy - -### Test Organization - -#### Directory Structure -``` -test/ -├── unit/ # Unit tests (mirror src structure) -│ ├── handler/ -│ ├── service/ -│ ├── repository/ -│ └── dao/ -├── integration/ # Integration tests -│ ├── api/ # API integration tests -│ ├── database/ # Database integration tests -│ └── external/ # External service tests -└── fixtures/ # Test data and fixtures -``` - -#### Test Naming Conventions -- **Unit Tests**: `{Component}_{Method}_{Scenario}_test.{ext}` -- **Integration Tests**: `{Component}_integration_test.{ext}` -- **Test Functions**: `Test{Component}_{Method}_{Scenario}` - -#### Test Categories - -##### Unit Tests -- **Handler Tests**: HTTP request/response validation -- **Service Tests**: Business logic validation -- **Repository Tests**: Data access logic -- **Utility Tests**: Helper function validation - -##### Integration Tests -- **API Tests**: Full HTTP endpoint testing -- **Database Tests**: Data persistence validation -- **External Service Tests**: Third-party integration validation - -#### Test Data Management -- **Fixtures**: Reusable test data structures -- **Factories**: Test data generation utilities -- **Mocks**: External dependency simulation -- **Cleanup**: Automatic test data cleanup - -## 5. Design Principles - -### Architectural Layers - -#### 1. Transport Layer (Handler) -- **Responsibility**: HTTP request/response handling -- **Dependencies**: Business logic layer only -- **Patterns**: Request validation, response formatting, error handling - -#### 2. Business Logic Layer (Service/API) -- **Responsibility**: Core business logic and orchestration -- **Dependencies**: Repository layer only -- **Patterns**: Transaction management, business rule enforcement - -#### 3. Data Access Layer (Repository/DAO) -- **Responsibility**: Data persistence and retrieval -- **Dependencies**: Data models only -- **Patterns**: Repository pattern, DAO pattern, query optimization - -#### 4. Data Model Layer (Entities/DTOs) -- **Responsibility**: Data structure definitions -- **Dependencies**: None (base layer) -- **Patterns**: Value objects, DTOs, domain entities - -### Design Patterns - -#### Repository Pattern -```typescript -// Interface definition -interface UserRepository { - findById(id: string): Promise; - save(user: User): Promise; - delete(id: string): Promise; -} - -// Implementation -class UserRepositoryImpl implements UserRepository { - // Implementation details -} -``` - -#### Service Layer Pattern -```typescript -// Business logic orchestration -class UserService { - constructor(private userRepository: UserRepository) {} - - async createUser(userData: CreateUserRequest): Promise { - // Business logic validation - // Repository interaction - // Response formatting - } -} -``` - -#### Handler Pattern -```typescript -// HTTP request handling -class UserHandler { - constructor(private userService: UserService) {} - - async createUser(req: Request, res: Response): Promise { - // Request validation - // Service call - // Response formatting - } -} -``` - -### Separation of Concerns - -#### Single Responsibility Principle -- Each class/function has one reason to change -- Clear boundaries between layers -- Minimal coupling between components - -#### Dependency Inversion -- High-level modules don't depend on low-level modules -- Both depend on abstractions -- Abstractions don't depend on details - -#### Interface Segregation -- Clients don't depend on interfaces they don't use -- Small, focused interfaces -- Composition over inheritance - -## 6. API Design Principles - -### RESTful Design -- **Resource-based URLs**: `/api/v1/users/{id}` -- **HTTP method semantics**: GET, POST, PUT, DELETE -- **Status code consistency**: 200, 201, 400, 404, 500 -- **Versioning**: URL path versioning (`/api/v1/`) - -### Request/Response Patterns - -#### Request DTOs -```typescript -interface CreateUserRequest { - email: string; - name: string; - role: UserRole; -} - -interface UpdateUserRequest { - name?: string; - role?: UserRole; -} -``` - -#### Response DTOs -```typescript -interface UserResponse { - id: string; - email: string; - name: string; - role: UserRole; - createdAt: string; - updatedAt: string; -} - -interface PaginatedResponse { - data: T[]; - total: number; - limit: number; - offset: number; -} -``` - -### Error Handling -- **Consistent error format**: `{ error: string, code?: string }` -- **Appropriate status codes**: 400 for client errors, 500 for server errors -- **Detailed logging**: Server-side error details with correlation IDs -- **User-friendly messages**: Client-safe error descriptions - -### Query Parameters -- **Pagination**: `limit`, `offset` -- **Filtering**: `status`, `type`, `date_range` -- **Sorting**: `sort_by`, `sort_order` -- **Search**: `q` for general search - -## 7. Data Management - -### Entity Design -- **Immutable IDs**: UUID or auto-incrementing IDs -- **Audit fields**: `created_at`, `updated_at`, `created_by`, `updated_by` -- **Soft deletes**: `deleted_at` field for data retention -- **Versioning**: `version` field for optimistic locking - -### Data Access Patterns -- **Repository abstraction**: Hide data source details -- **Query optimization**: Indexed fields, efficient queries -- **Connection pooling**: Database connection management -- **Transaction management**: ACID compliance - -### Caching Strategy -- **Application-level caching**: In-memory caches -- **Database caching**: Query result caching -- **CDN caching**: Static resource caching -- **Cache invalidation**: Event-driven cache updates - -## 8. Security Considerations - -### Input Validation -- **Request validation**: All inputs validated and sanitized -- **SQL injection prevention**: Parameterized queries -- **XSS prevention**: Output encoding -- **CSRF protection**: Token-based protection - -### Authentication & Authorization -- **JWT tokens**: Stateless authentication -- **Role-based access**: Granular permissions -- **API keys**: Service-to-service authentication -- **Rate limiting**: Request throttling - -### Data Protection -- **Encryption at rest**: Sensitive data encryption -- **Encryption in transit**: TLS/SSL for all communications -- **PII handling**: Personal data protection -- **Audit logging**: Security event tracking - -## 9. Performance Guidelines - -### Optimization Strategies -- **Database indexing**: Strategic index placement -- **Query optimization**: Efficient query patterns -- **Connection pooling**: Resource reuse -- **Async processing**: Non-blocking operations - -### Monitoring & Observability -- **Health checks**: Service availability monitoring -- **Metrics collection**: Performance metrics -- **Logging**: Structured logging with correlation IDs -- **Tracing**: Distributed request tracing - -### Scalability Patterns -- **Horizontal scaling**: Load balancer distribution -- **Vertical scaling**: Resource allocation -- **Caching layers**: Multi-level caching -- **Database sharding**: Data distribution - -## 10. Development Workflow - -### Code Quality Standards -- **Linting**: Automated code style enforcement -- **Formatting**: Consistent code formatting -- **Code review**: Peer review requirements -- **Documentation**: Inline and external documentation - -### Version Control -- **Branch naming**: `feature/`, `bugfix/`, `hotfix/` prefixes -- **Commit messages**: Conventional commit format -- **Pull requests**: Required for all changes -- **Release tagging**: Semantic versioning - -### CI/CD Pipeline -- **Automated testing**: Unit, integration, and e2e tests -- **Code quality checks**: Linting, security scanning -- **Build automation**: Automated artifact creation -- **Deployment automation**: Environment-specific deployments - -## 11. Environment Management - -### Configuration Management -- **Environment variables**: Runtime configuration -- **Configuration files**: Environment-specific configs -- **Secrets management**: Secure credential storage -- **Feature flags**: Runtime feature toggles - -### Environment Types -- **Development**: Local development setup -- **Staging**: Pre-production testing -- **Production**: Live environment -- **Testing**: Automated testing environment - -## 12. Compliance & Standards - -### Code Standards -- **Language-specific**: Follow language best practices -- **Framework conventions**: Adhere to framework patterns -- **Industry standards**: OWASP, SOLID principles -- **Team conventions**: Project-specific guidelines - -### Documentation Standards -- **API documentation**: OpenAPI/Swagger specifications -- **Code documentation**: Inline comments and docstrings -- **Architecture documentation**: System design documents -- **User documentation**: End-user guides - ---- - -## Implementation Checklist - -When starting a new project, ensure all these elements are in place: - -- [ ] Directory structure follows the defined layout -- [ ] Makefile includes all standard targets -- [ ] Docker configuration with health checks -- [ ] Comprehensive README.md -- [ ] Architecture documentation in `docs/architecture/` -- [ ] Test structure mirrors source code organization -- [ ] Repository pattern implementation -- [ ] Service layer abstraction -- [ ] Handler layer for transport concerns -- [ ] DTOs for request/response handling -- [ ] Error handling strategy -- [ ] Logging and monitoring setup -- [ ] Security considerations implemented -- [ ] CI/CD pipeline configuration -- [ ] Environment configuration management - -This framework ensures consistent, maintainable, and scalable applications across different technology stacks and team compositions. diff --git a/prompt-results/contact-service-experiment.md b/prompt-results/contact-service-experiment.md deleted file mode 100644 index 647691d..0000000 --- a/prompt-results/contact-service-experiment.md +++ /dev/null @@ -1,593 +0,0 @@ -# Cursor Rules - Language-Agnostic Project Standards - -## Overview - -This document defines the standardized structure, conventions, and best practices for all projects based on the patterns established in the contact-service-experiment repository. These rules are designed to be language-agnostic and focus on architectural principles rather than implementation details. This document was generated from a source project in python. - -## 1. Project Structure & Modularity - -### Core Directory Layout - -``` -project-root/ -├── src/ # Main source code -│ ├── api/ # API layer (REST endpoints, GraphQL, etc.) -│ ├── model/ # Domain models and business logic -│ ├── datastore/ # Data access layer (repositories, ORM models) -│ ├── handler/ # Request/response handlers -│ ├── utils/ # Shared utilities and helpers -│ ├── scripts/ # Utility scripts and data processing -│ └── main.py # Application entry point -├── tests/ # Test suite -│ ├── api/ # API integration tests -│ ├── unit/ # Unit tests -│ ├── integration/ # Integration tests -│ └── conftest.py # Test configuration and fixtures -├── dev/ # Development tools and configurations -├── docs/ # Documentation -├── architecture/ # Architecture diagrams and specifications -├── schema/ # Database schemas and migrations -├── docker-compose.yml # Container orchestration -├── Makefile # Build and development tasks -├── requirements.txt # Dependencies (language-specific) -├── README.md # Project documentation -└── .gitignore # Version control exclusions -``` - -### Naming Conventions - -#### Files and Directories -- Use **snake_case** for all file and directory names -- Separate concerns with clear, descriptive names -- Group related functionality in subdirectories -- Use plural forms for collections (e.g., `models/`, `tests/`) - -#### Code Elements -- **Models**: Use **PascalCase** for class names -- **Functions/Methods**: Use **snake_case** for function and method names -- **Constants**: Use **UPPER_SNAKE_CASE** for constants -- **Variables**: Use **snake_case** for variables and parameters - -## 2. Architectural Layers & Separation of Concerns - -### Layer Structure - -#### 1. API Layer (`src/api/`) -- **Purpose**: Handle HTTP requests, input validation, and response formatting -- **Responsibilities**: - - Route definitions and endpoint handlers - - Request/response serialization - - Input validation and sanitization - - Error handling and status codes -- **Patterns**: Controller pattern, dependency injection - -#### 2. Model Layer (`src/model/`) -- **Purpose**: Define domain entities and business logic -- **Responsibilities**: - - Domain model definitions - - Business rule validation - - Data transformation logic - - Domain-specific algorithms -- **Patterns**: Domain-driven design, value objects, entities - -#### 3. Data Access Layer (`src/datastore/`) -- **Purpose**: Manage data persistence and retrieval -- **Responsibilities**: - - Database schema definitions - - Query operations and data mapping - - Transaction management - - Connection pooling -- **Patterns**: Repository pattern, data mapper, unit of work - -#### 4. Handler Layer (`src/handler/`) -- **Purpose**: Coordinate between layers and manage application flow -- **Responsibilities**: - - Business logic orchestration - - Cross-cutting concerns (logging, caching) - - Service coordination - - Error handling and recovery -- **Patterns**: Service layer, facade pattern - -### Abstraction Patterns - -#### Repository Pattern -- Abstract data access behind interfaces -- Provide consistent API for different data sources -- Enable easy testing and mocking - -#### Service Layer Pattern -- Encapsulate business logic in service classes -- Coordinate between multiple repositories -- Handle complex operations and transactions - -#### Model-View-Controller (MVC) -- Separate data models from presentation logic -- Use controllers to handle user input -- Maintain clear boundaries between layers - -## 3. Build & Development Tooling - -### Makefile Standards - -```makefile -# Standard Makefile targets for all projects -.PHONY: setup run tests clean db db-init db-reset lint format - -# Environment setup -setup: venv install-deps -venv: # Create virtual environment -install-deps: # Install dependencies - -# Development -run: # Start development server -dev: # Start development environment with hot reload - -# Testing -tests: # Run all tests -test-unit: # Run unit tests only -test-integration: # Run integration tests only -test-coverage: # Run tests with coverage - -# Database -db: # Start database -db-init: # Initialize database schema -db-reset: # Reset database (drop and recreate) -db-migrate: # Run database migrations - -# Code Quality -lint: # Run linting tools -format: # Format code -type-check: # Run type checking - -# Cleanup -clean: # Remove generated files and caches -``` - -### Container Configuration - -#### Docker Compose Structure -```yaml -version: '3.8' -services: - app: - build: . - ports: - - "8000:8000" - environment: - - DATABASE_URL=postgresql://user:pass@db:5432/dbname - depends_on: - db: - condition: service_healthy - volumes: - - ./src:/app/src - - db: - image: postgres:15-alpine - environment: - POSTGRES_DB: dbname - POSTGRES_USER: user - POSTGRES_PASSWORD: pass - ports: - - "5432:5432" - volumes: - - db_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U user"] - interval: 5s - timeout: 5s - retries: 5 - -volumes: - db_data: -``` - -### Development Environment - -#### Required Files -- `requirements.txt` or equivalent dependency file -- `.env.example` for environment variable templates -- `docker-compose.yml` for containerized development -- `Makefile` for common development tasks - -#### Environment Variables -- Use `.env` files for local development -- Never commit sensitive data to version control -- Provide `.env.example` with dummy values -- Use environment-specific configuration files - -## 4. Testing Strategy - -### Test Organization - -#### Directory Structure -``` -tests/ -├── unit/ # Unit tests for individual components -│ ├── model/ # Domain model tests -│ ├── datastore/ # Data access layer tests -│ └── utils/ # Utility function tests -├── integration/ # Integration tests -│ ├── api/ # API endpoint tests -│ └── database/ # Database integration tests -├── fixtures/ # Test data and fixtures -├── conftest.py # Test configuration and shared fixtures -└── helpers/ # Test helper functions -``` - -#### Test Naming Conventions -- **Unit Tests**: `test__.py` -- **Integration Tests**: `test__integration.py` -- **API Tests**: `test__.py` - -#### Test Patterns - -##### Unit Test Structure -```python -def test_function_name_scenario(): - """Test description explaining the scenario being tested.""" - # Arrange - Set up test data and conditions - input_data = {...} - expected_result = {...} - - # Act - Execute the function being tested - result = function_under_test(input_data) - - # Assert - Verify the expected outcome - assert result == expected_result -``` - -##### Integration Test Structure -```python -def test_feature_integration(): - """Test complete feature workflow across multiple components.""" - # Setup test environment - # Execute feature workflow - # Verify end-to-end behavior - # Clean up test data -``` - -### Testing Principles - -#### Test Coverage Requirements -- **Unit Tests**: 80% minimum coverage for business logic -- **Integration Tests**: All critical user workflows -- **API Tests**: All public endpoints with various scenarios - -#### Mocking Strategy -- Mock external dependencies (databases, APIs, file systems) -- Use dependency injection for testability -- Create test doubles for complex dependencies - -#### Test Data Management -- Use factories for creating test data -- Implement database transactions for test isolation -- Provide cleanup mechanisms for test data - -## 5. Documentation Standards - -### Required Documentation Files - -#### README.md Structure -```markdown -# Project Name - -Brief description of the project and its purpose. - -## Features - -- Key feature 1 -- Key feature 2 -- Key feature 3 - -## Prerequisites - -- Required software and versions -- System requirements -- Dependencies - -## Installation - -Step-by-step installation instructions. - -## Usage - -How to use the application with examples. - -## API Documentation - -Links to API documentation and examples. - -## Development - -Development setup and contribution guidelines. - -## Testing - -How to run tests and testing strategy. - -## Deployment - -Deployment instructions and configuration. - -## License - -License information. -``` - -#### Architecture Documentation (`architecture/`) -``` -architecture/ -├── overview.md # High-level system overview -├── data-flow.md # Data flow diagrams -├── component-diagram.md # Component interaction diagrams -├── database-schema.md # Database design and relationships -├── api-specification.md # API design and contracts -└── deployment.md # Deployment architecture -``` - -### Documentation Standards - -#### Code Documentation -- Document all public APIs and interfaces -- Use clear, concise descriptions -- Include usage examples for complex functions -- Maintain documentation alongside code changes - -#### Architecture Diagrams -- Use Mermaid diagrams for flow charts -- Include sequence diagrams for complex interactions -- Document data models and relationships -- Keep diagrams up-to-date with code changes - -## 6. Design Principles - -### Core Principles - -#### Single Responsibility Principle -- Each class/module should have one reason to change -- Separate concerns into distinct layers -- Keep functions focused and cohesive - -#### Dependency Inversion -- Depend on abstractions, not concrete implementations -- Use interfaces for external dependencies -- Enable easy testing and mocking - -#### Don't Repeat Yourself (DRY) -- Extract common functionality into shared utilities -- Use inheritance and composition appropriately -- Create reusable components and patterns - -#### Separation of Concerns -- Keep business logic separate from infrastructure -- Isolate data access from business rules -- Maintain clear boundaries between layers - -### Design Patterns - -#### Repository Pattern -```python -# Abstract interface -class ContactRepository: - def find_by_email(self, email: str) -> Optional[Contact]: - pass - - def save(self, contact: Contact) -> Contact: - pass - -# Concrete implementation -class DatabaseContactRepository(ContactRepository): - def find_by_email(self, email: str) -> Optional[Contact]: - # Database-specific implementation - pass -``` - -#### Service Layer Pattern -```python -class ContactService: - def __init__(self, contact_repo: ContactRepository): - self.contact_repo = contact_repo - - def create_contact(self, contact_data: dict) -> Contact: - # Business logic here - contact = Contact(**contact_data) - return self.contact_repo.save(contact) -``` - -#### Factory Pattern -```python -class ContactFactory: - @staticmethod - def create_from_opportunity(opportunity: Opportunity) -> Contact: - # Factory logic for creating contacts - pass -``` - -### Error Handling - -#### Error Strategy -- Use consistent error types and messages -- Implement proper error logging -- Provide meaningful error responses to users -- Handle both expected and unexpected errors - -#### Validation -- Validate input at API boundaries -- Use schema validation for data models -- Implement business rule validation -- Provide clear validation error messages - -## 7. Code Quality Standards - -### Code Style - -#### General Guidelines -- Use consistent indentation and formatting -- Follow language-specific style guides -- Use meaningful variable and function names -- Keep functions small and focused -- Limit function complexity - -#### Comments and Documentation -- Write self-documenting code -- Comment complex algorithms and business logic -- Document public APIs and interfaces -- Keep comments up-to-date with code changes - -### Performance Considerations - -#### Optimization Guidelines -- Profile code before optimizing -- Focus on algorithmic improvements first -- Use appropriate data structures -- Implement caching where beneficial -- Monitor performance in production - -#### Database Optimization -- Use proper indexing strategies -- Optimize query patterns -- Implement connection pooling -- Use database transactions appropriately - -### Security Standards - -#### Security Principles -- Validate all input data -- Use parameterized queries -- Implement proper authentication and authorization -- Follow the principle of least privilege -- Keep dependencies updated - -#### Data Protection -- Encrypt sensitive data at rest and in transit -- Implement proper session management -- Use secure communication protocols -- Follow data privacy regulations - -## 8. Version Control & Collaboration - -### Git Workflow - -#### Branch Strategy -- `main` - Production-ready code -- `develop` - Integration branch for features -- `feature/*` - Feature development branches -- `hotfix/*` - Critical bug fixes -- `release/*` - Release preparation branches - -#### Commit Standards -- Use conventional commit messages -- Keep commits focused and atomic -- Write descriptive commit messages -- Reference issue numbers in commits - -#### Pull Request Process -- Require code reviews for all changes -- Use automated testing and linting -- Update documentation with code changes -- Provide clear descriptions of changes - -### Code Review Guidelines - -#### Review Checklist -- [ ] Code follows project standards -- [ ] Tests are included and passing -- [ ] Documentation is updated -- [ ] No security vulnerabilities -- [ ] Performance impact considered -- [ ] Error handling is appropriate - -#### Review Process -- Review for functionality and correctness -- Check code style and formatting -- Verify test coverage -- Ensure documentation is complete -- Consider security implications - -## 9. Deployment & Operations - -### Deployment Strategy - -#### Environment Management -- Separate development, staging, and production environments -- Use environment-specific configuration -- Implement blue-green or canary deployments -- Monitor deployment health and rollback capabilities - -#### Configuration Management -- Use environment variables for configuration -- Implement configuration validation -- Use secrets management for sensitive data -- Version control configuration templates - -### Monitoring & Observability - -#### Logging Standards -- Use structured logging -- Include correlation IDs for request tracing -- Log at appropriate levels (DEBUG, INFO, WARN, ERROR) -- Implement log aggregation and analysis - -#### Metrics and Monitoring -- Monitor application health and performance -- Track business metrics and KPIs -- Implement alerting for critical issues -- Use distributed tracing for complex systems - -### Disaster Recovery - -#### Backup Strategy -- Regular automated backups -- Test backup restoration procedures -- Implement data retention policies -- Document recovery procedures - -#### High Availability -- Design for fault tolerance -- Implement health checks and circuit breakers -- Use load balancing and auto-scaling -- Plan for regional failover if applicable - -## 10. Maintenance & Evolution - -### Technical Debt Management - -#### Debt Tracking -- Identify and document technical debt -- Prioritize debt reduction based on impact -- Allocate time for debt reduction in sprints -- Monitor debt accumulation over time - -#### Refactoring Guidelines -- Refactor incrementally and safely -- Maintain test coverage during refactoring -- Document architectural decisions -- Review and update patterns regularly - -### Dependency Management - -#### Dependency Strategy -- Keep dependencies up-to-date -- Use dependency vulnerability scanning -- Minimize dependency complexity -- Document dependency decisions - -#### Version Pinning -- Pin dependency versions for stability -- Use semantic versioning -- Implement dependency update automation -- Test thoroughly before updating major versions - ---- - -## Conclusion - -These rules provide a foundation for consistent, maintainable, and scalable software development across all projects. They emphasize: - -- **Modularity** and clear separation of concerns -- **Testability** and quality assurance -- **Documentation** and knowledge sharing -- **Security** and best practices -- **Maintainability** and long-term success - -Adapt these rules to specific project needs while maintaining the core principles of clean architecture and good software engineering practices. diff --git a/prompt-results/kickstart.md b/prompt-results/kickstart.md deleted file mode 100644 index c46523e..0000000 --- a/prompt-results/kickstart.md +++ /dev/null @@ -1,424 +0,0 @@ -## Project Structure & Organization -This was generated off a python project. - -### Core Directory Layout - -``` -project-root/ -├── src/ # Source code directory -│ ├── api/ # API layer (routes, controllers, handlers) -│ ├── core/ # Core business logic and domain models -│ ├── services/ # Service layer (business logic, external integrations) -│ ├── utils/ # Shared utilities and helpers -│ └── cli/ # Command-line interface (if applicable) -├── tests/ # Test directory -│ ├── unit/ # Unit tests (mirrors src/ structure) -│ ├── integration/ # Integration tests -│ └── e2e/ # End-to-end tests (if applicable) -├── architecture/ # Architecture documentation -├── infra/ # Infrastructure configuration -│ ├── docker/ # Docker configurations -│ ├── terraform/ # Infrastructure as Code -│ ├── helm/ # Kubernetes Helm charts -│ └── k8s/ # Kubernetes manifests -├── docs/ # Project documentation -├── scripts/ # Build and deployment scripts -└── config/ # Configuration files -``` - -### Naming Conventions - -#### Files and Directories -- Use **kebab-case** for directory names: `user-service/`, `api-gateway/` -- Use **snake_case** for file names: `user_service.py`, `api_routes.rs` -- Use **PascalCase** for class names: `UserService`, `ApiController` -- Use **camelCase** for function and variable names: `getUserById`, `apiEndpoint` - -#### Module Organization -- Group related functionality in dedicated modules -- Use `__init__.py` (Python) or `mod.rs` (Rust) for module definitions -- Separate concerns: API, business logic, data access, utilities - -## Build & Development Tooling - -### Essential Build Files - -#### Makefile Structure -```makefile -.PHONY: help setup install build run tests clean package - -help: - @echo "Usage:" - @echo " make setup - Set up development environment" - @echo " make install - Install dependencies" - @echo " make build - Build project" - @echo " make run - Run application" - @echo " make tests - Run test suite" - @echo " make clean - Clean build artifacts" - -setup install: - # Language-specific setup commands - -build: - # Language-specific build commands - -run: - # Language-specific run commands - -tests: - # Language-specific test commands - -clean: - # Language-specific cleanup commands -``` - -#### Docker Configuration -- Include `Dockerfile` for containerization -- Include `docker-compose.yml` for local development -- Use multi-stage builds for production optimization -- Specify base images with explicit versions - -#### Package Management -- Use language-specific package managers (Cargo.toml, pyproject.toml, package.json) -- Pin dependency versions for reproducible builds -- Include development dependencies separately - -### Development Environment - -#### Local Development Setup -- Provide clear setup instructions in README.md -- Include `.env.example` with required environment variables -- Use virtual environments or language-specific isolation tools -- Provide development database setup scripts - -#### CI/CD Pipeline Structure -```yaml -# .github/workflows/ci.yml -name: CI/CD Pipeline - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Setup environment - - name: Run tests - - name: Build artifact - - name: Deploy (if applicable) -``` - -## Documentation & Metadata - -### Required Documentation Files - -#### README.md Structure -```markdown -# Project Name - -Brief description of the project. - -## Features -- Key feature 1 -- Key feature 2 - -## Quick Start -```bash -# Installation commands -# Setup commands -# Run commands -``` - -## Development -- Setup instructions -- Testing instructions -- Deployment instructions - -## Architecture -Link to architecture documentation -``` - -#### Architecture Directory Structure -``` -architecture/ -├── README.md # Architecture overview -├── diagrams/ # Architecture diagrams -│ ├── system-overview.md # System architecture -│ ├── data-flow.md # Data flow diagrams -│ └── deployment.md # Deployment architecture -├── decisions/ # Architecture Decision Records (ADRs) -│ ├── 001-database-choice.md -│ └── 002-api-design.md -└── specs/ # Technical specifications - ├── api-spec.md # API specifications - └── data-models.md # Data model definitions -``` - -### Architecture Documentation Template - -#### System Overview Diagram -```mermaid -graph TB - Client[Client Application] --> API[API Gateway] - API --> Service1[Service 1] - API --> Service2[Service 2] - Service1 --> Database[(Database)] - Service2 --> Database -``` - -#### API Specification Template -```markdown -# API Specification - -## Endpoints - -### GET /api/v1/resource -**Description:** Retrieve resource information - -**Parameters:** -- `id` (string, required): Resource identifier - -**Response:** -```json -{ - "id": "string", - "name": "string", - "created_at": "datetime" -} -``` - -**Error Responses:** -- 404: Resource not found -- 500: Internal server error -``` - -## Testing Strategy - -### Test Organization - -#### Unit Tests -- Mirror the source code structure -- Test individual functions and classes -- Use descriptive test names: `test_user_creation_success()`, `test_invalid_email_rejection()` -- Mock external dependencies - -#### Integration Tests -- Test component interactions -- Use test databases and external services -- Focus on API endpoints and service boundaries -- Test error scenarios and edge cases - -#### End-to-End Tests -- Test complete user workflows -- Use real or mocked external services -- Focus on critical business paths -- Run in CI/CD pipeline - -### Test File Naming -- Unit tests: `test_.py` or `test_.rs` -- Integration tests: `test__integration.py` -- E2E tests: `test__e2e.py` - -### Test Structure -```python -# Example test structure -def test_user_service_creation(): - # Arrange - user_data = {"name": "John", "email": "john@example.com"} - - # Act - result = user_service.create_user(user_data) - - # Assert - assert result.name == "John" - assert result.email == "john@example.com" -``` - -## Design Principles - -### Architectural Patterns - -#### Layered Architecture -1. **Presentation Layer** (API/Controllers) - - Handle HTTP requests/responses - - Input validation and serialization - - Authentication and authorization - -2. **Business Logic Layer** (Services) - - Core business rules and workflows - - Orchestration of domain operations - - Transaction management - -3. **Data Access Layer** (Repositories/DAOs) - - Database operations - - External service integrations - - Caching strategies - -4. **Domain Layer** (Models/Entities) - - Business entities and value objects - - Domain logic and constraints - - Business rules and invariants - -#### Separation of Concerns -- Each module has a single responsibility -- Dependencies flow inward (Domain → Services → API) -- External dependencies are abstracted through interfaces -- Configuration is externalized and environment-specific - -### Code Organization Principles - -#### Module Structure -``` -src/ -├── api/ # HTTP layer -│ ├── routes.py # Route definitions -│ ├── controllers.py # Request handlers -│ └── middleware.py # Request/response middleware -├── core/ # Business logic -│ ├── services.py # Business services -│ ├── models.py # Domain models -│ └── exceptions.py # Custom exceptions -├── data/ # Data access -│ ├── repositories.py # Data access objects -│ ├── models.py # Data models -│ └── migrations.py # Database migrations -└── utils/ # Shared utilities - ├── config.py # Configuration management - ├── logger.py # Logging utilities - └── validators.py # Input validation -``` - -#### Dependency Injection -- Use dependency injection for loose coupling -- Inject dependencies through constructors -- Use interfaces for external dependencies -- Configure dependencies at application startup - -### Error Handling Strategy - -#### Error Types -1. **Domain Errors**: Business rule violations -2. **Infrastructure Errors**: Database, network, external service failures -3. **Validation Errors**: Input validation failures -4. **Authentication Errors**: Authorization and authentication failures - -#### Error Response Format -```json -{ - "error": { - "code": "VALIDATION_ERROR", - "message": "Invalid input provided", - "details": { - "field": "email", - "reason": "Invalid email format" - } - } -} -``` - -## Infrastructure & Deployment - -### Container Strategy -- Use multi-stage Docker builds -- Optimize for production and development -- Include health checks and graceful shutdown -- Use non-root users for security - -### Configuration Management -- Use environment variables for configuration -- Provide `.env.example` with all required variables -- Use configuration validation at startup -- Support different environments (dev, staging, prod) - -### Monitoring & Observability -- Include health check endpoints -- Implement structured logging -- Add metrics collection points -- Include distributed tracing support - -## Security Guidelines - -### Authentication & Authorization -- Implement proper authentication mechanisms -- Use role-based access control (RBAC) -- Validate and sanitize all inputs -- Implement rate limiting and throttling - -### Data Protection -- Encrypt sensitive data at rest and in transit -- Use secure communication protocols (HTTPS, TLS) -- Implement proper session management -- Follow principle of least privilege - -## Performance & Scalability - -### Performance Considerations -- Implement caching strategies where appropriate -- Use database connection pooling -- Optimize database queries -- Implement pagination for large datasets - -### Scalability Patterns -- Design for horizontal scaling -- Use stateless application design -- Implement proper session management -- Consider microservices architecture for large applications - -## Code Quality Standards - -### Code Style -- Follow language-specific style guides -- Use consistent formatting and indentation -- Write self-documenting code with clear variable names -- Keep functions and classes focused and small - -### Documentation -- Document public APIs and interfaces -- Include code examples in documentation -- Maintain up-to-date architecture diagrams -- Write clear commit messages - -### Code Review Guidelines -- Review for security vulnerabilities -- Check for performance implications -- Ensure proper error handling -- Validate test coverage - -## Version Control & Collaboration - -### Git Workflow -- Use feature branches for development -- Write descriptive commit messages -- Use conventional commit format -- Maintain clean git history - -### Branch Naming -- `feature/feature-name` for new features -- `bugfix/issue-description` for bug fixes -- `hotfix/critical-fix` for urgent fixes -- `release/version-number` for releases - -### Pull Request Guidelines -- Include clear description of changes -- Add tests for new functionality -- Update documentation as needed -- Request reviews from appropriate team members - -## Continuous Improvement - -### Metrics & Monitoring -- Track code quality metrics -- Monitor application performance -- Measure user experience metrics -- Regular security assessments - -### Regular Reviews -- Architecture review sessions -- Code quality assessments -- Performance optimization reviews -- Security vulnerability scans - ---- - -*This document serves as a living guide that should be updated as the project evolves and new patterns emerge.* diff --git a/prompt-results/otter-log-dashboard.md b/prompt-results/otter-log-dashboard.md deleted file mode 100644 index 5a600e6..0000000 --- a/prompt-results/otter-log-dashboard.md +++ /dev/null @@ -1,776 +0,0 @@ -# Cursor Rules - Language-Agnostic Project Standards - -## Table of Contents -1. [Project Structure](#project-structure) -2. [Naming Conventions](#naming-conventions) -3. [Build & Development Tooling](#build--development-tooling) -4. [Documentation Standards](#documentation-standards) -5. [Testing Strategy](#testing-strategy) -6. [Design Principles](#design-principles) -7. [Code Organization](#code-organization) -8. [API Design Patterns](#api-design-patterns) -9. [State Management](#state-management) -10. [Error Handling](#error-handling) -11. [Security Considerations](#security-considerations) -12. [Performance Guidelines](#performance-guidelines) - -## Project Structure - -### Core Directory Layout -``` -project-root/ -├── src/ # Source code -│ ├── api/ # API layer and external integrations -│ ├── components/ # Reusable UI components -│ │ ├── ui/ # Base UI components (buttons, inputs, etc.) -│ │ ├── layout/ # Layout components (headers, sidebars, etc.) -│ │ └── [domain]/ # Domain-specific components -│ ├── contexts/ # Global state management -│ ├── hooks/ # Custom hooks and business logic -│ ├── pages/ # Page-level components -│ │ ├── [domain]/ # Domain-specific pages -│ │ └── admin/ # Administrative pages -│ ├── types/ # Type definitions and interfaces -│ ├── utils/ # Utility functions and helpers -│ └── lib/ # Third-party library configurations -├── tests/ # Test files mirroring src structure -│ ├── api/ # API tests -│ ├── components/ # Component tests -│ ├── hooks/ # Hook tests -│ ├── pages/ # Page tests -│ ├── contexts/ # Context tests -│ ├── utils/ # Utility tests -│ └── mocks/ # Mock data and handlers -├── docker/ # Containerization files -├── public/ # Static assets -├── docs/ # Documentation -│ └── architecture/ # Architecture diagrams and specs -└── scripts/ # Build and deployment scripts -``` - -### Required Root Files -- `README.md` - Project overview and setup instructions -- `Makefile` - Build automation and common tasks -- `.gitignore` - Version control exclusions -- `package.json` / `requirements.txt` / `Cargo.toml` - Dependencies -- `Dockerfile` - Container definition -- `docker-compose.yml` (optional) - Multi-service setup - -## Naming Conventions - -### File Naming -- **Components**: PascalCase (e.g., `UserProfile.tsx`, `BusinessUnitList.tsx`) -- **Hooks**: camelCase with `use` prefix (e.g., `useNetworkStatus.ts`, `useAuth.ts`) -- **Utilities**: camelCase (e.g., `apiClient.ts`, `userUtils.ts`) -- **Types/Interfaces**: PascalCase (e.g., `User.ts`, `ApiResponse.ts`) -- **Constants**: UPPER_SNAKE_CASE (e.g., `API_ENDPOINTS.ts`, `STORAGE_KEYS.ts`) - -### Directory Naming -- **Feature directories**: kebab-case (e.g., `business-units/`, `user-management/`) -- **Generic directories**: lowercase (e.g., `api/`, `utils/`, `hooks/`) -- **Domain directories**: lowercase (e.g., `admin/`, `dashboard/`) - -### Code Naming -- **Variables**: camelCase -- **Functions**: camelCase -- **Classes**: PascalCase -- **Interfaces**: PascalCase with descriptive names -- **Enums**: PascalCase -- **Constants**: UPPER_SNAKE_CASE - -## Build & Development Tooling - -### Makefile Structure -```makefile -# Project variables -APP_NAME = [project-name] -DOCKER_IMAGE = $(APP_NAME):latest - -# Development commands -.PHONY: install -install: - [package-manager] install - -.PHONY: dev -dev: - [package-manager] run dev - -.PHONY: build -build: - [package-manager] run build - -# Docker commands -.PHONY: docker-build -docker-build: - docker build -t $(DOCKER_IMAGE) -f docker/Dockerfile . - -.PHONY: docker-run -docker-run: - docker run -p [port]:[port] $(DOCKER_IMAGE) - -.PHONY: docker-stop -docker-stop: - docker stop $$(docker ps -q --filter ancestor=$(DOCKER_IMAGE)) 2>/dev/null || true - -.PHONY: docker-clean -docker-clean: - docker rmi $(DOCKER_IMAGE) 2>/dev/null || true - -# Testing commands -.PHONY: test -test: - [package-manager] run test - -.PHONY: test:watch -test:watch: - [package-manager] run test:watch - -.PHONY: test:coverage -test:coverage: - [package-manager] run test:coverage - -# Help -.PHONY: help -help: - @echo "Available commands:" - @echo " install - Install dependencies" - @echo " dev - Start development server" - @echo " build - Build for production" - @echo " test - Run tests" - @echo " docker-build - Build Docker image" - @echo " docker-run - Run Docker container" - @echo " help - Show this help message" - -.DEFAULT_GOAL := help -``` - -### Docker Configuration -```dockerfile -# Multi-stage build for production -FROM [base-image] AS builder - -WORKDIR /app - -# Copy dependency files -COPY [dependency-files] ./ - -# Install dependencies -RUN [install-command] - -# Copy source code -COPY . . - -# Build application -RUN [build-command] - -# Production stage -FROM [production-base] AS production - -WORKDIR /app - -# Copy built application -COPY --from=builder /app/[build-output] ./ - -# Expose port -EXPOSE [port] - -# Start application -CMD ["[start-command]"] -``` - -## Documentation Standards - -### README.md Structure -```markdown -# Project Name - -Brief description of the project and its purpose. - -## Quick Start - -```bash -# Install dependencies -make install - -# Start development server -make dev - -# Build for production -make build -``` - -## Project Structure - -Brief overview of key directories and their purposes. - -## Development - -### Prerequisites -- Runtime requirements -- Development tools -- Environment setup - -### Environment Variables -| Variable | Description | Default | -|----------|-------------|---------| -| `API_URL` | Backend API endpoint | `http://localhost:3000` | -| `ENABLE_OFFLINE_MODE` | Enable offline functionality | `false` | - -### Available Scripts -- `make dev` - Start development server -- `make build` - Build for production -- `make test` - Run test suite -- `make docker-build` - Build Docker image - -## Testing - -### Running Tests -```bash -# Run all tests -make test - -# Run tests in watch mode -make test:watch - -# Run tests with coverage -make test:coverage -``` - -## Deployment - -### Docker Deployment -```bash -# Build image -make docker-build - -# Run container -make docker-run -``` - -## Contributing - -Guidelines for contributing to the project. - -## License - -Project license information. -``` - -### Architecture Documentation -Create an `architecture/` directory with: -- `README.md` - Architecture overview -- `system-design.md` - System design document -- `api-specs.md` - API specifications -- `database-schema.md` - Database design -- `deployment.md` - Deployment architecture -- `diagrams/` - Architecture diagrams (Mermaid, PlantUML, etc.) - -## Testing Strategy - -### Test Structure -``` -tests/ -├── README.md # Testing documentation -├── setupTests.[ext] # Global test setup -├── [test-config].[ext] # Test framework configuration -├── utils/ -│ └── test-utils.[ext] # Common test utilities -├── components/ # Mirror src/components structure -├── pages/ # Mirror src/pages structure -├── hooks/ # Mirror src/hooks structure -├── api/ # Mirror src/api structure -├── contexts/ # Mirror src/contexts structure -└── mocks/ # Mock data and handlers -``` - -### Test Categories -1. **Unit Tests**: Individual functions, components, and utilities -2. **Integration Tests**: Component interactions and API integration -3. **End-to-End Tests**: Complete user workflows -4. **Visual Regression Tests**: UI consistency checks - -### Testing Patterns -```typescript -// Component Testing Pattern -describe('[ComponentName]', () => { - it('renders with default props', () => { - // Arrange - // Act - // Assert - }); - - it('handles user interactions', () => { - // Test user interactions - }); - - it('displays loading states', () => { - // Test loading states - }); - - it('handles error states', () => { - // Test error handling - }); -}); - -// Hook Testing Pattern -describe('use[HookName]', () => { - it('returns expected initial state', () => { - // Test initial state - }); - - it('updates state correctly', () => { - // Test state updates - }); - - it('handles errors gracefully', () => { - // Test error handling - }); -}); - -// API Testing Pattern -describe('[ServiceName]', () => { - it('successfully performs [operation]', async () => { - // Test successful operations - }); - - it('handles API errors', async () => { - // Test error scenarios - }); - - it('handles network failures', async () => { - // Test network issues - }); -}); -``` - -### Mocking Strategy -- **Global Mocks**: Browser APIs, storage, network -- **Component Mocks**: External dependencies, context providers -- **API Mocks**: HTTP responses, error scenarios -- **Data Mocks**: Test data factories and fixtures - -## Design Principles - -### Separation of Concerns -- **Presentation Layer**: UI components and styling -- **Business Logic Layer**: Custom hooks and services -- **Data Layer**: API clients and data management -- **State Management**: Context providers and state logic - -### Single Responsibility Principle -- Each component should have one clear purpose -- Functions should perform a single operation -- Classes should represent one concept -- Modules should serve one domain - -### Dependency Inversion -- Depend on abstractions, not concrete implementations -- Use interfaces for external dependencies -- Mock external services for testing -- Inject dependencies where possible - -### Composition over Inheritance -- Prefer composition for code reuse -- Use higher-order components for shared behavior -- Create utility functions for common operations -- Build complex components from simple ones - -## Code Organization - -### Component Structure -```typescript -// 1. Imports (external libraries first, then internal) -import React from 'react'; -import { externalLibrary } from 'external-package'; -import { internalComponent } from '@/components/internal'; - -// 2. Type definitions -interface ComponentProps { - // Props definition -} - -// 3. Component definition -export const ComponentName: React.FC = ({ prop1, prop2 }) => { - // 4. Hooks and state - const [state, setState] = useState(initialValue); - const customHook = useCustomHook(); - - // 5. Event handlers - const handleEvent = () => { - // Event logic - }; - - // 6. Side effects - useEffect(() => { - // Side effect logic - }, [dependencies]); - - // 7. Render logic - return ( -
- {/* JSX */} -
- ); -}; -``` - -### Hook Structure -```typescript -// 1. Imports -import { useState, useEffect } from 'react'; - -// 2. Type definitions -interface HookReturn { - // Return type definition -} - -// 3. Hook implementation -export function useHookName(dependencies): HookReturn { - // 4. State management - const [state, setState] = useState(initialValue); - - // 5. Side effects - useEffect(() => { - // Effect logic - }, [dependencies]); - - // 6. Event handlers - const handleAction = () => { - // Action logic - }; - - // 7. Return values - return { - state, - handleAction, - }; -} -``` - -### Service Structure -```typescript -// 1. Imports -import { apiClient } from './apiClient'; - -// 2. Type definitions -interface ServiceRequest { - // Request type -} - -interface ServiceResponse { - // Response type -} - -// 3. Service implementation -export class ServiceName { - static async performAction(data: ServiceRequest): Promise { - try { - const response = await apiClient.post('/endpoint', data); - return response.data; - } catch (error) { - throw new ServiceError('Operation failed', error); - } - } -} -``` - -## API Design Patterns - -### Client-Side API Layer -```typescript -// Base API client -export class ApiClient { - private baseURL: string; - private timeout: number; - - constructor(config: ApiConfig) { - this.baseURL = config.baseURL; - this.timeout = config.timeout || 10000; - } - - async request(options: RequestOptions): Promise { - // Request implementation with error handling - } -} - -// Domain-specific API services -export class UserService { - static async getUsers(): Promise { - // Implementation - } - - static async createUser(data: CreateUserRequest): Promise { - // Implementation - } -} -``` - -### Error Handling Pattern -```typescript -export class ApiError extends Error { - constructor( - message: string, - public status?: number, - public data?: unknown, - public isOffline: boolean = false - ) { - super(message); - this.name = 'ApiError'; - } -} - -// Usage in services -try { - const response = await apiClient.get('/endpoint'); - return response.data; -} catch (error) { - if (error instanceof ApiError) { - // Handle API-specific errors - } else { - // Handle unexpected errors - } -} -``` - -### Request/Response Patterns -```typescript -// Standard request/response interfaces -interface ApiRequest { - data?: T; - params?: Record; -} - -interface ApiResponse { - data: T; - message?: string; - status: number; -} - -interface PaginatedResponse { - items: T[]; - total: number; - page: number; - limit: number; -} -``` - -## State Management - -### Context Pattern -```typescript -// Context definition -interface AppContextType { - state: AppState; - actions: AppActions; -} - -const AppContext = createContext(undefined); - -// Provider implementation -export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const [state, setState] = useState(initialState); - - const actions = { - updateState: (updates: Partial) => { - setState(prev => ({ ...prev, ...updates })); - }, - // Other actions - }; - - return ( - - {children} - - ); -}; - -// Hook for consuming context -export const useApp = () => { - const context = useContext(AppContext); - if (!context) { - throw new Error('useApp must be used within AppProvider'); - } - return context; -}; -``` - -### State Organization -- **Global State**: User authentication, app configuration -- **Domain State**: Business logic state (users, projects, etc.) -- **UI State**: Component-specific state (modals, forms, etc.) -- **Cache State**: API response caching and synchronization - -## Error Handling - -### Error Types -```typescript -// Base error class -export class AppError extends Error { - constructor( - message: string, - public code: string, - public statusCode?: number - ) { - super(message); - this.name = 'AppError'; - } -} - -// Specific error types -export class ValidationError extends AppError { - constructor(message: string, public field?: string) { - super(message, 'VALIDATION_ERROR'); - } -} - -export class NetworkError extends AppError { - constructor(message: string) { - super(message, 'NETWORK_ERROR'); - } -} -``` - -### Error Handling Strategy -1. **Prevention**: Input validation, type checking -2. **Detection**: Try-catch blocks, error boundaries -3. **Recovery**: Retry mechanisms, fallback states -4. **Reporting**: Error logging, user feedback - -### Error Boundaries -```typescript -export class ErrorBoundary extends Component { - constructor(props: Props) { - super(props); - this.state = { hasError: false, error: undefined }; - } - - static getDerivedStateFromError(error: Error): State { - return { hasError: true, error }; - } - - componentDidCatch(error: Error, errorInfo: ErrorInfo) { - // Log error to monitoring service - console.error('Error caught by boundary:', error, errorInfo); - } - - render() { - if (this.state.hasError) { - return this.props.fallback || ; - } - - return this.props.children; - } -} -``` - -## Security Considerations - -### Authentication & Authorization -- Implement proper token management -- Use secure storage for sensitive data -- Validate user permissions on both client and server -- Implement session timeout and refresh mechanisms - -### Input Validation -- Validate all user inputs -- Sanitize data before processing -- Use type-safe interfaces for data structures -- Implement CSRF protection where applicable - -### Data Protection -- Encrypt sensitive data in transit and at rest -- Implement proper CORS policies -- Use HTTPS for all communications -- Follow OWASP security guidelines - -## Performance Guidelines - -### Code Splitting -- Implement lazy loading for routes -- Split large components into smaller chunks -- Use dynamic imports for heavy dependencies -- Optimize bundle size with tree shaking - -### Caching Strategy -- Cache API responses appropriately -- Implement memoization for expensive calculations -- Use React.memo for component optimization -- Implement proper cache invalidation - -### Monitoring & Metrics -- Track application performance metrics -- Monitor API response times -- Implement error tracking and reporting -- Use performance profiling tools - -### Optimization Techniques -- Minimize re-renders with proper dependency arrays -- Use virtual scrolling for large lists -- Implement debouncing for user inputs -- Optimize images and assets - -## Environment Configuration - -### Environment Variables -```bash -# Development -NODE_ENV=development -API_URL=http://localhost:3000 -ENABLE_OFFLINE_MODE=false - -# Production -NODE_ENV=production -API_URL=https://api.example.com -ENABLE_OFFLINE_MODE=false -``` - -### Configuration Management -- Use environment-specific configuration files -- Validate required environment variables -- Provide sensible defaults for optional variables -- Document all configuration options - -## Deployment Guidelines - -### Containerization -- Use multi-stage builds for production -- Minimize container image size -- Implement health checks -- Use non-root users in containers - -### CI/CD Pipeline -- Automated testing on every commit -- Code quality checks (linting, formatting) -- Security scanning -- Automated deployment to staging/production - -### Monitoring & Logging -- Implement structured logging -- Set up application monitoring -- Configure error alerting -- Track performance metrics - ---- - -## Implementation Notes - -### Language-Specific Adaptations -- **TypeScript**: Use strict type checking and interfaces -- **JavaScript**: Implement JSDoc for type documentation -- **Python**: Use type hints and dataclasses -- **Rust**: Leverage strong type system and error handling -- **Go**: Use interfaces and structured error handling - -### Framework Considerations -- **React**: Follow hooks-first approach and functional components -- **Vue**: Use composition API and proper component structure -- **Angular**: Follow dependency injection and module patterns -- **Svelte**: Leverage reactive statements and stores - -### Testing Framework Adaptations -- **Jest/Vitest**: Use describe/it blocks and proper mocking -- **PyTest**: Use fixtures and parametrized tests -- **Rust**: Use #[cfg(test)] and proper test organization -- **Go**: Use table-driven tests and proper test naming - -This document serves as a comprehensive guide for maintaining consistency across all projects, regardless of the technology stack used. diff --git a/prompt-results/otter-log.md b/prompt-results/otter-log.md deleted file mode 100644 index 000f090..0000000 --- a/prompt-results/otter-log.md +++ /dev/null @@ -1,437 +0,0 @@ -# Cursor Rules - Language-Agnostic Project Standards - -## Overview - -This document defines the architectural patterns, conventions, and best practices for all projects based on the analysis of the otter-log repository. These rules are designed to be language-agnostic and focus on structural organization, design principles, and development workflows. This document was generated off a project in rust. - -## 1. Project Structure & Modularity - -### Core Directory Layout - -``` -project-root/ -├── src/ # Main source code -│ ├── api/ # Business logic layer (services) -│ ├── model/ # Data models and persistence -│ ├── routes/ # HTTP request handlers -│ ├── middleware/ # Cross-cutting concerns -│ ├── utils/ # Shared utilities -│ ├── config/ # Configuration management -│ └── main.rs # Application entry point -├── tests/ # Integration tests -├── migrations/ # Database schema migrations -├── docker/ # Container configuration -├── k8s/ # Kubernetes manifests -├── scripts/ # Build and deployment scripts -├── docs/ # Documentation -├── architecture/ # System design documents -└── .github/ # CI/CD workflows -``` - -### Naming Conventions - -- **Directories**: Use snake_case for directory names -- **Files**: Use snake_case for file names -- **Modules**: Use snake_case for module names -- **Classes/Types**: Use PascalCase for type definitions -- **Functions/Methods**: Use snake_case for function names -- **Constants**: Use SCREAMING_SNAKE_CASE for constants -- **Variables**: Use snake_case for variables - -### Module Organization - -Each domain should follow this structure: -``` -domain/ -├── mod.rs # Module exports -├── model.rs # Data structures -├── dao.rs # Data access objects -├── service.rs # Business logic -├── error.rs # Error definitions -├── response.rs # API response types -└── mock_dao.rs # Test doubles -``` - -## 2. Architectural Layers - -### Layered Architecture Pattern - -1. **Presentation Layer** (`routes/`) - - HTTP request/response handling - - Input validation - - Response formatting - - Route definitions - -2. **Business Logic Layer** (`api/`) - - Service implementations - - Business rules - - Orchestration logic - - Transaction management - -3. **Data Access Layer** (`model/`) - - Data Access Objects (DAOs) - - Repository implementations - - Database interactions - - Caching logic - -4. **Domain Layer** (`model/`) - - Entity definitions - - Value objects - - Domain services - - Business invariants - -### Cross-Cutting Concerns (`middleware/`) - -- Authentication & Authorization -- Logging & Monitoring -- Error handling -- Request/Response transformation -- Rate limiting -- CORS handling - -## 3. Design Principles - -### Separation of Concerns - -- **Single Responsibility**: Each module/class has one reason to change -- **Dependency Inversion**: High-level modules don't depend on low-level modules -- **Interface Segregation**: Clients depend only on interfaces they use -- **Open/Closed**: Open for extension, closed for modification - -### Data Flow Patterns - -1. **Request Flow**: `Route → Service → Repository → Database` -2. **Response Flow**: `Database → Repository → Service → Route` -3. **Error Flow**: `Error → Service → Route → Client` - -### Abstraction Layers - -``` -┌─────────────────────────────────────┐ -│ Presentation │ ← Routes, Controllers -├─────────────────────────────────────┤ -│ Business Logic │ ← Services, Use Cases -├─────────────────────────────────────┤ -│ Data Access │ ← Repositories, DAOs -├─────────────────────────────────────┤ -│ Infrastructure │ ← Database, External APIs -└─────────────────────────────────────┘ -``` - -## 4. Error Handling Strategy - -### Error Hierarchy - -``` -BaseError -├── ValidationError -├── AuthenticationError -├── AuthorizationError -├── NotFoundError -├── DatabaseError -└── InternalError -``` - -### Error Response Format - -```json -{ - "error": { - "type": "error_type", - "message": "Human-readable message", - "code": "ERROR_CODE", - "details": {}, - "timestamp": "2024-01-01T00:00:00Z" - } -} -``` - -### Error Handling Rules - -- Always return structured error responses -- Log errors with appropriate severity levels -- Don't expose internal implementation details -- Provide meaningful error messages -- Include error codes for programmatic handling - -## 5. Testing Strategy - -### Test Organization - -``` -tests/ -├── unit/ # Unit tests -├── integration/ # Integration tests -├── e2e/ # End-to-end tests -└── fixtures/ # Test data -``` - -### Test Naming Conventions - -- **Unit Tests**: `test__` -- **Integration Tests**: `test__` -- **Test Files**: `_test` or `test_` - -### Test Structure - -### Mocking Strategy - -- Create mock implementations for external dependencies -- Use trait-based abstractions for testability -- Implement mock DAOs for database testing -- Use dependency injection for service testing - -## 6. Configuration Management - -### Configuration Structure - -```rust -pub struct Config { - pub database_url: String, - pub jwt_secret: String, - pub port: u16, - pub environment: String, -} - -impl Config { - pub fn from_env() -> Self { - // Load from environment variables - } -} -``` - -## 7. Database Design - -### Database Patterns - -- Use connection pooling -- Implement proper indexing -- Handle database errors gracefully -- Use transactions for multi-step operations - -## 8. API Design - -### RESTful Conventions - -- Use HTTP methods appropriately (GET, POST, PUT, DELETE) -- Return appropriate HTTP status codes -- Use consistent URL patterns -- Implement proper pagination - -### API Response Format - -```json -{ - "data": {}, - "meta": { - "pagination": {}, - "timestamp": "2024-01-01T00:00:00Z" - } -} -``` - -### Authentication - -- Use JWT tokens for stateless authentication -- Implement proper token validation -- Include token expiration -- Support refresh tokens -## 10. Build & Deployment - -### Makefile Structure - -```makefile -# Development -dev-setup: ## Setup development environment -build: ## Build the application -test: ## Run all tests -fmt: ## Format code -lint: ## Run linter - -# Database -db-create: ## Create database -db-migrate: ## Run migrations -db-reset: ## Reset database - -# Docker -docker-build: ## Build Docker image -docker-run: ## Run Docker container -docker-push: ## Push to registry -``` - -## 11. Documentation Standards - -### README Structure - -```markdown -# Project Name - -Brief description of the project. - -## Features - -- Key feature 1 -- Key feature 2 - -## Quick Start - -Installation and setup instructions. - -## API Documentation - -Link to API docs. - -## Development - -Development setup and guidelines. - -## Deployment - -Deployment instructions. -``` - -### Architecture Documentation - -``` -architecture/ -├── README.md # Architecture overview -├── diagrams/ # System diagrams -│ ├── system-overview.md -│ ├── data-flow.md -│ └── deployment.md -├── decisions/ # Architecture decision records -└── specs/ # Technical specifications -``` - -### API Documentation - -- Use OpenAPI/Swagger for API documentation -- Include request/response examples -- Document error codes -- Provide authentication details - -## 12. Development Workflow - -### Git Workflow - -- Use feature branches -- Require pull request reviews -- Run automated tests on PR -- Use conventional commit messages - -### Code Quality - -- Run linters and formatters -- Enforce code style guidelines -- Use static analysis tools -- Maintain test coverage - -### CI/CD Pipeline - -```yaml -name: CI/CD Pipeline - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Run tests - run: make test - - name: Run linter - run: make lint -``` - -## 13. Monitoring & Observability - -### Logging Strategy - -- Use structured logging -- Include correlation IDs -- Log at appropriate levels -- Include context information - -### Metrics - -- Application metrics -- Business metrics -- Infrastructure metrics -- Custom dashboards - -### Health Checks - -- Database connectivity -- External service health -- Application readiness -- Custom health indicators - -## 14. Performance Considerations - -### Caching Strategy - -- Application-level caching -- Database query caching -- CDN for static assets -- Cache invalidation strategies - -### Database Optimization - -- Proper indexing -- Query optimization -- Connection pooling -- Read replicas - -### Scalability Patterns - -- Horizontal scaling -- Load balancing -- Microservices architecture -- Event-driven patterns - -## 15. Maintenance & Operations - -### Backup Strategy - -- Database backups -- Configuration backups -- Disaster recovery plans -- Backup testing - -### Monitoring - -- Application monitoring -- Infrastructure monitoring -- Alert configuration -- Incident response - -### Updates & Maintenance - -- Dependency updates -- Security patches -- Feature deprecation -- Version management - ---- - -## Implementation Guidelines - -1. **Start with the structure**: Always begin by setting up the directory structure -2. **Define interfaces first**: Create trait/interface definitions before implementations -3. **Write tests early**: Implement tests alongside features -4. **Document as you go**: Keep documentation current with code changes -5. **Follow the patterns**: Stick to established patterns for consistency -6. **Review regularly**: Periodically review and update these rules - -## Language-Specific Adaptations - -While these rules are language-agnostic, adapt them to your specific language: - -- **Rust**: Use traits instead of interfaces, implement proper error handling -- **Python**: Use abstract base classes, implement type hints -- **TypeScript**: Use interfaces and types, implement proper error handling -- **Go**: Use interfaces, implement proper error handling with custom types - -Remember: The goal is maintainable, testable, and scalable code that follows consistent patterns across the entire project. - diff --git a/prompts/cursor_generator.md b/prompts/cursor_generator.md deleted file mode 100644 index 88e867b..0000000 --- a/prompts/cursor_generator.md +++ /dev/null @@ -1,48 +0,0 @@ -# Prompt: Generate Language-Agnostic Cursor Rules from GitHub Project - -## Task - -Analyze the structure, patterns, and conventions used in the following GitHub repository: -`https://github.com//` - -## Goal - -Generate a **language-agnostic `CURSOR_RULES.md`** file that defines best practices, conventions, and expected structure for all future projects based on this example. - -## Requirements - -### 1. Modularity & Structure - -* Identify and formalize the directory layout (e.g., `src/`, `tests/`, `api/`, `model/`, etc.). -* Define naming conventions for files, modules, and interfaces. - -### 2. Build & Dev Tooling - -* Extract and generalize Makefile targets, scripts, or dev tools used. -* Specify expectations for Docker/Kubernetes files, local development setup, and CI/CD scripts. - -### 3. Documentation & Metadata - -* Describe required documentation files such as `README.md` and an `architecture/` directory. -* Include a template or expected contents for the `architecture/` folder (e.g., flowcharts, mermaid diagrams, spec docs). - -### 4. Testing Strategy - -* Define structure and naming conventions for test files. -* Capture any patterns in unit vs. integration testing organization. - -### 5. Design Principles - -* Identify architectural or engineering principles in use (e.g., separation of concerns, single-responsibility). -* Outline abstraction patterns (DAO, repository, service layer, etc.) and layering guidelines. - -### 6. Language-Agnostic Output - -* Avoid tying rules to specific languages (like Rust, Python, TypeScript) unless absolutely necessary. -* Prefer role-based descriptions (e.g., "data model definition", "business logic layer") over language-specific implementation details. - -## Format - -* Output should be in **Markdown**. -* Use clear headings and bullet points. - diff --git a/prompts/md-file-aggregator.md b/prompts/md-file-aggregator.md deleted file mode 100644 index 09a9f95..0000000 --- a/prompts/md-file-aggregator.md +++ /dev/null @@ -1,39 +0,0 @@ -Prompt: Synthesize Global Architecture Rules from Cursor-Generated Files - -Task - -Take N Cursor-generated CURSOR_RULES.md files (or similar project rules files) that were generated from different language-specific projects and extract the universal, language-agnostic principles they share about how to structure a high-quality software project. - -Input - -N markdown files, each containing project conventions for a specific codebase. - -Goal - -Produce a single summary file that distills the core architectural patterns, project structure conventions, and engineering principles found across the different languages and repositories. - -Requirements - -1. Abstract Over Language - -Focus on intent and design principles rather than syntax or language-specific idioms. - -2. Identify Convergent Patterns Without Preset Assumptions - -Carefully analyze each file on its own terms. Do not assume any fixed directory layout, naming convention, or modular structure.Instead, surface the organic overlaps and recurring themes in how these projects are structured and described—whether in how they organize source files, define responsibilities, manage dependencies, or encapsulate logic. - -3. Normalize Testing Strategy - -Identify shared principles in how testing is approached: test organization, naming conventions, test types, and what testing is expected to cover. - -4. Summarize Core Engineering Beliefs - -Abstract the shared philosophy across projects, including patterns of modularity, encapsulation, dependency management, and clarity of responsibilities. Include any implicit or explicit principles related to maintainability, scale, or team practices. - -5. Output Format - -Markdown with clear headings and bullet points - -Prioritize clarity, conciseness, and general applicability - -Avoid repeating language-specific patterns unless they clarify a higher-order principle diff --git a/scripts/check-editor-parity.sh b/scripts/check-editor-parity.sh new file mode 100755 index 0000000..8e75bcc --- /dev/null +++ b/scripts/check-editor-parity.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +FIXTURE="$ROOT_DIR/scripts/editor-parity.vim" + +run() { + printf '==> %s\n' "$*" + "$@" +} + +require() { + local command_name="$1" + if ! command -v "$command_name" >/dev/null 2>&1; then + printf 'Missing required command: %s\n' "$command_name" >&2 + exit 1 + fi +} + +require vim +require nvim + +if [[ ! -r "$HOME/.vim/vimrc" ]]; then + printf 'Missing %s/.vim/vimrc. Run ./install.sh --no-packages first.\n' "$HOME" >&2 + exit 1 +fi + +if [[ ! -r "$HOME/.config/nvim/init.vim" ]]; then + printf 'Missing %s/.config/nvim/init.vim. Run ./install.sh --no-packages first.\n' "$HOME" >&2 + exit 1 +fi + +if [[ ! -r "$HOME/.config/nvim/coc-settings.json" ]]; then + printf 'Missing %s/.config/nvim/coc-settings.json. Run ./install.sh --no-packages first.\n' "$HOME" >&2 + exit 1 +fi + +run vim -Nu "$HOME/.vim/vimrc" -n -es -S "$FIXTURE" +run nvim --headless -u "$HOME/.config/nvim/init.vim" -n -S "$FIXTURE" +run cmp -s "$HOME/.vim/coc-settings.json" "$HOME/.config/nvim/coc-settings.json" + +printf 'Editor parity checks passed.\n' diff --git a/scripts/editor-parity.vim b/scripts/editor-parity.vim new file mode 100644 index 0000000..c64571a --- /dev/null +++ b/scripts/editor-parity.vim @@ -0,0 +1,62 @@ +" Headless fixture for scripts/check-editor-parity.sh. + +set nomore + +let s:failures = [] + +function! s:Check(name, condition, detail) abort + if !a:condition + call add(s:failures, a:name . ': ' . a:detail) + endif +endfunction + +function! s:HasCommand(name) abort + return exists(':' . a:name) == 2 +endfunction + +function! s:MapRhs(mode, lhs) abort + return maparg(a:lhs, a:mode) +endfunction + +function! s:CheckIndent(filetype, tabstop, shiftwidth, softtabstop, expandtab) abort + execute 'setfiletype ' . a:filetype + call s:Check(a:filetype . ' tabstop', &l:tabstop == a:tabstop, 'expected ' . a:tabstop . ', got ' . &l:tabstop) + call s:Check(a:filetype . ' shiftwidth', &l:shiftwidth == a:shiftwidth, 'expected ' . a:shiftwidth . ', got ' . &l:shiftwidth) + call s:Check(a:filetype . ' softtabstop', &l:softtabstop == a:softtabstop, 'expected ' . a:softtabstop . ', got ' . &l:softtabstop) + call s:Check(a:filetype . ' expandtab', &l:expandtab == a:expandtab, 'expected ' . a:expandtab . ', got ' . &l:expandtab) + setlocal filetype= +endfunction + +call s:Check('colorscheme', get(g:, 'colors_name', '') ==# 'catppuccin_mocha', 'got ' . get(g:, 'colors_name', '')) + +for s:command in ['CocList', 'Files', 'GFiles', 'RG', 'Format'] + call s:Check('command ' . s:command, s:HasCommand(s:command), 'missing') +endfor + +call s:Check('insert jk', s:MapRhs('i', 'jk') ==# '', 'unexpected rhs: ' . string(s:MapRhs('i', 'jk'))) +call s:Check('visual jk', s:MapRhs('v', 'jk') ==# '', 'unexpected rhs: ' . string(s:MapRhs('v', 'jk'))) +call s:Check('normal tab', s:MapRhs('n', "\") ==# 'w', 'unexpected rhs: ' . string(s:MapRhs('n', "\"))) +call s:Check('leader f', !empty(s:MapRhs('n', 'f')), 'missing') +call s:Check('leader g', !empty(s:MapRhs('n', 'g')), 'missing') +call s:Check('gd', !empty(s:MapRhs('n', 'gd')), 'missing') +call s:Check('gr', !empty(s:MapRhs('n', 'gr')), 'missing') +call s:Check('F', s:MapRhs('n', 'F') =~# 'CocAction', 'unexpected rhs: ' . string(s:MapRhs('n', 'F'))) + +syntax off +call s:CheckIndent('python', 2, 2, 2, 1) +call s:CheckIndent('javascript', 2, 2, 2, 1) +call s:CheckIndent('typescript', 2, 2, 2, 1) +call s:CheckIndent('sh', 2, 2, 2, 1) +call s:CheckIndent('yaml', 2, 2, 2, 1) +call s:CheckIndent('json', 2, 2, 2, 1) +call s:CheckIndent('make', 2, 2, 0, 0) +bwipeout! + +if !empty(s:failures) + for s:failure in s:failures + echomsg 'PARITY FAIL: ' . s:failure + endfor + cquit 1 +endif + +quitall! diff --git a/scripts/minimal-bashrc.sh b/scripts/minimal-bashrc.sh index 2d28c8c..e727c30 100755 --- a/scripts/minimal-bashrc.sh +++ b/scripts/minimal-bashrc.sh @@ -4,6 +4,7 @@ # Just download the essential files directly mkdir -p ~/.config/shell-functions +mkdir -p ~/.config/git # Download server bashrc curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/common/shell/.bashrc.server -o ~/.bashrc @@ -14,4 +15,14 @@ curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/common/shell # Download git config curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/common/git/.gitconfig -o ~/.gitconfig -echo "✅ Minimal configs installed! Run: source ~/.bashrc" \ No newline at end of file +# Download git commit template +curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/common/git/commit-template.md -o ~/.config/git/commit-template.md + +# Download git hooks (the gitconfig sets core.hooksPath, so they must exist +# or git stops running ANY hooks, including repo-local ones like husky) +mkdir -p ~/.config/git/hooks +curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/common/git/hooks/pre-commit -o ~/.config/git/hooks/pre-commit +curl -sSL https://raw.githubusercontent.com/woud420/dotfiles/master/common/git/hooks/pre-push -o ~/.config/git/hooks/pre-push +chmod +x ~/.config/git/hooks/pre-commit ~/.config/git/hooks/pre-push + +echo "✅ Minimal configs installed! Run: source ~/.bashrc" diff --git a/scripts/quick-install.sh b/scripts/quick-install.sh index b1782de..6ef2187 100755 --- a/scripts/quick-install.sh +++ b/scripts/quick-install.sh @@ -21,10 +21,13 @@ fi cd "$DOTFILES_DIR" -# Detect if we're in a container or minimal environment +# Detect if we're in a container, SSH session, or minimal environment if [ -f /.dockerenv ] || [ -n "$CONTAINER" ]; then echo "Container environment detected, using minimal setup..." MINIMAL=1 +elif [ -n "$SSH_CONNECTION" ] || [ -n "$SSH_CLIENT" ]; then + echo "Remote SSH session detected, using server configs..." + MINIMAL=1 else MINIMAL=0 fi @@ -35,16 +38,27 @@ echo "Installing common configurations..." # Bash configs [ -f "$HOME/.bashrc" ] && mv "$HOME/.bashrc" "$HOME/.bashrc.backup" if [ "$MINIMAL" = "1" ]; then - ln -sf "$DOTFILES_DIR/common/shell/.bashrc.server" "$HOME/.bashrc" + cp -f "$DOTFILES_DIR/common/shell/.bashrc.server" "$HOME/.bashrc" else - ln -sf "$DOTFILES_DIR/common/shell/.bashrc" "$HOME/.bashrc" + cp -f "$DOTFILES_DIR/common/shell/.bashrc" "$HOME/.bashrc" fi -ln -sf "$DOTFILES_DIR/common/shell/.bash_profile" "$HOME/.bash_profile" +cp -f "$DOTFILES_DIR/common/shell/.bash_profile" "$HOME/.bash_profile" # Git config -ln -sf "$DOTFILES_DIR/common/git/.gitconfig" "$HOME/.gitconfig" +cp -f "$DOTFILES_DIR/common/git/.gitconfig" "$HOME/.gitconfig" mkdir -p "$HOME/.config/git" -ln -sf "$DOTFILES_DIR/common/git/.gitignore_global" "$HOME/.config/git/ignore" +cp -f "$DOTFILES_DIR/common/git/.gitignore_global" "$HOME/.config/git/ignore" +cp -f "$DOTFILES_DIR/common/git/commit-template.md" "$HOME/.config/git/commit-template.md" + +# Git hooks: the gitconfig above sets core.hooksPath, so the hooks must exist +# or git stops running ANY hooks (including repo-local ones like husky) +mkdir -p "$HOME/.config/git/hooks" +for hook in "$DOTFILES_DIR/common/git/hooks/"*; do + base="$(basename "$hook")" + [ -f "$hook" ] && [ "$base" != "README.md" ] || continue + cp -f "$hook" "$HOME/.config/git/hooks/$base" + chmod +x "$HOME/.config/git/hooks/$base" +done # GNU aliases (copy to avoid symlink on targets) cp -f "$DOTFILES_DIR/common/shell/.gnu_aliases" "$HOME/.gnu_aliases" diff --git a/scripts/refresh-machine-state.sh b/scripts/refresh-machine-state.sh new file mode 100755 index 0000000..b087d7d --- /dev/null +++ b/scripts/refresh-machine-state.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +# +# Regenerates machine-state.md with current system information. +# Run manually or via package manager hooks. +# + +set -euo pipefail + +DOTFILES_DIR="${DOTFILES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" + +# Detect OS and set output path +detect_os() { + case "$(uname -s)" in + Linux) + if [[ -f /etc/arch-release ]]; then + echo "arch" + elif [[ -f /etc/debian_version ]]; then + echo "debian" + elif [[ -f /etc/fedora-release ]]; then + echo "fedora" + elif [[ -f /etc/alpine-release ]]; then + echo "alpine" + else + echo "linux" + fi + ;; + Darwin) + echo "darwin" + ;; + *) + echo "unknown" + ;; + esac +} + +OS="$(detect_os)" + +# Set output path based on OS +case "$OS" in + arch) + OUTPUT_FILE="$DOTFILES_DIR/linux/arch/ai-context/machine-state.md" + ;; + debian) + OUTPUT_FILE="$DOTFILES_DIR/linux/debian/ai-context/machine-state.md" + ;; + fedora) + OUTPUT_FILE="$DOTFILES_DIR/linux/fedora/ai-context/machine-state.md" + ;; + alpine) + OUTPUT_FILE="$DOTFILES_DIR/linux/alpine/ai-context/machine-state.md" + ;; + darwin) + OUTPUT_FILE="$DOTFILES_DIR/darwin/ai-context/machine-state.md" + ;; + *) + OUTPUT_FILE="$DOTFILES_DIR/common/ai-context/machine-state.md" + ;; +esac + +# Ensure directory exists +mkdir -p "$(dirname "$OUTPUT_FILE")" + +# Helper: get version if command exists +version_of() { + local cmd="$1" + shift + if command -v "$cmd" &>/dev/null; then + if [[ $# -gt 0 ]]; then + "$cmd" "$@" 2>/dev/null | head -n1 + else + "$cmd" --version 2>/dev/null | head -n1 + fi + else + echo "not installed" + fi +} + +# Helper: get package count +package_count() { + case "$OS" in + arch) + pacman -Q 2>/dev/null | wc -l + ;; + debian) + dpkg -l 2>/dev/null | grep -c '^ii' + ;; + darwin) + brew list --formula 2>/dev/null | wc -l | tr -d ' ' + ;; + *) + echo "unknown" + ;; + esac +} + +# Helper: get recently installed packages (last 10) +recent_packages() { + case "$OS" in + arch) + grep -E '\[ALPM\] installed' /var/log/pacman.log 2>/dev/null | tail -10 | awk '{print $4}' | sed 's/(.*//' + ;; + debian) + grep ' install ' /var/log/dpkg.log 2>/dev/null | tail -10 | awk '{print $4}' | cut -d: -f1 + ;; + darwin) + # Homebrew doesn't have a great install log, just list some recent + brew list --formula -1 2>/dev/null | tail -10 + ;; + *) + echo "unavailable" + ;; + esac +} + +# Generate the file +cat > "$OUTPUT_FILE" << EOF +# Machine State + +> Auto-generated by \`refresh-machine-state.sh\` +> Last updated: $(date -Iseconds) + +## System + +- **OS**: $(uname -s) $(uname -r) +- **Hostname**: $(hostname) +- **Architecture**: $(uname -m) + +## Shell + +- **Current shell**: $SHELL +- **Bash**: $(version_of bash) +- **Zsh**: $(version_of zsh) + +## Languages + +| Language | Version | +|----------|---------| +| Rust | $(version_of rustc) | +| Python | $(version_of python3) | +| Node | $(version_of node -v) | +| Go | $(version_of go version) | + +## Tools + +| Tool | Version | +|------|---------| +| Git | $(version_of git) | +| Docker | $(version_of docker -v) | +| kubectl | $(version_of kubectl version --client --short 2>/dev/null || version_of kubectl version --client) | +| Terraform | $(version_of terraform -v) | +| Neovim | $(version_of nvim) | + +## Packages + +- **Total installed**: $(package_count) +- **Package manager**: $(case "$OS" in arch) echo "pacman";; debian) echo "apt";; darwin) echo "homebrew";; *) echo "unknown";; esac) + +### Recently Installed + +\`\`\` +$(recent_packages) +\`\`\` +EOF + +echo "Updated: $OUTPUT_FILE" diff --git a/scripts/ssh-copy-dotfiles.sh b/scripts/ssh-copy-dotfiles.sh index 96d8d3e..9e7d07a 100755 --- a/scripts/ssh-copy-dotfiles.sh +++ b/scripts/ssh-copy-dotfiles.sh @@ -13,7 +13,7 @@ DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" echo "Copying dotfiles to $HOST..." # Create directories -ssh "$HOST" 'mkdir -p ~/.config/shell-functions ~/.config/git' +ssh "$HOST" 'mkdir -p ~/.config/shell-functions ~/.config/git ~/.config/git/hooks' # Copy essential files scp "$DOTFILES_DIR/common/shell/.bashrc.server" "$HOST:~/.bashrc" @@ -21,7 +21,12 @@ scp "$DOTFILES_DIR/common/shell/.bash_profile" "$HOST:~/.bash_profile" scp "$DOTFILES_DIR/common/shell/.gnu_aliases" "$HOST:~/.gnu_aliases" scp "$DOTFILES_DIR/common/git/.gitconfig" "$HOST:~/.gitconfig" scp "$DOTFILES_DIR/common/git/.gitignore_global" "$HOST:~/.config/git/ignore" +scp "$DOTFILES_DIR/common/git/commit-template.md" "$HOST:~/.config/git/commit-template.md" scp "$DOTFILES_DIR/common/shell-functions/"*.sh "$HOST:~/.config/shell-functions/" +# Git hooks (the copied gitconfig sets core.hooksPath, so they must exist) +scp "$DOTFILES_DIR/common/git/hooks/pre-commit" "$DOTFILES_DIR/common/git/hooks/pre-push" "$HOST:~/.config/git/hooks/" +ssh "$HOST" 'chmod +x ~/.config/git/hooks/pre-commit ~/.config/git/hooks/pre-push' + echo "✅ Dotfiles copied to $HOST" -echo "Run 'source ~/.bashrc' on the remote host" \ No newline at end of file +echo "Run 'source ~/.bashrc' on the remote host" diff --git a/scripts/sudo-askpass.sh b/scripts/sudo-askpass.sh new file mode 100755 index 0000000..9e5fe1d --- /dev/null +++ b/scripts/sudo-askpass.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Cross-platform sudo askpass helper + +case "$(uname -s)" in + Darwin) + # macOS: use osascript (built-in) + osascript -e 'Tell application "System Events" to display dialog "Password:" default answer "" with hidden answer' -e 'text returned of result' 2>/dev/null + ;; + Linux) + # Linux: prefer rofi, fall back to zenity/kdialog + if command -v rofi &>/dev/null; then + rofi -dmenu -password -p "sudo" -l 0 -theme-str 'window {width: 300px;} listview {enabled: false;}' + elif command -v zenity &>/dev/null; then + zenity --password --title="sudo" + elif command -v kdialog &>/dev/null; then + kdialog --password "sudo" + else + echo "No askpass helper found" >&2 + exit 1 + fi + ;; +esac diff --git a/scripts/test-install.sh b/scripts/test-install.sh new file mode 100755 index 0000000..7f09bb9 --- /dev/null +++ b/scripts/test-install.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/dotfiles-install-test.XXXXXX")" +TEST_HOME="$TMP_DIR/home" +STUB_DIR="$TMP_DIR/bin" +STUB_LOG="$TMP_DIR/stubs.log" + +cleanup() { + rm -rf "$TMP_DIR" +} +trap cleanup EXIT + +mkdir -p "$TEST_HOME" "$STUB_DIR" + +cat > "$STUB_DIR/vim" <<'STUB' +#!/usr/bin/env bash +printf 'vim %s\n' "$*" >> "${DOTFILES_INSTALL_TEST_LOG:?}" +exit 0 +STUB + +cat > "$STUB_DIR/nvim" <<'STUB' +#!/usr/bin/env bash +printf 'nvim %s\n' "$*" >> "${DOTFILES_INSTALL_TEST_LOG:?}" +exit 0 +STUB + +chmod +x "$STUB_DIR/vim" "$STUB_DIR/nvim" + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + exit 1 +} + +assert_regular_copy() { + local path="$1" + local expected_source="$2" + [[ -f "$path" ]] || fail "$path is not a regular file" + [[ ! -L "$path" ]] || fail "$path must not be a symlink" + cmp -s "$path" "$expected_source" || fail "$path differs from $expected_source" +} + +assert_file() { + local path="$1" + [[ -f "$path" ]] || fail "$path is not a file" +} + +HOME="$TEST_HOME" \ +PATH="$STUB_DIR:$PATH" \ +DOTFILES_INSTALL_TEST_LOG="$STUB_LOG" \ + "$ROOT_DIR/install.sh" --no-packages > "$TMP_DIR/install.log" + +assert_regular_copy "$TEST_HOME/.bashrc" "$ROOT_DIR/common/shell/.bashrc" +assert_regular_copy "$TEST_HOME/.zshrc" "$ROOT_DIR/common/shell/.zshrc" +assert_regular_copy "$TEST_HOME/.gitconfig" "$ROOT_DIR/common/git/.gitconfig" +assert_regular_copy "$TEST_HOME/.vim/vimrc" "$ROOT_DIR/.vim/vimrc" +assert_regular_copy "$TEST_HOME/.config/nvim/init.vim" "$ROOT_DIR/common/nvim/init.vim" +assert_regular_copy "$TEST_HOME/.config/nvim/coc-settings.json" "$ROOT_DIR/.vim/coc-settings.json" + +assert_file "$TEST_HOME/.gnu_aliases" +assert_file "$TEST_HOME/.dircolors" +assert_file "$TEST_HOME/.config/kitty/kitty.conf" +assert_file "$TEST_HOME/.config/shell-functions/git.sh" +assert_regular_copy "$TEST_HOME/.config/shell-functions/editor.sh" "$ROOT_DIR/common/shell-functions/editor.sh" +assert_regular_copy "$TEST_HOME/.config/shell-functions/which.sh" "$ROOT_DIR/common/shell-functions/which.sh" + +AUDIT_LOG="$(find "$TEST_HOME" -path '*/.dotfiles-backup-*/install-audit.tsv' -print -quit)" +[[ -n "$AUDIT_LOG" ]] || fail "audit log was not created" +grep -q $'\tcopy\t' "$AUDIT_LOG" || fail "audit log has no copy action" +! grep -q $'\tlink\t' "$AUDIT_LOG" || fail "audit log must not contain link actions" +grep -q "$ROOT_DIR/common/nvim/init.vim" "$AUDIT_LOG" || fail "audit log does not include neovim init" + +# vim step defers to nvim when nvim exists (stubbed here), so no vim invocation +! grep -q '^vim ' "$STUB_LOG" || fail "vim should not be invoked when nvim is present" +grep -q '^nvim --headless +PlugInstall +qall$' "$STUB_LOG" || fail "nvim plugin install was not invoked" + +printf 'Installer test passed.\n' diff --git a/scripts/update_cursor_tools.py b/scripts/update_cursor_tools.py deleted file mode 100755 index 6f3a919..0000000 --- a/scripts/update_cursor_tools.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 -"""Generate tools.yaml for Cursor from brew packages and shell aliases.""" - -from __future__ import annotations - -import json -import os -import subprocess -from pathlib import Path - - -def get_brew_packages() -> list[str]: - """Return a sorted list of installed Homebrew formula packages.""" - brew = subprocess.run(["which", "brew"], capture_output=True, text=True) - if brew.returncode != 0 or not brew.stdout.strip(): - return [] - - try: - result = subprocess.run([ - "brew", - "list", - "--formula", - ], capture_output=True, text=True, check=True) - except subprocess.CalledProcessError: - return [] - packages = [line.strip() for line in result.stdout.splitlines() if line.strip()] - return sorted(packages) - - -def get_shell_aliases() -> dict[str, str]: - """Return shell aliases available in an interactive bash shell.""" - try: - result = subprocess.run( - ["bash", "-ic", "alias"], capture_output=True, text=True, check=True - ) - except subprocess.CalledProcessError: - return {} - aliases: dict[str, str] = {} - for line in result.stdout.splitlines(): - if not line.startswith("alias "): - continue - # alias ll='ls -l' - try: - name, value = line[6:].split("=", 1) - except ValueError: - continue - value = value.strip() - if (value.startswith("'") and value.endswith("'")) or ( - value.startswith('"') and value.endswith('"') - ): - value = value[1:-1] - aliases[name.strip()] = value - return aliases - - -def dump_yaml(data: dict) -> str: - """Return YAML representation of the provided data. - - Falls back to JSON if PyYAML is not available. - """ - try: - import yaml # type: ignore - - return yaml.safe_dump(data, sort_keys=False) - except Exception: - return json.dumps(data, indent=2) - - -def main() -> None: - data = { - "brew_packages": get_brew_packages(), - "aliases": get_shell_aliases(), - } - out_path = Path.home() / ".config/cursor/generated/tools.yaml" - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_text(dump_yaml(data)) - print(f"Wrote {out_path}") - - -if __name__ == "__main__": - main() diff --git a/shell/.dircolors b/shell/.dircolors deleted file mode 100644 index a20008b..0000000 --- a/shell/.dircolors +++ /dev/null @@ -1,32 +0,0 @@ -# ~/.catppuccin-mocho.dircolors - -# File types -di 38;5;117 # directory = sky blue -ln 38;5;153 # symlink = lavender -so 38;5;217 # socket = flamingo -pi 38;5;229 # pipe = yellow -ex 38;5;114 # executable = green -bd 38;5;174 # block special = maroon -cd 38;5;174 # character special = maroon -su 38;5;204 # setuid file = red -sg 38;5;204 # setgid file = red -tw 38;5;204 # sticky other writable = red -ow 38;5;204 # other writable = red -st 38;5;204 # sticky = red -mi 38;5;204 # missing file = red -or 38;5;204 # orphaned symlink = red - -# Extensions -*.rs 38;5;153 # Rust files = lavender -*.py 38;5;153 # Python files = lavender -*.sh 38;5;114 # Shell scripts = green -*.toml 38;5;229 # TOML = yellow -*.yaml 38;5;229 # YAML = yellow -*.yml 38;5;229 # YAML = yellow -*.md 38;5;218 # Markdown = pink -*.txt 38;5;218 # Text = pink -*.log 38;5;229 # Logs = yellow -*.json 38;5;229 # JSON = yellow - -# Special cases -Makefile 38;5;216 \ No newline at end of file diff --git a/shell/.gnu_aliases b/shell/.gnu_aliases deleted file mode 100644 index fdfccd6..0000000 --- a/shell/.gnu_aliases +++ /dev/null @@ -1,30 +0,0 @@ -# Improved safe_alias function -# safe_alias [alias-name] [primary-command] fallback [secondary-command] -safe_alias() { - local program - program="${2%% *}" # Extract first word of command (not args) - if command -v "$program" >/dev/null 2>&1; then - alias "$1"="$2" - else - if [ "$3" = "fallback" ] && [ -n "$4" ]; then - alias "$1"="$4" - fi - fi -} - -# GNU tools with fallback to BSD/macOS system versions -safe_alias ls 'gls --color=auto --group-directories-first' fallback 'ls' -safe_alias sed 'gsed' fallback 'sed' -safe_alias awk 'gawk' fallback 'awk' -safe_alias find 'gfind' fallback 'find' -safe_alias grep 'ggrep' fallback 'grep' -safe_alias xargs 'gxargs' fallback 'xargs' -safe_alias tar 'gtar' fallback 'tar' -safe_alias which 'gwhich' fallback 'which' -safe_alias make 'gmake' fallback 'make' -safe_alias dircolors 'gdircolors' fallback 'dircolors' - -# If dircolors is available, eval LS_COLORS -if command -v dircolors >/dev/null 2>&1; then - eval "$(dircolors -b ~/.dircolors)" -fi \ No newline at end of file diff --git a/shell/.zshrc b/shell/.zshrc deleted file mode 100644 index cecc2f1..0000000 --- a/shell/.zshrc +++ /dev/null @@ -1,158 +0,0 @@ -# Make sure autocomplete works properly -autoload -Uz compinit -compinit - -# Load colors -autoload -Uz colors && colors -setopt prompt_subst - -# Git branch info setup -autoload -Uz vcs_info -precmd() { vcs_info } -zstyle ':vcs_info:*' enable git -zstyle ':vcs_info:git:*' formats ' %b' - -ROSEWATER='%F{#f5e0dc}' -MAUVE='%F{#cba6f7}' -TEAL='%F{#94e2d5}' -PEACH='%F{#fab387}' -SOFT_GRAY='%F{#6c7086}' -RESET='%f%k' - -BUBBLE_BG='%{%K{#f5e0dc}%}' -BUBBLE_FG='%{%F{#1e1e2e}%}' - -function kube_prompt() { - local context=$(kubectl config current-context 2>/dev/null) - if [ -n "$context" ]; then - echo "(k8s:$context)" - fi -} - -function pretty_git() { - # Don't forget the space at the end of the echo - [[ -n "${vcs_info_msg_0_}" ]] && echo "${vcs_info_msg_0_} " -} - -# Custom function to show 🏡 if in home -function pretty_pwd() { - case "$PWD" in - "$HOME") - echo "🏡" - ;; - "$HOME/Documents") - echo "📄" - ;; - "$HOME/Downloads") - echo "📁" - ;; - "$HOME/Pictures") - echo "🖼️" - ;; - "$HOME/Music") - echo "🎵" - ;; - "$HOME/Desktop") - echo "🖥️" - ;; - "$HOME/workspace") - echo "💻" - ;; - *) - echo "%~" - ;; - esac - #if [[ "$PWD" == "$HOME" ]]; then - # echo "🏡" - #else - # echo "%~" - #fi -} - -# Dynamic time color based on hour -function dynamic_time_prompt() { - local hour=$(date +%H) - local color icon - - if (( hour >= 6 && hour < 12 )); then - color=$PEACH - icon='☀️' - elif (( hour >= 12 && hour < 18 )); then - color=$TEAL - icon='☀️' - elif (( hour >= 18 && hour < 21 )); then - color=$MAUVE - icon='🌙' - else - color=$SOFT_GRAY - icon='🌙' - fi - - echo "%{$color%}%*%{$RESET%}" -} - -function build_prompt() { - local GIT_INFO="$(pretty_git)" - local PWD_INFO="$(pretty_pwd)" - - PROMPT="⭐ ${MAUVE}[${ROSEWATER}%n${MAUVE}@${TEAL}${PWD_INFO}${MAUVE}] ${PEACH}${GIT_INFO}${RESET}➔ " -} - -precmd_functions+=(build_prompt) - -function build_rprompt() { - RPROMPT="$(dynamic_time_prompt)" -} - -precmd_functions+=(build_rprompt) - -source ~/.gnu_aliases - -# Soft pastel fzf colors -export FZF_DEFAULT_OPTS=" - --color=fg:#cdd6f4,bg:#1e1e2e,hl:#f38ba8 - --color=fg+:#f5e0dc,bg+:#313244,hl+:#fab387 - --color=info:#89b4fa,prompt:#94e2d5,pointer:#f5c2e7 - --color=marker:#a6e3a1,spinner:#b4befe,header:#cba6f7 - --layout=reverse - --border -" -[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh - -# Load custom shell functions -for f in ~/.config/shell-functions/*.sh; do - source "$f" -done - -function kctx() { - local selected - selected=$(kubectl config get-contexts -o name | \ - fzf --prompt="Select context > " \ - --height=40% \ - --layout=reverse \ - --border \ - --ansi) - - if [[ -n "$selected" ]]; then - kubectl config use-context "$selected" - else - echo "No context selected." - fi -} - -function git-ch() { - local branch - branch=$(git branch --sort=-committerdate | sed 's/* //' | sed 's/^[[:space:]]*//' | \ - fzf --prompt="Checkout branch > " \ - --height=40% \ - --layout=reverse \ - --border) - if [[ -n "$branch" ]]; then - git checkout "$branch" - fi -} - -alias kc=kctx -alias gch="git-ch" - -export PATH="/opt/homebrew/bin:$PATH" \ No newline at end of file