Rename ephemeral -> wisp terminology throughout Gas Town
- .beads-ephemeral/ -> .beads-wisp/ - Rename doctor checks: EphemeralCheck -> WispCheck - Update all docs to use 'transient' for polecats, 'wisp' for molecules - Preserve 'ephemeral' only as descriptive adjective for wisps - Steam engine metaphor: wisps are steam vapors that dissipate Part of Christmas launch wisp terminology unification.
This commit is contained in:
@@ -19,7 +19,7 @@ var crewCmd = &cobra.Command{
|
||||
Short: "Manage crew workspaces (user-managed persistent workspaces)",
|
||||
Long: `Crew workers are user-managed persistent workspaces within a rig.
|
||||
|
||||
Unlike polecats which are witness-managed and ephemeral, crew workers are:
|
||||
Unlike polecats which are witness-managed and transient, crew workers are:
|
||||
- Persistent: Not auto-garbage-collected
|
||||
- User-managed: Overseer controls lifecycle
|
||||
- Long-lived identities: recognizable names like dave, emma, fred
|
||||
|
||||
@@ -63,12 +63,12 @@ func runDoctor(cmd *cobra.Command, args []string) error {
|
||||
d.Register(doctor.NewIdentityCollisionCheck())
|
||||
d.Register(doctor.NewThemeCheck())
|
||||
|
||||
// Ephemeral beads checks
|
||||
d.Register(doctor.NewEphemeralExistsCheck())
|
||||
d.Register(doctor.NewEphemeralGitCheck())
|
||||
d.Register(doctor.NewEphemeralOrphansCheck())
|
||||
d.Register(doctor.NewEphemeralSizeCheck())
|
||||
d.Register(doctor.NewEphemeralStaleCheck())
|
||||
// Wisp storage checks
|
||||
d.Register(doctor.NewWispExistsCheck())
|
||||
d.Register(doctor.NewWispGitCheck())
|
||||
d.Register(doctor.NewWispOrphansCheck())
|
||||
d.Register(doctor.NewWispSizeCheck())
|
||||
d.Register(doctor.NewWispStaleCheck())
|
||||
|
||||
// Run checks
|
||||
var report *doctor.Report
|
||||
|
||||
@@ -56,7 +56,7 @@ const HQGitignore = `# Gas Town HQ .gitignore
|
||||
# Ignore: Git clones (polecats, mayor/refinery rigs), runtime state
|
||||
|
||||
# =============================================================================
|
||||
# Runtime state files (ephemeral)
|
||||
# Runtime state files (transient)
|
||||
# =============================================================================
|
||||
**/state.json
|
||||
**/*.lock
|
||||
|
||||
@@ -41,7 +41,7 @@ var polecatListCmd = &cobra.Command{
|
||||
Short: "List polecats in a rig",
|
||||
Long: `List polecats in a rig or all rigs.
|
||||
|
||||
In the ephemeral model, polecats exist only while working. The list shows
|
||||
In the transient model, polecats exist only while working. The list shows
|
||||
all currently active polecats with their states:
|
||||
- working: Actively working on an issue
|
||||
- done: Completed work, waiting for cleanup
|
||||
@@ -91,7 +91,7 @@ var polecatWakeCmd = &cobra.Command{
|
||||
Short: "(Deprecated) Resume a polecat to working state",
|
||||
Long: `Resume a polecat to working state.
|
||||
|
||||
DEPRECATED: In the ephemeral model, polecats are created fresh for each task
|
||||
DEPRECATED: In the transient model, polecats are created fresh for each task
|
||||
via 'gt spawn'. This command is kept for backward compatibility.
|
||||
|
||||
Transitions: done → working
|
||||
@@ -107,7 +107,7 @@ var polecatSleepCmd = &cobra.Command{
|
||||
Short: "(Deprecated) Mark polecat as done",
|
||||
Long: `Mark polecat as done.
|
||||
|
||||
DEPRECATED: In the ephemeral model, polecats use 'gt handoff' when complete,
|
||||
DEPRECATED: In the transient model, polecats use 'gt handoff' when complete,
|
||||
which triggers automatic cleanup by the Witness. This command is kept for
|
||||
backward compatibility.
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ func outputWitnessContext(ctx RoleContext) {
|
||||
fmt.Printf("You are the **Witness** for rig: %s\n\n", style.Bold.Render(ctx.Rig))
|
||||
fmt.Println("## Responsibilities")
|
||||
fmt.Println("- Monitor polecat health via heartbeat")
|
||||
fmt.Println("- Spawn ephemeral agents for stuck polecats")
|
||||
fmt.Println("- Spawn replacement agents for stuck polecats")
|
||||
fmt.Println("- Report rig status to Mayor")
|
||||
fmt.Println()
|
||||
fmt.Println("## Key Commands")
|
||||
|
||||
@@ -28,7 +28,7 @@ infrastructure agents are running:
|
||||
• Mayor - Global work coordinator
|
||||
• Witnesses - Per-rig polecat managers
|
||||
|
||||
Polecats are NOT started by this command - they are ephemeral workers
|
||||
Polecats are NOT started by this command - they are transient workers
|
||||
spawned on demand by the Mayor or Witnesses.
|
||||
|
||||
Running 'gt up' multiple times is safe - it only starts services that
|
||||
|
||||
@@ -165,9 +165,9 @@ var deaconMOTDMessages = []string{
|
||||
"Thanks for keeping the town running!",
|
||||
"You are Gas Town's most critical role.",
|
||||
"You are the heart of Gas Town! Be watchful!",
|
||||
"Tip: Polecats are ephemeral - spawn freely, kill liberally.",
|
||||
"Tip: Polecats are transient - spawn freely, kill liberally.",
|
||||
"Tip: Witnesses monitor polecats; you monitor witnesses.",
|
||||
"Tip: Wisps are ephemeral molecules for patrol cycles.",
|
||||
"Tip: Wisps are transient molecules for patrol cycles.",
|
||||
"The town sleeps soundly because you never do.",
|
||||
"Tip: Mayor handles cross-rig coordination; you handle health.",
|
||||
"Your vigilance keeps the agents honest.",
|
||||
|
||||
@@ -11,26 +11,26 @@ import (
|
||||
"github.com/steveyegge/gastown/internal/config"
|
||||
)
|
||||
|
||||
// EphemeralExistsCheck verifies that .beads-ephemeral/ exists for each rig.
|
||||
type EphemeralExistsCheck struct {
|
||||
// WispExistsCheck verifies that .beads-wisp/ exists for each rig.
|
||||
type WispExistsCheck struct {
|
||||
FixableCheck
|
||||
missingRigs []string // Cached for fix
|
||||
}
|
||||
|
||||
// NewEphemeralExistsCheck creates a new ephemeral exists check.
|
||||
func NewEphemeralExistsCheck() *EphemeralExistsCheck {
|
||||
return &EphemeralExistsCheck{
|
||||
// NewWispExistsCheck creates a new wisp exists check.
|
||||
func NewWispExistsCheck() *WispExistsCheck {
|
||||
return &WispExistsCheck{
|
||||
FixableCheck: FixableCheck{
|
||||
BaseCheck: BaseCheck{
|
||||
CheckName: "ephemeral-exists",
|
||||
CheckDescription: "Check if ephemeral beads directory exists for each rig",
|
||||
CheckName: "wisp-exists",
|
||||
CheckDescription: "Check if wisp directory exists for each rig",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run checks if .beads-ephemeral/ exists for each rig.
|
||||
func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
// Run checks if .beads-wisp/ exists for each rig.
|
||||
func (c *WispExistsCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
c.missingRigs = nil // Reset cache
|
||||
|
||||
// Find all rigs
|
||||
@@ -55,8 +55,8 @@ func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
// Check each rig
|
||||
var missing []string
|
||||
for _, rigName := range rigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) {
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
if _, err := os.Stat(wispPath); os.IsNotExist(err) {
|
||||
missing = append(missing, rigName)
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusWarning,
|
||||
Message: fmt.Sprintf("%d rig(s) missing ephemeral beads directory", len(missing)),
|
||||
Message: fmt.Sprintf("%d rig(s) missing wisp directory", len(missing)),
|
||||
Details: missing,
|
||||
FixHint: "Run 'gt doctor --fix' to create missing directories",
|
||||
}
|
||||
@@ -75,23 +75,23 @@ func (c *EphemeralExistsCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusOK,
|
||||
Message: fmt.Sprintf("All %d rig(s) have ephemeral beads directory", len(rigs)),
|
||||
Message: fmt.Sprintf("All %d rig(s) have wisp directory", len(rigs)),
|
||||
}
|
||||
}
|
||||
|
||||
// Fix creates missing .beads-ephemeral/ directories.
|
||||
func (c *EphemeralExistsCheck) Fix(ctx *CheckContext) error {
|
||||
// Fix creates missing .beads-wisp/ directories.
|
||||
func (c *WispExistsCheck) Fix(ctx *CheckContext) error {
|
||||
for _, rigName := range c.missingRigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
if err := os.MkdirAll(ephemeralPath, 0755); err != nil {
|
||||
return fmt.Errorf("creating %s: %w", ephemeralPath, err)
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
if err := os.MkdirAll(wispPath, 0755); err != nil {
|
||||
return fmt.Errorf("creating %s: %w", wispPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// discoverRigs finds all registered rigs.
|
||||
func (c *EphemeralExistsCheck) discoverRigs(townRoot string) ([]string, error) {
|
||||
func (c *WispExistsCheck) discoverRigs(townRoot string) ([]string, error) {
|
||||
rigsPath := filepath.Join(townRoot, "mayor", "rigs.json")
|
||||
data, err := os.ReadFile(rigsPath)
|
||||
if err != nil {
|
||||
@@ -113,26 +113,26 @@ func (c *EphemeralExistsCheck) discoverRigs(townRoot string) ([]string, error) {
|
||||
return rigs, nil
|
||||
}
|
||||
|
||||
// EphemeralGitCheck verifies that .beads-ephemeral/ is a valid git repo.
|
||||
type EphemeralGitCheck struct {
|
||||
// WispGitCheck verifies that .beads-wisp/ is a valid git repo.
|
||||
type WispGitCheck struct {
|
||||
FixableCheck
|
||||
invalidRigs []string // Cached for fix
|
||||
}
|
||||
|
||||
// NewEphemeralGitCheck creates a new ephemeral git check.
|
||||
func NewEphemeralGitCheck() *EphemeralGitCheck {
|
||||
return &EphemeralGitCheck{
|
||||
// NewWispGitCheck creates a new wisp git check.
|
||||
func NewWispGitCheck() *WispGitCheck {
|
||||
return &WispGitCheck{
|
||||
FixableCheck: FixableCheck{
|
||||
BaseCheck: BaseCheck{
|
||||
CheckName: "ephemeral-git",
|
||||
CheckDescription: "Check if ephemeral beads directories are valid git repos",
|
||||
CheckName: "wisp-git",
|
||||
CheckDescription: "Check if wisp directories are valid git repos",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run checks if .beads-ephemeral/ directories are valid git repos.
|
||||
func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
// Run checks if .beads-wisp/ directories are valid git repos.
|
||||
func (c *WispGitCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
c.invalidRigs = nil // Reset cache
|
||||
|
||||
// Find all rigs
|
||||
@@ -154,18 +154,18 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
}
|
||||
}
|
||||
|
||||
// Check each rig that has an ephemeral dir
|
||||
// Check each rig that has a wisp dir
|
||||
var invalid []string
|
||||
var checked int
|
||||
for _, rigName := range rigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) {
|
||||
continue // Skip if directory doesn't exist (handled by ephemeral-exists)
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
if _, err := os.Stat(wispPath); os.IsNotExist(err) {
|
||||
continue // Skip if directory doesn't exist (handled by wisp-exists)
|
||||
}
|
||||
checked++
|
||||
|
||||
// Check if it's a valid git repo
|
||||
gitDir := filepath.Join(ephemeralPath, ".git")
|
||||
gitDir := filepath.Join(wispPath, ".git")
|
||||
if _, err := os.Stat(gitDir); os.IsNotExist(err) {
|
||||
invalid = append(invalid, rigName)
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusOK,
|
||||
Message: "No ephemeral beads directories to check",
|
||||
Message: "No wisp directories to check",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusWarning,
|
||||
Message: fmt.Sprintf("%d ephemeral beads directory(ies) not initialized as git", len(invalid)),
|
||||
Message: fmt.Sprintf("%d wisp directory(ies) not initialized as git", len(invalid)),
|
||||
Details: invalid,
|
||||
FixHint: "Run 'gt doctor --fix' to initialize git repos",
|
||||
}
|
||||
@@ -193,47 +193,47 @@ func (c *EphemeralGitCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusOK,
|
||||
Message: fmt.Sprintf("All %d ephemeral beads directories are valid git repos", checked),
|
||||
Message: fmt.Sprintf("All %d wisp directories are valid git repos", checked),
|
||||
}
|
||||
}
|
||||
|
||||
// Fix initializes git repos in ephemeral directories.
|
||||
func (c *EphemeralGitCheck) Fix(ctx *CheckContext) error {
|
||||
// Fix initializes git repos in wisp directories.
|
||||
func (c *WispGitCheck) Fix(ctx *CheckContext) error {
|
||||
for _, rigName := range c.invalidRigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
cmd := exec.Command("git", "init")
|
||||
cmd.Dir = ephemeralPath
|
||||
cmd.Dir = wispPath
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("initializing git in %s: %w", ephemeralPath, err)
|
||||
return fmt.Errorf("initializing git in %s: %w", wispPath, err)
|
||||
}
|
||||
|
||||
// Create config.yaml for ephemeral beads
|
||||
configPath := filepath.Join(ephemeralPath, "config.yaml")
|
||||
configContent := "ephemeral: true\n# No sync-branch - ephemeral is local only\n"
|
||||
// Create config.yaml for wisp storage
|
||||
configPath := filepath.Join(wispPath, "config.yaml")
|
||||
configContent := "wisp: true\n# No sync-branch - wisps are local only\n"
|
||||
if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil {
|
||||
return fmt.Errorf("creating config.yaml in %s: %w", ephemeralPath, err)
|
||||
return fmt.Errorf("creating config.yaml in %s: %w", wispPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EphemeralOrphansCheck detects molecules started but never squashed (>24h old).
|
||||
type EphemeralOrphansCheck struct {
|
||||
// WispOrphansCheck detects molecules started but never squashed (>24h old).
|
||||
type WispOrphansCheck struct {
|
||||
BaseCheck
|
||||
}
|
||||
|
||||
// NewEphemeralOrphansCheck creates a new ephemeral orphans check.
|
||||
func NewEphemeralOrphansCheck() *EphemeralOrphansCheck {
|
||||
return &EphemeralOrphansCheck{
|
||||
// NewWispOrphansCheck creates a new wisp orphans check.
|
||||
func NewWispOrphansCheck() *WispOrphansCheck {
|
||||
return &WispOrphansCheck{
|
||||
BaseCheck: BaseCheck{
|
||||
CheckName: "ephemeral-orphans",
|
||||
CheckDescription: "Check for orphaned molecules (>24h old, never squashed)",
|
||||
CheckName: "wisp-orphans",
|
||||
CheckDescription: "Check for orphaned wisps (>24h old, never squashed)",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run checks for orphaned molecules.
|
||||
func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
// Run checks for orphaned wisps.
|
||||
func (c *WispOrphansCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
rigs, err := discoverRigs(ctx.TownRoot)
|
||||
if err != nil {
|
||||
return &CheckResult{
|
||||
@@ -256,13 +256,13 @@ func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
cutoff := time.Now().Add(-24 * time.Hour)
|
||||
|
||||
for _, rigName := range rigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) {
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
if _, err := os.Stat(wispPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Look for molecule directories or issue files older than 24h
|
||||
issuesPath := filepath.Join(ephemeralPath, "issues.jsonl")
|
||||
issuesPath := filepath.Join(wispPath, "issues.jsonl")
|
||||
info, err := os.Stat(issuesPath)
|
||||
if err != nil {
|
||||
continue // No issues file
|
||||
@@ -279,7 +279,7 @@ func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusWarning,
|
||||
Message: fmt.Sprintf("%d rig(s) have stale ephemeral data (>24h old)", len(orphans)),
|
||||
Message: fmt.Sprintf("%d rig(s) have stale wisp data (>24h old)", len(orphans)),
|
||||
Details: orphans,
|
||||
FixHint: "Manual review required - these may contain unsquashed work",
|
||||
}
|
||||
@@ -288,27 +288,27 @@ func (c *EphemeralOrphansCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusOK,
|
||||
Message: "No orphaned molecules found",
|
||||
Message: "No orphaned wisps found",
|
||||
}
|
||||
}
|
||||
|
||||
// EphemeralSizeCheck warns if ephemeral repo is too large (>100MB).
|
||||
type EphemeralSizeCheck struct {
|
||||
// WispSizeCheck warns if wisp repo is too large (>100MB).
|
||||
type WispSizeCheck struct {
|
||||
BaseCheck
|
||||
}
|
||||
|
||||
// NewEphemeralSizeCheck creates a new ephemeral size check.
|
||||
func NewEphemeralSizeCheck() *EphemeralSizeCheck {
|
||||
return &EphemeralSizeCheck{
|
||||
// NewWispSizeCheck creates a new wisp size check.
|
||||
func NewWispSizeCheck() *WispSizeCheck {
|
||||
return &WispSizeCheck{
|
||||
BaseCheck: BaseCheck{
|
||||
CheckName: "ephemeral-size",
|
||||
CheckDescription: "Check if ephemeral beads directories are too large (>100MB)",
|
||||
CheckName: "wisp-size",
|
||||
CheckDescription: "Check if wisp directories are too large (>100MB)",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run checks the size of ephemeral beads directories.
|
||||
func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
// Run checks the size of wisp directories.
|
||||
func (c *WispSizeCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
rigs, err := discoverRigs(ctx.TownRoot)
|
||||
if err != nil {
|
||||
return &CheckResult{
|
||||
@@ -331,12 +331,12 @@ func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
var oversized []string
|
||||
|
||||
for _, rigName := range rigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) {
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
if _, err := os.Stat(wispPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
size, err := dirSize(ephemeralPath)
|
||||
size, err := dirSize(wispPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -351,7 +351,7 @@ func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusWarning,
|
||||
Message: fmt.Sprintf("%d rig(s) have oversized ephemeral directories", len(oversized)),
|
||||
Message: fmt.Sprintf("%d rig(s) have oversized wisp directories", len(oversized)),
|
||||
Details: oversized,
|
||||
FixHint: "Consider cleaning up old completed molecules",
|
||||
}
|
||||
@@ -360,27 +360,27 @@ func (c *EphemeralSizeCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusOK,
|
||||
Message: "All ephemeral directories within size limits",
|
||||
Message: "All wisp directories within size limits",
|
||||
}
|
||||
}
|
||||
|
||||
// EphemeralStaleCheck detects molecules with no activity in the last hour.
|
||||
type EphemeralStaleCheck struct {
|
||||
// WispStaleCheck detects molecules with no activity in the last hour.
|
||||
type WispStaleCheck struct {
|
||||
BaseCheck
|
||||
}
|
||||
|
||||
// NewEphemeralStaleCheck creates a new ephemeral stale check.
|
||||
func NewEphemeralStaleCheck() *EphemeralStaleCheck {
|
||||
return &EphemeralStaleCheck{
|
||||
// NewWispStaleCheck creates a new wisp stale check.
|
||||
func NewWispStaleCheck() *WispStaleCheck {
|
||||
return &WispStaleCheck{
|
||||
BaseCheck: BaseCheck{
|
||||
CheckName: "ephemeral-stale",
|
||||
CheckDescription: "Check for stale molecules (no activity in last hour)",
|
||||
CheckName: "wisp-stale",
|
||||
CheckDescription: "Check for stale wisps (no activity in last hour)",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Run checks for stale molecules.
|
||||
func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
// Run checks for stale wisps.
|
||||
func (c *WispStaleCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
rigs, err := discoverRigs(ctx.TownRoot)
|
||||
if err != nil {
|
||||
return &CheckResult{
|
||||
@@ -403,15 +403,15 @@ func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
cutoff := time.Now().Add(-1 * time.Hour)
|
||||
|
||||
for _, rigName := range rigs {
|
||||
ephemeralPath := filepath.Join(ctx.TownRoot, rigName, ".beads-ephemeral")
|
||||
if _, err := os.Stat(ephemeralPath); os.IsNotExist(err) {
|
||||
wispPath := filepath.Join(ctx.TownRoot, rigName, ".beads-wisp")
|
||||
if _, err := os.Stat(wispPath); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for any recent activity in the ephemeral directory
|
||||
// Check for any recent activity in the wisp directory
|
||||
// We look at the most recent modification time of any file
|
||||
var mostRecent time.Time
|
||||
_ = filepath.Walk(ephemeralPath, func(path string, info os.FileInfo, err error) error {
|
||||
_ = filepath.Walk(wispPath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -432,7 +432,7 @@ func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusWarning,
|
||||
Message: fmt.Sprintf("%d rig(s) have stale ephemeral activity", len(stale)),
|
||||
Message: fmt.Sprintf("%d rig(s) have stale wisp activity", len(stale)),
|
||||
Details: stale,
|
||||
FixHint: "Check if polecats are stuck or crashed",
|
||||
}
|
||||
@@ -441,7 +441,7 @@ func (c *EphemeralStaleCheck) Run(ctx *CheckContext) *CheckResult {
|
||||
return &CheckResult{
|
||||
Name: c.Name(),
|
||||
Status: StatusOK,
|
||||
Message: "No stale ephemeral activity detected",
|
||||
Message: "No stale wisp activity detected",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ func (m *Manager) AssignIssue(name, issue string) error {
|
||||
}
|
||||
|
||||
// ClearIssue removes the issue assignment from a polecat.
|
||||
// In the ephemeral model, this transitions to Done state for cleanup.
|
||||
// In the transient model, this transitions to Done state for cleanup.
|
||||
// This clears the assignee from the currently assigned issue in beads.
|
||||
// If beads is not available, this is a no-op.
|
||||
func (m *Manager) ClearIssue(name string) error {
|
||||
@@ -485,7 +485,7 @@ func (m *Manager) ClearIssue(name string) error {
|
||||
}
|
||||
|
||||
// Wake transitions a polecat from idle to active.
|
||||
// Deprecated: In the ephemeral model, polecats start in working state.
|
||||
// Deprecated: In the transient model, polecats start in working state.
|
||||
// This method is kept for backward compatibility with existing polecats.
|
||||
func (m *Manager) Wake(name string) error {
|
||||
polecat, err := m.Get(name)
|
||||
@@ -502,7 +502,7 @@ func (m *Manager) Wake(name string) error {
|
||||
}
|
||||
|
||||
// Sleep transitions a polecat from active to idle.
|
||||
// Deprecated: In the ephemeral model, polecats are deleted when done.
|
||||
// Deprecated: In the transient model, polecats are deleted when done.
|
||||
// This method is kept for backward compatibility.
|
||||
func (m *Manager) Sleep(name string) error {
|
||||
polecat, err := m.Get(name)
|
||||
|
||||
@@ -4,12 +4,12 @@ package polecat
|
||||
import "time"
|
||||
|
||||
// State represents the current state of a polecat.
|
||||
// In the ephemeral model, polecats exist only while working.
|
||||
// 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 ephemeral polecats.
|
||||
// This is the initial and primary state for transient polecats.
|
||||
StateWorking State = "working"
|
||||
|
||||
// StateDone means the polecat has completed its assigned work
|
||||
@@ -31,7 +31,7 @@ func (s State) IsWorking() bool {
|
||||
}
|
||||
|
||||
// IsActive returns true if the polecat session is actively working.
|
||||
// For ephemeral polecats, this is true for working state and
|
||||
// For transient polecats, this is true for working state and
|
||||
// legacy idle/active states (treated as working).
|
||||
func (s State) IsActive() bool {
|
||||
return s == StateWorking || s == StateIdle || s == StateActive
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
## Your Role: CREW WORKER ({{ .Polecat }} in {{ .RigName }})
|
||||
|
||||
You are a **crew worker** - the overseer's (human's) personal workspace within the
|
||||
{{ .RigName }} rig. Unlike polecats which are witness-managed and ephemeral, you are:
|
||||
{{ .RigName }} rig. Unlike polecats which are witness-managed and transient, you are:
|
||||
|
||||
- **Persistent**: Your workspace is never auto-garbage-collected
|
||||
- **User-managed**: The overseer controls your lifecycle, not the Witness
|
||||
@@ -26,7 +26,7 @@ Town ({{ .TownRoot }})
|
||||
│ ├── .beads/ ← Issue tracking (you have write access)
|
||||
│ ├── crew/
|
||||
│ │ └── {{ .Polecat }}/ ← You are here (your git clone)
|
||||
│ ├── polecats/ ← Ephemeral workers (not you)
|
||||
│ ├── polecats/ ← Transient workers (not you)
|
||||
│ ├── refinery/ ← Merge queue processor
|
||||
│ └── witness/ ← Polecat lifecycle (doesn't monitor you)
|
||||
```
|
||||
@@ -141,7 +141,7 @@ Before ending your session:
|
||||
|
||||
## Tips
|
||||
|
||||
- **You own your workspace**: Unlike polecats, you're not ephemeral. Keep it organized.
|
||||
- **You own your workspace**: Unlike polecats, you're not transient. Keep it organized.
|
||||
- **Handoff liberally**: When in doubt, write a handoff mail. Context is precious.
|
||||
- **Stay in sync**: Pull from upstream regularly to avoid merge conflicts.
|
||||
- **Ask for help**: No Witness means no automatic escalation. Reach out proactively.
|
||||
|
||||
@@ -553,7 +553,7 @@ func extractPolecatName(body string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// cleanupPolecat performs the full cleanup sequence for an ephemeral polecat.
|
||||
// cleanupPolecat performs the full cleanup sequence for a transient polecat.
|
||||
// 1. Check for uncommitted work (stubbornly refuses to lose work)
|
||||
// 2. Kill session
|
||||
// 3. Remove worktree
|
||||
|
||||
Reference in New Issue
Block a user