Detailed changes
@@ -8,6 +8,7 @@ import (
"errors"
"fmt"
+ "git.secluded.site/go-lunatask"
"github.com/charmbracelet/huh"
"git.secluded.site/lune/internal/config"
@@ -137,6 +138,8 @@ func editArea(existing *config.Area, cfg *config.Config) (*config.Area, error) {
area := config.Area{}
if existing != nil {
area = *existing
+ } else {
+ area.Workflow = lunatask.WorkflowNowLater
}
err := runItemForm(&area.Name, &area.Key, &area.ID, itemFormConfig{
@@ -150,9 +153,37 @@ func editArea(existing *config.Area, cfg *config.Config) (*config.Area, error) {
return nil, err
}
+ if err := selectWorkflow(&area.Workflow); err != nil {
+ return nil, err
+ }
+
return &area, nil
}
+func selectWorkflow(selected *lunatask.Workflow) error {
+ options := make([]huh.Option[lunatask.Workflow], 0, len(lunatask.Workflows()))
+ for _, w := range lunatask.Workflows() {
+ label := fmt.Sprintf("%s - %s", w, w.Description())
+ options = append(options, huh.NewOption(label, w))
+ }
+
+ err := huh.NewSelect[lunatask.Workflow]().
+ Title("Workflow").
+ Description("Determines which task fields are relevant for this area").
+ Options(options...).
+ Value(selected).
+ Run()
+ if err != nil {
+ if errors.Is(err, huh.ErrUserAborted) {
+ return errQuit
+ }
+
+ return err
+ }
+
+ return nil
+}
+
func validateAreaKey(cfg *config.Config, existing *config.Area) func(string) error {
return func(input string) error {
if err := validateKeyFormat(input); err != nil {
@@ -56,10 +56,11 @@ func toAreaProviders(cfgAreas []config.Area) []shared.AreaProvider {
for _, area := range cfgAreas {
providers = append(providers, shared.AreaProvider{
- ID: area.ID,
- Name: area.Name,
- Key: area.Key,
- Goals: shared.ToGoalProviders(area.Goals),
+ ID: area.ID,
+ Name: area.Name,
+ Key: area.Key,
+ Workflow: area.Workflow,
+ Goals: shared.ToGoalProviders(area.Goals),
})
}
@@ -7,7 +7,7 @@ module git.secluded.site/lune
go 1.25.5
require (
- git.secluded.site/go-lunatask v0.1.0-rc9.1
+ git.secluded.site/go-lunatask v0.1.0-rc9.2
github.com/BurntSushi/toml v1.6.0
github.com/charmbracelet/fang v0.4.4
github.com/charmbracelet/huh v0.8.0
@@ -2,8 +2,8 @@ al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXy
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106193318-19329a3e8410 h1:D9PbaszZYpB4nj+d6HTWr1onlmlyuGVNfL9gAi8iB3k=
charm.land/lipgloss/v2 v2.0.0-beta.3.0.20251106193318-19329a3e8410/go.mod h1:1qZyvvVCenJO2M1ac2mX0yyiIZJoZmDM4DG4s0udJkU=
-git.secluded.site/go-lunatask v0.1.0-rc9.1 h1:6dJcP3P+2QraPQ/wfPjCWaXv2mr1B4lMvBuQCNZd1t8=
-git.secluded.site/go-lunatask v0.1.0-rc9.1/go.mod h1:rxps7BBqF+BkY8VN5E7J9zSOzSbtZ1hDmLEOHxjTHZQ=
+git.secluded.site/go-lunatask v0.1.0-rc9.2 h1:fk5fCGdHmKpwz5HPy/n/LURBNweJoRN2xSay36VgA7g=
+git.secluded.site/go-lunatask v0.1.0-rc9.2/go.mod h1:rxps7BBqF+BkY8VN5E7J9zSOzSbtZ1hDmLEOHxjTHZQ=
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
@@ -6,6 +6,7 @@
package completion
import (
+ "git.secluded.site/go-lunatask"
"git.secluded.site/lune/internal/config"
"github.com/spf13/cobra"
)
@@ -90,3 +91,15 @@ func Relationships(_ *cobra.Command, _ []string, _ string) ([]string, cobra.Shel
"almost-strangers",
}, cobra.ShellCompDirectiveNoFileComp
}
+
+// Workflows returns workflow options for shell completion.
+func Workflows(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
+ workflows := lunatask.Workflows()
+ keys := make([]string, len(workflows))
+
+ for i, w := range workflows {
+ keys[i] = string(w)
+ }
+
+ return keys, cobra.ShellCompDirectiveNoFileComp
+}
@@ -11,6 +11,7 @@ import (
"os"
"path/filepath"
+ "git.secluded.site/go-lunatask"
"github.com/BurntSushi/toml"
)
@@ -130,10 +131,11 @@ type Defaults struct {
//
//nolint:recvcheck // Value receivers for Keyed interface; pointer receiver for GoalByKey is intentional.
type Area struct {
- ID string `json:"id" toml:"id"`
- Name string `json:"name" toml:"name"`
- Key string `json:"key" toml:"key"`
- Goals []Goal `json:"goals" toml:"goals"`
+ ID string `json:"id" toml:"id"`
+ Name string `json:"name" toml:"name"`
+ Key string `json:"key" toml:"key"`
+ Workflow lunatask.Workflow `json:"workflow" toml:"workflow"`
+ Goals []Goal `json:"goals" toml:"goals"`
}
// Goal represents a goal within an area.
@@ -24,9 +24,16 @@ Each area represents a life domain (e.g., Work, Personal, Health) and contains:
- id: UUID to use when creating tasks in this area
- name: Human-readable area name
- key: Short alias for CLI usage
-- goals: List of goals within the area, each with id, name, and key
+- workflow: Task management style (determines which fields are relevant)
+- workflow_description: Human-readable explanation of the workflow
+- valid_statuses: Task statuses valid for this workflow
+- uses_motivation: Whether motivation field (must/should/want) is relevant
+- uses_eisenhower: Whether eisenhower matrix is relevant
+- uses_scheduling: Whether date scheduling is relevant
+- uses_priority: Whether priority field is relevant
+- goals: List of goals within the area
-Use this resource to discover valid area and goal IDs before creating or updating tasks.`
+Use workflow information to determine which task fields to set for each area.`
// Handler handles area resource requests.
type Handler struct {
@@ -40,10 +47,17 @@ func NewHandler(areas []shared.AreaProvider) *Handler {
// areaInfo represents an area in the resource response.
type areaInfo struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Key string `json:"key"`
- Goals []goalInfo `json:"goals"`
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Key string `json:"key"`
+ Workflow string `json:"workflow"`
+ WorkflowDescription string `json:"workflow_description"`
+ ValidStatuses []string `json:"valid_statuses"`
+ UsesMotivation bool `json:"uses_motivation"`
+ UsesEisenhower bool `json:"uses_eisenhower"`
+ UsesScheduling bool `json:"uses_scheduling"`
+ UsesPriority bool `json:"uses_priority"`
+ Goals []goalInfo `json:"goals"`
}
// goalInfo represents a goal in the resource response.
@@ -70,11 +84,23 @@ func (h *Handler) HandleRead(
})
}
+ validStatuses := make([]string, 0, len(area.Workflow.ValidStatuses()))
+ for _, s := range area.Workflow.ValidStatuses() {
+ validStatuses = append(validStatuses, string(s))
+ }
+
areasInfo = append(areasInfo, areaInfo{
- ID: area.ID,
- Name: area.Name,
- Key: area.Key,
- Goals: goals,
+ ID: area.ID,
+ Name: area.Name,
+ Key: area.Key,
+ Workflow: string(area.Workflow),
+ WorkflowDescription: area.Workflow.Description(),
+ ValidStatuses: validStatuses,
+ UsesMotivation: area.Workflow.UsesMotivation(),
+ UsesEisenhower: area.Workflow.UsesEisenhower(),
+ UsesScheduling: area.Workflow.UsesScheduling(),
+ UsesPriority: area.Workflow.UsesPriority(),
+ Goals: goals,
})
}
@@ -5,6 +5,8 @@
// Package shared provides common types and utilities for MCP resources and tools.
package shared
+import "git.secluded.site/go-lunatask"
+
// Keyed is an interface for types that have ID, Name, and Key fields.
type Keyed interface {
GetID() string
@@ -14,10 +16,11 @@ type Keyed interface {
// AreaProvider represents an area with its goals for MCP resources.
type AreaProvider struct {
- ID string
- Name string
- Key string
- Goals []GoalProvider
+ ID string
+ Name string
+ Key string
+ Workflow lunatask.Workflow
+ Goals []GoalProvider
}
// GoalProvider represents a goal within an area.