The installer's write_unix_wrapper shell-quotes the binary path, so
paths containing single quotes (or other shell metacharacters) appear
as shell-quoted strings in the generated wrapper file. The uninstall
script's literal grep -qF missed these, leaving the wrapper orphaned.
Add shell_quote to the uninstall script and match against both the raw
and shell-quoted forms before removing the wrapper.
- ensure_managed_install_dir / :EnsureManagedInstallDir now back up
non-qwen directories instead of refusing to install, so users
upgrading from npm or old installers don't hit a hard error
- Simplify header/footer output: remove banner bars, verbose INFO
lines, and redundant "Installation completed!" message
- Match bun.sh / code-server style: minimal, to the point
Prefer curl.exe with -# (hash-mark progress bar) for archive and installer
downloads on Windows 10+. Falls back to Invoke-WebRequest (which shows its
own progress bar) when curl.exe is unavailable. Matches the approach used
by code-server (curl -#fL) and bun.sh (curl.exe -#SfLo).
Add $ProgressPreference = 'SilentlyContinue' to DownloadFile so the
full-screen progress UI does not appear during archive downloads in
interactive PowerShell sessions, consistent with the .ps1 shim.
Add $ProgressPreference = 'SilentlyContinue' to the .ps1 wrapper so
Invoke-WebRequest downloads don't render a progress bar when invoked
via the irm | iex one-liner.
- Add Aliyun OSS sync steps to release workflow: package hosted assets,
install pinned ossutil, configure credentials, upload versioned and
latest paths, and verify upload via verify:installation-release plus
curl probes against the hosted installer endpoint.
- Document required production-release environment secrets and bucket
variables in INSTALLATION_GUIDE.md.
- Restructure hosted endpoint guidance to lead with the pre-sync
warning, splitting "Run today" (local checkout) from "After the OSS
sync" (hosted one-liners) so users no longer copy a one-liner that
silently installs latest.
- Distinguish mirror auto-selection timeout from successful selection
in install-qwen-standalone.sh and install-qwen-standalone.bat: emit
a "timed out; defaulting to github" log instead of pretending the
HEAD probe picked github.
- Support QWEN_INSTALLER_BAT_URL override (https only) in the
PowerShell shim so staging mirrors can be exercised without forking
the file.
- Strip a leading UTF-8 BOM in verify-installation-release.js
parseSha256Sums so BOM-prefixed SHA256SUMS reports a useful
"Missing checksum entry" error instead of "Malformed SHA256SUMS
line 1".
- Add tests for verifier HEAD→Range fallback, partial-failure
formatting, all-failure wording, and BOM tolerance.
The previous Windows quick-install one-liner used `Invoke-WebRequest -OutFile
(Join-Path $env:TEMP 'install-qwen.bat'); & (Join-Path …)`. When pasted into a
narrow terminal, line wrap could land on `-OutFile`, orphaning the parameter
from its value and producing the "missing argument for OutFile" failure
followed by a "file not found" when the second `&` ran. PowerShell's line
continuation rules cannot resolve this for parameter-name-at-EOL.
Add `install-qwen.ps1` as a thin hosted entrypoint that downloads
`install-qwen.bat` into TEMP, runs it, and cleans up. Documented one-liner
becomes the standard pattern used by bun, uv, scoop, deno, pnpm:
powershell -ExecutionPolicy Bypass -c "irm <url>/install-qwen.ps1 | iex"
The `.bat` remains the source of truth for installer behavior; `.ps1` is just
the modern hosted entrypoint. Version pinning via `$env:QWEN_INSTALL_VERSION`
flows through unchanged. Stored with `*.ps1 -text` so CRLF survives both
GitHub raw and OSS uploads, matching the existing `.bat` handling.
- Add standalone archive installer (bat/sh) that downloads platform binaries
from GitHub/Aliyun without requiring Node.js or npm on the target machine
- Add fork-friendly release-test workflow for manual GitHub Release creation
covering all 5 platforms (darwin-arm64/x64, linux-arm64/x64, win-x64)
- Add OSS upload/mirror tools for staging and release distribution
- Update .gitignore to exclude generated build artifacts (release-staging/,
hosted-staging/)
- Fix Windows PowerShell test command in copy-release-to-latest tool
Three small refinements from the second review pass:
- normalizeHttpsBaseUrl rejects everything except https, since real release
URLs are always HTTPS. Accepting http previously would let an operator
silently target a stale or attacker-controlled mirror.
- Drop EXPECTED_RELEASE_ASSET_NAMES from the public exports; it was only
used internally for the verification log line.
- Rename the test helper standaloneChecksumContent to
placeholderChecksumContent and document that the hashes in its output are
placeholders — the remote verifier does not download archives or compare
hashes, it only validates that SHA256SUMS lists the expected names and
that each archive URL is reachable.
The non-https rejection test now also covers `http://` in addition to the
existing `file://` case.
Adds `npm run verify:installation-release` and wires it into the release
workflow after `Build Standalone Archives`, so a broken release directory
fails CI before publishing.
Local mode (`--dir PATH`) checks:
- All five `qwen-code-{platform}.{ext}` standalone archives exist.
- `SHA256SUMS` covers exactly those five — missing or unexpected entries fail.
- Each archive's actual SHA256 matches its `SHA256SUMS` entry.
Remote mode (`--base-url URL`) checks:
- `SHA256SUMS` is downloadable, parseable, and contains exactly the expected
archive entries.
- Each archive URL is reachable via HEAD, with a 1-byte ranged GET fallback
for hosts that disable HEAD.
Hosted installer scripts (`install-qwen.sh` / `install-qwen.bat`) are
intentionally out of scope here — they are served from the hosted endpoint
prepared by `package:hosted-installation` (PR #3853), not from the GitHub
Release surface this verifier targets.
- Replace the loose `latest` fragment check with per-format regex patterns
in HOSTED_INSTALLER_DEFAULT_VERSION_PATTERNS so an unrelated occurrence
of `latest` (comment, help text) cannot satisfy the staging guard. The
patterns still tolerate whitespace variation, only the default-version
assignment itself must be intact.
- Add a "Hosted endpoint status" callout in INSTALLATION_GUIDE.md before
the curl examples. The documented `--version` flow does not work against
the OSS URL today because it currently serves the legacy NVM-based
installer; the callout points users at a local checkout until the next
release sync.
- Tests: drop `latest` from the fragments equality assertion, add positive
and negative regex coverage, add a failure-path case for sources whose
default version is not `latest`, and pin the new guide markers so the
callout cannot silently disappear.
Three CI failures and a few review followups in one pass.
- ensureMinimalDist places its dist/ backup beside dist/ instead of
under os.tmpdir(). On Windows GitHub runners the workspace lives on
D: while os.tmpdir() is on C:, so renameSync raised EXDEV for every
test that needed to swap dist/ in.
- create-standalone-package.js and the matching test fixture build
win-x64 zips with [IO.Compression.ZipFile]::CreateFromDirectory.
Compress-Archive emits backslash entry names that the .bat
installer's path-traversal guard then rejected, so every freshly
built archive failed the standalone install path on Windows.
- :ValidateArchiveContents normalizes entry separators to '/' before
checking for '..', absolute paths, and drive prefixes - archives
from any Windows zip tool still install while real traversal
entries remain rejected.
- createWindowsTraversalStandaloneArchive runs PowerShell via -File
instead of a single -Command line; the joined-with-'; ' form had a
function definition the runner's PowerShell refused to parse.
Drive-by review followups:
- replaceRequired uses replaceAll so a future duplicate placeholder
cannot silently keep the trailing copy as 'latest'.
- :ValidateOptions runs the unsafe-character check on SOURCE
alongside the other variables.
- build-installation-assets.js drops a dead INSTALLATION_ASSETS
re-export; consumers already import from release-asset-config.js.
- .gitignore covers the new sibling .qwen-dist-backup-* directory.
- sh: reject CR/LF in archive entry names before the literal `..` glob so
a `..\r` entry cannot bypass path validation.
- bat: prefer Tls12+Tls13 in PowerShell helpers, fall back to Tls12 alone
on older .NET Framework where the Tls13 enum is missing.
- bat: document the implicit `:ValidateOptions` dependency next to the
qwen.cmd wrapper writer so loosening the validator stays a conscious
choice.
- build-standalone-release: surface the `xz-utils` host requirement for
Linux Node downloads in `--help`.
- release-script-utils: support `--key=value` form in `parseCliArgs`.
- tests: cover the new CRLF message, TLS string, and `--key=value` parsing;
register process-level signal/exit handlers in `ensureMinimalDist` so a
crashed test still restores `dist/`.