@ai-sdk/harness-github-copilot 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/dist/index.js +242 -5
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/github-copilot-harness.ts +60 -4
- package/src/github-copilot-subscription.ts +310 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @ai-sdk/harness-github-copilot
|
|
2
2
|
|
|
3
|
+
## 1.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cdc12a1: feat(harness): add support for using adapter-native subscriptions where available
|
|
8
|
+
- Updated dependencies [4d1bf28]
|
|
9
|
+
- Updated dependencies [cdc12a1]
|
|
10
|
+
- Updated dependencies [d70a334]
|
|
11
|
+
- Updated dependencies [81ba84c]
|
|
12
|
+
- Updated dependencies [813bb36]
|
|
13
|
+
- Updated dependencies [c43e4b7]
|
|
14
|
+
- @ai-sdk/harness@1.0.108
|
|
15
|
+
- @ai-sdk/harness-acp@1.0.46
|
|
16
|
+
- @ai-sdk/provider-utils@5.0.40
|
|
17
|
+
|
|
18
|
+
## 1.0.2
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- @ai-sdk/harness@1.0.107
|
|
23
|
+
- @ai-sdk/provider-utils@5.0.39
|
|
24
|
+
- @ai-sdk/harness-acp@1.0.45
|
|
25
|
+
|
|
3
26
|
## 1.0.1
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -38,6 +38,6 @@ try {
|
|
|
38
38
|
|
|
39
39
|
The adapter uses `@ai-sdk/harness-acp`, which installs the pinned GitHub Copilot CLI inside the sandbox. The sandbox must provide network access and at least one exposed TCP port.
|
|
40
40
|
|
|
41
|
-
Set one of `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN` for direct authentication. Set `AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN` to use AI Gateway instead, or pass an isolated authentication environment with `createGitHubCopilot({ auth: { AI_GATEWAY_API_KEY: token } })`.
|
|
41
|
+
Set one of `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN` for direct authentication. Without one of these variables, direct authentication reads the GitHub Copilot CLI login from the host's native credential store or plaintext fallback. If neither contains a token and the host has `gh` on `PATH`, the adapter reads `gh auth token` without modifying either credential store. Set `AI_GATEWAY_API_KEY` or `VERCEL_OIDC_TOKEN` to use AI Gateway instead, or pass an isolated authentication environment with `createGitHubCopilot({ auth: { AI_GATEWAY_API_KEY: token } })`.
|
|
42
42
|
|
|
43
43
|
See the [GitHub Copilot harness documentation](https://ai-sdk.dev/providers/ai-sdk-harnesses/github-copilot) for authentication security, settings, tools, and lifecycle support.
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,224 @@
|
|
|
1
1
|
// src/github-copilot-harness.ts
|
|
2
|
+
import { createHash } from "crypto";
|
|
2
3
|
import {
|
|
3
4
|
commonTool
|
|
4
5
|
} from "@ai-sdk/harness";
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
createCredentialRequestTransformation,
|
|
8
|
+
isSandboxCredentialPlaceholder
|
|
9
|
+
} from "@ai-sdk/harness/utils";
|
|
6
10
|
import { createACP } from "@ai-sdk/harness-acp";
|
|
7
11
|
import { tool } from "@ai-sdk/provider-utils";
|
|
8
12
|
import { z } from "zod/v4";
|
|
9
13
|
|
|
14
|
+
// src/github-copilot-subscription.ts
|
|
15
|
+
import { execFile } from "child_process";
|
|
16
|
+
import { constants } from "fs";
|
|
17
|
+
import { access, readFile } from "fs/promises";
|
|
18
|
+
import { homedir } from "os";
|
|
19
|
+
import { join, resolve } from "path";
|
|
20
|
+
import { promisify } from "util";
|
|
21
|
+
import {
|
|
22
|
+
isHarnessAuthenticationEnvironment,
|
|
23
|
+
isLinux,
|
|
24
|
+
isMacOS,
|
|
25
|
+
isWindows,
|
|
26
|
+
readLinuxSecretServicePassword,
|
|
27
|
+
readMacOSKeychainPassword,
|
|
28
|
+
readWindowsCredentialManagerPassword,
|
|
29
|
+
shouldResolveNativeSubscription
|
|
30
|
+
} from "@ai-sdk/harness/utils";
|
|
31
|
+
import { isRecord } from "@ai-sdk/provider-utils";
|
|
32
|
+
import { parse } from "jsonc-parser";
|
|
33
|
+
var COPILOT_KEYRING_SERVICE = "copilot-cli";
|
|
34
|
+
var execFileAsync = promisify(execFile);
|
|
35
|
+
async function resolveGitHubCopilotSubscriptionEnvironment({
|
|
36
|
+
auth,
|
|
37
|
+
env,
|
|
38
|
+
readSubscription = readGitHubCopilotSubscription
|
|
39
|
+
}) {
|
|
40
|
+
if (isHarnessAuthenticationEnvironment(auth)) return auth;
|
|
41
|
+
if (!shouldResolveNativeSubscription({
|
|
42
|
+
auth,
|
|
43
|
+
env,
|
|
44
|
+
hasDirectCredential: env.COPILOT_GITHUB_TOKEN != null || env.GH_TOKEN != null || env.GITHUB_TOKEN != null
|
|
45
|
+
})) {
|
|
46
|
+
return env;
|
|
47
|
+
}
|
|
48
|
+
const subscription = await readSubscription({ env });
|
|
49
|
+
if (subscription == null) return env;
|
|
50
|
+
return {
|
|
51
|
+
...env,
|
|
52
|
+
COPILOT_GITHUB_TOKEN: subscription.token,
|
|
53
|
+
COPILOT_GH_HOST: normalizeGitHubHost(subscription.host)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function readGitHubCopilotSubscription({
|
|
57
|
+
env = process.env,
|
|
58
|
+
homeDirectory = homedir(),
|
|
59
|
+
platform = process.platform,
|
|
60
|
+
readSecureCredential,
|
|
61
|
+
findGitHubCliExecutable = findHostGitHubCliExecutable,
|
|
62
|
+
readGitHubCliToken = readHostGitHubCliToken
|
|
63
|
+
} = {}) {
|
|
64
|
+
const copilotHome = resolve(
|
|
65
|
+
env.COPILOT_HOME ?? join(homeDirectory, ".copilot")
|
|
66
|
+
);
|
|
67
|
+
const config = await readGitHubCopilotConfig({
|
|
68
|
+
path: join(copilotHome, "config.json")
|
|
69
|
+
});
|
|
70
|
+
const account = selectGitHubCopilotAccount({ config });
|
|
71
|
+
if (account != null) {
|
|
72
|
+
const accountKey = `${account.host}:${account.login}`;
|
|
73
|
+
const secureToken = await (readSecureCredential ?? ((options) => readGitHubCopilotSecureCredential({ ...options, platform })))({
|
|
74
|
+
service: COPILOT_KEYRING_SERVICE,
|
|
75
|
+
account: accountKey
|
|
76
|
+
}).catch(() => void 0);
|
|
77
|
+
if (isNonEmptyString(secureToken)) {
|
|
78
|
+
return { token: secureToken, host: account.host };
|
|
79
|
+
}
|
|
80
|
+
const plaintextToken = getPlaintextToken({ config, accountKey });
|
|
81
|
+
if (plaintextToken != null) {
|
|
82
|
+
return { token: plaintextToken, host: account.host };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const host = account?.host ?? normalizeGitHubOrigin(env.COPILOT_GH_HOST ?? env.GH_HOST ?? "github.com");
|
|
86
|
+
if (host == null) return void 0;
|
|
87
|
+
const executable = await findGitHubCliExecutable({ env, platform });
|
|
88
|
+
if (executable == null) return void 0;
|
|
89
|
+
const token = await readGitHubCliToken({
|
|
90
|
+
executable,
|
|
91
|
+
hostname: normalizeGitHubHost(host),
|
|
92
|
+
env
|
|
93
|
+
}).catch(() => void 0);
|
|
94
|
+
return isNonEmptyString(token) ? { token: token.trim(), host } : void 0;
|
|
95
|
+
}
|
|
96
|
+
async function findHostGitHubCliExecutable({
|
|
97
|
+
env,
|
|
98
|
+
platform
|
|
99
|
+
}) {
|
|
100
|
+
const path = env.PATH ?? env.Path ?? env.path;
|
|
101
|
+
if (path == null) return void 0;
|
|
102
|
+
const separator = isWindows(platform) ? ";" : ":";
|
|
103
|
+
const names = isWindows(platform) ? getWindowsGitHubCliExecutableNames({ pathExt: env.PATHEXT }) : ["gh"];
|
|
104
|
+
const mode = isWindows(platform) ? constants.F_OK : constants.X_OK;
|
|
105
|
+
for (const directory of path.split(separator)) {
|
|
106
|
+
const normalizedDirectory = directory.replace(/^"|"$/g, "");
|
|
107
|
+
if (normalizedDirectory.length === 0) continue;
|
|
108
|
+
for (const executableName of names) {
|
|
109
|
+
const candidate = resolve(normalizedDirectory, executableName);
|
|
110
|
+
try {
|
|
111
|
+
await access(candidate, mode);
|
|
112
|
+
return candidate;
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
async function readGitHubCopilotConfig({
|
|
120
|
+
path
|
|
121
|
+
}) {
|
|
122
|
+
const text = await readFile(path, "utf8").catch(() => void 0);
|
|
123
|
+
if (text == null) return void 0;
|
|
124
|
+
const errors = [];
|
|
125
|
+
const value = parse(text, errors, { allowTrailingComma: true });
|
|
126
|
+
return errors.length === 0 && isRecord(value) ? value : void 0;
|
|
127
|
+
}
|
|
128
|
+
function selectGitHubCopilotAccount({
|
|
129
|
+
config
|
|
130
|
+
}) {
|
|
131
|
+
if (config == null) return void 0;
|
|
132
|
+
for (const value of [config.last_logged_in_user, config.lastLoggedInUser]) {
|
|
133
|
+
const account = toGitHubCopilotAccount(value);
|
|
134
|
+
if (account != null) return account;
|
|
135
|
+
}
|
|
136
|
+
for (const values of [config.logged_in_users, config.loggedInUsers]) {
|
|
137
|
+
if (!Array.isArray(values)) continue;
|
|
138
|
+
for (const value of values) {
|
|
139
|
+
const account = toGitHubCopilotAccount(value);
|
|
140
|
+
if (account != null) return account;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
function toGitHubCopilotAccount(value) {
|
|
146
|
+
if (!isRecord(value) || !isNonEmptyString(value.host) || !isNonEmptyString(value.login)) {
|
|
147
|
+
return void 0;
|
|
148
|
+
}
|
|
149
|
+
const host = normalizeGitHubOrigin(value.host);
|
|
150
|
+
return host == null ? void 0 : { host, login: value.login };
|
|
151
|
+
}
|
|
152
|
+
function getPlaintextToken({
|
|
153
|
+
config,
|
|
154
|
+
accountKey
|
|
155
|
+
}) {
|
|
156
|
+
if (config == null || !isRecord(config.copilotTokens)) return void 0;
|
|
157
|
+
const token = config.copilotTokens[accountKey];
|
|
158
|
+
return isNonEmptyString(token) ? token : void 0;
|
|
159
|
+
}
|
|
160
|
+
async function readGitHubCopilotSecureCredential({
|
|
161
|
+
service,
|
|
162
|
+
account,
|
|
163
|
+
platform
|
|
164
|
+
}) {
|
|
165
|
+
if (isMacOS(platform)) {
|
|
166
|
+
return readMacOSKeychainPassword({ service, account });
|
|
167
|
+
}
|
|
168
|
+
if (isLinux(platform)) {
|
|
169
|
+
return readLinuxSecretServicePassword({
|
|
170
|
+
attributes: { service, username: account }
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (isWindows(platform)) {
|
|
174
|
+
return readWindowsCredentialManagerPassword({
|
|
175
|
+
targetName: `${account}.${service}`
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return void 0;
|
|
179
|
+
}
|
|
180
|
+
async function readHostGitHubCliToken({
|
|
181
|
+
executable,
|
|
182
|
+
hostname,
|
|
183
|
+
env
|
|
184
|
+
}) {
|
|
185
|
+
try {
|
|
186
|
+
const result = await execFileAsync(
|
|
187
|
+
executable,
|
|
188
|
+
["auth", "token", "--hostname", hostname],
|
|
189
|
+
{
|
|
190
|
+
env: { ...env },
|
|
191
|
+
timeout: 1e4,
|
|
192
|
+
windowsHide: true
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
return isNonEmptyString(result.stdout) ? result.stdout.trim() : void 0;
|
|
196
|
+
} catch {
|
|
197
|
+
return void 0;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function getWindowsGitHubCliExecutableNames({
|
|
201
|
+
pathExt
|
|
202
|
+
}) {
|
|
203
|
+
const extensions = (pathExt ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(isNonEmptyString);
|
|
204
|
+
return ["gh", ...extensions.map((extension) => `gh${extension}`)];
|
|
205
|
+
}
|
|
206
|
+
function normalizeGitHubOrigin(host) {
|
|
207
|
+
try {
|
|
208
|
+
return new URL(host.includes("://") ? host : `https://${host}`).origin;
|
|
209
|
+
} catch {
|
|
210
|
+
return void 0;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function normalizeGitHubHost(host) {
|
|
214
|
+
return new URL(host.includes("://") ? host : `https://${host}`).hostname;
|
|
215
|
+
}
|
|
216
|
+
function isNonEmptyString(value) {
|
|
217
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
10
220
|
// src/version.ts
|
|
11
|
-
var VERSION = true ? "1.0.
|
|
221
|
+
var VERSION = true ? "1.0.3" : "0.0.0-test";
|
|
12
222
|
|
|
13
223
|
// src/github-copilot-harness.ts
|
|
14
224
|
var GITHUB_COPILOT_CLIENT_APP = {
|
|
@@ -18,6 +228,13 @@ var GITHUB_COPILOT_CLIENT_APP = {
|
|
|
18
228
|
var GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON = '{\n "name": "harness-github-copilot-bridge",\n "version": "0.0.0",\n "private": true,\n "type": "module",\n "dependencies": {\n "@github/copilot": "1.0.82"\n }\n}\n';
|
|
19
229
|
var GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK = "lockfileVersion: '9.0'\n\nsettings:\n autoInstallPeers: true\n excludeLinksFromLockfile: false\n\nimporters:\n\n .:\n dependencies:\n '@github/copilot':\n specifier: 1.0.82\n version: 1.0.82\n\npackages:\n\n '@github/copilot-darwin-arm64@1.0.82':\n resolution: {integrity: sha512-UpVSFA0COmlIakAr7/6WJqJlabtKgY8y5en6La3IxGxXsLlbkGoeevSqyfXvqJyHxaGn0YGpOC1oEPL379JfCw==}\n cpu: [arm64]\n os: [darwin]\n hasBin: true\n\n '@github/copilot-darwin-x64@1.0.82':\n resolution: {integrity: sha512-wMKbxK8fpKsbATjn9dE31Pae67H1xu6dmaCuyXpXjXLsNPVjeLFszJZ30MAOwxRWz4dmA8VvEJZmLgJekojo2Q==}\n cpu: [x64]\n os: [darwin]\n hasBin: true\n\n '@github/copilot-linux-arm64@1.0.82':\n resolution: {integrity: sha512-YDQmh0F+GzWORPmNNxQdcjHcXHxcy08dhMhbAhu4cqtMeA2sZWQqhfk9mJhHppMm9U0uR7h0KAB6nsgw/8Bsuw==}\n cpu: [arm64]\n os: [linux]\n libc: [glibc]\n hasBin: true\n\n '@github/copilot-linux-x64@1.0.82':\n resolution: {integrity: sha512-vqmG9665ktgLHAkGKMjp4uVMdHqLxi8uS9zL+g2pMwZUPoM7JxkaSfOoeyYr99caF7J6VIJTWv4LdRNQyG5jrQ==}\n cpu: [x64]\n os: [linux]\n libc: [glibc]\n hasBin: true\n\n '@github/copilot-linuxmusl-arm64@1.0.82':\n resolution: {integrity: sha512-14dWfa4rBME55bKmF+Z8V+WzZNgPQZKFFBQX+EOiAgLVV/arQCnQ1m7wwa5oXjQeCIgkS/L9J8uM8jNm6cZbOA==}\n cpu: [arm64]\n os: [linux]\n libc: [musl]\n hasBin: true\n\n '@github/copilot-linuxmusl-x64@1.0.82':\n resolution: {integrity: sha512-Mauqa2TBjtB8W/1KXF/jJ4MbtwnLvoEQNHYoSyoX+s+nIpttmixmYBJDwKV89ZlQRdjOCuxOgraRLQ9hjjXvNQ==}\n cpu: [x64]\n os: [linux]\n libc: [musl]\n hasBin: true\n\n '@github/copilot-win32-arm64@1.0.82':\n resolution: {integrity: sha512-PaW9s0GTgM+svtDkB583dZRrhLrO4o10y2ozMmQ0Hi5eB11C24UdC5U81nFlvKPED7+GlnBJIFQ+oHaxHrnp3A==}\n cpu: [arm64]\n os: [win32]\n hasBin: true\n\n '@github/copilot-win32-x64@1.0.82':\n resolution: {integrity: sha512-m4iSROOMEPp1yRIQQwbnO0CDfwB4syESyHoeSLLFuynMR4/ApghAdyBrBQQcTKGsUu3R5rOE64RYlVmyKmuA9A==}\n cpu: [x64]\n os: [win32]\n hasBin: true\n\n '@github/copilot@1.0.82':\n resolution: {integrity: sha512-+mDIwBO3dCpL3k2rVLc4+1tFzqcVBTJNA/0co+okEpmCgcHjaz91Cqq7++pJKN5yJQuGC6bKangm7PSoheI1Xw==}\n hasBin: true\n\n detect-libc@2.1.2:\n resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}\n engines: {node: '>=8'}\n\nsnapshots:\n\n '@github/copilot-darwin-arm64@1.0.82':\n optional: true\n\n '@github/copilot-darwin-x64@1.0.82':\n optional: true\n\n '@github/copilot-linux-arm64@1.0.82':\n optional: true\n\n '@github/copilot-linux-x64@1.0.82':\n optional: true\n\n '@github/copilot-linuxmusl-arm64@1.0.82':\n optional: true\n\n '@github/copilot-linuxmusl-x64@1.0.82':\n optional: true\n\n '@github/copilot-win32-arm64@1.0.82':\n optional: true\n\n '@github/copilot-win32-x64@1.0.82':\n optional: true\n\n '@github/copilot@1.0.82':\n dependencies:\n detect-libc: 2.1.2\n optionalDependencies:\n '@github/copilot-darwin-arm64': 1.0.82\n '@github/copilot-darwin-x64': 1.0.82\n '@github/copilot-linux-arm64': 1.0.82\n '@github/copilot-linux-x64': 1.0.82\n '@github/copilot-linuxmusl-arm64': 1.0.82\n '@github/copilot-linuxmusl-x64': 1.0.82\n '@github/copilot-win32-arm64': 1.0.82\n '@github/copilot-win32-x64': 1.0.82\n\n detect-libc@2.1.2: {}\n";
|
|
20
230
|
var GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE = "allowBuilds:\n '@github/copilot@1.0.82': true\n";
|
|
231
|
+
var GITHUB_COPILOT_TOKEN_ENVIRONMENT_VARIABLES = /* @__PURE__ */ new Set([
|
|
232
|
+
"COPILOT_GITHUB_TOKEN",
|
|
233
|
+
"GH_TOKEN",
|
|
234
|
+
"GITHUB_TOKEN"
|
|
235
|
+
]);
|
|
236
|
+
var GITHUB_OAUTH_TOKEN_BODY_LENGTH = 36;
|
|
237
|
+
var GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER = "aisdkhc";
|
|
21
238
|
var GITHUB_COPILOT_BUILTIN_TOOLS = {
|
|
22
239
|
bash: {
|
|
23
240
|
...commonTool("bash", {
|
|
@@ -216,6 +433,7 @@ function createGitHubCopilot(settings = {}) {
|
|
|
216
433
|
...settings.reasoningEffort == null ? [] : [`--reasoning-effort=${settings.reasoningEffort}`]
|
|
217
434
|
],
|
|
218
435
|
auth: settings.auth,
|
|
436
|
+
resolveAuthenticationEnvironment: resolveGitHubCopilotSubscriptionEnvironment,
|
|
219
437
|
/*
|
|
220
438
|
* The Copilot CLI drops every MCP server that a client passes in ACP
|
|
221
439
|
* `session/new` unless it is declared with the `http` or `sse` transport,
|
|
@@ -367,7 +585,9 @@ function createGitHubCopilot(settings = {}) {
|
|
|
367
585
|
}
|
|
368
586
|
return transformations;
|
|
369
587
|
},
|
|
370
|
-
credentialForwarding:
|
|
588
|
+
credentialForwarding: createGitHubCopilotCredentialForwarding({
|
|
589
|
+
credentialForwarding: settings.credentialForwarding
|
|
590
|
+
}),
|
|
371
591
|
providerAuthentication: {
|
|
372
592
|
gateway: {
|
|
373
593
|
env: {
|
|
@@ -406,8 +626,25 @@ function createGitHubCopilot(settings = {}) {
|
|
|
406
626
|
mintBridgeToken: settings.mintBridgeToken
|
|
407
627
|
});
|
|
408
628
|
}
|
|
409
|
-
function
|
|
410
|
-
|
|
629
|
+
function createGitHubCopilotCredentialForwarding({
|
|
630
|
+
credentialForwarding
|
|
631
|
+
}) {
|
|
632
|
+
return ({ credential, environmentVariableName }) => {
|
|
633
|
+
const sandboxCredential = GITHUB_COPILOT_TOKEN_ENVIRONMENT_VARIABLES.has(environmentVariableName) && isSandboxCredentialPlaceholder(credential) ? createGitHubOAuthSandboxCredentialPlaceholder({ credential }) : credential;
|
|
634
|
+
return credentialForwarding == null ? sandboxCredential : credentialForwarding({
|
|
635
|
+
credential: sandboxCredential,
|
|
636
|
+
environmentVariableName
|
|
637
|
+
});
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function createGitHubOAuthSandboxCredentialPlaceholder({
|
|
641
|
+
credential
|
|
642
|
+
}) {
|
|
643
|
+
const tokenBody = createHash("sha256").update(credential).digest("hex").slice(
|
|
644
|
+
0,
|
|
645
|
+
GITHUB_OAUTH_TOKEN_BODY_LENGTH - GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER.length
|
|
646
|
+
);
|
|
647
|
+
return `gho_${GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER}${tokenBody}`;
|
|
411
648
|
}
|
|
412
649
|
|
|
413
650
|
// src/index.ts
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/github-copilot-harness.ts","../src/version.ts","../src/index.ts"],"sourcesContent":["import {\n commonTool,\n type HarnessV1,\n type HarnessV1BuiltinTool,\n type HarnessV1CredentialForwarding,\n type HarnessV1PortEndpoint,\n type HarnessV1RequestTransformation,\n} from '@ai-sdk/harness';\nimport { createCredentialRequestTransformation } from '@ai-sdk/harness/utils';\nimport { createACP, type ACPAuthenticationMode } from '@ai-sdk/harness-acp';\nimport { tool } from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport { VERSION } from './version';\n\ndeclare const __GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON__: string;\ndeclare const __GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK_YAML__: string;\ndeclare const __GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE_YAML__: string;\n\nconst GITHUB_COPILOT_CLIENT_APP = {\n name: 'ai-sdk/harness-github-copilot',\n version: VERSION,\n} as const;\nconst GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON =\n __GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON__;\nconst GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK =\n __GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK_YAML__;\nconst GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE =\n __GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE_YAML__;\n\nexport type GitHubCopilotAuthenticationMode = ACPAuthenticationMode;\n\nexport type GitHubCopilotHarnessSettings = {\n readonly auth?: GitHubCopilotAuthenticationMode;\n readonly credentialForwarding?: HarnessV1CredentialForwarding;\n readonly reasoningEffort?:\n | 'none'\n | 'minimal'\n | 'low'\n | 'medium'\n | 'high'\n | 'xhigh'\n | 'max';\n readonly mcpServers?: Record<string, unknown>;\n readonly port?: number;\n readonly portEndpoint?: HarnessV1PortEndpoint;\n readonly startupTimeoutMs?: number;\n readonly mintBridgeToken?: (sandboxId: string) => string;\n};\n\n/*\n * This catalog reflects the stable, non-MCP tool surface emitted by GitHub\n * Copilot CLI 1.0.82. Loose object schemas preserve compatibility when the\n * CLI adds fields without changing the established inputs.\n */\nconst GITHUB_COPILOT_BUILTIN_TOOLS = {\n bash: {\n ...commonTool('bash', {\n nativeName: 'bash',\n toolUseKind: 'bash',\n inputSchema: z.looseObject({\n command: z.string(),\n description: z.string().optional(),\n shellId: z.string().optional(),\n mode: z.enum(['sync', 'async']).optional(),\n detach: z.boolean().optional(),\n initial_wait: z.number().optional(),\n }),\n }),\n },\n read_bash: {\n ...tool({\n title: 'Reading shell output',\n inputSchema: z.looseObject({\n shellId: z.string(),\n delay: z.number(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n stop_bash: {\n ...tool({\n title: 'Stopping shell session',\n inputSchema: z.looseObject({ shellId: z.string() }),\n }),\n toolUseKind: 'bash',\n },\n list_bash: {\n ...tool({\n title: 'list_bash',\n inputSchema: z.looseObject({}),\n }),\n toolUseKind: 'readonly',\n },\n view: {\n ...tool({\n title: 'Viewing ',\n inputSchema: z.looseObject({\n path: z.string(),\n view_range: z.array(z.number()).optional(),\n forceReadLargeFiles: z.boolean().optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n create: {\n ...tool({\n title: 'Creating ',\n inputSchema: z.looseObject({\n path: z.string(),\n file_text: z.string(),\n }),\n }),\n toolUseKind: 'edit',\n },\n edit: {\n ...tool({\n title: 'Editing ',\n inputSchema: z.looseObject({\n path: z.string(),\n old_str: z.string().optional(),\n new_str: z.string(),\n }),\n }),\n toolUseKind: 'edit',\n },\n web_fetch: {\n ...tool({\n title: 'Fetching ',\n inputSchema: z.looseObject({\n url: z.string(),\n max_length: z.number().optional(),\n start_index: z.number().optional(),\n raw: z.boolean().optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n skill: tool({\n title: 'Using skill: ',\n inputSchema: z.looseObject({ skill: z.string() }),\n }),\n sql: tool({\n inputSchema: z.looseObject({\n description: z.string(),\n query: z.string(),\n database: z.enum(['session', 'session_store']).optional(),\n }),\n }),\n read_agent: {\n ...tool({\n title: 'read_agent',\n inputSchema: z.looseObject({\n agent_id: z.string(),\n wait: z.boolean().optional(),\n timeout: z.number().optional(),\n since_turn: z.number().int().nonnegative().optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n list_agents: {\n ...tool({\n title: 'list_agents',\n inputSchema: z.looseObject({\n include_completed: z.boolean().optional(),\n scope: z.enum(['siblings', 'children', 'all']).optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n write_agent: tool({\n title: 'write_agent',\n inputSchema: z.looseObject({\n message: z.string(),\n agent_id: z.string().optional(),\n agent_ids: z.array(z.string()).optional(),\n scope: z.enum(['siblings', 'children']).optional(),\n }),\n }),\n grep: {\n ...commonTool('grep', {\n nativeName: 'grep',\n toolUseKind: 'readonly',\n inputSchema: z.looseObject({\n pattern: z.string(),\n path: z.string().optional(),\n paths: z.array(z.string()).optional(),\n glob: z.string().optional(),\n output_mode: z\n .enum(['content', 'files_with_matches', 'count'])\n .optional(),\n case_insensitive: z.boolean().optional(),\n multiline: z.boolean().optional(),\n head_limit: z.number().optional(),\n context: z.number().optional(),\n before_context: z.number().optional(),\n after_context: z.number().optional(),\n }),\n }),\n title: 'Searching for ',\n },\n glob: {\n ...commonTool('glob', {\n nativeName: 'glob',\n toolUseKind: 'readonly',\n inputSchema: z.looseObject({\n pattern: z.string(),\n paths: z.array(z.string()).optional(),\n }),\n }),\n title: 'Finding files matching ',\n },\n task: tool({\n inputSchema: z.looseObject({\n name: z.string(),\n prompt: z.string(),\n agent_type: z.enum([\n 'explore',\n 'task',\n 'general-purpose',\n 'code-review',\n 'research',\n 'security-review',\n ]),\n description: z.string(),\n model: z.string().optional(),\n context_tier: z.enum(['default', 'long_context']).optional(),\n mode: z.enum(['sync', 'background']).optional(),\n }),\n }),\n} as const satisfies Record<string, HarnessV1BuiltinTool<any, any>>;\n\nexport type GitHubCopilotBuiltinTools = typeof GITHUB_COPILOT_BUILTIN_TOOLS;\n\nexport function createGitHubCopilot(\n settings: GitHubCopilotHarnessSettings = {},\n): HarnessV1<GitHubCopilotBuiltinTools> {\n const mcpToolTitlePrefixes = [\n 'github-mcp-server-',\n ...Object.keys(settings.mcpServers ?? {}).map(name => `${name}-`),\n ];\n\n return createACP({\n version: 'v1',\n harnessId: 'github-copilot',\n clientApp: GITHUB_COPILOT_CLIENT_APP,\n source: {\n type: 'npm-locked',\n packageJson: GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON,\n pnpmLockYaml: GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK,\n pnpmWorkspaceYaml: GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE,\n },\n executable: 'copilot',\n args: [\n '--acp',\n '--stdio',\n '--no-auto-update',\n ...(settings.reasoningEffort == null\n ? []\n : [`--reasoning-effort=${settings.reasoningEffort}`]),\n ],\n auth: settings.auth,\n /*\n * The Copilot CLI drops every MCP server that a client passes in ACP\n * `session/new` unless it is declared with the `http` or `sse` transport,\n * so host tools must be exposed over the bridge's HTTP MCP endpoint.\n */\n hostToolMcpTransport: 'http',\n forwardEnv: ['COPILOT_GH_HOST', 'GH_HOST'],\n credentialEnv: ['COPILOT_GITHUB_TOKEN', 'GH_TOKEN', 'GITHUB_TOKEN'],\n credentialBrokering: ({ env, sandboxEnv, headers }) => {\n const transformations: HarnessV1RequestTransformation[] = [];\n const githubHost = normalizeGitHubHost(\n env.COPILOT_GH_HOST ?? env.GH_HOST ?? 'github.com',\n );\n const githubHosts = [\n githubHost,\n `*.${githubHost}`,\n ...(githubHost === 'github.com'\n ? ['githubcopilot.com', '*.githubcopilot.com']\n : []),\n ];\n\n for (const host of githubHosts) {\n if (env.COPILOT_GITHUB_TOKEN && sandboxEnv?.COPILOT_GITHUB_TOKEN) {\n transformations.push(\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: {\n exact: `Bearer ${sandboxEnv.COPILOT_GITHUB_TOKEN}`,\n },\n },\n ],\n },\n transform: {\n headers: {\n Authorization: `Bearer ${env.COPILOT_GITHUB_TOKEN}`,\n },\n },\n },\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: {\n exact: `token ${sandboxEnv.COPILOT_GITHUB_TOKEN}`,\n },\n },\n ],\n },\n transform: {\n headers: {\n Authorization: `token ${env.COPILOT_GITHUB_TOKEN}`,\n },\n },\n },\n );\n }\n\n if (env.GH_TOKEN && sandboxEnv?.GH_TOKEN) {\n transformations.push(\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `Bearer ${sandboxEnv.GH_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `Bearer ${env.GH_TOKEN}` },\n },\n },\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `token ${sandboxEnv.GH_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `token ${env.GH_TOKEN}` },\n },\n },\n );\n }\n\n if (env.GITHUB_TOKEN && sandboxEnv?.GITHUB_TOKEN) {\n transformations.push(\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `Bearer ${sandboxEnv.GITHUB_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}` },\n },\n },\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `token ${sandboxEnv.GITHUB_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `token ${env.GITHUB_TOKEN}` },\n },\n },\n );\n }\n }\n\n const providerCredential = env.COPILOT_PROVIDER_API_KEY;\n const sandboxProviderCredential = sandboxEnv?.COPILOT_PROVIDER_API_KEY;\n const providerBaseUrl = env.COPILOT_PROVIDER_BASE_URL;\n if (providerCredential && sandboxProviderCredential && providerBaseUrl) {\n transformations.push(\n createCredentialRequestTransformation({\n matchUrl: providerBaseUrl,\n matchHeaders: {\n Authorization: `Bearer ${sandboxProviderCredential}`,\n },\n transformHeaders: {\n ...headers,\n Authorization: `Bearer ${providerCredential}`,\n },\n }),\n );\n } else if (headers != null) {\n const copilotHosts =\n githubHost === 'github.com'\n ? ['githubcopilot.com', '*.githubcopilot.com']\n : [githubHost, `*.${githubHost}`];\n for (const host of copilotHosts) {\n transformations.push({\n match: { host },\n transform: { headers },\n });\n }\n }\n\n return transformations;\n },\n credentialForwarding: settings.credentialForwarding,\n providerAuthentication: {\n gateway: {\n env: {\n COPILOT_PROVIDER_BASE_URL: {\n $source: 'gateway-base-url',\n ensureSuffix: '/v1',\n },\n COPILOT_PROVIDER_TYPE: 'openai',\n COPILOT_PROVIDER_API_KEY: {\n $source: 'gateway-api-key',\n },\n COPILOT_PROVIDER_WIRE_API: 'responses',\n COPILOT_MODEL: 'openai/gpt-5.5',\n COPILOT_PROVIDER_HEADERS: {\n $source: 'client-app',\n prefix: 'x-client-app: ',\n },\n },\n },\n },\n modelMapping: {\n type: 'session-config-option',\n path: 'model',\n },\n skillsDirectory: '.copilot/skills',\n instructionMapping: {\n type: 'filesystem',\n path: '.copilot/copilot-instructions.md',\n },\n builtinTools: GITHUB_COPILOT_BUILTIN_TOOLS,\n mcpServers: settings.mcpServers,\n isMcpToolCall: toolCall =>\n mcpToolTitlePrefixes.some(prefix => toolCall.title.startsWith(prefix)),\n port: settings.port,\n portEndpoint: settings.portEndpoint,\n startupTimeoutMs: settings.startupTimeoutMs,\n mintBridgeToken: settings.mintBridgeToken,\n });\n}\n\nfunction normalizeGitHubHost(host: string): string {\n return new URL(host.includes('://') ? host : `https://${host}`).hostname;\n}\n","declare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n","import { createGitHubCopilot } from './github-copilot-harness';\n\n/**\n * Default GitHub Copilot harness instance. Equivalent to\n * `createGitHubCopilot()`.\n */\nexport const githubCopilot = createGitHubCopilot();\n\nexport { createGitHubCopilot } from './github-copilot-harness';\nexport type {\n GitHubCopilotAuthenticationMode,\n GitHubCopilotBuiltinTools,\n GitHubCopilotHarnessSettings,\n} from './github-copilot-harness';\nexport { VERSION } from './version';\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/github-copilot-harness.ts","../src/github-copilot-subscription.ts","../src/version.ts","../src/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport {\n commonTool,\n type HarnessV1,\n type HarnessV1BuiltinTool,\n type HarnessV1CredentialForwarding,\n type HarnessV1PortEndpoint,\n type HarnessV1RequestTransformation,\n} from '@ai-sdk/harness';\nimport {\n createCredentialRequestTransformation,\n isSandboxCredentialPlaceholder,\n} from '@ai-sdk/harness/utils';\nimport { createACP, type ACPAuthenticationMode } from '@ai-sdk/harness-acp';\nimport { tool } from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport {\n normalizeGitHubHost,\n resolveGitHubCopilotSubscriptionEnvironment,\n} from './github-copilot-subscription';\nimport { VERSION } from './version';\n\ndeclare const __GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON__: string;\ndeclare const __GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK_YAML__: string;\ndeclare const __GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE_YAML__: string;\n\nconst GITHUB_COPILOT_CLIENT_APP = {\n name: 'ai-sdk/harness-github-copilot',\n version: VERSION,\n} as const;\nconst GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON =\n __GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON__;\nconst GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK =\n __GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK_YAML__;\nconst GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE =\n __GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE_YAML__;\nconst GITHUB_COPILOT_TOKEN_ENVIRONMENT_VARIABLES = new Set([\n 'COPILOT_GITHUB_TOKEN',\n 'GH_TOKEN',\n 'GITHUB_TOKEN',\n]);\nconst GITHUB_OAUTH_TOKEN_BODY_LENGTH = 36;\nconst GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER = 'aisdkhc';\n\nexport type GitHubCopilotAuthenticationMode = ACPAuthenticationMode;\n\nexport type GitHubCopilotHarnessSettings = {\n readonly auth?: GitHubCopilotAuthenticationMode;\n readonly credentialForwarding?: HarnessV1CredentialForwarding;\n readonly reasoningEffort?:\n | 'none'\n | 'minimal'\n | 'low'\n | 'medium'\n | 'high'\n | 'xhigh'\n | 'max';\n readonly mcpServers?: Record<string, unknown>;\n readonly port?: number;\n readonly portEndpoint?: HarnessV1PortEndpoint;\n readonly startupTimeoutMs?: number;\n readonly mintBridgeToken?: (sandboxId: string) => string;\n};\n\n/*\n * This catalog reflects the stable, non-MCP tool surface emitted by GitHub\n * Copilot CLI 1.0.82. Loose object schemas preserve compatibility when the\n * CLI adds fields without changing the established inputs.\n */\nconst GITHUB_COPILOT_BUILTIN_TOOLS = {\n bash: {\n ...commonTool('bash', {\n nativeName: 'bash',\n toolUseKind: 'bash',\n inputSchema: z.looseObject({\n command: z.string(),\n description: z.string().optional(),\n shellId: z.string().optional(),\n mode: z.enum(['sync', 'async']).optional(),\n detach: z.boolean().optional(),\n initial_wait: z.number().optional(),\n }),\n }),\n },\n read_bash: {\n ...tool({\n title: 'Reading shell output',\n inputSchema: z.looseObject({\n shellId: z.string(),\n delay: z.number(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n stop_bash: {\n ...tool({\n title: 'Stopping shell session',\n inputSchema: z.looseObject({ shellId: z.string() }),\n }),\n toolUseKind: 'bash',\n },\n list_bash: {\n ...tool({\n title: 'list_bash',\n inputSchema: z.looseObject({}),\n }),\n toolUseKind: 'readonly',\n },\n view: {\n ...tool({\n title: 'Viewing ',\n inputSchema: z.looseObject({\n path: z.string(),\n view_range: z.array(z.number()).optional(),\n forceReadLargeFiles: z.boolean().optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n create: {\n ...tool({\n title: 'Creating ',\n inputSchema: z.looseObject({\n path: z.string(),\n file_text: z.string(),\n }),\n }),\n toolUseKind: 'edit',\n },\n edit: {\n ...tool({\n title: 'Editing ',\n inputSchema: z.looseObject({\n path: z.string(),\n old_str: z.string().optional(),\n new_str: z.string(),\n }),\n }),\n toolUseKind: 'edit',\n },\n web_fetch: {\n ...tool({\n title: 'Fetching ',\n inputSchema: z.looseObject({\n url: z.string(),\n max_length: z.number().optional(),\n start_index: z.number().optional(),\n raw: z.boolean().optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n skill: tool({\n title: 'Using skill: ',\n inputSchema: z.looseObject({ skill: z.string() }),\n }),\n sql: tool({\n inputSchema: z.looseObject({\n description: z.string(),\n query: z.string(),\n database: z.enum(['session', 'session_store']).optional(),\n }),\n }),\n read_agent: {\n ...tool({\n title: 'read_agent',\n inputSchema: z.looseObject({\n agent_id: z.string(),\n wait: z.boolean().optional(),\n timeout: z.number().optional(),\n since_turn: z.number().int().nonnegative().optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n list_agents: {\n ...tool({\n title: 'list_agents',\n inputSchema: z.looseObject({\n include_completed: z.boolean().optional(),\n scope: z.enum(['siblings', 'children', 'all']).optional(),\n }),\n }),\n toolUseKind: 'readonly',\n },\n write_agent: tool({\n title: 'write_agent',\n inputSchema: z.looseObject({\n message: z.string(),\n agent_id: z.string().optional(),\n agent_ids: z.array(z.string()).optional(),\n scope: z.enum(['siblings', 'children']).optional(),\n }),\n }),\n grep: {\n ...commonTool('grep', {\n nativeName: 'grep',\n toolUseKind: 'readonly',\n inputSchema: z.looseObject({\n pattern: z.string(),\n path: z.string().optional(),\n paths: z.array(z.string()).optional(),\n glob: z.string().optional(),\n output_mode: z\n .enum(['content', 'files_with_matches', 'count'])\n .optional(),\n case_insensitive: z.boolean().optional(),\n multiline: z.boolean().optional(),\n head_limit: z.number().optional(),\n context: z.number().optional(),\n before_context: z.number().optional(),\n after_context: z.number().optional(),\n }),\n }),\n title: 'Searching for ',\n },\n glob: {\n ...commonTool('glob', {\n nativeName: 'glob',\n toolUseKind: 'readonly',\n inputSchema: z.looseObject({\n pattern: z.string(),\n paths: z.array(z.string()).optional(),\n }),\n }),\n title: 'Finding files matching ',\n },\n task: tool({\n inputSchema: z.looseObject({\n name: z.string(),\n prompt: z.string(),\n agent_type: z.enum([\n 'explore',\n 'task',\n 'general-purpose',\n 'code-review',\n 'research',\n 'security-review',\n ]),\n description: z.string(),\n model: z.string().optional(),\n context_tier: z.enum(['default', 'long_context']).optional(),\n mode: z.enum(['sync', 'background']).optional(),\n }),\n }),\n} as const satisfies Record<string, HarnessV1BuiltinTool<any, any>>;\n\nexport type GitHubCopilotBuiltinTools = typeof GITHUB_COPILOT_BUILTIN_TOOLS;\n\nexport function createGitHubCopilot(\n settings: GitHubCopilotHarnessSettings = {},\n): HarnessV1<GitHubCopilotBuiltinTools> {\n const mcpToolTitlePrefixes = [\n 'github-mcp-server-',\n ...Object.keys(settings.mcpServers ?? {}).map(name => `${name}-`),\n ];\n\n return createACP({\n version: 'v1',\n harnessId: 'github-copilot',\n clientApp: GITHUB_COPILOT_CLIENT_APP,\n source: {\n type: 'npm-locked',\n packageJson: GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON,\n pnpmLockYaml: GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK,\n pnpmWorkspaceYaml: GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE,\n },\n executable: 'copilot',\n args: [\n '--acp',\n '--stdio',\n '--no-auto-update',\n ...(settings.reasoningEffort == null\n ? []\n : [`--reasoning-effort=${settings.reasoningEffort}`]),\n ],\n auth: settings.auth,\n resolveAuthenticationEnvironment:\n resolveGitHubCopilotSubscriptionEnvironment,\n /*\n * The Copilot CLI drops every MCP server that a client passes in ACP\n * `session/new` unless it is declared with the `http` or `sse` transport,\n * so host tools must be exposed over the bridge's HTTP MCP endpoint.\n */\n hostToolMcpTransport: 'http',\n forwardEnv: ['COPILOT_GH_HOST', 'GH_HOST'],\n credentialEnv: ['COPILOT_GITHUB_TOKEN', 'GH_TOKEN', 'GITHUB_TOKEN'],\n credentialBrokering: ({ env, sandboxEnv, headers }) => {\n const transformations: HarnessV1RequestTransformation[] = [];\n const githubHost = normalizeGitHubHost(\n env.COPILOT_GH_HOST ?? env.GH_HOST ?? 'github.com',\n );\n const githubHosts = [\n githubHost,\n `*.${githubHost}`,\n ...(githubHost === 'github.com'\n ? ['githubcopilot.com', '*.githubcopilot.com']\n : []),\n ];\n\n for (const host of githubHosts) {\n if (env.COPILOT_GITHUB_TOKEN && sandboxEnv?.COPILOT_GITHUB_TOKEN) {\n transformations.push(\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: {\n exact: `Bearer ${sandboxEnv.COPILOT_GITHUB_TOKEN}`,\n },\n },\n ],\n },\n transform: {\n headers: {\n Authorization: `Bearer ${env.COPILOT_GITHUB_TOKEN}`,\n },\n },\n },\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: {\n exact: `token ${sandboxEnv.COPILOT_GITHUB_TOKEN}`,\n },\n },\n ],\n },\n transform: {\n headers: {\n Authorization: `token ${env.COPILOT_GITHUB_TOKEN}`,\n },\n },\n },\n );\n }\n\n if (env.GH_TOKEN && sandboxEnv?.GH_TOKEN) {\n transformations.push(\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `Bearer ${sandboxEnv.GH_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `Bearer ${env.GH_TOKEN}` },\n },\n },\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `token ${sandboxEnv.GH_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `token ${env.GH_TOKEN}` },\n },\n },\n );\n }\n\n if (env.GITHUB_TOKEN && sandboxEnv?.GITHUB_TOKEN) {\n transformations.push(\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `Bearer ${sandboxEnv.GITHUB_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}` },\n },\n },\n {\n match: {\n host,\n headers: [\n {\n key: { exact: 'Authorization' },\n value: { exact: `token ${sandboxEnv.GITHUB_TOKEN}` },\n },\n ],\n },\n transform: {\n headers: { Authorization: `token ${env.GITHUB_TOKEN}` },\n },\n },\n );\n }\n }\n\n const providerCredential = env.COPILOT_PROVIDER_API_KEY;\n const sandboxProviderCredential = sandboxEnv?.COPILOT_PROVIDER_API_KEY;\n const providerBaseUrl = env.COPILOT_PROVIDER_BASE_URL;\n if (providerCredential && sandboxProviderCredential && providerBaseUrl) {\n transformations.push(\n createCredentialRequestTransformation({\n matchUrl: providerBaseUrl,\n matchHeaders: {\n Authorization: `Bearer ${sandboxProviderCredential}`,\n },\n transformHeaders: {\n ...headers,\n Authorization: `Bearer ${providerCredential}`,\n },\n }),\n );\n } else if (headers != null) {\n const copilotHosts =\n githubHost === 'github.com'\n ? ['githubcopilot.com', '*.githubcopilot.com']\n : [githubHost, `*.${githubHost}`];\n for (const host of copilotHosts) {\n transformations.push({\n match: { host },\n transform: { headers },\n });\n }\n }\n\n return transformations;\n },\n credentialForwarding: createGitHubCopilotCredentialForwarding({\n credentialForwarding: settings.credentialForwarding,\n }),\n providerAuthentication: {\n gateway: {\n env: {\n COPILOT_PROVIDER_BASE_URL: {\n $source: 'gateway-base-url',\n ensureSuffix: '/v1',\n },\n COPILOT_PROVIDER_TYPE: 'openai',\n COPILOT_PROVIDER_API_KEY: {\n $source: 'gateway-api-key',\n },\n COPILOT_PROVIDER_WIRE_API: 'responses',\n COPILOT_MODEL: 'openai/gpt-5.5',\n COPILOT_PROVIDER_HEADERS: {\n $source: 'client-app',\n prefix: 'x-client-app: ',\n },\n },\n },\n },\n modelMapping: {\n type: 'session-config-option',\n path: 'model',\n },\n skillsDirectory: '.copilot/skills',\n instructionMapping: {\n type: 'filesystem',\n path: '.copilot/copilot-instructions.md',\n },\n builtinTools: GITHUB_COPILOT_BUILTIN_TOOLS,\n mcpServers: settings.mcpServers,\n isMcpToolCall: toolCall =>\n mcpToolTitlePrefixes.some(prefix => toolCall.title.startsWith(prefix)),\n port: settings.port,\n portEndpoint: settings.portEndpoint,\n startupTimeoutMs: settings.startupTimeoutMs,\n mintBridgeToken: settings.mintBridgeToken,\n });\n}\n\nfunction createGitHubCopilotCredentialForwarding({\n credentialForwarding,\n}: {\n credentialForwarding: HarnessV1CredentialForwarding | undefined;\n}): HarnessV1CredentialForwarding {\n return ({ credential, environmentVariableName }) => {\n const sandboxCredential =\n GITHUB_COPILOT_TOKEN_ENVIRONMENT_VARIABLES.has(environmentVariableName) &&\n isSandboxCredentialPlaceholder(credential)\n ? createGitHubOAuthSandboxCredentialPlaceholder({ credential })\n : credential;\n return credentialForwarding == null\n ? sandboxCredential\n : credentialForwarding({\n credential: sandboxCredential,\n environmentVariableName,\n });\n };\n}\n\nfunction createGitHubOAuthSandboxCredentialPlaceholder({\n credential,\n}: {\n credential: string;\n}): string {\n /*\n * Copilot CLI validates environment credentials as GitHub token formats\n * before making the request that credential brokering can transform. GitHub\n * OAuth tokens use `gho_` followed by a 36-character alphanumeric body.\n */\n const tokenBody = createHash('sha256')\n .update(credential)\n .digest('hex')\n .slice(\n 0,\n GITHUB_OAUTH_TOKEN_BODY_LENGTH -\n GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER.length,\n );\n return `gho_${GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER}${tokenBody}`;\n}\n","import { execFile } from 'node:child_process';\nimport { constants } from 'node:fs';\nimport { access, readFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { promisify } from 'node:util';\nimport type { ACPAuthenticationMode } from '@ai-sdk/harness-acp';\nimport {\n isHarnessAuthenticationEnvironment,\n isLinux,\n isMacOS,\n isWindows,\n readLinuxSecretServicePassword,\n readMacOSKeychainPassword,\n readWindowsCredentialManagerPassword,\n shouldResolveNativeSubscription,\n} from '@ai-sdk/harness/utils';\nimport { isRecord } from '@ai-sdk/provider-utils';\nimport { parse, type ParseError } from 'jsonc-parser';\n\nconst COPILOT_KEYRING_SERVICE = 'copilot-cli';\nconst execFileAsync = promisify(execFile);\n\ntype GitHubCopilotAccount = {\n readonly host: string;\n readonly login: string;\n};\n\nexport type GitHubCopilotSubscription = {\n readonly token: string;\n readonly host: string;\n};\n\ntype ReadSecureCredential = (options: {\n service: string;\n account: string;\n}) => Promise<string | undefined>;\n\ntype FindGitHubCliExecutable = (options: {\n env: Readonly<Record<string, string | undefined>>;\n platform: NodeJS.Platform;\n}) => Promise<string | undefined>;\n\ntype ReadGitHubCliToken = (options: {\n executable: string;\n hostname: string;\n env: Readonly<Record<string, string | undefined>>;\n}) => Promise<string | undefined>;\n\nexport async function resolveGitHubCopilotSubscriptionEnvironment({\n auth,\n env,\n readSubscription = readGitHubCopilotSubscription,\n}: {\n auth: ACPAuthenticationMode | undefined;\n env: Readonly<Record<string, string | undefined>>;\n readSubscription?: (options: {\n env: Readonly<Record<string, string | undefined>>;\n }) => Promise<GitHubCopilotSubscription | undefined>;\n}): Promise<Readonly<Record<string, string | undefined>>> {\n if (isHarnessAuthenticationEnvironment(auth)) return auth;\n if (\n !shouldResolveNativeSubscription({\n auth,\n env,\n hasDirectCredential:\n env.COPILOT_GITHUB_TOKEN != null ||\n env.GH_TOKEN != null ||\n env.GITHUB_TOKEN != null,\n })\n ) {\n return env;\n }\n\n const subscription = await readSubscription({ env });\n if (subscription == null) return env;\n\n return {\n ...env,\n COPILOT_GITHUB_TOKEN: subscription.token,\n COPILOT_GH_HOST: normalizeGitHubHost(subscription.host),\n };\n}\n\nexport async function readGitHubCopilotSubscription({\n env = process.env,\n homeDirectory = homedir(),\n platform = process.platform,\n readSecureCredential,\n findGitHubCliExecutable = findHostGitHubCliExecutable,\n readGitHubCliToken = readHostGitHubCliToken,\n}: {\n env?: Readonly<Record<string, string | undefined>>;\n homeDirectory?: string;\n platform?: NodeJS.Platform;\n readSecureCredential?: ReadSecureCredential;\n findGitHubCliExecutable?: FindGitHubCliExecutable;\n readGitHubCliToken?: ReadGitHubCliToken;\n} = {}): Promise<GitHubCopilotSubscription | undefined> {\n const copilotHome = resolve(\n env.COPILOT_HOME ?? join(homeDirectory, '.copilot'),\n );\n const config = await readGitHubCopilotConfig({\n path: join(copilotHome, 'config.json'),\n });\n const account = selectGitHubCopilotAccount({ config });\n\n if (account != null) {\n const accountKey = `${account.host}:${account.login}`;\n const secureToken = await (\n readSecureCredential ??\n (options => readGitHubCopilotSecureCredential({ ...options, platform }))\n )({\n service: COPILOT_KEYRING_SERVICE,\n account: accountKey,\n }).catch(() => undefined);\n if (isNonEmptyString(secureToken)) {\n return { token: secureToken, host: account.host };\n }\n\n const plaintextToken = getPlaintextToken({ config, accountKey });\n if (plaintextToken != null) {\n return { token: plaintextToken, host: account.host };\n }\n }\n\n const host =\n account?.host ??\n normalizeGitHubOrigin(env.COPILOT_GH_HOST ?? env.GH_HOST ?? 'github.com');\n if (host == null) return undefined;\n\n const executable = await findGitHubCliExecutable({ env, platform });\n if (executable == null) return undefined;\n\n const token = await readGitHubCliToken({\n executable,\n hostname: normalizeGitHubHost(host),\n env,\n }).catch(() => undefined);\n return isNonEmptyString(token) ? { token: token.trim(), host } : undefined;\n}\n\nexport async function findHostGitHubCliExecutable({\n env,\n platform,\n}: {\n env: Readonly<Record<string, string | undefined>>;\n platform: NodeJS.Platform;\n}): Promise<string | undefined> {\n const path = env.PATH ?? env.Path ?? env.path;\n if (path == null) return undefined;\n\n const separator = isWindows(platform) ? ';' : ':';\n const names = isWindows(platform)\n ? getWindowsGitHubCliExecutableNames({ pathExt: env.PATHEXT })\n : ['gh'];\n const mode = isWindows(platform) ? constants.F_OK : constants.X_OK;\n\n for (const directory of path.split(separator)) {\n const normalizedDirectory = directory.replace(/^\"|\"$/g, '');\n if (normalizedDirectory.length === 0) continue;\n for (const executableName of names) {\n const candidate = resolve(normalizedDirectory, executableName);\n try {\n await access(candidate, mode);\n return candidate;\n } catch {}\n }\n }\n\n return undefined;\n}\n\nasync function readGitHubCopilotConfig({\n path,\n}: {\n path: string;\n}): Promise<Record<string, unknown> | undefined> {\n const text = await readFile(path, 'utf8').catch(() => undefined);\n if (text == null) return undefined;\n\n const errors: ParseError[] = [];\n const value = parse(text, errors, { allowTrailingComma: true });\n return errors.length === 0 && isRecord(value) ? value : undefined;\n}\n\nfunction selectGitHubCopilotAccount({\n config,\n}: {\n config: Record<string, unknown> | undefined;\n}): GitHubCopilotAccount | undefined {\n if (config == null) return undefined;\n\n for (const value of [config.last_logged_in_user, config.lastLoggedInUser]) {\n const account = toGitHubCopilotAccount(value);\n if (account != null) return account;\n }\n\n for (const values of [config.logged_in_users, config.loggedInUsers]) {\n if (!Array.isArray(values)) continue;\n for (const value of values) {\n const account = toGitHubCopilotAccount(value);\n if (account != null) return account;\n }\n }\n return undefined;\n}\n\nfunction toGitHubCopilotAccount(\n value: unknown,\n): GitHubCopilotAccount | undefined {\n if (\n !isRecord(value) ||\n !isNonEmptyString(value.host) ||\n !isNonEmptyString(value.login)\n ) {\n return undefined;\n }\n const host = normalizeGitHubOrigin(value.host);\n return host == null ? undefined : { host, login: value.login };\n}\n\nfunction getPlaintextToken({\n config,\n accountKey,\n}: {\n config: Record<string, unknown> | undefined;\n accountKey: string;\n}): string | undefined {\n if (config == null || !isRecord(config.copilotTokens)) return undefined;\n const token = config.copilotTokens[accountKey];\n return isNonEmptyString(token) ? token : undefined;\n}\n\nasync function readGitHubCopilotSecureCredential({\n service,\n account,\n platform,\n}: {\n service: string;\n account: string;\n platform: NodeJS.Platform;\n}): Promise<string | undefined> {\n if (isMacOS(platform)) {\n return readMacOSKeychainPassword({ service, account });\n }\n if (isLinux(platform)) {\n return readLinuxSecretServicePassword({\n attributes: { service, username: account },\n });\n }\n if (isWindows(platform)) {\n return readWindowsCredentialManagerPassword({\n targetName: `${account}.${service}`,\n });\n }\n return undefined;\n}\n\nasync function readHostGitHubCliToken({\n executable,\n hostname,\n env,\n}: {\n executable: string;\n hostname: string;\n env: Readonly<Record<string, string | undefined>>;\n}): Promise<string | undefined> {\n try {\n const result = await execFileAsync(\n executable,\n ['auth', 'token', '--hostname', hostname],\n {\n env: { ...env },\n timeout: 10_000,\n windowsHide: true,\n },\n );\n return isNonEmptyString(result.stdout) ? result.stdout.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction getWindowsGitHubCliExecutableNames({\n pathExt,\n}: {\n pathExt: string | undefined;\n}): ReadonlyArray<string> {\n const extensions = (pathExt ?? '.COM;.EXE;.BAT;.CMD')\n .split(';')\n .filter(isNonEmptyString);\n return ['gh', ...extensions.map(extension => `gh${extension}`)];\n}\n\nfunction normalizeGitHubOrigin(host: string): string | undefined {\n try {\n return new URL(host.includes('://') ? host : `https://${host}`).origin;\n } catch {\n return undefined;\n }\n}\n\nexport function normalizeGitHubHost(host: string): string {\n return new URL(host.includes('://') ? host : `https://${host}`).hostname;\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n","declare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n","import { createGitHubCopilot } from './github-copilot-harness';\n\n/**\n * Default GitHub Copilot harness instance. Equivalent to\n * `createGitHubCopilot()`.\n */\nexport const githubCopilot = createGitHubCopilot();\n\nexport { createGitHubCopilot } from './github-copilot-harness';\nexport type {\n GitHubCopilotAuthenticationMode,\n GitHubCopilotBuiltinTools,\n GitHubCopilotHarnessSettings,\n} from './github-copilot-harness';\nexport { VERSION } from './version';\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness-github-copilot",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -26,9 +26,10 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@ai-sdk/harness": "1.0.
|
|
30
|
-
"@ai-sdk/harness-acp": "1.0.
|
|
31
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
29
|
+
"@ai-sdk/harness": "1.0.108",
|
|
30
|
+
"@ai-sdk/harness-acp": "1.0.46",
|
|
31
|
+
"@ai-sdk/provider-utils": "5.0.40",
|
|
32
|
+
"jsonc-parser": "3.3.1"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"zod": "^3.25.76 || ^4.1.8"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import {
|
|
2
3
|
commonTool,
|
|
3
4
|
type HarnessV1,
|
|
@@ -6,10 +7,17 @@ import {
|
|
|
6
7
|
type HarnessV1PortEndpoint,
|
|
7
8
|
type HarnessV1RequestTransformation,
|
|
8
9
|
} from '@ai-sdk/harness';
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
createCredentialRequestTransformation,
|
|
12
|
+
isSandboxCredentialPlaceholder,
|
|
13
|
+
} from '@ai-sdk/harness/utils';
|
|
10
14
|
import { createACP, type ACPAuthenticationMode } from '@ai-sdk/harness-acp';
|
|
11
15
|
import { tool } from '@ai-sdk/provider-utils';
|
|
12
16
|
import { z } from 'zod/v4';
|
|
17
|
+
import {
|
|
18
|
+
normalizeGitHubHost,
|
|
19
|
+
resolveGitHubCopilotSubscriptionEnvironment,
|
|
20
|
+
} from './github-copilot-subscription';
|
|
13
21
|
import { VERSION } from './version';
|
|
14
22
|
|
|
15
23
|
declare const __GITHUB_COPILOT_IMPLEMENTATION_PACKAGE_JSON__: string;
|
|
@@ -26,6 +34,13 @@ const GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK =
|
|
|
26
34
|
__GITHUB_COPILOT_IMPLEMENTATION_PNPM_LOCK_YAML__;
|
|
27
35
|
const GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE =
|
|
28
36
|
__GITHUB_COPILOT_IMPLEMENTATION_PNPM_WORKSPACE_YAML__;
|
|
37
|
+
const GITHUB_COPILOT_TOKEN_ENVIRONMENT_VARIABLES = new Set([
|
|
38
|
+
'COPILOT_GITHUB_TOKEN',
|
|
39
|
+
'GH_TOKEN',
|
|
40
|
+
'GITHUB_TOKEN',
|
|
41
|
+
]);
|
|
42
|
+
const GITHUB_OAUTH_TOKEN_BODY_LENGTH = 36;
|
|
43
|
+
const GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER = 'aisdkhc';
|
|
29
44
|
|
|
30
45
|
export type GitHubCopilotAuthenticationMode = ACPAuthenticationMode;
|
|
31
46
|
|
|
@@ -260,6 +275,8 @@ export function createGitHubCopilot(
|
|
|
260
275
|
: [`--reasoning-effort=${settings.reasoningEffort}`]),
|
|
261
276
|
],
|
|
262
277
|
auth: settings.auth,
|
|
278
|
+
resolveAuthenticationEnvironment:
|
|
279
|
+
resolveGitHubCopilotSubscriptionEnvironment,
|
|
263
280
|
/*
|
|
264
281
|
* The Copilot CLI drops every MCP server that a client passes in ACP
|
|
265
282
|
* `session/new` unless it is declared with the `http` or `sse` transport,
|
|
@@ -421,7 +438,9 @@ export function createGitHubCopilot(
|
|
|
421
438
|
|
|
422
439
|
return transformations;
|
|
423
440
|
},
|
|
424
|
-
credentialForwarding:
|
|
441
|
+
credentialForwarding: createGitHubCopilotCredentialForwarding({
|
|
442
|
+
credentialForwarding: settings.credentialForwarding,
|
|
443
|
+
}),
|
|
425
444
|
providerAuthentication: {
|
|
426
445
|
gateway: {
|
|
427
446
|
env: {
|
|
@@ -462,6 +481,43 @@ export function createGitHubCopilot(
|
|
|
462
481
|
});
|
|
463
482
|
}
|
|
464
483
|
|
|
465
|
-
function
|
|
466
|
-
|
|
484
|
+
function createGitHubCopilotCredentialForwarding({
|
|
485
|
+
credentialForwarding,
|
|
486
|
+
}: {
|
|
487
|
+
credentialForwarding: HarnessV1CredentialForwarding | undefined;
|
|
488
|
+
}): HarnessV1CredentialForwarding {
|
|
489
|
+
return ({ credential, environmentVariableName }) => {
|
|
490
|
+
const sandboxCredential =
|
|
491
|
+
GITHUB_COPILOT_TOKEN_ENVIRONMENT_VARIABLES.has(environmentVariableName) &&
|
|
492
|
+
isSandboxCredentialPlaceholder(credential)
|
|
493
|
+
? createGitHubOAuthSandboxCredentialPlaceholder({ credential })
|
|
494
|
+
: credential;
|
|
495
|
+
return credentialForwarding == null
|
|
496
|
+
? sandboxCredential
|
|
497
|
+
: credentialForwarding({
|
|
498
|
+
credential: sandboxCredential,
|
|
499
|
+
environmentVariableName,
|
|
500
|
+
});
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function createGitHubOAuthSandboxCredentialPlaceholder({
|
|
505
|
+
credential,
|
|
506
|
+
}: {
|
|
507
|
+
credential: string;
|
|
508
|
+
}): string {
|
|
509
|
+
/*
|
|
510
|
+
* Copilot CLI validates environment credentials as GitHub token formats
|
|
511
|
+
* before making the request that credential brokering can transform. GitHub
|
|
512
|
+
* OAuth tokens use `gho_` followed by a 36-character alphanumeric body.
|
|
513
|
+
*/
|
|
514
|
+
const tokenBody = createHash('sha256')
|
|
515
|
+
.update(credential)
|
|
516
|
+
.digest('hex')
|
|
517
|
+
.slice(
|
|
518
|
+
0,
|
|
519
|
+
GITHUB_OAUTH_TOKEN_BODY_LENGTH -
|
|
520
|
+
GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER.length,
|
|
521
|
+
);
|
|
522
|
+
return `gho_${GITHUB_OAUTH_SANDBOX_CREDENTIAL_MARKER}${tokenBody}`;
|
|
467
523
|
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { access, readFile } from 'node:fs/promises';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import type { ACPAuthenticationMode } from '@ai-sdk/harness-acp';
|
|
8
|
+
import {
|
|
9
|
+
isHarnessAuthenticationEnvironment,
|
|
10
|
+
isLinux,
|
|
11
|
+
isMacOS,
|
|
12
|
+
isWindows,
|
|
13
|
+
readLinuxSecretServicePassword,
|
|
14
|
+
readMacOSKeychainPassword,
|
|
15
|
+
readWindowsCredentialManagerPassword,
|
|
16
|
+
shouldResolveNativeSubscription,
|
|
17
|
+
} from '@ai-sdk/harness/utils';
|
|
18
|
+
import { isRecord } from '@ai-sdk/provider-utils';
|
|
19
|
+
import { parse, type ParseError } from 'jsonc-parser';
|
|
20
|
+
|
|
21
|
+
const COPILOT_KEYRING_SERVICE = 'copilot-cli';
|
|
22
|
+
const execFileAsync = promisify(execFile);
|
|
23
|
+
|
|
24
|
+
type GitHubCopilotAccount = {
|
|
25
|
+
readonly host: string;
|
|
26
|
+
readonly login: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type GitHubCopilotSubscription = {
|
|
30
|
+
readonly token: string;
|
|
31
|
+
readonly host: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ReadSecureCredential = (options: {
|
|
35
|
+
service: string;
|
|
36
|
+
account: string;
|
|
37
|
+
}) => Promise<string | undefined>;
|
|
38
|
+
|
|
39
|
+
type FindGitHubCliExecutable = (options: {
|
|
40
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
41
|
+
platform: NodeJS.Platform;
|
|
42
|
+
}) => Promise<string | undefined>;
|
|
43
|
+
|
|
44
|
+
type ReadGitHubCliToken = (options: {
|
|
45
|
+
executable: string;
|
|
46
|
+
hostname: string;
|
|
47
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
48
|
+
}) => Promise<string | undefined>;
|
|
49
|
+
|
|
50
|
+
export async function resolveGitHubCopilotSubscriptionEnvironment({
|
|
51
|
+
auth,
|
|
52
|
+
env,
|
|
53
|
+
readSubscription = readGitHubCopilotSubscription,
|
|
54
|
+
}: {
|
|
55
|
+
auth: ACPAuthenticationMode | undefined;
|
|
56
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
57
|
+
readSubscription?: (options: {
|
|
58
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
59
|
+
}) => Promise<GitHubCopilotSubscription | undefined>;
|
|
60
|
+
}): Promise<Readonly<Record<string, string | undefined>>> {
|
|
61
|
+
if (isHarnessAuthenticationEnvironment(auth)) return auth;
|
|
62
|
+
if (
|
|
63
|
+
!shouldResolveNativeSubscription({
|
|
64
|
+
auth,
|
|
65
|
+
env,
|
|
66
|
+
hasDirectCredential:
|
|
67
|
+
env.COPILOT_GITHUB_TOKEN != null ||
|
|
68
|
+
env.GH_TOKEN != null ||
|
|
69
|
+
env.GITHUB_TOKEN != null,
|
|
70
|
+
})
|
|
71
|
+
) {
|
|
72
|
+
return env;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const subscription = await readSubscription({ env });
|
|
76
|
+
if (subscription == null) return env;
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
...env,
|
|
80
|
+
COPILOT_GITHUB_TOKEN: subscription.token,
|
|
81
|
+
COPILOT_GH_HOST: normalizeGitHubHost(subscription.host),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function readGitHubCopilotSubscription({
|
|
86
|
+
env = process.env,
|
|
87
|
+
homeDirectory = homedir(),
|
|
88
|
+
platform = process.platform,
|
|
89
|
+
readSecureCredential,
|
|
90
|
+
findGitHubCliExecutable = findHostGitHubCliExecutable,
|
|
91
|
+
readGitHubCliToken = readHostGitHubCliToken,
|
|
92
|
+
}: {
|
|
93
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
94
|
+
homeDirectory?: string;
|
|
95
|
+
platform?: NodeJS.Platform;
|
|
96
|
+
readSecureCredential?: ReadSecureCredential;
|
|
97
|
+
findGitHubCliExecutable?: FindGitHubCliExecutable;
|
|
98
|
+
readGitHubCliToken?: ReadGitHubCliToken;
|
|
99
|
+
} = {}): Promise<GitHubCopilotSubscription | undefined> {
|
|
100
|
+
const copilotHome = resolve(
|
|
101
|
+
env.COPILOT_HOME ?? join(homeDirectory, '.copilot'),
|
|
102
|
+
);
|
|
103
|
+
const config = await readGitHubCopilotConfig({
|
|
104
|
+
path: join(copilotHome, 'config.json'),
|
|
105
|
+
});
|
|
106
|
+
const account = selectGitHubCopilotAccount({ config });
|
|
107
|
+
|
|
108
|
+
if (account != null) {
|
|
109
|
+
const accountKey = `${account.host}:${account.login}`;
|
|
110
|
+
const secureToken = await (
|
|
111
|
+
readSecureCredential ??
|
|
112
|
+
(options => readGitHubCopilotSecureCredential({ ...options, platform }))
|
|
113
|
+
)({
|
|
114
|
+
service: COPILOT_KEYRING_SERVICE,
|
|
115
|
+
account: accountKey,
|
|
116
|
+
}).catch(() => undefined);
|
|
117
|
+
if (isNonEmptyString(secureToken)) {
|
|
118
|
+
return { token: secureToken, host: account.host };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const plaintextToken = getPlaintextToken({ config, accountKey });
|
|
122
|
+
if (plaintextToken != null) {
|
|
123
|
+
return { token: plaintextToken, host: account.host };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const host =
|
|
128
|
+
account?.host ??
|
|
129
|
+
normalizeGitHubOrigin(env.COPILOT_GH_HOST ?? env.GH_HOST ?? 'github.com');
|
|
130
|
+
if (host == null) return undefined;
|
|
131
|
+
|
|
132
|
+
const executable = await findGitHubCliExecutable({ env, platform });
|
|
133
|
+
if (executable == null) return undefined;
|
|
134
|
+
|
|
135
|
+
const token = await readGitHubCliToken({
|
|
136
|
+
executable,
|
|
137
|
+
hostname: normalizeGitHubHost(host),
|
|
138
|
+
env,
|
|
139
|
+
}).catch(() => undefined);
|
|
140
|
+
return isNonEmptyString(token) ? { token: token.trim(), host } : undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function findHostGitHubCliExecutable({
|
|
144
|
+
env,
|
|
145
|
+
platform,
|
|
146
|
+
}: {
|
|
147
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
148
|
+
platform: NodeJS.Platform;
|
|
149
|
+
}): Promise<string | undefined> {
|
|
150
|
+
const path = env.PATH ?? env.Path ?? env.path;
|
|
151
|
+
if (path == null) return undefined;
|
|
152
|
+
|
|
153
|
+
const separator = isWindows(platform) ? ';' : ':';
|
|
154
|
+
const names = isWindows(platform)
|
|
155
|
+
? getWindowsGitHubCliExecutableNames({ pathExt: env.PATHEXT })
|
|
156
|
+
: ['gh'];
|
|
157
|
+
const mode = isWindows(platform) ? constants.F_OK : constants.X_OK;
|
|
158
|
+
|
|
159
|
+
for (const directory of path.split(separator)) {
|
|
160
|
+
const normalizedDirectory = directory.replace(/^"|"$/g, '');
|
|
161
|
+
if (normalizedDirectory.length === 0) continue;
|
|
162
|
+
for (const executableName of names) {
|
|
163
|
+
const candidate = resolve(normalizedDirectory, executableName);
|
|
164
|
+
try {
|
|
165
|
+
await access(candidate, mode);
|
|
166
|
+
return candidate;
|
|
167
|
+
} catch {}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function readGitHubCopilotConfig({
|
|
175
|
+
path,
|
|
176
|
+
}: {
|
|
177
|
+
path: string;
|
|
178
|
+
}): Promise<Record<string, unknown> | undefined> {
|
|
179
|
+
const text = await readFile(path, 'utf8').catch(() => undefined);
|
|
180
|
+
if (text == null) return undefined;
|
|
181
|
+
|
|
182
|
+
const errors: ParseError[] = [];
|
|
183
|
+
const value = parse(text, errors, { allowTrailingComma: true });
|
|
184
|
+
return errors.length === 0 && isRecord(value) ? value : undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function selectGitHubCopilotAccount({
|
|
188
|
+
config,
|
|
189
|
+
}: {
|
|
190
|
+
config: Record<string, unknown> | undefined;
|
|
191
|
+
}): GitHubCopilotAccount | undefined {
|
|
192
|
+
if (config == null) return undefined;
|
|
193
|
+
|
|
194
|
+
for (const value of [config.last_logged_in_user, config.lastLoggedInUser]) {
|
|
195
|
+
const account = toGitHubCopilotAccount(value);
|
|
196
|
+
if (account != null) return account;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
for (const values of [config.logged_in_users, config.loggedInUsers]) {
|
|
200
|
+
if (!Array.isArray(values)) continue;
|
|
201
|
+
for (const value of values) {
|
|
202
|
+
const account = toGitHubCopilotAccount(value);
|
|
203
|
+
if (account != null) return account;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function toGitHubCopilotAccount(
|
|
210
|
+
value: unknown,
|
|
211
|
+
): GitHubCopilotAccount | undefined {
|
|
212
|
+
if (
|
|
213
|
+
!isRecord(value) ||
|
|
214
|
+
!isNonEmptyString(value.host) ||
|
|
215
|
+
!isNonEmptyString(value.login)
|
|
216
|
+
) {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
const host = normalizeGitHubOrigin(value.host);
|
|
220
|
+
return host == null ? undefined : { host, login: value.login };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function getPlaintextToken({
|
|
224
|
+
config,
|
|
225
|
+
accountKey,
|
|
226
|
+
}: {
|
|
227
|
+
config: Record<string, unknown> | undefined;
|
|
228
|
+
accountKey: string;
|
|
229
|
+
}): string | undefined {
|
|
230
|
+
if (config == null || !isRecord(config.copilotTokens)) return undefined;
|
|
231
|
+
const token = config.copilotTokens[accountKey];
|
|
232
|
+
return isNonEmptyString(token) ? token : undefined;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function readGitHubCopilotSecureCredential({
|
|
236
|
+
service,
|
|
237
|
+
account,
|
|
238
|
+
platform,
|
|
239
|
+
}: {
|
|
240
|
+
service: string;
|
|
241
|
+
account: string;
|
|
242
|
+
platform: NodeJS.Platform;
|
|
243
|
+
}): Promise<string | undefined> {
|
|
244
|
+
if (isMacOS(platform)) {
|
|
245
|
+
return readMacOSKeychainPassword({ service, account });
|
|
246
|
+
}
|
|
247
|
+
if (isLinux(platform)) {
|
|
248
|
+
return readLinuxSecretServicePassword({
|
|
249
|
+
attributes: { service, username: account },
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
if (isWindows(platform)) {
|
|
253
|
+
return readWindowsCredentialManagerPassword({
|
|
254
|
+
targetName: `${account}.${service}`,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function readHostGitHubCliToken({
|
|
261
|
+
executable,
|
|
262
|
+
hostname,
|
|
263
|
+
env,
|
|
264
|
+
}: {
|
|
265
|
+
executable: string;
|
|
266
|
+
hostname: string;
|
|
267
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
268
|
+
}): Promise<string | undefined> {
|
|
269
|
+
try {
|
|
270
|
+
const result = await execFileAsync(
|
|
271
|
+
executable,
|
|
272
|
+
['auth', 'token', '--hostname', hostname],
|
|
273
|
+
{
|
|
274
|
+
env: { ...env },
|
|
275
|
+
timeout: 10_000,
|
|
276
|
+
windowsHide: true,
|
|
277
|
+
},
|
|
278
|
+
);
|
|
279
|
+
return isNonEmptyString(result.stdout) ? result.stdout.trim() : undefined;
|
|
280
|
+
} catch {
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function getWindowsGitHubCliExecutableNames({
|
|
286
|
+
pathExt,
|
|
287
|
+
}: {
|
|
288
|
+
pathExt: string | undefined;
|
|
289
|
+
}): ReadonlyArray<string> {
|
|
290
|
+
const extensions = (pathExt ?? '.COM;.EXE;.BAT;.CMD')
|
|
291
|
+
.split(';')
|
|
292
|
+
.filter(isNonEmptyString);
|
|
293
|
+
return ['gh', ...extensions.map(extension => `gh${extension}`)];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function normalizeGitHubOrigin(host: string): string | undefined {
|
|
297
|
+
try {
|
|
298
|
+
return new URL(host.includes('://') ? host : `https://${host}`).origin;
|
|
299
|
+
} catch {
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function normalizeGitHubHost(host: string): string {
|
|
305
|
+
return new URL(host.includes('://') ? host : `https://${host}`).hostname;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function isNonEmptyString(value: unknown): value is string {
|
|
309
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
310
|
+
}
|