Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion PolyPilot.Console/PolyPilot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="GitHub.Copilot.SDK" Version="0.2.0" />
<!-- Direct SDK reference to get the bundled copilot CLI binary (Core skips the download) -->
<PackageReference Include="GitHub.Copilot.SDK" Version="0.2.1" />
<PackageReference Include="Spectre.Console" Version="0.54.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../PolyPilot.Core/PolyPilot.Core.csproj" />
</ItemGroup>

</Project>
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ public static void OpenInBackground(string url)
{
if (!IsValidExternalUrl(url)) return;

#if MACCATALYST
try
if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst())
{
var psi = new ProcessStartInfo("open") { UseShellExecute = false };
psi.ArgumentList.Add("-g");
psi.ArgumentList.Add(url);
Process.Start(psi)?.Dispose();
try
{
var psi = new ProcessStartInfo("open") { UseShellExecute = false };
psi.ArgumentList.Add("-g");
psi.ArgumentList.Add(url);
Process.Start(psi)?.Dispose();
}
catch { }
}
catch { }
#endif
}
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,20 @@ namespace PolyPilot.Models;
public static class PlatformHelper
{
public static bool IsDesktop =>
#if MACCATALYST || WINDOWS
true;
#elif IOS || ANDROID
false;
#else
// Linux GTK and other non-mobile platforms are desktop
!OperatingSystem.IsIOS() && !OperatingSystem.IsAndroid();
#endif
// Runtime detection — OperatingSystem.IsIOS() returns true on Mac Catalyst,
// so we must exclude it explicitly to correctly identify Mac Catalyst as desktop.
OperatingSystem.IsMacCatalyst() || (!OperatingSystem.IsIOS() && !OperatingSystem.IsAndroid());

public static bool IsMobile =>
#if IOS || ANDROID
true;
#else
false;
#endif
(OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()) || OperatingSystem.IsAndroid();

public static string PlatformName =>
#if MACCATALYST
"maccatalyst";
#elif WINDOWS
"windows";
#elif IOS
"ios";
#elif ANDROID
"android";
#else
OperatingSystem.IsMacCatalyst() ? "maccatalyst" :
OperatingSystem.IsMacOS() ? "maccatalyst" :
OperatingSystem.IsWindows() ? "windows" :
OperatingSystem.IsIOS() ? "ios" :
OperatingSystem.IsAndroid() ? "android" :
OperatingSystem.IsLinux() ? "linux" : "unknown";
#endif

public static ConnectionMode[] AvailableModes => IsDesktop
? [ConnectionMode.Embedded, ConnectionMode.Persistent, ConnectionMode.Remote]
Expand Down
File renamed without changes.
File renamed without changes.
40 changes: 40 additions & 0 deletions PolyPilot.Core/PolyPilot.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Multi-target to preserve platform #if blocks (ANDROID, IOS, MACCATALYST, WINDOWS) -->
<TargetFrameworks>net10.0;net10.0-android</TargetFrameworks>
<TargetFrameworks Condition="!$([MSBuild]::IsOSPlatform('linux'))">$(TargetFrameworks);net10.0-ios;net10.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net10.0-windows10.0.19041.0</TargetFrameworks>
<RootNamespace>PolyPilot</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<!-- Skip the CLI binary download — Core is a library, not an app -->
<CopilotSkipCliDownload>true</CopilotSkipCliDownload>
<!-- Suppress MAUI head targets — Core is a library, not an app -->
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<!-- Allow the MAUI app, GTK app, and tests to access internal members -->
<InternalsVisibleTo Include="PolyPilot" />
<InternalsVisibleTo Include="PolyPilot.Gtk" />
<InternalsVisibleTo Include="PolyPilot.Tests" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="GitHub.Copilot.SDK" Version="0.2.1" />
<PackageReference Include="Markdig" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.5" />
<PackageReference Include="QRCoder" Version="1.7.0" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../PolyPilot.Provider.Abstractions/PolyPilot.Provider.Abstractions.csproj" />
</ItemGroup>

<!-- UI Automation for Windows Terminal tab switching (WindowFocusHelper.cs) -->
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
<FrameworkReference Include="Microsoft.WindowsDesktop.App" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -974,16 +974,17 @@ public async Task InitializeAsync(CancellationToken cancellationToken = default)
return;
}

#if ANDROID
// Android can't run Copilot CLI locally — must connect to remote server
settings.Mode = ConnectionMode.Persistent;
CurrentMode = ConnectionMode.Persistent;
if (settings.Host == "localhost" || settings.Host == "127.0.0.1")
if (OperatingSystem.IsAndroid())
{
Debug("Android detected with localhost — update Host in settings to your Mac's IP");
// Android can't run Copilot CLI locally — must connect to remote server
settings.Mode = ConnectionMode.Persistent;
CurrentMode = ConnectionMode.Persistent;
if (settings.Host == "localhost" || settings.Host == "127.0.0.1")
{
Debug("Android detected with localhost — update Host in settings to your Mac's IP");
}
Debug($"Android: connecting to remote server at {settings.CliUrl}");
}
Debug($"Android: connecting to remote server at {settings.CliUrl}");
#endif
// In Persistent mode, auto-start the server if not already running
if (settings.Mode == ConnectionMode.Persistent)
{
Expand Down Expand Up @@ -4864,11 +4865,13 @@ public async ValueTask DisposeAsync()

private void StartExternalSessionScannerIfNeeded()
{
#if ANDROID || IOS
// No local filesystem access on mobile
return;
#else
// UI-thread only -- callers are InitializeAsync, InitializeDemo, and ReconnectAsync
if (OperatingSystem.IsAndroid() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()))
{
// No local filesystem access on mobile
return;
}

// UI-thread only -- callers are InitializeAsync, InitializeDemo, and ReconnectAsync
if (_externalSessionScanner != null) return; // already running

// CWD-based exclusion: sessions whose CWD is inside ~/.polypilot/ are typically PolyPilot's own
Expand All @@ -4890,7 +4893,6 @@ private void StartExternalSessionScannerIfNeeded()
_externalSessionScanner.OnChanged += () => NotifyStateChangedCoalesced();
_externalSessionScanner.Start();
Debug("External session scanner started");
#endif
}

private void StopExternalSessionScanner()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,13 @@ private void SaveStats()
PreallocationSize = json.Length
};

#if !ANDROID && !IOS && !MACCATALYST
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
if (!OperatingSystem.IsAndroid() && !OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst())
{
options.UnixCreateMode = UnixFileMode.UserRead | UnixFileMode.UserWrite;
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
options.UnixCreateMode = UnixFileMode.UserRead | UnixFileMode.UserWrite;
}
}
#endif

using var stream = new FileStream(StatsPath, options);
using var writer = new StreamWriter(stream);
Expand Down
7 changes: 1 addition & 6 deletions PolyPilot.Gtk/PolyPilot.Gtk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../PolyPilot.Core/PolyPilot.Core.csproj" />
<ProjectReference Include="../PolyPilot.Provider.Abstractions/PolyPilot.Provider.Abstractions.csproj" />
</ItemGroup>

Expand All @@ -55,15 +56,9 @@
<PackageReference Include="Platform.Maui.Linux.Gtk4" Version="0.6.0" />
<PackageReference Include="Platform.Maui.Linux.Gtk4.Essentials" Version="0.6.0" />
<PackageReference Include="Platform.Maui.Linux.Gtk4.BlazorWebView" Version="0.6.0" />
<PackageReference Include="GitHub.Copilot.SDK" Version="0.2.0" />
<PackageReference Include="Markdig" Version="1.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebView" Version="10.0.5" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.5" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.11" />
<PackageReference Include="QRCoder" Version="*" />
<PackageReference Include="Microsoft.Maui.DevFlow.Agent.Gtk" Version="0.1.0-preview.4.26202.3" />
<PackageReference Include="Microsoft.Maui.DevFlow.Blazor.Gtk" Version="0.1.0-preview.4.26202.3" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
<PackageReference Include="GitHub.Copilot.SDK" Version="0.2.0" />
<PackageReference Include="GitHub.Copilot.SDK" Version="0.2.1" />
</ItemGroup>
</Project>
6 changes: 3 additions & 3 deletions PolyPilot.Tests/ChatExperienceSafetyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ public async Task FlushCurrentResponse_EmptyContent_NoOp()
public void WatchdogCallback_HasGenerationGuard()
{
var source = File.ReadAllText(
Path.Combine(GetRepoRoot(), "PolyPilot", "Services", "CopilotService.Events.cs"));
Path.Combine(GetRepoRoot(), "PolyPilot.Core", "Services", "CopilotService.Events.cs"));

// Find the watchdog callback inside InvokeOnUI
var watchdogIdx = source.IndexOf("watchdogGeneration != currentGen", StringComparison.Ordinal);
Expand All @@ -835,7 +835,7 @@ public void WatchdogCallback_HasGenerationGuard()
public void CompleteResponse_Source_ClearsSendingFlag()
{
var source = File.ReadAllText(
Path.Combine(GetRepoRoot(), "PolyPilot", "Services", "CopilotService.Events.cs"));
Path.Combine(GetRepoRoot(), "PolyPilot.Core", "Services", "CopilotService.Events.cs"));

// Find CompleteResponse method
var crIdx = source.IndexOf("private void CompleteResponse(", StringComparison.Ordinal);
Expand All @@ -854,7 +854,7 @@ public void CompleteResponse_Source_ClearsSendingFlag()
public void ReconnectPath_IncludesMcpServersAndSkills()
{
var source = File.ReadAllText(
Path.Combine(GetRepoRoot(), "PolyPilot", "Services", "CopilotService.cs"));
Path.Combine(GetRepoRoot(), "PolyPilot.Core", "Services", "CopilotService.cs"));

// After extraction to BuildFreshSessionConfig, verify the reconnect path calls the helper
var sessionNotFoundIdx = source.IndexOf("resumeEx.Message.Contains(\"Session not found\"", StringComparison.Ordinal);
Expand Down
Loading