← back to jmgilman__sow

Function bodies 590 total

All specs Real LLM only Function bodies
cmd.NewAdvanceCmd function · go · L27-L109 (83 LOC)
cli/cmd/advance.go
func NewAdvanceCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "advance [event]",
		Short: "Progress project to next state",
		Long: `Progress the project through its state machine.

The advance command:
1. Determines the next event based on current state (auto mode)
2. Or fires an explicitly specified event (explicit mode)
3. Evaluates guards to ensure transition is allowed
4. Fires the event if guards pass
5. Saves the updated state

Flags:
  --list     List available transitions without executing
  --dry-run  Validate transition without executing (requires event argument)

Guards may prevent transitions. Common guard failures:
- Planning → Implementation: task_list output not approved
- Implementation Planning → Executing: tasks not approved (metadata.tasks_approved)
- Implementation Executing → Review: not all tasks completed
- Review → Finalize: review not approved or assessment not set

Examples:
  sow advance                    # Auto-determine next event
  sow advance f
cmd.validateAdvanceFlags function · go · L113-L137 (25 LOC)
cli/cmd/advance.go
func validateAdvanceFlags(cmd *cobra.Command, args []string) error {
	listFlag, _ := cmd.Flags().GetBool("list")
	dryRunFlag, _ := cmd.Flags().GetBool("dry-run")

	// Get event argument if provided
	var event string
	if len(args) > 0 {
		event = args[0]
	}

	// Validate flag combinations (order matters - check conflicting flags first)
	if listFlag && dryRunFlag {
		return fmt.Errorf("cannot use --list and --dry-run together")
	}

	if listFlag && event != "" {
		return fmt.Errorf("cannot specify event argument with --list flag")
	}

	if dryRunFlag && event == "" {
		return fmt.Errorf("--dry-run requires an event argument")
	}

	return nil
}
cmd.executeAutoTransition function · go · L146-L191 (46 LOC)
cli/cmd/advance.go
func executeAutoTransition(
	cmd *cobra.Command,
	proj *state.Project,
	currentState string,
) error {
	fmt.Printf("Current state: %s\n", currentState)

	// Type assert to get full project type config
	config, ok := proj.Config().(*project.ProjectTypeConfig)
	if !ok {
		return fmt.Errorf("invalid project configuration")
	}

	// Build project machine for current state (returns *project.Machine, not raw *stateless.StateMachine)
	machine := config.BuildProjectMachine(proj, project.State(currentState))

	// Determine which event to fire from current state
	event, err := config.DetermineEvent(proj)
	if err != nil {
		// Enhanced error handling
		return enhanceAutoTransitionError(err, proj, currentState)
	}

	// Fire the event with automatic phase status updates
	if err := config.FireWithPhaseUpdates(machine, event, proj); err != nil {
		// Provide helpful error messages based on error type
		if strings.Contains(err.Error(), "cannot fire event") {
			return fmt.Errorf("transition blocked: %w
cmd.listAvailableTransitions function · go · L195-L264 (70 LOC)
cli/cmd/advance.go
func listAvailableTransitions(
	_ *cobra.Command,
	proj *state.Project,
	currentState string,
) error {
	fmt.Printf("Current state: %s\n\n", currentState)

	// Type assert to get access to introspection methods
	config, ok := proj.Config().(*project.ProjectTypeConfig)
	if !ok {
		return fmt.Errorf("cannot list transitions: invalid project configuration")
	}

	// Get all configured transitions
	allTransitions := config.GetAvailableTransitions(project.State(currentState))
	if len(allTransitions) == 0 {
		fmt.Println("No transitions available from current state.")
		fmt.Println("This may be a terminal state.")
		return nil
	}

	// Get guard-filtered events (what can fire now)
	// Build project machine for current state to evaluate guards
	machine := config.BuildProjectMachine(proj, project.State(currentState))
	permittedTriggers := machine.PermittedTriggers()

	// Build set of permitted events for quick lookup
	permitted := make(map[string]bool)
	for _, trigger := range permittedTriggers 
cmd.enhanceAutoTransitionError function · go · L268-L307 (40 LOC)
cli/cmd/advance.go
func enhanceAutoTransitionError(err error, proj *state.Project, currentState string) error {
	// Type assert to get access to introspection methods
	// The config is always *project.ProjectTypeConfig which has GetAvailableTransitions
	config, ok := proj.Config().(*project.ProjectTypeConfig)
	if !ok {
		// Fallback to basic error if type assertion fails (shouldn't happen in practice)
		return fmt.Errorf("cannot advance from state %s: %w", currentState, err)
	}

	// Check if this is a terminal state (no transitions configured)
	transitions := config.GetAvailableTransitions(project.State(currentState))
	if len(transitions) == 0 {
		return fmt.Errorf(
			"cannot advance from state %s: %w\n\nThis may be a terminal state",
			currentState,
			err,
		)
	}

	// Intent-based branching case (multiple transitions, no discriminator)
	if len(transitions) > 1 {
		// Extract event names
		events := make([]string, len(transitions))
		for i, t := range transitions {
			events[i] = string(t.Event)
		}

cmd.validateTransition function · go · L316-L374 (59 LOC)
cli/cmd/advance.go
func validateTransition(
	_ *sow.Context,
	proj *state.Project,
	currentState string,
	event string,
) error {
	fmt.Printf("Validating transition: %s -> %s\n\n", currentState, event)

	// Type assert to get access to introspection methods
	projectConfig, ok := proj.Config().(*project.ProjectTypeConfig)
	if !ok {
		return fmt.Errorf("cannot validate transition: invalid project configuration")
	}

	// Check if event is configured for this state
	targetState := projectConfig.GetTargetState(project.State(currentState), project.Event(event))
	if targetState == "" {
		fmt.Printf("✗ Event '%s' is not configured for state %s\n\n", event, currentState)
		fmt.Println("Use 'sow advance --list' to see available transitions.")
		return fmt.Errorf("event not configured")
	}

	// Build project machine to check if event can fire
	machine := projectConfig.BuildProjectMachine(proj, project.State(currentState))

	// Check if event can fire (guard passes)
	canFire := machine.CanFire(project.Event(event))
cmd.executeExplicitTransition function · go · L394-L447 (54 LOC)
cli/cmd/advance.go
func executeExplicitTransition(
	cmd *cobra.Command,
	ctx *sow.Context,
	proj *state.Project,
	currentState string,
	event string,
) error {
	fmt.Printf("Current state: %s\n", currentState)

	// Type assert to get access to introspection methods
	config, ok := proj.Config().(*project.ProjectTypeConfig)
	if !ok {
		return fmt.Errorf("cannot execute transition: invalid project configuration")
	}

	// Convert to typed values for API calls
	typedState := project.State(currentState)
	typedEvent := project.Event(event)

	// Validate event is configured for this state
	targetState := config.GetTargetState(typedState, typedEvent)
	if targetState == "" {
		fmt.Printf("\nError: Event '%s' is not configured for state %s\n\n", event, currentState)
		fmt.Println("Use 'sow advance --list' to see available transitions.")
		return fmt.Errorf("event not configured")
	}

	// Build project machine for current state (returns *project.Machine, not raw *stateless.StateMachine)
	machine := config.BuildProjec
Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
cmd.enhanceTransitionError function · go · L451-L479 (29 LOC)
cli/cmd/advance.go
func enhanceTransitionError(
	err error,
	currentState project.State,
	event project.Event,
	targetState project.State,
	config *project.ProjectTypeConfig,
) error {
	// Check if this is a guard failure
	if strings.Contains(err.Error(), "guard condition is not met") {
		guardDesc := config.GetGuardDescription(currentState, event)

		var msg strings.Builder
		msg.WriteString(fmt.Sprintf("Transition blocked: %s\n\n", guardDesc))
		msg.WriteString(fmt.Sprintf("Current state: %s\n", currentState))
		msg.WriteString(fmt.Sprintf("Event: %s\n", event))
		msg.WriteString(fmt.Sprintf("Target state: %s\n\n", targetState))

		if guardDesc != "" {
			msg.WriteString(fmt.Sprintf("The guard condition is not satisfied. %s\n\n", guardDesc))
		}

		msg.WriteString(fmt.Sprintf("Use 'sow advance --dry-run %s' to validate prerequisites.", event))

		return fmt.Errorf("%s", msg.String())
	}

	// Other error types - use default wrapping
	return fmt.Errorf("failed to advance: %w", err)
}
agent.NewAgentCmd function · go · L9-L31 (23 LOC)
cli/cmd/agent/agent.go
func NewAgentCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "agent",
		Short: "Manage AI agents",
		Long: `Manage AI agents for the sow multi-agent system.

Agents are roles (implementer, architect, reviewer, etc.) that can be
spawned by the orchestrator to perform specialized tasks. Each agent
has specific capabilities and prompts tailored to its role.

Commands:
  list      List available agents
  spawn     Spawn an agent to execute a task
  resume    Resume a paused agent session`,
	}

	// Add subcommands
	cmd.AddCommand(newListCmd())
	cmd.AddCommand(newSpawnCmd())
	cmd.AddCommand(newResumeCmd())

	return cmd
}
agent.newListCmd function · go · L10-L23 (14 LOC)
cli/cmd/agent/list.go
func newListCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "list",
		Short: "List available agents",
		Long: `List all available agents in the sow multi-agent system.

Agents are roles that can be spawned by the orchestrator to perform
specialized tasks. Each agent has specific capabilities and prompts
tailored to its role.

The list shows each agent's name and description.`,
		RunE: runList,
	}
}
agent.runList function · go · L25-L40 (16 LOC)
cli/cmd/agent/list.go
func runList(cmd *cobra.Command, _ []string) error {
	registry := agents.NewAgentRegistry()
	agentList := registry.List()

	// Sort agents alphabetically by name
	sort.Slice(agentList, func(i, j int) bool {
		return agentList[i].Name < agentList[j].Name
	})

	cmd.Println("Available agents:")
	for _, agent := range agentList {
		cmd.Printf("  %-14s%s\n", agent.Name, agent.Description)
	}

	return nil
}
agent.newResumeCmd function · go · L16-L64 (49 LOC)
cli/cmd/agent/resume.go
func newResumeCmd() *cobra.Command {
	var phase string
	var agentName string

	cmd := &cobra.Command{
		Use:   "resume [task-id] <prompt>",
		Short: "Resume a paused agent session with feedback",
		Long: `Resume a paused agent session with additional instructions or feedback.

The resume command has two modes:

TASK MODE (with task-id):
  Resumes an agent session that was previously spawned for a task.

  sow agent resume 010 "Use RS256 algorithm for JWT signing"
  sow agent resume 010 "Add error handling" --phase implementation

TASKLESS MODE (with --agent):
  Resumes an agent session that was spawned without a task.

  sow agent resume --agent planner "Focus on auth module first"
  sow agent resume --agent researcher "Look at OAuth 2.0 specifically"

Prerequisites:
  - The session must have been previously created with 'sow agent spawn'
  - The executor must support session resumption

The resume command is typically used in this workflow:
  1. Orchestrator spawns worker -> Worker ex
agent.runResume function · go · L67-L138 (72 LOC)
cli/cmd/agent/resume.go
func runResume(cmd *cobra.Command, args []string, explicitPhase, agentFlag string) error {
	// Get sow context
	ctx := cmdutil.GetContext(cmd.Context())

	// Check if sow is initialized
	if !ctx.IsInitialized() {
		return fmt.Errorf("sow not initialized. Run 'sow init' first")
	}

	// Determine mode based on --agent flag
	hasAgentFlag := agentFlag != ""

	// Parse arguments based on mode
	var taskID, prompt string
	if hasAgentFlag {
		// Taskless mode: only prompt is provided
		if len(args) != 1 {
			return fmt.Errorf("taskless resume requires exactly one argument: <prompt>\nUsage: sow agent resume --agent <name> <prompt>")
		}
		prompt = args[0]
	} else {
		// Task mode: task-id and prompt required
		if len(args) != 2 {
			return fmt.Errorf("task resume requires two arguments: <task-id> <prompt>\nUsage: sow agent resume <task-id> <prompt>")
		}
		taskID = args[0]
		prompt = args[1]
	}

	// Load project state
	proj, err := cmdutil.LoadProject(cmd.Context(), ctx)
	if err != nil {
		if s
agent.runResumeWithTask function · go · L141-L203 (63 LOC)
cli/cmd/agent/resume.go
func runResumeWithTask(cmd *cobra.Command, proj *state.Project, taskID, prompt, explicitPhase string, executorRegistry *agents.ExecutorRegistry, bindings *struct {
	Orchestrator *string `json:"orchestrator,omitempty"`
	Implementer  *string `json:"implementer,omitempty"`
	Architect    *string `json:"architect,omitempty"`
	Reviewer     *string `json:"reviewer,omitempty"`
	Planner      *string `json:"planner,omitempty"`
	Researcher   *string `json:"researcher,omitempty"`
	Decomposer   *string `json:"decomposer,omitempty"`
}) error {
	// Resolve which phase to use
	phaseName, err := resolveTaskPhase(proj, explicitPhase)
	if err != nil {
		return err
	}

	// Get phase
	phaseState, exists := proj.Phases[phaseName]
	if !exists {
		return fmt.Errorf("phase not found: %s", phaseName)
	}

	// Find task by ID
	taskIndex := -1
	for i, t := range phaseState.Tasks {
		if t.Id == taskID {
			taskIndex = i
			break
		}
	}

	if taskIndex == -1 {
		return fmt.Errorf("task %s not found in phase %s", task
agent.runResumeTaskless function · go · L206-L242 (37 LOC)
cli/cmd/agent/resume.go
func runResumeTaskless(cmd *cobra.Command, proj *state.Project, agentName, prompt string, executorRegistry *agents.ExecutorRegistry, bindings *struct {
	Orchestrator *string `json:"orchestrator,omitempty"`
	Implementer  *string `json:"implementer,omitempty"`
	Architect    *string `json:"architect,omitempty"`
	Reviewer     *string `json:"reviewer,omitempty"`
	Planner      *string `json:"planner,omitempty"`
	Researcher   *string `json:"researcher,omitempty"`
	Decomposer   *string `json:"decomposer,omitempty"`
}) error {
	// Look up session ID from project's agent_sessions
	if proj.Agent_sessions == nil {
		return fmt.Errorf("no session found for agent %s (spawn first with 'sow agent spawn --agent %s')", agentName, agentName)
	}

	sessionID, exists := proj.Agent_sessions[agentName]
	if !exists || sessionID == "" {
		return fmt.Errorf("no session found for agent %s (spawn first with 'sow agent spawn --agent %s')", agentName, agentName)
	}

	// Look up executor for this agent
	executor, err
All rows above produced by Repobility · https://repobility.com
agent.newSpawnCmd function · go · L28-L82 (55 LOC)
cli/cmd/agent/spawn.go
func newSpawnCmd() *cobra.Command {
	var phase string
	var agentName string
	var customPrompt string

	cmd := &cobra.Command{
		Use:   "spawn [task-id]",
		Short: "Spawn an agent to execute work",
		Long: `Spawn an agent to execute work.

The spawn command has two modes:

TASK MODE (with task-id):
  Spawns an agent to execute a specific task. The agent is determined by the
  task's assigned_agent field unless overridden with --agent.

  sow agent spawn 010                     # Use task's assigned agent
  sow agent spawn 010 --agent reviewer    # Override with different agent
  sow agent spawn 010 --prompt "Focus on error handling"

TASKLESS MODE (with --agent only):
  Spawns an agent directly without a task. Useful for orchestrator to spawn
  planning or research agents before tasks exist.

  sow agent spawn --agent planner --prompt "Create implementation plan"
  sow agent spawn --agent researcher --prompt "Research auth libraries"

Session IDs are persisted before spawning to support
agent.runSpawn function · go · L85-L145 (61 LOC)
cli/cmd/agent/spawn.go
func runSpawn(cmd *cobra.Command, args []string, explicitPhase, agentFlag, customPrompt string) error {
	// Get sow context
	ctx := cmdutil.GetContext(cmd.Context())

	// Check if sow is initialized
	if !ctx.IsInitialized() {
		return fmt.Errorf("sow not initialized. Run 'sow init' first")
	}

	// Determine mode based on arguments
	hasTaskID := len(args) > 0
	hasAgentFlag := agentFlag != ""

	// Validation: need at least one of task-id or --agent
	if !hasTaskID && !hasAgentFlag {
		return fmt.Errorf("must provide either <task-id> or --agent flag")
	}

	// Load project state (required for both modes)
	proj, err := cmdutil.LoadProject(cmd.Context(), ctx)
	if err != nil {
		if strings.Contains(err.Error(), "no such file") {
			return fmt.Errorf("no active project found")
		}
		return fmt.Errorf("failed to load project: %w", err)
	}

	// Load user config for executor settings
	userConfig, err := config.LoadUserConfig(ctx.FS())
	if err != nil {
		return fmt.Errorf("failed to load user confi
agent.runSpawnWithTask function · go · L148-L235 (88 LOC)
cli/cmd/agent/spawn.go
func runSpawnWithTask(cmd *cobra.Command, proj *state.Project, taskID, explicitPhase, agentOverride, customPrompt string, executorRegistry *agents.ExecutorRegistry, bindings *struct {
	Orchestrator *string `json:"orchestrator,omitempty"`
	Implementer  *string `json:"implementer,omitempty"`
	Architect    *string `json:"architect,omitempty"`
	Reviewer     *string `json:"reviewer,omitempty"`
	Planner      *string `json:"planner,omitempty"`
	Researcher   *string `json:"researcher,omitempty"`
	Decomposer   *string `json:"decomposer,omitempty"`
}) error {
	// Resolve which phase to use
	phaseName, err := resolveTaskPhase(proj, explicitPhase)
	if err != nil {
		return err
	}

	// Get phase
	phaseState, exists := proj.Phases[phaseName]
	if !exists {
		return fmt.Errorf("phase not found: %s", phaseName)
	}

	// Find task by ID
	taskIndex := -1
	for i, t := range phaseState.Tasks {
		if t.Id == taskID {
			taskIndex = i
			break
		}
	}

	if taskIndex == -1 {
		return fmt.Errorf("task %s not foun
agent.runSpawnTaskless function · go · L238-L293 (56 LOC)
cli/cmd/agent/spawn.go
func runSpawnTaskless(cmd *cobra.Command, proj *state.Project, agentName, customPrompt string, executorRegistry *agents.ExecutorRegistry, bindings *struct {
	Orchestrator *string `json:"orchestrator,omitempty"`
	Implementer  *string `json:"implementer,omitempty"`
	Architect    *string `json:"architect,omitempty"`
	Reviewer     *string `json:"reviewer,omitempty"`
	Planner      *string `json:"planner,omitempty"`
	Researcher   *string `json:"researcher,omitempty"`
	Decomposer   *string `json:"decomposer,omitempty"`
}) error {
	// Look up agent by name
	agentRegistry := agents.NewAgentRegistry()
	agent, err := agentRegistry.Get(agentName)
	if err != nil {
		return buildAgentNotFoundError(agentName, "", agentRegistry)
	}

	// Look up executor for this agent
	executor, err := executorRegistry.GetAgentExecutor(agentName, bindings)
	if err != nil {
		return fmt.Errorf("failed to get executor for agent %s: %w", agentName, err)
	}

	// Initialize agent_sessions map if nil
	if proj.Agent_sessions
agent.buildAgentNotFoundError function · go · L296-L308 (13 LOC)
cli/cmd/agent/spawn.go
func buildAgentNotFoundError(agentName, taskID string, registry *agents.AgentRegistry) error {
	availableAgents := registry.List()
	names := make([]string, len(availableAgents))
	for i, a := range availableAgents {
		names[i] = a.Name
	}
	sort.Strings(names)

	if taskID != "" {
		return fmt.Errorf("task %s has unknown assigned agent: %s\nAvailable agents: %s", taskID, agentName, strings.Join(names, ", "))
	}
	return fmt.Errorf("unknown agent: %s\nAvailable agents: %s", agentName, strings.Join(names, ", "))
}
agent.buildTaskPrompt function · go · L311-L319 (9 LOC)
cli/cmd/agent/spawn.go
func buildTaskPrompt(taskID, phaseName string) string {
	return fmt.Sprintf(`Execute task %s.

Task location: .sow/project/phases/%s/tasks/%s/

Read state.yaml for task metadata, description.md for requirements,
and feedback/ for any corrections from previous iterations.
`, taskID, phaseName, taskID)
}
agent.resolveTaskPhase function · go · L329-L362 (34 LOC)
cli/cmd/agent/spawn.go
func resolveTaskPhase(project *state.Project, explicitPhase string) (string, error) {
	// Get the project type config to query task support
	config := project.Config()

	// Case 1: Explicit phase provided via --phase flag
	if explicitPhase != "" {
		// Validate that the phase supports tasks
		if !config.PhaseSupportsTasks(explicitPhase) {
			supportedPhases := config.GetTaskSupportingPhases()
			if len(supportedPhases) == 0 {
				return "", fmt.Errorf("phase %s does not support tasks (no phases support tasks in this project type)", explicitPhase)
			}
			return "", fmt.Errorf("phase %s does not support tasks (supported phases: %s)",
				explicitPhase, strings.Join(supportedPhases, ", "))
		}
		return explicitPhase, nil
	}

	// Case 2: Smart default based on current project state
	currentState := project.Statechart.Current_state
	defaultPhase := config.GetDefaultTaskPhase(currentState)

	if defaultPhase == "" {
		// No smart default found - provide helpful error
		supportedPhases := con
config.NewConfigCmd function · go · L9-L38 (30 LOC)
cli/cmd/config/config.go
func NewConfigCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "config",
		Short: "Manage user configuration",
		Long: `Manage sow user configuration for agent preferences.

Configuration is stored at ~/.config/sow/config.yaml (Linux/Mac)
or %APPDATA%\sow\config.yaml (Windows).

If no configuration exists, sow uses defaults (Claude Code for all agents).

Commands:
  init      Create configuration file with template
  path      Show configuration file path
  show      Display effective configuration (merged)
  validate  Validate configuration file
  edit      Open configuration in editor
  reset     Remove configuration file`,
	}

	// Add subcommands
	cmd.AddCommand(newInitCmd())
	cmd.AddCommand(newPathCmd())
	cmd.AddCommand(newShowCmd())
	cmd.AddCommand(newValidateCmd())
	cmd.AddCommand(newEditCmd())
	cmd.AddCommand(newResetCmd())

	return cmd
}
About: code-quality intelligence by Repobility · https://repobility.com
config.newEditCmd function · go · L13-L24 (12 LOC)
cli/cmd/config/edit.go
func newEditCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "edit",
		Short: "Open configuration in editor",
		Long: `Open the configuration file in your preferred editor.

Uses $EDITOR environment variable, falling back to 'vi' if not set.

If no configuration file exists, creates one with the default template first.`,
		RunE: runEdit,
	}
}
config.runEdit function · go · L26-L34 (9 LOC)
cli/cmd/config/edit.go
func runEdit(cmd *cobra.Command, _ []string) error {
	path, err := config.GetUserConfigPath()
	if err != nil {
		return fmt.Errorf("failed to get config path: %w", err)
	}

	editor := getEditor()
	return runEditWithPath(cmd, path, editor)
}
config.getEditor function · go · L38-L43 (6 LOC)
cli/cmd/config/edit.go
func getEditor() string {
	if editor := os.Getenv("EDITOR"); editor != "" {
		return editor
	}
	return "vi"
}
config.runEditWithPath function · go · L46-L69 (24 LOC)
cli/cmd/config/edit.go
func runEditWithPath(cmd *cobra.Command, path string, editor string) error {
	// Create file with template if it doesn't exist
	if _, err := os.Stat(path); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
			return fmt.Errorf("failed to create config directory: %w", err)
		}
		if err := os.WriteFile(path, []byte(configTemplate), 0644); err != nil {
			return fmt.Errorf("failed to create config: %w", err)
		}
		cmd.Printf("Created new configuration at %s\n", path)
	}

	// Open editor
	editCmd := exec.CommandContext(cmd.Context(), editor, path)
	editCmd.Stdin = os.Stdin
	editCmd.Stdout = os.Stdout
	editCmd.Stderr = os.Stderr

	if err := editCmd.Run(); err != nil {
		return fmt.Errorf("editor failed: %w", err)
	}

	return nil
}
config.newInitCmd function · go · L12-L26 (15 LOC)
cli/cmd/config/init.go
func newInitCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "init",
		Short: "Create configuration file with template",
		Long: `Create a configuration file with a documented template.

The configuration file includes:
- Executor definitions (Claude Code, Cursor, Windsurf)
- Agent role bindings
- All available settings with documentation

If the file already exists, use 'sow config edit' to modify it.`,
		RunE: runInit,
	}
}
config.runInit function · go · L28-L34 (7 LOC)
cli/cmd/config/init.go
func runInit(cmd *cobra.Command, _ []string) error {
	path, err := config.GetUserConfigPath()
	if err != nil {
		return fmt.Errorf("failed to get config path: %w", err)
	}
	return runInitWithPath(cmd, path)
}
config.runInitWithPath function · go · L37-L44 (8 LOC)
cli/cmd/config/init.go
func runInitWithPath(cmd *cobra.Command, path string) error {
	if err := initConfigAtPath(path); err != nil {
		return err
	}

	cmd.Printf("Created configuration at %s\n", path)
	return nil
}
config.initConfigAtPath function · go · L48-L65 (18 LOC)
cli/cmd/config/init.go
func initConfigAtPath(path string) error {
	// Check if file exists
	if _, err := os.Stat(path); err == nil {
		return fmt.Errorf("config already exists at %s\nUse 'sow config edit' to modify", path)
	}

	// Create parent directories
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return fmt.Errorf("failed to create config directory: %w", err)
	}

	// Write template
	if err := os.WriteFile(path, []byte(configTemplate), 0644); err != nil {
		return fmt.Errorf("failed to write config: %w", err)
	}

	return nil
}
Powered by Repobility — scan your code at https://repobility.com
config.newPathCmd function · go · L11-L32 (22 LOC)
cli/cmd/config/path.go
func newPathCmd() *cobra.Command {
	var existsFlag bool

	cmd := &cobra.Command{
		Use:   "path",
		Short: "Show configuration file path",
		Long: `Show the path to the user configuration file.

The path is platform-specific:
  Linux/Mac: ~/.config/sow/config.yaml
  Windows:   %APPDATA%\sow\config.yaml

Use --exists to check if the file exists (for scripting).`,
		RunE: func(cmd *cobra.Command, _ []string) error {
			return runPath(cmd, existsFlag)
		},
	}

	cmd.Flags().BoolVar(&existsFlag, "exists", false, "Check if config file exists (outputs true/false)")

	return cmd
}
config.runPath function · go · L34-L52 (19 LOC)
cli/cmd/config/path.go
func runPath(cmd *cobra.Command, checkExists bool) error {
	path, err := config.GetUserConfigPath()
	if err != nil {
		return fmt.Errorf("failed to get config path: %w", err)
	}

	if checkExists {
		_, err := os.Stat(path)
		if err == nil {
			cmd.Println("true")
		} else {
			cmd.Println("false")
		}
		return nil
	}

	cmd.Println(path)
	return nil
}
config.runPathWithOptions function · go · L55-L67 (13 LOC)
cli/cmd/config/path.go
func runPathWithOptions(cmd *cobra.Command, path string, checkExists bool) {
	if checkExists {
		_, err := os.Stat(path)
		if err == nil {
			cmd.Println("true")
		} else {
			cmd.Println("false")
		}
		return
	}

	cmd.Println(path)
}
config.newResetCmd function · go · L13-L31 (19 LOC)
cli/cmd/config/reset.go
func newResetCmd() *cobra.Command {
	var forceFlag bool

	cmd := &cobra.Command{
		Use:   "reset",
		Short: "Remove configuration file",
		Long: `Remove the configuration file and revert to defaults.

A backup is created at config.yaml.backup before removal.
Use --force to skip the confirmation prompt.`,
		RunE: func(cmd *cobra.Command, _ []string) error {
			return runReset(cmd, forceFlag)
		},
	}

	cmd.Flags().BoolVarP(&forceFlag, "force", "f", false, "Skip confirmation prompt")

	return cmd
}
config.runReset function · go · L33-L39 (7 LOC)
cli/cmd/config/reset.go
func runReset(cmd *cobra.Command, force bool) error {
	path, err := config.GetUserConfigPath()
	if err != nil {
		return fmt.Errorf("failed to get config path: %w", err)
	}
	return resetConfigAtPath(cmd, path, force)
}
config.resetConfigAtPath function · go · L42-L77 (36 LOC)
cli/cmd/config/reset.go
func resetConfigAtPath(cmd *cobra.Command, path string, force bool) error {
	// Check if file exists
	if _, err := os.Stat(path); os.IsNotExist(err) {
		cmd.Println("No configuration file to reset")
		return nil
	}

	// Confirm unless --force
	if !force {
		cmd.Printf("This will remove %s\n", path)
		cmd.Print("Continue? [y/N] ")

		reader := bufio.NewReader(cmd.InOrStdin())
		response, err := reader.ReadString('\n')
		if err != nil {
			return fmt.Errorf("failed to read response: %w", err)
		}

		response = strings.TrimSpace(strings.ToLower(response))
		if response != "y" && response != "yes" {
			cmd.Println("Cancelled")
			return nil
		}
	}

	// Create backup
	backupPath := path + ".backup"
	if err := os.Rename(path, backupPath); err != nil {
		return fmt.Errorf("failed to create backup: %w", err)
	}

	cmd.Printf("Configuration removed (backup at %s)\n", backupPath)
	cmd.Println("Using built-in defaults")

	return nil
}
config.newShowCmd function · go · L14-L26 (13 LOC)
cli/cmd/config/show.go
func newShowCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "show",
		Short: "Show effective configuration",
		Long: `Display the effective configuration after merging:
  1. Built-in defaults
  2. Config file (if exists)
  3. Environment variables (highest priority)

The output shows what configuration is actually being used.`,
		RunE: runShow,
	}
}
config.runShow function · go · L28-L34 (7 LOC)
cli/cmd/config/show.go
func runShow(cmd *cobra.Command, _ []string) error {
	path, err := config.GetUserConfigPath()
	if err != nil {
		return fmt.Errorf("failed to get config path: %w", err)
	}
	return runShowWithPath(cmd, path)
}
Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
config.runShowWithPath function · go · L37-L74 (38 LOC)
cli/cmd/config/show.go
func runShowWithPath(cmd *cobra.Command, path string) error {
	// Create a local filesystem for config loading
	fsys := billy.NewLocal()

	// Load effective config using the internal loader for path-specific loading
	cfg, err := config.LoadUserConfigFromPath(fsys, path)
	if err != nil {
		return fmt.Errorf("failed to load config: %w", err)
	}

	// Get config file status
	_, fileErr := os.Stat(path)
	fileExists := fileErr == nil

	// Print header with source info
	cmd.Println("# Effective configuration (merged from defaults + file + environment)")
	if fileExists {
		cmd.Printf("# Config file: %s (exists)\n", path)
	} else {
		cmd.Printf("# Config file: %s (not found, using defaults)\n", path)
	}

	// Check for env overrides
	envOverrides := getEnvOverrides()
	if len(envOverrides) > 0 {
		cmd.Printf("# Environment overrides: %s\n", strings.Join(envOverrides, ", "))
	}
	cmd.Println()

	// Output as YAML
	output, err := yaml.Marshal(cfg)
	if err != nil {
		return fmt.Errorf("failed to mars
config.getEnvOverrides function · go · L77-L95 (19 LOC)
cli/cmd/config/show.go
func getEnvOverrides() []string {
	envVars := []string{
		"SOW_AGENTS_ORCHESTRATOR",
		"SOW_AGENTS_IMPLEMENTER",
		"SOW_AGENTS_ARCHITECT",
		"SOW_AGENTS_REVIEWER",
		"SOW_AGENTS_PLANNER",
		"SOW_AGENTS_RESEARCHER",
		"SOW_AGENTS_DECOMPOSER",
	}

	var set []string
	for _, ev := range envVars {
		if os.Getenv(ev) != "" {
			set = append(set, ev)
		}
	}
	return set
}
config.newValidateCmd function · go · L14-L27 (14 LOC)
cli/cmd/config/validate.go
func newValidateCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "validate",
		Short: "Validate configuration file",
		Long: `Validate the configuration file for syntax and semantic errors.

Checks performed:
  - YAML syntax is valid
  - Executor types are valid (claude, cursor, windsurf)
  - Bindings reference defined executors
  - (Optional) Executor binaries are available on PATH`,
		RunE: runValidate,
	}
}
config.runValidate function · go · L29-L35 (7 LOC)
cli/cmd/config/validate.go
func runValidate(cmd *cobra.Command, _ []string) error {
	path, err := config.GetUserConfigPath()
	if err != nil {
		return fmt.Errorf("failed to get config path: %w", err)
	}
	return runValidateWithPath(cmd, path)
}
config.runValidateWithPath function · go · L38-L99 (62 LOC)
cli/cmd/config/validate.go
func runValidateWithPath(cmd *cobra.Command, path string) error {
	cmd.Printf("Validating configuration at %s...\n\n", path)

	// Check if file exists
	data, err := os.ReadFile(path)
	if os.IsNotExist(err) {
		cmd.Println("No configuration file found (using defaults)")
		cmd.Println("Run 'sow config init' to create one.")
		return nil
	}
	if err != nil {
		return fmt.Errorf("failed to read config: %w", err)
	}

	// Handle empty file or comment-only file
	if len(data) == 0 || isCommentOnly(data) {
		cmd.Println("OK YAML syntax valid")
		cmd.Println("OK Schema valid")
		cmd.Println("OK Executor types valid")
		cmd.Println("OK Bindings reference defined executors")
		cmd.Println("\nConfiguration is valid.")
		return nil
	}

	// Validate YAML syntax
	var raw interface{}
	if err := yaml.Unmarshal(data, &raw); err != nil {
		cmd.Printf("X YAML syntax error: %v\n", err)
		return fmt.Errorf("validation failed")
	}
	cmd.Println("OK YAML syntax valid")

	// Parse into config struct
	var cfg sche
config.isCommentOnly function · go · L102-L113 (12 LOC)
cli/cmd/config/validate.go
func isCommentOnly(data []byte) bool {
	for _, line := range splitLines(data) {
		trimmed := trimSpace(line)
		if len(trimmed) == 0 {
			continue
		}
		if trimmed[0] != '#' {
			return false
		}
	}
	return true
}
config.splitLines function · go · L116-L129 (14 LOC)
cli/cmd/config/validate.go
func splitLines(data []byte) [][]byte {
	var lines [][]byte
	start := 0
	for i, b := range data {
		if b == '\n' {
			lines = append(lines, data[start:i])
			start = i + 1
		}
	}
	if start < len(data) {
		lines = append(lines, data[start:])
	}
	return lines
}
config.trimSpace function · go · L132-L142 (11 LOC)
cli/cmd/config/validate.go
func trimSpace(data []byte) []byte {
	start := 0
	end := len(data)
	for start < end && isSpace(data[start]) {
		start++
	}
	for end > start && isSpace(data[end-1]) {
		end--
	}
	return data[start:end]
}
All rows above produced by Repobility · https://repobility.com
config.checkExecutorBinariesFromConfig function · go · L151-L181 (31 LOC)
cli/cmd/config/validate.go
func checkExecutorBinariesFromConfig(config *schemas.UserConfig) []string {
	if config == nil || config.Agents == nil {
		return nil
	}

	var warnings []string

	// Map executor types to their binary names
	binaries := map[string]string{
		"claude":   "claude",
		"cursor":   "cursor",
		"windsurf": "windsurf",
	}

	for name, executor := range config.Agents.Executors {
		binary, ok := binaries[executor.Type]
		if !ok {
			continue
		}

		// Check if binary is on PATH
		if _, err := exec.LookPath(binary); err != nil {
			warnings = append(warnings, fmt.Sprintf(
				"%s executor '%s' requires '%s' binary, but it was not found on PATH",
				executor.Type, name, binary,
			))
		}
	}

	return warnings
}
cmd.resolveTaskPhase function · go · L17-L50 (34 LOC)
cli/cmd/helpers.go
func resolveTaskPhase(project *state.Project, explicitPhase string) (string, error) {
	// Get the project type config to query task support
	config := project.Config()

	// Case 1: Explicit phase provided via --phase flag
	if explicitPhase != "" {
		// Validate that the phase supports tasks
		if !config.PhaseSupportsTasks(explicitPhase) {
			supportedPhases := config.GetTaskSupportingPhases()
			if len(supportedPhases) == 0 {
				return "", fmt.Errorf("phase %s does not support tasks (no phases support tasks in this project type)", explicitPhase)
			}
			return "", fmt.Errorf("phase %s does not support tasks (supported phases: %s)",
				explicitPhase, strings.Join(supportedPhases, ", "))
		}
		return explicitPhase, nil
	}

	// Case 2: Smart default based on current project state
	currentState := project.Statechart.Current_state
	defaultPhase := config.GetDefaultTaskPhase(currentState)

	if defaultPhase == "" {
		// No smart default found - provide helpful error
		supportedPhases := con
cmd.NewInitCmd function · go · L12-L38 (27 LOC)
cli/cmd/init.go
func NewInitCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "init",
		Short: "Initialize sow structure",
		Long: `Initialize the .sow/ directory structure in the current repository.

Creates:
  .sow/knowledge/     - Repository-specific documentation (committed)
  .sow/refs/          - External knowledge and code references (symlinks)
  .sow/.version       - sow structure version file

This command must be run from a git repository root.`,
		RunE: func(cmd *cobra.Command, _ []string) error {
			ctx := cmdutil.GetContext(cmd.Context())

			// Initialize .sow structure
			if err := sow.Init(ctx.RepoRoot()); err != nil {
				return fmt.Errorf("initialization failed: %w", err)
			}

			cmd.Println("✓ sow initialized successfully")
			return nil
		},
	}

	return cmd
}
page 1 / 12next ›