Add type: event for state transitions (bd-ecmd)
Adds TypeEvent issue type for recording operational state changes as immutable beads. Events capture: - event_category: namespaced category (e.g., patrol.muted, agent.started) - event_actor: entity URI who caused the event - event_target: entity URI or bead ID affected - event_payload: event-specific JSON data Changes: - Add TypeEvent constant and IsValid() support in types.go - Add event fields to Issue struct with ComputeContentHash support - Add --event-category/actor/target/payload flags to bd create - Add event fields to RPC CreateArgs and UpdateArgs - Add migration 033_event_fields to add columns to issues table - Update insertIssue and queries to include event fields - Fix migrations_test.go for new column requirements This enables: - bd activity --follow showing events - bd list --type=event --target=agent:deacon - Full audit trail for operational state - HOP-compatible transaction records 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -130,6 +130,17 @@ var createCmd = &cobra.Command{
|
|||||||
FatalError("--role-type and --agent-rig flags require --type=agent")
|
FatalError("--role-type and --agent-rig flags require --type=agent")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event-specific flags
|
||||||
|
eventCategory, _ := cmd.Flags().GetString("event-category")
|
||||||
|
eventActor, _ := cmd.Flags().GetString("event-actor")
|
||||||
|
eventTarget, _ := cmd.Flags().GetString("event-target")
|
||||||
|
eventPayload, _ := cmd.Flags().GetString("event-payload")
|
||||||
|
|
||||||
|
// Validate event-specific flags require --type=event
|
||||||
|
if (eventCategory != "" || eventActor != "" || eventTarget != "" || eventPayload != "") && issueType != "event" {
|
||||||
|
FatalError("--event-category, --event-actor, --event-target, and --event-payload flags require --type=event")
|
||||||
|
}
|
||||||
|
|
||||||
// Handle --rig or --prefix flag: create issue in a different rig
|
// Handle --rig or --prefix flag: create issue in a different rig
|
||||||
// Both flags use the same forgiving lookup (accepts rig names or prefixes)
|
// Both flags use the same forgiving lookup (accepts rig names or prefixes)
|
||||||
targetRig := rigOverride
|
targetRig := rigOverride
|
||||||
@@ -273,6 +284,10 @@ var createCmd = &cobra.Command{
|
|||||||
MolType: string(molType),
|
MolType: string(molType),
|
||||||
RoleType: roleType,
|
RoleType: roleType,
|
||||||
Rig: agentRig,
|
Rig: agentRig,
|
||||||
|
EventCategory: eventCategory,
|
||||||
|
EventActor: eventActor,
|
||||||
|
EventTarget: eventTarget,
|
||||||
|
EventPayload: eventPayload,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := daemonClient.Create(createArgs)
|
resp, err := daemonClient.Create(createArgs)
|
||||||
@@ -322,6 +337,10 @@ var createCmd = &cobra.Command{
|
|||||||
MolType: molType,
|
MolType: molType,
|
||||||
RoleType: roleType,
|
RoleType: roleType,
|
||||||
Rig: agentRig,
|
Rig: agentRig,
|
||||||
|
EventKind: eventCategory,
|
||||||
|
Actor: eventActor,
|
||||||
|
Target: eventTarget,
|
||||||
|
Payload: eventPayload,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := rootCtx
|
ctx := rootCtx
|
||||||
@@ -503,7 +522,7 @@ func init() {
|
|||||||
createCmd.Flags().String("title", "", "Issue title (alternative to positional argument)")
|
createCmd.Flags().String("title", "", "Issue title (alternative to positional argument)")
|
||||||
createCmd.Flags().Bool("silent", false, "Output only the issue ID (for scripting)")
|
createCmd.Flags().Bool("silent", false, "Output only the issue ID (for scripting)")
|
||||||
registerPriorityFlag(createCmd, "2")
|
registerPriorityFlag(createCmd, "2")
|
||||||
createCmd.Flags().StringP("type", "t", "task", "Issue type (bug|feature|task|epic|chore|merge-request|molecule|gate|agent|role|convoy)")
|
createCmd.Flags().StringP("type", "t", "task", "Issue type (bug|feature|task|epic|chore|merge-request|molecule|gate|agent|role|convoy|event)")
|
||||||
registerCommonIssueFlags(createCmd)
|
registerCommonIssueFlags(createCmd)
|
||||||
createCmd.Flags().StringSliceP("labels", "l", []string{}, "Labels (comma-separated)")
|
createCmd.Flags().StringSliceP("labels", "l", []string{}, "Labels (comma-separated)")
|
||||||
createCmd.Flags().StringSlice("label", []string{}, "Alias for --labels")
|
createCmd.Flags().StringSlice("label", []string{}, "Alias for --labels")
|
||||||
@@ -523,6 +542,11 @@ func init() {
|
|||||||
// Agent-specific flags (only valid when --type=agent)
|
// Agent-specific flags (only valid when --type=agent)
|
||||||
createCmd.Flags().String("role-type", "", "Agent role type: polecat|crew|witness|refinery|mayor|deacon (requires --type=agent)")
|
createCmd.Flags().String("role-type", "", "Agent role type: polecat|crew|witness|refinery|mayor|deacon (requires --type=agent)")
|
||||||
createCmd.Flags().String("agent-rig", "", "Agent's rig name (requires --type=agent)")
|
createCmd.Flags().String("agent-rig", "", "Agent's rig name (requires --type=agent)")
|
||||||
|
// Event-specific flags (only valid when --type=event)
|
||||||
|
createCmd.Flags().String("event-category", "", "Event category (e.g., patrol.muted, agent.started) (requires --type=event)")
|
||||||
|
createCmd.Flags().String("event-actor", "", "Entity URI who caused this event (requires --type=event)")
|
||||||
|
createCmd.Flags().String("event-target", "", "Entity URI or bead ID affected (requires --type=event)")
|
||||||
|
createCmd.Flags().String("event-payload", "", "Event-specific JSON data (requires --type=event)")
|
||||||
// Note: --json flag is defined as a persistent flag in main.go, not here
|
// Note: --json flag is defined as a persistent flag in main.go, not here
|
||||||
rootCmd.AddCommand(createCmd)
|
rootCmd.AddCommand(createCmd)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ type CreateArgs struct {
|
|||||||
// Agent identity fields (only valid when IssueType == "agent")
|
// Agent identity fields (only valid when IssueType == "agent")
|
||||||
RoleType string `json:"role_type,omitempty"` // polecat|crew|witness|refinery|mayor|deacon
|
RoleType string `json:"role_type,omitempty"` // polecat|crew|witness|refinery|mayor|deacon
|
||||||
Rig string `json:"rig,omitempty"` // Rig name (empty for town-level agents)
|
Rig string `json:"rig,omitempty"` // Rig name (empty for town-level agents)
|
||||||
|
// Event fields (only valid when IssueType == "event")
|
||||||
|
EventCategory string `json:"event_category,omitempty"` // Namespaced category (e.g., patrol.muted, agent.started)
|
||||||
|
EventActor string `json:"event_actor,omitempty"` // Entity URI who caused this event
|
||||||
|
EventTarget string `json:"event_target,omitempty"` // Entity URI or bead ID affected
|
||||||
|
EventPayload string `json:"event_payload,omitempty"` // Event-specific JSON data
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateArgs represents arguments for the update operation
|
// UpdateArgs represents arguments for the update operation
|
||||||
@@ -142,6 +147,11 @@ type UpdateArgs struct {
|
|||||||
// Agent identity fields
|
// Agent identity fields
|
||||||
RoleType *string `json:"role_type,omitempty"` // polecat|crew|witness|refinery|mayor|deacon
|
RoleType *string `json:"role_type,omitempty"` // polecat|crew|witness|refinery|mayor|deacon
|
||||||
Rig *string `json:"rig,omitempty"` // Rig name (empty for town-level agents)
|
Rig *string `json:"rig,omitempty"` // Rig name (empty for town-level agents)
|
||||||
|
// Event fields (only valid when IssueType == "event")
|
||||||
|
EventCategory *string `json:"event_category,omitempty"` // Namespaced category (e.g., patrol.muted, agent.started)
|
||||||
|
EventActor *string `json:"event_actor,omitempty"` // Entity URI who caused this event
|
||||||
|
EventTarget *string `json:"event_target,omitempty"` // Entity URI or bead ID affected
|
||||||
|
EventPayload *string `json:"event_payload,omitempty"` // Event-specific JSON data
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseArgs represents arguments for the close operation
|
// CloseArgs represents arguments for the close operation
|
||||||
|
|||||||
@@ -122,6 +122,19 @@ func updatesFromArgs(a UpdateArgs) map[string]interface{} {
|
|||||||
if a.Rig != nil {
|
if a.Rig != nil {
|
||||||
u["rig"] = *a.Rig
|
u["rig"] = *a.Rig
|
||||||
}
|
}
|
||||||
|
// Event fields
|
||||||
|
if a.EventCategory != nil {
|
||||||
|
u["event_category"] = *a.EventCategory
|
||||||
|
}
|
||||||
|
if a.EventActor != nil {
|
||||||
|
u["event_actor"] = *a.EventActor
|
||||||
|
}
|
||||||
|
if a.EventTarget != nil {
|
||||||
|
u["event_target"] = *a.EventTarget
|
||||||
|
}
|
||||||
|
if a.EventPayload != nil {
|
||||||
|
u["event_payload"] = *a.EventPayload
|
||||||
|
}
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +221,11 @@ func (s *Server) handleCreate(req *Request) Response {
|
|||||||
// Agent identity fields
|
// Agent identity fields
|
||||||
RoleType: createArgs.RoleType,
|
RoleType: createArgs.RoleType,
|
||||||
Rig: createArgs.Rig,
|
Rig: createArgs.Rig,
|
||||||
|
// Event fields (map protocol names to internal names)
|
||||||
|
EventKind: createArgs.EventCategory,
|
||||||
|
Actor: createArgs.EventActor,
|
||||||
|
Target: createArgs.EventTarget,
|
||||||
|
Payload: createArgs.EventPayload,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any dependencies are discovered-from type
|
// Check if any dependencies are discovered-from type
|
||||||
|
|||||||
@@ -680,6 +680,11 @@ var allowedUpdateFields = map[string]bool{
|
|||||||
"rig": true,
|
"rig": true,
|
||||||
// Molecule type field
|
// Molecule type field
|
||||||
"mol_type": true,
|
"mol_type": true,
|
||||||
|
// Event fields
|
||||||
|
"event_category": true,
|
||||||
|
"event_actor": true,
|
||||||
|
"event_target": true,
|
||||||
|
"event_payload": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// validatePriority validates a priority value
|
// validatePriority validates a priority value
|
||||||
|
|||||||
Reference in New Issue
Block a user