Documentation
¶
Overview ¶
Package upgrade provides self-update functionality for the DWS CLI using GitHub Releases as the data source.
Index ¶
- Variables
- func BackupAndRemoveSkillDir(homeDir, dir string) (string, error)
- func BinaryName() string
- func CleanupStaleFiles()
- func CompareVersions(a, b string) int
- func ComputeSHA256(filePath string) (string, error)
- func CurrentBinaryPath() (string, error)
- func Download(url, destPath string) (int64, error)
- func DownloadCacheDir() string
- func DownloadWithConfig(ctx context.Context, url, destPath string, cfg *DownloadConfig) (int64, error)
- func DownloadWithProgress(ctx context.Context, url, destPath string, ...) (int64, error)
- func EnsureUpgradeDirectories() error
- func ExtractDigestSHA256(digest string) string
- func ExtractZip(zipPath, targetDir string) error
- func FindBinaryInDir(dir string) string
- func LocateSkillMD(extractDir string) string
- func LocateSkillsRoot(extractDir string) string
- func NeedsUpgrade(currentVersion, remoteVersion string) bool
- func ParseChecksumFile(content string) map[string]string
- func ReleaseSkillPathPublications(publications []SkillPathPublication) error
- func ReplaceSelf(newBinaryPath string) error
- func RestoreSkillPath(backup, original string) error
- func RollbackSkillPathPublications(publications []SkillPathPublication) (rollbackErr error)
- func SwapUserHomeDirForTest(t *testing.T, fn func() (string, error))
- func VerifyFileFromChecksums(filePath, filename, checksumsContent string) error
- func VerifySHA256(filePath, expectedHash string) error
- type BackupInfo
- type Client
- func (c *Client) FetchAllReleases() ([]VersionEntry, error)
- func (c *Client) FetchLatestPrerelease() (*ReleaseInfo, error)
- func (c *Client) FetchLatestRelease() (*ReleaseInfo, error)
- func (c *Client) FetchLatestReleaseForTrack(track ReleaseTrack) (*ReleaseInfo, error)
- func (c *Client) FetchLatestStableRelease() (*ReleaseInfo, error)
- func (c *Client) FetchReleaseByTag(tag string) (*ReleaseInfo, error)
- func (c *Client) FetchReleaseVersions(track ReleaseTrack) ([]VersionEntry, error)
- type DownloadConfig
- type GitHubAsset
- type GitHubRelease
- type ReleaseInfo
- type ReleaseTrack
- type RollbackManager
- type SkillDirResult
- type SkillDirStatus
- type SkillPathPublication
- type SkillUpgradeOptions
- type SkillUpgradeResult
- type VersionEntry
Constants ¶
This section is empty.
Variables ¶
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
BackupAndRemoveSkillDir is the exported wrapper over backupAndRemoveSkillDir for callers outside the upgrade package (the skill-setup channel in internal/app).
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 ¶
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 ¶
ComputeSHA256 computes the SHA256 hash of a file.
func CurrentBinaryPath ¶
CurrentBinaryPath returns the resolved path of the currently running binary.
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 ¶
ExtractDigestSHA256 extracts the hex hash from a GitHub asset digest field. GitHub format: "sha256:abcdef1234..."
func ExtractZip ¶
ExtractZip unzips zipPath contents into targetDir. Contains zip-slip protection against path traversal attacks.
func FindBinaryInDir ¶
FindBinaryInDir recursively finds the dws binary in an extracted directory.
func LocateSkillMD ¶
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
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 ¶
NeedsUpgrade returns true when remoteVersion is newer than currentVersion.
func ParseChecksumFile ¶
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 ¶
ReplaceSelf atomically replaces the currently running binary with newBinaryPath.
On Unix (macOS / Linux):
- Try atomic os.Rename (same filesystem, instant swap)
- 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
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
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 ¶
VerifyFileFromChecksums verifies a downloaded file against checksums.txt content.
func VerifySHA256 ¶
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 ¶
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.