@ai-sdk/harness-github-copilot 1.0.2 → 1.0.4

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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @ai-sdk/harness-github-copilot
2
2
 
3
+ ## 1.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - @ai-sdk/harness@1.0.109
8
+ - @ai-sdk/harness-acp@1.0.47
9
+
10
+ ## 1.0.3
11
+
12
+ ### Patch Changes
13
+
14
+ - cdc12a1: feat(harness): add support for using adapter-native subscriptions where available
15
+ - Updated dependencies [4d1bf28]
16
+ - Updated dependencies [cdc12a1]
17
+ - Updated dependencies [d70a334]
18
+ - Updated dependencies [81ba84c]
19
+ - Updated dependencies [813bb36]
20
+ - Updated dependencies [c43e4b7]
21
+ - @ai-sdk/harness@1.0.108
22
+ - @ai-sdk/harness-acp@1.0.46
23
+ - @ai-sdk/provider-utils@5.0.40
24
+
3
25
  ## 1.0.2
4
26
 
5
27
  ### 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 { createCredentialRequestTransformation } from "@ai-sdk/harness/utils";
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.2" : "0.0.0-test";
221
+ var VERSION = true ? "1.0.4" : "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: settings.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 normalizeGitHubHost(host) {
410
- return new URL(host.includes("://") ? host : `https://${host}`).hostname;
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.2",
3
+ "version": "1.0.4",
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.107",
30
- "@ai-sdk/harness-acp": "1.0.45",
31
- "@ai-sdk/provider-utils": "5.0.39"
29
+ "@ai-sdk/harness": "1.0.109",
30
+ "@ai-sdk/harness-acp": "1.0.47",
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 { createCredentialRequestTransformation } from '@ai-sdk/harness/utils';
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: settings.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 normalizeGitHubHost(host: string): string {
466
- return new URL(host.includes('://') ? host : `https://${host}`).hostname;
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
+ }