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 ¶
- type Brancher
- type Committer
- type Handler
- func (h *Handler) BumpMinimumVersion(ctx context.Context, cmd *command.BumpMinimumVersionCmd) error
- func (h *Handler) FinishWIP(ctx context.Context, cmd *command.FinishWIPCmd) error
- func (h *Handler) Init(ctx context.Context, cmd *command.InitCmd) error
- func (h *Handler) InstallSkills(ctx context.Context, cmd *command.InstallSkillsCmd) error
- func (h *Handler) LintFix(ctx context.Context, cmd *command.LintFixCmd) error
- func (h *Handler) NewEntry(ctx context.Context, cmd *command.NewEntryCmd) (retErr error)
- func (h *Handler) RewriteEntry(ctx context.Context, cmd *command.RewriteEntryCmd) error
- func (h *Handler) StartWIP(ctx context.Context, cmd *command.StartWIPCmd) error
- func (h *Handler) Summarize(ctx context.Context, cmd *command.SummarizeCmd) error
- func (h *Handler) SyncPull(ctx context.Context, cmd *command.SyncPullCmd) error
- func (h *Handler) WriteSchemaMeta(ctx context.Context, cmd *command.WriteSchemaMetaCmd) error
- type IndexHandler
- type IndexHandlerOptions
- type Mover
- type Options
- type Puller
- type Reader
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 ¶
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 (*Handler) BumpMinimumVersion ¶ added in v0.5.1
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 ¶
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 ¶
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
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 ¶
LintFix applies mechanical fixes to graph entries: loads the graph, identifies fixable issues, patches files in place, and commits.
func (*Handler) NewEntry ¶
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
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 ¶
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 ¶
Summarize executes a SummarizeCmd: loads the graph, determines which entries to (re)generate, generates them via the LLM, and writes updated frontmatter back to disk. Summaries are derived on demand with no staleness tracking (d-cpt-4qi): named entries always regenerate, while --all fills only entries that have no summary yet (--force regenerates every entry). Batch runs 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.
func (*Handler) SyncPull ¶ added in v0.8.0
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
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
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 {
// CurrentGraph returns the current graph through the read-side GraphSource
// seam (a fresh source per call — per-command lifetime, no retained cache).
// Handlers route through it rather than loading directly so cross-repo
// assembly reaches the write path for free at the one seam.
CurrentGraph(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.