Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

201 lines
6.1 KiB
Go

package managednpm
import (
"context"
"net/url"
"sort"
"strings"
"time"
)
const (
RegistryOverrideEnv = "TUTTI_AGENT_NPM_REGISTRY"
OfficialRegistryURL = "https://registry.npmjs.org"
HuaweiRegistryURL = "https://repo.huaweicloud.com/repository/npm/"
TencentRegistryURL = "https://mirrors.cloud.tencent.com/npm/"
// Registry probes can perform two cold npm metadata requests (the root
// package and its platform package) inside a newly started VM. Keep the
// candidates concurrent, but allow enough time for first DNS/TLS/cache use.
DefaultProbeTimeout = 20 * time.Second
MinimumRankDelta = 25 * time.Millisecond
)
type Registry struct {
ID string
URL string
Pinned bool
}
func ResolveOptionalPlatformPackage(packageName string, optionalDependencies map[string]string, platformOS string, platformArch string) (string, string, bool) {
packageName = strings.TrimSpace(packageName)
platformOS, platformArch, platformOK := NPMPlatform(platformOS, platformArch)
if packageName == "" || !platformOK {
return "", "", false
}
separator := strings.LastIndex(packageName, "/")
prefix, name := "", packageName
if separator >= 0 {
prefix, name = packageName[:separator+1], packageName[separator+1:]
}
dependencyName := prefix + name + "-" + platformOS + "-" + platformArch
spec := strings.TrimSpace(optionalDependencies[dependencyName])
if spec == "" {
return "", "", false
}
if !strings.HasPrefix(spec, "npm:") {
return dependencyName, spec, true
}
aliased := strings.TrimPrefix(spec, "npm:")
versionSeparator := strings.LastIndex(aliased, "@")
if versionSeparator <= 0 || versionSeparator == len(aliased)-1 {
return "", "", false
}
return aliased[:versionSeparator], aliased[versionSeparator+1:], true
}
// NPMPlatform maps Go target names to the operating-system and architecture
// suffixes used by npm platform packages. It also accepts already-canonical
// npm names so hosts do not need their own platform mapping tables.
func NPMPlatform(platformOS string, platformArch string) (string, string, bool) {
switch strings.TrimSpace(platformOS) {
case "linux":
platformOS = "linux"
case "darwin":
platformOS = "darwin"
case "windows", "win32":
platformOS = "win32"
default:
return "", "", false
}
switch strings.TrimSpace(platformArch) {
case "amd64", "x64":
platformArch = "x64"
case "arm64":
platformArch = "arm64"
default:
return "", "", false
}
return platformOS, platformArch, true
}
type RegistryProbeRequest struct {
Registry Registry
PackageName string
Version string
IncludeOptional bool
OperatingSystem string
Architecture string
}
type RegistryProbeResult struct {
Reachable bool
Complete bool
Duration time.Duration
}
type RegistryProber interface {
ProbeRegistry(context.Context, RegistryProbeRequest) RegistryProbeResult
}
type RankedRegistry struct {
Registry Registry
Probe RegistryProbeResult
}
func DefaultRegistries(override string) []Registry {
if value := strings.TrimSpace(override); value != "" {
return []Registry{{ID: "override", URL: value, Pinned: true}}
}
return []Registry{
{ID: "npm", URL: OfficialRegistryURL},
{ID: "huawei", URL: HuaweiRegistryURL},
{ID: "tencent", URL: TencentRegistryURL},
}
}
func RankRegistries(ctx context.Context, descriptor Descriptor, registries []Registry, platformOS string, platformArch string, prober RegistryProber) []RankedRegistry {
if len(registries) == 0 || prober == nil {
return nil
}
if ctx == nil {
ctx = context.Background()
}
type indexedResult struct {
index int
RankedRegistry
}
results := make(chan indexedResult, len(registries))
for index, registry := range registries {
go func(index int, registry Registry) {
probeCtx, cancel := context.WithTimeout(ctx, DefaultProbeTimeout)
defer cancel()
startedAt := time.Now()
probe := prober.ProbeRegistry(probeCtx, RegistryProbeRequest{
Registry: registry, PackageName: descriptor.PackageName,
Version: descriptor.RecommendedVersion, IncludeOptional: descriptor.IncludeOptional,
OperatingSystem: platformOS, Architecture: platformArch,
})
if probe.Duration <= 0 {
probe.Duration = time.Since(startedAt)
}
results <- indexedResult{index: index, RankedRegistry: RankedRegistry{Registry: registry, Probe: probe}}
}(index, registry)
}
probed := make([]indexedResult, 0, len(registries))
for range registries {
probed = append(probed, <-results)
}
fastestEligible := time.Duration(1<<63 - 1)
for _, candidate := range probed {
if candidate.Probe.Reachable && candidate.Probe.Complete && candidate.Probe.Duration < fastestEligible {
fastestEligible = candidate.Probe.Duration
}
}
sort.SliceStable(probed, func(i, j int) bool {
left, right := probed[i], probed[j]
leftEligible := left.Probe.Reachable && left.Probe.Complete
rightEligible := right.Probe.Reachable && right.Probe.Complete
if leftEligible != rightEligible {
return leftEligible
}
if leftEligible {
leftInFastBand := left.Probe.Duration <= fastestEligible+MinimumRankDelta
rightInFastBand := right.Probe.Duration <= fastestEligible+MinimumRankDelta
if leftInFastBand != rightInFastBand {
return leftInFastBand
}
if !leftInFastBand && left.Probe.Duration != right.Probe.Duration {
return left.Probe.Duration < right.Probe.Duration
}
}
return left.index < right.index
})
ranked := make([]RankedRegistry, len(probed))
for index := range probed {
ranked[index] = probed[index].RankedRegistry
}
return ranked
}
func PackageEndpoint(registryURL string, packageName string, version string) string {
registryURL = strings.TrimRight(strings.TrimSpace(registryURL), "/")
packageName = strings.TrimSpace(packageName)
if registryURL == "" || packageName == "" {
return registryURL
}
escapedPackage := strings.ReplaceAll(packageName, "/", "%2f")
endpoint := registryURL + "/" + escapedPackage
if value := strings.TrimSpace(version); value != "" {
endpoint += "/" + url.PathEscape(value)
}
return endpoint
}
func DisplayRegistryHost(registryURL string) string {
parsed, err := url.Parse(strings.TrimSpace(registryURL))
if err != nil || parsed.Hostname() == "" {
return "invalid-registry"
}
return parsed.Hostname()
}