Compare commits

..

10 Commits

7 changed files with 194 additions and 51 deletions
+4
View File
@@ -11,6 +11,10 @@ synopsis=# SYNOPSIS
description=# DESCRIPTION description=# DESCRIPTION
toc=# TABLE OF CONTENTS toc=# TABLE OF CONTENTS
contents=# TABLE OF CONTENTS contents=# TABLE OF CONTENTS
autopair=# DESCRIPTION
puffer=# DESCRIPTION
puffer-fish=# DESCRIPTION
logging-events=# DESCRIPTION
# ── Section 1: Configuration Variables ─────────────────────── # ── Section 1: Configuration Variables ───────────────────────
variables=# 1. CONFIGURATION VARIABLES variables=# 1. CONFIGURATION VARIABLES
+29 -8
View File
@@ -43,15 +43,18 @@ The configuration is split across:
config.fish Main entry point; sets env vars and PATH config.fish Main entry point; sets env vars and PATH
conf.d/ conf.d/
abbr.fish All abbreviations abbr.fish All abbreviations
cheat.fish cheat.sh completions autopair.fish Auto-pair brackets and quotes (bundled from jorgebucaran/autopair.fish)
cheat.fish cheat.sh tab completions
done.fish Desktop notifications for long commands done.fish Desktop notifications for long commands
first_run.fish One-time init: Fisher bootstrap, theme, welcome first_run.fish One-time init: Fisher bootstrap, theme, welcome
key_bindings.fish Custom key bindings and Vi mode key_bindings.fish Custom key bindings and Vi mode
logging-events.fish C5 --on-variable event handlers; syncs logging state at startup
paru-wrapper.fish Auto-generates ~/.local/bin/paru logging wrapper paru-wrapper.fish Auto-generates ~/.local/bin/paru logging wrapper
puffer.fish !! / !$ / ./ expansion (bundled from nickeb96/puffer-fish)
sponge_privacy.fish Sponge privacy patterns; filters credentials from history
starship.fish fish_prompt with OSC 133 shell-integration markers starship.fish fish_prompt with OSC 133 shell-integration markers
tailscale.fish Tailscale CLI tab completions tailscale.fish Tailscale CLI tab completions
theme.fish Catppuccin syntax highlight colors theme.fish Catppuccin syntax highlight colors
sponge_privacy.fish Sponge privacy patterns; filters credentials from history
tricks.fish PATH, bang-bang helpers, bat man pages, aliases tricks.fish PATH, bang-bang helpers, bat man pages, aliases
wakatime.fish WakaTime shell hook wakatime.fish WakaTime shell hook
yay-wrapper.fish Auto-generates ~/.local/bin/yay logging wrapper yay-wrapper.fish Auto-generates ~/.local/bin/yay logging wrapper
@@ -1105,15 +1108,33 @@ Add -i (interactive confirmation) to destructive commands:
file in the current directory, or opens an interactive fzf picker if no file in the current directory, or opens an interactive fzf picker if no
session file is found. session file is found.
### agents-init
Synopsis: agents-init [--agents | --plugins]
Scaffold an AGENTS/ sub-repository for tracking agent specs and plugin
directories. Creates AGENTS/ as a standalone git repo, initializes
standard plugin subdirectories (superpowers/, plans/, specs/), moves any
existing AGENTS.md and docs/plugin dirs into the sub-repo, and replaces
them with relative symlinks. Also adds CLAUDE.md -> AGENTS/AGENTS.md so
Claude Code picks up the shared agent instructions. Adds all managed
paths to .gitignore and auto-commits every change inside the AGENTS/
sub-repo. Fully idempotent: a second run produces no output and no new
commits. Flags: --agents re-runs only the AGENTS.md / symlink step;
--plugins re-runs only the plugin-directory wiring step. Called
automatically by the claude wrapper on every invocation.
agents-init
agents-init --agents
agents-init --plugins
### claude ### claude
Synopsis: claude [args...] Synopsis: claude [args...]
Wrapper for the claude CLI. Before launching, checks the current Wrapper for the claude CLI. Before launching, delegates to agents-init
directory and the git project root for CLAUDE.md; when it is absent but --agents to ensure AGENTS/ is scaffolded and CLAUDE.md is symlinked to
AGENTS.md is present, creates a relative symlink CLAUDE.md -> AGENTS.md AGENTS/AGENTS.md in the current project, then forwards all arguments
so Claude Code picks up shared agent instructions without duplicating verbatim to the real claude binary. Command shadow (C1): when
the file. All arguments are forwarded verbatim. Command shadow (C1): __fish_config_op_aliases (or the master) is disabled, the call is
when __fish_config_op_aliases (or the master) is disabled, the call is
passed through to the real claude binary unchanged. passed through to the real claude binary unchanged.
claude claude
+1 -1
View File
@@ -37,7 +37,7 @@ function _agents_init_ensure_gitignore
# Prefer git check-ignore (respects wildcards, parent globs, negations). # Prefer git check-ignore (respects wildcards, parent globs, negations).
# --no-index lets it evaluate non-existent paths. # --no-index lets it evaluate non-existent paths.
set -l already_ignored 0 set -l already_ignored 0
if test -d "$root/.git" if git -C "$root" rev-parse --git-dir >/dev/null 2>&1
git -C "$root" check-ignore -q --no-index "$pattern" 2>/dev/null git -C "$root" check-ignore -q --no-index "$pattern" 2>/dev/null
and set already_ignored 1 and set already_ignored 1
else if test -f "$gitignore" else if test -f "$gitignore"
+111 -9
View File
@@ -32,6 +32,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi
set -l c_cmd (set_color --bold white) set -l c_cmd (set_color --bold white)
set -l c_flag (set_color yellow) set -l c_flag (set_color yellow)
set -l c_ok (set_color green) set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_dim (set_color brblack) set -l c_dim (set_color brblack)
set -l c_err (set_color red) set -l c_err (set_color red)
set -l c_reset (set_color normal) set -l c_reset (set_color normal)
@@ -40,7 +41,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi
or return 1 or return 1
if set -q _flag_help if set -q _flag_help
echo "$c_head""Usage:$c_reset $c_cmd""agents-init$c_reset $c_flag""[--agents] [--plugins] [-h]$c_reset" echo "$c_head""Usage:$c_reset $c_cmd""agents-init$c_reset $c_flag""[--agents] [--plugins] [-h | --help]$c_reset"
echo echo
echo " Scaffold an AGENTS/ sub-repository for tracking agent specifications." echo " Scaffold an AGENTS/ sub-repository for tracking agent specifications."
echo echo
@@ -57,7 +58,7 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi
set -l do_plugins 0 set -l do_plugins 0
set -q _flag_agents; and set do_agents 1 set -q _flag_agents; and set do_agents 1
set -q _flag_plugins; and set do_plugins 1 set -q _flag_plugins; and set do_plugins 1
if test $do_agents -eq 0 -a $do_plugins -eq 0 if test $do_agents -eq 0; and test $do_plugins -eq 0
set do_agents 1 set do_agents 1
set do_plugins 1 set do_plugins 1
end end
@@ -70,10 +71,13 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi
set -l plugins_dir "$agents_dir/plugins" set -l plugins_dir "$agents_dir/plugins"
# ─────────────────────── Always: AGENTS/ sub-repo ─────────────────────── # ─────────────────────── Always: AGENTS/ sub-repo ───────────────────────
set -l did_init 0 set -l did_init 0 # set to 1 when git init runs this invocation; selects commit message
if not test -d "$agents_dir" if not test -d "$agents_dir"
mkdir -p "$agents_dir" if not mkdir -p "$agents_dir"
echo "$c_err""Error: could not create AGENTS/$c_reset" >&2
return 1
end
echo "$c_ok→ Created AGENTS/$c_reset" echo "$c_ok→ Created AGENTS/$c_reset"
end end
@@ -90,15 +94,113 @@ function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec fi
# Ensure plugins dirs with .gitkeep # Ensure plugins dirs with .gitkeep
for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs" for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs"
if not test -d "$dir" if not test -d "$dir"
mkdir -p "$dir" if not mkdir -p "$dir"
echo "$c_err""Error: could not create "(string replace "$root/" "" "$dir")"/$c_reset" >&2
return 1
end
echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset" echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset"
end end
test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep" test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep"
end end
# ── Auto-commit (runs at end — defined here as a closure-style block) ───── # ──────────────────────────── --agents mode ──────────────────────────────
# Implemented in Task 5; placeholder comment keeps structure clear. if test $do_agents -eq 1
# Move AGENTS.md from project root into sub-repo if it's a real file
if test -f "$root/AGENTS.md"; and not test -L "$root/AGENTS.md"
if not mv "$root/AGENTS.md" "$agents_dir/AGENTS.md"
echo "$c_err""Error: could not move AGENTS.md → AGENTS/AGENTS.md$c_reset" >&2
return 1
end
echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset"
end
# ── Mode dispatch ───────────────────────────────────────────────────────── # Create empty AGENTS.md in sub-repo if still missing
# --agents and --plugins blocks added in Tasks 3 and 4. if not test -f "$agents_dir/AGENTS.md"
touch "$agents_dir/AGENTS.md"
echo "$c_ok→ Created AGENTS/AGENTS.md$c_reset"
end
# Symlink AGENTS.md → AGENTS/AGENTS.md in project root
if not test -L "$root/AGENTS.md"
if not ln -s AGENTS/AGENTS.md "$root/AGENTS.md"
echo "$c_err""Error: could not create AGENTS.md symlink$c_reset" >&2
return 1
end
echo "$c_ok→ Linked AGENTS.md → AGENTS/AGENTS.md$c_reset"
end
# Symlink CLAUDE.md → AGENTS/AGENTS.md in project root
# If a real CLAUDE.md already exists, warn and skip — don't clobber or orphan content.
if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md"
echo "$c_warn""Warning: CLAUDE.md exists as a real file — skipping symlink. Remove it manually to let agents-init manage it.$c_reset" >&2
else if not test -L "$root/CLAUDE.md"
if not ln -s AGENTS/AGENTS.md "$root/CLAUDE.md"
echo "$c_err""Error: could not create CLAUDE.md symlink$c_reset" >&2
return 1
end
echo "$c_ok→ Linked CLAUDE.md → AGENTS/AGENTS.md$c_reset"
end
# Update .gitignore
for pattern in "AGENTS/" "/AGENTS.md" "/CLAUDE.md"
_agents_init_ensure_gitignore "$root" "$pattern"
end
end
# ─────────────────────────── --plugins mode ──────────────────────────────
if test $do_plugins -eq 1
set -l docs_dir "$root/docs"
if not test -d "$docs_dir"
if not mkdir -p "$docs_dir"
echo "$c_err""Error: could not create docs/$c_reset" >&2
return 1
end
echo "$c_ok→ Created docs/$c_reset"
end
for plug in superpowers plans specs
set -l docs_target "$docs_dir/$plug"
set -l agents_target "$plugins_dir/$plug"
# If a real directory exists in docs/, move its contents to AGENTS/plugins/
if test -d "$docs_target"; and not test -L "$docs_target"
set -l contents (ls -A "$docs_target" 2>/dev/null)
if test (count $contents) -gt 0
if not cp -r "$docs_target/." "$agents_target/"
echo "$c_err""Error: could not copy docs/$plug → AGENTS/plugins/$plug$c_reset" >&2
return 1
end
end
if not rm -rf "$docs_target"
echo "$c_err""Error: could not remove docs/$plug after copy$c_reset" >&2
return 1
end
echo "$c_ok→ Moved docs/$plug → AGENTS/plugins/$plug$c_reset"
end
# Create symlink docs/<plug> → ../AGENTS/plugins/<plug>
if not test -L "$docs_target"
if not ln -s "../AGENTS/plugins/$plug" "$docs_target"
echo "$c_err""Error: could not create docs/$plug symlink$c_reset" >&2
return 1
end
echo "$c_ok→ Linked docs/$plug → AGENTS/plugins/$plug$c_reset"
end
_agents_init_ensure_gitignore "$root" "docs/$plug"
end
end
# ──────────────────────── Auto-commit AGENTS/ ────────────────────────────
git -C "$agents_dir" add -A 2>/dev/null
set -l status_out (git -C "$agents_dir" status --porcelain 2>/dev/null)
if test -n "$status_out"
set -l msg "chore: sync AGENTS repository"
test $did_init -eq 1; and set msg "chore: initialize AGENTS repository"
if git -C "$agents_dir" -c commit.gpgsign=false commit -q -m "$msg" 2>/dev/null
set -l sha (git -C "$agents_dir" rev-parse --short HEAD 2>/dev/null)
echo "$c_ok→ Committed AGENTS/ ($sha) $c_dim$msg$c_reset"
end
end
end end
+5 -33
View File
@@ -5,12 +5,10 @@
# claude [ARGS...] # claude [ARGS...]
# #
# DESCRIPTION # DESCRIPTION
# Wrapper for the claude CLI that ensures CLAUDE.md exists before launch. # Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is
# Both the current directory and the git project root are checked. When # initialized and any agent-made changes are committed before launch.
# CLAUDE.md is absent but AGENTS.md is present in a checked directory, a # Delegates all scaffold and commit logic to agents-init --agents.
# relative symlink CLAUDE.md -> AGENTS.md is created automatically so that # All arguments are forwarded verbatim to the real claude binary.
# Claude Code picks up shared agent instructions without duplicating the
# file. All arguments are forwarded verbatim to the real claude binary.
# #
# Opinionated component (C1): when disabled via __fish_config_op_aliases # Opinionated component (C1): when disabled via __fish_config_op_aliases
# (or the __fish_config_opinionated master), the command is passed through # (or the __fish_config_opinionated master), the command is passed through
@@ -32,33 +30,7 @@ function claude --wraps=claude --description 'claude wrapper: auto-links AGENTS.
return $status return $status
end end
set -l c_ok (set_color green) agents-init --agents
set -l c_reset (set_color normal)
# Build the list of directories to inspect: cwd always, git root when different.
set -l check_dirs (pwd)
set -l git_root (git rev-parse --show-toplevel 2>/dev/null)
if test -n "$git_root" -a "$git_root" != (pwd)
set check_dirs $check_dirs $git_root
end
# Anchor for relative display: git root when available, otherwise cwd.
set -l anchor $git_root
test -z "$anchor" && set anchor (pwd)
for dir in $check_dirs
if not test -e "$dir/CLAUDE.md"
if test -f "$dir/AGENTS.md"
ln -s AGENTS.md "$dir/CLAUDE.md"
set -l prefix ""
if test "$dir" != "$anchor"
set prefix (string replace "$anchor/" "" "$dir")/
end
set -l msg (string join "" "→ Linked " $prefix "CLAUDE.md → " $prefix "AGENTS.md")
echo $c_ok$msg$c_reset >&2
end
end
end
command claude $argv command claude $argv
end end
+22
View File
@@ -3,6 +3,28 @@
# Copyright (C) 2026 Rootiest # Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# Invoked as an Antigravity session hook; reads JSON from stdin.
#
# DESCRIPTION
# Hook script called by the Antigravity CLI (agy) on session start.
# Reads a JSON payload from stdin, extracts the session_id field, and
# writes it to .antigravity_session in the current directory. Ensures
# that file is excluded via .gitignore. Sets the universal variable
# LAST_ANTIGRAVITY_SESSION for cross-terminal access. Falls back to a
# no-op (emitting "{}") when python3 is unavailable (Convention §6).
#
# ARGUMENTS
# stdin JSON payload from the Antigravity CLI containing a "session_id" key
#
# RETURNS
# 0 Always; emits "{}" to stdout as required by the hook contract
#
# EXAMPLE
# echo '{"session_id":"abc123"}' | fish save_antigravity_session.fish
# cat .antigravity_session # → abc123
# echo $LAST_ANTIGRAVITY_SESSION # → abc123
# 1. Read the JSON from stdin # 1. Read the JSON from stdin
set -l input (cat) set -l input (cat)
+22
View File
@@ -3,6 +3,28 @@
# Copyright (C) 2026 Rootiest # Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# Invoked as a Claude Code session hook; reads JSON from stdin.
#
# DESCRIPTION
# Hook script called by Claude Code on session start. Reads a JSON payload
# from stdin, extracts the session_id field, and writes it to .claude_session
# in the current directory. Ensures that file is excluded via .gitignore.
# Sets the universal variable LAST_CLAUDE_SESSION for cross-terminal access.
# Falls back to a no-op (emitting "{}") when python3 is unavailable
# (Convention §6).
#
# ARGUMENTS
# stdin JSON payload from Claude Code containing a "session_id" key
#
# RETURNS
# 0 Always; emits "{}" to stdout as required by the hook contract
#
# EXAMPLE
# echo '{"session_id":"abc123"}' | fish save_claude_session.fish
# cat .claude_session # → abc123
# echo $LAST_CLAUDE_SESSION # → abc123
# 1. Read input and extract session ID # 1. Read input and extract session ID
# python3 parses the session_id out of the hook's JSON payload. If it is # python3 parses the session_id out of the hook's JSON payload. If it is
# unavailable we emit valid empty JSON and skip session tracking rather # unavailable we emit valid empty JSON and skip session tracking rather