diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-02-08 21:35:45 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-02-08 21:35:45 -1000 |
| commit | 2e2b2187b957e9af78797a67ec5c6874615fae02 (patch) | |
| tree | 1181dbb7e43f5d30cb025fa4d50fd4e7a2c893b3 /internal/task/task.go | |
Initial project: task model, executor, API server, CLI, storage, reporter
Claudomator automation toolkit for Claude Code with:
- Task model with YAML parsing, validation, state machine (49 tests, 0 races)
- SQLite storage for tasks and executions
- Executor pool with bounded concurrency, timeout, cancellation
- REST API + WebSocket for mobile PWA integration
- Webhook/multi-notifier system
- CLI: init, run, serve, list, status commands
- Console, JSON, HTML reporters with cost tracking
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/task/task.go')
| -rw-r--r-- | internal/task/task.go | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/internal/task/task.go b/internal/task/task.go new file mode 100644 index 0000000..3796cf3 --- /dev/null +++ b/internal/task/task.go @@ -0,0 +1,100 @@ +package task + +import "time" + +type State string + +const ( + StatePending State = "PENDING" + StateQueued State = "QUEUED" + StateRunning State = "RUNNING" + StateCompleted State = "COMPLETED" + StateFailed State = "FAILED" + StateTimedOut State = "TIMED_OUT" + StateCancelled State = "CANCELLED" + StateBudgetExceeded State = "BUDGET_EXCEEDED" +) + +type Priority string + +const ( + PriorityHigh Priority = "high" + PriorityNormal Priority = "normal" + PriorityLow Priority = "low" +) + +type ClaudeConfig struct { + Model string `yaml:"model"` + ContextFiles []string `yaml:"context_files"` + Instructions string `yaml:"instructions"` + WorkingDir string `yaml:"working_dir"` + MaxBudgetUSD float64 `yaml:"max_budget_usd"` + PermissionMode string `yaml:"permission_mode"` + AllowedTools []string `yaml:"allowed_tools"` + DisallowedTools []string `yaml:"disallowed_tools"` + SystemPromptAppend string `yaml:"system_prompt_append"` + AdditionalArgs []string `yaml:"additional_args"` +} + +type RetryConfig struct { + MaxAttempts int `yaml:"max_attempts"` + Backoff string `yaml:"backoff"` // "linear", "exponential" +} + +type Task struct { + ID string `yaml:"id"` + Name string `yaml:"name"` + Description string `yaml:"description"` + Claude ClaudeConfig `yaml:"claude"` + Timeout Duration `yaml:"timeout"` + Retry RetryConfig `yaml:"retry"` + Priority Priority `yaml:"priority"` + Tags []string `yaml:"tags"` + DependsOn []string `yaml:"depends_on"` + State State `yaml:"-"` + CreatedAt time.Time `yaml:"-"` + UpdatedAt time.Time `yaml:"-"` +} + +// Duration wraps time.Duration for YAML unmarshaling from strings like "30m". +type Duration struct { + time.Duration +} + +func (d *Duration) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + dur, err := time.ParseDuration(s) + if err != nil { + return err + } + d.Duration = dur + return nil +} + +func (d Duration) MarshalYAML() (interface{}, error) { + return d.Duration.String(), nil +} + +// BatchFile represents a YAML file containing multiple tasks. +type BatchFile struct { + Tasks []Task `yaml:"tasks"` +} + +// ValidTransition returns true if moving from the current state to next is allowed. +func ValidTransition(from, to State) bool { + transitions := map[State][]State{ + StatePending: {StateQueued, StateCancelled}, + StateQueued: {StateRunning, StateCancelled}, + StateRunning: {StateCompleted, StateFailed, StateTimedOut, StateCancelled, StateBudgetExceeded}, + StateFailed: {StateQueued}, // retry + } + for _, allowed := range transitions[from] { + if allowed == to { + return true + } + } + return false +} |
