fix: spawn and swarm bug fixes from MVP testing

- spawn.go: Parse bd show --json as array, fix issue_type json tag
- session/manager.go: Check filesystem directly in hasPolecat()
  to handle newly-created polecats
- swarm/manager.go: Use bd show to get children via dependents field
  instead of non-existent bd list --parent flag

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-16 22:07:13 -08:00
parent 59921d52c8
commit e1c041f3b0
3 changed files with 41 additions and 20 deletions

View File

@@ -60,7 +60,7 @@ type BeadsIssue struct {
Title string `json:"title"`
Description string `json:"description"`
Priority int `json:"priority"`
Type string `json:"type"`
Type string `json:"issue_type"`
Status string `json:"status"`
}
@@ -256,12 +256,16 @@ func fetchBeadsIssue(rigPath, issueID string) (*BeadsIssue, error) {
return nil, err
}
var issue BeadsIssue
if err := json.Unmarshal(stdout.Bytes(), &issue); err != nil {
// bd show --json returns an array, take the first element
var issues []BeadsIssue
if err := json.Unmarshal(stdout.Bytes(), &issues); err != nil {
return nil, fmt.Errorf("parsing issue: %w", err)
}
if len(issues) == 0 {
return nil, fmt.Errorf("issue not found: %s", issueID)
}
return &issue, nil
return &issues[0], nil
}
// buildSpawnContext creates the initial context message for the polecat.

View File

@@ -4,6 +4,7 @@ package session
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"
@@ -72,12 +73,13 @@ func (m *Manager) polecatDir(polecat string) string {
// hasPolecat checks if the polecat exists in this rig.
func (m *Manager) hasPolecat(polecat string) bool {
for _, p := range m.rig.Polecats {
if p == polecat {
return true
}
// Check filesystem directly to handle newly-created polecats
polecatPath := m.polecatDir(polecat)
info, err := os.Stat(polecatPath)
if err != nil {
return false
}
return false
return info.IsDir()
}
// Start creates and starts a new session for a polecat.

View File

@@ -278,8 +278,8 @@ func isValidTransition(from, to SwarmState) bool {
// loadTasksFromBeads loads child issues from beads CLI.
func (m *Manager) loadTasksFromBeads(epicID string) ([]SwarmTask, error) {
// Run: bd list --parent <epicID> --json
cmd := exec.Command("bd", "list", "--parent", epicID, "--json")
// Run: bd show <epicID> --json to get epic with children
cmd := exec.Command("bd", "show", epicID, "--json")
cmd.Dir = m.workDir
var stdout, stderr bytes.Buffer
@@ -287,24 +287,39 @@ func (m *Manager) loadTasksFromBeads(epicID string) ([]SwarmTask, error) {
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("bd list: %s", strings.TrimSpace(stderr.String()))
return nil, fmt.Errorf("bd show: %s", strings.TrimSpace(stderr.String()))
}
// Parse JSON output
// Parse JSON output - bd show returns an array
var issues []struct {
ID string `json:"id"`
Title string `json:"title"`
Status string `json:"status"`
ID string `json:"id"`
Title string `json:"title"`
Status string `json:"status"`
Dependents []struct {
ID string `json:"id"`
Title string `json:"title"`
Status string `json:"status"`
DependencyType string `json:"dependency_type"`
} `json:"dependents"`
}
if err := json.Unmarshal(stdout.Bytes(), &issues); err != nil {
return nil, fmt.Errorf("parsing bd output: %w", err)
}
if len(issues) == 0 {
return nil, fmt.Errorf("epic not found: %s", epicID)
}
// Extract parent-child dependents as tasks
var tasks []SwarmTask
for _, issue := range issues {
for _, dep := range issues[0].Dependents {
if dep.DependencyType != "parent-child" {
continue
}
state := TaskPending
switch issue.Status {
switch dep.Status {
case "in_progress":
state = TaskInProgress
case "closed":
@@ -312,8 +327,8 @@ func (m *Manager) loadTasksFromBeads(epicID string) ([]SwarmTask, error) {
}
tasks = append(tasks, SwarmTask{
IssueID: issue.ID,
Title: issue.Title,
IssueID: dep.ID,
Title: dep.Title,
State: state,
})
}