@mastra/code-sdk 1.0.3-alpha.1 → 1.1.0-alpha.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 +45 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +11 -11
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- package/dist/tools/index.js.map +0 -1
|
@@ -1,329 +1,340 @@
|
|
|
1
|
+
//#region src/auth/providers/github-copilot.ts
|
|
1
2
|
const decode = (s) => atob(s);
|
|
2
3
|
const CLIENT_ID = decode("SXYxLmI1MDdhMDhjODdlY2ZlOTg=");
|
|
3
4
|
const COPILOT_USER_AGENT = "GitHubCopilotChat/0.35.0";
|
|
5
|
+
/** Headers that Copilot endpoints expect from a VS Code-like client. */
|
|
4
6
|
const COPILOT_HEADERS = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
"User-Agent": COPILOT_USER_AGENT,
|
|
8
|
+
"Editor-Version": "vscode/1.107.0",
|
|
9
|
+
"Editor-Plugin-Version": "copilot-chat/0.35.0",
|
|
10
|
+
"Copilot-Integration-Id": "vscode-chat"
|
|
9
11
|
};
|
|
10
12
|
const INITIAL_POLL_INTERVAL_MULTIPLIER = 1.2;
|
|
11
13
|
const SLOW_DOWN_POLL_INTERVAL_MULTIPLIER = 1.4;
|
|
14
|
+
/**
|
|
15
|
+
* Normalize a user-entered Enterprise URL/domain into a hostname (e.g. `company.ghe.com`).
|
|
16
|
+
* Returns null for an empty input or an unparseable URL.
|
|
17
|
+
*/
|
|
12
18
|
function normalizeDomain(input) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
19
|
+
const trimmed = input.trim();
|
|
20
|
+
if (!trimmed) return null;
|
|
21
|
+
try {
|
|
22
|
+
return (trimmed.includes("://") ? new URL(trimmed) : new URL(`https://${trimmed}`)).hostname || null;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
function getUrls(domain) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
return {
|
|
29
|
+
deviceCodeUrl: `https://${domain}/login/device/code`,
|
|
30
|
+
accessTokenUrl: `https://${domain}/login/oauth/access_token`,
|
|
31
|
+
copilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`
|
|
32
|
+
};
|
|
28
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Parse the `proxy-ep` segment from a Copilot bearer token and convert to its API base URL.
|
|
36
|
+
* Token shape: `tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...`
|
|
37
|
+
*/
|
|
29
38
|
function getBaseUrlFromToken(token) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const apiHost = proxyHost.replace(/^proxy\./, "api.");
|
|
34
|
-
return `https://${apiHost}`;
|
|
39
|
+
const match = token.match(/proxy-ep=([^;]+)/);
|
|
40
|
+
if (!match) return null;
|
|
41
|
+
return `https://${match[1].replace(/^proxy\./, "api.")}`;
|
|
35
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the Copilot API base URL.
|
|
45
|
+
* Prefers the `proxy-ep` parsed from the bearer token, then falls back to enterprise/individual defaults.
|
|
46
|
+
*/
|
|
36
47
|
function getGitHubCopilotBaseUrl(token, enterpriseDomain) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
if (token) {
|
|
49
|
+
const fromToken = getBaseUrlFromToken(token);
|
|
50
|
+
if (fromToken) return fromToken;
|
|
51
|
+
}
|
|
52
|
+
if (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;
|
|
53
|
+
return "https://api.individual.githubcopilot.com";
|
|
43
54
|
}
|
|
44
55
|
async function fetchJson(url, init, signal) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
const response = await fetch(url, signal ? {
|
|
57
|
+
...init,
|
|
58
|
+
signal
|
|
59
|
+
} : init);
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const text = await response.text().catch(() => "");
|
|
62
|
+
throw new Error(`${response.status} ${response.statusText}: ${text}`);
|
|
63
|
+
}
|
|
64
|
+
return response.json();
|
|
51
65
|
}
|
|
52
66
|
async function startDeviceFlow(domain, signal) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
throw new Error("Invalid device code response fields");
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
device_code: deviceCode,
|
|
84
|
-
user_code: userCode,
|
|
85
|
-
verification_uri: verificationUri,
|
|
86
|
-
interval,
|
|
87
|
-
expires_in: expiresIn
|
|
88
|
-
};
|
|
67
|
+
const data = await fetchJson(getUrls(domain).deviceCodeUrl, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
Accept: "application/json",
|
|
71
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
72
|
+
"User-Agent": COPILOT_USER_AGENT
|
|
73
|
+
},
|
|
74
|
+
body: new URLSearchParams({
|
|
75
|
+
client_id: CLIENT_ID,
|
|
76
|
+
scope: "read:user"
|
|
77
|
+
})
|
|
78
|
+
}, signal);
|
|
79
|
+
if (!data || typeof data !== "object") throw new Error("Invalid device code response");
|
|
80
|
+
const obj = data;
|
|
81
|
+
const deviceCode = obj.device_code;
|
|
82
|
+
const userCode = obj.user_code;
|
|
83
|
+
const verificationUri = obj.verification_uri;
|
|
84
|
+
const interval = obj.interval;
|
|
85
|
+
const expiresIn = obj.expires_in;
|
|
86
|
+
if (typeof deviceCode !== "string" || typeof userCode !== "string" || typeof verificationUri !== "string" || typeof interval !== "number" || typeof expiresIn !== "number") throw new Error("Invalid device code response fields");
|
|
87
|
+
return {
|
|
88
|
+
device_code: deviceCode,
|
|
89
|
+
user_code: userCode,
|
|
90
|
+
verification_uri: verificationUri,
|
|
91
|
+
interval,
|
|
92
|
+
expires_in: expiresIn
|
|
93
|
+
};
|
|
89
94
|
}
|
|
95
|
+
/** Sleep that can be interrupted by an AbortSignal. */
|
|
90
96
|
function abortableSleep(ms, signal) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
return new Promise((resolve, reject) => {
|
|
98
|
+
if (signal?.aborted) {
|
|
99
|
+
reject(/* @__PURE__ */ new Error("Login cancelled"));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let timeout;
|
|
103
|
+
const onAbort = () => {
|
|
104
|
+
clearTimeout(timeout);
|
|
105
|
+
reject(/* @__PURE__ */ new Error("Login cancelled"));
|
|
106
|
+
};
|
|
107
|
+
timeout = setTimeout(() => {
|
|
108
|
+
signal?.removeEventListener("abort", onAbort);
|
|
109
|
+
resolve();
|
|
110
|
+
}, ms);
|
|
111
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
112
|
+
});
|
|
107
113
|
}
|
|
114
|
+
/** Delay to wait before the next upstream poll for a pending Copilot device login. */
|
|
108
115
|
function copilotNextPollDelayMs(pending) {
|
|
109
|
-
|
|
116
|
+
return Math.ceil(pending.intervalMs * pending.intervalMultiplier);
|
|
110
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Start a Copilot device-code login: request a user code and return the
|
|
120
|
+
* serializable pending state for subsequent polls. Wait `copilotNextPollDelayMs`
|
|
121
|
+
* before the first poll.
|
|
122
|
+
*/
|
|
111
123
|
async function startGitHubCopilotDeviceLogin(enterpriseDomain, options) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
const domain = enterpriseDomain || "github.com";
|
|
125
|
+
const device = await startDeviceFlow(domain, options?.signal);
|
|
126
|
+
return {
|
|
127
|
+
domain,
|
|
128
|
+
...enterpriseDomain ? { enterpriseDomain } : {},
|
|
129
|
+
deviceCode: device.device_code,
|
|
130
|
+
userCode: device.user_code,
|
|
131
|
+
url: device.verification_uri,
|
|
132
|
+
instructions: `Enter code: ${device.user_code}`,
|
|
133
|
+
intervalMs: Math.max(1e3, Math.floor(device.interval * 1e3)),
|
|
134
|
+
intervalMultiplier: INITIAL_POLL_INTERVAL_MULTIPLIER,
|
|
135
|
+
slowDownCount: 0,
|
|
136
|
+
deadlineAt: Date.now() + device.expires_in * 1e3
|
|
137
|
+
};
|
|
126
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Perform exactly one upstream poll for a pending Copilot device login.
|
|
141
|
+
* On success, exchanges the GitHub OAuth token for a Copilot bearer token and
|
|
142
|
+
* returns full credentials. Never throws for flow-level conditions; network
|
|
143
|
+
* errors from fetch still propagate.
|
|
144
|
+
*/
|
|
127
145
|
async function pollGitHubCopilotDeviceLogin(pending, options) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
146
|
+
if (Date.now() >= pending.deadlineAt) {
|
|
147
|
+
if (pending.slowDownCount > 0) return {
|
|
148
|
+
status: "failed",
|
|
149
|
+
error: "Device flow timed out after one or more slow_down responses. This is often caused by clock drift in WSL or VM environments. Please sync or restart the VM clock and try again."
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
status: "failed",
|
|
153
|
+
error: "Device flow timed out"
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const raw = await fetchJson(getUrls(pending.domain).accessTokenUrl, {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: {
|
|
159
|
+
Accept: "application/json",
|
|
160
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
161
|
+
"User-Agent": COPILOT_USER_AGENT
|
|
162
|
+
},
|
|
163
|
+
body: new URLSearchParams({
|
|
164
|
+
client_id: CLIENT_ID,
|
|
165
|
+
device_code: pending.deviceCode,
|
|
166
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
167
|
+
})
|
|
168
|
+
}, options?.signal);
|
|
169
|
+
if (raw && typeof raw === "object" && typeof raw.access_token === "string") {
|
|
170
|
+
const githubAccessToken = raw.access_token;
|
|
171
|
+
options?.onProgress?.("Fetching Copilot token...");
|
|
172
|
+
return {
|
|
173
|
+
status: "complete",
|
|
174
|
+
credentials: await refreshGitHubCopilotToken(githubAccessToken, pending.enterpriseDomain, options?.signal)
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (raw && typeof raw === "object" && typeof raw.error === "string") {
|
|
178
|
+
const { error, error_description: description, interval } = raw;
|
|
179
|
+
if (error === "slow_down") {
|
|
180
|
+
const next = {
|
|
181
|
+
...pending,
|
|
182
|
+
slowDownCount: pending.slowDownCount + 1,
|
|
183
|
+
intervalMs: typeof interval === "number" && interval > 0 ? interval * 1e3 : Math.max(1e3, pending.intervalMs + 5e3),
|
|
184
|
+
intervalMultiplier: SLOW_DOWN_POLL_INTERVAL_MULTIPLIER
|
|
185
|
+
};
|
|
186
|
+
return {
|
|
187
|
+
status: "pending",
|
|
188
|
+
pending: next,
|
|
189
|
+
nextPollMs: copilotNextPollDelayMs(next)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (error !== "authorization_pending") return {
|
|
193
|
+
status: "failed",
|
|
194
|
+
error: `Device flow failed: ${error}${description ? `: ${description}` : ""}`
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
status: "pending",
|
|
199
|
+
pending,
|
|
200
|
+
nextPollMs: copilotNextPollDelayMs(pending)
|
|
201
|
+
};
|
|
178
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Refresh the short-lived Copilot bearer token using the long-lived GitHub OAuth token.
|
|
205
|
+
*
|
|
206
|
+
* `refreshToken` here is the GitHub OAuth access token; the Copilot endpoint returns a
|
|
207
|
+
* fresh bearer token (`token`) and absolute expiry (`expires_at`, seconds since epoch).
|
|
208
|
+
*/
|
|
179
209
|
async function refreshGitHubCopilotToken(refreshToken, enterpriseDomain, signal) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const token = obj.token;
|
|
198
|
-
const expiresAt = obj.expires_at;
|
|
199
|
-
if (typeof token !== "string" || typeof expiresAt !== "number") {
|
|
200
|
-
throw new Error("Invalid Copilot token response fields");
|
|
201
|
-
}
|
|
202
|
-
const credentials = {
|
|
203
|
-
refresh: refreshToken,
|
|
204
|
-
access: token,
|
|
205
|
-
// expires_at is seconds; subtract 5 minutes so we refresh before actual expiry.
|
|
206
|
-
expires: expiresAt * 1e3 - 5 * 60 * 1e3
|
|
207
|
-
};
|
|
208
|
-
if (enterpriseDomain) {
|
|
209
|
-
credentials.enterpriseUrl = enterpriseDomain;
|
|
210
|
-
}
|
|
211
|
-
return credentials;
|
|
210
|
+
const raw = await fetchJson(getUrls(enterpriseDomain || "github.com").copilotTokenUrl, { headers: {
|
|
211
|
+
Accept: "application/json",
|
|
212
|
+
Authorization: `Bearer ${refreshToken}`,
|
|
213
|
+
...COPILOT_HEADERS
|
|
214
|
+
} }, signal);
|
|
215
|
+
if (!raw || typeof raw !== "object") throw new Error("Invalid Copilot token response");
|
|
216
|
+
const obj = raw;
|
|
217
|
+
const token = obj.token;
|
|
218
|
+
const expiresAt = obj.expires_at;
|
|
219
|
+
if (typeof token !== "string" || typeof expiresAt !== "number") throw new Error("Invalid Copilot token response fields");
|
|
220
|
+
const credentials = {
|
|
221
|
+
refresh: refreshToken,
|
|
222
|
+
access: token,
|
|
223
|
+
expires: expiresAt * 1e3 - 300 * 1e3
|
|
224
|
+
};
|
|
225
|
+
if (enterpriseDomain) credentials.enterpriseUrl = enterpriseDomain;
|
|
226
|
+
return credentials;
|
|
212
227
|
}
|
|
228
|
+
/**
|
|
229
|
+
* Login with GitHub Copilot OAuth (device-code flow).
|
|
230
|
+
*
|
|
231
|
+
* Prompts for an optional GitHub Enterprise URL/domain, performs the device-code flow,
|
|
232
|
+
* then exchanges the GitHub OAuth token for a Copilot bearer token.
|
|
233
|
+
*/
|
|
213
234
|
async function loginGitHubCopilot(options) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
onProgress: options.onProgress
|
|
238
|
-
});
|
|
239
|
-
if (result.status === "complete") {
|
|
240
|
-
return result.credentials;
|
|
241
|
-
}
|
|
242
|
-
if (result.status === "failed") {
|
|
243
|
-
throw new Error(result.error);
|
|
244
|
-
}
|
|
245
|
-
pending = result.pending;
|
|
246
|
-
}
|
|
235
|
+
const input = await options.onPrompt({
|
|
236
|
+
message: "GitHub Enterprise URL/domain (blank for github.com)",
|
|
237
|
+
placeholder: "company.ghe.com",
|
|
238
|
+
allowEmpty: true
|
|
239
|
+
});
|
|
240
|
+
if (options.signal?.aborted) throw new Error("Login cancelled");
|
|
241
|
+
const trimmed = input.trim();
|
|
242
|
+
const enterpriseDomain = normalizeDomain(input);
|
|
243
|
+
if (trimmed && !enterpriseDomain) throw new Error("Invalid GitHub Enterprise URL/domain");
|
|
244
|
+
let pending = await startGitHubCopilotDeviceLogin(enterpriseDomain ?? void 0, { signal: options.signal });
|
|
245
|
+
options.onAuth(pending.url, pending.instructions);
|
|
246
|
+
while (true) {
|
|
247
|
+
if (options.signal?.aborted) throw new Error("Login cancelled");
|
|
248
|
+
const remainingMs = Math.max(pending.deadlineAt - Date.now(), 0);
|
|
249
|
+
await abortableSleep(Math.min(copilotNextPollDelayMs(pending), remainingMs), options.signal);
|
|
250
|
+
const result = await pollGitHubCopilotDeviceLogin(pending, {
|
|
251
|
+
signal: options.signal,
|
|
252
|
+
onProgress: options.onProgress
|
|
253
|
+
});
|
|
254
|
+
if (result.status === "complete") return result.credentials;
|
|
255
|
+
if (result.status === "failed") throw new Error(result.error);
|
|
256
|
+
pending = result.pending;
|
|
257
|
+
}
|
|
247
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Fetch the Copilot model list available to the current subscription.
|
|
261
|
+
*
|
|
262
|
+
* Hits `${baseURL}/models` with the Copilot bearer token, filters to
|
|
263
|
+
* `model_picker_enabled === true && policy.state !== 'disabled'`, and returns
|
|
264
|
+
* a normalized list. Mirrors opencode's filtering rules.
|
|
265
|
+
*
|
|
266
|
+
* Inspired by:
|
|
267
|
+
* - opencode: https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/plugin/github-copilot/models.ts
|
|
268
|
+
*/
|
|
248
269
|
async function fetchCopilotModels(opts) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
return result;
|
|
270
|
+
const url = `${opts.baseUrl.replace(/\/$/, "")}/models`;
|
|
271
|
+
const response = await fetch(url, {
|
|
272
|
+
headers: {
|
|
273
|
+
Accept: "application/json",
|
|
274
|
+
Authorization: `Bearer ${opts.bearerToken}`,
|
|
275
|
+
...COPILOT_HEADERS
|
|
276
|
+
},
|
|
277
|
+
signal: opts.signal
|
|
278
|
+
});
|
|
279
|
+
if (!response.ok) {
|
|
280
|
+
const text = await response.text().catch(() => "");
|
|
281
|
+
throw new Error(`Failed to fetch Copilot models: ${response.status} ${response.statusText}: ${text}`);
|
|
282
|
+
}
|
|
283
|
+
const json = await response.json().catch(() => null);
|
|
284
|
+
if (!json || typeof json !== "object" || !Array.isArray(json.data)) throw new Error("Invalid Copilot models response: missing `data` array");
|
|
285
|
+
const data = json.data;
|
|
286
|
+
const result = [];
|
|
287
|
+
for (const item of data) {
|
|
288
|
+
if (!item || typeof item !== "object") continue;
|
|
289
|
+
const obj = item;
|
|
290
|
+
if (obj.model_picker_enabled !== true) continue;
|
|
291
|
+
const policy = obj.policy;
|
|
292
|
+
if (policy && policy.state === "disabled") continue;
|
|
293
|
+
const id = obj.id;
|
|
294
|
+
if (typeof id !== "string" || !id) continue;
|
|
295
|
+
const name = typeof obj.name === "string" ? obj.name : id;
|
|
296
|
+
const vendor = typeof obj.vendor === "string" ? obj.vendor : "";
|
|
297
|
+
const supports = obj.capabilities?.supports;
|
|
298
|
+
const supportsVision = supports?.vision === true;
|
|
299
|
+
const supportsToolCalls = supports?.tool_calls === true;
|
|
300
|
+
const rawEndpoints = obj.supported_endpoints;
|
|
301
|
+
const supportedEndpoints = Array.isArray(rawEndpoints) ? rawEndpoints.filter((e) => typeof e === "string") : [];
|
|
302
|
+
const isAnthropicShaped = supportedEndpoints.includes("/v1/messages");
|
|
303
|
+
result.push({
|
|
304
|
+
id,
|
|
305
|
+
name,
|
|
306
|
+
vendor,
|
|
307
|
+
supportedEndpoints,
|
|
308
|
+
isAnthropicShaped,
|
|
309
|
+
supportsVision,
|
|
310
|
+
supportsToolCalls
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
return result;
|
|
296
314
|
}
|
|
297
315
|
const githubCopilotOAuthProvider = {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
COPILOT_USER_AGENT,
|
|
319
|
-
copilotNextPollDelayMs,
|
|
320
|
-
fetchCopilotModels,
|
|
321
|
-
getGitHubCopilotBaseUrl,
|
|
322
|
-
githubCopilotOAuthProvider,
|
|
323
|
-
loginGitHubCopilot,
|
|
324
|
-
normalizeDomain,
|
|
325
|
-
pollGitHubCopilotDeviceLogin,
|
|
326
|
-
refreshGitHubCopilotToken,
|
|
327
|
-
startGitHubCopilotDeviceLogin
|
|
316
|
+
id: "github-copilot",
|
|
317
|
+
name: "GitHub Copilot",
|
|
318
|
+
async login(callbacks) {
|
|
319
|
+
return loginGitHubCopilot({
|
|
320
|
+
onAuth: (url, instructions) => callbacks.onAuth({
|
|
321
|
+
url,
|
|
322
|
+
instructions
|
|
323
|
+
}),
|
|
324
|
+
onPrompt: callbacks.onPrompt,
|
|
325
|
+
onProgress: callbacks.onProgress,
|
|
326
|
+
signal: callbacks.signal
|
|
327
|
+
});
|
|
328
|
+
},
|
|
329
|
+
async refreshToken(credentials) {
|
|
330
|
+
const creds = credentials;
|
|
331
|
+
return refreshGitHubCopilotToken(creds.refresh, creds.enterpriseUrl);
|
|
332
|
+
},
|
|
333
|
+
getApiKey(credentials) {
|
|
334
|
+
return credentials.access;
|
|
335
|
+
}
|
|
328
336
|
};
|
|
337
|
+
//#endregion
|
|
338
|
+
export { COPILOT_HEADERS, COPILOT_USER_AGENT, copilotNextPollDelayMs, fetchCopilotModels, getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, loginGitHubCopilot, normalizeDomain, pollGitHubCopilotDeviceLogin, refreshGitHubCopilotToken, startGitHubCopilotDeviceLogin };
|
|
339
|
+
|
|
329
340
|
//# sourceMappingURL=github-copilot.js.map
|