feat(scripts): winget id harvester to close the Windows-install gap#61
Merged
Conversation
The generator already renders a winget install/update method whenever a recipe_data.py row carries a `winget` key, but almost no rows do — so the bulk-generated recipes install nothing on Windows. scripts/winget_candidates.py resolves winget PackageIdentifiers against the winget community-source index (the SQLite catalog winget itself uses), tiered by confidence: high gh owner/repo exact id, or command/moniker match whose publisher == gh owner medium a unique installed-command match, no gh corroboration low moniker-only (weakest — monikers collide across unrelated apps) Publisher corroboration rejects look-alike false positives (e.g. the Windows app Japplis.Pastel for the Rust sharkdp.pastel). Default emits winget_proposals.json for review; --apply stages keys into recipe_data.py as a reviewable git diff. Stdlib only, installs nothing, runs anywhere. A HIGH run resolves ~145 ids (winget coverage 13 → ~158 recipes). Adds a manual winget-ingest workflow (uploads proposals artifact) mirroring the brew ingester. Tests: 31 new (100% coverage of the module), including mutation guards on every confidence boundary; full suite 3604 passed. conftest puts scripts/ on sys.path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…port Applied all resolved winget PackageIdentifiers (145 high / 29 medium / 20 low) into recipe_data.py and regenerated the recipes, taking winget coverage from 13 to 207 recipes. Windows is best-effort: bulk-resolved ids are only spot-checked, so some may be wrong/stale/look-alikes (a winget install can fail or install the wrong tool). Each method's `when:` guard makes a bad winget method fail cleanly rather than break a POSIX bootstrap. Added a README warning + CHANGELOG note. test_every_winget_recipe_is_covered now pins winget recipes to two sources of truth — the hand-curated flagship map (proven by the windows real-bootstrap job) and recipe_data.py (bulk, best-effort) — instead of the flagship-only lock. Full suite: 3604 passed, 511 skipped. Recipes lint clean; ruff clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The generator already renders a
wingetinstall/update method whenever arecipe_data.pyrow carries awingetkey — but only 13 of 520 recipes do, sothe ~483 bulk-generated recipes install nothing on Windows. This adds a
maintainer harvester that resolves winget
PackageIdentifiers for the rows thatlack one, closing that gap. (Addresses the "generated recipes are POSIX-first
(no winget methods yet)" note under 0.2.1.)
How it resolves ids (confidence tiers)
Queries the winget community-source index — the SQLite catalog (
Public/index.dbinside
source2.msix) that thewingetCLI itself uses — not the msstore source.Each row is tiered by trust:
ghowner/repo exactly, or a command/moniker match whose publisher == the GitHub ownerPublisher corroboration is what makes
hightrustworthy: it rejects look-alikefalse positives — e.g. the moniker
pastelmatches the Windows appJapplis.Pastel, but thegh: sharkdp/pastelcorroboration resolves the correctsharkdp.pastelinstead.Usage
Stdlib only, installs nothing, runs anywhere. Default emits a JSON artifact for
review (same propose→human-merges idiom as the brew ingester);
--applystagesthe keys as a reviewable diff. A new manual
winget-ingestworkflow uploads theproposals artifact. Nothing about
recipe_data.py/recipes/changes in this PR —applying the keys is the follow-up you approve after reviewing the table below.
Verification (per the review discipline)
--applyon a copy of the realrecipe_data.pyproduces valid Python (py_compileOK); a resolved row renders a lint-clean recipe with guardedwinget install/upgrademethods through the realgen_recipes+lint_recipes.>=) each turn the suite red.0.15.20clean,py_compileOK, recipe linter clean.Impact
A HIGH-confidence run resolves 145 ids → winget coverage 13 → ~158 recipes (~30%).
The 145 proposed keys for review:
145 HIGH-confidence proposals:
actnektos.actageFiloSottile.ageaichatsigoden.AIChatargocdargoproj.argocdaria2aria2.aria2ast-grepast-grep.ast-grepatuinAtuinsh.Atuinaws-vault99designs.aws-vaultbiomeBiomeJS.Biomeblackpsf.blackbrotliGoogle.Brotlibtoparistocratos.btop4winbufbufbuild.bufbunOven-sh.BuncaddyCaddyServer.CaddyccacheCcache.Ccachechafahpjansson.Chafachezmoitwpayne.chezmoicloudflaredCloudflare.cloudflaredcmakeKitware.CMakeconsulHashicorp.ConsulcosignSigstore.Cosigncrocschollz.croccrystalCrystalLang.CrystalcurlcURL.cURLdbmateamacneil.dbmatedenoDenoLand.Denodirenvdirenv.direnvdivewagoodman.divedoctlDigitalOcean.Doctldogogham.dogdprintdprint.dprintduaByron.dua-clidufmuesli.duffastfetchFastfetch-cli.Fastfetchfendprintfn.fendffufffuf.ffufflatbuffersGoogle.flatbuffersfnmSchniz.fnmfreezecharmbracelet.freezefswatchemcrisostomo.fswatchfzfjunegunn.fzfgallery-dlmikf.gallery-dlgdudundee.gdugenactsvenstaro.genactghqx-motemen.ghqgifskiImageOptim.gifskigit-absorbtummychow.git-absorbgit-clifforhun.git-cliffgitleaksGitleaks.Gitleaksglowcharmbracelet.glowgolangci-lintGolangCI.golangci-lintgoreleasergoreleaser.goreleasergpingorf.gpinggrpcurlfullstorydev.grpcurlgrypeAnchore.Grypegumcharmbracelet.gumhadolinthadolint.hadolinthatchPyPA.HatchhcloudHetznerCloud.CLIhelmHelm.Helmhexylsharkdp.hexylhurlOrange-OpenSource.HurlimagemagickImageMagick.ImageMagickinfracostInfracost.InfracostjuliaJulialang.JuliajustCasey.Justk9sDerailed.k9skalkerPaddiM8.kalkerkomposeKubernetes.komposekondotbillington.kondokopiaKopia.KopiaCLIkube-linterstackrox.kube-linterkubectlKubernetes.kubectlkubectxahmetb.kubectxkubescapekubescape.kubescapelazydockerJesseDuffield.Lazydockerlefthookevilmartians.lefthooklsdlsd-rs.lsdmcMinIO.Clientmesonmesonbuild.mesonmicrozyedidia.microminikubeKubernetes.minikubeminiservesvenstaro.miniservemisejdx.misemitmproxymitmproxy.mitmproxymkcertFiloSottile.mkcertmodscharmbracelet.modsmprocspvolok.mprocsneovimNeovim.NeovimninjaNinja-build.NinjanomadHashicorp.NomadnushellNushell.Nushellohahatoo.ohaollamaOllama.Ollamaonefetcho2sh.onefetchopaopen-policy-agent.opaopamOCaml.opamorasORASProject.ORASovnoborus.ovoxipngShssoichiro.OxipngpackerHashicorp.Packerpastelsharkdp.pastelpnpmpnpm.pnpmpresentermmfontanini.presentermpulumiPulumi.PulumiqpdfQPDF.QPDFrcloneRclone.RcloneredisRedis.Redisresticrestic.resticruffastral-sh.ruffsccacheMozilla.sccacheserverlessServerless.Serverlessshellcheckkoalaman.shellcheckshfmtmvdan.shfmtstackcommercialhaskell.stackstarshipStarship.StarshipstepSmallstep.stepsternstern.sternstreamlinkStreamlink.StreamlinkstyluaJohnnyMorganz.StyLuasyftAnchore.SyfttailscaleTailscale.TailscaletailwindcssTailwindLabs.TailwindCSStaplotamasfe.taplotelevisionalexpasmantier.televisionterraform-docsTerraform-docs.Terraform-docstesseracttesseract-ocr.tesseracttflintTerraformLinters.tflinttopgradetopgrade-rs.topgradetrivyAquaSecurity.TrivytyposCrate-CI.TypostypstTypst.TypstugrepGenivia.ugrepvaleerrata-ai.ValevaultHashicorp.Vaultvhscharmbracelet.vhsvividsharkdp.vividwasmtimeBytecodeAlliance.Wasmtimewatchmanfacebook.watchmanxhducaale.xhxonshxonsh.xonsh-wingetyazisxyazi.yaziyt-dlpyt-dlp.yt-dlpzolagetzola.zola🤖 Generated with Claude Code