opencode-openai-profiles 0.1.0

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 ADDED
@@ -0,0 +1,150 @@
1
+ # opencode-openai-profiles
2
+
3
+ OpenCode TUI plugin for switching between saved OpenAI ChatGPT Pro/Plus OAuth profiles.
4
+
5
+ OpenCode has one active `openai` auth slot. This plugin saves named copies of that auth object and swaps one into `auth.json` when you switch profiles.
6
+
7
+ ## Status
8
+
9
+ Early local-first plugin. Profile switches apply live when your OpenCode version supports runtime auth updates.
10
+
11
+ ## Install
12
+
13
+ Build from this repo:
14
+
15
+ ```bash
16
+ pnpm install
17
+ pnpm build
18
+ ```
19
+
20
+ Install the local plugin:
21
+
22
+ ```bash
23
+ opencode plugin "$PWD" --global --force
24
+ ```
25
+
26
+ The command adds the package to OpenCode's server and TUI plugin configs when OpenCode exposes both targets.
27
+
28
+ After publishing, add the package to your OpenCode config:
29
+
30
+ ```json
31
+ {
32
+ "plugin": ["opencode-openai-profiles"]
33
+ }
34
+ ```
35
+
36
+ For OpenCode versions with external TUI plugin targets, add the TUI target:
37
+
38
+ ```json
39
+ {
40
+ "plugin": ["opencode-openai-profiles/tui"]
41
+ }
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ Open the account picker:
47
+
48
+ ```text
49
+ /openai-profiles
50
+ ```
51
+
52
+ Short alias:
53
+
54
+ ```text
55
+ /oa
56
+ ```
57
+
58
+ If the TUI target is unavailable, use the CLI fallback:
59
+
60
+ ```text
61
+ /openai-account-cli save <name>
62
+ /openai-account-cli switch <name>
63
+ /openai-account-cli rename <old> <new>
64
+ /openai-account-cli list
65
+ /openai-account-cli active
66
+ /openai-account-cli login [browser|headless]
67
+ ```
68
+
69
+ ## First Setup
70
+
71
+ Save your current OpenAI account:
72
+
73
+ ```text
74
+ /openai-profiles
75
+ ```
76
+
77
+ Choose `Save Current Profile`, then enter `account-1` or another name.
78
+
79
+ If you skip this step, the plugin saves the active unsaved account as `account-1` before starting a new OpenAI login.
80
+
81
+ Log in to another account:
82
+
83
+ ```text
84
+ /openai-profiles
85
+ ```
86
+
87
+ Choose `Login to OpenAI`. Select `ChatGPT Pro/Plus (headless)` if you want to paste the final callback URL by hand.
88
+
89
+ CLI fallback:
90
+
91
+ ```text
92
+ /openai-account-cli login browser
93
+ /openai-account-cli login headless
94
+ ```
95
+
96
+ If OpenCode prompts you to restart after login, restart it before saving the new active account:
97
+
98
+ ```text
99
+ /openai-profiles
100
+ ```
101
+
102
+ Choose `Save Current Profile`, then enter `account-2` or another name.
103
+
104
+ Switch profiles:
105
+
106
+ ```text
107
+ /openai-profiles
108
+ ```
109
+
110
+ Choose `Switch Profile`, then select a saved profile.
111
+
112
+ If OpenCode cannot apply the switch live, the plugin will tell you to restart.
113
+
114
+ CLI fallback:
115
+
116
+ ```text
117
+ /openai-account-cli switch account-1
118
+ /openai-account-cli switch account-2
119
+ ```
120
+
121
+ ## Storage
122
+
123
+ OpenCode stores the active auth file here:
124
+
125
+ ```text
126
+ ~/.local/share/opencode/auth.json
127
+ ```
128
+
129
+ This plugin stores saved OpenAI profiles here:
130
+
131
+ ```text
132
+ ~/.local/share/opencode/auth-profiles/
133
+ ```
134
+
135
+ Example files:
136
+
137
+ ```text
138
+ openai-account-1.json
139
+ openai-account-2.json
140
+ ```
141
+
142
+ Each profile file contains only the `openai` OAuth object. The plugin preserves other providers in `auth.json`.
143
+
144
+ ## Security
145
+
146
+ Profile files contain OAuth tokens. Treat them as secrets.
147
+
148
+ Do not commit `auth.json` or `auth-profiles`.
149
+
150
+ The plugin never displays token values. It only shows the OpenAI `accountId` when available.
@@ -0,0 +1,21 @@
1
+ import type { OAuth } from "@opencode-ai/sdk/v2";
2
+ import { type OpenCodeAuthPaths } from "./paths.js";
3
+ export type OpenAIAuthProfile = OAuth;
4
+ export type AuthJson = Record<string, unknown> & {
5
+ openai?: unknown;
6
+ };
7
+ export type SavedProfile = {
8
+ name: string;
9
+ accountId?: string;
10
+ };
11
+ export declare function getActiveOpenAIProfile(paths: OpenCodeAuthPaths): Promise<OpenAIAuthProfile>;
12
+ export declare function saveActiveOpenAIProfile(paths: OpenCodeAuthPaths, inputProfileName: string): Promise<SavedProfile>;
13
+ export declare function saveActiveOpenAIProfileIfUnsaved(paths: OpenCodeAuthPaths): Promise<SavedProfile | undefined>;
14
+ export declare function switchActiveOpenAIProfile(paths: OpenCodeAuthPaths, inputProfileName: string): Promise<SavedProfile>;
15
+ export declare function renameOpenAIProfile(paths: OpenCodeAuthPaths, inputCurrentName: string, inputNextName: string): Promise<SavedProfile>;
16
+ export declare function setActiveOpenAIProfile(paths: OpenCodeAuthPaths, profile: OpenAIAuthProfile): Promise<OpenAIAuthProfile>;
17
+ export declare function listOpenAIProfiles(paths: OpenCodeAuthPaths): Promise<SavedProfile[]>;
18
+ export declare function openProfilesFolder(paths: OpenCodeAuthPaths): Promise<void>;
19
+ export declare function parseOpenAIAuthProfile(value: unknown): OpenAIAuthProfile;
20
+ export declare function replaceOpenAIAuthProfile(authJson: AuthJson, selectedProfile: OpenAIAuthProfile): AuthJson;
21
+ export declare function authFileExists(paths: OpenCodeAuthPaths): Promise<boolean>;
@@ -0,0 +1,270 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { constants } from "node:fs";
3
+ import { access, chmod, mkdir, readdir, readFile, rename, stat, unlink, writeFile, } from "node:fs/promises";
4
+ import { basename, join } from "node:path";
5
+ import { getProfileFileName, OPENAI_PROVIDER_ID, PROFILE_FILE_EXTENSION, PROFILE_FILE_PREFIX, } from "./paths.js";
6
+ import { parseProfileName } from "./profile-name.js";
7
+ const SECRET_FILE_MODE = 0o600;
8
+ const SECRET_DIRECTORY_MODE = 0o700;
9
+ const JSON_INDENT_SPACES = 2;
10
+ export async function getActiveOpenAIProfile(paths) {
11
+ const authJson = await readAuthJson(paths.authFilePath);
12
+ return parseOpenAIAuthProfile(authJson[OPENAI_PROVIDER_ID]);
13
+ }
14
+ export async function saveActiveOpenAIProfile(paths, inputProfileName) {
15
+ const profileName = parseProfileName(inputProfileName);
16
+ const activeProfile = await getActiveOpenAIProfile(paths);
17
+ const profileFilePath = getProfileFilePath(paths, profileName);
18
+ await ensureProfileDirectory(paths.profileDirectoryPath);
19
+ await writeSecretJsonFile(profileFilePath, activeProfile);
20
+ return createSavedProfile(profileName, activeProfile);
21
+ }
22
+ export async function saveActiveOpenAIProfileIfUnsaved(paths) {
23
+ const activeProfile = await getActiveOpenAIProfileIfPresent(paths);
24
+ if (!activeProfile) {
25
+ return undefined;
26
+ }
27
+ const savedProfiles = await listOpenAIProfiles(paths);
28
+ for (const savedProfile of savedProfiles) {
29
+ const profile = await readOpenAIProfile(paths, savedProfile.name);
30
+ if (isSameOpenAIProfile(activeProfile, profile)) {
31
+ return undefined;
32
+ }
33
+ }
34
+ const profileName = getNextDefaultProfileName(savedProfiles);
35
+ const profileFilePath = getProfileFilePath(paths, profileName);
36
+ await ensureProfileDirectory(paths.profileDirectoryPath);
37
+ await writeSecretJsonFile(profileFilePath, activeProfile);
38
+ return createSavedProfile(profileName, activeProfile);
39
+ }
40
+ export async function switchActiveOpenAIProfile(paths, inputProfileName) {
41
+ const profileName = parseProfileName(inputProfileName);
42
+ const selectedProfile = await readOpenAIProfile(paths, profileName);
43
+ const authJson = await readAuthJson(paths.authFilePath);
44
+ authJson[OPENAI_PROVIDER_ID] = selectedProfile;
45
+ await writeAuthJsonAtomically(paths.authFilePath, authJson);
46
+ return createSavedProfile(profileName, selectedProfile);
47
+ }
48
+ export async function renameOpenAIProfile(paths, inputCurrentName, inputNextName) {
49
+ const currentName = parseProfileName(inputCurrentName);
50
+ const nextName = parseProfileName(inputNextName);
51
+ if (currentName === nextName) {
52
+ throw new Error("Profile names must be different");
53
+ }
54
+ const currentProfileFilePath = getProfileFilePath(paths, currentName);
55
+ const nextProfileFilePath = getProfileFilePath(paths, nextName);
56
+ const profile = await readOpenAIProfile(paths, currentName);
57
+ if (await fileExists(nextProfileFilePath)) {
58
+ throw new Error(`Profile already exists: ${nextName}`);
59
+ }
60
+ await ensureProfileDirectory(paths.profileDirectoryPath);
61
+ await rename(currentProfileFilePath, nextProfileFilePath);
62
+ await chmod(nextProfileFilePath, SECRET_FILE_MODE);
63
+ return createSavedProfile(nextName, profile);
64
+ }
65
+ export async function setActiveOpenAIProfile(paths, profile) {
66
+ const authJson = await readAuthJson(paths.authFilePath);
67
+ authJson[OPENAI_PROVIDER_ID] = profile;
68
+ await writeAuthJsonAtomically(paths.authFilePath, authJson);
69
+ return profile;
70
+ }
71
+ export async function listOpenAIProfiles(paths) {
72
+ let profileFileNames;
73
+ try {
74
+ profileFileNames = await readdir(paths.profileDirectoryPath);
75
+ }
76
+ catch (error) {
77
+ if (isNodeErrorWithCode(error, "ENOENT")) {
78
+ return [];
79
+ }
80
+ throw error;
81
+ }
82
+ const savedProfiles = [];
83
+ for (const profileFileName of profileFileNames) {
84
+ const profileName = parseProfileNameFromFileName(profileFileName);
85
+ if (!profileName) {
86
+ continue;
87
+ }
88
+ const profile = await readOpenAIProfile(paths, profileName);
89
+ savedProfiles.push(createSavedProfile(profileName, profile));
90
+ }
91
+ return savedProfiles.sort((leftProfile, rightProfile) => leftProfile.name.localeCompare(rightProfile.name));
92
+ }
93
+ export async function openProfilesFolder(paths) {
94
+ await ensureProfileDirectory(paths.profileDirectoryPath);
95
+ }
96
+ export function parseOpenAIAuthProfile(value) {
97
+ if (!isRecord(value)) {
98
+ throw new Error("OpenAI auth profile is missing or invalid");
99
+ }
100
+ if (value.type !== "oauth") {
101
+ throw new Error("OpenAI auth profile must be an oauth profile");
102
+ }
103
+ if (typeof value.refresh !== "string" || value.refresh.length === 0) {
104
+ throw new Error("OpenAI auth profile is missing a refresh token");
105
+ }
106
+ if (typeof value.access !== "string" || value.access.length === 0) {
107
+ throw new Error("OpenAI auth profile is missing an access token");
108
+ }
109
+ if (typeof value.expires !== "number" || !Number.isFinite(value.expires)) {
110
+ throw new Error("OpenAI auth profile is missing a valid expiration timestamp");
111
+ }
112
+ return value;
113
+ }
114
+ export function replaceOpenAIAuthProfile(authJson, selectedProfile) {
115
+ return {
116
+ ...authJson,
117
+ [OPENAI_PROVIDER_ID]: selectedProfile,
118
+ };
119
+ }
120
+ function createSavedProfile(profileName, profile) {
121
+ if (profile.accountId) {
122
+ return {
123
+ name: profileName,
124
+ accountId: profile.accountId,
125
+ };
126
+ }
127
+ return {
128
+ name: profileName,
129
+ };
130
+ }
131
+ async function readOpenAIProfile(paths, profileName) {
132
+ const profileFilePath = getProfileFilePath(paths, profileName);
133
+ const profileJson = await readJsonFile(profileFilePath);
134
+ return parseOpenAIAuthProfile(profileJson);
135
+ }
136
+ async function readAuthJson(authFilePath) {
137
+ const authJson = await readJsonFile(authFilePath);
138
+ if (!isRecord(authJson)) {
139
+ throw new Error("opencode auth.json must contain a JSON object");
140
+ }
141
+ return authJson;
142
+ }
143
+ async function getActiveOpenAIProfileIfPresent(paths) {
144
+ let authJson;
145
+ try {
146
+ authJson = await readAuthJson(paths.authFilePath);
147
+ }
148
+ catch (error) {
149
+ if (isNodeErrorWithCode(error, "ENOENT")) {
150
+ return undefined;
151
+ }
152
+ throw error;
153
+ }
154
+ if (!(OPENAI_PROVIDER_ID in authJson)) {
155
+ return undefined;
156
+ }
157
+ return parseOpenAIAuthProfile(authJson[OPENAI_PROVIDER_ID]);
158
+ }
159
+ function getNextDefaultProfileName(savedProfiles) {
160
+ const usedProfileNames = new Set(savedProfiles.map((profile) => profile.name));
161
+ let nextProfileIndex = 1;
162
+ while (usedProfileNames.has(`account-${nextProfileIndex}`)) {
163
+ nextProfileIndex += 1;
164
+ }
165
+ return `account-${nextProfileIndex}`;
166
+ }
167
+ function isSameOpenAIProfile(leftProfile, rightProfile) {
168
+ if (leftProfile.accountId && rightProfile.accountId) {
169
+ return leftProfile.accountId === rightProfile.accountId;
170
+ }
171
+ return leftProfile.refresh === rightProfile.refresh;
172
+ }
173
+ async function readJsonFile(filePath) {
174
+ const fileContents = await readFile(filePath, "utf8");
175
+ return JSON.parse(fileContents);
176
+ }
177
+ async function writeAuthJsonAtomically(authFilePath, authJson) {
178
+ const temporaryFilePath = `${authFilePath}.tmp-${randomUUID()}`;
179
+ const fileMode = await getExistingFileMode(authFilePath);
180
+ try {
181
+ await writeFile(temporaryFilePath, `${JSON.stringify(authJson, null, JSON_INDENT_SPACES)}\n`, { mode: fileMode });
182
+ await chmod(temporaryFilePath, fileMode);
183
+ await rename(temporaryFilePath, authFilePath);
184
+ }
185
+ catch (error) {
186
+ await unlinkIfExists(temporaryFilePath);
187
+ throw error;
188
+ }
189
+ }
190
+ async function writeSecretJsonFile(filePath, value) {
191
+ await writeFile(filePath, `${JSON.stringify(value, null, JSON_INDENT_SPACES)}\n`, { mode: SECRET_FILE_MODE });
192
+ await chmod(filePath, SECRET_FILE_MODE);
193
+ }
194
+ async function ensureProfileDirectory(profileDirectoryPath) {
195
+ await mkdir(profileDirectoryPath, {
196
+ recursive: true,
197
+ mode: SECRET_DIRECTORY_MODE,
198
+ });
199
+ await chmod(profileDirectoryPath, SECRET_DIRECTORY_MODE);
200
+ }
201
+ async function getExistingFileMode(filePath) {
202
+ try {
203
+ const fileStats = await stat(filePath);
204
+ return fileStats.mode & 0o777;
205
+ }
206
+ catch (error) {
207
+ if (isNodeErrorWithCode(error, "ENOENT")) {
208
+ return SECRET_FILE_MODE;
209
+ }
210
+ throw error;
211
+ }
212
+ }
213
+ async function unlinkIfExists(filePath) {
214
+ try {
215
+ await unlink(filePath);
216
+ }
217
+ catch (error) {
218
+ if (!isNodeErrorWithCode(error, "ENOENT")) {
219
+ throw error;
220
+ }
221
+ }
222
+ }
223
+ async function fileExists(filePath) {
224
+ try {
225
+ await access(filePath, constants.F_OK);
226
+ return true;
227
+ }
228
+ catch (error) {
229
+ if (isNodeErrorWithCode(error, "ENOENT")) {
230
+ return false;
231
+ }
232
+ throw error;
233
+ }
234
+ }
235
+ function getProfileFilePath(paths, profileName) {
236
+ return join(paths.profileDirectoryPath, getProfileFileName(profileName));
237
+ }
238
+ function parseProfileNameFromFileName(profileFileName) {
239
+ const safeFileName = basename(profileFileName);
240
+ if (!safeFileName.startsWith(PROFILE_FILE_PREFIX) ||
241
+ !safeFileName.endsWith(PROFILE_FILE_EXTENSION)) {
242
+ return undefined;
243
+ }
244
+ const profileName = safeFileName.slice(PROFILE_FILE_PREFIX.length, -PROFILE_FILE_EXTENSION.length);
245
+ try {
246
+ return parseProfileName(profileName);
247
+ }
248
+ catch {
249
+ return undefined;
250
+ }
251
+ }
252
+ function isRecord(value) {
253
+ return typeof value === "object" && value !== null && !Array.isArray(value);
254
+ }
255
+ function isNodeErrorWithCode(error, code) {
256
+ return error instanceof Error && "code" in error && error.code === code;
257
+ }
258
+ export async function authFileExists(paths) {
259
+ try {
260
+ await access(paths.authFilePath, constants.R_OK);
261
+ return true;
262
+ }
263
+ catch (error) {
264
+ if (isNodeErrorWithCode(error, "ENOENT")) {
265
+ return false;
266
+ }
267
+ throw error;
268
+ }
269
+ }
270
+ //# sourceMappingURL=auth-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../src/auth-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { OpenAIAuthProfile } from "./auth-store.js";
2
+ export type ManualCodexLogin = {
3
+ url: string;
4
+ state: string;
5
+ verifier: string;
6
+ };
7
+ export declare function createManualCodexLogin(): Promise<ManualCodexLogin>;
8
+ export declare function completeManualCodexLogin(login: ManualCodexLogin, callbackUrlOrCode: string): Promise<OpenAIAuthProfile>;
9
+ export declare function extractAuthorizationCode(callbackUrlOrCode: string, expectedState: string): string;
@@ -0,0 +1,126 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
3
+ const ISSUER = "https://auth.openai.com";
4
+ const REDIRECT_URI = "http://localhost:1455/auth/callback";
5
+ const PKCE_VERIFIER_LENGTH = 43;
6
+ const STATE_BYTE_LENGTH = 32;
7
+ const OAUTH_TOKEN_PATH = "/oauth/token";
8
+ export async function createManualCodexLogin() {
9
+ const pkce = createPkceCodes();
10
+ const state = createState();
11
+ return {
12
+ url: buildAuthorizeUrl(pkce.challenge, state),
13
+ state,
14
+ verifier: pkce.verifier,
15
+ };
16
+ }
17
+ export async function completeManualCodexLogin(login, callbackUrlOrCode) {
18
+ const code = extractAuthorizationCode(callbackUrlOrCode, login.state);
19
+ const tokenResponse = await exchangeCodeForTokens(code, login.verifier);
20
+ const accountId = extractAccountId(tokenResponse);
21
+ return {
22
+ type: "oauth",
23
+ refresh: tokenResponse.refresh_token,
24
+ access: tokenResponse.access_token,
25
+ expires: Date.now() + (tokenResponse.expires_in ?? 3600) * 1000,
26
+ ...(accountId ? { accountId } : {}),
27
+ };
28
+ }
29
+ export function extractAuthorizationCode(callbackUrlOrCode, expectedState) {
30
+ const trimmedInput = callbackUrlOrCode.trim();
31
+ if (trimmedInput.length === 0) {
32
+ throw new Error("Paste the callback URL or authorization code");
33
+ }
34
+ try {
35
+ const callbackUrl = new URL(trimmedInput);
36
+ const callbackError = callbackUrl.searchParams.get("error");
37
+ if (callbackError) {
38
+ throw new Error(callbackUrl.searchParams.get("error_description") ?? callbackError);
39
+ }
40
+ const state = callbackUrl.searchParams.get("state");
41
+ if (state !== expectedState) {
42
+ throw new Error("Callback URL state does not match this login attempt");
43
+ }
44
+ const code = callbackUrl.searchParams.get("code");
45
+ if (!code) {
46
+ throw new Error("Callback URL is missing an authorization code");
47
+ }
48
+ return code;
49
+ }
50
+ catch (error) {
51
+ if (error instanceof TypeError) {
52
+ return trimmedInput;
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ function createPkceCodes() {
58
+ const verifier = generateRandomString(PKCE_VERIFIER_LENGTH);
59
+ const challenge = base64UrlEncode(createHash("sha256").update(verifier).digest());
60
+ return { verifier, challenge };
61
+ }
62
+ function createState() {
63
+ return base64UrlEncode(randomBytes(STATE_BYTE_LENGTH));
64
+ }
65
+ function buildAuthorizeUrl(challenge, state) {
66
+ const params = new URLSearchParams({
67
+ response_type: "code",
68
+ client_id: CLIENT_ID,
69
+ redirect_uri: REDIRECT_URI,
70
+ scope: "openid profile email offline_access",
71
+ code_challenge: challenge,
72
+ code_challenge_method: "S256",
73
+ id_token_add_organizations: "true",
74
+ codex_cli_simplified_flow: "true",
75
+ state,
76
+ originator: "opencode",
77
+ });
78
+ return `${ISSUER}/oauth/authorize?${params.toString()}`;
79
+ }
80
+ async function exchangeCodeForTokens(code, verifier) {
81
+ const response = await fetch(`${ISSUER}${OAUTH_TOKEN_PATH}`, {
82
+ method: "POST",
83
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
84
+ body: new URLSearchParams({
85
+ grant_type: "authorization_code",
86
+ code,
87
+ redirect_uri: REDIRECT_URI,
88
+ client_id: CLIENT_ID,
89
+ code_verifier: verifier,
90
+ }).toString(),
91
+ });
92
+ if (!response.ok) {
93
+ throw new Error(`Token exchange failed: ${response.status}`);
94
+ }
95
+ return (await response.json());
96
+ }
97
+ function extractAccountId(tokenResponse) {
98
+ if (tokenResponse.id_token) {
99
+ return extractAccountIdFromToken(tokenResponse.id_token);
100
+ }
101
+ return extractAccountIdFromToken(tokenResponse.access_token);
102
+ }
103
+ function extractAccountIdFromToken(token) {
104
+ const tokenParts = token.split(".");
105
+ if (tokenParts.length !== 3 || !tokenParts[1]) {
106
+ return undefined;
107
+ }
108
+ try {
109
+ const claims = JSON.parse(Buffer.from(tokenParts[1], "base64url").toString());
110
+ return (claims.chatgpt_account_id ??
111
+ claims["https://api.openai.com/auth"]?.chatgpt_account_id ??
112
+ claims.organizations?.[0]?.id);
113
+ }
114
+ catch {
115
+ return undefined;
116
+ }
117
+ }
118
+ function generateRandomString(length) {
119
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
120
+ const bytes = randomBytes(length);
121
+ return Array.from(bytes, (byte) => chars[byte % chars.length]).join("");
122
+ }
123
+ function base64UrlEncode(buffer) {
124
+ return buffer.toString("base64url");
125
+ }
126
+ //# sourceMappingURL=codex-oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-oauth.js","sourceRoot":"","sources":["../src/codex-oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ import type { TuiPluginApi } from "@opencode-ai/plugin/tui";
3
+ export declare const id = "opencode-openai-profiles";
4
+ export declare const OpenAIAccountSwitcherPlugin: Plugin;
5
+ export default OpenAIAccountSwitcherPlugin;
6
+ export declare const tui: (inputApi: TuiPluginApi | Record<string, unknown>) => Promise<void>;