-
Notifications
You must be signed in to change notification settings - Fork 815
[go] support bundling and auto installing the GitHub Copilot CLI #414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Cross-SDK Consistency ReviewSummaryThis PR introduces CLI bundling/embedding capability exclusively to the Go SDK, creating a significant feature disparity across the SDK implementations. While this is an excellent feature for Go users, the same capability would be valuable for Node.js, Python, and .NET SDKs. Current StateGo SDK (this PR):
Node.js SDK:
Python SDK:
.NET SDK:
Consistency ImpactRequirements sections now differ: Go SDK (after this PR): ## Distributing your application with an embedded GitHub Copilot CLI
The SDK supports bundling, using Go's `embed` package, the Copilot CLI binary within your application's distribution.
This allows you to bundle a specific CLI version and avoid external dependencies on the user's system.All other SDKs: ## Requirements
- [Language runtime]
- GitHub Copilot CLI installed and in PATH (or provide custom path)RecommendationsOption 1: Track feature parity (Recommended)Accept this PR as-is since it's Go-specific infrastructure, but create tracking issues to implement equivalent functionality in other SDKs: Node.js: Could use npm's optional dependencies or postinstall scripts to download platform-specific binaries Option 2: Document the differenceIf bundling is intentionally Go-only (due to Go's superior embedding capabilities), explicitly document this as a Go-specific advantage in the main README to set user expectations. Why This MattersDistribution simplification: This feature allows Go SDK users to ship applications without external CLI dependencies, significantly improving the deployment experience. Users of other SDKs would benefit equally from this capability. Version pinning: Embedding specific CLI versions ensures consistent behavior across deployments, which is valuable regardless of language. Offline environments: Bundled CLIs work in airgapped/restricted environments where downloading dependencies isn't possible. Suggested Next Steps
Would you like me to help create those tracking issues or provide implementation guidance for the other languages?
|
Cross-SDK Consistency Review: CLI Bundling FeatureI've reviewed PR #414 which adds CLI embedding/bundling functionality to the Go SDK. Here's the consistency analysis across all four SDK implementations: ✅ Good News: Feature Parity Already Exists!All four SDKs already have CLI bundling/embedding functionality, though implemented using different approaches appropriate to each ecosystem:
📋 Implementation ComparisonGo SDK (this PR)
Node.js/TypeScript SDK
Python SDK
.NET SDK
🎯 Consistency AssessmentAPI Consistency: ✅ All SDKs follow the same priority order:
Naming Consistency: ✅ Follows language conventions:
💡 Suggestions for ImprovementWhile this PR maintains cross-SDK consistency, consider these non-blocking documentation improvements across all SDKs:
✅ ConclusionThis PR maintains excellent cross-SDK consistency. The Go implementation uses idiomatic Go patterns (embed package, build tools) while achieving the same user-facing behavior as other SDKs. The feature allows users across all platforms to:
No blocking issues found. The implementation differences are appropriate ecosystem adaptations rather than inconsistencies.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds Go SDK support for bundling and automatically installing a GitHub Copilot CLI binary embedded into an application, so users don’t need a separate CLI installation.
Changes:
- Introduces a small cross-platform file-locking helper (
internal/flock) with tests. - Adds an embedded CLI installer (
internal/embeddedcli) plus a small public wrapper package (embeddedcli) and hooksNewClientto prefer the embedded CLI when available. - Adds a
go/cmd/bundlertool to download the CLI from npm, zstd-compress it, and generate Go source that embeds the artifacts; updates Go module deps and README.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| go/internal/flock/flock.go | Adds Acquire API for lockfiles (currently has an open-flag bug). |
| go/internal/flock/flock_unix.go | Unix flock implementation. |
| go/internal/flock/flock_windows.go | Windows LockFileEx/UnlockFileEx implementation. |
| go/internal/flock/flock_other.go | Stub implementation for unsupported platforms. |
| go/internal/flock/flock_test.go | Concurrency + idempotent release tests for flock. |
| go/internal/embeddedcli/embeddedcli.go | Implements lazy install + lookup of embedded CLI (hashing/dir choice need hardening). |
| go/internal/embeddedcli/embeddedcli_test.go | Tests for setup constraints, install, version sanitization, and hash mismatch behavior. |
| go/embeddedcli/installer.go | Public wrapper exposing embeddedcli.Setup + config type alias. |
| go/cmd/bundler/main.go | New bundler tool to download, compress, and generate embed-ready Go code (has a panic bug + networking/resource concerns). |
| go/client.go | Uses embedded CLI path when COPILOT_CLI_PATH is unset and default CLIPath is used (needs guard for external-server mode). |
| go/README.md | Documents embedding flow via bundler tool. |
| go/go.mod | Adds zstd dependency for generated code. |
| go/go.sum | Adds checksums for new dependency. |
Comments suppressed due to low confidence (3)
go/internal/embeddedcli/embeddedcli.go:130
- After writing
config.Clito disk, the code never verifies the written file matchesconfig.CliHash. This defeats the purpose of shipping a hash and allows silent corruption (or unexpected reader contents). Compute/compare the SHA-256 while writing (or immediately after), and return an error on mismatch (ideally via an atomic temp-file+rename install).
f, err := os.OpenFile(finalPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
if err != nil {
return "", fmt.Errorf("creating binary file: %w", err)
}
_, err = io.Copy(f, config.Cli)
go/internal/embeddedcli/embeddedcli.go:123
- If
finalPathexists but has the wrong hash,installAtreturns an error and gives up. A previous interrupted install (partial file) would then permanently break embedded CLI usage. Consider a safer install strategy (temp file + rename) and a recovery path for hash mismatches (e.g., delete+reinstall in a trusted per-user dir or surface a clearer remediation).
}
if !bytes.Equal(existingHash, config.CliHash) {
return "", fmt.Errorf("existing binary hash mismatch")
}
return finalPath, nil
go/cmd/bundler/main.go:527
- File handle may be writable as a result of data flow from a call to OpenFile and closing it may result in data loss upon failure, which is not handled explicitly.
outFile.Close()
| // | ||
| // --platform: Target platform using Go conventions (linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64, windows/arm64). Defaults to current platform. | ||
| // --output: Output directory for embedded artifacts. Defaults to the current directory. | ||
| // --cli-version: CLI version to download. If not specified, automatically detects from the copilot-sdk version in go.mod. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there something that forces developers to realise if their local bundled version is out of date?
Cross-SDK Consistency Review: Embedded CLI SupportI've reviewed PR #414 which adds embedded CLI support to the Go SDK. Here's my analysis of consistency across all four SDK implementations: Summary✅ This PR maintains good cross-SDK consistency. All four SDKs now have embedded/bundled CLI support, though with different implementation approaches that are appropriate for each language's ecosystem. Comparison of Embedded CLI Features Across SDKs
Key Observations1. Different but Appropriate ApproachesEach SDK uses an approach that fits its ecosystem:
2. Go's Unique FeaturesThis PR adds capabilities that other SDKs don't have:
Question for consideration: Should these features be added to other SDKs for consistency? Or are they Go-specific optimizations? 3. Configuration Consistency ✅All SDKs follow the same resolution priority:
4. Documentation Consistency ✅The Go README now documents the bundling process similar to other SDKs. However, the workflow differs:
Recommendations
ConclusionThis PR successfully adds embedded CLI support to Go while respecting language-specific conventions. The feature is consistent at the API level (same fallback chain, same config options) while using ecosystem-appropriate implementation patterns. ✅ Great work! 🎉
|
…ithout error handling' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Cross-SDK Consistency ReviewThank you for this PR! I've reviewed the Go SDK's embedded CLI implementation for consistency with the other SDK implementations (Node.js, Python, and .NET). Here are my findings: SummaryThis PR adds embedded CLI support to the Go SDK, which is excellent for feature parity. However, there's a significant difference in user experience compared to the other three SDKs that should be considered. Current State Across SDKs
Key InconsistencyOther SDKs: The CLI is automatically bundled when the SDK package is installed/published. Users get the embedded CLI "out of the box" with zero configuration. Go SDK (this PR): Users must explicitly run a bundler tool ( User Experience ImpactNode.js/Python/.NET Example: // Just works - CLI is already bundled
client := copilot.NewClient(nil)Go SDK (this PR) Example: # Extra steps required before this works:
go get -tool github.com/github/copilot-sdk/go/cmd/bundler
go tool bundler
# Then in code:
embeddedcli.Setup(embeddedcli.Config{...}) // Must configure
client := copilot.NewClient(nil)Suggestions for Better ConsistencyTo align with other SDKs, consider one of these approaches:
API Consistency NotesThe PR does maintain good API-level consistency: ✅ RecommendationConsider whether requiring a manual bundler step aligns with the SDK's goal of feature parity and consistent user experience. If this approach is intentional for Go's ecosystem (e.g., to keep module size small), I'd suggest:
Overall, this is solid work! The implementation quality is high—this feedback is purely about user experience consistency across language SDKs.
|
| 1. Run `go get -tool github.com/github/copilot-sdk/go/cmd/bundler`. This is a one-time setup step per project. | ||
| 2. Run `go tool bundler` in your build environment just before building your application. | ||
|
|
||
| That's it! When your application calls `copilot.NewClient` without a `CLIPath` nor the `COPILOT_CLI_PATH` environment variable, the SDK will automatically install the embedded CLI to a cache directory and use it for all operations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cross-SDK consistency note: Consider adding a comparison section here explaining why Go requires manual bundling while Node.js, Python, and .NET SDKs have the CLI automatically bundled.
For example:
> **Note**: Unlike the Node.js, Python, and .NET SDKs where the CLI is automatically bundled with the package, the Go SDK requires you to explicitly run the bundler tool. This keeps the Go module size small and gives you control over which CLI version to embed.This would help users understand the different approach and set appropriate expectations.
AI generated by SDK Consistency Review Agent for #414
|
|
||
| // Setup sets the embedded GitHub Copilot CLI install configuration. | ||
| // The CLI will be lazily installed when needed. | ||
| func Setup(cfg Config) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API consistency observation: The Setup() function requiring explicit user configuration is different from other SDKs where the bundling is handled automatically at package install time.
Consider whether it would be beneficial to add a note in the godoc explaining this design choice, especially for developers familiar with the other SDK implementations. For example:
// Setup sets the embedded GitHub Copilot CLI install configuration.
// The CLI will be lazily installed when needed.
//
// Note: Unlike the Node.js, Python, and .NET SDKs where the CLI is
// automatically bundled, the Go SDK requires explicit embedding via
// the bundler tool to keep module size minimal.This helps maintain consistency in understanding across the SDK family.
AI generated by SDK Consistency Review Agent for #414
| // If no CLI path is provided, attempt to use the embedded CLI if available | ||
| cliPath = embeddedcli.Path() | ||
| } | ||
| if cliPath == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good consistency: This fallback logic (embedded → "copilot" in PATH) matches the behavior in other SDKs nicely.
However, when the CLI is not found, consider if the error message should mention running go tool bundler to help users who haven't embedded the CLI yet. For comparison:
- Python SDK raises:
"Copilot CLI not found. The bundled CLI binary is not available. Ensure you installed a platform-specific wheel, or provide cli_path." - .NET SDK throws:
"Copilot CLI not found at '{searchedPath}'. Ensure the SDK NuGet package was restored correctly or provide an explicit CliPath."
A similar helpful message for Go might be: "Copilot CLI not found. Run 'go tool bundler' to embed the CLI, ensure 'copilot' is in PATH, or provide CLIPath option."
AI generated by SDK Consistency Review Agent for #414
This pull request introduces support for embedding the GitHub Copilot CLI binary directly within Go applications using the SDK, removing the need for users to have the CLI installed separately. It adds a robust mechanism for embedding, unpacking, and managing the Copilot CLI binary, including versioning, file locking for concurrency, and hash validation. The changes also include comprehensive tests and documentation updates.
The bundling works as follows: