diff --git a/.gitignore b/.gitignore index 6a40d02..9e67ebd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ nvim/snapshot nvim/plugin nvim/nvim +nvim/lazy-lock.json + +gemini/history +gemini/tmp +gemini/google_accounts.json +gemini/installation_id +gemini/oauth_creds.json +gemini/projects.json +gemini/state.json +gemini/trustedFolders.json diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..1faed1a --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,54 @@ +# Dotfiles Project Overview + +This repository contains personal configuration files (dotfiles) for various tools, including Zsh, Neovim, Tmux, Git, and more. It is designed to be portable across macOS (Darwin) and Linux (Debian-based distributions). + +## Core Technologies +- **Shell:** Zsh with [Oh My Zsh](https://ohmyz.sh/), [ys theme](https://github.com/ohmyzsh/ohmyzsh/wiki/Themes#ys), and several plugins (`gh`, `git`, `vi-mode`, `pyenv`, `nodenv`, `asdf`, `poetry`). +- **Editor:** Neovim configured using [LazyVim](https://www.lazyvim.org/) and [lazy.nvim](https://github.com/folke/lazy.nvim). +- **Terminal Multiplexer:** Tmux with platform-specific configurations (`tmux/Darwin.conf` and `tmux/Linux.conf`). +- **Tool Managers:** Supports `pyenv`, `nodenv`, `rbenv`, `goenv`, `tfenv`, and `rustup`. +- **Package Managers:** Homebrew (macOS) and `apt` (Linux). + +## Directory Structure +- `bin/`: Custom scripts and binaries. +- `nvim/`: Neovim configuration (`init.lua`, `lua/config/`, `lua/plugins/`). +- `shlibs/`: Shell libraries for installation, logging, and environment detection. +- `tmux/`: Tmux configurations, including OS-specific overrides. +- `zsh/`: Zsh environment, aliases, functions, and SSH agent setup. +- `install.sh`: The main installation script for dependencies and configuration linking. + +## Building and Running + +### Installation +The primary entry point for setting up the environment is `install.sh`. + +```bash +# General installation (deps + config) +./install.sh install + +# Only install configurations (symlinking) +./install.sh config + +# Fast installation (skips some prompts) +./install.sh fast-install + +# Install only Neovim and its dependencies +./install.sh install-neovim +``` + +The `install.sh` script performs the following actions: +1. Installs system-level dependencies via Homebrew or `apt`. +2. Sets up tool version managers (`pyenv`, `nodenv`, etc.). +3. Installs Rust, Neovim, and various CLI tools (`ripgrep`, `fd`, `gh`). +4. Symlinks configuration files from the repository to the home directory (e.g., `~/.zshrc`, `~/.tmux.conf`, `~/.config/nvim`). + +### Maintenance +- **Purge configurations:** `./install.sh purge` removes the symlinks created by the installer. +- **Update Neovim:** The installer includes a `compile_neovim` function for Linux environments to build from source. + +## Development Conventions + +- **Shell Scripting:** Shared logic is modularized in `shlibs/`. Use `shlibs/logging.sh` for output and `shlibs/os.sh` for platform detection. +- **Neovim Configuration:** Follows the `LazyVim` structure. Custom plugins should be added to `nvim/lua/plugins/`, and core configurations to `nvim/lua/config/`. +- **Environment Variables:** Managed in `zsh/env.zsh`. Paths and tool initializations should be added there to ensure they are available in the shell. +- **Aliases:** Custom aliases are located in `zsh/aliases.zsh`. diff --git a/gemini/GEMINI.md b/gemini/GEMINI.md new file mode 100644 index 0000000..f489d30 --- /dev/null +++ b/gemini/GEMINI.md @@ -0,0 +1,15 @@ + +# Use Tools available +use mcp_context7_query-docs to query for api documentation +use mcp_github for relevant github tasks +use mcp_astgrep for abstract syntax tree dumps and efficient structured code search + +# Making changes +- break down commits by units of work +- commits should be broken down into logical parts +- do not group unrelated changes into a single commit +- do not comment code. +- code should be self documenting. +- use clear naming, descriptive variables. +- code should prioritize readability +- code should be concise, but not obfuscated. diff --git a/gemini/policies/tools.toml b/gemini/policies/tools.toml new file mode 100644 index 0000000..ddf8e47 --- /dev/null +++ b/gemini/policies/tools.toml @@ -0,0 +1,167 @@ +# Project-level tool permissions migrated from tools.allowed and tools.exclude +# Generated to comply with Gemini CLI 1.0 Policy Engine migration. + +# Allowed shell commands (No-prompt) +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git status" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git diff" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git log" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git grep" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git branch --show-current" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git remote -v" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "gh pr status" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "gh show" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "gh pr checks" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "gh pr view" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "gh run view" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "diff" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "find" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "pwd" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "grep" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "cat" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "ls" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "poetry run flake8" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "poetry run pyright" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "cd" +decision = "allow" +priority = 100 + +# Other allowed tools +[[rule]] +toolName = "find_code" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "list_directory" +decision = "allow" +priority = 100 + +[[rule]] +toolName = "read_file" +decision = "allow" +priority = 100 + +# Explicitly allowed git commands for specific repositories +# Uses argsPattern to match both the command and the dir_path (keys are sorted alphabetically) +[[rule]] +toolName = "run_shell_command" +argsPattern = '"command":"git (add|commit|push|pull|fetch|rebase|reset|stash|status|diff|log|grep).*","dir_path":"/.*/repos/jaybocc2/.*"' +decision = "allow" +priority = 120 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git commit" +decision = "ask_user" +priority = 100 + +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git add" +decision = "ask_user" +priority = 100 + +# Explicitly denied shell commands +[[rule]] +toolName = "run_shell_command" +commandPrefix = "git push" +decision = "deny" +priority = 100 +deny_message = "Git push is restricted by project policy. Please use git commands directly if needed." diff --git a/gemini/settings.json b/gemini/settings.json index 14a3cff..50ab305 100644 --- a/gemini/settings.json +++ b/gemini/settings.json @@ -1,6 +1,12 @@ { - "selectedAuthType": "oauth-personal", - "preferredEditor": "neovim", + "policyPaths": [ + "./gemini/policies" + ], + "security": { + "auth": { + "selectedType": "oauth-personal" + } + }, "checkpointing": { "enabled": true }, @@ -20,17 +26,64 @@ ] }, "github": { + "description": "Connect AI assistants to GitHub - manage repos, issues, PRs, and workflows through natural language.", "httpUrl": "https://api.githubcopilot.com/mcp/", "headers": { - "Authorization": "${GITHUB_PAT}" + "Authorization": "Bearer ${GITHUB_PAT}" }, "timeout": 5000 }, "context7": { + "description": "Up-to-date code docs for any prompt", "httpUrl": "https://mcp.context7.com/mcp", "headers": { "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}" } } + }, + "context": { + "fileName": [ + "AGENTS.md", + "CONTEXT.md", + "GEMINI.md", + "CLAUDE.md", + ".claude/CLAUDE.md" + ] + }, + "tools": { + "core": [ + "list_directory", + "read_file", + "grep_search", + "glob", + "replace", + "write_file", + "web_fetch", + "run_shell_command", + "save_memory", + "google_web_search", + "ask_user", + "codebase_investigator", + "cli_help", + "activate_skill" + ] + }, + "general": { + "preferredEditor": "neovim", + "sessionRetention": { + "enabled": true, + "maxAge": "30d", + "warningAcknowledged": true + } + }, + "experimental": { + "plan": true + }, + "vimMode": true, + "fileFiltering": { + "respectGitIgnore": true + }, + "model": { + "name": "auto-gemini-3" } -} +} \ No newline at end of file diff --git a/gemini/skills/address-pr-feedback/SKILL.md b/gemini/skills/address-pr-feedback/SKILL.md new file mode 100644 index 0000000..59e1005 --- /dev/null +++ b/gemini/skills/address-pr-feedback/SKILL.md @@ -0,0 +1,61 @@ +--- +name: address-pr-comments +description: Address review comments on a GitHub pull request. Use when the user asks to "address PR comments", "respond to review feedback", "handle reviewer comments", or "resolve review threads". +disable-model-invocation: true +--- + +# Address PR Review Comments + +## Context + +- Current branch: !`git branch --show-current` +- get pull request review with git mcp: `pull_request_read` + +## Your task + +Work through every unresolved review thread on this PR systematically. For each thread: + +### Step 1 — Understand the comment +Read the comment carefully. Identify: +- What file and line it refers to +- What the reviewer is asking for (change, question, clarification, nitpick) +- Whether a code change is actually required + +### Step 2 — Make changes if needed +If a code change is warranted: +- Read the relevant file(s) first +- Make the change using Edit (or Write for new files) +- Do NOT commit yet — collect all changes first + +If no change is needed (e.g. the reviewer asked a question, or you disagree), prepare a clear explanation. + +### Step 3 — Commit each change separately +After addressing a comment that requires code changes, create a single follow-up commit. Write a short message that summarizes what was changed (e.g. `"fix: use const for immutable bindings per review"`) rather than a generic message: + +Skip this step if no code changes were made. +Provide a commit message and wait until prompted to continue if not allowed by policy to commit. + +### Step 4 — Reply to each comment +use github mcp + +Good reply patterns: +- For changes made: "Done — ." +- For questions answered: "< direct answer to question >." +- For declined suggestions: "I kept the existing approach because ." +- For issues already resolved in code: "I fixed this in " + +### Step 5 — Resolve each thread +Resolve every thread/comment if satisfactory +use git mcp / gh cli and GraphQL id field: + +``` +gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: ""}) { thread { id isResolved } } }' +``` +## Notes + +- break down commits by units of work +- commits should be broken down into logical parts +- do not group unrelated changes into a single commit +- If the PR has no open review threads, report that there is nothing to address +- Always reply before resolving so the reviewer sees the response +- Keep replies concise and direct diff --git a/gitconfig b/gitconfig index 1c0fceb..52485da 100644 --- a/gitconfig +++ b/gitconfig @@ -19,3 +19,8 @@ [credential "https://gist.github.com"] helper = helper = !/opt/homebrew/bin/gh auth git-credential + +[includeIf "gitdir:~/repos/work/"] + path = ~/.gitconfig-work +[alias] + syncmain = "!f() { CURRENT_BRANCH=$(git symbolic-ref --short HEAD); if [ \"$CURRENT_BRANCH\" = main ]; then echo 'Error: cannot run syncmain on main branch.' >&2; exit 1; fi; git checkout main && git pull origin main && git checkout \"$CURRENT_BRANCH\" && git rebase origin/main && git push origin \"$CURRENT_BRANCH\" --force-with-lease; }; f" diff --git a/gitignore_global b/gitignore_global index d57981a..c3062ca 100644 --- a/gitignore_global +++ b/gitignore_global @@ -24,3 +24,4 @@ # misc # ######## *.sw? +.worktrees/ diff --git a/install.sh b/install.sh index f018784..9335ef6 100755 --- a/install.sh +++ b/install.sh @@ -10,13 +10,13 @@ git rev-parse --abbrev-ref --symbolic-full-name '@{u}' || { exit 1 } -DOT_FILES=$(git ls-tree '@{u}' | awk '{print $4}' | grep -Ev '(/|LICENSE|README|install.sh|shlibs|test.sh|.gitignore|.gitmodules|bashrc|^vim|vimrc|screenrc|gemini)') +DOT_FILES=$(git ls-tree '@{u}' | awk '{print $4}' | grep -Ev '(/|LICENSE|README|install.sh|shlibs|test.sh|.gitignore|.gitmodules|bashrc|^vim|vimrc|screenrc)') DEB_DEPS="zip unzip curl exuberant-ctags wget tmux zsh zsh-common vim git xclip zlib1g zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \ libncurses5-dev libssl-dev build-essential htop libffi-dev libffi7 xz-utils" # DEB_BACKPORTS_DEPS="" # DEB_BACKPORTS_REPO="" # DEB_TESTING_DEPS="" -OSX_DEPS="ctags wget tmux zsh vim git gh readline xz htop" +OSX_DEPS="ctags wget tmux zsh vim git gh readline xz htop grep fzf colima docker yq jq libpq pre-commit direnv" GO_VERSION=1.18.4 PY3_VERSION=3.13.7 RUBY_VERSION=3.1.2 # update in nvim/lua/options.lua @@ -153,7 +153,7 @@ install_ast_grep() { cargo install ast-grep } -iinstall_uv() { +install_uv() { cargo install --git https://github.com/astral-sh/uv uv } @@ -179,10 +179,11 @@ install_neovim() { install_uv if [[ "${OS}" == "darwin" ]]; then - if which nvim >/dev/null; then + if which -a nvim | grep -v aliased >/dev/null; then brew upgrade neovim else - brew install neovim + # install development version to support plugins + brew install neovim --HEAD fi else if [ "$(nvim -v | head -n 1)" != "NVIM ${NEOVIM_VERSION}" ]; then @@ -194,7 +195,7 @@ install_neovim() { install_zsh() { # install oh-my-zsh if ! grep -q /opt/homebrew/bin/zsh /etc/shells; then - echo "/opt/homebrew/bin/zsh" >>/etc/shells + echo "/opt/homebrew/bin/zsh" | sudo tee -a /etc/shells >/dev/null fi chsh -s /opt/homebrew/bin/zsh $USER @@ -217,8 +218,8 @@ install_deps() { else brew update fi - brew install "${OSX_DEPS}" - brew upgrade "${OSX_DEPS}" + brew install ${OSX_DEPS} + brew upgrade ${OSX_DEPS} elif [[ "${OS}" == "linux" ]]; then if [ "${ID}" == "ubuntu" ] || [ "${ID}" == "debian" ] || [ "${ID}" == "raspbian" ] || [ "${ID}" == "armbian" ]; then for PKG in ${DEB_DEPS}; do @@ -284,11 +285,9 @@ install_configs() { } install() { + install_deps install_configs - install_fonts - - install_deps } purge_dotfiles() { diff --git a/nvim/lazyvim.json b/nvim/lazyvim.json index 27ec1b8..5f37ffa 100644 --- a/nvim/lazyvim.json +++ b/nvim/lazyvim.json @@ -1,7 +1,5 @@ { "extras": [ - "lazyvim.plugins.extras.ai.copilot-chat", - "lazyvim.plugins.extras.ai.copilot-native", "lazyvim.plugins.extras.coding.mini-surround", "lazyvim.plugins.extras.dap.core", "lazyvim.plugins.extras.editor.aerial", diff --git a/shlibs/lsp-deps.sh b/shlibs/lsp-deps.sh index d5d17f9..79f512e 100755 --- a/shlibs/lsp-deps.sh +++ b/shlibs/lsp-deps.sh @@ -68,7 +68,11 @@ jdtls_bazel() { curl -L -o "$(pwd)/${fname}.zip" "${url}" || TRACE "failed to download jdtls bazel plugins" unzip ${fname}.zip mkdir -p "${install_dir}" - cp "$(pwd)/${fname}/plugins/*.jar" "${install_dir}/" + if [ -d "plugins" ]; then + cp plugins/*.jar "${install_dir}/" + else + cp "${fname}/plugins/*.jar" "${install_dir}/" + fi rmtmp } diff --git a/zsh/env.zsh b/zsh/env.zsh index 34f42c4..aadf229 100644 --- a/zsh/env.zsh +++ b/zsh/env.zsh @@ -11,14 +11,14 @@ check_if_dir_exists() { check_add_langenv() { local envbin=${HOME}/.$1/bin if [ ! -e ${envbin} ];then - return false + return 1 fi if ! command -v $1 >/dev/null; then export PATH="${envbin}:${PATH}" fi - return true + return 0 } check_shims() { @@ -66,23 +66,23 @@ fi # golang if check_add_langenv goenv; then - check_shims goenv || eval "$(goenv init -)" + typeset -f goenv >/dev/null || eval "$(goenv init -)" fi # ruby / rbenv if check_add_langenv rbenv; then - check_shims rbenv || eval "$(rbenv init -)" + typeset -f rbenv >/dev/null || eval "$(rbenv init -)" fi # python / pyenv / pyenv-virtualenv if check_add_langenv pyenv; then - check_shims pyenv || eval "$(pyenv init -)" - check_shims "pyenv/plugins/pyenv-virtualenv" || eval "$(pyenv virtualenv-init -)" + typeset -f pyenv >/dev/null || eval "$(pyenv init -)" + typeset -f _pyenv_virtualenv_hook >/dev/null || eval "$(pyenv virtualenv-init -)" fi # node / nodenv if check_add_langenv nodenv; then - check_shims nodenv || eval "$(nodenv init -)" + typeset -f nodenv >/dev/null || eval "$(nodenv init -)" fi # terraform / tfenv diff --git a/zsh/functions.zsh b/zsh/functions.zsh index c2073c0..57afcc9 100644 --- a/zsh/functions.zsh +++ b/zsh/functions.zsh @@ -34,3 +34,27 @@ tmuxsession () { tmux attach -t ${name} fi } + +tokb() { + echo $(( $1.0 / 1024 )) +} + +tomb() { + echo $(( $1.0 / (1024 * 1024) )) +} + +togb() { + echo $(( $1.0 / (1024 * 1024 * 1024) )) +} + +totb() { + echo $(( $1.0 / (1024 * 1024 * 1024 * 1024) )) +} + +rmkhkey() { + if [[ "$(uname)" == "Darwin" ]]; then + sed -i '' "${1}d" ~/.ssh/known_hosts + else + sed -i "${1}d" ~/.ssh/known_hosts + fi +} diff --git a/zshrc b/zshrc index f34a437..8a1c719 100644 --- a/zshrc +++ b/zshrc @@ -72,8 +72,13 @@ ZSH_CUSTOM=${HOME}/.zsh # Example format: plugins=(rails git textmate ruby lighthouse) # Add wisely, as too many plugins slow down shell startup. plugins=( + gh git vi-mode + pyenv + nodenv + asdf + poetry ) source $ZSH/oh-my-zsh.sh