Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
14582ca
Initial plan
Copilot Feb 13, 2026
6bf7777
Add ReflectionCycle mechanism for iterative goal-driven prompt refine…
Copilot Feb 13, 2026
a8d55db
Address code review: extract completion marker constant, consolidate …
Copilot Feb 13, 2026
63f730b
Harden Ralph's Loop: structured sentinel, stall detection, improved p…
PureWeen Feb 16, 2026
e5adc76
Add reflection cycle UI: /reflect command, status pill, completion me…
PureWeen Feb 16, 2026
4c37f9c
Improve reflection cycle UX: compact messages, user steering, stall w…
PureWeen Feb 16, 2026
04ebb65
Enhance reflection cycle: observability, discoverability, and user co…
PureWeen Feb 16, 2026
08b697f
Fix reflection cycle: auto-send goal prompt and defer evaluation when…
PureWeen Feb 17, 2026
4a8a15b
Fix queue dispatch: send immediately without Task.Run delay
PureWeen Feb 17, 2026
accda00
Fix review issues: thread safety, stop purge, JS escaping, resume, st…
PureWeen Feb 17, 2026
1d10153
Fix CliPath tests on Windows: use platform-aware binary name
PureWeen Feb 17, 2026
61ec65c
Add independent evaluator session for reflection cycles
PureWeen Feb 17, 2026
c0cc82f
Fix evaluator follow-up dispatch when session is idle
PureWeen Feb 17, 2026
6e7611d
Hide evaluator session from sidebar, org, and persistence
PureWeen Feb 17, 2026
3c848c6
Make evaluator stricter in early iterations, lenient on final
PureWeen Feb 17, 2026
a06d256
Add debug logging for evaluator path diagnosis
PureWeen Feb 17, 2026
0d91568
Force evaluator to FAIL early iterations unless truly exceptional
PureWeen Feb 17, 2026
5876189
Fix 5 code review issues from multi-model review
PureWeen Feb 17, 2026
83aef2e
Remove accidental screenshot from PR
PureWeen Feb 17, 2026
f3ac920
Prevent screenshot/image commits: gitignore + instructions
PureWeen Feb 17, 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
2 changes: 2 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ When switching between Embedded and Persistent modes (via Settings → Save & Re

### Git Workflow
- **NEVER use `git push --force`** — always use `git push --force-with-lease` instead when a force push is needed (e.g., after a rebase). This prevents overwriting remote changes made by others.
- **NEVER commit screenshots, images, or binary files** — use `git diff --stat` or `git status` before committing to verify no `.png`, `.jpg`, `.bmp`, or other image files are staged. Screenshots from PolyPilot (e.g., `screenshot_*.png`) are generated locally and must NEVER be committed. The `.gitignore` blocks common patterns, but always double-check.
- **NEVER use `git add -A` or `git add .` blindly** — always review what's being staged first with `git status`. Prefer `git add <specific-files>` when possible to avoid accidentally committing generated files.
- When contributing to an existing PR, prefer adding commits on top. Rebase only when explicitly asked.
- Use `git add -f` when adding files matched by `.gitignore` patterns (e.g., `*.app/` catches `PolyPilot/`).

Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ launchSettings.json

## .NET
*.binlog

## Screenshots & images (never commit these)
screenshot_*.png
*.screenshot.png
*.bmp
*.tiff
11 changes: 11 additions & 0 deletions PolyPilot.Tests/ChatMessageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ public void SystemMessage_SetsSystemRole()
Assert.False(msg.IsAssistant);
}

[Fact]
public void ReflectionMessage_SetsReflectionType()
{
var msg = ChatMessage.ReflectionMessage("🔄 Iteration 2/5");

Assert.Equal("system", msg.Role);
Assert.Equal(ChatMessageType.Reflection, msg.MessageType);
Assert.Equal("🔄 Iteration 2/5", msg.Content);
Assert.True(msg.IsComplete);
}

[Fact]
public void Constructor_UserRole_OverridesMessageType()
{
Expand Down
26 changes: 14 additions & 12 deletions PolyPilot.Tests/CliPathResolutionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace PolyPilot.Tests;
/// </summary>
public class CliPathResolutionTests
{
private static string CopilotBinaryName =>
OperatingSystem.IsWindows() ? "copilot.exe" : "copilot";
[Fact]
public void CliSourceMode_BuiltIn_IsDefault()
{
Expand Down Expand Up @@ -121,7 +123,7 @@ public void SdkAutoDiscoveredCliPath_IsNotNull()
Assert.NotNull(assemblyDir);

var rid = RuntimeInformation.RuntimeIdentifier;
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", "copilot");
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", CopilotBinaryName);

Assert.True(File.Exists(bundledPath),
$"Bundled copilot binary not found at: {bundledPath} (RID={rid})");
Expand All @@ -136,11 +138,11 @@ public void SdkAutoDiscoveredCliPath_PointsToRuntimesDir()
Assert.NotNull(assemblyDir);

var rid = RuntimeInformation.RuntimeIdentifier;
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", "copilot");
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", CopilotBinaryName);

Assert.Contains("runtimes", bundledPath);
Assert.Contains(rid, bundledPath);
Assert.EndsWith("copilot", bundledPath);
Assert.EndsWith(CopilotBinaryName, bundledPath);
}

[Fact]
Expand Down Expand Up @@ -181,7 +183,7 @@ public void EmbeddedMode_BuiltIn_PrefersBundled()
Assert.NotNull(assemblyDir);

var rid = RuntimeInformation.RuntimeIdentifier;
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", "copilot");
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", CopilotBinaryName);

Assert.True(File.Exists(bundledPath),
$"Bundled copilot binary should exist at: {bundledPath}");
Expand Down Expand Up @@ -226,12 +228,12 @@ public void ServerManager_WouldUseBundledPath_WhenNoSystem()
Assert.NotNull(assemblyDir);

var rid = RuntimeInformation.RuntimeIdentifier;
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", "copilot");
var bundledPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", CopilotBinaryName);

// The path should be well-formed and match the pattern ServerManager expects
Assert.Contains("runtimes", bundledPath);
Assert.Contains("native", bundledPath);
Assert.EndsWith("copilot", bundledPath);
Assert.EndsWith(CopilotBinaryName, bundledPath);
}

[Fact]
Expand All @@ -244,21 +246,21 @@ public void BundledBinary_ExistsInBuildOutput()
Assert.NotNull(assemblyDir);

var rid = RuntimeInformation.RuntimeIdentifier;
var expectedPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", "copilot");
var expectedPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", CopilotBinaryName);

// The test project runs as net10.0 (not maccatalyst), so the RID is typically
// osx-arm64 on Apple Silicon Macs. The SDK packages the binary for this RID.
if (!File.Exists(expectedPath))
{
// Try common alternative RIDs in case the exact RID doesn't match
var alternativeRids = new[] { "osx-arm64", "osx-x64", "maccatalyst-arm64" };
var alternativeRids = new[] { "win-x64", "osx-arm64", "osx-x64", "maccatalyst-arm64" };
var found = false;
var checkedPaths = new List<string> { expectedPath };

foreach (var altRid in alternativeRids)
{
if (altRid == rid) continue;
var altPath = Path.Combine(assemblyDir!, "runtimes", altRid, "native", "copilot");
var altPath = Path.Combine(assemblyDir!, "runtimes", altRid, "native", CopilotBinaryName);
checkedPaths.Add(altPath);
if (File.Exists(altPath))
{
Expand Down Expand Up @@ -296,17 +298,17 @@ public void MonoBundleFallback_PathIsAssemblyDir()
var assemblyDir = Path.GetDirectoryName(typeof(CopilotClient).Assembly.Location);
Assert.NotNull(assemblyDir);

var monoBundlePath = Path.Combine(assemblyDir!, "copilot");
var monoBundlePath = Path.Combine(assemblyDir!, CopilotBinaryName);

// In test context, the MonoBundle path typically doesn't exist (we're not in a .app bundle).
// But the path should be well-formed and point to the assembly directory.
Assert.Equal(assemblyDir, Path.GetDirectoryName(monoBundlePath));
Assert.Equal("copilot", Path.GetFileName(monoBundlePath));
Assert.Equal(CopilotBinaryName, Path.GetFileName(monoBundlePath));

// The runtimes/{rid}/native/ path is the primary bundled path;
// MonoBundle is only a fallback for the Mac Catalyst app bundle layout.
var rid = RuntimeInformation.RuntimeIdentifier;
var primaryPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", "copilot");
var primaryPath = Path.Combine(assemblyDir!, "runtimes", rid, "native", CopilotBinaryName);
Assert.NotEqual(primaryPath, monoBundlePath);
}
}
1 change: 1 addition & 0 deletions PolyPilot.Tests/PolyPilot.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<Compile Include="../PolyPilot/Services/WsBridgeServer.cs" Link="Shared/WsBridgeServer.cs" />
<Compile Include="../PolyPilot/Services/DevTunnelService.cs" Link="Shared/DevTunnelService.cs" />
<Compile Include="../PolyPilot/Services/FiestaService.cs" Link="Shared/FiestaService.cs" />
<Compile Include="../PolyPilot/Models/ReflectionCycle.cs" Link="Shared/ReflectionCycle.cs" />
</ItemGroup>

</Project>
Loading