upgrade

package
v1.0.64-beta.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

Documentation

Overview

Package upgrade provides self-update functionality for the DWS CLI using npm Registry by default and explicitly configured GitHub Releases.

Index

Constants

View Source
const (
	CheckStatusUpToDate        = "up_to_date"
	CheckStatusUpdateAvailable = "update_available"
	CheckStatusUnknown         = "unknown"
	CheckStatusSkipped         = "skipped"
)

Variables

View Source
var ErrSkillPathPublicationUncertain = errors.New("Skill 发布状态不确定")

ErrSkillPathPublicationUncertain marks a publication whose transactional outcome cannot be determined safely: this transaction did occupy the destination at some point, but a stronger witness — the fresh mkdir-claim identity captured by the child-move fallback — now indicates that the object currently at the destination may belong to a concurrent writer. Callers must not automatically retract, replace, or retry-copy over the destination; instead they should surface the state so the user or a higher layer can inspect it. Errors wrapping this sentinel are safe to test with errors.Is.

Functions

func BackupAndRemoveSkillDir added in v1.0.58

func BackupAndRemoveSkillDir(homeDir, dir string) (string, error)

BackupAndRemoveSkillDir is the exported wrapper over backupAndRemoveSkillDir for callers outside the upgrade package (the skill-setup channel in internal/app).

func BinaryName

func BinaryName() string

BinaryName returns the platform-specific binary name.

func CleanupStaleFiles

func CleanupStaleFiles()

CleanupStaleFiles removes leftover .old and .rollback-tmp files from previous upgrades (relevant on Windows where locked files cannot be deleted immediately).

func CompareVersions

func CompareVersions(a, b string) int

CompareVersions compares two semver strings (e.g. "1.0.5", "v1.0.6-beta"). Returns -1 if a < b, 0 if equal, 1 if a > b. Stable releases sort after prereleases with the same numeric version.

func ComputeSHA256

func ComputeSHA256(filePath string) (string, error)

ComputeSHA256 computes the SHA256 hash of a file.

func CurrentBinaryPath

func CurrentBinaryPath() (string, error)

CurrentBinaryPath returns the resolved path of the currently running binary.

func Download

func Download(url, destPath string) (int64, error)

Download fetches url to destPath with default config.

func DownloadCacheDir

func DownloadCacheDir() string

DownloadCacheDir returns the path for temporary downloads during upgrade.

func DownloadWithConfig

func DownloadWithConfig(ctx context.Context, url, destPath string, cfg *DownloadConfig) (int64, error)

DownloadWithConfig fetches a file with custom configuration and retries.

func DownloadWithProgress

func DownloadWithProgress(ctx context.Context, url, destPath string, showProgress func(percent float64, downloaded, total int64)) (int64, error)

DownloadWithProgress downloads a file and reports progress.

func EnsureUpgradeDirectories

func EnsureUpgradeDirectories() error

EnsureUpgradeDirectories creates the directories needed for upgrade operations.

func ExtractDigestSHA256

func ExtractDigestSHA256(digest string) string

ExtractDigestSHA256 extracts the hex hash from a GitHub asset digest field. GitHub format: "sha256:abcdef1234..."

func ExtractZip

func ExtractZip(zipPath, targetDir string) error

ExtractZip unzips zipPath contents into targetDir. Contains zip-slip protection against path traversal attacks.

func FindBinaryInDir

func FindBinaryInDir(dir string) string

FindBinaryInDir recursively finds the dws binary in an extracted directory.

func LocateSkillMD

func LocateSkillMD(extractDir string) string

LocateSkillMD finds the directory containing SKILL.md in an extracted zip. It handles both flat layouts (SKILL.md at root) and nested layouts (dws/SKILL.md).

func LocateSkillsRoot added in v1.0.58

func LocateSkillsRoot(extractDir string) string

LocateSkillsRoot resolves the skill root inside an extracted dws-skills.zip, preferring the multi bundle ({extractDir}/multi) over the legacy mono layouts handled by LocateSkillMD.

func NeedsUpgrade

func NeedsUpgrade(currentVersion, remoteVersion string) bool

NeedsUpgrade returns true when remoteVersion is newer than currentVersion.

func ParseChecksumFile

func ParseChecksumFile(content string) map[string]string

ParseChecksumFile parses a SHA256SUMS-style file. Each line: "hash filename" (two spaces or whitespace separated). Returns a map of filename -> lowercase hex hash.

func ReleaseSkillPathPublications added in v1.0.63

func ReleaseSkillPathPublications(publications []SkillPathPublication) error

ReleaseSkillPathPublications 在事务提交后释放身份句柄,不删除发布内容。 回滚入口也会释放;重复释放安全。Linux 句柄释放后不再授权回滚删除。

func ReplaceSelf

func ReplaceSelf(newBinaryPath string) error

ReplaceSelf atomically replaces the currently running binary with newBinaryPath.

On Unix (macOS / Linux):

  1. Try atomic os.Rename (same filesystem, instant swap)
  2. Fallback to copy if cross-device

On Windows the running .exe is locked by the OS, so direct overwrite fails. Strategy: rename running exe → .old, then rename/copy new binary in, then clean up .old (best-effort, may be cleaned on next run).

func RestoreSkillPath added in v1.0.59

func RestoreSkillPath(backup, original string) error

RestoreSkillPath restores a previously recorded backup using the same rename-first, verified cross-device fallback as backup publication.

func RollbackSkillPathPublications added in v1.0.59

func RollbackSkillPathPublications(publications []SkillPathPublication) (rollbackErr error)

RollbackSkillPathPublications removes only objects that can still be proven to have been published by this transaction. Each live path is first claimed into a private sibling quarantine. A concurrent replacement is restored when possible, otherwise retained in quarantine and reported explicitly.

func SwapUserHomeDirForTest added in v1.0.58

func SwapUserHomeDirForTest(t *testing.T, fn func() (string, error))

SwapUserHomeDirForTest swaps the home-dir seam used by UpgradeSkillLocations and related upgrade path helpers. Restored via t.Cleanup; not safe with t.Parallel.

func VerifyFileFromChecksums

func VerifyFileFromChecksums(filePath, filename, checksumsContent string) error

VerifyFileFromChecksums verifies a downloaded file against checksums.txt content.

func VerifySHA256

func VerifySHA256(filePath, expectedHash string) error

VerifySHA256 verifies a file against its expected SHA256 hash.

Types

type BackupInfo

type BackupInfo struct {
	Path       string    `json:"path"`
	BinaryPath string    `json:"binaryPath"`
	Version    string    `json:"version"`
	CreatedAt  time.Time `json:"createdAt"`
	Size       int64     `json:"size"`
}

BackupInfo contains information about a single backup.

type CheckOptions

type CheckOptions struct {
	CacheDir string
	Edition  string
	Track    ReleaseTrack
	ReadOnly bool
	Force    bool
}

CheckOptions 控制版本检查;空 CacheDir 禁用持久缓存,空 Track 按当前版本选择轨道。 ReadOnly 优先于 Force,只读取有效缓存,不发网络请求或写入文件。

type CheckResult

type CheckResult struct {
	Current   string       `json:"current"`
	Latest    string       `json:"latest,omitempty"`
	Status    string       `json:"status"`
	CheckedAt string       `json:"checked_at,omitempty"`
	Cached    bool         `json:"cached,omitempty"`
	Track     ReleaseTrack `json:"-"`
}

CheckResult 是检查事实,不改变业务命令的成功状态或退出码。 unknown 表示无法确认是否最新;Cached=true 表示使用了仍在有效期内的检查结果。

func CheckVersion

func CheckVersion(ctx context.Context, current string, opts CheckOptions) CheckResult

CheckVersion 在一秒网络预算内检查发行版本。检查与缓存错误均返回 unknown, 不输出诊断、不安装升级,也不把陈旧缓存当作当前发行状态。

func (CheckResult) UpgradeCommand

func (r CheckResult) UpgradeCommand() string

UpgradeCommand 返回与检查轨道一致的升级动作,本方法不会执行升级。

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client queries the selected release source.

func NewClient

func NewClient() *Client

NewClient 默认查询 npm;显式 GitHub 配置继续使用原有升级源。

func NewClientWithBaseURL

func NewClientWithBaseURL(baseURL string) *Client

NewClientWithBaseURL creates a client with a custom base URL (for testing).

func NewVersionClient

func NewVersionClient() *Client

NewVersionClient 选择版本元数据来源:默认 npm,显式 GitHub 配置优先。 独立入口允许只读版本检查先采用 Registry,而不改变尚未支持 npm 包的安装链路。

func (*Client) FetchAllReleases

func (c *Client) FetchAllReleases() ([]VersionEntry, error)

FetchAllReleases returns all non-draft releases, newest first.

func (*Client) FetchLatestPrerelease added in v1.0.48

func (c *Client) FetchLatestPrerelease() (*ReleaseInfo, error)

FetchLatestPrerelease returns the newest non-draft prerelease.

func (*Client) FetchLatestRelease

func (c *Client) FetchLatestRelease() (*ReleaseInfo, error)

FetchLatestRelease returns the latest non-draft release.

func (*Client) FetchLatestReleaseForTrack added in v1.0.48

func (c *Client) FetchLatestReleaseForTrack(track ReleaseTrack) (*ReleaseInfo, error)

FetchLatestReleaseForTrack returns the latest release in the requested track.

func (*Client) FetchLatestReleaseForTrackContext

func (c *Client) FetchLatestReleaseForTrackContext(ctx context.Context, track ReleaseTrack) (*ReleaseInfo, error)

FetchLatestReleaseForTrackContext 让自动检查与显式升级共用来源,并保留调用方预算。

func (*Client) FetchLatestStableRelease added in v1.0.48

func (c *Client) FetchLatestStableRelease() (*ReleaseInfo, error)

FetchLatestStableRelease returns the newest non-draft, non-prerelease release whose tag is a formal semantic version (vX.Y.Z).

func (*Client) FetchReleaseByTag

func (c *Client) FetchReleaseByTag(tag string) (*ReleaseInfo, error)

FetchReleaseByTag returns the release for a specific tag (e.g. "v1.0.5").

func (*Client) FetchReleaseVersions added in v1.0.48

func (c *Client) FetchReleaseVersions(track ReleaseTrack) ([]VersionEntry, error)

FetchReleaseVersions returns non-draft releases matching the requested track, newest first. The GitHub API already returns releases newest first.

type DownloadConfig

type DownloadConfig struct {
	MaxRetries int
	// MaxBytes 非零时同时限制响应声明大小和实际下载量;零保持既有行为。
	MaxBytes         int64
	CheckRedirect    func(*http.Request, []*http.Request) error
	Timeout          time.Duration
	ProgressCallback func(downloaded, total int64)
	ProgressInterval time.Duration
}

DownloadConfig holds download configuration.

func DefaultDownloadConfig

func DefaultDownloadConfig() *DownloadConfig

DefaultDownloadConfig returns sensible download defaults.

type GitHubAsset

type GitHubAsset struct {
	Name               string `json:"name"`
	Size               int64  `json:"size"`
	Digest             string `json:"digest"`
	BrowserDownloadURL string `json:"browser_download_url"`
	ContentType        string `json:"content_type"`
}

GitHubAsset represents a release asset (downloadable file).

func FindBinaryAsset

func FindBinaryAsset(assets []GitHubAsset) (*GitHubAsset, error)

FindBinaryAsset locates the platform-specific binary archive from the release assets. Pattern: dws-{os}-{arch}.tar.gz (or .zip for windows).

func FindBinaryAssetFor

func FindBinaryAssetFor(assets []GitHubAsset, goos, goarch string) (*GitHubAsset, error)

FindBinaryAssetFor locates the binary archive for a specific platform.

func FindChecksumsAsset

func FindChecksumsAsset(assets []GitHubAsset) *GitHubAsset

FindChecksumsAsset locates the checksums.txt asset.

func FindSkillsAsset

func FindSkillsAsset(assets []GitHubAsset) *GitHubAsset

FindSkillsAsset locates the dws-skills.zip asset.

type GitHubRelease

type GitHubRelease struct {
	TagName     string        `json:"tag_name"`
	Name        string        `json:"name"`
	Body        string        `json:"body"`
	Prerelease  bool          `json:"prerelease"`
	Draft       bool          `json:"draft"`
	PublishedAt string        `json:"published_at"`
	Assets      []GitHubAsset `json:"assets"`
	HTMLURL     string        `json:"html_url"`
}

GitHubRelease represents a single release from the GitHub Releases API.

type NPMPackage

type NPMPackage struct {
	RegistryURL string
	Name        string
	Version     string
	TarballURL  string
	Integrity   string
}

NPMPackage 是经元数据验证的包来源;下载方须验证 Integrity 和归档内的 name/version。 Assets 仅声明包内标准文件名,不能将 tarball URL 当作单个二进制的下载地址。

type PreparedNPMPackage

type PreparedNPMPackage struct {
	BinaryArchivePath string
	SkillsArchivePath string
	ChecksumsContent  string
}

PreparedNPMPackage 是完成外层 SRI、身份和内层 SHA256 校验的安装材料。 文件位于 destDir 下的私有子目录;调用方统一清理 destDir。

func PrepareNPMPackage

func PrepareNPMPackage(ctx context.Context, pkg NPMPackage, destDir string, skipSkills bool, showProgress func(float64, int64, int64)) (PreparedNPMPackage, error)

PrepareNPMPackage 直接下载并验证 npm 包,不执行包内脚本,也不依赖 npm/node。

type ReleaseInfo

type ReleaseInfo struct {
	Version    string
	Date       string
	Changelog  string
	Prerelease bool
	HTMLURL    string
	Assets     []GitHubAsset
	NPM        *NPMPackage
}

ReleaseInfo is the simplified view of a release used throughout the upgrade flow.

type ReleaseTrack added in v1.0.48

type ReleaseTrack string

ReleaseTrack selects which release stream an upgrade operation should use.

const (
	ReleaseTrackRelease ReleaseTrack = "release"
	ReleaseTrackBeta    ReleaseTrack = "beta"
	ReleaseTrackAll     ReleaseTrack = "all"
)

type RollbackManager

type RollbackManager struct {
	// contains filtered or unexported fields
}

RollbackManager manages backup and rollback operations.

func NewRollbackManager

func NewRollbackManager() *RollbackManager

NewRollbackManager creates a rollback manager using the standard backup directory.

func NewRollbackManagerWithDir

func NewRollbackManagerWithDir(backupDir string) *RollbackManager

NewRollbackManagerWithDir creates a rollback manager with a custom directory.

func (*RollbackManager) Backup

func (r *RollbackManager) Backup(currentVersion string) (string, error)

Backup creates a backup of the currently running binary. Returns the backup directory path.

func (*RollbackManager) Cleanup

func (r *RollbackManager) Cleanup(keep int) error

Cleanup removes old backups, keeping only the most recent N.

func (*RollbackManager) ListBackups

func (r *RollbackManager) ListBackups() ([]BackupInfo, error)

ListBackups returns all available backups, newest first.

func (*RollbackManager) Rollback

func (r *RollbackManager) Rollback() error

Rollback restores the most recent backup.

func (*RollbackManager) RollbackTo

func (r *RollbackManager) RollbackTo(backup BackupInfo) error

RollbackTo restores a specific backup. Uses replaceExeFile to handle Windows file-lock semantics correctly.

type SkillDirResult

type SkillDirResult struct {
	Dir    string         // destination directory (e.g. ~/.claude/skills/dws)
	Status SkillDirStatus // outcome
	Err    error          // non-nil when Status == SkillDirFailed or SkillDirRetireWarning
}

SkillDirResult holds the per-directory install result.

type SkillDirStatus

type SkillDirStatus int

SkillDirStatus describes the installation outcome for a single skill directory.

const (
	SkillDirOK          SkillDirStatus = iota // successfully installed
	SkillDirSkipped                           // agent not detected, directory skipped
	SkillDirBlacklisted                       // blacklisted, never touched
	SkillDirFailed                            // installation attempted but failed
	// SkillDirRetireWarning marks a universal Agent whose obsolete private copy
	// could not be retired. Nothing is installed below such a root, so the
	// leftover is reported without counting as an install failure.
	SkillDirRetireWarning
)

type SkillPathPublication added in v1.0.59

type SkillPathPublication struct {
	Destination string
	// contains filtered or unexported fields
}

SkillPathPublication records enough immutable identity to prove that a destination still belongs to the transaction that published it. The fingerprint is intentionally private so callers cannot forge records.

func PublishSkillPathNoReplace added in v1.0.59

func PublishSkillPathNoReplace(staged, destination string) (publication SkillPathPublication, err error)

PublishSkillPathNoReplace atomically publishes a staged path without ever replacing a destination created after the backup phase.

The rename returns a mkdir-claim identity when (and only when) the child-move fallback published dest. That identity is the tamperproof witness that dest is still the mkdir claim this transaction created (unlike the staged shell, whose presence alone is compatible with a wholesale replacement of dest by a concurrent writer). When the claim identity no longer matches dest, publication reports uncertain state (ErrSkillPathPublicationUncertain) and keeps dest — auto-retracting or overwriting would delete the concurrent writer's data.

type SkillUpgradeOptions added in v1.0.58

type SkillUpgradeOptions struct {
	Version string
}

type SkillUpgradeResult

type SkillUpgradeResult struct {
	Results []SkillDirResult
}

SkillUpgradeResult aggregates the outcome of an UpgradeSkillLocations call.

func UpgradeSkillLocations

func UpgradeSkillLocations(extractedDir string) (*SkillUpgradeResult, error)

UpgradeSkillLocations refreshes skills from extractedDir into agent homes. extractedDir may be a multi-skill bundle root (subdirectories each containing SKILL.md) or a legacy mono root (SKILL.md at its top level). Callers that resolve a release zip usually pass LocateSkillsRoot's result (multi/ preferred when present).

Package-driven layout:

  • release zip has multi/ → install and overwrite the complete official bundle. Locally deleted bundled skills are restored on the next upgrade; local absence is never treated as a persistent exclusion.
  • dingtalk-shared is mandatory whenever it exists in the bundle.
  • legacy zip with no multi tree → mono refresh path (unchanged fallback)

Fresh install defaults to multi with opt-in mono via the interactive `dws skill setup --mode mono` flow.

Strategy (matches npm install.js installSkillsToHomes):

  • ~/.agents/skills/ is always the canonical global store
  • universal Agents (Codex, Cursor, Gemini, Cline, Amp, Copilot) read the canonical store directly, so old agent-specific copies are retired
  • detected non-universal Agents receive relative links to canonical; filesystems that reject links receive a direct-copy fallback
  • ~/.real/ and other blacklisted paths are NEVER touched
  • canonical publication is mandatory and fails the upgrade loudly

Opposite-mode leftovers are backed up to ~/.dws/skill-backups/ and then removed so mono and multi never co-exist after an upgrade; a leftover that cannot be backed up is never removed and fails that home. Same-name bundle skills are refreshed in place (verified DWS-managed overwrite). Caches under ~/.dws/skills/{multi,mono} are refreshed best-effort.

func UpgradeSkillLocationsWithOptions added in v1.0.58

func UpgradeSkillLocationsWithOptions(extractedDir string, opts SkillUpgradeOptions) (*SkillUpgradeResult, error)

func (*SkillUpgradeResult) Failed

func (r *SkillUpgradeResult) Failed() []SkillDirResult

Failed returns directories where installation was attempted but failed.

func (*SkillUpgradeResult) RetireWarnings added in v1.0.59

func (r *SkillUpgradeResult) RetireWarnings() []SkillDirResult

RetireWarnings returns universal Agent roots that still hold an obsolete private copy because retiring it failed.

func (*SkillUpgradeResult) Succeeded

func (r *SkillUpgradeResult) Succeeded() []SkillDirResult

Succeeded returns directories that were successfully updated.

type VersionEntry

type VersionEntry struct {
	Version    string
	Date       string
	Changelog  string
	Prerelease bool
}

VersionEntry represents a single version in the version list.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL