@gnahz77/opencode-copilot-multi-auth 0.1.0 → 0.1.2
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/README.md +56 -7
- package/dist/auth.d.ts +18 -0
- package/dist/auth.js +195 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.js +28 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +6 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +309 -0
- package/dist/models.d.ts +193 -0
- package/dist/models.js +150 -0
- package/dist/pool.d.ts +8 -0
- package/dist/pool.js +157 -0
- package/dist/routing.d.ts +8 -0
- package/dist/routing.js +12 -0
- package/dist/tui.d.ts +5 -0
- package/dist/tui.js +44 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.js +1 -0
- package/dist/usage.d.ts +11 -0
- package/dist/usage.js +113 -0
- package/dist/utils.d.ts +28 -0
- package/dist/utils.js +216 -0
- package/index.mjs +12 -1211
- package/package.json +28 -3
package/README.md
CHANGED
|
@@ -12,26 +12,73 @@ Add the plugin to your `opencode` config:
|
|
|
12
12
|
{
|
|
13
13
|
"$schema": "https://opencode.ai/config.json",
|
|
14
14
|
"plugin": [
|
|
15
|
-
"@gnahz77/opencode-copilot-multi-auth@0.1.
|
|
15
|
+
"@gnahz77/opencode-copilot-multi-auth@0.1.2"
|
|
16
16
|
]
|
|
17
17
|
}
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
Then start `opencode` and log in to the `github-copilot` provider. The plugin handles the Copilot CLI-style device flow and will reuse the stored GitHub OAuth token afterward.
|
|
21
21
|
|
|
22
|
+
If you also want the TUI command support provided by this package, add the same plugin to your `tui.json` or `tui.jsonc`:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"$schema": "https://opencode.ai/tui.json",
|
|
27
|
+
"plugin": [
|
|
28
|
+
"@gnahz77/opencode-copilot-multi-auth@0.1.2"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
After restarting OpenCode TUI, you can open the command palette and run `copilot-usage`, or type `/copilot-usage`.
|
|
34
|
+
The plugin will open a popup dialog showing all accounts currently stored in `~/.local/share/opencode/copilot-auth.json`.
|
|
35
|
+
|
|
22
36
|
For local development before publishing, you can load the file directly:
|
|
23
37
|
|
|
24
38
|
```json
|
|
25
39
|
{
|
|
26
40
|
"$schema": "https://opencode.ai/config.json",
|
|
27
41
|
"plugin": [
|
|
28
|
-
"file:///absolute/path/to/index.
|
|
42
|
+
"file:///absolute/path/to/dist/index.js"
|
|
29
43
|
]
|
|
30
44
|
}
|
|
31
45
|
```
|
|
32
46
|
|
|
33
47
|
Important: if the file path contains `opencode-copilot-auth`, current `opencode` builds may skip loading it because of a hardcoded plugin-name filter. Use a path that does not contain that substring.
|
|
34
48
|
|
|
49
|
+
If you are loading the plugin locally during development and want to use `copilot-usage`, add the built TUI entry to your TUI config as well:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"$schema": "https://opencode.ai/tui.json",
|
|
54
|
+
"plugin": [
|
|
55
|
+
"file:///absolute/path/to/dist/tui.js"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## `copilot-usage` command
|
|
61
|
+
|
|
62
|
+
This package now includes a TUI command named `copilot-usage`.
|
|
63
|
+
|
|
64
|
+
- Command palette entry: `copilot-usage`
|
|
65
|
+
- Slash command: `/copilot-usage`
|
|
66
|
+
|
|
67
|
+
What it does:
|
|
68
|
+
|
|
69
|
+
- Reads every Copilot account stored in `~/.local/share/opencode/copilot-auth.json`
|
|
70
|
+
- Calls the GitHub Copilot entitlement endpoint `/copilot_internal/user` for each account using that account's OAuth token
|
|
71
|
+
- Opens a popup dialog showing, for each account:
|
|
72
|
+
- account name
|
|
73
|
+
- used / total usage bar
|
|
74
|
+
- used percentage
|
|
75
|
+
|
|
76
|
+
Notes:
|
|
77
|
+
|
|
78
|
+
- The command is part of the package's TUI target, so `opencode.json` alone is not enough; `tui.json` must also load the plugin.
|
|
79
|
+
- Disabled accounts are still shown in the popup and are marked as disabled.
|
|
80
|
+
- If one account fails to load usage data, the popup still shows the other accounts and includes the per-account error message inline.
|
|
81
|
+
|
|
35
82
|
## What changed in this fork
|
|
36
83
|
|
|
37
84
|
- Auth flow: uses the Copilot CLI-style OAuth client flow and keeps the GitHub OAuth token directly.
|
|
@@ -110,11 +157,13 @@ The pool stores one object per account under `accounts` in a `version: 1` docume
|
|
|
110
157
|
| `id` | Stable human-friendly identifier stored with the account record. |
|
|
111
158
|
| `name` | Display name for the account. |
|
|
112
159
|
| `enabled` | Whether the account can participate in automatic routing. Disabled accounts stay stored but are ignored for winner selection. |
|
|
113
|
-
| `priority` |
|
|
114
|
-
| `allowlist` |
|
|
115
|
-
| `blocklist` |
|
|
160
|
+
| `priority` | Lower values win when multiple enabled accounts can serve the same raw model ID. |
|
|
161
|
+
| `allowlist` | Raw model IDs or `*` wildcard patterns this account is allowed to serve. If non-empty, the account can only serve models that match one of these entries. |
|
|
162
|
+
| `blocklist` | Raw model IDs or `*` wildcard patterns this account must never serve. If both `allowlist` and `blocklist` are non-empty, the plugin checks `allowlist` first and then applies `blocklist`. |
|
|
163
|
+
|
|
164
|
+
Automatic routing works on the raw Copilot model IDs that `opencode` already uses. The plugin filters eligible accounts by `enabled`, then checks `allowlist` first (when non-empty, the model must match one of its exact entries or wildcard patterns), then applies `blocklist`, and finally picks exactly one winning account by lowest `priority` (with a stable key-based tie-breaker). The model ID itself is not rewritten, so account identity does not appear in model IDs.
|
|
116
165
|
|
|
117
|
-
|
|
166
|
+
Wildcard matching is case-sensitive and currently supports `*` for zero or more characters anywhere in the pattern. For example, `claude-*` matches `claude-sonnet-4.6` and `claude-opus-4.6`.
|
|
118
167
|
|
|
119
168
|
Example pool file:
|
|
120
169
|
|
|
@@ -128,7 +177,7 @@ Example pool file:
|
|
|
128
177
|
"name": "Work",
|
|
129
178
|
"enabled": true,
|
|
130
179
|
"priority": 100,
|
|
131
|
-
"allowlist": ["claude
|
|
180
|
+
"allowlist": ["claude-*"],
|
|
132
181
|
"blocklist": [],
|
|
133
182
|
"deployment": "github.com",
|
|
134
183
|
"domain": "github.com",
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AccountPool, AuthInput, PoolAccount } from "./types.js";
|
|
2
|
+
export declare function getUrls(domain: string): {
|
|
3
|
+
DEVICE_CODE_URL: string;
|
|
4
|
+
ACCESS_TOKEN_URL: string;
|
|
5
|
+
COPILOT_ENTITLEMENT_URL: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function lookupGitHubIdentity(accessToken: string, enterpriseUrl?: string): Promise<{
|
|
8
|
+
login: any;
|
|
9
|
+
userId: number;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function fetchEntitlement(info: AuthInput): Promise<any>;
|
|
12
|
+
export declare function getBaseURL(info: AuthInput): Promise<any>;
|
|
13
|
+
export declare function buildHeaders(init: RequestInit | undefined, info: AuthInput, isVision: boolean, isAgent: boolean): {
|
|
14
|
+
[k: string]: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function resolveSelectedPoolAccount(pool: AccountPool, accountKey?: string, requestedRawModelId?: string): PoolAccount | null;
|
|
17
|
+
export declare function refreshSelectedAccountBaseURL(accountKey: string): Promise<PoolAccount>;
|
|
18
|
+
export declare function fetchWithSelectedAccount(input: RequestInfo | URL, init: RequestInit | undefined, selectedAccount: PoolAccount): Promise<Response>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { API_VERSION } from "./constants.js";
|
|
2
|
+
import { getSelectedAccountExpiredError, getSelectedAccountMissingError } from "./errors.js";
|
|
3
|
+
import { readPool, resolveWinnerAccount, writePool } from "./pool.js";
|
|
4
|
+
import { stripRoutingHeaders } from "./routing.js";
|
|
5
|
+
import { applyBaseURLToRequestInput, getConversationMetadata, isValidBaseURL, normalizeDomain, normalizeHeaderObject, } from "./utils.js";
|
|
6
|
+
export function getUrls(domain) {
|
|
7
|
+
const apiDomain = domain === "github.com" ? "api.github.com" : `api.${domain}`;
|
|
8
|
+
return {
|
|
9
|
+
DEVICE_CODE_URL: `https://${domain}/login/device/code`,
|
|
10
|
+
ACCESS_TOKEN_URL: `https://${domain}/login/oauth/access_token`,
|
|
11
|
+
COPILOT_ENTITLEMENT_URL: `https://${apiDomain}/copilot_internal/user`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export async function lookupGitHubIdentity(accessToken, enterpriseUrl) {
|
|
15
|
+
const deployment = enterpriseUrl ? normalizeDomain(enterpriseUrl) : "github.com";
|
|
16
|
+
const apiDomain = deployment === "github.com" ? "api.github.com" : `api.${deployment}`;
|
|
17
|
+
const identityUrl = `https://${apiDomain}/user`;
|
|
18
|
+
const response = await fetch(identityUrl, {
|
|
19
|
+
method: "GET",
|
|
20
|
+
headers: {
|
|
21
|
+
Accept: "application/json",
|
|
22
|
+
Authorization: `Bearer ${accessToken}`,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`[opencode-copilot-cli-auth] Failed to lookup GitHub identity from ${identityUrl}: ${response.status} ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
const payload = await response.json();
|
|
29
|
+
const userId = Number(payload?.id);
|
|
30
|
+
if (!Number.isFinite(userId)) {
|
|
31
|
+
throw new Error("[opencode-copilot-cli-auth] Failed to lookup GitHub identity: response did not include a numeric user id.");
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
login: typeof payload?.login === "string" ? payload.login : "",
|
|
35
|
+
userId,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export async function fetchEntitlement(info) {
|
|
39
|
+
const domain = info.enterpriseUrl ? normalizeDomain(info.enterpriseUrl) : "github.com";
|
|
40
|
+
const urls = getUrls(domain);
|
|
41
|
+
const response = await fetch(urls.COPILOT_ENTITLEMENT_URL, {
|
|
42
|
+
headers: {
|
|
43
|
+
Accept: "application/json",
|
|
44
|
+
Authorization: `Bearer ${info.refresh}`,
|
|
45
|
+
"User-Agent": "GithubCopilot/1.155.0",
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`[opencode-copilot-cli-auth] Entitlement fetch failed: ${response.status}`);
|
|
50
|
+
}
|
|
51
|
+
return response.json();
|
|
52
|
+
}
|
|
53
|
+
export async function getBaseURL(info) {
|
|
54
|
+
if (info.baseUrl)
|
|
55
|
+
return info.baseUrl;
|
|
56
|
+
const entitlement = await fetchEntitlement(info);
|
|
57
|
+
return entitlement?.endpoints?.api;
|
|
58
|
+
}
|
|
59
|
+
function getHeader(headers, name) {
|
|
60
|
+
if (!headers)
|
|
61
|
+
return undefined;
|
|
62
|
+
const target = name.toLowerCase();
|
|
63
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
64
|
+
return headers.get(name) ?? headers.get(target) ?? undefined;
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(headers)) {
|
|
67
|
+
const found = headers.find(([key]) => String(key).toLowerCase() === target);
|
|
68
|
+
return typeof found?.[1] === "string" ? found[1] : undefined;
|
|
69
|
+
}
|
|
70
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
71
|
+
if (key.toLowerCase() === target) {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
export function buildHeaders(init, info, isVision, isAgent) {
|
|
78
|
+
const explicitInitiator = getHeader(init?.headers, "x-initiator");
|
|
79
|
+
const headers = {
|
|
80
|
+
...normalizeHeaderObject(init?.headers),
|
|
81
|
+
Authorization: `Bearer ${info.refresh}`,
|
|
82
|
+
"Copilot-Integration-Id": "copilot-developer-cli",
|
|
83
|
+
"Openai-Intent": "conversation-agent",
|
|
84
|
+
"User-Agent": "opencode-copilot-cli-auth/0.0.16",
|
|
85
|
+
"X-GitHub-Api-Version": API_VERSION,
|
|
86
|
+
"X-Initiator": explicitInitiator ?? (isAgent ? "agent" : "user"),
|
|
87
|
+
"X-Interaction-Id": crypto.randomUUID(),
|
|
88
|
+
"X-Interaction-Type": "conversation-agent",
|
|
89
|
+
"X-Request-Id": crypto.randomUUID(),
|
|
90
|
+
};
|
|
91
|
+
if (isVision) {
|
|
92
|
+
headers["Copilot-Vision-Request"] = "true";
|
|
93
|
+
}
|
|
94
|
+
delete headers["x-api-key"];
|
|
95
|
+
delete headers.authorization;
|
|
96
|
+
delete headers["x-initiator"];
|
|
97
|
+
return stripRoutingHeaders(headers);
|
|
98
|
+
}
|
|
99
|
+
export function resolveSelectedPoolAccount(pool, accountKey, requestedRawModelId) {
|
|
100
|
+
const accounts = Array.isArray(pool?.accounts) ? pool.accounts : [];
|
|
101
|
+
if (accounts.length === 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
let selectedAccount = null;
|
|
105
|
+
if (accountKey) {
|
|
106
|
+
const headerAccount = accounts.find((account) => account?.key === accountKey);
|
|
107
|
+
if (!headerAccount || headerAccount.enabled === false) {
|
|
108
|
+
throw getSelectedAccountMissingError();
|
|
109
|
+
}
|
|
110
|
+
selectedAccount = headerAccount;
|
|
111
|
+
}
|
|
112
|
+
if (requestedRawModelId) {
|
|
113
|
+
const winner = resolveWinnerAccount(requestedRawModelId, pool);
|
|
114
|
+
if (!winner) {
|
|
115
|
+
throw new Error(`[opencode-copilot-cli-auth] No eligible account found for model ${requestedRawModelId}; re-login required`);
|
|
116
|
+
}
|
|
117
|
+
if (selectedAccount && winner.key !== selectedAccount.key) {
|
|
118
|
+
throw new Error(`[opencode-copilot-cli-auth] Selected account cannot serve model ${requestedRawModelId}; re-login required`);
|
|
119
|
+
}
|
|
120
|
+
selectedAccount = winner;
|
|
121
|
+
}
|
|
122
|
+
if (!selectedAccount) {
|
|
123
|
+
throw new Error("[opencode-copilot-cli-auth] No eligible account found for routed request; re-login required");
|
|
124
|
+
}
|
|
125
|
+
if (selectedAccount.auth?.type !== "oauth"
|
|
126
|
+
|| typeof selectedAccount.auth.refresh !== "string"
|
|
127
|
+
|| !selectedAccount.auth.refresh.trim()) {
|
|
128
|
+
throw getSelectedAccountExpiredError(selectedAccount.key ?? "unknown");
|
|
129
|
+
}
|
|
130
|
+
return selectedAccount;
|
|
131
|
+
}
|
|
132
|
+
export async function refreshSelectedAccountBaseURL(accountKey) {
|
|
133
|
+
const currentPool = readPool();
|
|
134
|
+
const accountIndex = currentPool.accounts.findIndex((account) => account?.key === accountKey);
|
|
135
|
+
const currentAccount = accountIndex >= 0 ? currentPool.accounts[accountIndex] : null;
|
|
136
|
+
if (!currentAccount || currentAccount.enabled === false) {
|
|
137
|
+
throw getSelectedAccountMissingError();
|
|
138
|
+
}
|
|
139
|
+
if (currentAccount.auth?.type !== "oauth"
|
|
140
|
+
|| typeof currentAccount.auth.refresh !== "string"
|
|
141
|
+
|| !currentAccount.auth.refresh.trim()) {
|
|
142
|
+
throw getSelectedAccountExpiredError(currentAccount.key ?? accountKey ?? "unknown");
|
|
143
|
+
}
|
|
144
|
+
let entitlement;
|
|
145
|
+
try {
|
|
146
|
+
entitlement = await fetchEntitlement({
|
|
147
|
+
refresh: currentAccount.auth.refresh,
|
|
148
|
+
enterpriseUrl: currentAccount.enterpriseUrl ?? null,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
throw getSelectedAccountExpiredError(currentAccount.key);
|
|
153
|
+
}
|
|
154
|
+
const nextBaseURL = entitlement?.endpoints?.api;
|
|
155
|
+
if (!isValidBaseURL(nextBaseURL)) {
|
|
156
|
+
throw getSelectedAccountExpiredError(currentAccount.key);
|
|
157
|
+
}
|
|
158
|
+
const updatedPool = {
|
|
159
|
+
...currentPool,
|
|
160
|
+
accounts: currentPool.accounts.map((account, index) => index === accountIndex
|
|
161
|
+
? {
|
|
162
|
+
...account,
|
|
163
|
+
baseUrl: nextBaseURL,
|
|
164
|
+
updatedAt: new Date().toISOString(),
|
|
165
|
+
}
|
|
166
|
+
: account),
|
|
167
|
+
};
|
|
168
|
+
writePool(updatedPool);
|
|
169
|
+
return updatedPool.accounts[accountIndex];
|
|
170
|
+
}
|
|
171
|
+
export async function fetchWithSelectedAccount(input, init, selectedAccount) {
|
|
172
|
+
const { isVision, isAgent } = getConversationMetadata(init);
|
|
173
|
+
const dispatch = async (account) => {
|
|
174
|
+
const headers = buildHeaders(init, account.auth, isVision, isAgent);
|
|
175
|
+
const requestInput = applyBaseURLToRequestInput(input, account.baseUrl);
|
|
176
|
+
return fetch(requestInput, {
|
|
177
|
+
...init,
|
|
178
|
+
headers,
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
let activeAccount = selectedAccount;
|
|
182
|
+
if (!isValidBaseURL(activeAccount.baseUrl)) {
|
|
183
|
+
activeAccount = await refreshSelectedAccountBaseURL(activeAccount.key);
|
|
184
|
+
}
|
|
185
|
+
const response = await dispatch(activeAccount);
|
|
186
|
+
if (![401, 403].includes(response.status)) {
|
|
187
|
+
return response;
|
|
188
|
+
}
|
|
189
|
+
const refreshedAccount = await refreshSelectedAccountBaseURL(activeAccount.key);
|
|
190
|
+
const retryResponse = await dispatch(refreshedAccount);
|
|
191
|
+
if ([401, 403].includes(retryResponse.status)) {
|
|
192
|
+
throw getSelectedAccountExpiredError(refreshedAccount.key);
|
|
193
|
+
}
|
|
194
|
+
return retryResponse;
|
|
195
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const ACCOUNT_POOL_SCHEMA_VERSION = 1;
|
|
2
|
+
export declare const ROUTING_ACCOUNT_KEY_HEADER = "x-opencode-copilot-account-key";
|
|
3
|
+
export declare const ROUTING_SOURCE_HEADER = "x-opencode-copilot-route-source";
|
|
4
|
+
export declare const INTERNAL_ROUTING_HEADERS: Set<string>;
|
|
5
|
+
export declare const CLIENT_ID = "Ov23ctDVkRmgkPke0Mmm";
|
|
6
|
+
export declare const API_VERSION = "2025-05-01";
|
|
7
|
+
export declare const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000;
|
|
8
|
+
export declare const OAUTH_SCOPES = "read:user read:org repo gist";
|
|
9
|
+
export declare const RESPONSES_API_ALTERNATE_INPUT_TYPES: readonly ["file_search_call", "computer_call", "computer_call_output", "web_search_call", "function_call", "function_call_output", "image_generation_call", "code_interpreter_call", "local_shell_call", "local_shell_call_output", "mcp_list_tools", "mcp_approval_request", "mcp_approval_response", "mcp_call", "reasoning"];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const ACCOUNT_POOL_SCHEMA_VERSION = 1;
|
|
2
|
+
export const ROUTING_ACCOUNT_KEY_HEADER = "x-opencode-copilot-account-key";
|
|
3
|
+
export const ROUTING_SOURCE_HEADER = "x-opencode-copilot-route-source";
|
|
4
|
+
export const INTERNAL_ROUTING_HEADERS = new Set([
|
|
5
|
+
ROUTING_ACCOUNT_KEY_HEADER,
|
|
6
|
+
ROUTING_SOURCE_HEADER,
|
|
7
|
+
]);
|
|
8
|
+
export const CLIENT_ID = "Ov23ctDVkRmgkPke0Mmm";
|
|
9
|
+
export const API_VERSION = "2025-05-01";
|
|
10
|
+
export const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000;
|
|
11
|
+
export const OAUTH_SCOPES = "read:user read:org repo gist";
|
|
12
|
+
export const RESPONSES_API_ALTERNATE_INPUT_TYPES = [
|
|
13
|
+
"file_search_call",
|
|
14
|
+
"computer_call",
|
|
15
|
+
"computer_call_output",
|
|
16
|
+
"web_search_call",
|
|
17
|
+
"function_call",
|
|
18
|
+
"function_call_output",
|
|
19
|
+
"image_generation_call",
|
|
20
|
+
"code_interpreter_call",
|
|
21
|
+
"local_shell_call",
|
|
22
|
+
"local_shell_call_output",
|
|
23
|
+
"mcp_list_tools",
|
|
24
|
+
"mcp_approval_request",
|
|
25
|
+
"mcp_approval_response",
|
|
26
|
+
"mcp_call",
|
|
27
|
+
"reasoning",
|
|
28
|
+
];
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function getSelectedAccountMissingError() {
|
|
2
|
+
return new Error("[opencode-copilot-cli-auth] Selected account is disabled or not found; re-login required");
|
|
3
|
+
}
|
|
4
|
+
export function getSelectedAccountExpiredError(accountKey) {
|
|
5
|
+
return new Error(`[opencode-copilot-cli-auth] Account auth expired for ${accountKey}; re-login required`);
|
|
6
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
+
import { lookupGitHubIdentity } from "./auth.js";
|
|
3
|
+
import { deriveAccountKey, getPoolPath, readPool, resolveWinnerAccount, upsertAccount, writePool } from "./pool.js";
|
|
4
|
+
import { injectRoutingHeaders, stripRoutingHeaders } from "./routing.js";
|
|
5
|
+
export { getPoolPath, readPool, writePool, deriveAccountKey, lookupGitHubIdentity, upsertAccount, resolveWinnerAccount };
|
|
6
|
+
export { injectRoutingHeaders, stripRoutingHeaders };
|
|
7
|
+
export declare const CopilotAuthPlugin: Plugin;
|