Files
goclaw/internal/bootstrap/seed.go
T
Viet Tran 6895e369f6 refactor: remove standalone mode, consolidate to managed-only (PostgreSQL) (#70)
- Remove standalone mode code: file-based stores, standalone gateway,
  heartbeat service, SQLite memory, standalone docker-compose
- Rename docker-compose.managed.yml → docker-compose.postgres.yml
- Clean up ~130 Go comments referencing "managed mode" qualifier
- Simplify docker-compose.yml env vars (providers/channels via web UI)
- Update .env.example to essential vars only (token + encryption key)
- Add setup wizard UI (provider → agent → channel bootstrap flow)
- Add logs.tail WebSocket handler for live log streaming
- Add cursor-pointer to interactive UI components
- Clean up config page (remove standalone-only sections)
- Update README and docs for managed-only architecture
2026-03-06 18:51:11 +07:00

100 lines
2.5 KiB
Go

package bootstrap
import (
"embed"
"log/slog"
"os"
"path/filepath"
)
//go:embed templates/*.md
var templateFS embed.FS
// templateFiles lists the templates to seed, in order.
// BOOTSTRAP.md is handled separately (only seeded for brand-new workspaces).
var templateFiles = []string{
AgentsFile,
SoulFile,
ToolsFile,
IdentityFile,
UserFile,
}
// ReadTemplate returns the content of an embedded template file.
func ReadTemplate(name string) (string, error) {
content, err := templateFS.ReadFile(filepath.Join("templates", name))
if err != nil {
return "", err
}
return string(content), nil
}
// EnsureWorkspaceFiles seeds template files into a workspace directory.
// Only writes files that don't already exist (will not overwrite).
// BOOTSTRAP.md is only seeded if the workspace is brand new (no AGENTS.md exists).
// Returns the list of files that were created.
func EnsureWorkspaceFiles(workspaceDir string) ([]string, error) {
if err := os.MkdirAll(workspaceDir, 0755); err != nil {
return nil, err
}
var created []string
// Check if this is a brand-new workspace (no AGENTS.md yet)
_, agentsErr := os.Stat(filepath.Join(workspaceDir, AgentsFile))
isBrandNew := os.IsNotExist(agentsErr)
// Seed standard template files
for _, name := range templateFiles {
ok, err := seedTemplate(workspaceDir, name)
if err != nil {
slog.Warn("bootstrap: failed to seed template", "file", name, "error", err)
continue
}
if ok {
created = append(created, name)
}
}
// Seed BOOTSTRAP.md only for brand-new workspaces
if isBrandNew {
ok, err := seedTemplate(workspaceDir, BootstrapFile)
if err != nil {
slog.Warn("bootstrap: failed to seed BOOTSTRAP.md", "error", err)
} else if ok {
created = append(created, BootstrapFile)
}
}
return created, nil
}
// seedTemplate writes a template file to the workspace if it doesn't exist.
// Returns true if the file was created, false if it already exists.
func seedTemplate(workspaceDir, name string) (bool, error) {
dstPath := filepath.Join(workspaceDir, name)
// Only create if file doesn't exist (O_EXCL)
f, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
if err != nil {
if os.IsExist(err) {
return false, nil // already exists, skip
}
return false, err
}
defer f.Close()
// Read embedded template
content, err := templateFS.ReadFile(filepath.Join("templates", name))
if err != nil {
os.Remove(dstPath) // clean up empty file
return false, err
}
if _, err := f.Write(content); err != nil {
return false, err
}
return true, nil
}