upgrade

package
v1.0.63 Latest Latest
Warning

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

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

Documentation

Overview

Package upgrade provides self-update functionality for the DWS CLI using GitHub Releases as the data source.

Index

Constants

This section is empty.

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 Client

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

Client communicates with the GitHub Releases API.

func NewClient

func NewClient() *Client

NewClient creates a GitHub release client with default settings.

func NewClientWithBaseURL

func NewClientWithBaseURL(baseURL string) *Client

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

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) 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
	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 ReleaseInfo

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

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