opencode-openai-account-switcher 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/LICENSE +151 -0
- package/README.md +43 -0
- package/dist/auth-store.d.ts +13 -0
- package/dist/auth-store.js +43 -0
- package/dist/codex-auth-source.d.ts +16 -0
- package/dist/codex-auth-source.js +63 -0
- package/dist/codex-invalid-account.d.ts +32 -0
- package/dist/codex-invalid-account.js +106 -0
- package/dist/codex-network-retry.d.ts +2 -0
- package/dist/codex-network-retry.js +9 -0
- package/dist/codex-status-command.d.ts +56 -0
- package/dist/codex-status-command.js +341 -0
- package/dist/codex-status-fetcher.d.ts +71 -0
- package/dist/codex-status-fetcher.js +300 -0
- package/dist/codex-store.d.ts +49 -0
- package/dist/codex-store.js +267 -0
- package/dist/common-settings-actions.d.ts +15 -0
- package/dist/common-settings-actions.js +22 -0
- package/dist/common-settings-store.d.ts +17 -0
- package/dist/common-settings-store.js +72 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/menu-runtime.d.ts +81 -0
- package/dist/menu-runtime.js +141 -0
- package/dist/network-retry-engine.d.ts +33 -0
- package/dist/network-retry-engine.js +62 -0
- package/dist/plugin-hooks.d.ts +49 -0
- package/dist/plugin-hooks.js +123 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +127 -0
- package/dist/providers/codex-menu-adapter.d.ts +58 -0
- package/dist/providers/codex-menu-adapter.js +429 -0
- package/dist/providers/descriptor.d.ts +24 -0
- package/dist/providers/descriptor.js +16 -0
- package/dist/providers/registry.d.ts +15 -0
- package/dist/providers/registry.js +49 -0
- package/dist/retry/codex-policy.d.ts +5 -0
- package/dist/retry/codex-policy.js +75 -0
- package/dist/retry/common-policy.d.ts +37 -0
- package/dist/retry/common-policy.js +68 -0
- package/dist/store-paths.d.ts +4 -0
- package/dist/store-paths.js +22 -0
- package/dist/ui/ansi.d.ts +18 -0
- package/dist/ui/ansi.js +32 -0
- package/dist/ui/confirm.d.ts +1 -0
- package/dist/ui/confirm.js +14 -0
- package/dist/ui/menu.d.ts +168 -0
- package/dist/ui/menu.js +305 -0
- package/dist/ui/select.d.ts +36 -0
- package/dist/ui/select.js +350 -0
- package/dist/upstream/codex-loader-adapter.d.ts +99 -0
- package/dist/upstream/codex-loader-adapter.js +80 -0
- package/dist/upstream/codex-plugin.snapshot.d.ts +32 -0
- package/dist/upstream/codex-plugin.snapshot.js +638 -0
- package/package.json +40 -0
- package/scripts/sync-codex-upstream.mjs +348 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import process from "node:process"
|
|
4
|
+
|
|
5
|
+
const defaultOutput = path.resolve("src/upstream/codex-plugin.snapshot.ts")
|
|
6
|
+
const upstreamRepo = process.env.OPENCODE_SYNC_UPSTREAM_REPO ?? "anomalyco/opencode"
|
|
7
|
+
const upstreamBranch = process.env.OPENCODE_SYNC_UPSTREAM_BRANCH ?? "dev"
|
|
8
|
+
const upstreamPath = "packages/opencode/src/plugin/codex.ts"
|
|
9
|
+
const rawBaseUrl = (process.env.OPENCODE_SYNC_RAW_BASE_URL ?? "https://raw.githubusercontent.com").replace(/\/$/, "")
|
|
10
|
+
const defaultSourceUrl = `${rawBaseUrl}/${upstreamRepo}/${upstreamBranch}/${upstreamPath}`
|
|
11
|
+
const canonicalRepositoryUrl = `https://github.com/${upstreamRepo}`
|
|
12
|
+
|
|
13
|
+
function formatError(error) {
|
|
14
|
+
return error instanceof Error ? error.message : String(error)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createSnapshotDriftError(message) {
|
|
18
|
+
const error = new Error(`snapshot drift detected\n${message}`)
|
|
19
|
+
error.code = "SNAPSHOT_DRIFT_DETECTED"
|
|
20
|
+
return error
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function parseArgs(argv) {
|
|
24
|
+
const result = {
|
|
25
|
+
check: false,
|
|
26
|
+
output: defaultOutput,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function requireValue(flag, index) {
|
|
30
|
+
const next = argv[index + 1]
|
|
31
|
+
if (!next || next.startsWith("--")) {
|
|
32
|
+
throw new Error(`Missing value for ${flag}`)
|
|
33
|
+
}
|
|
34
|
+
return next
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
38
|
+
const arg = argv[i]
|
|
39
|
+
if (arg === "--check") {
|
|
40
|
+
result.check = true
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
if (arg === "--source") {
|
|
44
|
+
result.source = requireValue(arg, i)
|
|
45
|
+
i += 1
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
if (arg === "--output") {
|
|
49
|
+
result.output = path.resolve(requireValue(arg, i))
|
|
50
|
+
i += 1
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
if (arg === "--upstream-commit") {
|
|
54
|
+
result.upstreamCommit = requireValue(arg, i)
|
|
55
|
+
i += 1
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
if (arg === "--sync-date") {
|
|
59
|
+
result.syncDate = requireValue(arg, i)
|
|
60
|
+
i += 1
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new Error(`Unknown argument: ${arg}`)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return result
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function readText(source) {
|
|
71
|
+
if (/^https?:\/\//.test(source)) {
|
|
72
|
+
const response = await fetch(source)
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`Failed to fetch source: ${response.status}`)
|
|
75
|
+
}
|
|
76
|
+
return response.text()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return readFile(path.resolve(source), "utf8")
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalize(text) {
|
|
83
|
+
return text.replace(/\r\n/g, "\n")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function ensureSingleMatch(text, pattern, label) {
|
|
87
|
+
const count = [...text.matchAll(pattern)].length
|
|
88
|
+
if (count !== 1) {
|
|
89
|
+
throw new Error(`Expected exactly one ${label} anchor, found ${count}`)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function stripImports(source) {
|
|
94
|
+
const match = source.match(/^(?:import[^\n]*\n)+\n?/)
|
|
95
|
+
if (!match) throw new Error("Unable to locate import block in upstream source")
|
|
96
|
+
return source.slice(match[0].length).trimStart()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function buildHeader(meta) {
|
|
100
|
+
return `// @ts-nocheck
|
|
101
|
+
import { AsyncLocalStorage } from "node:async_hooks"
|
|
102
|
+
import { createServer } from "node:http"
|
|
103
|
+
import os from "node:os"
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* Upstream snapshot source:
|
|
107
|
+
* - Repository: ${meta.repositoryUrl}
|
|
108
|
+
* - Original path: ${upstreamPath}
|
|
109
|
+
* - Sync date: ${meta.syncDate}
|
|
110
|
+
* - Upstream commit: ${meta.upstreamCommit}
|
|
111
|
+
*
|
|
112
|
+
* Generated by scripts/sync-codex-upstream.mjs.
|
|
113
|
+
* Do not edit this file directly; update the sync script and regenerate it.
|
|
114
|
+
*/`
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function buildShimBlock() {
|
|
118
|
+
return `/* LOCAL_SHIMS_START */
|
|
119
|
+
type RequestInfo = Request | URL | string
|
|
120
|
+
|
|
121
|
+
type Hooks = any
|
|
122
|
+
type PluginInput = any
|
|
123
|
+
const officialCodexExportBridgeStorage = new AsyncLocalStorage<{
|
|
124
|
+
fetchImpl: typeof globalThis.fetch
|
|
125
|
+
version: string
|
|
126
|
+
}>()
|
|
127
|
+
|
|
128
|
+
const officialCodexExportBridge = {
|
|
129
|
+
version: "snapshot",
|
|
130
|
+
fetchImpl(request: RequestInfo | URL, init?: RequestInit) {
|
|
131
|
+
return globalThis.fetch(request, init)
|
|
132
|
+
},
|
|
133
|
+
async run(options: { fetchImpl?: typeof globalThis.fetch; version?: string } = {}, fn: () => Promise<any>) {
|
|
134
|
+
return officialCodexExportBridgeStorage.run(
|
|
135
|
+
{
|
|
136
|
+
fetchImpl: options.fetchImpl ?? this.fetchImpl,
|
|
137
|
+
version: options.version ?? this.version,
|
|
138
|
+
},
|
|
139
|
+
fn,
|
|
140
|
+
)
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const Installation = {
|
|
145
|
+
get VERSION() {
|
|
146
|
+
return officialCodexExportBridgeStorage.getStore()?.version ?? officialCodexExportBridge.version
|
|
147
|
+
},
|
|
148
|
+
set VERSION(value) {
|
|
149
|
+
officialCodexExportBridge.version = value
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const OAUTH_DUMMY_KEY = "official-codex-oauth"
|
|
154
|
+
|
|
155
|
+
function fetch(request: RequestInfo | URL, init?: RequestInit) {
|
|
156
|
+
return (officialCodexExportBridgeStorage.getStore()?.fetchImpl ?? officialCodexExportBridge.fetchImpl)(request, init)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function sleep(ms: number) {
|
|
160
|
+
return Bun.sleep(ms)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const Bun = {
|
|
164
|
+
serve(options: { port: number; fetch: (request: Request) => Response | Promise<Response> }) {
|
|
165
|
+
let closed = false
|
|
166
|
+
let listening = false
|
|
167
|
+
let closePromise: Promise<void> | undefined
|
|
168
|
+
let resolveReady: (() => void) | undefined
|
|
169
|
+
let rejectReady: ((error: Error) => void) | undefined
|
|
170
|
+
const ready = new Promise<void>((resolve, reject) => {
|
|
171
|
+
resolveReady = resolve
|
|
172
|
+
rejectReady = reject
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
const server = createServer((req, res) => {
|
|
176
|
+
const chunks: Buffer[] = []
|
|
177
|
+
|
|
178
|
+
req.on("data", (chunk) => {
|
|
179
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
req.on("error", (error) => {
|
|
183
|
+
res.statusCode = 500
|
|
184
|
+
res.end(String(error))
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
req.on("end", () => {
|
|
188
|
+
const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined
|
|
189
|
+
const request = new Request("http://127.0.0.1:" + options.port + (req.url ?? "/"), {
|
|
190
|
+
method: req.method,
|
|
191
|
+
headers: req.headers,
|
|
192
|
+
body,
|
|
193
|
+
duplex: "half",
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
Promise.resolve(options.fetch(request))
|
|
197
|
+
.then(async (response) => {
|
|
198
|
+
res.statusCode = response.status
|
|
199
|
+
response.headers.forEach((value, key) => res.setHeader(key, value))
|
|
200
|
+
const payload = Buffer.from(await response.arrayBuffer())
|
|
201
|
+
res.end(payload)
|
|
202
|
+
})
|
|
203
|
+
.catch((error) => {
|
|
204
|
+
res.statusCode = 500
|
|
205
|
+
res.end(String(error))
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
server.once("listening", () => {
|
|
211
|
+
listening = true
|
|
212
|
+
resolveReady?.()
|
|
213
|
+
resolveReady = undefined
|
|
214
|
+
rejectReady = undefined
|
|
215
|
+
})
|
|
216
|
+
server.once("error", (error: Error) => {
|
|
217
|
+
if (!listening) {
|
|
218
|
+
rejectReady?.(error)
|
|
219
|
+
resolveReady = undefined
|
|
220
|
+
rejectReady = undefined
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
server.listen(options.port)
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
ready,
|
|
228
|
+
stop() {
|
|
229
|
+
if (closePromise) return closePromise
|
|
230
|
+
closePromise = new Promise((resolve, reject) => {
|
|
231
|
+
if (closed) {
|
|
232
|
+
resolve()
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
server.close((error) => {
|
|
236
|
+
if (error) {
|
|
237
|
+
reject(error)
|
|
238
|
+
return
|
|
239
|
+
}
|
|
240
|
+
closed = true
|
|
241
|
+
resolve()
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
return closePromise
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
sleep(ms: number) {
|
|
249
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const Log = {
|
|
254
|
+
create() {
|
|
255
|
+
return {
|
|
256
|
+
info() {},
|
|
257
|
+
warn() {},
|
|
258
|
+
error() {},
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
}
|
|
262
|
+
/* LOCAL_SHIMS_END */`
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function buildExportBridgeBlock() {
|
|
266
|
+
return `/* GENERATED_EXPORT_BRIDGE_START */
|
|
267
|
+
export { officialCodexExportBridge }
|
|
268
|
+
/* GENERATED_EXPORT_BRIDGE_END */`
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function validateSnapshotMarkers(source) {
|
|
272
|
+
const shimsStart = [...source.matchAll(/\/\* LOCAL_SHIMS_START \*\//g)].length
|
|
273
|
+
const shimsEnd = [...source.matchAll(/\/\* LOCAL_SHIMS_END \*\//g)].length
|
|
274
|
+
const bridgeStart = [...source.matchAll(/\/\* GENERATED_EXPORT_BRIDGE_START \*\//g)].length
|
|
275
|
+
const bridgeEnd = [...source.matchAll(/\/\* GENERATED_EXPORT_BRIDGE_END \*\//g)].length
|
|
276
|
+
if (shimsStart !== 1 || shimsEnd !== 1) {
|
|
277
|
+
throw new Error("Invalid LOCAL_SHIMS markers in snapshot")
|
|
278
|
+
}
|
|
279
|
+
if (bridgeStart !== 1 || bridgeEnd !== 1) {
|
|
280
|
+
throw new Error("Invalid GENERATED_EXPORT_BRIDGE markers in snapshot")
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function buildSnapshot(source, meta) {
|
|
285
|
+
const normalized = normalize(source).trim() + "\n"
|
|
286
|
+
ensureSingleMatch(normalized, /export\s+async\s+function\s+CodexAuthPlugin\s*\(/gm, "CodexAuthPlugin")
|
|
287
|
+
ensureSingleMatch(normalized, /async\s+loader\s*\(/g, "auth.loader")
|
|
288
|
+
ensureSingleMatch(normalized, /methods\s*:\s*\[/g, "auth.methods")
|
|
289
|
+
ensureSingleMatch(normalized, /"chat\.headers"\s*:\s*async\s*\(/g, "chat.headers")
|
|
290
|
+
const stripped = stripImports(normalized)
|
|
291
|
+
|
|
292
|
+
return `${buildHeader(meta)}\n\n${buildShimBlock()}\n\n${stripped.trimEnd()}\n\n${buildExportBridgeBlock()}\n`
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function summarizeMismatch(expected, actual) {
|
|
296
|
+
const expectedLines = expected.split("\n")
|
|
297
|
+
const actualLines = actual.split("\n")
|
|
298
|
+
const limit = Math.max(expectedLines.length, actualLines.length)
|
|
299
|
+
|
|
300
|
+
for (let index = 0; index < limit; index += 1) {
|
|
301
|
+
if (expectedLines[index] === actualLines[index]) continue
|
|
302
|
+
return [
|
|
303
|
+
`first difference at line ${index + 1}`,
|
|
304
|
+
`expected: ${expectedLines[index] ?? "<eof>"}`,
|
|
305
|
+
`actual: ${actualLines[index] ?? "<eof>"}`,
|
|
306
|
+
].join("\n")
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return "files differ"
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function main() {
|
|
313
|
+
const args = parseArgs(process.argv.slice(2))
|
|
314
|
+
const source = args.source ?? defaultSourceUrl
|
|
315
|
+
const currentBuffer = await readFile(args.output).catch(() => Buffer.alloc(0))
|
|
316
|
+
const current = currentBuffer.toString("utf8")
|
|
317
|
+
const normalizedCurrent = normalize(current)
|
|
318
|
+
if (current && (current.includes("LOCAL_SHIMS_START") || current.includes("GENERATED_EXPORT_BRIDGE_START"))) {
|
|
319
|
+
validateSnapshotMarkers(normalizedCurrent)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const generated = buildSnapshot(await readText(source), {
|
|
323
|
+
repositoryUrl: canonicalRepositoryUrl,
|
|
324
|
+
upstreamCommit: args.upstreamCommit ?? "unknown",
|
|
325
|
+
syncDate: args.syncDate ?? new Date().toISOString().slice(0, 10),
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
if (args.check) {
|
|
329
|
+
if (currentBuffer.equals(Buffer.from(generated, "utf8"))) {
|
|
330
|
+
process.stdout.write("in-sync\n")
|
|
331
|
+
return
|
|
332
|
+
}
|
|
333
|
+
process.stdout.write(`${createSnapshotDriftError(summarizeMismatch(generated, current)).message}\n`)
|
|
334
|
+
process.exitCode = 1
|
|
335
|
+
return
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
await mkdir(path.dirname(args.output), { recursive: true })
|
|
339
|
+
await writeFile(args.output, generated, "utf8")
|
|
340
|
+
process.stdout.write(`wrote ${args.output}\n`)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
await main()
|
|
345
|
+
} catch (error) {
|
|
346
|
+
process.stderr.write(`${formatError(error)}\n`)
|
|
347
|
+
process.exitCode = 1
|
|
348
|
+
}
|