Local mirror only -- AUR account registration is still disabled
(since 2026-06-15), so this isn't pushed to aur.archlinux.org yet.
Kept in sync so it's ready to publish the moment registration
reopens.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
IMPLEMENTATION_PLAN.md (Phases 1-5: CLI direct-to-Microsoft, Redis L2
cache, /contribute crowdsourcing, web graceful degradation, CLI
handoff UI, distribution) had shipped in full but still read "Status:
Proposed" -- folded a summary of what actually landed into
PROGRESS.md instead.
issues.md's one drafted issue (inactive products still triggering
backend requests) is already fixed -- ProductDetailPage.tsx gates the
SKU-info effect on meta.active.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prior commit staged an intermediate version of this file. Completes
the Method 1 / Method 2 writeup with usage examples, the comparison
table, and the field-name bug/session-permit history.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves msdls_v3.py from repo root into scripts/check-new-releases/,
alongside a new Go tool, documented as Method 1 (Python brute-force
range scan, can write results to a catalog-shaped JSON) and Method 2
(Go auto-discovery via page-scrape + bounded adjacent-ID probe, no
range-guessing needed). Only Windows 11 is checked -- 8.1 is fully
frozen and Windows 10 is past end-of-life, so neither will produce a
new consumer ISO again.
Fixed msdls_v3.py's release-name extraction: it checked EditionName/
ReleaseName/FriendlyName, none of which exist in the real API
response -- the actual field is ProductDisplayName, confirmed live.
Also added the vlscppe session-permit call to setup_session(), which
was skipped entirely; higher-risk gap for this script's brute-force
range-scan usage pattern than for a single lookup.
Both tools' live runs surfaced a real catalog gap: product IDs
3322/3323/3325/3326 (Home/Pro China variants of the 25H2 "V2" refresh)
exist on Microsoft's side but weren't in our catalog. Added them to
cli/catalog.go, products.json, validContributeProducts, and
sitemap.xml, and renamed 3321/3324 from our own guessed "(Updated
Oct)" label to Microsoft's actual name for this refresh, "(V2)"
(their internal name is "Windows 11 25H2__V2"; cleaned up the
double-underscore for user-facing display).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The msdl-cli vs msdl naming footnote is useful context in README/release
notes, but unnecessary clutter for a casual visitor on the web CLI page --
the "recommended" badge and the command itself are enough.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
homebrew/core already has an unrelated package literally named "msdl"
(a streaming-protocol downloader). brew install msdl silently
resolved to that instead of our tap, since Homebrew always prefers
core for a bare-name collision -- confirmed in production when a
user's `brew install msdl` pulled homebrew-core's msdl 1.2.7-r2
instead of ours. The tap's formula is renamed to msdl-cli
(starkSV/homebrew-msdl, separate repo) to fix this permanently; the
installed command itself is unaffected, still just `msdl`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a GET /install.sh endpoint on the backend (embedded via Go's
embed package, so the script stays a real, shellcheck-able .sh file
rather than a Go string literal). Auto-detects OS/arch (including
Termux on Android via $PREFIX) and always resolves the latest GitHub
release via the /releases/latest/download/ redirect, so unlike the
winget/brew/AUR manifests it needs no per-release maintenance.
Verified end-to-end in an ephemeral Ubuntu container (both the normal
/usr/local/bin path and the Termux $PREFIX path), and locally against
a running backend instance.
Documented alongside the existing winget/Homebrew instructions in
README.md, the release notes template, the web CLI page, and the
per-product CliHandoff card.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Arch Linux disabled new AUR account registrations on 2026-06-15 after
a malware campaign compromised 1,500+ AUR packages. There's no
announced reopening date, so aur/msdl-bin/README.md now says so
clearly instead of implying publishing is just a pending step.
Adds the Homebrew tap install command (brew tap starkSV/msdl && brew
install msdl) to every place winget is already documented: README.md,
the release workflow's notes, the web CLI page, and the per-product
CliHandoff card. Also adds the missing linux-arm64 row to the manual
download tables.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.SRCINFO generated with the real makepkg tool inside an ephemeral
archlinux container -- no VM or native Arch install needed, and no
risk of hand-written formatting drift from the makepkg-canonical
output.
Also adds .gitattributes forcing LF for PKGBUILD/.SRCINFO regardless
of platform checkout settings -- both are parsed by shell/makepkg
tooling that breaks on CRLF.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tracks the AUR PKGBUILD in-repo for version history, mirroring how
winget/manifests/ already works. Also corrects CONTRIBUTING.md's claim
that winget auto-updates via CI -- WINGET_TOKEN isn't set, so that
step always no-ops; package manager updates are all submitted
manually by the maintainer after each release.
Homebrew tap published separately at starkSV/homebrew-msdl.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Matches the shape actually asked for and how every other telemetry
counter in this file already works (all-time cumulative via HIncrBy,
no expiry, no per-day key rotation): /metrics now exposes flat
sentinel_errors and sentinel_distinct_sources_est fields instead of a
nested, date-scoped sentinel_today object.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CLI telemetry showed a growing count of Sentinel rejections but no way
to tell whether they come from one user retrying repeatedly or many
distinct users independently getting blocked.
Adds a per-day Redis HyperLogLog (msdl:telemetry:sentinel_hll:<date>)
seeded from the reporting IP whenever a CLI error contains "Sentinel",
plus a parallel daily counter. /metrics now exposes sentinel_today:
{date, errors_today, distinct_sources_est}. No raw IPs are stored --
HLL is a one-way cardinality estimator, and both keys expire after 48h.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The bare `msdl` invocation showed all 22 products (17 consumer + 5
eval) as a flat numbered list. Replaces it with a curated landing
screen: 5 popular products (picked from real usage telemetry) plus a
2-item eval shortlist, with "list" as an escape hatch to today's full
picker and free text routed through the existing search flow.
Also fixes a search bug: querying "windows 10" incorrectly matched
Windows 11 24H2 because "10" is a substring of its build number
(26100.1742). Query words now must start at a word boundary rather
than matching anywhere, so digit fragments inside unrelated numbers
can no longer collide -- while "arm" still fuzzy-matches "ARM64".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Consumer Windows products list their English option as "English" (or
"English International"), not "English (United States)" -- the exact
example this used, which is why it was such a common source of --lang
mismatch errors. Applies to --help, the --lang flag description, and
the release workflow's usage example.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs combined to make v0.3.4's changelog show the previous
release's version-bump commit instead of the actual change:
1. The path filter (cli/ backend/ frontend/) excluded workflow-only
changes, so a CI-only addition (like linux-arm64) never appeared.
2. The "bump version + winget manifest" commit is created *after* its
own tag (it needs the release's SHA256, which doesn't exist until
after tagging) -- so it always lands in the *next* release's diff
range instead of its own, showing up as stale noise.
Adds .github/workflows/cli-release.yml to the path filter, filters
out "chore(release): bump" commits as noise, and falls back to a
generic line if a release genuinely has nothing else to show.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves the README's inline contributing notes into a dedicated file
and expands them with dev setup, PR conventions, and how CLI releases
work, so contributors have one place to look.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Telemetry showed a growing number of Termux (Android) users running
the CLI, but the release workflow only builds linux-amd64 -- those
users had to build from source since Termux runs on ARM64. Adds a
linux-arm64 binary and install line so they can just curl it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Real-world telemetry showed --lang "English (United States)" failing
for several consumer products that only list "English International"
-- the exact example used in --help. The mismatch error now lists the
languages actually available, and the help text notes names vary by
product.
Also fixes truncateError to keep both head and tail of long error
strings (previously kept only the head, which for wrapped errors with
a long URL cut off the actual root cause at the end).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Sentinel lockdown gate served any linkCache hit as "stale"
regardless of whether the entry was still within its own TTL. A link
just contributed via CLI (still valid for ~24h) would get labeled
stale, causing the frontend to hide it and show the CLI-only banner
again instead of the working link it just received.
Now checks the entry's actual expiry: still-fresh entries are labeled
"cached" (frontend shows the link normally); only genuinely expired
entries are labeled "stale".
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Failure telemetry only recorded success=false with no context. Adds
a truncated error string (150 chars, CLI-side) forwarded to a new
msdl:telemetry:errors Redis hash so failure causes are diagnosable
from /metrics instead of guessed at.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Telemetry was fired as a goroutine then the process exited immediately,
killing it before the HTTP request could complete. Now called
synchronously — sendTelemetry already has a 2s internal timeout so
worst-case latency is unchanged for the user.
Also moves the combined picker into run() so eval products selected
interactively are tagged action=eval with the correct eval_slug instead
of action=interactive with no slug.
Adds What's New changelog section to release notes, auto-generated from
commits since the previous tag.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- GET /cli/version update-check endpoint
- POST /telemetry anonymous usage counters (Redis-persisted)
- Telemetry counters in /metrics response
CLI:
- Version var injected via ldflags at build time
- Update notice on every run (non-blocking, 500ms timeout)
- Architecture picker when multiple links returned
- Post-fetch [O] Open in browser / [C] Copy / [Enter] Exit menu
- Combined interactive picker includes Evaluation/Enterprise products
(Windows Server 2025/2022/2019/2016, Windows 11 Enterprise)
- openInBrowser: writes URL to temp .url file — & no longer truncated
- copyToClipboard: calls clip.exe via full SystemRoot path
Frontend:
- Winget elevated to primary install on CLI page + CliHandoff card
- CliHandoff command shows msdl (no .exe suffix)
Docs: README telemetry disclosure
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Interactive `msdl` (no flags) now lists consumer + eval products in one
picker with an Evaluation / Enterprise separator; selecting a server
product routes to the eval flow automatically
- copyToClipboard calls clip.exe by full SystemRoot path, bypassing
cmd.exe PATH lookup that failed in some terminal environments
- CliHandoff card: winget primary install + msdl (no .exe) in run command
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
cmd.exe treats & as a command separator, truncating Microsoft's signed
download URLs at the first query parameter boundary. Writing the URL to
a Windows Internet Shortcut (.url) file means cmd.exe only ever sees a
temp filename with no special characters; the browser reads the full URL
from the file contents.
Uses %COMSPEC% to locate cmd.exe reliably across environments.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>