Files
gastown/internal/polecat/types.go
blackfinger 904a773ade refactor: Add CleanupStatus type to replace raw strings (gt-77gq7)
Introduces a typed CleanupStatus with constants:
- CleanupClean, CleanupUncommitted, CleanupStash, CleanupUnpushed, CleanupUnknown

Adds helper methods:
- IsSafe(): true for clean status
- RequiresRecovery(): true for uncommitted/stash/unpushed
- CanForceRemove(): true if force flag can bypass

Updated files to use the new type:
- internal/polecat/types.go: Type definition and methods
- internal/polecat/manager.go: Validation logic
- internal/witness/handlers.go: Nuke safety checks
- internal/cmd/done.go: Status reporting
- internal/cmd/polecat.go: Recovery status checks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 00:19:00 -08:00

126 lines
3.7 KiB
Go

// Package polecat provides polecat lifecycle management.
package polecat
import "time"
// State represents the current state of a polecat.
// In the transient model, polecats exist only while working.
type State string
const (
// StateWorking means the polecat is actively working on an issue.
// This is the initial and primary state for transient polecats.
StateWorking State = "working"
// StateDone means the polecat has completed its assigned work
// and is ready for cleanup by the Witness.
StateDone State = "done"
// StateStuck means the polecat needs assistance.
StateStuck State = "stuck"
// StateActive is deprecated: use StateWorking.
// Kept only for backward compatibility with existing data.
StateActive State = "active"
)
// IsWorking returns true if the polecat is currently working.
func (s State) IsWorking() bool {
return s == StateWorking
}
// IsActive returns true if the polecat session is actively working.
// For transient polecats, this is true for working state and
// legacy active state (treated as working).
func (s State) IsActive() bool {
return s == StateWorking || s == StateActive
}
// Polecat represents a worker agent in a rig.
type Polecat struct {
// Name is the polecat identifier.
Name string `json:"name"`
// Rig is the rig this polecat belongs to.
Rig string `json:"rig"`
// State is the current lifecycle state.
State State `json:"state"`
// ClonePath is the path to the polecat's clone of the rig.
ClonePath string `json:"clone_path"`
// Branch is the current git branch.
Branch string `json:"branch"`
// Issue is the currently assigned issue ID (if any).
Issue string `json:"issue,omitempty"`
// CreatedAt is when the polecat was created.
CreatedAt time.Time `json:"created_at"`
// UpdatedAt is when the polecat was last updated.
UpdatedAt time.Time `json:"updated_at"`
}
// Summary provides a concise view of polecat status.
type Summary struct {
Name string `json:"name"`
State State `json:"state"`
Issue string `json:"issue,omitempty"`
}
// Summary returns a Summary for this polecat.
func (p *Polecat) Summary() Summary {
return Summary{
Name: p.Name,
State: p.State,
Issue: p.Issue,
}
}
// CleanupStatus represents the git state of a polecat for cleanup decisions.
// The Witness uses this to determine whether it's safe to nuke a polecat worktree.
type CleanupStatus string
const (
// CleanupClean means the worktree has no uncommitted work and is safe to remove.
CleanupClean CleanupStatus = "clean"
// CleanupUncommitted means there are uncommitted changes in the worktree.
CleanupUncommitted CleanupStatus = "has_uncommitted"
// CleanupStash means there are stashed changes that would be lost.
CleanupStash CleanupStatus = "has_stash"
// CleanupUnpushed means there are commits not pushed to the remote.
CleanupUnpushed CleanupStatus = "has_unpushed"
// CleanupUnknown means the status could not be determined.
CleanupUnknown CleanupStatus = "unknown"
)
// IsSafe returns true if the status indicates it's safe to remove the worktree
// without losing any work.
func (s CleanupStatus) IsSafe() bool {
return s == CleanupClean
}
// RequiresRecovery returns true if the status indicates there is work that
// needs to be recovered before removal. This includes uncommitted changes,
// stashes, and unpushed commits.
func (s CleanupStatus) RequiresRecovery() bool {
switch s {
case CleanupUncommitted, CleanupStash, CleanupUnpushed:
return true
default:
return false
}
}
// CanForceRemove returns true if the status allows forced removal.
// Uncommitted changes can be force-removed, but stashes and unpushed commits cannot.
func (s CleanupStatus) CanForceRemove() bool {
return s == CleanupClean || s == CleanupUncommitted
}