fix: Address golangci-lint errors (errcheck, gosec) (#76)

Apply PR #76 from dannomayernotabot:

- Add golangci exclusions for internal package false positives
- Tighten file permissions (0644 -> 0600) for sensitive files
- Add ReadHeaderTimeout to HTTP server (slowloris prevention)
- Explicit error ignoring with _ = for intentional cases
- Add //nolint comments with justifications
- Spelling: cancelled -> canceled (US locale)

Co-Authored-By: dannomayernotabot <noreply@github.com>

🤖 Generated with Claude Code
This commit is contained in:
max
2026-01-03 16:11:40 -08:00
committed by Steve Yegge
parent 62848065e3
commit 1b69576573
82 changed files with 325 additions and 355 deletions
+1 -1
View File
@@ -159,7 +159,7 @@ func parseDuration(s string) (time.Duration, error) {
}
// collectGitCommits queries git log for commits by the actor.
func collectGitCommits(townRoot, actor string, since time.Time) ([]AuditEntry, error) {
func collectGitCommits(townRoot, actor string, since time.Time) ([]AuditEntry, error) { //nolint:unparam // error return kept for future use
var entries []AuditEntry
// Build git log command
+1 -4
View File
@@ -277,10 +277,7 @@ func runDegradedTriage(b *boot.Boot) (action, target string, err error) {
tm := b.Tmux()
// Check if Deacon session exists
deaconSession, err := getDeaconSessionName()
if err != nil {
return "error", "deacon", fmt.Errorf("getting deacon session name: %w", err)
}
deaconSession := getDeaconSessionName()
hasDeacon, err := tm.HasSession(deaconSession)
if err != nil {
return "error", "deacon", fmt.Errorf("checking deacon session: %w", err)
+3 -3
View File
@@ -274,7 +274,7 @@ func classifyCallback(subject string) CallbackType {
// handlePolecatDone processes a POLECAT_DONE callback.
// These come from Witnesses forwarding polecat completion notices.
func handlePolecatDone(townRoot string, msg *mail.Message, dryRun bool) (string, error) {
func handlePolecatDone(townRoot string, msg *mail.Message, dryRun bool) (string, error) { //nolint:unparam // error return kept for consistency with callback interface
matches := patternPolecatDone.FindStringSubmatch(msg.Subject)
polecatName := ""
if len(matches) > 1 {
@@ -306,7 +306,7 @@ func handlePolecatDone(townRoot string, msg *mail.Message, dryRun bool) (string,
}
// handleMergeCompleted processes a merge completion callback from Refinery.
func handleMergeCompleted(townRoot string, msg *mail.Message, dryRun bool) (string, error) {
func handleMergeCompleted(townRoot string, msg *mail.Message, dryRun bool) (string, error) { //nolint:unparam // error return kept for consistency with callback interface
matches := patternMergeCompleted.FindStringSubmatch(msg.Subject)
branch := ""
if len(matches) > 1 {
@@ -353,7 +353,7 @@ func handleMergeCompleted(townRoot string, msg *mail.Message, dryRun bool) (stri
}
// handleMergeRejected processes a merge rejection callback from Refinery.
func handleMergeRejected(townRoot string, msg *mail.Message, dryRun bool) (string, error) {
func handleMergeRejected(townRoot string, msg *mail.Message, dryRun bool) (string, error) { //nolint:unparam // error return kept for consistency with callback interface
matches := patternMergeRejected.FindStringSubmatch(msg.Subject)
branch := ""
if len(matches) > 1 {
+1 -1
View File
@@ -23,7 +23,7 @@ import (
// generateShortID generates a short random ID (5 lowercase chars).
func generateShortID() string {
b := make([]byte, 3)
rand.Read(b)
_, _ = rand.Read(b)
return strings.ToLower(base32.StdEncoding.EncodeToString(b)[:5])
}
+2 -2
View File
@@ -202,7 +202,7 @@ func attachToTmuxSession(sessionID string) error {
// ensureMainBranch checks if a git directory is on main branch.
// If not, warns the user and offers to switch.
// Returns true if on main (or switched to main), false if user declined.
func ensureMainBranch(dir, roleName string) bool {
func ensureMainBranch(dir, roleName string) bool { //nolint:unparam // bool return kept for future callers to check
g := git.NewGit(dir)
branch, err := g.CurrentBranch()
@@ -271,7 +271,7 @@ func parseCrewSessionName(sessionName string) (rigName, crewName string, ok bool
// findRigCrewSessions returns all crew sessions for a given rig, sorted alphabetically.
// Uses tmux list-sessions to find sessions matching gt-<rig>-crew-* pattern.
func findRigCrewSessions(rigName string) ([]string, error) {
func findRigCrewSessions(rigName string) ([]string, error) { //nolint:unparam // error return kept for future use
cmd := exec.Command("tmux", "list-sessions", "-F", "#{session_name}")
out, err := cmd.Output()
if err != nil {
+3 -3
View File
@@ -337,7 +337,7 @@ func runCrewRestart(cmd *cobra.Command, args []string) error {
}
// Set environment
t.SetEnvironment(sessionID, "GT_ROLE", "crew")
_ = t.SetEnvironment(sessionID, "GT_ROLE", "crew")
// Apply rig-based theming (non-fatal: theming failure doesn't affect operation)
theme := getThemeForRig(r.Name)
_ = t.ConfigureGasTownSession(sessionID, theme, r.Name, name, "crew")
@@ -596,7 +596,7 @@ func runCrewStop(cmd *cobra.Command, args []string) error {
if townRoot != "" {
agent := fmt.Sprintf("%s/crew/%s", r.Name, name)
logger := townlog.NewLogger(townRoot)
logger.Log(townlog.EventKill, agent, "gt crew stop")
_ = logger.Log(townlog.EventKill, agent, "gt crew stop")
}
// Log captured output (truncated)
@@ -682,7 +682,7 @@ func runCrewStopAll() error {
townRoot, _ := workspace.FindFromCwd()
if townRoot != "" {
logger := townlog.NewLogger(townRoot)
logger.Log(townlog.EventKill, agentName, "gt crew stop --all")
_ = logger.Log(townlog.EventKill, agentName, "gt crew stop --all")
}
// Log captured output (truncated)
+8 -2
View File
@@ -5,6 +5,7 @@ import (
"net/http"
"os/exec"
"runtime"
"time"
"github.com/spf13/cobra"
"github.com/steveyegge/gastown/internal/web"
@@ -67,11 +68,16 @@ func runDashboard(cmd *cobra.Command, args []string) error {
go openBrowser(url)
}
// Start the server
// Start the server with timeouts
fmt.Printf("🚚 Gas Town Dashboard starting at %s\n", url)
fmt.Printf(" Press Ctrl+C to stop\n")
return http.ListenAndServe(fmt.Sprintf(":%d", dashboardPort), handler)
server := &http.Server{
Addr: fmt.Sprintf(":%d", dashboardPort),
Handler: handler,
ReadHeaderTimeout: 10 * time.Second,
}
return server.ListenAndServe()
}
// openBrowser opens the specified URL in the default browser.
+9 -24
View File
@@ -22,8 +22,8 @@ import (
)
// getDeaconSessionName returns the Deacon session name.
func getDeaconSessionName() (string, error) {
return session.DeaconSessionName(), nil
func getDeaconSessionName() string {
return session.DeaconSessionName()
}
var deaconCmd = &cobra.Command{
@@ -276,10 +276,7 @@ func init() {
func runDeaconStart(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getDeaconSessionName()
if err != nil {
return err
}
sessionName := getDeaconSessionName()
// Check if session already exists
running, err := t.HasSession(sessionName)
@@ -370,10 +367,7 @@ func startDeaconSession(t *tmux.Tmux, sessionName string) error {
func runDeaconStop(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getDeaconSessionName()
if err != nil {
return err
}
sessionName := getDeaconSessionName()
// Check if session exists
running, err := t.HasSession(sessionName)
@@ -402,10 +396,7 @@ func runDeaconStop(cmd *cobra.Command, args []string) error {
func runDeaconAttach(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getDeaconSessionName()
if err != nil {
return err
}
sessionName := getDeaconSessionName()
// Check if session exists
running, err := t.HasSession(sessionName)
@@ -428,10 +419,7 @@ func runDeaconAttach(cmd *cobra.Command, args []string) error {
func runDeaconStatus(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getDeaconSessionName()
if err != nil {
return err
}
sessionName := getDeaconSessionName()
running, err := t.HasSession(sessionName)
if err != nil {
@@ -470,10 +458,7 @@ func runDeaconStatus(cmd *cobra.Command, args []string) error {
func runDeaconRestart(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getDeaconSessionName()
if err != nil {
return err
}
sessionName := getDeaconSessionName()
running, err := t.HasSession(sessionName)
if err != nil {
@@ -1092,7 +1077,7 @@ func getPolecatStaleness(polecatPath string) time.Duration {
}
// nukeZombie cleans up a zombie polecat.
func nukeZombie(townRoot string, z zombieInfo, t *tmux.Tmux) error {
func nukeZombie(townRoot string, z zombieInfo, t *tmux.Tmux) error { //nolint:unparam // error return kept for future use
// Step 1: Kill tmux session if somehow still exists
if exists, _ := t.HasSession(z.sessionName); exists {
_ = t.KillSession(z.sessionName)
@@ -1204,7 +1189,7 @@ func sendMail(townRoot, to, subject, body string) {
}
// updateAgentBeadState updates an agent bead's state.
func updateAgentBeadState(townRoot, agent, state, reason string) {
func updateAgentBeadState(townRoot, agent, state, _ string) { // reason unused but kept for API consistency
beadID, _, err := agentAddressToIDs(agent)
if err != nil {
return
+2 -2
View File
@@ -326,7 +326,7 @@ func runDone(cmd *cobra.Command, args []string) error {
}
// Log done event (townlog and activity feed)
LogDone(townRoot, sender, issueID)
_ = LogDone(townRoot, sender, issueID)
_ = events.LogFeed(events.TypeDone, sender, events.DonePayload(issueID, branch))
// Update agent bead state (ZFC: self-report completion)
@@ -352,7 +352,7 @@ func runDone(cmd *cobra.Command, args []string) error {
// - PHASE_COMPLETE → "awaiting-gate"
//
// Also self-reports cleanup_status for ZFC compliance (#10).
func updateAgentStateOnDone(cwd, townRoot, exitType, issueID string) {
func updateAgentStateOnDone(cwd, townRoot, exitType, _ string) { // issueID unused but kept for future audit logging
// Get role context
roleInfo, err := GetRoleWithContext(cwd, townRoot)
if err != nil {
+2 -2
View File
@@ -74,8 +74,8 @@ func runDown(cmd *cobra.Command, args []string) error {
}
// Get session names
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
// 2. Stop Mayor
if err := stopSession(t, mayorSession); err != nil {
+4 -4
View File
@@ -226,7 +226,7 @@ func runFeedTUI(workDir string) error {
// Combine all sources
multiSource := feed.NewMultiSource(sources...)
defer multiSource.Close()
defer func() { _ = multiSource.Close() }()
// Create model and connect event source
m := feed.NewModel()
@@ -305,7 +305,7 @@ func runFeedInWindow(workDir string, bdArgs []string) error {
// windowExists checks if a window with the given name exists in the session.
// Note: getCurrentTmuxSession is defined in handoff.go
func windowExists(t *tmux.Tmux, session, windowName string) (bool, error) {
func windowExists(_ *tmux.Tmux, session, windowName string) (bool, error) { // t unused: direct exec for simplicity
cmd := exec.Command("tmux", "list-windows", "-t", session, "-F", "#{window_name}")
out, err := cmd.Output()
if err != nil {
@@ -321,14 +321,14 @@ func windowExists(t *tmux.Tmux, session, windowName string) (bool, error) {
}
// createWindow creates a new tmux window with the given name and command.
func createWindow(t *tmux.Tmux, session, windowName, workDir, command string) error {
func createWindow(_ *tmux.Tmux, session, windowName, workDir, command string) error { // t unused: direct exec for simplicity
args := []string{"new-window", "-t", session, "-n", windowName, "-c", workDir, command}
cmd := exec.Command("tmux", args...)
return cmd.Run()
}
// selectWindow switches to the specified window.
func selectWindow(t *tmux.Tmux, target string) error {
func selectWindow(_ *tmux.Tmux, target string) error { // t unused: direct exec for simplicity
cmd := exec.Command("tmux", "select-window", "-t", target)
return cmd.Run()
}
+1 -1
View File
@@ -683,7 +683,7 @@ func extractPrompts(content string) map[string]string {
// generateFormulaShortID generates a short random ID (5 lowercase chars)
func generateFormulaShortID() string {
b := make([]byte, 3)
rand.Read(b)
_, _ = rand.Read(b)
return strings.ToLower(base32.StdEncoding.EncodeToString(b)[:5])
}
+5 -13
View File
@@ -155,7 +155,7 @@ func runHandoff(cmd *cobra.Command, args []string) error {
if agent == "" {
agent = currentSession
}
LogHandoff(townRoot, agent, handoffSubject)
_ = LogHandoff(townRoot, agent, handoffSubject)
// Also log to activity feed
_ = events.LogFeed(events.TypeHandoff, agent, events.HandoffPayload(handoffSubject, true))
}
@@ -230,18 +230,10 @@ func resolveRoleToSession(role string) (string, error) {
switch strings.ToLower(role) {
case "mayor", "may":
mayorSession, err := getMayorSessionName()
if err != nil {
return "", fmt.Errorf("cannot determine mayor session name: %w", err)
}
return mayorSession, nil
return getMayorSessionName(), nil
case "deacon", "dea":
deaconSession, err := getDeaconSessionName()
if err != nil {
return "", fmt.Errorf("cannot determine deacon session name: %w", err)
}
return deaconSession, nil
return getDeaconSessionName(), nil
case "crew":
// Try to get rig and crew name from environment or cwd
@@ -369,8 +361,8 @@ func buildRestartCommand(sessionName string) (string, error) {
// This is the canonical home for each role type.
func sessionWorkDir(sessionName, townRoot string) (string, error) {
// Get session names for comparison
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
switch {
case sessionName == mayorSession:
+1 -1
View File
@@ -114,7 +114,7 @@ func runHookOrStatus(cmd *cobra.Command, args []string) error {
return runHook(cmd, args)
}
func runHook(cmd *cobra.Command, args []string) error {
func runHook(_ *cobra.Command, args []string) error {
beadID := args[0]
// Polecats cannot hook - they use gt done for lifecycle
+1 -4
View File
@@ -122,10 +122,7 @@ func detectCurrentSession() string {
// Check if we're mayor
if os.Getenv("GT_ROLE") == "mayor" {
mayorSession, err := getMayorSessionName()
if err == nil {
return mayorSession
}
return getMayorSessionName()
}
return ""
+1 -1
View File
@@ -433,7 +433,7 @@ func init() {
// Reply flags
mailReplyCmd.Flags().StringVarP(&mailReplySubject, "subject", "s", "", "Override reply subject (default: Re: <original>)")
mailReplyCmd.Flags().StringVarP(&mailReplyMessage, "message", "m", "", "Reply message body (required)")
mailReplyCmd.MarkFlagRequired("message")
_ = mailReplyCmd.MarkFlagRequired("message")
// Search flags
mailSearchCmd.Flags().StringVar(&mailSearchFrom, "from", "", "Filter by sender address")
+7 -22
View File
@@ -15,8 +15,8 @@ import (
)
// getMayorSessionName returns the Mayor session name.
func getMayorSessionName() (string, error) {
return session.MayorSessionName(), nil
func getMayorSessionName() string {
return session.MayorSessionName()
}
var mayorCmd = &cobra.Command{
@@ -90,10 +90,7 @@ func init() {
func runMayorStart(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getMayorSessionName()
if err != nil {
return err
}
sessionName := getMayorSessionName()
// Check if session already exists
running, err := t.HasSession(sessionName)
@@ -172,10 +169,7 @@ func startMayorSession(t *tmux.Tmux, sessionName string) error {
func runMayorStop(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getMayorSessionName()
if err != nil {
return err
}
sessionName := getMayorSessionName()
// Check if session exists
running, err := t.HasSession(sessionName)
@@ -204,10 +198,7 @@ func runMayorStop(cmd *cobra.Command, args []string) error {
func runMayorAttach(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getMayorSessionName()
if err != nil {
return err
}
sessionName := getMayorSessionName()
// Check if session exists
running, err := t.HasSession(sessionName)
@@ -229,10 +220,7 @@ func runMayorAttach(cmd *cobra.Command, args []string) error {
func runMayorStatus(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getMayorSessionName()
if err != nil {
return err
}
sessionName := getMayorSessionName()
running, err := t.HasSession(sessionName)
if err != nil {
@@ -271,10 +259,7 @@ func runMayorStatus(cmd *cobra.Command, args []string) error {
func runMayorRestart(cmd *cobra.Command, args []string) error {
t := tmux.NewTmux()
sessionName, err := getMayorSessionName()
if err != nil {
return err
}
sessionName := getMayorSessionName()
running, err := t.HasSession(sessionName)
if err != nil {
+1 -1
View File
@@ -235,7 +235,7 @@ func calculateEffectiveTimeout(idleCycles int) (time.Duration, error) {
}
// waitForActivitySignal starts bd activity --follow and waits for any output.
// Returns immediately when a line is received, or when context is cancelled.
// Returns immediately when a line is received, or when context is canceled.
func waitForActivitySignal(ctx context.Context, workDir string) (*AwaitSignalResult, error) {
// Start bd activity --follow
cmd := exec.CommandContext(ctx, "bd", "activity", "--follow")
+1 -1
View File
@@ -250,7 +250,7 @@ func findNextReadyStep(b *beads.Beads, moleculeID string) (*beads.Issue, bool, e
}
// handleStepContinue handles continuing to the next step.
func handleStepContinue(cwd, townRoot, workDir string, nextStep *beads.Issue, dryRun bool) error {
func handleStepContinue(cwd, townRoot, _ string, nextStep *beads.Issue, dryRun bool) error { // workDir unused but kept for signature consistency
fmt.Printf("\n%s Next step: %s\n", style.Bold.Render("→"), nextStep.ID)
fmt.Printf(" %s\n", nextStep.Title)
+4 -4
View File
@@ -163,7 +163,7 @@ func runNudge(cmd *cobra.Command, args []string) error {
// Log nudge event
if townRoot, err := workspace.FindFromCwd(); err == nil && townRoot != "" {
LogNudge(townRoot, "deacon", message)
_ = LogNudge(townRoot, "deacon", message)
}
_ = events.LogFeed(events.TypeNudge, sender, events.NudgePayload("", "deacon", message))
return nil
@@ -202,7 +202,7 @@ func runNudge(cmd *cobra.Command, args []string) error {
// Log nudge event
if townRoot, err := workspace.FindFromCwd(); err == nil && townRoot != "" {
LogNudge(townRoot, target, message)
_ = LogNudge(townRoot, target, message)
}
_ = events.LogFeed(events.TypeNudge, sender, events.NudgePayload(rigName, target, message))
} else {
@@ -223,7 +223,7 @@ func runNudge(cmd *cobra.Command, args []string) error {
// Log nudge event
if townRoot, err := workspace.FindFromCwd(); err == nil && townRoot != "" {
LogNudge(townRoot, target, message)
_ = LogNudge(townRoot, target, message)
}
_ = events.LogFeed(events.TypeNudge, sender, events.NudgePayload("", target, message))
}
@@ -424,7 +424,7 @@ func resolveNudgePattern(pattern string, agents []*AgentSession) []string {
// Returns (shouldSend bool, level string, err error).
// If force is true, always returns true.
// If the agent bead cannot be found, returns true (fail-open for backward compatibility).
func shouldNudgeTarget(townRoot, targetAddress string, force bool) (bool, string, error) {
func shouldNudgeTarget(townRoot, targetAddress string, force bool) (bool, string, error) { //nolint:unparam // error return kept for future use
if force {
return true, "", nil
}
+4 -4
View File
@@ -82,15 +82,15 @@ func cyclePolecatSession(direction int, sessionOverride string) error {
// parsePolecatSessionName extracts rig and polecat name from a tmux session name.
// Format: gt-<rig>-<name> where name is NOT crew-*, witness, or refinery.
// Returns empty strings and false if the format doesn't match.
func parsePolecatSessionName(sessionName string) (rigName, polecatName string, ok bool) {
func parsePolecatSessionName(sessionName string) (rigName, polecatName string, ok bool) { //nolint:unparam // polecatName kept for API consistency
// Must start with "gt-"
if !strings.HasPrefix(sessionName, "gt-") {
return "", "", false
}
// Exclude town-level sessions by exact match
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
if sessionName == mayorSession || sessionName == deaconSession {
return "", "", false
}
@@ -133,7 +133,7 @@ func parsePolecatSessionName(sessionName string) (rigName, polecatName string, o
// findRigPolecatSessions returns all polecat sessions for a given rig.
// Uses tmux list-sessions to find sessions matching gt-<rig>-<name> pattern,
// excluding crew, witness, and refinery sessions.
func findRigPolecatSessions(rigName string) ([]string, error) {
func findRigPolecatSessions(rigName string) ([]string, error) { //nolint:unparam // error return kept for future use
cmd := exec.Command("tmux", "list-sessions", "-F", "#{session_name}")
out, err := cmd.Output()
if err != nil {
+3 -3
View File
@@ -101,8 +101,8 @@ func runPrime(cmd *cobra.Command, args []string) error {
persistSessionID(cwd, sessionID)
}
// Set environment for this process (affects event emission below)
os.Setenv("GT_SESSION_ID", sessionID)
os.Setenv("CLAUDE_SESSION_ID", sessionID) // Legacy compatibility
_ = os.Setenv("GT_SESSION_ID", sessionID)
_ = os.Setenv("CLAUDE_SESSION_ID", sessionID) // Legacy compatibility
// Output session beacon
fmt.Printf("[session:%s]\n", sessionID)
if source != "" {
@@ -1564,7 +1564,7 @@ func emitSessionEvent(ctx RoleContext) {
// Emit the event
payload := events.SessionPayload(sessionID, actor, topic, ctx.WorkDir)
events.LogFeed(events.TypeSessionStart, actor, payload)
_ = events.LogFeed(events.TypeSessionStart, actor, payload)
}
// outputSessionMetadata prints a structured metadata line for seance discovery.
+2 -2
View File
@@ -278,7 +278,7 @@ func runSessionStart(cmd *cobra.Command, args []string) error {
if townRoot, err := workspace.FindFromCwd(); err == nil && townRoot != "" {
agent := fmt.Sprintf("%s/%s", rigName, polecatName)
logger := townlog.NewLogger(townRoot)
logger.Log(townlog.EventWake, agent, sessionIssue)
_ = logger.Log(townlog.EventWake, agent, sessionIssue)
}
return nil
@@ -314,7 +314,7 @@ func runSessionStop(cmd *cobra.Command, args []string) error {
reason = "gt session stop --force"
}
logger := townlog.NewLogger(townRoot)
logger.Log(townlog.EventKill, agent, reason)
_ = logger.Log(townlog.EventKill, agent, reason)
}
return nil
+2 -2
View File
@@ -904,7 +904,7 @@ func runSlingFormula(args []string) error {
// requires cross-database access (agent in rig db, hook bead in town db), but
// bd slot set has a bug where it doesn't support this. See BD_BUG_AGENT_STATE_ROUTING.md.
// The work is still correctly attached via `bd update <bead> --assignee=<agent>`.
func updateAgentHookBead(agentID, beadID, workDir, townBeadsDir string) {
func updateAgentHookBead(agentID, _, workDir, townBeadsDir string) { // beadID unused due to BD_BUG_AGENT_STATE_ROUTING
_ = townBeadsDir // Not used - BEADS_DIR breaks redirect mechanism
// Convert agent ID to agent bead ID
@@ -1166,7 +1166,7 @@ func generateDogName(mgr *dog.Manager) string {
// slingGenerateShortID generates a short random ID (5 lowercase chars).
func slingGenerateShortID() string {
b := make([]byte, 3)
rand.Read(b)
_, _ = rand.Read(b)
return strings.ToLower(base32.StdEncoding.EncodeToString(b)[:5])
}
+15 -21
View File
@@ -179,14 +179,8 @@ func runStart(cmd *cobra.Command, args []string) error {
// startCoreAgents starts Mayor and Deacon sessions.
func startCoreAgents(t *tmux.Tmux) error {
// Get session names
mayorSession, err := getMayorSessionName()
if err != nil {
return fmt.Errorf("getting Mayor session name: %w", err)
}
deaconSession, err := getDeaconSessionName()
if err != nil {
return fmt.Errorf("getting Deacon session name: %w", err)
}
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
// Start Mayor first (so Deacon sees it as up)
mayorRunning, _ := t.HasSession(mayorSession)
@@ -335,15 +329,15 @@ func ensureRefinerySession(rigName string, r *rig.Rig) (bool, error) {
// Set environment
bdActor := fmt.Sprintf("%s/refinery", rigName)
t.SetEnvironment(sessionName, "GT_ROLE", "refinery")
t.SetEnvironment(sessionName, "GT_RIG", rigName)
t.SetEnvironment(sessionName, "BD_ACTOR", bdActor)
_ = t.SetEnvironment(sessionName, "GT_ROLE", "refinery")
_ = t.SetEnvironment(sessionName, "GT_RIG", rigName)
_ = t.SetEnvironment(sessionName, "BD_ACTOR", bdActor)
// Set beads environment
beadsDir := filepath.Join(r.Path, "mayor", "rig", ".beads")
t.SetEnvironment(sessionName, "BEADS_DIR", beadsDir)
t.SetEnvironment(sessionName, "BEADS_NO_DAEMON", "1")
t.SetEnvironment(sessionName, "BEADS_AGENT_NAME", fmt.Sprintf("%s/refinery", rigName))
_ = t.SetEnvironment(sessionName, "BEADS_DIR", beadsDir)
_ = t.SetEnvironment(sessionName, "BEADS_NO_DAEMON", "1")
_ = t.SetEnvironment(sessionName, "BEADS_AGENT_NAME", fmt.Sprintf("%s/refinery", rigName))
// Apply Gas Town theming (non-fatal: theming failure doesn't affect operation)
theme := tmux.AssignTheme(rigName)
@@ -391,8 +385,8 @@ func runShutdown(cmd *cobra.Command, args []string) error {
}
// Get session names for categorization
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
toStop, preserved := categorizeSessions(sessions, mayorSession, deaconSession)
if len(toStop) == 0 {
@@ -421,7 +415,7 @@ func runShutdown(cmd *cobra.Command, args []string) error {
response, _ := reader.ReadString('\n')
response = strings.TrimSpace(strings.ToLower(response))
if response != "y" && response != "yes" {
fmt.Println("Shutdown cancelled.")
fmt.Println("Shutdown canceled.")
return nil
}
}
@@ -515,8 +509,8 @@ func runGracefulShutdown(t *tmux.Tmux, gtSessions []string, townRoot string) err
// Phase 4: Kill sessions in correct order
fmt.Printf("\nPhase 4: Terminating sessions...\n")
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
stopped := killSessionsInOrder(t, gtSessions, mayorSession, deaconSession)
// Phase 5: Cleanup polecat worktrees and branches
@@ -533,8 +527,8 @@ func runGracefulShutdown(t *tmux.Tmux, gtSessions []string, townRoot string) err
func runImmediateShutdown(t *tmux.Tmux, gtSessions []string, townRoot string) error {
fmt.Println("Shutting down Gas Town...")
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
stopped := killSessionsInOrder(t, gtSessions, mayorSession, deaconSession)
// Cleanup polecat worktrees and branches
+3 -3
View File
@@ -469,7 +469,7 @@ func outputStatusText(status TownStatus) error {
}
// renderAgentDetails renders full agent bead details
func renderAgentDetails(agent AgentRuntime, indent string, hooks []AgentHookInfo, townRoot string) {
func renderAgentDetails(agent AgentRuntime, indent string, hooks []AgentHookInfo, townRoot string) { //nolint:unparam // indent kept for future customization
// Line 1: Agent bead ID + status
// Reconcile bead state with tmux session state to surface mismatches
// States: "running" (active), "idle" (waiting), "stopped", "dead", etc.
@@ -646,8 +646,8 @@ func discoverRigHooks(r *rig.Rig, crews []string) []AgentHookInfo {
// allHookBeads is a preloaded map of hook beads for O(1) lookup.
func discoverGlobalAgents(allSessions map[string]bool, allAgentBeads map[string]*beads.Issue, allHookBeads map[string]*beads.Issue, mailRouter *mail.Router, skipMail bool) []AgentRuntime {
// Get session names dynamically
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
// Define agents to discover
agentDefs := []struct {
+4 -4
View File
@@ -53,8 +53,8 @@ func runStatusLine(cmd *cobra.Command, args []string) error {
}
// Get session names for comparison
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
// Determine identity and output based on role
if role == "mayor" || statusLineSession == mayorSession {
@@ -164,7 +164,7 @@ func runMayorStatusLine(t *tmux.Tmux) error {
// Get town root from mayor pane's working directory
var townRoot string
mayorSession, _ := getMayorSessionName()
mayorSession := getMayorSessionName()
paneDir, err := t.GetPaneWorkDir(mayorSession)
if err == nil && paneDir != "" {
townRoot, _ = workspace.Find(paneDir)
@@ -241,7 +241,7 @@ func runDeaconStatusLine(t *tmux.Tmux) error {
// Get town root from deacon pane's working directory
var townRoot string
deaconSession, _ := getDeaconSessionName()
deaconSession := getDeaconSessionName()
paneDir, err := t.GetPaneWorkDir(deaconSession)
if err == nil && paneDir != "" {
townRoot, _ = workspace.Find(paneDir)
+1 -1
View File
@@ -146,7 +146,7 @@ func runStop(cmd *cobra.Command, args []string) error {
// Log kill event
agent := fmt.Sprintf("%s/%s", r.Name, info.Polecat)
logger := townlog.NewLogger(townRoot)
logger.Log(townlog.EventKill, agent, "gt stop")
_ = logger.Log(townlog.EventKill, agent, "gt stop")
// Log kill event to activity feed
_ = events.LogFeed(events.TypeKill, "gt", events.KillPayload(r.Name, info.Polecat, "gt stop"))
+6 -6
View File
@@ -114,7 +114,7 @@ var swarmCancelCmd = &cobra.Command{
Short: "Cancel a swarm",
Long: `Cancel an active swarm.
Marks the swarm as cancelled and optionally cleans up branches.`,
Marks the swarm as canceled and optionally cleans up branches.`,
Args: cobra.ExactArgs(1),
RunE: runSwarmCancel,
}
@@ -158,7 +158,7 @@ func init() {
swarmStatusCmd.Flags().BoolVar(&swarmStatusJSON, "json", false, "Output as JSON")
// List flags
swarmListCmd.Flags().StringVar(&swarmListStatus, "status", "", "Filter by status (active, landed, cancelled, failed)")
swarmListCmd.Flags().StringVar(&swarmListStatus, "status", "", "Filter by status (active, landed, canceled, failed)")
swarmListCmd.Flags().BoolVar(&swarmListJSON, "json", false, "Output as JSON")
// Dispatch flags
@@ -526,7 +526,7 @@ func runSwarmDispatch(cmd *cobra.Command, args []string) error {
func spawnSwarmWorkersFromBeads(r *rig.Rig, townRoot string, swarmID string, workers []string, tasks []struct {
ID string `json:"id"`
Title string `json:"title"`
}) error {
}) error { //nolint:unparam // error return kept for future use
t := tmux.NewTmux()
sessMgr := session.NewManager(t, r)
polecatGit := git.NewGit(r.Path)
@@ -866,8 +866,8 @@ func runSwarmCancel(cmd *cobra.Command, args []string) error {
}
}
// Close the swarm epic in beads with cancelled reason
closeArgs := []string{"close", swarmID, "--reason", "Swarm cancelled"}
// Close the swarm epic in beads with canceled reason
closeArgs := []string{"close", swarmID, "--reason", "Swarm canceled"}
if sessionID := os.Getenv("CLAUDE_SESSION_ID"); sessionID != "" {
closeArgs = append(closeArgs, "--session="+sessionID)
}
@@ -877,7 +877,7 @@ func runSwarmCancel(cmd *cobra.Command, args []string) error {
return fmt.Errorf("closing swarm: %w", err)
}
fmt.Printf("%s Swarm %s cancelled\n", style.Bold.Render("✓"), swarmID)
fmt.Printf("%s Swarm %s canceled\n", style.Bold.Render("✓"), swarmID)
return nil
}
+1 -1
View File
@@ -408,7 +408,7 @@ func getConvoyMeta(convoyID string) (*ConvoyMeta, error) {
}
// collectLegOutputs gathers outputs from all convoy legs.
func collectLegOutputs(meta *ConvoyMeta, f *formula.Formula) ([]LegOutput, bool, error) {
func collectLegOutputs(meta *ConvoyMeta, f *formula.Formula) ([]LegOutput, bool, error) { //nolint:unparam // error return kept for future use
var outputs []LegOutput
allComplete := true
+4 -8
View File
@@ -15,13 +15,9 @@ import (
var townCycleSession string
// getTownLevelSessions returns the town-level session names for the current workspace.
// Returns empty slice if workspace cannot be determined.
func getTownLevelSessions() []string {
mayorSession, errMayor := getMayorSessionName()
deaconSession, errDeacon := getDeaconSessionName()
if errMayor != nil || errDeacon != nil {
return nil
}
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
return []string{mayorSession, deaconSession}
}
@@ -35,8 +31,8 @@ func isTownLevelSession(sessionName string) bool {
if err != nil {
return false
}
mayorSession, _ := getMayorSessionName()
deaconSession, _ := getDeaconSessionName()
mayorSession := getMayorSessionName()
deaconSession := getDeaconSessionName()
_ = townName // used for session name generation
return sessionName == mayorSession || sessionName == deaconSession
}
+2 -2
View File
@@ -80,8 +80,8 @@ func runUp(cmd *cobra.Command, args []string) error {
}
// Get session names
deaconSession, _ := getDeaconSessionName()
mayorSession, _ := getMayorSessionName()
deaconSession := getDeaconSessionName()
mayorSession := getMayorSessionName()
// 2. Deacon (Claude agent)
if err := ensureSession(t, deaconSession, townRoot, "deacon"); err != nil {
+3 -3
View File
@@ -333,9 +333,9 @@ func ensureWitnessSession(rigName string, r *rig.Rig) (bool, error) {
// Set environment
bdActor := fmt.Sprintf("%s/witness", rigName)
t.SetEnvironment(sessionName, "GT_ROLE", "witness")
t.SetEnvironment(sessionName, "GT_RIG", rigName)
t.SetEnvironment(sessionName, "BD_ACTOR", bdActor)
_ = t.SetEnvironment(sessionName, "GT_ROLE", "witness")
_ = t.SetEnvironment(sessionName, "GT_RIG", rigName)
_ = t.SetEnvironment(sessionName, "BD_ACTOR", bdActor)
// Apply Gas Town theming (non-fatal: theming failure doesn't affect operation)
theme := tmux.AssignTheme(rigName)