cli

package
v0.0.0-...-64c266f Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2026 License: MIT Imports: 113 Imported by: 0

Documentation

Overview

Package cli builds the Cobra command tree for the gemba binary. The cmd/gemba entry point delegates to Execute so subcommand wiring stays out of package main and can be tested directly.

gemba spec — ASDD interception layer command tree.

Subcommands:

spec new <slug>     Scaffold a new spec directory (and optionally Kit files).
spec init           Seed ASDD project artifacts (constitution, hooks, CLAUDE.md).
spec hook           PreToolUse hook handlers (Write/Edit/NotebookEdit, Bash).
spec preflight      Refuse /implement when tasks.md still exists.
spec reconcile      Stub — to be implemented by the analyzer (gm-v0sp.21).

spec_analyze.go — `gemba spec analyze` command tree.

Reads a rejected tasks.md / todo.md payload (from --input, stdin, or the GEMBA_REJECTED_PAYLOAD env var the spec hook sets when it blocks a write), runs internal/spec/analyzer over it, prints the proposal as a table, and — when both --apply and --confirm are passed — materializes each ProposedBead via `bd create`.

The shellout to bd intentionally re-lists every label cumulatively (gemba CLAUDE.md: bd does not auto-inherit). When --parent is provided, the analyzer first calls `bd show <parent>` to harvest that parent's labels and folds them into the cumulative list applied to every new bead, alongside an `analyzer-generated` marker.

gemba spec promote — surface bd mail decision threads as a unified diff the operator can review and `git apply` manually. Per ASDD DoD: we never mutate the spec file in place. Git is the journal.

Index

Constants

View Source
const DefaultDaemonTickPeriod = 10 * time.Second

DefaultDaemonTickPeriod is the period the autodispatch daemon's loop runs at when no per-pool override is set. Spec §6 doesn't pin a number; 10s matches `work-planning.md`'s "loop runs every few seconds" prose without thrashing on a quiet rig.

Variables

View Source
var ErrConformanceFailed = fmt.Errorf("gemba adaptor test: one or more conformance probes failed")

ErrConformanceFailed signals one or more probes failed. Execute() returns a non-zero exit code on this sentinel without re-printing cobra's usage block — the text summary already tells the operator exactly what went wrong.

View Source
var ErrSpecExists = errors.New("spec: target file exists (use --force)")

ErrSpecExists is returned by writePhase2Spec when the target file already exists and --force was not supplied.

Functions

func Execute

func Execute(b BuildInfo) int

Execute builds the root command and runs it. Returns the process exit code.

Types

type AffinityOut

type AffinityOut struct {
	Rows []AffinityRow `json:"rows"`
}

type AffinityRow

type AffinityRow struct {
	BeadID    core.WorkItemID        `json:"bead_id"`
	SessionID string                 `json:"session_id"`
	AgentID   core.AgentID           `json:"agent_id,omitempty"`
	Scores    planner.AffinityScores `json:"scores"`
}

type BackupManifest

type BackupManifest struct {
	CreatedAt     time.Time         `json:"created_at"`
	ServerVersion string            `json:"server_version"`
	Checksums     map[string]string `json:"checksums"`
}

BackupManifest is the JSON document embedded at the root of every backup tarball. The Checksums map is keyed by tar entry path and holds sha256 hex; restorers verify each entry against this map.

type BuildInfo

type BuildInfo struct {
	Version string
	Commit  string
	Date    string
}

BuildInfo carries -ldflags-injected build metadata from cmd/gemba.

type ConflictsOut

type ConflictsOut struct {
	Edges               []conflicts.Edge             `json:"edges"`
	Batches             []conflicts.Batch            `json:"batches"`
	WorkspaceCollisions []planner.WorkspaceCollision `json:"workspace_collisions"`
	SemanticConflicts   []planner.SemanticConflict   `json:"semantic_conflicts"`
	Notices             []string                     `json:"notices,omitempty"`
}

type OperationalContextInput

type OperationalContextInput struct {
	Sessions   []*core.Session                    `json:"sessions"`
	Agents     []*core.AgentRef                   `json:"agents,omitempty"`
	Workspaces []*core.Workspace                  `json:"workspaces,omitempty"`
	Profiles   map[string]*planner.SessionProfile `json:"profiles,omitempty"` // key = session id
	// Optional: explicit clock for deterministic test runs (RFC3339).
	Now string `json:"now,omitempty"`
}

OperationalContextInput is the offline-mode envelope. Operators supply the session/agent/workspace/profile pieces they have and the CLI runs ReadOperationalContext against in-memory readers.

Populating only Sessions still produces a useful result — TimeOnTask is meaningful from a Session alone (see gm-s47n.5.1). Populate Profiles too for ContextPressure + ConceptDrift.

type PlannerInput

type PlannerInput struct {
	// Beads are the candidate WorkItems the planner is reasoning
	// about. Each entry is the planner's projection — id + tags
	// + targets + repo affinity — derived from a real WorkItem
	// upstream.
	Beads []PlannerInputBead `json:"beads"`
	// SessionContexts are the live agent sessions the planner can
	// dispatch against. Pass them along even when only running
	// conflicts: workspace-collision detection cross-references
	// these so a ready bead routed to a worktree another session
	// is already writing in is flagged.
	SessionContexts []planner.OperationalContext `json:"session_contexts,omitempty"`
}

PlannerInput is the wire shape both commands accept on stdin. Fields are optional so an operator can prepare just-conflicts input (no SessionContexts) or just-affinity input (no targets on the beads). The CLI only reads what each command needs.

type PlannerInputBead

type PlannerInputBead struct {
	ID           core.WorkItemID         `json:"id"`
	Concepts     []planner.ConceptTag    `json:"concepts,omitempty"`
	Targets      []string                `json:"targets,omitempty"`
	Repositories []string                `json:"repositories,omitempty"`
	Branch       string                  `json:"branch,omitempty"`
	WorktreePath string                  `json:"worktree_path,omitempty"`
	GlobPatterns []targets.Pattern       `json:"glob_patterns,omitempty"`
	SemanticHits []sourceanalysis.Target `json:"semantic_hits,omitempty"`
}

PlannerInputBead captures every per-bead field the two CLI commands need. Targets are file paths (already glob-expanded by the caller); BeadTarget is the routing-collision input for workspace conflict.

type PlannerJSONOut

type PlannerJSONOut struct {
	Conflicts *ConflictsOut `json:"conflicts,omitempty"`
	Affinity  *AffinityOut  `json:"affinity,omitempty"`
}

PlannerJSONOut is the stable shape for both --json modes. The command sets exactly one of Conflicts or Affinity per call.

type RetroListInput

type RetroListInput struct {
	Grades []retro.Grade `json:"grades"`
}

RetroListInput is the offline-mode wire shape for `gemba retro list`. Grades is the input set; ListFilter narrows it the same way the dolt-mode SQL filter would.

type RetroListOut

type RetroListOut struct {
	Rows []retro.Grade `json:"rows"`
}

RetroListOut is the stable --json envelope.

type SessionHealthEntry

type SessionHealthEntry struct {
	Session *core.Session           `json:"session"`
	Profile *planner.SessionProfile `json:"profile,omitempty"`
}

SessionHealthEntry is one (Session, Profile) pair. Profile is optional: a session that's still booting may have no profile row yet — TimeOnTask is meaningful from the session alone.

type SessionHealthInput

type SessionHealthInput struct {
	Sessions     []SessionHealthEntry                               `json:"sessions"`
	BeadConcepts map[core.WorkItemID]map[planner.ConceptTag]float64 `json:"bead_concepts,omitempty"`
	// Now overrides time.Now for deterministic test runs. RFC3339
	// string. Empty → live wall clock.
	Now string `json:"now,omitempty"`
}

SessionHealthInput is the wire shape `gemba session-health` consumes. One entry per session under inspection. Optional bead_concepts seeds the drift-vector lookup — when omitted, the computation falls through to ConceptDrift=0 (treat as "no recent drift signal"), still useful for the other two numbers.

type SessionHealthOut

type SessionHealthOut struct {
	Rows []SessionHealthRow `json:"rows"`
}

SessionHealthOut is the stable --json envelope. One row per input session, in the same order, with thresholds rendered as strings so consumers don't reimplement the rule table.

type SessionHealthRow

type SessionHealthRow struct {
	SessionID         string  `json:"session_id"`
	AgentID           string  `json:"agent_id,omitempty"`
	ContextPressure   float64 `json:"context_pressure"`
	ConceptDrift      float64 `json:"concept_drift"`
	TimeOnTaskSeconds float64 `json:"time_on_task_seconds"`
	// PressureLevel and DriftLevel are "ok" | "warn" | "recycle"
	// per spec §4 Layer 4. The CLI carries the labels so a future
	// machine consumer doesn't need to duplicate the threshold
	// table.
	PressureLevel string `json:"pressure_level"`
	DriftLevel    string `json:"drift_level"`
}

type SessionStatusEntry

type SessionStatusEntry struct {
	Session     *core.Session           `json:"session"`
	Profile     *planner.SessionProfile `json:"profile,omitempty"`
	Calibration float64                 `json:"calibration,omitempty"`
}

SessionStatusEntry is one (Session, Profile, Calibration) tuple. Calibration is optional; zero falls through to runway's default.

type SessionStatusInput

type SessionStatusInput struct {
	Sessions     []SessionStatusEntry                               `json:"sessions"`
	BeadConcepts map[core.WorkItemID]map[planner.ConceptTag]float64 `json:"bead_concepts,omitempty"`
	// Now overrides time.Now for deterministic test runs.
	Now string `json:"now,omitempty"`
}

SessionStatusInput is the wire shape `gemba session-status` consumes. Mirrors SessionHealthInput plus a per-session calibration override so the operator can replay promised-vs-actual data without rebuilding the input from scratch.

type SessionStatusOut

type SessionStatusOut struct {
	Rows []SessionStatusRow `json:"rows"`
}

SessionStatusOut is the stable --json envelope. One row per input session in the same order.

type SessionStatusRow

type SessionStatusRow struct {
	SessionID         string        `json:"session_id"`
	AgentID           string        `json:"agent_id,omitempty"`
	ContextPressure   float64       `json:"context_pressure"`
	ConceptDrift      float64       `json:"concept_drift"`
	TimeOnTaskSeconds float64       `json:"time_on_task_seconds"`
	PressureLevel     string        `json:"pressure_level"`
	DriftLevel        string        `json:"drift_level"`
	Runway            runway.Runway `json:"runway"`
}

type SizeCalibrationInput

type SizeCalibrationInput struct {
	Samples []SizeCalibrationSample `json:"samples"`
	// Targets is optional — when omitted the aggregator uses
	// sizecalibration.DefaultBucketTargets.
	Targets *SizeCalibrationTargets `json:"targets,omitempty"`
	// CurrentThresholds is optional — when omitted the aggregator
	// uses enrichment.DefaultSizeThresholds.
	CurrentThresholds *enrichment.SizeHeuristicThresholds `json:"current_thresholds,omitempty"`
}

SizeCalibrationInput is the wire shape `gemba size-calibration` accepts on stdin. Samples carry actual_seconds rather than a time.Duration so JSON is unambiguous; the CLI converts at the boundary.

type SizeCalibrationSample

type SizeCalibrationSample struct {
	BeadID        core.WorkItemID          `json:"bead_id,omitempty"`
	Predicted     enrichment.EstimatedSize `json:"predicted"`
	ActualSeconds float64                  `json:"actual_seconds"`
	Author        string                   `json:"author,omitempty"`
}

type SizeCalibrationTargets

type SizeCalibrationTargets struct {
	SmallSeconds  float64 `json:"small_seconds"`
	MediumSeconds float64 `json:"medium_seconds"`
	LargeSeconds  float64 `json:"large_seconds"`
}

Directories

Path Synopsis
Package serverconfig resolves the gemba server URL for CLI verbs.
Package serverconfig resolves the gemba server URL for CLI verbs.

Jump to

Keyboard shortcuts

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