fix(lifecycle): propagate RepositoryName through PublishGitStatus
The agentctl WorkspaceTracker stamps every per-repo GitStatusUpdate with RepositoryName, but the lifecycle PublishGitStatus translation into GitEventPayload was dropping that field. The orchestrator then forwarded a status with empty repository_name, the frontend store routed everything into the empty-key bucket, and the Changes panel's multi-repo grouping never triggered — no header, no per-repo split. - GitStatusData gains RepositoryName (omitempty so single-repo payloads stay byte-identical on the wire). - PublishGitStatus copies update.RepositoryName onto the payload. - Test asserts the field survives the publish → subscribe round trip via the in-memory event bus on the GitEvent.<sessionID> subject. Restart the agentctl process for any running multi-repo task to pick up the new field; new launches get it automatically. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -225,6 +225,10 @@ type GitStatusData struct {
|
||||
Files interface{} `json:"files,omitempty"`
|
||||
BranchAdditions int `json:"branch_additions,omitempty"`
|
||||
BranchDeletions int `json:"branch_deletions,omitempty"`
|
||||
// RepositoryName identifies which repository this status belongs to in
|
||||
// multi-repo task workspaces. Empty for single-repo. Carried through to
|
||||
// the frontend so the Changes panel can render per-repo group headers.
|
||||
RepositoryName string `json:"repository_name,omitempty"`
|
||||
}
|
||||
|
||||
type GitCommitData struct {
|
||||
|
||||
@@ -247,6 +247,7 @@ func (p *EventPublisher) PublishGitStatus(execution *AgentExecution, update *age
|
||||
Files: update.Files,
|
||||
BranchAdditions: update.BranchAdditions,
|
||||
BranchDeletions: update.BranchDeletions,
|
||||
RepositoryName: update.RepositoryName,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package lifecycle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
agentctl "github.com/kandev/kandev/internal/agentctl/client"
|
||||
"github.com/kandev/kandev/internal/common/logger"
|
||||
"github.com/kandev/kandev/internal/events"
|
||||
"github.com/kandev/kandev/internal/events/bus"
|
||||
)
|
||||
|
||||
// Verifies the fix for "Changes panel shows no header / no existing changes".
|
||||
// agentctl tags every per-repo GitStatusUpdate with RepositoryName; that field
|
||||
// must survive the lifecycle PublishGitStatus translation so the orchestrator
|
||||
// (and thus the frontend) sees it.
|
||||
func TestPublishGitStatus_PropagatesRepositoryName(t *testing.T) {
|
||||
log, _ := logger.NewLogger(logger.LoggingConfig{Level: "error", Format: "json"})
|
||||
eventBus := bus.NewMemoryEventBus(log)
|
||||
pub := NewEventPublisher(eventBus, log)
|
||||
|
||||
received := make(chan *bus.Event, 1)
|
||||
subj := events.BuildGitEventSubject("sess-multi")
|
||||
sub, err := eventBus.Subscribe(subj, func(_ context.Context, ev *bus.Event) error {
|
||||
received <- ev
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("subscribe: %v", err)
|
||||
}
|
||||
defer func() { _ = sub.Unsubscribe() }()
|
||||
|
||||
exec := &AgentExecution{
|
||||
ID: "exec-1",
|
||||
TaskID: "task-1",
|
||||
SessionID: "sess-multi",
|
||||
}
|
||||
pub.PublishGitStatus(exec, &agentctl.GitStatusUpdate{
|
||||
Timestamp: time.Now(),
|
||||
RepositoryName: "frontend",
|
||||
Branch: "feature/x",
|
||||
Modified: []string{"src/app.tsx"},
|
||||
Files: map[string]agentctl.FileInfo{"src/app.tsx": {Path: "src/app.tsx"}},
|
||||
})
|
||||
|
||||
select {
|
||||
case ev := <-received:
|
||||
payload, ok := ev.Data.(*GitEventPayload)
|
||||
if !ok || payload == nil {
|
||||
t.Fatalf("expected *GitEventPayload, got %T", ev.Data)
|
||||
}
|
||||
if payload.Status == nil {
|
||||
t.Fatal("expected non-nil Status on payload")
|
||||
}
|
||||
if payload.Status.RepositoryName != "frontend" {
|
||||
t.Errorf("repository_name was dropped: got %q", payload.Status.RepositoryName)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("timed out waiting for git status event")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user