package internal import ( "fmt" "charm.land/bubbletea/v2" ) // Model 主模型 type Model struct { activeGroup int cursor int selected map[int]bool inputBuf string width int height int launched string history HistoryState pendingCmd string update UpdateState wsFocus int // workspace 焦点列: 0=tabs 1=list wsTabCur int // tabs 列光标 (0..len(Groups), 最后一个是历史入口) forkMode bool // 分叉输入模式 forkBuf string // 分叉方向提示输入 } func NewModel() *Model { return &Model{ activeGroup: len(Groups), // 默认打开历史对话 selected: make(map[int]bool), } } func (m *Model) Init() tea.Cmd { m.update.Checking = true cmds := []tea.Cmd{CheckUpdateCmd()} if cmd := m.onTabSwitch(); cmd != nil { cmds = append(cmds, cmd) } return tea.Batch(cmds...) } func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyPressMsg: return m.handleKey(msg.String()) case tea.WindowSizeMsg: m.width = msg.Width m.height = msg.Height case ScanCompleteMsg: m.history.Projects = msg.Projects m.history.Cache = msg.Cache m.history.Loaded = true m.history.Scanning = false if m.history.Favorites == nil { m.history.Favorites = loadFavorites() } // 填充 ForkFrom forks := loadForks() if len(forks) > 0 { for _, pd := range m.history.Projects { for _, s := range pd.Sessions { if src, ok := forks[s.ID]; ok { s.ForkFrom = src } } } } total := 0 for _, pd := range msg.Projects { total += len(pd.Sessions) } m.launched = fmt.Sprintf("refreshed: %d projects, %d sessions", len(msg.Projects), total) if len(msg.UpdatedIDs) > 0 { return m, m.nextSummaryCmd() } return m, nil 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 } func (m *Model) GetPendingCmd() string { return m.pendingCmd }