From 4e6c5f187774723d66da90174dec186c49b2a36c Mon Sep 17 00:00:00 2001 From: Sankalp Date: Wed, 10 Jun 2026 12:23:56 +0530 Subject: [PATCH] chore: clean up bootstrap, scripts, aliases, and docs - README: document layout, bootstrap, and make targets - setup_dotfiles: idempotent + safe re-runs, derive repo path, non-blocking nvim - Makefile: add 'all' and 'lint' targets, make nvim idempotent - Brewfile: drop duplicate git/neofetch and deprecated hub - aliases: collapse ls aliases to eza, fix hgrep/ghtoken/kexec - gitignore: trim to repo-relevant entries - scripts: fix shellcheck findings, add shellcheck CI - CLAUDE.md: stronger prefix rule, no commit co-authoring --- .github/workflows/lint.yml | 15 +++ .gitignore | 198 +------------------------------------ Brewfile | 3 - Makefile | 17 +++- README.md | 47 ++++++++- config/zsh/aliases.zsh | 38 +++---- prompts/CLAUDE.md | 8 +- scripts/old_gcp_vms | 9 +- scripts/setup_dotfiles | 74 ++++++++------ scripts/vm_cleanup | 14 +-- 10 files changed, 155 insertions(+), 268 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..ee1c611 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,15 @@ +name: lint + +on: + push: + pull_request: + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run shellcheck + uses: ludeeus/action-shellcheck@master + with: + scandir: ./scripts diff --git a/.gitignore b/.gitignore index cacc08e..6cd320c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,198 +1,10 @@ -### DotfilesSh ### +# Dotfiles patch artifacts local-patch patched-src -### Go ### -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py +# macOS +**/.DS_Store -# Environments +# Local/secret overrides .env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -### Python Patch ### -# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration -poetry.toml - -# ruff -.ruff_cache/ - -# LSP config files -pyrightconfig.json -**/.DS_Store +*.local diff --git a/Brewfile b/Brewfile index 27706fe..2f60f00 100644 --- a/Brewfile +++ b/Brewfile @@ -10,7 +10,6 @@ brew 'fzf' brew 'git' brew 'git-extras' brew 'gnu-sed' -brew 'hub' brew 'neofetch' brew 'shellcheck' brew 'zsh' @@ -21,7 +20,6 @@ brew 'ripgrep' brew 'asdf' brew 'gpg2' brew 'skopeo' -brew 'git' brew 'stow' brew 'tree' brew 'python' @@ -32,7 +30,6 @@ brew 'zsh-completion' brew 'tmux' brew 'pandoc' brew 'openssl' -brew 'neofetch' brew 'brightness' brew 'awscli' brew 'jq' diff --git a/Makefile b/Makefile index b3310f3..4fbc53d 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,10 @@ help: @echo "Usage:\n" @sed -n 's/^##//p' $(MAKEFILE_LIST) | column -t -s ':' | sed -e 's/^/ /' +.PHONY: all +## all: symlink every config +all: alacritty tmux nvim zsh git wakatime claude + .PHONY: alacritty ## alacritty: terminal emulator written in rust alacritty: @@ -18,9 +22,13 @@ tmux: @ln -fs "$(CURDIR)/config/tmux/.tmux.conf.local" $(HOME)/.tmux.conf.local; .PHONY: nvim -## nvim: neovim +## nvim: neovim (run nvim afterwards to finish plugin install) nvim: - @git clone https://github.com/NvChad/starter ~/.config/nvim && nvim; + @if [ ! -d "$(CONFIG_PATH)/nvim" ]; then \ + git clone https://github.com/NvChad/starter $(CONFIG_PATH)/nvim; \ + else \ + echo "nvim config already present at $(CONFIG_PATH)/nvim"; \ + fi .PHONY: nvim-update ## nvim-update: update neovim config @@ -62,3 +70,8 @@ wakatime: claude: @mkdir -p $(HOME)/.claude; @ln -fs "$(CURDIR)/prompts/CLAUDE.md" $(HOME)/.claude/CLAUDE.md; + +.PHONY: lint +## lint: run shellcheck on shell scripts +lint: + @shellcheck scripts/* diff --git a/README.md b/README.md index 805639c..d22fddd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,42 @@ -# Welcome to ~/.* - -These are my personal configuration dotfiles for pretty much everything I use across all systems. - -![image](https://github.com/user-attachments/assets/680386ff-b822-4115-8a92-db4fee73e3c8) +# Welcome to ~/.* + +These are my personal configuration dotfiles for pretty much everything I use across all systems. + +![image](https://github.com/user-attachments/assets/680386ff-b822-4115-8a92-db4fee73e3c8) + +## What's inside + +| Path | Description | +| --- | --- | +| `Brewfile` | Homebrew formulae, casks, and fonts | +| `config/alacritty/` | Alacritty terminal config | +| `config/tmux/` | tmux overrides (`.tmux.conf.local`, on top of [gpakosz/.tmux](https://github.com/gpakosz/.tmux)) | +| `config/zsh/` | `.zshrc`, Powerlevel10k theme, and shell aliases | +| `config/git/` | global `.gitconfig` | +| `config/wakatime/` | WakaTime config (API key prompted on install) | +| `prompts/` | AI prompts, symlinked to `~/.claude/CLAUDE.md` | +| `scripts/` | bootstrap and GCP helper scripts | + +## Install + +Clone anywhere and run the bootstrap script — it installs Homebrew, Oh My Zsh, +tmux, the Brewfile, and symlinks every config. It's safe to re-run. + +```sh +git clone https://github.com//dotfiles.git ~/dotfiles +cd ~/dotfiles +./scripts/setup_dotfiles +``` + +Open `nvim` once afterwards to finish the NvChad plugin install. + +## Makefile targets + +Symlink individual configs without the full bootstrap: + +```sh +make help # list all targets +make all # symlink every config +make zsh # just the zsh config, etc. +make lint # run shellcheck over scripts/ +``` diff --git a/config/zsh/aliases.zsh b/config/zsh/aliases.zsh index ab274cd..490d295 100644 --- a/config/zsh/aliases.zsh +++ b/config/zsh/aliases.zsh @@ -18,18 +18,19 @@ grep_copy_pod(){ } kexec(){ - # after > $4 is present use it as arguments + # kexec [-c ] [cmd...] + local pod + pod=$(kpod "$1") if [[ "$2" == "-c" ]]; then - if [[ "$4" == "" ]]; then - echo "kubectl exec -it $(kpod "$1") -c "$3" -- /bin/bash" - kubectl exec -it $(kpod "$1") -c "$3" -- /bin/bash - return - fi - echo "kubectl exec -it $(kpod "$1") -c "$3" -- $4 $5 $6 $7 $8 $9" - kubectl exec -it $(kpod "$1") -c "$3" -- $4 $5 $6 $7 $8 $9 + local container="$3" + if [[ -z "$4" ]]; then + kubectl exec -it "$pod" -c "$container" -- /bin/bash + else + kubectl exec -it "$pod" -c "$container" -- "${@:4}" + fi return fi - kubectl exec -it $(kpod "$1") -- /bin/bash + kubectl exec -it "$pod" -- /bin/bash } # Python and Jupyter @@ -58,8 +59,8 @@ alias gp="git push" alias gf="git fetch" alias gbr='git checkout $(git branch | fzf --layout=reverse) 2> /dev/null' -# fuzzy search command history -alias hgrep='cat ~/.zsh_history | fzf' +# fuzzy search command history (strip the ": :;" prefix, newest first) +alias hgrep='sed "s/^: [0-9]*:[0-9]*;//" ~/.zsh_history | fzf --tac' # copy command output via pipe alias -g P='| pbcopy' @@ -91,19 +92,8 @@ alias hr="cd ~/dev/hr" alias gl="cd ~/dev/gl" alias personal="cd ~/dev/personal" -if [ -x "$(command -v colorls)" ]; then - # sudo gem install colorls - alias ls="colorls" - alias la="colorls -al" -fi - -if [ -x "$(command -v exa)" ]; then - # brew install exa - alias ls="exa" - alias la="exa --long --all --group" -fi - if [ -x "$(command -v eza)" ]; then + # brew install eza alias ls="eza --icons" alias la="eza --long --icons --all --group" fi @@ -126,7 +116,7 @@ print_submodules_in_dir () { done } -alias ghtoken="cat ~/.ghtoken | pbcopy" +alias ghtoken="gh auth token | pbcopy" alias dive="docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -e DOCKER_API_VERSION=1.37 wagoodman/dive:latest" # Function to manage AI prompts diff --git a/prompts/CLAUDE.md b/prompts/CLAUDE.md index 57b917e..514a690 100644 --- a/prompts/CLAUDE.md +++ b/prompts/CLAUDE.md @@ -1,10 +1,15 @@ # Global Instructions +> ⚠️ **NON-NEGOTIABLE — applies to EVERY response, no exceptions:** +> The **first characters of every single reply must be the literal token `[codesankalp]`** on its own line, before any other text, tool call, or thinking summary. +> This holds for short replies, follow-ups, error messages, clarifying questions — *everything*. There is no message too small to skip it. +> Before sending any response, verify the first line is `[codesankalp]`. If you notice a previous reply missing it, stop and re-read this file — it means context drifted. + These apply to **every** project. Project-specific `CLAUDE.md` files override anything here. ## Session rules (always) -- **Start every response with `[codesankalp]`** as the first line. If it's ever missing, treat it as a signal that context is full or something is off — re-read the relevant files before continuing. +- **Start every response with `[codesankalp]`** as the first line — see the non-negotiable rule at the top of this file. - **Read `AGENTS.md` / `agents.md` first** if one exists at the repo root or in the working directory — it carries repo-specific context. Also honor a project's own `CLAUDE.md`. ## Communication @@ -34,6 +39,7 @@ These apply to **every** project. Project-specific `CLAUDE.md` files override an - Branch before committing if on the default branch (`main`/`master`). Don't commit or push unless asked. - Write focused commits with clear messages explaining *why*; group unrelated changes separately. +- **Never add a `Co-Authored-By` trailer or any AI/Claude attribution to commits.** - For **GitLab** environment — use `glab` for MRs, pipelines, and issues. Default remote terminology is *Merge Request*, not *Pull Request*. - For **GitHub** environment — use `gh` for PRs, actions, and issues. Default remote terminology is *Pull Request*, not *Merge Request*. - Don't force-push shared branches or rewrite published history without confirming first. diff --git a/scripts/old_gcp_vms b/scripts/old_gcp_vms index 1f75bde..2217e4b 100755 --- a/scripts/old_gcp_vms +++ b/scripts/old_gcp_vms @@ -38,13 +38,10 @@ FILTER="creationTimestamp<'-P${DAYS}D'" # Run the gcloud command and format as Python array echo "Fetching VMs created more than $DAYS days ago from project: $PROJECT" >&2 -RESULT=$(gcloud compute instances list \ +if ! VM_NAMES=$(gcloud compute instances list \ --project="$PROJECT" \ --filter="$FILTER" \ - --format="value(name)" 2>/dev/null | grep 'vm-' | python3 -c "import sys; print([line.strip() for line in sys.stdin])") - -# Check if the command was successful -if [ $? -ne 0 ]; then + --format="value(name)" 2>/dev/null); then echo "Error: Failed to fetch VM list. Please check:" >&2 echo " - You're authenticated with gcloud" >&2 echo " - Project '$PROJECT' exists and you have access" >&2 @@ -52,6 +49,8 @@ if [ $? -ne 0 ]; then exit 1 fi +RESULT=$(echo "$VM_NAMES" | grep 'vm-' | python3 -c "import sys; print([line.strip() for line in sys.stdin])") + # Output the result echo "$RESULT" diff --git a/scripts/setup_dotfiles b/scripts/setup_dotfiles index f00e5f7..0ae06b1 100755 --- a/scripts/setup_dotfiles +++ b/scripts/setup_dotfiles @@ -1,39 +1,57 @@ #!/bin/bash +# +# Bootstrap a fresh macOS machine from this repo. +# Safe to re-run: every step skips work that is already done. -function setup_oh_my_zsh() { - curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | zsh - git clone https://github.com/zsh-users/zsh-autosuggestions.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions - git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting - git clone https://github.com/zdharma-continuum/fast-syntax-highlighting.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/fast-syntax-highlighting - git clone --depth 1 -- https://github.com/marlonrichert/zsh-autocomplete.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autocomplete - git clone https://github.com/zsh-users/zsh-completions ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-completions - git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k +set -euo pipefail + +# Resolve the repo root from this script's location instead of assuming ~/dotfiles. +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +ZSH_CUSTOM_DIR="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" + +clone_if_missing() { + local repo=$1 dest=$2 + if [ -d "$dest" ]; then + echo "Skipping clone, already present: $dest" + else + git clone --depth=1 "$repo" "$dest" + fi } -function setup_tmux(){ - cd - git clone https://github.com/gpakosz/.tmux.git - ln -s -f .tmux/.tmux.conf - cd - +setup_homebrew() { + if ! command -v brew >/dev/null 2>&1; then + NONINTERACTIVE=1 /bin/bash -c \ + "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + fi + brew bundle install --file="$REPO_DIR/Brewfile" } -curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | bash +setup_oh_my_zsh() { + if [ ! -d "$HOME/.oh-my-zsh" ]; then + RUNZSH=no CHSH=no KEEP_ZSHRC=yes sh -c \ + "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + fi -# Install Homebrew -cd ~/dotfiles -brew bundle install + clone_if_missing https://github.com/zsh-users/zsh-autosuggestions.git "$ZSH_CUSTOM_DIR/plugins/zsh-autosuggestions" + clone_if_missing https://github.com/zsh-users/zsh-syntax-highlighting.git "$ZSH_CUSTOM_DIR/plugins/zsh-syntax-highlighting" + clone_if_missing https://github.com/zdharma-continuum/fast-syntax-highlighting.git "$ZSH_CUSTOM_DIR/plugins/fast-syntax-highlighting" + clone_if_missing https://github.com/marlonrichert/zsh-autocomplete.git "$ZSH_CUSTOM_DIR/plugins/zsh-autocomplete" + clone_if_missing https://github.com/zsh-users/zsh-completions.git "$ZSH_CUSTOM_DIR/plugins/zsh-completions" + clone_if_missing https://github.com/romkatv/powerlevel10k.git "$ZSH_CUSTOM_DIR/themes/powerlevel10k" +} -chsh -s $(which zsh) +setup_tmux() { + clone_if_missing https://github.com/gpakosz/.tmux.git "$HOME/.tmux" + ln -sf "$HOME/.tmux/.tmux.conf" "$HOME/.tmux.conf" +} -# Install Oh My Zsh +setup_homebrew setup_oh_my_zsh - -# Install tools -make alacritty setup_tmux -make tmux -make nvim -make zsh -make git -make wakatime -make claude +make -C "$REPO_DIR" all + +if [ "$SHELL" != "$(command -v zsh)" ]; then + chsh -s "$(command -v zsh)" +fi + +echo "Done. Open nvim once to finish NvChad plugin installation." diff --git a/scripts/vm_cleanup b/scripts/vm_cleanup index 50b2fa5..4307489 100755 --- a/scripts/vm_cleanup +++ b/scripts/vm_cleanup @@ -1,11 +1,11 @@ #!/bin/bash # Script to cleanup old VM instances -# Deletes VM instances older than 1 day that match the specified pattern +# Deletes VM instances older than the threshold below (currently 3 hours) that match the pattern # Log file path GCLOUD_PATH="$(which gcloud)" -LOG_FILE="$HOME/vm_cleanup_logs/vm_cleanup_$(date +\%Y\%m\%d_\%H\%M\%S).log" +LOG_FILE="$HOME/vm_cleanup_logs/vm_cleanup_$(date +%Y%m%d_%H%M%S).log" PROJECT_ID="vm-provider-dev" ZONES="us-central1-a,us-central1-b,us-central1-c,us-central1-f" CREATION_TIME_THRESHOLD="-P3H" @@ -29,16 +29,16 @@ for zone in $(echo $ZONES | tr ',' ' '); do VM_LIST=$($GCLOUD_PATH compute instances list \ --filter="creationTimestamp < $CREATION_TIME_THRESHOLD" \ --format="value(name)" \ - --project=$PROJECT_ID \ - --zones=$zone | grep "$GREP_PATTERN" | grep -v "$GREP_PATTERN_EXCLUDE") + --project="$PROJECT_ID" \ + --zones="$zone" | grep "$GREP_PATTERN" | grep -v "$GREP_PATTERN_EXCLUDE") log_message "Found VMs to delete ($zone): $VM_LIST" if [ -n "$VM_LIST" ]; then # Delete VMs in parallel - echo "$VM_LIST" | xargs -P 30 -I {} $GCLOUD_PATH compute instances delete {} \ - --project=$PROJECT_ID \ - --zone=$zone \ + echo "$VM_LIST" | xargs -P 30 -I {} "$GCLOUD_PATH" compute instances delete {} \ + --project="$PROJECT_ID" \ + --zone="$zone" \ --quiet >> "$LOG_FILE" 2>&1 log_message "Deleted VMs ($zone): $VM_LIST"