fix(agents-vault): always link the current project's memory
The guard around the symlink step only linked when the live Claude project directory already existed, which is exactly backwards for the clone-onto-a-new-machine restore case: a freshly cloned vault entry would be silently left unlinked and a starting agent would write fresh, history-less memory instead. _agents_repo_ensure_symlink already makes its own parent directories and is idempotent, so nothing depended on the guard; it is removed and the link is now attempted unconditionally. Also stop swallowing a refused or failed link as success: the helper's exit status is now checked, and agents-vault reports its own error and exits 1 instead of silently continuing with no link in place. Smaller fixes from the same review pass: - check the exit status of _agents_repo_install_tools and the core.hooksPath git config write, instead of discarding both - give the vmem mkdir failure a stderr message like every other fatal in the function - guard hostname with type -q and add it to DEPENDENCIES - .version creation now sets changed, so --link (which skips the commit step) reports it in --quiet mode - reword --link's help/doc text: it still scaffolds the vault and links memory, it only skips the final commit - drop the unused c_dim color variable - move the __fish_agent_vault_dir / __fish_agent_vault_autopush documentation below Opinionated Components so its NOTE: callout (now flush-left so it actually renders as a Starlight Aside, per review) doesn't become the first Note aside in the page and steal the existing test's assertions about the original 4-bullet one Adds two tests: pre-seeded vault entry with no live directory at all (the restore path the guard was breaking), and a forced link failure asserting agents-vault now exits 1 instead of 0.
This commit is contained in:
@@ -54,25 +54,6 @@ Example: to increase the scrollback history limit:
|
|||||||
set -gx SCROLLBACK_HISTORY_MAX_FILES 200
|
set -gx SCROLLBACK_HISTORY_MAX_FILES 200
|
||||||
|
|
||||||
|
|
||||||
## Agent Memory Vault
|
|
||||||
|
|
||||||
__fish_agent_vault_dir
|
|
||||||
|
|
||||||
Overrides the agent memory vault location. Defaults to
|
|
||||||
$XDG_DATA_HOME/agent-vault (or ~/.local/share/agent-vault).
|
|
||||||
|
|
||||||
__fish_agent_vault_autopush
|
|
||||||
|
|
||||||
When set to 1, agents-vault also pushes on wrapper launch. Defaults to
|
|
||||||
off: the vault commits locally on every launch and pushes from the
|
|
||||||
Claude Code SessionEnd hook or an explicit agents-vault --push.
|
|
||||||
|
|
||||||
NOTE:
|
|
||||||
With autopush off and no SessionEnd hook installed, backups accumulate
|
|
||||||
locally and never reach the remote. Run agents-vault --status to check
|
|
||||||
how far ahead the vault is.
|
|
||||||
|
|
||||||
|
|
||||||
## Fish Universal Variables
|
## Fish Universal Variables
|
||||||
|
|
||||||
Some settings (fzf colors, theme) are stored in fish_variables via
|
Some settings (fzf colors, theme) are stored in fish_variables via
|
||||||
@@ -178,6 +159,25 @@ interactively. See [Components Reference](/08-components-reference/) for the
|
|||||||
full sub-category breakdown of every category.
|
full sub-category breakdown of every category.
|
||||||
|
|
||||||
|
|
||||||
|
## Agent Memory Vault
|
||||||
|
|
||||||
|
__fish_agent_vault_dir
|
||||||
|
|
||||||
|
Overrides the agent memory vault location. Defaults to
|
||||||
|
$XDG_DATA_HOME/agent-vault (or ~/.local/share/agent-vault).
|
||||||
|
|
||||||
|
__fish_agent_vault_autopush
|
||||||
|
|
||||||
|
When set to 1, agents-vault also pushes on wrapper launch. Defaults to
|
||||||
|
off: the vault commits locally on every launch and pushes from the
|
||||||
|
Claude Code SessionEnd hook or an explicit agents-vault --push.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
With autopush off and no SessionEnd hook installed, backups accumulate
|
||||||
|
locally and never reach the remote. Run agents-vault --status to check
|
||||||
|
how far ahead the vault is.
|
||||||
|
|
||||||
|
|
||||||
## Prompt and Theme
|
## Prompt and Theme
|
||||||
|
|
||||||
### Starship
|
### Starship
|
||||||
|
|||||||
+42
-13
@@ -6,7 +6,7 @@
|
|||||||
#
|
#
|
||||||
# DEPENDENCIES
|
# DEPENDENCIES
|
||||||
# _agents_vault_dir, _agents_repo_slug, _agents_repo_ensure_symlink,
|
# _agents_vault_dir, _agents_repo_slug, _agents_repo_ensure_symlink,
|
||||||
# _agents_repo_sync, _agents_repo_install_tools, git
|
# _agents_repo_sync, _agents_repo_install_tools, git, hostname
|
||||||
#
|
#
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
# agents-vault [--link] [--push] [--restore] [--status]
|
# agents-vault [--link] [--push] [--restore] [--status]
|
||||||
@@ -36,7 +36,8 @@
|
|||||||
# never denylisted, so nothing new upstream adds can leak in.
|
# never denylisted, so nothing new upstream adds can leak in.
|
||||||
#
|
#
|
||||||
# ARGUMENTS
|
# ARGUMENTS
|
||||||
# --link Ensure this project's memory link only; do not commit
|
# --link Scaffold the vault and link this project's memory; skip
|
||||||
|
# the final commit
|
||||||
# --push Commit and push to the vault remote
|
# --push Commit and push to the vault remote
|
||||||
# --restore Walk the vault, relink what is possible, report the rest
|
# --restore Walk the vault, relink what is possible, report the rest
|
||||||
# --status Show entries, link health, remote state, and orphans
|
# --status Show entries, link health, remote state, and orphans
|
||||||
@@ -68,7 +69,6 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
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_warn (set_color yellow)
|
||||||
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)
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
echo
|
echo
|
||||||
echo "$c_head""Options:$c_reset"
|
echo "$c_head""Options:$c_reset"
|
||||||
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message"
|
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message"
|
||||||
echo " $c_flag--link$c_reset Ensure this project's memory link only"
|
echo " $c_flag--link$c_reset Scaffold + link this project; skip the commit"
|
||||||
echo " $c_flag--push$c_reset Commit and push to the vault remote"
|
echo " $c_flag--push$c_reset Commit and push to the vault remote"
|
||||||
echo " $c_flag--restore$c_reset Relink everything possible, report the rest"
|
echo " $c_flag--restore$c_reset Relink everything possible, report the rest"
|
||||||
echo " $c_flag--status$c_reset Show entries, link health, remote, orphans"
|
echo " $c_flag--status$c_reset Show entries, link health, remote, orphans"
|
||||||
@@ -133,7 +133,10 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
test $verbose -eq 1; and echo "$c_ok→ Initialized vault repo at $vault$c_reset"
|
test $verbose -eq 1; and echo "$c_ok→ Initialized vault repo at $vault$c_reset"
|
||||||
end
|
end
|
||||||
|
|
||||||
test -f "$vault/.version"; or echo 1.0.0 >"$vault/.version"
|
if not test -f "$vault/.version"
|
||||||
|
echo 1.0.0 >"$vault/.version"
|
||||||
|
set changed 1
|
||||||
|
end
|
||||||
|
|
||||||
if not test -f "$vault/.gitignore"
|
if not test -f "$vault/.gitignore"
|
||||||
printf '%s\n' \
|
printf '%s\n' \
|
||||||
@@ -165,6 +168,10 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
end
|
end
|
||||||
|
|
||||||
set -l tools_msg (_agents_repo_install_tools "$vault")
|
set -l tools_msg (_agents_repo_install_tools "$vault")
|
||||||
|
or begin
|
||||||
|
echo "$c_err""agents-vault: could not install .agents-tools/ into $vault$c_reset" >&2
|
||||||
|
return 1
|
||||||
|
end
|
||||||
if test -n "$tools_msg"
|
if test -n "$tools_msg"
|
||||||
set changed 1
|
set changed 1
|
||||||
test $verbose -eq 1; and echo "$c_ok$tools_msg$c_reset"
|
test $verbose -eq 1; and echo "$c_ok$tools_msg$c_reset"
|
||||||
@@ -173,6 +180,10 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
set -l hp (git -C "$vault" config --local core.hooksPath 2>/dev/null)
|
set -l hp (git -C "$vault" config --local core.hooksPath 2>/dev/null)
|
||||||
if test "$hp" != .agents-tools/hooks
|
if test "$hp" != .agents-tools/hooks
|
||||||
git -C "$vault" config --local core.hooksPath .agents-tools/hooks
|
git -C "$vault" config --local core.hooksPath .agents-tools/hooks
|
||||||
|
or begin
|
||||||
|
echo "$c_err""agents-vault: could not set core.hooksPath in $vault$c_reset" >&2
|
||||||
|
return 1
|
||||||
|
end
|
||||||
set changed 1
|
set changed 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -192,7 +203,10 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
set -l vmem "$entry/claude/memory"
|
set -l vmem "$entry/claude/memory"
|
||||||
|
|
||||||
if not test -d "$vmem"
|
if not test -d "$vmem"
|
||||||
mkdir -p "$vmem"; or return 1
|
if not mkdir -p "$vmem"
|
||||||
|
echo "$c_err""agents-vault: could not create $vmem$c_reset" >&2
|
||||||
|
return 1
|
||||||
|
end
|
||||||
set changed 1
|
set changed 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -201,19 +215,34 @@ function agents-vault --description 'track curated agent memory in a host-scoped
|
|||||||
set -l mangled (string replace -a '/' '-' -- "$root" | string replace -a '.' '-')
|
set -l mangled (string replace -a '/' '-' -- "$root" | string replace -a '.' '-')
|
||||||
set -l live "$claude_root/$mangled/memory"
|
set -l live "$claude_root/$mangled/memory"
|
||||||
|
|
||||||
if test -d "$claude_root/$mangled"; or test -d "$live"
|
# Unconditional: this is the emergent-restore path. On a freshly
|
||||||
set -l link_msg (_agents_repo_ensure_symlink "$live" "$vmem")
|
# cloned vault, $vmem already exists (populated from the clone) and
|
||||||
if test -n "$link_msg"
|
# $live does not exist yet -- skipping the link here would silently
|
||||||
set changed 1
|
# leave the clone's memory unlinked and let a starting agent write
|
||||||
test $verbose -eq 1; and echo "$c_ok$link_msg$c_reset"
|
# fresh, history-less memory instead. _agents_repo_ensure_symlink is
|
||||||
end
|
# idempotent and makes its own parent directories, so there is
|
||||||
|
# nothing this guard would protect that the helper does not already
|
||||||
|
# handle on its own.
|
||||||
|
set -l link_msg (_agents_repo_ensure_symlink "$live" "$vmem")
|
||||||
|
set -l link_rc $status
|
||||||
|
if test $link_rc -ne 0
|
||||||
|
echo "$c_err""agents-vault: could not link $live$c_reset" >&2
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
if test -n "$link_msg"
|
||||||
|
set changed 1
|
||||||
|
test $verbose -eq 1; and echo "$c_ok$link_msg$c_reset"
|
||||||
end
|
end
|
||||||
|
|
||||||
if not test -f "$entry/origin"
|
if not test -f "$entry/origin"
|
||||||
set -l url (git -C "$root" remote get-url origin 2>/dev/null)
|
set -l url (git -C "$root" remote get-url origin 2>/dev/null)
|
||||||
test -n "$url"; or set url "(none)"
|
test -n "$url"; or set url "(none)"
|
||||||
|
set -l host ""
|
||||||
|
if type -q hostname
|
||||||
|
set host (hostname 2>/dev/null)
|
||||||
|
end
|
||||||
printf 'remote: %s\npath: %s\nhost: %s\n' \
|
printf 'remote: %s\npath: %s\nhost: %s\n' \
|
||||||
"$url" "$root" (hostname 2>/dev/null) >"$entry/origin"
|
"$url" "$root" "$host" >"$entry/origin"
|
||||||
set changed 1
|
set changed 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -243,6 +243,73 @@ check "second run adds no commit" $before (git -C $vroot/agent-vault rev-list --
|
|||||||
set -e __fish_agent_vault_dir
|
set -e __fish_agent_vault_dir
|
||||||
set -e __fish_agent_vault_claude_root
|
set -e __fish_agent_vault_claude_root
|
||||||
|
|
||||||
|
# ─────────────────── emergent restore (vault -> live) ──────────────────
|
||||||
|
# The reverse of the adoption case above: a vault entry already has curated
|
||||||
|
# memory (as if cloned from a remote onto a fresh machine) but the live
|
||||||
|
# Claude project directory does not exist at all yet. agents-vault must
|
||||||
|
# still create the link so the pre-existing memory is what a starting
|
||||||
|
# agent sees, rather than silently skipping the link because there was
|
||||||
|
# nothing local to notice yet.
|
||||||
|
echo ""
|
||||||
|
echo "== agents-vault (emergent restore) =="
|
||||||
|
|
||||||
|
set -l vroot2 (mktemp -d); set -ga TMPDIRS $vroot2
|
||||||
|
set -l croot2 (mktemp -d); set -ga TMPDIRS $croot2
|
||||||
|
set -g __fish_agent_vault_dir $vroot2/agent-vault
|
||||||
|
set -g __fish_agent_vault_claude_root $croot2
|
||||||
|
|
||||||
|
set -l proj2 (new_repo https://git.rootiest.dev/rootiest/agent-vault.git)
|
||||||
|
set -l pslug2 git.rootiest.dev-rootiest-agent-vault
|
||||||
|
set -l mangled2 (string replace -a '/' '-' -- $proj2 | string replace -a '.' '-')
|
||||||
|
|
||||||
|
# Pre-seed the vault entry the way a cloned vault would already have it.
|
||||||
|
# Deliberately no $croot2/$mangled2 directory at all -- not even the
|
||||||
|
# project's own entry, let alone a memory/ subdirectory -- so the fix under
|
||||||
|
# test is exercised: linking must not depend on the live side existing.
|
||||||
|
mkdir -p $vroot2/agent-vault/projects/$pslug2/claude/memory
|
||||||
|
echo "restored memory" >$vroot2/agent-vault/projects/$pslug2/claude/memory/old.md
|
||||||
|
|
||||||
|
pushd $proj2 >/dev/null
|
||||||
|
agents-vault --silent
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
check "restore: live memory link created with no prior live dir" true (test -L $croot2/$mangled2/memory; and echo true; or echo false)
|
||||||
|
check "restore: pre-existing vault content readable through the link" "restored memory" (cat $croot2/$mangled2/memory/old.md 2>/dev/null)
|
||||||
|
|
||||||
|
set -e __fish_agent_vault_dir
|
||||||
|
set -e __fish_agent_vault_claude_root
|
||||||
|
|
||||||
|
# ─────────────────── a refused link is reported as failure ─────────────
|
||||||
|
# _agents_repo_ensure_symlink refuses (exit 1, no stdout) when it cannot
|
||||||
|
# make the link -- e.g. its mkdir -p of the link's parent directory fails.
|
||||||
|
# agents-vault must surface that as its own exit 1, not swallow it and
|
||||||
|
# report success because stdout happened to be empty either way.
|
||||||
|
echo ""
|
||||||
|
echo "== agents-vault (link failure surfaces as exit 1) =="
|
||||||
|
|
||||||
|
set -l vroot3 (mktemp -d); set -ga TMPDIRS $vroot3
|
||||||
|
set -l croot3 (mktemp -d); set -ga TMPDIRS $croot3
|
||||||
|
set -g __fish_agent_vault_dir $vroot3/agent-vault
|
||||||
|
set -g __fish_agent_vault_claude_root $croot3
|
||||||
|
|
||||||
|
set -l proj3 (new_repo https://git.rootiest.dev/rootiest/link-fail-test.git)
|
||||||
|
set -l mangled3 (string replace -a '/' '-' -- $proj3 | string replace -a '.' '-')
|
||||||
|
|
||||||
|
# Make the mangled project path a plain FILE. _agents_repo_ensure_symlink's
|
||||||
|
# own `mkdir -p (path dirname $link)` then fails outright (ENOTDIR), which
|
||||||
|
# is exactly the class of failure (permissions, ENOSPC, ...) this guards.
|
||||||
|
touch $croot3/$mangled3
|
||||||
|
|
||||||
|
pushd $proj3 >/dev/null
|
||||||
|
set -l rc (agents-vault --silent 2>/dev/null; echo $status)
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
check "link failure: agents-vault exits 1" 1 "$rc"
|
||||||
|
check "link failure: no link was left behind" false (test -L $croot3/$mangled3/memory; and echo true; or echo false)
|
||||||
|
|
||||||
|
set -e __fish_agent_vault_dir
|
||||||
|
set -e __fish_agent_vault_claude_root
|
||||||
|
|
||||||
cleanup
|
cleanup
|
||||||
echo ""
|
echo ""
|
||||||
echo (math $TESTS_RUN - $TESTS_FAILED)"/$TESTS_RUN passed"
|
echo (math $TESTS_RUN - $TESTS_FAILED)"/$TESTS_RUN passed"
|
||||||
|
|||||||
Reference in New Issue
Block a user