Files
gastown/internal/cmd/activity.go
Steve Yegge 91fa5e63dc Replace 'gastown' with 'greenplace' in user-facing docs/examples
Using "greenplace" (The Green Place from Mad Max: Fury Road) as the
canonical example project/rig name in documentation and help text.
This provides a clearer distinction from the actual gastown repo name.

Changes:
- docs/*.md: Updated all example paths and commands
- internal/cmd/*.go: Updated help text examples
- internal/templates/: Updated example references
- Tests: Updated to use greenplace in example session names

Note: Import paths (github.com/steveyegge/gastown) and actual code
paths referencing the gastown repo structure are unchanged.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 18:03:06 -08:00

199 lines
6.5 KiB
Go

package cmd
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"github.com/steveyegge/gastown/internal/events"
"github.com/steveyegge/gastown/internal/style"
"github.com/steveyegge/gastown/internal/workspace"
)
// Activity emit command flags
var (
activityEventType string
activityActor string
activityRig string
activityPolecat string
activityTarget string
activityReason string
activityMessage string
activityStatus string
activityIssue string
activityTo string
activityCount int
)
var activityCmd = &cobra.Command{
Use: "activity",
GroupID: GroupDiag,
Short: "Emit and view activity events",
Long: `Emit and view activity events for the Gas Town activity feed.
Events are written to ~/gt/.events.jsonl and can be viewed with 'gt feed'.
Subcommands:
emit Emit an activity event`,
}
var activityEmitCmd = &cobra.Command{
Use: "emit <event-type>",
Short: "Emit an activity event",
Long: `Emit an activity event to the Gas Town activity feed.
Supported event types for witness patrol:
patrol_started - When witness begins patrol cycle
polecat_checked - When witness checks a polecat
polecat_nudged - When witness nudges a stuck polecat
escalation_sent - When witness escalates to Mayor/Deacon
patrol_complete - When patrol cycle finishes
Supported event types for refinery:
merge_started - When refinery starts a merge
merge_complete - When merge succeeds
merge_failed - When merge fails
queue_processed - When refinery finishes processing queue
Common options:
--actor Who is emitting the event (e.g., greenplace/witness)
--rig Which rig the event is about
--message Human-readable message
Examples:
gt activity emit patrol_started --rig greenplace --count 3
gt activity emit polecat_checked --rig greenplace --polecat Toast --status working --issue gp-xyz
gt activity emit polecat_nudged --rig greenplace --polecat Toast --reason "idle for 10 minutes"
gt activity emit escalation_sent --rig greenplace --target Toast --to mayor --reason "unresponsive"
gt activity emit patrol_complete --rig greenplace --count 3 --message "All polecats healthy"`,
Args: cobra.ExactArgs(1),
RunE: runActivityEmit,
}
func init() {
// Emit command flags
activityEmitCmd.Flags().StringVar(&activityActor, "actor", "", "Actor emitting the event (auto-detected if not set)")
activityEmitCmd.Flags().StringVar(&activityRig, "rig", "", "Rig the event is about")
activityEmitCmd.Flags().StringVar(&activityPolecat, "polecat", "", "Polecat involved (for polecat_checked, polecat_nudged)")
activityEmitCmd.Flags().StringVar(&activityTarget, "target", "", "Target of the action (for escalation)")
activityEmitCmd.Flags().StringVar(&activityReason, "reason", "", "Reason for the action")
activityEmitCmd.Flags().StringVar(&activityMessage, "message", "", "Human-readable message")
activityEmitCmd.Flags().StringVar(&activityStatus, "status", "", "Status (for polecat_checked: working, idle, stuck)")
activityEmitCmd.Flags().StringVar(&activityIssue, "issue", "", "Issue ID (for polecat_checked)")
activityEmitCmd.Flags().StringVar(&activityTo, "to", "", "Escalation target (for escalation_sent: mayor, deacon)")
activityEmitCmd.Flags().IntVar(&activityCount, "count", 0, "Polecat count (for patrol events)")
activityCmd.AddCommand(activityEmitCmd)
rootCmd.AddCommand(activityCmd)
}
func runActivityEmit(cmd *cobra.Command, args []string) error {
eventType := args[0]
// Validate we're in a Gas Town workspace
_, err := workspace.FindFromCwdOrError()
if err != nil {
return fmt.Errorf("not in a Gas Town workspace: %w", err)
}
// Auto-detect actor if not provided
actor := activityActor
if actor == "" {
actor = detectActor()
}
// Build payload based on event type
var payload map[string]interface{}
switch eventType {
case events.TypePatrolStarted, events.TypePatrolComplete:
if activityRig == "" {
return fmt.Errorf("--rig is required for %s events", eventType)
}
payload = events.PatrolPayload(activityRig, activityCount, activityMessage)
case events.TypePolecatChecked:
if activityRig == "" || activityPolecat == "" {
return fmt.Errorf("--rig and --polecat are required for polecat_checked events")
}
if activityStatus == "" {
activityStatus = "checked"
}
payload = events.PolecatCheckPayload(activityRig, activityPolecat, activityStatus, activityIssue)
case events.TypePolecatNudged:
if activityRig == "" || activityPolecat == "" {
return fmt.Errorf("--rig and --polecat are required for polecat_nudged events")
}
payload = events.NudgePayload(activityRig, activityPolecat, activityReason)
case events.TypeEscalationSent:
if activityRig == "" || activityTarget == "" || activityTo == "" {
return fmt.Errorf("--rig, --target, and --to are required for escalation_sent events")
}
payload = events.EscalationPayload(activityRig, activityTarget, activityTo, activityReason)
case events.TypeMergeStarted, events.TypeMerged, events.TypeMergeFailed, events.TypeMergeSkipped:
// Refinery events - flexible payload
payload = make(map[string]interface{})
if activityRig != "" {
payload["rig"] = activityRig
}
if activityMessage != "" {
payload["message"] = activityMessage
}
if activityTarget != "" {
payload["branch"] = activityTarget
}
if activityReason != "" {
payload["reason"] = activityReason
}
default:
// Generic event - use whatever flags are provided
payload = make(map[string]interface{})
if activityRig != "" {
payload["rig"] = activityRig
}
if activityPolecat != "" {
payload["polecat"] = activityPolecat
}
if activityTarget != "" {
payload["target"] = activityTarget
}
if activityReason != "" {
payload["reason"] = activityReason
}
if activityMessage != "" {
payload["message"] = activityMessage
}
if activityStatus != "" {
payload["status"] = activityStatus
}
if activityIssue != "" {
payload["issue"] = activityIssue
}
if activityTo != "" {
payload["to"] = activityTo
}
if activityCount > 0 {
payload["count"] = activityCount
}
}
// Emit the event
if err := events.LogFeed(eventType, actor, payload); err != nil {
return fmt.Errorf("emitting event: %w", err)
}
// Print confirmation
payloadJSON, _ := json.Marshal(payload)
fmt.Printf("%s Emitted %s event\n", style.Success.Render("✓"), style.Bold.Render(eventType))
fmt.Printf(" Actor: %s\n", actor)
fmt.Printf(" Payload: %s\n", string(payloadJSON))
return nil
}
// Note: detectActor is defined in sling.go and reused here