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.
Files changed (56) hide show
  1. package/LICENSE +151 -0
  2. package/README.md +43 -0
  3. package/dist/auth-store.d.ts +13 -0
  4. package/dist/auth-store.js +43 -0
  5. package/dist/codex-auth-source.d.ts +16 -0
  6. package/dist/codex-auth-source.js +63 -0
  7. package/dist/codex-invalid-account.d.ts +32 -0
  8. package/dist/codex-invalid-account.js +106 -0
  9. package/dist/codex-network-retry.d.ts +2 -0
  10. package/dist/codex-network-retry.js +9 -0
  11. package/dist/codex-status-command.d.ts +56 -0
  12. package/dist/codex-status-command.js +341 -0
  13. package/dist/codex-status-fetcher.d.ts +71 -0
  14. package/dist/codex-status-fetcher.js +300 -0
  15. package/dist/codex-store.d.ts +49 -0
  16. package/dist/codex-store.js +267 -0
  17. package/dist/common-settings-actions.d.ts +15 -0
  18. package/dist/common-settings-actions.js +22 -0
  19. package/dist/common-settings-store.d.ts +17 -0
  20. package/dist/common-settings-store.js +72 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/menu-runtime.d.ts +81 -0
  24. package/dist/menu-runtime.js +141 -0
  25. package/dist/network-retry-engine.d.ts +33 -0
  26. package/dist/network-retry-engine.js +62 -0
  27. package/dist/plugin-hooks.d.ts +49 -0
  28. package/dist/plugin-hooks.js +123 -0
  29. package/dist/plugin.d.ts +2 -0
  30. package/dist/plugin.js +127 -0
  31. package/dist/providers/codex-menu-adapter.d.ts +58 -0
  32. package/dist/providers/codex-menu-adapter.js +429 -0
  33. package/dist/providers/descriptor.d.ts +24 -0
  34. package/dist/providers/descriptor.js +16 -0
  35. package/dist/providers/registry.d.ts +15 -0
  36. package/dist/providers/registry.js +49 -0
  37. package/dist/retry/codex-policy.d.ts +5 -0
  38. package/dist/retry/codex-policy.js +75 -0
  39. package/dist/retry/common-policy.d.ts +37 -0
  40. package/dist/retry/common-policy.js +68 -0
  41. package/dist/store-paths.d.ts +4 -0
  42. package/dist/store-paths.js +22 -0
  43. package/dist/ui/ansi.d.ts +18 -0
  44. package/dist/ui/ansi.js +32 -0
  45. package/dist/ui/confirm.d.ts +1 -0
  46. package/dist/ui/confirm.js +14 -0
  47. package/dist/ui/menu.d.ts +168 -0
  48. package/dist/ui/menu.js +305 -0
  49. package/dist/ui/select.d.ts +36 -0
  50. package/dist/ui/select.js +350 -0
  51. package/dist/upstream/codex-loader-adapter.d.ts +99 -0
  52. package/dist/upstream/codex-loader-adapter.js +80 -0
  53. package/dist/upstream/codex-plugin.snapshot.d.ts +32 -0
  54. package/dist/upstream/codex-plugin.snapshot.js +638 -0
  55. package/package.json +40 -0
  56. 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
+ }