feat(distro): add Alibaba Cloud Linux (alinux) icon and detection

Alibaba Cloud Linux hosts (os-release ID="alinux") previously showed the
generic Linux icon because normalizeDistroId fell through to the catch-all
`linux` branch ('alinux'.includes('linux') is true).

- Add a dedicated `alinux` branch in normalizeDistroId, matching the
  os-release ID, the legacy `aliyun` ID, and the NAME/PRETTY_NAME text
  "Alibaba Cloud Linux"; place it before the generic linux fallback.
- Register `alinux` in LINUX_DISTRO_OPTIONS so it is selectable in the
  manual distro override and classified as linux-like.
- Add the brand SVG (public/distro/alinux.svg) plus logo/color mappings
  in DistroAvatar (brand color #FF6A00).
- Add the localized label in en / ru / zh-CN.
- Cover normalizeDistroId's alinux cases (ID, legacy aliyun, PRETTY_NAME)
  with unit tests, including a regression guard against the generic linux
  fallback.

Icon source: simple-icons "Alibaba Cloud" mark (CC0-1.0, public domain),
matching the existing distro icon set already sourced from simple-icons.

Closes #1200

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
bincxz
2026-06-03 10:24:44 +08:00
parent b7093f88b1
commit 66cf610cc0
7 changed files with 37 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import assert from "node:assert/strict";
import type { Host } from "./models.ts";
import {
detectVendorFromSshVersion,
normalizeDistroId,
normalizePrimaryTelnetState,
resolveHostKeepalive,
resolveTelnetPort,
@@ -170,6 +171,29 @@ test("detectVendorFromSshVersion recognizes Ruijie RGOS banner", () => {
assert.equal(detectVendorFromSshVersion("SSH-2.0-RGOS_SSH"), "ruijie");
});
test("normalizeDistroId maps Alibaba Cloud Linux os-release ID to alinux", () => {
// /etc/os-release ID="alinux" — the canonical signal from Alibaba Cloud
// Linux 3 (issue #1200). Regression guard: 'alinux'.includes('linux') is
// true, so without a dedicated branch this would fall through to the
// generic 'linux' icon (the bug the issue reports).
assert.equal(normalizeDistroId("alinux"), "alinux");
assert.notEqual(normalizeDistroId("alinux"), "linux");
});
test("normalizeDistroId maps legacy Aliyun Linux IDs to alinux", () => {
// Older releases branded the distro as "Aliyun Linux" with ID=aliyun.
assert.equal(normalizeDistroId("aliyun"), "alinux");
});
test("normalizeDistroId matches Alibaba Cloud Linux PRETTY_NAME/NAME fallback", () => {
// When ID is absent the detector falls back to NAME / PRETTY_NAME text.
assert.equal(normalizeDistroId("Alibaba Cloud Linux"), "alinux");
assert.equal(
normalizeDistroId("Alibaba Cloud Linux 3.2104 U13.1 (OpenAnolis Edition)"),
"alinux",
);
});
test("shouldProbeSessionCwd allows the probe on a plain Linux host", () => {
assert.equal(
shouldProbeSessionCwd({ isNetworkDevice: false, remoteSshVersion: "OpenSSH_9.6" }),

View File

@@ -16,6 +16,7 @@ export const LINUX_DISTRO_OPTIONS = [
'almalinux',
'oracle',
'kali',
'alinux',
] as const;
/**
@@ -55,6 +56,12 @@ export const normalizeDistroId = (value?: string) => {
if (v.includes('almalinux')) return 'almalinux';
if (v.includes('oracle')) return 'oracle';
if (v.includes('kali')) return 'kali';
// Alibaba Cloud Linux: os-release ID is `alinux` (older branding: Aliyun
// Linux / `aliyun`). Must come before the generic `linux` fallback because
// 'alinux'.includes('linux') is true and would otherwise resolve to 'linux'.
if (v.includes('alinux') || v.includes('aliyun') || v.includes('alibaba cloud')) {
return 'alinux';
}
// Network device vendor IDs may arrive here after detection — preserve them.
if ((NETWORK_DEVICE_OPTIONS as readonly string[]).includes(v)) return v;
if (v === 'linux' || v.includes('linux')) return 'linux';