Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
17b25f6
Initial plan
Copilot Feb 14, 2026
0729bac
Add CCA session support: models, bridge protocol, service layer, side…
Copilot Feb 14, 2026
bc9755a
Add delegate-to-CCA support: /delegate command, Mode parameter on Sen…
Copilot Feb 14, 2026
5a139d0
Add error handling for /delegate command failures
Copilot Feb 14, 2026
e964268
Add user-visible error feedback when /delegate fails
PureWeen Feb 15, 2026
7d29dd6
Always show CCA Sessions section header, load on expand
PureWeen Feb 15, 2026
b76f95f
Add CCA runs per repo group, remove standalone CCA section
PureWeen Feb 15, 2026
4adf76b
Filter CCA runs to only show coding agent sessions, not comment-respo…
Copilot Feb 15, 2026
1912fe7
Enrich CCA runs with PR info, add action links, fix duplicate branch …
PureWeen Feb 15, 2026
764d614
Initial plan
Copilot Feb 15, 2026
388397d
Add plan block display in chat area during plan mode
Copilot Feb 15, 2026
d43e331
Add CCA session loading: fetch logs, parse conversation, create local…
PureWeen Feb 15, 2026
2547f79
Remove PR/Logs links from CCA runs — Load button replaces them
PureWeen Feb 15, 2026
3dcf286
Prevent duplicate CCA loads — show 'Open →' for already-loaded runs
PureWeen Feb 15, 2026
d13523f
Persist CCA metadata across app restarts
PureWeen Feb 15, 2026
4d07be4
Merge remote-tracking branch 'origin/copilot/add-plan-mode-preview-op…
PureWeen Feb 15, 2026
f1aee1d
Fix CCA session matching to survive restarts — fallback to name-based…
PureWeen Feb 15, 2026
d68ea5c
Fix 6 issues from multi-model code review
PureWeen Feb 15, 2026
dff8df7
Security hardening: input validation and prompt injection defense
PureWeen Feb 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions PolyPilot.Tests/BridgeMessageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ public void ClientToServer_TypeConstants_AreCorrect()
Assert.Equal("get_sessions", BridgeMessageTypes.GetSessions);
Assert.Equal("get_history", BridgeMessageTypes.GetHistory);
Assert.Equal("get_persisted_sessions", BridgeMessageTypes.GetPersistedSessions);
Assert.Equal("get_cca_sessions", BridgeMessageTypes.GetCcaSessions);
Assert.Equal("send_message", BridgeMessageTypes.SendMessage);
Assert.Equal("create_session", BridgeMessageTypes.CreateSession);
Assert.Equal("resume_session", BridgeMessageTypes.ResumeSession);
Expand All @@ -152,6 +153,12 @@ public void ClientToServer_TypeConstants_AreCorrect()
Assert.Equal("list_directories", BridgeMessageTypes.ListDirectories);
}

[Fact]
public void CcaSessionsList_TypeConstant_IsCorrect()
{
Assert.Equal("cca_sessions", BridgeMessageTypes.CcaSessionsList);
}

[Fact]
public void DirectoriesList_TypeConstant_IsCorrect()
{
Expand Down Expand Up @@ -310,6 +317,40 @@ public void QueueMessagePayload_RoundTrip()
Assert.Equal("do something", restored!.Message);
}

[Fact]
public void SendMessagePayload_WithDelegateMode_RoundTrip()
{
var payload = new SendMessagePayload
{
SessionName = "s1",
Message = "fix the login bug",
Mode = "delegate"
};
var msg = BridgeMessage.Create(BridgeMessageTypes.SendMessage, payload);
var json = msg.Serialize();
var restored = BridgeMessage.Deserialize(json)!.GetPayload<SendMessagePayload>();

Assert.Equal("s1", restored!.SessionName);
Assert.Equal("fix the login bug", restored.Message);
Assert.Equal("delegate", restored.Mode);
}

[Fact]
public void SendMessagePayload_WithoutMode_RoundTrip()
{
var payload = new SendMessagePayload
{
SessionName = "s1",
Message = "hello"
};
var msg = BridgeMessage.Create(BridgeMessageTypes.SendMessage, payload);
var restored = BridgeMessage.Deserialize(msg.Serialize())!.GetPayload<SendMessagePayload>();

Assert.Equal("s1", restored!.SessionName);
Assert.Equal("hello", restored.Message);
Assert.Null(restored.Mode);
}

[Fact]
public void PersistedSessionsPayload_RoundTrip()
{
Expand Down Expand Up @@ -436,4 +477,86 @@ public void AttentionNeededPayload_AllReasons_RoundTrip(AttentionReason reason)

Assert.Equal(reason, restored!.Reason);
}

[Fact]
public void CcaSessionsPayload_RoundTrip()
{
var payload = new CcaSessionsPayload
{
Sessions = new List<CcaSessionSummary>
{
new()
{
SessionId = "cca-guid-1",
Summary = "Fix login bug",
StartTime = new DateTime(2025, 6, 15, 10, 0, 0, DateTimeKind.Utc),
ModifiedTime = new DateTime(2025, 6, 15, 11, 0, 0, DateTimeKind.Utc),
Repository = "owner/repo",
Branch = "copilot/fix-123",
WorkingDirectory = "/home/runner/work/repo"
},
new()
{
SessionId = "cca-guid-2",
Summary = "Add tests for API",
StartTime = new DateTime(2025, 6, 15, 12, 0, 0, DateTimeKind.Utc),
ModifiedTime = new DateTime(2025, 6, 15, 13, 0, 0, DateTimeKind.Utc),
Repository = "owner/other-repo",
Branch = "copilot/add-tests",
}
}
};
var msg = BridgeMessage.Create(BridgeMessageTypes.CcaSessionsList, payload);
var json = msg.Serialize();
var restored = BridgeMessage.Deserialize(json)!.GetPayload<CcaSessionsPayload>();

Assert.NotNull(restored);
Assert.Equal(2, restored!.Sessions.Count);
Assert.Equal("cca-guid-1", restored.Sessions[0].SessionId);
Assert.Equal("Fix login bug", restored.Sessions[0].Summary);
Assert.Equal("owner/repo", restored.Sessions[0].Repository);
Assert.Equal("copilot/fix-123", restored.Sessions[0].Branch);
Assert.Equal("/home/runner/work/repo", restored.Sessions[0].WorkingDirectory);
Assert.Equal("cca-guid-2", restored.Sessions[1].SessionId);
Assert.Equal("Add tests for API", restored.Sessions[1].Summary);
Assert.Null(restored.Sessions[1].WorkingDirectory);
}

[Fact]
public void CcaSessionSummary_NullOptionalFields_RoundTrip()
{
var payload = new CcaSessionsPayload
{
Sessions = new List<CcaSessionSummary>
{
new()
{
SessionId = "cca-minimal",
StartTime = DateTime.UtcNow,
ModifiedTime = DateTime.UtcNow
}
}
};
var msg = BridgeMessage.Create(BridgeMessageTypes.CcaSessionsList, payload);
var json = msg.Serialize();
var restored = BridgeMessage.Deserialize(json)!.GetPayload<CcaSessionsPayload>();

Assert.Single(restored!.Sessions);
Assert.Equal("cca-minimal", restored.Sessions[0].SessionId);
Assert.Null(restored.Sessions[0].Summary);
Assert.Null(restored.Sessions[0].Repository);
Assert.Null(restored.Sessions[0].Branch);
Assert.Null(restored.Sessions[0].WorkingDirectory);
}

[Fact]
public void CcaSessionsPayload_EmptyList_RoundTrip()
{
var payload = new CcaSessionsPayload { Sessions = new List<CcaSessionSummary>() };
var msg = BridgeMessage.Create(BridgeMessageTypes.CcaSessionsList, payload);
var restored = BridgeMessage.Deserialize(msg.Serialize())!.GetPayload<CcaSessionsPayload>();

Assert.NotNull(restored);
Assert.Empty(restored!.Sessions);
}
}
Loading