sidekick

package
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package sidekick scaffolds lint-clean sidekick-seed artifacts — the scaled-down Idea one-pagers parked under spec/ideas/seeds/.

Features implemented: cli/sidekick/new

Index

Constants

View Source
const (
	// MaxOneLinerChars caps the trimmed one-liner length
	// (cli/sidekick/new#req:one-liner-length).
	MaxOneLinerChars = 500
	// MaxBodyChars caps the body region (H1 line through end of optional
	// content) at capture. A freshly captured seed is `status: queued`, so
	// this matches the sidekick-seed lint rule's OPEN (queued) hard cap
	// (cli/sidekick/new#req:optional-body). Authors are advised (via a lint
	// warning) to keep a queued seed under 2500.
	MaxBodyChars = 3000
	// MaxSlugChars caps the derived slug length
	// (cli/sidekick/new#req:slug-derivation).
	MaxSlugChars = 60
)
View Source
const (
	SeedQueued      lifecycle.Status = "Queued"
	SeedImplemented lifecycle.Status = "Implemented"
	SeedRejected    lifecycle.Status = "Rejected"
	SeedStale       lifecycle.Status = "Stale"
)

Seed lifecycle statuses. Values reuse the canonical title-case strings from pkg/lifecycle where they overlap; `Queued` is seed-specific.

Variables

View Source
var ErrFrontmatterStatusNotFound = fmt.Errorf("sidekick: seed has no frontmatter status: line")

ErrFrontmatterStatusNotFound is returned by RewriteFrontmatterStatus when the seed has no recognizable frontmatter `status:` line.

Functions

func CheckSeedSource added in v0.11.0

func CheckSeedSource(current string) error

CheckSeedSource enforces the strict source-state check: the legal source set for every seed target is {Queued}. A current frontmatter status (matched case-insensitively against `Queued`) other than the legal source yields an exit-4 (InvalidTransition) error whose message names the current status and the legal source set, per cli/sidekick/change-status#req:legal-transition-matrix and lifecycle-transitions#req:state-machine-strictness. A `Queued` source returns nil.

current is the verbatim on-disk frontmatter `status:` value.

func DeriveSlug

func DeriveSlug(oneLiner string) (string, error)

DeriveSlug turns a one-liner into a lowercase, hyphen-separated, URL-safe slug, mirroring the specstudio:sidekick skill's algorithm so the CLI and the skill produce identical slugs for identical input (cli/sidekick/new#req:slug-derivation). It returns an error when the one-liner contains no slug-safe characters.

func ParseSeedTarget added in v0.11.0

func ParseSeedTarget(raw string) (lifecycle.Status, error)

ParseSeedTarget does case-insensitive parsing of a raw `--to` flag value against the seed terminal set {Implemented, Rejected, Stale}, returning the canonical title-case Status on success. Whitespace is trimmed and case is folded ("implemented", "IMPLEMENTED", " Rejected " all match).

An unrecognized value (including `Queued`, which is a source-only status and never a target) yields an exit-2 (InvalidArgs) error. Callers MUST invoke this BEFORE the state-machine source check so a bad `--to` fails at exit 2 rather than slipping through to an exit-4 rejection (cli/sidekick/change-status#req:target-status-flag).

func ReadFrontmatterStatus added in v0.11.0

func ReadFrontmatterStatus(seedPath string) (string, error)

ReadFrontmatterStatus returns the verbatim frontmatter `status:` value at seedPath (trimmed of surrounding whitespace), for the strict source-state check the change-status verb runs before any mutation. If the seed has no recognizable frontmatter `status:` line, it returns ErrFrontmatterStatusNotFound.

func Relocate added in v0.11.0

func Relocate(opts RelocateOptions) error

Relocate performs the terminal relocation for a sidekick seed:

  1. If spec/ideas/archived/<slug>.md already exists, exits 1 (Conflict) WITHOUT touching the source seed — it remains byte-identical at spec/ideas/seeds/<slug>.md with its original frontmatter status.
  2. Rewrites the frontmatter status: value to NewStatus (Task 3).
  3. Adds the frontmatter key type: sidekick-seed.
  4. mkdir-p's spec/ideas/archived/ and moves the seed there.

On ANY failure after the status rewrite (step 2 onward) — including the afterMoveHook test seam — Relocate restores the seed to its exact pre-invocation seeds/ state: original status, no type, file back at seeds/<slug>.md, and (via RollbackHook) no body note. The returned error carries exit 1 for a collision and exit 10 for an I/O or post-move failure.

func ResolveSeedPath added in v0.11.0

func ResolveSeedPath(specRoot, slug string) (string, error)

ResolveSeedPath resolves slug to its canonical seed path spec/ideas/seeds/<slug>.md under specRoot (the project root containing the spec/ subtree, NOT the spec/ directory itself), honoring any configured ideas-path override via idea.ResolveSeedsDir.

A seed already relocated to spec/ideas/archived/<slug>.md is NEVER a fallback (lifecycle-transitions#req:slug-resolves-to-existing-artifact): the canonical lookup is the seeds/ path only. When no file exists at that path, ResolveSeedPath returns an exit-3 (NotFound) error naming the expected spec/ideas/seeds/<slug>.md path (cli/sidekick/change-status#req:seed-slug-resolution).

func RewriteFrontmatterStatus added in v0.11.0

func RewriteFrontmatterStatus(seedPath string, newStatus string) (string, error)

RewriteFrontmatterStatus rewrites the frontmatter `status:` value at seedPath to newStatus in place, replacing only the value text. Every other byte of the file (line ordering, indentation, line endings, trailing whitespace, and all other frontmatter keys and body) is preserved (cli/sidekick/change-status#req:seed-status-surface).

The returned string is the ORIGINAL `status:` line content (including its line terminator), suitable for a later rollback to undo the mutation.

If the seed has no frontmatter `status:` line, RewriteFrontmatterStatus returns ErrFrontmatterStatusNotFound and the file is left untouched.

func Scaffold

func Scaffold(opts ScaffoldOptions) ([]byte, error)

Scaffold returns a lint-clean sidekick-seed file body: the minimal `{captured_by, status}` frontmatter the `sidekick-seed` lint rule enforces, followed by an H1 whose heading is the one-liner verbatim and any optional body. The `type: sidekick-seed` key is NOT written here — captured seeds in spec/ideas/seeds/ are identified by location; `type` is added only when a seed is archived. It validates the one-liner and body cap, returning an error on violation.

func SeedReasonRequiredSet added in v0.11.0

func SeedReasonRequiredSet() lifecycle.ReasonRequiredSet

SeedReasonRequiredSet returns the seed verb's reason-required designation: the `Queued → Rejected` arc requires a non-empty `--note`. Implemented and Stale keep `--note` optional. The change-status verb passes this set to lifecycle.GuardReason before any mutation (cli/sidekick/change-status#req:reason-required-rejected).

func SeedTargetNames added in v0.11.0

func SeedTargetNames() []string

SeedTargetNames returns the canonical title-case names of the legal `--to` values, for cobra help text and stderr rendering.

func ValidateSlug added in v0.7.3

func ValidateSlug(slug string) error

ValidateSlug returns nil when slug is a lowercase, hyphen-separated, URL-safe identifier with no `/` — the same shape DeriveSlug produces. It is used to validate a caller-supplied `--slug` override (cli/sidekick/new#req:slug-override).

Types

type RelocateOptions added in v0.11.0

type RelocateOptions struct {
	// SpecRoot is the project root containing the spec/ subtree.
	SpecRoot string
	// Slug is the seed slug (file basename without .md).
	Slug string
	// SeedPath is the resolved absolute path to spec/ideas/seeds/<slug>.md,
	// as returned by ResolveSeedPath.
	SeedPath string
	// NewStatus is the canonical title-case terminal status to write into the
	// frontmatter, as returned by ParseSeedTarget.
	NewStatus lifecycle.Status

	// RollbackHook, when non-nil, is invoked during rollback (after the seed's
	// frontmatter status and the file location have been restored) so the
	// caller can undo any body mutation it applied before calling Relocate —
	// e.g. lifecycle.RestoreBody to drop a `## Resolution` note. Its error is
	// surfaced if the primary rollback succeeded.
	RollbackHook func() error

	// AfterMoveHook, when non-nil, is invoked immediately after the file has
	// been moved to the archived path and re-written with the `type:` tag.
	// The change-status verb injects its `spec lint --fix` index sync here so
	// a lint failure triggers the same full rollback (move back to seeds/,
	// restore bytes, RollbackHook) as any other post-move failure
	// (cli/sidekick/change-status#req:rollback-includes-relocation).
	AfterMoveHook func() error
	// contains filtered or unexported fields
}

RelocateOptions parameterizes Relocate.

type ScaffoldOptions

type ScaffoldOptions struct {
	OneLiner string // the H1 text; trimmed before use
	// CapturedBy defaults to "user" when empty.
	CapturedBy string
	// Body is optional markdown appended after the H1 line.
	Body string
}

ScaffoldOptions controls the lint-clean seed file Scaffold emits.

Jump to

Keyboard shortcuts

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