get_history_correction aligns a failed script with near-identical
history commands segment by segment (shell_ast words with byte-true
offsets) and splices the corrected tokens back in place. It only
returns a fix when exactly one candidate matches the structure with
at most two diverged tokens, each at least 80 percent similar;
looser or ambiguous matches decline so the asking history rule
stays in charge of them.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Consult a PATH-resolved binary's own --help (mtime-cached, LC_ALL=C,
2s timeout with kill) when a segment's first non-flag token is not a
listed subcommand, and splice the unique close match (ratio >= 0.8,
same first character). Ambiguity, sudo heads, flat-fallback artifact
heads, valid subcommands and nested levels all decline to the rest of
the chain; only <binary> --help is ever run.
put_to_history wrote entries without a trailing newline, so fixed
commands concatenated onto one line, and backslash-continued
multiline entries were read back as broken fragments. Join
continuations when reading and terminate entries with a newline,
matching the fish adapter convention.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
parse() turns a script into pipeline command segments via bashlex,
keeping byte-true char offsets for every word (quotes included as
typed, redirects and env assignments excluded from words), and
splice() rebuilds a corrected script from (start, end, text)
replacements applied right-to-left. When bashlex is missing or
rejects the script, a flat split(' ') segment keeps the old view.
bashlex (GPL-3+) powers upcoming structural command analysis: parsing
pipelines into segments with word offsets so a typo anywhere in a
command can be fixed as confidently as one at the start. Because the
license is incompatible with distributing the MIT-licensed app, the
dependency is import-guarded: thefuck/shell_ast.py exposes
AST_AVAILABLE, which is False when bashlex is missing or under python 2
(the py2.7 CI requirements.txt deliberately omits it), so all new
behavior must gate on it and the fork stays personal-use only.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
tests/entrypoints/test_fix_command.py sets TF_HISTORY, which makes the
real _get_raw_command call get_all_executables() and memoize the
machine's actual PATH. TestGetValidHistoryWithoutCurrent then mocks
thefuck.utils.Path to plant a fake café binary, but gets the stale
memoized list, so the café history line is filtered out and the four
parametrized cases fail whenever the entrypoint tests ran first.
Use the existing no_memoize fixture, like the neighboring
executables tests already do.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
When no learned correction matches, fuzzy-match the mistyped token
against executables from $PATH and shell aliases. A guess is auto-run
and recorded into the learned-corrections db only when it is
unambiguous: the token is not an existing executable, contains no
path separators or extensions, shares its first character with the
candidate, has similarity of at least 0.8, and exactly one candidate
survives. Asking the user stays the last resort.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Record user-accepted corrections in a shelve-backed store and replay
them on future matching mistakes, bypassing rule evaluation entirely.
Two-level matching: exact full-command lookup, then word-level
reconstruction that generalises to different arguments (e.g. learning
'git psuh origin main' also fixes 'git psuh origin dev').
Implement Nushell shell adapter (from nvbn/thefuck#1442) with alias
resolution, history management, and subprocess-based command execution.
Add uv2nix-based Nix flake for reproducible builds with Python 3.11,
pinned setuptools<71 for pkg_resources compatibility, and dev shell
with uv for local development.
* Add git clone missing rule
* Clean up tests and improve matching
* Make rules behave correctly?
* Improve tests and redo matcher
* Remove unnecessary tests
* Improvements as per code review
* Remove dead tests
* Improve match function for git clone missing
* Improve tests
* Fix more tests
* Fix failing test
* Add Macos's /bin/sh command output to match
* Add output for lines uncovered by tests
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
* fix: Update output for brew_install test: fixed
* chore: fixing flake8 styles
* feat: show more suggestions
* test: new functions added and multi suggestions
* refactor: rename to _get_suggestions
* added updatedb(mlocate) to sudo rules
* Add test
Co-authored-by: phk <phk@terminal21.de>
Co-authored-by: Pablo Santiago Blum de Aguiar <scorphus@gmail.com>
Using the `force_command` argument will run into issues as the
`_get_raw_command` method simply returns the value of `force_command`
(which is a string) while it should actually return a list.
Fix#1240