Skip to content

Bundling#382

Merged
SteveSandersonMS merged 12 commits intomainfrom
stevesa/bundling
Feb 6, 2026
Merged

Bundling#382
SteveSandersonMS merged 12 commits intomainfrom
stevesa/bundling

Conversation

@SteveSandersonMS
Copy link
Contributor

@SteveSandersonMS SteveSandersonMS commented Feb 5, 2026

Plan:

  • For Node, we'll use an NPM dependency as the "bundled" CLI
  • For .NET, we'll fetch the desired version of the Copilot CLI binary at build time matching whichever RID is being built/published (using the current machine RID if none specified)
  • For Python, we'll produce different wheels for each target platform, each containing the Copilot CLI binary
  • For Go, we'll leave things as-is because we don't want to include the Copilot CLI as a binary in the repo. There may be a better solution but it's sufficient for now.

NuGet bundling

Two common ways this is done in NuGet, but won't work for us:

  • Most typical (example: how SkiaSharp works):
    • Include binaries for all supported platforms in a single NuGet package, organized into RID-specific folders, so that the .NET SDK can select only the RID-matching option when publishing applications.
    • However that would lead to a bad result in our case: each platform's binary is ~55 MiB compressed / 110 MiB uncompressed, and there are 6 of them, so the single package would be a ~330 MiB download which expands to 660 MiB on the developer's machine. This is massively outside the normally acceptable size range and would get worse if we add more platforms.
  • Also common (example: how Playwright works):
    • Download at runtime.
    • But this complicates deployment for apps using the SDK, forcing end users to wait for the download during app startup and failing if the end user machine doesn't have permissions to download executables. OK for dev tools like Playwright, not good for consumer apps.

So, the approach chosen here is a middle ground: we download the CLI dynamically but at app build time from NPM. It's not included in our NuGet package, but when a developer takes a dependency on our package and builds their app, it will download a single RID-specific version and use that in the build output (caching in obj). So when the app is published to consumers they have it pre-bundled and don't need to dynamically install it, and the app author didn't have to download for any RIDs they aren't publishing for.

@SteveSandersonMS SteveSandersonMS requested a review from a team as a code owner February 5, 2026 15:23
Copilot AI review requested due to automatic review settings February 5, 2026 15:23
@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Cross-SDK Consistency Review: CLI Bundling Implementation

This PR implements CLI bundling for the .NET SDK, which is an important feature for distribution. However, this creates a significant consistency gap with the other SDK implementations. Here's my analysis:

Current State Across SDKs

✅ Node.js/TypeScript: Already bundles CLI via NPM dependency (@github/copilot in dependencies)

  • Bundled by default, no explicit path needed in most cases
  • Users can override with cliPath option if needed

⚠️ .NET (this PR): Implementing CLI bundling

  • Downloads platform-specific CLI binary at build time
  • Places binary in runtimes/{rid}/native/ directory
  • Falls back to bundled CLI if no CliPath provided
  • Breaking change: Removes PATH fallback and Windows cmd wrapper

❌ Python: No CLI bundling implemented

  • Still relies on COPILOT_CLI_PATH environment variable or default "copilot" PATH lookup
  • E2E tests manually locate CLI from nodejs/node_modules/@github/copilot/

❌ Go: No CLI bundling implemented

  • Still relies on COPILOT_CLI_PATH environment variable or default "copilot" PATH lookup
  • E2E tests manually locate CLI from nodejs/node_modules/@github/copilot/

Concerns

  1. Feature Parity: Python and Go SDKs now lack an important distribution feature that .NET will have. According to the PR description, "For Go, we'll leave things as-is" - but this creates inconsistent user experience across platforms.

  2. Breaking Change in .NET: The removal of PATH fallback ("copilot" → bundled binary) and Windows cmd wrapper could break existing code that:

    • Relies on a system-installed Copilot CLI
    • Uses the default behavior without specifying CliPath

    The new error message is clear, but this is still a behavioral change users should be aware of.

  3. Build-time Dependency: .NET's approach requires Node.js at build time (to read package-lock.json). This is an unusual cross-platform dependency that Python and Go don't have.

Recommendations

For this PR:

  • ✅ The .NET implementation looks solid architecturally
  • ⚠️ Consider documenting the breaking change more prominently (changelog, migration guide)
  • ⚠️ The Node.js build-time dependency should be documented

For follow-up work (to maintain consistency):

  • Python should implement similar bundling using platform-specific wheels (as mentioned in the PR description but not implemented yet)
  • Go approach needs clarification - if it truly won't bundle the CLI, document why this SDK is different

Verdict

While this PR is well-implemented for .NET, it creates an intentional inconsistency according to the PR description. The team should ensure:

  1. Python bundling is implemented soon (per the plan)
  2. The rationale for Go remaining different is clearly documented
  3. Users understand which SDKs bundle the CLI and which require manual installation

AI generated by SDK Consistency Review Agent

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements CLI bundling for the .NET SDK, enabling automatic download and packaging of the platform-specific Copilot CLI binary at build time. This eliminates the need for consumers to separately install or configure the CLI.

Changes:

  • Introduced MSBuild targets that automatically download the appropriate CLI binary for the target platform during build
  • Modified client initialization to use bundled CLI binaries from the runtimes folder by default
  • Simplified test setup by removing explicit CLI path configuration

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
dotnet/src/build/GitHub.Copilot.SDK.targets New MSBuild targets file that downloads, extracts, and copies platform-specific CLI binaries during build
dotnet/src/GitHub.Copilot.SDK.csproj Updated to generate version props file and include targets/props in NuGet package
dotnet/src/Client.cs Modified CLI resolution to prefer bundled binaries over PATH, removed Windows cmd shell workaround
dotnet/test/ClientTests.cs Removed explicit CLI path setup, relying on bundled CLI
dotnet/test/Harness/E2ETestContext.cs Removed CLI path from test context initialization
dotnet/.gitignore Added generated props file to gitignore
Comments suppressed due to low confidence (3)

dotnet/src/GitHub.Copilot.SDK.csproj:47

  • The _GenerateVersionProps target runs on every build (BeforeTargets="BeforeBuild") and executes a Node.js command that parses package-lock.json. This will fail if the nodejs directory or Node.js itself is not available, which could happen in CI builds or when building the packaged NuGet. Consider conditionalizing this target to only run during SDK development builds, not when building consuming projects or when creating the NuGet package.
    <Target Name="_GenerateVersionProps" BeforeTargets="BeforeBuild">
        <Exec Command="node -e &quot;console.log(require('./nodejs/package-lock.json').packages['node_modules/@github/copilot'].version)&quot;" WorkingDirectory="$(MSBuildThisFileDirectory)../.." ConsoleToMSBuild="true" StandardOutputImportance="low">
            <Output TaskParameter="ConsoleOutput" PropertyName="CopilotCliVersion" />
        </Exec>
        <Error Condition="'$(CopilotCliVersion)' == ''" Text="CopilotCliVersion could not be read from nodejs/package-lock.json" />
        <PropertyGroup>
            <_VersionPropsContent>
                <![CDATA[<Project>
  <PropertyGroup>
    <CopilotCliVersion>$(CopilotCliVersion)</CopilotCliVersion>
  </PropertyGroup>
</Project>]]>
            </_VersionPropsContent>
        </PropertyGroup>
        <WriteLinesToFile File="$(MSBuildThisFileDirectory)build\GitHub.Copilot.SDK.props" Lines="$(_VersionPropsContent)" Overwrite="true" WriteOnlyWhenDifferent="true" />
    </Target>

dotnet/src/Client.cs:980

  • The RuntimeInformation.RuntimeIdentifier may return values that don't match the expected patterns (e.g., "osx.13-arm64" instead of "osx-arm64"). This could cause the bundled CLI lookup to fail at runtime. Consider using more robust RID normalization or provide a better error message that includes the actual RID value encountered.
    private static string? GetBundledCliPath(out string searchedPath)
    {
        var binaryName = OperatingSystem.IsWindows() ? "copilot.exe" : "copilot";
        var rid = System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier;
        searchedPath = Path.Combine(AppContext.BaseDirectory, "runtimes", rid, "native", binaryName);
        return File.Exists(searchedPath) ? searchedPath : null;

dotnet/src/build/GitHub.Copilot.SDK.targets:57

  • Parallel builds or multiple projects building simultaneously could race to download and extract the same CLI binary to the cache directory. While the checks for file existence provide some protection, there's a time-of-check-time-of-use (TOCTOU) race condition between checking if the file exists and extracting it. Consider adding file locking or making the extraction operation idempotent.
    <!-- Download if not cached -->
    <MakeDir Directories="$(_CopilotCacheDir)" Condition="!Exists('$(_CopilotCliBinaryPath)')" />
    <Message Importance="high" Text="Downloading Copilot CLI $(CopilotCliVersion) for $(_CopilotPlatform)..." Condition="!Exists('$(_CopilotCliBinaryPath)')" />
    <DownloadFile SourceUrl="$(_CopilotDownloadUrl)" DestinationFolder="$(_CopilotCacheDir)" DestinationFileName="copilot$(_CopilotArchiveExt)"
                  Condition="!Exists('$(_CopilotCliBinaryPath)') And !Exists('$(_CopilotArchivePath)')" />

    <!-- Extract: Windows uses Unzip, others use tar -->
    <Unzip SourceFiles="$(_CopilotArchivePath)" DestinationFolder="$(_CopilotCacheDir)"
           Condition="'$(_CopilotIsWindows)' == 'true' And !Exists('$(_CopilotCliBinaryPath)')" />
    <Exec Command="tar -xzf &quot;$(_CopilotArchivePath)&quot; --strip-components=1 -C &quot;$(_CopilotCacheDir)&quot;"
          Condition="'$(_CopilotIsWindows)' != 'true' And !Exists('$(_CopilotCliBinaryPath)')" />

    <Error Condition="!Exists('$(_CopilotCliBinaryPath)')" Text="Failed to extract Copilot CLI binary to $(_CopilotCliBinaryPath)" />

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Cross-SDK Consistency Review: CLI Bundling

I've reviewed PR #382 for cross-SDK consistency. This PR implements CLI bundling for the .NET SDK, which changes how the Copilot CLI binary is distributed and resolved.

Summary

According to the PR description, this is part of a larger bundling strategy:

  • Node.js: Uses NPM dependency @github/copilot (already bundled)
  • .NET: This PR implements build-time CLI download matching the target RID
  • ⚠️ Python: Planned to produce different wheels per platform, each containing the CLI binary
  • ⚠️ Go: Intentionally left as-is (no bundling)

Key Changes in This PR

The .NET SDK now:

  1. Downloads the CLI at build time from npm registry via MSBuild targets
  2. Removes fallback to PATH - no longer searches for copilot in system PATH
  3. Looks for bundled CLI only at runtimes/{rid}/native/copilot[.exe]
  4. Throws clear error if bundled CLI not found

Consistency Issues Identified

1. CLI Resolution Fallback Strategy ⚠️

Inconsistency: The .NET SDK now has no fallback to system PATH, while other SDKs still do:

  • Node.js: Falls back to "copilot" (PATH search) if not .js file

    cliPath: options.cliPath || "copilot",  // line 171 in client.ts
  • Python: Falls back to "copilot" via COPILOT_CLI_PATH env or PATH:

    default_cli_path = os.environ.get("COPILOT_CLI_PATH", "copilot")
    cli_path = opts.get("cli_path", default_cli_path)
  • Go: Falls back to "copilot" via COPILOT_CLI_PATH env or default:

    opts := ClientOptions{
        CLIPath: "copilot",  // default, line 105
    }
    if cliPath := os.Getenv("COPILOT_CLI_PATH"); cliPath != "" {
        opts.CLIPath = cliPath
    }
  • .NET (after this PR): No PATH fallback - bundled CLI only:

    var cliPath = options.CliPath ?? GetBundledCliPath(out var searchedPath)
        ?? throw new InvalidOperationException(...);

Impact:

  • Users upgrading the .NET SDK who rely on COPILOT_CLI_PATH or system PATH will experience breaking changes
  • The error message is helpful, but the behavior diverges from other SDKs
  • Cross-language developers may be confused by different resolution strategies

2. Documentation Gap ⚠️

The repository's main README still states:

Do I need to install the Copilot CLI separately?

Yes, the Copilot CLI must be installed separately.

This will be outdated for .NET (and eventually Python) once bundling is complete. The README should be updated to reflect the new bundling approach per SDK.

Recommendations

For Immediate Action (This PR):

  1. Consider retaining COPILOT_CLI_PATH support in .NET SDK to maintain consistency:

    var cliPath = options.CliPath 
        ?? Environment.GetEnvironmentVariable("COPILOT_CLI_PATH")
        ?? GetBundledCliPath(out var searchedPath)
        ?? throw new InvalidOperationException(...);

    This would:

    • Maintain backward compatibility
    • Align with Python/Go/Node behavior
    • Allow advanced users to override bundled CLI for testing
  2. Update error message to mention the CliPath option explicitly:

    throw new InvalidOperationException(
        $"Copilot CLI not found at '{searchedPath}'. " +
        "Ensure the SDK NuGet package was restored correctly, " +
        "or provide an explicit CliPath via CopilotClientOptions.CliPath."
    );

For Follow-up Work:

  1. Update main README.md to document the bundling strategy and clarify which SDKs bundle the CLI vs. require external installation

  2. Update .NET README to document:

    • CLI is now bundled (no separate installation needed for .NET)
    • How RID resolution works
    • How to override with custom CLI path if needed
  3. Plan Python bundling implementation to ensure consistency with .NET approach

  4. Document Go's intentional difference - why Go doesn't bundle (likely to keep binaries small and leverage system PATH)

Positive Aspects ✅

  • The MSBuild integration is elegant and automated
  • Build-time download with caching is efficient
  • RID-based resolution is correct for cross-platform support
  • Error messages are clear and actionable
  • Tests correctly updated to rely on bundled CLI

Conclusion

This PR represents a strategic shift toward bundled CLI distribution, which improves the out-of-box experience. However, it creates a temporary consistency gap between SDKs. Consider the recommendations above to:

  1. Minimize breaking changes for existing .NET users
  2. Maintain cross-SDK consistency during the transition period
  3. Update documentation to reflect the new architecture

Would you like me to elaborate on any of these points or provide specific code suggestions?

AI generated by SDK Consistency Review Agent

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Cross-SDK Consistency Review: CLI Bundling Implementation

I've reviewed this PR for consistency with the other SDK implementations (Node.js, Python, Go). Here are my findings:

✅ What's Consistent

  1. Bundling approach is intentionally different per language (as documented in PR description):

    • Node.js: NPM dependency @github/copilot (already exists)
    • .NET: Build-time download from npm registry (this PR)
    • Python: Platform-specific wheels (planned)
    • Go: No bundling (by design)
  2. The CliPath option is still available to override bundled CLI in all SDKs

  3. Documentation updated to clarify that CliPath now defaults to bundled CLI

⚠️ Consistency Issues Found

1. Behavioral divergence: CLI resolution

After this PR, .NET will have different CLI discovery behavior than Node.js, Python, and Go:

SDK COPILOT_CLI_PATH env var PATH fallback Bundled CLI
Node.js ❌ Not checked ✅ Default "copilot" ✅ Via NPM dep
Python ✅ Checked ✅ Default "copilot" ❌ Not yet
Go ✅ Checked ✅ Default "copilot" ❌ By design
.NET (this PR) ❌ No longer checked ❌ Removed ✅ Required

Current .NET behavior (before this PR):

var cliPath = options.CliPath ?? "copilot";  // Falls back to PATH

New .NET behavior (after this PR):

var cliPath = options.CliPath ?? GetBundledCliPath(out var searchedPath)
    ?? throw new InvalidOperationException($"Copilot CLI not found at '{searchedPath}'...");

Impact: This makes .NET the only SDK that:

  • Throws an exception if the bundled CLI isn't found (instead of trying PATH)
  • Doesn't respect COPILOT_CLI_PATH environment variable
  • Requires explicit CliPath if users want to use a system-installed CLI

📋 Recommendations

Option A: Match Node.js behavior (recommended for consistency)

var cliPath = options.CliPath ?? Environment.GetEnvironmentVariable("COPILOT_CLI_PATH") 
    ?? GetBundledCliPath(out _) ?? "copilot";

This would:

  • ✅ Prioritize explicit CliPath option
  • ✅ Fall back to COPILOT_CLI_PATH env var (matches Python/Go)
  • ✅ Try bundled CLI next
  • ✅ Finally fall back to "copilot" on PATH (matches all other SDKs)
  • ✅ Provide better migration path for existing users

Option B: Document the breaking change

If the stricter behavior is intentional (force users to use bundled CLI), this should be:

  1. Called out as a breaking change in release notes
  2. Documented in .NET README to explain why it differs from other SDKs
  3. Consider adding COPILOT_CLI_PATH support even if PATH fallback is removed

🔍 Additional Notes

  1. Test consistency: The .NET tests now correctly avoid requiring explicit CliPath, which is good. Python/Go tests still use COPILOT_CLI_PATH for E2E tests, which is reasonable given their different bundling approach.

  2. Windows cmd wrapper removed: The removal of cmd /c wrapper logic in ResolveCliCommand is correct since bundled binaries are always absolute paths. However, if you restore PATH fallback, this logic should be restored too.

  3. Error messages: The new error message is helpful, but consider mentioning the CliPath option as a workaround for users who want to use a custom CLI location.

Summary

This PR introduces an intentional architectural difference in how .NET resolves the CLI compared to other SDKs. While the bundling mechanism itself is appropriate for .NET's ecosystem, the complete removal of environment variable and PATH fallbacks creates an inconsistency that may surprise users familiar with other SDK implementations.

Recommendation: Consider Option A above to maintain cross-SDK consistency in fallback behavior while still benefiting from bundled CLI as the default.

AI generated by SDK Consistency Review Agent

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Cross-SDK Consistency Review: CLI Bundling Feature

I've reviewed this PR for cross-language SDK consistency. Here's my analysis:

✅ What's Been Changed

This PR implements CLI bundling for Node.js and .NET SDKs:

Node.js (nodejs/src/client.ts & nodejs/src/types.ts):

  • Adds getBundledCliPath() function that resolves the bundled CLI from the @github/copilot NPM package
  • Changes default cliPath from "copilot" (PATH lookup) to getBundledCliPath()
  • Updates documentation to reflect bundled CLI as the default

.NET (dotnet/src/Client.cs & dotnet/src/Types.cs):

  • Adds GetBundledCliPath() method that looks for the CLI in runtimes/{rid}/native/copilot[.exe]
  • Changes default from "copilot" (PATH lookup) to bundled CLI with error if not found
  • Removes Windows cmd /c fallback for PATH resolution (no longer needed with bundling)
  • Updates documentation to reflect bundled CLI as the default

⚠️ Consistency Gap: Python SDK

According to the PR description, Python "will produce different wheels for each target platform, each containing the Copilot CLI binary." However, no Python changes are included in this PR.

Current Python behavior (python/copilot/client.py):

  • Default cli_path is "copilot" (via COPILOT_CLI_PATH env var or PATH lookup)
  • Uses shutil.which() to resolve the executable
  • No bundled CLI support

Recommendation: The Python SDK should be updated to maintain feature parity:

  1. Add a function to detect and use a bundled CLI (similar to Node's getBundledCliPath())
  2. Look for platform-specific binary in the wheel package structure
  3. Fall back to PATH if bundled CLI not found (for development/custom installations)
  4. Update default cli_path behavior and documentation

Example implementation approach:

def _get_bundled_cli_path() -> Optional[str]:
    """Get path to bundled CLI if present in the installed package."""
    import sys
    from pathlib import Path
    
    # Check for bundled binary in package directory
    package_dir = Path(__file__).parent
    binary_name = "copilot.exe" if sys.platform == "win32" else "copilot"
    bundled_path = package_dir / "bin" / binary_name
    
    return str(bundled_path) if bundled_path.exists() else None

Then update the default in __init__:

default_cli_path = (
    _get_bundled_cli_path() or 
    os.environ.get("COPILOT_CLI_PATH", "copilot")
)

✅ Go SDK

The Go SDK is intentionally left unchanged per the PR description ("leave things as-is because we don't want to include the Copilot CLI as a binary in the repo"), which is an acceptable design decision for that ecosystem.

📊 Summary

SDK Bundling Status Default Behavior
Node.js ✅ Implemented Uses bundled CLI from @github/copilot package
.NET ✅ Implemented Uses bundled CLI from runtimes/{rid}/native/
Python ⚠️ Not implemented Still uses PATH lookup ("copilot")
Go ✅ Intentionally unchanged Uses PATH lookup ("copilot")

The Python SDK should be updated to implement bundling to maintain feature parity with Node.js and .NET. The current state creates an inconsistency where Python users will need to install the CLI separately while Node.js and .NET users get it automatically.

AI generated by SDK Consistency Review Agent

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

SDK Consistency Review: ✅ Approved

I've reviewed this PR for cross-SDK consistency and found that the bundling implementation is appropriately consistent across all SDKs.

Summary

This PR adds CLI bundling support to Node.js, Python, and .NET while deliberately leaving Go unchanged (as stated in the PR description). Each implementation follows language-specific conventions:

  • Node.js: Uses @github/copilot NPM dependency via getBundledCliPath()
  • Python: Includes platform-specific binaries in wheels via _get_bundled_cli_path()
  • .NET: Downloads RID-specific binaries at build time via GetBundledCliPath()
  • Go: No bundling (intentional - continues using COPILOT_CLI_PATH or explicit CLIPath)

API Consistency ✅

All three SDKs that implement bundling follow the same logical pattern:

  1. Check for explicit path option first (cliPath, cli_path, CliPath)
  2. Fall back to bundled CLI if available
  3. Throw error if neither exists (no PATH fallback)

The naming follows each language's conventions:

  • TypeScript: cliPath (camelCase)
  • Python: cli_path (snake_case)
  • .NET: CliPath (PascalCase)
  • Go: CLIPath (PascalCase, unchanged)

Documentation Consistency ✅

All three updated SDKs have consistent documentation stating that CliPath/cli_path/cliPath is optional and defaults to the bundled CLI.

No Action Required

This PR maintains excellent cross-SDK consistency while respecting each language's ecosystem conventions. The Go SDK exclusion is documented in the PR description and makes sense given the constraints around binary distribution in Go modules.

AI generated by SDK Consistency Review Agent

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Cross-SDK Consistency Review ✅

I've reviewed PR #382 for consistency across the SDK implementations. This PR introduces CLI bundling for Node.js, Python, and .NET, while intentionally leaving Go unchanged.

Overall Assessment: Changes maintain good cross-SDK consistency

The implementation is well-aligned across the three modified SDKs with appropriate handling of language-specific conventions.


Consistent Implementation Patterns

All three SDKs follow the same design:

  1. Bundled CLI path discovery - Each SDK includes platform-appropriate helper functions
  2. Error handling - All SDKs throw clear exceptions when bundled CLI is unavailable
  3. Explicit override support - Users can still provide custom cli_path/cliPath/CliPath
  4. Platform binary naming - Correct handling of .exe on Windows

📝 Notable Design Decisions

1. Go SDK Intentionally Excluded

Per the PR description, Go continues to use PATH lookup. This is a deliberate choice to avoid binary bundling. The user experience differs:

  • Node/Python/.NET: Bundled CLI works out of the box
  • Go: Requires manual CLI installation or explicit path

Suggestion: Consider adding a note to the Go README explaining why bundling isn't included and how users should install the CLI.

2. Python Breaking Change: COPILOT_CLI_PATH Environment Variable Removed ⚠️

The Python SDK previously supported COPILOT_CLI_PATH env var for specifying CLI location. This PR removes that support in favor of the bundled binary.

Before:

default_cli_path = os.environ.get("COPILOT_CLI_PATH", "copilot")

After:

# Only checks bundled path or explicit cli_path option
bundled_path = _get_bundled_cli_path()

Impact: Python users who set COPILOT_CLI_PATH will experience a breaking change. They'll need to switch to the cli_path parameter.

Suggestion: Consider one of:

  • Restore env var support as a fallback (check order: explicit cli_pathCOPILOT_CLI_PATH env → bundled)
  • Document this as a breaking change in release notes

Verified Consistency

Aspect Node.js Python .NET Go Status
Bundled CLI support ❌ (intentional) ✅ Consistent
Error on missing CLI N/A ✅ Consistent
Explicit path override cliPath cli_path CliPath CLIPath ✅ Idiomatic
Windows binary naming .js wrapper .exe handled .exe handled N/A ✅ Consistent
Validation timing At spawn At init At init N/A ⚠️ Minor difference

Summary

The PR maintains excellent cross-SDK consistency for the three SDKs being modified. The main consideration is the Python breaking change with COPILOT_CLI_PATH, which may affect existing users. Otherwise, the implementation is solid and follows language-appropriate patterns.

Recommendation: ✅ Approve with optional consideration for the Python env var backward compatibility.

AI generated by SDK Consistency Review Agent

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

SDK Consistency Review Summary

I've reviewed this PR for cross-SDK consistency. Overall, the implementation is well-coordinated across Node.js, .NET, and Python! 🎉

✅ What's Consistent

  1. Bundle discovery patterns: All three modified SDKs implement helper functions (GetBundledCliPath, getBundledCliPath, _get_bundled_cli_path) to locate bundled CLIs in platform-appropriate locations
  2. Default behavior: All default to bundled CLI when cliPath/cli_path/CLIPath not specified
  3. Error messages: All provide helpful errors when bundled CLI is missing, with platform-specific guidance
  4. API surface: The cliPath/cli_path/CLIPath option remains optional and works identically across all SDKs

⚠️ Issue Found

One documentation inconsistency in Python:

  • python/copilot/types.py line 25 still documents cli_path with the old default ("copilot" from PATH)
  • This should be updated to match .NET and Node.js, which now document the bundled CLI default

See inline comment for suggested fix.

📝 Note on Go SDK

The Go SDK intentionally lacks bundling (as stated in the PR description). Its documentation (go/types.go) still says CLIPath defaults to "copilot", which is correct. However, users might be surprised by the different behavior across SDKs. Consider adding a note in Go's README or documentation explaining this difference if it's not already documented elsewhere.

AI generated by SDK Consistency Review Agent

@friggeri friggeri mentioned this pull request Feb 5, 2026
4 tasks
@SteveSandersonMS SteveSandersonMS added this pull request to the merge queue Feb 6, 2026
Merged via the queue into main with commit 4253946 Feb 6, 2026
31 checks passed
@SteveSandersonMS SteveSandersonMS deleted the stevesa/bundling branch February 6, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants