handlers

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Jun 28, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package handlers is the only place framework Go code is allowed to have side effects. Handlers are the write side of CQRS: they accept a domain command, do any validation against loaded state, perform IO (git, disk, pre-flight via a finder dependency), and return only errors. Results flow back through callbacks defined on the command struct.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Brancher

type Brancher interface {
	Checkout(branch string, create bool) error
	BranchMerged(branch string) bool
	DeleteBranch(branch string, force bool) error
}

Brancher performs git branch operations. Injected so tests can fake checkout/branch deletion without touching real git.

type Committer

type Committer interface {
	Commit(message string, paths ...string) error
}

Committer performs a git commit of the given paths with the given message. Injected so tests can record or no-op commits.

type Handler

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

Handler holds injected dependencies shared across command methods. Each public method corresponds to one command and lives in its own file (handler_new_entry.go, etc.).

func New

func New(opts Options) *Handler

New constructs a Handler with the given options.

func (*Handler) BumpMinimumVersion added in v0.5.1

func (h *Handler) BumpMinimumVersion(ctx context.Context, cmd *command.BumpMinimumVersionCmd) error

BumpMinimumVersion raises .sdd/meta.json's minimum_version field to the running binary's version when the binary is strictly higher (or no minimum was recorded). Equal versions are a no-op so repeat invocations stay quiet.

Dev builds are rejected with a fixed message — only released binaries may raise the floor, otherwise a developer's local pinning could lock every other contributor out of the graph until that exact dev build is available.

func (*Handler) FinishWIP

func (h *Handler) FinishWIP(ctx context.Context, cmd *command.FinishWIPCmd) error

FinishWIP removes the WIP marker identified by cmd.MarkerID, commits the removal, and (if the marker referenced a branch) deletes the branch when merged or when --force is set. Unmerged non-force branches are preserved and OnBranchPreserved fires so the CLI can print guidance.

func (*Handler) Init

func (h *Handler) Init(ctx context.Context, cmd *command.InitCmd) error

Init executes an InitCmd. The operation is idempotent:

  • On an empty tree, it creates .sdd/, writes config.yaml and meta.json, creates the graph dir, updates .gitignore, and installs the embedded skill bundle.
  • On an existing tree, it leaves config.yaml and meta.json alone, ensures the expected directories are in place, and runs the skill install pass to refresh whatever's drifted (user-modified files are routed through cmd.PromptOverwrite).

The skill install step and the meta-write step are implemented as nested commands (h.InstallSkills and h.WriteSchemaMeta), keeping each side effect in its own handler method.

func (*Handler) InstallSkills added in v0.2.0

func (h *Handler) InstallSkills(ctx context.Context, cmd *command.InstallSkillsCmd) error

InstallSkills writes the embedded skill bundle to the target agent's skill directory. Side effects are limited to filesystem writes — the skill status classification itself comes from the injected reader (SkillStatus query).

func (*Handler) LintFix

func (h *Handler) LintFix(ctx context.Context, cmd *command.LintFixCmd) error

LintFix applies mechanical fixes to graph entries: loads the graph, identifies fixable issues, patches files in place, and commits.

func (*Handler) NewEntry

func (h *Handler) NewEntry(ctx context.Context, cmd *command.NewEntryCmd) (retErr error)

NewEntry executes a NewEntryCmd: validates, loads the graph, runs pre-flight, writes the entry + attachments, commits, and fires cmd.OnNewEntry with the new ID. Stdin attachments are persisted to .sdd-tmp/ on pre-flight rejection and on every --dry-run invocation so the user can iterate without re-piping heredocs.

Returns only errors. On dry-run success, returns nil without invoking the callback (no entry was created).

func (*Handler) RewriteEntry added in v0.2.0

func (h *Handler) RewriteEntry(ctx context.Context, cmd *command.RewriteEntryCmd) error

RewriteEntry executes a RewriteEntryCmd: resolves the target entry, computes its new ID from the requested type, walks the graph for inbound references, renames the file (and attachment directory) when the type changes, rewrites frontmatter on the target and every inbound entry, and commits atomically. Bypasses pre-flight per the plan: rewrite is a mechanical operation, not a capture.

DryRun returns without touching disk after reporting intended changes via the OnRewritten callback. NoCommit writes to disk but skips the git commit.

func (*Handler) StartWIP

func (h *Handler) StartWIP(ctx context.Context, cmd *command.StartWIPCmd) error

StartWIP creates a WIP marker for cmd.EntryID, commits it, and optionally creates + checks out a derived git branch. Validates that the entry exists in the graph and warns (via OnExclusiveCollision) when another exclusive marker already covers the entry.

func (*Handler) Summarize

func (h *Handler) Summarize(ctx context.Context, cmd *command.SummarizeCmd) error

Summarize executes a SummarizeCmd: loads the graph, determines which entries need summaries, generates them via the LLM, and writes updated frontmatter back to disk. Batch runs (--all or multiple entries) use an errgroup with SetLimit(concurrency) — for remote providers the factory applies a rate limiter on top. A short-lived mutex guards graph reads and writes; the LLM call itself runs without the lock.

When cmd.ExplicitText is set, the LLM is bypassed entirely: the supplied text is written as the summary on a single named entry, with the hash recomputed from the current prompt so future regenerations skip-by-hash.

func (*Handler) SyncPull added in v0.8.0

func (h *Handler) SyncPull(ctx context.Context, cmd *command.SyncPullCmd) error

SyncPull pulls the shared graph from upstream using a merge (never a rebase), so background sync never rewrites the shared history. It refuses on a dirty working tree and defers to the user with an actionable message; on a clean tree it runs the merge pull and reports git's output through the command's OnPulled callback.

func (*Handler) WriteSchemaMeta added in v0.2.0

func (h *Handler) WriteSchemaMeta(ctx context.Context, cmd *command.WriteSchemaMetaCmd) error

WriteSchemaMeta creates .sdd/meta.json when it does not yet exist. Existing files are preserved as-is — both graph_schema_version and minimum_version have write-once semantics in the init flow (schema bumps are migration concerns, minimum_version is set at graph creation time and preserved thereafter).

type IndexHandler added in v0.4.0

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

IndexHandler is the side-effecting code path for building and lazily filling the search index. Per d-tac-lqr it owns chunking, embedding, and upserting; the SearchFinder is pure-read and consults the index via index.Index directly.

Two operations:

  • Build (sdd index): full warm-up over every entry on disk. Skips entries whose manifest record is up-to-date unless Force is set.

  • LazyFill (sdd search prelude): reconciles the manifest against entries on disk — re-embeds entries that are missing, or whose content hash / embedder fingerprint differs from the stored state.

func NewIndexHandler added in v0.4.0

func NewIndexHandler(opts IndexHandlerOptions) *IndexHandler

NewIndexHandler constructs an IndexHandler with the given dependencies.

func (*IndexHandler) Build added in v0.4.0

func (h *IndexHandler) Build(ctx context.Context, cmd *command.BuildIndexCmd) error

Build is the sdd-index warm-up. It loads the graph, derives chunks for every entry (skipping unchanged ones unless cmd.Force), embeds in batches across entries (one Embed call per outer batch), and upserts per-entry into the index. The manifest is saved after every batch — a crash mid-build leaves a partially-populated index that lazy-fill can finish later.

func (*IndexHandler) LazyFill added in v0.4.0

func (h *IndexHandler) LazyFill(ctx context.Context, cmd *command.LazyFillIndexCmd) error

LazyFill is the sdd-search prelude — only entries missing from the manifest, or whose hash/fingerprint differs from current, are re-embedded.

type IndexHandlerOptions added in v0.4.0

type IndexHandlerOptions struct {
	GraphDir   string
	IndexDir   string
	Embedder   llm.Embedder
	Splitter   *textsplitter.Splitter
	IndexStore *index.Index
	Reader     Reader
	Now        func() time.Time
	Stderr     io.Writer
}

IndexHandlerOptions configures NewIndexHandler. Required fields are GraphDir, IndexDir, Embedder, IndexStore, Reader. Splitter defaults to textsplitter.NewSplitter() with default options when nil; Now defaults to time.Now.

type Mover added in v0.2.0

type Mover interface {
	Move(src, dst string) error
}

Mover renames a path in the working tree and the git index as one operation — the semantics of `git mv`. Injected so tests can fake moves without shelling out. Used by the rewrite handler when the target entry changes type and its file needs a new on-disk location.

type Options

type Options struct {
	GraphDir  string
	SDDDir    string // path to .sdd/ directory; required for commands that write tmp files
	Reader    Reader
	LLMRunner llm.Runner
	Committer Committer
	Brancher  Brancher
	Mover     Mover
	Puller    Puller
	Stderr    io.Writer
	Now       func() time.Time
}

Options configures a new Handler. Zero-valued fields get sensible defaults.

type Puller added in v0.8.0

type Puller interface {
	// IsClean reports whether the working tree has no uncommitted changes
	// (a `git status --porcelain` with empty output).
	IsClean(ctx context.Context) (bool, error)
	// MergePull runs a merge-only pull (`git pull --no-rebase`) and returns
	// git's combined output. A non-nil error means the pull failed.
	MergePull(ctx context.Context) (string, error)
}

Puller is the git surface for `sdd sync --pull`: a merge-only pull that never rewrites the shared graph's history. Injected so tests can fake the working-tree state and the pull without shelling out to git.

type Reader

type Reader interface {
	LoadGraph(dir string) (*model.Graph, error)
	LoadWIPMarkers(graphDir string) ([]*model.WIPMarker, error)
	Preflight(ctx context.Context, q query.PreflightQuery) (*query.PreflightResult, error)
	SkillStatus(ctx context.Context, q query.SkillStatusQuery) (*query.SkillStatusResult, error)
}

Reader is the handler-side view of the finder. It bundles every read operation handlers need (graph loading, pre-flight, WIP markers, install state). Defined here (rather than imported as the concrete *finders.Finder) so consumers can substitute fakes in tests — standard "accept interfaces, return structs" Go pattern. *finders.Finder satisfies this interface.

Jump to

Keyboard shortcuts

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