Wire Marvin tasks adapter into the daemon
main constructs the Marvin adapter (command overridable via ANTIDRIFT_MARVIN_CMD) and injects it. Adds a web test asserting the planning state payload carries today's tasks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
"antidrift/internal/session"
|
||||
"antidrift/internal/statusfile"
|
||||
"antidrift/internal/store"
|
||||
"antidrift/internal/tasks"
|
||||
"antidrift/internal/web"
|
||||
)
|
||||
|
||||
@@ -46,6 +47,13 @@ func main() {
|
||||
log.Printf("ai: %s backend (coach + drift judge + nudge)", backend.Name())
|
||||
}
|
||||
|
||||
// Wire the Tasks port: Amazing Marvin via ampy's `am` CLI. The command is
|
||||
// overridable with ANTIDRIFT_MARVIN_CMD (e.g. "uv run am" or an absolute
|
||||
// path). A missing or failing CLI degrades to no tasks panel at fetch time —
|
||||
// planning still works.
|
||||
ctrl.SetTasks(tasks.NewMarvin(os.Getenv("ANTIDRIFT_MARVIN_CMD")))
|
||||
log.Printf("tasks: marvin adapter (am)")
|
||||
|
||||
// Mirror runtime status to ~/.antidrift_status for a window-manager bar.
|
||||
// A misconfigured home dir degrades to no status file, not a failed start.
|
||||
if statusPath, err := statusfile.DefaultPath(); err != nil {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"antidrift/internal/domain"
|
||||
"antidrift/internal/evidence"
|
||||
"antidrift/internal/session"
|
||||
"antidrift/internal/tasks"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -230,6 +231,37 @@ func TestServesStaticAssets(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type stubProvider struct {
|
||||
list []tasks.Task
|
||||
}
|
||||
|
||||
func (s stubProvider) Today(ctx context.Context) ([]tasks.Task, error) {
|
||||
return s.list, nil
|
||||
}
|
||||
|
||||
func TestPlanningStatePayloadCarriesTasks(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
s.ctrl.SetTasks(stubProvider{list: []tasks.Task{{ID: "a", Title: "Write the spec", Day: "2026-05-31"}}})
|
||||
r := s.Router()
|
||||
if w := post(t, r, "/planning", ""); w.Code != http.StatusOK {
|
||||
t.Fatalf("/planning code %d", w.Code)
|
||||
}
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if tv := s.ctrl.State().Tasks; tv != nil && tv.Status == "ready" {
|
||||
break
|
||||
}
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
js := s.stateJSON()
|
||||
if !strings.Contains(js, `"tasks"`) {
|
||||
t.Fatalf("planning payload missing tasks object: %s", js)
|
||||
}
|
||||
if !strings.Contains(js, `"title":"Write the spec"`) {
|
||||
t.Fatalf("planning payload missing task title: %s", js)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitmentCarriesAllowedClassesAndRoutesWork(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
r := s.Router()
|
||||
|
||||
Reference in New Issue
Block a user