Merge pull request #86 from vessenes/fix/install-copy-formulas

fix(install): Copy embedded formulas to new installations
This commit is contained in:
Steve Yegge
2026-01-03 21:27:25 -08:00
committed by GitHub
5 changed files with 133 additions and 2 deletions

View File

@@ -13,6 +13,7 @@ import (
"github.com/steveyegge/gastown/internal/beads"
"github.com/steveyegge/gastown/internal/config"
"github.com/steveyegge/gastown/internal/deps"
"github.com/steveyegge/gastown/internal/formula"
"github.com/steveyegge/gastown/internal/session"
"github.com/steveyegge/gastown/internal/style"
"github.com/steveyegge/gastown/internal/templates"
@@ -196,6 +197,14 @@ func runInstall(cmd *cobra.Command, args []string) error {
fmt.Printf(" %s Could not initialize town beads: %v\n", style.Dim.Render("⚠"), err)
} else {
fmt.Printf(" ✓ Initialized .beads/ (town-level beads with hq- prefix)\n")
// Provision embedded formulas to .beads/formulas/
if count, err := formula.ProvisionFormulas(absPath); err != nil {
// Non-fatal: formulas are optional, just convenience
fmt.Printf(" %s Could not provision formulas: %v\n", style.Dim.Render("⚠"), err)
} else if count > 0 {
fmt.Printf(" ✓ Provisioned %d formulas\n", count)
}
}
// Create town-level agent beads (Mayor, Deacon) and role beads.

View File

@@ -163,6 +163,60 @@ func TestInstallIdempotent(t *testing.T) {
}
}
// TestInstallFormulasProvisioned validates that embedded formulas are copied
// to .beads/formulas/ during installation.
func TestInstallFormulasProvisioned(t *testing.T) {
// Skip if bd is not available
if _, err := exec.LookPath("bd"); err != nil {
t.Skip("bd not installed, skipping formulas test")
}
tmpDir := t.TempDir()
hqPath := filepath.Join(tmpDir, "test-hq")
gtBinary := buildGT(t)
// Run gt install (includes beads and formula provisioning)
cmd := exec.Command(gtBinary, "install", hqPath)
cmd.Env = append(os.Environ(), "HOME="+tmpDir)
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("gt install failed: %v\nOutput: %s", err, output)
}
// Verify .beads/formulas/ directory exists
formulasDir := filepath.Join(hqPath, ".beads", "formulas")
assertDirExists(t, formulasDir, ".beads/formulas/")
// Verify at least some expected formulas exist
expectedFormulas := []string{
"mol-deacon-patrol.formula.toml",
"mol-refinery-patrol.formula.toml",
"code-review.formula.toml",
}
for _, f := range expectedFormulas {
formulaPath := filepath.Join(formulasDir, f)
assertFileExists(t, formulaPath, f)
}
// Verify the count matches embedded formulas
entries, err := os.ReadDir(formulasDir)
if err != nil {
t.Fatalf("failed to read formulas dir: %v", err)
}
// Count only formula files (not directories)
var fileCount int
for _, e := range entries {
if !e.IsDir() {
fileCount++
}
}
// Should have at least 20 formulas (allows for some variation)
if fileCount < 20 {
t.Errorf("expected at least 20 formulas, got %d", fileCount)
}
}
// TestInstallNoBeadsFlag validates that --no-beads skips beads initialization.
func TestInstallNoBeadsFlag(t *testing.T) {
tmpDir := t.TempDir()