tasklist

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package tasklist implements a small, self-contained store for labelled, ordered collections of tasks. It owns the task_lists and tasks tables in the shared SQLite database (opened by the statestore package) but knows nothing about plans, phases, or any other owner: a task list is just a label, a lifecycle status, and an ordered set of task rows.

planengine consumes this package to back a plan phase's tasks, but the decoupling is deliberate — a future standalone task-list path can use tasklist directly without going through planengine at all.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("tasklist: not found")

ErrNotFound is returned when a lookup by ID finds no row. Callers can match against this with errors.Is.

Functions

func FenceFor

func FenceFor(content string) string

FenceFor returns a backtick fence string long enough to safely wrap content as a Markdown code block: at least three backticks, and always longer than the longest run of backticks appearing inside content. This prevents a hint that itself contains a fenced code block from prematurely closing the wrapping fence.

func RenderHint

func RenderHint(hint, indent string) string

RenderHint renders a task hint as a fenced code block, with every line (including the fences) prefixed by indent so it nests under its task bullet. The fence length is chosen by FenceFor so hint content containing backticks renders intact. The returned string ends with a newline.

func RenderMarkdown

func RenderMarkdown(tl TaskListWithTasks) string

RenderMarkdown produces the human-readable view of a single task list: an H1 with the list label, a status line, then a checkbox list of the tasks in display order. The function is pure — it takes a TaskListWithTasks and returns a string; the caller is responsible for writing the bytes anywhere.

Types

type ListStatus

type ListStatus string

ListStatus names the lifecycle state of a whole task list. pending is the starting state; in_progress once work has begun; completed when every task is resolved; abandoned when the list is dropped without completion.

const (
	ListStatusPending    ListStatus = "pending"
	ListStatusInProgress ListStatus = "in_progress"
	ListStatusCompleted  ListStatus = "completed"
	ListStatusAbandoned  ListStatus = "abandoned"
)

func (ListStatus) IsValid

func (s ListStatus) IsValid() bool

IsValid reports whether s is one of the four recognised list statuses. Used to validate input on UpdateListStatus.

type Status

type Status string

Status names the lifecycle state of a single task within a list. pending is the starting state when the task is created. in_progress is set just before work begins; done after it is verified; skipped when the task can no longer be completed cleanly and the owner has agreed to move on. The values mirror planengine's task statuses so a plan-backed list renders identically.

const (
	StatusPending    Status = "pending"
	StatusInProgress Status = "in_progress"
	StatusDone       Status = "done"
	StatusSkipped    Status = "skipped"
)

func (Status) IsValid

func (s Status) IsValid() bool

IsValid reports whether s is one of the four recognised task statuses. Used to validate input on UpdateTaskStatus so a typo is surfaced to the caller instead of silently corrupting the DB.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store wraps the shared SQLite connection and offers narrowly-scoped helpers for creating task lists, adding tasks, and transitioning statuses. It borrows the connection from statestore and never closes it; the session owns the connection lifecycle.

func New

func New(db *statestore.DB) (*Store, error)

New returns a Store backed by the shared statestore connection, bootstrapping its tables on first use. It does not open or own the database — statestore does — so the connection is shared with every other state-owning package.

func (*Store) AddTask

func (s *Store) AddTask(listID int64, body, hint string) (Task, error)

AddTask appends a new task to the list identified by listID, auto- assigning the next ord and bumping the list's updated_at. hint is optional freeform execution context; pass "" for none. Returns the persisted Task. Errors with ErrNotFound if listID does not exist.

func (*Store) Bootstrap

func (s *Store) Bootstrap(ctx context.Context) error

Bootstrap creates the task_lists/tasks tables and the task index on the shared connection via the embedded CREATE TABLE IF NOT EXISTS script. It is idempotent: a no-op on an already-bootstrapped database, full creation on a fresh one. modernc.org/sqlite executes the multi-statement script as a batch.

func (*Store) CreateList

func (s *Store) CreateList(label string) (TaskList, error)

CreateList inserts a new task list with the default pending status and equal created_at/updated_at timestamps. Returns the persisted TaskList with its allocated ID. label is required.

func (*Store) GetList

func (s *Store) GetList(id int64) (TaskListWithTasks, error)

GetList returns the list and its tasks in display order. Errors with ErrNotFound if the list does not exist.

func (*Store) GetTask

func (s *Store) GetTask(taskID int64) (Task, error)

GetTask loads a single task by ID, including its task_list_id so callers can resolve the owning list. Errors with ErrNotFound if absent.

func (*Store) ListLists

func (s *Store) ListLists(filter ListStatus) ([]TaskList, error)

ListLists returns all task lists ordered most-recently-updated first. When filter is non-empty, only lists with that status are returned; passing "" returns every list.

func (*Store) ReorderTask

func (s *Store) ReorderTask(taskID int64, targetPos int) error

ReorderTask moves the task identified by taskID to targetPos (1-based) among its list's tasks, using the shared collision-safe reorder algorithm, and bumps the owning list's updated_at. Fires afterMutate on success, same as UpdateTask. Errors with ErrNotFound if the task does not exist.

func (*Store) SetAfterMutate

func (s *Store) SetAfterMutate(fn func(taskID int64) error)

SetAfterMutate registers a hook invoked after every committed task insert or status change, receiving the affected task's ID. Pass nil to clear it. It exists so the session can wire planengine's plan-touch onto the single shared task store without coupling tasklist to plan concepts. Not safe for concurrent use with task writes; set it once during session setup.

func (*Store) UpdateListStatus

func (s *Store) UpdateListStatus(listID int64, status ListStatus) error

UpdateListStatus sets a list's status and bumps its updated_at. Errors if the list does not exist or the status is not a recognised ListStatus.

func (*Store) UpdateTask

func (s *Store) UpdateTask(taskID int64, upd TaskUpdate) error

UpdateTask applies the provided fields of upd to the task identified by taskID, bumps the owning list's updated_at, and fires afterMutate. Only the non-nil pointer fields are written, built into a dynamic SET clause, so a caller can change any subset of body, hint, and status in one round trip. A nil-everywhere update is a no-op error. A non-nil Status is validated; a Hint set to "" stores SQL NULL (clearing the hint). Errors with ErrNotFound if the task does not exist.

func (*Store) UpdateTaskStatus

func (s *Store) UpdateTaskStatus(taskID int64, status Status) error

UpdateTaskStatus sets a task's status and bumps the owning list's updated_at. Errors if the task does not exist or the status string is not one of the four recognised values.

type Task

type Task struct {
	ID         int64
	TaskListID int64
	Ord        int
	Body       string
	Hint       string
	Status     Status
}

Task is one row of the tasks table. TaskListID identifies the owning list (used for owner resolution by consumers). Ord is the 1-based display order within the list; the store assigns it on insert as MAX(ord)+1. Body is a single imperative-mood sentence; Status drives the checkbox glyph in the rendered markdown. Hint is optional freeform execution context (rationale or a code snippet) authored by the planning model and consumed by the executing model; empty when unset.

type TaskList

type TaskList struct {
	ID        int64
	Label     string
	Status    ListStatus
	CreatedAt time.Time
	UpdatedAt time.Time
}

TaskList is one row of the task_lists table. Label is the human-readable heading shown in the rendered markdown; Status drives the list-level lifecycle. CreatedAt/UpdatedAt are maintained by the store.

func CreateListTx

func CreateListTx(tx *sql.Tx, label string) (TaskList, error)

CreateListTx inserts a new task list within an existing transaction and returns the persisted TaskList. It exists so a caller composing a larger multi-table write — e.g. planengine.AddPhase creating a phase and its linked task list atomically — can do so on a single connection. Opening a second pool connection (via Store.CreateList) while a write transaction is already open would deadlock under SQLite's single-writer model. label is required.

type TaskListWithTasks

type TaskListWithTasks struct {
	List  TaskList
	Tasks []Task
}

TaskListWithTasks groups a list with its tasks in display order. It is the shape returned by GetList so a consumer can load a whole list in one call.

type TaskUpdate

type TaskUpdate struct {
	Body   *string
	Hint   *string
	Status *Status
}

TaskUpdate carries an optional, partial edit to a task: each non-nil pointer field is applied, each nil field is left unchanged. It lets a single UpdateTask call change any subset of a task's body, hint, or status while distinguishing an omitted field from one explicitly set to the empty string (e.g. clearing a hint).

Source Files

  • render.go
  • store.go
  • tasklist.go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL