Merge pull request 'feat(agents-init): scaffold AGENTS/ sub-repo with symlinks, plugin dirs, and AI wrapper integration' (#52) from feat/agents-init into main
Generate documentation / build-docs (push) Successful in 37s
Generate documentation / build-docs (push) Successful in 37s
Reviewed-on: #52
This commit was merged in pull request #52.
This commit is contained in:
@@ -288,3 +288,8 @@ poetry.toml
|
||||
pyrightconfig.json
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
|
||||
# ──────────────── Added by agents-init ──────────────────
|
||||
# agents-init --agents
|
||||
AGENTS/
|
||||
# ────────────────────────────────────────────────────────
|
||||
|
||||
+2
-2
@@ -72,8 +72,8 @@ abbr -a g git
|
||||
abbr -a gitig gi
|
||||
abbr -a git-ignore gi
|
||||
# Antigravity
|
||||
abbr -a ag antigravity
|
||||
abbr -a ag. antigravity .
|
||||
abbr -a ag agy
|
||||
abbr -a ag. agy .
|
||||
# Quit
|
||||
abbr -a /exit exit
|
||||
# Window-management abbreviations are opinionated (C4 integrations)
|
||||
|
||||
@@ -11,6 +11,10 @@ synopsis=# SYNOPSIS
|
||||
description=# DESCRIPTION
|
||||
toc=# TABLE OF CONTENTS
|
||||
contents=# TABLE OF CONTENTS
|
||||
autopair=# DESCRIPTION
|
||||
puffer=# DESCRIPTION
|
||||
puffer-fish=# DESCRIPTION
|
||||
logging-events=# DESCRIPTION
|
||||
|
||||
# ── Section 1: Configuration Variables ───────────────────────
|
||||
variables=# 1. CONFIGURATION VARIABLES
|
||||
|
||||
+41
-15
@@ -43,15 +43,18 @@ The configuration is split across:
|
||||
config.fish Main entry point; sets env vars and PATH
|
||||
conf.d/
|
||||
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
|
||||
first_run.fish One-time init: Fisher bootstrap, theme, welcome
|
||||
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
|
||||
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
|
||||
tailscale.fish Tailscale CLI tab completions
|
||||
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
|
||||
wakatime.fish WakaTime shell hook
|
||||
yay-wrapper.fish Auto-generates ~/.local/bin/yay logging wrapper
|
||||
@@ -413,8 +416,8 @@ Appending n to any :cd* abbreviation also runs nvim after changing dir.
|
||||
|
||||
## 4.8 AI Assistants
|
||||
|
||||
ag antigravity
|
||||
ag. antigravity .
|
||||
ag agy
|
||||
ag. agy .
|
||||
v antigravity-ide
|
||||
s wezterm ssh (WezTerm only)
|
||||
|
||||
@@ -1085,13 +1088,18 @@ Add -i (interactive confirmation) to destructive commands:
|
||||
|
||||
## 5.12 AI and Developer Tools
|
||||
|
||||
### antigravity
|
||||
### agy
|
||||
|
||||
Synopsis: antigravity [args...]
|
||||
Runs the agy CLI (Antigravity AI assistant) with noisy deprecation
|
||||
warnings filtered from stderr.
|
||||
Synopsis: agy [args...]
|
||||
Wrapper for the agy Antigravity AI CLI. Before launching, delegates to
|
||||
agents-init --agents to ensure AGENTS/ is scaffolded and CLAUDE.md is
|
||||
symlinked to AGENTS/AGENTS.md in the current project, then forwards all
|
||||
arguments verbatim to the real agy binary. Command shadow (C1): when
|
||||
__fish_config_op_aliases (or the master) is disabled, the call is
|
||||
passed through to the real agy binary unchanged.
|
||||
|
||||
antigravity chat
|
||||
agy chat
|
||||
agy resume
|
||||
|
||||
### antigravity-ide
|
||||
|
||||
@@ -1105,15 +1113,33 @@ Add -i (interactive confirmation) to destructive commands:
|
||||
file in the current directory, or opens an interactive fzf picker if no
|
||||
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 and agy wrappers on every invocation.
|
||||
|
||||
agents-init
|
||||
agents-init --agents
|
||||
agents-init --plugins
|
||||
|
||||
### claude
|
||||
|
||||
Synopsis: claude [args...]
|
||||
Wrapper for the claude CLI. Before launching, checks the current
|
||||
directory and the git project root for CLAUDE.md; when it is absent but
|
||||
AGENTS.md is present, creates a relative symlink CLAUDE.md -> AGENTS.md
|
||||
so Claude Code picks up shared agent instructions without duplicating
|
||||
the file. All arguments are forwarded verbatim. Command shadow (C1):
|
||||
when __fish_config_op_aliases (or the master) is disabled, the call is
|
||||
Wrapper for the claude CLI. Before launching, delegates to agents-init
|
||||
--agents to ensure AGENTS/ is scaffolded and CLAUDE.md is symlinked to
|
||||
AGENTS/AGENTS.md in the current project, then forwards all arguments
|
||||
verbatim to the real claude binary. Command shadow (C1): when
|
||||
__fish_config_op_aliases (or the master) is disabled, the call is
|
||||
passed through to the real claude binary unchanged.
|
||||
|
||||
claude
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# _agents_init_ensure_gitignore <root> <label> <pattern>...
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Appends any patterns not already covered by the project's .gitignore.
|
||||
# Uses `git check-ignore` for accurate rule matching (catches wildcards
|
||||
# and parent-dir globs). Falls back to a plain string search when the
|
||||
# root is not a git repository. Leading `/` is stripped from each pattern
|
||||
# before the path-based check so root-anchored patterns (e.g. /AGENTS.md)
|
||||
# are matched correctly.
|
||||
#
|
||||
# Missing patterns are written as a single labeled block:
|
||||
#
|
||||
# # ──────────────── Added by agents-init ──────────────────
|
||||
# # <label>
|
||||
# <pattern>
|
||||
# # ────────────────────────────────────────────────────────
|
||||
#
|
||||
# ARGUMENTS
|
||||
# root Absolute path to the project root containing .gitignore
|
||||
# label Short description used in the block comment header
|
||||
# pattern One or more gitignore patterns to ensure are present
|
||||
#
|
||||
# RETURNS
|
||||
# 0 All patterns already ignored or successfully appended
|
||||
# 1 Could not write to .gitignore
|
||||
#
|
||||
# EXAMPLE
|
||||
# _agents_init_ensure_gitignore /home/user/myproject "agents-init" "AGENTS/" "/AGENTS.md"
|
||||
function _agents_init_ensure_gitignore
|
||||
set -l c_ok (set_color green)
|
||||
set -l c_reset (set_color normal)
|
||||
|
||||
if test (count $argv) -lt 3
|
||||
echo (set_color red)"_agents_init_ensure_gitignore: requires <root> <label> <pattern>..."(set_color normal) >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l root $argv[1]
|
||||
set -l label $argv[2]
|
||||
set -l patterns $argv[3..]
|
||||
set -l gitignore "$root/.gitignore"
|
||||
|
||||
set -l in_git 0
|
||||
git -C "$root" rev-parse --git-dir >/dev/null 2>&1
|
||||
and set in_git 1
|
||||
|
||||
# Collect patterns not already covered
|
||||
set -l missing
|
||||
for pattern in $patterns
|
||||
# Strip leading / so git check-ignore receives a repo-relative path,
|
||||
# not an absolute filesystem path (which it cannot match against rules).
|
||||
set -l check_path (string replace -r '^/' '' "$pattern")
|
||||
set -l already 0
|
||||
if test $in_git -eq 1
|
||||
git -C "$root" check-ignore -q --no-index "$check_path" 2>/dev/null
|
||||
and set already 1
|
||||
else if test -f "$gitignore"
|
||||
grep -qF "$pattern" "$gitignore"
|
||||
and set already 1
|
||||
end
|
||||
if test $already -eq 0
|
||||
set -a missing "$pattern"
|
||||
end
|
||||
end
|
||||
|
||||
test (count $missing) -eq 0; and return 0
|
||||
|
||||
# Write missing patterns as a labeled block
|
||||
set -l header "# ──────────────── Added by agents-init ──────────────────"
|
||||
set -l footer "# ────────────────────────────────────────────────────────"
|
||||
printf '\n%s\n# %s\n' "$header" "$label" >>"$gitignore"
|
||||
for p in $missing
|
||||
printf '%s\n' "$p" >>"$gitignore"
|
||||
end
|
||||
printf '%s\n' "$footer" >>"$gitignore"
|
||||
|
||||
echo "$c_ok→ Added "(count $missing)" pattern(s) to .gitignore$c_reset"
|
||||
end
|
||||
@@ -0,0 +1,337 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# agents-init [-a | --agents] [-p | --plugins] [-v | --verbose]
|
||||
# [-q | --quiet] [-s | --silent] [-h | --help]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Scaffolds an AGENTS/ sub-repository inside a project directory. Creates
|
||||
# a self-contained git repo for agent specifications, moves any existing
|
||||
# agent-related files into it, and replaces them with symlinks so the outer
|
||||
# project never tracks agent files directly.
|
||||
#
|
||||
# File layout after setup:
|
||||
# AGENTS/AGENTS.md canonical agent spec (real file)
|
||||
# AGENTS/CLAUDE.md real file (if CLAUDE.md existed separately)
|
||||
# or symlink → AGENTS.md (single-source case)
|
||||
# <root>/AGENTS.md → AGENTS/AGENTS.md
|
||||
# <root>/CLAUDE.md → AGENTS/CLAUDE.md
|
||||
# docs/<plug> → ../AGENTS/plugins/<plug>
|
||||
#
|
||||
# With no flags, runs both --agents and --plugins setup. At the end of
|
||||
# every invocation, commits any uncommitted changes in the AGENTS/ sub-repo
|
||||
# so that agent-made edits are captured automatically.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# -a, --agents Set up AGENTS/ repo + AGENTS.md / CLAUDE.md symlinks only
|
||||
# -p, --plugins Set up AGENTS/ repo + plugins dirs + docs/ symlinks only
|
||||
# -v, --verbose Print all per-step output (default)
|
||||
# -q, --quiet Print one summary line only if changes were made
|
||||
# -s, --silent Suppress all output; errors only (standard UNIX convention)
|
||||
# -h, --help Show this help message and exit
|
||||
#
|
||||
# RETURNS
|
||||
# 0 Setup completed successfully
|
||||
# 1 Fatal error (git init failed, move failed, etc.)
|
||||
#
|
||||
# EXAMPLE
|
||||
# agents-init
|
||||
# agents-init --agents
|
||||
# agents-init --plugins
|
||||
# agents-init --quiet
|
||||
function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec files and plugin dirs'
|
||||
set -l c_head (set_color --bold cyan)
|
||||
set -l c_cmd (set_color --bold white)
|
||||
set -l c_flag (set_color yellow)
|
||||
set -l c_ok (set_color green)
|
||||
set -l c_warn (set_color yellow)
|
||||
set -l c_dim (set_color brblack)
|
||||
set -l c_err (set_color red)
|
||||
set -l c_reset (set_color normal)
|
||||
|
||||
argparse h/help a/agents p/plugins v/verbose q/quiet s/silent -- $argv
|
||||
or return 1
|
||||
|
||||
if set -q _flag_help
|
||||
echo "$c_head""Usage:$c_reset $c_cmd""agents-init$c_reset $c_flag""[-a] [-p] [-v] [-q] [-s] [-h | --help]$c_reset"
|
||||
echo
|
||||
echo " Scaffold an AGENTS/ sub-repository for tracking agent specifications."
|
||||
echo
|
||||
echo "$c_head""Options:$c_reset"
|
||||
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message"
|
||||
echo " $c_flag-a$c_reset, $c_flag--agents$c_reset Set up AGENTS.md / CLAUDE.md symlinks only"
|
||||
echo " $c_flag-p$c_reset, $c_flag--plugins$c_reset Set up plugins dirs and docs/ symlinks only"
|
||||
echo " $c_flag-v$c_reset, $c_flag--verbose$c_reset Print all per-step output (default)"
|
||||
echo " $c_flag-q$c_reset, $c_flag--quiet$c_reset Print one summary line only if changes were made"
|
||||
echo " $c_flag-s$c_reset, $c_flag--silent$c_reset Suppress all output; only errors are printed"
|
||||
echo " $c_dim(no flags)$c_reset Run both --agents and --plugins setup"
|
||||
return 0
|
||||
end
|
||||
|
||||
# No flags → run both modes
|
||||
set -l do_agents 0
|
||||
set -l do_plugins 0
|
||||
set -q _flag_agents; and set do_agents 1
|
||||
set -q _flag_plugins; and set do_plugins 1
|
||||
if test $do_agents -eq 0; and test $do_plugins -eq 0
|
||||
set do_agents 1
|
||||
set do_plugins 1
|
||||
end
|
||||
|
||||
# Output verbosity: verbose (default), quiet (summary if changed), silent (errors only)
|
||||
set -l verbose 1
|
||||
set -l quiet 0
|
||||
if set -q _flag_silent
|
||||
set verbose 0
|
||||
else if set -q _flag_quiet
|
||||
set verbose 0
|
||||
set quiet 1
|
||||
end
|
||||
# --verbose is explicit default; no-op but accepted for completeness
|
||||
|
||||
# Resolve target root: git root if available, otherwise cwd
|
||||
set -l root (git rev-parse --show-toplevel 2>/dev/null)
|
||||
test -z "$root"; and set root (pwd)
|
||||
|
||||
set -l agents_dir "$root/AGENTS"
|
||||
set -l plugins_dir "$agents_dir/plugins"
|
||||
|
||||
# Track whether any action was taken this run (drives quiet-mode summary)
|
||||
set -l changed 0
|
||||
|
||||
# ─────────────────────── Always: AGENTS/ sub-repo ───────────────────────
|
||||
set -l did_init 0
|
||||
|
||||
if not test -d "$agents_dir"
|
||||
if not mkdir -p "$agents_dir"
|
||||
echo "$c_err""Error: could not create AGENTS/$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Created AGENTS/$c_reset"
|
||||
end
|
||||
|
||||
if not test -d "$agents_dir/.git"
|
||||
git -C "$agents_dir" init -q
|
||||
or begin
|
||||
echo "$c_err""Error: git init failed in AGENTS/$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
set did_init 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Initialized git repo in AGENTS/$c_reset"
|
||||
end
|
||||
|
||||
# ──────────────────────────── --agents mode ──────────────────────────────
|
||||
if test $do_agents -eq 1
|
||||
# Detect which root-level files are real (not symlinks)
|
||||
set -l has_agents 0
|
||||
set -l has_claude 0
|
||||
if test -f "$root/AGENTS.md"; and not test -L "$root/AGENTS.md"
|
||||
set has_agents 1
|
||||
end
|
||||
if test -f "$root/CLAUDE.md"; and not test -L "$root/CLAUDE.md"
|
||||
set has_claude 1
|
||||
end
|
||||
|
||||
# ── Move real files into AGENTS/ ──────────────────────────────────────
|
||||
if test $has_agents -eq 1; and test $has_claude -eq 1
|
||||
# Both exist: preserve each as its own file in AGENTS/
|
||||
if not test -f "$agents_dir/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
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset"
|
||||
end
|
||||
if not test -f "$agents_dir/CLAUDE.md"; and not test -L "$agents_dir/CLAUDE.md"
|
||||
if not mv "$root/CLAUDE.md" "$agents_dir/CLAUDE.md"
|
||||
echo "$c_err""Error: could not move CLAUDE.md → AGENTS/CLAUDE.md$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Moved CLAUDE.md → AGENTS/CLAUDE.md$c_reset"
|
||||
end
|
||||
else if test $has_agents -eq 1
|
||||
if not test -f "$agents_dir/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
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Moved AGENTS.md → AGENTS/AGENTS.md$c_reset"
|
||||
end
|
||||
else if test $has_claude -eq 1
|
||||
# Only CLAUDE.md: treat it as the agent spec
|
||||
if not test -f "$agents_dir/AGENTS.md"
|
||||
if not mv "$root/CLAUDE.md" "$agents_dir/AGENTS.md"
|
||||
echo "$c_err""Error: could not move CLAUDE.md → AGENTS/AGENTS.md$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Moved CLAUDE.md → AGENTS/AGENTS.md$c_reset"
|
||||
end
|
||||
else
|
||||
# Neither exists: create AGENTS/AGENTS.md with the agent directive
|
||||
if not test -f "$agents_dir/AGENTS.md"
|
||||
printf '%s\n' \
|
||||
'# AGENTS.md' \
|
||||
'' \
|
||||
'> ⚠️ **SYSTEM DIRECTIVE FOR AI AGENTS: FILE EDITING**' \
|
||||
'> You may be reading this file via a symlink (`CLAUDE.md` or `AGENTS.md`) in' \
|
||||
'> the root of the project. Your environment'\''s file-editing tools cannot write' \
|
||||
'> through symlinks and will throw an error.' \
|
||||
'>' \
|
||||
'> **DO NOT** attempt to write to or edit `CLAUDE.md` or `AGENTS.md` in the' \
|
||||
'> project root. If you need to update these instructions, you **MUST write' \
|
||||
'> directly to `AGENTS/AGENTS.md`**.' >"$agents_dir/AGENTS.md"
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Created AGENTS/AGENTS.md with agent directive$c_reset"
|
||||
end
|
||||
end
|
||||
|
||||
# ── Ensure AGENTS/CLAUDE.md exists ────────────────────────────────────
|
||||
# When both files existed, AGENTS/CLAUDE.md is already a real file.
|
||||
# Otherwise, create it as a symlink → AGENTS.md (within AGENTS/).
|
||||
if not test -f "$agents_dir/CLAUDE.md"; and not test -L "$agents_dir/CLAUDE.md"
|
||||
if not ln -s AGENTS.md "$agents_dir/CLAUDE.md"
|
||||
echo "$c_err""Error: could not create AGENTS/CLAUDE.md symlink$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Linked AGENTS/CLAUDE.md → AGENTS/AGENTS.md$c_reset"
|
||||
end
|
||||
|
||||
# ── Root symlink: AGENTS.md → AGENTS/AGENTS.md ───────────────────────
|
||||
set -l _need_link 0
|
||||
if not test -L "$root/AGENTS.md"
|
||||
set _need_link 1
|
||||
else if test (readlink "$root/AGENTS.md") != AGENTS/AGENTS.md
|
||||
rm -f "$root/AGENTS.md"
|
||||
set _need_link 1
|
||||
end
|
||||
if test $_need_link -eq 1
|
||||
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
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Linked AGENTS.md → AGENTS/AGENTS.md$c_reset"
|
||||
end
|
||||
|
||||
# ── Root symlink: CLAUDE.md → AGENTS/CLAUDE.md ───────────────────────
|
||||
set -l _need_link 0
|
||||
if not test -L "$root/CLAUDE.md"
|
||||
set _need_link 1
|
||||
else if test (readlink "$root/CLAUDE.md") != AGENTS/CLAUDE.md
|
||||
rm -f "$root/CLAUDE.md"
|
||||
set _need_link 1
|
||||
end
|
||||
if test $_need_link -eq 1
|
||||
if not ln -s AGENTS/CLAUDE.md "$root/CLAUDE.md"
|
||||
echo "$c_err""Error: could not create CLAUDE.md symlink$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Linked CLAUDE.md → AGENTS/CLAUDE.md$c_reset"
|
||||
end
|
||||
|
||||
# ── .gitignore ────────────────────────────────────────────────────────
|
||||
set -l _gi (_agents_init_ensure_gitignore "$root" "agents-init --agents" "AGENTS/" "/AGENTS.md" "/CLAUDE.md")
|
||||
if test -n "$_gi"
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo $_gi
|
||||
end
|
||||
end
|
||||
|
||||
# ─────────────────────────── --plugins mode ──────────────────────────────
|
||||
if test $do_plugins -eq 1
|
||||
# Ensure AGENTS/plugins/ dirs exist with .gitkeep
|
||||
for dir in "$plugins_dir" "$plugins_dir/superpowers" "$plugins_dir/plans" "$plugins_dir/specs"
|
||||
if not test -d "$dir"
|
||||
if not mkdir -p "$dir"
|
||||
echo "$c_err""Error: could not create "(string replace "$root/" "" "$dir")"/$c_reset" >&2
|
||||
return 1
|
||||
end
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Created "(string replace "$root/" "" "$dir")"/$c_reset"
|
||||
end
|
||||
test -f "$dir/.gitkeep"; or touch "$dir/.gitkeep"
|
||||
end
|
||||
|
||||
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
|
||||
set changed 1
|
||||
test $verbose -eq 1; and 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/, migrate 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 command cp -rn "$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
|
||||
set changed 1
|
||||
test $verbose -eq 1; and 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
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo "$c_ok→ Linked docs/$plug → AGENTS/plugins/$plug$c_reset"
|
||||
end
|
||||
end
|
||||
|
||||
set -l _gi (_agents_init_ensure_gitignore "$root" "agents-init --plugins" "docs/superpowers" "docs/plans" "docs/specs")
|
||||
if test -n "$_gi"
|
||||
set changed 1
|
||||
test $verbose -eq 1; and echo $_gi
|
||||
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 changed 1
|
||||
if test $verbose -eq 1
|
||||
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
|
||||
|
||||
# Quiet summary: one line at the end, only if something actually changed
|
||||
if test $quiet -eq 1; and test $changed -eq 1
|
||||
if test $did_init -eq 1
|
||||
echo "$c_ok→ Initialized AGENTS scaffolding$c_reset"
|
||||
else
|
||||
echo "$c_ok→ Synced AGENTS scaffolding$c_reset"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# agy [ARGS...]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Wrapper for the agy Antigravity AI CLI that ensures the AGENTS/
|
||||
# sub-repository is initialized and any agent-made changes are committed
|
||||
# before launch. Delegates all scaffold and commit logic to agents-init
|
||||
# (full setup). All arguments are forwarded verbatim to the real agy binary.
|
||||
#
|
||||
# Opinionated component (C1): when disabled via __fish_config_op_aliases
|
||||
# (or the __fish_config_opinionated master), the command is passed through
|
||||
# to the real agy binary unchanged.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# ARGS Any arguments forwarded verbatim to the underlying agy binary
|
||||
#
|
||||
# RETURNS
|
||||
# Exit status of the underlying agy binary
|
||||
#
|
||||
# EXAMPLE
|
||||
# agy
|
||||
# agy chat
|
||||
# agy resume
|
||||
function agy --wraps=agy --description 'agy wrapper: auto-initializes AGENTS/ sub-repo before launch'
|
||||
if not __fish_config_op_enabled __fish_config_op_aliases
|
||||
command agy $argv
|
||||
return $status
|
||||
end
|
||||
|
||||
agents-init --quiet
|
||||
|
||||
command agy $argv
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
# SYNOPSIS
|
||||
# antigravity [args...]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Wrapper for the agy Antigravity AI CLI that filters a known noisy warning
|
||||
# about an unrecognized 'app' option from stderr.
|
||||
#
|
||||
# ARGUMENTS
|
||||
# args... Arguments passed through to the agy command
|
||||
#
|
||||
# EXAMPLE
|
||||
# antigravity chat
|
||||
function antigravity --wraps='agy' --description 'alias antigravity=agy'
|
||||
# In fish, we pipe stderr using '2>|' to another command
|
||||
command agy $argv 2>| grep -v "'app' is not in the list of known options" >&2
|
||||
end
|
||||
+5
-33
@@ -5,12 +5,10 @@
|
||||
# claude [ARGS...]
|
||||
#
|
||||
# DESCRIPTION
|
||||
# Wrapper for the claude CLI that ensures CLAUDE.md exists before launch.
|
||||
# Both the current directory and the git project root are checked. When
|
||||
# CLAUDE.md is absent but AGENTS.md is present in a checked directory, a
|
||||
# relative symlink CLAUDE.md -> AGENTS.md is created automatically so that
|
||||
# Claude Code picks up shared agent instructions without duplicating the
|
||||
# file. All arguments are forwarded verbatim to the real claude binary.
|
||||
# Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is
|
||||
# initialized and any agent-made changes are committed before launch.
|
||||
# Delegates all scaffold and commit logic to agents-init (full setup).
|
||||
# All arguments are forwarded verbatim to the real claude binary.
|
||||
#
|
||||
# Opinionated component (C1): when disabled via __fish_config_op_aliases
|
||||
# (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
|
||||
end
|
||||
|
||||
set -l c_ok (set_color green)
|
||||
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
|
||||
agents-init --quiet
|
||||
|
||||
command claude $argv
|
||||
end
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# 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
|
||||
set -l input (cat)
|
||||
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
# Copyright (C) 2026 Rootiest
|
||||
# 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
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user