新增: 自动更新与一键自升级
This commit is contained in:
@@ -30,6 +30,7 @@ type Model struct {
|
||||
launched string
|
||||
history HistoryState
|
||||
pendingCmd string // Linux: 退出后执行的命令
|
||||
update UpdateState
|
||||
}
|
||||
|
||||
func NewModel() *Model {
|
||||
@@ -40,7 +41,8 @@ func NewModel() *Model {
|
||||
}
|
||||
|
||||
func (m *Model) Init() tea.Cmd {
|
||||
return nil
|
||||
m.update.Checking = true
|
||||
return CheckUpdateCmd()
|
||||
}
|
||||
|
||||
// totalTabs 包含 HISTORY 的总 Tab 数
|
||||
@@ -71,6 +73,22 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case SummaryResultMsg:
|
||||
m.applySummary(msg.SessionID, msg.Summary, msg.Completed, msg.Pending)
|
||||
return m, m.nextSummaryCmd()
|
||||
case UpdateAvailableMsg:
|
||||
m.update.Checking = false
|
||||
m.update.Available = true
|
||||
m.update.NewVersion = msg.NewVersion
|
||||
m.update.Changelog = msg.Changelog
|
||||
m.update.DownloadURL = msg.DownloadURL
|
||||
m.update.SHA256 = msg.SHA256
|
||||
m.update.FileSize = msg.FileSize
|
||||
case UpdateCompleteMsg:
|
||||
m.update.Updating = false
|
||||
m.update.Done = true
|
||||
m.update.Available = false
|
||||
case UpdateErrorMsg:
|
||||
m.update.Updating = false
|
||||
m.update.Error = msg.Err
|
||||
m.update.Checking = false
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
@@ -82,6 +100,11 @@ func (m *Model) handleKey(s string) (*Model, tea.Cmd) {
|
||||
switch s {
|
||||
case "q", "ctrl+c":
|
||||
return m, tea.Quit
|
||||
case "u":
|
||||
if m.update.Available && !m.update.Updating {
|
||||
m.update.Updating = true
|
||||
return m, SelfUpdateCmd(m.update.DownloadURL, m.update.SHA256, m.update.NewVersion)
|
||||
}
|
||||
}
|
||||
|
||||
// 数字键跳转 Tab
|
||||
@@ -400,7 +423,7 @@ func (m *Model) render() string {
|
||||
var b strings.Builder
|
||||
|
||||
// ── header: title + tabs ──
|
||||
b.WriteString(style.TitleStyle.Render(" u-tabs "))
|
||||
b.WriteString(style.TitleStyle.Render(" u-tabs v" + Version + " "))
|
||||
sep := style.TabSep.Render(" | ")
|
||||
|
||||
// Workspace Tabs
|
||||
@@ -455,6 +478,20 @@ func (m *Model) render() string {
|
||||
b.WriteString(lipgloss.NewStyle().Foreground(style.Accent).Render(fmt.Sprintf(" ✓ %s", m.launched)))
|
||||
m.launched = ""
|
||||
}
|
||||
// update status
|
||||
if m.update.Done {
|
||||
b.WriteString(lipgloss.NewStyle().Foreground(style.Success).Bold(true).
|
||||
Render(fmt.Sprintf(" updated to v%s, restart to apply", m.update.NewVersion)))
|
||||
} else if m.update.Error != nil {
|
||||
b.WriteString(lipgloss.NewStyle().Foreground(style.Red).
|
||||
Render(fmt.Sprintf(" update failed: %v", m.update.Error)))
|
||||
} else if m.update.Updating {
|
||||
b.WriteString(lipgloss.NewStyle().Foreground(style.Warning).
|
||||
Render(" updating..."))
|
||||
} else if m.update.Available {
|
||||
b.WriteString(lipgloss.NewStyle().Foreground(style.Warning).Bold(true).
|
||||
Render(fmt.Sprintf(" v%s available [u]update", m.update.NewVersion)))
|
||||
}
|
||||
b.WriteString("\n")
|
||||
|
||||
helpParts := m.renderHelp()
|
||||
|
||||
Reference in New Issue
Block a user