Merge morsov: AgentIdentity, session helpers
This commit is contained in:
@@ -227,6 +227,8 @@ func runDone(cmd *cobra.Command, args []string) error {
|
||||
// - COMPLETED → "done"
|
||||
// - ESCALATED → "stuck"
|
||||
// - DEFERRED → "idle"
|
||||
//
|
||||
// Also self-reports cleanup_status for ZFC compliance (#10).
|
||||
func updateAgentStateOnDone(cwd, townRoot, exitType, issueID string) {
|
||||
// Get role context
|
||||
roleInfo, err := GetRoleWithContext(cwd, townRoot)
|
||||
@@ -267,4 +269,37 @@ func updateAgentStateOnDone(cwd, townRoot, exitType, issueID string) {
|
||||
// Silently ignore - beads might not be configured
|
||||
return
|
||||
}
|
||||
|
||||
// ZFC #10: Self-report cleanup status
|
||||
// Compute git state and report so Witness can decide removal safety
|
||||
cleanupStatus := computeCleanupStatus(cwd)
|
||||
if cleanupStatus != "" {
|
||||
if err := bd.UpdateAgentCleanupStatus(agentBeadID, cleanupStatus); err != nil {
|
||||
// Silently ignore
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// computeCleanupStatus checks git state and returns the cleanup status.
|
||||
// Returns the most critical issue: has_unpushed > has_stash > has_uncommitted > clean
|
||||
func computeCleanupStatus(cwd string) string {
|
||||
g := git.NewGit(cwd)
|
||||
status, err := g.CheckUncommittedWork()
|
||||
if err != nil {
|
||||
// If we can't check, report unknown - Witness should be cautious
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// Check in priority order (most critical first)
|
||||
if status.UnpushedCommits > 0 {
|
||||
return "has_unpushed"
|
||||
}
|
||||
if status.StashCount > 0 {
|
||||
return "has_stash"
|
||||
}
|
||||
if status.HasUncommittedChanges {
|
||||
return "has_uncommitted"
|
||||
}
|
||||
return "clean"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/gastown/internal/session"
|
||||
"github.com/steveyegge/gastown/internal/style"
|
||||
"github.com/steveyegge/gastown/internal/tmux"
|
||||
"github.com/steveyegge/gastown/internal/workspace"
|
||||
@@ -371,34 +372,13 @@ func sessionWorkDir(sessionName, townRoot string) (string, error) {
|
||||
}
|
||||
|
||||
// sessionToGTRole converts a session name to a GT_ROLE value.
|
||||
// Uses session.ParseSessionName for consistent parsing across the codebase.
|
||||
func sessionToGTRole(sessionName string) string {
|
||||
switch {
|
||||
case sessionName == "gt-mayor":
|
||||
return "mayor"
|
||||
case sessionName == "gt-deacon":
|
||||
return "deacon"
|
||||
case strings.Contains(sessionName, "-crew-"):
|
||||
// gt-<rig>-crew-<name> -> <rig>/crew/<name>
|
||||
parts := strings.Split(sessionName, "-")
|
||||
for i, p := range parts {
|
||||
if p == "crew" && i > 1 && i < len(parts)-1 {
|
||||
rig := strings.Join(parts[1:i], "-")
|
||||
name := strings.Join(parts[i+1:], "-")
|
||||
return fmt.Sprintf("%s/crew/%s", rig, name)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
case strings.HasSuffix(sessionName, "-witness"):
|
||||
rig := strings.TrimPrefix(sessionName, "gt-")
|
||||
rig = strings.TrimSuffix(rig, "-witness")
|
||||
return fmt.Sprintf("%s/witness", rig)
|
||||
case strings.HasSuffix(sessionName, "-refinery"):
|
||||
rig := strings.TrimPrefix(sessionName, "gt-")
|
||||
rig = strings.TrimSuffix(rig, "-refinery")
|
||||
return fmt.Sprintf("%s/refinery", rig)
|
||||
default:
|
||||
identity, err := session.ParseSessionName(sessionName)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return identity.GTRole()
|
||||
}
|
||||
|
||||
// detectTownRootFromCwd walks up from the current directory to find the town root.
|
||||
|
||||
@@ -6,18 +6,14 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/gastown/internal/beads"
|
||||
"github.com/steveyegge/gastown/internal/session"
|
||||
"github.com/steveyegge/gastown/internal/style"
|
||||
"github.com/steveyegge/gastown/internal/tmux"
|
||||
)
|
||||
|
||||
// claudeStartupDelay is how long to wait for Claude to start before nudging.
|
||||
// This fixes gt-1dbcp: polecat auto-start doesn't process initial nudge.
|
||||
const claudeStartupDelay = 2 * time.Second
|
||||
|
||||
var slingCmd = &cobra.Command{
|
||||
Use: "sling <bead-or-formula> [target]",
|
||||
GroupID: GroupWork,
|
||||
@@ -181,12 +177,6 @@ func runSling(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
targetAgent = spawnInfo.AgentID()
|
||||
targetPane = spawnInfo.Pane
|
||||
|
||||
// Wait for Claude to start up before nudging (fixes gt-1dbcp)
|
||||
if targetPane != "" {
|
||||
fmt.Printf("Waiting for Claude to initialize...\n")
|
||||
time.Sleep(claudeStartupDelay)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Slinging to an existing agent
|
||||
@@ -257,7 +247,7 @@ func runSling(cmd *cobra.Command, args []string) error {
|
||||
if slingArgs != "" {
|
||||
if err := storeArgsInBead(beadID, slingArgs); err != nil {
|
||||
// Warn but don't fail - args will still be in the nudge prompt
|
||||
style.PrintWarning("Could not store args in bead: %v", err)
|
||||
fmt.Printf("%s Could not store args in bead: %v\n", style.Dim.Render("Warning:"), err)
|
||||
} else {
|
||||
fmt.Printf("%s Args stored in bead (durable)\n", style.Bold.Render("✓"))
|
||||
}
|
||||
@@ -373,40 +363,14 @@ func resolveTargetAgent(target string) (agentID string, pane string, hookRoot st
|
||||
}
|
||||
|
||||
// sessionToAgentID converts a session name to agent ID format.
|
||||
func sessionToAgentID(session string) string {
|
||||
switch {
|
||||
case session == "gt-mayor":
|
||||
return "mayor"
|
||||
case session == "gt-deacon":
|
||||
return "deacon"
|
||||
case strings.Contains(session, "-crew-"):
|
||||
// gt-gastown-crew-max -> gastown/crew/max
|
||||
parts := strings.Split(session, "-")
|
||||
for i, p := range parts {
|
||||
if p == "crew" && i > 1 && i < len(parts)-1 {
|
||||
rig := strings.Join(parts[1:i], "-")
|
||||
name := strings.Join(parts[i+1:], "-")
|
||||
return fmt.Sprintf("%s/crew/%s", rig, name)
|
||||
}
|
||||
}
|
||||
case strings.HasSuffix(session, "-witness"):
|
||||
rig := strings.TrimPrefix(session, "gt-")
|
||||
rig = strings.TrimSuffix(rig, "-witness")
|
||||
return fmt.Sprintf("%s/witness", rig)
|
||||
case strings.HasSuffix(session, "-refinery"):
|
||||
rig := strings.TrimPrefix(session, "gt-")
|
||||
rig = strings.TrimSuffix(rig, "-refinery")
|
||||
return fmt.Sprintf("%s/refinery", rig)
|
||||
case strings.HasPrefix(session, "gt-"):
|
||||
// gt-gastown-nux -> gastown/polecats/nux (polecat)
|
||||
parts := strings.Split(strings.TrimPrefix(session, "gt-"), "-")
|
||||
if len(parts) >= 2 {
|
||||
rig := parts[0]
|
||||
name := strings.Join(parts[1:], "-")
|
||||
return fmt.Sprintf("%s/polecats/%s", rig, name)
|
||||
}
|
||||
// Uses session.ParseSessionName for consistent parsing across the codebase.
|
||||
func sessionToAgentID(sessionName string) string {
|
||||
identity, err := session.ParseSessionName(sessionName)
|
||||
if err != nil {
|
||||
// Fallback for unparseable sessions
|
||||
return sessionName
|
||||
}
|
||||
return session
|
||||
return identity.Address()
|
||||
}
|
||||
|
||||
// verifyBeadExists checks that the bead exists using bd show.
|
||||
@@ -550,12 +514,6 @@ func runSlingFormula(args []string) error {
|
||||
}
|
||||
targetAgent = spawnInfo.AgentID()
|
||||
targetPane = spawnInfo.Pane
|
||||
|
||||
// Wait for Claude to start up before nudging (fixes gt-1dbcp)
|
||||
if targetPane != "" {
|
||||
fmt.Printf("Waiting for Claude to initialize...\n")
|
||||
time.Sleep(claudeStartupDelay)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Slinging to an existing agent
|
||||
@@ -614,7 +572,7 @@ func runSlingFormula(args []string) error {
|
||||
}
|
||||
if err := json.Unmarshal(wispOut, &wispResult); err != nil {
|
||||
// Fallback: use formula name as identifier, but warn user
|
||||
style.PrintWarning("Could not parse wisp output, using formula name as ID")
|
||||
fmt.Printf("%s Could not parse wisp output, using formula name as ID\n", style.Dim.Render("Warning:"))
|
||||
wispResult.RootID = formulaName
|
||||
}
|
||||
|
||||
@@ -634,7 +592,7 @@ func runSlingFormula(args []string) error {
|
||||
// Store args in wisp bead if provided (no-tmux mode: beads as data plane)
|
||||
if slingArgs != "" {
|
||||
if err := storeArgsInBead(wispResult.RootID, slingArgs); err != nil {
|
||||
style.PrintWarning("Could not store args in bead: %v", err)
|
||||
fmt.Printf("%s Could not store args in bead: %v\n", style.Dim.Render("Warning:"), err)
|
||||
} else {
|
||||
fmt.Printf("%s Args stored in bead (durable)\n", style.Bold.Render("✓"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user