feat(v0.5): add launch_dir field to TaskMeta

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-22 19:44:36 -04:00
parent ba8b3a19f9
commit 175fbb0075
2 changed files with 57 additions and 1 deletions
+4 -1
View File
@@ -12,7 +12,9 @@ import (
// TaskMeta represents the task.yaml schema.
// The Type field is v0.3+; older workspaces without this field are treated as "task"
// (see EffectiveType). Field order in this struct is the YAML output order.
// (see EffectiveType). LaunchDir is v0.5+; empty for tasks and pre-v0.5 projects,
// defaults to the project slug for new projects. Field order in this struct is
// the YAML output order.
type TaskMeta struct {
ID string `yaml:"id"`
Slug string `yaml:"slug"`
@@ -26,6 +28,7 @@ type TaskMeta struct {
Agent string `yaml:"agent"`
WorkspacePath string `yaml:"workspace_path"`
ArchivedAt *time.Time `yaml:"archived_at"`
LaunchDir string `yaml:"launch_dir,omitempty"`
}
// EffectiveType returns "task" or "project". An empty or missing Type field
+53
View File
@@ -255,3 +255,56 @@ func TestMetaArchive(t *testing.T) {
t.Errorf("ArchivedAt: got %v, want %v", got.ArchivedAt, archiveTime)
}
}
func TestMetaLaunchDirRoundTrip(t *testing.T) {
tmp := t.TempDir()
path := filepath.Join(tmp, "task.yaml")
meta := &TaskMeta{
ID: "test",
Slug: "demo",
Title: "demo",
CreatedAt: time.Now().UTC().Truncate(time.Second),
UpdatedAt: time.Now().UTC().Truncate(time.Second),
Status: "active",
Category: "projects",
Type: "project",
Mode: "local",
Agent: "claude",
LaunchDir: "demo",
}
if err := WriteMeta(path, meta); err != nil {
t.Fatalf("WriteMeta: %v", err)
}
got, err := ReadMeta(path)
if err != nil {
t.Fatalf("ReadMeta: %v", err)
}
if got.LaunchDir != "demo" {
t.Errorf("LaunchDir round-trip: got %q, want %q", got.LaunchDir, "demo")
}
}
func TestMetaLaunchDirOmittedWhenEmpty(t *testing.T) {
// Backward compat: a task workspace with no LaunchDir must not serialize
// a launch_dir key (keeps on-disk task.yaml clean for pre-v0.5 shape).
tmp := t.TempDir()
path := filepath.Join(tmp, "task.yaml")
meta := &TaskMeta{
ID: "t", Slug: "t", Title: "t",
CreatedAt: time.Now().UTC().Truncate(time.Second),
UpdatedAt: time.Now().UTC().Truncate(time.Second),
Status: "active", Category: "general", Type: "task",
Mode: "local", Agent: "claude",
}
if err := WriteMeta(path, meta); err != nil {
t.Fatalf("WriteMeta: %v", err)
}
body, err := os.ReadFile(path)
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
if strings.Contains(string(body), "launch_dir") {
t.Errorf("empty LaunchDir must not serialize launch_dir key; got:\n%s", body)
}
}