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>
199 lines
6.5 KiB
Go
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
|