Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/cli_mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ var agentAllowed = map[string]bool{
"schedule.list": true,
"schedule.get": true,
"schedule.cancel": true,
"schedule.create": true,
"schedule.create-recurring": true,
"schedule.pause": true,
"schedule.resume": true,
"schedule.delete": true,
"schedule.history": true,
"shared-dir": true,
"shared-dir.list": true,
Expand Down
17 changes: 9 additions & 8 deletions cmd/cli_mode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,9 @@ func TestApplyModeRestrictions_Agent(t *testing.T) {
"notifications.ack", "notifications.subscribe", "notifications.subscriptions",
"notifications.unsubscribe", "notifications.update",
"resume",
"schedule", "schedule.cancel", "schedule.get", "schedule.history", "schedule.list",
"schedule", "schedule.cancel", "schedule.create", "schedule.create-recurring",
"schedule.delete", "schedule.get", "schedule.history", "schedule.list",
"schedule.pause", "schedule.resume",
"shared-dir", "shared-dir.info", "shared-dir.list",
"start", "stop",
"template",
Expand Down Expand Up @@ -334,11 +336,11 @@ func TestApplyModeRestrictions_AgentScheduleSubcommands(t *testing.T) {
assert.Contains(t, remaining, "schedule.cancel")
assert.Contains(t, remaining, "schedule.history")

assert.NotContains(t, remaining, "schedule.create")
assert.NotContains(t, remaining, "schedule.create-recurring")
assert.NotContains(t, remaining, "schedule.pause")
assert.NotContains(t, remaining, "schedule.resume")
assert.NotContains(t, remaining, "schedule.delete")
assert.Contains(t, remaining, "schedule.create")
assert.Contains(t, remaining, "schedule.create-recurring")
assert.Contains(t, remaining, "schedule.pause")
assert.Contains(t, remaining, "schedule.resume")
assert.Contains(t, remaining, "schedule.delete")
}

func TestApplyModeRestrictions_HelpAlwaysKept(t *testing.T) {
Expand Down Expand Up @@ -413,6 +415,7 @@ func TestAgentAllowedList(t *testing.T) {
"resume", "version",
"notifications",
"schedule", "schedule.list", "schedule.get", "schedule.cancel", "schedule.history",
"schedule.create", "schedule.create-recurring", "schedule.pause", "schedule.resume", "schedule.delete",
"shared-dir", "shared-dir.list", "shared-dir.info",
"templates", "templates.list", "templates.show", "templates.create",
"templates.clone", "templates.delete", "templates.update-default",
Expand All @@ -436,8 +439,6 @@ func TestAgentAllowedList(t *testing.T) {
"hub.auth", "hub.token", "hub.groves", "hub.brokers",
"hub.env", "hub.secret", "hub.status", "hub.notifications",
"messages.read",
"schedule.create", "schedule.create-recurring", "schedule.delete",
"schedule.pause", "schedule.resume",
"shared-dir.create", "shared-dir.remove",
}
for _, path := range notAllowed {
Expand Down
56 changes: 12 additions & 44 deletions cmd/schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ var (
scheduleName string
scheduleCron string
scheduleListType string // "events", "recurring", "all"
scheduleTemplate string
scheduleTask string
scheduleBranch string
)

// scheduleCmd is the top-level command group for schedule management.
Expand Down Expand Up @@ -77,17 +74,15 @@ var scheduleCancelCmd = &cobra.Command{
var scheduleCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a one-shot scheduled event",
Long: `Create a one-shot scheduled event. Requires --type, timing (--in or --at),
and type-specific flags (e.g. --agent and --message for message events).`,
Long: `Create a one-shot scheduled event. Requires timing (--in or --at), --agent, and --message.`,
RunE: runScheduleCreate,
}

// scheduleCreateRecurringCmd creates a new recurring schedule.
var scheduleCreateRecurringCmd = &cobra.Command{
Use: "create-recurring",
Short: "Create a recurring schedule",
Long: `Create a recurring schedule with a cron expression. Requires --name, --cron,
--type, and type-specific flags (e.g. --agent and --message for message events).`,
Long: `Create a recurring schedule with a cron expression. Requires --name, --cron, --agent, and --message.`,
RunE: runScheduleCreateRecurring,
}

Expand Down Expand Up @@ -408,9 +403,6 @@ func runScheduleCancel(cmd *cobra.Command, args []string) error {
}

func runScheduleCreate(cmd *cobra.Command, args []string) error {
if scheduleType == "" {
return fmt.Errorf("--type is required")
}
if scheduleIn == "" && scheduleAt == "" {
return fmt.Errorf("either --in or --at is required")
}
Expand All @@ -427,12 +419,8 @@ func runScheduleCreate(cmd *cobra.Command, args []string) error {
if scheduleMessage == "" {
return fmt.Errorf("--message is required for message events")
}
case "dispatch_agent":
if scheduleAgent == "" {
return fmt.Errorf("--agent is required for dispatch_agent events (the name of the agent to create)")
}
default:
return fmt.Errorf("unsupported event type: %q (supported: message, dispatch_agent)", scheduleType)
return fmt.Errorf("unsupported event type: %q (supported: message)", scheduleType)
}

hubCtx, err := CheckHubAvailabilityWithOptions(projectPath, true)
Expand All @@ -457,9 +445,6 @@ func runScheduleCreate(cmd *cobra.Command, args []string) error {
AgentName: scheduleAgent,
Message: scheduleMessage,
Interrupt: scheduleInterrupt,
Template: scheduleTemplate,
Task: scheduleTask,
Branch: scheduleBranch,
}

if scheduleIn != "" {
Expand Down Expand Up @@ -494,10 +479,6 @@ func runScheduleCreateRecurring(cmd *cobra.Command, args []string) error {
if scheduleCron == "" {
return fmt.Errorf("--cron is required")
}
if scheduleType == "" {
return fmt.Errorf("--type is required")
}

// Validate type-specific flags
switch scheduleType {
case "message":
Expand All @@ -507,12 +488,8 @@ func runScheduleCreateRecurring(cmd *cobra.Command, args []string) error {
if scheduleMessage == "" {
return fmt.Errorf("--message is required for message schedules")
}
case "dispatch_agent":
if scheduleAgent == "" {
return fmt.Errorf("--agent is required for dispatch_agent schedules (the name of the agent to create)")
}
default:
return fmt.Errorf("unsupported event type: %q (supported: message, dispatch_agent)", scheduleType)
return fmt.Errorf("unsupported event type: %q (supported: message)", scheduleType)
}

hubCtx, err := CheckHubAvailabilityWithOptions(projectPath, true)
Expand All @@ -539,9 +516,6 @@ func runScheduleCreateRecurring(cmd *cobra.Command, args []string) error {
AgentName: scheduleAgent,
Message: scheduleMessage,
Interrupt: scheduleInterrupt,
Template: scheduleTemplate,
Task: scheduleTask,
Branch: scheduleBranch,
}

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
Expand Down Expand Up @@ -805,24 +779,18 @@ func init() {
scheduleListCmd.Flags().StringVar(&scheduleListType, "show", "", "Filter by resource type: events, recurring, or all (default: all)")

// Create one-shot flags
scheduleCreateCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message, dispatch_agent)")
scheduleCreateCmd.Flags().StringVar(&scheduleType, "type", "message", "Event type")
scheduleCreateCmd.Flags().StringVar(&scheduleIn, "in", "", "Schedule after a duration (e.g. 30m, 1h)")
scheduleCreateCmd.Flags().StringVar(&scheduleAt, "at", "", "Schedule at an absolute time (ISO 8601)")
scheduleCreateCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name")
scheduleCreateCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body (for message events)")
scheduleCreateCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent (for message events)")
scheduleCreateCmd.Flags().StringVar(&scheduleTemplate, "template", "", "Agent template (for dispatch_agent events)")
scheduleCreateCmd.Flags().StringVar(&scheduleTask, "task", "", "Task/prompt for the agent (for dispatch_agent events)")
scheduleCreateCmd.Flags().StringVar(&scheduleBranch, "branch", "", "Git branch name (for dispatch_agent events)")
scheduleCreateCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body")
scheduleCreateCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent")

// Create recurring flags
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleName, "name", "", "Schedule name (required)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleCron, "cron", "", "Cron expression (required, 5-field: minute hour day month weekday)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleType, "type", "", "Event type (required: message, dispatch_agent)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name (for message: name or 'all'; for dispatch_agent: name to create)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body (for message events)")
scheduleCreateRecurringCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent (for message events)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleTemplate, "template", "", "Agent template (for dispatch_agent events)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleTask, "task", "", "Task/prompt for the agent (for dispatch_agent events)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleBranch, "branch", "", "Git branch name (for dispatch_agent events)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleCron, "cron", "", "Cron expression (required, 5-field: minute hour day month weekday, UTC)")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleType, "type", "message", "Event type")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleAgent, "agent", "", "Target agent name")
scheduleCreateRecurringCmd.Flags().StringVar(&scheduleMessage, "message", "", "Message body")
scheduleCreateRecurringCmd.Flags().BoolVar(&scheduleInterrupt, "interrupt", false, "Interrupt the agent")
}
4 changes: 2 additions & 2 deletions cmd/schedule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ func TestScheduleCreateValidation(t *testing.T) {
scheduleMessage = origMessage
}()

t.Run("missing type", func(t *testing.T) {
t.Run("empty type rejected", func(t *testing.T) {
scheduleType = ""
scheduleIn = "30m"
err := runScheduleCreate(nil, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "--type is required")
assert.Contains(t, err.Error(), "unsupported event type")
})

t.Run("missing timing", func(t *testing.T) {
Expand Down
Loading