Commit Graph
30 Commits
Author SHA1 Message Date
rootiest af7502d6b1 fix(ci): silence CI/tool noise found auditing the test-job log
An audit of a full green run's test + build-docs logs (agy scan, spot-
checked) turned up stray output beyond the mkrep git-init hint already
fixed. Two real bugs, plus CI-config cosmetics:

- agents-vault.fish/agents-init.fish: `set -l x (some_fish_function ...)`
  command substitutions do not inherit a caller-scoped stderr redirect in
  fish (proven with a two-line repro: `outer 2>/dev/null` where outer
  does `set -l x (inner)` still leaks inner's stderr to the real
  terminal). This let _agents_repo_ensure_symlink's and
  _agents_repo_sync's raw internal error messages leak past `--silent`
  for real users too, always duplicating the clean summary message each
  caller already echoes on failure. Fixed at all 4 call sites by adding
  an explicit `2>/dev/null` directly on each command substitution, since
  a redirect on the outer call cannot reach it.
- ci.yml: apt-get install missing `apt-utils`, so debconf printed
  "delaying package configuration" on every install in both jobs --
  installing it first fixes the chicken-and-egg.
- ci.yml: added `NODE_OPTIONS: --no-deprecation` at the build-docs job
  level to silence Node's internal punycode-module deprecation notice
  (astro's toolchain still pulls it in transitively).
- ci.yml: `npm ci --no-fund` drops the funding nag.
- ci.yml: `gpg --batch --quiet --import` drops gpg's normal-case import
  status lines during the bot commit-signing setup.

Deliberately NOT silenced: npm's deprecated-glob warning, its audit
vulnerability summary, and its allow-scripts notice about esbuild's
postinstall -- these are genuine dependency-hygiene signal, not noise,
and no workflow-level flag exists to hide them without also hiding real
future findings. Also not fixable here: a Gitea Actions/act runner
warning ('runs-on' key not defined in CI/test) that traces to neither
workflow YAML in this repo -- both already set runs-on on every job,
confirmed twice; it's runner-internal, like actions/checkout's own
git-init hint in its Checkout-step preamble.

Verified: full suite 730/730 passing ($status 0); the exact mkdir-
collision repro that surfaced the command-substitution bug re-run
clean (rc=1, empty stderr); test-agents-vault.fish standalone,
320/320, zero occurrences of the previously-leaked messages.
2026-09-22 02:37:42 -04:00
rootiest 86aecf0d9d fix(functions): use cp --update=none instead of non-portable -n
GNU cp warns that -n's behavior is non-portable and may change; the
long form is stable and silences the CI warning.
2026-09-21 22:33:44 -04:00
rootiest 3414f81cb6 feat(tests): add shadow-classification lint; fix real cp/mv/less bugs
New Phase 1b in tests/run-tests.fish: catches a bare C1-shadowed-command
call in a functions/*.fish body with no matching uses-shadow(name) or
self-limiting(name) in that function's own CLASSIFICATION header. This
is exactly the check discussed after the rm and cd audits -- runtime
auto-unwrapping isn't viable in fish (there's no hook finer than
shadowing itself, and rewriting behavior invisibly at runtime is its
own footgun); a static lint using the CLASSIFICATION tag as the
declared-intentional marker is. Scoped to functions/*.fish only: the
one-function-per-file convention there makes body extraction exact
with no block-depth parser needed.

Added a new self-limiting(name) tag to the schema for the case a bare
call is safe not because the caller did anything, but because the
shadow's own logic already neutralizes the override: rm's and mkdir's
flag checks (verified precisely -- rm falls back to command rm for any
flag except a bare -r/-R/--recursive alone, which still routes to
trash; mkdir falls back to command mkdir -p for any flag, no
exception), and grep/fgrep/egrep/dir/vdir/cat's own tty auto-detection
(--color=auto, and bat's default color behavior -- verified
byte-identical to stock cat when piped, since bat also auto-disables
highlighting on a non-terminal). Explicit and durable rather than a
silent lint exemption: if a shadow's bypass condition is ever
weakened, every self-limiting site is one grep away instead of
silently wrong.

Running the first draft of the lint surfaced three more real bugs,
none previously audited:

- config-help.fish's --man pager path checks `type -q less` (proving
  it wants the real less binary specifically, for less-only -R/+N
  flag syntax) then called it bare, routing through our own
  $PAGER -> ov -> less -> more -> cat fallback chain instead -- which
  could hand those less-specific flags to a completely different
  program. Now command less.
- _fish_deps_install.fish and _fish_deps_update.fish's binary-upgrade
  paths cp a freshly downloaded binary over an already-installed one
  with no existence guard -- the update flow's target is guaranteed to
  already exist. Our cp shadow forces -i unconditionally (a plain
  alias, not flag-aware like rm's), so this would hang waiting on a
  confirmation prompt in any non-interactive run. Now command cp.
  Same two files' lazydocker install path piped curl output into bare
  bash, invoking our shell-switch wrapper instead of a plain
  subshell. Now command bash.
- agents-init.fish's AGENTS.md/CLAUDE.md relocation calls mv bare in
  four places; each is already guarded by a preceding test -f check on
  the destination, so the -i alias was unlikely to ever fire in
  practice, but explicit command mv removes the reliance on that guard
  entirely rather than leaving it as the only thing standing between a
  file move and an unattended hang.

The remaining ~65 flagged call sites across ~24 files were reviewed
individually and tagged self-limiting(rm)/self-limiting(mkdir)
(verified flagged with -f/-rf or -p) and self-limiting(grep)/
self-limiting(cat) (verified piped, captured, or -q/-c; none display
color to a human), plus uses-shadow(ls) for two existence-check-only
calls (cffetch.fish, ffetch.fish) whose output is redirected to
/dev/null.
2026-09-21 21:26:55 -04:00
rootiest 63288d9fd6 fix(agents-init): only scaffold inside a git repository
Resolving the root to (pwd) meant running an agent CLI anywhere created an
AGENTS/ git repo, an AGENTS.md, two root symlinks, and a docs/ tree in that
directory. Scaffolding now requires a git repo or a pre-existing agent file
(AGENTS.md, CLAUDE.md, or AGENTS/); elsewhere it is a no-op.
2026-09-16 19:06:43 -04:00
rootiest e64e964666 refactor: use __fish_palette in agents and auto-pull functions
34 duplicated declarations replaced by 5 calls. Output strings untouched;
byte-identical across 29 harness cases.
2026-09-07 20:02:15 -04:00
rootiest 16ea31289d fix(agents-vault): repair slug migration, keep the network off the launch path
Six findings from the whole-branch review, all of which end in the same
place: a backup tool reporting success while nothing was backed up.

Slug migration nested the old entry inside the new one. The clear before
the rename was gated on the destination's claude/memory subdirectory
rather than on the destination itself, so an entry that exists without
one survived, `git mv A B` moved A *inside* B, and the mkdir below
fabricated a fresh empty memory directory for the live link to point at.
The real memory ended up one level deeper than --status and --restore
ever look, and the run returned 0. That shape is not exotic: git cannot
track an empty directory, so an entry committed while its memory was
empty comes back from a clone as projects/<slug>/origin and nothing
else -- and cloning the vault is this feature's own recovery path. The
destination is now moved aside the way --adopt already does it rather
than deleted (widening the rm -rf would have destroyed the clone's
origin log), its provenance is folded into the migrated entry, and every
failure path rolls back and reports.

The launch path pulled over the network. Both wrappers call agents-vault
synchronously before starting an agent, and the pull in the shared sync
helper was unguarded once an upstream existed: against a blackholed
remote it blocked the launch indefinitely and then aborted the commit,
so an offline laptop silently stopped being backed up at all. Committing
never needed a remote, so the pull moved to the push path, which was
already opt-in for exactly this reason. A failure there now distinguishes
a real rebase conflict (rebase-merge/ or rebase-apply/ present) from an
unreachable remote instead of calling both a conflict, and both network
calls set GIT_TERMINAL_PROMPT=0 and GIT_ASKPASS so they fail fast rather
than prompt with nobody watching. The helper still refuses to commit a
rebase in progress, and leaves it standing rather than aborting one it
did not start. This also restores agents-init's pre-refactor ability to
commit while offline.

The agy knowledge copy was unfiltered. The allowlist held at the agy root
and nowhere below it, so a planted .credentials.json inside knowledge/
was committed verbatim while the documentation promised nothing new
upstream added could leak in. Only *.md and *.json are copied now --
which is what the store actually holds -- so lock files, transcripts and
conversation databases are excluded by having no business in a backup
rather than by being known about. The scaffolded .gitignore also ignored
only the SQLite sidecars and not the databases, which is worse than
ignoring neither: a torn database landed in history with the write-ahead
log that would have completed it deliberately excluded. Both changes are
template-only, on a feature that has never shipped.

agents-init reported success when nothing was committed. It ended on a
branchless `if` with no arm for a failed commit, which fish resolves to
0 -- the same false zero already fixed in agents-vault, left in the
function the refactor was rewriting. It now has the arm and an explicit
final status.

The --adopt forward-failure path with no stash left a raw coreutils `mv:`
line and no statement that the adopt had been abandoned cleanly; it is
branded like every other error exit in the function.

Tests: the suite now clones a vault with git and runs agents-vault
against the clone, instead of trusting hand-built fixtures to have shapes
git can actually produce -- that blind spot shipped both of the merge
blockers. The "present but empty" migration fixture is rebuilt as the
origin-only directory a clone leaves behind, with the hand-built shape
kept as a separate case. Reverting each fix drops the suite from 285 to
279 (migration), 261 (network), 275 (knowledge allowlist) and 283
(agents-init status).
2026-09-03 18:56:46 -04:00
rootiest b0585d00ad refactor(agents-init): use the shared repo helpers
Renames _agents_init_install_tools to _agents_repo_install_tools now that
the vault shares it, collapses the two duplicated root-symlink blocks into
one loop, and routes the auto-commit through _agents_repo_sync so a failed
rebase can no longer be committed as conflict markers.
2026-09-03 18:56:45 -04:00
rootiest 500dd8a735 feat(help): standardize colored --help output across functions
Add the established c_head/c_cmd/c_flag/c_dim/c_arg color scheme to
--help (or usage-on-error) output in play-media and 13 other functions
that lacked it or used an ad hoc scheme: bkg, detach, replay, p, y,
spark, wake-lock, open-url, repo-open, dng2avif, dockup, fish-deps
(__fish_deps_help), and scrub.

Also tweak the standard itself:
- c_cmd now uses plain `set_color --bold` instead of `--bold white`,
  so the command name adapts to the terminal's foreground instead of
  forcing white text that washes out on light-background themes.
  Applied across all functions already using the pattern.
- jobrunner's reset variable renamed from c_rst to c_reset to match
  the naming used everywhere else.
2026-08-22 00:19:43 -04:00
rootiest e651566e14 docs(functions): split RETURNS into EXIT STATUS and stdout RETURNS
RETURNS previously conflated fish's $status exit code with genuine
stdout/printed output, e.g. rm listing "0/1" as if they were print
values rather than exit codes. Rename RETURNS to EXIT STATUS across
all 83 documented functions, and reintroduce RETURNS as a distinct
label reserved for the 15 functions that actually print to stdout.

Update build-manual.py's ENTRY_HEADS to render Exit Status before
Returns, manualtools.py's SECTIONS constant, and AGENTS.md's label
order and label-usage guidance to match. Add two verify-manual.py
regression tests: EXIT STATUS bodies must never contain stray
stdout/printed language, and Returns: must always render after
Exit Status: when both are present. Regenerate docs/fish-config.md.
2026-07-26 16:41:57 -04:00
rootiest 00f70e8558 docs(functions): merge remaining manual-only facts into headers
Word-level diff of every manual entry against its generated counterpart
surfaced 546 tokens present in the manual and absent from the header —
losses reconcile.py missed, because it compared description length and
these headers are longer overall thanks to ARGUMENTS/RETURNS.

Merged the substantive ones (546 -> 202 residual tokens, the remainder
being synonym drift). Notable real fixes:

- git-clean: -f/--force was missing from ARGUMENTS entirely
- pkg: per-package-manager query table
- qc: cli-role rationale, role paths, --role passthrough
- config-help: site URL, xdg-open, man page path, case-insensitivity
- agents-init: idempotency, .gitignore paths, upstream pull, wrapper callers
- smart_exit: exit-builtin wiring note, $SCROLLBACK_HISTORY_DIR

The manual's claim that claude/agy pass `agents-init --agents` is stale;
both pass `--quiet` (full setup). Header wins, manual dropped.
2026-07-26 04:02:57 -04:00
rootiest 4c51ef7a33 docs(functions): add # CATEGORY to documented function headers
Records each documented function's manual category in its own header, so
Section 5 can later be generated from source instead of hand-maintained
alongside it. Values reproduce the current grouping in
docs/manual/05-functions/ exactly; no documentation changes meaning here.

Four functions are skipped because they have no header at all yet
(branch, fc, gitup, sudo-toggle); they get one in the merge that follows.
2026-07-26 03:44:03 -04:00
rootiest c3e39b7a96 fix(agents): chain AGENTS git hooks to global core.hooksPath
The local core.hooksPath override set by agents-init shadowed the user's
global hooks (ggshield, Git LFS) since git honors only one hooksPath. Each
shim now execs the global/system hook of the same name after running
version-bump, so global hooks still run after version increment. Bumped the
agents-tools version marker to 2 so existing AGENTS repos refresh.
2026-06-17 22:39:18 -04:00
rootiest 70f1ec2eeb docs: document AGENTS/ structure versioning and current layout 2026-06-17 21:42:36 -04:00
rootiest 46dd6cd3a9 feat(agents-init): scaffold .version + commit-time version hooks, pull before commit 2026-06-17 21:40:40 -04:00
rootiest 5cbb01497c fix(agents-tools): harden version-bump test (CDPATH + hooks isolation), drop LFS band-aid 2026-06-17 21:29:05 -04:00
rootiest a5966fd982 chore(agents-init): fix formatting and alignment 2026-06-13 00:24:18 -04:00
rootiest 976f46757c fix(agents-init): quiet only on change, add -v/--verbose flag
- quiet mode now outputs one summary line only when something actually changed;
  idempotent re-runs produce no output
- add -v/--verbose flag as an explicit alias for the default verbose behavior
- gitignore helper output captured to detect changes without printing in quiet mode
- drop eager "Initializing…" header in favour of end-of-run conditional summary
2026-06-13 00:19:11 -04:00
rootiest 2a7cb0f5cb feat(agents-init): add -a/--agents and -p/--plugins short flags 2026-06-13 00:05:31 -04:00
rootiest 8f845f7cf2 feat(agents-init): add --quiet and --silent flags; wrappers use --quiet 2026-06-13 00:03:11 -04:00
rootiest 69384f6427 fix(agents-init): use command cp -rn to bypass interactive wrapper and skip existing files 2026-06-12 23:51:30 -04:00
rootiest 9f9248deb1 fix(agents-init): fix gitignore duplicate entries, add block comment style
- Strip leading / from pattern before git check-ignore so root-anchored
  patterns like /AGENTS.md are checked as repo-relative paths (AGENTS.md)
  and correctly match existing rules — fixes duplicates on every run
- Rework helper to accept multiple patterns and write them as a single
  labeled block with project-style header/footer comment rather than
  appending bare patterns one at a time
- Move gitignore calls out of per-plug loop in --plugins mode so all
  three docs/ patterns are checked and written in one block
- Remove 5 duplicate bare entries left in .gitignore by the broken runs
2026-06-12 23:30:12 -04:00
rootiest 3a054021cf fix(agents-init): migrate plugin dirs, smarter CLAUDE.md handling, wrappers run full init
- Move plugin dir creation into --plugins mode (not 'Always') so --agents
  alone no longer creates empty AGENTS/plugins/ dirs
- Wrappers (claude, agy) now call plain agents-init (both modes) so plugin
  dirs in docs/ are migrated on the first AI launch, not just --agents
- Rewrite --agents CLAUDE.md logic: detect which root files are real vs
  symlinks and handle all four cases (both/agents-only/claude-only/neither)
  without ever losing content
- AGENTS/CLAUDE.md is now its own file in AGENTS/ (real file when both
  existed, symlink → AGENTS.md for single-source cases)
- Root CLAUDE.md now points to AGENTS/CLAUDE.md instead of AGENTS/AGENTS.md;
  readlink checks auto-fix existing symlinks with the wrong target
- New empty setups get AGENTS/AGENTS.md pre-populated with the agent
  directive warning editors not to write through the root symlinks
2026-06-12 23:05:40 -04:00
rootiest 45cba3a15b fix(agents-init): address final review issues (CLAUDE.md safety, rm-rf guard, gitignore anchoring, worktree detection) 2026-06-12 22:09:44 -04:00
rootiest 8d0f425b10 feat(agents-init): add auto-commit step for AGENTS/ sub-repo 2026-06-12 21:59:02 -04:00
rootiest a483c30c05 fix(agents-init): use fish-idiomatic command substitution in --plugins mode 2026-06-12 21:55:05 -04:00
rootiest 3befc07887 feat(agents-init): add --plugins mode (docs/ move + symlinks + gitignore) 2026-06-12 21:53:32 -04:00
rootiest 2a9a7ed2ff fix(agents-init): add error checks and CLAUDE.md move to --agents mode 2026-06-12 21:51:05 -04:00
rootiest d1949953df feat(agents-init): add --agents mode (AGENTS.md move + symlinks + gitignore) 2026-06-12 21:48:25 -04:00
rootiest 7463d894f2 fix(agents-init): address code quality issues in skeleton 2026-06-12 21:46:59 -04:00
rootiest 1e1c2003f3 feat(agents-init): scaffold function with argparse, help, and sub-repo init 2026-06-12 21:42:58 -04:00