Commit Graph
952 Commits
Author SHA1 Message Date
rootiest 4240a04754 fix(agents-init): clean up stale anchored gitignore patterns on migration 2026-09-23 19:46:16 -04:00
rootiest ecfb93a818 feat(agents-init): discover and normalize AGENTS.md/CLAUDE.md in every subdirectory 2026-09-23 19:36:24 -04:00
rootiest a776d4d12d fix(agents-init): add missing branch test coverage and explicit terminal return 2026-09-23 19:32:36 -04:00
rootiest 731661b581 feat(agents-init): add per-directory AGENTS.md/CLAUDE.md sync helper 2026-09-23 19:25:01 -04:00
rootiest c48af2fa23 Merge pull request 'ci: push docs-regen commit with a real account token, not the default bot' (#176) from ci/bot-push-token into main
Reviewed-on: #176
2026-09-23 22:55:11 +00:00
rootiest 028478940f ci: push docs-regen commit with a real account token, not the default bot
CI / test (pull_request) Successful in 2m40s
CI / github-mirror (pull_request) Skipped
CI / docs (pull_request) Successful in 20s
The default `secrets.GITEA_TOKEN` is Gitea Actions' built-in synthetic
bot identity, not a whitelistable user account. main's branch protection
rejects its pushes outright regardless of retries (run 983, run 990) --
the retry/rebase loop in the next step was built for a non-fast-forward
race (run 976), not a bare permission rejection, so it can't recover
from this.

Point the docs job's checkout token at BOT_PUSH_TOKEN, a PAT on the
already-bypass-whitelisted rootiest account, so the later push
succeeds. Commit authorship and GPG signing (fishconfig-bot) are set
separately via git config a few steps later and are unaffected -- push
auth and commit identity are independent.
2026-09-23 18:50:30 -04:00
rootiest 27b6f5d263 Merge pull request 'docs: rename to Rootiest Fish Configuration in README and site title' (#175) from docs/rootiest-fish-configuration-title into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m28s
CI / docs (push) Failing after 4m5s
2026-09-23 21:14:18 +00:00
rootiest 59ace6fe6b docs: rename to Rootiest Fish Configuration in README and site title
CI / test (pull_request) Successful in 2m27s
CI / github-mirror (pull_request) Skipped
CI / docs (pull_request) Successful in 1m15s
Both said the generic 'Fish Shell Configuration' -- the site nav already
reads 'Rootiest Fish Config'. Reworded README's opening line to match
the sentiment, not just the name swap.
2026-09-23 16:35:37 -04:00
rootiest 344ee60acd Merge pull request 'docs: reword README's Documentation Site heading to Documentation Wiki' (#174) from docs/readme-documentation-wiki-wording into main 2026-09-23 20:30:12 +00:00
rootiest 1b9f1558c4 docs: reword README's Documentation Site heading to Documentation Wiki
CI / test (pull_request) Successful in 19s
CI / github-mirror (pull_request) Skipped
CI / docs (pull_request) Successful in 1m23s
Missed in the earlier site-to-wiki wording sweep -- line 8's Project Wiki
link already used the new term, this heading further down didn't.
2026-09-23 16:28:54 -04:00
rootiest ea1575f902 Merge pull request 'ci: gate docs job on PRs by label/path, gate test job by label too' (#173) from ci/label-and-path-gated-docs-and-tests into main
Reviewed-on: #173
2026-09-23 20:27:18 +00:00
rootiest 4797af85f3 ci: gate docs job on PRs by label/path, gate test job by label too
CI / test (pull_request) Successful in 2m34s
CI / github-mirror (pull_request) Skipped
CI / docs (pull_request) Successful in 24s
Adds scripts/** to the push path filter -- it was missing entirely, so
that directory never triggered CI regardless of what changed there.

pull_request no longer has a paths: filter (moved that check inside each
job, in shell, since a label-only PR with no relevant diff still needs
to trigger the workflow for the job-level label check to ever run).
Added labeled/unlabeled to pull_request types for the same reason.

Splits the old build-docs job into a docs job with two sections: doc
tests/build (generate concat, verify-manual.py, compile man page) run
whenever relevant on any event; publish (site build, Cloudflare deploy,
commit-back) is step-gated to push/dispatch only, as before. The docs
job now also runs on a PR when it's labeled Kind/Documentation or
Area/Docs, or its diff touches docs/manual/**, docs/build-manual.py,
docs/manualtools.py, docs/verify-manual.py, or docs/site/**.

test gains the same shape: also runs on a PR labeled Kind/Testing,
Area/Tests, Area/CI, or Area/Scripts, independent of what it touches.

docs no longer needs: test. main's branch protection already requires
test to pass before a PR merges, so by the time a push-to-main reaches
this job, test has necessarily already passed; re-checking it here
would be redundant. Leaves the same gap as
block_admin_merge_override=false on that rule: a direct admin push
bypasses it, an accepted trust boundary, not a new one.
2026-09-23 16:18:29 -04:00
rootiest 6074687a80 Merge pull request 'feat: add gitignore-scrub to catch tracked files newly matched by .gitignore' (#172) from feat/gitignore-scrub into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m31s
CI / build-docs (push) Failing after 4m20s
Reviewed-on: #172
2026-09-23 20:04:06 +00:00
rootiest 7e3d48ddac feat: add -r/--reset, -f/--force, -i/--individual to gitignore-scrub
CI / github-mirror (pull_request) Skipped
CI / test (pull_request) Successful in 2m15s
CI / build-docs (pull_request) Skipped
-r clears the repo's skip list first so declined files are reconsidered.
-f untracks every pending match immediately, no prompt. -i prompts once
per file instead of once for the whole group. -w, -f, -i are mutually
exclusive (argparse --exclusive), -r combines with any of them.
2026-09-23 15:52:01 -04:00
rootiest 37fea155b3 chore: untrack fisher-managed files left tracked since initial commit
CI / github-mirror (pull_request) Skipped
CI / test (pull_request) Successful in 2m36s
CI / build-docs (pull_request) Skipped
completions/fisher.fish and functions/fisher.fish match the Fisher-managed
ignore rule added in c77a52a but were never scrubbed from the index. Found
by gitignore-scrub itself (gi fish). Files remain on disk, untracked only.
2026-09-23 15:44:24 -04:00
rootiest 355688c134 feat: add gitignore-scrub to catch tracked files newly matched by .gitignore
CI / github-mirror (pull_request) Skipped
CI / test (pull_request) Successful in 2m26s
CI / build-docs (pull_request) Skipped
Standalone function, not gi-private: default mode prompts once for all
tracked-but-ignored files and offers git rm --cached, remembering a
decline per-path in the repo's local git config (gitignore-scrub.skip)
so the same file isn't re-asked. -w/--warn is read-only (prints Warning
lines, no prompt, no mutation) for non-interactive callers like a git
hook. Skips silently above $GITIGNORE_SCRUB_LIMIT tracked files (default
5000) to avoid latency on huge repos.

gi now calls gitignore-scrub at the end of any run that touched
.gitignore.
2026-09-23 14:59:58 -04:00
rootiest 9e8d29cc30 Merge pull request 'fix: guard and document the external tools PR #168 flagged as unguarded' (#170) from docs/guard-external-deps into main
CI / github-mirror (push) Skipped
CI / test (push) Failing after 53s
CI / build-docs (push) Skipped
2026-09-23 03:00:00 +00:00
rootiest af65092102 Merge pull request 'ci: retry the generated-docs push through a rebase on rejection' (#171) from ci/retry-docs-commit-push into main 2026-09-23 02:59:52 +00:00
rootiest 35a48ac868 ci: retry the generated-docs push through a rebase on rejection
build-docs's auto-commit step was seen rejected as non-fast-forward
(run 976, sha 3bbda31): npm ci + astro build + the Cloudflare Pages
deploy ahead of it can take several minutes, long enough for another
PR to merge into main first. A bare `git push` has no way to recover
from that -- the whole job just fails, even though every real step
(tests, manual verification, man page, site build, deploy) already
succeeded.

This commit only ever touches three generated files
(fish-config.md/.1, the component registry), so a rebase onto
whatever landed is always mechanical -- retry push up to 3 times,
rebasing onto origin/main between attempts. Ends on an explicit
`test "$pushed" -eq 1` rather than trailing off the for loop, so a
run that exhausts all three retries still fails loudly instead of
reporting success.
2026-09-22 22:54:47 -04:00
rootiest 8dcbc62359 fix: guard and document the external tools PR #168 flagged as unguarded
PR #168's Notes section named several functions with a real
external-tool dependency that no `type -q`/`command -q`/`command -v`/
`which` guard covers anywhere in the tree, deliberately left out of
DEPENDENCIES to avoid breaking test_dependencies_resolve. Adds the
guard each was missing, then declares the dependency now that it
resolves:

- bkg, detach: nohup
- gitui: gitui (self-shadow; type -q -f to skip the function itself)
- play-media: mpv, vlc -- already guarded via `type -q -f $p` in a
  loop, just never recognized as one (see next point)
- steam-dl: systemd-inhibit, steam
- wake-lock: systemd-inhibit
- split, spwin, tab: wezterm, konsole (kitty already declared)

docs/verify-manual.py's guard-detection regex only matched `type -q
<name>` immediately, so `type -q -f $p` (the `-f` flag excludes
functions from the match, needed wherever a wrapper shadows a binary
of its own name) was invisible to it -- both as a direct guard and
through the loop-variable indirection. Broadened both patterns to
skip over any flags between `-q` and the name/variable.

split/spwin/tab dispatch on $TERM/$TERM_PROGRAM/$KONSOLE_VERSION to
pick which terminal-specific binary to call, per this repo's C4
convention -- but those env vars only prove the terminal type, not
that its CLI binary is on $PATH: they propagate over ssh, so sshing
out from Kitty/WezTerm inherits the var on a remote host that never
installed the binary. Same latent gap in clone/clonet, whose
clone-in-kitty is a function Kitty's own shell integration injects,
not present on a remote shell that only inherited $TERM. All five now
check the actual thing they are about to call, not just the env var
that selects it.

Also guards and documents three more real, previously-undeclared
dependencies found by the same audit, unrelated to PR #168's named
list but the identical pattern: fast-cli (fast), lock (loginctl),
ports (lsof), screensleep (busctl).

docs/fish-config.md regenerated to match.
2026-09-22 22:40:33 -04:00
rootiest 17a95abebe Merge pull request 'ci: trigger CI on PR creation, gate build-docs to push/dispatch only' (#169) from ci/pr-trigger into main 2026-09-23 02:33:12 +00:00
rootiest b03ba7490e ci: trigger CI on PR creation, gate build-docs to push/dispatch only
Adds a pull_request trigger (same path filters, YAML anchor to share
them with push) so branches get CI feedback before merge instead of
only after. build-docs is excluded on pull_request: it auto-commits
generated docs straight to the checked-out ref and deploys the
Cloudflare Pages production site with --branch=main, neither of which
should run against PR content that is not main yet.
2026-09-22 22:32:11 -04:00
rootiest 3bbda31eff Merge pull request 'docs(functions): add DEPENDENCIES sections to doc headers' (#168) from claude/function-docs-dependencies-bfnnag into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 3m18s
CI / build-docs (push) Failing after 4m42s
Reviewed-on: #168
2026-09-23 02:31:09 +00:00
Claude fceddfc43f docs: add DEPENDENCIES sections to function doc headers
Documents what each function needs for full functionality -- other
repo functions it calls, and external CLI tools it uses or falls
back gracefully without (e.g. rm/trash, ls/eza+lsd) -- matching the
existing CLASSIFICATION convention's placement and the ~20 functions
that already carried this label.

Also broadens verify-manual.py's dependency-resolution check to
recognize this repo's other existence-check idioms (command -q,
command -v, which -- not just type -q) and dng2avif's dynamic
type -q $cmd loop, since several genuine dependencies (eza, lsd,
fastfetch, fd, ps, ...) are only ever guarded that way.
2026-09-22 22:22:27 -04:00
rootiest b10f076105 Merge pull request 'feat(functions): add -l/--local flag to mkrep' (#167) from feat/mkrep-local-flag into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m47s
CI / build-docs (push) Successful in 4m39s
2026-09-22 07:18:17 +00:00
rootiest 8b1689aa82 Merge pull request 'fix: silence stray CI/tool noise, fix real --silent leak in agents-vault/agents-init' (#166) from fix/ci-log-noise-cleanup into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m55s
CI / build-docs (push) Successful in 4m30s
2026-09-22 07:17:49 +00:00
rootiest 7724ec6d31 Merge pull request 'fix(tests): silence mkrep's git-init default-branch hint in CI' (#165) from fix/mkrep-test-defaultbranch-hint into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m43s
CI / build-docs (push) Successful in 5m12s
2026-09-22 07:17:27 +00:00
fishconfig-bot cde9396e70 chore(docs): regenerate manual, man page, and component registry 2026-09-22 07:14:38 +00:00
rootiest 9614ee17e1 fix(ci): stop chasing apt-utils' own debconf notice, document why
Verified live, twice: bundling apt-utils with another package (first
attempt) and installing it fully alone, first (second attempt) both
still print debconf's "delaying package configuration" notice exactly
once per job. It fires during apt-utils' own first-ever install, before
debconf considers it "installed" -- no install ordering this workflow
controls can pre-seed that. Reverted to the simpler bundled form (the
separate-step version added a step for zero measured benefit) and
documented it as accepted/unfixable, same class as the runs-on/
checkout-hint noise already left alone.
2026-09-22 02:58:55 -04:00
rootiest b0e09ef2a3 feat(functions): add -l/--local flag to mkrep
Add -l/--local flag to enforce strictly local repository creation in mkrep, overriding and ignoring any remote flags or environment variables that would link to or create a remote.
2026-09-22 02:54:14 -04:00
rootiest 135c375dcf fix(ci): install apt-utils in its own step, not bundled
The previous fix bundled apt-utils into the same apt-get install as
software-properties-common. Verified against a live CI run: debconf
still printed "delaying package configuration" once per job, because
apt-utils configures in the same transaction as everything else and
still lands after at least one other package -- bundling doesn't help.
Installing it alone, first, actually finishes it before anything else
runs.
2026-09-22 02:46:36 -04:00
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 018309581d fix(tests): pin init.defaultBranch in test-mkrep to silence git's hint
Every mkrep call in this suite runs a bare `git init`. On a runner with
no init.defaultBranch configured, git prints its "Using 'master' as the
name for the initial branch" advice block on each one (20 occurrences in
CI's test-job log, all from this file). test-agents-vault.fish already
pins the same setting via GIT_CONFIG_COUNT/KEY/VALUE for the identical
reason; apply the same fix here rather than in mkrep.fish itself, so a
real user's own git config still wins in normal use.
2026-09-22 00:04:36 -04:00
rootiest 6156aa7cb9 Merge pull request 'fix: CI build-docs link validation + non-portable cp -n warning' (#164) from fix/classification-schema-link-validation into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 4m28s
CI / build-docs (push) Successful in 4m10s
2026-09-22 02:52:42 +00:00
fishconfig-bot 694b084ff1 chore(docs): regenerate manual, man page, and component registry 2026-09-22 02:42:06 +00: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 18e04dd5fb fix(docs): point classification-schema link at Gitea, not a relative path
The schema file lives at docs/function-classification-schema.md but is
not a published Starlight page, so a relative link resolves fine in the
manual source tree but breaks once copied into
docs/site/src/content/docs/ — starlight-links-validator failed CI's
build-docs job on it. Rewrite it as an absolute Gitea blob URL, the same
pattern _rewrite_repo_links already uses for CONTRIBUTING.md/LICENSE.
2026-09-21 22:33:44 -04:00
rootiest abdb9cfacf Merge pull request 'feat: CLASSIFICATION function-header field + shadow-classification lint' (#163) from feat/classification-header-field into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m52s
CI / build-docs (push) Failing after 3m29s
Reviewed-on: #163
2026-09-22 02:12:56 +00:00
rootiest 2367f5749d docs(index): add config-help keyword aliases for CLASSIFICATION
The CLASSIFICATION schema (docs/function-classification-schema.md) had
no path into config-help's lookup: no fish-config.index keyword, and
the only in-pipeline section (the C1 doc's "For function authors")
doesn't contain the word classification itself, so even the
normalized-heading-scan fallback missed it on that term. Two aliases
added, pointing at the existing section -- no heading renamed, matching
the index file's own stated purpose.
2026-09-21 21:36:39 -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 373917d002 fix(functions): stop routing deterministic cd through zoxide's shadow
Verified an agy audit of every bare cd call by hand. conf.d/zoxide.fish
gates alias cd=z behind status is-interactive plus the C1 toggle, and
_zoxide_hook fires on --on-variable PWD, so it tracks a directory
change no matter how PWD got there -- switching to builtin cd loses
zoxide's frecency tracking nothing.

mkcd.fish's single cd and mkrep.fish's 9 (entering the new repo, plus
8 rollback-to-original-directory sites on error paths and --no-cd)
were both intended as exact, deterministic path navigation, never a
zoxide query. The real risk was mkrep's rollback path: if $orig_pwd
ever failed cd's own -d check for any reason, z's fallback branch
queries zoxide for a *guessed* frecent directory instead -- landing a
failed run's cleanup in a directory the caller never asked for, not
the one it was trying to return to. All 9 sites now use builtin cd.

Corrected both functions' CLASSIFICATION from uses-shadow(cd) to
bypasses-shadow(cd) -- neither wanted zoxide's query, they were tagged
that way only because the header audit recorded what the code was
doing at the time, not what it needed.

integrations/fzf.fish's fzf-alt-c-widget also calls bare cd, but it's
vendored upstream code (PatrickF1/fzf.fish) and is itself an
interactive directory-jump binding, not a script/automation caller --
left alone, same as fisher.fish's rm calls.
2026-09-21 21:26:52 -04:00
rootiest 100cb478bc fix(functions): stop leaking scratch files to trash via bare rm
Verified an agy audit of every bare rm call (the trash-routing C1
shadow) by hand rather than trusting its report. Confirmed correct:
scrub.fish's custom_rm strategy and logs.fish's Ctrl-D delete both
deliberately want trash for a real, user-facing deletion.

Confirmed and fixed three cases where a function's own throwaway
scratch file was going to the user's trash instead of being wiped:
fc.fish's edited-command tmpfile, dng2avif.fish's intermediate PNM
(inconsistent with its own failure-path cleanup two lines up, which
already used -f), and _scrollback_prune_junk.fish's junk log files
(its sibling _prune_terminal_logs.fish already documents this exact
pitfall in its header).

Also went further than the report and classified every bypasses-shadow(rm)
caller found by grep that had never been audited at all:
config-settings.fish and edit.fish (own scratch cleanup, no destructive
data at stake) and key-crypt.fish (--remove deletes the user's real
input file after encryption, genuinely destructive, already documented
in its own header as 'not a secure wipe'). Corrected scrub.fish's tag,
which was missing uses-shadow(rm) for its deliberate trash-routing
branch alongside the bypass branch it already had tagged.

Added a note to the schema doc: rm's flag-based fallback lives inside
the shadow itself, so a bare rm -f/rm -rf call is not the caller
bypassing anything -- only an explicit command rm/builtin rm earns
the tag. This is why dng2avif.fish's fix needed no CLASSIFICATION
change: it already used rm -f, which was never actually the bug --
the missing -f on line 122 was.
2026-09-21 21:26:50 -04:00
rootiest 069a1f7743 docs(classification): move schema out of gitignored AGENTS/, into docs/
AGENTS/functions/CLAUDE.md is git-ignored local agent state, not part
of the repo -- a comment/commit referencing it as the schema's home
points contributors at a file they can't see. The canonical CLASSIFICATION
schema now lives at docs/function-classification-schema.md (tracked),
with CONTRIBUTING.md's existing function-header-conventions section
extended to introduce it, and the C1 shadow doc's pointer updated to
match. AGENTS/functions/CLAUDE.md keeps only a one-line pointer to the
tracked file instead of duplicating the definitions.
2026-09-21 21:26:47 -04:00
rootiest 859f14a6e9 feat(functions): tag CLASSIFICATION across functions/ and conf.d/
Audits every function's interaction with the C1-shadowed commands
(uses-shadow/bypasses-shadow) and general hazards (destructive,
network, blocking-prompt) per the CLASSIFICATION schema.

Delegated the initial mechanical sweep to agy, then reviewed every
file by hand: fixed a systemic double-blank-comment-line formatting
bug from the delegate pass, and corrected several judgment errors
found on review -- three false blocking-prompt tags where a fish
'read' was consuming piped input rather than waiting on a terminal
(open-url.fish, sbver.fish, play-media.fish, now untagged entirely),
a blocking-prompt tag on mkrep.fish despite its documented --yes
escape hatch, an untagged read in jobrunner.fish's own baseless
blocking-prompt claim (removed, along with a destructive tag on
cleanup of its own mktemp output -- the schema explicitly excludes
that), the same own-output-cleanup false positive on
_zellij_dump_log.fish's destructive tag, an interactive fzf-gated
confirmation on logs.fish and replay.fish's piped read misread the
same way as the first three, and a uses-shadow(mkdir) on mkcd.fish
that actually belongs to the _fish_mkdir_p helper it delegates to,
not to mkcd itself.
2026-09-21 21:26:44 -04:00
rootiest aef686af86 feat(docs): add CLASSIFICATION function-header field, rename history shadow
Rename the C1 history() shadow to pretty-history so it never collides
with the fish builtin -- every function expecting stock history
semantics (search, --max, merge, ...) would otherwise silently break.
hist.fish, which relied on the shadow's timestamp formatting, now
requests it explicitly via builtin history --show-time.

Add a CLASSIFICATION doc-header label so a function can declare its
interaction with C1-shadowed commands (uses-shadow/bypasses-shadow)
and general hazards (destructive, network, blocking-prompt) for
anyone deciding to disable an opinionated category or call the
function from automation. Wired into the manual/site build pipeline
(manualtools.py, build-manual.py) and the C1 shadow doc gets a new
"For function authors" bypass-mechanism reference table
(command/builtin/__original_help, and which shadows have no real
bypass target at all).
2026-09-21 21:26:40 -04:00
rootiest 392e6593ac fix(keybind): bypass history shadow in ctrl-alt-u empty-prompt recall
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m3s
CI / build-docs (push) Successful in 4m5s
The tricks.fish C1 history() shadow drops all args and always shows
timestamps. Calling plain history --max 1 hit that shadow, dumping the
entire history with timestamps instead of one plain entry. Use builtin
history --max 1, matching the convention already used by fc.fish,
_fzf_search_history.fish, and bash_expands.fish.
2026-09-21 19:29:37 -04:00
fishconfig-bot 6fd25028d9 chore(docs): regenerate manual, man page, and component registry 2026-09-21 23:20:18 +00:00
rootiest e2c25fac64 Merge pull request 'feat(keybind): recall last history entry on empty prompt for ctrl-alt-u' (#162) from feat/replace-command-token-empty-recall into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m11s
CI / build-docs (push) Successful in 3m55s
2026-09-21 23:14:16 +00:00
rootiest e4df160fc0 docs(key-bindings): document ctrl-alt-u empty-prompt history recall 2026-09-21 19:07:02 -04:00
rootiest 2630342d81 feat(keybind): recall last history entry on empty prompt for ctrl-alt-u 2026-09-21 19:06:59 -04:00