feat: Deep Squad Integration — Phase 1 & 2 (#436)#575
Open
Conversation
- Project-level MCP config: LoadMcpServers now reads .copilot/mcp-config.json from the session's working directory (highest priority), giving Squad's project MCP tools to PolyPilot sessions automatically. All 5 callers updated. - Squad metadata surfacing: SquadDiscovery now reads manifest.json, upstream.json, identity/now.md, and detects squad.config.ts presence. New SquadMetadata/SquadManifest/SquadUpstreamEntry records on GroupPreset. - Squad initialized badge: IsSquadInitialized() detects .squad/team.md + .copilot/skills/ to show a badge in the preset picker. - Set up Squad button: RunSquadInit() runs 'squad init --no-workflows' from the preset picker when Squad is not yet initialized. - Skills source labels: DiscoverAvailableSkills labels .copilot/skills/ as 'squad' (vs 'project') when Squad is initialized in the worktree. - SquadWriter safety: Throws InvalidOperationException when squad.config.ts exists to prevent edits that would be overwritten by 'squad build'. - 23 new tests covering all new behavior, 3346 total tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
#436) Add IPermissionAwareProvider extension interface to Provider.Abstractions: - ProviderPermissionRequest model with Id, ToolName, AgentId, Description, etc. - OnPermissionRequested/OnPermissionResolved events - GetPendingPermissions(), ApprovePermissionAsync(), DenyPermissionAsync() Wire into CopilotService.Providers.cs: - WirePermissionEvents() subscribes to permission-aware providers - ApproveProviderPermissionAsync/DenyProviderPermissionAsync public API - GetPendingPermissions() aggregates across all providers - IsPermissionAwareProvider() helper - Service-level OnPermissionRequested/OnPermissionResolved events This is the foundational infrastructure for Phase 3's Squad RemoteBridge integration, where Squad agents request tool approval via RCPermissionEvent. 9 new tests, 3355 total passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add permission request cards to the Dashboard: - Shows pending permission requests from IPermissionAwareProvider plugins - Card displays tool name, description, arguments, and agent name - Approve (✅) and Deny (❌) buttons with proper error handling - Animated slide-in with themed styling matching existing notice cards - Auto-refreshes via existing OnStateChanged event subscription This completes Design Challenge #1 from the issue — PP can now display and handle Squad RemoteBridge permission requests when a SquadSessionProvider plugin is connected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… picker (#436) Show upstream squad registrations and manifest description in the preset picker: - Upstream entries from upstream.json shown as 🔗 links with name and URL tooltip - Manifest description shown below the preset when available - Consistent styling with existing Squad metadata (identity, skills, config.ts badge) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Display the success/error result message from RunSquadInit() below the 'Set up Squad' button. Uses green styling for success (✅) and red styling for errors (❌). Previously _squadInitResult was set but never rendered, so users got no visible feedback if squad init failed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New PolyPilot.Provider.Squad project implementing ISessionProvider + IPermissionAwareProvider to connect to Squad's RemoteBridge WebSocket. Components: - SquadProtocol.cs — C# models for all 10 RC server events and 5 client commands, matching Squad SDK v0.9.1 protocol.ts - SquadBridgeClient.cs — WebSocket client with ticket-based auth, keepalive pings, and event dispatch loop - SquadSessionProvider.cs — Full IPermissionAwareProvider implementation mapping RC events to PP's provider interface (delta→content, agents→ members, tool_call→tools, permission→approval flow). Custom actions for squad status/nap/cast/economy. - SquadProviderFactory.cs — DI factory with env var + JSON file config 35 new tests covering protocol serialization, round-trips, provider interface compliance, branding, lifecycle, and error handling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…436) 1. HandleToolCall now correlates callIds between 'running' and 'completed'/'error' events using _activeToolCalls dictionary. Previously each event generated a unique ticks-based callId, making it impossible for the host to match start/end. 2. HandleStatus now compares server protocol version major number against client ProtocolVersion. Fires OnError if they differ. Stores ServerVersion for diagnostics. 3. Added ReconnectAsync() — disconnects, clears all local state (members, history, permissions, tool calls), and re-initializes. 6 new tests covering callId correlation (start→complete, start→error), version match/mismatch/minor-diff, and ReconnectAsync method existence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Owner
Author
🔍 Multi-Model Re-Review — PR #575 (Final)Tests: ✅ 3403 passed, 0 failed Previous Findings — All Critical/Moderate Fixed
Re-Review New Issues — Fixed
Recommendation✅ Approve — All critical and moderate issues are resolved. 3 items deferred as cross-cutting concerns for follow-up. Tests green (3403 passed). |
…imeout Fixes all 21 findings from multi-model PR review: CRITICAL: 1. SemaphoreSlim for concurrent WebSocket sends (ping + UI race) 2. Lock + snapshot for _history and _members (background to UI thread) 3. Interlocked for IsInitializing (atomic CAS) 4. 4MB max message size cap with drain on overflow (DoS protection) MODERATE: 5. DisconnectAsync awaits receive/ping loops before dispose 7. Removed session token from URL fallback (credential leak) 9. CTS disposed in DisconnectAsync (was only in DisposeAsync) 10. Client disposed on init failure (was leaked) 11. ConnectAsync throws if already connected (idempotency guard) 12. IsInitializing uses Interlocked.CompareExchange (atomic) 13. RunSquadInit 60s timeout with process termination on expiry 14. Port range validation (1-65535) in SquadBridgeClient ctor 15. Double-disconnect guard via _disposed flag MINOR: 16. HttpResponse disposed (using var) 17. MemoryStream disposed (using var) 18. TryGetProperty guard for type and ticket JSON parsing 7 new tests covering port validation, max message size, snapshot copies for History/GetMembers, atomic IsInitializing flag. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move _disposed=true after DisconnectAsync() to prevent cleanup skip - Read stdout/stderr in parallel to avoid pipe buffer deadlock in RunSquadInit Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Deep Squad Integration (Issue #436)
This PR implements Phase 1 (Squad as Config) and Phase 2 (Squad as Runtime) of the Squad integration roadmap.
How Users Use This Feature
Mode 1: Squad as Config (Phase 1)
Use when you want PP's multi-agent orchestrator with Squad's team definitions and skills.
Squad owns: team definitions, skills, MCP config, upstream registry.
PP owns: orchestration, session lifecycle, UI rendering.
Or click "Set up Squad" in the preset picker to run
squad init --no-workflowsdirectly from PolyPilot.Mode 2: Squad as Runtime (Phase 2)
Use when you want Squad's full runtime — coordinator persona, casting, event bus, history.
Squad owns: everything (orchestration, agents, tools, history).
PP owns: native UI, mobile access, permission approval.
Mobile:
squad rc --tunnel+ PP mobile QR scanner → approve permissions from phone.What's Included
Phase 1 — Squad as Config (7 features)
LoadMcpServers()merges project-local.copilot/mcp-config.jsonmanifest.json,upstream.json,identity/now.mdfrom.squad/.squad/team.md+.copilot/skills/and shows ✅ badgesquad init --no-workflowsfrom preset picker (with 60s timeout)squad.config.tsexistsPhase 2 — Squad as Runtime (4 components)
SquadSessionProvider— FullIPermissionAwareProviderimplementation mapping Squad's RC protocol:RCDeltaEvent→OnContentReceived/OnMemberContentReceivedRCAgentsEvent→GetMembers()with live status (idle/working/streaming)RCToolCallEvent→OnToolStarted/OnToolCompleted(with correlated callIds)RCPermissionEvent→OnPermissionRequested→ approve/deny flowRCCompleteEvent→ history +OnTurnEndSquadBridgeClient— WebSocket client with:SquadProviderFactory— DI factory with env var + JSON file configIPermissionAwareProvider— Extension interface in Provider.Abstractions for permission approval flowsReview Fixes (21 findings addressed)
Files Changed
PolyPilot.Provider.Squad/— SquadProtocol.cs, SquadBridgeClient.cs, SquadSessionProvider.cs, SquadProviderFactory.csIPermissionAwareProvider.cs,ProviderPermissionRequest.csSquadDiscovery.cs(metadata),SessionSidebar.razor(UI),CopilotService.cs(MCP merge),SquadWriter.cs(safety)CopilotService.Providers.cs(permission event wiring)SquadProviderTests.cs+ existing tests across Phase 1 featuresTest Results
Known Limitations
rccommand uses random ports and doesn't expose the session token. A.squad/rc-session.jsonauto-discovery mechanism would improve UX (Squad-side feature request).Closes #436 (Phase 1 & 2)