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
- Variables
- func CheckSeedSource(current string) error
- func DeriveSlug(oneLiner string) (string, error)
- func ParseSeedTarget(raw string) (lifecycle.Status, error)
- func ReadFrontmatterStatus(seedPath string) (string, error)
- func Relocate(opts RelocateOptions) error
- func ResolveSeedPath(specRoot, slug string) (string, error)
- func RewriteFrontmatterStatus(seedPath string, newStatus string) (string, error)
- func Scaffold(opts ScaffoldOptions) ([]byte, error)
- func SeedReasonRequiredSet() lifecycle.ReasonRequiredSet
- func SeedTargetNames() []string
- func ValidateSlug(slug string) error
- type RelocateOptions
- type ScaffoldOptions
Constants ¶
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 )
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 ¶
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
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 ¶
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
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
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:
- 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.
- Rewrites the frontmatter status: value to NewStatus (Task 3).
- Adds the frontmatter key type: sidekick-seed.
- 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
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
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
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.