sdkvm 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 jvm contributors
3
+ Copyright (c) 2026 sdkvm contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.en.md ADDED
@@ -0,0 +1,599 @@
1
+ <div align="center">
2
+
3
+ # sdkvm
4
+
5
+ **A simple, cross-platform version manager for language SDKs**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/sdkvm)](https://www.npmjs.com/package/sdkvm)
8
+ [![CI](https://github.com/QInJ1995/sdkvm/actions/workflows/ci.yml/badge.svg)](https://github.com/QInJ1995/sdkvm/actions/workflows/ci.yml)
9
+ [![license](https://img.shields.io/npm/l/sdkvm)](./LICENSE)
10
+ [![node](https://img.shields.io/badge/node-%3E%3D18.15-green)](./package.json)
11
+ [![platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-blue)](#requirements)
12
+
13
+ [中文](./README.md) | English
14
+
15
+ Manage **Java JDKs**, the **Go toolchain**, the **Flutter SDK**, and the **Node.js runtime**.
16
+
17
+ </div>
18
+
19
+ ## Contents
20
+
21
+ - [Overview](#overview)
22
+ - [Requirements](#requirements)
23
+ - [Install](#install)
24
+ - [Upgrade](#upgrade)
25
+ - [Quick start](#quick-start)
26
+ - [Commands](#commands)
27
+ - [Version syntax](#version-syntax)
28
+ - [How it works](#how-it-works)
29
+ - [Configuration](#configuration)
30
+ - [Mirrors and npm registry](#mirrors-and-npm-registry)
31
+ - [Security](#security)
32
+ - [FAQ](#faq)
33
+ - [Uninstall](#uninstall)
34
+ - [Development](#development)
35
+ - [License](#license)
36
+
37
+ ## Overview
38
+
39
+ `sdkvm` is a Node.js CLI that installs, switches, and removes SDKs.
40
+
41
+ | SDK | Source | Notes |
42
+ |---|---|---|
43
+ | Java | [Temurin](https://adoptium.net/), [Zulu](https://www.azul.com/downloads/), [Corretto](https://aws.amazon.com/corretto/) | `lts` is currently 8 / 11 / 17 / 21 / 25 |
44
+ | Go | [go.dev](https://go.dev/dl/) | All historical stable releases |
45
+ | Flutter | Official release manifest | stable / beta; both macOS architectures; Linux / Windows are x64 only |
46
+ | Node.js | [nodejs.org/dist](https://nodejs.org/dist) | `lts` (currently 24 Krypton) / `latest` / major line; npm switches with the runtime |
47
+
48
+ Behavior:
49
+
50
+ - Each SDK lives in its own directory. `JAVA_HOME`, `GO_HOME`, `FLUTTER_HOME`, and `NODE_HOME` do not overwrite each other.
51
+ - `use` updates one symlink (a junction on Windows). Installed trees are not moved.
52
+ - Download URLs come from official APIs. Go, Flutter, and Node.js require a SHA-256 match. Java vendors are verified when a checksum is available.
53
+ - Temurin, Go, Flutter, and Node.js accept a mirror. Checksums still come from the official manifest.
54
+ - Adding a language means implementing one vendor module. See [Development](#development).
55
+
56
+ ## Requirements
57
+
58
+ | Dependency | Version | Notes |
59
+ |---|---|---|
60
+ | Node.js | >= 18.15 | Required for an npm install. The install script ships an isolated runtime |
61
+ | OS | — | macOS (Apple Silicon / Intel), mainstream Linux, Windows 10+ |
62
+ | Extractor | built in | `tar` on macOS / Linux. Windows uses bsdtar, then PowerShell `Expand-Archive` |
63
+
64
+ Platform limits:
65
+
66
+ - Extracting Flutter (`.tar.xz`) on Linux needs `xz` (`xz-utils`). Mainstream distributions include it.
67
+ - Official Flutter archives for Linux and Windows are x64 only. ARM Linux and ARM Windows cannot install Flutter. Both macOS architectures are supported.
68
+ - The first `flutter` run builds an internal cache. That wait is expected.
69
+
70
+ ## Install
71
+
72
+ ### npm, pnpm, yarn, bun
73
+
74
+ The machine needs Node.js >= 18.15. All four commands install from the npm registry:
75
+
76
+ ```sh
77
+ npm install -g sdkvm
78
+ pnpm add -g sdkvm
79
+ yarn global add sdkvm
80
+ bun add -g sdkvm
81
+ ```
82
+
83
+ The CLI then runs on whatever `node` is first on `PATH`. Switching to a Node older than 18.15 stops the CLI until you switch back.
84
+
85
+ ### Install script
86
+
87
+ No preinstalled Node.js is required. A GitHub Release that already contains `sdkvm.tgz` and `SHA256SUMS` is required (uploaded by CI after a `v*` tag).
88
+
89
+ macOS / Linux:
90
+
91
+ ```sh
92
+ curl -fsSL https://raw.githubusercontent.com/QInJ1995/sdkvm/main/install.sh | sh
93
+ ```
94
+
95
+ Windows (PowerShell):
96
+
97
+ ```powershell
98
+ irm https://raw.githubusercontent.com/QInJ1995/sdkvm/main/install.ps1 | iex
99
+ ```
100
+
101
+ The script:
102
+
103
+ 1. Downloads Node.js 22.20.0 into `~/.sdkvm/runtime`. That copy only launches the CLI. `sdkvm node use` does not change it.
104
+ 2. Downloads `sdkvm.tgz` from the GitHub Release, checks SHA-256, and extracts it to `~/.sdkvm/cli`.
105
+ 3. Writes `~/.local/bin/sdkvm` (on Windows, `%USERPROFILE%\.local\bin\sdkvm.cmd`). If that directory is not on `PATH`, the script prints the line to add.
106
+
107
+ The data root matches the CLI: `SDKVM_HOME` overrides it, otherwise `~/.sdkvm`. Both the runtime and the CLI live under that root. Override download prefixes when needed:
108
+
109
+ ```sh
110
+ SDKVM_NODE_DIST=https://npmmirror.com/mirrors/node \
111
+ SDKVM_RELEASE_BASE=https://github.com/QInJ1995/sdkvm/releases \
112
+ sh install.sh
113
+ ```
114
+
115
+ Check:
116
+
117
+ ```console
118
+ $ sdkvm version
119
+ 1.0.1
120
+ ```
121
+
122
+ ## Upgrade
123
+
124
+ | Install method | Command | What changes |
125
+ |---|---|---|
126
+ | npm | `npm update -g sdkvm` | CLI only. pnpm / yarn / bun use their own global update command |
127
+ | script | `sdkvm upgrade` | Replaces `~/.sdkvm/cli` only. The runtime and installed SDKs stay |
128
+
129
+ `~/.sdkvm` data is independent of a CLI upgrade. A script install can also be refreshed by running the install script again.
130
+
131
+ ## Quick start
132
+
133
+ Java accepts bare commands (same as `sdkvm java`). Go, Flutter, and Node use subcommands.
134
+
135
+ ```sh
136
+ # Optional: faster downloads in China (scoped per SDK type)
137
+ sdkvm mirror use nju # Java Temurin
138
+ sdkvm go mirror use nju
139
+ sdkvm flutter mirror use nju
140
+ sdkvm node mirror use nju
141
+ sdkvm nrm use taobao # npm install only; independent of mirror above
142
+
143
+ # Java
144
+ sdkvm install lts
145
+ sdkvm use 25
146
+ java -version
147
+
148
+ # Go
149
+ sdkvm go install 1.24
150
+ sdkvm go use 1.24
151
+ go version
152
+
153
+ # Flutter (stable)
154
+ sdkvm flutter install 3.47
155
+ sdkvm flutter use 3.47
156
+ flutter --version
157
+
158
+ # Node.js (npm switches with this runtime)
159
+ sdkvm node install lts
160
+ sdkvm node use 24
161
+ node --version
162
+
163
+ # Inspect and remove
164
+ sdkvm current
165
+ sdkvm java install 21 --vendor zulu
166
+ sdkvm java use zulu-21
167
+ sdkvm ls
168
+ sdkvm go ls
169
+ sdkvm uninstall zulu-21
170
+ ```
171
+
172
+ After the first `use`, **open a new terminal**, or on macOS / Linux run `source ~/.zshrc` (or the matching bash rc). Restart the IDE so it picks up the new environment variables.
173
+
174
+ Day-to-day: `install` → `use` → `current` / `ls`. Mirrors and npm registries: [Mirrors and npm registry](#mirrors-and-npm-registry).
175
+
176
+ ## Commands
177
+
178
+ Java accepts bare commands (`sdkvm install`) or `sdkvm java`. Go, Flutter, and Node.js use `sdkvm go`, `sdkvm flutter`, and `sdkvm node`.
179
+
180
+ ### Cheat sheet
181
+
182
+ | Command | Effect |
183
+ |---|---|
184
+ | `sdkvm install <version>` | Install Java (same as `sdkvm java install`) |
185
+ | `sdkvm use <version>` | Switch the current Java |
186
+ | `sdkvm ls` / `sdkvm ls -r` | List installed versions / installable lines |
187
+ | `sdkvm current` | Show the current version of every SDK |
188
+ | `sdkvm uninstall <version>` | Remove one version |
189
+ | `sdkvm mirror ls\|use\|current\|show\|set\|unset` | Manage SDK download mirror sites / URLs (install archives, not the npm package registry) |
190
+ | `sdkvm nrm ls\|use\|current\|add\|del\|test` | Manage the user-level npm registry (like nrm) |
191
+ | `sdkvm java\|go\|flutter\|node …` | Full command group for that SDK |
192
+ | `sdkvm version` | Print the CLI version (same as `sdkvm --version`) |
193
+ | `sdkvm upgrade` | Upgrade the CLI. See [Upgrade](#upgrade) |
194
+
195
+ Version forms:
196
+
197
+ ```sh
198
+ sdkvm java install lts | 21 | 21.0.5 | 21.0.5+11 | zulu-21
199
+ sdkvm go install latest | 1.24 | 1.24.5 | golang-1.24
200
+ sdkvm flutter install latest | 3.47 | 3.47.5 | 3.49.0-0.1.pre | flutter-3.47
201
+ sdkvm node install lts | latest | 22 | 22.20.0 | nodejs-22.20.0
202
+ ```
203
+
204
+ ### `sdkvm install <version>`
205
+
206
+ Resolve, download (SHA-256 is hashed while bytes arrive), verify, extract into a temp directory, then move into place.
207
+
208
+ ```console
209
+ $ sdkvm install 21
210
+ sdkvm resolving Adoptium Temurin 21 for mac/aarch64 ...
211
+ sdkvm downloading https://github.com/adoptium/temurin21-binaries/releases/...
212
+ ↓ Temurin 21.0.12.1 160.2MB / 200.4MB
213
+ sdkvm installed Temurin 21.0.12.1 → ~/.sdkvm/jdks/temurin-21.0.12.1
214
+ sdkvm switch to it: sdkvm use 21
215
+ ```
216
+
217
+ | Option | Meaning |
218
+ |---|---|
219
+ | `--vendor <id>` | Java: `temurin` (default) / `zulu` / `corretto`. Go is `golang`, Flutter is `flutter`, Node.js is `nodejs` |
220
+ | `--force` | Delete and reinstall. The default is to skip a version that is already present |
221
+
222
+ A failed checksum or extract removes the partial directory and the cache. The download timer is 60 seconds without data, not a cap on total time.
223
+
224
+ ### `sdkvm use <version>`
225
+
226
+ Match an installed version, then update the `current-*` link and `JAVA_HOME` / `GO_HOME` / `FLUTTER_HOME` / `NODE_HOME` / `PATH`.
227
+
228
+ ```sh
229
+ sdkvm use 21
230
+ sdkvm use temurin-21.0.5+11
231
+ sdkvm go use 1.24.5
232
+ sdkvm flutter use 3.47.5
233
+ sdkvm node use 22.20.0
234
+ ```
235
+
236
+ On macOS / Linux the first `use` appends an init block to the shell rc. Open a new terminal or `source ~/.zshrc`. Later switches only move the link. IDEs need a restart before they see the new variables. See [Switching](#switching).
237
+
238
+ ### `sdkvm ls`
239
+
240
+ Installed versions. `→` marks the current one.
241
+
242
+ ```console
243
+ $ sdkvm go ls
244
+ → golang-1.24.5
245
+ golang-1.23.9
246
+ ```
247
+
248
+ `sdkvm ls -r` (`--remote`) fetches installable lines from every vendor of that SDK in parallel. The name at the start of a row can be passed to `install`. The default list is the latest 12 lines. Older versions are installed by exact name.
249
+
250
+ ```console
251
+ $ sdkvm flutter ls -r
252
+
253
+ # Flutter (official)
254
+ flutter-3.47 latest: flutter-3.47.5
255
+ flutter-3.44 latest: flutter-3.44.9
256
+
257
+ # install with: sdkvm flutter install <name>
258
+ ```
259
+
260
+ `--vendor <id>` limits the list to one vendor.
261
+
262
+ ### `sdkvm current`
263
+
264
+ SDKs that are not installed are omitted.
265
+
266
+ ```console
267
+ $ sdkvm current
268
+ java: temurin-21.0.12.1
269
+ JAVA_HOME → ~/.sdkvm/jdks/temurin-21.0.12.1
270
+ go: golang-1.24.5
271
+ GO_HOME → ~/.sdkvm/gos/golang-1.24.5
272
+ flutter: flutter-3.47.5
273
+ FLUTTER_HOME → ~/.sdkvm/flutters/flutter-3.47.5
274
+ node: nodejs-22.20.0
275
+ NODE_HOME → ~/.sdkvm/nodes/nodejs-22.20.0
276
+ ```
277
+
278
+ ### `sdkvm uninstall <version>`
279
+
280
+ Same syntax as `use`. Uninstalling the current version clears that `current-*` link and asks you to pick another. Other installed versions stay.
281
+
282
+ ### `sdkvm mirror`
283
+
284
+ Manages **install-archive mirrors** per SDK type (not the npm package registry). Java: `sdkvm mirror`. Others: `sdkvm go|flutter|node mirror`. Scopes do not overlap.
285
+
286
+ ```sh
287
+ sdkvm mirror ls
288
+ sdkvm mirror use nju
289
+ sdkvm go mirror use aliyun
290
+ sdkvm node mirror use official # restore official source for that type
291
+ ```
292
+
293
+ | Action | Meaning |
294
+ |---|---|
295
+ | `ls` / `current` / `show` | List sites and show the current config for this type |
296
+ | `use <site>` | Switch to a built-in site (`nju` / `tuna` / `aliyun` / `huawei` / `official`) |
297
+ | `set [vendor] <url>` / `unset` | Set or clear a raw URL |
298
+
299
+ Coverage and hand-entered URLs: [Mirrors and npm registry](#mirrors-and-npm-registry).
300
+
301
+ ### `sdkvm nrm`
302
+
303
+ Manages the user-level **npm registry** (where `npm install` fetches packages). The UX follows [nrm](https://github.com/Pana/nrm). Independent of `mirror`.
304
+
305
+ ```sh
306
+ sdkvm nrm ls
307
+ sdkvm nrm use taobao
308
+ sdkvm nrm use npm
309
+ sdkvm nrm add myprivate http://xxx/registry
310
+ sdkvm nrm del myprivate
311
+ sdkvm nrm test
312
+ ```
313
+
314
+ Built-in names: `npm`, `yarn`, `taobao` (alias `npmmirror`), `tencent`, `cnpm`, `huawei`, `npmMirror`. `npm` must be on `PATH`.
315
+
316
+ ## Version syntax
317
+
318
+ `install`, `use`, and `uninstall` share this table. Combinations that are not listed are rejected with a rewrite hint.
319
+
320
+ | Form | Java | Go | Flutter | Node.js | Example |
321
+ |---|---|---|---|---|---|
322
+ | `<major>` | Latest patch of that major | — | — | Latest of that major | `21`, `22` |
323
+ | `<major.minor>` | — | Latest patch of that minor line | Latest stable patch of that minor line | — | `1.24`, `3.47` |
324
+ | `lts` | Latest LTS major | — | — | Latest LTS line (currently 24 Krypton) | `lts` |
325
+ | `latest` | — | Newest stable | Newest stable, not beta | Newest Current | `latest` |
326
+ | `<full-version>` | Exact or prefix | Exact | Exact, including a prerelease | Exact | `21.0.5+11`, `1.24.5`, `3.49.0-0.1.pre`, `22.20.0` |
327
+ | `<vendor>-…` | Pin a distribution | Same | Same | Same | `zulu-21`, `golang-1.24`, `nodejs-22.20.0` |
328
+
329
+ Rules:
330
+
331
+ - `21`, `1.24`, `3.47`, and `22` select the newest installed or installable patch on that line.
332
+ - Java `21.0.5` is a prefix and can match `21.0.5+11`. Go, Flutter, and Node.js exact versions match the full string.
333
+ - Flutter `latest` and `3.47` resolve on stable only. A beta needs the full prerelease, for example `3.49.0-0.1.pre`.
334
+ - Java `lts` follows the Adoptium list: 8 / 11 / 17 / 21 / 25. Node.js `lts` is the newest `index.json` entry that carries an LTS codename.
335
+ - Node.js rejects a two-part version such as `22.20`. Use `22` or `22.20.0`.
336
+ - Omitting the vendor uses the default distribution. Only Java's default is configurable. See [Config file](#config-file).
337
+
338
+ ## How it works
339
+
340
+ ### Layout
341
+
342
+ The data root is `~/.sdkvm` (`%USERPROFILE%\.sdkvm` on Windows). `SDKVM_HOME` overrides it.
343
+
344
+ ```
345
+ ~/.sdkvm/
346
+ ├── jdks/ # Java: temurin-21.0.12.1
347
+ ├── gos/ # Go: golang-1.24.5
348
+ ├── flutters/ # Flutter: flutter-3.47.5
349
+ ├── nodes/ # Node.js: nodejs-22.20.0
350
+ ├── current-java # JAVA_HOME link (junction on Windows)
351
+ ├── current-go
352
+ ├── current-flutter
353
+ ├── current-node
354
+ ├── runtime/ # Script-install Node, isolated from current-node
355
+ ├── cli/ # Script-install CLI package
356
+ ├── config.json
357
+ ├── cache/ # Download staging, removed after a successful install
358
+ └── tmp/ # Extract staging, also removed
359
+ ```
360
+
361
+ Unpacked size, roughly: Java 300 MB, Go 250 MB, Node.js 100 MB (bundled npm included), Flutter several GB (the archive itself is about 1–2.2 GB).
362
+
363
+ ### Switching
364
+
365
+ On macOS / Linux, each `current-*` entry is a symlink to the selected version. The first `use` appends a marked block: zsh writes `~/.zshrc`, bash writes `~/.bash_profile` or `~/.bashrc`. Each SDK has its own block.
366
+
367
+ ```sh
368
+ # >>> sdkvm java init >>>
369
+ export JAVA_HOME="$HOME/.sdkvm/current-java"
370
+ case ":$PATH:" in *":$JAVA_HOME/bin:"*) ;; *) export PATH="$JAVA_HOME/bin:$PATH";; esac
371
+ # <<< sdkvm java init <<<
372
+
373
+ # >>> sdkvm go init >>>
374
+ export GO_HOME="$HOME/.sdkvm/current-go"
375
+ case ":$PATH:" in *":$GO_HOME/bin:"*) ;; *) export PATH="$GO_HOME/bin:$PATH";; esac
376
+ # <<< sdkvm go init <<<
377
+
378
+ # >>> sdkvm flutter init >>>
379
+ export FLUTTER_HOME="$HOME/.sdkvm/current-flutter"
380
+ case ":$PATH:" in *":$FLUTTER_HOME/bin:"*) ;; *) export PATH="$FLUTTER_HOME/bin:$PATH";; esac
381
+ # <<< sdkvm flutter init <<<
382
+
383
+ # >>> sdkvm node init >>>
384
+ export NODE_HOME="$HOME/.sdkvm/current-node"
385
+ case ":$PATH:" in *":$NODE_HOME/bin:"*) ;; *) export PATH="$NODE_HOME/bin:$PATH";; esac
386
+ # <<< sdkvm node init <<<
387
+ ```
388
+
389
+ The variables point at the link. Later `use` calls only retarget that link, and a new terminal reads the new value.
390
+
391
+ On Windows the four `current-*` entries are junctions. `use` writes user environment variables as `REG_EXPAND_SZ` and keeps `%VAR%` references, which avoids the 1024-character `setx` truncation. PATH gains `%JAVA_HOME%\bin`, `%GO_HOME%\bin`, and `%FLUTTER_HOME%\bin`. The Windows Node.js archive has no `bin/` directory, so its PATH entry is `%NODE_HOME%` itself. Open a new terminal or restart the IDE.
392
+
393
+ ## Configuration
394
+
395
+ ### Config file
396
+
397
+ Path: `~/.sdkvm/config.json`. A corrupt file is renamed to `config.json.bak` and replaced with defaults.
398
+
399
+ ```json
400
+ {
401
+ "version": 1,
402
+ "defaultVendor": "temurin",
403
+ "mirror": {
404
+ "temurin": "https://mirrors.nju.edu.cn/adoptium",
405
+ "golang": "https://golang.google.cn/dl",
406
+ "flutter": "https://mirror.nju.edu.cn/flutter/flutter_infra_release",
407
+ "nodejs": "https://mirror.nju.edu.cn/nodejs-release"
408
+ },
409
+ "npmRegistries": {
410
+ "myprivate": "http://xxx/registry/"
411
+ }
412
+ }
413
+ ```
414
+
415
+ | Field | Meaning | Default |
416
+ |---|---|---|
417
+ | `version` | Schema version | `1` |
418
+ | `defaultVendor` | Java distribution used when the vendor prefix is omitted | `"temurin"` |
419
+ | `mirror` | Vendor id to mirror root URL. Ids are unique across SDKs | `{}` |
420
+ | `npmRegistries` | Custom npm registries from `sdkvm nrm add` | `{}` |
421
+
422
+ ### Environment variables
423
+
424
+ | Variable | Meaning |
425
+ |---|---|
426
+ | `SDKVM_HOME` | Data root. Default `~/.sdkvm` |
427
+ | `SDKVM_MIRROR` | One-shot mirror. Wins over the config file and is not saved |
428
+ | `SDKVM_QUIET` | Non-empty suppresses info and warn logs |
429
+ | `SDKVM_NODE_DIST` | Node distribution root used by the install script |
430
+ | `SDKVM_RELEASE_BASE` | GitHub Release root used by the install script and `sdkvm upgrade` |
431
+ | `SDKVM_RUNTIME_NODE` | Node version bundled by the install script. Default `22.20.0` |
432
+
433
+ Mirror precedence: `SDKVM_MIRROR` > `config.mirror[<vendor>]` > official source. See [Mirrors and npm registry](#mirrors-and-npm-registry).
434
+
435
+ ## Mirrors and npm registry
436
+
437
+ Two independent features:
438
+
439
+ | | `sdkvm mirror` | `sdkvm nrm` |
440
+ |---|---|---|
441
+ | Changes | JDK / Go / Flutter / Node **install archive** URLs | **npm package** registry |
442
+ | Affects | `sdkvm … install` | `npm install` |
443
+ | Scope | Per SDK type | User-level global |
444
+
445
+ ### SDK install mirrors
446
+
447
+ Prefer a built-in site per type (`use` only writes vendors for the current type; aliases: `tsinghua`→`tuna`, `ali`→`aliyun`):
448
+
449
+ ```sh
450
+ sdkvm mirror use nju
451
+ sdkvm go mirror use nju
452
+ sdkvm flutter mirror use nju
453
+ sdkvm node mirror use nju
454
+ ```
455
+
456
+ | Site | Java (temurin) | Go | Flutter | Node.js |
457
+ |---|---|---|---|---|
458
+ | `nju` | ✓ | ✓ | ✓ | ✓ |
459
+ | `tuna` | ✓ | — | ✓ | — (incomplete archives; not listed) |
460
+ | `aliyun` | — | ✓ | — | ✓ |
461
+ | `huawei` | — | — | — | ✓ |
462
+ | `official` | Clear this type | Clear this type | Clear this type | Clear this type |
463
+
464
+ Raw URL or one-shot override:
465
+
466
+ ```sh
467
+ sdkvm go mirror set golang https://golang.google.cn/dl
468
+ SDKVM_MIRROR=https://golang.google.cn/dl sdkvm go install 1.24
469
+ ```
470
+
471
+ Precedence: `SDKVM_MIRROR` > `config.mirror[<vendor>]` > official. A mirror replaces the archive URL only; metadata and checksums still come from the official API. If a mirrored download cannot fetch the official checksum source, install **fails hard**.
472
+
473
+ | Vendor | Notes |
474
+ |---|---|
475
+ | Temurin | Adoptium layout; verified against [NJU](https://mirrors.nju.edu.cn/adoptium) and [TUNA](https://mirrors.tuna.tsinghua.edu.cn/Adoptium) |
476
+ | Go | File name appended to the root; e.g. `nju` / `aliyun` |
477
+ | Flutter | Bucket-prefix replacement; verified against [NJU](https://mirror.nju.edu.cn/flutter/flutter_infra_release). Do not use `storage.flutter-io.cn` |
478
+ | Node.js | Prefix replacement; verified against [NJU](https://mirror.nju.edu.cn/nodejs-release). Do not use TUNA nodejs-release |
479
+ | Zulu, Corretto | Official CDN only; no mirror support yet |
480
+
481
+ ### npm registry
482
+
483
+ ```sh
484
+ sdkvm nrm use taobao # common in China
485
+ sdkvm nrm use npm # official
486
+ sdkvm nrm test # latency
487
+ ```
488
+
489
+ ## Security
490
+
491
+ - URLs are resolved from official APIs: Adoptium, Azul Metadata, Corretto, go.dev/dl, Flutter releases, and nodejs.org/dist `index.json`. Search pages are not scraped.
492
+ - Archives are hashed with SHA-256 as they download. Go, Flutter, and Node.js (official `SHASUMS256.txt`) abort on mismatch. If a Java checksum source is unreachable: official downloads warn and continue; **mirrored downloads fail hard** so an unverifiable mirror package is never accepted.
493
+ - After extract, the tree must have a single root and the expected executable. Extraction always targets a fresh empty directory.
494
+ - Install and `sdkvm upgrade` hold `~/.sdkvm/.lock` so concurrent writers do not overwrite each other.
495
+
496
+ ## FAQ
497
+
498
+ ### The command is still the old version after `use`
499
+
500
+ The rc block applies in a new terminal, or after `source ~/.zshrc`. Restart the IDE. `sdkvm current` shows whether the link already moved. On Windows the registry is updated, but an open terminal keeps the old values.
501
+
502
+ ### `GOROOT` / `FLUTTER_ROOT` were renamed
503
+
504
+ They are now `GO_HOME` and `FLUTTER_HOME` (aligned with `JAVA_HOME` / `NODE_HOME`). After upgrading the CLI, run `use` again for each enabled SDK, and remove leftover old variable names from the user environment (Windows registry / hand-edited rc lines).
505
+
506
+ ### fish or nushell
507
+
508
+ Automatic rc writes support zsh and bash. Translate the blocks in [Switching](#switching). fish example:
509
+
510
+ ```fish
511
+ set -gx JAVA_HOME $HOME/.sdkvm/current-java
512
+ set -gx GO_HOME $HOME/.sdkvm/current-go
513
+ set -gx FLUTTER_HOME $HOME/.sdkvm/current-flutter
514
+ set -gx NODE_HOME $HOME/.sdkvm/current-node
515
+ fish_add_path $JAVA_HOME/bin $GO_HOME/bin $FLUTTER_HOME/bin $NODE_HOME/bin
516
+ ```
517
+
518
+ ### Flutter downloads are slow or they stop
519
+
520
+ Run `sdkvm flutter mirror use nju` (or `tuna`) first. The timeout is 60 seconds with no data, so a steady slow transfer continues. Re-run `install` after a real interruption. Nothing partial is left behind.
521
+
522
+ ### Install a Flutter beta
523
+
524
+ Pass the full prerelease, for example `sdkvm flutter install 3.49.0-0.1.pre`. `latest` and `3.47` resolve on stable only.
525
+
526
+ ### Does a managed Node break sdkvm itself?
527
+
528
+ A script install launches the CLI with `~/.sdkvm/runtime`, so `sdkvm node use` does not affect it. An npm global install follows the `node` on `PATH`. A Node older than 18.15 can stop the CLI; `sdkvm node use 22` brings it back.
529
+
530
+ ### What is the difference between `nrm` and `mirror`?
531
+
532
+ See [Mirrors and npm registry](#mirrors-and-npm-registry): `nrm` is for npm packages; `mirror` is for SDK install archives.
533
+
534
+ ### Proxies
535
+
536
+ `HTTPS_PROXY` is not read. A transparent system proxy works.
537
+
538
+ ### Isolate data for CI or multiple users
539
+
540
+ Set `SDKVM_HOME=/path/to/dir`. Installs, links, and config all follow that directory.
541
+
542
+ ## Uninstall
543
+
544
+ npm install:
545
+
546
+ ```sh
547
+ npm uninstall -g sdkvm
548
+ ```
549
+
550
+ pnpm, yarn, and bun use their own global uninstall command.
551
+
552
+ A script install removes the shim and the CLI runtime. Installed SDKs stay:
553
+
554
+ ```sh
555
+ rm -f ~/.local/bin/sdkvm
556
+ rm -rf ~/.sdkvm/cli ~/.sdkvm/runtime
557
+ ```
558
+
559
+ On Windows, delete `%USERPROFILE%\.local\bin\sdkvm.cmd`, plus `%USERPROFILE%\.sdkvm\cli` and `%USERPROFILE%\.sdkvm\runtime`.
560
+
561
+ After you no longer need the installed JDKs, Go, Flutter, and Node.js, remove the data directory:
562
+
563
+ ```sh
564
+ rm -rf ~/.sdkvm
565
+ ```
566
+
567
+ Also delete the shell blocks between `>>> sdkvm java init >>>`, `>>> sdkvm go init >>>`, `>>> sdkvm flutter init >>>`, `>>> sdkvm node init >>>` and their matching `<<< … <<<` markers.
568
+
569
+ On Windows, remove `JAVA_HOME`, `GO_HOME`, `FLUTTER_HOME`, and `NODE_HOME` from the user environment, and remove `%JAVA_HOME%\bin`, `%GO_HOME%\bin`, `%FLUTTER_HOME%\bin`, and `%NODE_HOME%` from the user PATH.
570
+
571
+ ## Development
572
+
573
+ ```sh
574
+ git clone https://github.com/QInJ1995/sdkvm.git && cd sdkvm
575
+ npm install
576
+ npm test
577
+ npm run typecheck
578
+ npm run build
579
+ ```
580
+
581
+ `npm run build` runs tsup and writes `dist/index.js`. Try it with `node dist/index.js`.
582
+
583
+ ```
584
+ src/
585
+ ├── cli/ # install / use / ls / uninstall / mirror / nrm / upgrade
586
+ ├── core/ # version parsing, registry, config, file lock
587
+ ├── sdk/ # java / go / flutter / node: directories, env vars, version syntax
588
+ ├── vendor/ # temurin / zulu / corretto / golang / flutter / nodejs, plus mirror rewrite
589
+ ├── fs/ # extract, layout normalize, links
590
+ ├── shell/ # rc writes, Windows registry
591
+ ├── net/ # fetch, streaming download, checksums
592
+ └── ui/ # logs and progress
593
+ ```
594
+
595
+ To add a language, implement `listMajors` and `resolve` under `src/vendor/`, add a type descriptor under `src/sdk/` (install directory, current link, environment variable, version syntax, binary path), and register it in `sdk/index.ts`. The install / use / ls / uninstall / mirror commands, plus rc and registry writes, follow from that registration.
596
+
597
+ ## License
598
+
599
+ [MIT](./LICENSE) © QINJIN