package models import ( "encoding/json" "fmt" "time" ) // Workstream represents a stacked-diff workflow type Workstream struct { // Name is the unique identifier for the workstream Name string `json:"name"` // Description provides context about the workstream Description string `json:"description"` // BaseBranch is the Git branch this workstream is based on BaseBranch string `json:"base_branch"` // Commits is an ordered list of commits in this workstream Commits []WorkstreamCommit `json:"commits"` // Created is when the workstream was created Created time.Time `json:"created"` // Updated is when the workstream was last modified Updated time.Time `json:"updated"` // Status indicates the current state (active, merged, abandoned) Status WorkstreamStatus `json:"status"` // Metadata contains additional workstream-specific data Metadata map[string]string `json:"metadata,omitempty"` } // WorkstreamCommit represents a single commit in a workstream type WorkstreamCommit struct { // SHA is the Git commit hash SHA string `json:"sha"` // Message is the commit message Message string `json:"message"` // Author is the commit author Author string `json:"author"` // Timestamp is when the commit was created Timestamp time.Time `json:"timestamp"` // ParentSHA is the parent commit in the workstream (empty for first commit) ParentSHA string `json:"parent_sha,omitempty"` // BaseSHA is the base commit from the base branch BaseSHA string `json:"base_sha"` // BranchRef is the Git reference for this commit (e.g., refs/onyx/workstreams/name/commit-1) BranchRef string `json:"branch_ref"` } // WorkstreamStatus represents the state of a workstream type WorkstreamStatus string const ( // WorkstreamStatusActive indicates the workstream is being actively developed WorkstreamStatusActive WorkstreamStatus = "active" // WorkstreamStatusMerged indicates the workstream has been merged WorkstreamStatusMerged WorkstreamStatus = "merged" // WorkstreamStatusAbandoned indicates the workstream has been abandoned WorkstreamStatusAbandoned WorkstreamStatus = "abandoned" // WorkstreamStatusArchived indicates the workstream has been archived WorkstreamStatusArchived WorkstreamStatus = "archived" ) // WorkstreamCollection represents the collection of all workstreams type WorkstreamCollection struct { // Workstreams is a map of workstream name to Workstream Workstreams map[string]*Workstream `json:"workstreams"` // CurrentWorkstream is the name of the active workstream CurrentWorkstream string `json:"current_workstream,omitempty"` } // NewWorkstream creates a new workstream func NewWorkstream(name, description, baseBranch string) *Workstream { now := time.Now() return &Workstream{ Name: name, Description: description, BaseBranch: baseBranch, Commits: []WorkstreamCommit{}, Created: now, Updated: now, Status: WorkstreamStatusActive, Metadata: make(map[string]string), } } // AddCommit adds a commit to the workstream func (w *Workstream) AddCommit(commit WorkstreamCommit) { w.Commits = append(w.Commits, commit) w.Updated = time.Now() } // GetLatestCommit returns the latest commit in the workstream func (w *Workstream) GetLatestCommit() (*WorkstreamCommit, error) { if len(w.Commits) == 0 { return nil, fmt.Errorf("workstream has no commits") } return &w.Commits[len(w.Commits)-1], nil } // GetCommitCount returns the number of commits in the workstream func (w *Workstream) GetCommitCount() int { return len(w.Commits) } // IsEmpty returns true if the workstream has no commits func (w *Workstream) IsEmpty() bool { return len(w.Commits) == 0 } // NewWorkstreamCommit creates a new workstream commit func NewWorkstreamCommit(sha, message, author, parentSHA, baseSHA, branchRef string) WorkstreamCommit { return WorkstreamCommit{ SHA: sha, Message: message, Author: author, Timestamp: time.Now(), ParentSHA: parentSHA, BaseSHA: baseSHA, BranchRef: branchRef, } } // NewWorkstreamCollection creates a new workstream collection func NewWorkstreamCollection() *WorkstreamCollection { return &WorkstreamCollection{ Workstreams: make(map[string]*Workstream), } } // AddWorkstream adds a workstream to the collection func (wc *WorkstreamCollection) AddWorkstream(workstream *Workstream) error { if _, exists := wc.Workstreams[workstream.Name]; exists { return fmt.Errorf("workstream '%s' already exists", workstream.Name) } wc.Workstreams[workstream.Name] = workstream return nil } // GetWorkstream retrieves a workstream by name func (wc *WorkstreamCollection) GetWorkstream(name string) (*Workstream, error) { workstream, exists := wc.Workstreams[name] if !exists { return nil, fmt.Errorf("workstream '%s' not found", name) } return workstream, nil } // RemoveWorkstream removes a workstream from the collection func (wc *WorkstreamCollection) RemoveWorkstream(name string) error { if _, exists := wc.Workstreams[name]; !exists { return fmt.Errorf("workstream '%s' not found", name) } delete(wc.Workstreams, name) return nil } // ListWorkstreams returns all workstreams func (wc *WorkstreamCollection) ListWorkstreams() []*Workstream { workstreams := make([]*Workstream, 0, len(wc.Workstreams)) for _, ws := range wc.Workstreams { workstreams = append(workstreams, ws) } return workstreams } // SetCurrentWorkstream sets the active workstream func (wc *WorkstreamCollection) SetCurrentWorkstream(name string) error { if _, exists := wc.Workstreams[name]; !exists { return fmt.Errorf("workstream '%s' not found", name) } wc.CurrentWorkstream = name return nil } // GetCurrentWorkstream returns the current workstream func (wc *WorkstreamCollection) GetCurrentWorkstream() (*Workstream, error) { if wc.CurrentWorkstream == "" { return nil, fmt.Errorf("no current workstream set") } return wc.GetWorkstream(wc.CurrentWorkstream) } // Serialize converts the workstream collection to JSON func (wc *WorkstreamCollection) Serialize() ([]byte, error) { data, err := json.MarshalIndent(wc, "", " ") if err != nil { return nil, fmt.Errorf("failed to marshal workstream collection: %w", err) } return data, nil } // DeserializeWorkstreamCollection converts JSON data to a workstream collection func DeserializeWorkstreamCollection(data []byte) (*WorkstreamCollection, error) { wc := &WorkstreamCollection{} if err := json.Unmarshal(data, wc); err != nil { return nil, fmt.Errorf("failed to unmarshal workstream collection: %w", err) } return wc, nil }