Skip to content

Commit f1d8cc1

Browse files
[go] support bundling and auto installing the GitHub Copilot CLI (#414)
* support bundling and auto installing the GitHub Copilot CLI * fix lint * catch missing errors * copilot feedback * Potential fix for pull request finding 'Writable file handle closed without error handling' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Potential fix for pull request finding 'Writable file handle closed without error handling' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * add --check-only --------- Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
1 parent 4dc5629 commit f1d8cc1

File tree

13 files changed

+1284
-5
lines changed

13 files changed

+1284
-5
lines changed

go/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@ func main() {
6969
}
7070
```
7171

72+
## Distributing your application with an embedded GitHub Copilot CLI
73+
74+
The SDK supports bundling, using Go's `embed` package, the Copilot CLI binary within your application's distribution.
75+
This allows you to bundle a specific CLI version and avoid external dependencies on the user's system.
76+
77+
Follow these steps to embed the CLI:
78+
79+
1. Run `go get -tool github.com/github/copilot-sdk/go/cmd/bundler`. This is a one-time setup step per project.
80+
2. Run `go tool bundler` in your build environment just before building your application.
81+
82+
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.
83+
7284
## API Reference
7385

7486
### Client

go/client.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
"sync"
4343
"time"
4444

45+
"github.com/github/copilot-sdk/go/internal/embeddedcli"
4546
"github.com/github/copilot-sdk/go/internal/jsonrpc2"
4647
)
4748

@@ -102,7 +103,7 @@ type Client struct {
102103
// })
103104
func NewClient(options *ClientOptions) *Client {
104105
opts := ClientOptions{
105-
CLIPath: "copilot",
106+
CLIPath: "",
106107
Cwd: "",
107108
Port: 0,
108109
LogLevel: "info",
@@ -994,6 +995,15 @@ func (c *Client) verifyProtocolVersion(ctx context.Context) error {
994995
// This spawns the CLI server as a subprocess using the configured transport
995996
// mode (stdio or TCP).
996997
func (c *Client) startCLIServer(ctx context.Context) error {
998+
cliPath := c.options.CLIPath
999+
if cliPath == "" {
1000+
// If no CLI path is provided, attempt to use the embedded CLI if available
1001+
cliPath = embeddedcli.Path()
1002+
}
1003+
if cliPath == "" {
1004+
// Default to "copilot" in PATH if no embedded CLI is available and no custom path is set
1005+
cliPath = "copilot"
1006+
}
9971007
args := []string{"--headless", "--no-auto-update", "--log-level", c.options.LogLevel}
9981008

9991009
// Choose transport mode
@@ -1020,10 +1030,10 @@ func (c *Client) startCLIServer(ctx context.Context) error {
10201030

10211031
// If CLIPath is a .js file, run it with node
10221032
// Note we can't rely on the shebang as Windows doesn't support it
1023-
command := c.options.CLIPath
1024-
if strings.HasSuffix(c.options.CLIPath, ".js") {
1033+
command := cliPath
1034+
if strings.HasSuffix(cliPath, ".js") {
10251035
command = "node"
1026-
args = append([]string{c.options.CLIPath}, args...)
1036+
args = append([]string{cliPath}, args...)
10271037
}
10281038

10291039
c.process = exec.CommandContext(ctx, command, args...)

0 commit comments

Comments
 (0)