From f9dfe399f1789857e6f4e0f146c61bfbdf22f80f Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Tue, 27 May 2014 20:29:25 +0530 Subject: [PATCH 01/51] Adding basic files --- .gitignore | 16 +++++ bash/.bashrc | 118 +++++++++++++++++++++++++++++++++++++ emacs/Cask | 33 +++++++++++ emacs/init.el | 144 +++++++++++++++++++++++++++++++++++++++++++++ git/.gitconfig | 5 ++ i3-wm/config | 155 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 471 insertions(+) create mode 100644 .gitignore create mode 100644 bash/.bashrc create mode 100644 emacs/Cask create mode 100644 emacs/init.el create mode 100644 git/.gitconfig create mode 100644 i3-wm/config diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98f032d --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +auto-save-list/* +eshell/* +ac-comphist.dat +*~ +elpa/* +var/* +emms/* +url/* +.emacs.desktop +.emacs.desktop.lock +session* +rcirc* +.cask/* +.mc-lists.el +tramp + diff --git a/bash/.bashrc b/bash/.bashrc new file mode 100644 index 0000000..1aff36b --- /dev/null +++ b/bash/.bashrc @@ -0,0 +1,118 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) +# for examples + +# If not running interactively, don't do anything +case $- in + *i*) ;; + *) return;; +esac + +# don't put duplicate lines or lines starting with space in the history. +# See bash(1) for more options +HISTCONTROL=ignoreboth + +# append to the history file, don't overwrite it +shopt -s histappend + +# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) +HISTSIZE=1000 +HISTFILESIZE=2000 + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# If set, the pattern "**" used in a pathname expansion context will +# match all files and zero or more directories and subdirectories. +#shopt -s globstar + +# make less more friendly for non-text input files, see lesspipe(1) +[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# set a fancy prompt (non-color, unless we know we "want" color) +case "$TERM" in + xterm-color) color_prompt=yes;; +esac + +# uncomment for a colored prompt, if the terminal has the capability; turned +# off by default to not distract the user: the focus in a terminal window +# should be on the output of commands, not on the prompt +#force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes + else + color_prompt= + fi +fi + +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' +fi +unset color_prompt force_color_prompt + +# If this is an xterm set the title to user@host:dir +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac + +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +# some more ls aliases +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' + +# Add an "alert" alias for long running commands. Use like so: +# sleep 10; alert +alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' + +# Alias definitions. +# You may want to put all your additions into a separate file like +# ~/.bash_aliases, instead of adding them here directly. +# See /usr/share/doc/bash-doc/examples in the bash-doc package. + +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi + +# enable programmable completion features (you don't need to enable +# this, if it's already enabled in /etc/bash.bashrc and /etc/profile +# sources /etc/bash.bashrc). +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + + +export PS1='$(__git_ps1) \w\$ ' +export PATH="/home/sanket/.cask/bin:$PATH" diff --git a/emacs/Cask b/emacs/Cask new file mode 100644 index 0000000..4a23156 --- /dev/null +++ b/emacs/Cask @@ -0,0 +1,33 @@ +(source gnu) +(source melpa) + +(depends-on "bind-key") +(depends-on "cask") +(depends-on "dash") +(depends-on "drag-stuff") +(depends-on "exec-path-from-shell") +(depends-on "expand-region") +(depends-on "f") +(depends-on "flycheck") +(depends-on "flycheck-cask") +(depends-on "htmlize") +(depends-on "idle-highlight-mode") +(depends-on "magit") +(depends-on "multiple-cursors") +(depends-on "nyan-mode") +(depends-on "pallet") +(depends-on "popwin") +(depends-on "prodigy") +(depends-on "projectile") +(depends-on "s") +(depends-on "smartparens") +(depends-on "smex") +(depends-on "use-package") +(depends-on "web-mode") +(depends-on "yasnippet") +(depends-on "volatile-highlights") +(depends-on "powerline") +(depends-on "autopair") +(depends-on "popup-switcher") +(depends-on "c-eldoc") +(depends-on "auto-complete") diff --git a/emacs/init.el b/emacs/init.el new file mode 100644 index 0000000..967b13b --- /dev/null +++ b/emacs/init.el @@ -0,0 +1,144 @@ +;; Sanket Sudake +(require 'cask "~/.cask/cask.el") +(cask-initialize) + +;; Disable Arrow Keys +(global-set-key (kbd "") 'disabled-key) +(global-set-key (kbd "") 'disabled-key) +(global-set-key (kbd "") 'disabled-key) +(global-set-key (kbd "") 'disabled-key) +(global-set-key (kbd "") 'disabled-key) +(global-set-key (kbd "") 'disabled-key) + +;; Set No UI +(dolist (mode '(menu-bar-mode tool-bar-mode scroll-bar-mode)) + (when (fboundp mode) (funcall mode -1))) + +;; yes or no becomes y or n +(defalias 'yes-or-no-p 'y-or-n-p) + +;; Coding style +(prefer-coding-system 'utf-8) +(prefer-coding-system 'utf-8) +(set-language-environment 'UTF-8) +(set-default-coding-systems 'utf-8) +(setq file-name-coding-system 'utf-8) +(setq buffer-file-coding-system 'utf-8) +(setq coding-system-for-write 'utf-8) +(set-keyboard-coding-system 'utf-8) +(set-terminal-coding-system 'utf-8) +(set-clipboard-coding-system 'utf-8) +(set-selection-coding-system 'utf-8) +(setq default-process-coding-system '(utf-8 . utf-8)) + +;; Completion ignores filenames ending in any string in this list. +(setq completion-ignored-extensions + '(".o" ".elc" "~" ".bin" ".class" ".exe" ".ps" ".abs" ".mx" + ".~jv" ".rbc" ".pyc" ".beam" ".aux" ".out" ".pdf")) + + +;; Mode tweaks +;; + + +;;;; Text mode and Auto Fill mode +(setq default-major-mode 'text-mode) +(add-hook 'text-mode-hook 'turn-on-auto-fill) + +(require 'volatile-highlights) +(volatile-highlights-mode t) +(autoload 'enable-paredit-mode "paredit" + "Turn on pseudo-structural editing of Lisp code." t) + +;;;; Ido mode +(setq ido-enable-flex-matching t) +(setq ido-everywhere t) +;;This tab override shouldn't be necessary given ido's default +;;configuration, but minibuffer-complete otherwise dominates the +;;tab binding because of my custom tab-completion-everywhere +;;configuration. +(add-hook 'ido-setup-hook + (lambda () + (define-key ido-completion-map [tab] 'ido-complete))) +(ido-mode 1) +(setq ido-vertical-mode t) + +;;;; Stop autobackup +;;stop creating those backup~ files +(setq make-backup-files nil) +;;stop creating those #autosave# files +(setq auto-save-default nil) + +;;;; autopair mode +(require 'autopair) +(autopair-global-mode 1) +(setq autopair-autowrap t) + +;; Save emacs session before exit +(setq desktop-save 'if-exists) +(desktop-save-mode 1) + +;; Powerline Mode +(require 'powerline) +(powerline-default-theme) + +;;;; Popup switcher +(require 'popup-switcher) +(global-set-key [f2] 'psw-switch-buffer) +(define-key global-map (kbd "C-+") 'text-scale-increase) +(define-key global-map (kbd "C--") 'text-scale-decrease) + + +;;; cc mode setup +(require 'cc-mode) +(setq-default c-basic-offset 4 c-default-style "linux") +;;(setq-default tab-width 4 indent-tabs-mode t) +(define-key c-mode-base-map (kbd "RET") 'newline-and-indent) +(setq indent-tabs-mode nil) + +;; autocomplete and yasnippet mode +(require 'yasnippet) +(yas-global-mode 1) +(require 'auto-complete) +(require 'auto-complete-config) +(ac-config-default) +(ac-flyspell-workaround) +(add-to-list 'ac-dictionary-directories + "~/.emacs.d/dict") + +(setq ac-ignore-case 'smart) +(set-face-background 'ac-candidate-face "lightgray") +(set-face-underline 'ac-candidate-face "darkgray") +(set-face-background 'ac-selection-face "steelblue") +(defun ac-cc-mode-setup () + (setq ac-sources '( + ac-source-words-in-buffer + ac-source-words-in-same-mode-buffers + ac-source-filename + ac-source-files-in-current-dir + ac-source-yasnippet + ac-source-dictionary + ac-source-semantic + ac-source-gtags + ac-source-css-property + ))) +(defun my-ac-config () + (add-hook 'c-mode-common-hook 'ac-cc-mode-setup) + (add-hook 'c++-mode-common-hook 'ac-cc-mode-setup) + (add-hook 'auto-complete-mode-hook 'ac-common-setup) + (global-auto-complete-mode t)) +(my-ac-config) +(setq ac-use-menu-map t) +;; Default settings +(define-key ac-menu-map "\C-n" 'ac-next) +(define-key ac-menu-map "\C-p" 'ac-previous) + +;;;; Eldoc mode +(setq c-eldoc-includes "`pkg-config gtk+-2.0 --cflags` -I./ -I../ -I/usr/include/opencv -I/usr/include/GL -I/usr/include") +(load "c-eldoc") +(add-hook 'c-mode-hook 'c-turn-on-eldoc-mode) +(add-hook 'c++-mode-hook 'c-turn-on-eldoc-mode) + +(global-linum-mode 1) +;;(highlight-tabs) +;;(highlight-trailing-whitespace) diff --git a/git/.gitconfig b/git/.gitconfig new file mode 100644 index 0000000..ac77e61 --- /dev/null +++ b/git/.gitconfig @@ -0,0 +1,5 @@ +[user] + email = sanketsudake@gmail.com + name = Sanket Sudake +[alias] + hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short diff --git a/i3-wm/config b/i3-wm/config new file mode 100644 index 0000000..97ab704 --- /dev/null +++ b/i3-wm/config @@ -0,0 +1,155 @@ +# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. +# +# Should you change your keyboard layout somewhen, delete +# this file and re-run i3-config-wizard(1). +# + +# i3 config file (v4) +# +# Please see http://i3wm.org/docs/userguide.html for a complete reference! + +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. ISO 10646 = Unicode +font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +# The font above is very space-efficient, that is, it looks good, sharp and +# clear in small sizes. However, if you need a lot of unicode glyphs or +# right-to-left text rendering, you should instead use pango for rendering and +# chose a FreeType font, such as: +# font pango:DejaVu Sans Mono 10 + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# start a terminal +bindsym $mod+Return exec i3-sensible-terminal + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +bindsym $mod+d exec dmenu_run +# There also is the (new) i3-dmenu-desktop which only displays applications +# shipping a .desktop file. It is a wrapper around dmenu, so you need that +# installed. +# bindsym $mod+d exec --no-startup-id i3-dmenu-desktop + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor 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 + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# switch to workspace +bindsym $mod+1 workspace 1 +bindsym $mod+2 workspace 2 +bindsym $mod+3 workspace 3 +bindsym $mod+4 workspace 4 +bindsym $mod+5 workspace 5 +bindsym $mod+6 workspace 6 +bindsym $mod+7 workspace 7 +bindsym $mod+8 workspace 8 +bindsym $mod+9 workspace 9 +bindsym $mod+0 workspace 10 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace 1 +bindsym $mod+Shift+2 move container to workspace 2 +bindsym $mod+Shift+3 move container to workspace 3 +bindsym $mod+Shift+4 move container to workspace 4 +bindsym $mod+Shift+5 move container to workspace 5 +bindsym $mod+Shift+6 move container to workspace 6 +bindsym $mod+Shift+7 move container to workspace 7 +bindsym $mod+Shift+8 move container to workspace 8 +bindsym $mod+Shift+9 move container to workspace 9 +bindsym $mod+Shift+0 move container to workspace 10 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 10 px or 10 ppt + bindsym k resize grow height 10 px or 10 ppt + bindsym l resize shrink height 10 px or 10 ppt + bindsym semicolon resize grow width 10 px or 10 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + + # back to normal: Enter or Escape + bindsym Return mode "default" + bindsym Escape mode "default" +} + +bindsym $mod+r mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +bar { + status_command i3status +} + +exec --no-startup-id nm-applet + +bindsym XF86AudioRaiseVolume exec "amixer set Master 5%+ && killall -USR1 i3status" +bindsym XF86AudioLowerVolume exec "amixer set Master 5%- && killall -USR1 i3status" From 6973991c701f38cf260ed00b754f17aab4f6dcee Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 23 Jun 2014 21:15:59 +0530 Subject: [PATCH 02/51] Update directories for config files --- bash/.bashrc => config/bash/bashrc | 0 {emacs => config/emacs}/Cask | 0 {emacs => config/emacs}/init.el | 0 {git => config/git}/.gitconfig | 0 config/git/gitconfig | 5 +++++ {i3-wm => config/i3-wm}/config | 0 6 files changed, 5 insertions(+) rename bash/.bashrc => config/bash/bashrc (100%) rename {emacs => config/emacs}/Cask (100%) rename {emacs => config/emacs}/init.el (100%) rename {git => config/git}/.gitconfig (100%) create mode 100644 config/git/gitconfig rename {i3-wm => config/i3-wm}/config (100%) diff --git a/bash/.bashrc b/config/bash/bashrc similarity index 100% rename from bash/.bashrc rename to config/bash/bashrc diff --git a/emacs/Cask b/config/emacs/Cask similarity index 100% rename from emacs/Cask rename to config/emacs/Cask diff --git a/emacs/init.el b/config/emacs/init.el similarity index 100% rename from emacs/init.el rename to config/emacs/init.el diff --git a/git/.gitconfig b/config/git/.gitconfig similarity index 100% rename from git/.gitconfig rename to config/git/.gitconfig diff --git a/config/git/gitconfig b/config/git/gitconfig new file mode 100644 index 0000000..ac77e61 --- /dev/null +++ b/config/git/gitconfig @@ -0,0 +1,5 @@ +[user] + email = sanketsudake@gmail.com + name = Sanket Sudake +[alias] + hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short diff --git a/i3-wm/config b/config/i3-wm/config similarity index 100% rename from i3-wm/config rename to config/i3-wm/config From bc1e5e01321dc2c62c7232713f2b4a0410c1d323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanket=20Sudake=20=28=E0=A4=B8=E0=A4=82=E0=A4=95=E0=A5=87?= =?UTF-8?q?=E0=A4=A4=20=29?= Date: Fri, 25 Jul 2014 10:20:26 +0530 Subject: [PATCH 03/51] Update bashrc --- config/bash/bashrc | 69 +++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/config/bash/bashrc b/config/bash/bashrc index 1aff36b..05ab884 100644 --- a/config/bash/bashrc +++ b/config/bash/bashrc @@ -16,8 +16,8 @@ HISTCONTROL=ignoreboth shopt -s histappend # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) -HISTSIZE=1000 -HISTFILESIZE=2000 +HISTSIZE=1000000 +HISTFILESIZE=2000000 # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. @@ -47,12 +47,12 @@ esac if [ -n "$force_color_prompt" ]; then if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then - # We have color support; assume it's compliant with Ecma-48 - # (ISO/IEC-6429). (Lack of such support is extremely rare, and such - # a case would tend to support setf rather than setaf.) - color_prompt=yes + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes else - color_prompt= + color_prompt= fi fi @@ -89,30 +89,31 @@ alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' -# Add an "alert" alias for long running commands. Use like so: -# sleep 10; alert -alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' - -# Alias definitions. -# You may want to put all your additions into a separate file like -# ~/.bash_aliases, instead of adding them here directly. -# See /usr/share/doc/bash-doc/examples in the bash-doc package. - -if [ -f ~/.bash_aliases ]; then - . ~/.bash_aliases -fi - -# enable programmable completion features (you don't need to enable -# this, if it's already enabled in /etc/bash.bashrc and /etc/profile -# sources /etc/bash.bashrc). -if ! shopt -oq posix; then - if [ -f /usr/share/bash-completion/bash_completion ]; then - . /usr/share/bash-completion/bash_completion - elif [ -f /etc/bash_completion ]; then - . /etc/bash_completion - fi -fi - - -export PS1='$(__git_ps1) \w\$ ' -export PATH="/home/sanket/.cask/bin:$PATH" +function findf +{ + find . -name $1 +} + +# Correct misspelled typed directories in cd +shopt -s cdspell + +alias emacs="/lhome/ssudake/emacs-24.2/src/emacs" +alias build="~/cmds/build_cmd/build" +export PATH="$HOME/.cask/bin:$HOME/downloads/git-2.0.2:$PATH" +export TERM=xterm-256color + +function pd +{ + for i in $(seq 1 $1) + do + cd .. + done +} +function ppd +{ + pushd . + for i in $(seq 1 $1) + do + cd .. + done +} From 1c40700426db24f2a613bf8721e08b25577e4e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanket=20Sudake=20=28=E0=A4=B8=E0=A4=82=E0=A4=95=E0=A5=87?= =?UTF-8?q?=E0=A4=A4=20=29?= Date: Wed, 20 Aug 2014 16:58:15 +0530 Subject: [PATCH 04/51] Update bashrc --- config/bash/bashrc | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/config/bash/bashrc b/config/bash/bashrc index 05ab884..ec82494 100644 --- a/config/bash/bashrc +++ b/config/bash/bashrc @@ -88,6 +88,7 @@ fi alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' +alias meow="less" function findf { @@ -97,23 +98,35 @@ function findf # Correct misspelled typed directories in cd shopt -s cdspell -alias emacs="/lhome/ssudake/emacs-24.2/src/emacs" -alias build="~/cmds/build_cmd/build" -export PATH="$HOME/.cask/bin:$HOME/downloads/git-2.0.2:$PATH" -export TERM=xterm-256color +alias emacs="export TERM=xterm-256color;/lhome/ssudake/emacs-24.2/src/emacs" +alias r="fc -s" +alias reload="cat ~/.profile > ~/.bashrc; source ~/.bashrc" +alias deldirs="rm -r */" +export PATH="$HOME/.cask/bin:$HOME/downloads/git-2.0.2:$PATH" +function fullpath +{ + case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; + esac; +} function pd { - for i in $(seq 1 $1) - do - cd .. - done + if [ $1 ] ; then + MAX=$1; + else + MAX=0 + fi + PR="../" + _COUNTER=1 + while [ $_COUNTER -lt $MAX ]; do + PR=$(echo "$PR../") + let _COUNTER=_COUNTER+1 + done + cd $PR } function ppd { pushd . - for i in $(seq 1 $1) - do - cd .. - done + pd $1 } +export PATH="$HOME/cmds/build_cmd/:$PATH" From 7ddecdea5c94d5810eb252ade7bd23093d9c4c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sanket=20Sudake=20=28=E0=A4=B8=E0=A4=82=E0=A4=95=E0=A5=87?= =?UTF-8?q?=E0=A4=A4=20=29?= Date: Wed, 20 Aug 2014 18:07:20 +0530 Subject: [PATCH 05/51] Update bashrc --- config/bash/bashrc | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/config/bash/bashrc b/config/bash/bashrc index ec82494..2a037c6 100644 --- a/config/bash/bashrc +++ b/config/bash/bashrc @@ -10,22 +10,24 @@ esac # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options -HISTCONTROL=ignoreboth +HISTCONTROL="erasedups:ignoreboth" # append to the history file, don't overwrite it shopt -s histappend - -# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) -HISTSIZE=1000000 -HISTFILESIZE=2000000 - +shopt -s cmdhist +# Correct misspelled typed directories in cd +shopt -s cdspell # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. shopt -s checkwinsize # If set, the pattern "**" used in a pathname expansion context will # match all files and zero or more directories and subdirectories. -#shopt -s globstar +# shopt -s globstar + +# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) +HISTSIZE=1000000 +HISTFILESIZE=2000000 # make less more friendly for non-text input files, see lesspipe(1) [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" @@ -89,21 +91,15 @@ alias ll='ls -alF' alias la='ls -A' alias l='ls -CF' alias meow="less" +alias emacs="export TERM=xterm-256color;/lhome/ssudake/emacs-24.2/src/emacs" +alias r="fc -s" +alias reload="cat ~/.profile > ~/.bashrc; source ~/.bashrc" +alias deldirs="rm -r */" function findf { find . -name $1 } - -# Correct misspelled typed directories in cd -shopt -s cdspell - -alias emacs="export TERM=xterm-256color;/lhome/ssudake/emacs-24.2/src/emacs" -alias r="fc -s" -alias reload="cat ~/.profile > ~/.bashrc; source ~/.bashrc" - -alias deldirs="rm -r */" -export PATH="$HOME/.cask/bin:$HOME/downloads/git-2.0.2:$PATH" function fullpath { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; @@ -111,11 +107,8 @@ function fullpath } function pd { - if [ $1 ] ; then - MAX=$1; - else - MAX=0 - fi + MAX=0 + [ $1 ] && MAX=$1 PR="../" _COUNTER=1 while [ $_COUNTER -lt $MAX ]; do @@ -129,4 +122,6 @@ function ppd pushd . pd $1 } + +export PATH="$HOME/.cask/bin:$HOME/downloads/git-2.0.2:$PATH" export PATH="$HOME/cmds/build_cmd/:$PATH" From 75ac1d20f944b5ce40a0fd244361a4e1fe21087d Mon Sep 17 00:00:00 2001 From: Sanket Date: Sun, 27 Aug 2017 12:46:01 +0530 Subject: [PATCH 06/51] Tmux config --- config/tmux/.tmux.conf | 1113 ++++++++++++++++++++++++++++++++++ config/tmux/.tmux.conf.local | 267 ++++++++ config/tmux/LICENSE.MIT | 18 + config/tmux/LICENSE.WTFPLv2 | 13 + config/tmux/README.md | 318 ++++++++++ 5 files changed, 1729 insertions(+) create mode 100644 config/tmux/.tmux.conf create mode 100644 config/tmux/.tmux.conf.local create mode 100644 config/tmux/LICENSE.MIT create mode 100644 config/tmux/LICENSE.WTFPLv2 create mode 100644 config/tmux/README.md diff --git a/config/tmux/.tmux.conf b/config/tmux/.tmux.conf new file mode 100644 index 0000000..99203d3 --- /dev/null +++ b/config/tmux/.tmux.conf @@ -0,0 +1,1113 @@ +# cat << EOF > /dev/null +# https://github.com/gpakosz/.tmux +# (‑●‑●)> dual licensed under the WTFPL v2 license and the MIT license, +# without any warranty. +# Copyright 2012— Gregory Pakosz (@gpakosz). +# /!\ do not edit this file +# instead, override settings in ~/.tmux.conf.local, see README.md + + +# -- general ------------------------------------------------------------------- + +set -g default-terminal "screen-256color" # colors! +setw -g xterm-keys on +set -s escape-time 10 # faster command sequences +set -sg repeat-time 600 # increase repeat timeout +set -s focus-events on + +set -g prefix2 C-a # GNU-Screen compatible prefix +bind C-a send-prefix -2 + +set -q -g status-utf8 on # expect UTF-8 (tmux < 2.2) +setw -q -g utf8 on + +set -g history-limit 5000 # boost history + +# edit configuration +bind e new-window -n '~/.tmux.conf.local' "sh -c '\${EDITOR:-vim} ~/.tmux.conf.local && tmux source ~/.tmux.conf && tmux display \"~/.tmux.conf sourced\"'" + +# reload configuration +bind r source-file ~/.tmux.conf \; display '~/.tmux.conf sourced' + + +# -- display ------------------------------------------------------------------- + +set -g base-index 1 # start windows numbering at 1 +setw -g pane-base-index 1 # make pane numbering consistent with windows + +setw -g automatic-rename on # rename window to reflect current program +set -g renumber-windows on # renumber windows when a window is closed + +set -g set-titles on # set terminal title +set -g set-titles-string '#h ❐ #S ● #I #W' + +set -g display-panes-time 800 # slightly longer pane indicators display time +set -g display-time 1000 # slightly longer status messages display time + +set -g status-interval 10 # redraw status line every 10 seconds + +# clear both screen and history +bind -n C-l send-keys C-l \; run 'sleep 0.1' \; clear-history + +# activity +set -g monitor-activity on +set -g visual-activity off + + +# -- navigation ---------------------------------------------------------------- + +# create session +bind C-c new-session + +# find session +bind C-f command-prompt -p find-session 'switch-client -t %%' + +# split current window horizontally +bind - split-window -v +# split current window vertically +bind _ split-window -h + +# pane navigation +bind -r h select-pane -L # move left +bind -r j select-pane -D # move down +bind -r k select-pane -U # move up +bind -r l select-pane -R # move right +bind > swap-pane -D # swap current pane with the next one +bind < swap-pane -U # swap current pane with the previous one + +# maximize current pane +bind + run 'cut -c3- ~/.tmux.conf | sh -s _maximize_pane #{session_name} #D' + +# pane resizing +bind -r H resize-pane -L 2 +bind -r J resize-pane -D 2 +bind -r K resize-pane -U 2 +bind -r L resize-pane -R 2 + +# window navigation +unbind n +unbind p +bind -r C-h previous-window # select previous window +bind -r C-l next-window # select next window +bind Tab last-window # move to last active window + +# toggle mouse +bind m run "cut -c3- ~/.tmux.conf | sh -s _toggle_mouse" + + +# -- urlview ------------------------------------------------------------------- + +bind U run "cut -c3- ~/.tmux.conf | sh -s _urlview #{pane_id}" + + +# -- facebook pathpicker ------------------------------------------------------- + +bind F run "cut -c3- ~/.tmux.conf | sh -s _fpp #{pane_id}" + + +# -- list choice (tmux < 2.4) -------------------------------------------------- + +# vi-choice is gone in tmux >= 2.4 +run -b 'tmux bind -t vi-choice h tree-collapse 2> /dev/null || true' +run -b 'tmux bind -t vi-choice l tree-expand 2> /dev/null || true' +run -b 'tmux bind -t vi-choice K start-of-list 2> /dev/null || true' +run -b 'tmux bind -t vi-choice J end-of-list 2> /dev/null || true' +run -b 'tmux bind -t vi-choice H tree-collapse-all 2> /dev/null || true' +run -b 'tmux bind -t vi-choice L tree-expand-all 2> /dev/null || true' +run -b 'tmux bind -t vi-choice Escape cancel 2> /dev/null || true' + + +# -- edit mode (tmux < 2.4) ---------------------------------------------------- + +# vi-edit is gone in tmux >= 2.4 +run -b 'tmux bind -ct vi-edit H start-of-line 2> /dev/null || true' +run -b 'tmux bind -ct vi-edit L end-of-line 2> /dev/null || true' +run -b 'tmux bind -ct vi-edit q cancel 2> /dev/null || true' +run -b 'tmux bind -ct vi-edit Escape cancel 2> /dev/null || true' + + +# -- copy mode ----------------------------------------------------------------- + +bind Enter copy-mode # enter copy mode + +run -b 'tmux bind -t vi-copy v begin-selection 2> /dev/null || true' +run -b 'tmux bind -T copy-mode-vi v send -X begin-selection 2> /dev/null || true' +run -b 'tmux bind -t vi-copy C-v rectangle-toggle 2> /dev/null || true' +run -b 'tmux bind -T copy-mode-vi C-v send -X rectangle-toggle 2> /dev/null || true' +run -b 'tmux bind -t vi-copy y copy-selection 2> /dev/null || true' +run -b 'tmux bind -T copy-mode-vi y send -X copy-selection-and-cancel 2> /dev/null || true' +run -b 'tmux bind -t vi-copy Escape cancel 2> /dev/null || true' +run -b 'tmux bind -T copy-mode-vi Escape send -X cancel 2> /dev/null || true' +run -b 'tmux bind -t vi-copy H start-of-line 2> /dev/null || true' +run -b 'tmux bind -T copy-mode-vi L send -X end-of-line 2> /dev/null || true' + +# copy to Mac OSX clipboard +if -b 'command -v reattach-to-user-namespace > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | reattach-to-user-namespace pbcopy"' +# copy to X11 clipboard +if -b 'command -v xsel > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | xsel -i -b"' +if -b '! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | xclip -i -selection clipboard >/dev/null 2>&1"' +# copy to Windows clipboard +if -b 'command -v clip.exe > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | clip.exe"' +if -b '[ -c /dev/clipboard ]' 'bind y run -b "tmux save-buffer - > /dev/clipboard"' + + +# -- buffers ------------------------------------------------------------------- + +bind b list-buffers # list paste buffers +bind p paste-buffer # paste from the top paste buffer +bind P choose-buffer # choose which buffer to paste from + + +# -- user defined overrides ---------------------------------------------------- + +if '[ -f ~/.tmux.conf.local ]' 'source ~/.tmux.conf.local' + + +# -- 8< ------------------------------------------------------------------------ + +run 'cut -c3- ~/.tmux.conf | sh -s _apply_configuration' + + +# EOF +# +# # exit the script if any statement returns a non-true return value +# set -e +# +# __newline=' +# ' +# +# _is_enabled() { +# ( ([ x"$1" = x"enabled" ] || [ x"$1" = x"true" ] || [ x"$1" = x"yes" ] || [ x"$1" = x"1" ]) && return 0 ) || return 1 +# } +# +# _circled_digit() { +# circled_digits='⓪ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳' +# if [ "$1" -le 20 ] 2>/dev/null; then +# i=$(( $1 + 1 )) +# eval set -- "$circled_digits" +# eval echo "\${$i}" +# else +# echo "$1" +# fi +# } +# +# _maximize_pane() { +# current_session=${1:-$(tmux display -p '#{session_name}')} +# current_pane=${2:-$(tmux display -p '#{pane_id}')} +# +# dead_panes=$(tmux list-panes -s -t "$current_session" -F '#{pane_dead} #{pane_id} #{pane_start_command}' | grep -o '^1 %.\+maximized.\+$' || true) +# restore=$(echo "$dead_panes" | sed -n -E -e "s/^1 $current_pane .+maximized.+(%[0-9]+)$/tmux swap-pane -s \1 -t $current_pane \; kill-pane -t $current_pane/p" -e "s/^1 (%[0-9]+) .+maximized.+$current_pane$/tmux swap-pane -s \1 -t $current_pane \; kill-pane -t \1/p" ) +# +# if [ -z "$restore" ]; then +# [ "$(tmux list-panes -t "$current_session:" | wc -l | sed 's/^ *//g')" -eq 1 ] && tmux display "Can't maximize with only one pane" && return +# window=$(tmux new-window -t "$current_session:" -P "exec maximized... 2> /dev/null & tmux setw -t $current_session: remain-on-exit on; printf 'Pane has been maximized, press + to restore. %s' \\$current_pane") +# window=${window%.*} +# +# guard=10 +# while [ x"$(tmux list-panes -t "$window" -F '#{session_name}:#{window_index} #{pane_dead}' 2>/dev/null)" != x"$window 1" ] && [ "$guard" -ne 0 ]; do +# sleep 0.01 +# guard=$((guard - 1)) +# done +# if [ "$guard" -eq 0 ]; then +# tmux display 'Unable to maximize pane' +# fi +# +# new_pane=$(tmux display -p '#{pane_id}') +# tmux setw -t "$window" remain-on-exit off \; swap-pane -s "$current_pane" -t "$new_pane" +# else +# $restore || tmux kill-pane +# fi +# } +# +# _toggle_mouse() { +# old=$(tmux show -gv mouse) +# new="" +# +# if [ "$old" = "on" ]; then +# new="off" +# else +# new="on" +# fi +# +# tmux set -g mouse $new \;\ +# display "mouse: $new" +# } +# +# _battery() { +# charge=0 +# uname_s=$(uname -s) +# case "$uname_s" in +# *Darwin*) +# while IFS= read -r line; do +# if [ x"$discharging" != x"true" ]; then +# discharging=$(printf '%s' "$line" | grep -qi "discharging" && echo "true" || echo "false") +# fi +# percentage=$(printf '%s' "$line" | grep -E -o '[0-9]+%') +# charge=$(awk -v charge="$charge" -v percentage="${percentage%%%}" 'BEGIN { print charge + percentage / 100 }') +# count=$((count + 1)) +# done << EOF +# $(pmset -g batt | grep 'InternalBattery') +# EOF +# ;; +# *Linux*) +# while IFS= read -r batpath; do +# if [ x"$discharging" != x"true" ]; then +# discharging=$(grep -qi "discharging" "$batpath/status" && echo "true" || echo "false") +# fi +# bat_capacity="$batpath/capacity" +# if [ -r "$bat_capacity" ]; then +# charge=$(awk -v charge="$charge" -v capacity="$(cat "$bat_capacity")" 'BEGIN { print charge + capacity / 100 }') +# else +# bat_energy_full="$batpath/energy_full" +# bat_energy_now="$batpath/energy_now" +# if [ -r "$bat_energy_full" ] && [ -r "$bat_energy_now" ]; then +# charge=$(awk -v charge="$charge" -v energy_now="$(cat "$bat_energy_now")" -v energy_full="$(cat "$bat_energy_full")" 'BEGIN { print charge + energy_now / energy_full }') +# fi +# fi +# count=$((count + 1)) +# done << EOF +# $(find /sys/class/power_supply -maxdepth 1 -iname '*bat*') +# EOF +# ;; +# *CYGWIN*|*MSYS*|*MINGW*) +# while IFS= read -r line; do +# [ -z "$line" ] && continue +# if [ x"$discharging" != x"true" ]; then +# discharging=$(printf '%s' "$line" | awk '{ s = ($1 == 1) ? "true" : "false"; print s }') +# fi +# charge=$(printf '%s' "$line" | awk -v charge="$charge" '{ print charge + $2 / 100 }') +# count=$((count + 1)) +# done << EOF +# $(wmic path Win32_Battery get BatteryStatus, EstimatedChargeRemaining | tr -d '\r' | tail -n +2) +# EOF +# ;; +# *OpenBSD*) +# for batid in 0 1 2; do +# sysctl -n "hw.sensors.acpibat$batid.raw0" 2>&1 | grep -q 'not found' && continue +# if [ x"$discharging" != x"true" ]; then +# discharging=$(sysctl -n "hw.sensors.acpibat$batid.raw0" | grep -q 1 && echo "true" || echo "false") +# fi +# if sysctl -n "hw.sensors.acpibat$batid" | grep -q amphour; then +# charge=$(awk -v charge="$charge" -v remaining="$(sysctl -n hw.sensors.acpibat$batid.amphour3 | cut -d' ' -f1)" -v full="$(sysctl -n hw.sensors.acpibat$batid.amphour0 | cut -d' ' -f1)" 'BEGIN { print charge + remaining / full }') +# else +# charge=$(awk -v charge="$charge" -v remaining="$(sysctl -n hw.sensors.acpibat$batid.watthour3 | cut -d' ' -f1)" -v full="$(sysctl -n hw.sensors.acpibat$batid.watthour0 | cut -d' ' -f1)" 'BEGIN { print charge + remaining / full }') +# fi +# count=$((count + 1)) +# done +# ;; +# esac +# charge=$(awk -v charge="$charge" -v count="$count" 'BEGIN { print charge / count }') +# if [ "$charge" -eq 0 ]; then +# tmux set -ug '@battery_status' \;\ +# set -ug '@battery_bar' \;\ +# set -ug '@battery_hbar' \;\ +# set -ug '@battery_vbar' \;\ +# set -ug '@battery_percentage' +# return +# fi +# +# variables=$(tmux show -gqv '@battery_bar_symbol_full' \;\ +# show -gqv '@battery_bar_symbol_empty' \;\ +# show -gqv '@battery_bar_length' \;\ +# show -gqv '@battery_bar_palette' \;\ +# show -gqv '@battery_hbar_palette' \;\ +# show -gqv '@battery_vbar_palette' \;\ +# show -gqv '@battery_status_charging' \;\ +# show -gqv '@battery_status_discharging') +# # shellcheck disable=SC2086 +# { set -f; IFS="$__newline"; set -- $variables; unset IFS; set +f; } +# +# battery_bar_symbol_full=$1 +# battery_bar_symbol_empty=$2 +# battery_bar_length=$3 +# battery_bar_palette=$4 +# battery_hbar_palette=$5 +# battery_vbar_palette=$6 +# battery_status_charging=$7 +# battery_status_discharging=$8 +# +# if [ x"$battery_bar_length" = x"auto" ]; then +# columns=$(tmux -q display -p '#{client_width}' 2> /dev/null || echo 80) +# if [ "$columns" -ge 80 ]; then +# battery_bar_length=10 +# else +# battery_bar_length=5 +# fi +# fi +# +# if [ x"$discharging" = x"true" ]; then +# battery_status="$battery_status_discharging" +# else +# battery_status="$battery_status_charging" +# fi +# +# if echo "$battery_bar_palette" | grep -q -E '^heat|gradient(,[#a-z0-9]{7,9})?$'; then +# # shellcheck disable=SC2086 +# { set -f; IFS=,; set -- $battery_bar_palette; unset IFS; set +f; } +# palette_style=$1 +# battery_bg=${2:-none} +# [ x"$palette_style" = x"gradient" ] && \ +# palette="196 202 208 214 220 226 190 154 118 82 46" +# [ x"$palette_style" = x"heat" ] && \ +# palette="233 234 235 237 239 241 243 245 247 144 143 142 184 214 208 202 196" +# +# palette=$(echo "$palette" | awk -v n="$battery_bar_length" '{ for (i = 0; i < n; ++i) printf $(1 + (i * NF / n))" " }') +# eval set -- "$palette" +# +# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") +# battery_bar="#[bg=$battery_bg]" +# # shellcheck disable=SC2046 +# [ "$full" -gt 0 ] && \ +# battery_bar="$battery_bar$(printf "#[fg=colour%s]$battery_bar_symbol_full" $(echo "$palette" | cut -d' ' -f1-"$full"))" +# # shellcheck disable=SC2046 +# empty=$((battery_bar_length - full)) +# # shellcheck disable=SC2046 +# [ "$empty" -gt 0 ] && \ +# battery_bar="$battery_bar$(printf "#[fg=colour%s]$battery_bar_symbol_empty" $(echo "$palette" | cut -d' ' -f$((full + 1))-$((full + empty))))" +# eval battery_bar="$battery_bar#[fg=colour\${$((full == 0 ? 1 : full))}]" +# elif echo "$battery_bar_palette" | grep -q -E '^(([#a-z0-9]{7,9}|none),?){3}$'; then +# # shellcheck disable=SC2086 +# { set -f; IFS=,; set -- $battery_bar_palette; unset IFS; set +f; } +# battery_full_fg=$1 +# battery_empty_fg=$2 +# battery_bg=$3 +# +# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") +# [ x"$battery_bg" != x"none" ] && \ +# battery_bar="#[bg=$battery_bg]" +# #shellcheck disable=SC2046 +# [ "$full" -gt 0 ] && \ +# battery_bar="$battery_bar#[fg=$battery_full_fg]$(printf "%0.s$battery_bar_symbol_full" $(seq 1 "$full"))" +# empty=$((battery_bar_length - full)) +# #shellcheck disable=SC2046 +# [ "$empty" -gt 0 ] && \ +# battery_bar="$battery_bar#[fg=$battery_empty_fg]$(printf "%0.s$battery_bar_symbol_empty" $(seq 1 "$empty"))" && \ +# battery_bar="$battery_bar#[fg=$battery_empty_fg]" +# fi +# +# if echo "$battery_hbar_palette" | grep -q -E '^heat|gradient(,[#a-z0-9]{7,9})?$'; then +# # shellcheck disable=SC2086 +# { set -f; IFS=,; set -- $battery_hbar_palette; unset IFS; set +f; } +# palette_style=$1 +# [ x"$palette_style" = x"gradient" ] && \ +# palette="196 202 208 214 220 226 190 154 118 82 46" +# [ x"$palette_style" = x"heat" ] && \ +# palette="233 234 235 237 239 241 243 245 247 144 143 142 184 214 208 202 196" +# +# palette=$(echo "$palette" | awk -v n="$battery_bar_length" '{ for (i = 0; i < n; ++i) printf $(1 + (i * NF / n))" " }') +# eval set -- "$palette" +# +# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") +# eval battery_hbar_fg="colour\${$((full == 0 ? 1 : full))}" +# elif echo "$battery_hbar_palette" | grep -q -E '^([#a-z0-9]{7,9},?){3}$'; then +# # shellcheck disable=SC2086 +# { set -f; IFS=,; set -- $battery_hbar_palette; unset IFS; set +f; } +# +# # shellcheck disable=SC2046 +# eval $(awk "BEGIN { printf \"battery_hbar_fg=$%d\", (($charge) - 0.001) * $# + 1 }") +# fi +# +# eval set -- "▏ ▎ ▍ ▌ ▋ ▊ ▉ █" +# # shellcheck disable=SC2046 +# eval $(awk "BEGIN { printf \"battery_hbar_symbol=$%d\", ($charge) * ($# - 1) + 1 }") +# battery_hbar="#[fg=${battery_hbar_fg?}]${battery_hbar_symbol?}" +# +# if echo "$battery_vbar_palette" | grep -q -E '^heat|gradient(,[#a-z0-9]{7,9})?$'; then +# # shellcheck disable=SC2086 +# { set -f; IFS=,; set -- $battery_vbar_palette; unset IFS; set +f; } +# palette_style=$1 +# [ x"$palette_style" = x"gradient" ] && \ +# palette="196 202 208 214 220 226 190 154 118 82 46" +# [ x"$palette_style" = x"heat" ] && \ +# palette="233 234 235 237 239 241 243 245 247 144 143 142 184 214 208 202 196" +# +# palette=$(echo "$palette" | awk -v n="$battery_bar_length" '{ for (i = 0; i < n; ++i) printf $(1 + (i * NF / n))" " }') +# eval set -- "$palette" +# +# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") +# eval battery_vbar_fg="colour\${$((full == 0 ? 1 : full))}" +# elif echo "$battery_vbar_palette" | grep -q -E '^([#a-z0-9]{7,9},?){3}$'; then +# # shellcheck disable=SC2086 +# { set -f; IFS=,; set -- $battery_vbar_palette; unset IFS; set +f; } +# +# # shellcheck disable=SC2046 +# eval $(awk "BEGIN { printf \"battery_vbar_fg=$%d\", (($charge) - 0.001) * $# + 1 }") +# fi +# +# eval set -- "▁ ▂ ▃ ▄ ▅ ▆ ▇ █" +# # shellcheck disable=SC2046 +# eval $(awk "BEGIN { printf \"battery_vbar_symbol=$%d\", ($charge) * ($# - 1) + 1 }") +# battery_vbar="#[fg=${battery_vbar_fg?}]${battery_vbar_symbol?}" +# +# battery_percentage="$(awk "BEGIN { printf \"%.0f%%\", ($charge) * 100 }")" +# +# tmux set -g '@battery_status' "$battery_status" \;\ +# set -g '@battery_bar' "$battery_bar" \;\ +# set -g '@battery_hbar' "$battery_hbar" \;\ +# set -g '@battery_vbar' "$battery_vbar" \;\ +# set -g '@battery_percentage' "$battery_percentage" +# } +# +# _username() { +# tty=${1:-$(tmux display -p '#{pane_tty}')} +# ssh_only=$2 +# # shellcheck disable=SC2039 +# if [ x"$OSTYPE" = x"cygwin" ]; then +# pid=$(ps -a | awk -v tty="${tty##/dev/}" '$5 == tty && /ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { print $1 }') +# [ -n "$pid" ] && ssh_parameters=$(tr '\0' ' ' < "/proc/$pid/cmdline" | sed 's/^ssh //') +# else +# ssh_parameters=$(ps -t "$tty" -o command= | awk '/ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { $1=""; print $0; exit }') +# fi +# if [ -n "$ssh_parameters" ]; then +# # shellcheck disable=SC2086 +# username=$(ssh -G $ssh_parameters 2>/dev/null | awk 'NR > 2 { exit } ; /^user / { print $2 }') +# # shellcheck disable=SC2086 +# [ -z "$username" ] && username=$(ssh -T -o ControlPath=none -o ProxyCommand="sh -c 'echo %%username%% %r >&2'" $ssh_parameters 2>&1 | awk '/^%username% / { print $2; exit }') +# else +# if ! _is_enabled "$ssh_only"; then +# # shellcheck disable=SC2039 +# if [ x"$OSTYPE" = x"cygwin" ]; then +# username=$(whoami) +# else +# username=$(ps -t "$tty" -o user= -o pid= -o ppid= -o command= | awk ' +# !/ssh/ { user[$2] = $1; ppid[$3] = 1 } +# END { +# for (i in user) +# if (!(i in ppid)) +# { +# print user[i] +# exit +# } +# } +# ') +# fi +# fi +# fi +# +# echo "$username" +# } +# +# _hostname() { +# tty=${1:-$(tmux display -p '#{pane_tty}')} +# ssh_only=$2 +# # shellcheck disable=SC2039 +# if [ x"$OSTYPE" = x"cygwin" ]; then +# pid=$(ps -a | awk -v tty="${tty##/dev/}" '$5 == tty && /ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { print $1 }') +# [ -n "$pid" ] && ssh_parameters=$(tr '\0' ' ' < "/proc/$pid/cmdline" | sed 's/^ssh //') +# else +# ssh_parameters=$(ps -t "$tty" -o command= | awk '/ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { $1=""; print $0; exit }') +# fi +# if [ -n "$ssh_parameters" ]; then +# # shellcheck disable=SC2086 +# hostname=$(ssh -G $ssh_parameters 2>/dev/null | awk 'NR > 2 { exit } ; /^hostname / { print $2 }') +# # shellcheck disable=SC2086 +# [ -z "$hostname" ] && hostname=$(ssh -T -o ControlPath=none -o ProxyCommand="sh -c 'echo %%hostname%% %h >&2'" $ssh_parameters 2>&1 | awk '/^%hostname% / { print $2; exit }') +# #shellcheck disable=SC1004 +# hostname=$(echo "$hostname" | awk '\ +# { \ +# if ($1~/^[0-9.:]+$/) \ +# print $1; \ +# else \ +# split($1, a, ".") ; print a[1] \ +# }') +# else +# if ! _is_enabled "$ssh_only"; then +# hostname=$(command hostname -s) +# fi +# fi +# +# echo "$hostname" +# } +# +# _root() { +# tty=${1:-$(tmux display -p '#{pane_tty}')} +# username=$(_username "$tty" false) +# +# if [ x"$username" = x"root" ]; then +# tmux show -gqv '@root' +# else +# echo "" +# fi +# } +# +# _uptime() { +# case $(uname -s) in +# *Darwin*) +# boot=$(sysctl -q -n kern.boottime | awk -F'[ ,:]+' '{ print $4 }') +# now=$(date +%s) +# ;; +# *Linux*|*CYGWIN*|*MSYS*|*MINGW*) +# now=$(cut -d' ' -f1 < /proc/uptime) +# ;; +# *OpenBSD*) +# boot=$(sysctl -n kern.boottime) +# now=$(date +%s) +# esac +# # shellcheck disable=SC1004 +# awk -v boot="$boot" -v now="$now" ' +# BEGIN { +# uptime = now - boot +# d = int(uptime / 86400) +# h = int(uptime / 3600) % 24 +# m = int(uptime / 60) % 60 +# s = int(uptime) % 60 +# +# system("tmux set -g @uptime_d " d + 0 " \\; " \ +# "set -g @uptime_h " h + 0 " \\; " \ +# "set -g @uptime_m " m + 0 " \\; " \ +# "set -g @uptime_s " s + 0) +# }' +# } +# +# _loadavg() { +# case $(uname -s) in +# *Darwin*) +# tmux set -g @loadavg "$(sysctl -q -n vm.loadavg | cut -d' ' -f2)" +# ;; +# *Linux*) +# tmux set -g @loadavg "$(cut -d' ' -f1 < /proc/loadavg)" +# ;; +# *OpenBSD*) +# tmux set -g @loadavg "$(sysctl -q -n vm.loadavg | cut -d' ' -f1)" +# ;; +# esac +# } +# +# _split_window() { +# tty=${1:-$(tmux display -p '#{pane_tty}')} +# shift +# # shellcheck disable=SC2039 +# if [ x"$OSTYPE" = x"cygwin" ]; then +# pid=$(ps -a | sort -d | awk -v tty="${tty##/dev/}" '$5 == tty && /ssh/ && !/-W/ { print $1; exit 0 }') +# [ -n "$pid" ] && ssh=$(tr '\0' ' ' < "/proc/$pid/cmdline") +# else +# ssh=$(ps -t "$tty" -o command= | sort -d | awk '/ssh/ && !/-W/ { print $0; exit 0 }') +# fi +# if [ -n "$ssh" ]; then +# # shellcheck disable=SC2046 +# tmux split-window "$@" $(echo "$ssh" | sed -e "s/;/\\\\;/g") +# else +# tmux split-window "$@" +# fi +# } +# +# _apply_overrides() { +# tmux_conf_theme_24b_colour=${tmux_conf_theme_24b_colour:-false} +# if _is_enabled "$tmux_conf_theme_24b_colour"; then +# case "$TERM" in +# screen-*|tmux-*) +# ;; +# *) +# tmux set-option -ga terminal-overrides ",$TERM:Tc" +# ;; +# esac +# fi +# } +# +# _apply_bindings() { +# line=$(tmux list-keys | grep new-window | head -1) +# prefix=${line%new-window*} +# column=${#prefix} +# +# tmux_conf_new_window_retain_current_path=${tmux_conf_new_window_retain_current_path:-false} +# while IFS= read -r line; do +# [ -z "$line" ] && continue +# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') +# if _is_enabled "$tmux_conf_new_window_retain_current_path"; then +# right=$(printf '%s' "$line" | cut -c"$column-" | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/new-window$/new-window -c "#{pane_current_path}"/g') +# else +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/-c[ \t]+"#\{pane_current_path\}"$//g') +# fi +# eval "tmux $left $right" 2>/dev/null || true +# done << EOF +# $(tmux list-keys 2>/dev/null | grep -e 'new-window\(\s\+-c\s\+"#{pane_current_path}\|$\)') +# EOF +# +# tmux_conf_new_pane_retain_current_path=${tmux_conf_new_pane_retain_current_path:-true} +# while IFS= read -r line; do +# [ -z "$line" ] && continue +# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') +# if _is_enabled "$tmux_conf_new_pane_retain_current_path"; then +# right=$(printf '%s' "$line" | cut -c"$column-" | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/split-window([ \t]+-(h|v))?$/& -c "#{pane_current_path}"/g') +# else +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/-c[ \t]+"#\{pane_current_path\}"$//g') +# fi +# eval "tmux $left $right" 2>/dev/null || true +# done << EOF +# $(tmux list-keys 2>/dev/null | grep -e 'split\(-\|_\)window') +# EOF +# +# tmux_conf_new_pane_reconnect_ssh=${tmux_conf_new_pane_reconnect_ssh:-false} +# while IFS= read -r line; do +# [ -z "$line" ] && continue +# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') +# if _is_enabled "$tmux_conf_new_pane_reconnect_ssh"; then +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/split-window([^;]+)/run-shell "cut -c3- ~\/\.tmux\.conf | sh -s _split_window #{pane_tty}\1"/g') +# else +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/run-shell "cut -c3- ~\/\.tmux\.conf \| sh -s _split_window #\{pane_tty\}([^;]+)"/split-window\1/g' -e 's/#\{.+\}/\"&\"/g') +# fi +# eval "tmux $left $right" 2>/dev/null || true +# done << EOF +# $(tmux list-keys 2>/dev/null | grep -e 'split\(-\|_\)window') +# EOF +# +# tmux_conf_new_session_prompt=${tmux_conf_new_session_prompt:-false} +# while IFS= read -r line; do +# [ -z "$line" ] && continue +# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') +# if _is_enabled "$tmux_conf_new_session_prompt"; then +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/new-session$/command-prompt -p new-session \"new-session -s %%\"/g') +# else +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }'| sed -E -e 's/command-prompt -p new-session[^;]+/new-session/g') +# fi +# eval "tmux $left $right" 2>/dev/null || true +# done << EOF +# $(tmux list-keys 2>/dev/null | grep -e 'new-session') +# EOF +# +# tmux_conf_copy_to_os_clipboard=${tmux_conf_copy_to_os_clipboard:-false} +# command -v pbcopy > /dev/null 2>&1 && command='pbcopy' +# command -v reattach-to-user-namespace > /dev/null 2>&1 && command='reattach-to-user-namespace pbcopy' +# command -v xsel > /dev/null 2>&1 && command='xsel -i -b' +# ! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1 && command='xclip -i -selection clipboard > \/dev\/null 2>\&1' +# command -v clip.exe > /dev/null 2>&1 && command='clip\.exe' +# [ -c /dev/clipboard ] && command='cat > \/dev\/clipboard' +# +# if [ -n "$command" ]; then +# # shellcheck disable=SC2086 +# for table in "" "-t emacs-copy" "-t vi-copy"; do +# line=$(tmux list-keys $table 2>/dev/null | grep -e 'copy-selection\|copy-pipe' | head -1) +# prefix=${line%copy-*} +# column=${#prefix} +# [ -z "$line" ] && continue +# +# while IFS= read -r line; do +# [ -z "$line" ] && continue +# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') +# if _is_enabled "$tmux_conf_copy_to_os_clipboard"; then +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e "s/copy-selection(-and-cancel)?$/copy-pipe\1 \"$command\"/g") +# else +# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e "s/copy-pipe(-and-cancel)? \"$command\"$/copy-selection\1/g") +# fi +# eval "tmux $left $right" 2>/dev/null || true +# done << EOF +# $(tmux list-keys $table 2>/dev/null | grep -e 'copy-selection\|copy-pipe') +# EOF +# done +# fi +# } +# +# _apply_theme() { +# +# # -- panes ------------------------------------------------------------- +# +# tmux_conf_theme_window_fg=${tmux_conf_theme_window_fg:-default} +# tmux_conf_theme_window_bg=${tmux_conf_theme_window_bg:-default} +# tmux_conf_theme_highlight_focused_pane=${tmux_conf_theme_highlight_focused_pane:-false} +# tmux_conf_theme_focused_pane_fg=${tmux_conf_theme_focused_pane_fg:-'default'} # default +# tmux_conf_theme_focused_pane_bg=${tmux_conf_theme_focused_pane_bg:-'#0087d7'} # light blue +# +# # tmux 1.9 doesn't really like set -q +# if tmux show -g -w | grep -q window-style; then +# tmux setw -g window-style "fg=$tmux_conf_theme_window_fg,bg=$tmux_conf_theme_window_bg" +# +# if _is_enabled "$tmux_conf_theme_highlight_focused_pane"; then +# tmux setw -g window-active-style "fg=$tmux_conf_theme_focused_pane_fg,bg=$tmux_conf_theme_focused_pane_bg" +# else +# tmux setw -g window-active-style default +# fi +# fi +# +# tmux_conf_theme_pane_border_style=${tmux_conf_theme_pane_border_style:-thin} +# tmux_conf_theme_pane_border=${tmux_conf_theme_pane_border:-'#444444'} # light gray +# tmux_conf_theme_pane_active_border=${tmux_conf_theme_pane_active_border:-'#00afff'} # light blue +# tmux_conf_theme_pane_border_fg=${tmux_conf_theme_pane_border_fg:-$tmux_conf_theme_pane_border} +# tmux_conf_theme_pane_active_border_fg=${tmux_conf_theme_pane_active_border_fg:-$tmux_conf_theme_pane_active_border} +# case "$tmux_conf_theme_pane_border_style" in +# fat) +# tmux_conf_theme_pane_border_bg=${tmux_conf_theme_pane_border_bg:-$tmux_conf_theme_pane_border_fg} +# tmux_conf_theme_pane_active_border_bg=${tmux_conf_theme_pane_active_border_bg:-$tmux_conf_theme_pane_active_border_fg} +# ;; +# thin|*) +# tmux_conf_theme_pane_border_bg=${tmux_conf_theme_pane_border_bg:-'default'} +# tmux_conf_theme_pane_active_border_bg=${tmux_conf_theme_pane_active_border_bg:-'default'} +# ;; +# esac +# tmux setw -g pane-border-style "fg=$tmux_conf_theme_pane_border_fg,bg=$tmux_conf_theme_pane_border_bg" \; set -g pane-active-border-style "fg=$tmux_conf_theme_pane_active_border_fg,bg=$tmux_conf_theme_pane_active_border_bg" +# +# tmux_conf_theme_pane_indicator=${tmux_conf_theme_pane_indicator:-'#00afff'} # light blue +# tmux_conf_theme_pane_active_indicator=${tmux_conf_theme_pane_active_indicator:-'#00afff'} # light blue +# +# tmux set -g display-panes-colour "$tmux_conf_theme_pane_indicator" \; set -g display-panes-active-colour "$tmux_conf_theme_pane_active_indicator" +# +# # -- status line ------------------------------------------------------- +# +# tmux_conf_theme_left_separator_main=${tmux_conf_theme_left_separator_main-''} +# tmux_conf_theme_left_separator_sub=${tmux_conf_theme_left_separator_sub-'|'} +# tmux_conf_theme_right_separator_main=${tmux_conf_theme_right_separator_main-''} +# tmux_conf_theme_right_separator_sub=${tmux_conf_theme_right_separator_sub-'|'} +# +# tmux_conf_theme_message_fg=${tmux_conf_theme_message_fg:-'#000000'} # black +# tmux_conf_theme_message_bg=${tmux_conf_theme_message_bg:-'#ffff00'} # yellow +# tmux_conf_theme_message_attr=${tmux_conf_theme_message_attr:-'bold'} +# tmux set -g message-style "fg=$tmux_conf_theme_message_fg,bg=$tmux_conf_theme_message_bg,$tmux_conf_theme_message_attr" +# +# tmux_conf_theme_message_command_fg=${tmux_conf_theme_message_command_fg:-'#ffff00'} # yellow +# tmux_conf_theme_message_command_bg=${tmux_conf_theme_message_command_bg:-'#000000'} # black +# tmux_conf_theme_message_command_attr=${tmux_conf_theme_message_command_attr:-'bold'} +# tmux set -g message-command-style "fg=$tmux_conf_theme_message_command_fg,bg=$tmux_conf_theme_message_command_bg,$tmux_conf_theme_message_command_attr" +# +# tmux_conf_theme_mode_fg=${tmux_conf_theme_mode_fg:-'#000000'} # black +# tmux_conf_theme_mode_bg=${tmux_conf_theme_mode_bg:-'#ffff00'} # yellow +# tmux_conf_theme_mode_attr=${tmux_conf_theme_mode_attr:-'bold'} +# tmux setw -g mode-style "fg=$tmux_conf_theme_mode_fg,bg=$tmux_conf_theme_mode_bg,$tmux_conf_theme_mode_attr" +# +# tmux_conf_theme_status_fg=${tmux_conf_theme_status_fg:-'#8a8a8a'} # white +# tmux_conf_theme_status_bg=${tmux_conf_theme_status_bg:-'#080808'} # dark gray +# tmux_conf_theme_status_attr=${tmux_conf_theme_status_attr:-'none'} +# tmux set -g status-style "fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr" \;\ +# set -g status-left-style "fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr" \;\ +# set -g status-right-style "fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr" +# +# tmux_conf_theme_window_status_fg=${tmux_conf_theme_window_status_fg:-'#8a8a8a'} # white +# tmux_conf_theme_window_status_bg=${tmux_conf_theme_window_status_bg:-'#080808'} # dark gray +# tmux_conf_theme_window_status_attr=${tmux_conf_theme_window_status_attr:-'none'} +# tmux_conf_theme_window_status_format=${tmux_conf_theme_window_status_format:-'#I #W'} +# +# tmux_conf_theme_window_status_current_fg=${tmux_conf_theme_window_status_current_fg:-'#000000'} # black +# tmux_conf_theme_window_status_current_bg=${tmux_conf_theme_window_status_current_bg:-'#00afff'} # light blue +# tmux_conf_theme_window_status_current_attr=${tmux_conf_theme_window_status_current_attr:-'bold'} +# tmux_conf_theme_window_status_current_format=${tmux_conf_theme_window_status_current_format:-'#I #W'} +# if [ x"$(tmux show -g -v status-justify)" = x"right" ]; then +# tmux_conf_theme_window_status_current_format="#[fg=$tmux_conf_theme_window_status_current_bg,bg=$tmux_conf_theme_window_status_bg]$tmux_conf_theme_right_separator_main#[fg=default,bg=default,default] $tmux_conf_theme_window_status_current_format #[fg=$tmux_conf_theme_window_status_bg,bg=$tmux_conf_theme_window_status_current_bg,none]$tmux_conf_theme_right_separator_main" +# else +# tmux_conf_theme_window_status_current_format="#[fg=$tmux_conf_theme_window_status_bg,bg=$tmux_conf_theme_window_status_current_bg]$tmux_conf_theme_left_separator_main#[fg=default,bg=default,default] $tmux_conf_theme_window_status_current_format #[fg=$tmux_conf_theme_window_status_current_bg,bg=$tmux_conf_theme_status_bg,none]$tmux_conf_theme_left_separator_main" +# fi +# +# tmux_conf_theme_window_status_format=$(echo "$tmux_conf_theme_window_status_format" | sed 's%#{circled_window_index}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #I)%g') +# tmux_conf_theme_window_status_current_format=$(echo "$tmux_conf_theme_window_status_current_format" | sed 's%#{circled_window_index}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #I)%g') +# +# tmux setw -g window-status-style "fg=$tmux_conf_theme_window_status_fg,bg=$tmux_conf_theme_window_status_bg,$tmux_conf_theme_window_status_attr" \;\ +# setw -g window-status-format "$tmux_conf_theme_window_status_format" \;\ +# setw -g window-status-current-style "fg=$tmux_conf_theme_window_status_current_fg,bg=$tmux_conf_theme_window_status_current_bg,$tmux_conf_theme_window_status_current_attr" \;\ +# setw -g window-status-current-format "$tmux_conf_theme_window_status_current_format" +# +# tmux_conf_theme_window_status_activity_fg=${tmux_conf_theme_window_status_activity_fg:-'default'} +# tmux_conf_theme_window_status_activity_bg=${tmux_conf_theme_window_status_activity_bg:-'default'} +# tmux_conf_theme_window_status_activity_attr=${tmux_conf_theme_window_status_activity_attr:-'underscore'} +# tmux setw -g window-status-activity-style "fg=$tmux_conf_theme_window_status_activity_fg,bg=$tmux_conf_theme_window_status_activity_bg,$tmux_conf_theme_window_status_activity_attr" +# +# tmux_conf_theme_window_status_bell_fg=${tmux_conf_theme_window_status_bell_fg:-'#ffff00'} # yellow +# tmux_conf_theme_window_status_bell_bg=${tmux_conf_theme_window_status_bell_bg:-'default'} +# tmux_conf_theme_window_status_bell_attr=${tmux_conf_theme_window_status_bell_attr:-'blink,bold'} +# tmux setw -g window-status-bell-style "fg=$tmux_conf_theme_window_status_bell_fg,bg=$tmux_conf_theme_window_status_bell_bg,$tmux_conf_theme_window_status_bell_attr" +# +# tmux_conf_theme_window_status_last_fg=${tmux_conf_theme_window_status_last_fg:-'#00afff'} # light blue +# tmux_conf_theme_window_status_last_bg=${tmux_conf_theme_window_status_last_bg:-'default'} +# tmux_conf_theme_window_status_last_attr=${tmux_conf_theme_window_status_last_attr:-'none'} +# tmux setw -g window-status-last-style "fg=$tmux_conf_theme_window_status_last_fg,bg=$tmux_conf_theme_window_status_last_bg,$tmux_conf_theme_window_status_last_attr" +# +# # -- indicators +# +# tmux_conf_theme_pairing=${tmux_conf_theme_pairing:-'👓'} # U+1F453 +# tmux_conf_theme_pairing_fg=${tmux_conf_theme_pairing_fg:-'#e4e4e4'} # white +# tmux_conf_theme_pairing_bg=${tmux_conf_theme_pairing_bg:-'none'} +# tmux_conf_theme_pairing_attr=${tmux_conf_theme_pairing_attr:-'none'} +# +# tmux_conf_theme_prefix=${tmux_conf_theme_prefix:-'⌨'} # U+2328 +# tmux_conf_theme_prefix_fg=${tmux_conf_theme_prefix_fg:-'#e4e4e4'} # white +# tmux_conf_theme_prefix_bg=${tmux_conf_theme_prefix_bg:-'none'} +# tmux_conf_theme_prefix_attr=${tmux_conf_theme_prefix_attr:-'none'} +# +# tmux_conf_theme_root=${tmux_conf_theme_root:-'!'} +# tmux_conf_theme_root_fg=${tmux_conf_theme_root_fg:-'none'} +# tmux_conf_theme_root_bg=${tmux_conf_theme_root_bg:-'none'} +# tmux_conf_theme_root_attr=${tmux_conf_theme_root_attr:-'bold,blink'} +# +# # -- status left style +# +# tmux_conf_theme_status_left=${tmux_conf_theme_status_left-' ❐ #S '} +# tmux_conf_theme_status_left_fg=${tmux_conf_theme_status_left_fg:-'#000000,#e4e4e4,#e4e4e4'} # black, white , white +# tmux_conf_theme_status_left_bg=${tmux_conf_theme_status_left_bg:-'#ffff00,#ff00af,#00afff'} # yellow, pink, white blue +# tmux_conf_theme_status_left_attr=${tmux_conf_theme_status_left_attr:-'bold,none,none'} +# +# tmux_conf_theme_status_left=$(echo "$tmux_conf_theme_status_left" | sed \ +# -e "s/#{pairing}/#[fg=$tmux_conf_theme_pairing_fg]#[bg=$tmux_conf_theme_pairing_bg]#[$tmux_conf_theme_pairing_attr]#{?session_many_attached,$tmux_conf_theme_pairing,}/g") +# +# tmux_conf_theme_status_left=$(echo "$tmux_conf_theme_status_left" | sed \ +# -e "s/#{prefix}/#[fg=$tmux_conf_theme_prefix_fg]#[bg=$tmux_conf_theme_prefix_bg]#[$tmux_conf_theme_prefix_attr]#{?client_prefix,$tmux_conf_theme_prefix,}/g") +# +# tmux_conf_theme_status_left=$(echo "$tmux_conf_theme_status_left" | sed \ +# -e "s%#{root}%#[fg=$tmux_conf_theme_root_fg]#[bg=$tmux_conf_theme_root_bg]#[$tmux_conf_theme_root_attr]#(cut -c3- ~/.tmux.conf | sh -s _root #{pane_tty} #D)#[inherit]%g") +# +# if [ -n "$tmux_conf_theme_status_left" ]; then +# status_left=$(awk \ +# -v fg_="$tmux_conf_theme_status_left_fg" \ +# -v bg_="$tmux_conf_theme_status_left_bg" \ +# -v attr_="$tmux_conf_theme_status_left_attr" \ +# -v mainsep="$tmux_conf_theme_left_separator_main" \ +# -v subsep="$tmux_conf_theme_left_separator_sub" ' +# function subsplit(s, l, i, a, r) +# { +# l = split(s, a, ",") +# for (i = 1; i <= l; ++i) +# { +# o = split(a[i], _, "(") - 1 +# c = split(a[i], _, ")") - 1 +# open += o - c +# o_ = split(a[i], _, "{") - 1 +# c_ = split(a[i], _, "}") - 1 +# open_ += o_ - c_ +# o__ = split(a[i], _, "[") - 1 +# c__ = split(a[i], _, "]") - 1 +# open__ += o__ - c__ +# +# if (i == l) +# r = sprintf("%s%s", r, a[i]) +# else if (open || open_ || open__) +# r = sprintf("%s%s,", r, a[i]) +# else +# r = sprintf("%s%s#[fg=%s,bg=%s,%s]%s", r, a[i], fg[j], bg[j], attr[j], subsep) +# } +# +# gsub(/#\[inherit\]/, sprintf("#[default]#[fg=%s,bg=%s,%s]", fg[j], bg[j], attr[j]), r) +# return r +# } +# BEGIN { +# FS = "|" +# l1 = split(fg_, fg, ",") +# l2 = split(bg_, bg, ",") +# l3 = split(attr_, attr, ",") +# l = l1 < l2 ? (l1 < l3 ? l1 : l3) : (l2 < l3 ? l2 : l3) +# } +# { +# for (i = j = 1; i <= NF; ++i) +# { +# if (open || open_ || open__) +# printf "|%s", subsplit($i) +# else +# { +# if (i > 1) +# printf "#[fg=%s,bg=%s,none]%s#[fg=%s,bg=%s,%s]%s", bg[j_], bg[j], mainsep, fg[j], bg[j], attr[j], subsplit($i) +# else +# printf "#[fg=%s,bg=%s,%s]%s", fg[j], bg[j], attr[j], subsplit($i) +# } +# +# if (!open && !open_ && !open__) +# { +# j_ = j +# j = j % l + 1 +# } +# } +# printf "#[fg=%s,bg=%s,none]%s", bg[j_], "default", mainsep +# }' << EOF +# $tmux_conf_theme_status_left +# EOF +# ) +# fi +# +# status_left="$status_left " +# +# # -- status right style +# +# tmux_conf_theme_status_right=${tmux_conf_theme_status_right-'#{pairing}#{prefix} #{battery_status} #{battery_bar} #{battery_percentage} , %R , %d %b | #{username} | #{hostname} '} +# tmux_conf_theme_status_right_fg=${tmux_conf_theme_status_right_fg:-'#8a8a8a,#e4e4e4,#000000'} # light gray, white, black +# tmux_conf_theme_status_right_bg=${tmux_conf_theme_status_right_bg:-'#080808,#d70000,#e4e4e4'} # dark gray, red, white +# tmux_conf_theme_status_right_attr=${tmux_conf_theme_status_right_attr:-'none,none,bold'} +# +# tmux_conf_theme_status_right=$(echo "$tmux_conf_theme_status_right" | sed \ +# -e "s/#{pairing}/#[fg=$tmux_conf_theme_pairing_fg]#[bg=$tmux_conf_theme_pairing_bg]#[$tmux_conf_theme_pairing_attr]#{?session_many_attached,$tmux_conf_theme_pairing,}/g") +# +# tmux_conf_theme_status_right=$(echo "$tmux_conf_theme_status_right" | sed \ +# -e "s/#{prefix}/#[fg=$tmux_conf_theme_prefix_fg]#[bg=$tmux_conf_theme_prefix_bg]#[$tmux_conf_theme_prefix_attr]#{?client_prefix,$tmux_conf_theme_prefix,}/g") +# +# tmux_conf_theme_status_right=$(echo "$tmux_conf_theme_status_right" | sed \ +# -e "s%#{root}%#[fg=$tmux_conf_theme_root_fg]#[bg=$tmux_conf_theme_root_bg]#[$tmux_conf_theme_root_attr]#(cut -c3- ~/.tmux.conf | sh -s _root #{pane_tty} #D)#[inherit]%g") +# +# if [ -n "$tmux_conf_theme_status_right" ]; then +# status_right=$(awk \ +# -v fg_="$tmux_conf_theme_status_right_fg" \ +# -v bg_="$tmux_conf_theme_status_right_bg" \ +# -v attr_="$tmux_conf_theme_status_right_attr" \ +# -v mainsep="$tmux_conf_theme_right_separator_main" \ +# -v subsep="$tmux_conf_theme_right_separator_sub" ' +# function subsplit(s, l, i, a, r) +# { +# l = split(s, a, ",") +# for (i = 1; i <= l; ++i) +# { +# o = split(a[i], _, "(") - 1 +# c = split(a[i], _, ")") - 1 +# open += o - c +# o_ = split(a[i], _, "{") - 1 +# c_ = split(a[i], _, "}") - 1 +# open_ += o_ - c_ +# o__ = split(a[i], _, "[") - 1 +# c__ = split(a[i], _, "]") - 1 +# open__ += o__ - c__ +# +# if (i == l) +# r = sprintf("%s%s", r, a[i]) +# else if (open || open_ || open__) +# r = sprintf("%s%s,", r, a[i]) +# else +# r = sprintf("%s%s#[fg=%s,bg=%s,%s]%s", r, a[i], fg[j], bg[j], attr[j], subsep) +# } +# +# gsub(/#\[inherit\]/, sprintf("#[default]#[fg=%s,bg=%s,%s]", fg[j], bg[j], attr[j]), r) +# return r +# } +# BEGIN { +# FS = "|" +# l1 = split(fg_, fg, ",") +# l2 = split(bg_, bg, ",") +# l3 = split(attr_, attr, ",") +# l = l1 < l2 ? (l1 < l3 ? l1 : l3) : (l2 < l3 ? l2 : l3) +# } +# { +# for (i = j = 1; i <= NF; ++i) +# { +# if (open_ || open || open__) +# printf "|%s", subsplit($i) +# else +# printf "#[fg=%s,bg=%s,none]%s#[fg=%s,bg=%s,%s]%s", bg[j], (i == 1) ? "default" : bg[j_], mainsep, fg[j], bg[j], attr[j], subsplit($i) +# +# if (!open && !open_ && !open__) +# { +# j_ = j +# j = j % l + 1 +# } +# } +# }' << EOF +# $tmux_conf_theme_status_right +# EOF +# ) +# fi +# +# # -- variables +# +# tmux set -g '@root' "$tmux_conf_theme_root" +# +# tmux_conf_battery_bar_symbol_full=${tmux_conf_battery_bar_symbol_full:-'◼'} +# tmux_conf_battery_bar_symbol_empty=${tmux_conf_battery_bar_symbol_empty:-'◻'} +# tmux_conf_battery_bar_length=${tmux_conf_battery_bar_length:-'auto'} +# tmux_conf_battery_bar_palette=${tmux_conf_battery_bar_palette:-'gradient'} +# tmux_conf_battery_hbar_palette=${tmux_conf_battery_hbar_palette:-'gradient'} # red, orange, green +# tmux_conf_battery_vbar_palette=${tmux_conf_battery_vbar_palette:-'gradient'} # red, orange, green +# tmux_conf_battery_status_charging=${tmux_conf_battery_status_charging:-'↑'} # U+2191 +# tmux_conf_battery_status_discharging=${tmux_conf_battery_status_discharging:-'↓'} # U+2193 +# +# case "$status_left $status_right" in +# *'#{battery_status}'*|*'#{battery_bar}'*|*'#{battery_hbar}'*|*'#{battery_vbar}'*|*'#{battery_percentage}'*) +# status_left=$(echo "$status_left" | sed -E \ +# -e 's/#\{(\?)?battery_bar/#\{\1@battery_bar/g' \ +# -e 's/#\{(\?)?battery_hbar/#\{\1@battery_hbar/g' \ +# -e 's/#\{(\?)?battery_vbar/#\{\1@battery_vbar/g' \ +# -e 's/#\{(\?)?battery_status/#\{\1@battery_status/g' \ +# -e 's/#\{(\?)?battery_percentage/#\{\1@battery_percentage/g') +# status_right=$(echo "$status_right" | sed -E \ +# -e 's/#\{(\?)?battery_bar/#\{\1@battery_bar/g' \ +# -e 's/#\{(\?)?battery_hbar/#\{\1@battery_hbar/g' \ +# -e 's/#\{(\?)?battery_vbar/#\{\1@battery_vbar/g' \ +# -e 's/#\{(\?)?battery_status/#\{\1@battery_status/g' \ +# -e 's/#\{(\?)?battery_percentage/#\{\1@battery_percentage/g') +# +# tmux set -g '@battery_bar_symbol_full' "$tmux_conf_battery_bar_symbol_full" \;\ +# set -g '@battery_bar_symbol_empty' "$tmux_conf_battery_bar_symbol_empty" \;\ +# set -g '@battery_bar_length' "$tmux_conf_battery_bar_length" \;\ +# set -g '@battery_bar_palette' "$tmux_conf_battery_bar_palette" \;\ +# set -g '@battery_hbar_palette' "$tmux_conf_battery_hbar_palette" \;\ +# set -g '@battery_vbar_palette' "$tmux_conf_battery_vbar_palette" \;\ +# set -g '@battery_status_charging' "$tmux_conf_battery_status_charging" \;\ +# set -g '@battery_status_discharging' "$tmux_conf_battery_status_discharging" +# status_right="#(cut -c3- ~/.tmux.conf | sh -s _battery)$status_right" +# ;; +# esac +# +# case "$status_left $status_right" in +# *'#{username}'*|*'#{hostname}'*|*'#{username_ssh}'*|*'#{hostname_ssh}'*) +# status_left=$(echo "$status_left" | sed \ +# -e 's%#{username}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} false #D)%g' \ +# -e 's%#{hostname}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} false #D)%g' \ +# -e 's%#{username_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} true #D)%g' \ +# -e 's%#{hostname_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} true #D)%g') +# status_right=$(echo "$status_right" | sed \ +# -e 's%#{username}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} false #D)%g' \ +# -e 's%#{hostname}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} false #D)%g' \ +# -e 's%#{username_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} true #D)%g' \ +# -e 's%#{hostname_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} true #D)%g') +# ;; +# esac +# +# case "$status_left $status_right" in +# *'#{uptime_d}'*|*'#{uptime_h}'*|*'#{uptime_m}'*) +# status_left=$(echo "$status_left" | sed -E \ +# -e 's/#\{(\?)?uptime_d/#\{\1@uptime_d/g' \ +# -e 's/#\{(\?)?uptime_h/#\{\1@uptime_h/g' \ +# -e 's/#\{(\?)?uptime_m/#\{\1@uptime_m/g' \ +# -e 's/#\{(\?)?uptime_s/#\{\1@uptime_s/g') +# status_right=$(echo "$status_right" | sed -E \ +# -e 's/#\{(\?)?uptime_d/#\{\1@uptime_d/g' \ +# -e 's/#\{(\?)?uptime_h/#\{\1@uptime_h/g' \ +# -e 's/#\{(\?)?uptime_m/#\{\1@uptime_m/g' \ +# -e 's/#\{(\?)?uptime_s/#\{\1@uptime_s/g') +# status_right="#(cut -c3- ~/.tmux.conf | sh -s _uptime)$status_right" +# ;; +# esac +# +# case "$status_left $status_right" in +# *'#{loadavg}'*) +# status_left=$(echo "$status_left" | sed -E \ +# -e 's/#\{(\?)?loadavg/#\{\1@loadavg/g') +# status_right=$(echo "$status_right" | sed -E \ +# -e 's/#\{(\?)?loadavg/#\{\1@loadavg/g') +# status_right="#(cut -c3- ~/.tmux.conf | sh -s _loadavg)$status_right" +# ;; +# esac +# +# status_left=$(echo "$status_left" | sed 's%#{circled_session_name}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #S)%g') +# status_right=$(echo "$status_right" | sed 's%#{circled_session_name}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #S)%g') +# +# tmux set -g status-left-length 1000 \; set -g status-left "$status_left" \;\ +# set -g status-right-length 1000 \; set -g status-right "$status_right" +# +# # -- clock ------------------------------------------------------------- +# +# tmux_conf_theme_clock_colour=${tmux_conf_theme_clock_colour:-'#00afff'} # light blue +# tmux_conf_theme_clock_style=${tmux_conf_theme_clock_style:-'24'} +# tmux setw -g clock-mode-colour "$tmux_conf_theme_clock_colour" \;\ +# setw -g clock-mode-style "$tmux_conf_theme_clock_style" +# } +# +# _apply_configuration() { +# +# # see https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard +# if command -v reattach-to-user-namespace > /dev/null 2>&1; then +# default_shell="$(tmux show -gv default-shell)" +# case "$default_shell" in +# *fish) +# tmux set -g default-command "reattach-to-user-namespace -l $default_shell" +# ;; +# *sh) +# tmux set -g default-command "exec $default_shell... 2> /dev/null & reattach-to-user-namespace -l $default_shell" +# ;; +# esac +# fi +# +# _apply_overrides +# _apply_bindings +# _apply_theme +# for name in $(printenv | grep -Eo '^tmux_conf_[^=]+'); do tmux setenv -gu "$name"; done; +# } +# +# _urlview() { +# tmux capture-pane -J -S - -E - -b "urlview-$1" -t "$1" +# tmux split-window "tmux show-buffer -b urlview-$1 | urlview || true; tmux delete-buffer -b urlview-$1" +# } +# +# _fpp() { +# tmux capture-pane -J -S - -E - -b "fpp-$1" -t "$1" +# tmux split-window "tmux show-buffer -b fpp-$1 | fpp || true; tmux delete-buffer -b fpp-$1" +# } +# +# "$@" diff --git a/config/tmux/.tmux.conf.local b/config/tmux/.tmux.conf.local new file mode 100644 index 0000000..5d053ee --- /dev/null +++ b/config/tmux/.tmux.conf.local @@ -0,0 +1,267 @@ +# https://github.com/gpakosz/.tmux +# (‑●‑●)> dual licensed under the WTFPL v2 license and the MIT license, +# without any warranty. +# Copyright 2012— Gregory Pakosz (@gpakosz). + + +# -- navigation ---------------------------------------------------------------- + +# if you're running tmux within iTerm2 +# - and tmux is 1.9 or 1.9a +# - and iTerm2 is configured to let option key act as +Esc +# - and iTerm2 is configured to send [1;9A -> [1;9D for option + arrow keys +# then uncomment the following line to make Meta + arrow keys mapping work +#set -ga terminal-overrides "*:kUP3=\e[1;9A,*:kDN3=\e[1;9B,*:kRIT3=\e[1;9C,*:kLFT3=\e[1;9D" + + +# -- windows & pane creation --------------------------------------------------- + +# new window retains current path, possible values are: +# - true +# - false (default) +tmux_conf_new_window_retain_current_path=false + +# new pane retains current path, possible values are: +# - true (default) +# - false +tmux_conf_new_pane_retain_current_path=true + +# new pane tries to reconnect ssh sessions (experimental), possible values are: +# - true +# - false (default) +tmux_conf_new_pane_reconnect_ssh=false + +# prompt for session name when creating a new session, possible values are: +# - true +# - false (default) +tmux_conf_new_session_prompt=false + + +# -- display ------------------------------------------------------------------- + +# RGB 24-bit colour support (tmux >= 2.2), possible values are: +# - true +# - false (default) +tmux_conf_theme_24b_colour=false + +# window style +tmux_conf_theme_window_fg='default' +tmux_conf_theme_window_bg='default' + +# highlight focused pane (tmux >= 2.1), possible values are: +# - true +# - false (default) +tmux_conf_theme_highlight_focused_pane=false + +# focused pane colours: +tmux_conf_theme_focused_pane_fg='default' +tmux_conf_theme_focused_pane_bg='#0087d7' # light blue + +# pane border style, possible values are: +# - thin (default) +# - fat +tmux_conf_theme_pane_border_style=thin + +# pane borders colours: +tmux_conf_theme_pane_border='#444444' # gray +tmux_conf_theme_pane_active_border='#00afff' # light blue + +# pane indicator colours +tmux_conf_theme_pane_indicator='#00afff' # light blue +tmux_conf_theme_pane_active_indicator='#00afff' # light blue + +# status line style +tmux_conf_theme_message_fg='#000000' # black +tmux_conf_theme_message_bg='#ffff00' # yellow +tmux_conf_theme_message_attr='bold' + +# status line command style ( : Escape) +tmux_conf_theme_message_command_fg='#ffff00' # yellow +tmux_conf_theme_message_command_bg='#000000' # black +tmux_conf_theme_message_command_attr='bold' + +# window modes style +tmux_conf_theme_mode_fg='#000000' # black +tmux_conf_theme_mode_bg='#ffff00' # yellow +tmux_conf_theme_mode_attr='bold' + +# status line style +tmux_conf_theme_status_fg='#8a8a8a' # light gray +tmux_conf_theme_status_bg='#080808' # dark gray +tmux_conf_theme_status_attr='none' + +# window status style +# - built-in variables are: +# - #{circled_window_index} +tmux_conf_theme_window_status_fg='#8a8a8a' # light gray +tmux_conf_theme_window_status_bg='#080808' # dark gray +tmux_conf_theme_window_status_attr='none' +tmux_conf_theme_window_status_format='#I #W' +#tmux_conf_theme_window_status_format='#{circled_window_index} #W' +#tmux_conf_theme_window_status_format='#I #W#{?window_bell_flag,🔔,}#{?window_zoomed_flag,🔍,}' + +# window current status style +# - built-in variables are: +# - #{circled_window_index} +tmux_conf_theme_window_status_current_fg='#000000' # black +tmux_conf_theme_window_status_current_bg='#00afff' # light blue +tmux_conf_theme_window_status_current_attr='bold' +tmux_conf_theme_window_status_current_format='#I #W' +#tmux_conf_theme_window_status_current_format='#{circled_window_index} #W' +#tmux_conf_theme_window_status_current_format='#I #W#{?window_zoomed_flag,🔍,}' + +# window activity status style +tmux_conf_theme_window_status_activity_fg='default' +tmux_conf_theme_window_status_activity_bg='default' +tmux_conf_theme_window_status_activity_attr='underscore' + +# window bell status style +tmux_conf_theme_window_status_bell_fg='#ffff00' # yellow +tmux_conf_theme_window_status_bell_bg='default' +tmux_conf_theme_window_status_bell_attr='blink,bold' + +# window last status style +tmux_conf_theme_window_status_last_fg='#00afff' # light blue +tmux_conf_theme_window_status_last_bg='default' +tmux_conf_theme_window_status_last_attr='none' + +# status left/right sections separators +tmux_conf_theme_left_separator_main='' +tmux_conf_theme_left_separator_sub='|' +tmux_conf_theme_right_separator_main='' +tmux_conf_theme_right_separator_sub='|' +#tmux_conf_theme_left_separator_main='' # /!\ you don't need to install Powerline +#tmux_conf_theme_left_separator_sub='' # you only need fonts patched with +#tmux_conf_theme_right_separator_main='' # Powerline symbols or the standalone +#tmux_conf_theme_right_separator_sub='' # PowerlineSymbols.otf font + +# status left/right content: +# - separate main sections with '|' +# - separate subsections with ',' +# - built-in variables are: +# - #{battery_bar} +# - #{battery_hbar} +# - #{battery_percentage} +# - #{battery_status} +# - #{battery_vbar} +# - #{circled_session_name} +# - #{hostname_ssh} +# - #{hostname} +# - #{loadavg} +# - #{pairing} +# - #{prefix} +# - #{root} +# - #{uptime_d} +# - #{uptime_h} +# - #{uptime_m} +# - #{uptime_s} +# - #{username} +# - #{username_ssh} +tmux_conf_theme_status_left=' ❐ #S | ↑#{?uptime_d, #{uptime_d}d,}#{?uptime_h, #{uptime_h}h,}#{?uptime_m, #{uptime_m}m,} ' +tmux_conf_theme_status_right='#{prefix}#{pairing} #{?battery_status, #{battery_status},}#{?battery_bar, #{battery_bar},}#{?battery_percentage, #{battery_percentage},} , %R , %d %b | #{username}#{root} | #{hostname} ' + +# status left style +tmux_conf_theme_status_left_fg='#000000,#e4e4e4,#e4e4e4' # black, white , white +tmux_conf_theme_status_left_bg='#ffff00,#ff00af,#00afff' # yellow, pink, white blue +tmux_conf_theme_status_left_attr='bold,none,none' + +# status right style +tmux_conf_theme_status_right_fg='#8a8a8a,#e4e4e4,#000000' # light gray, white, black +tmux_conf_theme_status_right_bg='#080808,#d70000,#e4e4e4' # dark gray, red, white +tmux_conf_theme_status_right_attr='none,none,bold' + +# pairing indicator +tmux_conf_theme_pairing='👓' # U+1F453 +tmux_conf_theme_pairing_fg='none' +tmux_conf_theme_pairing_bg='none' +tmux_conf_theme_pairing_attr='none' + +# prefix indicator +tmux_conf_theme_prefix='⌨' # U+2328 +tmux_conf_theme_prefix_fg='none' +tmux_conf_theme_prefix_bg='none' +tmux_conf_theme_prefix_attr='none' + +# root indicator +tmux_conf_theme_root='!' +tmux_conf_theme_root_fg='none' +tmux_conf_theme_root_bg='none' +tmux_conf_theme_root_attr='bold,blink' + +# battery bar symbols +#tmux_conf_battery_bar_symbol_full='◼' +#tmux_conf_battery_bar_symbol_empty='◻' +tmux_conf_battery_bar_symbol_full='♥' +tmux_conf_battery_bar_symbol_empty='·' + +# battery bar length (in number of symbols), possible values are: +# - auto +# - a number, e.g. 5 +tmux_conf_battery_bar_length='auto' + +# battery bar palette, possible values are: +# - gradient (default) +# - heat +# - 'colour_full_fg,colour_empty_fg,colour_bg' +tmux_conf_battery_bar_palette='gradient' +#tmux_conf_battery_bar_palette='#d70000,#e4e4e4,#000000' # red, white, black + +# battery hbar palette, possible values are: +# - gradient (default) +# - heat +# - 'colour_low,colour_half,colour_full' +tmux_conf_battery_hbar_palette='gradient' +#tmux_conf_battery_hbar_palette='#d70000,#ff5f00,#5fff00' # red, orange, green + +# battery vbar palette, possible values are: +# - gradient (default) +# - heat +# - 'colour_low,colour_half,colour_full' +tmux_conf_battery_vbar_palette='gradient' +#tmux_conf_battery_vbar_palette='#d70000,#ff5f00,#5fff00' # red, orange, green + +# symbols used to indicate whether battery is charging or discharging +tmux_conf_battery_status_charging='↑' # U+2191 +tmux_conf_battery_status_discharging='↓' # U+2193 +#tmux_conf_battery_status_charging='⚡ ' # U+26A1 +#tmux_conf_battery_status_charging='🔌 ' # U+1F50C +#tmux_conf_battery_status_discharging='🔋 ' # U+1F50B + +# clock style +tmux_conf_theme_clock_colour='#00afff' # light blue +tmux_conf_theme_clock_style='24' + + +# -- clipboard ----------------------------------------------------------------- + +# in copy mode, copying selection also copies to the OS clipboard +# - true +# - false (default) +# on macOS, this requires installing reattach-to-user-namespace, see README.md +# on Linux, this requires xsel or xclip +tmux_conf_copy_to_os_clipboard=false + + +# -- user customizations ------------------------------------------------------- +# this is the place to override or undo settings + +# increase history size +set -g history-limit 10000 + +# start with mouse mode enabled +#set -g mouse on + +# force Vi mode +# really you should export VISUAL or EDITOR environment variable, see manual +#set -g status-keys vi +#set -g mode-keys vi + +# replace C-b by C-a instead of using both prefixes +# set -gu prefix2 +# unbind C-a +# unbind C-b +# set -g prefix C-a +# bind C-a send-prefix + +# move status line to top +#set -g status-position top diff --git a/config/tmux/LICENSE.MIT b/config/tmux/LICENSE.MIT new file mode 100644 index 0000000..cbda5cd --- /dev/null +++ b/config/tmux/LICENSE.MIT @@ -0,0 +1,18 @@ +Copyright 2012— Gregory Pakosz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/config/tmux/LICENSE.WTFPLv2 b/config/tmux/LICENSE.WTFPLv2 new file mode 100644 index 0000000..c6c7def --- /dev/null +++ b/config/tmux/LICENSE.WTFPLv2 @@ -0,0 +1,13 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/config/tmux/README.md b/config/tmux/README.md new file mode 100644 index 0000000..9dad518 --- /dev/null +++ b/config/tmux/README.md @@ -0,0 +1,318 @@ +.tmux +===== + +Self-contained, pretty and versatile `.tmux.conf` configuration file. + +![Screenshot](https://cloud.githubusercontent.com/assets/553208/19740585/85596a5a-9bbf-11e6-8aa1-7c8d9829c008.gif) + +Installation +------------ + +Requirements: + + - tmux **`>= 2.1`** running inside Linux, Mac, OpenBSD, Cygwin or WSL (Bash on + Ubuntu on Windows) + - outside of tmux, `$TERM` must be set to `xterm-256color` + +To install, run the following from your terminal: (you may want to backup your +existing `~/.tmux.conf` first) + +``` +$ cd +$ git clone https://github.com/gpakosz/.tmux.git +$ ln -s -f .tmux/.tmux.conf +$ cp .tmux/.tmux.conf.local . +``` + +Then proceed to [customize] your `~/.tmux.conf.local` copy. + +[customize]: #enabling-the-powerline-look + +If you're a Vim user, setting the `$EDITOR` environment variable to `vim` will +enable and further customize the vi-style key bindings (see tmux manual). + +If you're new to tmux, I recommmend you read [tmux 2: Productive Mouse-Free +Development][bhtmux2] by [@bphogan]. + +[bhtmux2]: https://pragprog.com/book/bhtmux2/tmux-2 +[@bphogan]: https://twitter.com/bphogan + +Troubleshooting +--------------- + + - **I'm running tmux `HEAD` and things don't work properly. What should I do?** + + Please open an issue describing what doesn't work with upcoming tmux. I'll do + my best to address it. + + - **Status line is broken and/or gets duplicated at the bottom of the screen. + What gives?** + + This particularly happens on Linux when the distribution provides a version + of glib that received Unicode 9.0 upgrades (glib `>= 2.50.1`) while providing + a version of glibc that didn't (glibc `< 2.26`). You may also configure + `LC_CTYPE` to use an `UTF-8` locale. Typically VTE based terminal emulators + rely on glib's `g_unichar_iswide()` function while tmux relies on glibc's + `wcwidth()` function. When these two functions disagree, display gets messed + up. + + This can also happen on macOS when using iTerm2 and "Use Unicode version 9 + character widths" is enabled in `Preferences... > Profiles > Text` + + For that reason, the default `~/.tmux.conf.local` file stopped using Unicode + characters for which width changed in between Unicode 8.0 and 9.0 standards, + as well as Emojis. + + - **I installed Powerline and/or (patched) fonts but can't see Powerline + symbols.** + + First, you don't need to install Powerline. You only need fonts patched with + Powerline symbols or the standalone `PowerlineSymbols.otf` font. Then make + sure your `~/.tmux.conf.local` copy uses the right code points for + `tmux_conf_theme_left_separator_XXX` values. + + - **I'm using Bash On Windows (WSL), colors and Powerline look are broken.** + + There is currently a [bug][1681] in the new console powering Bash On Windows + preventing text attributes (bold, underscore, ...) to combine properly with + colors. The workaround is to search your `~/.tmux.conf.local` copy and + replace attributes with `'none'`. + + Also, until Window's console replaces its GDI based render with a DirectWrite + one, Powerline symbols will be broken. + + The alternative is to use the [Mintty terminal for WSL][wsltty]. + +[1681]: https://github.com/Microsoft/BashOnWindows/issues/1681 +[wsltty]: https://github.com/mintty/wsltty + +Features +-------- + + - `C-a` acts as secondary prefix, while keeping default `C-b` prefix + - visual theme inspired by [Powerline][] + - [maximize any pane to a new window with ` +`][maximize-pane] + - SSH aware username and hostname status line information + - mouse mode toggle with ` m` + - automatic usage of [`reattach-to-user-namespace`][reattach-to-user-namespace] + if available + - laptop battery status line information + - uptime status line information + - optional highlight of focused pane (tmux `>= 2.1`) + - configurable new windows and panes behavior (optionally retain current path) + - SSH aware split pane (reconnects to remote server, experimental) + - copy to OS clipboard (needs [`reattach-to-user-namespace`][reattach-to-user-namespace] + on macOS, `xsel` or `xclip` on Linux) + - [Facebook PathPicker][] integration if available + - [Urlview][] integration if available + +[Powerline]: https://github.com/Lokaltog/powerline +[maximize-pane]: http://pempek.net/articles/2013/04/14/maximizing-tmux-pane-new-window/ +[reattach-to-user-namespace]: https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard +[Facebook PathPicker]: https://facebook.github.io/PathPicker/ +[Urlview]: https://packages.debian.org/stable/misc/urlview + +tmux may be controlled from an attached client by using a key combination of a +prefix key, followed by a command key. This configuration uses `C-a` as a +secondary prefix while keeping `C-b` as the default prefix. In the following +list of key bindings: + - `` means you have to either hit Ctrl + a or Ctrl + b + - ` c` means you have to hit Ctrl + a or Ctrl + b followed by c + - ` C-c` means you have to hit Ctrl + a or Ctrl + b followed by Ctrl + c + +This configuration uses the following bindings: + + - ` C-c` creates a new session + - ` e` opens `~/.tmux.conf.local` with the editor defined by the + `$EDITOR` environment variable (defaults to `vim` when empty) + - ` r` reloads the configuration + - ` C-f` lets you switch to another session by name + - ` C-h` and ` C-l` let you navigate windows (default + ` n` and ` p` are unbound) + - ` Tab` brings you to the last active window + - ` h`, ` j`, ` k` and ` l` let you navigate + panes ala Vim + - ` H`, ` J`, ` K`, ` L` let you resize panes + - ` <` and ` >` let you swap panes + - ` +` maximizes the current pane to a new window + - ` m` toggles mouse mode on or off + - ` U` launches Urlview (if available) + - ` F` launches Facebook PathPicker (if available) + - ` Enter` enters copy-mode + - ` b` lists the paste-buffers + - ` p` pastes from the top paste-buffer + - ` P` lets you choose the paste-buffer to paste from + - `C-l` clears both the screen and the history + +Additionally, `vi-choice`, `vi-edit` and `vi-copy` named tables are adjusted + to closely match [my own Vim configuration][] + +[my own Vim configuration]: https://github.com/gpakosz/.vim.git + +Bindings for the `vi-choice` mode-table: + +- `h` collapses the current tree node +- `l` expands the current tree node +- `H` collapses all the tree nodes +- `L` expands all the tree nodes +- `K` jumps to the start of list (tmux `2.0+`) +- `L` jumps to the end of list (tmux `2.0+`) +- `Escape` cancels the current operation + +Bindings for the `vi-edit` mode-table: + +- `H` jumps to the start of line +- `L` jumps to the end of line +- `q` cancels the current operation +- `Escape` cancels the current operation + +Bindings for the `vi-copy` mode-table: + +- `v` begins selection / visual mode +- `C-v` toggles between blockwise visual mode and visual mode +- `H` jumps to the start of line +- `L` jumps to the end of line +- `y` copies the selection to the top paste-buffer +- `Escape` cancels the current operation + +The "maximize any pane to a new window with ` +`" feature is different +from builtin `resize-pane -Z` as it allows you to further split a maximized +pane. It's also more flexible by allowing you to maximize a pane to a new +window, then change window, then go back and the pane is still in maximized +state in its own window. You can then minimize a pane by using ` +` +either from the source window or the maximized window. + +![Maximize pane](https://cloud.githubusercontent.com/assets/553208/9890858/ee3c0ca6-5c02-11e5-890e-05d825a46c92.gif) + +Mouse mode allows you to set the active window, set the active pane, resize +panes and automatically switches to copy-mode to select text. + +![Mouse mode](https://cloud.githubusercontent.com/assets/553208/9890797/8dffe542-5c02-11e5-9c06-a25b452e6fcc.gif) + +Configuration +------------- + +While this configuration tries to bring sane default settings, you may want to +customize it further to your needs. Instead of altering the `~/.tmux.conf` file +and diverging from upstream, the proper way is to edit the `~/.tmux.conf.local` +file. + +Please refer to the default `~/.tmux.conf.local` file to know more about +variables you can adjust to alter different behaviors. Pressing ` e` +will open `~/.tmux.conf.local` with the editor defined by the `$EDITOR` +environment variable (defaults to `vim` when empty). + +### Enabling the Powerline look + +Powerline originated as a status-line plugin for Vim. Its popular eye-catching +look is based on the use of special symbols: Powerline Symbols + +To make use of these symbols, there are several options: + +- use a font that already bundles those: this is e.g. the case of the + [2.030R-ro/1.050R-it version][source code pro] of the Source Code Pro] font +- use a [pre-patched font][powerline patched fonts] +- use your preferred font along with the [Powerline font][powerline font] (that + only contains the Powerline symbols): [this highly depends on your operating + system and your terminal emulator][terminal support] +- [patch your preferred font][powerline font patcher] by adding the missing + Powerline symbols: this is the most difficult way and is no more documented in + the [Powerline manual] + +[source code pro]: https://github.com/adobe-fonts/source-code-pro/releases/tag/2.030R-ro/1.050R-it +[powerline patched fonts]: https://github.com/powerline/fonts +[powerline font]: https://github.com/powerline/powerline/raw/develop/font/PowerlineSymbols.otf +[powerline font patcher]: https://github.com/powerline/fontpatcher +[terminal support]: http://powerline.readthedocs.io/en/master/usage.html#usage-terminal-emulators +[Powerline manual]: http://powerline.readthedocs.org/en/latest/installation.html#fonts-installation + +Please see the [Powerline manual] for further details. + +Then edit the `~/.tmux.conf.local` file (` e`) and adjust the following +variables: + +``` +tmux_conf_theme_left_separator_main='' +tmux_conf_theme_left_separator_sub='' +tmux_conf_theme_right_separator_main='' +tmux_conf_theme_right_separator_sub='' +``` +### Configuring the status line + +Contrary to the first iterations of this configuration, by now you have total +control on the content and order of `status-left` and `status-right`. + +Edit the `~/.tmux.conf.local` file (` e`) and adjust the +`tmux_conf_theme_status_left` and `tmux_conf_theme_status_right` variables to +your own preferences. + +This configuration supports the following builtin variables: + + - `#{battery_bar}`: horizontal battery charge bar + - `#{battery_percentage}`: battery percentage + - `#{battery_status}`: is battery charging or discharging? + - `#{battery_vbar}`: vertical battery charge bar + - `#{circled_session_name}`: circled session number, up to 20 + - `#{hostname}`: SSH aware hostname information + - `#{hostname_ssh}`: SSH aware hostname information, blank when no SSH + connection detected + - `#{loadavg}`: load average + - `#{pairing}`: is session attached to more than one client? + - `#{prefix}`: is prefix being depressed? + - `#{root}`: is current user root? + - `#{uptime_d}`: uptime days + - `#{uptime_h}`: uptime hours + - `#{uptime_m}`: uptime minutes + - `#{uptime_s}`: uptime seconds + - `#{username}`: SSH aware username information + - `#{username_ssh}`: SSH aware username information, blank when no SSH + connection detected + +### Accessing the macOS clipboard from within tmux sessions + +[Chris Johnsen created the `reattach-to-user-namespace` +utility][reattach-to-user-namespace] that makes `pbcopy` and `pbpaste` work +again within tmux. + +To install `reattach-to-user-namespace`, use either [MacPorts][] or +[Homebrew][]: + + $ port install tmux-pasteboard + +or + + $ brew install reattach-to-user-namespace + +Once installed, `reattach-to-usernamespace` will be automatically detected. + +[MacPorts]: http://www.macports.org/ +[Homebrew]: http://brew.sh/ + +### Using the configuration under Cygwin within Mintty + +**I don't recommend running this configuration with Cygwin anymore. Forking +under Cygwin is extremely slow and this configuration issues a lot of +`run-shell` commands under the hood. As such, you will experience high CPU +usage. As an alternative consider using [Mintty terminal for WSL][wsltty].** + +![cygwin](https://cloud.githubusercontent.com/assets/553208/19741789/67a3f3d8-9bc2-11e6-9ecc-499fc0228ee6.png) + +It is possible to use this configuration under Cygwin within Mintty, however +support for Unicode symbols and emojis lacks behind Mac and Linux. + +Particularly, Mintty's text rendering is implemented with GDI which has +limitations: + +- color emojis are only available through DirectWrite starting with Windows 8.1 +- display of double width symbols, like the battery discharging symbol indicator + (U+1F50B) is buggy + +To get Unicode symbols displayed properly, you have to use [font linking]. +Open `regedit.exe` then navigate to the registry key at +`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink` +and add a new entry for you preferred font to link it with the Segoe UI Symbol +font. + +![regedit](https://cloud.githubusercontent.com/assets/553208/19741304/71a2f3ae-9bc0-11e6-96aa-4c09a812c313.png) + +[font linking]: https://msdn.microsoft.com/en-us/goglobal/bb688134.aspx From 6bd607c03f050f39d2ad12a7a8a23ad816f773a2 Mon Sep 17 00:00:00 2001 From: Sanket Date: Sun, 27 Aug 2017 12:47:44 +0530 Subject: [PATCH 07/51] vimrc --- config/.vimrc | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 config/.vimrc diff --git a/config/.vimrc b/config/.vimrc new file mode 100644 index 0000000..1c8acc0 --- /dev/null +++ b/config/.vimrc @@ -0,0 +1,13 @@ +call plug#begin() +Plug 'fatih/vim-go' +call plug#end() +filetype plugin indent on +syn on se title +set tabstop=4 +set softtabstop=4 +set shiftwidth=4 +set expandtab +set listchars=eol:$,tab:>-,trail:~,extends:>,precedes:< +set list +set laststatus=2 +set statusline=%<%f\ %h%m%r\ %y%=%{v:register}\ %-14.(%l,%c%V%)\ %P From 80d9b1d7c8a4b2f2beddd1ee262529190af8a1a5 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Sat, 30 Sep 2017 23:28:24 +0530 Subject: [PATCH 08/51] Vimrc reconfigure --- .gitignore | 16 - Makefile | 21 + config/bash/bashrc | 127 ---- config/emacs/Cask | 33 - config/emacs/init.el | 144 ----- config/git/.gitconfig | 5 - config/git/gitconfig | 5 - config/i3-wm/config | 155 ----- config/tmux/.tmux.conf | 1113 ---------------------------------- config/tmux/.tmux.conf.local | 267 -------- config/tmux/LICENSE.MIT | 18 - config/tmux/LICENSE.WTFPLv2 | 13 - config/tmux/README.md | 318 ---------- config/.vimrc => vimrc | 11 + 14 files changed, 32 insertions(+), 2214 deletions(-) delete mode 100644 .gitignore create mode 100644 Makefile delete mode 100644 config/bash/bashrc delete mode 100644 config/emacs/Cask delete mode 100644 config/emacs/init.el delete mode 100644 config/git/.gitconfig delete mode 100644 config/git/gitconfig delete mode 100644 config/i3-wm/config delete mode 100644 config/tmux/.tmux.conf delete mode 100644 config/tmux/.tmux.conf.local delete mode 100644 config/tmux/LICENSE.MIT delete mode 100644 config/tmux/LICENSE.WTFPLv2 delete mode 100644 config/tmux/README.md rename config/.vimrc => vimrc (59%) diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 98f032d..0000000 --- a/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -auto-save-list/* -eshell/* -ac-comphist.dat -*~ -elpa/* -var/* -emms/* -url/* -.emacs.desktop -.emacs.desktop.lock -session* -rcirc* -.cask/* -.mc-lists.el -tramp - diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2313ad5 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +CWD=$(shell pwd) + +all: vim-plugins git-config vim-rc + + +vim-plugins: vim-plug + +vim-rc: + ln -sf ${CWD}/vimrc ${HOME}/.vimrc + +vim-plug: + mkdir -p ~/.vim/autoload ~/.vim/bundle + curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + +git-config: + git config --global core.editor vim + git config --global user.name "Sanket Sudake" + git config --global user.email "sanket@infracloud.io" + git config --global color.ui true + git config --global gitreview.username "ssudake21" + diff --git a/config/bash/bashrc b/config/bash/bashrc deleted file mode 100644 index 2a037c6..0000000 --- a/config/bash/bashrc +++ /dev/null @@ -1,127 +0,0 @@ -# ~/.bashrc: executed by bash(1) for non-login shells. -# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) -# for examples - -# If not running interactively, don't do anything -case $- in - *i*) ;; - *) return;; -esac - -# don't put duplicate lines or lines starting with space in the history. -# See bash(1) for more options -HISTCONTROL="erasedups:ignoreboth" - -# append to the history file, don't overwrite it -shopt -s histappend -shopt -s cmdhist -# Correct misspelled typed directories in cd -shopt -s cdspell -# check the window size after each command and, if necessary, -# update the values of LINES and COLUMNS. -shopt -s checkwinsize - -# If set, the pattern "**" used in a pathname expansion context will -# match all files and zero or more directories and subdirectories. -# shopt -s globstar - -# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) -HISTSIZE=1000000 -HISTFILESIZE=2000000 - -# make less more friendly for non-text input files, see lesspipe(1) -[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" - -# set variable identifying the chroot you work in (used in the prompt below) -if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then - debian_chroot=$(cat /etc/debian_chroot) -fi - -# set a fancy prompt (non-color, unless we know we "want" color) -case "$TERM" in - xterm-color) color_prompt=yes;; -esac - -# uncomment for a colored prompt, if the terminal has the capability; turned -# off by default to not distract the user: the focus in a terminal window -# should be on the output of commands, not on the prompt -#force_color_prompt=yes - -if [ -n "$force_color_prompt" ]; then - if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then - # We have color support; assume it's compliant with Ecma-48 - # (ISO/IEC-6429). (Lack of such support is extremely rare, and such - # a case would tend to support setf rather than setaf.) - color_prompt=yes - else - color_prompt= - fi -fi - -if [ "$color_prompt" = yes ]; then - PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' -else - PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' -fi -unset color_prompt force_color_prompt - -# If this is an xterm set the title to user@host:dir -case "$TERM" in -xterm*|rxvt*) - PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" - ;; -*) - ;; -esac - -# enable color support of ls and also add handy aliases -if [ -x /usr/bin/dircolors ]; then - test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" - alias ls='ls --color=auto' - #alias dir='dir --color=auto' - #alias vdir='vdir --color=auto' - - alias grep='grep --color=auto' - alias fgrep='fgrep --color=auto' - alias egrep='egrep --color=auto' -fi - -# some more ls aliases -alias ll='ls -alF' -alias la='ls -A' -alias l='ls -CF' -alias meow="less" -alias emacs="export TERM=xterm-256color;/lhome/ssudake/emacs-24.2/src/emacs" -alias r="fc -s" -alias reload="cat ~/.profile > ~/.bashrc; source ~/.bashrc" -alias deldirs="rm -r */" - -function findf -{ - find . -name $1 -} -function fullpath -{ - case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; - esac; -} -function pd -{ - MAX=0 - [ $1 ] && MAX=$1 - PR="../" - _COUNTER=1 - while [ $_COUNTER -lt $MAX ]; do - PR=$(echo "$PR../") - let _COUNTER=_COUNTER+1 - done - cd $PR -} -function ppd -{ - pushd . - pd $1 -} - -export PATH="$HOME/.cask/bin:$HOME/downloads/git-2.0.2:$PATH" -export PATH="$HOME/cmds/build_cmd/:$PATH" diff --git a/config/emacs/Cask b/config/emacs/Cask deleted file mode 100644 index 4a23156..0000000 --- a/config/emacs/Cask +++ /dev/null @@ -1,33 +0,0 @@ -(source gnu) -(source melpa) - -(depends-on "bind-key") -(depends-on "cask") -(depends-on "dash") -(depends-on "drag-stuff") -(depends-on "exec-path-from-shell") -(depends-on "expand-region") -(depends-on "f") -(depends-on "flycheck") -(depends-on "flycheck-cask") -(depends-on "htmlize") -(depends-on "idle-highlight-mode") -(depends-on "magit") -(depends-on "multiple-cursors") -(depends-on "nyan-mode") -(depends-on "pallet") -(depends-on "popwin") -(depends-on "prodigy") -(depends-on "projectile") -(depends-on "s") -(depends-on "smartparens") -(depends-on "smex") -(depends-on "use-package") -(depends-on "web-mode") -(depends-on "yasnippet") -(depends-on "volatile-highlights") -(depends-on "powerline") -(depends-on "autopair") -(depends-on "popup-switcher") -(depends-on "c-eldoc") -(depends-on "auto-complete") diff --git a/config/emacs/init.el b/config/emacs/init.el deleted file mode 100644 index 967b13b..0000000 --- a/config/emacs/init.el +++ /dev/null @@ -1,144 +0,0 @@ -;; Sanket Sudake -(require 'cask "~/.cask/cask.el") -(cask-initialize) - -;; Disable Arrow Keys -(global-set-key (kbd "") 'disabled-key) -(global-set-key (kbd "") 'disabled-key) -(global-set-key (kbd "") 'disabled-key) -(global-set-key (kbd "") 'disabled-key) -(global-set-key (kbd "") 'disabled-key) -(global-set-key (kbd "") 'disabled-key) - -;; Set No UI -(dolist (mode '(menu-bar-mode tool-bar-mode scroll-bar-mode)) - (when (fboundp mode) (funcall mode -1))) - -;; yes or no becomes y or n -(defalias 'yes-or-no-p 'y-or-n-p) - -;; Coding style -(prefer-coding-system 'utf-8) -(prefer-coding-system 'utf-8) -(set-language-environment 'UTF-8) -(set-default-coding-systems 'utf-8) -(setq file-name-coding-system 'utf-8) -(setq buffer-file-coding-system 'utf-8) -(setq coding-system-for-write 'utf-8) -(set-keyboard-coding-system 'utf-8) -(set-terminal-coding-system 'utf-8) -(set-clipboard-coding-system 'utf-8) -(set-selection-coding-system 'utf-8) -(setq default-process-coding-system '(utf-8 . utf-8)) - -;; Completion ignores filenames ending in any string in this list. -(setq completion-ignored-extensions - '(".o" ".elc" "~" ".bin" ".class" ".exe" ".ps" ".abs" ".mx" - ".~jv" ".rbc" ".pyc" ".beam" ".aux" ".out" ".pdf")) - - -;; Mode tweaks -;; - - -;;;; Text mode and Auto Fill mode -(setq default-major-mode 'text-mode) -(add-hook 'text-mode-hook 'turn-on-auto-fill) - -(require 'volatile-highlights) -(volatile-highlights-mode t) -(autoload 'enable-paredit-mode "paredit" - "Turn on pseudo-structural editing of Lisp code." t) - -;;;; Ido mode -(setq ido-enable-flex-matching t) -(setq ido-everywhere t) -;;This tab override shouldn't be necessary given ido's default -;;configuration, but minibuffer-complete otherwise dominates the -;;tab binding because of my custom tab-completion-everywhere -;;configuration. -(add-hook 'ido-setup-hook - (lambda () - (define-key ido-completion-map [tab] 'ido-complete))) -(ido-mode 1) -(setq ido-vertical-mode t) - -;;;; Stop autobackup -;;stop creating those backup~ files -(setq make-backup-files nil) -;;stop creating those #autosave# files -(setq auto-save-default nil) - -;;;; autopair mode -(require 'autopair) -(autopair-global-mode 1) -(setq autopair-autowrap t) - -;; Save emacs session before exit -(setq desktop-save 'if-exists) -(desktop-save-mode 1) - -;; Powerline Mode -(require 'powerline) -(powerline-default-theme) - -;;;; Popup switcher -(require 'popup-switcher) -(global-set-key [f2] 'psw-switch-buffer) -(define-key global-map (kbd "C-+") 'text-scale-increase) -(define-key global-map (kbd "C--") 'text-scale-decrease) - - -;;; cc mode setup -(require 'cc-mode) -(setq-default c-basic-offset 4 c-default-style "linux") -;;(setq-default tab-width 4 indent-tabs-mode t) -(define-key c-mode-base-map (kbd "RET") 'newline-and-indent) -(setq indent-tabs-mode nil) - -;; autocomplete and yasnippet mode -(require 'yasnippet) -(yas-global-mode 1) -(require 'auto-complete) -(require 'auto-complete-config) -(ac-config-default) -(ac-flyspell-workaround) -(add-to-list 'ac-dictionary-directories - "~/.emacs.d/dict") - -(setq ac-ignore-case 'smart) -(set-face-background 'ac-candidate-face "lightgray") -(set-face-underline 'ac-candidate-face "darkgray") -(set-face-background 'ac-selection-face "steelblue") -(defun ac-cc-mode-setup () - (setq ac-sources '( - ac-source-words-in-buffer - ac-source-words-in-same-mode-buffers - ac-source-filename - ac-source-files-in-current-dir - ac-source-yasnippet - ac-source-dictionary - ac-source-semantic - ac-source-gtags - ac-source-css-property - ))) -(defun my-ac-config () - (add-hook 'c-mode-common-hook 'ac-cc-mode-setup) - (add-hook 'c++-mode-common-hook 'ac-cc-mode-setup) - (add-hook 'auto-complete-mode-hook 'ac-common-setup) - (global-auto-complete-mode t)) -(my-ac-config) -(setq ac-use-menu-map t) -;; Default settings -(define-key ac-menu-map "\C-n" 'ac-next) -(define-key ac-menu-map "\C-p" 'ac-previous) - -;;;; Eldoc mode -(setq c-eldoc-includes "`pkg-config gtk+-2.0 --cflags` -I./ -I../ -I/usr/include/opencv -I/usr/include/GL -I/usr/include") -(load "c-eldoc") -(add-hook 'c-mode-hook 'c-turn-on-eldoc-mode) -(add-hook 'c++-mode-hook 'c-turn-on-eldoc-mode) - -(global-linum-mode 1) -;;(highlight-tabs) -;;(highlight-trailing-whitespace) diff --git a/config/git/.gitconfig b/config/git/.gitconfig deleted file mode 100644 index ac77e61..0000000 --- a/config/git/.gitconfig +++ /dev/null @@ -1,5 +0,0 @@ -[user] - email = sanketsudake@gmail.com - name = Sanket Sudake -[alias] - hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short diff --git a/config/git/gitconfig b/config/git/gitconfig deleted file mode 100644 index ac77e61..0000000 --- a/config/git/gitconfig +++ /dev/null @@ -1,5 +0,0 @@ -[user] - email = sanketsudake@gmail.com - name = Sanket Sudake -[alias] - hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short diff --git a/config/i3-wm/config b/config/i3-wm/config deleted file mode 100644 index 97ab704..0000000 --- a/config/i3-wm/config +++ /dev/null @@ -1,155 +0,0 @@ -# This file has been auto-generated by i3-config-wizard(1). -# It will not be overwritten, so edit it as you like. -# -# Should you change your keyboard layout somewhen, delete -# this file and re-run i3-config-wizard(1). -# - -# i3 config file (v4) -# -# Please see http://i3wm.org/docs/userguide.html for a complete reference! - -set $mod Mod4 - -# Font for window titles. Will also be used by the bar unless a different font -# is used in the bar {} block below. ISO 10646 = Unicode -font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 -# The font above is very space-efficient, that is, it looks good, sharp and -# clear in small sizes. However, if you need a lot of unicode glyphs or -# right-to-left text rendering, you should instead use pango for rendering and -# chose a FreeType font, such as: -# font pango:DejaVu Sans Mono 10 - -# Use Mouse+$mod to drag floating windows to their wanted position -floating_modifier $mod - -# start a terminal -bindsym $mod+Return exec i3-sensible-terminal - -# kill focused window -bindsym $mod+Shift+q kill - -# start dmenu (a program launcher) -bindsym $mod+d exec dmenu_run -# There also is the (new) i3-dmenu-desktop which only displays applications -# shipping a .desktop file. It is a wrapper around dmenu, so you need that -# installed. -# bindsym $mod+d exec --no-startup-id i3-dmenu-desktop - -# change focus -bindsym $mod+j focus left -bindsym $mod+k focus down -bindsym $mod+l focus up -bindsym $mod+semicolon focus right - -# alternatively, you can use the cursor keys: -bindsym $mod+Left focus left -bindsym $mod+Down focus down -bindsym $mod+Up focus up -bindsym $mod+Right focus right - -# move focused window -bindsym $mod+Shift+j move left -bindsym $mod+Shift+k move down -bindsym $mod+Shift+l move up -bindsym $mod+Shift+semicolon move right - -# alternatively, you can use the cursor 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 - -# split in horizontal orientation -bindsym $mod+h split h - -# split in vertical orientation -bindsym $mod+v split v - -# enter fullscreen mode for the focused container -bindsym $mod+f fullscreen - -# change container layout (stacked, tabbed, toggle split) -bindsym $mod+s layout stacking -bindsym $mod+w layout tabbed -bindsym $mod+e layout toggle split - -# toggle tiling / floating -bindsym $mod+Shift+space floating toggle - -# change focus between tiling / floating windows -bindsym $mod+space focus mode_toggle - -# focus the parent container -bindsym $mod+a focus parent - -# focus the child container -#bindsym $mod+d focus child - -# switch to workspace -bindsym $mod+1 workspace 1 -bindsym $mod+2 workspace 2 -bindsym $mod+3 workspace 3 -bindsym $mod+4 workspace 4 -bindsym $mod+5 workspace 5 -bindsym $mod+6 workspace 6 -bindsym $mod+7 workspace 7 -bindsym $mod+8 workspace 8 -bindsym $mod+9 workspace 9 -bindsym $mod+0 workspace 10 - -# move focused container to workspace -bindsym $mod+Shift+1 move container to workspace 1 -bindsym $mod+Shift+2 move container to workspace 2 -bindsym $mod+Shift+3 move container to workspace 3 -bindsym $mod+Shift+4 move container to workspace 4 -bindsym $mod+Shift+5 move container to workspace 5 -bindsym $mod+Shift+6 move container to workspace 6 -bindsym $mod+Shift+7 move container to workspace 7 -bindsym $mod+Shift+8 move container to workspace 8 -bindsym $mod+Shift+9 move container to workspace 9 -bindsym $mod+Shift+0 move container to workspace 10 - -# reload the configuration file -bindsym $mod+Shift+c reload -# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) -bindsym $mod+Shift+r restart -# exit i3 (logs you out of your X session) -bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" - -# resize window (you can also use the mouse for that) -mode "resize" { - # These bindings trigger as soon as you enter the resize mode - - # Pressing left will shrink the window’s width. - # Pressing right will grow the window’s width. - # Pressing up will shrink the window’s height. - # Pressing down will grow the window’s height. - bindsym j resize shrink width 10 px or 10 ppt - bindsym k resize grow height 10 px or 10 ppt - bindsym l resize shrink height 10 px or 10 ppt - bindsym semicolon resize grow width 10 px or 10 ppt - - # same bindings, but for the arrow keys - bindsym Left resize shrink width 10 px or 10 ppt - bindsym Down resize grow height 10 px or 10 ppt - bindsym Up resize shrink height 10 px or 10 ppt - bindsym Right resize grow width 10 px or 10 ppt - - # back to normal: Enter or Escape - bindsym Return mode "default" - bindsym Escape mode "default" -} - -bindsym $mod+r mode "resize" - -# Start i3bar to display a workspace bar (plus the system information i3status -# finds out, if available) -bar { - status_command i3status -} - -exec --no-startup-id nm-applet - -bindsym XF86AudioRaiseVolume exec "amixer set Master 5%+ && killall -USR1 i3status" -bindsym XF86AudioLowerVolume exec "amixer set Master 5%- && killall -USR1 i3status" diff --git a/config/tmux/.tmux.conf b/config/tmux/.tmux.conf deleted file mode 100644 index 99203d3..0000000 --- a/config/tmux/.tmux.conf +++ /dev/null @@ -1,1113 +0,0 @@ -# cat << EOF > /dev/null -# https://github.com/gpakosz/.tmux -# (‑●‑●)> dual licensed under the WTFPL v2 license and the MIT license, -# without any warranty. -# Copyright 2012— Gregory Pakosz (@gpakosz). -# /!\ do not edit this file -# instead, override settings in ~/.tmux.conf.local, see README.md - - -# -- general ------------------------------------------------------------------- - -set -g default-terminal "screen-256color" # colors! -setw -g xterm-keys on -set -s escape-time 10 # faster command sequences -set -sg repeat-time 600 # increase repeat timeout -set -s focus-events on - -set -g prefix2 C-a # GNU-Screen compatible prefix -bind C-a send-prefix -2 - -set -q -g status-utf8 on # expect UTF-8 (tmux < 2.2) -setw -q -g utf8 on - -set -g history-limit 5000 # boost history - -# edit configuration -bind e new-window -n '~/.tmux.conf.local' "sh -c '\${EDITOR:-vim} ~/.tmux.conf.local && tmux source ~/.tmux.conf && tmux display \"~/.tmux.conf sourced\"'" - -# reload configuration -bind r source-file ~/.tmux.conf \; display '~/.tmux.conf sourced' - - -# -- display ------------------------------------------------------------------- - -set -g base-index 1 # start windows numbering at 1 -setw -g pane-base-index 1 # make pane numbering consistent with windows - -setw -g automatic-rename on # rename window to reflect current program -set -g renumber-windows on # renumber windows when a window is closed - -set -g set-titles on # set terminal title -set -g set-titles-string '#h ❐ #S ● #I #W' - -set -g display-panes-time 800 # slightly longer pane indicators display time -set -g display-time 1000 # slightly longer status messages display time - -set -g status-interval 10 # redraw status line every 10 seconds - -# clear both screen and history -bind -n C-l send-keys C-l \; run 'sleep 0.1' \; clear-history - -# activity -set -g monitor-activity on -set -g visual-activity off - - -# -- navigation ---------------------------------------------------------------- - -# create session -bind C-c new-session - -# find session -bind C-f command-prompt -p find-session 'switch-client -t %%' - -# split current window horizontally -bind - split-window -v -# split current window vertically -bind _ split-window -h - -# pane navigation -bind -r h select-pane -L # move left -bind -r j select-pane -D # move down -bind -r k select-pane -U # move up -bind -r l select-pane -R # move right -bind > swap-pane -D # swap current pane with the next one -bind < swap-pane -U # swap current pane with the previous one - -# maximize current pane -bind + run 'cut -c3- ~/.tmux.conf | sh -s _maximize_pane #{session_name} #D' - -# pane resizing -bind -r H resize-pane -L 2 -bind -r J resize-pane -D 2 -bind -r K resize-pane -U 2 -bind -r L resize-pane -R 2 - -# window navigation -unbind n -unbind p -bind -r C-h previous-window # select previous window -bind -r C-l next-window # select next window -bind Tab last-window # move to last active window - -# toggle mouse -bind m run "cut -c3- ~/.tmux.conf | sh -s _toggle_mouse" - - -# -- urlview ------------------------------------------------------------------- - -bind U run "cut -c3- ~/.tmux.conf | sh -s _urlview #{pane_id}" - - -# -- facebook pathpicker ------------------------------------------------------- - -bind F run "cut -c3- ~/.tmux.conf | sh -s _fpp #{pane_id}" - - -# -- list choice (tmux < 2.4) -------------------------------------------------- - -# vi-choice is gone in tmux >= 2.4 -run -b 'tmux bind -t vi-choice h tree-collapse 2> /dev/null || true' -run -b 'tmux bind -t vi-choice l tree-expand 2> /dev/null || true' -run -b 'tmux bind -t vi-choice K start-of-list 2> /dev/null || true' -run -b 'tmux bind -t vi-choice J end-of-list 2> /dev/null || true' -run -b 'tmux bind -t vi-choice H tree-collapse-all 2> /dev/null || true' -run -b 'tmux bind -t vi-choice L tree-expand-all 2> /dev/null || true' -run -b 'tmux bind -t vi-choice Escape cancel 2> /dev/null || true' - - -# -- edit mode (tmux < 2.4) ---------------------------------------------------- - -# vi-edit is gone in tmux >= 2.4 -run -b 'tmux bind -ct vi-edit H start-of-line 2> /dev/null || true' -run -b 'tmux bind -ct vi-edit L end-of-line 2> /dev/null || true' -run -b 'tmux bind -ct vi-edit q cancel 2> /dev/null || true' -run -b 'tmux bind -ct vi-edit Escape cancel 2> /dev/null || true' - - -# -- copy mode ----------------------------------------------------------------- - -bind Enter copy-mode # enter copy mode - -run -b 'tmux bind -t vi-copy v begin-selection 2> /dev/null || true' -run -b 'tmux bind -T copy-mode-vi v send -X begin-selection 2> /dev/null || true' -run -b 'tmux bind -t vi-copy C-v rectangle-toggle 2> /dev/null || true' -run -b 'tmux bind -T copy-mode-vi C-v send -X rectangle-toggle 2> /dev/null || true' -run -b 'tmux bind -t vi-copy y copy-selection 2> /dev/null || true' -run -b 'tmux bind -T copy-mode-vi y send -X copy-selection-and-cancel 2> /dev/null || true' -run -b 'tmux bind -t vi-copy Escape cancel 2> /dev/null || true' -run -b 'tmux bind -T copy-mode-vi Escape send -X cancel 2> /dev/null || true' -run -b 'tmux bind -t vi-copy H start-of-line 2> /dev/null || true' -run -b 'tmux bind -T copy-mode-vi L send -X end-of-line 2> /dev/null || true' - -# copy to Mac OSX clipboard -if -b 'command -v reattach-to-user-namespace > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | reattach-to-user-namespace pbcopy"' -# copy to X11 clipboard -if -b 'command -v xsel > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | xsel -i -b"' -if -b '! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | xclip -i -selection clipboard >/dev/null 2>&1"' -# copy to Windows clipboard -if -b 'command -v clip.exe > /dev/null 2>&1' 'bind y run -b "tmux save-buffer - | clip.exe"' -if -b '[ -c /dev/clipboard ]' 'bind y run -b "tmux save-buffer - > /dev/clipboard"' - - -# -- buffers ------------------------------------------------------------------- - -bind b list-buffers # list paste buffers -bind p paste-buffer # paste from the top paste buffer -bind P choose-buffer # choose which buffer to paste from - - -# -- user defined overrides ---------------------------------------------------- - -if '[ -f ~/.tmux.conf.local ]' 'source ~/.tmux.conf.local' - - -# -- 8< ------------------------------------------------------------------------ - -run 'cut -c3- ~/.tmux.conf | sh -s _apply_configuration' - - -# EOF -# -# # exit the script if any statement returns a non-true return value -# set -e -# -# __newline=' -# ' -# -# _is_enabled() { -# ( ([ x"$1" = x"enabled" ] || [ x"$1" = x"true" ] || [ x"$1" = x"yes" ] || [ x"$1" = x"1" ]) && return 0 ) || return 1 -# } -# -# _circled_digit() { -# circled_digits='⓪ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳' -# if [ "$1" -le 20 ] 2>/dev/null; then -# i=$(( $1 + 1 )) -# eval set -- "$circled_digits" -# eval echo "\${$i}" -# else -# echo "$1" -# fi -# } -# -# _maximize_pane() { -# current_session=${1:-$(tmux display -p '#{session_name}')} -# current_pane=${2:-$(tmux display -p '#{pane_id}')} -# -# dead_panes=$(tmux list-panes -s -t "$current_session" -F '#{pane_dead} #{pane_id} #{pane_start_command}' | grep -o '^1 %.\+maximized.\+$' || true) -# restore=$(echo "$dead_panes" | sed -n -E -e "s/^1 $current_pane .+maximized.+(%[0-9]+)$/tmux swap-pane -s \1 -t $current_pane \; kill-pane -t $current_pane/p" -e "s/^1 (%[0-9]+) .+maximized.+$current_pane$/tmux swap-pane -s \1 -t $current_pane \; kill-pane -t \1/p" ) -# -# if [ -z "$restore" ]; then -# [ "$(tmux list-panes -t "$current_session:" | wc -l | sed 's/^ *//g')" -eq 1 ] && tmux display "Can't maximize with only one pane" && return -# window=$(tmux new-window -t "$current_session:" -P "exec maximized... 2> /dev/null & tmux setw -t $current_session: remain-on-exit on; printf 'Pane has been maximized, press + to restore. %s' \\$current_pane") -# window=${window%.*} -# -# guard=10 -# while [ x"$(tmux list-panes -t "$window" -F '#{session_name}:#{window_index} #{pane_dead}' 2>/dev/null)" != x"$window 1" ] && [ "$guard" -ne 0 ]; do -# sleep 0.01 -# guard=$((guard - 1)) -# done -# if [ "$guard" -eq 0 ]; then -# tmux display 'Unable to maximize pane' -# fi -# -# new_pane=$(tmux display -p '#{pane_id}') -# tmux setw -t "$window" remain-on-exit off \; swap-pane -s "$current_pane" -t "$new_pane" -# else -# $restore || tmux kill-pane -# fi -# } -# -# _toggle_mouse() { -# old=$(tmux show -gv mouse) -# new="" -# -# if [ "$old" = "on" ]; then -# new="off" -# else -# new="on" -# fi -# -# tmux set -g mouse $new \;\ -# display "mouse: $new" -# } -# -# _battery() { -# charge=0 -# uname_s=$(uname -s) -# case "$uname_s" in -# *Darwin*) -# while IFS= read -r line; do -# if [ x"$discharging" != x"true" ]; then -# discharging=$(printf '%s' "$line" | grep -qi "discharging" && echo "true" || echo "false") -# fi -# percentage=$(printf '%s' "$line" | grep -E -o '[0-9]+%') -# charge=$(awk -v charge="$charge" -v percentage="${percentage%%%}" 'BEGIN { print charge + percentage / 100 }') -# count=$((count + 1)) -# done << EOF -# $(pmset -g batt | grep 'InternalBattery') -# EOF -# ;; -# *Linux*) -# while IFS= read -r batpath; do -# if [ x"$discharging" != x"true" ]; then -# discharging=$(grep -qi "discharging" "$batpath/status" && echo "true" || echo "false") -# fi -# bat_capacity="$batpath/capacity" -# if [ -r "$bat_capacity" ]; then -# charge=$(awk -v charge="$charge" -v capacity="$(cat "$bat_capacity")" 'BEGIN { print charge + capacity / 100 }') -# else -# bat_energy_full="$batpath/energy_full" -# bat_energy_now="$batpath/energy_now" -# if [ -r "$bat_energy_full" ] && [ -r "$bat_energy_now" ]; then -# charge=$(awk -v charge="$charge" -v energy_now="$(cat "$bat_energy_now")" -v energy_full="$(cat "$bat_energy_full")" 'BEGIN { print charge + energy_now / energy_full }') -# fi -# fi -# count=$((count + 1)) -# done << EOF -# $(find /sys/class/power_supply -maxdepth 1 -iname '*bat*') -# EOF -# ;; -# *CYGWIN*|*MSYS*|*MINGW*) -# while IFS= read -r line; do -# [ -z "$line" ] && continue -# if [ x"$discharging" != x"true" ]; then -# discharging=$(printf '%s' "$line" | awk '{ s = ($1 == 1) ? "true" : "false"; print s }') -# fi -# charge=$(printf '%s' "$line" | awk -v charge="$charge" '{ print charge + $2 / 100 }') -# count=$((count + 1)) -# done << EOF -# $(wmic path Win32_Battery get BatteryStatus, EstimatedChargeRemaining | tr -d '\r' | tail -n +2) -# EOF -# ;; -# *OpenBSD*) -# for batid in 0 1 2; do -# sysctl -n "hw.sensors.acpibat$batid.raw0" 2>&1 | grep -q 'not found' && continue -# if [ x"$discharging" != x"true" ]; then -# discharging=$(sysctl -n "hw.sensors.acpibat$batid.raw0" | grep -q 1 && echo "true" || echo "false") -# fi -# if sysctl -n "hw.sensors.acpibat$batid" | grep -q amphour; then -# charge=$(awk -v charge="$charge" -v remaining="$(sysctl -n hw.sensors.acpibat$batid.amphour3 | cut -d' ' -f1)" -v full="$(sysctl -n hw.sensors.acpibat$batid.amphour0 | cut -d' ' -f1)" 'BEGIN { print charge + remaining / full }') -# else -# charge=$(awk -v charge="$charge" -v remaining="$(sysctl -n hw.sensors.acpibat$batid.watthour3 | cut -d' ' -f1)" -v full="$(sysctl -n hw.sensors.acpibat$batid.watthour0 | cut -d' ' -f1)" 'BEGIN { print charge + remaining / full }') -# fi -# count=$((count + 1)) -# done -# ;; -# esac -# charge=$(awk -v charge="$charge" -v count="$count" 'BEGIN { print charge / count }') -# if [ "$charge" -eq 0 ]; then -# tmux set -ug '@battery_status' \;\ -# set -ug '@battery_bar' \;\ -# set -ug '@battery_hbar' \;\ -# set -ug '@battery_vbar' \;\ -# set -ug '@battery_percentage' -# return -# fi -# -# variables=$(tmux show -gqv '@battery_bar_symbol_full' \;\ -# show -gqv '@battery_bar_symbol_empty' \;\ -# show -gqv '@battery_bar_length' \;\ -# show -gqv '@battery_bar_palette' \;\ -# show -gqv '@battery_hbar_palette' \;\ -# show -gqv '@battery_vbar_palette' \;\ -# show -gqv '@battery_status_charging' \;\ -# show -gqv '@battery_status_discharging') -# # shellcheck disable=SC2086 -# { set -f; IFS="$__newline"; set -- $variables; unset IFS; set +f; } -# -# battery_bar_symbol_full=$1 -# battery_bar_symbol_empty=$2 -# battery_bar_length=$3 -# battery_bar_palette=$4 -# battery_hbar_palette=$5 -# battery_vbar_palette=$6 -# battery_status_charging=$7 -# battery_status_discharging=$8 -# -# if [ x"$battery_bar_length" = x"auto" ]; then -# columns=$(tmux -q display -p '#{client_width}' 2> /dev/null || echo 80) -# if [ "$columns" -ge 80 ]; then -# battery_bar_length=10 -# else -# battery_bar_length=5 -# fi -# fi -# -# if [ x"$discharging" = x"true" ]; then -# battery_status="$battery_status_discharging" -# else -# battery_status="$battery_status_charging" -# fi -# -# if echo "$battery_bar_palette" | grep -q -E '^heat|gradient(,[#a-z0-9]{7,9})?$'; then -# # shellcheck disable=SC2086 -# { set -f; IFS=,; set -- $battery_bar_palette; unset IFS; set +f; } -# palette_style=$1 -# battery_bg=${2:-none} -# [ x"$palette_style" = x"gradient" ] && \ -# palette="196 202 208 214 220 226 190 154 118 82 46" -# [ x"$palette_style" = x"heat" ] && \ -# palette="233 234 235 237 239 241 243 245 247 144 143 142 184 214 208 202 196" -# -# palette=$(echo "$palette" | awk -v n="$battery_bar_length" '{ for (i = 0; i < n; ++i) printf $(1 + (i * NF / n))" " }') -# eval set -- "$palette" -# -# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") -# battery_bar="#[bg=$battery_bg]" -# # shellcheck disable=SC2046 -# [ "$full" -gt 0 ] && \ -# battery_bar="$battery_bar$(printf "#[fg=colour%s]$battery_bar_symbol_full" $(echo "$palette" | cut -d' ' -f1-"$full"))" -# # shellcheck disable=SC2046 -# empty=$((battery_bar_length - full)) -# # shellcheck disable=SC2046 -# [ "$empty" -gt 0 ] && \ -# battery_bar="$battery_bar$(printf "#[fg=colour%s]$battery_bar_symbol_empty" $(echo "$palette" | cut -d' ' -f$((full + 1))-$((full + empty))))" -# eval battery_bar="$battery_bar#[fg=colour\${$((full == 0 ? 1 : full))}]" -# elif echo "$battery_bar_palette" | grep -q -E '^(([#a-z0-9]{7,9}|none),?){3}$'; then -# # shellcheck disable=SC2086 -# { set -f; IFS=,; set -- $battery_bar_palette; unset IFS; set +f; } -# battery_full_fg=$1 -# battery_empty_fg=$2 -# battery_bg=$3 -# -# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") -# [ x"$battery_bg" != x"none" ] && \ -# battery_bar="#[bg=$battery_bg]" -# #shellcheck disable=SC2046 -# [ "$full" -gt 0 ] && \ -# battery_bar="$battery_bar#[fg=$battery_full_fg]$(printf "%0.s$battery_bar_symbol_full" $(seq 1 "$full"))" -# empty=$((battery_bar_length - full)) -# #shellcheck disable=SC2046 -# [ "$empty" -gt 0 ] && \ -# battery_bar="$battery_bar#[fg=$battery_empty_fg]$(printf "%0.s$battery_bar_symbol_empty" $(seq 1 "$empty"))" && \ -# battery_bar="$battery_bar#[fg=$battery_empty_fg]" -# fi -# -# if echo "$battery_hbar_palette" | grep -q -E '^heat|gradient(,[#a-z0-9]{7,9})?$'; then -# # shellcheck disable=SC2086 -# { set -f; IFS=,; set -- $battery_hbar_palette; unset IFS; set +f; } -# palette_style=$1 -# [ x"$palette_style" = x"gradient" ] && \ -# palette="196 202 208 214 220 226 190 154 118 82 46" -# [ x"$palette_style" = x"heat" ] && \ -# palette="233 234 235 237 239 241 243 245 247 144 143 142 184 214 208 202 196" -# -# palette=$(echo "$palette" | awk -v n="$battery_bar_length" '{ for (i = 0; i < n; ++i) printf $(1 + (i * NF / n))" " }') -# eval set -- "$palette" -# -# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") -# eval battery_hbar_fg="colour\${$((full == 0 ? 1 : full))}" -# elif echo "$battery_hbar_palette" | grep -q -E '^([#a-z0-9]{7,9},?){3}$'; then -# # shellcheck disable=SC2086 -# { set -f; IFS=,; set -- $battery_hbar_palette; unset IFS; set +f; } -# -# # shellcheck disable=SC2046 -# eval $(awk "BEGIN { printf \"battery_hbar_fg=$%d\", (($charge) - 0.001) * $# + 1 }") -# fi -# -# eval set -- "▏ ▎ ▍ ▌ ▋ ▊ ▉ █" -# # shellcheck disable=SC2046 -# eval $(awk "BEGIN { printf \"battery_hbar_symbol=$%d\", ($charge) * ($# - 1) + 1 }") -# battery_hbar="#[fg=${battery_hbar_fg?}]${battery_hbar_symbol?}" -# -# if echo "$battery_vbar_palette" | grep -q -E '^heat|gradient(,[#a-z0-9]{7,9})?$'; then -# # shellcheck disable=SC2086 -# { set -f; IFS=,; set -- $battery_vbar_palette; unset IFS; set +f; } -# palette_style=$1 -# [ x"$palette_style" = x"gradient" ] && \ -# palette="196 202 208 214 220 226 190 154 118 82 46" -# [ x"$palette_style" = x"heat" ] && \ -# palette="233 234 235 237 239 241 243 245 247 144 143 142 184 214 208 202 196" -# -# palette=$(echo "$palette" | awk -v n="$battery_bar_length" '{ for (i = 0; i < n; ++i) printf $(1 + (i * NF / n))" " }') -# eval set -- "$palette" -# -# full=$(awk "BEGIN { printf \"%.0f\", ($charge) * $battery_bar_length }") -# eval battery_vbar_fg="colour\${$((full == 0 ? 1 : full))}" -# elif echo "$battery_vbar_palette" | grep -q -E '^([#a-z0-9]{7,9},?){3}$'; then -# # shellcheck disable=SC2086 -# { set -f; IFS=,; set -- $battery_vbar_palette; unset IFS; set +f; } -# -# # shellcheck disable=SC2046 -# eval $(awk "BEGIN { printf \"battery_vbar_fg=$%d\", (($charge) - 0.001) * $# + 1 }") -# fi -# -# eval set -- "▁ ▂ ▃ ▄ ▅ ▆ ▇ █" -# # shellcheck disable=SC2046 -# eval $(awk "BEGIN { printf \"battery_vbar_symbol=$%d\", ($charge) * ($# - 1) + 1 }") -# battery_vbar="#[fg=${battery_vbar_fg?}]${battery_vbar_symbol?}" -# -# battery_percentage="$(awk "BEGIN { printf \"%.0f%%\", ($charge) * 100 }")" -# -# tmux set -g '@battery_status' "$battery_status" \;\ -# set -g '@battery_bar' "$battery_bar" \;\ -# set -g '@battery_hbar' "$battery_hbar" \;\ -# set -g '@battery_vbar' "$battery_vbar" \;\ -# set -g '@battery_percentage' "$battery_percentage" -# } -# -# _username() { -# tty=${1:-$(tmux display -p '#{pane_tty}')} -# ssh_only=$2 -# # shellcheck disable=SC2039 -# if [ x"$OSTYPE" = x"cygwin" ]; then -# pid=$(ps -a | awk -v tty="${tty##/dev/}" '$5 == tty && /ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { print $1 }') -# [ -n "$pid" ] && ssh_parameters=$(tr '\0' ' ' < "/proc/$pid/cmdline" | sed 's/^ssh //') -# else -# ssh_parameters=$(ps -t "$tty" -o command= | awk '/ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { $1=""; print $0; exit }') -# fi -# if [ -n "$ssh_parameters" ]; then -# # shellcheck disable=SC2086 -# username=$(ssh -G $ssh_parameters 2>/dev/null | awk 'NR > 2 { exit } ; /^user / { print $2 }') -# # shellcheck disable=SC2086 -# [ -z "$username" ] && username=$(ssh -T -o ControlPath=none -o ProxyCommand="sh -c 'echo %%username%% %r >&2'" $ssh_parameters 2>&1 | awk '/^%username% / { print $2; exit }') -# else -# if ! _is_enabled "$ssh_only"; then -# # shellcheck disable=SC2039 -# if [ x"$OSTYPE" = x"cygwin" ]; then -# username=$(whoami) -# else -# username=$(ps -t "$tty" -o user= -o pid= -o ppid= -o command= | awk ' -# !/ssh/ { user[$2] = $1; ppid[$3] = 1 } -# END { -# for (i in user) -# if (!(i in ppid)) -# { -# print user[i] -# exit -# } -# } -# ') -# fi -# fi -# fi -# -# echo "$username" -# } -# -# _hostname() { -# tty=${1:-$(tmux display -p '#{pane_tty}')} -# ssh_only=$2 -# # shellcheck disable=SC2039 -# if [ x"$OSTYPE" = x"cygwin" ]; then -# pid=$(ps -a | awk -v tty="${tty##/dev/}" '$5 == tty && /ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { print $1 }') -# [ -n "$pid" ] && ssh_parameters=$(tr '\0' ' ' < "/proc/$pid/cmdline" | sed 's/^ssh //') -# else -# ssh_parameters=$(ps -t "$tty" -o command= | awk '/ssh/ && !/vagrant ssh/ && !/autossh/ && !/-W/ { $1=""; print $0; exit }') -# fi -# if [ -n "$ssh_parameters" ]; then -# # shellcheck disable=SC2086 -# hostname=$(ssh -G $ssh_parameters 2>/dev/null | awk 'NR > 2 { exit } ; /^hostname / { print $2 }') -# # shellcheck disable=SC2086 -# [ -z "$hostname" ] && hostname=$(ssh -T -o ControlPath=none -o ProxyCommand="sh -c 'echo %%hostname%% %h >&2'" $ssh_parameters 2>&1 | awk '/^%hostname% / { print $2; exit }') -# #shellcheck disable=SC1004 -# hostname=$(echo "$hostname" | awk '\ -# { \ -# if ($1~/^[0-9.:]+$/) \ -# print $1; \ -# else \ -# split($1, a, ".") ; print a[1] \ -# }') -# else -# if ! _is_enabled "$ssh_only"; then -# hostname=$(command hostname -s) -# fi -# fi -# -# echo "$hostname" -# } -# -# _root() { -# tty=${1:-$(tmux display -p '#{pane_tty}')} -# username=$(_username "$tty" false) -# -# if [ x"$username" = x"root" ]; then -# tmux show -gqv '@root' -# else -# echo "" -# fi -# } -# -# _uptime() { -# case $(uname -s) in -# *Darwin*) -# boot=$(sysctl -q -n kern.boottime | awk -F'[ ,:]+' '{ print $4 }') -# now=$(date +%s) -# ;; -# *Linux*|*CYGWIN*|*MSYS*|*MINGW*) -# now=$(cut -d' ' -f1 < /proc/uptime) -# ;; -# *OpenBSD*) -# boot=$(sysctl -n kern.boottime) -# now=$(date +%s) -# esac -# # shellcheck disable=SC1004 -# awk -v boot="$boot" -v now="$now" ' -# BEGIN { -# uptime = now - boot -# d = int(uptime / 86400) -# h = int(uptime / 3600) % 24 -# m = int(uptime / 60) % 60 -# s = int(uptime) % 60 -# -# system("tmux set -g @uptime_d " d + 0 " \\; " \ -# "set -g @uptime_h " h + 0 " \\; " \ -# "set -g @uptime_m " m + 0 " \\; " \ -# "set -g @uptime_s " s + 0) -# }' -# } -# -# _loadavg() { -# case $(uname -s) in -# *Darwin*) -# tmux set -g @loadavg "$(sysctl -q -n vm.loadavg | cut -d' ' -f2)" -# ;; -# *Linux*) -# tmux set -g @loadavg "$(cut -d' ' -f1 < /proc/loadavg)" -# ;; -# *OpenBSD*) -# tmux set -g @loadavg "$(sysctl -q -n vm.loadavg | cut -d' ' -f1)" -# ;; -# esac -# } -# -# _split_window() { -# tty=${1:-$(tmux display -p '#{pane_tty}')} -# shift -# # shellcheck disable=SC2039 -# if [ x"$OSTYPE" = x"cygwin" ]; then -# pid=$(ps -a | sort -d | awk -v tty="${tty##/dev/}" '$5 == tty && /ssh/ && !/-W/ { print $1; exit 0 }') -# [ -n "$pid" ] && ssh=$(tr '\0' ' ' < "/proc/$pid/cmdline") -# else -# ssh=$(ps -t "$tty" -o command= | sort -d | awk '/ssh/ && !/-W/ { print $0; exit 0 }') -# fi -# if [ -n "$ssh" ]; then -# # shellcheck disable=SC2046 -# tmux split-window "$@" $(echo "$ssh" | sed -e "s/;/\\\\;/g") -# else -# tmux split-window "$@" -# fi -# } -# -# _apply_overrides() { -# tmux_conf_theme_24b_colour=${tmux_conf_theme_24b_colour:-false} -# if _is_enabled "$tmux_conf_theme_24b_colour"; then -# case "$TERM" in -# screen-*|tmux-*) -# ;; -# *) -# tmux set-option -ga terminal-overrides ",$TERM:Tc" -# ;; -# esac -# fi -# } -# -# _apply_bindings() { -# line=$(tmux list-keys | grep new-window | head -1) -# prefix=${line%new-window*} -# column=${#prefix} -# -# tmux_conf_new_window_retain_current_path=${tmux_conf_new_window_retain_current_path:-false} -# while IFS= read -r line; do -# [ -z "$line" ] && continue -# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') -# if _is_enabled "$tmux_conf_new_window_retain_current_path"; then -# right=$(printf '%s' "$line" | cut -c"$column-" | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/new-window$/new-window -c "#{pane_current_path}"/g') -# else -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/-c[ \t]+"#\{pane_current_path\}"$//g') -# fi -# eval "tmux $left $right" 2>/dev/null || true -# done << EOF -# $(tmux list-keys 2>/dev/null | grep -e 'new-window\(\s\+-c\s\+"#{pane_current_path}\|$\)') -# EOF -# -# tmux_conf_new_pane_retain_current_path=${tmux_conf_new_pane_retain_current_path:-true} -# while IFS= read -r line; do -# [ -z "$line" ] && continue -# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') -# if _is_enabled "$tmux_conf_new_pane_retain_current_path"; then -# right=$(printf '%s' "$line" | cut -c"$column-" | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/split-window([ \t]+-(h|v))?$/& -c "#{pane_current_path}"/g') -# else -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/-c[ \t]+"#\{pane_current_path\}"$//g') -# fi -# eval "tmux $left $right" 2>/dev/null || true -# done << EOF -# $(tmux list-keys 2>/dev/null | grep -e 'split\(-\|_\)window') -# EOF -# -# tmux_conf_new_pane_reconnect_ssh=${tmux_conf_new_pane_reconnect_ssh:-false} -# while IFS= read -r line; do -# [ -z "$line" ] && continue -# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') -# if _is_enabled "$tmux_conf_new_pane_reconnect_ssh"; then -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/split-window([^;]+)/run-shell "cut -c3- ~\/\.tmux\.conf | sh -s _split_window #{pane_tty}\1"/g') -# else -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/run-shell "cut -c3- ~\/\.tmux\.conf \| sh -s _split_window #\{pane_tty\}([^;]+)"/split-window\1/g' -e 's/#\{.+\}/\"&\"/g') -# fi -# eval "tmux $left $right" 2>/dev/null || true -# done << EOF -# $(tmux list-keys 2>/dev/null | grep -e 'split\(-\|_\)window') -# EOF -# -# tmux_conf_new_session_prompt=${tmux_conf_new_session_prompt:-false} -# while IFS= read -r line; do -# [ -z "$line" ] && continue -# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') -# if _is_enabled "$tmux_conf_new_session_prompt"; then -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e 's/new-session$/command-prompt -p new-session \"new-session -s %%\"/g') -# else -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }'| sed -E -e 's/command-prompt -p new-session[^;]+/new-session/g') -# fi -# eval "tmux $left $right" 2>/dev/null || true -# done << EOF -# $(tmux list-keys 2>/dev/null | grep -e 'new-session') -# EOF -# -# tmux_conf_copy_to_os_clipboard=${tmux_conf_copy_to_os_clipboard:-false} -# command -v pbcopy > /dev/null 2>&1 && command='pbcopy' -# command -v reattach-to-user-namespace > /dev/null 2>&1 && command='reattach-to-user-namespace pbcopy' -# command -v xsel > /dev/null 2>&1 && command='xsel -i -b' -# ! command -v xsel > /dev/null 2>&1 && command -v xclip > /dev/null 2>&1 && command='xclip -i -selection clipboard > \/dev\/null 2>\&1' -# command -v clip.exe > /dev/null 2>&1 && command='clip\.exe' -# [ -c /dev/clipboard ] && command='cat > \/dev\/clipboard' -# -# if [ -n "$command" ]; then -# # shellcheck disable=SC2086 -# for table in "" "-t emacs-copy" "-t vi-copy"; do -# line=$(tmux list-keys $table 2>/dev/null | grep -e 'copy-selection\|copy-pipe' | head -1) -# prefix=${line%copy-*} -# column=${#prefix} -# [ -z "$line" ] && continue -# -# while IFS= read -r line; do -# [ -z "$line" ] && continue -# left=$(printf '%s' "$line" | cut -c-"$column" | sed -E -e 's/[^ \ta-zA-Z0-9,._+@%/-]/\\&/g') -# if _is_enabled "$tmux_conf_copy_to_os_clipboard"; then -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e "s/copy-selection(-and-cancel)?$/copy-pipe\1 \"$command\"/g") -# else -# right=$(printf '%s' "$line" | cut -c"$column"- | awk -F'\"' 'BEGIN { OFS = FS } { for (i = 1; i <= NF; i+=2) { gsub(/#{.+}/, "\"&\"", $i) } print }' | sed -E -e "s/copy-pipe(-and-cancel)? \"$command\"$/copy-selection\1/g") -# fi -# eval "tmux $left $right" 2>/dev/null || true -# done << EOF -# $(tmux list-keys $table 2>/dev/null | grep -e 'copy-selection\|copy-pipe') -# EOF -# done -# fi -# } -# -# _apply_theme() { -# -# # -- panes ------------------------------------------------------------- -# -# tmux_conf_theme_window_fg=${tmux_conf_theme_window_fg:-default} -# tmux_conf_theme_window_bg=${tmux_conf_theme_window_bg:-default} -# tmux_conf_theme_highlight_focused_pane=${tmux_conf_theme_highlight_focused_pane:-false} -# tmux_conf_theme_focused_pane_fg=${tmux_conf_theme_focused_pane_fg:-'default'} # default -# tmux_conf_theme_focused_pane_bg=${tmux_conf_theme_focused_pane_bg:-'#0087d7'} # light blue -# -# # tmux 1.9 doesn't really like set -q -# if tmux show -g -w | grep -q window-style; then -# tmux setw -g window-style "fg=$tmux_conf_theme_window_fg,bg=$tmux_conf_theme_window_bg" -# -# if _is_enabled "$tmux_conf_theme_highlight_focused_pane"; then -# tmux setw -g window-active-style "fg=$tmux_conf_theme_focused_pane_fg,bg=$tmux_conf_theme_focused_pane_bg" -# else -# tmux setw -g window-active-style default -# fi -# fi -# -# tmux_conf_theme_pane_border_style=${tmux_conf_theme_pane_border_style:-thin} -# tmux_conf_theme_pane_border=${tmux_conf_theme_pane_border:-'#444444'} # light gray -# tmux_conf_theme_pane_active_border=${tmux_conf_theme_pane_active_border:-'#00afff'} # light blue -# tmux_conf_theme_pane_border_fg=${tmux_conf_theme_pane_border_fg:-$tmux_conf_theme_pane_border} -# tmux_conf_theme_pane_active_border_fg=${tmux_conf_theme_pane_active_border_fg:-$tmux_conf_theme_pane_active_border} -# case "$tmux_conf_theme_pane_border_style" in -# fat) -# tmux_conf_theme_pane_border_bg=${tmux_conf_theme_pane_border_bg:-$tmux_conf_theme_pane_border_fg} -# tmux_conf_theme_pane_active_border_bg=${tmux_conf_theme_pane_active_border_bg:-$tmux_conf_theme_pane_active_border_fg} -# ;; -# thin|*) -# tmux_conf_theme_pane_border_bg=${tmux_conf_theme_pane_border_bg:-'default'} -# tmux_conf_theme_pane_active_border_bg=${tmux_conf_theme_pane_active_border_bg:-'default'} -# ;; -# esac -# tmux setw -g pane-border-style "fg=$tmux_conf_theme_pane_border_fg,bg=$tmux_conf_theme_pane_border_bg" \; set -g pane-active-border-style "fg=$tmux_conf_theme_pane_active_border_fg,bg=$tmux_conf_theme_pane_active_border_bg" -# -# tmux_conf_theme_pane_indicator=${tmux_conf_theme_pane_indicator:-'#00afff'} # light blue -# tmux_conf_theme_pane_active_indicator=${tmux_conf_theme_pane_active_indicator:-'#00afff'} # light blue -# -# tmux set -g display-panes-colour "$tmux_conf_theme_pane_indicator" \; set -g display-panes-active-colour "$tmux_conf_theme_pane_active_indicator" -# -# # -- status line ------------------------------------------------------- -# -# tmux_conf_theme_left_separator_main=${tmux_conf_theme_left_separator_main-''} -# tmux_conf_theme_left_separator_sub=${tmux_conf_theme_left_separator_sub-'|'} -# tmux_conf_theme_right_separator_main=${tmux_conf_theme_right_separator_main-''} -# tmux_conf_theme_right_separator_sub=${tmux_conf_theme_right_separator_sub-'|'} -# -# tmux_conf_theme_message_fg=${tmux_conf_theme_message_fg:-'#000000'} # black -# tmux_conf_theme_message_bg=${tmux_conf_theme_message_bg:-'#ffff00'} # yellow -# tmux_conf_theme_message_attr=${tmux_conf_theme_message_attr:-'bold'} -# tmux set -g message-style "fg=$tmux_conf_theme_message_fg,bg=$tmux_conf_theme_message_bg,$tmux_conf_theme_message_attr" -# -# tmux_conf_theme_message_command_fg=${tmux_conf_theme_message_command_fg:-'#ffff00'} # yellow -# tmux_conf_theme_message_command_bg=${tmux_conf_theme_message_command_bg:-'#000000'} # black -# tmux_conf_theme_message_command_attr=${tmux_conf_theme_message_command_attr:-'bold'} -# tmux set -g message-command-style "fg=$tmux_conf_theme_message_command_fg,bg=$tmux_conf_theme_message_command_bg,$tmux_conf_theme_message_command_attr" -# -# tmux_conf_theme_mode_fg=${tmux_conf_theme_mode_fg:-'#000000'} # black -# tmux_conf_theme_mode_bg=${tmux_conf_theme_mode_bg:-'#ffff00'} # yellow -# tmux_conf_theme_mode_attr=${tmux_conf_theme_mode_attr:-'bold'} -# tmux setw -g mode-style "fg=$tmux_conf_theme_mode_fg,bg=$tmux_conf_theme_mode_bg,$tmux_conf_theme_mode_attr" -# -# tmux_conf_theme_status_fg=${tmux_conf_theme_status_fg:-'#8a8a8a'} # white -# tmux_conf_theme_status_bg=${tmux_conf_theme_status_bg:-'#080808'} # dark gray -# tmux_conf_theme_status_attr=${tmux_conf_theme_status_attr:-'none'} -# tmux set -g status-style "fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr" \;\ -# set -g status-left-style "fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr" \;\ -# set -g status-right-style "fg=$tmux_conf_theme_status_fg,bg=$tmux_conf_theme_status_bg,$tmux_conf_theme_status_attr" -# -# tmux_conf_theme_window_status_fg=${tmux_conf_theme_window_status_fg:-'#8a8a8a'} # white -# tmux_conf_theme_window_status_bg=${tmux_conf_theme_window_status_bg:-'#080808'} # dark gray -# tmux_conf_theme_window_status_attr=${tmux_conf_theme_window_status_attr:-'none'} -# tmux_conf_theme_window_status_format=${tmux_conf_theme_window_status_format:-'#I #W'} -# -# tmux_conf_theme_window_status_current_fg=${tmux_conf_theme_window_status_current_fg:-'#000000'} # black -# tmux_conf_theme_window_status_current_bg=${tmux_conf_theme_window_status_current_bg:-'#00afff'} # light blue -# tmux_conf_theme_window_status_current_attr=${tmux_conf_theme_window_status_current_attr:-'bold'} -# tmux_conf_theme_window_status_current_format=${tmux_conf_theme_window_status_current_format:-'#I #W'} -# if [ x"$(tmux show -g -v status-justify)" = x"right" ]; then -# tmux_conf_theme_window_status_current_format="#[fg=$tmux_conf_theme_window_status_current_bg,bg=$tmux_conf_theme_window_status_bg]$tmux_conf_theme_right_separator_main#[fg=default,bg=default,default] $tmux_conf_theme_window_status_current_format #[fg=$tmux_conf_theme_window_status_bg,bg=$tmux_conf_theme_window_status_current_bg,none]$tmux_conf_theme_right_separator_main" -# else -# tmux_conf_theme_window_status_current_format="#[fg=$tmux_conf_theme_window_status_bg,bg=$tmux_conf_theme_window_status_current_bg]$tmux_conf_theme_left_separator_main#[fg=default,bg=default,default] $tmux_conf_theme_window_status_current_format #[fg=$tmux_conf_theme_window_status_current_bg,bg=$tmux_conf_theme_status_bg,none]$tmux_conf_theme_left_separator_main" -# fi -# -# tmux_conf_theme_window_status_format=$(echo "$tmux_conf_theme_window_status_format" | sed 's%#{circled_window_index}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #I)%g') -# tmux_conf_theme_window_status_current_format=$(echo "$tmux_conf_theme_window_status_current_format" | sed 's%#{circled_window_index}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #I)%g') -# -# tmux setw -g window-status-style "fg=$tmux_conf_theme_window_status_fg,bg=$tmux_conf_theme_window_status_bg,$tmux_conf_theme_window_status_attr" \;\ -# setw -g window-status-format "$tmux_conf_theme_window_status_format" \;\ -# setw -g window-status-current-style "fg=$tmux_conf_theme_window_status_current_fg,bg=$tmux_conf_theme_window_status_current_bg,$tmux_conf_theme_window_status_current_attr" \;\ -# setw -g window-status-current-format "$tmux_conf_theme_window_status_current_format" -# -# tmux_conf_theme_window_status_activity_fg=${tmux_conf_theme_window_status_activity_fg:-'default'} -# tmux_conf_theme_window_status_activity_bg=${tmux_conf_theme_window_status_activity_bg:-'default'} -# tmux_conf_theme_window_status_activity_attr=${tmux_conf_theme_window_status_activity_attr:-'underscore'} -# tmux setw -g window-status-activity-style "fg=$tmux_conf_theme_window_status_activity_fg,bg=$tmux_conf_theme_window_status_activity_bg,$tmux_conf_theme_window_status_activity_attr" -# -# tmux_conf_theme_window_status_bell_fg=${tmux_conf_theme_window_status_bell_fg:-'#ffff00'} # yellow -# tmux_conf_theme_window_status_bell_bg=${tmux_conf_theme_window_status_bell_bg:-'default'} -# tmux_conf_theme_window_status_bell_attr=${tmux_conf_theme_window_status_bell_attr:-'blink,bold'} -# tmux setw -g window-status-bell-style "fg=$tmux_conf_theme_window_status_bell_fg,bg=$tmux_conf_theme_window_status_bell_bg,$tmux_conf_theme_window_status_bell_attr" -# -# tmux_conf_theme_window_status_last_fg=${tmux_conf_theme_window_status_last_fg:-'#00afff'} # light blue -# tmux_conf_theme_window_status_last_bg=${tmux_conf_theme_window_status_last_bg:-'default'} -# tmux_conf_theme_window_status_last_attr=${tmux_conf_theme_window_status_last_attr:-'none'} -# tmux setw -g window-status-last-style "fg=$tmux_conf_theme_window_status_last_fg,bg=$tmux_conf_theme_window_status_last_bg,$tmux_conf_theme_window_status_last_attr" -# -# # -- indicators -# -# tmux_conf_theme_pairing=${tmux_conf_theme_pairing:-'👓'} # U+1F453 -# tmux_conf_theme_pairing_fg=${tmux_conf_theme_pairing_fg:-'#e4e4e4'} # white -# tmux_conf_theme_pairing_bg=${tmux_conf_theme_pairing_bg:-'none'} -# tmux_conf_theme_pairing_attr=${tmux_conf_theme_pairing_attr:-'none'} -# -# tmux_conf_theme_prefix=${tmux_conf_theme_prefix:-'⌨'} # U+2328 -# tmux_conf_theme_prefix_fg=${tmux_conf_theme_prefix_fg:-'#e4e4e4'} # white -# tmux_conf_theme_prefix_bg=${tmux_conf_theme_prefix_bg:-'none'} -# tmux_conf_theme_prefix_attr=${tmux_conf_theme_prefix_attr:-'none'} -# -# tmux_conf_theme_root=${tmux_conf_theme_root:-'!'} -# tmux_conf_theme_root_fg=${tmux_conf_theme_root_fg:-'none'} -# tmux_conf_theme_root_bg=${tmux_conf_theme_root_bg:-'none'} -# tmux_conf_theme_root_attr=${tmux_conf_theme_root_attr:-'bold,blink'} -# -# # -- status left style -# -# tmux_conf_theme_status_left=${tmux_conf_theme_status_left-' ❐ #S '} -# tmux_conf_theme_status_left_fg=${tmux_conf_theme_status_left_fg:-'#000000,#e4e4e4,#e4e4e4'} # black, white , white -# tmux_conf_theme_status_left_bg=${tmux_conf_theme_status_left_bg:-'#ffff00,#ff00af,#00afff'} # yellow, pink, white blue -# tmux_conf_theme_status_left_attr=${tmux_conf_theme_status_left_attr:-'bold,none,none'} -# -# tmux_conf_theme_status_left=$(echo "$tmux_conf_theme_status_left" | sed \ -# -e "s/#{pairing}/#[fg=$tmux_conf_theme_pairing_fg]#[bg=$tmux_conf_theme_pairing_bg]#[$tmux_conf_theme_pairing_attr]#{?session_many_attached,$tmux_conf_theme_pairing,}/g") -# -# tmux_conf_theme_status_left=$(echo "$tmux_conf_theme_status_left" | sed \ -# -e "s/#{prefix}/#[fg=$tmux_conf_theme_prefix_fg]#[bg=$tmux_conf_theme_prefix_bg]#[$tmux_conf_theme_prefix_attr]#{?client_prefix,$tmux_conf_theme_prefix,}/g") -# -# tmux_conf_theme_status_left=$(echo "$tmux_conf_theme_status_left" | sed \ -# -e "s%#{root}%#[fg=$tmux_conf_theme_root_fg]#[bg=$tmux_conf_theme_root_bg]#[$tmux_conf_theme_root_attr]#(cut -c3- ~/.tmux.conf | sh -s _root #{pane_tty} #D)#[inherit]%g") -# -# if [ -n "$tmux_conf_theme_status_left" ]; then -# status_left=$(awk \ -# -v fg_="$tmux_conf_theme_status_left_fg" \ -# -v bg_="$tmux_conf_theme_status_left_bg" \ -# -v attr_="$tmux_conf_theme_status_left_attr" \ -# -v mainsep="$tmux_conf_theme_left_separator_main" \ -# -v subsep="$tmux_conf_theme_left_separator_sub" ' -# function subsplit(s, l, i, a, r) -# { -# l = split(s, a, ",") -# for (i = 1; i <= l; ++i) -# { -# o = split(a[i], _, "(") - 1 -# c = split(a[i], _, ")") - 1 -# open += o - c -# o_ = split(a[i], _, "{") - 1 -# c_ = split(a[i], _, "}") - 1 -# open_ += o_ - c_ -# o__ = split(a[i], _, "[") - 1 -# c__ = split(a[i], _, "]") - 1 -# open__ += o__ - c__ -# -# if (i == l) -# r = sprintf("%s%s", r, a[i]) -# else if (open || open_ || open__) -# r = sprintf("%s%s,", r, a[i]) -# else -# r = sprintf("%s%s#[fg=%s,bg=%s,%s]%s", r, a[i], fg[j], bg[j], attr[j], subsep) -# } -# -# gsub(/#\[inherit\]/, sprintf("#[default]#[fg=%s,bg=%s,%s]", fg[j], bg[j], attr[j]), r) -# return r -# } -# BEGIN { -# FS = "|" -# l1 = split(fg_, fg, ",") -# l2 = split(bg_, bg, ",") -# l3 = split(attr_, attr, ",") -# l = l1 < l2 ? (l1 < l3 ? l1 : l3) : (l2 < l3 ? l2 : l3) -# } -# { -# for (i = j = 1; i <= NF; ++i) -# { -# if (open || open_ || open__) -# printf "|%s", subsplit($i) -# else -# { -# if (i > 1) -# printf "#[fg=%s,bg=%s,none]%s#[fg=%s,bg=%s,%s]%s", bg[j_], bg[j], mainsep, fg[j], bg[j], attr[j], subsplit($i) -# else -# printf "#[fg=%s,bg=%s,%s]%s", fg[j], bg[j], attr[j], subsplit($i) -# } -# -# if (!open && !open_ && !open__) -# { -# j_ = j -# j = j % l + 1 -# } -# } -# printf "#[fg=%s,bg=%s,none]%s", bg[j_], "default", mainsep -# }' << EOF -# $tmux_conf_theme_status_left -# EOF -# ) -# fi -# -# status_left="$status_left " -# -# # -- status right style -# -# tmux_conf_theme_status_right=${tmux_conf_theme_status_right-'#{pairing}#{prefix} #{battery_status} #{battery_bar} #{battery_percentage} , %R , %d %b | #{username} | #{hostname} '} -# tmux_conf_theme_status_right_fg=${tmux_conf_theme_status_right_fg:-'#8a8a8a,#e4e4e4,#000000'} # light gray, white, black -# tmux_conf_theme_status_right_bg=${tmux_conf_theme_status_right_bg:-'#080808,#d70000,#e4e4e4'} # dark gray, red, white -# tmux_conf_theme_status_right_attr=${tmux_conf_theme_status_right_attr:-'none,none,bold'} -# -# tmux_conf_theme_status_right=$(echo "$tmux_conf_theme_status_right" | sed \ -# -e "s/#{pairing}/#[fg=$tmux_conf_theme_pairing_fg]#[bg=$tmux_conf_theme_pairing_bg]#[$tmux_conf_theme_pairing_attr]#{?session_many_attached,$tmux_conf_theme_pairing,}/g") -# -# tmux_conf_theme_status_right=$(echo "$tmux_conf_theme_status_right" | sed \ -# -e "s/#{prefix}/#[fg=$tmux_conf_theme_prefix_fg]#[bg=$tmux_conf_theme_prefix_bg]#[$tmux_conf_theme_prefix_attr]#{?client_prefix,$tmux_conf_theme_prefix,}/g") -# -# tmux_conf_theme_status_right=$(echo "$tmux_conf_theme_status_right" | sed \ -# -e "s%#{root}%#[fg=$tmux_conf_theme_root_fg]#[bg=$tmux_conf_theme_root_bg]#[$tmux_conf_theme_root_attr]#(cut -c3- ~/.tmux.conf | sh -s _root #{pane_tty} #D)#[inherit]%g") -# -# if [ -n "$tmux_conf_theme_status_right" ]; then -# status_right=$(awk \ -# -v fg_="$tmux_conf_theme_status_right_fg" \ -# -v bg_="$tmux_conf_theme_status_right_bg" \ -# -v attr_="$tmux_conf_theme_status_right_attr" \ -# -v mainsep="$tmux_conf_theme_right_separator_main" \ -# -v subsep="$tmux_conf_theme_right_separator_sub" ' -# function subsplit(s, l, i, a, r) -# { -# l = split(s, a, ",") -# for (i = 1; i <= l; ++i) -# { -# o = split(a[i], _, "(") - 1 -# c = split(a[i], _, ")") - 1 -# open += o - c -# o_ = split(a[i], _, "{") - 1 -# c_ = split(a[i], _, "}") - 1 -# open_ += o_ - c_ -# o__ = split(a[i], _, "[") - 1 -# c__ = split(a[i], _, "]") - 1 -# open__ += o__ - c__ -# -# if (i == l) -# r = sprintf("%s%s", r, a[i]) -# else if (open || open_ || open__) -# r = sprintf("%s%s,", r, a[i]) -# else -# r = sprintf("%s%s#[fg=%s,bg=%s,%s]%s", r, a[i], fg[j], bg[j], attr[j], subsep) -# } -# -# gsub(/#\[inherit\]/, sprintf("#[default]#[fg=%s,bg=%s,%s]", fg[j], bg[j], attr[j]), r) -# return r -# } -# BEGIN { -# FS = "|" -# l1 = split(fg_, fg, ",") -# l2 = split(bg_, bg, ",") -# l3 = split(attr_, attr, ",") -# l = l1 < l2 ? (l1 < l3 ? l1 : l3) : (l2 < l3 ? l2 : l3) -# } -# { -# for (i = j = 1; i <= NF; ++i) -# { -# if (open_ || open || open__) -# printf "|%s", subsplit($i) -# else -# printf "#[fg=%s,bg=%s,none]%s#[fg=%s,bg=%s,%s]%s", bg[j], (i == 1) ? "default" : bg[j_], mainsep, fg[j], bg[j], attr[j], subsplit($i) -# -# if (!open && !open_ && !open__) -# { -# j_ = j -# j = j % l + 1 -# } -# } -# }' << EOF -# $tmux_conf_theme_status_right -# EOF -# ) -# fi -# -# # -- variables -# -# tmux set -g '@root' "$tmux_conf_theme_root" -# -# tmux_conf_battery_bar_symbol_full=${tmux_conf_battery_bar_symbol_full:-'◼'} -# tmux_conf_battery_bar_symbol_empty=${tmux_conf_battery_bar_symbol_empty:-'◻'} -# tmux_conf_battery_bar_length=${tmux_conf_battery_bar_length:-'auto'} -# tmux_conf_battery_bar_palette=${tmux_conf_battery_bar_palette:-'gradient'} -# tmux_conf_battery_hbar_palette=${tmux_conf_battery_hbar_palette:-'gradient'} # red, orange, green -# tmux_conf_battery_vbar_palette=${tmux_conf_battery_vbar_palette:-'gradient'} # red, orange, green -# tmux_conf_battery_status_charging=${tmux_conf_battery_status_charging:-'↑'} # U+2191 -# tmux_conf_battery_status_discharging=${tmux_conf_battery_status_discharging:-'↓'} # U+2193 -# -# case "$status_left $status_right" in -# *'#{battery_status}'*|*'#{battery_bar}'*|*'#{battery_hbar}'*|*'#{battery_vbar}'*|*'#{battery_percentage}'*) -# status_left=$(echo "$status_left" | sed -E \ -# -e 's/#\{(\?)?battery_bar/#\{\1@battery_bar/g' \ -# -e 's/#\{(\?)?battery_hbar/#\{\1@battery_hbar/g' \ -# -e 's/#\{(\?)?battery_vbar/#\{\1@battery_vbar/g' \ -# -e 's/#\{(\?)?battery_status/#\{\1@battery_status/g' \ -# -e 's/#\{(\?)?battery_percentage/#\{\1@battery_percentage/g') -# status_right=$(echo "$status_right" | sed -E \ -# -e 's/#\{(\?)?battery_bar/#\{\1@battery_bar/g' \ -# -e 's/#\{(\?)?battery_hbar/#\{\1@battery_hbar/g' \ -# -e 's/#\{(\?)?battery_vbar/#\{\1@battery_vbar/g' \ -# -e 's/#\{(\?)?battery_status/#\{\1@battery_status/g' \ -# -e 's/#\{(\?)?battery_percentage/#\{\1@battery_percentage/g') -# -# tmux set -g '@battery_bar_symbol_full' "$tmux_conf_battery_bar_symbol_full" \;\ -# set -g '@battery_bar_symbol_empty' "$tmux_conf_battery_bar_symbol_empty" \;\ -# set -g '@battery_bar_length' "$tmux_conf_battery_bar_length" \;\ -# set -g '@battery_bar_palette' "$tmux_conf_battery_bar_palette" \;\ -# set -g '@battery_hbar_palette' "$tmux_conf_battery_hbar_palette" \;\ -# set -g '@battery_vbar_palette' "$tmux_conf_battery_vbar_palette" \;\ -# set -g '@battery_status_charging' "$tmux_conf_battery_status_charging" \;\ -# set -g '@battery_status_discharging' "$tmux_conf_battery_status_discharging" -# status_right="#(cut -c3- ~/.tmux.conf | sh -s _battery)$status_right" -# ;; -# esac -# -# case "$status_left $status_right" in -# *'#{username}'*|*'#{hostname}'*|*'#{username_ssh}'*|*'#{hostname_ssh}'*) -# status_left=$(echo "$status_left" | sed \ -# -e 's%#{username}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} false #D)%g' \ -# -e 's%#{hostname}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} false #D)%g' \ -# -e 's%#{username_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} true #D)%g' \ -# -e 's%#{hostname_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} true #D)%g') -# status_right=$(echo "$status_right" | sed \ -# -e 's%#{username}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} false #D)%g' \ -# -e 's%#{hostname}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} false #D)%g' \ -# -e 's%#{username_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _username #{pane_tty} true #D)%g' \ -# -e 's%#{hostname_ssh}%#(cut -c3- ~/.tmux.conf | sh -s _hostname #{pane_tty} true #D)%g') -# ;; -# esac -# -# case "$status_left $status_right" in -# *'#{uptime_d}'*|*'#{uptime_h}'*|*'#{uptime_m}'*) -# status_left=$(echo "$status_left" | sed -E \ -# -e 's/#\{(\?)?uptime_d/#\{\1@uptime_d/g' \ -# -e 's/#\{(\?)?uptime_h/#\{\1@uptime_h/g' \ -# -e 's/#\{(\?)?uptime_m/#\{\1@uptime_m/g' \ -# -e 's/#\{(\?)?uptime_s/#\{\1@uptime_s/g') -# status_right=$(echo "$status_right" | sed -E \ -# -e 's/#\{(\?)?uptime_d/#\{\1@uptime_d/g' \ -# -e 's/#\{(\?)?uptime_h/#\{\1@uptime_h/g' \ -# -e 's/#\{(\?)?uptime_m/#\{\1@uptime_m/g' \ -# -e 's/#\{(\?)?uptime_s/#\{\1@uptime_s/g') -# status_right="#(cut -c3- ~/.tmux.conf | sh -s _uptime)$status_right" -# ;; -# esac -# -# case "$status_left $status_right" in -# *'#{loadavg}'*) -# status_left=$(echo "$status_left" | sed -E \ -# -e 's/#\{(\?)?loadavg/#\{\1@loadavg/g') -# status_right=$(echo "$status_right" | sed -E \ -# -e 's/#\{(\?)?loadavg/#\{\1@loadavg/g') -# status_right="#(cut -c3- ~/.tmux.conf | sh -s _loadavg)$status_right" -# ;; -# esac -# -# status_left=$(echo "$status_left" | sed 's%#{circled_session_name}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #S)%g') -# status_right=$(echo "$status_right" | sed 's%#{circled_session_name}%#(cut -c3- ~/.tmux.conf | sh -s _circled_digit #S)%g') -# -# tmux set -g status-left-length 1000 \; set -g status-left "$status_left" \;\ -# set -g status-right-length 1000 \; set -g status-right "$status_right" -# -# # -- clock ------------------------------------------------------------- -# -# tmux_conf_theme_clock_colour=${tmux_conf_theme_clock_colour:-'#00afff'} # light blue -# tmux_conf_theme_clock_style=${tmux_conf_theme_clock_style:-'24'} -# tmux setw -g clock-mode-colour "$tmux_conf_theme_clock_colour" \;\ -# setw -g clock-mode-style "$tmux_conf_theme_clock_style" -# } -# -# _apply_configuration() { -# -# # see https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard -# if command -v reattach-to-user-namespace > /dev/null 2>&1; then -# default_shell="$(tmux show -gv default-shell)" -# case "$default_shell" in -# *fish) -# tmux set -g default-command "reattach-to-user-namespace -l $default_shell" -# ;; -# *sh) -# tmux set -g default-command "exec $default_shell... 2> /dev/null & reattach-to-user-namespace -l $default_shell" -# ;; -# esac -# fi -# -# _apply_overrides -# _apply_bindings -# _apply_theme -# for name in $(printenv | grep -Eo '^tmux_conf_[^=]+'); do tmux setenv -gu "$name"; done; -# } -# -# _urlview() { -# tmux capture-pane -J -S - -E - -b "urlview-$1" -t "$1" -# tmux split-window "tmux show-buffer -b urlview-$1 | urlview || true; tmux delete-buffer -b urlview-$1" -# } -# -# _fpp() { -# tmux capture-pane -J -S - -E - -b "fpp-$1" -t "$1" -# tmux split-window "tmux show-buffer -b fpp-$1 | fpp || true; tmux delete-buffer -b fpp-$1" -# } -# -# "$@" diff --git a/config/tmux/.tmux.conf.local b/config/tmux/.tmux.conf.local deleted file mode 100644 index 5d053ee..0000000 --- a/config/tmux/.tmux.conf.local +++ /dev/null @@ -1,267 +0,0 @@ -# https://github.com/gpakosz/.tmux -# (‑●‑●)> dual licensed under the WTFPL v2 license and the MIT license, -# without any warranty. -# Copyright 2012— Gregory Pakosz (@gpakosz). - - -# -- navigation ---------------------------------------------------------------- - -# if you're running tmux within iTerm2 -# - and tmux is 1.9 or 1.9a -# - and iTerm2 is configured to let option key act as +Esc -# - and iTerm2 is configured to send [1;9A -> [1;9D for option + arrow keys -# then uncomment the following line to make Meta + arrow keys mapping work -#set -ga terminal-overrides "*:kUP3=\e[1;9A,*:kDN3=\e[1;9B,*:kRIT3=\e[1;9C,*:kLFT3=\e[1;9D" - - -# -- windows & pane creation --------------------------------------------------- - -# new window retains current path, possible values are: -# - true -# - false (default) -tmux_conf_new_window_retain_current_path=false - -# new pane retains current path, possible values are: -# - true (default) -# - false -tmux_conf_new_pane_retain_current_path=true - -# new pane tries to reconnect ssh sessions (experimental), possible values are: -# - true -# - false (default) -tmux_conf_new_pane_reconnect_ssh=false - -# prompt for session name when creating a new session, possible values are: -# - true -# - false (default) -tmux_conf_new_session_prompt=false - - -# -- display ------------------------------------------------------------------- - -# RGB 24-bit colour support (tmux >= 2.2), possible values are: -# - true -# - false (default) -tmux_conf_theme_24b_colour=false - -# window style -tmux_conf_theme_window_fg='default' -tmux_conf_theme_window_bg='default' - -# highlight focused pane (tmux >= 2.1), possible values are: -# - true -# - false (default) -tmux_conf_theme_highlight_focused_pane=false - -# focused pane colours: -tmux_conf_theme_focused_pane_fg='default' -tmux_conf_theme_focused_pane_bg='#0087d7' # light blue - -# pane border style, possible values are: -# - thin (default) -# - fat -tmux_conf_theme_pane_border_style=thin - -# pane borders colours: -tmux_conf_theme_pane_border='#444444' # gray -tmux_conf_theme_pane_active_border='#00afff' # light blue - -# pane indicator colours -tmux_conf_theme_pane_indicator='#00afff' # light blue -tmux_conf_theme_pane_active_indicator='#00afff' # light blue - -# status line style -tmux_conf_theme_message_fg='#000000' # black -tmux_conf_theme_message_bg='#ffff00' # yellow -tmux_conf_theme_message_attr='bold' - -# status line command style ( : Escape) -tmux_conf_theme_message_command_fg='#ffff00' # yellow -tmux_conf_theme_message_command_bg='#000000' # black -tmux_conf_theme_message_command_attr='bold' - -# window modes style -tmux_conf_theme_mode_fg='#000000' # black -tmux_conf_theme_mode_bg='#ffff00' # yellow -tmux_conf_theme_mode_attr='bold' - -# status line style -tmux_conf_theme_status_fg='#8a8a8a' # light gray -tmux_conf_theme_status_bg='#080808' # dark gray -tmux_conf_theme_status_attr='none' - -# window status style -# - built-in variables are: -# - #{circled_window_index} -tmux_conf_theme_window_status_fg='#8a8a8a' # light gray -tmux_conf_theme_window_status_bg='#080808' # dark gray -tmux_conf_theme_window_status_attr='none' -tmux_conf_theme_window_status_format='#I #W' -#tmux_conf_theme_window_status_format='#{circled_window_index} #W' -#tmux_conf_theme_window_status_format='#I #W#{?window_bell_flag,🔔,}#{?window_zoomed_flag,🔍,}' - -# window current status style -# - built-in variables are: -# - #{circled_window_index} -tmux_conf_theme_window_status_current_fg='#000000' # black -tmux_conf_theme_window_status_current_bg='#00afff' # light blue -tmux_conf_theme_window_status_current_attr='bold' -tmux_conf_theme_window_status_current_format='#I #W' -#tmux_conf_theme_window_status_current_format='#{circled_window_index} #W' -#tmux_conf_theme_window_status_current_format='#I #W#{?window_zoomed_flag,🔍,}' - -# window activity status style -tmux_conf_theme_window_status_activity_fg='default' -tmux_conf_theme_window_status_activity_bg='default' -tmux_conf_theme_window_status_activity_attr='underscore' - -# window bell status style -tmux_conf_theme_window_status_bell_fg='#ffff00' # yellow -tmux_conf_theme_window_status_bell_bg='default' -tmux_conf_theme_window_status_bell_attr='blink,bold' - -# window last status style -tmux_conf_theme_window_status_last_fg='#00afff' # light blue -tmux_conf_theme_window_status_last_bg='default' -tmux_conf_theme_window_status_last_attr='none' - -# status left/right sections separators -tmux_conf_theme_left_separator_main='' -tmux_conf_theme_left_separator_sub='|' -tmux_conf_theme_right_separator_main='' -tmux_conf_theme_right_separator_sub='|' -#tmux_conf_theme_left_separator_main='' # /!\ you don't need to install Powerline -#tmux_conf_theme_left_separator_sub='' # you only need fonts patched with -#tmux_conf_theme_right_separator_main='' # Powerline symbols or the standalone -#tmux_conf_theme_right_separator_sub='' # PowerlineSymbols.otf font - -# status left/right content: -# - separate main sections with '|' -# - separate subsections with ',' -# - built-in variables are: -# - #{battery_bar} -# - #{battery_hbar} -# - #{battery_percentage} -# - #{battery_status} -# - #{battery_vbar} -# - #{circled_session_name} -# - #{hostname_ssh} -# - #{hostname} -# - #{loadavg} -# - #{pairing} -# - #{prefix} -# - #{root} -# - #{uptime_d} -# - #{uptime_h} -# - #{uptime_m} -# - #{uptime_s} -# - #{username} -# - #{username_ssh} -tmux_conf_theme_status_left=' ❐ #S | ↑#{?uptime_d, #{uptime_d}d,}#{?uptime_h, #{uptime_h}h,}#{?uptime_m, #{uptime_m}m,} ' -tmux_conf_theme_status_right='#{prefix}#{pairing} #{?battery_status, #{battery_status},}#{?battery_bar, #{battery_bar},}#{?battery_percentage, #{battery_percentage},} , %R , %d %b | #{username}#{root} | #{hostname} ' - -# status left style -tmux_conf_theme_status_left_fg='#000000,#e4e4e4,#e4e4e4' # black, white , white -tmux_conf_theme_status_left_bg='#ffff00,#ff00af,#00afff' # yellow, pink, white blue -tmux_conf_theme_status_left_attr='bold,none,none' - -# status right style -tmux_conf_theme_status_right_fg='#8a8a8a,#e4e4e4,#000000' # light gray, white, black -tmux_conf_theme_status_right_bg='#080808,#d70000,#e4e4e4' # dark gray, red, white -tmux_conf_theme_status_right_attr='none,none,bold' - -# pairing indicator -tmux_conf_theme_pairing='👓' # U+1F453 -tmux_conf_theme_pairing_fg='none' -tmux_conf_theme_pairing_bg='none' -tmux_conf_theme_pairing_attr='none' - -# prefix indicator -tmux_conf_theme_prefix='⌨' # U+2328 -tmux_conf_theme_prefix_fg='none' -tmux_conf_theme_prefix_bg='none' -tmux_conf_theme_prefix_attr='none' - -# root indicator -tmux_conf_theme_root='!' -tmux_conf_theme_root_fg='none' -tmux_conf_theme_root_bg='none' -tmux_conf_theme_root_attr='bold,blink' - -# battery bar symbols -#tmux_conf_battery_bar_symbol_full='◼' -#tmux_conf_battery_bar_symbol_empty='◻' -tmux_conf_battery_bar_symbol_full='♥' -tmux_conf_battery_bar_symbol_empty='·' - -# battery bar length (in number of symbols), possible values are: -# - auto -# - a number, e.g. 5 -tmux_conf_battery_bar_length='auto' - -# battery bar palette, possible values are: -# - gradient (default) -# - heat -# - 'colour_full_fg,colour_empty_fg,colour_bg' -tmux_conf_battery_bar_palette='gradient' -#tmux_conf_battery_bar_palette='#d70000,#e4e4e4,#000000' # red, white, black - -# battery hbar palette, possible values are: -# - gradient (default) -# - heat -# - 'colour_low,colour_half,colour_full' -tmux_conf_battery_hbar_palette='gradient' -#tmux_conf_battery_hbar_palette='#d70000,#ff5f00,#5fff00' # red, orange, green - -# battery vbar palette, possible values are: -# - gradient (default) -# - heat -# - 'colour_low,colour_half,colour_full' -tmux_conf_battery_vbar_palette='gradient' -#tmux_conf_battery_vbar_palette='#d70000,#ff5f00,#5fff00' # red, orange, green - -# symbols used to indicate whether battery is charging or discharging -tmux_conf_battery_status_charging='↑' # U+2191 -tmux_conf_battery_status_discharging='↓' # U+2193 -#tmux_conf_battery_status_charging='⚡ ' # U+26A1 -#tmux_conf_battery_status_charging='🔌 ' # U+1F50C -#tmux_conf_battery_status_discharging='🔋 ' # U+1F50B - -# clock style -tmux_conf_theme_clock_colour='#00afff' # light blue -tmux_conf_theme_clock_style='24' - - -# -- clipboard ----------------------------------------------------------------- - -# in copy mode, copying selection also copies to the OS clipboard -# - true -# - false (default) -# on macOS, this requires installing reattach-to-user-namespace, see README.md -# on Linux, this requires xsel or xclip -tmux_conf_copy_to_os_clipboard=false - - -# -- user customizations ------------------------------------------------------- -# this is the place to override or undo settings - -# increase history size -set -g history-limit 10000 - -# start with mouse mode enabled -#set -g mouse on - -# force Vi mode -# really you should export VISUAL or EDITOR environment variable, see manual -#set -g status-keys vi -#set -g mode-keys vi - -# replace C-b by C-a instead of using both prefixes -# set -gu prefix2 -# unbind C-a -# unbind C-b -# set -g prefix C-a -# bind C-a send-prefix - -# move status line to top -#set -g status-position top diff --git a/config/tmux/LICENSE.MIT b/config/tmux/LICENSE.MIT deleted file mode 100644 index cbda5cd..0000000 --- a/config/tmux/LICENSE.MIT +++ /dev/null @@ -1,18 +0,0 @@ -Copyright 2012— Gregory Pakosz - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/config/tmux/LICENSE.WTFPLv2 b/config/tmux/LICENSE.WTFPLv2 deleted file mode 100644 index c6c7def..0000000 --- a/config/tmux/LICENSE.WTFPLv2 +++ /dev/null @@ -1,13 +0,0 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/config/tmux/README.md b/config/tmux/README.md deleted file mode 100644 index 9dad518..0000000 --- a/config/tmux/README.md +++ /dev/null @@ -1,318 +0,0 @@ -.tmux -===== - -Self-contained, pretty and versatile `.tmux.conf` configuration file. - -![Screenshot](https://cloud.githubusercontent.com/assets/553208/19740585/85596a5a-9bbf-11e6-8aa1-7c8d9829c008.gif) - -Installation ------------- - -Requirements: - - - tmux **`>= 2.1`** running inside Linux, Mac, OpenBSD, Cygwin or WSL (Bash on - Ubuntu on Windows) - - outside of tmux, `$TERM` must be set to `xterm-256color` - -To install, run the following from your terminal: (you may want to backup your -existing `~/.tmux.conf` first) - -``` -$ cd -$ git clone https://github.com/gpakosz/.tmux.git -$ ln -s -f .tmux/.tmux.conf -$ cp .tmux/.tmux.conf.local . -``` - -Then proceed to [customize] your `~/.tmux.conf.local` copy. - -[customize]: #enabling-the-powerline-look - -If you're a Vim user, setting the `$EDITOR` environment variable to `vim` will -enable and further customize the vi-style key bindings (see tmux manual). - -If you're new to tmux, I recommmend you read [tmux 2: Productive Mouse-Free -Development][bhtmux2] by [@bphogan]. - -[bhtmux2]: https://pragprog.com/book/bhtmux2/tmux-2 -[@bphogan]: https://twitter.com/bphogan - -Troubleshooting ---------------- - - - **I'm running tmux `HEAD` and things don't work properly. What should I do?** - - Please open an issue describing what doesn't work with upcoming tmux. I'll do - my best to address it. - - - **Status line is broken and/or gets duplicated at the bottom of the screen. - What gives?** - - This particularly happens on Linux when the distribution provides a version - of glib that received Unicode 9.0 upgrades (glib `>= 2.50.1`) while providing - a version of glibc that didn't (glibc `< 2.26`). You may also configure - `LC_CTYPE` to use an `UTF-8` locale. Typically VTE based terminal emulators - rely on glib's `g_unichar_iswide()` function while tmux relies on glibc's - `wcwidth()` function. When these two functions disagree, display gets messed - up. - - This can also happen on macOS when using iTerm2 and "Use Unicode version 9 - character widths" is enabled in `Preferences... > Profiles > Text` - - For that reason, the default `~/.tmux.conf.local` file stopped using Unicode - characters for which width changed in between Unicode 8.0 and 9.0 standards, - as well as Emojis. - - - **I installed Powerline and/or (patched) fonts but can't see Powerline - symbols.** - - First, you don't need to install Powerline. You only need fonts patched with - Powerline symbols or the standalone `PowerlineSymbols.otf` font. Then make - sure your `~/.tmux.conf.local` copy uses the right code points for - `tmux_conf_theme_left_separator_XXX` values. - - - **I'm using Bash On Windows (WSL), colors and Powerline look are broken.** - - There is currently a [bug][1681] in the new console powering Bash On Windows - preventing text attributes (bold, underscore, ...) to combine properly with - colors. The workaround is to search your `~/.tmux.conf.local` copy and - replace attributes with `'none'`. - - Also, until Window's console replaces its GDI based render with a DirectWrite - one, Powerline symbols will be broken. - - The alternative is to use the [Mintty terminal for WSL][wsltty]. - -[1681]: https://github.com/Microsoft/BashOnWindows/issues/1681 -[wsltty]: https://github.com/mintty/wsltty - -Features --------- - - - `C-a` acts as secondary prefix, while keeping default `C-b` prefix - - visual theme inspired by [Powerline][] - - [maximize any pane to a new window with ` +`][maximize-pane] - - SSH aware username and hostname status line information - - mouse mode toggle with ` m` - - automatic usage of [`reattach-to-user-namespace`][reattach-to-user-namespace] - if available - - laptop battery status line information - - uptime status line information - - optional highlight of focused pane (tmux `>= 2.1`) - - configurable new windows and panes behavior (optionally retain current path) - - SSH aware split pane (reconnects to remote server, experimental) - - copy to OS clipboard (needs [`reattach-to-user-namespace`][reattach-to-user-namespace] - on macOS, `xsel` or `xclip` on Linux) - - [Facebook PathPicker][] integration if available - - [Urlview][] integration if available - -[Powerline]: https://github.com/Lokaltog/powerline -[maximize-pane]: http://pempek.net/articles/2013/04/14/maximizing-tmux-pane-new-window/ -[reattach-to-user-namespace]: https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard -[Facebook PathPicker]: https://facebook.github.io/PathPicker/ -[Urlview]: https://packages.debian.org/stable/misc/urlview - -tmux may be controlled from an attached client by using a key combination of a -prefix key, followed by a command key. This configuration uses `C-a` as a -secondary prefix while keeping `C-b` as the default prefix. In the following -list of key bindings: - - `` means you have to either hit Ctrl + a or Ctrl + b - - ` c` means you have to hit Ctrl + a or Ctrl + b followed by c - - ` C-c` means you have to hit Ctrl + a or Ctrl + b followed by Ctrl + c - -This configuration uses the following bindings: - - - ` C-c` creates a new session - - ` e` opens `~/.tmux.conf.local` with the editor defined by the - `$EDITOR` environment variable (defaults to `vim` when empty) - - ` r` reloads the configuration - - ` C-f` lets you switch to another session by name - - ` C-h` and ` C-l` let you navigate windows (default - ` n` and ` p` are unbound) - - ` Tab` brings you to the last active window - - ` h`, ` j`, ` k` and ` l` let you navigate - panes ala Vim - - ` H`, ` J`, ` K`, ` L` let you resize panes - - ` <` and ` >` let you swap panes - - ` +` maximizes the current pane to a new window - - ` m` toggles mouse mode on or off - - ` U` launches Urlview (if available) - - ` F` launches Facebook PathPicker (if available) - - ` Enter` enters copy-mode - - ` b` lists the paste-buffers - - ` p` pastes from the top paste-buffer - - ` P` lets you choose the paste-buffer to paste from - - `C-l` clears both the screen and the history - -Additionally, `vi-choice`, `vi-edit` and `vi-copy` named tables are adjusted - to closely match [my own Vim configuration][] - -[my own Vim configuration]: https://github.com/gpakosz/.vim.git - -Bindings for the `vi-choice` mode-table: - -- `h` collapses the current tree node -- `l` expands the current tree node -- `H` collapses all the tree nodes -- `L` expands all the tree nodes -- `K` jumps to the start of list (tmux `2.0+`) -- `L` jumps to the end of list (tmux `2.0+`) -- `Escape` cancels the current operation - -Bindings for the `vi-edit` mode-table: - -- `H` jumps to the start of line -- `L` jumps to the end of line -- `q` cancels the current operation -- `Escape` cancels the current operation - -Bindings for the `vi-copy` mode-table: - -- `v` begins selection / visual mode -- `C-v` toggles between blockwise visual mode and visual mode -- `H` jumps to the start of line -- `L` jumps to the end of line -- `y` copies the selection to the top paste-buffer -- `Escape` cancels the current operation - -The "maximize any pane to a new window with ` +`" feature is different -from builtin `resize-pane -Z` as it allows you to further split a maximized -pane. It's also more flexible by allowing you to maximize a pane to a new -window, then change window, then go back and the pane is still in maximized -state in its own window. You can then minimize a pane by using ` +` -either from the source window or the maximized window. - -![Maximize pane](https://cloud.githubusercontent.com/assets/553208/9890858/ee3c0ca6-5c02-11e5-890e-05d825a46c92.gif) - -Mouse mode allows you to set the active window, set the active pane, resize -panes and automatically switches to copy-mode to select text. - -![Mouse mode](https://cloud.githubusercontent.com/assets/553208/9890797/8dffe542-5c02-11e5-9c06-a25b452e6fcc.gif) - -Configuration -------------- - -While this configuration tries to bring sane default settings, you may want to -customize it further to your needs. Instead of altering the `~/.tmux.conf` file -and diverging from upstream, the proper way is to edit the `~/.tmux.conf.local` -file. - -Please refer to the default `~/.tmux.conf.local` file to know more about -variables you can adjust to alter different behaviors. Pressing ` e` -will open `~/.tmux.conf.local` with the editor defined by the `$EDITOR` -environment variable (defaults to `vim` when empty). - -### Enabling the Powerline look - -Powerline originated as a status-line plugin for Vim. Its popular eye-catching -look is based on the use of special symbols: Powerline Symbols - -To make use of these symbols, there are several options: - -- use a font that already bundles those: this is e.g. the case of the - [2.030R-ro/1.050R-it version][source code pro] of the Source Code Pro] font -- use a [pre-patched font][powerline patched fonts] -- use your preferred font along with the [Powerline font][powerline font] (that - only contains the Powerline symbols): [this highly depends on your operating - system and your terminal emulator][terminal support] -- [patch your preferred font][powerline font patcher] by adding the missing - Powerline symbols: this is the most difficult way and is no more documented in - the [Powerline manual] - -[source code pro]: https://github.com/adobe-fonts/source-code-pro/releases/tag/2.030R-ro/1.050R-it -[powerline patched fonts]: https://github.com/powerline/fonts -[powerline font]: https://github.com/powerline/powerline/raw/develop/font/PowerlineSymbols.otf -[powerline font patcher]: https://github.com/powerline/fontpatcher -[terminal support]: http://powerline.readthedocs.io/en/master/usage.html#usage-terminal-emulators -[Powerline manual]: http://powerline.readthedocs.org/en/latest/installation.html#fonts-installation - -Please see the [Powerline manual] for further details. - -Then edit the `~/.tmux.conf.local` file (` e`) and adjust the following -variables: - -``` -tmux_conf_theme_left_separator_main='' -tmux_conf_theme_left_separator_sub='' -tmux_conf_theme_right_separator_main='' -tmux_conf_theme_right_separator_sub='' -``` -### Configuring the status line - -Contrary to the first iterations of this configuration, by now you have total -control on the content and order of `status-left` and `status-right`. - -Edit the `~/.tmux.conf.local` file (` e`) and adjust the -`tmux_conf_theme_status_left` and `tmux_conf_theme_status_right` variables to -your own preferences. - -This configuration supports the following builtin variables: - - - `#{battery_bar}`: horizontal battery charge bar - - `#{battery_percentage}`: battery percentage - - `#{battery_status}`: is battery charging or discharging? - - `#{battery_vbar}`: vertical battery charge bar - - `#{circled_session_name}`: circled session number, up to 20 - - `#{hostname}`: SSH aware hostname information - - `#{hostname_ssh}`: SSH aware hostname information, blank when no SSH - connection detected - - `#{loadavg}`: load average - - `#{pairing}`: is session attached to more than one client? - - `#{prefix}`: is prefix being depressed? - - `#{root}`: is current user root? - - `#{uptime_d}`: uptime days - - `#{uptime_h}`: uptime hours - - `#{uptime_m}`: uptime minutes - - `#{uptime_s}`: uptime seconds - - `#{username}`: SSH aware username information - - `#{username_ssh}`: SSH aware username information, blank when no SSH - connection detected - -### Accessing the macOS clipboard from within tmux sessions - -[Chris Johnsen created the `reattach-to-user-namespace` -utility][reattach-to-user-namespace] that makes `pbcopy` and `pbpaste` work -again within tmux. - -To install `reattach-to-user-namespace`, use either [MacPorts][] or -[Homebrew][]: - - $ port install tmux-pasteboard - -or - - $ brew install reattach-to-user-namespace - -Once installed, `reattach-to-usernamespace` will be automatically detected. - -[MacPorts]: http://www.macports.org/ -[Homebrew]: http://brew.sh/ - -### Using the configuration under Cygwin within Mintty - -**I don't recommend running this configuration with Cygwin anymore. Forking -under Cygwin is extremely slow and this configuration issues a lot of -`run-shell` commands under the hood. As such, you will experience high CPU -usage. As an alternative consider using [Mintty terminal for WSL][wsltty].** - -![cygwin](https://cloud.githubusercontent.com/assets/553208/19741789/67a3f3d8-9bc2-11e6-9ecc-499fc0228ee6.png) - -It is possible to use this configuration under Cygwin within Mintty, however -support for Unicode symbols and emojis lacks behind Mac and Linux. - -Particularly, Mintty's text rendering is implemented with GDI which has -limitations: - -- color emojis are only available through DirectWrite starting with Windows 8.1 -- display of double width symbols, like the battery discharging symbol indicator - (U+1F50B) is buggy - -To get Unicode symbols displayed properly, you have to use [font linking]. -Open `regedit.exe` then navigate to the registry key at -`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink` -and add a new entry for you preferred font to link it with the Segoe UI Symbol -font. - -![regedit](https://cloud.githubusercontent.com/assets/553208/19741304/71a2f3ae-9bc0-11e6-96aa-4c09a812c313.png) - -[font linking]: https://msdn.microsoft.com/en-us/goglobal/bb688134.aspx diff --git a/config/.vimrc b/vimrc similarity index 59% rename from config/.vimrc rename to vimrc index 1c8acc0..402fb36 100644 --- a/config/.vimrc +++ b/vimrc @@ -1,6 +1,14 @@ call plug#begin() +" Common VIM agreements +Plug 'tpope/vim-sensible' +" File browser +Plug 'scrooloose/nerdtree' +" Distraction-free writing in Vim +Plug 'junegunn/goyo.vim' +" Go Support Plug 'fatih/vim-go' call plug#end() + filetype plugin indent on syn on se title set tabstop=4 @@ -11,3 +19,6 @@ set listchars=eol:$,tab:>-,trail:~,extends:>,precedes:< set list set laststatus=2 set statusline=%<%f\ %h%m%r\ %y%=%{v:register}\ %-14.(%l,%c%V%)\ %P + +" Keybindings +map :NERDTreeToggle From 6de1f4bd3b81762c0748ca933b22769afcfc8dfb Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Fri, 6 Oct 2017 14:08:49 +0530 Subject: [PATCH 09/51] Set nu and hls in vimrc --- Makefile | 1 + vimrc | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2313ad5..d1551b8 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ vim-rc: ln -sf ${CWD}/vimrc ${HOME}/.vimrc vim-plug: + sudo apt-get install -y build-essential cmake mkdir -p ~/.vim/autoload ~/.vim/bundle curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim diff --git a/vimrc b/vimrc index 402fb36..33a4418 100644 --- a/vimrc +++ b/vimrc @@ -1,3 +1,13 @@ +function! BuildYCM(info) + " info is a dictionary with 3 fields + " - name: name of the plugin + " - status: 'installed', 'updated', or 'unchanged' + " - force: set on PlugInstall! or PlugUpdate! + if a:info.status == 'installed' || a:info.force + !./install.py + endif +endfunction + call plug#begin() " Common VIM agreements Plug 'tpope/vim-sensible' @@ -6,7 +16,9 @@ Plug 'scrooloose/nerdtree' " Distraction-free writing in Vim Plug 'junegunn/goyo.vim' " Go Support -Plug 'fatih/vim-go' +Plug 'fatih/vim-go', { 'do': ':GoInstallBinaries' } +" Autocompletion +Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') } call plug#end() filetype plugin indent on @@ -19,6 +31,8 @@ set listchars=eol:$,tab:>-,trail:~,extends:>,precedes:< set list set laststatus=2 set statusline=%<%f\ %h%m%r\ %y%=%{v:register}\ %-14.(%l,%c%V%)\ %P +set nu +set hls " Keybindings map :NERDTreeToggle From 2bf5de72993758cc279cf754ab14b5b30ada6859 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Sun, 22 Oct 2017 20:06:40 +0530 Subject: [PATCH 10/51] 1. PlugInstall in make 2. Disable swap files and backups --- Makefile | 2 +- vimrc | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index d1551b8..38c1af5 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ vim-plug: sudo apt-get install -y build-essential cmake mkdir -p ~/.vim/autoload ~/.vim/bundle curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim + vim +PlugInstall +qall git-config: git config --global core.editor vim @@ -19,4 +20,3 @@ git-config: git config --global user.email "sanket@infracloud.io" git config --global color.ui true git config --global gitreview.username "ssudake21" - diff --git a/vimrc b/vimrc index 33a4418..a5ff1f9 100644 --- a/vimrc +++ b/vimrc @@ -19,20 +19,76 @@ Plug 'junegunn/goyo.vim' Plug 'fatih/vim-go', { 'do': ':GoInstallBinaries' } " Autocompletion Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') } +" Peaksea theme +Plug 'vim-scripts/peaksea' +" Git diff in modified files +Plug 'airblade/vim-gitgutter' + call plug#end() -filetype plugin indent on +filetype plugin on +filetype indent on syn on se title + +" Always show current position +set ruler + +" Height of the command bar +set cmdheight=2 + +" Use space instead of tabs +set expandtab + +" Buffer becomes hidden when it is abandoned +set hid + +" Be smart when using tabs +set smarttab + +" 1 tab == 4 spaces set tabstop=4 set softtabstop=4 set shiftwidth=4 -set expandtab -set listchars=eol:$,tab:>-,trail:~,extends:>,precedes:< + +set listchars=tab:>-,trail:~,extends:>,precedes:< set list set laststatus=2 set statusline=%<%f\ %h%m%r\ %y%=%{v:register}\ %-14.(%l,%c%V%)\ %P set nu -set hls + +" Highlight search results +set hlsearch + +" Make search act like search in modern browsers +set incsearch + +" Show matching brackets when text indicator is over them +set showmatch + +" Turn backup off, since most stuff is in git anyway +set nobackup +set nowb +set noswapfile " Keybindings map :NERDTreeToggle + +" Enable 256 colors pallete in Gnome Terminal +if $COLORTERM == 'gnome-terminal' + set t_Co=256 +endif + +try + colorscheme peaksea +catch +endtry + + +try + set switchbuf=useopen,usetab,newtab + set stal=2 +catch +endtry + + +set encoding=utf8 From 14372314cc57087002a8d727ca0fc5942342f6fd Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 23 Oct 2017 23:10:12 -0700 Subject: [PATCH 11/51] Centos package installation --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 38c1af5..511545c 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ vim-rc: ln -sf ${CWD}/vimrc ${HOME}/.vimrc vim-plug: - sudo apt-get install -y build-essential cmake + python -mplatform | grep -qi Ubuntu && sudo apt-get install -y build-essential cmake || sudo yum install cmake mkdir -p ~/.vim/autoload ~/.vim/bundle curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim vim +PlugInstall +qall From 1f52c6beec315c8e7ea32ac23576b03da5466043 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Sun, 4 Mar 2018 22:30:21 +0530 Subject: [PATCH 12/51] I3 wm configuration --- i3/config | 187 ++++++++++++++++++++++++++++++++++++++++++++++++ i3status/config | 67 +++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 i3/config create mode 100644 i3status/config diff --git a/i3/config b/i3/config new file mode 100644 index 0000000..f2d638b --- /dev/null +++ b/i3/config @@ -0,0 +1,187 @@ +# This file has been auto-generated by i3-config-wizard(1). +# It will not be overwritten, so edit it as you like. +# +# Should you change your keyboard layout some time, delete +# this file and re-run i3-config-wizard(1). +# + +# i3 config file (v4) +# +# Please see http://i3wm.org/docs/userguide.html for a complete reference! + +set $mod Mod4 + +# Font for window titles. Will also be used by the bar unless a different font +# is used in the bar {} block below. +font pango:monospace 12 + +# This font is widely installed, provides lots of unicode glyphs, right-to-left +# text rendering and scalability on retina/hidpi displays (thanks to pango). +font pango:DejaVu Sans Mono 12 + +# Before i3 v4.8, we used to recommend this one as the default: +# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 +# The font above is very space-efficient, that is, it looks good, sharp and +# clear in small sizes. However, its unicode glyph coverage is limited, the old +# X core fonts rendering does not support right-to-left and this being a bitmap +# font, it doesn’t scale on retina/hidpi displays. + +# Use Mouse+$mod to drag floating windows to their wanted position +floating_modifier $mod + +# start a terminal +bindsym $mod+Return exec i3-sensible-terminal + +# kill focused window +bindsym $mod+Shift+q kill + +# start dmenu (a program launcher) +bindsym $mod+d exec dmenu_run +# There also is the (new) i3-dmenu-desktop which only displays applications +# shipping a .desktop file. It is a wrapper around dmenu, so you need that +# installed. +# bindsym $mod+d exec --no-startup-id i3-dmenu-desktop + +# change focus +bindsym $mod+j focus left +bindsym $mod+k focus down +bindsym $mod+l focus up +bindsym $mod+semicolon focus right + +# alternatively, you can use the cursor keys: +bindsym $mod+Left focus left +bindsym $mod+Down focus down +bindsym $mod+Up focus up +bindsym $mod+Right focus right + +# move focused window +bindsym $mod+Shift+j move left +bindsym $mod+Shift+k move down +bindsym $mod+Shift+l move up +bindsym $mod+Shift+semicolon move right + +# alternatively, you can use the cursor 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 + +# split in horizontal orientation +bindsym $mod+h split h + +# split in vertical orientation +bindsym $mod+v split v + +# enter fullscreen mode for the focused container +bindsym $mod+f fullscreen toggle + +# change container layout (stacked, tabbed, toggle split) +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +# toggle tiling / floating +bindsym $mod+Shift+space floating toggle + +# change focus between tiling / floating windows +bindsym $mod+space focus mode_toggle + +# focus the parent container +bindsym $mod+a focus parent + +# focus the child container +#bindsym $mod+d focus child + +# switch to workspace +bindsym $mod+1 workspace 1 +bindsym $mod+2 workspace 2 +bindsym $mod+3 workspace 3 +bindsym $mod+4 workspace 4 +bindsym $mod+5 workspace 5 +bindsym $mod+6 workspace 6 +bindsym $mod+7 workspace 7 +bindsym $mod+8 workspace 8 +bindsym $mod+9 workspace 9 +bindsym $mod+0 workspace 10 + +# move focused container to workspace +bindsym $mod+Shift+1 move container to workspace 1 +bindsym $mod+Shift+2 move container to workspace 2 +bindsym $mod+Shift+3 move container to workspace 3 +bindsym $mod+Shift+4 move container to workspace 4 +bindsym $mod+Shift+5 move container to workspace 5 +bindsym $mod+Shift+6 move container to workspace 6 +bindsym $mod+Shift+7 move container to workspace 7 +bindsym $mod+Shift+8 move container to workspace 8 +bindsym $mod+Shift+9 move container to workspace 9 +bindsym $mod+Shift+0 move container to workspace 10 + +# reload the configuration file +bindsym $mod+Shift+c reload +# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) +bindsym $mod+Shift+r restart +# exit i3 (logs you out of your X session) +bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" + +# resize window (you can also use the mouse for that) +mode "resize" { + # These bindings trigger as soon as you enter the resize mode + + # Pressing left will shrink the window’s width. + # Pressing right will grow the window’s width. + # Pressing up will shrink the window’s height. + # Pressing down will grow the window’s height. + bindsym j resize shrink width 10 px or 10 ppt + bindsym k resize grow height 10 px or 10 ppt + bindsym l resize shrink height 10 px or 10 ppt + bindsym semicolon resize grow width 10 px or 10 ppt + + # same bindings, but for the arrow keys + bindsym Left resize shrink width 10 px or 10 ppt + bindsym Down resize grow height 10 px or 10 ppt + bindsym Up resize shrink height 10 px or 10 ppt + bindsym Right resize grow width 10 px or 10 ppt + + # back to normal: Enter or Escape + bindsym Return mode "default" + bindsym Escape mode "default" +} + +bindsym $mod+r mode "resize" + +# Start i3bar to display a workspace bar (plus the system information i3status +# finds out, if available) +bar { + status_command i3status + tray_output primary + colors { + background #285477 + statusline #dedede + separator #2d2d2d + focused_workspace #636e88 #285de7 #dedfdg + active_workspace #556677 #234567 #56ef67 + inactive_workspace #636d72 #2d2d2d #dedede + urgent_workspace #ffffff #900000 #d23d32 + } +} +exec --no-startup-id nm-applet + + +# Volume control +bindsym XF86AudioRaiseVolume exec --no-startup-id amixer -c 0 -q set Master 2dB+ unmute +bindsym XF86AudioLowerVolume exec --no-startup-id amixer -c 0 -q set Master 2dB- unmute +#bindsym XF86AudioMute exec --no-startup-id amixer -D pulse set Master 1+ toggle + +# new window +new_window none +new_float normal +hide_edge_borders both + +# window colors +# class border backgr. text indicator child_border +client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577 +client.focused_inactive #81c2d6 #5f676a #ffffff #484e50 #0b6e48 +client.unfocused #c9cabb #222222 #888888 #292d2e #222222 +client.urgent #2f343a #900000 #ffffff #199475 #900000 +client.placeholder #a2b4ba #0c0c0c #ffffff #1793d0 #0c0c0c +client.background #82abba diff --git a/i3status/config b/i3status/config new file mode 100644 index 0000000..8310081 --- /dev/null +++ b/i3status/config @@ -0,0 +1,67 @@ +# i3status configuration file. +# see "man i3status" for documentation. + +# It is important that this file is edited as UTF-8. +# The following line should contain a sharp s: +# ß +# If the above line is not correctly displayed, fix your editor first! + +general { + colors = true + interval = 20 +} + +order += "wireless _first_" +order += "ethernet _first_" +#order += "ipv6" +order += "load" +order += "disk /" +order += "run_watch DHCP" +order += "run_watch VPN" +order += "battery 0" +order += "volume master" +order += "tztime local" + +wireless _first_ { + format_up = "W: %ip@%essid-%quality" + format_down = "W: down" +} + +ethernet _first_ { + # if you use %speed, i3status requires root privileges + format_up = "E: %ip (%speed)" + format_down = "E: down" +} + +battery 0 { + format = "%status %percentage %remaining" +} + +run_watch DHCP { + pidfile = "/var/run/dhclient*.pid" +} + +run_watch VPN { + pidfile = "/var/run/vpnc/pid" +} + +tztime local { + format = "%Y-%m-%d %H:%M:%S" +} + +load { + format = "%1min" +} + +disk "/" { + format = "%avail" +} + + +volume master { + format = "♪%volume" + format_muted = "♪muted" + device = "default" + mixer = "Master" + mixer_idx = 0 +} From 916b9bdae502619764bab88913b3dfae8627459a Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Tue, 6 Mar 2018 10:13:01 +0530 Subject: [PATCH 13/51] Use xrandr to switch between monitor/laptop --- i3/config | 2 ++ i3/monitor.sh | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100755 i3/monitor.sh diff --git a/i3/config b/i3/config index f2d638b..db1bd37 100644 --- a/i3/config +++ b/i3/config @@ -185,3 +185,5 @@ client.unfocused #c9cabb #222222 #888888 #292d2e #222222 client.urgent #2f343a #900000 #ffffff #199475 #900000 client.placeholder #a2b4ba #0c0c0c #ffffff #1793d0 #0c0c0c client.background #82abba + +bindsym $mod+p exec ~/.config/i3/monitor.sh diff --git a/i3/monitor.sh b/i3/monitor.sh new file mode 100755 index 0000000..5308395 --- /dev/null +++ b/i3/monitor.sh @@ -0,0 +1,9 @@ +#!/bin/bash +intern=eDP-1 +extern=HDMI-1 + +if xrandr | grep "$extern disconnected"; then + xrandr --output "$extern" --off --output "$intern" --auto +else + xrandr --output "$intern" --off --output "$extern" --auto +fi From 8da68f405a9a4493a66b19abe204a2e96e67320d Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:42:24 +0530 Subject: [PATCH 14/51] Remove legacy Linux config (recoverable in history) The old Makefile targeted apt/yum systems and overwrote the global gitconfig with a stale identity; i3/i3status/xrandr configs are X11-only. All content remains recoverable via git history. --- Makefile | 22 ------ i3/config | 189 ------------------------------------------------ i3/monitor.sh | 9 --- i3status/config | 67 ----------------- vimrc | 94 ------------------------ 5 files changed, 381 deletions(-) delete mode 100644 Makefile delete mode 100644 i3/config delete mode 100755 i3/monitor.sh delete mode 100644 i3status/config delete mode 100644 vimrc diff --git a/Makefile b/Makefile deleted file mode 100644 index 511545c..0000000 --- a/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -CWD=$(shell pwd) - -all: vim-plugins git-config vim-rc - - -vim-plugins: vim-plug - -vim-rc: - ln -sf ${CWD}/vimrc ${HOME}/.vimrc - -vim-plug: - python -mplatform | grep -qi Ubuntu && sudo apt-get install -y build-essential cmake || sudo yum install cmake - mkdir -p ~/.vim/autoload ~/.vim/bundle - curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim - vim +PlugInstall +qall - -git-config: - git config --global core.editor vim - git config --global user.name "Sanket Sudake" - git config --global user.email "sanket@infracloud.io" - git config --global color.ui true - git config --global gitreview.username "ssudake21" diff --git a/i3/config b/i3/config deleted file mode 100644 index db1bd37..0000000 --- a/i3/config +++ /dev/null @@ -1,189 +0,0 @@ -# This file has been auto-generated by i3-config-wizard(1). -# It will not be overwritten, so edit it as you like. -# -# Should you change your keyboard layout some time, delete -# this file and re-run i3-config-wizard(1). -# - -# i3 config file (v4) -# -# Please see http://i3wm.org/docs/userguide.html for a complete reference! - -set $mod Mod4 - -# Font for window titles. Will also be used by the bar unless a different font -# is used in the bar {} block below. -font pango:monospace 12 - -# This font is widely installed, provides lots of unicode glyphs, right-to-left -# text rendering and scalability on retina/hidpi displays (thanks to pango). -font pango:DejaVu Sans Mono 12 - -# Before i3 v4.8, we used to recommend this one as the default: -# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 -# The font above is very space-efficient, that is, it looks good, sharp and -# clear in small sizes. However, its unicode glyph coverage is limited, the old -# X core fonts rendering does not support right-to-left and this being a bitmap -# font, it doesn’t scale on retina/hidpi displays. - -# Use Mouse+$mod to drag floating windows to their wanted position -floating_modifier $mod - -# start a terminal -bindsym $mod+Return exec i3-sensible-terminal - -# kill focused window -bindsym $mod+Shift+q kill - -# start dmenu (a program launcher) -bindsym $mod+d exec dmenu_run -# There also is the (new) i3-dmenu-desktop which only displays applications -# shipping a .desktop file. It is a wrapper around dmenu, so you need that -# installed. -# bindsym $mod+d exec --no-startup-id i3-dmenu-desktop - -# change focus -bindsym $mod+j focus left -bindsym $mod+k focus down -bindsym $mod+l focus up -bindsym $mod+semicolon focus right - -# alternatively, you can use the cursor keys: -bindsym $mod+Left focus left -bindsym $mod+Down focus down -bindsym $mod+Up focus up -bindsym $mod+Right focus right - -# move focused window -bindsym $mod+Shift+j move left -bindsym $mod+Shift+k move down -bindsym $mod+Shift+l move up -bindsym $mod+Shift+semicolon move right - -# alternatively, you can use the cursor 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 - -# split in horizontal orientation -bindsym $mod+h split h - -# split in vertical orientation -bindsym $mod+v split v - -# enter fullscreen mode for the focused container -bindsym $mod+f fullscreen toggle - -# change container layout (stacked, tabbed, toggle split) -bindsym $mod+s layout stacking -bindsym $mod+w layout tabbed -bindsym $mod+e layout toggle split - -# toggle tiling / floating -bindsym $mod+Shift+space floating toggle - -# change focus between tiling / floating windows -bindsym $mod+space focus mode_toggle - -# focus the parent container -bindsym $mod+a focus parent - -# focus the child container -#bindsym $mod+d focus child - -# switch to workspace -bindsym $mod+1 workspace 1 -bindsym $mod+2 workspace 2 -bindsym $mod+3 workspace 3 -bindsym $mod+4 workspace 4 -bindsym $mod+5 workspace 5 -bindsym $mod+6 workspace 6 -bindsym $mod+7 workspace 7 -bindsym $mod+8 workspace 8 -bindsym $mod+9 workspace 9 -bindsym $mod+0 workspace 10 - -# move focused container to workspace -bindsym $mod+Shift+1 move container to workspace 1 -bindsym $mod+Shift+2 move container to workspace 2 -bindsym $mod+Shift+3 move container to workspace 3 -bindsym $mod+Shift+4 move container to workspace 4 -bindsym $mod+Shift+5 move container to workspace 5 -bindsym $mod+Shift+6 move container to workspace 6 -bindsym $mod+Shift+7 move container to workspace 7 -bindsym $mod+Shift+8 move container to workspace 8 -bindsym $mod+Shift+9 move container to workspace 9 -bindsym $mod+Shift+0 move container to workspace 10 - -# reload the configuration file -bindsym $mod+Shift+c reload -# restart i3 inplace (preserves your layout/session, can be used to upgrade i3) -bindsym $mod+Shift+r restart -# exit i3 (logs you out of your X session) -bindsym $mod+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" - -# resize window (you can also use the mouse for that) -mode "resize" { - # These bindings trigger as soon as you enter the resize mode - - # Pressing left will shrink the window’s width. - # Pressing right will grow the window’s width. - # Pressing up will shrink the window’s height. - # Pressing down will grow the window’s height. - bindsym j resize shrink width 10 px or 10 ppt - bindsym k resize grow height 10 px or 10 ppt - bindsym l resize shrink height 10 px or 10 ppt - bindsym semicolon resize grow width 10 px or 10 ppt - - # same bindings, but for the arrow keys - bindsym Left resize shrink width 10 px or 10 ppt - bindsym Down resize grow height 10 px or 10 ppt - bindsym Up resize shrink height 10 px or 10 ppt - bindsym Right resize grow width 10 px or 10 ppt - - # back to normal: Enter or Escape - bindsym Return mode "default" - bindsym Escape mode "default" -} - -bindsym $mod+r mode "resize" - -# Start i3bar to display a workspace bar (plus the system information i3status -# finds out, if available) -bar { - status_command i3status - tray_output primary - colors { - background #285477 - statusline #dedede - separator #2d2d2d - focused_workspace #636e88 #285de7 #dedfdg - active_workspace #556677 #234567 #56ef67 - inactive_workspace #636d72 #2d2d2d #dedede - urgent_workspace #ffffff #900000 #d23d32 - } -} -exec --no-startup-id nm-applet - - -# Volume control -bindsym XF86AudioRaiseVolume exec --no-startup-id amixer -c 0 -q set Master 2dB+ unmute -bindsym XF86AudioLowerVolume exec --no-startup-id amixer -c 0 -q set Master 2dB- unmute -#bindsym XF86AudioMute exec --no-startup-id amixer -D pulse set Master 1+ toggle - -# new window -new_window none -new_float normal -hide_edge_borders both - -# window colors -# class border backgr. text indicator child_border -client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577 -client.focused_inactive #81c2d6 #5f676a #ffffff #484e50 #0b6e48 -client.unfocused #c9cabb #222222 #888888 #292d2e #222222 -client.urgent #2f343a #900000 #ffffff #199475 #900000 -client.placeholder #a2b4ba #0c0c0c #ffffff #1793d0 #0c0c0c -client.background #82abba - -bindsym $mod+p exec ~/.config/i3/monitor.sh diff --git a/i3/monitor.sh b/i3/monitor.sh deleted file mode 100755 index 5308395..0000000 --- a/i3/monitor.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -intern=eDP-1 -extern=HDMI-1 - -if xrandr | grep "$extern disconnected"; then - xrandr --output "$extern" --off --output "$intern" --auto -else - xrandr --output "$intern" --off --output "$extern" --auto -fi diff --git a/i3status/config b/i3status/config deleted file mode 100644 index 8310081..0000000 --- a/i3status/config +++ /dev/null @@ -1,67 +0,0 @@ -# i3status configuration file. -# see "man i3status" for documentation. - -# It is important that this file is edited as UTF-8. -# The following line should contain a sharp s: -# ß -# If the above line is not correctly displayed, fix your editor first! - -general { - colors = true - interval = 20 -} - -order += "wireless _first_" -order += "ethernet _first_" -#order += "ipv6" -order += "load" -order += "disk /" -order += "run_watch DHCP" -order += "run_watch VPN" -order += "battery 0" -order += "volume master" -order += "tztime local" - -wireless _first_ { - format_up = "W: %ip@%essid-%quality" - format_down = "W: down" -} - -ethernet _first_ { - # if you use %speed, i3status requires root privileges - format_up = "E: %ip (%speed)" - format_down = "E: down" -} - -battery 0 { - format = "%status %percentage %remaining" -} - -run_watch DHCP { - pidfile = "/var/run/dhclient*.pid" -} - -run_watch VPN { - pidfile = "/var/run/vpnc/pid" -} - -tztime local { - format = "%Y-%m-%d %H:%M:%S" -} - -load { - format = "%1min" -} - -disk "/" { - format = "%avail" -} - - -volume master { - format = "♪%volume" - format_muted = "♪muted" - device = "default" - mixer = "Master" - mixer_idx = 0 -} diff --git a/vimrc b/vimrc deleted file mode 100644 index a5ff1f9..0000000 --- a/vimrc +++ /dev/null @@ -1,94 +0,0 @@ -function! BuildYCM(info) - " info is a dictionary with 3 fields - " - name: name of the plugin - " - status: 'installed', 'updated', or 'unchanged' - " - force: set on PlugInstall! or PlugUpdate! - if a:info.status == 'installed' || a:info.force - !./install.py - endif -endfunction - -call plug#begin() -" Common VIM agreements -Plug 'tpope/vim-sensible' -" File browser -Plug 'scrooloose/nerdtree' -" Distraction-free writing in Vim -Plug 'junegunn/goyo.vim' -" Go Support -Plug 'fatih/vim-go', { 'do': ':GoInstallBinaries' } -" Autocompletion -Plug 'Valloric/YouCompleteMe', { 'do': function('BuildYCM') } -" Peaksea theme -Plug 'vim-scripts/peaksea' -" Git diff in modified files -Plug 'airblade/vim-gitgutter' - -call plug#end() - -filetype plugin on -filetype indent on -syn on se title - -" Always show current position -set ruler - -" Height of the command bar -set cmdheight=2 - -" Use space instead of tabs -set expandtab - -" Buffer becomes hidden when it is abandoned -set hid - -" Be smart when using tabs -set smarttab - -" 1 tab == 4 spaces -set tabstop=4 -set softtabstop=4 -set shiftwidth=4 - -set listchars=tab:>-,trail:~,extends:>,precedes:< -set list -set laststatus=2 -set statusline=%<%f\ %h%m%r\ %y%=%{v:register}\ %-14.(%l,%c%V%)\ %P -set nu - -" Highlight search results -set hlsearch - -" Make search act like search in modern browsers -set incsearch - -" Show matching brackets when text indicator is over them -set showmatch - -" Turn backup off, since most stuff is in git anyway -set nobackup -set nowb -set noswapfile - -" Keybindings -map :NERDTreeToggle - -" Enable 256 colors pallete in Gnome Terminal -if $COLORTERM == 'gnome-terminal' - set t_Co=256 -endif - -try - colorscheme peaksea -catch -endtry - - -try - set switchbuf=useopen,usetab,newtab - set stal=2 -catch -endtry - - -set encoding=utf8 From df764bee864146306a8181c026e1837b861ef012 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:42:48 +0530 Subject: [PATCH 15/51] Add repo skeleton: secret-safety gitignore, README stub, agent guide --- .gitignore | 17 +++++++++++++++++ CLAUDE.md | 26 ++++++++++++++++++++++++++ README.md | 4 ++++ 3 files changed, 47 insertions(+) create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27118a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Secret-safety net — none of these should ever be committed. +hosts.yml +.env +.env.* +*.pem +*.key +*token* +*credential* + +# Machine-local zsh overrides (see packages/zsh/dot-config/zsh/90-local.zsh.example). +packages/zsh/dot-config/zsh/90-local.zsh + +# Generated dump for Brewfile re-curation (make brew-dump); never committed. +Brewfile.dump + +# macOS noise. +.DS_Store diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..dd98065 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,26 @@ +# dotfiles — agent guide + +macOS dotfiles provisioned with GNU stow; the Makefile is the interface (no app to build or test). + +## Layout + +- `packages/` — every stow package, one directory per tool; only files here are ever stowed or committed. +- `Brewfile` — curated package list; `Brewfile.dump` (gitignored) is regenerated via `make brew-dump` for re-curation diffs only. +- `bootstrap.sh` — new-Mac entry point; idempotent, check-then-act steps. +- `macos/defaults.sh` — macOS `defaults` capture (phase 2). +- `scripts/doctor.sh` — health checks behind `make doctor`. + +## Conventions + +- Stow flags are fixed: `--dotfiles --no-folding` (see Makefile). + `--no-folding` is a security invariant: `~/.config/` must stay a real directory so tools that write credentials beside their config (e.g. `gh`'s `hosts.yml`) never write into this repo. +- File names use the `dot-` prefix (`dot-zshrc` → `~/.zshrc`); requires stow ≥ 2.4.0. +- Makefile targets follow `-` naming (`brew-install`, `stow-link`, `harness-install`), matching the sibling `harness-configs` repo. +- Never add packages for credential-bearing dirs: `gh/hosts.yml`, `gcloud`, `1Password`, `op`, `github-copilot`. +- The sibling repo `~/personal/harness-configs` owns all AI-harness config; this repo only bootstraps it (`make harness-install`) and sources its shell functions from `packages/zsh/dot-config/zsh/50-harness.zsh`. + +## Adding a new tool config + +1. `mkdir -p packages//dot-config/` and copy the non-secret config file(s) in, using `dot-` names for anything dotted. +2. Add `` to `PACKAGES` in the Makefile. +3. `make stow-adopt`, then review `git diff` before committing. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4422946 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# dotfiles + +macOS dotfiles managed with GNU stow, plus a Brewfile and a one-shot bootstrap for new machines. +Full documentation lands as the revamp completes. From c65e783f2abcf87e90d62ce1bac3728ec6197ba1 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:44:27 +0530 Subject: [PATCH 16/51] Add zsh and git stow packages plus Makefile zsh config becomes a thin ~/.zshrc sourcing numbered modules under ~/.config/zsh/; interactive pieces move out of .zprofile so they exist in all interactive shells. Git config is copied byte-identical from the live multi-identity setup. Stow runs with --dotfiles --no-folding so ~/.config/ dirs stay real directories (credential safety). --- Makefile | 61 +++++++++++++++++++ packages/git/dot-config/git/config-personal | 3 + packages/git/dot-config/git/config-qwiet | 3 + packages/git/dot-config/git/ignore | 1 + packages/git/dot-gitconfig | 19 ++++++ packages/zsh/dot-config/zsh/00-env.zsh | 3 + packages/zsh/dot-config/zsh/10-path.zsh | 9 +++ packages/zsh/dot-config/zsh/20-aliases.zsh | 2 + packages/zsh/dot-config/zsh/30-functions.zsh | 38 ++++++++++++ packages/zsh/dot-config/zsh/40-tools.zsh | 7 +++ packages/zsh/dot-config/zsh/50-harness.zsh | 5 ++ .../zsh/dot-config/zsh/90-local.zsh.example | 7 +++ packages/zsh/dot-zprofile | 6 ++ packages/zsh/dot-zshrc | 5 ++ 14 files changed, 169 insertions(+) create mode 100644 Makefile create mode 100644 packages/git/dot-config/git/config-personal create mode 100644 packages/git/dot-config/git/config-qwiet create mode 100644 packages/git/dot-config/git/ignore create mode 100644 packages/git/dot-gitconfig create mode 100644 packages/zsh/dot-config/zsh/00-env.zsh create mode 100644 packages/zsh/dot-config/zsh/10-path.zsh create mode 100644 packages/zsh/dot-config/zsh/20-aliases.zsh create mode 100644 packages/zsh/dot-config/zsh/30-functions.zsh create mode 100644 packages/zsh/dot-config/zsh/40-tools.zsh create mode 100644 packages/zsh/dot-config/zsh/50-harness.zsh create mode 100644 packages/zsh/dot-config/zsh/90-local.zsh.example create mode 100644 packages/zsh/dot-zprofile create mode 100644 packages/zsh/dot-zshrc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9299b55 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +SHELL := /bin/bash + +STOW := stow +# --no-folding is a security invariant: ~/.config/ must stay a real +# directory so tools that write credentials beside their config (gh's +# hosts.yml) never write into this repo. --dotfiles needs stow >= 2.4.0. +STOW_FLAGS := --dir=$(CURDIR)/packages --target=$(HOME) --dotfiles --no-folding --verbose=1 +PACKAGES := zsh git atuin btop gh + +BREWFILE := $(CURDIR)/Brewfile +HARNESS_DIR ?= $(abspath $(CURDIR)/../harness-configs) +HARNESS_REPO := git@github.com:sanketsudake/harness-configs.git + +.PHONY: install uninstall doctor \ + brew-install brew-check brew-dump \ + stow-link stow-unlink stow-adopt \ + harness-clone harness-install \ + macos-apply + +install: brew-install stow-link harness-install + +uninstall: stow-unlink + +brew-install: + brew bundle --file=$(BREWFILE) + +brew-check: + brew bundle check --file=$(BREWFILE) + +# Regenerate Brewfile.dump (gitignored) to diff against the curated Brewfile; +# never overwrites Brewfile itself. +brew-dump: + brew bundle dump --file=$(CURDIR)/Brewfile.dump --describe --force + @echo "wrote Brewfile.dump — diff against Brewfile to re-curate" + +stow-link: + $(STOW) $(STOW_FLAGS) --restow $(PACKAGES) + +stow-unlink: + $(STOW) $(STOW_FLAGS) --delete $(PACKAGES) + +# Absorb pre-existing real files at target paths into the repo working tree. +stow-adopt: + $(STOW) $(STOW_FLAGS) --adopt $(PACKAGES) + @echo "" + @echo "== adopted; repo state now ==" + @git status --short + @echo "" + @echo "!! REVIEW 'git diff' BEFORE COMMITTING — adopt replaces repo files with the live ones !!" + +harness-clone: + @test -d $(HARNESS_DIR) || git clone $(HARNESS_REPO) $(HARNESS_DIR) + +harness-install: harness-clone + $(MAKE) -C $(HARNESS_DIR) install + +macos-apply: + bash $(CURDIR)/macos/defaults.sh + +doctor: + bash $(CURDIR)/scripts/doctor.sh diff --git a/packages/git/dot-config/git/config-personal b/packages/git/dot-config/git/config-personal new file mode 100644 index 0000000..19e4e9e --- /dev/null +++ b/packages/git/dot-config/git/config-personal @@ -0,0 +1,3 @@ +[user] + name = Sanket Sudake + email = sanketsudake@gmail.com diff --git a/packages/git/dot-config/git/config-qwiet b/packages/git/dot-config/git/config-qwiet new file mode 100644 index 0000000..56ac5d7 --- /dev/null +++ b/packages/git/dot-config/git/config-qwiet @@ -0,0 +1,3 @@ +[user] + name = Sanket Sudake + email = sanket.infracloud@qwiet.ai diff --git a/packages/git/dot-config/git/ignore b/packages/git/dot-config/git/ignore new file mode 100644 index 0000000..66d62f8 --- /dev/null +++ b/packages/git/dot-config/git/ignore @@ -0,0 +1 @@ +**/.claude/settings.local.json diff --git a/packages/git/dot-gitconfig b/packages/git/dot-gitconfig new file mode 100644 index 0000000..0c56d94 --- /dev/null +++ b/packages/git/dot-gitconfig @@ -0,0 +1,19 @@ +[filter "lfs"] + clean = git-lfs clean -- %f + smudge = git-lfs smudge -- %f + process = git-lfs filter-process + required = true +[url "ssh://git@github.com/"] + insteadOf = https://github.com/ +[includeIf "hasconfig:remote.*.url:git@github.com:*/**"] + path = ~/.config/git/config-personal +[includeIf "hasconfig:remote.*.url:git@github.com:ShiftLeftSecurity/**"] + path = ~/.config/git/config-qwiet +[includeIf "hasconfig:remote.*.url:https://git0.harness.io/**"] + path = ~/.config/git/config-qwiet +[includeIf "hasconfig:remote.*.url:gh-qwiet:ShiftLeftSecurity/**"] + path = ~/.config/git/config-qwiet +[includeIf "hasconfig:remote.*.url:git@github.com:fission/**"] + path = ~/.config/git/config-personal +[url "gh-qwiet:ShiftLeftSecurity"] + insteadOf = git@github.com:ShiftLeftSecurity diff --git a/packages/zsh/dot-config/zsh/00-env.zsh b/packages/zsh/dot-config/zsh/00-env.zsh new file mode 100644 index 0000000..26a7099 --- /dev/null +++ b/packages/zsh/dot-config/zsh/00-env.zsh @@ -0,0 +1,3 @@ +export DOTFILES="$HOME/personal/dotfiles" +export HARNESS_DIR="$HOME/personal/harness-configs" +export CPPFLAGS="-I${HOMEBREW_PREFIX:-/opt/homebrew}/opt/openjdk/include" diff --git a/packages/zsh/dot-config/zsh/10-path.zsh b/packages/zsh/dot-config/zsh/10-path.zsh new file mode 100644 index 0000000..d7fd057 --- /dev/null +++ b/packages/zsh/dot-config/zsh/10-path.zsh @@ -0,0 +1,9 @@ +# HOMEBREW_PREFIX is set by brew shellenv in ~/.zprofile; fall back for odd shells. +_brew_prefix="${HOMEBREW_PREFIX:-/opt/homebrew}" +export PATH="$_brew_prefix/opt/libpq/bin:$PATH" +export PATH="$_brew_prefix/opt/openjdk/bin:$PATH" +export PATH="$_brew_prefix/opt/grep/libexec/gnubin:$PATH" +export PATH="$_brew_prefix/opt/make/libexec/gnubin:$PATH" +export PATH="$HOME/go/bin:$PATH" +export PATH="$HOME/.codeium/windsurf/bin:$PATH" +unset _brew_prefix diff --git a/packages/zsh/dot-config/zsh/20-aliases.zsh b/packages/zsh/dot-config/zsh/20-aliases.zsh new file mode 100644 index 0000000..66aa020 --- /dev/null +++ b/packages/zsh/dot-config/zsh/20-aliases.zsh @@ -0,0 +1,2 @@ +alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale" +alias chrome-doctor="$HOME/chrome-doctor.sh" diff --git a/packages/zsh/dot-config/zsh/30-functions.zsh b/packages/zsh/dot-config/zsh/30-functions.zsh new file mode 100644 index 0000000..ff5672f --- /dev/null +++ b/packages/zsh/dot-config/zsh/30-functions.zsh @@ -0,0 +1,38 @@ +# Decode a JWT's header and payload (needs jq); the signature is printed, not verified. +jwtd() { + if [[ -x $(command -v jq) ]]; then + jq -R 'split(".") | .[0],.[1] | @base64d | fromjson' <<< "${1}" + echo "Signature: $(echo "${1}" | awk -F'.' '{print $3}')" + fi +} + +# Strip the password from a PDF -> passwordless copy (needs qpdf). +# Usage: pdfunlock input.pdf [output.pdf] (default output: -unlocked.pdf) +# Prompts for the password hidden, so it never lands in shell history. +pdfunlock() { + if [[ -z "$1" ]]; then + echo "usage: pdfunlock input.pdf [output.pdf]" >&2 + return 2 + fi + local in="$1" + local out="${2:-${1%.pdf}-unlocked.pdf}" + local pw + read -rs "pw?Password for $in: " + echo + if printf '%s' "$pw" | qpdf --password-file=- --decrypt "$in" "$out"; then + echo "Unlocked -> $out" + else + echo "Failed (wrong password, or file not encrypted?)" >&2 + return 1 + fi +} + +# Copy an image file to the macOS clipboard as PNG data (pasteable into Docs, Slack, etc.) +imgcopy() { + if [ ! -f "$1" ]; then + echo "imgcopy: no such file: $1" >&2 + return 1 + fi + osascript -e "set the clipboard to (read (POSIX file \"$(realpath "$1")\") as «class PNGf»)" \ + && echo "copied: $1" +} diff --git a/packages/zsh/dot-config/zsh/40-tools.zsh b/packages/zsh/dot-config/zsh/40-tools.zsh new file mode 100644 index 0000000..d645342 --- /dev/null +++ b/packages/zsh/dot-config/zsh/40-tools.zsh @@ -0,0 +1,7 @@ +# atuin — shell history sync/search. +command -v atuin >/dev/null && eval "$(atuin init zsh)" + +# nvm — node version manager (also provides npx for harness-configs tooling). +export NVM_DIR="$HOME/.nvm" +[ -s "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/nvm.sh" ] && \. "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/nvm.sh" +[ -s "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/etc/bash_completion.d/nvm" ] && \. "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/etc/bash_completion.d/nvm" diff --git a/packages/zsh/dot-config/zsh/50-harness.zsh b/packages/zsh/dot-config/zsh/50-harness.zsh new file mode 100644 index 0000000..5668dc1 --- /dev/null +++ b/packages/zsh/dot-config/zsh/50-harness.zsh @@ -0,0 +1,5 @@ +# AI-harness shell functions (pclaude/wclaude/claude wrappers) from the sibling +# harness-configs repo; skipped silently until that repo is cloned (make harness-install). +_harness_sh="${HARNESS_DIR:-$HOME/personal/harness-configs}/scripts/claude-multi-account.sh" +[ -r "$_harness_sh" ] && source "$_harness_sh" +unset _harness_sh diff --git a/packages/zsh/dot-config/zsh/90-local.zsh.example b/packages/zsh/dot-config/zsh/90-local.zsh.example new file mode 100644 index 0000000..72a109a --- /dev/null +++ b/packages/zsh/dot-config/zsh/90-local.zsh.example @@ -0,0 +1,7 @@ +# Machine-local overrides — copy to 90-local.zsh (gitignored) on this machine only. +# Put anything here that must not be committed: secrets, work-specific exports, +# host-specific paths. +# +# cp ~/.config/zsh/90-local.zsh.example ~/.config/zsh/90-local.zsh +# +# export MY_TOKEN=... diff --git a/packages/zsh/dot-zprofile b/packages/zsh/dot-zprofile new file mode 100644 index 0000000..26e43ae --- /dev/null +++ b/packages/zsh/dot-zprofile @@ -0,0 +1,6 @@ +# Login-shell setup only; everything interactive lives in ~/.config/zsh/ (see ~/.zshrc). +if [ -x /opt/homebrew/bin/brew ]; then + eval "$(/opt/homebrew/bin/brew shellenv)" +elif [ -x /usr/local/bin/brew ]; then + eval "$(/usr/local/bin/brew shellenv)" +fi diff --git a/packages/zsh/dot-zshrc b/packages/zsh/dot-zshrc new file mode 100644 index 0000000..906da1d --- /dev/null +++ b/packages/zsh/dot-zshrc @@ -0,0 +1,5 @@ +# Thin loader — all interactive config lives in ~/.config/zsh/*.zsh (managed in dotfiles). +# Modules load in NN- prefix order; drop a new file in to extend. +for f in "$HOME"/.config/zsh/*.zsh(N); do + source "$f" +done From 0c96f0690616f2ef10faba7f1dca09e0afcf67a0 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:45:56 +0530 Subject: [PATCH 17/51] Add curated Brewfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Curated from brew bundle dump cross-checked against brew leaves --installed-on-request; adds jq explicitly (harness-configs prereq previously present only as a dependency). go/npm dump entries are intentionally excluded — those are managed by go install and nvm. --- Brewfile | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Brewfile diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000..321f8db --- /dev/null +++ b/Brewfile @@ -0,0 +1,135 @@ +# Curated package list — installed via `make brew-install` (brew bundle). +# Re-curation flow: `make brew-dump` writes Brewfile.dump (gitignored); diff it +# against this file and promote keepers by hand. The dump is the menu, not the +# Brewfile. `go`/`npm` entries from the dump are intentionally excluded (managed +# by go install / nvm, not brew). + +# --- taps ------------------------------------------------------------------- +tap "atlassian/acli" +tap "jesseduffield/lazydocker", trusted: true +tap "loft-sh/tap", trusted: true +tap "minio/stable", trusted: true +tap "openclaw/tap", trusted: true +tap "sanketsudake/tap" + +# --- core CLI --------------------------------------------------------------- +brew "bash" +brew "coreutils" +brew "findutils" +brew "gnu-sed" +brew "grep" +brew "make" +brew "moreutils" +brew "ripgrep" +brew "tree" +brew "wget" + +# --- harness-configs prereqs (stow, jq, gh, node-via-nvm, python) ----------- +brew "stow" # dotfiles + harness-configs symlink manager (needs >= 2.4.0) +brew "jq" +brew "gh" +brew "nvm" # provides node/npx for harness-configs skill tooling +brew "python@3.13" + +# --- shell & everyday tools -------------------------------------------------- +brew "atuin" +brew "btop" +brew "ffmpeg" +brew "pandoc" +brew "poppler" +brew "qpdf" # pdfunlock() +brew "git-lfs" + +# --- languages & build ------------------------------------------------------- +brew "go" +brew "golangci-lint" +brew "gomplate" +brew "goreleaser" +brew "mage" +brew "rust" +brew "openjdk" +brew "maven" +brew "sbt" +brew "protobuf" +brew "pipx" +brew "uv" +brew "virtualenv" +brew "libpq" +brew "comby" + +# --- containers & kubernetes ------------------------------------------------- +brew "colima" +brew "docker" +brew "docker-buildx" +brew "cosign" +brew "helm" +brew "k9s" +brew "kind" +brew "ko" +brew "kustomize" +brew "skaffold" +brew "skopeo" +brew "stern" +brew "k6" +brew "mkcert" +brew "jesseduffield/lazydocker/lazydocker" +brew "loft-sh/tap/vcluster" +brew "minio/stable/mc" + +# --- cloud & misc ------------------------------------------------------------ +brew "awscli" +brew "okta-awscli" +brew "cloudflared" +brew "codecov-cli" +brew "semgrep" +brew "hugo" +brew "agent-browser" +brew "herdr" +brew "openclaw/tap/gitcrawl" + +# --- casks ------------------------------------------------------------------- +cask "1password-cli" +cask "claude-code@latest" +cask "copilot-cli" +cask "devin-cli" +cask "dbeaver-community" +cask "gcloud-cli" +cask "ghostty" +cask "insomnia" +cask "itsycal" +cask "obsidian" +cask "postman" +cask "slack" +cask "visual-studio-code" +cask "zoom" +cask "sanketsudake/tap/cc-proxy", trusted: true +cask "sanketsudake/tap/chrome-cdp", trusted: true +cask "sanketsudake/tap/portless", trusted: true + +# --- vscode extensions ------------------------------------------------------- +vscode "adpyke.vscode-sql-formatter" +vscode "anthropic.claude-code" +vscode "davidanson.vscode-markdownlint" +vscode "docker.docker" +vscode "drblury.protobuf-vsc" +vscode "eamodio.gitlens" +vscode "foxundermoon.shell-format" +vscode "github.github-vscode-theme" +vscode "github.vscode-github-actions" +vscode "golang.go" +vscode "mechatroner.rainbow-csv" +vscode "ms-azuretools.vscode-containers" +vscode "ms-python.debugpy" +vscode "ms-python.python" +vscode "ms-python.vscode-pylance" +vscode "ms-python.vscode-python-envs" +vscode "ms-vscode.makefile-tools" +vscode "ms-vscode.vscode-speech" +vscode "oracle.oracle-java" +vscode "redhat.vscode-yaml" +vscode "scala-lang.scala" +vscode "shd101wyy.markdown-preview-enhanced" +vscode "shiftleft.shiftleft-core" +vscode "vscjava.vscode-java-debug" +vscode "vscjava.vscode-java-dependency" +vscode "vscjava.vscode-maven" From f9a1539811943c94378a2081231d3b153755b7b4 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:46:14 +0530 Subject: [PATCH 18/51] Add atuin, btop, and gh tool config packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh package carries config.yml only — hosts.yml (oauth tokens) stays an unmanaged local file, guaranteed by stow --no-folding keeping ~/.config/gh a real directory. --- packages/atuin/dot-config/atuin/config.toml | 272 +++++++++++++++++++ packages/btop/dot-config/btop/btop.conf | 283 ++++++++++++++++++++ packages/gh/dot-config/gh/config.yml | 19 ++ 3 files changed, 574 insertions(+) create mode 100644 packages/atuin/dot-config/atuin/config.toml create mode 100644 packages/btop/dot-config/btop/btop.conf create mode 100644 packages/gh/dot-config/gh/config.yml diff --git a/packages/atuin/dot-config/atuin/config.toml b/packages/atuin/dot-config/atuin/config.toml new file mode 100644 index 0000000..ac9f8a1 --- /dev/null +++ b/packages/atuin/dot-config/atuin/config.toml @@ -0,0 +1,272 @@ +## where to store your database, default is your system data directory +## linux/mac: ~/.local/share/atuin/history.db +## windows: %USERPROFILE%/.local/share/atuin/history.db +# db_path = "~/.history.db" + +## where to store your encryption key, default is your system data directory +## linux/mac: ~/.local/share/atuin/key +## windows: %USERPROFILE%/.local/share/atuin/key +# key_path = "~/.key" + +## where to store your auth session token, default is your system data directory +## linux/mac: ~/.local/share/atuin/session +## windows: %USERPROFILE%/.local/share/atuin/session +# session_path = "~/.session" + +## date format used, either "us" or "uk" +# dialect = "us" + +## default timezone to use when displaying time +## either "l", "local" to use the system's current local timezone, or an offset +## from UTC in the format of "<+|->H[H][:M[M][:S[S]]]" +## for example: "+9", "-05", "+03:30", "-01:23:45", etc. +# timezone = "local" + +## enable or disable automatic sync +# auto_sync = true + +## enable or disable automatic update checks +# update_check = true + +## address of the sync server +# sync_address = "https://api.atuin.sh" + +## how often to sync history. note that this is only triggered when a command +## is ran, so sync intervals may well be longer +## set it to 0 to sync after every command +# sync_frequency = "10m" + +## which search mode to use +## possible values: prefix, fulltext, fuzzy, skim +# search_mode = "fuzzy" + +## which filter mode to use by default +## possible values: "global", "host", "session", "directory", "workspace" +## consider using search.filters to customize the enablement and order of filter modes +# filter_mode = "global" + +## With workspace filtering enabled, Atuin will filter for commands executed +## in any directory within a git repository tree (default: false). +## +## To use workspace mode by default when available, set this to true and +## set filter_mode to "workspace" or leave it unspecified and +## set search.filters to include "workspace" before other filter modes. +# workspaces = false + +## which filter mode to use when atuin is invoked from a shell up-key binding +## the accepted values are identical to those of "filter_mode" +## leave unspecified to use same mode set in "filter_mode" +# filter_mode_shell_up_key_binding = "global" + +## which search mode to use when atuin is invoked from a shell up-key binding +## the accepted values are identical to those of "search_mode" +## leave unspecified to use same mode set in "search_mode" +# search_mode_shell_up_key_binding = "fuzzy" + +## which style to use +## possible values: auto, full, compact +# style = "auto" + +## the maximum number of lines the interface should take up +## set it to 0 to always go full screen +# inline_height = 0 + +## Invert the UI - put the search bar at the top , Default to `false` +# invert = false + +## enable or disable showing a preview of the selected command +## useful when the command is longer than the terminal width and is cut off +# show_preview = true + +## what to do when the escape key is pressed when searching +## possible values: return-original, return-query +# exit_mode = "return-original" + +## possible values: emacs, subl +# word_jump_mode = "emacs" + +## characters that count as a part of a word +# word_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +## number of context lines to show when scrolling by pages +# scroll_context_lines = 1 + +## use ctrl instead of alt as the shortcut modifier key for numerical UI shortcuts +## alt-0 .. alt-9 +# ctrl_n_shortcuts = false + +## default history list format - can also be specified with the --format arg +# history_format = "{time}\t{command}\t{duration}" + +## prevent commands matching any of these regexes from being written to history. +## Note that these regular expressions are unanchored, i.e. if they don't start +## with ^ or end with $, they'll match anywhere in the command. +## For details on the supported regular expression syntax, see +## https://docs.rs/regex/latest/regex/#syntax +# history_filter = [ +# "^secret-cmd", +# "^innocuous-cmd .*--secret=.+", +# ] + +## prevent commands run with cwd matching any of these regexes from being written +## to history. Note that these regular expressions are unanchored, i.e. if they don't +## start with ^ or end with $, they'll match anywhere in CWD. +## For details on the supported regular expression syntax, see +## https://docs.rs/regex/latest/regex/#syntax +# cwd_filter = [ +# "^/very/secret/area", +# ] + +## Configure the maximum height of the preview to show. +## Useful when you have long scripts in your history that you want to distinguish +## by more than the first few lines. +# max_preview_height = 4 + +## Configure whether or not to show the help row, which includes the current Atuin +## version (and whether an update is available), a keymap hint, and the total +## amount of commands in your history. +# show_help = true + +## Configure whether or not to show tabs for search and inspect +# show_tabs = true + +## Configure whether or not the tabs row may be auto-hidden, which includes the current Atuin +## tab, such as Search or Inspector, and other tabs you may wish to see. This will +## only be hidden if there are fewer than this count of lines available, and does not affect the use +## of keyboard shortcuts to switch tab. 0 to never auto-hide, default is 8 (lines). +## This is ignored except in `compact` mode. +# auto_hide_height = 8 + +## Defaults to true. This matches history against a set of default regex, and will not save it if we get a match. Defaults include +## 1. AWS key id +## 2. Github pat (old and new) +## 3. Slack oauth tokens (bot, user) +## 4. Slack webhooks +## 5. Stripe live/test keys +# secrets_filter = true + +## Defaults to true. If enabled, upon hitting enter Atuin will immediately execute the command. Press tab to return to the shell and edit. +# This applies for new installs. Old installs will keep the old behaviour unless configured otherwise. +enter_accept = true + +## Defaults to "emacs". This specifies the keymap on the startup of `atuin +## search`. If this is set to "auto", the startup keymap mode in the Atuin +## search is automatically selected based on the shell's keymap where the +## keybinding is defined. If this is set to "emacs", "vim-insert", or +## "vim-normal", the startup keymap mode in the Atuin search is forced to be +## the specified one. +# keymap_mode = "auto" + +## Cursor style in each keymap mode. If specified, the cursor style is changed +## in entering the cursor shape. Available values are "default" and +## "{blink,steady}-{block,underline,bar}". +# keymap_cursor = { emacs = "blink-block", vim_insert = "blink-block", vim_normal = "steady-block" } + +# network_connect_timeout = 5 +# network_timeout = 5 + +## Timeout (in seconds) for acquiring a local database connection (sqlite) +# local_timeout = 5 + +## Set this to true and Atuin will minimize motion in the UI - timers will not update live, etc. +## Alternatively, set env NO_MOTION=true +# prefers_reduced_motion = false + +[stats] +## Set commands where we should consider the subcommand for statistics. Eg, kubectl get vs just kubectl +# common_subcommands = [ +# "apt", +# "cargo", +# "composer", +# "dnf", +# "docker", +# "git", +# "go", +# "ip", +# "jj", +# "kubectl", +# "nix", +# "nmcli", +# "npm", +# "pecl", +# "pnpm", +# "podman", +# "port", +# "systemctl", +# "tmux", +# "yarn", +# ] + +## Set commands that should be totally stripped and ignored from stats +# common_prefix = ["sudo"] + +## Set commands that will be completely ignored from stats +# ignored_commands = [ +# "cd", +# "ls", +# "vi" +# ] + +[keys] +# Defaults to true. If disabled, using the up/down key won't exit the TUI when scrolled past the first/last entry. +# scroll_exits = true +# Defaults to true. The left arrow key will exit the TUI when scrolling before the first character +# exit_past_line_start = true +# Defaults to true. The right arrow key performs the same functionality as Tab and copies the selected line to the command line to be modified. +# accept_past_line_end = true + +[sync] +# Enable sync v2 by default +# This ensures that sync v2 is enabled for new installs only +# In a later release it will become the default across the board +records = true + +[preview] +## which preview strategy to use to calculate the preview height (respects max_preview_height). +## possible values: auto, static +## auto: length of the selected command. +## static: length of the longest command stored in the history. +## fixed: use max_preview_height as fixed height. +# strategy = "auto" + +[daemon] +## Enables using the daemon to sync. Requires the daemon to be running in the background. Start it with `atuin daemon` +# enabled = false + +## How often the daemon should sync in seconds +# sync_frequency = 300 + +## The path to the unix socket used by the daemon (on unix systems) +## linux/mac: ~/.local/share/atuin/atuin.sock +## windows: Not Supported +# socket_path = "~/.local/share/atuin/atuin.sock" + +## Use systemd socket activation rather than opening the given path (the path must still be correct for the client) +## linux: false +## mac/windows: Not Supported +# systemd_socket = false + +## The port that should be used for TCP on non unix systems +# tcp_port = 8889 + +# [theme] +## Color theme to use for rendering in the terminal. +## There are some built-in themes, including the base theme ("default"), +## "autumn" and "marine". You can add your own themes to the "./themes" subdirectory of your +## Atuin config (or ATUIN_THEME_DIR, if provided) as TOML files whose keys should be one or +## more of AlertInfo, AlertWarn, AlertError, Annotation, Base, Guidance, Important, and +## the string values as lowercase entries from this list: +## https://ogeon.github.io/docs/palette/master/palette/named/index.html +## If you provide a custom theme file, it should be called "NAME.toml" and the theme below +## should be the stem, i.e. `theme = "NAME"` for your chosen NAME. +# name = "autumn" + +## Whether the theme manager should output normal or extra information to help fix themes. +## Boolean, true or false. If unset, left up to the theme manager. +# debug = true + +[search] +## The list of enabled filter modes, in order of priority. +## The "workspace" mode is skipped when not in a workspace or workspaces = false. +## Default filter mode can be overridden with the filter_mode setting. +# filters = [ "global", "host", "session", "workspace", "directory" ] diff --git a/packages/btop/dot-config/btop/btop.conf b/packages/btop/dot-config/btop/btop.conf new file mode 100644 index 0000000..67846f3 --- /dev/null +++ b/packages/btop/dot-config/btop/btop.conf @@ -0,0 +1,283 @@ +#? Config file for btop v.1.4.7 + +#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. +#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" +color_theme = "Default" + +#* If the theme set background should be shown, set to False if you want terminal background transparency. +theme_background = true + +#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. +truecolor = true + +#* Set to true to force tty mode regardless if a real tty has been detected or not. +#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols. +force_tty = false + +#* Option to disable presets. Either the default preset, custom presets, or all presets. +#* "Off" All presets are enabled. +#* "Default" preset is disabled.#* "Custom" presets are disabled.#* "All" presets are disabled. +disable_presets = "Off" + +#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. +#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box. +#* Use whitespace " " as separator between different presets. +#* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty" +presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty" + +#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists. +#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift. +vim_keys = false + +#* Disable all mouse events. +disable_mouse = false + +#* Rounded corners on boxes, is ignored if TTY mode is ON. +rounded_corners = true + +#* Use terminal synchronized output sequences to reduce flickering on supported terminals. +terminal_sync = true + +#* Default symbols to use for graph creation, "braille", "block" or "tty". +#* "braille" offers the highest resolution but might not be included in all fonts. +#* "block" has half the resolution of braille but uses more common characters. +#* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY. +#* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view. +graph_symbol = "braille" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_cpu = "default" + +# Graph symbol to use for graphs in gpu box, "default", "braille", "block" or "tty". +graph_symbol_gpu = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_mem = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_net = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_proc = "default" + +#* Manually set which boxes to show. Available values are "cpu mem net proc" and "gpu0" through "gpu5", separate values with whitespace. +shown_boxes = "cpu mem net" + +#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. +update_ms = 2000 + +#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", +#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. +proc_sorting = "cpu direct" + +#* Reverse sorting order, True or False. +proc_reversed = false + +#* Show processes as a tree. +proc_tree = false + +#* Use the cpu graph colors in the process list. +proc_colors = true + +#* Use a darkening gradient in the process list. +proc_gradient = true + +#* If process cpu usage should be of the core it's running on or usage of the total available cpu power. +proc_per_core = false + +#* Show process memory as bytes instead of percent. +proc_mem_bytes = true + +#* Show cpu graph for each process. +proc_cpu_graphs = true + +#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) +proc_info_smaps = false + +#* Show proc box on left side of screen instead of right. +proc_left = false + +#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop). +proc_filter_kernel = false + +#* Should the process list follow the selected process when detailed view is open. +proc_follow_detailed = true + +#* In tree-view, always accumulate child process resources in the parent process. +proc_aggregate = false + +#* Should cpu and memory usage display be preserved for dead processes when paused. +keep_dead_proc_usage = false + +#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_upper = "Auto" + +#* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_lower = "Auto" + +#* If gpu info should be shown in the cpu box. Available values = "Auto", "On" and "Off". +show_gpu_info = "Auto" + +#* Toggles if the lower CPU graph should be inverted. +cpu_invert_lower = true + +#* Set to True to completely disable the lower CPU graph. +cpu_single_graph = false + +#* Show cpu box at bottom of screen instead of top. +cpu_bottom = false + +#* Shows the system uptime in the CPU box. +show_uptime = true + +#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo. +show_cpu_watts = true + +#* Show cpu temperature. +check_temp = true + +#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. +cpu_sensor = "Auto" + +#* Show temperatures for cpu cores also if check_temp is True and sensors has been found. +show_coretemp = true + +#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. +#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. +#* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries. +#* Example: "4:0 5:1 6:3" +cpu_core_map = "" + +#* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine". +temp_scale = "celsius" + +#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024. +base_10_sizes = false + +#* Show CPU frequency. +show_cpu_freq = true + +#* Draw a clock at top of screen, formatting according to strftime, empty string to disable. +#* Special formatting: /host = hostname | /user = username | /uptime = system uptime +clock_format = "%X" + +#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. +background_update = true + +#* Custom cpu model name, empty string to disable. +custom_cpu_name = "" + +#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ". +#* Only disks matching the filter will be shown. Prepend exclude= to only show disks not matching the filter. Examples: disk_filter="/boot /home/user", disks_filter="exclude=/boot /home/user" +disks_filter = "" + +#* Show graphs instead of meters for memory values. +mem_graphs = true + +#* Show mem box below net box instead of above. +mem_below_net = false + +#* Count ZFS ARC in cached and available memory. +zfs_arc_cached = true + +#* If swap memory should be shown in memory box. +show_swap = true + +#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. +swap_disk = true + +#* If mem box should be split to also show disks info. +show_disks = true + +#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. +only_physical = true + +#* Read disks list from /etc/fstab. This also disables only_physical. +use_fstab = true + +#* Setting this to True will hide all datasets, and only show ZFS pools. (IO stats will be calculated per-pool) +zfs_hide_datasets = false + +#* Set to true to show available disk space for privileged users. +disk_free_priv = false + +#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. +show_io_stat = true + +#* Toggles io mode for disks, showing big graphs for disk read/write speeds. +io_mode = false + +#* Set to True to show combined read/write io graphs in io mode. +io_graph_combined = false + +#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ". +#* Example: "/mnt/media:100 /:20 /boot:1". +io_graph_speeds = "" + +#* Swap the positions of the upload and download speed graphs. When true, upload will be on top. +swap_upload_download = false + +#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. +net_download = 100 + +net_upload = 100 + +#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. +net_auto = true + +#* Sync the auto scaling for download and upload to whichever currently has the highest scale. +net_sync = true + +#* Starts with the Network Interface specified here. +net_iface = "" + +#* "True" shows bitrates in base 10 (Kbps, Mbps). "False" shows bitrates in binary sizes (Kibps, Mibps, etc.). "Auto" uses base_10_sizes. +base_10_bitrate = "Auto" + +#* Show battery stats in top right if battery is present. +show_battery = true + +#* Which battery to use if multiple are present. "Auto" for auto detection. +selected_battery = "Auto" + +#* Show power stats of battery next to charge indicator. +show_battery_watts = true + +#* Set loglevel for "~/.local/state/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". +#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info. +log_level = "WARNING" + +#* Automatically save current settings to config file on exit. +save_config_on_exit = true + +#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards. +nvml_measure_pcie_speeds = true + +#* Measure PCIe throughput on AMD cards, may impact performance on certain cards. +rsmi_measure_pcie_speeds = true + +#* Horizontally mirror the GPU graph. +gpu_mirror_graph = true + +#* Set which GPU vendors to show. Available values are "nvidia amd intel apple" +shown_gpus = "nvidia amd intel apple" + +#* Custom gpu0 model name, empty string to disable. +custom_gpu_name0 = "" + +#* Custom gpu1 model name, empty string to disable. +custom_gpu_name1 = "" + +#* Custom gpu2 model name, empty string to disable. +custom_gpu_name2 = "" + +#* Custom gpu3 model name, empty string to disable. +custom_gpu_name3 = "" + +#* Custom gpu4 model name, empty string to disable. +custom_gpu_name4 = "" + +#* Custom gpu5 model name, empty string to disable. +custom_gpu_name5 = "" diff --git a/packages/gh/dot-config/gh/config.yml b/packages/gh/dot-config/gh/config.yml new file mode 100644 index 0000000..1044065 --- /dev/null +++ b/packages/gh/dot-config/gh/config.yml @@ -0,0 +1,19 @@ +# The current version of the config schema +version: 1 +# What protocol to use when performing git operations. Supported values: ssh, https +git_protocol: https +# What editor gh should run when creating issues, pull requests, etc. If blank, will refer to environment. +editor: +# When to interactively prompt. This is a global config that cannot be overridden by hostname. Supported values: enabled, disabled +prompt: enabled +# Preference for editor-based interactive prompting. This is a global config that cannot be overridden by hostname. Supported values: enabled, disabled +prefer_editor_prompt: disabled +# A pager program to send command output to, e.g. "less". If blank, will refer to environment. Set the value to "cat" to disable the pager. +pager: +# Aliases allow you to create nicknames for gh commands +aliases: + co: pr checkout +# The path to a unix socket through which send HTTP connections. If blank, HTTP traffic will be handled by net/http.DefaultTransport. +http_unix_socket: +# What web browser gh should use when opening URLs. If blank, will refer to environment. +browser: From 7152b84e903a28c6ec226786623d3f5752f757b0 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:46:45 +0530 Subject: [PATCH 19/51] Add new-Mac bootstrap and macOS defaults placeholder bootstrap.sh is curl-able and idempotent: CLT, Homebrew, clone, brew bundle, stow (adopt on first run with a mandatory diff review), then harness-configs make install as a sibling repo. macos/defaults.sh is the phase-2 landing spot for defaults-write capture behind make macos-apply. --- bootstrap.sh | 77 +++++++++++++++++++++++++++++++++++++++++++++++ macos/defaults.sh | 9 ++++++ 2 files changed, 86 insertions(+) create mode 100755 bootstrap.sh create mode 100755 macos/defaults.sh diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..e5993aa --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# New-Mac bootstrap: Xcode CLT -> Homebrew -> clone dotfiles -> brew bundle -> +# stow links -> harness-configs -> doctor. Idempotent; every step checks first. +# +# curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh | bash +set -euo pipefail + +DOTFILES_DIR="${DOTFILES_DIR:-$HOME/personal/dotfiles}" +DOTFILES_SSH="git@github.com:sanketsudake/dotfiles.git" +DOTFILES_HTTPS="https://github.com/sanketsudake/dotfiles.git" + +step() { printf '\n==> %s\n' "$*"; } + +step "Xcode Command Line Tools" +if ! xcode-select -p >/dev/null 2>&1; then + xcode-select --install + echo "CLT install dialog opened — finish it, then re-run this script." + exit 0 +fi +echo "ok: $(xcode-select -p)" + +step "Homebrew" +if [ -x /opt/homebrew/bin/brew ]; then + eval "$(/opt/homebrew/bin/brew shellenv)" +elif [ -x /usr/local/bin/brew ]; then + eval "$(/usr/local/bin/brew shellenv)" +else + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + if [ -x /opt/homebrew/bin/brew ]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + else + eval "$(/usr/local/bin/brew shellenv)" + fi +fi +echo "ok: $(brew --prefix)" + +step "Dotfiles repo" +# When piped via curl there is no local clone yet; clone it. SSH first (keys +# usually not set up yet on a fresh machine, so fall back to https). +if [ ! -d "$DOTFILES_DIR/.git" ]; then + mkdir -p "$(dirname "$DOTFILES_DIR")" + git clone "$DOTFILES_SSH" "$DOTFILES_DIR" 2>/dev/null \ + || git clone "$DOTFILES_HTTPS" "$DOTFILES_DIR" +fi +cd "$DOTFILES_DIR" +echo "ok: $DOTFILES_DIR" + +step "Brew packages (brew bundle)" +make brew-install + +step "Stow links" +# First run on a machine with pre-existing real dotfiles: adopt absorbs them +# into the working tree so stow can link, then the diff MUST be reviewed. +if [ -e "$HOME/.zshrc" ] && [ ! -L "$HOME/.zshrc" ]; then + make stow-adopt + echo "" + echo "!! Pre-existing dotfiles were adopted into the repo working tree." + echo "!! Review with: git -C $DOTFILES_DIR diff" + echo "!! Restore the repo versions with: git -C $DOTFILES_DIR checkout -- packages/" +else + make stow-link +fi + +step "harness-configs (AI harness setup)" +make harness-install + +step "Doctor" +make doctor || true + +cat <<'EOF' + +Bootstrap complete. Manual steps that need your credentials: + 1. gh auth login + 2. atuin login (history sync) + 3. git lfs install + 4. Open a new terminal so zsh picks up the managed config. +EOF diff --git a/macos/defaults.sh b/macos/defaults.sh new file mode 100755 index 0000000..e217b92 --- /dev/null +++ b/macos/defaults.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# macOS system preferences as code (defaults write ...). +# Phase 2 of the dotfiles revamp — settings not yet captured. +# When populated: group by domain (Dock, Finder, keyboard, trackpad, screenshots), +# make every write idempotent, and end with `killall Dock Finder SystemUIServer` +# as needed. Apply with `make macos-apply`. +set -euo pipefail + +echo "macos/defaults.sh: no settings captured yet (phase 2) — nothing to apply." From fc9d6ee0f0d339adcfeeb1f53c4f367d6628be3a Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 16:47:48 +0530 Subject: [PATCH 20/51] Add doctor health checks and full README doctor verifies stow version, Brewfile satisfaction, every managed symlink, the --no-folding secret-safety invariants (real ~/.config dirs, hosts.yml not a symlink, no secret-pattern files tracked), and the harness-configs sibling. --- README.md | 85 +++++++++++++++++++++++++++++++++++++++++++++-- scripts/doctor.sh | 83 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 2 deletions(-) create mode 100755 scripts/doctor.sh diff --git a/README.md b/README.md index 4422946..575b3fa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,85 @@ # dotfiles -macOS dotfiles managed with GNU stow, plus a Brewfile and a one-shot bootstrap for new machines. -Full documentation lands as the revamp completes. +macOS dotfiles managed with GNU stow, a curated Brewfile, and a one-shot bootstrap for new machines. +Pairs with the sibling [harness-configs](https://github.com/sanketsudake/harness-configs) repo, which owns all AI coding-harness config. + +## New Mac quick start + +```sh +curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh | bash +``` + +The script is idempotent: it installs Xcode CLT and Homebrew if missing, clones this repo to `~/personal/dotfiles`, runs `brew bundle`, stows the packages, clones and installs harness-configs as a sibling, and finishes with `make doctor`. +Afterwards run the printed manual steps (`gh auth login`, `atuin login`, `git lfs install`) and open a new terminal. + +On an existing machine, clone the repo and run `make install`. + +## Layout + +| Path | Purpose | +|---|---| +| `packages/` | Stow packages, one directory per tool; only files here are ever stowed or committed | +| `Brewfile` | Curated brew formulae, casks, and VS Code extensions | +| `bootstrap.sh` | New-Mac entry point | +| `macos/defaults.sh` | macOS `defaults` capture (phase 2, empty placeholder) | +| `scripts/doctor.sh` | Health checks behind `make doctor` | + +## Make targets + +| Target | Does | +|---|---| +| `install` | `brew-install` + `stow-link` + `harness-install` | +| `uninstall` | Remove the stow symlinks | +| `brew-install` / `brew-check` | Apply / verify the Brewfile | +| `brew-dump` | Regenerate `Brewfile.dump` (gitignored) to diff against the curated Brewfile | +| `stow-link` / `stow-unlink` | Create / remove symlinks (`--restow` makes link idempotent) | +| `stow-adopt` | Absorb pre-existing real files into the working tree; always review `git diff` after | +| `harness-install` | Clone harness-configs if missing, then run its `make install` | +| `macos-apply` | Run `macos/defaults.sh` | +| `doctor` | Run all health checks | + +## The stow model + +Packages live under `packages/` and are stowed with `--dotfiles --no-folding` into `$HOME`. +`--dotfiles` maps `dot-zshrc` → `~/.zshrc`, so no hidden files exist in the repo (requires stow ≥ 2.4.0, enforced by `doctor`). +`--no-folding` is a security invariant, not a style choice: it links individual files instead of whole directories, so `~/.config/` stays a real directory. +That is what keeps `gh`'s `hosts.yml` (OAuth tokens) a plain local file that can never land in the repo — only `config.yml` is managed. +Never add packages for credential-bearing dirs (`gcloud`, `1Password`, `op`, `github-copilot`). + +## zsh structure + +`~/.zshrc` is a thin loader that sources `~/.config/zsh/*.zsh` in `NN-` prefix order. +Adding shell config means dropping a new numbered file into `packages/zsh/dot-config/zsh/` — no editing of `.zshrc` itself. +`~/.zprofile` only sets up `brew shellenv` (guarded for Apple Silicon and Intel paths). +Machine-local, uncommitted overrides go in `~/.config/zsh/90-local.zsh` (gitignored; see `90-local.zsh.example`). + +## Multi-identity git + +`packages/git/dot-gitconfig` selects identity by remote URL via `includeIf "hasconfig:remote.*.url:..."` blocks. +Personal repos get `~/.config/git/config-personal` (gmail); ShiftLeftSecurity/Harness remotes get `~/.config/git/config-qwiet`. +The work email in `config-qwiet` is an identity, not a credential, and is committed intentionally. + +## harness-configs integration + +The two repos are siblings: this repo lives at `~/personal/dotfiles`, harness-configs at `~/personal/harness-configs` (override with `HARNESS_DIR=`). +`make harness-install` clones it if missing and runs its idempotent `make install`. +`packages/zsh/dot-config/zsh/50-harness.zsh` sources its `claude-multi-account.sh`, so the `pclaude`/`wclaude` wrappers exist in every interactive shell with no manual profile editing. +The Brewfile carries its prerequisites (`stow`, `jq`, `gh`, `nvm` for node/npx, `python@3.13`). + +## Adding a new tool config + +1. `mkdir -p packages//dot-config/` and copy the non-secret config file(s) in, using `dot-` names for anything dotted. +2. Add `` to `PACKAGES` in the Makefile. +3. `make stow-adopt`, review `git diff`, then commit. + +## Secrets policy + +Nothing outside `packages/` is ever stowed, and no package references a credential-bearing file. +`.gitignore` blocks `hosts.yml`, `.env*`, keys, and token-like names as a second layer. +`make doctor` fails if any tracked file matches a secret pattern or if a `~/.config` dir has become a symlink. +Review `git diff --cached` before every commit regardless. + +## macOS defaults (phase 2) + +`macos/defaults.sh` is the landing spot for `defaults write` capture (Dock, Finder, keyboard, trackpad, screenshots), applied via `make macos-apply`. +It is currently an intentional no-op. diff --git a/scripts/doctor.sh b/scripts/doctor.sh new file mode 100755 index 0000000..4711027 --- /dev/null +++ b/scripts/doctor.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +# Health checks for the dotfiles setup. Exit non-zero if anything is wrong. +set -uo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +HARNESS_DIR="${HARNESS_DIR:-$(cd "$REPO_DIR/.." && pwd)/harness-configs}" +FAIL=0 + +ok() { printf ' ok: %s\n' "$*"; } +bad() { printf 'FAIL: %s\n' "$*"; FAIL=1; } + +echo "== tools ==" +if command -v brew >/dev/null; then ok "brew $(brew --version | head -1 | awk '{print $2}')"; else bad "brew not found"; fi +if command -v stow >/dev/null; then + stow_ver="$(stow --version | head -1 | awk '{print $NF}')" + case "$stow_ver" in + 2.[0-3]*|1.*) bad "stow $stow_ver too old — need >= 2.4.0 for --dotfiles dir handling" ;; + *) ok "stow $stow_ver" ;; + esac +else + bad "stow not found" +fi +if command -v npx >/dev/null; then ok "npx ($(command -v npx))"; else bad "npx not found (nvm node not installed? run: nvm install --lts)"; fi + +echo "== brew bundle ==" +if brew bundle check --file="$REPO_DIR/Brewfile" >/dev/null 2>&1; then + ok "Brewfile satisfied" +else + bad "Brewfile unsatisfied — run: make brew-install" +fi + +echo "== symlinks ==" +for target in .zshrc .zprofile .gitconfig \ + .config/git/config-personal .config/git/config-qwiet .config/git/ignore \ + .config/zsh/00-env.zsh .config/atuin/config.toml .config/btop/btop.conf \ + .config/gh/config.yml; do + path="$HOME/$target" + # Stow links are relative; resolve and confirm they land inside packages/. + resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$path")" + if [ -L "$path" ] && [[ "$resolved" == "$REPO_DIR/packages/"* ]]; then + ok "$target" + else + bad "$target is not a symlink into packages/ — run: make stow-link" + fi +done + +echo "== secret safety ==" +for dir in .config/gh .config/git .config/zsh; do + if [ -d "$HOME/$dir" ] && [ ! -L "$HOME/$dir" ]; then + ok "~/$dir is a real directory" + else + bad "~/$dir is missing or a symlink — credentials could land in the repo (--no-folding violated)" + fi +done +if [ -e "$HOME/.config/gh/hosts.yml" ] && [ ! -L "$HOME/.config/gh/hosts.yml" ]; then + ok "gh hosts.yml is a plain local file" +elif [ -L "$HOME/.config/gh/hosts.yml" ]; then + bad "gh hosts.yml is a symlink — tokens may be inside the repo" +else + ok "gh hosts.yml absent (run gh auth login)" +fi +leaks="$(cd "$REPO_DIR" && git ls-files | grep -Ei 'hosts\.yml|\.env($|\.)|\.pem$|\.key$|token|credential' || true)" +if [ -z "$leaks" ]; then + ok "no secret-pattern files tracked by git" +else + bad "secret-pattern files tracked by git:"$'\n'"$leaks" +fi + +echo "== harness-configs ==" +if [ -d "$HARNESS_DIR/.git" ]; then + ok "repo present at $HARNESS_DIR" + if [ -r "$HARNESS_DIR/scripts/claude-multi-account.sh" ]; then + ok "claude-multi-account.sh readable (sourced by ~/.config/zsh/50-harness.zsh)" + else + bad "claude-multi-account.sh missing" + fi +else + bad "harness-configs not found at $HARNESS_DIR — run: make harness-install" +fi + +echo "" +if [ "$FAIL" -eq 0 ]; then echo "doctor: all checks passed"; else echo "doctor: FAILURES above"; fi +exit "$FAIL" From 113b2dc28ab89e140805ac38f1a3e299d2212c1e Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:01:59 +0530 Subject: [PATCH 21/51] Fix review findings: fresh-Mac bootstrap path and secret scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - harness-clone falls back to https with GIT_CONFIG_GLOBAL=/dev/null so the gitconfig ssh rewrite cannot defeat it; bootstrap continues past a failed harness step and still prints the credential instructions - bootstrap stow step is deterministic: move pre-existing real files at managed paths to ~/.dotfiles-backup- and always stow-link, instead of branching on ~/.zshrc alone (auto-adopt removed — adopt is now a deliberate manual target only) - scripts/managed-targets.sh derives the managed path list from packages/ so doctor and bootstrap can never drift from the tree - doctor: content-level secret scan of tracked packages/, numeric stow version compare, realpath instead of bare python3, npx demoted to a warning, all symlinks checked via the derived list - jwtd fails loudly without jq; aliases guard their targets' existence - README: download-then-run bootstrap form, gh-qwiet ssh alias documented, secrets-policy claims match what is actually enforced --- Makefile | 7 +- README.md | 14 ++-- bootstrap.sh | 70 ++++++++++++-------- packages/zsh/dot-config/zsh/20-aliases.zsh | 7 +- packages/zsh/dot-config/zsh/30-functions.zsh | 8 ++- scripts/doctor.sh | 44 ++++++++---- scripts/managed-targets.sh | 10 +++ 7 files changed, 109 insertions(+), 51 deletions(-) create mode 100755 scripts/managed-targets.sh diff --git a/Makefile b/Makefile index 9299b55..7751ad1 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ PACKAGES := zsh git atuin btop gh BREWFILE := $(CURDIR)/Brewfile HARNESS_DIR ?= $(abspath $(CURDIR)/../harness-configs) HARNESS_REPO := git@github.com:sanketsudake/harness-configs.git +HARNESS_REPO_HTTPS := https://github.com/sanketsudake/harness-configs.git .PHONY: install uninstall doctor \ brew-install brew-check brew-dump \ @@ -48,8 +49,12 @@ stow-adopt: @echo "" @echo "!! REVIEW 'git diff' BEFORE COMMITTING — adopt replaces repo files with the live ones !!" +# SSH first; fall back to https for machines without GitHub keys yet. The +# fallback bypasses the global gitconfig because dot-gitconfig rewrites +# https://github.com/ to SSH, which would defeat it. harness-clone: - @test -d $(HARNESS_DIR) || git clone $(HARNESS_REPO) $(HARNESS_DIR) + @test -d $(HARNESS_DIR) || git clone $(HARNESS_REPO) $(HARNESS_DIR) 2>/dev/null \ + || GIT_CONFIG_GLOBAL=/dev/null git clone $(HARNESS_REPO_HTTPS) $(HARNESS_DIR) harness-install: harness-clone $(MAKE) -C $(HARNESS_DIR) install diff --git a/README.md b/README.md index 575b3fa..52fe523 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,13 @@ Pairs with the sibling [harness-configs](https://github.com/sanketsudake/harness ## New Mac quick start ```sh -curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh | bash +curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh -o /tmp/bootstrap.sh +bash /tmp/bootstrap.sh ``` -The script is idempotent: it installs Xcode CLT and Homebrew if missing, clones this repo to `~/personal/dotfiles`, runs `brew bundle`, stows the packages, clones and installs harness-configs as a sibling, and finishes with `make doctor`. -Afterwards run the printed manual steps (`gh auth login`, `atuin login`, `git lfs install`) and open a new terminal. +Download-then-run (rather than `curl | bash`) matters: casks can prompt for sudo, and a piped bash shares stdin with the script. +The script is idempotent: it installs Xcode CLT and Homebrew if missing, clones this repo to `~/personal/dotfiles`, runs `brew bundle`, moves any pre-existing real files at managed paths to a timestamped `~/.dotfiles-backup-*` dir, stows the packages, clones and installs harness-configs as a sibling, and finishes with `make doctor`. +Afterwards run the printed manual steps (`gh auth login`, `atuin login`, `git lfs install`, and for work remotes the `gh-qwiet` SSH host alias in `~/.ssh/config`) and open a new terminal. On an existing machine, clone the repo and run `make install`. @@ -58,6 +60,7 @@ Machine-local, uncommitted overrides go in `~/.config/zsh/90-local.zsh` (gitigno `packages/git/dot-gitconfig` selects identity by remote URL via `includeIf "hasconfig:remote.*.url:..."` blocks. Personal repos get `~/.config/git/config-personal` (gmail); ShiftLeftSecurity/Harness remotes get `~/.config/git/config-qwiet`. The work email in `config-qwiet` is an identity, not a credential, and is committed intentionally. +ShiftLeftSecurity remotes are additionally rewritten through a `gh-qwiet` SSH host alias, which must exist in `~/.ssh/config` (kept out of this repo; see the bootstrap manual steps). ## harness-configs integration @@ -75,8 +78,9 @@ The Brewfile carries its prerequisites (`stow`, `jq`, `gh`, `nvm` for node/npx, ## Secrets policy Nothing outside `packages/` is ever stowed, and no package references a credential-bearing file. -`.gitignore` blocks `hosts.yml`, `.env*`, keys, and token-like names as a second layer. -`make doctor` fails if any tracked file matches a secret pattern or if a `~/.config` dir has become a symlink. +`.gitignore` blocks `hosts.yml`, `.env*`, keys, and token-like names as a second layer (note it cannot protect already-tracked paths). +`make doctor` fails if any tracked filename matches a secret pattern, if tracked file content looks credential-like (token/key/password assignments, private-key blocks), or if a `~/.config` dir has become a symlink. +After `make stow-adopt`, always review `git diff` before committing — adopt imports live machine files into tracked paths, which is exactly how a stray exported token could enter the repo. Review `git diff --cached` before every commit regardless. ## macOS defaults (phase 2) diff --git a/bootstrap.sh b/bootstrap.sh index e5993aa..a5a352e 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -2,7 +2,10 @@ # New-Mac bootstrap: Xcode CLT -> Homebrew -> clone dotfiles -> brew bundle -> # stow links -> harness-configs -> doctor. Idempotent; every step checks first. # -# curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh | bash +# Preferred invocation (casks may prompt for sudo, which clashes with curl|bash +# sharing stdin with the script): +# curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh -o /tmp/bootstrap.sh +# bash /tmp/bootstrap.sh set -euo pipefail DOTFILES_DIR="${DOTFILES_DIR:-$HOME/personal/dotfiles}" @@ -11,6 +14,18 @@ DOTFILES_HTTPS="https://github.com/sanketsudake/dotfiles.git" step() { printf '\n==> %s\n' "$*"; } +# Load brew into this shell from whichever prefix exists (Apple Silicon/Intel). +brew_env() { + local p + for p in /opt/homebrew /usr/local; do + if [ -x "$p/bin/brew" ]; then + eval "$("$p/bin/brew" shellenv)" + return 0 + fi + done + return 1 +} + step "Xcode Command Line Tools" if ! xcode-select -p >/dev/null 2>&1; then xcode-select --install @@ -20,27 +35,20 @@ fi echo "ok: $(xcode-select -p)" step "Homebrew" -if [ -x /opt/homebrew/bin/brew ]; then - eval "$(/opt/homebrew/bin/brew shellenv)" -elif [ -x /usr/local/bin/brew ]; then - eval "$(/usr/local/bin/brew shellenv)" -else +if ! brew_env; then /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - if [ -x /opt/homebrew/bin/brew ]; then - eval "$(/opt/homebrew/bin/brew shellenv)" - else - eval "$(/usr/local/bin/brew shellenv)" - fi + brew_env fi echo "ok: $(brew --prefix)" step "Dotfiles repo" -# When piped via curl there is no local clone yet; clone it. SSH first (keys -# usually not set up yet on a fresh machine, so fall back to https). +# When run via curl there is no local clone yet; clone it. SSH first (keys +# usually not set up yet on a fresh machine, so fall back to https, bypassing +# any pre-existing gitconfig https->ssh rewrite). if [ ! -d "$DOTFILES_DIR/.git" ]; then mkdir -p "$(dirname "$DOTFILES_DIR")" git clone "$DOTFILES_SSH" "$DOTFILES_DIR" 2>/dev/null \ - || git clone "$DOTFILES_HTTPS" "$DOTFILES_DIR" + || GIT_CONFIG_GLOBAL=/dev/null git clone "$DOTFILES_HTTPS" "$DOTFILES_DIR" fi cd "$DOTFILES_DIR" echo "ok: $DOTFILES_DIR" @@ -49,20 +57,28 @@ step "Brew packages (brew bundle)" make brew-install step "Stow links" -# First run on a machine with pre-existing real dotfiles: adopt absorbs them -# into the working tree so stow can link, then the diff MUST be reviewed. -if [ -e "$HOME/.zshrc" ] && [ ! -L "$HOME/.zshrc" ]; then - make stow-adopt - echo "" - echo "!! Pre-existing dotfiles were adopted into the repo working tree." - echo "!! Review with: git -C $DOTFILES_DIR diff" - echo "!! Restore the repo versions with: git -C $DOTFILES_DIR checkout -- packages/" -else - make stow-link +# Deterministic: move any pre-existing real file at a managed path aside, then +# link. End state is always the repo's configs live, originals preserved. +backup_dir="$HOME/.dotfiles-backup-$(date +%s)" +while IFS= read -r rel; do + target="$HOME/$rel" + if [ -e "$target" ] && [ ! -L "$target" ]; then + mkdir -p "$backup_dir/$(dirname "$rel")" + mv "$target" "$backup_dir/$rel" + echo "moved aside: ~/$rel -> $backup_dir/$rel" + fi +done < <(scripts/managed-targets.sh) +make stow-link +if [ -d "$backup_dir" ]; then + echo "!! Pre-existing files were moved to $backup_dir — port anything you need" + echo "!! into ~/.config/zsh/90-local.zsh (gitignored), then delete the backup." fi step "harness-configs (AI harness setup)" -make harness-install +make harness-install || { + echo "!! harness-configs setup failed (no GitHub access yet?)." + echo "!! After 'gh auth login' / SSH keys, run: make harness-install" +} step "Doctor" make doctor || true @@ -73,5 +89,7 @@ Bootstrap complete. Manual steps that need your credentials: 1. gh auth login 2. atuin login (history sync) 3. git lfs install - 4. Open a new terminal so zsh picks up the managed config. + 4. Work remotes only: add the gh-qwiet host alias to ~/.ssh/config + (the gitconfig rewrites ShiftLeftSecurity remotes through it). + 5. Open a new terminal so zsh picks up the managed config. EOF diff --git a/packages/zsh/dot-config/zsh/20-aliases.zsh b/packages/zsh/dot-config/zsh/20-aliases.zsh index 66aa020..5461225 100644 --- a/packages/zsh/dot-config/zsh/20-aliases.zsh +++ b/packages/zsh/dot-config/zsh/20-aliases.zsh @@ -1,2 +1,5 @@ -alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale" -alias chrome-doctor="$HOME/chrome-doctor.sh" +# Guarded: only define aliases whose targets exist on this machine. +[ -x /Applications/Tailscale.app/Contents/MacOS/Tailscale ] \ + && alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale" +[ -x "$HOME/chrome-doctor.sh" ] \ + && alias chrome-doctor="$HOME/chrome-doctor.sh" diff --git a/packages/zsh/dot-config/zsh/30-functions.zsh b/packages/zsh/dot-config/zsh/30-functions.zsh index ff5672f..9f3c531 100644 --- a/packages/zsh/dot-config/zsh/30-functions.zsh +++ b/packages/zsh/dot-config/zsh/30-functions.zsh @@ -1,9 +1,11 @@ # Decode a JWT's header and payload (needs jq); the signature is printed, not verified. jwtd() { - if [[ -x $(command -v jq) ]]; then - jq -R 'split(".") | .[0],.[1] | @base64d | fromjson' <<< "${1}" - echo "Signature: $(echo "${1}" | awk -F'.' '{print $3}')" + if ! command -v jq >/dev/null; then + echo "jwtd: needs jq (brew install jq)" >&2 + return 127 fi + jq -R 'split(".") | .[0],.[1] | @base64d | fromjson' <<< "${1}" + echo "Signature: $(echo "${1}" | awk -F'.' '{print $3}')" } # Strip the password from a PDF -> passwordless copy (needs qpdf). diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 4711027..f495f52 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -7,20 +7,30 @@ HARNESS_DIR="${HARNESS_DIR:-$(cd "$REPO_DIR/.." && pwd)/harness-configs}" FAIL=0 ok() { printf ' ok: %s\n' "$*"; } +warn() { printf ' warn: %s\n' "$*"; } bad() { printf 'FAIL: %s\n' "$*"; FAIL=1; } +resolve() { + realpath "$1" 2>/dev/null \ + || python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$1" 2>/dev/null \ + || true +} + echo "== tools ==" if command -v brew >/dev/null; then ok "brew $(brew --version | head -1 | awk '{print $2}')"; else bad "brew not found"; fi if command -v stow >/dev/null; then stow_ver="$(stow --version | head -1 | awk '{print $NF}')" - case "$stow_ver" in - 2.[0-3]*|1.*) bad "stow $stow_ver too old — need >= 2.4.0 for --dotfiles dir handling" ;; - *) ok "stow $stow_ver" ;; - esac + IFS=. read -r maj min _ <<< "$stow_ver" + if [ "${maj:-0}" -gt 2 ] 2>/dev/null || { [ "${maj:-0}" -eq 2 ] && [ "${min:-0}" -ge 4 ]; } 2>/dev/null; then + ok "stow $stow_ver" + else + bad "stow $stow_ver too old or unparseable — need >= 2.4.0 for --dotfiles dir handling" + fi else bad "stow not found" fi -if command -v npx >/dev/null; then ok "npx ($(command -v npx))"; else bad "npx not found (nvm node not installed? run: nvm install --lts)"; fi +# npx is only needed for harness-configs' optional skills-find/vendor targets. +if command -v npx >/dev/null; then ok "npx ($(command -v npx))"; else warn "npx not found — run: nvm install --lts (needed only for harness-configs skill vendoring)"; fi echo "== brew bundle ==" if brew bundle check --file="$REPO_DIR/Brewfile" >/dev/null 2>&1; then @@ -30,19 +40,17 @@ else fi echo "== symlinks ==" -for target in .zshrc .zprofile .gitconfig \ - .config/git/config-personal .config/git/config-qwiet .config/git/ignore \ - .config/zsh/00-env.zsh .config/atuin/config.toml .config/btop/btop.conf \ - .config/gh/config.yml; do +# Target list is derived from packages/ (managed-targets.sh), so new packages +# are health-checked automatically. +while IFS= read -r target; do path="$HOME/$target" - # Stow links are relative; resolve and confirm they land inside packages/. - resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$path")" + resolved="$(resolve "$path")" if [ -L "$path" ] && [[ "$resolved" == "$REPO_DIR/packages/"* ]]; then ok "$target" else bad "$target is not a symlink into packages/ — run: make stow-link" fi -done +done < <("$REPO_DIR/scripts/managed-targets.sh") echo "== secret safety ==" for dir in .config/gh .config/git .config/zsh; do @@ -61,9 +69,17 @@ else fi leaks="$(cd "$REPO_DIR" && git ls-files | grep -Ei 'hosts\.yml|\.env($|\.)|\.pem$|\.key$|token|credential' || true)" if [ -z "$leaks" ]; then - ok "no secret-pattern files tracked by git" + ok "no secret-pattern filenames tracked by git" +else + bad "secret-pattern filenames tracked by git:"$'\n'"$leaks" +fi +# Content scan: catch credential-looking values inside tracked files (e.g. a +# stow-adopted shell profile that carried exported tokens). +content_leaks="$(cd "$REPO_DIR" && git grep -nIiE "(api[_-]?key|secret|token|password)[[:space:]]*[=:][[:space:]]*['\"]?[A-Za-z0-9_/+=-]{12,}|BEGIN [A-Z ]*PRIVATE KEY" -- packages/ 2>/dev/null || true)" +if [ -z "$content_leaks" ]; then + ok "no credential-looking content in tracked packages/" else - bad "secret-pattern files tracked by git:"$'\n'"$leaks" + bad "credential-looking content in tracked files:"$'\n'"$content_leaks" fi echo "== harness-configs ==" diff --git a/scripts/managed-targets.sh b/scripts/managed-targets.sh new file mode 100755 index 0000000..183c07b --- /dev/null +++ b/scripts/managed-targets.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Print every $HOME-relative path managed by the stow packages, derived from +# packages/ itself so the list can never drift from reality. +# Mapping mirrors stow --dotfiles: a leading "dot-" on any path component -> ".". +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../packages" +find . -mindepth 2 \( -type f -o -type l \) \ + | sed -E 's#^\./[^/]+/##' \ + | sed -E 's#(^|/)dot-#\1.#g' \ + | sort -u From cd0ff00bc16f3c76667db63118279337840f7f92 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:06:59 +0530 Subject: [PATCH 22/51] Simplification pass: trim atuin config, dedup docs, unify function contracts - atuin config.toml reduced from 272 commented upstream-default lines to the 2 active settings plus a docs pointer (parses identically) - --no-folding rationale and the new-tool recipe each keep one canonical copy (README); Makefile and CLAUDE.md point there - jwtd/pdfunlock/imgcopy share one missing-tool contract (stderr + return 127) and consistent indentation; nvm paths hoisted to a local --- CLAUDE.md | 7 +- Makefile | 4 +- packages/atuin/dot-config/atuin/config.toml | 271 +------------------ packages/zsh/dot-config/zsh/30-functions.zsh | 20 +- packages/zsh/dot-config/zsh/40-tools.zsh | 6 +- 5 files changed, 25 insertions(+), 283 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index dd98065..95c3b1d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,8 +12,7 @@ macOS dotfiles provisioned with GNU stow; the Makefile is the interface (no app ## Conventions -- Stow flags are fixed: `--dotfiles --no-folding` (see Makefile). - `--no-folding` is a security invariant: `~/.config/` must stay a real directory so tools that write credentials beside their config (e.g. `gh`'s `hosts.yml`) never write into this repo. +- Stow flags are fixed at `--dotfiles --no-folding` and must not be changed; both are security invariants, explained in README.md § "The stow model". - File names use the `dot-` prefix (`dot-zshrc` → `~/.zshrc`); requires stow ≥ 2.4.0. - Makefile targets follow `-` naming (`brew-install`, `stow-link`, `harness-install`), matching the sibling `harness-configs` repo. - Never add packages for credential-bearing dirs: `gh/hosts.yml`, `gcloud`, `1Password`, `op`, `github-copilot`. @@ -21,6 +20,4 @@ macOS dotfiles provisioned with GNU stow; the Makefile is the interface (no app ## Adding a new tool config -1. `mkdir -p packages//dot-config/` and copy the non-secret config file(s) in, using `dot-` names for anything dotted. -2. Add `` to `PACKAGES` in the Makefile. -3. `make stow-adopt`, then review `git diff` before committing. +Follow the numbered recipe in README.md § "Adding a new tool config"; it is the canonical version. diff --git a/Makefile b/Makefile index 7751ad1..c7458ac 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ SHELL := /bin/bash STOW := stow -# --no-folding is a security invariant: ~/.config/ must stay a real -# directory so tools that write credentials beside their config (gh's -# hosts.yml) never write into this repo. --dotfiles needs stow >= 2.4.0. +# Flags are a security invariant, not a style choice — see "The stow model" in README.md. STOW_FLAGS := --dir=$(CURDIR)/packages --target=$(HOME) --dotfiles --no-folding --verbose=1 PACKAGES := zsh git atuin btop gh diff --git a/packages/atuin/dot-config/atuin/config.toml b/packages/atuin/dot-config/atuin/config.toml index ac9f8a1..986199c 100644 --- a/packages/atuin/dot-config/atuin/config.toml +++ b/packages/atuin/dot-config/atuin/config.toml @@ -1,272 +1,9 @@ -## where to store your database, default is your system data directory -## linux/mac: ~/.local/share/atuin/history.db -## windows: %USERPROFILE%/.local/share/atuin/history.db -# db_path = "~/.history.db" +# Only the settings that differ from atuin's defaults. +# Full reference: https://docs.atuin.sh/configuration/config/ -## where to store your encryption key, default is your system data directory -## linux/mac: ~/.local/share/atuin/key -## windows: %USERPROFILE%/.local/share/atuin/key -# key_path = "~/.key" - -## where to store your auth session token, default is your system data directory -## linux/mac: ~/.local/share/atuin/session -## windows: %USERPROFILE%/.local/share/atuin/session -# session_path = "~/.session" - -## date format used, either "us" or "uk" -# dialect = "us" - -## default timezone to use when displaying time -## either "l", "local" to use the system's current local timezone, or an offset -## from UTC in the format of "<+|->H[H][:M[M][:S[S]]]" -## for example: "+9", "-05", "+03:30", "-01:23:45", etc. -# timezone = "local" - -## enable or disable automatic sync -# auto_sync = true - -## enable or disable automatic update checks -# update_check = true - -## address of the sync server -# sync_address = "https://api.atuin.sh" - -## how often to sync history. note that this is only triggered when a command -## is ran, so sync intervals may well be longer -## set it to 0 to sync after every command -# sync_frequency = "10m" - -## which search mode to use -## possible values: prefix, fulltext, fuzzy, skim -# search_mode = "fuzzy" - -## which filter mode to use by default -## possible values: "global", "host", "session", "directory", "workspace" -## consider using search.filters to customize the enablement and order of filter modes -# filter_mode = "global" - -## With workspace filtering enabled, Atuin will filter for commands executed -## in any directory within a git repository tree (default: false). -## -## To use workspace mode by default when available, set this to true and -## set filter_mode to "workspace" or leave it unspecified and -## set search.filters to include "workspace" before other filter modes. -# workspaces = false - -## which filter mode to use when atuin is invoked from a shell up-key binding -## the accepted values are identical to those of "filter_mode" -## leave unspecified to use same mode set in "filter_mode" -# filter_mode_shell_up_key_binding = "global" - -## which search mode to use when atuin is invoked from a shell up-key binding -## the accepted values are identical to those of "search_mode" -## leave unspecified to use same mode set in "search_mode" -# search_mode_shell_up_key_binding = "fuzzy" - -## which style to use -## possible values: auto, full, compact -# style = "auto" - -## the maximum number of lines the interface should take up -## set it to 0 to always go full screen -# inline_height = 0 - -## Invert the UI - put the search bar at the top , Default to `false` -# invert = false - -## enable or disable showing a preview of the selected command -## useful when the command is longer than the terminal width and is cut off -# show_preview = true - -## what to do when the escape key is pressed when searching -## possible values: return-original, return-query -# exit_mode = "return-original" - -## possible values: emacs, subl -# word_jump_mode = "emacs" - -## characters that count as a part of a word -# word_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -## number of context lines to show when scrolling by pages -# scroll_context_lines = 1 - -## use ctrl instead of alt as the shortcut modifier key for numerical UI shortcuts -## alt-0 .. alt-9 -# ctrl_n_shortcuts = false - -## default history list format - can also be specified with the --format arg -# history_format = "{time}\t{command}\t{duration}" - -## prevent commands matching any of these regexes from being written to history. -## Note that these regular expressions are unanchored, i.e. if they don't start -## with ^ or end with $, they'll match anywhere in the command. -## For details on the supported regular expression syntax, see -## https://docs.rs/regex/latest/regex/#syntax -# history_filter = [ -# "^secret-cmd", -# "^innocuous-cmd .*--secret=.+", -# ] - -## prevent commands run with cwd matching any of these regexes from being written -## to history. Note that these regular expressions are unanchored, i.e. if they don't -## start with ^ or end with $, they'll match anywhere in CWD. -## For details on the supported regular expression syntax, see -## https://docs.rs/regex/latest/regex/#syntax -# cwd_filter = [ -# "^/very/secret/area", -# ] - -## Configure the maximum height of the preview to show. -## Useful when you have long scripts in your history that you want to distinguish -## by more than the first few lines. -# max_preview_height = 4 - -## Configure whether or not to show the help row, which includes the current Atuin -## version (and whether an update is available), a keymap hint, and the total -## amount of commands in your history. -# show_help = true - -## Configure whether or not to show tabs for search and inspect -# show_tabs = true - -## Configure whether or not the tabs row may be auto-hidden, which includes the current Atuin -## tab, such as Search or Inspector, and other tabs you may wish to see. This will -## only be hidden if there are fewer than this count of lines available, and does not affect the use -## of keyboard shortcuts to switch tab. 0 to never auto-hide, default is 8 (lines). -## This is ignored except in `compact` mode. -# auto_hide_height = 8 - -## Defaults to true. This matches history against a set of default regex, and will not save it if we get a match. Defaults include -## 1. AWS key id -## 2. Github pat (old and new) -## 3. Slack oauth tokens (bot, user) -## 4. Slack webhooks -## 5. Stripe live/test keys -# secrets_filter = true - -## Defaults to true. If enabled, upon hitting enter Atuin will immediately execute the command. Press tab to return to the shell and edit. -# This applies for new installs. Old installs will keep the old behaviour unless configured otherwise. +# Hitting enter runs the selected command instead of only pasting it at the prompt. enter_accept = true -## Defaults to "emacs". This specifies the keymap on the startup of `atuin -## search`. If this is set to "auto", the startup keymap mode in the Atuin -## search is automatically selected based on the shell's keymap where the -## keybinding is defined. If this is set to "emacs", "vim-insert", or -## "vim-normal", the startup keymap mode in the Atuin search is forced to be -## the specified one. -# keymap_mode = "auto" - -## Cursor style in each keymap mode. If specified, the cursor style is changed -## in entering the cursor shape. Available values are "default" and -## "{blink,steady}-{block,underline,bar}". -# keymap_cursor = { emacs = "blink-block", vim_insert = "blink-block", vim_normal = "steady-block" } - -# network_connect_timeout = 5 -# network_timeout = 5 - -## Timeout (in seconds) for acquiring a local database connection (sqlite) -# local_timeout = 5 - -## Set this to true and Atuin will minimize motion in the UI - timers will not update live, etc. -## Alternatively, set env NO_MOTION=true -# prefers_reduced_motion = false - -[stats] -## Set commands where we should consider the subcommand for statistics. Eg, kubectl get vs just kubectl -# common_subcommands = [ -# "apt", -# "cargo", -# "composer", -# "dnf", -# "docker", -# "git", -# "go", -# "ip", -# "jj", -# "kubectl", -# "nix", -# "nmcli", -# "npm", -# "pecl", -# "pnpm", -# "podman", -# "port", -# "systemctl", -# "tmux", -# "yarn", -# ] - -## Set commands that should be totally stripped and ignored from stats -# common_prefix = ["sudo"] - -## Set commands that will be completely ignored from stats -# ignored_commands = [ -# "cd", -# "ls", -# "vi" -# ] - -[keys] -# Defaults to true. If disabled, using the up/down key won't exit the TUI when scrolled past the first/last entry. -# scroll_exits = true -# Defaults to true. The left arrow key will exit the TUI when scrolling before the first character -# exit_past_line_start = true -# Defaults to true. The right arrow key performs the same functionality as Tab and copies the selected line to the command line to be modified. -# accept_past_line_end = true - [sync] -# Enable sync v2 by default -# This ensures that sync v2 is enabled for new installs only -# In a later release it will become the default across the board +# Sync v2 (record store) instead of the legacy history sync. records = true - -[preview] -## which preview strategy to use to calculate the preview height (respects max_preview_height). -## possible values: auto, static -## auto: length of the selected command. -## static: length of the longest command stored in the history. -## fixed: use max_preview_height as fixed height. -# strategy = "auto" - -[daemon] -## Enables using the daemon to sync. Requires the daemon to be running in the background. Start it with `atuin daemon` -# enabled = false - -## How often the daemon should sync in seconds -# sync_frequency = 300 - -## The path to the unix socket used by the daemon (on unix systems) -## linux/mac: ~/.local/share/atuin/atuin.sock -## windows: Not Supported -# socket_path = "~/.local/share/atuin/atuin.sock" - -## Use systemd socket activation rather than opening the given path (the path must still be correct for the client) -## linux: false -## mac/windows: Not Supported -# systemd_socket = false - -## The port that should be used for TCP on non unix systems -# tcp_port = 8889 - -# [theme] -## Color theme to use for rendering in the terminal. -## There are some built-in themes, including the base theme ("default"), -## "autumn" and "marine". You can add your own themes to the "./themes" subdirectory of your -## Atuin config (or ATUIN_THEME_DIR, if provided) as TOML files whose keys should be one or -## more of AlertInfo, AlertWarn, AlertError, Annotation, Base, Guidance, Important, and -## the string values as lowercase entries from this list: -## https://ogeon.github.io/docs/palette/master/palette/named/index.html -## If you provide a custom theme file, it should be called "NAME.toml" and the theme below -## should be the stem, i.e. `theme = "NAME"` for your chosen NAME. -# name = "autumn" - -## Whether the theme manager should output normal or extra information to help fix themes. -## Boolean, true or false. If unset, left up to the theme manager. -# debug = true - -[search] -## The list of enabled filter modes, in order of priority. -## The "workspace" mode is skipped when not in a workspace or workspaces = false. -## Default filter mode can be overridden with the filter_mode setting. -# filters = [ "global", "host", "session", "workspace", "directory" ] diff --git a/packages/zsh/dot-config/zsh/30-functions.zsh b/packages/zsh/dot-config/zsh/30-functions.zsh index 9f3c531..5254497 100644 --- a/packages/zsh/dot-config/zsh/30-functions.zsh +++ b/packages/zsh/dot-config/zsh/30-functions.zsh @@ -16,6 +16,10 @@ pdfunlock() { echo "usage: pdfunlock input.pdf [output.pdf]" >&2 return 2 fi + if ! command -v qpdf >/dev/null; then + echo "pdfunlock: needs qpdf (brew install qpdf)" >&2 + return 127 + fi local in="$1" local out="${2:-${1%.pdf}-unlocked.pdf}" local pw @@ -31,10 +35,14 @@ pdfunlock() { # Copy an image file to the macOS clipboard as PNG data (pasteable into Docs, Slack, etc.) imgcopy() { - if [ ! -f "$1" ]; then - echo "imgcopy: no such file: $1" >&2 - return 1 - fi - osascript -e "set the clipboard to (read (POSIX file \"$(realpath "$1")\") as «class PNGf»)" \ - && echo "copied: $1" + if ! command -v osascript >/dev/null; then + echo "imgcopy: needs osascript (macOS only)" >&2 + return 127 + fi + if [[ ! -f "$1" ]]; then + echo "imgcopy: no such file: $1" >&2 + return 1 + fi + osascript -e "set the clipboard to (read (POSIX file \"$(realpath "$1")\") as «class PNGf»)" \ + && echo "copied: $1" } diff --git a/packages/zsh/dot-config/zsh/40-tools.zsh b/packages/zsh/dot-config/zsh/40-tools.zsh index d645342..1e09857 100644 --- a/packages/zsh/dot-config/zsh/40-tools.zsh +++ b/packages/zsh/dot-config/zsh/40-tools.zsh @@ -2,6 +2,8 @@ command -v atuin >/dev/null && eval "$(atuin init zsh)" # nvm — node version manager (also provides npx for harness-configs tooling). +_nvm_dir="${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm" export NVM_DIR="$HOME/.nvm" -[ -s "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/nvm.sh" ] && \. "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/nvm.sh" -[ -s "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/etc/bash_completion.d/nvm" ] && \. "${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm/etc/bash_completion.d/nvm" +[ -s "$_nvm_dir/nvm.sh" ] && \. "$_nvm_dir/nvm.sh" +[ -s "$_nvm_dir/etc/bash_completion.d/nvm" ] && \. "$_nvm_dir/etc/bash_completion.d/nvm" +unset _nvm_dir From a9025edc1a54a1ce2760b607c6f383d7ddf9a33a Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:06:59 +0530 Subject: [PATCH 23/51] Trim README to minimal; keep machine-specific git details undocumented --- README.md | 53 ++++++++++++---------------------------------------- bootstrap.sh | 3 +-- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 52fe523..6697683 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # dotfiles macOS dotfiles managed with GNU stow, a curated Brewfile, and a one-shot bootstrap for new machines. -Pairs with the sibling [harness-configs](https://github.com/sanketsudake/harness-configs) repo, which owns all AI coding-harness config. +Pairs with the sibling [harness-configs](https://github.com/sanketsudake/harness-configs) repo, which owns all AI coding-harness config; `make harness-install` clones it and runs its installer. ## New Mac quick start @@ -10,10 +10,8 @@ curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootst bash /tmp/bootstrap.sh ``` -Download-then-run (rather than `curl | bash`) matters: casks can prompt for sudo, and a piped bash shares stdin with the script. -The script is idempotent: it installs Xcode CLT and Homebrew if missing, clones this repo to `~/personal/dotfiles`, runs `brew bundle`, moves any pre-existing real files at managed paths to a timestamped `~/.dotfiles-backup-*` dir, stows the packages, clones and installs harness-configs as a sibling, and finishes with `make doctor`. -Afterwards run the printed manual steps (`gh auth login`, `atuin login`, `git lfs install`, and for work remotes the `gh-qwiet` SSH host alias in `~/.ssh/config`) and open a new terminal. - +The script is idempotent: Xcode CLT and Homebrew if missing, clone to `~/personal/dotfiles`, `brew bundle`, stow links (pre-existing files are moved to a timestamped `~/.dotfiles-backup-*` dir), harness-configs, and `make doctor`. +Afterwards run the printed manual steps (`gh auth login`, `atuin login`, `git lfs install`) and open a new terminal. On an existing machine, clone the repo and run `make install`. ## Layout @@ -23,7 +21,7 @@ On an existing machine, clone the repo and run `make install`. | `packages/` | Stow packages, one directory per tool; only files here are ever stowed or committed | | `Brewfile` | Curated brew formulae, casks, and VS Code extensions | | `bootstrap.sh` | New-Mac entry point | -| `macos/defaults.sh` | macOS `defaults` capture (phase 2, empty placeholder) | +| `macos/defaults.sh` | macOS `defaults` capture (phase 2, currently a no-op) | | `scripts/doctor.sh` | Health checks behind `make doctor` | ## Make targets @@ -33,8 +31,8 @@ On an existing machine, clone the repo and run `make install`. | `install` | `brew-install` + `stow-link` + `harness-install` | | `uninstall` | Remove the stow symlinks | | `brew-install` / `brew-check` | Apply / verify the Brewfile | -| `brew-dump` | Regenerate `Brewfile.dump` (gitignored) to diff against the curated Brewfile | -| `stow-link` / `stow-unlink` | Create / remove symlinks (`--restow` makes link idempotent) | +| `brew-dump` | Regenerate gitignored `Brewfile.dump` to diff against the curated Brewfile | +| `stow-link` / `stow-unlink` | Create / remove symlinks (idempotent) | | `stow-adopt` | Absorb pre-existing real files into the working tree; always review `git diff` after | | `harness-install` | Clone harness-configs if missing, then run its `make install` | | `macos-apply` | Run `macos/defaults.sh` | @@ -42,32 +40,12 @@ On an existing machine, clone the repo and run `make install`. ## The stow model -Packages live under `packages/` and are stowed with `--dotfiles --no-folding` into `$HOME`. -`--dotfiles` maps `dot-zshrc` → `~/.zshrc`, so no hidden files exist in the repo (requires stow ≥ 2.4.0, enforced by `doctor`). -`--no-folding` is a security invariant, not a style choice: it links individual files instead of whole directories, so `~/.config/` stays a real directory. -That is what keeps `gh`'s `hosts.yml` (OAuth tokens) a plain local file that can never land in the repo — only `config.yml` is managed. +Packages are stowed from `packages/` into `$HOME` with `--dotfiles --no-folding` (stow ≥ 2.4.0, enforced by `doctor`). +`--dotfiles` maps `dot-zshrc` → `~/.zshrc`, so no hidden files exist in the repo. +`--no-folding` is a security invariant: it links individual files instead of whole directories, so `~/.config/` stays a real directory and credential files written beside managed configs (e.g. `gh`'s `hosts.yml`) can never land in the repo. Never add packages for credential-bearing dirs (`gcloud`, `1Password`, `op`, `github-copilot`). -## zsh structure - -`~/.zshrc` is a thin loader that sources `~/.config/zsh/*.zsh` in `NN-` prefix order. -Adding shell config means dropping a new numbered file into `packages/zsh/dot-config/zsh/` — no editing of `.zshrc` itself. -`~/.zprofile` only sets up `brew shellenv` (guarded for Apple Silicon and Intel paths). -Machine-local, uncommitted overrides go in `~/.config/zsh/90-local.zsh` (gitignored; see `90-local.zsh.example`). - -## Multi-identity git - -`packages/git/dot-gitconfig` selects identity by remote URL via `includeIf "hasconfig:remote.*.url:..."` blocks. -Personal repos get `~/.config/git/config-personal` (gmail); ShiftLeftSecurity/Harness remotes get `~/.config/git/config-qwiet`. -The work email in `config-qwiet` is an identity, not a credential, and is committed intentionally. -ShiftLeftSecurity remotes are additionally rewritten through a `gh-qwiet` SSH host alias, which must exist in `~/.ssh/config` (kept out of this repo; see the bootstrap manual steps). - -## harness-configs integration - -The two repos are siblings: this repo lives at `~/personal/dotfiles`, harness-configs at `~/personal/harness-configs` (override with `HARNESS_DIR=`). -`make harness-install` clones it if missing and runs its idempotent `make install`. -`packages/zsh/dot-config/zsh/50-harness.zsh` sources its `claude-multi-account.sh`, so the `pclaude`/`wclaude` wrappers exist in every interactive shell with no manual profile editing. -The Brewfile carries its prerequisites (`stow`, `jq`, `gh`, `nvm` for node/npx, `python@3.13`). +zsh follows the same drop-in idea: `~/.zshrc` is a thin loader sourcing `~/.config/zsh/*.zsh` in `NN-` prefix order, and machine-local uncommitted overrides go in `~/.config/zsh/90-local.zsh` (gitignored; see `90-local.zsh.example`). ## Adding a new tool config @@ -78,12 +56,5 @@ The Brewfile carries its prerequisites (`stow`, `jq`, `gh`, `nvm` for node/npx, ## Secrets policy Nothing outside `packages/` is ever stowed, and no package references a credential-bearing file. -`.gitignore` blocks `hosts.yml`, `.env*`, keys, and token-like names as a second layer (note it cannot protect already-tracked paths). -`make doctor` fails if any tracked filename matches a secret pattern, if tracked file content looks credential-like (token/key/password assignments, private-key blocks), or if a `~/.config` dir has become a symlink. -After `make stow-adopt`, always review `git diff` before committing — adopt imports live machine files into tracked paths, which is exactly how a stray exported token could enter the repo. -Review `git diff --cached` before every commit regardless. - -## macOS defaults (phase 2) - -`macos/defaults.sh` is the landing spot for `defaults write` capture (Dock, Finder, keyboard, trackpad, screenshots), applied via `make macos-apply`. -It is currently an intentional no-op. +`.gitignore` blocks secret-like filenames as a second layer, and `make doctor` fails on secret-pattern filenames, credential-looking content in tracked files, or a `~/.config` dir that has become a symlink. +`stow-adopt` imports live machine files into tracked paths, so always review `git diff` before committing after it. diff --git a/bootstrap.sh b/bootstrap.sh index a5a352e..1e0e122 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -89,7 +89,6 @@ Bootstrap complete. Manual steps that need your credentials: 1. gh auth login 2. atuin login (history sync) 3. git lfs install - 4. Work remotes only: add the gh-qwiet host alias to ~/.ssh/config - (the gitconfig rewrites ShiftLeftSecurity remotes through it). + 4. Restore any machine-private ~/.ssh/config entries (host aliases, keys). 5. Open a new terminal so zsh picks up the managed config. EOF From d59d2fd509f01e7b50846bfcdd9ec14aa69f4f8b Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:30:13 +0530 Subject: [PATCH 24/51] Track App Store apps and adopted direct-download casks in Brewfile Adds mas (+ entries for Numbers, 1Password for Safari, Okta Verify) and casks for the previously direct-download apps, adopted in place with brew install --cask --adopt. MDM-managed work apps stay unmanaged. tailscale-app and openvpn-connect are pkg casks needing interactive sudo: run make cask-adopt once to finish adoption. --- Brewfile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Brewfile b/Brewfile index 321f8db..3749cd9 100644 --- a/Brewfile +++ b/Brewfile @@ -30,6 +30,7 @@ brew "jq" brew "gh" brew "nvm" # provides node/npx for harness-configs skill tooling brew "python@3.13" +brew "mas" # Mac App Store CLI (for the mas entries below) # --- shell & everyday tools -------------------------------------------------- brew "atuin" @@ -88,6 +89,15 @@ brew "herdr" brew "openclaw/tap/gitcrawl" # --- casks ------------------------------------------------------------------- +# Previously direct-download apps, adopted into brew management (make cask-adopt). +cask "1password" +cask "claude" +cask "devin-desktop" +cask "google-chrome" +cask "openvpn-connect" +cask "tailscale-app" +cask "wispr-flow" + cask "1password-cli" cask "claude-code@latest" cask "copilot-cli" @@ -106,6 +116,11 @@ cask "sanketsudake/tap/cc-proxy", trusted: true cask "sanketsudake/tap/chrome-cdp", trusted: true cask "sanketsudake/tap/portless", trusted: true +# --- App Store apps (need App Store sign-in on a new Mac) -------------------- +mas "1Password for Safari", id: 1569813296 +mas "Numbers", id: 361304891 +mas "Okta Verify", id: 490179405 + # --- vscode extensions ------------------------------------------------------- vscode "adpyke.vscode-sql-formatter" vscode "anthropic.claude-code" From ff14b264983164f683298b3b1d0cf65d6ca1d668 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:30:13 +0530 Subject: [PATCH 25/51] Capture non-brew tools: go, npm-global, and pipx manifests manifests/*.txt track curated tool lists (accidental go install ./... artifacts excluded); go-install/npm-install/pipx-install apply them and tools-install joins the install aggregate. cask-adopt takes over apps installed outside brew. --- Makefile | 33 +++++++++++++++++++++++++++++-- manifests/go-tools.txt | 41 +++++++++++++++++++++++++++++++++++++++ manifests/npm-globals.txt | 4 ++++ manifests/pipx-tools.txt | 2 ++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 manifests/go-tools.txt create mode 100644 manifests/npm-globals.txt create mode 100644 manifests/pipx-tools.txt diff --git a/Makefile b/Makefile index c7458ac..f55960a 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,16 @@ HARNESS_DIR ?= $(abspath $(CURDIR)/../harness-configs) HARNESS_REPO := git@github.com:sanketsudake/harness-configs.git HARNESS_REPO_HTTPS := https://github.com/sanketsudake/harness-configs.git +MANIFESTS := $(CURDIR)/manifests + .PHONY: install uninstall doctor \ - brew-install brew-check brew-dump \ + brew-install brew-check brew-dump cask-adopt \ + go-install npm-install pipx-install tools-install \ stow-link stow-unlink stow-adopt \ harness-clone harness-install \ macos-apply -install: brew-install stow-link harness-install +install: brew-install stow-link tools-install harness-install uninstall: stow-unlink @@ -32,6 +35,32 @@ brew-dump: brew bundle dump --file=$(CURDIR)/Brewfile.dump --describe --force @echo "wrote Brewfile.dump — diff against Brewfile to re-curate" +# Take over apps that were installed outside brew (pkg-based casks prompt for sudo). +cask-adopt: + brew install --cask --adopt 1password claude devin-desktop google-chrome \ + openvpn-connect tailscale-app wispr-flow + +tools-install: go-install npm-install pipx-install + +# Installs each module from manifests/go-tools.txt; lines without @version get @latest. +go-install: + @command -v go >/dev/null || { echo "go not found — run: make brew-install"; exit 1; } + @grep -vE '^[[:space:]]*#|^[[:space:]]*$$' $(MANIFESTS)/go-tools.txt | while read -r mod; do \ + case "$$mod" in *@*) ;; *) mod="$$mod@latest" ;; esac; \ + echo "go install $$mod"; \ + go install "$$mod"; \ + done + +npm-install: + @command -v npm >/dev/null || { echo "npm not found — run: nvm install --lts"; exit 1; } + @grep -vE '^[[:space:]]*#|^[[:space:]]*$$' $(MANIFESTS)/npm-globals.txt | xargs npm install -g + +pipx-install: + @command -v pipx >/dev/null || { echo "pipx not found — run: make brew-install"; exit 1; } + @grep -vE '^[[:space:]]*#|^[[:space:]]*$$' $(MANIFESTS)/pipx-tools.txt | while read -r pkg; do \ + pipx install "$$pkg"; \ + done + stow-link: $(STOW) $(STOW_FLAGS) --restow $(PACKAGES) diff --git a/manifests/go-tools.txt b/manifests/go-tools.txt new file mode 100644 index 0000000..0409c69 --- /dev/null +++ b/manifests/go-tools.txt @@ -0,0 +1,41 @@ +# Go tools installed to ~/go/bin via `make go-install` (go install @latest). +# Lines may pin a version with module@vX.Y.Z; default is @latest. +# Curated deliberately — accidental `go install ./...` artifacts are not tracked. + +# debugging & language server +github.com/go-delve/delve/cmd/dlv +golang.org/x/tools/gopls + +# code generation & scaffolding +golang.org/x/tools/cmd/goimports +golang.org/x/tools/cmd/stringer +github.com/josharian/impl +github.com/cweill/gotests/gotests +github.com/vektra/mockery/v3 + +# testing +gotest.tools/gotestsum +chipaca.com/goctest +github.com/t-yuki/gocover-cobertura + +# analysis & linting +honnef.co/go/tools/cmd/staticcheck +golang.org/x/tools/cmd/deadcode +golang.org/x/vuln/cmd/govulncheck +github.com/ashanbrown/makezero/v2 +chipaca.com/gofomash + +# supply chain & licensing +github.com/google/go-licenses +github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier + +# protobuf +google.golang.org/protobuf/cmd/protoc-gen-go +google.golang.org/grpc/cmd/protoc-gen-go-grpc +github.com/ckaznocha/protoc-gen-lint +github.com/favadi/protoc-go-inject-tag + +# kubernetes & misc +sigs.k8s.io/controller-runtime/tools/setup-envtest +github.com/grafana/dashboard-linter +github.com/darccio/diffty/cmd/diffty diff --git a/manifests/npm-globals.txt b/manifests/npm-globals.txt new file mode 100644 index 0000000..501890b --- /dev/null +++ b/manifests/npm-globals.txt @@ -0,0 +1,4 @@ +# npm packages installed globally (into the active nvm node) via `make npm-install`. +@readwise/cli +@tobilu/qmd +corepack diff --git a/manifests/pipx-tools.txt b/manifests/pipx-tools.txt new file mode 100644 index 0000000..228e2f8 --- /dev/null +++ b/manifests/pipx-tools.txt @@ -0,0 +1,2 @@ +# Python CLI tools installed in isolated envs via `make pipx-install`. +evernote-backup From 3f72b46f3baf2a30d833905820b6b62a2621f60f Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:30:13 +0530 Subject: [PATCH 26/51] Capture live macOS defaults: dark mode, Finder list view, tap to click Only deliberately-changed settings are recorded so stock defaults can evolve without this file fighting them; make macos-apply is idempotent. --- README.md | 9 ++++++--- macos/defaults.sh | 30 ++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 6697683..beb31c0 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,19 @@ On an existing machine, clone the repo and run `make install`. | Path | Purpose | |---|---| | `packages/` | Stow packages, one directory per tool; only files here are ever stowed or committed | -| `Brewfile` | Curated brew formulae, casks, and VS Code extensions | +| `Brewfile` | Curated brew formulae, casks, App Store apps (mas), and VS Code extensions | +| `manifests/` | Non-brew tools: `go-tools.txt`, `npm-globals.txt`, `pipx-tools.txt` | | `bootstrap.sh` | New-Mac entry point | -| `macos/defaults.sh` | macOS `defaults` capture (phase 2, currently a no-op) | +| `macos/defaults.sh` | Deliberately-changed macOS settings, applied via `make macos-apply` | | `scripts/doctor.sh` | Health checks behind `make doctor` | ## Make targets | Target | Does | |---|---| -| `install` | `brew-install` + `stow-link` + `harness-install` | +| `install` | `brew-install` + `stow-link` + `tools-install` + `harness-install` | +| `tools-install` | `go-install` + `npm-install` + `pipx-install` from `manifests/` | +| `cask-adopt` | Take over apps installed outside brew (pkg casks prompt for sudo) | | `uninstall` | Remove the stow symlinks | | `brew-install` / `brew-check` | Apply / verify the Brewfile | | `brew-dump` | Regenerate gitignored `Brewfile.dump` to diff against the curated Brewfile | diff --git a/macos/defaults.sh b/macos/defaults.sh index e217b92..911587f 100755 --- a/macos/defaults.sh +++ b/macos/defaults.sh @@ -1,9 +1,27 @@ #!/usr/bin/env bash -# macOS system preferences as code (defaults write ...). -# Phase 2 of the dotfiles revamp — settings not yet captured. -# When populated: group by domain (Dock, Finder, keyboard, trackpad, screenshots), -# make every write idempotent, and end with `killall Dock Finder SystemUIServer` -# as needed. Apply with `make macos-apply`. +# macOS system preferences as code, captured from the live machine on 2026-08-03. +# Only deliberately-changed settings are recorded — stock defaults are not +# restated, so Apple's defaults can evolve without this file fighting them. +# Apply with `make macos-apply`; idempotent. Grouped by domain; append new +# settings to the matching group and re-run. set -euo pipefail -echo "macos/defaults.sh: no settings captured yet (phase 2) — nothing to apply." +echo "Applying macOS defaults..." + +# --- appearance -------------------------------------------------------------- +# Dark mode (fully applies to running apps after re-login). +defaults write NSGlobalDomain AppleInterfaceStyle -string "Dark" + +# --- finder ------------------------------------------------------------------ +# List view in all Finder windows by default. +defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv" + +# --- trackpad ---------------------------------------------------------------- +# Tap to click (built-in + bluetooth trackpads, and the per-host mouse behavior). +defaults write com.apple.AppleMultitouchTrackpad Clicking -bool true +defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true +defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 + +# --- apply ------------------------------------------------------------------- +killall Finder 2>/dev/null || true +echo "Done. Some settings (appearance) fully apply after re-login." From 904ecefae52239d527b139637d4f9ee9f73e72be Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:39:31 +0530 Subject: [PATCH 27/51] Drop unused atlassian/acli tap (untrusted under Homebrew 6 tap trust) --- Brewfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Brewfile b/Brewfile index 3749cd9..84368ea 100644 --- a/Brewfile +++ b/Brewfile @@ -5,7 +5,6 @@ # by go install / nvm, not brew). # --- taps ------------------------------------------------------------------- -tap "atlassian/acli" tap "jesseduffield/lazydocker", trusted: true tap "loft-sh/tap", trusted: true tap "minio/stable", trusted: true From 5ca1f5b7a9bc63c636a5cf721eba9007e227d4f5 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 17:42:23 +0530 Subject: [PATCH 28/51] doctor: warn instead of fail when only mas entries are unmet but apps exist mas depends on the Spotlight index, which can lag or go stale for /Applications; verify App Store apps on disk before failing. --- scripts/doctor.sh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/doctor.sh b/scripts/doctor.sh index f495f52..7b690e4 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -36,7 +36,20 @@ echo "== brew bundle ==" if brew bundle check --file="$REPO_DIR/Brewfile" >/dev/null 2>&1; then ok "Brewfile satisfied" else - bad "Brewfile unsatisfied — run: make brew-install" + # mas relies on the Spotlight index, which can lag or go stale; if the only + # unmet entries are App Store apps that exist on disk, that's a warning. + unmet="$(brew bundle check --verbose --file="$REPO_DIR/Brewfile" 2>&1 | grep '^→' || true)" + non_mas="$(printf '%s\n' "$unmet" | grep -v '^→ App ' || true)" + missing_apps="" + while IFS= read -r line; do + app="${line#→ App }"; app="${app% needs to be installed or updated.}" + [ -d "/Applications/$app.app" ] || missing_apps="$missing_apps $app" + done < <(printf '%s\n' "$unmet" | grep '^→ App ' || true) + if [ -z "$non_mas" ] && [ -z "$missing_apps" ]; then + warn "Brewfile mas entries unmet only per Spotlight index; all apps present on disk" + else + bad "Brewfile unsatisfied — run: make brew-install"$'\n'"$unmet" + fi fi echo "== symlinks ==" From 25f071dd2680e2bde6e97beec7b2ae35fa58a011 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 18:28:36 +0530 Subject: [PATCH 29/51] Add modern CLI, k8s tooling, zsh plugins, and raycast to Brewfile CLI: fzf, zoxide, eza, bat, fd, git-delta, yq, jless, dust, lazygit. k8s: kubectx, kubecolor, dive, trivy, dyff, viddy, kubeconform. Shell: zsh-autosuggestions, zsh-syntax-highlighting. Cask: raycast. --- Brewfile | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Brewfile b/Brewfile index 84368ea..159fd78 100644 --- a/Brewfile +++ b/Brewfile @@ -39,6 +39,20 @@ brew "pandoc" brew "poppler" brew "qpdf" # pdfunlock() brew "git-lfs" +brew "zsh-autosuggestions" # ghost-text next-command suggestion from history +brew "zsh-syntax-highlighting" # invalid commands go red before you hit enter + +# --- modern CLI -------------------------------------------------------------- +brew "fzf" # fuzzy pickers + Ctrl-T/Alt-C (Ctrl-R stays with atuin) +brew "zoxide" # frecency-ranked cd (z ) +brew "eza" # ls with git status column (ll alias) +brew "bat" # syntax-highlighted cat with git gutter +brew "fd" # gitignore-aware find +brew "git-delta" # readable side-by-side git diffs (wired in gitconfig) +brew "yq" # jq for YAML/TOML/XML +brew "jless" # interactive JSON pager +brew "dust" # visual du +brew "lazygit" # git TUI (same author as lazydocker) # --- languages & build ------------------------------------------------------- brew "go" @@ -72,6 +86,13 @@ brew "skopeo" brew "stern" brew "k6" brew "mkcert" +brew "kubectx" # kubectx + kubens; fuzzy pickers with fzf installed +brew "kubecolor" # colorized kubectl output (aliased to kubectl) +brew "dive" # layer-by-layer container image explorer +brew "trivy" # CVE/misconfig scanner for images, IaC, clusters +brew "dyff" # YAML-aware structural diff (helm/k8s manifests) +brew "viddy" # modern watch with diff highlighting + time travel +brew "kubeconform" # fast k8s manifest schema validation brew "jesseduffield/lazydocker/lazydocker" brew "loft-sh/tap/vcluster" brew "minio/stable/mc" @@ -108,6 +129,7 @@ cask "insomnia" cask "itsycal" cask "obsidian" cask "postman" +cask "raycast" # launcher + clipboard history + window snapping + extensions cask "slack" cask "visual-studio-code" cask "zoom" From f37a7159b52d0e05d2a91deb7f0f46f764b90acd Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 18:28:36 +0530 Subject: [PATCH 30/51] Wire new tools into zsh modules and gitconfig 35-fzf.zsh loads before 40-tools.zsh so atuin keeps Ctrl-R; fzf owns Ctrl-T/Alt-C with fd as the source. zoxide + autosuggestions join 40-tools; syntax highlighting sources last as 95. kubectl aliases to kubecolor (completions preserved); delta becomes the git pager with zdiff3 conflict style. --- packages/git/dot-gitconfig | 8 ++++++++ packages/zsh/dot-config/zsh/20-aliases.zsh | 6 ++++++ packages/zsh/dot-config/zsh/35-fzf.zsh | 6 ++++++ packages/zsh/dot-config/zsh/40-tools.zsh | 10 +++++++++- packages/zsh/dot-config/zsh/95-syntax-highlighting.zsh | 5 +++++ 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 packages/zsh/dot-config/zsh/35-fzf.zsh create mode 100644 packages/zsh/dot-config/zsh/95-syntax-highlighting.zsh diff --git a/packages/git/dot-gitconfig b/packages/git/dot-gitconfig index 0c56d94..977fde5 100644 --- a/packages/git/dot-gitconfig +++ b/packages/git/dot-gitconfig @@ -3,6 +3,14 @@ smudge = git-lfs smudge -- %f process = git-lfs filter-process required = true +[core] + pager = delta +[interactive] + diffFilter = delta --color-only +[delta] + navigate = true +[merge] + conflictStyle = zdiff3 [url "ssh://git@github.com/"] insteadOf = https://github.com/ [includeIf "hasconfig:remote.*.url:git@github.com:*/**"] diff --git a/packages/zsh/dot-config/zsh/20-aliases.zsh b/packages/zsh/dot-config/zsh/20-aliases.zsh index 5461225..9fb2ed5 100644 --- a/packages/zsh/dot-config/zsh/20-aliases.zsh +++ b/packages/zsh/dot-config/zsh/20-aliases.zsh @@ -3,3 +3,9 @@ && alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale" [ -x "$HOME/chrome-doctor.sh" ] \ && alias chrome-doctor="$HOME/chrome-doctor.sh" +if command -v kubecolor >/dev/null; then + alias kubectl=kubecolor + compdef kubecolor=kubectl 2>/dev/null +fi +command -v eza >/dev/null && alias ll='eza -l --git' +command -v lazygit >/dev/null && alias lg=lazygit diff --git a/packages/zsh/dot-config/zsh/35-fzf.zsh b/packages/zsh/dot-config/zsh/35-fzf.zsh new file mode 100644 index 0000000..b8e6171 --- /dev/null +++ b/packages/zsh/dot-config/zsh/35-fzf.zsh @@ -0,0 +1,6 @@ +# fzf keybindings + completion (Ctrl-T files, Alt-C cd, ** tab-completion). +# Numbered BEFORE 40-tools.zsh on purpose: fzf binds Ctrl-R here, then atuin +# (loaded later) rebinds it, so history search stays with atuin. +command -v fzf >/dev/null && eval "$(fzf --zsh)" +export FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git 2>/dev/null || find . -type f' +export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND" diff --git a/packages/zsh/dot-config/zsh/40-tools.zsh b/packages/zsh/dot-config/zsh/40-tools.zsh index 1e09857..f8de175 100644 --- a/packages/zsh/dot-config/zsh/40-tools.zsh +++ b/packages/zsh/dot-config/zsh/40-tools.zsh @@ -1,6 +1,14 @@ -# atuin — shell history sync/search. +# atuin — shell history sync/search (binds Ctrl-R after fzf in 35-fzf.zsh). command -v atuin >/dev/null && eval "$(atuin init zsh)" +# zoxide — frecency-ranked cd (z , zi interactive). +command -v zoxide >/dev/null && eval "$(zoxide init zsh)" + +# zsh-autosuggestions — ghost-text next-command suggestion, accept with right arrow. +_zsh_autosuggest="${HOMEBREW_PREFIX:-/opt/homebrew}/share/zsh-autosuggestions/zsh-autosuggestions.zsh" +[ -r "$_zsh_autosuggest" ] && source "$_zsh_autosuggest" +unset _zsh_autosuggest + # nvm — node version manager (also provides npx for harness-configs tooling). _nvm_dir="${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm" export NVM_DIR="$HOME/.nvm" diff --git a/packages/zsh/dot-config/zsh/95-syntax-highlighting.zsh b/packages/zsh/dot-config/zsh/95-syntax-highlighting.zsh new file mode 100644 index 0000000..59d2a8a --- /dev/null +++ b/packages/zsh/dot-config/zsh/95-syntax-highlighting.zsh @@ -0,0 +1,5 @@ +# zsh-syntax-highlighting must be sourced after all other plugins and widgets — +# hence the highest module number (after the gitignored 90-local.zsh too). +_zsh_hl="${HOMEBREW_PREFIX:-/opt/homebrew}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" +[ -r "$_zsh_hl" ] && source "$_zsh_hl" +unset _zsh_hl From 23fcd2f13b78130627dff605cf84f388e849a47a Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 18:28:36 +0530 Subject: [PATCH 31/51] Add make drift: two-way divergence report for recorded vs live config Compares Brewfile (via normalized brew bundle dump), go/npm/pipx manifests, and macos/defaults.sh recorded values against the live system, printing the reconcile command per finding; exit 1 on drift. mas entries lagged by the Spotlight index stay warnings. doctor gains a broken-symlink sweep (warn-only) of ~ to depth 3. --- Makefile | 5 +- README.md | 1 + scripts/doctor.sh | 8 +++ scripts/drift.sh | 142 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 scripts/drift.sh diff --git a/Makefile b/Makefile index f55960a..471a978 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ MANIFESTS := $(CURDIR)/manifests go-install npm-install pipx-install tools-install \ stow-link stow-unlink stow-adopt \ harness-clone harness-install \ - macos-apply + macos-apply drift install: brew-install stow-link tools-install harness-install @@ -91,3 +91,6 @@ macos-apply: doctor: bash $(CURDIR)/scripts/doctor.sh + +drift: + bash $(CURDIR)/scripts/drift.sh diff --git a/README.md b/README.md index beb31c0..f6bbffa 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ On an existing machine, clone the repo and run `make install`. | `harness-install` | Clone harness-configs if missing, then run its `make install` | | `macos-apply` | Run `macos/defaults.sh` | | `doctor` | Run all health checks | +| `drift` | Report divergence between recorded config and the live system, both directions, with the reconcile command per finding | ## The stow model diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 7b690e4..65ac13d 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -95,6 +95,14 @@ else bad "credential-looking content in tracked files:"$'\n'"$content_leaks" fi +echo "== broken symlinks ==" +broken="$(find "$HOME" -maxdepth 3 -type l ! -exec test -e {} \; -print 2>/dev/null || true)" +if [ -z "$broken" ]; then + ok "no broken symlinks in ~ (depth 3)" +else + warn "broken symlinks (stale stow links or removed targets):"$'\n'"$(printf '%s\n' "$broken" | sed 's/^/ /')" +fi + echo "== harness-configs ==" if [ -d "$HARNESS_DIR/.git" ]; then ok "repo present at $HARNESS_DIR" diff --git a/scripts/drift.sh b/scripts/drift.sh new file mode 100644 index 0000000..8785005 --- /dev/null +++ b/scripts/drift.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +# Drift report: recorded configuration (Brewfile, manifests/, macos/defaults.sh) +# vs the live system, in both directions. Prints the reconcile command for every +# finding. Exit 1 if any drift; Spotlight-lagged mas entries are warnings only. +set -uo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +DRIFT=0 + +ok() { printf ' ok: %s\n' "$*"; } +warn() { printf ' warn: %s\n' "$*"; } +drift() { printf 'DRIFT: %s\n' "$*"; DRIFT=1; } + +manifest_entries() { grep -vE '^[[:space:]]*#|^[[:space:]]*$' "$1"; } + +# Normalize a Brewfile-ish file to sorted "kind name" pairs. Only kinds we +# curate; brew-6 dump also emits go/npm lines, which our manifests own. +normalize_bundle() { + awk ' + /^(tap|brew|cask|mas|vscode) / { + kind=$1; name=$2 + gsub(/[",]/, "", name) + print kind, name + } + ' "$1" | sort -u +} + +echo "== brew (formulae, casks, taps, mas, vscode) ==" +dump="$(mktemp)" +trap 'rm -f "$dump"' EXIT +if brew bundle dump --file="$dump" --force >/dev/null 2>&1; then + declared="$(normalize_bundle "$REPO_DIR/Brewfile")" + installed="$(normalize_bundle "$dump")" + missing="$(comm -23 <(printf '%s\n' "$declared") <(printf '%s\n' "$installed"))" + extra="$(comm -13 <(printf '%s\n' "$declared") <(printf '%s\n' "$installed"))" + # mas can't see App Store apps when the Spotlight index lags; if the app + # bundle exists on disk, downgrade declared-but-missing mas rows to warnings. + if [ -n "$missing" ]; then + real_missing="" + while IFS= read -r row; do + [ -z "$row" ] && continue + kind="${row%% *}"; name="${row#* }" + if [ "$kind" = "mas" ]; then + app_line="$(grep -E "^mas \"[^\"]+\", id: .*$" "$REPO_DIR/Brewfile" | grep -F "$name" || true)" + app_name="$(printf '%s' "$app_line" | sed -E 's/^mas "([^"]+)".*/\1/')" + if [ -n "$app_name" ] && [ -d "/Applications/$app_name.app" ]; then + warn "mas $app_name unmet only per Spotlight index; app present on disk" + continue + fi + fi + real_missing="$real_missing$row"$'\n' + done <<< "$missing" + missing="$(printf '%s' "$real_missing")" + fi + if [ -n "$missing" ]; then + drift "declared but not installed — run: make brew-install"$'\n'"$(printf '%s\n' "$missing" | sed 's/^/ /')" + fi + if [ -n "$extra" ]; then + drift "installed but not in Brewfile — add there, or brew uninstall / brew untap:"$'\n'"$(printf '%s\n' "$extra" | sed 's/^/ /')" + fi + [ -z "$missing" ] && [ -z "$extra" ] && ok "Brewfile matches installed state" +else + drift "brew bundle dump failed — is brew healthy?" +fi + +echo "== go tools (manifests/go-tools.txt vs ~/go/bin) ==" +declared_bins="$(manifest_entries "$REPO_DIR/manifests/go-tools.txt" | while read -r mod; do + mod="${mod%@*}" + bin="${mod##*/}" + case "$bin" in v[0-9]*) mod="${mod%/*}"; bin="${mod##*/}" ;; esac + printf '%s\n' "$bin" +done | sort -u)" +installed_bins="$(ls "$HOME/go/bin" 2>/dev/null | sort -u || true)" +go_missing="$(comm -23 <(printf '%s\n' "$declared_bins") <(printf '%s\n' "$installed_bins"))" +go_extra="$(comm -13 <(printf '%s\n' "$declared_bins") <(printf '%s\n' "$installed_bins"))" +[ -n "$go_missing" ] && drift "manifest tools missing from ~/go/bin — run: make go-install"$'\n'"$(printf '%s\n' "$go_missing" | sed 's/^/ /')" +[ -n "$go_extra" ] && drift "~/go/bin binaries not in the manifest — add there, or rm ~/go/bin/:"$'\n'"$(printf '%s\n' "$go_extra" | sed 's/^/ /')" +[ -z "$go_missing" ] && [ -z "$go_extra" ] && ok "go tools match manifest" + +echo "== npm globals (manifests/npm-globals.txt) ==" +if command -v npm >/dev/null; then + declared_npm="$(manifest_entries "$REPO_DIR/manifests/npm-globals.txt" | sort -u)" + installed_npm="$(npm ls -g --depth=0 --json 2>/dev/null | jq -r '.dependencies | keys[]' 2>/dev/null | grep -vx npm | sort -u || true)" + npm_missing="$(comm -23 <(printf '%s\n' "$declared_npm") <(printf '%s\n' "$installed_npm"))" + npm_extra="$(comm -13 <(printf '%s\n' "$declared_npm") <(printf '%s\n' "$installed_npm"))" + [ -n "$npm_missing" ] && drift "manifest npm globals missing — run: make npm-install"$'\n'"$(printf '%s\n' "$npm_missing" | sed 's/^/ /')" + [ -n "$npm_extra" ] && drift "npm globals not in manifest — add there, or npm uninstall -g :"$'\n'"$(printf '%s\n' "$npm_extra" | sed 's/^/ /')" + [ -z "$npm_missing" ] && [ -z "$npm_extra" ] && ok "npm globals match manifest" +else + warn "npm not on PATH — skipping (nvm not loaded in this shell?)" +fi + +echo "== pipx (manifests/pipx-tools.txt) ==" +if command -v pipx >/dev/null; then + declared_pipx="$(manifest_entries "$REPO_DIR/manifests/pipx-tools.txt" | sort -u)" + installed_pipx="$(pipx list --short 2>/dev/null | awk '{print $1}' | sort -u || true)" + pipx_missing="$(comm -23 <(printf '%s\n' "$declared_pipx") <(printf '%s\n' "$installed_pipx"))" + pipx_extra="$(comm -13 <(printf '%s\n' "$declared_pipx") <(printf '%s\n' "$installed_pipx"))" + [ -n "$pipx_missing" ] && drift "manifest pipx tools missing — run: make pipx-install"$'\n'"$(printf '%s\n' "$pipx_missing" | sed 's/^/ /')" + [ -n "$pipx_extra" ] && drift "pipx tools not in manifest — add there, or pipx uninstall :"$'\n'"$(printf '%s\n' "$pipx_extra" | sed 's/^/ /')" + [ -z "$pipx_missing" ] && [ -z "$pipx_extra" ] && ok "pipx tools match manifest" +else + warn "pipx not on PATH — skipping" +fi + +echo "== macOS defaults (macos/defaults.sh vs live) ==" +defaults_drift=0 +# Parse each `defaults [-currentHost] write - ` line +# and compare with the live value. Booleans normalize to 1/0. +while IFS= read -r line; do + line="${line#"${line%%[![:space:]]*}"}" + host_flag="" + rest="${line#defaults }" + case "$rest" in + -currentHost\ write\ *) host_flag="-currentHost"; rest="${rest#-currentHost write }" ;; + write\ *) rest="${rest#write }" ;; + *) continue ;; + esac + domain="${rest%% *}"; rest="${rest#* }" + key="${rest%% *}"; rest="${rest#* }" + rest="${rest# }" + value="${rest#-* }" + value="${value%\"}"; value="${value#\"}" + case "$value" in + true) value=1 ;; + false) value=0 ;; + esac + live="$(defaults $host_flag read "$domain" "$key" 2>/dev/null || echo '')" + if [ "$live" != "$value" ]; then + drift "$domain $key: recorded '$value', live '$live' — update macos/defaults.sh, or run: make macos-apply" + defaults_drift=1 + fi +done < <(grep -E '^[[:space:]]*defaults (-currentHost )?write ' "$REPO_DIR/macos/defaults.sh") +[ "$defaults_drift" -eq 0 ] && ok "recorded defaults match live values" + +echo "" +if [ "$DRIFT" -eq 0 ]; then + echo "drift: system matches recorded configuration" +else + echo "drift: DIVERGENCES above — reconcile in whichever direction is right" +fi +exit "$DRIFT" From 5afb574a785c25d1a6226f489a0463539ad16275 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 18:47:06 +0530 Subject: [PATCH 32/51] Add raycast-export target; keep .rayconfig exports out of the repo Raycast stores settings in an encrypted local DB and extension configs can hold API tokens, so backup goes through its own encrypted export to a private location rather than this repo. --- .gitignore | 1 + Makefile | 10 +++++++++- README.md | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 27118a7..4b422e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Secret-safety net — none of these should ever be committed. hosts.yml +*.rayconfig .env .env.* *.pem diff --git a/Makefile b/Makefile index 471a978..c9c6ac2 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ MANIFESTS := $(CURDIR)/manifests go-install npm-install pipx-install tools-install \ stow-link stow-unlink stow-adopt \ harness-clone harness-install \ - macos-apply drift + macos-apply drift raycast-export install: brew-install stow-link tools-install harness-install @@ -94,3 +94,11 @@ doctor: drift: bash $(CURDIR)/scripts/drift.sh + +# Raycast keeps settings in an encrypted local DB (extension configs can hold +# API tokens), so its own encrypted export is the backup mechanism — never this +# repo (*.rayconfig is gitignored). Opens the export dialog; save the file to a +# private location (iCloud Drive / 1Password). Restore on a new Mac via +# Raycast Settings -> Advanced -> Import. +raycast-export: + open "raycast://extensions/raycast/raycast/export-settings-data" diff --git a/README.md b/README.md index f6bbffa..e48445e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ On an existing machine, clone the repo and run `make install`. | `macos-apply` | Run `macos/defaults.sh` | | `doctor` | Run all health checks | | `drift` | Report divergence between recorded config and the live system, both directions, with the reconcile command per finding | +| `raycast-export` | Open Raycast's encrypted settings export; save the file privately (never committed — `*.rayconfig` is gitignored) | ## The stow model From 3df95e177a4e01d56bc6817152566d1ac105cc7e Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 19:04:57 +0530 Subject: [PATCH 33/51] Point bootstrap URLs at main after default-branch rename --- README.md | 2 +- bootstrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e48445e..2ba4380 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Pairs with the sibling [harness-configs](https://github.com/sanketsudake/harness ## New Mac quick start ```sh -curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh -o /tmp/bootstrap.sh +curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/main/bootstrap.sh -o /tmp/bootstrap.sh bash /tmp/bootstrap.sh ``` diff --git a/bootstrap.sh b/bootstrap.sh index 1e0e122..e863158 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -4,7 +4,7 @@ # # Preferred invocation (casks may prompt for sudo, which clashes with curl|bash # sharing stdin with the script): -# curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/master/bootstrap.sh -o /tmp/bootstrap.sh +# curl -fsSL https://raw.githubusercontent.com/sanketsudake/dotfiles/main/bootstrap.sh -o /tmp/bootstrap.sh # bash /tmp/bootstrap.sh set -euo pipefail From de57a32df0bfdcb7fcdc2a2a9029219fc90d6f48 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 19:27:04 +0530 Subject: [PATCH 34/51] Expand macOS defaults: keyboard, Finder, screenshots, Dock, dialogs Fast key repeat + hold-to-repeat; Finder shows extensions/pathbar/status bar without extension-change warnings and stops writing .DS_Store to network/USB volumes; screenshots land in ~/Screenshots without window shadows; Dock autohides with no recents and stable Spaces order; save and print dialogs open expanded and save locally. drift.sh learns to expand $HOME when comparing recorded values. --- macos/defaults.sh | 42 ++++++++++++++++++++++++++++++++++++++++-- scripts/drift.sh | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/macos/defaults.sh b/macos/defaults.sh index 911587f..d00b1f3 100755 --- a/macos/defaults.sh +++ b/macos/defaults.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# macOS system preferences as code, captured from the live machine on 2026-08-03. +# macOS system preferences as code, captured from the live machine (expanded 2026-08-03). # Only deliberately-changed settings are recorded — stock defaults are not # restated, so Apple's defaults can evolve without this file fighting them. # Apply with `make macos-apply`; idempotent. Grouped by domain; append new @@ -12,9 +12,45 @@ echo "Applying macOS defaults..." # Dark mode (fully applies to running apps after re-login). defaults write NSGlobalDomain AppleInterfaceStyle -string "Dark" +# --- keyboard ---------------------------------------------------------------- +# Fast key repeat (values below the Settings UI minimum; re-login to fully apply). +defaults write NSGlobalDomain KeyRepeat -int 2 +defaults write NSGlobalDomain InitialKeyRepeat -int 15 +# Holding a key repeats it instead of opening the accent picker. +defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false + # --- finder ------------------------------------------------------------------ # List view in all Finder windows by default. defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv" +# Show all filename extensions, the path bar, and the status bar. +defaults write NSGlobalDomain AppleShowAllExtensions -bool true +defaults write com.apple.finder ShowPathbar -bool true +defaults write com.apple.finder ShowStatusBar -bool true +# No warning when changing a file extension. +defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false +# Don't litter network shares and USB volumes with .DS_Store files. +defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true +defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true + +# --- screenshots ------------------------------------------------------------- +# Save to ~/Screenshots (created here) without the window drop shadow. +mkdir -p "$HOME/Screenshots" +defaults write com.apple.screencapture location -string "$HOME/Screenshots" +defaults write com.apple.screencapture disable-shadow -bool true + +# --- dock & spaces ----------------------------------------------------------- +# Auto-hide the Dock, no recent apps section, and Spaces keep their order. +defaults write com.apple.dock autohide -bool true +defaults write com.apple.dock show-recents -bool false +defaults write com.apple.dock mru-spaces -bool false + +# --- dialogs ----------------------------------------------------------------- +# Save and print dialogs open expanded; new documents save locally, not iCloud. +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode2 -bool true +defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true +defaults write NSGlobalDomain PMPrintingExpandedStateForPrint2 -bool true +defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false # --- trackpad ---------------------------------------------------------------- # Tap to click (built-in + bluetooth trackpads, and the per-host mouse behavior). @@ -24,4 +60,6 @@ defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 # --- apply ------------------------------------------------------------------- killall Finder 2>/dev/null || true -echo "Done. Some settings (appearance) fully apply after re-login." +killall Dock 2>/dev/null || true +killall SystemUIServer 2>/dev/null || true +echo "Done. Keyboard repeat and appearance fully apply after re-login." diff --git a/scripts/drift.sh b/scripts/drift.sh index 8785005..7f302fe 100644 --- a/scripts/drift.sh +++ b/scripts/drift.sh @@ -121,6 +121,7 @@ while IFS= read -r line; do rest="${rest# }" value="${rest#-* }" value="${value%\"}"; value="${value#\"}" + value="${value//\$HOME/$HOME}" case "$value" in true) value=1 ;; false) value=0 ;; From 1cc5c3f5f4ad1a26ea758a2ff9f30b35df7bdb2e Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 3 Aug 2026 19:15:02 +0530 Subject: [PATCH 35/51] Add coffee: caffeinate wrapper to keep the Mac awake on demand coffee [duration] / watch / status / stop, with -d to also keep the display on. Ships as a bin stow package into ~/.local/bin (added to PATH); managed-targets/doctor/drift pick the package up automatically. --- Makefile | 2 +- packages/bin/dot-local/bin/coffee | 85 +++++++++++++++++++++++++ packages/zsh/dot-config/zsh/10-path.zsh | 1 + 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100755 packages/bin/dot-local/bin/coffee diff --git a/Makefile b/Makefile index c9c6ac2..9982d6a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ SHELL := /bin/bash STOW := stow # Flags are a security invariant, not a style choice — see "The stow model" in README.md. STOW_FLAGS := --dir=$(CURDIR)/packages --target=$(HOME) --dotfiles --no-folding --verbose=1 -PACKAGES := zsh git atuin btop gh +PACKAGES := zsh git atuin btop gh bin BREWFILE := $(CURDIR)/Brewfile HARNESS_DIR ?= $(abspath $(CURDIR)/../harness-configs) diff --git a/packages/bin/dot-local/bin/coffee b/packages/bin/dot-local/bin/coffee new file mode 100755 index 0000000..e6949d7 --- /dev/null +++ b/packages/bin/dot-local/bin/coffee @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# coffee — keep the Mac awake (a friendly caffeinate wrapper). +# +# coffee stay awake until 'coffee stop' (display may sleep) +# coffee 45m | 2h | 90s stay awake for a duration +# coffee watch stay awake while a process runs, e.g. coffee watch claude +# coffee status is a coffee session active? +# coffee stop end the session +# +# Add -d before any form to also keep the display awake: coffee -d 2h +# Note: closing the lid still sleeps the Mac unless on power with an external display. +set -euo pipefail + +PIDFILE="${TMPDIR:-/tmp}/coffee-$USER.pid" +FLAGS="-is" # -i idle sleep, -s system sleep (AC power) + +usage() { grep '^# ' "$0" | sed 's/^# //'; } + +alive() { [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; } + +start_bg() { + if alive; then + echo "coffee: already brewing (pid $(cat "$PIDFILE")) — 'coffee stop' first" >&2 + exit 1 + fi + caffeinate $FLAGS "$@" & + echo $! > "$PIDFILE" +} + +if [ "${1:-}" = "-d" ]; then + FLAGS="-dis" + shift +fi + +case "${1:-}" in + -h|--help) + usage + ;; + status) + if alive; then + echo "coffee: awake (pid $(cat "$PIDFILE"), since $(ps -o lstart= -p "$(cat "$PIDFILE")" | sed 's/^ *//'))" + else + echo "coffee: not running — Mac sleeps normally" + fi + ;; + stop) + if alive; then + kill "$(cat "$PIDFILE")" && rm -f "$PIDFILE" + echo "coffee: stopped — Mac sleeps normally" + else + rm -f "$PIDFILE" + echo "coffee: nothing to stop" + fi + ;; + watch) + target="${2:-}" + [ -n "$target" ] || { echo "usage: coffee watch " >&2; exit 2; } + if [[ "$target" =~ ^[0-9]+$ ]]; then + pid="$target" + else + pid="$(pgrep -n "$target" || true)" + [ -n "$pid" ] || { echo "coffee: no process matching '$target'" >&2; exit 1; } + fi + start_bg -w "$pid" + echo "coffee: awake while pid $pid ($(ps -o comm= -p "$pid" | xargs basename)) runs" + ;; + "") + start_bg + echo "coffee: awake until 'coffee stop'" + ;; + *[0-9][smh]|*[0-9]) + n="${1%[smh]}" + case "$1" in + *m) secs=$((n * 60)) ;; + *h) secs=$((n * 3600)) ;; + *) secs=$n ;; + esac + start_bg -t "$secs" + echo "coffee: awake for $1" + ;; + *) + usage >&2 + exit 2 + ;; +esac diff --git a/packages/zsh/dot-config/zsh/10-path.zsh b/packages/zsh/dot-config/zsh/10-path.zsh index d7fd057..fa50837 100644 --- a/packages/zsh/dot-config/zsh/10-path.zsh +++ b/packages/zsh/dot-config/zsh/10-path.zsh @@ -6,4 +6,5 @@ export PATH="$_brew_prefix/opt/grep/libexec/gnubin:$PATH" export PATH="$_brew_prefix/opt/make/libexec/gnubin:$PATH" export PATH="$HOME/go/bin:$PATH" export PATH="$HOME/.codeium/windsurf/bin:$PATH" +export PATH="$HOME/.local/bin:$PATH" unset _brew_prefix From c6e572c8c31ef6b99f34d7d0efa025556ea171de Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Fri, 7 Aug 2026 18:06:48 +0530 Subject: [PATCH 36/51] Route git identity by path instead of remote URL Replace the five hasconfig:remote includeIf rules with a plain include of config-personal plus a gitdir:~/qwiet/ override for config-qwiet. Later include wins, so personal is the default everywhere and work identity applies only under ~/qwiet. The url.insteadOf rewrites are unchanged; they rewrite remotes, not identity. Trade-off: a work repo cloned outside ~/qwiet now gets the personal identity and needs a per-repo user.email. --- packages/git/dot-gitconfig | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/git/dot-gitconfig b/packages/git/dot-gitconfig index 977fde5..16b00bc 100644 --- a/packages/git/dot-gitconfig +++ b/packages/git/dot-gitconfig @@ -13,15 +13,10 @@ conflictStyle = zdiff3 [url "ssh://git@github.com/"] insteadOf = https://github.com/ -[includeIf "hasconfig:remote.*.url:git@github.com:*/**"] - path = ~/.config/git/config-personal -[includeIf "hasconfig:remote.*.url:git@github.com:ShiftLeftSecurity/**"] - path = ~/.config/git/config-qwiet -[includeIf "hasconfig:remote.*.url:https://git0.harness.io/**"] - path = ~/.config/git/config-qwiet -[includeIf "hasconfig:remote.*.url:gh-qwiet:ShiftLeftSecurity/**"] - path = ~/.config/git/config-qwiet -[includeIf "hasconfig:remote.*.url:git@github.com:fission/**"] - path = ~/.config/git/config-personal +# Identity: personal everywhere, work under ~/qwiet. Later include wins. +[include] + path = ~/.config/git/config-personal +[includeIf "gitdir:~/qwiet/"] + path = ~/.config/git/config-qwiet [url "gh-qwiet:ShiftLeftSecurity"] insteadOf = git@github.com:ShiftLeftSecurity From d5fdb1c345c967d08f77ba39a4179c890ff4fa97 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Sat, 22 Aug 2026 16:11:48 +0530 Subject: [PATCH 37/51] Add helium-browser cask ahead of the Chrome swap Helium is a Chromium-based browser that will take over from Google Chrome as the daily driver. Install it alongside Chrome for now; the google-chrome cask, the cask-adopt target, and the chrome-doctor alias stay until the cutover. --- Brewfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Brewfile b/Brewfile index 159fd78..98186be 100644 --- a/Brewfile +++ b/Brewfile @@ -125,6 +125,7 @@ cask "devin-cli" cask "dbeaver-community" cask "gcloud-cli" cask "ghostty" +cask "helium-browser" # Chromium-based; to replace google-chrome eventually cask "insomnia" cask "itsycal" cask "obsidian" From e0105c0217d4db0657e600b8f9f3e71265519a79 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Sat, 22 Aug 2026 16:39:16 +0530 Subject: [PATCH 38/51] Hide Helium's frequently-visited new-tab tiles The new tab page shows Most Visited tiles by default. No enterprise policy covers that, so the setting lives in the profile's Preferences JSON as ntp.shortcust_visible (the typo is Chromium's own key name). Patch it from macos/defaults.sh, guarded three ways: skip when there is no profile, skip while Helium is running because it rewrites the file on exit, and skip when the key is already false. The write goes through a temp file and rename so a failure cannot truncate the profile. macos/defaults.sh is no longer defaults(1)-only, so say "macOS and app settings" in the README layout table. --- README.md | 2 +- macos/defaults.sh | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ba4380..c332fdc 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ On an existing machine, clone the repo and run `make install`. | `Brewfile` | Curated brew formulae, casks, App Store apps (mas), and VS Code extensions | | `manifests/` | Non-brew tools: `go-tools.txt`, `npm-globals.txt`, `pipx-tools.txt` | | `bootstrap.sh` | New-Mac entry point | -| `macos/defaults.sh` | Deliberately-changed macOS settings, applied via `make macos-apply` | +| `macos/defaults.sh` | Deliberately-changed macOS and app settings, applied via `make macos-apply` | | `scripts/doctor.sh` | Health checks behind `make doctor` | ## Make targets diff --git a/macos/defaults.sh b/macos/defaults.sh index d00b1f3..070912d 100755 --- a/macos/defaults.sh +++ b/macos/defaults.sh @@ -58,6 +58,43 @@ defaults write com.apple.AppleMultitouchTrackpad Clicking -bool true defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 +# --- helium (browser) -------------------------------------------------------- +# New tab page: no "frequently visited" tiles. No enterprise policy covers this, +# so it lives in the profile's Preferences JSON. Helium rewrites that file when +# it exits, so the patch only applies while Helium is closed. The key name has a +# typo (`shortcust`); that typo is Chromium's own and is the real key. +HELIUM_PREFS="$HOME/Library/Application Support/net.imput.helium/Default/Preferences" +if [[ ! -f "$HELIUM_PREFS" ]]; then + echo " helium: no profile at $HELIUM_PREFS — skipped" +elif pgrep -x Helium >/dev/null 2>&1; then + echo " helium: running — quit Helium and re-run to hide the new-tab tiles" +else + python3 - "$HELIUM_PREFS" <<'PY' +import json, os, sys, tempfile + +path = sys.argv[1] +with open(path, encoding="utf-8") as fh: + prefs = json.load(fh) + +ntp = prefs.setdefault("ntp", {}) +if ntp.get("shortcust_visible") is False: + print(" helium: new-tab tiles already hidden") +else: + ntp["shortcust_visible"] = False + directory = os.path.dirname(path) + fd, tmp = tempfile.mkstemp(dir=directory, prefix="Preferences.") + try: + with os.fdopen(fd, "w", encoding="utf-8") as fh: + json.dump(prefs, fh, separators=(",", ":")) + os.chmod(tmp, os.stat(path).st_mode & 0o777) + os.replace(tmp, path) + except BaseException: + os.path.exists(tmp) and os.unlink(tmp) + raise + print(" helium: new-tab tiles hidden") +PY +fi + # --- apply ------------------------------------------------------------------- killall Finder 2>/dev/null || true killall Dock 2>/dev/null || true From d09d92dbf392fc0d3b3bd89a3e6b8975275b5a7c Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Sat, 22 Aug 2026 16:52:52 +0530 Subject: [PATCH 39/51] Add Helium privacy and autofill policies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Helium reads Chromium enterprise policy from its own preferences domain, so `defaults write net.imput.helium ...` reaches it — no administrator rights and no /Library/Managed Preferences file. Verified on helium://policy: the keys come back as source "platform", scope "user", level "recommended". Recommended means the policy sets the default while Settings can still override it, which is the right strength for a personal machine. Set: card and address autofill off, payment-method probing off, omnibox search suggestions off, link prefetch off, and prompt for the download location. PasswordManagerEnabled is deliberately absent. Helium's built-in HOP (Helium Opinionated Policy) provider already forces it and the passkeys policy off, at a higher priority than platform policy, so restating them here would be dead weight. Generalise the JSON patch to a WANTED table so keys without a policy are a one-line addition. It still holds only the new-tab tiles; credentials_enable_autosignin was considered and dropped, because it is a top-level pref rather than a profile.* one and is moot anyway once HOP disables the password manager. --- macos/defaults.sh | 48 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/macos/defaults.sh b/macos/defaults.sh index 070912d..92f5d45 100755 --- a/macos/defaults.sh +++ b/macos/defaults.sh @@ -59,28 +59,54 @@ defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 # --- helium (browser) -------------------------------------------------------- -# New tab page: no "frequently visited" tiles. No enterprise policy covers this, -# so it lives in the profile's Preferences JSON. Helium rewrites that file when -# it exits, so the patch only applies while Helium is closed. The key name has a -# typo (`shortcust`); that typo is Chromium's own and is the real key. +# Helium reads Chromium enterprise policy from its own preferences domain, so +# `defaults write` reaches it — no sudo, no /Library/Managed Preferences. An +# unforced write lands as level "recommended": it sets the default but Settings +# can still override it. Confirm with helium://policy after a relaunch. +# Not set here: PasswordManagerEnabled and PasswordManagerPasskeysEnabled. +# Helium's built-in HOP provider already forces both off, at a higher priority +# than any policy this file can write. +# No autofill of cards or addresses, and sites cannot probe for saved cards. +defaults write net.imput.helium AutofillCreditCardEnabled -bool false +defaults write net.imput.helium AutofillAddressEnabled -bool false +defaults write net.imput.helium PaymentMethodQueryEnabled -bool false +# No omnibox keystrokes to the search engine, and no link prefetch (2 = off). +defaults write net.imput.helium SearchSuggestEnabled -bool false +defaults write net.imput.helium NetworkPredictionOptions -int 2 +# Ask where to save each download. +defaults write net.imput.helium PromptForDownloadLocation -bool true + +# The new tab page's "frequently visited" tiles have no policy, so they live in +# the profile's Preferences JSON. The `shortcust` typo is Chromium's own key +# name. Helium rewrites that file when it exits, so the patch only applies while +# it is closed. Add further JSON-only keys to WANTED below. HELIUM_PREFS="$HOME/Library/Application Support/net.imput.helium/Default/Preferences" if [[ ! -f "$HELIUM_PREFS" ]]; then - echo " helium: no profile at $HELIUM_PREFS — skipped" + echo " helium: no profile at $HELIUM_PREFS — prefs patch skipped" elif pgrep -x Helium >/dev/null 2>&1; then - echo " helium: running — quit Helium and re-run to hide the new-tab tiles" + echo " helium: running — quit Helium and re-run to apply the prefs patch" else python3 - "$HELIUM_PREFS" <<'PY' import json, os, sys, tempfile +WANTED = { + ("ntp", "shortcust_visible"): False, # typo is Chromium's own key +} + path = sys.argv[1] with open(path, encoding="utf-8") as fh: prefs = json.load(fh) -ntp = prefs.setdefault("ntp", {}) -if ntp.get("shortcust_visible") is False: - print(" helium: new-tab tiles already hidden") +changed = [] +for (section, key), value in WANTED.items(): + block = prefs.setdefault(section, {}) + if block.get(key) != value: + block[key] = value + changed.append(key) + +if not changed: + print(" helium: prefs already set") else: - ntp["shortcust_visible"] = False directory = os.path.dirname(path) fd, tmp = tempfile.mkstemp(dir=directory, prefix="Preferences.") try: @@ -91,7 +117,7 @@ else: except BaseException: os.path.exists(tmp) and os.unlink(tmp) raise - print(" helium: new-tab tiles hidden") + print(" helium: set " + ", ".join(sorted(changed))) PY fi From 6e8d16dc05d0cac86d08f707071c8394f4f652a6 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Fri, 28 Aug 2026 12:50:01 +0530 Subject: [PATCH 40/51] Add glow markdown renderer with md alias glow renders markdown in the terminal, alongside bat for code and jless for JSON. The md alias pages output through glow -p, guarded by command -v like the other modern-CLI aliases. --- Brewfile | 1 + packages/zsh/dot-config/zsh/20-aliases.zsh | 1 + 2 files changed, 2 insertions(+) diff --git a/Brewfile b/Brewfile index 98186be..b4205da 100644 --- a/Brewfile +++ b/Brewfile @@ -51,6 +51,7 @@ brew "fd" # gitignore-aware find brew "git-delta" # readable side-by-side git diffs (wired in gitconfig) brew "yq" # jq for YAML/TOML/XML brew "jless" # interactive JSON pager +brew "glow" # markdown renderer/pager for the terminal brew "dust" # visual du brew "lazygit" # git TUI (same author as lazydocker) diff --git a/packages/zsh/dot-config/zsh/20-aliases.zsh b/packages/zsh/dot-config/zsh/20-aliases.zsh index 9fb2ed5..b339b4c 100644 --- a/packages/zsh/dot-config/zsh/20-aliases.zsh +++ b/packages/zsh/dot-config/zsh/20-aliases.zsh @@ -9,3 +9,4 @@ if command -v kubecolor >/dev/null; then fi command -v eza >/dev/null && alias ll='eza -l --git' command -v lazygit >/dev/null && alias lg=lazygit +command -v glow >/dev/null && alias md='glow -p' From 9684db4fcc3efdca81a03dc3557405d1cc003581 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 11:35:07 +0530 Subject: [PATCH 41/51] Drop unused cloud and API client packages Remove six entries that are no longer used: awscli, okta-awscli, dbeaver-community, gcloud-cli, insomnia, postman. dbeaver-community and postman had no app installed on the machine, only orphaned application data. The AWS and gcloud credential stores were removed alongside the CLIs. google-chrome stays until the Helium cutover is complete. --- Brewfile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Brewfile b/Brewfile index b4205da..09f8f9f 100644 --- a/Brewfile +++ b/Brewfile @@ -99,8 +99,6 @@ brew "loft-sh/tap/vcluster" brew "minio/stable/mc" # --- cloud & misc ------------------------------------------------------------ -brew "awscli" -brew "okta-awscli" brew "cloudflared" brew "codecov-cli" brew "semgrep" @@ -123,14 +121,10 @@ cask "1password-cli" cask "claude-code@latest" cask "copilot-cli" cask "devin-cli" -cask "dbeaver-community" -cask "gcloud-cli" cask "ghostty" cask "helium-browser" # Chromium-based; to replace google-chrome eventually -cask "insomnia" cask "itsycal" cask "obsidian" -cask "postman" cask "raycast" # launcher + clipboard history + window snapping + extensions cask "slack" cask "visual-studio-code" From 5204e32713c6acdcbef9c73ba3e87852bce5644f Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 11:39:07 +0530 Subject: [PATCH 42/51] Drop semgrep and codecov-cli Neither tool is used locally. Removing them cascaded their Python dependency trees, which freed about 235 MB. The improve-codecov-coverage skill reads the Codecov REST API directly, so it does not depend on the codecovcli binary. --- Brewfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Brewfile b/Brewfile index 09f8f9f..7794645 100644 --- a/Brewfile +++ b/Brewfile @@ -100,8 +100,6 @@ brew "minio/stable/mc" # --- cloud & misc ------------------------------------------------------------ brew "cloudflared" -brew "codecov-cli" -brew "semgrep" brew "hugo" brew "agent-browser" brew "herdr" From 5234bbc59088b22e5a64e362477bab9a5e43c69b Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 11:42:28 +0530 Subject: [PATCH 43/51] Drop the ShiftLeft VS Code extension The sl CLI and its 2.3 GB toolchain cache under ~/.shiftleft were removed from the machine at the same time. This leaves the qwiet git and SSH identity untouched, because that configuration controls work repository access, not the scanner. --- Brewfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Brewfile b/Brewfile index 7794645..2fe9674 100644 --- a/Brewfile +++ b/Brewfile @@ -159,7 +159,6 @@ vscode "oracle.oracle-java" vscode "redhat.vscode-yaml" vscode "scala-lang.scala" vscode "shd101wyy.markdown-preview-enhanced" -vscode "shiftleft.shiftleft-core" vscode "vscjava.vscode-java-debug" vscode "vscjava.vscode-java-dependency" vscode "vscjava.vscode-maven" From 8b755ea9c2398b5ebcdf52edbad6e387a18573c7 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 11:50:16 +0530 Subject: [PATCH 44/51] Remove the qwiet git identity routing The ~/qwiet work tree and its SSH key no longer exist, so the conditional include and the ShiftLeftSecurity URL rewrite pointed at paths and a host that are gone. Personal identity now applies everywhere. --- packages/git/dot-gitconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/git/dot-gitconfig b/packages/git/dot-gitconfig index 16b00bc..9954938 100644 --- a/packages/git/dot-gitconfig +++ b/packages/git/dot-gitconfig @@ -13,10 +13,6 @@ conflictStyle = zdiff3 [url "ssh://git@github.com/"] insteadOf = https://github.com/ -# Identity: personal everywhere, work under ~/qwiet. Later include wins. +# Identity: personal everywhere. [include] path = ~/.config/git/config-personal -[includeIf "gitdir:~/qwiet/"] - path = ~/.config/git/config-qwiet -[url "gh-qwiet:ShiftLeftSecurity"] - insteadOf = git@github.com:ShiftLeftSecurity From c8f9a9187ea8d726028ba55c103b301901aa1501 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 21:39:08 +0530 Subject: [PATCH 45/51] Bump vendored skill pins and regenerate catalogs --- skills/README.md | 48 +++++++++++++------------- skills/vendored.json | 60 ++++++++++++++++----------------- suites/pr-shepherding/README.md | 4 +-- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/skills/README.md b/skills/README.md index 0547933..f135e99 100644 --- a/skills/README.md +++ b/skills/README.md @@ -26,12 +26,12 @@ Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` | Skill | Purpose | |-------|---------| -| [`docx`](https://github.com/anthropics/skills/tree/b29e7cf65e5cb78a5ac33d582270551bc74a14eb/skills/docx) | Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). | -| [`pdf`](https://github.com/anthropics/skills/tree/b29e7cf65e5cb78a5ac33d582270551bc74a14eb/skills/pdf) | Use this skill whenever the user wants to do anything with PDF files. | -| [`pptx`](https://github.com/anthropics/skills/tree/b29e7cf65e5cb78a5ac33d582270551bc74a14eb/skills/pptx) | Use this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. | +| [`docx`](https://github.com/anthropics/skills/tree/3b3fad96af16a10759d930941b4520ba0c40edae/skills/docx) | Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). | +| [`pdf`](https://github.com/anthropics/skills/tree/3b3fad96af16a10759d930941b4520ba0c40edae/skills/pdf) | Use this skill whenever the user wants to do anything with PDF files. | +| [`pptx`](https://github.com/anthropics/skills/tree/3b3fad96af16a10759d930941b4520ba0c40edae/skills/pptx) | Use this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. | | [`sembr-reformat`](https://github.com/sembr/skills/tree/5f973aaa75b1165b03dd45dca4cd1dc0437deba3/skills/sembr-reformat) | Reformat prose using Semantic Line Breaks (SemBr) from https://sembr.org while preserving rendered output and meaning. | | [`tufte-information-design`](tufte-information-design/SKILL.md) | Applies Edward Tufte's information-design principles to any information display — slides/decks, documents, blog posts, dashboards, HTML artifacts, tables, di... | -| [`xlsx`](https://github.com/anthropics/skills/tree/b29e7cf65e5cb78a5ac33d582270551bc74a14eb/skills/xlsx) | Use this skill any time a spreadsheet file is the primary input or output. | +| [`xlsx`](https://github.com/anthropics/skills/tree/3b3fad96af16a10759d930941b4520ba0c40edae/skills/xlsx) | Use this skill any time a spreadsheet file is the primary input or output. | ## engineering @@ -39,18 +39,18 @@ Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` | Skill | Purpose | |-------|---------| -| [`codebase-design`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/codebase-design) | Shared vocabulary for designing deep modules. | -| [`domain-modeling`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/domain-modeling) | Build and sharpen a project's domain model. | -| [`grill-with-docs`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/grill-with-docs) | A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go. | -| [`grilling`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/productivity/grilling) | Grill the user relentlessly about a plan, decision, or idea. | -| [`implement`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/implement) | Implement a piece of work based on a spec or set of tickets. | -| [`improve-codebase-architecture`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/improve-codebase-architecture) | Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick. | -| [`matt-code-review`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/code-review) | Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding st... | -| [`prototype`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/prototype) | Build a throwaway prototype to answer a design question. | -| [`setup-matt-pocock-skills`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/setup-matt-pocock-skills) | Configure this repo for the engineering skills — set up its issue tracker, triage label vocabulary, and domain doc layout. | -| [`to-spec`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/to-spec) | Turn the current conversation into a spec and publish it to the project issue tracker — no interview, just synthesis of what you've already discussed. | -| [`to-tickets`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/to-tickets) | Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker —... | -| [`wayfinder`](https://github.com/mattpocock/skills/tree/2ffb184ffbb752faa664c0b204f3c9241b1428e9/skills/engineering/wayfinder) | Plan a huge chunk of work — more than one agent session can hold — as a shared map of decision tickets on your issue tracker, and resolve them one at a time ... | +| [`codebase-design`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/codebase-design) | Shared vocabulary for designing deep modules. | +| [`domain-modeling`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/domain-modeling) | Build and sharpen a project's domain model. | +| [`grill-with-docs`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/grill-with-docs) | A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go. | +| [`grilling`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/productivity/grilling) | Grill the user relentlessly about a plan, decision, or idea. | +| [`implement`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/implement) | Implement a piece of work based on a spec or set of tickets. | +| [`improve-codebase-architecture`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/improve-codebase-architecture) | Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick. | +| [`matt-code-review`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/code-review) | Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes: Standards (does the code follow this repo's documented coding sta... | +| [`prototype`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/prototype) | Build a throwaway prototype to answer a design question. | +| [`setup-matt-pocock-skills`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/setup-matt-pocock-skills) | Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. | +| [`to-spec`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/to-spec) | Turn the current conversation into a spec and publish it to the project issue tracker: no interview, just synthesis of what you've already discussed. | +| [`to-tickets`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/to-tickets) | Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker (... | +| [`wayfinder`](https://github.com/mattpocock/skills/tree/6654f6b60cd9d5be8b54c6fafe44346dabeb3b76/skills/engineering/wayfinder) | Plan a huge chunk of work (more than one agent session can hold) as a shared map of decision tickets on your issue tracker, and resolve them one at a time un... | ## gh-maintenance @@ -115,8 +115,8 @@ Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` | Skill | Purpose | |-------|---------| -| [`caveman`](https://github.com/juliusbrussee/caveman/tree/ec83e5bace4c20484d704dea21e12fc4eb94e9aa/skills/caveman) | Ultra-compressed communication mode. | -| [`find-skills`](https://github.com/vercel-labs/skills/tree/ab4fc49265c443279a5deae20297e631470da68c/skills/find-skills) | Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express ... | +| [`caveman`](https://github.com/juliusbrussee/caveman/tree/81536f57b3303b7de7f5bc5b564cc344f9112d68/skills/caveman) | Ultra-compressed communication mode. | +| [`find-skills`](https://github.com/vercel-labs/skills/tree/435076e78988e1e6ec40d00b0b1d76bdbbc5419a/skills/find-skills) | Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express ... | | [`harvest-automation`](harvest-automation/SKILL.md) | Mines past Claude Code sessions for recurring patterns and turns them into durable automation: skills, CLAUDE.md entries, memory, and permission allowlists. | ## personal-finance @@ -133,13 +133,13 @@ Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` | Skill | Purpose | |-------|---------| -| [`deslop`](https://github.com/cursor/plugins/tree/8185ad9fbb903efc7d1cf152a9be9777e516cfbc/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | -| [`make-pr-easy-to-review`](https://github.com/cursor/plugins/tree/8185ad9fbb903efc7d1cf152a9be9777e516cfbc/cursor-team-kit/skills/make-pr-easy-to-review) | Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. | -| [`pr-review-canvas`](https://github.com/cursor/plugins/tree/8185ad9fbb903efc7d1cf152a9be9777e516cfbc/cursor-team-kit/skills/pr-review-canvas) | Generate an interactive PR review walkthrough as an HTML page. | +| [`deslop`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | +| [`make-pr-easy-to-review`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/make-pr-easy-to-review) | Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. | +| [`pr-review-canvas`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/pr-review-canvas) | Generate an interactive PR review walkthrough as an HTML page. | | [`resolve-bot-review-threads`](resolve-bot-review-threads/SKILL.md) | Clears bot/Copilot review threads on a PR — fixes the issues, marks threads resolved via GraphQL, and re-requests the bot until the PR is clean. | | [`review-battery`](review-battery/SKILL.md) | Full review of a change set — the working diff, a branch vs a base ref, or a GitHub PR number reviewed in an isolated worktree — using the thermos subagents ... | -| [`thermo-nuclear-code-quality-review`](https://github.com/cursor/plugins/tree/60c641e4fad674784b30abcf9f8915dea39df38d/thermos/skills/thermo-nuclear-code-quality-review) | Run an extremely strict maintainability review for abstraction quality, giant files, and spaghetti-condition growth. | -| [`thermo-nuclear-review`](https://github.com/cursor/plugins/tree/60c641e4fad674784b30abcf9f8915dea39df38d/thermos/skills/thermo-nuclear-review) | Comprehensive security and correctness audit of a branch's changes. | +| [`thermo-nuclear-code-quality-review`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/thermos/skills/thermo-nuclear-code-quality-review) | Run an extremely strict maintainability review for abstraction quality, giant files, and spaghetti-condition growth. | +| [`thermo-nuclear-review`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/thermos/skills/thermo-nuclear-review) | Comprehensive security and correctness audit of a branch's changes. | ## search-media @@ -147,7 +147,7 @@ Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` | Skill | Purpose | |-------|---------| -| [`agent-browser`](https://github.com/vercel-labs/agent-browser/tree/acbc22bdc5d4f6c5a88d97d4a4745d3c5eb0591f/skills/agent-browser) | Browser automation CLI for AI agents. | +| [`agent-browser`](https://github.com/vercel-labs/agent-browser/tree/9d9a3bbd5e4f8c0a17a1c4dfd2f8e8d74b5ee998/skills/agent-browser) | Browser automation CLI for AI agents. | | [`brave-search`](https://github.com/badlogic/pi-skills/tree/90bb51cae36515a648515b633a81c0c6efc8c74d/brave-search) | Web search and content extraction via Brave Search API. | | [`transcribe`](https://github.com/badlogic/pi-skills/tree/90bb51cae36515a648515b633a81c0c6efc8c74d/transcribe) | Local speech-to-text transcription on Apple Silicon macOS. | | [`vscode`](https://github.com/badlogic/pi-skills/tree/90bb51cae36515a648515b633a81c0c6efc8c74d/vscode) | VS Code integration for viewing diffs and comparing files. | diff --git a/skills/vendored.json b/skills/vendored.json index b387b9b..1976ab6 100644 --- a/skills/vendored.json +++ b/skills/vendored.json @@ -4,7 +4,7 @@ "repo": "https://github.com/vercel-labs/agent-browser", "subpath": "skills/agent-browser", "ref": "main", - "commit": "acbc22bdc5d4f6c5a88d97d4a4745d3c5eb0591f", + "commit": "9d9a3bbd5e4f8c0a17a1c4dfd2f8e8d74b5ee998", "category": "search-media", "description": "Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools." }, @@ -22,7 +22,7 @@ "repo": "https://github.com/juliusbrussee/caveman", "subpath": "skills/caveman", "ref": "main", - "commit": "ec83e5bace4c20484d704dea21e12fc4eb94e9aa", + "commit": "81536f57b3303b7de7f5bc5b564cc344f9112d68", "category": "meta", "description": "Ultra-compressed communication mode. Cuts output tokens 65% (measured) by speaking like caveman while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra, wenyan-lite, wenyan-full, wenyan-ultra. Use when user says \"caveman mode\", \"talk like caveman\", \"use caveman\", \"less tokens\", \"be brief\", or invokes /caveman. Also auto-triggers when token efficiency is requested." }, @@ -31,7 +31,7 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/codebase-design", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", "description": "Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary." }, @@ -40,7 +40,7 @@ "repo": "https://github.com/cursor/plugins", "subpath": "cursor-team-kit/skills/deslop", "ref": "main", - "commit": "8185ad9fbb903efc7d1cf152a9be9777e516cfbc", + "commit": "bdf7aa355337897f167153e05069aca505dae17c", "category": "pr-review", "description": "Remove AI-generated code slop and clean up code style" }, @@ -49,7 +49,7 @@ "repo": "https://github.com/anthropics/skills", "subpath": "skills/docx", "ref": "main", - "commit": "b29e7cf65e5cb78a5ac33d582270551bc74a14eb", + "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", "category": "documents", "description": "\"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', '.dotx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx or .dotx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a 'report', 'memo', 'letter', 'template', or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"" }, @@ -58,9 +58,9 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/domain-modeling", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", - "description": "Build and sharpen a project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to maintain the domain model." + "description": "Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a CONTEXT.md, or recording or editing an ADR." }, { "name": "drive-chrome-cdp", @@ -76,7 +76,7 @@ "repo": "https://github.com/vercel-labs/skills", "subpath": "skills/find-skills", "ref": "main", - "commit": "ab4fc49265c443279a5deae20297e631470da68c", + "commit": "435076e78988e1e6ec40d00b0b1d76bdbbc5419a", "category": "meta", "description": "Helps users discover and install agent skills when they ask questions like \"how do I do X\", \"find a skill for X\", \"is there a skill that can...\", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill." }, @@ -112,7 +112,7 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/grill-with-docs", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", "description": "A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go." }, @@ -121,7 +121,7 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/productivity/grilling", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", "description": "Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases." }, @@ -130,7 +130,7 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/implement", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", "description": "\"Implement a piece of work based on a spec or set of tickets.\"" }, @@ -139,7 +139,7 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/improve-codebase-architecture", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", "description": "Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick." }, @@ -157,7 +157,7 @@ "repo": "https://github.com/cursor/plugins", "subpath": "cursor-team-kit/skills/make-pr-easy-to-review", "ref": "main", - "commit": "8185ad9fbb903efc7d1cf152a9be9777e516cfbc", + "commit": "bdf7aa355337897f167153e05069aca505dae17c", "category": "pr-review", "description": "Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. Use for \"make this easy to review\", \"tidy this PR\", \"clean up commits\", or \"annotate the diff\"." }, @@ -166,16 +166,16 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/code-review", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", - "description": "Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/spec asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to \"review since X\"." + "description": "\"Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes: Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/spec asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to \\\"review since X\\\".\"" }, { "name": "pdf", "repo": "https://github.com/anthropics/skills", "subpath": "skills/pdf", "ref": "main", - "commit": "b29e7cf65e5cb78a5ac33d582270551bc74a14eb", + "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", "category": "documents", "description": "Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill." }, @@ -184,7 +184,7 @@ "repo": "https://github.com/anthropics/skills", "subpath": "skills/pptx", "ref": "main", - "commit": "b29e7cf65e5cb78a5ac33d582270551bc74a14eb", + "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", "category": "documents", "description": "\"Use this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates (.potx), layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx or .potx filename, regardless of what they plan to do with the content afterward. If a .pptx or .potx file needs to be opened, created, or touched, use this skill.\"" }, @@ -193,7 +193,7 @@ "repo": "https://github.com/cursor/plugins", "subpath": "cursor-team-kit/skills/pr-review-canvas", "ref": "main", - "commit": "8185ad9fbb903efc7d1cf152a9be9777e516cfbc", + "commit": "bdf7aa355337897f167153e05069aca505dae17c", "category": "pr-review", "description": "Generate an interactive PR review walkthrough as an HTML page. Fetches PR data via gh API, categorizes files into core vs mechanical changes, adds reviewer annotations, and renders diffs with moved-code detection. Use when the user pastes a GitHub PR URL and asks for a review, walkthrough, or summary, or says \"review this PR\"." }, @@ -202,7 +202,7 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/prototype", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", "description": "Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like." }, @@ -292,16 +292,16 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/setup-matt-pocock-skills", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", - "description": "Configure this repo for the engineering skills — set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills." + "description": "\"Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.\"" }, { "name": "thermo-nuclear-code-quality-review", "repo": "https://github.com/cursor/plugins", "subpath": "thermos/skills/thermo-nuclear-code-quality-review", "ref": "main", - "commit": "60c641e4fad674784b30abcf9f8915dea39df38d", + "commit": "bdf7aa355337897f167153e05069aca505dae17c", "category": "pr-review", "description": "Run an extremely strict maintainability review for abstraction quality, giant files, and spaghetti-condition growth. Use for a thermo-nuclear code quality review, thermonuclear review, deep code quality audit, or especially harsh maintainability review." }, @@ -310,7 +310,7 @@ "repo": "https://github.com/cursor/plugins", "subpath": "thermos/skills/thermo-nuclear-review", "ref": "main", - "commit": "60c641e4fad674784b30abcf9f8915dea39df38d", + "commit": "bdf7aa355337897f167153e05069aca505dae17c", "category": "pr-review", "description": "Comprehensive security and correctness audit of a branch's changes. Use for thermo nuclear, thermonuclear, or deep review requests, or branch/PR diff audits focused on bugs, breaking changes, security issues, devex regressions, and feature-gate leaks." }, @@ -319,18 +319,18 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/to-spec", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", - "description": "Turn the current conversation into a spec and publish it to the project issue tracker — no interview, just synthesis of what you've already discussed." + "description": "\"Turn the current conversation into a spec and publish it to the project issue tracker: no interview, just synthesis of what you've already discussed.\"" }, { "name": "to-tickets", "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/to-tickets", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", - "description": "Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker — edges as text in one file per ticket locally, or native blocking links on a real tracker." + "description": "Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker (edges as text in one file per ticket locally, or native blocking links on a real tracker)." }, { "name": "transcribe", @@ -355,16 +355,16 @@ "repo": "https://github.com/mattpocock/skills", "subpath": "skills/engineering/wayfinder", "ref": "main", - "commit": "2ffb184ffbb752faa664c0b204f3c9241b1428e9", + "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", "category": "engineering", - "description": "Plan a huge chunk of work — more than one agent session can hold — as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear." + "description": "Plan a huge chunk of work (more than one agent session can hold) as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear." }, { "name": "xlsx", "repo": "https://github.com/anthropics/skills", "subpath": "skills/xlsx", "ref": "main", - "commit": "b29e7cf65e5cb78a5ac33d582270551bc74a14eb", + "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", "category": "documents", "description": "\"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .xltx, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \\\"the xlsx in my downloads\\\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"" }, diff --git a/suites/pr-shepherding/README.md b/suites/pr-shepherding/README.md index 798ddad..de2012a 100644 --- a/suites/pr-shepherding/README.md +++ b/suites/pr-shepherding/README.md @@ -48,8 +48,8 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h | Skill | Purpose | |-------|---------| -| [`make-pr-easy-to-review`](https://github.com/cursor/plugins/tree/8185ad9fbb903efc7d1cf152a9be9777e516cfbc/cursor-team-kit/skills/make-pr-easy-to-review) | Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. | -| [`deslop`](https://github.com/cursor/plugins/tree/8185ad9fbb903efc7d1cf152a9be9777e516cfbc/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | +| [`make-pr-easy-to-review`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/make-pr-easy-to-review) | Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. | +| [`deslop`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | | [`resolve-bot-review-threads`](../../skills/resolve-bot-review-threads/SKILL.md) | Clears bot/Copilot review threads on a PR — fixes the issues, marks threads resolved via GraphQL, and re-requests the bot until the PR is clean. | | [`watch-ci`](../../skills/watch-ci/SKILL.md) | Watches a PR's CI checks to terminal state in the background and turns each transition into a notification, instead of a foreground polling loop. | | [`debug-ci`](../../skills/debug-ci/SKILL.md) | Triages and root-causes a failing GitHub Actions CI run on a PR by separating real regressions from pre-existing noise and escalating log fetches cheapest-fi... | From da94848e6496ff507401220cb356c3f3b080f32d Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 21:39:08 +0530 Subject: [PATCH 46/51] Exclude bot-templated threads from duplicate clustering in triage-gh-backlog --- .../triage-gh-backlog/references/pipeline.md | 3 +- .../scripts/config.example.toml | 7 +++ skills/triage-gh-backlog/scripts/triage.py | 54 +++++++++++++++++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/skills/triage-gh-backlog/references/pipeline.md b/skills/triage-gh-backlog/references/pipeline.md index 01b00ad..e5c9ffe 100644 --- a/skills/triage-gh-backlog/references/pipeline.md +++ b/skills/triage-gh-backlog/references/pipeline.md @@ -43,7 +43,8 @@ No network. Safe to re-run any time after a sync. ## Stage 3 — triage (`triage.py`) -Deterministic rule engine over `threads.jsonl`, config-driven. Triages **open, not-locally-closed** threads only. Builds duplicate groups locally (same-kind title-token Jaccard ≥ `dup_title_jaccard`, default 0.7; cross-references upgrade confidence) — no embeddings. Emits `triage.jsonl`: `disposition, tier, add_labels[], comment_template, context, rationale, type, areas`. +Deterministic rule engine over `threads.jsonl`, config-driven. Triages **open, not-locally-closed** threads only. Builds duplicate groups locally (same-kind title-token Jaccard ≥ `dup_title_jaccard`, default 0.7; cross-references upgrade confidence) — no embeddings. +`dup_exclude_authors` / `dup_exclude_title_patterns` drop machine-generated threads out of clustering entirely (bot logins match bare, `app/`-prefixed and `[bot]`-suffixed forms): they share a title template by construction, so title overlap is pure false-positive signal for them. Emits `triage.jsonl`: `disposition, tier, add_labels[], comment_template, context, rationale, type, areas`. See `triage-rules.md` for the full rule list. Pure; re-run after tuning config without re-syncing. diff --git a/skills/triage-gh-backlog/scripts/config.example.toml b/skills/triage-gh-backlog/scripts/config.example.toml index 8e3fc23..2777cfb 100644 --- a/skills/triage-gh-backlog/scripts/config.example.toml +++ b/skills/triage-gh-backlog/scripts/config.example.toml @@ -31,6 +31,13 @@ gitcrawl_db = "~/.config/gitcrawl/gitcrawl.db" # stricter. Cross-references only UPGRADE confidence (title->ref => auto tier); # they never create a duplicate on their own (a "fixes #N" link is not a dup). dup_title_jaccard = 0.7 +# Threads excluded from duplicate clustering entirely. Machine-generated threads +# share a title template by construction, so title-token overlap is meaningless +# for them: every "chore(deps): bump the X group with N updates" scores near 1.0 +# against every other one and the engine proposes closing live PRs as duplicates. +# Author logins match bare, "app/" -prefixed and "[bot]"-suffixed forms. +dup_exclude_authors = ["dependabot", "renovate", "github-actions"] +dup_exclude_title_patterns = ["^chore\\(deps\\)", "^build\\(deps"] # --- staleness --- stale_days = 540 # ~18mo no activity -> stale candidate stale_comment_max = 8 # skip stale-close if more engaged than this diff --git a/skills/triage-gh-backlog/scripts/triage.py b/skills/triage-gh-backlog/scripts/triage.py index 9ff2553..517726f 100644 --- a/skills/triage-gh-backlog/scripts/triage.py +++ b/skills/triage-gh-backlog/scripts/triage.py @@ -66,14 +66,48 @@ def below_floor(found: str, floor: str) -> bool: # --------------------------------------------------------------------------- # # duplicate grouping # # --------------------------------------------------------------------------- # -def build_dup_groups(threads: list[dict], jaccard_floor: float = 0.7) -> dict[int, dict]: +def _dup_excluded_numbers( + threads: list[dict], + exclude_authors: list[str] | None, + exclude_title_patterns: list[str] | None, +) -> set[int]: + """Numbers that must never participate in duplicate clustering.""" + authors = {a.lower() for a in (exclude_authors or [])} + pats = [re.compile(p, re.I) for p in (exclude_title_patterns or [])] + out: set[int] = set() + for t in threads: + author = (t.get("author") or "").lower() + # match bare and app-suffixed bot logins: dependabot / app/dependabot / dependabot[bot] + stripped = author.removeprefix("app/").removesuffix("[bot]") + if author in authors or stripped in authors: + out.add(t["number"]) + continue + title = t.get("title") or "" + if any(p.search(title) for p in pats): + out.add(t["number"]) + return out + + +def build_dup_groups( + threads: list[dict], + jaccard_floor: float = 0.7, + exclude_authors: list[str] | None = None, + exclude_title_patterns: list[str] | None = None, +) -> dict[int, dict]: """Return {number: {"canonical": n, "evidence": "ref"|"title", "members":[...]}}. A group's canonical is its oldest still-relevant thread (lowest number). Only OPEN, non-protected members get a dup disposition later; the canonical is whichever member is open with the lowest number (fallback: lowest number). + + `exclude_authors` / `exclude_title_patterns` remove threads from duplicate + clustering entirely. Machine-generated threads share a title template by + construction — every `chore(deps): bump the X group with N updates` from a + bot scores near-1.0 Jaccard against every other one — so title overlap + carries no duplicate signal for them, only false positives. """ by_num = {t["number"]: t for t in threads} + dup_excluded = _dup_excluded_numbers(threads, exclude_authors, exclude_title_patterns) parent: dict[int, int] = {} def find(x: int) -> int: @@ -100,10 +134,16 @@ def union(a: int, b: int) -> None: for ref in t["references"]: other = by_num.get(ref) if other and other["kind"] == t["kind"]: + if t["number"] in dup_excluded or ref in dup_excluded: + continue ref_pairs.add(frozenset((t["number"], ref))) toks = {t["number"]: norm_tokens(t["title"]) for t in threads} - nums = [t["number"] for t in threads if len(toks[t["number"]]) >= 4] + nums = [ + t["number"] + for t in threads + if len(toks[t["number"]]) >= 4 and t["number"] not in dup_excluded + ] bucket: dict[str, list[int]] = defaultdict(list) for n in nums: for tok in toks[n]: @@ -384,8 +424,14 @@ def main() -> None: # Only triage things that are actionable: open and not already locally closed. open_threads = [t for t in threads if t["state"] == "open" and not t["closed_local"]] - jac = ctx["cfg"].get("triage", {}).get("dup_title_jaccard", 0.7) - dup_map = build_dup_groups(threads, jaccard_floor=jac) # over all to find canonicals + tri_cfg = ctx["cfg"].get("triage", {}) + jac = tri_cfg.get("dup_title_jaccard", 0.7) + dup_map = build_dup_groups( # over all threads, to find canonicals + threads, + jaccard_floor=jac, + exclude_authors=tri_cfg.get("dup_exclude_authors", []), + exclude_title_patterns=tri_cfg.get("dup_exclude_title_patterns", []), + ) keepers = load_keepers(wd) if keepers: common.info(f"keepers.txt: {len(keepers)} numbers force-kept") From 836a244a85e809cf4d9537399b749cb5839687af Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 21:46:22 +0530 Subject: [PATCH 47/51] Repackage claude and pi as stow packages under packages/ claude/ and pi/ move to packages/claude and packages/pi; the six hand-rolled *-link/*-unlink target pairs collapse into stow-based harness-link/harness-unlink (folding on, unlike the --no-folding invariant that protects the $HOME packages). Each package reaches the shared skills/ tree through a committed relative symlink, and plugins.txt joins the other line-format manifests as manifests/claude-plugins.txt. --- Makefile | 199 ++++-------------- .../claude-plugins.txt | 0 {claude => packages/claude}/CLAUDE.md | 0 .../claude}/agents/bulk-mechanic.md | 0 .../claude}/agents/bulk-mechanic.source.json | 0 .../claude}/agents/plan-reviewer.md | 0 .../claude}/agents/plan-reviewer.source.json | 0 .../claude}/agents/pr-shepherd.md | 0 .../claude}/agents/pr-shepherd.source.json | 0 .../claude}/agents/skill-auditor.md | 0 .../claude}/agents/skill-auditor.source.json | 0 ...mo-nuclear-code-quality-review-subagent.md | 0 ...r-code-quality-review-subagent.source.json | 0 .../agents/thermo-nuclear-review-subagent.md | 0 ...thermo-nuclear-review-subagent.source.json | 0 {claude => packages/claude}/commands/.gitkeep | 0 .../claude}/commands/history.md | 0 .../claude}/rules/delegation.md | 0 .../claude}/rules/git-hygiene.md | 0 .../claude}/rules/model-routing.md | 0 .../claude}/scripts/agent-routing-hook.sh | 0 .../claude}/scripts/browser-endpoint.sh | 0 .../claude}/scripts/safety-guard-hook.py | 0 .../claude}/scripts/statusline-command.sh | 0 .../claude}/scripts/usage-log-hook.py | 0 .../claude}/scripts/usage-report.py | 0 packages/claude/skills | 1 + {pi => packages/pi}/README.md | 0 {pi => packages/pi}/agent/settings.json | 0 .../pi}/extensions/confirm-destructive.ts | 0 .../pi}/extensions/dirty-repo-guard.ts | 0 {pi => packages/pi}/extensions/handoff.ts | 0 .../pi}/extensions/mac-system-theme.ts | 0 {pi => packages/pi}/extensions/notify.ts | 0 .../pi}/extensions/permission-gate.ts | 0 .../pi}/extensions/protected-paths.ts | 0 {pi => packages/pi}/extensions/status-line.ts | 0 .../pi}/extensions/subagent/README.md | 0 .../pi}/extensions/subagent/agents.ts | 0 .../pi}/extensions/subagent/agents/planner.md | 0 .../extensions/subagent/agents/reviewer.md | 0 .../pi}/extensions/subagent/agents/scout.md | 0 .../pi}/extensions/subagent/agents/worker.md | 0 .../pi}/extensions/subagent/index.ts | 0 .../subagent/prompts/implement-and-review.md | 0 .../extensions/subagent/prompts/implement.md | 0 .../subagent/prompts/scout-and-plan.md | 0 {pi => packages/pi}/extensions/todo.ts | 0 {pi => packages/pi}/prompts/.gitkeep | 0 packages/pi/skills | 1 + scripts/resource-manager.sh | 8 +- scripts/test-safety-guard-hook.py | 4 +- 52 files changed, 51 insertions(+), 162 deletions(-) rename claude/plugins.txt => manifests/claude-plugins.txt (100%) rename {claude => packages/claude}/CLAUDE.md (100%) rename {claude => packages/claude}/agents/bulk-mechanic.md (100%) rename {claude => packages/claude}/agents/bulk-mechanic.source.json (100%) rename {claude => packages/claude}/agents/plan-reviewer.md (100%) rename {claude => packages/claude}/agents/plan-reviewer.source.json (100%) rename {claude => packages/claude}/agents/pr-shepherd.md (100%) rename {claude => packages/claude}/agents/pr-shepherd.source.json (100%) rename {claude => packages/claude}/agents/skill-auditor.md (100%) rename {claude => packages/claude}/agents/skill-auditor.source.json (100%) rename {claude => packages/claude}/agents/thermo-nuclear-code-quality-review-subagent.md (100%) rename {claude => packages/claude}/agents/thermo-nuclear-code-quality-review-subagent.source.json (100%) rename {claude => packages/claude}/agents/thermo-nuclear-review-subagent.md (100%) rename {claude => packages/claude}/agents/thermo-nuclear-review-subagent.source.json (100%) rename {claude => packages/claude}/commands/.gitkeep (100%) rename {claude => packages/claude}/commands/history.md (100%) rename {claude => packages/claude}/rules/delegation.md (100%) rename {claude => packages/claude}/rules/git-hygiene.md (100%) rename {claude => packages/claude}/rules/model-routing.md (100%) rename {claude => packages/claude}/scripts/agent-routing-hook.sh (100%) rename {claude => packages/claude}/scripts/browser-endpoint.sh (100%) rename {claude => packages/claude}/scripts/safety-guard-hook.py (100%) rename {claude => packages/claude}/scripts/statusline-command.sh (100%) rename {claude => packages/claude}/scripts/usage-log-hook.py (100%) rename {claude => packages/claude}/scripts/usage-report.py (100%) create mode 120000 packages/claude/skills rename {pi => packages/pi}/README.md (100%) rename {pi => packages/pi}/agent/settings.json (100%) rename {pi => packages/pi}/extensions/confirm-destructive.ts (100%) rename {pi => packages/pi}/extensions/dirty-repo-guard.ts (100%) rename {pi => packages/pi}/extensions/handoff.ts (100%) rename {pi => packages/pi}/extensions/mac-system-theme.ts (100%) rename {pi => packages/pi}/extensions/notify.ts (100%) rename {pi => packages/pi}/extensions/permission-gate.ts (100%) rename {pi => packages/pi}/extensions/protected-paths.ts (100%) rename {pi => packages/pi}/extensions/status-line.ts (100%) rename {pi => packages/pi}/extensions/subagent/README.md (100%) rename {pi => packages/pi}/extensions/subagent/agents.ts (100%) rename {pi => packages/pi}/extensions/subagent/agents/planner.md (100%) rename {pi => packages/pi}/extensions/subagent/agents/reviewer.md (100%) rename {pi => packages/pi}/extensions/subagent/agents/scout.md (100%) rename {pi => packages/pi}/extensions/subagent/agents/worker.md (100%) rename {pi => packages/pi}/extensions/subagent/index.ts (100%) rename {pi => packages/pi}/extensions/subagent/prompts/implement-and-review.md (100%) rename {pi => packages/pi}/extensions/subagent/prompts/implement.md (100%) rename {pi => packages/pi}/extensions/subagent/prompts/scout-and-plan.md (100%) rename {pi => packages/pi}/extensions/todo.ts (100%) rename {pi => packages/pi}/prompts/.gitkeep (100%) create mode 120000 packages/pi/skills diff --git a/Makefile b/Makefile index d9014d4..bda56e3 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,4 @@ STOW := stow -STOW_DIR := $(CURDIR) PI_TARGET := $(HOME)/.pi # Home stow packages (dotfiles). Flags are a security invariant, not a style @@ -15,15 +14,17 @@ PI_SKILLS_CACHE := /tmp/pi-skills PI_SKILLS_DIR := $(CURDIR)/skills CLAUDE_CONFIG_DIRS := $(HOME)/.claude-personal $(HOME)/.claude-work -SKILL_LINK_TARGETS := $(PI_TARGET) $(CLAUDE_CONFIG_DIRS) -CLAUDE_DIR := $(CURDIR)/claude -PLUGINS_FILE := $(CLAUDE_DIR)/plugins.txt -CLAUDE_MD_FILE := $(CLAUDE_DIR)/CLAUDE.md -COMMANDS_DIR := $(CLAUDE_DIR)/commands -RULES_DIR := $(CLAUDE_DIR)/rules +CLAUDE_DIR := $(CURDIR)/packages/claude +PLUGINS_FILE := $(MANIFESTS)/claude-plugins.txt SCRIPTS_DIR := $(CLAUDE_DIR)/scripts -AGENTS_DIR := $(CLAUDE_DIR)/agents + +# Harness stow packages (claude → each profile, pi → ~/.pi). These stow with +# directory folding ON — whole-dir symlinks are the point, unlike the +# --no-folding invariant that protects the $HOME packages. +HARNESS_STOW := $(STOW) --dir=$(CURDIR)/packages +CLAUDE_PKG_ENTRIES := CLAUDE.md commands rules scripts agents skills +PI_PKG_ENTRIES := agent extensions prompts skills README.md RESOURCE_MANAGER := $(CURDIR)/scripts/resource-manager.sh # NVIDIA SkillSpector release the security scan and its baselines were reviewed @@ -60,9 +61,7 @@ SHELL := /bin/bash brew-install brew-check brew-dump cask-adopt \ go-install npm-install pipx-install tools-install \ stow-link stow-unlink stow-adopt macos-apply raycast-export \ - skills-link skills-unlink claude-md-link claude-md-unlink \ - commands-link commands-unlink rules-link rules-unlink scripts-link scripts-unlink \ - agents-link agents-unlink \ + harness-link harness-unlink \ skills-sync extensions-sync plugins-check plugins-sync \ skills-find skills-add \ skills-fetch skills-materialize skills-list skills-update skills-update-all skills-category skills-delete \ @@ -70,12 +69,9 @@ SHELL := /bin/bash agents-fetch agents-list agents-update agents-update-all agents-category agents-delete \ agents-doctor preflight lint test -install: brew-install stow-link skills-materialize skills-link claude-md-link commands-link rules-link scripts-link agents-link tools-install - mkdir -p $(PI_TARGET) - $(STOW) --dir=$(STOW_DIR) --target=$(PI_TARGET) --adopt pi +install: brew-install stow-link skills-materialize harness-link tools-install -uninstall: stow-unlink skills-unlink claude-md-unlink commands-unlink rules-unlink scripts-unlink agents-unlink - $(STOW) --dir=$(STOW_DIR) --target=$(PI_TARGET) --delete pi +uninstall: stow-unlink harness-unlink brew-install: brew bundle --file=$(BREWFILE) @@ -147,145 +143,36 @@ drift: raycast-export: open "raycast://extensions/raycast/raycast/export-settings-data" -skills-link: - mkdir -p $(PI_SKILLS_DIR) - for target in $(SKILL_LINK_TARGETS); do \ - mkdir -p $$target; \ - link=$$target/skills; \ - if [ -L $$link ]; then \ - rm $$link; \ - elif [ -d $$link ]; then \ - rmdir $$link 2>/dev/null || { echo "skip: $$link is a non-empty directory"; continue; }; \ - fi; \ - ln -s $(PI_SKILLS_DIR) $$link; \ - echo "linked: $$link -> $(PI_SKILLS_DIR)"; \ - done - -skills-unlink: - for target in $(SKILL_LINK_TARGETS); do \ - link=$$target/skills; \ - if [ -L $$link ] && [ "$$(readlink $$link)" = "$(PI_SKILLS_DIR)" ]; then \ - rm $$link; \ - echo "unlinked: $$link"; \ - fi; \ - done - -claude-md-link: - @test -f $(CLAUDE_MD_FILE) || { echo "missing: $(CLAUDE_MD_FILE)"; exit 1; } - for target in $(CLAUDE_CONFIG_DIRS); do \ - mkdir -p $$target; \ - link=$$target/CLAUDE.md; \ - if [ -L $$link ]; then \ - rm $$link; \ - elif [ -f $$link ]; then \ - backup=$$link.bak.$$(date +%Y%m%d%H%M%S); \ - mv $$link $$backup; \ - echo "backed up: $$link -> $$backup"; \ - fi; \ - ln -s $(CLAUDE_MD_FILE) $$link; \ - echo "linked: $$link -> $(CLAUDE_MD_FILE)"; \ - done - -claude-md-unlink: - for target in $(CLAUDE_CONFIG_DIRS); do \ - link=$$target/CLAUDE.md; \ - if [ -L $$link ] && [ "$$(readlink $$link)" = "$(CLAUDE_MD_FILE)" ]; then \ - rm $$link; \ - echo "unlinked: $$link"; \ - fi; \ +# Stow the claude package into each profile and the pi package into ~/.pi. +# Pre-clean removes only SYMLINKS at the managed names (stale links from the +# pre-stow era, or dangling ones after a repo move — including per-file links +# inside real target subdirs); a real file or dir is left +# for stow to conflict on — move it aside yourself (timestamped backup), and do +# not reach for --adopt on the profile dirs. +harness-link: + @for d in $(CLAUDE_CONFIG_DIRS); do \ + mkdir -p $$d; \ + for entry in $(CLAUDE_PKG_ENTRIES); do \ + if [ -L $$d/$$entry ]; then rm $$d/$$entry; fi; \ + done; \ + find $$d -maxdepth 2 -type l ! -exec test -e {} \; -delete; \ + $(HARNESS_STOW) --target=$$d --restow claude; \ + echo "stowed: claude -> $$d"; \ done - -commands-link: - mkdir -p $(COMMANDS_DIR) - for target in $(CLAUDE_CONFIG_DIRS); do \ - mkdir -p $$target; \ - link=$$target/commands; \ - if [ -L $$link ]; then \ - rm $$link; \ - elif [ -d $$link ]; then \ - rmdir $$link 2>/dev/null || { echo "skip: $$link is a non-empty directory"; continue; }; \ - fi; \ - ln -s $(COMMANDS_DIR) $$link; \ - echo "linked: $$link -> $(COMMANDS_DIR)"; \ + @mkdir -p $(PI_TARGET) + @for entry in $(PI_PKG_ENTRIES); do \ + if [ -L $(PI_TARGET)/$$entry ]; then rm $(PI_TARGET)/$$entry; fi; \ done + @find $(PI_TARGET) -maxdepth 2 -type l ! -exec test -e {} \; -delete + @$(HARNESS_STOW) --target=$(PI_TARGET) --adopt pi + @echo "stowed: pi -> $(PI_TARGET)" -commands-unlink: - for target in $(CLAUDE_CONFIG_DIRS); do \ - link=$$target/commands; \ - if [ -L $$link ] && [ "$$(readlink $$link)" = "$(COMMANDS_DIR)" ]; then \ - rm $$link; \ - echo "unlinked: $$link"; \ - fi; \ - done - -rules-link: - mkdir -p $(RULES_DIR) - for target in $(CLAUDE_CONFIG_DIRS); do \ - mkdir -p $$target; \ - link=$$target/rules; \ - if [ -L $$link ]; then \ - rm $$link; \ - elif [ -d $$link ]; then \ - rmdir $$link 2>/dev/null || { echo "skip: $$link is a non-empty directory"; continue; }; \ - fi; \ - ln -s $(RULES_DIR) $$link; \ - echo "linked: $$link -> $(RULES_DIR)"; \ - done - -rules-unlink: - for target in $(CLAUDE_CONFIG_DIRS); do \ - link=$$target/rules; \ - if [ -L $$link ] && [ "$$(readlink $$link)" = "$(RULES_DIR)" ]; then \ - rm $$link; \ - echo "unlinked: $$link"; \ - fi; \ - done - -scripts-link: - mkdir -p $(SCRIPTS_DIR) - for target in $(CLAUDE_CONFIG_DIRS); do \ - mkdir -p $$target; \ - link=$$target/scripts; \ - if [ -L $$link ]; then \ - rm $$link; \ - elif [ -d $$link ]; then \ - rmdir $$link 2>/dev/null || { echo "skip: $$link is a non-empty directory"; continue; }; \ - fi; \ - ln -s $(SCRIPTS_DIR) $$link; \ - echo "linked: $$link -> $(SCRIPTS_DIR)"; \ - done - -scripts-unlink: - for target in $(CLAUDE_CONFIG_DIRS); do \ - link=$$target/scripts; \ - if [ -L $$link ] && [ "$$(readlink $$link)" = "$(SCRIPTS_DIR)" ]; then \ - rm $$link; \ - echo "unlinked: $$link"; \ - fi; \ - done - -agents-link: - mkdir -p $(AGENTS_DIR) - for target in $(CLAUDE_CONFIG_DIRS); do \ - mkdir -p $$target; \ - link=$$target/agents; \ - if [ -L $$link ]; then \ - rm $$link; \ - elif [ -d $$link ]; then \ - rmdir $$link 2>/dev/null || { echo "skip: $$link is a non-empty directory"; continue; }; \ - fi; \ - ln -s $(AGENTS_DIR) $$link; \ - echo "linked: $$link -> $(AGENTS_DIR)"; \ - done - -agents-unlink: - for target in $(CLAUDE_CONFIG_DIRS); do \ - link=$$target/agents; \ - if [ -L $$link ] && [ "$$(readlink $$link)" = "$(AGENTS_DIR)" ]; then \ - rm $$link; \ - echo "unlinked: $$link"; \ - fi; \ +harness-unlink: + @for d in $(CLAUDE_CONFIG_DIRS); do \ + $(HARNESS_STOW) --target=$$d --delete claude && echo "unstowed: claude -> $$d"; \ done + @$(HARNESS_STOW) --target=$(PI_TARGET) --delete pi + @echo "unstowed: pi -> $(PI_TARGET)" plugins-check: @test -f $(PLUGINS_FILE) || { echo "missing: $(PLUGINS_FILE)"; exit 1; } @@ -368,7 +255,7 @@ extensions-sync: # the result into skills/ through resource-manager.sh, so each lands with a # .source.json and stays manageable by skills-list / skills-update / skills-delete. # The CLI is used only as a resolver/fetcher — it never installs per-agent, so -# the two Claude profiles and claude/agents/ subagents are unaffected. +# the two Claude profiles and packages/claude/agents/ subagents are unaffected. # Set GITHUB_TOKEN (or have `gh` logged in) to avoid anonymous rate limits. skills-find: @@ -385,7 +272,7 @@ skills-add: $(if $(FORCE),--force) # --- Source management (scripts/resource-manager.sh) ----------------------- -# Fetch one skill (dir under skills/) or agent (.md under claude/agents/) from +# Fetch one skill (dir under skills/) or agent (.md under packages/claude/agents/) from # any repo/subpath, tracking its source in a .source.json sidecar so it can be # listed, updated, and deleted. @@ -441,7 +328,7 @@ suites-catalog: context-budget: @$(RESOURCE_MANAGER) --kind skill budget $(if $(CHECK),--check) $(if $(TOP),--top $(TOP)) -# Aggregate the usage telemetry (claude/scripts/usage-log-hook.py) of every +# Aggregate the usage telemetry (packages/claude/scripts/usage-log-hook.py) of every # profile: subagent spend by agent type × model, per-day cache-hit ratio. # SINCE=N limits to the last N days (default 30). usage-report: @@ -503,8 +390,8 @@ agents-doctor: preflight: skills-doctor agents-doctor lint lint: - @for f in scripts/*.sh claude/scripts/*.sh; do bash -n "$$f" || exit 1; done - @python3 -m py_compile scripts/*.py claude/scripts/*.py + @for f in scripts/*.sh packages/claude/scripts/*.sh; do bash -n "$$f" || exit 1; done + @python3 -m py_compile scripts/*.py packages/claude/scripts/*.py # The repo's own regression tests: every scripts/test-*.sh and scripts/test-*.py. test: diff --git a/claude/plugins.txt b/manifests/claude-plugins.txt similarity index 100% rename from claude/plugins.txt rename to manifests/claude-plugins.txt diff --git a/claude/CLAUDE.md b/packages/claude/CLAUDE.md similarity index 100% rename from claude/CLAUDE.md rename to packages/claude/CLAUDE.md diff --git a/claude/agents/bulk-mechanic.md b/packages/claude/agents/bulk-mechanic.md similarity index 100% rename from claude/agents/bulk-mechanic.md rename to packages/claude/agents/bulk-mechanic.md diff --git a/claude/agents/bulk-mechanic.source.json b/packages/claude/agents/bulk-mechanic.source.json similarity index 100% rename from claude/agents/bulk-mechanic.source.json rename to packages/claude/agents/bulk-mechanic.source.json diff --git a/claude/agents/plan-reviewer.md b/packages/claude/agents/plan-reviewer.md similarity index 100% rename from claude/agents/plan-reviewer.md rename to packages/claude/agents/plan-reviewer.md diff --git a/claude/agents/plan-reviewer.source.json b/packages/claude/agents/plan-reviewer.source.json similarity index 100% rename from claude/agents/plan-reviewer.source.json rename to packages/claude/agents/plan-reviewer.source.json diff --git a/claude/agents/pr-shepherd.md b/packages/claude/agents/pr-shepherd.md similarity index 100% rename from claude/agents/pr-shepherd.md rename to packages/claude/agents/pr-shepherd.md diff --git a/claude/agents/pr-shepherd.source.json b/packages/claude/agents/pr-shepherd.source.json similarity index 100% rename from claude/agents/pr-shepherd.source.json rename to packages/claude/agents/pr-shepherd.source.json diff --git a/claude/agents/skill-auditor.md b/packages/claude/agents/skill-auditor.md similarity index 100% rename from claude/agents/skill-auditor.md rename to packages/claude/agents/skill-auditor.md diff --git a/claude/agents/skill-auditor.source.json b/packages/claude/agents/skill-auditor.source.json similarity index 100% rename from claude/agents/skill-auditor.source.json rename to packages/claude/agents/skill-auditor.source.json diff --git a/claude/agents/thermo-nuclear-code-quality-review-subagent.md b/packages/claude/agents/thermo-nuclear-code-quality-review-subagent.md similarity index 100% rename from claude/agents/thermo-nuclear-code-quality-review-subagent.md rename to packages/claude/agents/thermo-nuclear-code-quality-review-subagent.md diff --git a/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json b/packages/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json similarity index 100% rename from claude/agents/thermo-nuclear-code-quality-review-subagent.source.json rename to packages/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json diff --git a/claude/agents/thermo-nuclear-review-subagent.md b/packages/claude/agents/thermo-nuclear-review-subagent.md similarity index 100% rename from claude/agents/thermo-nuclear-review-subagent.md rename to packages/claude/agents/thermo-nuclear-review-subagent.md diff --git a/claude/agents/thermo-nuclear-review-subagent.source.json b/packages/claude/agents/thermo-nuclear-review-subagent.source.json similarity index 100% rename from claude/agents/thermo-nuclear-review-subagent.source.json rename to packages/claude/agents/thermo-nuclear-review-subagent.source.json diff --git a/claude/commands/.gitkeep b/packages/claude/commands/.gitkeep similarity index 100% rename from claude/commands/.gitkeep rename to packages/claude/commands/.gitkeep diff --git a/claude/commands/history.md b/packages/claude/commands/history.md similarity index 100% rename from claude/commands/history.md rename to packages/claude/commands/history.md diff --git a/claude/rules/delegation.md b/packages/claude/rules/delegation.md similarity index 100% rename from claude/rules/delegation.md rename to packages/claude/rules/delegation.md diff --git a/claude/rules/git-hygiene.md b/packages/claude/rules/git-hygiene.md similarity index 100% rename from claude/rules/git-hygiene.md rename to packages/claude/rules/git-hygiene.md diff --git a/claude/rules/model-routing.md b/packages/claude/rules/model-routing.md similarity index 100% rename from claude/rules/model-routing.md rename to packages/claude/rules/model-routing.md diff --git a/claude/scripts/agent-routing-hook.sh b/packages/claude/scripts/agent-routing-hook.sh similarity index 100% rename from claude/scripts/agent-routing-hook.sh rename to packages/claude/scripts/agent-routing-hook.sh diff --git a/claude/scripts/browser-endpoint.sh b/packages/claude/scripts/browser-endpoint.sh similarity index 100% rename from claude/scripts/browser-endpoint.sh rename to packages/claude/scripts/browser-endpoint.sh diff --git a/claude/scripts/safety-guard-hook.py b/packages/claude/scripts/safety-guard-hook.py similarity index 100% rename from claude/scripts/safety-guard-hook.py rename to packages/claude/scripts/safety-guard-hook.py diff --git a/claude/scripts/statusline-command.sh b/packages/claude/scripts/statusline-command.sh similarity index 100% rename from claude/scripts/statusline-command.sh rename to packages/claude/scripts/statusline-command.sh diff --git a/claude/scripts/usage-log-hook.py b/packages/claude/scripts/usage-log-hook.py similarity index 100% rename from claude/scripts/usage-log-hook.py rename to packages/claude/scripts/usage-log-hook.py diff --git a/claude/scripts/usage-report.py b/packages/claude/scripts/usage-report.py similarity index 100% rename from claude/scripts/usage-report.py rename to packages/claude/scripts/usage-report.py diff --git a/packages/claude/skills b/packages/claude/skills new file mode 120000 index 0000000..5dcab58 --- /dev/null +++ b/packages/claude/skills @@ -0,0 +1 @@ +../../skills \ No newline at end of file diff --git a/pi/README.md b/packages/pi/README.md similarity index 100% rename from pi/README.md rename to packages/pi/README.md diff --git a/pi/agent/settings.json b/packages/pi/agent/settings.json similarity index 100% rename from pi/agent/settings.json rename to packages/pi/agent/settings.json diff --git a/pi/extensions/confirm-destructive.ts b/packages/pi/extensions/confirm-destructive.ts similarity index 100% rename from pi/extensions/confirm-destructive.ts rename to packages/pi/extensions/confirm-destructive.ts diff --git a/pi/extensions/dirty-repo-guard.ts b/packages/pi/extensions/dirty-repo-guard.ts similarity index 100% rename from pi/extensions/dirty-repo-guard.ts rename to packages/pi/extensions/dirty-repo-guard.ts diff --git a/pi/extensions/handoff.ts b/packages/pi/extensions/handoff.ts similarity index 100% rename from pi/extensions/handoff.ts rename to packages/pi/extensions/handoff.ts diff --git a/pi/extensions/mac-system-theme.ts b/packages/pi/extensions/mac-system-theme.ts similarity index 100% rename from pi/extensions/mac-system-theme.ts rename to packages/pi/extensions/mac-system-theme.ts diff --git a/pi/extensions/notify.ts b/packages/pi/extensions/notify.ts similarity index 100% rename from pi/extensions/notify.ts rename to packages/pi/extensions/notify.ts diff --git a/pi/extensions/permission-gate.ts b/packages/pi/extensions/permission-gate.ts similarity index 100% rename from pi/extensions/permission-gate.ts rename to packages/pi/extensions/permission-gate.ts diff --git a/pi/extensions/protected-paths.ts b/packages/pi/extensions/protected-paths.ts similarity index 100% rename from pi/extensions/protected-paths.ts rename to packages/pi/extensions/protected-paths.ts diff --git a/pi/extensions/status-line.ts b/packages/pi/extensions/status-line.ts similarity index 100% rename from pi/extensions/status-line.ts rename to packages/pi/extensions/status-line.ts diff --git a/pi/extensions/subagent/README.md b/packages/pi/extensions/subagent/README.md similarity index 100% rename from pi/extensions/subagent/README.md rename to packages/pi/extensions/subagent/README.md diff --git a/pi/extensions/subagent/agents.ts b/packages/pi/extensions/subagent/agents.ts similarity index 100% rename from pi/extensions/subagent/agents.ts rename to packages/pi/extensions/subagent/agents.ts diff --git a/pi/extensions/subagent/agents/planner.md b/packages/pi/extensions/subagent/agents/planner.md similarity index 100% rename from pi/extensions/subagent/agents/planner.md rename to packages/pi/extensions/subagent/agents/planner.md diff --git a/pi/extensions/subagent/agents/reviewer.md b/packages/pi/extensions/subagent/agents/reviewer.md similarity index 100% rename from pi/extensions/subagent/agents/reviewer.md rename to packages/pi/extensions/subagent/agents/reviewer.md diff --git a/pi/extensions/subagent/agents/scout.md b/packages/pi/extensions/subagent/agents/scout.md similarity index 100% rename from pi/extensions/subagent/agents/scout.md rename to packages/pi/extensions/subagent/agents/scout.md diff --git a/pi/extensions/subagent/agents/worker.md b/packages/pi/extensions/subagent/agents/worker.md similarity index 100% rename from pi/extensions/subagent/agents/worker.md rename to packages/pi/extensions/subagent/agents/worker.md diff --git a/pi/extensions/subagent/index.ts b/packages/pi/extensions/subagent/index.ts similarity index 100% rename from pi/extensions/subagent/index.ts rename to packages/pi/extensions/subagent/index.ts diff --git a/pi/extensions/subagent/prompts/implement-and-review.md b/packages/pi/extensions/subagent/prompts/implement-and-review.md similarity index 100% rename from pi/extensions/subagent/prompts/implement-and-review.md rename to packages/pi/extensions/subagent/prompts/implement-and-review.md diff --git a/pi/extensions/subagent/prompts/implement.md b/packages/pi/extensions/subagent/prompts/implement.md similarity index 100% rename from pi/extensions/subagent/prompts/implement.md rename to packages/pi/extensions/subagent/prompts/implement.md diff --git a/pi/extensions/subagent/prompts/scout-and-plan.md b/packages/pi/extensions/subagent/prompts/scout-and-plan.md similarity index 100% rename from pi/extensions/subagent/prompts/scout-and-plan.md rename to packages/pi/extensions/subagent/prompts/scout-and-plan.md diff --git a/pi/extensions/todo.ts b/packages/pi/extensions/todo.ts similarity index 100% rename from pi/extensions/todo.ts rename to packages/pi/extensions/todo.ts diff --git a/pi/prompts/.gitkeep b/packages/pi/prompts/.gitkeep similarity index 100% rename from pi/prompts/.gitkeep rename to packages/pi/prompts/.gitkeep diff --git a/packages/pi/skills b/packages/pi/skills new file mode 120000 index 0000000..5dcab58 --- /dev/null +++ b/packages/pi/skills @@ -0,0 +1 @@ +../../skills \ No newline at end of file diff --git a/scripts/resource-manager.sh b/scripts/resource-manager.sh index 90f0c4d..54cbef4 100755 --- a/scripts/resource-manager.sh +++ b/scripts/resource-manager.sh @@ -4,7 +4,7 @@ # (skills or agents) from arbitrary git repos, tracking each resource's source. # # A "skill" is a directory containing SKILL.md, vendored under skills/. -# An "agent" is a single .md file, vendored under claude/agents/. +# An "agent" is a single .md file, vendored under packages/claude/agents/. # # VENDORED SKILLS are recorded in a single committed manifest and their files # are NOT committed — they are materialized from their pinned commit on install: @@ -18,7 +18,7 @@ # local sidecar: {"repo": null[, "category"]} # remote sidecar (agents): {"repo","subpath","ref","commit","fetched_at"[,"category"]} # skill sidecar: skills//.source.json (inside the dir) -# agent sidecar: claude/agents/.source.json (sibling of the .md) +# agent sidecar: packages/claude/agents/.source.json (sibling of the .md) # A resource with neither a manifest entry nor a sidecar is "unmanaged". # # Usage: @@ -68,7 +68,7 @@ SCAN_BASELINE_DIR="$REPO_ROOT/security/skillspector" # per-skill SkillSpector configure_kind() { case "$KIND" in skill) RESOURCE_ROOT="$REPO_ROOT/skills"; MANIFEST="$RESOURCE_ROOT/vendored.json" ;; - agent) RESOURCE_ROOT="$REPO_ROOT/claude/agents" ;; + agent) RESOURCE_ROOT="$REPO_ROOT/packages/claude/agents" ;; *) die "missing or unknown --kind '$KIND' (expected skill|agent)" ;; esac } @@ -1015,7 +1015,7 @@ cmd_budget() { esac done [[ "$limit" =~ ^[1-9][0-9]*$ ]] || die "budget: limit must be a positive integer (got '$limit'; set CONTEXT_BUDGET_TOKENS or --limit)" - local claude_dir="$REPO_ROOT/claude" + local claude_dir="$REPO_ROOT/packages/claude" # Each segment is "N items, T estimated tokens"; sum_segment reads whole # files, sum_descs reads "name: description" strings from stdin, one per line. sum_segment() { local t=0 n=0 f; for f in "$@"; do [[ -f "$f" ]] || continue; t=$((t + $(est_tokens "$(cat "$f")"))); n=$((n + 1)); done; echo "$t $n"; } diff --git a/scripts/test-safety-guard-hook.py b/scripts/test-safety-guard-hook.py index b0ff778..af905fc 100755 --- a/scripts/test-safety-guard-hook.py +++ b/scripts/test-safety-guard-hook.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Table-driven test for claude/scripts/safety-guard-hook.py. +"""Table-driven test for packages/claude/scripts/safety-guard-hook.py. Each case: (tool, tool_input, expected decision). Runs the hook as a subprocess with a stock PATH and a temp CLAUDE_CONFIG_DIR, exactly as Claude Code would. @@ -15,7 +15,7 @@ import unittest from pathlib import Path -HOOK = Path(__file__).resolve().parent.parent / "claude" / "scripts" / "safety-guard-hook.py" +HOOK = Path(__file__).resolve().parent.parent / "packages" / "claude" / "scripts" / "safety-guard-hook.py" CASES = [ # --- Bash: deny From eca9baee65e93db29c55445968e60f6a2feed11d Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 21:47:41 +0530 Subject: [PATCH 48/51] Point cross-repo references at the merged repo doctor checks harness symlink health in-repo instead of a sibling clone; bootstrap links the harness directly; the zsh modules export DOTFILES_DIR and source claude-multi-account.sh from this repo; suite pages and the skills.sh install repo say sanketsudake/dotfiles. The never-committed runtime config dir ~/.config/harness-configs/ keeps its name so live machine configs stay valid. --- Brewfile | 6 +++--- bootstrap.sh | 10 ++++----- packages/zsh/dot-config/zsh/00-env.zsh | 2 +- packages/zsh/dot-config/zsh/40-tools.zsh | 2 +- packages/zsh/dot-config/zsh/50-harness.zsh | 6 +++--- scripts/doctor.sh | 25 +++++++++++----------- scripts/resource-manager.sh | 2 +- suites/go-ci-health/README.md | 4 ++-- suites/hugo-site/README.md | 4 ++-- suites/oss-maintainer/README.md | 4 ++-- suites/pr-shepherding/README.md | 4 ++-- suites/second-brain/README.md | 4 ++-- 12 files changed, 37 insertions(+), 36 deletions(-) diff --git a/Brewfile b/Brewfile index 2fe9674..dd4e8a8 100644 --- a/Brewfile +++ b/Brewfile @@ -23,11 +23,11 @@ brew "ripgrep" brew "tree" brew "wget" -# --- harness-configs prereqs (stow, jq, gh, node-via-nvm, python) ----------- -brew "stow" # dotfiles + harness-configs symlink manager (needs >= 2.4.0) +# --- AI-harness prereqs (stow, jq, gh, node-via-nvm, python) ---------------- +brew "stow" # dotfiles + harness symlink manager (needs >= 2.4.0) brew "jq" brew "gh" -brew "nvm" # provides node/npx for harness-configs skill tooling +brew "nvm" # provides node/npx for skill-vendoring tooling brew "python@3.13" brew "mas" # Mac App Store CLI (for the mas entries below) diff --git a/bootstrap.sh b/bootstrap.sh index e863158..eb5be29 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # New-Mac bootstrap: Xcode CLT -> Homebrew -> clone dotfiles -> brew bundle -> -# stow links -> harness-configs -> doctor. Idempotent; every step checks first. +# stow links -> harness links -> doctor. Idempotent; every step checks first. # # Preferred invocation (casks may prompt for sudo, which clashes with curl|bash # sharing stdin with the script): @@ -74,10 +74,10 @@ if [ -d "$backup_dir" ]; then echo "!! into ~/.config/zsh/90-local.zsh (gitignored), then delete the backup." fi -step "harness-configs (AI harness setup)" -make harness-install || { - echo "!! harness-configs setup failed (no GitHub access yet?)." - echo "!! After 'gh auth login' / SSH keys, run: make harness-install" +step "AI harness (claude profiles + pi)" +make skills-materialize harness-link || { + echo "!! harness link failed (skills materialize needs network)." + echo "!! Re-run: make skills-materialize harness-link" } step "Doctor" diff --git a/packages/zsh/dot-config/zsh/00-env.zsh b/packages/zsh/dot-config/zsh/00-env.zsh index 26a7099..50faed4 100644 --- a/packages/zsh/dot-config/zsh/00-env.zsh +++ b/packages/zsh/dot-config/zsh/00-env.zsh @@ -1,3 +1,3 @@ export DOTFILES="$HOME/personal/dotfiles" -export HARNESS_DIR="$HOME/personal/harness-configs" +export DOTFILES_DIR="$HOME/personal/dotfiles" export CPPFLAGS="-I${HOMEBREW_PREFIX:-/opt/homebrew}/opt/openjdk/include" diff --git a/packages/zsh/dot-config/zsh/40-tools.zsh b/packages/zsh/dot-config/zsh/40-tools.zsh index f8de175..de18da5 100644 --- a/packages/zsh/dot-config/zsh/40-tools.zsh +++ b/packages/zsh/dot-config/zsh/40-tools.zsh @@ -9,7 +9,7 @@ _zsh_autosuggest="${HOMEBREW_PREFIX:-/opt/homebrew}/share/zsh-autosuggestions/zs [ -r "$_zsh_autosuggest" ] && source "$_zsh_autosuggest" unset _zsh_autosuggest -# nvm — node version manager (also provides npx for harness-configs tooling). +# nvm — node version manager (also provides npx for the skill-vendoring tooling). _nvm_dir="${HOMEBREW_PREFIX:-/opt/homebrew}/opt/nvm" export NVM_DIR="$HOME/.nvm" [ -s "$_nvm_dir/nvm.sh" ] && \. "$_nvm_dir/nvm.sh" diff --git a/packages/zsh/dot-config/zsh/50-harness.zsh b/packages/zsh/dot-config/zsh/50-harness.zsh index 5668dc1..7411d9c 100644 --- a/packages/zsh/dot-config/zsh/50-harness.zsh +++ b/packages/zsh/dot-config/zsh/50-harness.zsh @@ -1,5 +1,5 @@ -# AI-harness shell functions (pclaude/wclaude/claude wrappers) from the sibling -# harness-configs repo; skipped silently until that repo is cloned (make harness-install). -_harness_sh="${HARNESS_DIR:-$HOME/personal/harness-configs}/scripts/claude-multi-account.sh" +# AI-harness shell functions (pclaude/wclaude/claude wrappers) from this +# repo's scripts/; skipped silently until the repo is cloned. +_harness_sh="${DOTFILES_DIR:-$HOME/personal/dotfiles}/scripts/claude-multi-account.sh" [ -r "$_harness_sh" ] && source "$_harness_sh" unset _harness_sh diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 65ac13d..6f58ca1 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -3,7 +3,6 @@ set -uo pipefail REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -HARNESS_DIR="${HARNESS_DIR:-$(cd "$REPO_DIR/.." && pwd)/harness-configs}" FAIL=0 ok() { printf ' ok: %s\n' "$*"; } @@ -29,8 +28,8 @@ if command -v stow >/dev/null; then else bad "stow not found" fi -# npx is only needed for harness-configs' optional skills-find/vendor targets. -if command -v npx >/dev/null; then ok "npx ($(command -v npx))"; else warn "npx not found — run: nvm install --lts (needed only for harness-configs skill vendoring)"; fi +# npx is only needed for the optional skills-find/vendor targets. +if command -v npx >/dev/null; then ok "npx ($(command -v npx))"; else warn "npx not found — run: nvm install --lts (needed only for skill vendoring)"; fi echo "== brew bundle ==" if brew bundle check --file="$REPO_DIR/Brewfile" >/dev/null 2>&1; then @@ -103,17 +102,19 @@ else warn "broken symlinks (stale stow links or removed targets):"$'\n'"$(printf '%s\n' "$broken" | sed 's/^/ /')" fi -echo "== harness-configs ==" -if [ -d "$HARNESS_DIR/.git" ]; then - ok "repo present at $HARNESS_DIR" - if [ -r "$HARNESS_DIR/scripts/claude-multi-account.sh" ]; then - ok "claude-multi-account.sh readable (sourced by ~/.config/zsh/50-harness.zsh)" - else - bad "claude-multi-account.sh missing" - fi +echo "== AI harness ==" +if [ -r "$REPO_DIR/scripts/claude-multi-account.sh" ]; then + ok "claude-multi-account.sh readable (sourced by ~/.config/zsh/50-harness.zsh)" else - bad "harness-configs not found at $HARNESS_DIR — run: make harness-install" + bad "claude-multi-account.sh missing" fi +for t in "$HOME/.claude-personal/CLAUDE.md" "$HOME/.claude-work/CLAUDE.md" "$HOME/.pi/skills"; do + r="$(resolve "$t")" + case "$r" in + "$REPO_DIR"/packages/*) ok "$t -> repo" ;; + *) bad "$t does not resolve into $REPO_DIR/packages — run: make harness-link" ;; + esac +done echo "" if [ "$FAIL" -eq 0 ]; then echo "doctor: all checks passed"; else echo "doctor: FAILURES above"; fi diff --git a/scripts/resource-manager.sh b/scripts/resource-manager.sh index 54cbef4..ff99adf 100755 --- a/scripts/resource-manager.sh +++ b/scripts/resource-manager.sh @@ -853,7 +853,7 @@ cmd_catalog() { # command) and the Suites index in the top-level README.md. SUITES_ROOT="$REPO_ROOT/suites" -SUITE_INSTALL_REPO="sanketsudake/harness-configs" +SUITE_INSTALL_REPO="sanketsudake/dotfiles" SUITE_BEGIN='' SUITE_END='' SUITES_INDEX_BEGIN='' diff --git a/suites/go-ci-health/README.md b/suites/go-ci-health/README.md index afa48eb..7b8354f 100644 --- a/suites/go-ci-health/README.md +++ b/suites/go-ci-health/README.md @@ -67,7 +67,7 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h With the [skills.sh](https://www.skills.sh/) CLI (needs Node.js): ```bash -npx skills add sanketsudake/harness-configs \ +npx skills add sanketsudake/dotfiles \ --skill debug-ci \ --skill watch-ci \ --skill analyze-go-pprof \ @@ -89,4 +89,4 @@ npx skills add sanketsudake/harness-configs \ --- -Part of [harness-configs](../../README.md); browse all skills in the [catalog](../../skills/README.md). +Part of [dotfiles](../../README.md); browse all skills in the [catalog](../../skills/README.md). diff --git a/suites/hugo-site/README.md b/suites/hugo-site/README.md index 9a09a3e..81eed9a 100644 --- a/suites/hugo-site/README.md +++ b/suites/hugo-site/README.md @@ -72,7 +72,7 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h With the [skills.sh](https://www.skills.sh/) CLI (needs Node.js): ```bash -npx skills add sanketsudake/harness-configs \ +npx skills add sanketsudake/dotfiles \ --skill write-hugo-blog-post \ --skill author-mermaid-diagram \ --skill generate-og-images \ @@ -96,4 +96,4 @@ npx skills add sanketsudake/harness-configs \ --- -Part of [harness-configs](../../README.md); browse all skills in the [catalog](../../skills/README.md). +Part of [dotfiles](../../README.md); browse all skills in the [catalog](../../skills/README.md). diff --git a/suites/oss-maintainer/README.md b/suites/oss-maintainer/README.md index 6e31f0a..6d94254 100644 --- a/suites/oss-maintainer/README.md +++ b/suites/oss-maintainer/README.md @@ -56,7 +56,7 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h With the [skills.sh](https://www.skills.sh/) CLI (needs Node.js): ```bash -npx skills add sanketsudake/harness-configs \ +npx skills add sanketsudake/dotfiles \ --skill triage-gh-backlog \ --skill remediate-codeql-alerts \ --skill go-deps-security-sweep \ @@ -76,4 +76,4 @@ npx skills add sanketsudake/harness-configs \ --- -Part of [harness-configs](../../README.md); browse all skills in the [catalog](../../skills/README.md). +Part of [dotfiles](../../README.md); browse all skills in the [catalog](../../skills/README.md). diff --git a/suites/pr-shepherding/README.md b/suites/pr-shepherding/README.md index de2012a..c03586c 100644 --- a/suites/pr-shepherding/README.md +++ b/suites/pr-shepherding/README.md @@ -59,7 +59,7 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h With the [skills.sh](https://www.skills.sh/) CLI (needs Node.js): ```bash -npx skills add sanketsudake/harness-configs \ +npx skills add sanketsudake/dotfiles \ --skill make-pr-easy-to-review \ --skill deslop \ --skill resolve-bot-review-threads \ @@ -77,4 +77,4 @@ npx skills add sanketsudake/harness-configs \ --- -Part of [harness-configs](../../README.md); browse all skills in the [catalog](../../skills/README.md). +Part of [dotfiles](../../README.md); browse all skills in the [catalog](../../skills/README.md). diff --git a/suites/second-brain/README.md b/suites/second-brain/README.md index a067b2f..a8e7c54 100644 --- a/suites/second-brain/README.md +++ b/suites/second-brain/README.md @@ -61,7 +61,7 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h With the [skills.sh](https://www.skills.sh/) CLI (needs Node.js): ```bash -npx skills add sanketsudake/harness-configs \ +npx skills add sanketsudake/dotfiles \ --skill second-brain \ --skill readwise-second-brain-sync \ --skill second-brain-ingest \ @@ -83,4 +83,4 @@ Optional companion: if you use Readwise, also install [`readwise-cli`](../../ski --- -Part of [harness-configs](../../README.md); browse all skills in the [catalog](../../skills/README.md). +Part of [dotfiles](../../README.md); browse all skills in the [catalog](../../skills/README.md). From 84780160833e022e4b21012b507df5abbf328041 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 22:05:13 +0530 Subject: [PATCH 49/51] Consolidate all source tracking into one sources.toml manifest skills/vendored.json, the committed authored-skill .source.json sidecars, and the agent sidecars collapse into a single sources.toml ([[skill]] and [[agent]] arrays), read and written through the new stdlib-only scripts/toml-manifest.py with a deterministic writer so diffs stay per-entry. resource-manager.sh keeps its jq pipelines but round-trips the full document at the persistence boundary; agents gain first-class manifest support across every verb. The gitignored .source.json inside a vendored skill dir remains, as the materialize marker only. python >= 3.11 (tomllib) becomes a preflight- and doctor-checked dependency, pinned via the Makefile PYTHON variable. --- CLAUDE.md | 93 +-- Makefile | 26 +- README.md | 2 +- .../claude/agents/bulk-mechanic.source.json | 4 - .../claude/agents/plan-reviewer.source.json | 4 - .../claude/agents/pr-shepherd.source.json | 4 - packages/claude/agents/skill-auditor.md | 4 +- .../claude/agents/skill-auditor.source.json | 4 - ...r-code-quality-review-subagent.source.json | 8 - ...thermo-nuclear-review-subagent.source.json | 8 - scripts/doctor.sh | 6 + scripts/resource-manager.sh | 261 ++++---- scripts/skills-vendor.sh | 4 +- scripts/test-resource-manager.sh | 15 +- scripts/toml-manifest.py | 82 +++ skills/README.md | 2 +- skills/add-llms-txt/.source.json | 5 - skills/analyze-go-pprof/.source.json | 5 - skills/analyze-prometheus-tsdb/.source.json | 5 - skills/apply-workday-leave/.source.json | 4 - skills/approve-workday-tasks/.source.json | 4 - skills/audit-static-site/.source.json | 5 - skills/author-mermaid-diagram/.source.json | 5 - skills/author-security-advisory/.source.json | 5 - skills/bump-ci-tool-versions/.source.json | 5 - skills/bump-hugo-versions/.source.json | 5 - skills/debug-ci/.source.json | 5 - skills/fill-workday-timesheet/.source.json | 4 - skills/generate-og-images/.source.json | 5 - skills/go-deps-security-sweep/.source.json | 5 - skills/harvest-automation/.source.json | 5 - skills/harvest-automation/SKILL.md | 4 +- skills/improve-codecov-coverage/.source.json | 5 - skills/list-week-meetings/.source.json | 4 - skills/login-microsoft-sso/.source.json | 4 - skills/login-microsoft-sso/SKILL.md | 2 +- skills/optimize-svg/.source.json | 5 - skills/record-engage-activity/.source.json | 4 - skills/remediate-codeql-alerts/.source.json | 5 - skills/report-site-analytics/.source.json | 5 - .../resolve-bot-review-threads/.source.json | 5 - skills/review-battery/.source.json | 5 - .../source-code-for-gh-advisory/.source.json | 5 - skills/triage-gh-backlog/.source.json | 5 - skills/tufte-information-design/.source.json | 4 - skills/vendored.json | 380 ------------ skills/verify-hugo-build/.source.json | 5 - skills/watch-ci/.source.json | 5 - skills/write-hugo-blog-post/.source.json | 5 - sources.toml | 559 ++++++++++++++++++ 50 files changed, 862 insertions(+), 753 deletions(-) delete mode 100644 packages/claude/agents/bulk-mechanic.source.json delete mode 100644 packages/claude/agents/plan-reviewer.source.json delete mode 100644 packages/claude/agents/pr-shepherd.source.json delete mode 100644 packages/claude/agents/skill-auditor.source.json delete mode 100644 packages/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json delete mode 100644 packages/claude/agents/thermo-nuclear-review-subagent.source.json create mode 100755 scripts/toml-manifest.py delete mode 100644 skills/add-llms-txt/.source.json delete mode 100644 skills/analyze-go-pprof/.source.json delete mode 100644 skills/analyze-prometheus-tsdb/.source.json delete mode 100644 skills/apply-workday-leave/.source.json delete mode 100644 skills/approve-workday-tasks/.source.json delete mode 100644 skills/audit-static-site/.source.json delete mode 100644 skills/author-mermaid-diagram/.source.json delete mode 100644 skills/author-security-advisory/.source.json delete mode 100644 skills/bump-ci-tool-versions/.source.json delete mode 100644 skills/bump-hugo-versions/.source.json delete mode 100644 skills/debug-ci/.source.json delete mode 100644 skills/fill-workday-timesheet/.source.json delete mode 100644 skills/generate-og-images/.source.json delete mode 100644 skills/go-deps-security-sweep/.source.json delete mode 100644 skills/harvest-automation/.source.json delete mode 100644 skills/improve-codecov-coverage/.source.json delete mode 100644 skills/list-week-meetings/.source.json delete mode 100644 skills/login-microsoft-sso/.source.json delete mode 100644 skills/optimize-svg/.source.json delete mode 100644 skills/record-engage-activity/.source.json delete mode 100644 skills/remediate-codeql-alerts/.source.json delete mode 100644 skills/report-site-analytics/.source.json delete mode 100644 skills/resolve-bot-review-threads/.source.json delete mode 100644 skills/review-battery/.source.json delete mode 100644 skills/source-code-for-gh-advisory/.source.json delete mode 100644 skills/triage-gh-backlog/.source.json delete mode 100644 skills/tufte-information-design/.source.json delete mode 100644 skills/vendored.json delete mode 100644 skills/verify-hugo-build/.source.json delete mode 100644 skills/watch-ci/.source.json delete mode 100644 skills/write-hugo-blog-post/.source.json create mode 100644 sources.toml diff --git a/CLAUDE.md b/CLAUDE.md index 031cdc8..3233b25 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,7 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co One repo for the whole machine: - **macOS dotfiles** — stow packages under `packages/` (targeted at `$HOME`), a curated `Brewfile`, tool manifests under `manifests/`, `bootstrap.sh` for new Macs, and `macos/defaults.sh`. -- **pi** (the `pi-mono` coding agent) — config lives under `pi/` and is stowed into `~/.pi` via GNU stow. +- **pi** (the `pi-mono` coding agent) — config lives under `packages/pi/` and is stowed into `~/.pi` via GNU stow. - **Claude Code** — a shared global `CLAUDE.md`, `skills/`, `commands/`, `rules/`, `scripts/`, and `agents/` are symlinked into `~/.claude-personal/` and `~/.claude-work/`. There is no application to build/test/lint. @@ -17,16 +17,16 @@ The `Makefile` is the primary interface; targets follow `-` na All targets follow a `-` naming convention (e.g. `skills-link`, `skills-sync`), except the `install`/`uninstall` aggregates. -- `make install` — runs `skills-materialize` (reconstructs the gitignored vendored skill dirs from `skills/vendored.json`), then `skills-link`, `claude-md-link`, `commands-link`, `rules-link`, `scripts-link`, `agents-link`, then `stow --adopt pi` into `~/.pi`. - Safe to re-run; it replaces existing symlinks and backs up real files it would overwrite. +- `make install` — runs `brew-install`, `stow-link` (the `$HOME` packages), `skills-materialize` (reconstructs the gitignored vendored skill dirs from `sources.toml`), `harness-link` (stows the `claude` package into both profiles and the `pi` package into `~/.pi`), then `tools-install`. + Safe to re-run; `harness-link` removes stale symlinks at the managed names, and a real file at a target must be moved aside by hand (never `--adopt` on the profile dirs). Materialization needs network on a fresh clone; offline, already-present vendored skills are left as-is and missing ones are reported as skipped. - `make uninstall` — reverses the above. - `make skills-sync` — clones/pulls `github.com/badlogic/pi-skills` into `/tmp/pi-skills` and copies each skill dir into `./skills/`. Bulk vendoring of the badlogic set; local edits to files under those `skills//` dirs are overwritten on next sync. For single skills from arbitrary repos, use `skills-fetch` (see "Skill & agent source management" below). -- `make extensions-sync` — clones/pulls `github.com/badlogic/pi-mono` into `/tmp/pi-mono` and copies the whitelisted set (see `PI_EXTENSIONS` in the Makefile) from `packages/coding-agent/examples/extensions` into `./pi/extensions/`. +- `make extensions-sync` — clones/pulls `github.com/badlogic/pi-mono` into `/tmp/pi-mono` and copies the whitelisted set (see `PI_EXTENSIONS` in the Makefile) from `packages/coding-agent/examples/extensions` into `./packages/pi/extensions/`. Same vendoring caveat applies. -- `make plugins-check` — diffs `claude/plugins.txt` (desired, user-scoped) against `/plugins/installed_plugins.json` for each profile, reporting missing/extra. +- `make plugins-check` — diffs `manifests/claude-plugins.txt` (desired, user-scoped) against `/plugins/installed_plugins.json` for each profile, reporting missing/extra. Requires `jq`. - `make plugins-sync` — same diff as `plugins-check` but emits the exact `/plugin install ` lines per profile, prefixed with the wrapper to enter (`pclaude` / `wclaude`). Copy-paste into a session in the right profile to close the drift. @@ -35,7 +35,7 @@ All targets follow a `-` naming convention (e.g. `skills-link` ## Skill & agent source management `scripts/resource-manager.sh` (wrapped by the `skills-*` and `agents-*` make targets) fetches individual **skills** or **agents** from any git repo at any subpath and tracks where each came from, so they can be updated later. -It is repo tooling and lives in top-level `scripts/`, not `claude/scripts/` — it is not symlinked into the profiles. +It is repo tooling and lives in top-level `scripts/`, not `packages/claude/scripts/` — it is not symlinked into the profiles. `scripts/test-*.sh` and `scripts/test-*.py` are the repo's own regression tests (run by CI); `scripts/test-resource-manager.sh` round-trips a fetch → materialize → doctor → delete in a throwaway clone, `scripts/test-safety-guard-hook.py` is the table-driven test of the safety gate. Hook scripts and repo tooling that parse JSON or do regex work are Python (stdlib only, 3.9+); shell stays for the thin wrappers around `make`/`git`. Requires `git` and `jq`. @@ -44,7 +44,7 @@ The tool takes a leading `--kind skill|agent`; the make targets supply it. The two kinds differ in structure: - A **skill** is a directory under `skills/` validated by a `SKILL.md`. -- An **agent** is a single `.md` file under `claude/agents/`; its sidecar is a **sibling** at `claude/agents/.source.json`. +- An **agent** is a single `.md` file under `packages/claude/agents/`; its committed record is its `[[agent]]` entry in `sources.toml`. They also differ in what gets committed, which turns on a resource's **provenance**: @@ -53,21 +53,24 @@ They also differ in what gets committed, which turns on a resource's **provenanc - **Authored** — born in this repo (`repo: null`, e.g. `harvest-automation`, `debug-ci`); this repo is its only home. `update` and `delete` treat it as having no upstream. +**Every resource is recorded in the single committed manifest, `sources.toml`** — name-sorted `[[skill]]` and `[[agent]]` arrays of tables, read and written through `scripts/toml-manifest.py` (stdlib `tomllib`, python >= 3.11; the writer is deterministic, so diffs stay per-entry). +A vendored entry carries `{name, repo, subpath, ref, commit, category, description}`, where `commit` is the resolved SHA of `ref` and `category`/`description` are cached so the catalog and doctor render without materializing; an authored entry carries just `{name, category[, note]}`. + **Vendored skills are not committed.** -They are recorded in a single committed manifest, `skills/vendored.json` — a name-sorted array of `{name, repo, subpath, ref, commit, category, description}`, where `commit` is the resolved SHA of `ref` and `category`/`description` are cached so the catalog and doctor render without materializing. -Each vendored skill's `skills//` dir — including its regenerated `.source.json` sidecar — is **gitignored** (a managed block in `.gitignore`, rewritten by the tool) and **materialized** from the pinned `commit` by `make install`. -So for skills the manifest is the source of truth; the on-disk `.source.json` is a materialization artifact, not the committed record. +Each vendored skill's `skills//` dir — including its regenerated `.source.json` materialize marker — is **gitignored** (a managed block in `.gitignore`, rewritten by the tool) and **materialized** from the pinned `commit` by `make install`. +The manifest is the source of truth; the on-disk `.source.json` is a materialization artifact, not a committed record. -**Authored skills stay committed** as normal `skills//` dirs with a `{"repo": null}` sidecar, exactly as before — they survive materialize and `skills-update-all` untouched. +**Authored skills stay committed** as normal `skills//` dirs — they survive materialize and `skills-update-all` untouched. -**Agents are always committed** (the manifest is skills-only): each carries a `.source.json` sidecar — `{"repo","subpath","ref","commit","fetched_at"}` when remote, `{"repo": null, ...}` when local; an agent with no sidecar is reported `unmanaged`. +**Agent `.md` files are always committed**, vendored or authored; only their source record lives in the manifest. +A resource with no manifest entry is reported `unmanaged`. -An optional `category` field groups a resource in `list`/catalog output (for vendored skills it lives in the manifest entry; for authored skills and agents, in the sidecar). +An optional `category` field on the manifest entry groups a resource in `list`/catalog output. Skills are categorized this way rather than by folder because Claude Code and pi scan `skills/` only one level deep, so nesting skills into category subfolders would hide them. Targets (each `skills-*` has an `agents-*` twin taking the same variables): -- `make skills-fetch REPO=owner/name SUBPATH=path/to/skill [REF=main] [NAME=…] [FORCE=1]` — shallow sparse-clone, validate the subpath, copy it into `skills//`; for a vendored skill it also upserts the `skills/vendored.json` entry (pinned `commit` + cached `category`/`description`) and adds the `.gitignore` line, so the fetched dir lands untracked. +- `make skills-fetch REPO=owner/name SUBPATH=path/to/skill [REF=main] [NAME=…] [FORCE=1]` — shallow sparse-clone, validate the subpath, copy it into `skills//`; for a vendored skill it also upserts the `sources.toml` entry (pinned `commit` + cached `category`/`description`) and adds the `.gitignore` line, so the fetched dir lands untracked. Refuses to overwrite unless `FORCE=1`. A full GitHub URL also works: `URL='https://github.com/owner/name/tree//'`. - `make skills-materialize [NAME=…] [FORCE=1]` — reconstruct the gitignored vendored skill dirs from the manifest pins (git-init + shallow fetch of the exact `commit` + sparse-checkout). @@ -76,23 +79,23 @@ Targets (each `skills-*` has an `agents-*` twin taking the same variables): Pruning is guarded to untracked dirs whose `.source.json` still names a `repo`, so a committed authored skill is never removed. `NAME=` materializes just that one and prunes nothing. `make install` runs this first; it never fails the build offline — unreachable skills are warned and skipped. -- `make agents-fetch REPO=owner/name SUBPATH=path/to/agent.md [REF=main] [NAME=…] [FORCE=1]` — same, but the subpath is a `.md` file (NAME defaults to its basename minus `.md`), copied into `claude/agents/.md`. +- `make agents-fetch REPO=owner/name SUBPATH=path/to/agent.md [REF=main] [NAME=…] [FORCE=1]` — same, but the subpath is a `.md` file (NAME defaults to its basename minus `.md`), copied into `packages/claude/agents/.md`. Accepts a `/blob/` URL too. - `fetch` also takes an optional `CATEGORY=…` to tag the sidecar on the way in. + `fetch` also takes an optional `CATEGORY=…` to tag the manifest entry on the way in. - `make skills-list` / `make agents-list` — every resource with its status (`remote`/`local`/`unmanaged`) and source, grouped under a ` ()` header (uncategorized last-ish, sorted). -- `make skills-category NAME=… CATEGORY=…` / `make agents-category NAME=… CATEGORY=…` — set/replace a resource's category in place: for a vendored skill it updates the `skills/vendored.json` entry; for an authored skill or agent it updates the `.source.json` sidecar (creating a minimal local one if none exists). +- `make skills-category NAME=… CATEGORY=…` / `make agents-category NAME=… CATEGORY=…` — set/replace a resource's category on its `sources.toml` entry (creating a minimal authored entry if none exists). Use kebab-case slugs that match the README's domain groups. - `make skills-update NAME=…` / `make agents-update NAME=…` — re-resolve the recorded `ref`; if the upstream commit moved, pin the new commit and re-copy, else report up to date (prints `old→new`, preserving `category`). - For a vendored skill this re-materializes the dir and rewrites its `skills/vendored.json` entry (refreshing the cached `description`); for an agent it rewrites the sidecar. + For a vendored skill this re-materializes the dir and rewrites its `sources.toml` entry (refreshing the cached `description`); for an agent it re-copies the `.md` and rewrites the entry. Skips `local`/authored and `unmanaged`. - `make skills-update-all` / `make agents-update-all` — update every remote resource of that kind. -- `make skills-delete NAME=… [YES=1]` / `make agents-delete NAME=… [YES=1]` — remove the resource; for a vendored skill this also drops its `skills/vendored.json` entry and `.gitignore` line, for an agent it removes both the `.md` and its sidecar. +- `make skills-delete NAME=… [YES=1]` / `make agents-delete NAME=… [YES=1]` — remove the resource and its `sources.toml` entry; for a vendored skill this also drops its `.gitignore` line. Prompts unless `YES=1`. - `make skills-catalog [CHECK=1]` — regenerate the standalone catalog at `skills/README.md` (category-grouped tables). - Vendored skills' `category`/`description` come from `skills/vendored.json`; authored skills' come from their `.source.json` `category` + `SKILL.md` frontmatter `description` (first sentence, truncated) — so the catalog regenerates correctly even on a bare checkout where the vendored dirs aren't materialized. + Every skill's `category` comes from `sources.toml`; vendored descriptions are cached there too, while authored ones come from `SKILL.md` frontmatter (first sentence, truncated) — so the catalog regenerates correctly even on a bare checkout where the vendored dirs aren't materialized. The main `README.md` just links to it. Run it after adding, removing, or recategorizing a skill; `CHECK=1` only verifies (exit 1 if stale). -- `make context-budget [CHECK=1] [TOP=N]` — estimate the always-loaded context this repo injects into every Claude Code session (shared `claude/CLAUDE.md` + `rules/*.md`, every skill's name+description, every agent's and command's name+description; tokens ≈ chars/4, no API call), per segment and in total, plus the N heaviest skill descriptions. +- `make context-budget [CHECK=1] [TOP=N]` — estimate the always-loaded context this repo injects into every Claude Code session (shared `packages/claude/CLAUDE.md` + `rules/*.md`, every skill's name+description, every agent's and command's name+description; tokens ≈ chars/4, no API call), per segment and in total, plus the N heaviest skill descriptions. `CHECK=1` exits 1 when the total exceeds `CONTEXT_BUDGET_TOKENS` (Makefile default 12000; `skills-doctor` enforces the same cap, so CI and the commit gate catch growth). Raise the cap deliberately in the Makefile — the diff is the alert. Plugin/marketplace skills live outside this repo and are not counted. @@ -103,7 +106,7 @@ Targets (each `skills-*` has an `agents-*` twin taking the same variables): `skills-fetch` and `skills-update` run the same scan on the staged skill **before** installing it and refuse on failure (`SKILLS_SCAN=0` installs unscanned, logged); when `skillspector` is not installed the gate warns and lets the install through. Install: `make skillspector-install` — pinned to `SKILLSPECTOR_REF` in the Makefile (the release the baselines were reviewed against); bump it deliberately and re-review `security/skillspector/`. `skills-delete` also removes the skill's baseline, and `skills-doctor` flags a baseline that names no skill. -- `make skills-doctor` / `make agents-doctor` — validate every resource: for skills, the manifest is well-formed (required fields, no duplicate names, every vendored dir gitignored), each authored dir has a `SKILL.md` + sidecar with `category`, an authored skill's optional `evals/evals.json` (golden tasks in the skill-creator shape `{skill_name, evals: [{id, name, prompt, expected_output, files}]}`, grown by `harvest-automation`'s `apply evals`) is well-formed, and no dir is a stale vendored orphan (a `.source.json` naming a `repo` with no manifest entry — `skills-materialize` prunes these), plus `skills/README.md` is current and the always-loaded context is under `CONTEXT_BUDGET_TOKENS` (see `context-budget`); for agents, markdown present with non-empty frontmatter `name`/`description` and a sidecar carrying a `category`. +- `make skills-doctor` / `make agents-doctor` — validate every resource: for skills, the manifest is valid TOML (required fields on vendored entries, no duplicate names, every vendored dir gitignored), each authored dir has a `SKILL.md` + a `sources.toml` entry with `category`, an authored skill's optional `evals/evals.json` (golden tasks in the skill-creator shape `{skill_name, evals: [{id, name, prompt, expected_output, files}]}`, grown by `harvest-automation`'s `apply evals`) is well-formed, and no dir is a stale vendored orphan (a `.source.json` naming a `repo` with no manifest entry — `skills-materialize` prunes these), plus `skills/README.md` is current and the always-loaded context is under `CONTEXT_BUDGET_TOKENS` (see `context-budget`); for agents, markdown present with non-empty frontmatter `name`/`description` and a `sources.toml` entry carrying a `category`. Exit 1 on any issue. - `make suites-catalog [CHECK=1]` — regenerate (or verify) the generated blocks in `suites/*/README.md` and the Suites index in `README.md` (see "Skill suites"). - `make preflight` / `make lint` / `make test` — the pre-flight gate (both doctors + lint), the syntax pass alone (`bash -n`, `py_compile`), and the repo's own regression tests (`scripts/test-*.{sh,py}`); the commit-gate hook and CI call these same targets. @@ -114,7 +117,7 @@ Note: the make variable is `SUBPATH`, not `PATH` — `PATH=` on a make command l A **suite** is a curated, ordered set of skills with a shareable landing page — pure metadata + docs, the flat `skills/` tree is untouched. -- `suites//suite.json` — `{"title", "tagline"?, "skills": [ordered skill names]}`; membership lives here, never in sidecars. +- `suites//suite.json` — `{"title", "tagline"?, "skills": [ordered skill names]}`; membership lives here, never in `sources.toml`. - `suites//README.md` — hand-written narrative; the region between `` markers (skill table + skills.sh install command) is generated. - The main `README.md`'s `` region (the Suites index) is generated too; `skills/README.md` remains owned by `skills-catalog` alone. - `make suites-catalog [CHECK=1]` regenerates (or verifies) all generated regions; `make skills-doctor` includes the check. @@ -128,43 +131,43 @@ Requires `npx` (Node.js) and `jq`; it also relies on `resource-manager.sh`. - `make skills-find [Q=query] [OWNER=org]` — `npx skills find`; prints ranked skills.sh hits as `owner/repo@skill`. - `make skills-add SOURCE=owner/repo [SKILL='a b'] [ALL=1] [REF=…] [CATEGORY=…] [FORCE=1]` — fetch + vendor. `SOURCE` accepts the `owner/repo@skill` form `skills-find` prints (paste it verbatim); the `@skill` suffix is peeled into a selected skill. - `CATEGORY=` tags every skill fetched in the call (it flows through to `resource-manager.sh`'s sidecar). + `CATEGORY=` tags every skill fetched in the call (it flows through to the `sources.toml` entry). The integration is deliberately **hybrid**, not a replacement for `resource-manager.sh`. `skills-vendor.sh` uses the CLI only as a *resolver/fetcher*: it runs `skills add … --copy` into a throwaway staging dir, reads the CLI's project `skills-lock.json` (per skill: `source`, `sourceType`, `skillPath`), then re-vendors each through `resource-manager.sh fetch`. -So a CLI-fetched skill is recorded in `skills/vendored.json` and gitignored/materialized **exactly like any other vendored skill**, and `skills-list` / `skills-update` / `skills-delete` plus the Makefile symlinks keep working unchanged — no second update mechanism, no CLI lockfile committed to the repo. +So a CLI-fetched skill is recorded in `sources.toml` and gitignored/materialized **exactly like any other vendored skill**, and `skills-list` / `skills-update` / `skills-delete` plus the Makefile symlinks keep working unchanged — no second update mechanism, no CLI lockfile committed to the repo. Why not let the `skills` CLI own installation directly (its `add`/`update`/`experimental_install`): - Its agent→path map is fixed (`claude-code` → `~/.claude/skills`); it ignores `CLAUDE_CONFIG_DIR`, so it can't target the two profiles (`~/.claude-personal`, `~/.claude-work`) — which our single symlinked `skills/` tree already serves. -- It manages skills only, not the `claude/agents/` subagents (`resource-manager.sh --kind agent` still owns those). -- It installs into per-agent dirs from its own canonical copy; this repo's reproducibility comes from the pinned `skills/vendored.json` manifest (materialized deterministically from each recorded `commit`), so our vendoring pipeline stays the backbone. +- It manages skills only, not the `packages/claude/agents/` subagents (`resource-manager.sh --kind agent` still owns those). +- It installs into per-agent dirs from its own canonical copy; this repo's reproducibility comes from the pinned `sources.toml` manifest (materialized deterministically from each recorded `commit`), so our vendoring pipeline stays the backbone. ## Architecture notes that are easy to miss - **Two Claude profiles via `CLAUDE_CONFIG_DIR`.** `scripts/claude-multi-account.sh` is documentation (shell-function snippets to copy into `~/.zprofile`), not something that runs. The `pclaude`/`wclaude` wrappers set `CLAUDE_CONFIG_DIR` to `~/.claude-personal` or `~/.claude-work`. - Both dirs share the same `CLAUDE.md` and `skills/` via symlinks maintained by the Makefile — changes to `claude/CLAUDE.md` or `skills/` immediately apply to both profiles. -- **`claude/CLAUDE.md` is the shared global user CLAUDE.md**, not this file. + Both dirs share the same `CLAUDE.md` and `skills/` via symlinks maintained by the Makefile — changes to `packages/claude/CLAUDE.md` or `skills/` immediately apply to both profiles. +- **`packages/claude/CLAUDE.md` is the shared global user CLAUDE.md**, not this file. It gets symlinked to `~/.claude-personal/CLAUDE.md` and `~/.claude-work/CLAUDE.md` by `claude-md-link`. Keep it minimal and profile-agnostic. -- **`pi/` is stowed with `--adopt`.** +- **`packages/pi/` is stowed with `--adopt`.** On first `make install`, stow moves any pre-existing files in `~/.pi` into this repo, replacing them with symlinks. - That means `pi/agent/settings.json`, `pi/extensions/*.ts`, and `pi/prompts/` are the live files the agent reads — edits here take effect immediately in `~/.pi/...`. - The `.pi/` directory in the repo root is unrelated scaffolding (empty). -- **`pi/extensions/subagent/` is a directory extension** (listed without `.ts` suffix in `PI_EXTENSIONS`); the rest are single-file TS extensions. + That means `packages/pi/agent/settings.json`, `packages/pi/extensions/*.ts`, and `packages/pi/prompts/` are the live files the agent reads — edits here take effect immediately in `~/.pi/...`. + +- **`packages/pi/extensions/subagent/` is a directory extension** (listed without `.ts` suffix in `PI_EXTENSIONS`); the rest are single-file TS extensions. Adding a new upstream extension requires editing `PI_EXTENSIONS` in the Makefile. - **`skills/` is the single source of truth** for skills across pi and both Claude profiles. - `skills-link` symlinks `$(CURDIR)/skills` into `~/.pi/skills`, `~/.claude-personal/skills`, `~/.claude-work/skills`. - What's *committed* under it, though, is only the authored skill dirs plus the `skills/vendored.json` manifest; vendored skill dirs are gitignored and materialized into place (see the manifest model above), so the symlinked tree the tools read is authored-committed + vendored-materialized. -- **`claude/commands/`, `claude/rules/`, `claude/scripts/`, and `claude/agents/`** are the single source of truth for user-scoped slash commands, rules, helper scripts, and subagents across both Claude profiles. -`commands-link` / `rules-link` / `scripts-link` / `agents-link` symlink them into `~/.claude-personal/` and `~/.claude-work/` (not into `~/.pi/` — pi doesn't consume these; pi has its own vendored `pi/extensions/subagent/agents/`). + The `claude` and `pi` stow packages each carry a committed `skills -> ../../skills` symlink, so `harness-link` exposes the tree at `~/.pi/skills`, `~/.claude-personal/skills`, `~/.claude-work/skills`. + What's *committed* under it, though, is only the authored skill dirs (their source records live in `sources.toml`); vendored skill dirs are gitignored and materialized into place (see the manifest model above), so the symlinked tree the tools read is authored-committed + vendored-materialized. +- **`packages/claude/commands/`, `packages/claude/rules/`, `packages/claude/scripts/`, and `packages/claude/agents/`** are the single source of truth for user-scoped slash commands, rules, helper scripts, and subagents across both Claude profiles. +`commands-link` / `rules-link` / `scripts-link` / `agents-link` symlink them into `~/.claude-personal/` and `~/.claude-work/` (not into `~/.pi/` — pi doesn't consume these; pi has its own vendored `packages/pi/extensions/subagent/agents/`). Rules and docs reference scripts via `$CLAUDE_CONFIG_DIR/scripts/...` so the path resolves correctly under either profile. -`claude/scripts/` currently holds `agent-routing-hook.sh` (the `PreToolUse` routing hook referenced by `rules/model-routing.md`), +`packages/claude/scripts/` currently holds `agent-routing-hook.sh` (the `PreToolUse` routing hook referenced by `rules/model-routing.md`), `safety-guard-hook.py` (a `PreToolUse` deny/ask gate on `Bash` and `Edit|Write` — the Claude-side twin of pi's `permission-gate.ts` + `protected-paths.ts`, referenced by `rules/git-hygiene.md`), `usage-log-hook.py` + `usage-report.py` (`SubagentStop`/`Stop`/`SessionEnd` telemetry into `$CLAUDE_CONFIG_DIR/usage.jsonl` and its aggregator, also referenced by `rules/model-routing.md`; `make usage-report` runs the aggregator for every profile), -`browser-endpoint.sh` (prints the CDP endpoint of the user's browser, referenced by `claude/CLAUDE.md`), +`browser-endpoint.sh` (prints the CDP endpoint of the user's browser, referenced by `packages/claude/CLAUDE.md`), and `statusline-command.sh` (a `statusLine` hook script). No hook among them is wired by default; a profile must opt in via its own `settings.json`, which is not tracked in this repo — each hook script's header carries its wiring snippet. `browser-endpoint.sh` is a plain helper instead: it is invoked by path and needs no wiring. @@ -173,7 +176,7 @@ Agents are single `.md` files fetched and tracked by `resource-manager.sh` (see Installation is manual per-profile; the Makefile only reports drift. Lines are `@`; blanks and `#` comments are ignored. - **Several `.gitignore`'d paths live in the tree but are not checked in.** - The vendored skill dirs (a managed block in `.gitignore`, one `/skills//` line each — rewritten by `resource-manager.sh`) are materialized from `skills/vendored.json`, so after a fresh clone they're absent until `make install` (or `make skills-materialize`) reconstructs them. + The vendored skill dirs (a managed block in `.gitignore`, one `/skills//` line each — rewritten by `resource-manager.sh`) are materialized from `sources.toml`, so after a fresh clone they're absent until `make install` (or `make skills-materialize`) reconstructs them. `docs/superpowers/` holds local-only design artifacts (brainstorming specs, implementation plans). `skills/bin/` holds the `parakeet-cpp-transcribe` binary the `transcribe` skill downloads at runtime — under the symlinked profiles its `../bin` resolves back into the repo, so it's ignored to keep the blob out of git. Don't expect any of these to be present after a fresh clone. @@ -184,13 +187,13 @@ Agents are single `.md` files fetched and tracked by `resource-manager.sh` (see Each skill should do one well-scoped thing so it can be invoked on its own or chained with others, rather than bundling several unrelated workflows. Prefer extracting shared logic into a script the skill calls over duplicating it across skills, and keep `SKILL.md` focused enough that another skill (or the model) can lean on it without inheriting unrelated behavior. When a skill needs another skill, reference it by name as a soft dependency instead of copying its contents. -- Treat vendored skill dirs and `pi/extensions/` as read-only upstream copies — for vendored skills the dir is gitignored and `make skills-materialize`/`skills-update` overwrites it wholesale from the pinned commit, so local edits there are lost with no trace. - If you genuinely need to diverge from a vendored skill, **reclassify it as authored**: restore the committed dir, rewrite its `.source.json` to `{"repo": null, ...}` with a `note` recording the fork point, drop it from `skills/vendored.json` and the `.gitignore` block — then it's committed and safe to edit. +- Treat vendored skill dirs and `packages/pi/extensions/` as read-only upstream copies — for vendored skills the dir is gitignored and `make skills-materialize`/`skills-update` overwrites it wholesale from the pinned commit, so local edits there are lost with no trace. + If you genuinely need to diverge from a vendored skill, **reclassify it as authored**: restore the committed dir, strip the `repo`/`subpath`/`ref`/`commit` fields from its `sources.toml` entry (keep `category`, add a `note` recording the fork point), and drop its `.gitignore` line — then it's committed and safe to edit. This is a temporary state, not a destination: `itr-india` was forked this way, the divergence was contributed back upstream, and once it merged the skill was re-vendored (`make skills-fetch … FORCE=1` + `git rm -r --cached`) so it tracks a pin again. Prefer that round trip over holding a permanent fork. -- The committed record for a vendored skill is its `skills/vendored.json` entry, not the on-disk `.source.json` (which is gitignored and regenerated on materialize); change a vendored skill's source by re-fetching/updating, which rewrites the manifest entry. - For agents and authored skills, the `.source.json` sidecar is still the committed record but is likewise regenerated on fetch/update — don't hand-edit it expecting persistence. - Authored resources (no upstream) keep a `{"repo": null}` sidecar so they survive `skills-update-all` / `agents-update-all` untouched. +- The committed record for every resource is its `sources.toml` entry, not the on-disk `.source.json` (a gitignored marker regenerated on materialize); change a resource's source by re-fetching/updating, which rewrites the entry. + Fetch/update rewrite an entry wholesale, so a hand-added field other than the known ones does not persist. + Authored resources (no `repo` in their entry) survive `skills-update-all` / `agents-update-all` untouched. - When adding a new profile, update `CLAUDE_CONFIG_DIRS` (Makefile line 9) — it drives both the CLAUDE.md and skills symlink loops. ## Skill authoring addenda diff --git a/Makefile b/Makefile index bda56e3..4a5ff13 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,10 @@ STOW := stow PI_TARGET := $(HOME)/.pi +# sources.toml is read/written via tomllib, so python >= 3.11 is required; +# prefer the brew python the Brewfile installs over a stale system python3. +PYTHON ?= python3 + # Home stow packages (dotfiles). Flags are a security invariant, not a style # choice — see "The stow model" in README.md. HOME_STOW_FLAGS := --dir=$(CURDIR)/packages --target=$(HOME) --dotfiles --no-folding --verbose=1 @@ -57,7 +61,7 @@ PI_EXTENSIONS := \ SHELL := /bin/bash -.PHONY: install uninstall doctor drift \ +.PHONY: install uninstall doctor drift python-check \ brew-install brew-check brew-dump cask-adopt \ go-install npm-install pipx-install tools-install \ stow-link stow-unlink stow-adopt macos-apply raycast-export \ @@ -253,7 +257,7 @@ extensions-sync: # Front-end onto the vercel-labs `skills` CLI (npx skills, the skills.sh # ecosystem). skills-find discovers; skills-add fetches via the CLI and vendors # the result into skills/ through resource-manager.sh, so each lands with a -# .source.json and stays manageable by skills-list / skills-update / skills-delete. +# sources.toml entry and stays manageable by skills-list / skills-update / skills-delete. # The CLI is used only as a resolver/fetcher — it never installs per-agent, so # the two Claude profiles and packages/claude/agents/ subagents are unaffected. # Set GITHUB_TOKEN (or have `gh` logged in) to avoid anonymous rate limits. @@ -273,7 +277,7 @@ skills-add: # --- Source management (scripts/resource-manager.sh) ----------------------- # Fetch one skill (dir under skills/) or agent (.md under packages/claude/agents/) from -# any repo/subpath, tracking its source in a .source.json sidecar so it can be +# any repo/subpath, tracking its source in the sources.toml manifest so it can be # listed, updated, and deleted. skills-fetch: @@ -287,7 +291,7 @@ skills-fetch: $(if $(FORCE),--force) # Reconstruct vendored skills' working files from the pinned commits in -# skills/vendored.json (their files are gitignored, not committed). Idempotent — +# sources.toml (their files are gitignored, not committed). Idempotent — # skips any skill already present at the right commit. Run by `make install`; # NAME= materializes one, FORCE=1 re-fetches even if present. skills-materialize: @@ -332,7 +336,7 @@ context-budget: # profile: subagent spend by agent type × model, per-day cache-hit ratio. # SINCE=N limits to the last N days (default 30). usage-report: - @python3 $(SCRIPTS_DIR)/usage-report.py $(if $(SINCE),--since $(SINCE)) $(foreach d,$(CLAUDE_CONFIG_DIRS),--log "$(d)/usage.jsonl") + @$(PYTHON) $(SCRIPTS_DIR)/usage-report.py $(if $(SINCE),--since $(SINCE)) $(foreach d,$(CLAUDE_CONFIG_DIRS),--log "$(d)/usage.jsonl") # Security-scan skills with NVIDIA SkillSpector (scripts/skills-scan.py): # every skill by default, NAME=x for one, LLM=1 adds the semantic pass via the @@ -342,7 +346,7 @@ usage-report: # skills-fetch / skills-update run the same scan on the staged skill before # installing it (SKILLS_SCAN=0 skips). skills-scan: - @python3 $(CURDIR)/scripts/skills-scan.py $(if $(NAME),--name "$(NAME)") $(if $(LLM),--llm) $(if $(SHOW),--show-suppressed) $(if $(REPORT),--report "$(REPORT)") $(if $(FAIL_AT),--fail-at $(FAIL_AT)) $(if $(QUIET),--quiet) + @$(PYTHON) $(CURDIR)/scripts/skills-scan.py $(if $(NAME),--name "$(NAME)") $(if $(LLM),--llm) $(if $(SHOW),--show-suppressed) $(if $(REPORT),--report "$(REPORT)") $(if $(FAIL_AT),--fail-at $(FAIL_AT)) $(if $(QUIET),--quiet) # Install (or move to) the pinned SkillSpector release with uv. skillspector-install: @@ -387,13 +391,17 @@ agents-doctor: # catalog, suites, and the context budget) plus a syntax pass over every script. # The project commit-gate hook (scripts/precommit-gate-hook.sh) and CI run this # same target; a new check goes here and nowhere else. -preflight: skills-doctor agents-doctor lint +preflight: python-check skills-doctor agents-doctor lint + +python-check: + @$(PYTHON) -c 'import tomllib' 2>/dev/null \ + || { echo "python3 >= 3.11 with tomllib is required (brew install python)"; exit 1; } lint: @for f in scripts/*.sh packages/claude/scripts/*.sh; do bash -n "$$f" || exit 1; done - @python3 -m py_compile scripts/*.py packages/claude/scripts/*.py + @$(PYTHON) -m py_compile scripts/*.py packages/claude/scripts/*.py # The repo's own regression tests: every scripts/test-*.sh and scripts/test-*.py. test: @set -e; for t in scripts/test-*.sh; do echo "== $$t"; bash "$$t"; done; \ - for t in scripts/test-*.py; do echo "== $$t"; python3 "$$t"; done + for t in scripts/test-*.py; do echo "== $$t"; $(PYTHON) "$$t"; done diff --git a/README.md b/README.md index 78ebd25..b441bdc 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ On an existing machine, clone the repo and run `make install`. - **Two Claude profiles via `CLAUDE_CONFIG_DIR`.** `pclaude` / `wclaude` wrappers keep personal and work accounts isolated while sharing the same skills and rules. - **Per-resource source tracking.** - Each vendored skill is pinned in `skills/vendored.json` (repo, subpath, commit) and materialized on install — so an upstream update is one command and a bare clone stays reproducible. + Every skill and agent source lives in one `sources.toml` manifest; vendored skills are pinned there (repo, subpath, commit) and materialized on install — so an upstream update is one command and a bare clone stays reproducible. - **Generated catalog, enforced by a doctor.** `skills/README.md` is generated from that metadata; `make skills-doctor` fails when anything drifts. - **Guardrails as code, not hope.** diff --git a/packages/claude/agents/bulk-mechanic.source.json b/packages/claude/agents/bulk-mechanic.source.json deleted file mode 100644 index 4dabdaf..0000000 --- a/packages/claude/agents/bulk-mechanic.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "execution" -} diff --git a/packages/claude/agents/plan-reviewer.source.json b/packages/claude/agents/plan-reviewer.source.json deleted file mode 100644 index f4c5a5d..0000000 --- a/packages/claude/agents/plan-reviewer.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "planning" -} diff --git a/packages/claude/agents/pr-shepherd.source.json b/packages/claude/agents/pr-shepherd.source.json deleted file mode 100644 index c23ee95..0000000 --- a/packages/claude/agents/pr-shepherd.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "pr-review" -} diff --git a/packages/claude/agents/skill-auditor.md b/packages/claude/agents/skill-auditor.md index efb87bb..281c568 100644 --- a/packages/claude/agents/skill-auditor.md +++ b/packages/claude/agents/skill-auditor.md @@ -25,7 +25,7 @@ It is the local copy of those guidelines — audit against it even when offline. Don't let the description script the workflow step-by-step — agents may follow it instead of reading the body. 4. **License** — `license:` present (this repo stamps `Apache-2.0`, matching the repo LICENSE on authored skills). 5. **Metadata** — `metadata:` map present with at least `author` and `version`. - (`category` deliberately lives in the `.source.json` sidecar / `skills/vendored.json`, not frontmatter — flag duplication as drift risk.) + (`category` deliberately lives in the skill's `sources.toml` entry, not frontmatter — flag duplication as drift risk.) 6. **Optional fields sane** — `compatibility` ≤500 chars if present; `allowed-tools` space-delimited; `disable-model-invocation` boolean. ### B. Body content (best practices) @@ -47,7 +47,7 @@ It is the local copy of those guidelines — audit against it even when offline. Flag bundled unrelated workflows; each should be its own skill. 15. **Soft dependencies** — when the skill needs another skill, it references it by name instead of copying its content. Flag duplicated logic that should be a shared script. -16. **Sidecar** — `.source.json` present with a `category`; locally authored skills carry `{"repo": null}`. +16. **Manifest entry** — a `sources.toml` entry present with a `category`; locally authored skills have no `repo` field there. (`make skills-doctor` checks this mechanically — still report it so one audit covers everything.) 17. **No PII** — examples use fake placeholders; no real names, meetings, client/project identifiers, emails, or tokens anywhere in the skill. 18. **Self-containment** — referenced helper scripts exist inside the skill dir (or are declared external tools); paths use `{baseDir}`-style or relative references that survive the symlinked profiles. diff --git a/packages/claude/agents/skill-auditor.source.json b/packages/claude/agents/skill-auditor.source.json deleted file mode 100644 index 16609c9..0000000 --- a/packages/claude/agents/skill-auditor.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "meta" -} diff --git a/packages/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json b/packages/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json deleted file mode 100644 index 60c3011..0000000 --- a/packages/claude/agents/thermo-nuclear-code-quality-review-subagent.source.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "repo": "https://github.com/cursor/plugins", - "subpath": "thermos/agents/thermo-nuclear-code-quality-review-subagent.md", - "ref": "main", - "commit": "60c641e4fad674784b30abcf9f8915dea39df38d", - "fetched_at": "2026-08-19T16:02:26Z", - "category": "pr-review" -} diff --git a/packages/claude/agents/thermo-nuclear-review-subagent.source.json b/packages/claude/agents/thermo-nuclear-review-subagent.source.json deleted file mode 100644 index 2ba5903..0000000 --- a/packages/claude/agents/thermo-nuclear-review-subagent.source.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "repo": "https://github.com/cursor/plugins", - "subpath": "thermos/agents/thermo-nuclear-review-subagent.md", - "ref": "main", - "commit": "60c641e4fad674784b30abcf9f8915dea39df38d", - "fetched_at": "2026-08-19T16:02:17Z", - "category": "pr-review" -} diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 6f58ca1..6e04361 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -31,6 +31,12 @@ fi # npx is only needed for the optional skills-find/vendor targets. if command -v npx >/dev/null; then ok "npx ($(command -v npx))"; else warn "npx not found — run: nvm install --lts (needed only for skill vendoring)"; fi +if python3 -c 'import tomllib' 2>/dev/null; then + ok "python3 with tomllib ($(python3 --version | awk '{print $2}'))" +else + bad "python3 >= 3.11 with tomllib not found — sources.toml tooling needs it (brew install python)" +fi + echo "== brew bundle ==" if brew bundle check --file="$REPO_DIR/Brewfile" >/dev/null 2>&1; then ok "Brewfile satisfied" diff --git a/scripts/resource-manager.sh b/scripts/resource-manager.sh index ff99adf..531ef33 100755 --- a/scripts/resource-manager.sh +++ b/scripts/resource-manager.sh @@ -6,20 +6,17 @@ # A "skill" is a directory containing SKILL.md, vendored under skills/. # An "agent" is a single .md file, vendored under packages/claude/agents/. # -# VENDORED SKILLS are recorded in a single committed manifest and their files -# are NOT committed — they are materialized from their pinned commit on install: -# manifest: skills/vendored.json — an array of -# {"name","repo","subpath","ref","commit","category","description"} -# working files: skills// — gitignored, rebuilt by `materialize`. -# (materialize also writes a gitignored skills//.source.json marker.) +# EVERY resource is recorded in the single committed manifest, sources.toml +# ([[skill]] and [[agent]] arrays of tables; read/written via +# scripts/toml-manifest.py). An entry with a non-empty "repo" is VENDORED: +# {"name","repo","subpath","ref","commit","category","description"[,"fetched_at"]} +# a VENDORED SKILL's files are NOT committed — skills// is gitignored and +# materialized from the pinned commit on install (materialize also writes a +# gitignored skills//.source.json marker recording what is on disk). +# Vendored AGENT .md files stay committed. # -# AUTHORED skills (no upstream) and ALL AGENTS keep an in-tree sidecar and stay -# committed as before: -# local sidecar: {"repo": null[, "category"]} -# remote sidecar (agents): {"repo","subpath","ref","commit","fetched_at"[,"category"]} -# skill sidecar: skills//.source.json (inside the dir) -# agent sidecar: packages/claude/agents/.source.json (sibling of the .md) -# A resource with neither a manifest entry nor a sidecar is "unmanaged". +# An entry without "repo" is AUTHORED (born here): {"name","category"[,"note"]}; +# its files are committed. A resource with no manifest entry is "unmanaged". # # Usage: # resource-manager.sh --kind {skill|agent} fetch (--url URL | --repo REPO --subpath SUBPATH) [--ref REF] [--name NAME] [--category CAT] [--force] @@ -44,6 +41,7 @@ rel() { printf '%s' "${1#"$REPO_ROOT"/}"; } command -v git >/dev/null || die "git is required" command -v jq >/dev/null || die "jq is required" +command -v python3 >/dev/null || die "python3 (>= 3.11, for tomllib) is required" # Temp dirs are tracked globally and cleaned once on exit. A per-function # RETURN trap would be wrong here: bash traps are global, so it would re-fire @@ -61,16 +59,18 @@ mktmp() { MKTMP_DIR="$(mktemp -d)"; TMPDIRS+=("$MKTMP_DIR"); } KIND="" RESOURCE_ROOT="" -MANIFEST="" # skills/vendored.json (skill kind only) +MANIFEST="" # sources.toml (both kinds; KIND selects the array) +TOML_MANIFEST="$REPO_ROOT/scripts/toml-manifest.py" GITIGNORE="$REPO_ROOT/.gitignore" SCAN_BASELINE_DIR="$REPO_ROOT/security/skillspector" # per-skill SkillSpector baselines configure_kind() { case "$KIND" in - skill) RESOURCE_ROOT="$REPO_ROOT/skills"; MANIFEST="$RESOURCE_ROOT/vendored.json" ;; + skill) RESOURCE_ROOT="$REPO_ROOT/skills" ;; agent) RESOURCE_ROOT="$REPO_ROOT/packages/claude/agents" ;; *) die "missing or unknown --kind '$KIND' (expected skill|agent)" ;; esac + MANIFEST="$REPO_ROOT/sources.toml" } # Primary artifact path for a resource (a dir for skills, a .md file for agents). @@ -81,12 +81,10 @@ artifact_path() { esac } -# Sidecar path: inside the dir for skills, sibling of the .md for agents. +# Gitignored materialize-marker path (skill kind only): records what commit is +# on disk so materialize can skip up-to-date dirs. Not a committed record. sidecar_path() { - case "$KIND" in - skill) printf '%s/%s/.source.json' "$RESOURCE_ROOT" "$1" ;; - agent) printf '%s/%s.source.json' "$RESOURCE_ROOT" "$1" ;; - esac + printf '%s/%s/.source.json' "$RESOURCE_ROOT" "$1" } # Default resource name from a subpath. @@ -125,23 +123,19 @@ copy_artifact() { esac } -# Emit "namesidecar_path" for each managed resource of this kind. +# Emit the name of each on-disk resource of this kind. iter_resources() { case "$KIND" in skill) - local dir name + local dir for dir in "$RESOURCE_ROOT"/*/; do - [[ -d "$dir" ]] || continue - name="$(basename "$dir")" - printf '%s\t%s\n' "$name" "$dir.source.json" + [[ -d "$dir" ]] && basename "$dir" done ;; agent) - local f name + local f for f in "$RESOURCE_ROOT"/*.md; do - [[ -f "$f" ]] || continue - name="$(basename "$f" .md)" - printf '%s\t%s\n' "$name" "$RESOURCE_ROOT/$name.source.json" + [[ -f "$f" ]] && basename "$f" .md done ;; esac @@ -214,33 +208,48 @@ fetch_commit() { git -C "$dest" checkout -q FETCH_HEAD 2>/dev/null || return 1 } -# --- vendored-skill manifest (skills/vendored.json) ------------------------ -# The manifest is the committed source of truth for vendored skills. Their -# files are gitignored and materialized from the pinned commit. +# --- sources manifest (sources.toml, both kinds) --------------------------- +# The manifest is the committed source of truth for every skill and agent. +# Reads and writes go through toml-manifest.py; the jq logic in between works +# on the {"skill": [...], "agent": [...]} JSON form, and mutations always +# round-trip the FULL document so the other kind's entries are preserved. -manifest_read() { [[ -f "$MANIFEST" ]] && cat "$MANIFEST" || printf '[]'; } +sources_read_all() { + if [[ -f "$MANIFEST" ]]; then python3 "$TOML_MANIFEST" to-json "$MANIFEST" + else printf '{"skill":[],"agent":[]}'; fi +} +# Apply a jq filter (with its args) to the full doc and persist the result. +sources_write() { + local tmp; tmp="$(mktemp)" + sources_read_all | jq "$@" > "$tmp" || { rm -f "$tmp"; return 1; } + python3 "$TOML_MANIFEST" from-json "$MANIFEST" < "$tmp" + rm -f "$tmp" +} +manifest_read() { sources_read_all | jq -c --arg k "$KIND" '.[$k] // []'; } manifest_names() { manifest_read | jq -r '.[].name'; } +vendored_names() { manifest_read | jq -r '.[] | select((.repo // "") != "") | .name'; } manifest_entry() { manifest_read | jq -c --arg n "$1" 'map(select(.name==$n))[0] // empty'; } manifest_field() { local e; e="$(manifest_entry "$1")"; [[ -n "$e" ]] && jq -r --arg f "$2" '.[$f] // ""' <<<"$e" || printf ''; } -is_vendored() { [[ -n "$(manifest_entry "$1")" ]]; } +is_vendored() { [[ -n "$(manifest_field "$1" repo)" ]]; } -manifest_upsert() { # name repo subpath ref commit category description - local tmp; tmp="$(mktemp)" - manifest_read | jq \ +manifest_upsert() { # name repo subpath ref commit category description [fetched_at] + sources_write --arg kind "$KIND" \ --arg name "$1" --arg repo "$2" --arg subpath "$3" --arg ref "$4" \ - --arg commit "$5" --arg category "$6" --arg description "$7" \ - 'map(select(.name != $name)) - + [{name:$name, repo:$repo, subpath:$subpath, ref:$ref, commit:$commit, category:$category, description:$description}] - | sort_by(.name)' \ - > "$tmp" && mv "$tmp" "$MANIFEST" + --arg commit "$5" --arg category "$6" --arg description "$7" --arg fetched_at "${8:-}" \ + '.[$kind] |= (map(select(.name != $name)) + + [{name:$name, repo:$repo, subpath:$subpath, ref:$ref, commit:$commit, + category:$category, description:$description, fetched_at:$fetched_at}] + | sort_by(.name))' } manifest_remove() { - local tmp; tmp="$(mktemp)" - manifest_read | jq --arg n "$1" 'map(select(.name != $n))' > "$tmp" && mv "$tmp" "$MANIFEST" + sources_write --arg kind "$KIND" --arg n "$1" '.[$kind] |= map(select(.name != $n))' } +# Set/replace a category, creating a minimal authored entry if none exists. manifest_set_category() { - local tmp; tmp="$(mktemp)" - manifest_read | jq --arg n "$1" --arg c "$2" 'map(if .name==$n then .category=$c else . end)' > "$tmp" && mv "$tmp" "$MANIFEST" + sources_write --arg kind "$KIND" --arg n "$1" --arg c "$2" \ + '.[$kind] |= (if any(.[]; .name==$n) + then map(if .name==$n then .category=$c else . end) + else . + [{name:$n, category:$c}] | sort_by(.name) end)' } # --- skill accessors (dual-source: manifest for vendored, sidecar/SKILL.md @@ -258,12 +267,8 @@ skill_description() { else frontmatter_field "$RESOURCE_ROOT/$1/SKILL.md" description; fi } skill_category() { - local c sc - if is_vendored "$1"; then c="$(manifest_field "$1" category)"; printf '%s' "${c:-uncategorized}" - else - sc="$RESOURCE_ROOT/$1/.source.json" - if [[ -f "$sc" ]]; then jq -r '.category // "uncategorized"' "$sc"; else printf 'uncategorized'; fi - fi + local c; c="$(manifest_field "$1" category)" + printf '%s' "${c:-uncategorized}" } # Catalog link target for a skill. Vendored skill dirs are gitignored (absent on # GitHub), so link to their upstream source at the pinned commit; authored dirs @@ -291,7 +296,7 @@ sync_gitignore() { local blk tmp blk="$(mktemp)"; tmp="$(mktemp)" { printf '%s\n' "$GI_BEGIN" - manifest_names | sort | while IFS= read -r n; do [[ -n "$n" ]] && printf '/skills/%s/\n' "$n"; done + vendored_names | sort | while IFS= read -r n; do [[ -n "$n" ]] && printf '/skills/%s/\n' "$n"; done printf '%s\n' "$GI_END" } > "$blk" if [[ -f "$GITIGNORE" ]] && grep -qxF "$GI_BEGIN" "$GITIGNORE"; then @@ -375,7 +380,7 @@ cmd_materialize() { while IFS= read -r n; do [[ -n "$n" ]] || continue if materialize_one "$n" "$force"; then ok=$((ok + 1)); else fail=$((fail + 1)); fi - done < <(manifest_names) + done < <(vendored_names) # Reconcile: a vendored dir dropped from the manifest is stale — remove it so the # on-disk vendored set matches the manifest, rather than leaving a skill active in @@ -478,35 +483,37 @@ cmd_fetch() { write_sidecar "$name" "$repo" "$subpath" "$ref" "$commit" "$category" # gitignored materialize marker sync_gitignore else - write_sidecar "$name" "$repo" "$subpath" "$ref" "$commit" "$category" + manifest_upsert "$name" "$repo" "$subpath" "$ref" "$commit" "$category" "" \ + "$(date -u +%Y-%m-%dT%H:%M:%SZ)" fi info "fetched $(rel "$dest") @ ${commit:0:7}${category:+ [$category]}" } -# Build list rows from in-tree sidecars (agents, and authored/unmanaged skill -# dirs). Emits: category\tname\tstatus\trepo\tsubpath\tref\tcommit\tfetched. +# Build list rows for agents from the manifest plus the on-disk .md files. +# Emits: category\tname\tstatus\trepo\tsubpath\tref\tcommit\tfetched. list_data_generic() { - local name sidecar repo subpath ref commit fetched category status - while IFS=$'\t' read -r name sidecar; do + local name entry repo subpath ref commit fetched category status + while IFS= read -r name; do [[ -n "$name" ]] || continue + entry="$(manifest_entry "$name")" repo=-; subpath=-; ref=-; commit=-; fetched=- - if [[ ! -f "$sidecar" ]]; then + if [[ -z "$entry" ]]; then status=unmanaged; category=uncategorized else - category="$(jq -r '.category // "uncategorized"' "$sidecar")" - repo="$(jq -r '.repo // empty' "$sidecar")" + category="$(jq -r '.category // "uncategorized"' <<<"$entry")" + repo="$(jq -r '.repo // empty' <<<"$entry")" if [[ -z "$repo" ]]; then status=local; repo=- else status=remote - subpath="$(jq -r '.subpath // "-"' "$sidecar")" - ref="$(jq -r '.ref // "-"' "$sidecar")" - commit="$(jq -r '.commit // "-"' "$sidecar")"; commit="${commit:0:7}" - fetched="$(jq -r '.fetched_at // "-"' "$sidecar")" + subpath="$(jq -r '.subpath // "-"' <<<"$entry")" + ref="$(jq -r '.ref // "-"' <<<"$entry")" + commit="$(jq -r '.commit // "-"' <<<"$entry")"; commit="${commit:0:7}" + fetched="$(jq -r '.fetched_at // "-"' <<<"$entry")" fi fi printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$category" "$name" "$status" "$repo" "$subpath" "$ref" "$commit" "$fetched" - done < <(iter_resources) + done < <({ iter_resources; manifest_names; } | sort -u) } # Build skill list rows: vendored from the manifest (status materialized/pinned @@ -523,16 +530,15 @@ list_data_skill() { category="$(jq -r '.category // "uncategorized"' <<<"$entry")"; [[ -n "$category" ]] || category=uncategorized if [[ -f "$RESOURCE_ROOT/$name/SKILL.md" ]]; then status=materialized; else status=pinned; fi printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$category" "$name" "$status" "$repo" "$subpath" "$ref" "$commit" "-" - done < <(manifest_names) + done < <(vendored_names) for dir in "$RESOURCE_ROOT"/*/; do [[ -d "$dir" ]] || continue name="$(basename "$dir")" is_vendored "$name" && continue - sidecar="$dir.source.json" - if [[ ! -f "$sidecar" ]]; then + if [[ -z "$(manifest_entry "$name")" ]]; then status=unmanaged; category=uncategorized else - category="$(jq -r '.category // "uncategorized"' "$sidecar")" + category="$(skill_category "$name")" status=local fi printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$category" "$name" "$status" "-" "-" "-" "-" "-" @@ -603,24 +609,24 @@ update_one_skill() { update_one() { local name="$1" [[ "$KIND" == "skill" ]] && { update_one_skill "$name"; return; } - local artifact sidecar + local artifact entry artifact="$(artifact_path "$name")" - sidecar="$(sidecar_path "$name")" [[ -e "$artifact" ]] || { err "$name: no such $KIND"; return 1; } - if [[ ! -f "$sidecar" ]]; then - info "$name: unmanaged (no .source.json), skipping" + entry="$(manifest_entry "$name")" + if [[ -z "$entry" ]]; then + info "$name: unmanaged (no manifest entry), skipping" return 0 fi - local repo; repo="$(jq -r '.repo // empty' "$sidecar")" + local repo; repo="$(jq -r '.repo // empty' <<<"$entry")" if [[ -z "$repo" ]]; then info "$name: local $KIND, nothing to update" return 0 fi local subpath ref old_commit category - subpath="$(jq -r '.subpath' "$sidecar")" - ref="$(jq -r '.ref' "$sidecar")" - old_commit="$(jq -r '.commit' "$sidecar")" - category="$(jq -r '.category // ""' "$sidecar")" # preserve across re-fetch + subpath="$(jq -r '.subpath' <<<"$entry")" + ref="$(jq -r '.ref' <<<"$entry")" + old_commit="$(jq -r '.commit' <<<"$entry")" + category="$(jq -r '.category // ""' <<<"$entry")" # preserve across re-fetch local tmp; mktmp; tmp="$MKTMP_DIR" sparse_clone "$repo" "$ref" "$(sparse_set_path "$subpath")" "$tmp/repo" @@ -634,7 +640,8 @@ update_one() { || { err "$name: subpath $subpath is no longer a valid $KIND upstream, skipping"; return 1; } copy_artifact "$tmp/repo/$subpath" "$artifact" - write_sidecar "$name" "$repo" "$subpath" "$ref" "$new_commit" "$category" + manifest_upsert "$name" "$repo" "$subpath" "$ref" "$new_commit" "$category" "" \ + "$(date -u +%Y-%m-%dT%H:%M:%SZ)" info "$name: updated ${old_commit:0:7} -> ${new_commit:0:7}" } @@ -649,19 +656,10 @@ cmd_update() { done if [[ "$all" -eq 1 ]]; then - if [[ "$KIND" == "skill" ]]; then - local n - while IFS= read -r n; do - [[ -n "$n" ]] && { update_one_skill "$n" || true; } - done < <(manifest_names) - else - local n s - while IFS=$'\t' read -r n s; do - [[ -f "$s" ]] || continue - [[ "$(jq -r '.repo // empty' "$s")" ]] || continue - update_one "$n" || true - done < <(iter_resources) - fi + local n + while IFS= read -r n; do + [[ -n "$n" ]] && { update_one "$n" || true; } + done < <(vendored_names) return 0 fi @@ -703,8 +701,9 @@ cmd_delete() { fi case "$KIND" in skill) rm -rf "$artifact"; drop_scan_baseline "$name" ;; - agent) rm -f "$artifact" "$(sidecar_path "$name")" ;; + agent) rm -f "$artifact" ;; esac + manifest_remove "$name" info "deleted $(rel "$artifact")" } @@ -767,7 +766,8 @@ render_catalog() { local data="" name category desc purpose link total # all_skill_names is sorted, so rows are alphabetical within each category. # Vendored skills draw category/description from the manifest (so the catalog - # renders on a bare checkout); authored skills from their sidecar + SKILL.md. + # renders on a bare checkout); authored skills their category from the + # manifest and their description from the committed SKILL.md. while IFS= read -r name; do [[ -n "$name" ]] || continue skill_exists "$name" || continue @@ -790,7 +790,7 @@ render_catalog() { fi printf '# Skills catalog\n\n' - printf '%s skills, grouped by `category` (from `skills/vendored.json` for vendored skills, from each `.source.json` sidecar for authored ones).\n' "$total" + printf '%s skills, grouped by `category` (from each `sources.toml` entry).\n' "$total" printf 'Each name links to its source: authored skills to the in-repo `SKILL.md`, vendored skills to their upstream repo at the pinned commit (their dirs are gitignored, so they are not present in this repo).\n' printf 'Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` flags a stale file).\n\n' @@ -1056,11 +1056,12 @@ cmd_doctor() { flag() { printf '%s\n' "$*"; issues=$((issues + 1)); } if [[ "$KIND" == "skill" ]]; then - # Vendored skills: validate the manifest. Their files may be un-materialized. + # The manifest itself, then vendored entries (their files may be + # un-materialized), then authored entries. if [[ ! -f "$MANIFEST" ]]; then flag "$(rel "$MANIFEST"): missing" - elif ! jq -e 'type == "array"' "$MANIFEST" >/dev/null 2>&1; then - flag "$(rel "$MANIFEST"): not a JSON array" + elif ! python3 "$TOML_MANIFEST" to-json "$MANIFEST" >/dev/null 2>&1; then + flag "$(rel "$MANIFEST"): not valid TOML" else local dup f dup="$(manifest_names | sort | uniq -d)" @@ -1074,9 +1075,18 @@ cmd_doctor() { done grep -qxF "/skills/$name/" "$GITIGNORE" 2>/dev/null \ || flag "$name: vendored dir not listed in .gitignore managed block" + done < <(vendored_names) + # Authored entries must have a category and a committed dir. + while IFS= read -r name; do + [[ -n "$name" ]] || continue + is_vendored "$name" && continue + [[ -n "$(manifest_field "$name" category)" ]] \ + || flag "$name: manifest entry has no 'category'" + [[ -f "$RESOURCE_ROOT/$name/SKILL.md" ]] \ + || flag "$name: manifest entry for an authored skill with no skills/$name/SKILL.md" done < <(manifest_names) fi - # Authored / unmanaged skills: dirs not in the manifest. + # Authored / unmanaged skills: dirs not vendored. local dir for dir in "$RESOURCE_ROOT"/*/; do [[ -d "$dir" ]] || continue @@ -1095,13 +1105,13 @@ cmd_doctor() { ' "$dir/evals/evals.json" >/dev/null 2>&1; then flag "$name: evals/evals.json malformed (want {skill_name: \"$name\", evals: [{name, prompt, expected_output, files?}, ...]} with unique names)" fi - sidecar="$dir.source.json" - if [[ ! -f "$sidecar" ]]; then - flag "$name: unmanaged (no .source.json sidecar)" - elif [[ "$(jq -r '.repo // "null"' "$sidecar")" != "null" ]]; then - flag "$name: stale vendored dir (sidecar names a repo but not in $(rel "$MANIFEST")); prune with 'make skills-materialize' or re-add with 'make skills-fetch'" - elif [[ "$(jq -r '.category // ""' "$sidecar")" == "" ]]; then - flag "$name: sidecar has no 'category'" + if [[ -z "$(manifest_entry "$name")" ]]; then + sidecar="$dir.source.json" + if [[ -f "$sidecar" && "$(jq -r '.repo // "null"' "$sidecar" 2>/dev/null)" != "null" ]]; then + flag "$name: stale vendored dir (on-disk marker names a repo but no $(rel "$MANIFEST") entry); prune with 'make skills-materialize' or re-add with 'make skills-fetch'" + else + flag "$name: unmanaged (no $(rel "$MANIFEST") entry)" + fi fi done # Scan baselines must name a live skill (skills-delete removes them; catch drift). @@ -1116,22 +1126,22 @@ cmd_doctor() { cmd_suites --check || issues=$((issues + 1)) cmd_budget --check --top 0 >/dev/null || issues=$((issues + 1)) else - while IFS=$'\t' read -r name sidecar; do + while IFS= read -r name; do [[ -n "$name" ]] || continue md="$RESOURCE_ROOT/$name.md" if [[ ! -f "$md" ]]; then - flag "$name: missing $(rel "$md")" + flag "$name: manifest entry for a missing $(rel "$md")" continue fi [[ -n "$(frontmatter_field "$md" name)" ]] || flag "$name: agent frontmatter has no 'name'" desc="$(frontmatter_field "$md" description)" [[ -n "$desc" ]] || flag "$name: frontmatter has no 'description'" - if [[ ! -f "$sidecar" ]]; then - flag "$name: unmanaged (no .source.json sidecar)" - elif [[ "$(jq -r '.category // ""' "$sidecar")" == "" ]]; then - flag "$name: sidecar has no 'category'" + if [[ -z "$(manifest_entry "$name")" ]]; then + flag "$name: unmanaged (no $(rel "$MANIFEST") entry)" + elif [[ -z "$(manifest_field "$name" category)" ]]; then + flag "$name: manifest entry has no 'category'" fi - done < <(iter_resources) + done < <({ iter_resources; manifest_names; } | sort -u) fi if [[ "$issues" -gt 0 ]]; then @@ -1141,8 +1151,8 @@ cmd_doctor() { info "doctor: all ${KIND}s healthy" } -# Set/replace the category on an existing resource's sidecar (in place, so it -# survives update). Creates a minimal local sidecar if none exists yet. +# Set/replace the category on a resource's manifest entry (in place, so it +# survives update). Creates a minimal authored entry if none exists yet. cmd_category() { local name="" category="" while [[ $# -gt 0 ]]; do @@ -1154,21 +1164,10 @@ cmd_category() { done [[ -n "$name" ]] || die "category: --name NAME is required" [[ -n "$category" ]] || die "category: --category CAT is required" - if [[ "$KIND" == "skill" ]] && is_vendored "$name"; then - manifest_set_category "$name" "$category" - info "$name: category set to '$category'" - return 0 - fi - local artifact sidecar - artifact="$(artifact_path "$name")" - sidecar="$(sidecar_path "$name")" - [[ -e "$artifact" ]] || die "$name: no such $KIND" - if [[ -f "$sidecar" ]]; then - local tmp; tmp="$(mktemp)" - jq --arg c "$category" '.category = $c' "$sidecar" > "$tmp" && mv "$tmp" "$sidecar" - else - jq -n --arg c "$category" '{repo:null, category:$c}' > "$sidecar" + if ! is_vendored "$name" && [[ ! -e "$(artifact_path "$name")" ]]; then + die "$name: no such $KIND" fi + manifest_set_category "$name" "$category" info "$name: category set to '$category'" } diff --git a/scripts/skills-vendor.sh b/scripts/skills-vendor.sh index 79112ea..53761ac 100755 --- a/scripts/skills-vendor.sh +++ b/scripts/skills-vendor.sh @@ -2,7 +2,7 @@ # # skills-vendor.sh — discover/fetch skills with the vercel-labs `skills` CLI # (the skills.sh ecosystem), then vendor them into this repo's skills/ tree -# via resource-manager.sh so they keep a .source.json sidecar and stay +# via resource-manager.sh so they land in sources.toml and stay # manageable with the existing skills-list / skills-update / skills-delete # targets and the Makefile symlinks. # @@ -77,7 +77,7 @@ lock="$staging/skills-lock.json" [[ -f "$lock" ]] || die "skills CLI wrote no skills-lock.json (nothing fetched?)" # Translate each lock entry into a resource-manager fetch so the vendored skill -# gets our standard .source.json. lock schema (v1): +# gets our standard sources.toml entry. lock schema (v1): # skills. = { source, sourceType, skillPath: "/SKILL.md", ... } # Read into an array with a while-loop (mapfile is bash 4+; macOS ships 3.2). entries=() diff --git a/scripts/test-resource-manager.sh b/scripts/test-resource-manager.sh index 4af0922..b1637b9 100755 --- a/scripts/test-resource-manager.sh +++ b/scripts/test-resource-manager.sh @@ -10,8 +10,14 @@ git clone --quiet "$REPO_ROOT" "$tmp/repo" # Test the tooling as it is on disk (uncommitted edits included), not the last commit. cp "$REPO_ROOT"/scripts/*.sh "$REPO_ROOT"/scripts/*.py "$tmp/repo/scripts/" cp "$REPO_ROOT/Makefile" "$tmp/repo/Makefile" +cp "$REPO_ROOT/sources.toml" "$tmp/repo/sources.toml" cd "$tmp/repo" -git -c user.email=ci@example.invalid -c user.name=ci commit -qam "working-tree tooling" || true +git add scripts Makefile sources.toml +git -c user.email=ci@example.invalid -c user.name=ci commit -qm "working-tree tooling" || true +# Absorb catalog-wording drift the working-tree tooling may carry, so the +# final clean-tree assertion checks only the round-trip's own effects. +make -s skills-catalog >/dev/null 2>&1 || true +git -c user.email=ci@example.invalid -c user.name=ci commit -qam "working-tree catalog" || true # Hermetic upstream: a local git repo holding one small skill, so the test # never depends on a third party's default branch (a rename there must not red CI). @@ -39,13 +45,14 @@ fail() { echo "FAIL: $*" >&2; exit 1; } echo "== fetch" make -s skills-fetch REPO=$REPO SUBPATH=$SUBPATH NAME=$NAME CATEGORY=ci-smoke -commit=$(jq -re --arg n "$NAME" '.[]|select(.name==$n)|.commit' skills/vendored.json) || fail "no manifest entry" +manifest_json() { python3 scripts/toml-manifest.py to-json sources.toml; } +commit=$(manifest_json | jq -re --arg n "$NAME" '.skill[]|select(.name==$n)|.commit') || fail "no manifest entry" [[ "$commit" =~ ^[0-9a-f]{40}$ ]] || fail "manifest commit is not a sha: $commit" grep -qx "/skills/$NAME/" .gitignore || fail ".gitignore line missing" [[ -f skills/$NAME/SKILL.md ]] || fail "SKILL.md not fetched" [[ "$(jq -r .commit skills/$NAME/.source.json)" == "$commit" ]] || fail "sidecar commit != manifest commit" [[ -z "$(git status --porcelain -- skills/$NAME)" ]] || fail "fetched dir is not gitignored" -jq -e --arg n "$NAME" '[.[]|select(.name==$n)]|length==1' skills/vendored.json >/dev/null || fail "duplicate manifest entries" +manifest_json | jq -e --arg n "$NAME" '[.skill[]|select(.name==$n)]|length==1' >/dev/null || fail "duplicate manifest entries" echo "== materialize (fresh-clone path)" rm -rf "skills/$NAME" @@ -62,7 +69,7 @@ mkdir -p security/skillspector && echo '{"version":2,"rules":[]}' > "security/sk make -s skills-delete NAME=$NAME YES=1 [[ ! -e "security/skillspector/$NAME.json" ]] || fail "scan baseline survived delete" make -s skills-catalog -jq -e --arg n "$NAME" '[.[]|select(.name==$n)]|length==0' skills/vendored.json >/dev/null || fail "manifest entry survived delete" +manifest_json | jq -e --arg n "$NAME" '[.skill[]|select(.name==$n)]|length==0' >/dev/null || fail "manifest entry survived delete" grep -qx "/skills/$NAME/" .gitignore && fail ".gitignore line survived delete" [[ ! -e skills/$NAME ]] || fail "dir survived delete" [[ -z "$(git status --porcelain)" ]] || { git status --porcelain; fail "tree not clean after round-trip"; } diff --git a/scripts/toml-manifest.py b/scripts/toml-manifest.py new file mode 100755 index 0000000..3cde18e --- /dev/null +++ b/scripts/toml-manifest.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +"""toml-manifest.py — read/write the repo's sources.toml manifest. + +The manifest is the single committed record of every skill and agent +source: two arrays of tables, [[skill]] and [[agent]], each entry at +least {name}, plus {repo, subpath, ref, commit} when vendored and +optional {category, description, fetched_at, note}. + +Commands (stdin/stdout are JSON; the TOML file is the argument): + to-json print {"skill": [...], "agent": [...]} + from-json read the same JSON on stdin, write the file + +The writer is deterministic — fixed key order, entries sorted by name, +one key per line — so a round-trip of an untouched manifest is +byte-identical and diffs stay per-entry. Stdlib only (tomllib, py>=3.11). +""" +import json +import sys +import tomllib + +KINDS = ("skill", "agent") +KEY_ORDER = ("name", "repo", "subpath", "ref", "commit", "fetched_at", "category", "description", "note") + + +def die(msg: str) -> None: + print(f"toml-manifest: {msg}", file=sys.stderr) + raise SystemExit(1) + + +def toml_str(s: str) -> str: + if any(c in s for c in "\\\"\n\t"): + return json.dumps(s) # JSON string escapes are valid TOML basic-string escapes + return f'"{s}"' + + +def to_json(path: str) -> None: + try: + with open(path, "rb") as fh: + doc = tomllib.load(fh) + except FileNotFoundError: + doc = {} + out = {k: doc.get(k, []) for k in KINDS} + json.dump(out, sys.stdout) + print() + + +def from_json(path: str) -> None: + doc = json.load(sys.stdin) + lines = [ + "# sources.toml — the single manifest of every skill and agent source.", + "# Managed by scripts/resource-manager.sh (make skills-* / agents-*);", + "# an entry with repo+commit is vendored (skill files gitignored,", + "# materialized from the pin), one without repo is authored here.", + ] + for kind in KINDS: + entries = doc.get(kind) or [] + for entry in sorted(entries, key=lambda e: e.get("name", "")): + lines.append("") + lines.append(f"[[{kind}]]") + for key in KEY_ORDER: + val = entry.get(key) + if val is None or val == "": + continue + if not isinstance(val, str): + die(f"{kind} '{entry.get('name')}': field '{key}' must be a string") + lines.append(f"{key} = {toml_str(val)}") + extra = set(entry) - set(KEY_ORDER) - {"repo"} + extra = {k for k in extra if entry[k] not in (None, "")} + if extra: + die(f"{kind} '{entry.get('name')}': unknown fields {sorted(extra)}") + with open(path, "w", encoding="utf-8") as fh: + fh.write("\n".join(lines) + "\n") + + +def main() -> None: + if len(sys.argv) != 3 or sys.argv[1] not in ("to-json", "from-json"): + die("usage: toml-manifest.py {to-json|from-json} ") + (to_json if sys.argv[1] == "to-json" else from_json)(sys.argv[2]) + + +if __name__ == "__main__": + main() diff --git a/skills/README.md b/skills/README.md index f135e99..9676110 100644 --- a/skills/README.md +++ b/skills/README.md @@ -1,6 +1,6 @@ # Skills catalog -72 skills, grouped by `category` (from `skills/vendored.json` for vendored skills, from each `.source.json` sidecar for authored ones). +72 skills, grouped by `category` (from each `sources.toml` entry). Each name links to its source: authored skills to the in-repo `SKILL.md`, vendored skills to their upstream repo at the pinned commit (their dirs are gitignored, so they are not present in this repo). Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` flags a stale file). diff --git a/skills/add-llms-txt/.source.json b/skills/add-llms-txt/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/add-llms-txt/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/analyze-go-pprof/.source.json b/skills/analyze-go-pprof/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/analyze-go-pprof/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/analyze-prometheus-tsdb/.source.json b/skills/analyze-prometheus-tsdb/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/analyze-prometheus-tsdb/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/apply-workday-leave/.source.json b/skills/apply-workday-leave/.source.json deleted file mode 100644 index bea005a..0000000 --- a/skills/apply-workday-leave/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "internal-automation" -} diff --git a/skills/approve-workday-tasks/.source.json b/skills/approve-workday-tasks/.source.json deleted file mode 100644 index bea005a..0000000 --- a/skills/approve-workday-tasks/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "internal-automation" -} diff --git a/skills/audit-static-site/.source.json b/skills/audit-static-site/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/audit-static-site/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/author-mermaid-diagram/.source.json b/skills/author-mermaid-diagram/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/author-mermaid-diagram/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/author-security-advisory/.source.json b/skills/author-security-advisory/.source.json deleted file mode 100644 index c33f095..0000000 --- a/skills/author-security-advisory/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "gh-security" -} diff --git a/skills/bump-ci-tool-versions/.source.json b/skills/bump-ci-tool-versions/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/bump-ci-tool-versions/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/bump-hugo-versions/.source.json b/skills/bump-hugo-versions/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/bump-hugo-versions/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/debug-ci/.source.json b/skills/debug-ci/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/debug-ci/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/fill-workday-timesheet/.source.json b/skills/fill-workday-timesheet/.source.json deleted file mode 100644 index bea005a..0000000 --- a/skills/fill-workday-timesheet/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "internal-automation" -} diff --git a/skills/generate-og-images/.source.json b/skills/generate-og-images/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/generate-og-images/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/go-deps-security-sweep/.source.json b/skills/go-deps-security-sweep/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/go-deps-security-sweep/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/harvest-automation/.source.json b/skills/harvest-automation/.source.json deleted file mode 100644 index 336204f..0000000 --- a/skills/harvest-automation/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "meta" -} diff --git a/skills/harvest-automation/SKILL.md b/skills/harvest-automation/SKILL.md index c86ed43..64987c2 100644 --- a/skills/harvest-automation/SKILL.md +++ b/skills/harvest-automation/SKILL.md @@ -19,7 +19,7 @@ metadata: # Harvest Automation -> Local skill (`.source.json` has `"repo": null`); replaces the old `retrospect` and `workflow-from-chats` skills. +> Local skill (its `sources.toml` entry has no `repo`); replaces the old `retrospect` and `workflow-from-chats` skills. ## Core principle @@ -77,7 +77,7 @@ Delegate to existing skills; do not reimplement their logic. - Skill — a recurring multi-step workflow with clear triggers. Draft a proposal (name, "Use when…" description, trigger, steps, scripts) and hand it to `superpowers:writing-skills` to author and validate under `skills//`. - Mark it local with a `{"repo": null}` `.source.json`. + Mark it local with a repo-less `sources.toml` entry (`make skills-category NAME=… CATEGORY=…` creates one). Never scaffold skill files by hand. - CLAUDE.md — a collaborator-visible project fact (build/test commands, invariants, code locations, "always use X helper"). - Memory — a user-private preference (terse vs verbose, tool choices, workflow habits). diff --git a/skills/improve-codecov-coverage/.source.json b/skills/improve-codecov-coverage/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/improve-codecov-coverage/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/list-week-meetings/.source.json b/skills/list-week-meetings/.source.json deleted file mode 100644 index bea005a..0000000 --- a/skills/list-week-meetings/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "internal-automation" -} diff --git a/skills/login-microsoft-sso/.source.json b/skills/login-microsoft-sso/.source.json deleted file mode 100644 index bea005a..0000000 --- a/skills/login-microsoft-sso/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "internal-automation" -} diff --git a/skills/login-microsoft-sso/SKILL.md b/skills/login-microsoft-sso/SKILL.md index 244fcd5..ebceb3a 100644 --- a/skills/login-microsoft-sso/SKILL.md +++ b/skills/login-microsoft-sso/SKILL.md @@ -23,7 +23,7 @@ Ensure a browser tab is signed in to an app behind your organization's **Microso Use the **`chrome-cdp`** CLI on the user's real, already signed-in browser — this skill types **no** credentials. > See **`drive-chrome-cdp`** for CLI setup, output contract, and the passkey rule. -> Local skill, maintained in this repo (`.source.json` has `"repo": null`). +> Local skill, maintained in this repo (its `sources.toml` entry has no `repo`). ## Supported apps & config diff --git a/skills/optimize-svg/.source.json b/skills/optimize-svg/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/optimize-svg/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/record-engage-activity/.source.json b/skills/record-engage-activity/.source.json deleted file mode 100644 index bea005a..0000000 --- a/skills/record-engage-activity/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "internal-automation" -} diff --git a/skills/remediate-codeql-alerts/.source.json b/skills/remediate-codeql-alerts/.source.json deleted file mode 100644 index c33f095..0000000 --- a/skills/remediate-codeql-alerts/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "gh-security" -} diff --git a/skills/report-site-analytics/.source.json b/skills/report-site-analytics/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/report-site-analytics/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/resolve-bot-review-threads/.source.json b/skills/resolve-bot-review-threads/.source.json deleted file mode 100644 index ee0c0d8..0000000 --- a/skills/resolve-bot-review-threads/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "pr-review" -} diff --git a/skills/review-battery/.source.json b/skills/review-battery/.source.json deleted file mode 100644 index d9b98d6..0000000 --- a/skills/review-battery/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Authored orchestrator; replaces the former review-battery and review-pr-worktree commands and drives the vendored thermos subagents", - "category": "pr-review" -} diff --git a/skills/source-code-for-gh-advisory/.source.json b/skills/source-code-for-gh-advisory/.source.json deleted file mode 100644 index c33f095..0000000 --- a/skills/source-code-for-gh-advisory/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "gh-security" -} diff --git a/skills/triage-gh-backlog/.source.json b/skills/triage-gh-backlog/.source.json deleted file mode 100644 index 301bc9f..0000000 --- a/skills/triage-gh-backlog/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "gh-maintenance" -} diff --git a/skills/tufte-information-design/.source.json b/skills/tufte-information-design/.source.json deleted file mode 100644 index 33a0a3e..0000000 --- a/skills/tufte-information-design/.source.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repo": null, - "category": "documents" -} diff --git a/skills/vendored.json b/skills/vendored.json deleted file mode 100644 index 1976ab6..0000000 --- a/skills/vendored.json +++ /dev/null @@ -1,380 +0,0 @@ -[ - { - "name": "agent-browser", - "repo": "https://github.com/vercel-labs/agent-browser", - "subpath": "skills/agent-browser", - "ref": "main", - "commit": "9d9a3bbd5e4f8c0a17a1c4dfd2f8e8d74b5ee998", - "category": "search-media", - "description": "Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools." - }, - { - "name": "brave-search", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "brave-search", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "search-media", - "description": "Web search and content extraction via Brave Search API. Use for searching documentation, facts, or any web content. Lightweight, no browser required." - }, - { - "name": "caveman", - "repo": "https://github.com/juliusbrussee/caveman", - "subpath": "skills/caveman", - "ref": "main", - "commit": "81536f57b3303b7de7f5bc5b564cc344f9112d68", - "category": "meta", - "description": "Ultra-compressed communication mode. Cuts output tokens 65% (measured) by speaking like caveman while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra, wenyan-lite, wenyan-full, wenyan-ultra. Use when user says \"caveman mode\", \"talk like caveman\", \"use caveman\", \"less tokens\", \"be brief\", or invokes /caveman. Also auto-triggers when token efficiency is requested." - }, - { - "name": "codebase-design", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/codebase-design", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary." - }, - { - "name": "deslop", - "repo": "https://github.com/cursor/plugins", - "subpath": "cursor-team-kit/skills/deslop", - "ref": "main", - "commit": "bdf7aa355337897f167153e05069aca505dae17c", - "category": "pr-review", - "description": "Remove AI-generated code slop and clean up code style" - }, - { - "name": "docx", - "repo": "https://github.com/anthropics/skills", - "subpath": "skills/docx", - "ref": "main", - "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", - "category": "documents", - "description": "\"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', '.dotx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx or .dotx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a 'report', 'memo', 'letter', 'template', or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"" - }, - { - "name": "domain-modeling", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/domain-modeling", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a CONTEXT.md, or recording or editing an ADR." - }, - { - "name": "drive-chrome-cdp", - "repo": "https://github.com/sanketsudake/chrome-cdp-cli", - "subpath": "skills/drive-chrome-cdp", - "ref": "main", - "commit": "deee3056260e6dea5f182760e3559d79a7222291", - "category": "internal-automation", - "description": "Drive the user's real, already-running local Chrome — its live tabs, logins, and cookies, so it types no credentials — from the shell via the `chrome-cdp` CLI, which answers every command with one JSON envelope and a stable exit code. Use when a skill names `chrome-cdp`, or when a task needs addressing CSS cannot express (`--by name|ref|cell|label`, `--in-row`), cascade `select`, `grid` table reads, `wait --request`, or `console`/`net` to explain why an action did nothing. Triggers include \"click X in my browser\", \"read what's on my screen\", \"fill in this form in Chrome\", \"check console/network errors on this page\", \"automate this web app in my logged-in session\". The building block other logged-in-app skills follow to get a driven, signed-in tab." - }, - { - "name": "find-skills", - "repo": "https://github.com/vercel-labs/skills", - "subpath": "skills/find-skills", - "ref": "main", - "commit": "435076e78988e1e6ec40d00b0b1d76bdbbc5419a", - "category": "meta", - "description": "Helps users discover and install agent skills when they ask questions like \"how do I do X\", \"find a skill for X\", \"is there a skill that can...\", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill." - }, - { - "name": "gccli", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "gccli", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "google-cli", - "description": "Google Calendar CLI for listing calendars, viewing/creating/updating events, and checking availability." - }, - { - "name": "gdcli", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "gdcli", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "google-cli", - "description": "Google Drive CLI for listing, searching, uploading, downloading, and sharing files and folders." - }, - { - "name": "gmcli", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "gmcli", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "google-cli", - "description": "Gmail CLI for searching emails, reading threads, sending messages, managing drafts, and handling labels/attachments." - }, - { - "name": "grill-with-docs", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/grill-with-docs", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go." - }, - { - "name": "grilling", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/productivity/grilling", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases." - }, - { - "name": "implement", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/implement", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "\"Implement a piece of work based on a spec or set of tickets.\"" - }, - { - "name": "improve-codebase-architecture", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/improve-codebase-architecture", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick." - }, - { - "name": "itr-india", - "repo": "https://github.com/shivprime94/file-itr", - "subpath": "skills/itr-india", - "ref": "main", - "commit": "59185d78128bdef6b6d079f885cb6f4778454929", - "category": "personal-finance", - "description": "Assist a resident Indian individual with preparing and e-filing an Income Tax Return (ITR-1/2/3/4) on the e-filing portal (eportal.incometax.gov.in), under EITHER the old or new tax regime (non-resident / RNOR returns are out of scope). Use WHENEVER the user mentions filing taxes in India, ITR, income tax return, 26AS, AIS, Form 16, old vs new regime, 115BAC, Form 10-IEA, 80C/80D/HRA/home-loan/NPS/80G deductions, 44ADA/44AD presumptive, self-assessment/advance tax/234B/234C, TDS reconciliation, capital gains on Indian shares/mutual funds/property, or crypto/VDA (115BBH/194S) — even if they don't name the form or regime. Covers gathering and reconciling income documents, comparing both regimes to pick the cheaper one, choosing the form, computing tax, filling the portal schedule-by-schedule, fixing validation defects, and guiding payment and e-verification. India personal income tax only — not US/UK/other-country tax, GST, TDS-return (24Q/26Q), or company returns." - }, - { - "name": "make-pr-easy-to-review", - "repo": "https://github.com/cursor/plugins", - "subpath": "cursor-team-kit/skills/make-pr-easy-to-review", - "ref": "main", - "commit": "bdf7aa355337897f167153e05069aca505dae17c", - "category": "pr-review", - "description": "Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. Use for \"make this easy to review\", \"tidy this PR\", \"clean up commits\", or \"annotate the diff\"." - }, - { - "name": "matt-code-review", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/code-review", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "\"Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes: Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/spec asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to \\\"review since X\\\".\"" - }, - { - "name": "pdf", - "repo": "https://github.com/anthropics/skills", - "subpath": "skills/pdf", - "ref": "main", - "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", - "category": "documents", - "description": "Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill." - }, - { - "name": "pptx", - "repo": "https://github.com/anthropics/skills", - "subpath": "skills/pptx", - "ref": "main", - "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", - "category": "documents", - "description": "\"Use this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates (.potx), layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx or .potx filename, regardless of what they plan to do with the content afterward. If a .pptx or .potx file needs to be opened, created, or touched, use this skill.\"" - }, - { - "name": "pr-review-canvas", - "repo": "https://github.com/cursor/plugins", - "subpath": "cursor-team-kit/skills/pr-review-canvas", - "ref": "main", - "commit": "bdf7aa355337897f167153e05069aca505dae17c", - "category": "pr-review", - "description": "Generate an interactive PR review walkthrough as an HTML page. Fetches PR data via gh API, categorizes files into core vs mechanical changes, adds reviewer annotations, and renders diffs with moved-code detection. Use when the user pastes a GitHub PR URL and asks for a review, walkthrough, or summary, or says \"review this PR\"." - }, - { - "name": "prototype", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/prototype", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like." - }, - { - "name": "readwise-cli", - "repo": "https://github.com/readwiseio/readwise-skills", - "subpath": "skills/readwise-cli", - "ref": "master", - "commit": "2d1ce9627c611d24f510dfc2e05a123fa509d2f6", - "category": "knowledge-base", - "description": "How to use the Readwise CLI — access highlights, documents, and your entire reading library from the command line" - }, - { - "name": "readwise-second-brain-sync", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/readwise-second-brain-sync", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Syncs Readwise highlights and Reader documents into the second-brain vault's raw/ folder in Obsidian-Web-Clipper format. Use when the user says \"sync readwise\", \"pull my readwise highlights\", \"update raw/ from reader\", or wants their reading library reflected in the wiki (triggers: readwise sync, reader sync, import highlights). Sync only — follow with /second-brain-ingest." - }, - { - "name": "second-brain", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/second-brain", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Sets up a new Obsidian knowledge base using the LLM Wiki pattern, where the LLM acts as librarian over raw sources. Use when the user wants to create a second brain, initialize a vault, set up a personal knowledge base, or says \"onboard\". Interactive setup wizard." - }, - { - "name": "second-brain-ideate", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/second-brain-ideate", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Mines the knowledge-base wiki for strong, defensible content ideas — blog posts, conference talks, internal sessions, threads. Use when the user says \"ideate\", \"what should I write about\", \"find content ideas in my wiki\", \"blog/talk ideas\", or wants to turn collected knowledge into publishable content. Produces a scored shortlist with outlines in output/ and maintains an ideas backlog in wiki/synthesis/." - }, - { - "name": "second-brain-ingest", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/second-brain-ingest", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Process raw source documents into wiki pages. Use when the user adds files to raw/ and wants them ingested, or says \"process this source\", \"ingest this article\", \"batch ingest\", \"deepen\", \"I added something to raw/\", \"I clipped some articles\", or wants to incorporate new material into their knowledge base. Sweeps the vault's Clippings/ folder (Obsidian Web Clipper) into raw/ first, enriching metadata on the way." - }, - { - "name": "second-brain-lint", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/second-brain-lint", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Health-checks the wiki for contradictions, orphan pages, stale claims, and missing cross-references. Use when the user says \"audit\", \"health check\", \"lint\", \"find problems\", or wants to improve wiki quality." - }, - { - "name": "second-brain-query", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/second-brain-query", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Answers questions against the knowledge base wiki. Use when the user asks a question about their collected knowledge, wants to explore connections between topics, says \"what do I know about X\", or wants to search their wiki." - }, - { - "name": "second-brain-review", - "repo": "https://github.com/sanketsudake/second-brain", - "subpath": "skills/second-brain-review", - "ref": "main", - "commit": "7c503f4367c7ef08a0a74a70541672ccab0de86d", - "category": "knowledge-base", - "description": "Resurfaces knowledge from the second-brain wiki: a daily or periodic review of highlights, concepts, and stale pages, replacing Readwise's daily review. Use when the user says \"daily review\", \"review my highlights\", \"resurface something\", \"what should I revisit\", or wants spaced-repetition-style engagement with their wiki." - }, - { - "name": "sembr-reformat", - "repo": "https://github.com/sembr/skills", - "subpath": "skills/sembr-reformat", - "ref": "main", - "commit": "5f973aaa75b1165b03dd45dca4cd1dc0437deba3", - "category": "documents", - "description": "Reformat prose using Semantic Line Breaks (SemBr) from https://sembr.org while preserving rendered output and meaning. Use when asked to reflow plain text or compatible markup (Markdown, AsciiDoc, reStructuredText, LaTeX, Org, MediaWiki) into semantic one-thought-per-line formatting, or when improving prose diffs and editorial readability." - }, - { - "name": "setup-matt-pocock-skills", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/setup-matt-pocock-skills", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "\"Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.\"" - }, - { - "name": "thermo-nuclear-code-quality-review", - "repo": "https://github.com/cursor/plugins", - "subpath": "thermos/skills/thermo-nuclear-code-quality-review", - "ref": "main", - "commit": "bdf7aa355337897f167153e05069aca505dae17c", - "category": "pr-review", - "description": "Run an extremely strict maintainability review for abstraction quality, giant files, and spaghetti-condition growth. Use for a thermo-nuclear code quality review, thermonuclear review, deep code quality audit, or especially harsh maintainability review." - }, - { - "name": "thermo-nuclear-review", - "repo": "https://github.com/cursor/plugins", - "subpath": "thermos/skills/thermo-nuclear-review", - "ref": "main", - "commit": "bdf7aa355337897f167153e05069aca505dae17c", - "category": "pr-review", - "description": "Comprehensive security and correctness audit of a branch's changes. Use for thermo nuclear, thermonuclear, or deep review requests, or branch/PR diff audits focused on bugs, breaking changes, security issues, devex regressions, and feature-gate leaks." - }, - { - "name": "to-spec", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/to-spec", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "\"Turn the current conversation into a spec and publish it to the project issue tracker: no interview, just synthesis of what you've already discussed.\"" - }, - { - "name": "to-tickets", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/to-tickets", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker (edges as text in one file per ticket locally, or native blocking links on a real tracker)." - }, - { - "name": "transcribe", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "transcribe", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "search-media", - "description": "Local speech-to-text transcription on Apple Silicon macOS. Supports wav directly and other audio formats via ffmpeg." - }, - { - "name": "vscode", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "vscode", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "search-media", - "description": "VS Code integration for viewing diffs and comparing files. Use when showing file differences to the user." - }, - { - "name": "wayfinder", - "repo": "https://github.com/mattpocock/skills", - "subpath": "skills/engineering/wayfinder", - "ref": "main", - "commit": "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76", - "category": "engineering", - "description": "Plan a huge chunk of work (more than one agent session can hold) as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear." - }, - { - "name": "xlsx", - "repo": "https://github.com/anthropics/skills", - "subpath": "skills/xlsx", - "ref": "main", - "commit": "3b3fad96af16a10759d930941b4520ba0c40edae", - "category": "documents", - "description": "\"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .xltx, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \\\"the xlsx in my downloads\\\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"" - }, - { - "name": "youtube-transcript", - "repo": "https://github.com/badlogic/pi-skills", - "subpath": "youtube-transcript", - "ref": "main", - "commit": "90bb51cae36515a648515b633a81c0c6efc8c74d", - "category": "search-media", - "description": "Fetch transcripts from YouTube videos for summarization and analysis." - } -] diff --git a/skills/verify-hugo-build/.source.json b/skills/verify-hugo-build/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/verify-hugo-build/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/skills/watch-ci/.source.json b/skills/watch-ci/.source.json deleted file mode 100644 index 13b5f5e..0000000 --- a/skills/watch-ci/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "ci-go" -} diff --git a/skills/write-hugo-blog-post/.source.json b/skills/write-hugo-blog-post/.source.json deleted file mode 100644 index 89f5d82..0000000 --- a/skills/write-hugo-blog-post/.source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "repo": null, - "note": "Local skill, maintained in this repo", - "category": "static-site" -} diff --git a/sources.toml b/sources.toml new file mode 100644 index 0000000..eb77d3b --- /dev/null +++ b/sources.toml @@ -0,0 +1,559 @@ +# sources.toml — the single manifest of every skill and agent source. +# Managed by scripts/resource-manager.sh (make skills-* / agents-*); +# an entry with repo+commit is vendored (skill files gitignored, +# materialized from the pin), one without repo is authored here. + +[[skill]] +name = "add-llms-txt" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "agent-browser" +repo = "https://github.com/vercel-labs/agent-browser" +subpath = "skills/agent-browser" +ref = "main" +commit = "9d9a3bbd5e4f8c0a17a1c4dfd2f8e8d74b5ee998" +category = "search-media" +description = "Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools." + +[[skill]] +name = "analyze-go-pprof" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "analyze-prometheus-tsdb" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "apply-workday-leave" +category = "internal-automation" + +[[skill]] +name = "approve-workday-tasks" +category = "internal-automation" + +[[skill]] +name = "audit-static-site" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "author-mermaid-diagram" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "author-security-advisory" +category = "gh-security" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "brave-search" +repo = "https://github.com/badlogic/pi-skills" +subpath = "brave-search" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "search-media" +description = "Web search and content extraction via Brave Search API. Use for searching documentation, facts, or any web content. Lightweight, no browser required." + +[[skill]] +name = "bump-ci-tool-versions" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "bump-hugo-versions" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "caveman" +repo = "https://github.com/juliusbrussee/caveman" +subpath = "skills/caveman" +ref = "main" +commit = "81536f57b3303b7de7f5bc5b564cc344f9112d68" +category = "meta" +description = "Ultra-compressed communication mode. Cuts output tokens 65% (measured) by speaking like caveman while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra, wenyan-lite, wenyan-full, wenyan-ultra. Use when user says \"caveman mode\", \"talk like caveman\", \"use caveman\", \"less tokens\", \"be brief\", or invokes /caveman. Also auto-triggers when token efficiency is requested." + +[[skill]] +name = "codebase-design" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/codebase-design" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary." + +[[skill]] +name = "debug-ci" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "deslop" +repo = "https://github.com/cursor/plugins" +subpath = "cursor-team-kit/skills/deslop" +ref = "main" +commit = "bdf7aa355337897f167153e05069aca505dae17c" +category = "pr-review" +description = "Remove AI-generated code slop and clean up code style" + +[[skill]] +name = "docx" +repo = "https://github.com/anthropics/skills" +subpath = "skills/docx" +ref = "main" +commit = "3b3fad96af16a10759d930941b4520ba0c40edae" +category = "documents" +description = "\"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files) or Word templates (.dotx files). Triggers include: any mention of 'Word doc', 'word document', '.docx', '.dotx', or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx or .dotx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a 'report', 'memo', 'letter', 'template', or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"" + +[[skill]] +name = "domain-modeling" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/domain-modeling" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a CONTEXT.md, or recording or editing an ADR." + +[[skill]] +name = "drive-chrome-cdp" +repo = "https://github.com/sanketsudake/chrome-cdp-cli" +subpath = "skills/drive-chrome-cdp" +ref = "main" +commit = "deee3056260e6dea5f182760e3559d79a7222291" +category = "internal-automation" +description = "Drive the user's real, already-running local Chrome \u2014 its live tabs, logins, and cookies, so it types no credentials \u2014 from the shell via the `chrome-cdp` CLI, which answers every command with one JSON envelope and a stable exit code. Use when a skill names `chrome-cdp`, or when a task needs addressing CSS cannot express (`--by name|ref|cell|label`, `--in-row`), cascade `select`, `grid` table reads, `wait --request`, or `console`/`net` to explain why an action did nothing. Triggers include \"click X in my browser\", \"read what's on my screen\", \"fill in this form in Chrome\", \"check console/network errors on this page\", \"automate this web app in my logged-in session\". The building block other logged-in-app skills follow to get a driven, signed-in tab." + +[[skill]] +name = "fill-workday-timesheet" +category = "internal-automation" + +[[skill]] +name = "find-skills" +repo = "https://github.com/vercel-labs/skills" +subpath = "skills/find-skills" +ref = "main" +commit = "435076e78988e1e6ec40d00b0b1d76bdbbc5419a" +category = "meta" +description = "Helps users discover and install agent skills when they ask questions like \"how do I do X\", \"find a skill for X\", \"is there a skill that can...\", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill." + +[[skill]] +name = "gccli" +repo = "https://github.com/badlogic/pi-skills" +subpath = "gccli" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "google-cli" +description = "Google Calendar CLI for listing calendars, viewing/creating/updating events, and checking availability." + +[[skill]] +name = "gdcli" +repo = "https://github.com/badlogic/pi-skills" +subpath = "gdcli" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "google-cli" +description = "Google Drive CLI for listing, searching, uploading, downloading, and sharing files and folders." + +[[skill]] +name = "generate-og-images" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "gmcli" +repo = "https://github.com/badlogic/pi-skills" +subpath = "gmcli" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "google-cli" +description = "Gmail CLI for searching emails, reading threads, sending messages, managing drafts, and handling labels/attachments." + +[[skill]] +name = "go-deps-security-sweep" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "grill-with-docs" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/grill-with-docs" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go." + +[[skill]] +name = "grilling" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/productivity/grilling" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases." + +[[skill]] +name = "harvest-automation" +category = "meta" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "implement" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/implement" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "\"Implement a piece of work based on a spec or set of tickets.\"" + +[[skill]] +name = "improve-codebase-architecture" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/improve-codebase-architecture" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick." + +[[skill]] +name = "improve-codecov-coverage" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "itr-india" +repo = "https://github.com/shivprime94/file-itr" +subpath = "skills/itr-india" +ref = "main" +commit = "59185d78128bdef6b6d079f885cb6f4778454929" +category = "personal-finance" +description = "Assist a resident Indian individual with preparing and e-filing an Income Tax Return (ITR-1/2/3/4) on the e-filing portal (eportal.incometax.gov.in), under EITHER the old or new tax regime (non-resident / RNOR returns are out of scope). Use WHENEVER the user mentions filing taxes in India, ITR, income tax return, 26AS, AIS, Form 16, old vs new regime, 115BAC, Form 10-IEA, 80C/80D/HRA/home-loan/NPS/80G deductions, 44ADA/44AD presumptive, self-assessment/advance tax/234B/234C, TDS reconciliation, capital gains on Indian shares/mutual funds/property, or crypto/VDA (115BBH/194S) — even if they don't name the form or regime. Covers gathering and reconciling income documents, comparing both regimes to pick the cheaper one, choosing the form, computing tax, filling the portal schedule-by-schedule, fixing validation defects, and guiding payment and e-verification. India personal income tax only — not US/UK/other-country tax, GST, TDS-return (24Q/26Q), or company returns." + +[[skill]] +name = "list-week-meetings" +category = "internal-automation" + +[[skill]] +name = "login-microsoft-sso" +category = "internal-automation" + +[[skill]] +name = "make-pr-easy-to-review" +repo = "https://github.com/cursor/plugins" +subpath = "cursor-team-kit/skills/make-pr-easy-to-review" +ref = "main" +commit = "bdf7aa355337897f167153e05069aca505dae17c" +category = "pr-review" +description = "Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. Use for \"make this easy to review\", \"tidy this PR\", \"clean up commits\", or \"annotate the diff\"." + +[[skill]] +name = "matt-code-review" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/code-review" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "\"Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes: Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/spec asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to \\\"review since X\\\".\"" + +[[skill]] +name = "optimize-svg" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "pdf" +repo = "https://github.com/anthropics/skills" +subpath = "skills/pdf" +ref = "main" +commit = "3b3fad96af16a10759d930941b4520ba0c40edae" +category = "documents" +description = "Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill." + +[[skill]] +name = "pptx" +repo = "https://github.com/anthropics/skills" +subpath = "skills/pptx" +ref = "main" +commit = "3b3fad96af16a10759d930941b4520ba0c40edae" +category = "documents" +description = "\"Use this skill any time a .pptx or .potx file is involved in any way \u2014 as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates (.potx), layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx or .potx filename, regardless of what they plan to do with the content afterward. If a .pptx or .potx file needs to be opened, created, or touched, use this skill.\"" + +[[skill]] +name = "pr-review-canvas" +repo = "https://github.com/cursor/plugins" +subpath = "cursor-team-kit/skills/pr-review-canvas" +ref = "main" +commit = "bdf7aa355337897f167153e05069aca505dae17c" +category = "pr-review" +description = "Generate an interactive PR review walkthrough as an HTML page. Fetches PR data via gh API, categorizes files into core vs mechanical changes, adds reviewer annotations, and renders diffs with moved-code detection. Use when the user pastes a GitHub PR URL and asks for a review, walkthrough, or summary, or says \"review this PR\"." + +[[skill]] +name = "prototype" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/prototype" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like." + +[[skill]] +name = "readwise-cli" +repo = "https://github.com/readwiseio/readwise-skills" +subpath = "skills/readwise-cli" +ref = "master" +commit = "2d1ce9627c611d24f510dfc2e05a123fa509d2f6" +category = "knowledge-base" +description = "How to use the Readwise CLI — access highlights, documents, and your entire reading library from the command line" + +[[skill]] +name = "readwise-second-brain-sync" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/readwise-second-brain-sync" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Syncs Readwise highlights and Reader documents into the second-brain vault's raw/ folder in Obsidian-Web-Clipper format. Use when the user says \"sync readwise\", \"pull my readwise highlights\", \"update raw/ from reader\", or wants their reading library reflected in the wiki (triggers: readwise sync, reader sync, import highlights). Sync only \u2014 follow with /second-brain-ingest." + +[[skill]] +name = "record-engage-activity" +category = "internal-automation" + +[[skill]] +name = "remediate-codeql-alerts" +category = "gh-security" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "report-site-analytics" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "resolve-bot-review-threads" +category = "pr-review" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "review-battery" +category = "pr-review" +note = "Authored orchestrator; replaces the former review-battery and review-pr-worktree commands and drives the vendored thermos subagents" + +[[skill]] +name = "second-brain" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/second-brain" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Sets up a new Obsidian knowledge base using the LLM Wiki pattern, where the LLM acts as librarian over raw sources. Use when the user wants to create a second brain, initialize a vault, set up a personal knowledge base, or says \"onboard\". Interactive setup wizard." + +[[skill]] +name = "second-brain-ideate" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/second-brain-ideate" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Mines the knowledge-base wiki for strong, defensible content ideas \u2014 blog posts, conference talks, internal sessions, threads. Use when the user says \"ideate\", \"what should I write about\", \"find content ideas in my wiki\", \"blog/talk ideas\", or wants to turn collected knowledge into publishable content. Produces a scored shortlist with outlines in output/ and maintains an ideas backlog in wiki/synthesis/." + +[[skill]] +name = "second-brain-ingest" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/second-brain-ingest" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Process raw source documents into wiki pages. Use when the user adds files to raw/ and wants them ingested, or says \"process this source\", \"ingest this article\", \"batch ingest\", \"deepen\", \"I added something to raw/\", \"I clipped some articles\", or wants to incorporate new material into their knowledge base. Sweeps the vault's Clippings/ folder (Obsidian Web Clipper) into raw/ first, enriching metadata on the way." + +[[skill]] +name = "second-brain-lint" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/second-brain-lint" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Health-checks the wiki for contradictions, orphan pages, stale claims, and missing cross-references. Use when the user says \"audit\", \"health check\", \"lint\", \"find problems\", or wants to improve wiki quality." + +[[skill]] +name = "second-brain-query" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/second-brain-query" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Answers questions against the knowledge base wiki. Use when the user asks a question about their collected knowledge, wants to explore connections between topics, says \"what do I know about X\", or wants to search their wiki." + +[[skill]] +name = "second-brain-review" +repo = "https://github.com/sanketsudake/second-brain" +subpath = "skills/second-brain-review" +ref = "main" +commit = "7c503f4367c7ef08a0a74a70541672ccab0de86d" +category = "knowledge-base" +description = "Resurfaces knowledge from the second-brain wiki: a daily or periodic review of highlights, concepts, and stale pages, replacing Readwise's daily review. Use when the user says \"daily review\", \"review my highlights\", \"resurface something\", \"what should I revisit\", or wants spaced-repetition-style engagement with their wiki." + +[[skill]] +name = "sembr-reformat" +repo = "https://github.com/sembr/skills" +subpath = "skills/sembr-reformat" +ref = "main" +commit = "5f973aaa75b1165b03dd45dca4cd1dc0437deba3" +category = "documents" +description = "Reformat prose using Semantic Line Breaks (SemBr) from https://sembr.org while preserving rendered output and meaning. Use when asked to reflow plain text or compatible markup (Markdown, AsciiDoc, reStructuredText, LaTeX, Org, MediaWiki) into semantic one-thought-per-line formatting, or when improving prose diffs and editorial readability." + +[[skill]] +name = "setup-matt-pocock-skills" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/setup-matt-pocock-skills" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "\"Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.\"" + +[[skill]] +name = "source-code-for-gh-advisory" +category = "gh-security" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "thermo-nuclear-code-quality-review" +repo = "https://github.com/cursor/plugins" +subpath = "thermos/skills/thermo-nuclear-code-quality-review" +ref = "main" +commit = "bdf7aa355337897f167153e05069aca505dae17c" +category = "pr-review" +description = "Run an extremely strict maintainability review for abstraction quality, giant files, and spaghetti-condition growth. Use for a thermo-nuclear code quality review, thermonuclear review, deep code quality audit, or especially harsh maintainability review." + +[[skill]] +name = "thermo-nuclear-review" +repo = "https://github.com/cursor/plugins" +subpath = "thermos/skills/thermo-nuclear-review" +ref = "main" +commit = "bdf7aa355337897f167153e05069aca505dae17c" +category = "pr-review" +description = "Comprehensive security and correctness audit of a branch's changes. Use for thermo nuclear, thermonuclear, or deep review requests, or branch/PR diff audits focused on bugs, breaking changes, security issues, devex regressions, and feature-gate leaks." + +[[skill]] +name = "to-spec" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/to-spec" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "\"Turn the current conversation into a spec and publish it to the project issue tracker: no interview, just synthesis of what you've already discussed.\"" + +[[skill]] +name = "to-tickets" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/to-tickets" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Break a plan, spec, or the current conversation into a set of tracer-bullet tickets, each declaring its blocking edges, published to the configured tracker (edges as text in one file per ticket locally, or native blocking links on a real tracker)." + +[[skill]] +name = "transcribe" +repo = "https://github.com/badlogic/pi-skills" +subpath = "transcribe" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "search-media" +description = "Local speech-to-text transcription on Apple Silicon macOS. Supports wav directly and other audio formats via ffmpeg." + +[[skill]] +name = "triage-gh-backlog" +category = "gh-maintenance" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "tufte-information-design" +category = "documents" + +[[skill]] +name = "verify-hugo-build" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "vscode" +repo = "https://github.com/badlogic/pi-skills" +subpath = "vscode" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "search-media" +description = "VS Code integration for viewing diffs and comparing files. Use when showing file differences to the user." + +[[skill]] +name = "watch-ci" +category = "ci-go" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "wayfinder" +repo = "https://github.com/mattpocock/skills" +subpath = "skills/engineering/wayfinder" +ref = "main" +commit = "6654f6b60cd9d5be8b54c6fafe44346dabeb3b76" +category = "engineering" +description = "Plan a huge chunk of work (more than one agent session can hold) as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear." + +[[skill]] +name = "write-hugo-blog-post" +category = "static-site" +note = "Local skill, maintained in this repo" + +[[skill]] +name = "xlsx" +repo = "https://github.com/anthropics/skills" +subpath = "skills/xlsx" +ref = "main" +commit = "3b3fad96af16a10759d930941b4520ba0c40edae" +category = "documents" +description = "\"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .xltx, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path \u2014 even casually (like \\\"the xlsx in my downloads\\\") \u2014 and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"" + +[[skill]] +name = "youtube-transcript" +repo = "https://github.com/badlogic/pi-skills" +subpath = "youtube-transcript" +ref = "main" +commit = "90bb51cae36515a648515b633a81c0c6efc8c74d" +category = "search-media" +description = "Fetch transcripts from YouTube videos for summarization and analysis." + +[[agent]] +name = "bulk-mechanic" +category = "execution" + +[[agent]] +name = "plan-reviewer" +category = "planning" + +[[agent]] +name = "pr-shepherd" +category = "pr-review" + +[[agent]] +name = "skill-auditor" +category = "meta" + +[[agent]] +name = "thermo-nuclear-code-quality-review-subagent" +repo = "https://github.com/cursor/plugins" +subpath = "thermos/agents/thermo-nuclear-code-quality-review-subagent.md" +ref = "main" +commit = "60c641e4fad674784b30abcf9f8915dea39df38d" +fetched_at = "2026-08-19T16:02:26Z" +category = "pr-review" + +[[agent]] +name = "thermo-nuclear-review-subagent" +repo = "https://github.com/cursor/plugins" +subpath = "thermos/agents/thermo-nuclear-review-subagent.md" +ref = "main" +commit = "60c641e4fad674784b30abcf9f8915dea39df38d" +fetched_at = "2026-08-19T16:02:17Z" +category = "pr-review" From 91fda37360ba2e073fb922a445ef08365bd42279 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 22:06:23 +0530 Subject: [PATCH 50/51] Refresh the deslop pin and let doctor accept the shared skills tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The harness symlink health check resolved ~/.pi/skills through the package symlink to the top-level skills/ tree, outside packages/ — accept any path inside the repo. The deslop bump is the skills-update round-trip check on the new manifest. --- scripts/doctor.sh | 4 ++-- sources.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 6e04361..6d62b7e 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -117,8 +117,8 @@ fi for t in "$HOME/.claude-personal/CLAUDE.md" "$HOME/.claude-work/CLAUDE.md" "$HOME/.pi/skills"; do r="$(resolve "$t")" case "$r" in - "$REPO_DIR"/packages/*) ok "$t -> repo" ;; - *) bad "$t does not resolve into $REPO_DIR/packages — run: make harness-link" ;; + "$REPO_DIR"/*) ok "$t -> repo" ;; + *) bad "$t does not resolve into $REPO_DIR — run: make harness-link" ;; esac done diff --git a/sources.toml b/sources.toml index eb77d3b..7df2df8 100644 --- a/sources.toml +++ b/sources.toml @@ -97,7 +97,7 @@ name = "deslop" repo = "https://github.com/cursor/plugins" subpath = "cursor-team-kit/skills/deslop" ref = "main" -commit = "bdf7aa355337897f167153e05069aca505dae17c" +commit = "fd878692de15a3069c21c8f429eb0b9f2fe178fa" category = "pr-review" description = "Remove AI-generated code slop and clean up code style" From f59889c62af7937cc771272b8a83baadf3709b66 Mon Sep 17 00:00:00 2001 From: Sanket Sudake Date: Mon, 31 Aug 2026 22:14:08 +0530 Subject: [PATCH 51/51] Refresh vendored agent pins and regenerate catalogs agents-update-all exercises the agent-kind manifest write path on the new sources.toml; the deslop description refresh from the previous round-trip lands in the regenerated catalog and suite page. --- skills/README.md | 2 +- sources.toml | 8 ++++---- suites/pr-shepherding/README.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/skills/README.md b/skills/README.md index 9676110..7117d76 100644 --- a/skills/README.md +++ b/skills/README.md @@ -133,7 +133,7 @@ Generated by `make skills-catalog` — do not edit by hand (`make skills-doctor` | Skill | Purpose | |-------|---------| -| [`deslop`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | +| [`deslop`](https://github.com/cursor/plugins/tree/fd878692de15a3069c21c8f429eb0b9f2fe178fa/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | | [`make-pr-easy-to-review`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/make-pr-easy-to-review) | Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. | | [`pr-review-canvas`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/pr-review-canvas) | Generate an interactive PR review walkthrough as an HTML page. | | [`resolve-bot-review-threads`](resolve-bot-review-threads/SKILL.md) | Clears bot/Copilot review threads on a PR — fixes the issues, marks threads resolved via GraphQL, and re-requests the bot until the PR is clean. | diff --git a/sources.toml b/sources.toml index 7df2df8..e7c4058 100644 --- a/sources.toml +++ b/sources.toml @@ -545,8 +545,8 @@ name = "thermo-nuclear-code-quality-review-subagent" repo = "https://github.com/cursor/plugins" subpath = "thermos/agents/thermo-nuclear-code-quality-review-subagent.md" ref = "main" -commit = "60c641e4fad674784b30abcf9f8915dea39df38d" -fetched_at = "2026-08-19T16:02:26Z" +commit = "fd878692de15a3069c21c8f429eb0b9f2fe178fa" +fetched_at = "2026-08-31T16:38:45Z" category = "pr-review" [[agent]] @@ -554,6 +554,6 @@ name = "thermo-nuclear-review-subagent" repo = "https://github.com/cursor/plugins" subpath = "thermos/agents/thermo-nuclear-review-subagent.md" ref = "main" -commit = "60c641e4fad674784b30abcf9f8915dea39df38d" -fetched_at = "2026-08-19T16:02:17Z" +commit = "fd878692de15a3069c21c8f429eb0b9f2fe178fa" +fetched_at = "2026-08-31T16:38:52Z" category = "pr-review" diff --git a/suites/pr-shepherding/README.md b/suites/pr-shepherding/README.md index c03586c..f4f0e8f 100644 --- a/suites/pr-shepherding/README.md +++ b/suites/pr-shepherding/README.md @@ -49,7 +49,7 @@ Each step is the literal phrase you say to your agent (Claude Code, pi, or any h | Skill | Purpose | |-------|---------| | [`make-pr-easy-to-review`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/make-pr-easy-to-review) | Prepare PRs for review by cleaning noisy history, improving PR descriptions, and adding reviewer guidance without changing code behavior. | -| [`deslop`](https://github.com/cursor/plugins/tree/bdf7aa355337897f167153e05069aca505dae17c/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | +| [`deslop`](https://github.com/cursor/plugins/tree/fd878692de15a3069c21c8f429eb0b9f2fe178fa/cursor-team-kit/skills/deslop) | Remove AI-generated code slop and clean up code style | | [`resolve-bot-review-threads`](../../skills/resolve-bot-review-threads/SKILL.md) | Clears bot/Copilot review threads on a PR — fixes the issues, marks threads resolved via GraphQL, and re-requests the bot until the PR is clean. | | [`watch-ci`](../../skills/watch-ci/SKILL.md) | Watches a PR's CI checks to terminal state in the background and turns each transition into a notification, instead of a foreground polling loop. | | [`debug-ci`](../../skills/debug-ci/SKILL.md) | Triages and root-causes a failing GitHub Actions CI run on a PR by separating real regressions from pre-existing noise and escalating log fetches cheapest-fi... |