Documentation
¶
Overview ¶
Package poller provides the BeadPoller which discovers ready work across registered anvils by invoking 'bd ready --json' in each anvil directory.
Index ¶
- Constants
- func ExtractEpicBranch(b Bead) stringdeprecated
- func ExtractParentBranch(b Bead) string
- func IsEpicBead(b Bead) bool
- func ResolveBlocks(ctx context.Context, beads []Bead, anvilPaths map[string]string)
- func ResolveEpicBranches(ctx context.Context, beads []Bead, anvilPaths map[string]string)
- type AnvilResult
- type Bead
- type BeadDep
- type BeadPoller
Constants ¶
const DefaultEpicBranchPrefix = "epic/"
DefaultEpicBranchPrefix is the branch name prefix used when an epic bead has no explicit epic-branch label. The branch name is derived as "epic/<epic-id>".
const DefaultFeatureBranchPrefix = "feature/"
DefaultFeatureBranchPrefix is the branch name prefix used for non-epic parent beads (e.g. features) that have no explicit epic-branch label.
const EpicBranchLabelPrefix = "epic-branch:"
EpicBranchLabelPrefix is the label prefix used to define an epic's feature branch. A label "epic-branch:feature/depcheck" means the epic uses "feature/depcheck" as its shared branch.
Variables ¶
This section is empty.
Functions ¶
func ExtractEpicBranch
deprecated
ExtractEpicBranch is a backward-compatible wrapper that preserves the legacy semantics used by older callers. It mirrors the label parsing logic of ExtractParentBranch, but for non-epic beads without an explicit epic-branch label it returns the empty string instead of a default feature branch. New code should prefer ExtractParentBranch.
Deprecated: Use ExtractParentBranch instead.
func ExtractParentBranch ¶
ExtractParentBranch extracts the shared feature branch name from a parent bead's labels. It looks for a label with the "epic-branch:" prefix. If none is found, it returns a default branch: "epic/<bead-id>" for epics, or "feature/<bead-id>" for other types (e.g. features with children).
func IsEpicBead ¶
IsEpicBead returns true if the bead is an epic type. This is used by the daemon for the legacy epic branch creation path. For Crucible candidacy, use crucible.IsCrucibleCandidate which checks for children (Blocks) instead.
func ResolveBlocks ¶
ResolveBlocks enriches ready beads with their blocks (children) field by calling `bd show <id> --json` for each bead. Lookups are run concurrently to avoid adding sequential latency when there are many beads.
This is needed because `bd ready --json` may not include the blocks field. All bead types are checked — any bead (feature, task, etc.) can have children that need to be resolved.
func ResolveEpicBranches ¶
ResolveEpicBranches enriches beads that belong to an epic with the epic's branch name. It discovers the epic relationship via two paths:
- Parent field: child.Parent is set to an epic bead ID (legacy).
- Blocks field: child.Blocks contains an epic-type bead ID, meaning the child blocks the epic in the dependency graph. This is the preferred approach because beads with a parent set are hidden from `bd ready`.
It calls `bd show <id> --json` for each unique candidate, caching results to avoid duplicate calls.
Types ¶
type AnvilResult ¶
AnvilResult holds the poll result for a single anvil.
type Bead ¶
type Bead struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Status string `json:"status"`
Priority int `json:"priority"`
IssueType string `json:"issue_type"`
Assignee string `json:"assignee"`
Parent string `json:"parent"`
Labels []string `json:"labels"`
Blocks []string `json:"blocks"` // Bead IDs that this bead blocks (children)
DependsOn []string `json:"depends_on"` // Bead IDs that this bead depends on
Dependencies []BeadDep `json:"dependencies"` // Detailed dependency info from bd
DependentCount int `json:"dependent_count"` // Number of beads that depend on this bead
// Forge-injected: which anvil this bead belongs to
Anvil string `json:"-"`
// Forge-injected: epic branch name resolved from parent epic's labels.
// When set, this bead should branch from and PR to this branch instead of main.
EpicBranch string `json:"-"`
// Forge-injected: when true, dispatch as standalone — skip epic and crucible detection.
ForceIndependent bool `json:"-"`
}
Bead represents an issue returned by 'bd ready --json'. Only the fields Forge needs are extracted.
type BeadDep ¶ added in v0.2.0
type BeadDep struct {
IssueID string `json:"issue_id"`
DependsOnID string `json:"depends_on_id"`
Type string `json:"type"` // "parent-child", "blocks", etc.
}
BeadDep represents a dependency entry in the bd JSON output.
type BeadPoller ¶
type BeadPoller struct {
// StaggerInterval is the delay between starting each anvil's poll.
// When non-zero, each anvil's poll is started sequentially with this delay
// between starts, giving a staggered start across anvils and spreading
// bd/git commands over time instead of firing all at once. The total
// stagger should be less than the poll interval.
StaggerInterval time.Duration
// contains filtered or unexported fields
}
BeadPoller polls registered anvils for ready beads.
func New ¶
func New(anvils map[string]config.AnvilConfig) *BeadPoller
New creates a BeadPoller for the given anvil configurations.
func NewStaggered ¶ added in v0.9.0
func NewStaggered(anvils map[string]config.AnvilConfig, pollInterval time.Duration) *BeadPoller
NewStaggered creates a BeadPoller that staggers anvil polls across the given poll interval. When there are 2 or more anvils, each anvil's poll is delayed by pollInterval / len(anvils) relative to the previous one. With only one anvil no stagger is applied (StaggerInterval remains zero).
func (*BeadPoller) Poll ¶
func (p *BeadPoller) Poll(ctx context.Context) ([]Bead, []AnvilResult)
Poll runs 'bd ready --json' in each anvil directory, merges results, and returns them sorted by priority (lowest number = highest priority). Errors per-anvil are collected but do not stop other anvils from being polled. When StaggerInterval is set, each anvil's poll is delayed relative to the previous one to spread bd/git commands over time.
func (*BeadPoller) PollInProgress ¶
func (p *BeadPoller) PollInProgress(ctx context.Context) ([]Bead, []AnvilResult)
PollInProgress runs 'bd list --status=in_progress --json' in each anvil directory concurrently. It returns all in-progress beads, merged and sorted by priority, along with per-anvil results so callers can distinguish "no in-progress beads" from "bd list failed" and log errors accordingly.
func (*BeadPoller) PollSingle ¶
PollSingle polls a single anvil by name and returns its beads.