[agent] feat(recipe): add --in flag for field-scoped recipe search #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "agent/search-by-ingredient"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Add a
--in {title,ingredients,both}flag tomealie-cli recipe search.Until now,
recipe searchwas a thin pass-through to Mealie's/api/recipes?search=…endpoint, which is fuzzy and unreliable (itreturns 100 results even when only a handful contain the query, and
it doesn't search ingredient lines at all). The new flag makes the
search deterministic and adds ingredient-level matching.
Why
User case: "find me recipes that use ground beef" (recettes qui
utilisent du boeuf haché). The previous
recipe search boeufreturned 100 results, mostly unrelated. Going to the API and
post-filtering on each recipe's
recipeIngredient[]list gave thereal answer (16 recipes for that specific query on a 296-recipe
household), but the CLI didn't expose that capability. This PR
turns the manual investigation into a first-class flag.
How
mealie.SearchRecipes(ctx, query, opts)method ininternal/mealie/search.gothat:?search=hint)detail concurrently (8 workers by default, bounded by a
semaphore)
--inflag in therecipe searchCLI, defaultbothRecipeIngredienttype added tointernal/mealie/types.goso
recipe getactually decodes and returns the ingredient list(it was previously dropped silently)
bœufmatchesboeuf,BŒUF,Boeuf,crèmematchescreme. Uses NFKD +a manual mapping for the
œligature (Go'snorm.NFKDingolang.org/x/text v0.38.0doesn't decompose it — verifiedwith a
go rundebug).skills/mealie-cli/SKILL.mdwith the newflag, four example invocations, and the rationale for the change
Verification
Tests: 23 new test cases
ParseSearchFieldfold(coversœ,BŒUF,bœuf,crème,déjà vu,fallback for unknown chars)
matchInText(case + accent insensitivity, wordboundaries, empty needles, etc.)
matchTitlematchIngredients(note + display fallback)fakeTransport(httptest-stylefake) that asserts the right slugs come back for each
SearchField, that accent folding works end-to-end, and thatLimitis respectedPerformance:
--in titlemakes 1 paginated list call and no detailcalls.
--in ingredientsand--in bothmake 1 list call + 1 GETper recipe, bounded by 8 concurrent fetches. For 296 recipes, the
boeuf-haché query returns in ~12s.
Diffstat
Caveats
recipe search: thedefault behaviour (now
--in both) is different from before(which used Mealie's fuzzy
?search=). The new behaviour isstrictly more correct (no false positives) and is what users
actually want, but anyone with shell scripts relying on
recipe searchreturning ~100 fuzzy results will see a change.The previous behaviour can still be approximated with
recipe list --search <query>, which still uses Mealie's fuzzyfilter (though that has its own caveats — see the skill).
golang.org/x/textfamily foraccented-char folding. The repo now has one indirect dependency
(
golang.org/x/text v0.38.0) — small, well-maintained, notransitive bloat. Could be replaced by a 20-line pure-Go fold
function if the dependency is unwanted, but the
normpackagedoes the right thing for the ~30 diacritics found in real recipe
text and is the more conservative choice.
Until now 'recipe search' was a thin pass-through to Mealie's fuzzy ?search= endpoint, which is unreliable: it returns 100 results even when only a handful actually contain the query (e.g. searching 'boeuf' returns 'Aiglefin au curry et miel' just because the description mentions boeuf). It also doesn't search ingredient lines, so 'find me recipes that USE ground beef' wasn't directly answerable from the CLI. This commit adds a new SearchRecipes method that: 1. pulls the full recipe list (predictable, no fuzzy filter) 2. post-filters on the field(s) requested 3. when ingredients are in scope, fetches each recipe's full detail concurrently (8 workers by default) to scan its recipeIngredient[] list The CLI gains a --in flag (default 'both') with three values: title — case- and diacritic-insensitive substring on Name ingredients — same on recipeIngredient[].note / .display both — title OR ingredients (the new default) Matching is case- and diacritic-insensitive: 'bœuf' (with circumflex) matches 'Boeuf' (without), 'BŒUF' (capital ligature) matches 'boeuf', etc. The fold uses NFKD + a manual mapping for the 'œ' ligature (which Go's norm.NFKD doesn't decompose in golang.org/x/text v0.38.0). Other changes: - Recipe struct gains RecipeIngredient []RecipeIngredient (previously not decoded, so 'recipe get' was dropping the ingredient list) - bump version 0.1.0 → 0.2.0 - update in-repo skill with the new flag, the four example invocations, and the rationale (Mealie's fuzzy is unreliable) Tests: 23 new test cases (8 table-driven for ParseSearchField, 8 for fold, 10 for matchInText, 4 for matchTitle, 7 for matchIngredients, 5 integration tests using a fake RoundTripper). All pass on a real Go 1.26.3 toolchain. Live verified against mealie.polensky.me (v3.12.0, 296 recipes): 'recipe search "boeuf haché" --in ingredients' returns the same 16 ground-beef recipes the Python investigation found, in ~12s.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.