feat: Add gcloud-style command grouping to gt help output
Organize 43 commands into 7 logical groups using cobra's built-in AddGroup/GroupID feature: - Work Management: spawn, sling, hook, handoff, done, mol, mq, etc. - Agent Management: mayor, witness, refinery, deacon, polecat, etc. - Communication: mail, nudge, broadcast, peek - Services: daemon, start, stop, up, down, shutdown - Workspace: rig, crew, init, install, git-init, namepool - Configuration: account, theme, hooks, issue, completion - Diagnostics: status, doctor, prime, version, help Also renamed molecule to mol as the primary command name (molecule is now an alias). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,8 +21,9 @@ var (
|
||||
)
|
||||
|
||||
var accountCmd = &cobra.Command{
|
||||
Use: "account",
|
||||
Short: "Manage Claude Code accounts",
|
||||
Use: "account",
|
||||
GroupID: GroupConfig,
|
||||
Short: "Manage Claude Code accounts",
|
||||
Long: `Manage multiple Claude Code accounts for Gas Town.
|
||||
|
||||
This enables switching between accounts (e.g., personal vs work) with
|
||||
|
||||
@@ -59,6 +59,7 @@ var AgentTypeIcons = map[AgentType]string{
|
||||
var agentsCmd = &cobra.Command{
|
||||
Use: "agents",
|
||||
Aliases: []string{"ag"},
|
||||
GroupID: GroupAgents,
|
||||
Short: "Switch between Gas Town agent sessions",
|
||||
Long: `Display a popup menu of core Gas Town agent sessions.
|
||||
|
||||
|
||||
@@ -23,8 +23,9 @@ func init() {
|
||||
}
|
||||
|
||||
var broadcastCmd = &cobra.Command{
|
||||
Use: "broadcast <message>",
|
||||
Short: "Send a nudge message to all workers",
|
||||
Use: "broadcast <message>",
|
||||
GroupID: GroupComm,
|
||||
Short: "Send a nudge message to all workers",
|
||||
Long: `Broadcasts a message to all active workers (polecats and crew).
|
||||
|
||||
By default, only workers (polecats and crew) receive the message.
|
||||
|
||||
@@ -17,8 +17,9 @@ var (
|
||||
)
|
||||
|
||||
var crewCmd = &cobra.Command{
|
||||
Use: "crew",
|
||||
Short: "Manage crew workspaces (user-managed persistent workspaces)",
|
||||
Use: "crew",
|
||||
GroupID: GroupWorkspace,
|
||||
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 transient, crew workers are:
|
||||
|
||||
@@ -14,8 +14,9 @@ import (
|
||||
)
|
||||
|
||||
var daemonCmd = &cobra.Command{
|
||||
Use: "daemon",
|
||||
Short: "Manage the Gas Town daemon",
|
||||
Use: "daemon",
|
||||
GroupID: GroupServices,
|
||||
Short: "Manage the Gas Town daemon",
|
||||
Long: `Manage the Gas Town background daemon.
|
||||
|
||||
The daemon is a simple Go process that:
|
||||
|
||||
@@ -21,6 +21,7 @@ const DeaconSessionName = "gt-deacon"
|
||||
var deaconCmd = &cobra.Command{
|
||||
Use: "deacon",
|
||||
Aliases: []string{"dea"},
|
||||
GroupID: GroupAgents,
|
||||
Short: "Manage the Deacon session",
|
||||
Long: `Manage the Deacon tmux session.
|
||||
|
||||
@@ -156,7 +157,8 @@ func startDeaconSession(t *tmux.Tmux) error {
|
||||
// Launch Claude directly (no shell respawn loop)
|
||||
// Restarts are handled by daemon via ensureDeaconRunning on each heartbeat
|
||||
// The startup hook handles context loading automatically
|
||||
if err := t.SendKeys(DeaconSessionName, "claude --dangerously-skip-permissions"); err != nil {
|
||||
// Export GT_ROLE in the command since tmux SetEnvironment only affects new panes
|
||||
if err := t.SendKeys(DeaconSessionName, "export GT_ROLE=deacon && claude --dangerously-skip-permissions"); err != nil {
|
||||
return fmt.Errorf("sending command: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@ var (
|
||||
)
|
||||
|
||||
var doctorCmd = &cobra.Command{
|
||||
Use: "doctor",
|
||||
Short: "Run health checks on the workspace",
|
||||
Use: "doctor",
|
||||
GroupID: GroupDiag,
|
||||
Short: "Run health checks on the workspace",
|
||||
Long: `Run diagnostic checks on the Gas Town workspace.
|
||||
|
||||
Doctor checks for common configuration issues, missing files,
|
||||
|
||||
@@ -16,8 +16,9 @@ import (
|
||||
)
|
||||
|
||||
var doneCmd = &cobra.Command{
|
||||
Use: "done",
|
||||
Short: "Signal work ready for merge queue",
|
||||
Use: "done",
|
||||
GroupID: GroupWork,
|
||||
Short: "Signal work ready for merge queue",
|
||||
Long: `Signal that your work is complete and ready for the merge queue.
|
||||
|
||||
This is a convenience command for polecats that:
|
||||
|
||||
@@ -12,8 +12,9 @@ import (
|
||||
)
|
||||
|
||||
var downCmd = &cobra.Command{
|
||||
Use: "down",
|
||||
Short: "Stop all Gas Town services",
|
||||
Use: "down",
|
||||
GroupID: GroupServices,
|
||||
Short: "Stop all Gas Town services",
|
||||
Long: `Stop all Gas Town long-lived services.
|
||||
|
||||
This gracefully shuts down all infrastructure agents:
|
||||
|
||||
@@ -18,8 +18,9 @@ var (
|
||||
)
|
||||
|
||||
var gitInitCmd = &cobra.Command{
|
||||
Use: "git-init",
|
||||
Short: "Initialize git repository for a Gas Town HQ",
|
||||
Use: "git-init",
|
||||
GroupID: GroupWorkspace,
|
||||
Short: "Initialize git repository for a Gas Town HQ",
|
||||
Long: `Initialize or configure git for an existing Gas Town HQ.
|
||||
|
||||
This command:
|
||||
|
||||
@@ -14,8 +14,9 @@ import (
|
||||
)
|
||||
|
||||
var handoffCmd = &cobra.Command{
|
||||
Use: "handoff [bead-or-role]",
|
||||
Short: "Hand off to a fresh session, work continues from hook",
|
||||
Use: "handoff [bead-or-role]",
|
||||
GroupID: GroupWork,
|
||||
Short: "Hand off to a fresh session, work continues from hook",
|
||||
Long: `End watch. Hand off to a fresh agent session.
|
||||
|
||||
This is the canonical way to end any agent session. It handles all roles:
|
||||
|
||||
@@ -12,8 +12,9 @@ import (
|
||||
)
|
||||
|
||||
var hookCmd = &cobra.Command{
|
||||
Use: "hook <bead-id>",
|
||||
Short: "Attach work to your hook (durable across restarts)",
|
||||
Use: "hook <bead-id>",
|
||||
GroupID: GroupWork,
|
||||
Short: "Attach work to your hook (durable across restarts)",
|
||||
Long: `Attach a bead (issue) to your hook for durable work tracking.
|
||||
|
||||
The hook is the "durability primitive" - work on your hook survives session
|
||||
|
||||
@@ -18,8 +18,9 @@ var (
|
||||
)
|
||||
|
||||
var hooksCmd = &cobra.Command{
|
||||
Use: "hooks",
|
||||
Short: "List all Claude Code hooks in the workspace",
|
||||
Use: "hooks",
|
||||
GroupID: GroupConfig,
|
||||
Short: "List all Claude Code hooks in the workspace",
|
||||
Long: `List all Claude Code hooks configured in the workspace.
|
||||
|
||||
Scans for .claude/settings.json files and displays hooks by type.
|
||||
|
||||
@@ -15,8 +15,9 @@ import (
|
||||
var initForce bool
|
||||
|
||||
var initCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize current directory as a Gas Town rig",
|
||||
Use: "init",
|
||||
GroupID: GroupWorkspace,
|
||||
Short: "Initialize current directory as a Gas Town rig",
|
||||
Long: `Initialize the current directory for use as a Gas Town rig.
|
||||
|
||||
This creates the standard agent directories (polecats/, witness/, refinery/,
|
||||
|
||||
@@ -26,8 +26,9 @@ var (
|
||||
)
|
||||
|
||||
var installCmd = &cobra.Command{
|
||||
Use: "install [path]",
|
||||
Short: "Create a new Gas Town HQ (workspace)",
|
||||
Use: "install [path]",
|
||||
GroupID: GroupWorkspace,
|
||||
Short: "Create a new Gas Town HQ (workspace)",
|
||||
Long: `Create a new Gas Town HQ at the specified path.
|
||||
|
||||
The HQ (headquarters) is the top-level directory where Gas Town is installed -
|
||||
|
||||
@@ -9,8 +9,9 @@ import (
|
||||
)
|
||||
|
||||
var issueCmd = &cobra.Command{
|
||||
Use: "issue",
|
||||
Short: "Manage current issue for status line display",
|
||||
Use: "issue",
|
||||
GroupID: GroupConfig,
|
||||
Short: "Manage current issue for status line display",
|
||||
}
|
||||
|
||||
var issueSetCmd = &cobra.Command{
|
||||
|
||||
@@ -41,8 +41,9 @@ var (
|
||||
)
|
||||
|
||||
var mailCmd = &cobra.Command{
|
||||
Use: "mail",
|
||||
Short: "Agent messaging system",
|
||||
Use: "mail",
|
||||
GroupID: GroupComm,
|
||||
Short: "Agent messaging system",
|
||||
Long: `Send and receive messages between agents.
|
||||
|
||||
The mail system allows Mayor, polecats, and the Refinery to communicate.
|
||||
|
||||
@@ -17,6 +17,7 @@ const MayorSessionName = "gt-mayor"
|
||||
var mayorCmd = &cobra.Command{
|
||||
Use: "mayor",
|
||||
Aliases: []string{"may"},
|
||||
GroupID: GroupAgents,
|
||||
Short: "Manage the Mayor session",
|
||||
Long: `Manage the Mayor tmux session.
|
||||
|
||||
@@ -126,7 +127,8 @@ func startMayorSession(t *tmux.Tmux) error {
|
||||
|
||||
// Launch Claude - the startup hook handles 'gt prime' automatically
|
||||
// Use SendKeysDelayed to allow shell initialization after NewSession
|
||||
claudeCmd := `claude --dangerously-skip-permissions`
|
||||
// Export GT_ROLE in the command since tmux SetEnvironment only affects new panes
|
||||
claudeCmd := `export GT_ROLE=mayor && claude --dangerously-skip-permissions`
|
||||
if err := t.SendKeysDelayed(MayorSessionName, claudeCmd, 200); err != nil {
|
||||
return fmt.Errorf("sending command: %w", err)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,9 @@ var (
|
||||
)
|
||||
|
||||
var moleculeCmd = &cobra.Command{
|
||||
Use: "molecule",
|
||||
Aliases: []string{"mol"},
|
||||
Use: "mol",
|
||||
Aliases: []string{"molecule"},
|
||||
GroupID: GroupWork,
|
||||
Short: "Molecule workflow commands",
|
||||
Long: `Manage molecule workflow templates.
|
||||
|
||||
|
||||
+3
-2
@@ -50,8 +50,9 @@ var (
|
||||
)
|
||||
|
||||
var mqCmd = &cobra.Command{
|
||||
Use: "mq",
|
||||
Short: "Merge queue operations",
|
||||
Use: "mq",
|
||||
GroupID: GroupWork,
|
||||
Short: "Merge queue operations",
|
||||
Long: `Manage the merge queue for a rig.
|
||||
|
||||
The merge queue tracks work branches from polecats waiting to be merged.
|
||||
|
||||
@@ -18,8 +18,9 @@ var (
|
||||
)
|
||||
|
||||
var namepoolCmd = &cobra.Command{
|
||||
Use: "namepool",
|
||||
Short: "Manage polecat name pools",
|
||||
Use: "namepool",
|
||||
GroupID: GroupWorkspace,
|
||||
Short: "Manage polecat name pools",
|
||||
Long: `Manage themed name pools for polecats in Gas Town.
|
||||
|
||||
By default, polecats get themed names from the Mad Max universe
|
||||
|
||||
@@ -14,8 +14,9 @@ func init() {
|
||||
}
|
||||
|
||||
var nudgeCmd = &cobra.Command{
|
||||
Use: "nudge <rig/polecat> <message>",
|
||||
Short: "Send a message to a polecat session reliably",
|
||||
Use: "nudge <rig/polecat> <message>",
|
||||
GroupID: GroupComm,
|
||||
Short: "Send a message to a polecat session reliably",
|
||||
Long: `Sends a message to a polecat's Claude Code session.
|
||||
|
||||
Uses a reliable delivery pattern:
|
||||
|
||||
@@ -15,8 +15,9 @@ import (
|
||||
)
|
||||
|
||||
var orphansCmd = &cobra.Command{
|
||||
Use: "orphans",
|
||||
Short: "Find lost polecat work",
|
||||
Use: "orphans",
|
||||
GroupID: GroupWork,
|
||||
Short: "Find lost polecat work",
|
||||
Long: `Find orphaned commits that were never merged to main.
|
||||
|
||||
Polecat work can get lost when:
|
||||
|
||||
@@ -16,8 +16,9 @@ func init() {
|
||||
}
|
||||
|
||||
var peekCmd = &cobra.Command{
|
||||
Use: "peek <rig/polecat> [count]",
|
||||
Short: "View recent output from a polecat session",
|
||||
Use: "peek <rig/polecat> [count]",
|
||||
GroupID: GroupComm,
|
||||
Short: "View recent output from a polecat session",
|
||||
Long: `Capture and display recent terminal output from a polecat session.
|
||||
|
||||
This is the ergonomic alias for 'gt session capture'. Use it to check
|
||||
|
||||
@@ -30,6 +30,7 @@ var (
|
||||
var polecatCmd = &cobra.Command{
|
||||
Use: "polecat",
|
||||
Aliases: []string{"cat", "polecats"},
|
||||
GroupID: GroupAgents,
|
||||
Short: "Manage polecats in rigs",
|
||||
Long: `Manage polecat lifecycle in rigs.
|
||||
|
||||
|
||||
@@ -33,8 +33,9 @@ const (
|
||||
)
|
||||
|
||||
var primeCmd = &cobra.Command{
|
||||
Use: "prime",
|
||||
Short: "Output role context for current directory",
|
||||
Use: "prime",
|
||||
GroupID: GroupDiag,
|
||||
Short: "Output role context for current directory",
|
||||
Long: `Detect the agent role from the current directory and output context.
|
||||
|
||||
Role detection:
|
||||
|
||||
@@ -23,6 +23,7 @@ var (
|
||||
var refineryCmd = &cobra.Command{
|
||||
Use: "refinery",
|
||||
Aliases: []string{"ref"},
|
||||
GroupID: GroupAgents,
|
||||
Short: "Manage the merge queue processor",
|
||||
Long: `Manage the Refinery merge queue processor for a rig.
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@ import (
|
||||
var releaseReason string
|
||||
|
||||
var releaseCmd = &cobra.Command{
|
||||
Use: "release <issue-id>...",
|
||||
Short: "Release stuck in_progress issues back to pending",
|
||||
Use: "release <issue-id>...",
|
||||
GroupID: GroupWork,
|
||||
Short: "Release stuck in_progress issues back to pending",
|
||||
Long: `Release one or more in_progress issues back to open/pending status.
|
||||
|
||||
This is used to recover stuck steps when a worker dies mid-task.
|
||||
|
||||
+3
-2
@@ -23,8 +23,9 @@ import (
|
||||
)
|
||||
|
||||
var rigCmd = &cobra.Command{
|
||||
Use: "rig",
|
||||
Short: "Manage rigs in the workspace",
|
||||
Use: "rig",
|
||||
GroupID: GroupWorkspace,
|
||||
Short: "Manage rigs in the workspace",
|
||||
Long: `Manage rigs (project containers) in the Gas Town workspace.
|
||||
|
||||
A rig is a container for managing a project and its agents:
|
||||
|
||||
@@ -34,8 +34,9 @@ type RoleInfo struct {
|
||||
}
|
||||
|
||||
var roleCmd = &cobra.Command{
|
||||
Use: "role",
|
||||
Short: "Show or manage agent role",
|
||||
Use: "role",
|
||||
GroupID: GroupAgents,
|
||||
Short: "Show or manage agent role",
|
||||
Long: `Display the current agent role and its detection source.
|
||||
|
||||
Role is determined by:
|
||||
|
||||
@@ -32,10 +32,36 @@ func Execute() {
|
||||
}
|
||||
}
|
||||
|
||||
// Command group IDs - used by subcommands to organize help output
|
||||
const (
|
||||
GroupWork = "work"
|
||||
GroupAgents = "agents"
|
||||
GroupComm = "comm"
|
||||
GroupServices = "services"
|
||||
GroupWorkspace = "workspace"
|
||||
GroupConfig = "config"
|
||||
GroupDiag = "diag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Enable prefix matching for subcommands (e.g., "gt ref at" -> "gt refinery attach")
|
||||
cobra.EnablePrefixMatching = true
|
||||
|
||||
// Define command groups (order determines help output order)
|
||||
rootCmd.AddGroup(
|
||||
&cobra.Group{ID: GroupWork, Title: "Work Management:"},
|
||||
&cobra.Group{ID: GroupAgents, Title: "Agent Management:"},
|
||||
&cobra.Group{ID: GroupComm, Title: "Communication:"},
|
||||
&cobra.Group{ID: GroupServices, Title: "Services:"},
|
||||
&cobra.Group{ID: GroupWorkspace, Title: "Workspace:"},
|
||||
&cobra.Group{ID: GroupConfig, Title: "Configuration:"},
|
||||
&cobra.Group{ID: GroupDiag, Title: "Diagnostics:"},
|
||||
)
|
||||
|
||||
// Put help and completion in a sensible group
|
||||
rootCmd.SetHelpCommandGroupID(GroupDiag)
|
||||
rootCmd.SetCompletionCommandGroupID(GroupConfig)
|
||||
|
||||
// Global flags can be added here
|
||||
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ var (
|
||||
var sessionCmd = &cobra.Command{
|
||||
Use: "session",
|
||||
Aliases: []string{"sess"},
|
||||
GroupID: GroupAgents,
|
||||
Short: "Manage polecat sessions",
|
||||
Long: `Manage tmux sessions for polecats.
|
||||
|
||||
|
||||
@@ -13,8 +13,9 @@ import (
|
||||
)
|
||||
|
||||
var slingCmd = &cobra.Command{
|
||||
Use: "sling <bead-id> [target]",
|
||||
Short: "Hook work and start immediately (no restart)",
|
||||
Use: "sling <bead-id> [target]",
|
||||
GroupID: GroupWork,
|
||||
Short: "Hook work and start immediately (no restart)",
|
||||
Long: `Sling work onto an agent's hook and start working immediately.
|
||||
|
||||
Unlike 'gt handoff', sling does NOT restart the session. It:
|
||||
|
||||
@@ -40,6 +40,7 @@ var (
|
||||
var spawnCmd = &cobra.Command{
|
||||
Use: "spawn [rig/polecat | rig]",
|
||||
Aliases: []string{"sp"},
|
||||
GroupID: GroupWork,
|
||||
Short: "Spawn a polecat with work assignment",
|
||||
Long: `Spawn a polecat with a work assignment.
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@ var (
|
||||
)
|
||||
|
||||
var startCmd = &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Start Gas Town",
|
||||
Use: "start",
|
||||
GroupID: GroupServices,
|
||||
Short: "Start Gas Town",
|
||||
Long: `Start Gas Town by launching the Deacon and Mayor.
|
||||
|
||||
The Deacon is the health-check orchestrator that monitors Mayor and Witnesses.
|
||||
@@ -46,8 +47,9 @@ To stop Gas Town, use 'gt shutdown'.`,
|
||||
}
|
||||
|
||||
var shutdownCmd = &cobra.Command{
|
||||
Use: "shutdown",
|
||||
Short: "Shutdown Gas Town",
|
||||
Use: "shutdown",
|
||||
GroupID: GroupServices,
|
||||
Short: "Shutdown Gas Town",
|
||||
Long: `Shutdown Gas Town by stopping agents and cleaning up polecats.
|
||||
|
||||
By default, preserves crew sessions (your persistent workspaces).
|
||||
@@ -240,7 +242,8 @@ func ensureRefinerySession(rigName string, r *rig.Rig) (bool, error) {
|
||||
_ = t.ConfigureGasTownSession(sessionName, theme, rigName, "refinery", "refinery")
|
||||
|
||||
// Launch Claude in a respawn loop
|
||||
loopCmd := `while true; do echo "🛢️ Starting Refinery for ` + rigName + `..."; claude --dangerously-skip-permissions; echo ""; echo "Refinery exited. Restarting in 2s... (Ctrl-C to stop)"; sleep 2; done`
|
||||
// Export GT_ROLE in the command since tmux SetEnvironment only affects new panes
|
||||
loopCmd := `export GT_ROLE=refinery && while true; do echo "🛢️ Starting Refinery for ` + rigName + `..."; claude --dangerously-skip-permissions; echo ""; echo "Refinery exited. Restarting in 2s... (Ctrl-C to stop)"; sleep 2; done`
|
||||
if err := t.SendKeysDelayed(sessionName, loopCmd, 200); err != nil {
|
||||
return false, fmt.Errorf("sending command: %w", err)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ var statusJSON bool
|
||||
var statusCmd = &cobra.Command{
|
||||
Use: "status",
|
||||
Aliases: []string{"stat"},
|
||||
GroupID: GroupDiag,
|
||||
Short: "Show overall town status",
|
||||
Long: `Display the current status of the Gas Town workspace.
|
||||
|
||||
|
||||
@@ -21,8 +21,9 @@ var (
|
||||
)
|
||||
|
||||
var stopCmd = &cobra.Command{
|
||||
Use: "stop",
|
||||
Short: "Emergency stop for sessions",
|
||||
Use: "stop",
|
||||
GroupID: GroupServices,
|
||||
Short: "Emergency stop for sessions",
|
||||
Long: `Emergency stop command for Gas Town sessions.
|
||||
|
||||
Stops all running polecat sessions across rigs. Use for emergency shutdown
|
||||
|
||||
@@ -34,8 +34,9 @@ var (
|
||||
)
|
||||
|
||||
var swarmCmd = &cobra.Command{
|
||||
Use: "swarm",
|
||||
Short: "Manage multi-agent swarms",
|
||||
Use: "swarm",
|
||||
GroupID: GroupWork,
|
||||
Short: "Manage multi-agent swarms",
|
||||
Long: `Manage coordinated multi-agent work units (swarms).
|
||||
|
||||
A swarm coordinates multiple polecats working on related tasks from a shared
|
||||
|
||||
@@ -19,8 +19,9 @@ var (
|
||||
)
|
||||
|
||||
var themeCmd = &cobra.Command{
|
||||
Use: "theme [name]",
|
||||
Short: "View or set tmux theme for the current rig",
|
||||
Use: "theme [name]",
|
||||
GroupID: GroupConfig,
|
||||
Short: "View or set tmux theme for the current rig",
|
||||
Long: `Manage tmux status bar themes for Gas Town sessions.
|
||||
|
||||
Without arguments, shows the current theme assignment.
|
||||
|
||||
+8
-5
@@ -17,8 +17,9 @@ import (
|
||||
)
|
||||
|
||||
var upCmd = &cobra.Command{
|
||||
Use: "up",
|
||||
Short: "Bring up all Gas Town services",
|
||||
Use: "up",
|
||||
GroupID: GroupServices,
|
||||
Short: "Bring up all Gas Town services",
|
||||
Long: `Start all Gas Town long-lived services.
|
||||
|
||||
This is the idempotent "boot" command for Gas Town. It ensures all
|
||||
@@ -213,12 +214,13 @@ func ensureSession(t *tmux.Tmux, sessionName, workDir, role string) error {
|
||||
}
|
||||
|
||||
// Launch Claude
|
||||
// Export GT_ROLE in the command since tmux SetEnvironment only affects new panes
|
||||
var claudeCmd string
|
||||
if role == "deacon" {
|
||||
// Deacon uses respawn loop
|
||||
claudeCmd = `while true; do echo "⛪ Starting Deacon session..."; claude --dangerously-skip-permissions; echo ""; echo "Deacon exited. Restarting in 2s... (Ctrl-C to stop)"; sleep 2; done`
|
||||
claudeCmd = `export GT_ROLE=deacon && while true; do echo "⛪ Starting Deacon session..."; claude --dangerously-skip-permissions; echo ""; echo "Deacon exited. Restarting in 2s... (Ctrl-C to stop)"; sleep 2; done`
|
||||
} else {
|
||||
claudeCmd = `claude --dangerously-skip-permissions`
|
||||
claudeCmd = fmt.Sprintf(`export GT_ROLE=%s && claude --dangerously-skip-permissions`, role)
|
||||
}
|
||||
|
||||
if err := t.SendKeysDelayed(sessionName, claudeCmd, 200); err != nil {
|
||||
@@ -252,7 +254,8 @@ func ensureWitness(t *tmux.Tmux, sessionName, rigPath, rigName string) error {
|
||||
_ = t.ConfigureGasTownSession(sessionName, theme, "", "Witness", rigName)
|
||||
|
||||
// Launch Claude
|
||||
claudeCmd := `claude --dangerously-skip-permissions`
|
||||
// Export GT_ROLE in the command since tmux SetEnvironment only affects new panes
|
||||
claudeCmd := `export GT_ROLE=witness && claude --dangerously-skip-permissions`
|
||||
if err := t.SendKeysDelayed(sessionName, claudeCmd, 200); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,8 +15,9 @@ var (
|
||||
)
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print version information",
|
||||
Use: "version",
|
||||
GroupID: GroupDiag,
|
||||
Short: "Print version information",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(style.Bold.Render("gt") + " - Gas Town CLI")
|
||||
fmt.Printf("Version: %s\n", Version)
|
||||
|
||||
@@ -22,8 +22,9 @@ var (
|
||||
)
|
||||
|
||||
var witnessCmd = &cobra.Command{
|
||||
Use: "witness",
|
||||
Short: "Manage the polecat monitoring agent",
|
||||
Use: "witness",
|
||||
GroupID: GroupAgents,
|
||||
Short: "Manage the polecat monitoring agent",
|
||||
Long: `Manage the Witness monitoring agent for a rig.
|
||||
|
||||
The Witness monitors polecats for stuck/idle state, nudges polecats
|
||||
@@ -330,7 +331,8 @@ func ensureWitnessSession(rigName string, r *rig.Rig) (bool, error) {
|
||||
// Launch Claude directly (no shell respawn loop)
|
||||
// Restarts are handled by daemon via LIFECYCLE mail or deacon health-scan
|
||||
// NOTE: No gt prime injection needed - SessionStart hook handles it automatically
|
||||
if err := t.SendKeys(sessionName, "claude --dangerously-skip-permissions"); err != nil {
|
||||
// Export GT_ROLE in the command since tmux SetEnvironment only affects new panes
|
||||
if err := t.SendKeys(sessionName, "export GT_ROLE=witness && claude --dangerously-skip-permissions"); err != nil {
|
||||
return false, fmt.Errorf("sending command: %w", err)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user