opencode-codex-auth-rotation 1.0.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 (95) hide show
  1. package/LICENSE +37 -0
  2. package/README.md +170 -0
  3. package/assets/codex-auth.schema.json +26 -0
  4. package/assets/opencode-logo-ornate-dark.svg +18 -0
  5. package/assets/readme-hero.svg +31 -0
  6. package/config/README.md +103 -0
  7. package/config/minimal-opencode.json +12 -0
  8. package/config/opencode-legacy.json +571 -0
  9. package/config/opencode-modern.json +239 -0
  10. package/dist/index.d.ts +42 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +299 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/lib/auth/auth.d.ts +43 -0
  15. package/dist/lib/auth/auth.d.ts.map +1 -0
  16. package/dist/lib/auth/auth.js +163 -0
  17. package/dist/lib/auth/auth.js.map +1 -0
  18. package/dist/lib/auth/browser.d.ts +17 -0
  19. package/dist/lib/auth/browser.d.ts.map +1 -0
  20. package/dist/lib/auth/browser.js +76 -0
  21. package/dist/lib/auth/browser.js.map +1 -0
  22. package/dist/lib/auth/server.d.ts +10 -0
  23. package/dist/lib/auth/server.d.ts.map +1 -0
  24. package/dist/lib/auth/server.js +78 -0
  25. package/dist/lib/auth/server.js.map +1 -0
  26. package/dist/lib/config.d.ts +33 -0
  27. package/dist/lib/config.d.ts.map +1 -0
  28. package/dist/lib/config.js +84 -0
  29. package/dist/lib/config.js.map +1 -0
  30. package/dist/lib/constants.d.ts +67 -0
  31. package/dist/lib/constants.d.ts.map +1 -0
  32. package/dist/lib/constants.js +67 -0
  33. package/dist/lib/constants.js.map +1 -0
  34. package/dist/lib/logger.d.ts +21 -0
  35. package/dist/lib/logger.d.ts.map +1 -0
  36. package/dist/lib/logger.js +77 -0
  37. package/dist/lib/logger.js.map +1 -0
  38. package/dist/lib/oauth-success.html +712 -0
  39. package/dist/lib/prompts/codex-opencode-bridge.d.ts +19 -0
  40. package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
  41. package/dist/lib/prompts/codex-opencode-bridge.js +152 -0
  42. package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
  43. package/dist/lib/prompts/codex.d.ts +27 -0
  44. package/dist/lib/prompts/codex.d.ts.map +1 -0
  45. package/dist/lib/prompts/codex.js +241 -0
  46. package/dist/lib/prompts/codex.js.map +1 -0
  47. package/dist/lib/prompts/opencode-codex.d.ts +21 -0
  48. package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
  49. package/dist/lib/prompts/opencode-codex.js +91 -0
  50. package/dist/lib/prompts/opencode-codex.js.map +1 -0
  51. package/dist/lib/request/fetch-helpers.d.ts +73 -0
  52. package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
  53. package/dist/lib/request/fetch-helpers.js +221 -0
  54. package/dist/lib/request/fetch-helpers.js.map +1 -0
  55. package/dist/lib/request/helpers/input-utils.d.ts +6 -0
  56. package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
  57. package/dist/lib/request/helpers/input-utils.js +174 -0
  58. package/dist/lib/request/helpers/input-utils.js.map +1 -0
  59. package/dist/lib/request/helpers/model-map.d.ts +28 -0
  60. package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
  61. package/dist/lib/request/helpers/model-map.js +109 -0
  62. package/dist/lib/request/helpers/model-map.js.map +1 -0
  63. package/dist/lib/request/request-transformer.d.ts +93 -0
  64. package/dist/lib/request/request-transformer.d.ts.map +1 -0
  65. package/dist/lib/request/request-transformer.js +403 -0
  66. package/dist/lib/request/request-transformer.js.map +1 -0
  67. package/dist/lib/request/response-handler.d.ts +14 -0
  68. package/dist/lib/request/response-handler.d.ts.map +1 -0
  69. package/dist/lib/request/response-handler.js +88 -0
  70. package/dist/lib/request/response-handler.js.map +1 -0
  71. package/dist/lib/types.d.ts +184 -0
  72. package/dist/lib/types.d.ts.map +1 -0
  73. package/dist/lib/types.js +2 -0
  74. package/dist/lib/types.js.map +1 -0
  75. package/dist/src/plugin/accounts.d.ts +21 -0
  76. package/dist/src/plugin/accounts.d.ts.map +1 -0
  77. package/dist/src/plugin/accounts.js +53 -0
  78. package/dist/src/plugin/accounts.js.map +1 -0
  79. package/dist/src/plugin/config/schema.d.ts +38 -0
  80. package/dist/src/plugin/config/schema.d.ts.map +1 -0
  81. package/dist/src/plugin/config/schema.js +32 -0
  82. package/dist/src/plugin/config/schema.js.map +1 -0
  83. package/dist/src/plugin/storage.d.ts +15 -0
  84. package/dist/src/plugin/storage.d.ts.map +1 -0
  85. package/dist/src/plugin/storage.js +38 -0
  86. package/dist/src/plugin/storage.js.map +1 -0
  87. package/dist/src/plugin/usage.d.ts +9 -0
  88. package/dist/src/plugin/usage.d.ts.map +1 -0
  89. package/dist/src/plugin/usage.js +76 -0
  90. package/dist/src/plugin/usage.js.map +1 -0
  91. package/package.json +74 -0
  92. package/scripts/check-usage.ts +92 -0
  93. package/scripts/install-opencode-codex-auth.js +430 -0
  94. package/scripts/test-all-models.sh +259 -0
  95. package/scripts/validate-model-map.sh +97 -0
@@ -0,0 +1,184 @@
1
+ import type { Auth, Provider, Model } from "@opencode-ai/sdk";
2
+ /**
3
+ * Account selection strategy
4
+ */
5
+ export type AccountSelectionStrategy = "sticky" | "round-robin";
6
+ /**
7
+ * Plugin configuration from ~/.opencode/openai-codex-auth-config.json
8
+ */
9
+ export interface PluginConfig {
10
+ /**
11
+ * Enable CODEX_MODE (Codex-OpenCode bridge prompt instead of tool remap)
12
+ * @default true
13
+ */
14
+ codexMode?: boolean;
15
+ /**
16
+ * Account selection strategy
17
+ * - sticky: Stay with current account until rate-limited
18
+ * - round-robin: Rotate through accounts based on usage
19
+ * @default "sticky"
20
+ */
21
+ strategy?: AccountSelectionStrategy;
22
+ /**
23
+ * Enable PID-based offset for initial account selection
24
+ * Distributes starting accounts across parallel processes
25
+ * @default false
26
+ */
27
+ pidOffset?: boolean;
28
+ }
29
+ /**
30
+ * User configuration structure from opencode.json
31
+ */
32
+ export interface UserConfig {
33
+ global: ConfigOptions;
34
+ models: {
35
+ [modelName: string]: {
36
+ options?: ConfigOptions;
37
+ variants?: Record<string, (ConfigOptions & {
38
+ disabled?: boolean;
39
+ }) | undefined>;
40
+ [key: string]: unknown;
41
+ };
42
+ };
43
+ }
44
+ /**
45
+ * Configuration options for reasoning and text settings
46
+ */
47
+ export interface ConfigOptions {
48
+ reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
49
+ reasoningSummary?: "auto" | "concise" | "detailed" | "off" | "on";
50
+ textVerbosity?: "low" | "medium" | "high";
51
+ include?: string[];
52
+ }
53
+ /**
54
+ * Reasoning configuration for requests
55
+ */
56
+ export interface ReasoningConfig {
57
+ effort: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
58
+ summary: "auto" | "concise" | "detailed" | "off" | "on";
59
+ }
60
+ /**
61
+ * OAuth server information
62
+ */
63
+ export interface OAuthServerInfo {
64
+ port: number;
65
+ ready: boolean;
66
+ close: () => void;
67
+ waitForCode: (state: string) => Promise<{
68
+ code: string;
69
+ } | null>;
70
+ }
71
+ /**
72
+ * PKCE challenge and verifier
73
+ */
74
+ export interface PKCEPair {
75
+ challenge: string;
76
+ verifier: string;
77
+ }
78
+ /**
79
+ * Authorization flow result
80
+ */
81
+ export interface AuthorizationFlow {
82
+ pkce: PKCEPair;
83
+ state: string;
84
+ url: string;
85
+ }
86
+ /**
87
+ * Token exchange success result
88
+ */
89
+ export interface TokenSuccess {
90
+ type: "success";
91
+ access: string;
92
+ refresh: string;
93
+ expires: number;
94
+ }
95
+ /**
96
+ * Token exchange failure result
97
+ */
98
+ export interface TokenFailure {
99
+ type: "failed";
100
+ }
101
+ /**
102
+ * Token exchange result
103
+ */
104
+ export type TokenResult = TokenSuccess | TokenFailure;
105
+ /**
106
+ * Parsed authorization input
107
+ */
108
+ export interface ParsedAuthInput {
109
+ code?: string;
110
+ state?: string;
111
+ }
112
+ /**
113
+ * JWT payload with ChatGPT account info
114
+ */
115
+ export interface JWTPayload {
116
+ "https://api.openai.com/auth"?: {
117
+ chatgpt_account_id?: string;
118
+ };
119
+ [key: string]: unknown;
120
+ }
121
+ /**
122
+ * Message input item
123
+ */
124
+ export interface InputItem {
125
+ id?: string;
126
+ type: string;
127
+ role: string;
128
+ content?: unknown;
129
+ [key: string]: unknown;
130
+ }
131
+ /**
132
+ * Request body structure
133
+ */
134
+ export interface RequestBody {
135
+ model: string;
136
+ store?: boolean;
137
+ stream?: boolean;
138
+ instructions?: string;
139
+ input?: InputItem[];
140
+ tools?: unknown;
141
+ reasoning?: Partial<ReasoningConfig>;
142
+ text?: {
143
+ verbosity?: "low" | "medium" | "high";
144
+ };
145
+ include?: string[];
146
+ providerOptions?: {
147
+ openai?: Partial<ConfigOptions> & {
148
+ store?: boolean;
149
+ include?: string[];
150
+ };
151
+ [key: string]: unknown;
152
+ };
153
+ /** Stable key to enable prompt-token caching on Codex backend */
154
+ prompt_cache_key?: string;
155
+ max_output_tokens?: number;
156
+ max_completion_tokens?: number;
157
+ [key: string]: unknown;
158
+ }
159
+ /**
160
+ * SSE event data structure
161
+ */
162
+ export interface SSEEventData {
163
+ type: string;
164
+ response?: unknown;
165
+ [key: string]: unknown;
166
+ }
167
+ /**
168
+ * Cache metadata for Codex instructions
169
+ */
170
+ export interface CacheMetadata {
171
+ etag: string | null;
172
+ tag: string;
173
+ lastChecked: number;
174
+ url: string;
175
+ }
176
+ /**
177
+ * GitHub release data
178
+ */
179
+ export interface GitHubRelease {
180
+ tag_name: string;
181
+ [key: string]: unknown;
182
+ }
183
+ export type { Auth, Provider, Model };
184
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../lib/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ export interface CodexAccount {
2
+ id: string;
3
+ email: string;
4
+ accessToken: string;
5
+ refreshToken: string;
6
+ chatgptAccountId: string;
7
+ rateLimitResetTime?: number;
8
+ enabled: boolean;
9
+ }
10
+ export declare class AccountManager {
11
+ private accounts;
12
+ private currentIndex;
13
+ addAccount(account: CodexAccount): void;
14
+ getAccount(id: string): CodexAccount | undefined;
15
+ getCurrentAccount(): CodexAccount | null;
16
+ rotateAccount(): void;
17
+ getAccountCount(): number;
18
+ updateRateLimitResetTime(accountId: string, resetTime: number): void;
19
+ private getAvailableAccounts;
20
+ }
21
+ //# sourceMappingURL=accounts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../../src/plugin/accounts.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,YAAY,CAAK;IAEzB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IASvC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIhD,iBAAiB,IAAI,YAAY,GAAG,IAAI;IAYxC,aAAa,IAAI,IAAI;IASrB,eAAe,IAAI,MAAM;IAIzB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAOpE,OAAO,CAAC,oBAAoB;CAY5B"}
@@ -0,0 +1,53 @@
1
+ export class AccountManager {
2
+ accounts = [];
3
+ currentIndex = 0;
4
+ addAccount(account) {
5
+ const existingIndex = this.accounts.findIndex(acc => acc.id === account.id);
6
+ if (existingIndex >= 0) {
7
+ this.accounts[existingIndex] = account;
8
+ return;
9
+ }
10
+ this.accounts.push(account);
11
+ }
12
+ getAccount(id) {
13
+ return this.accounts.find(acc => acc.id === id);
14
+ }
15
+ getCurrentAccount() {
16
+ const available = this.getAvailableAccounts();
17
+ if (available.length === 0) {
18
+ return null;
19
+ }
20
+ const validIndex = this.currentIndex % available.length;
21
+ const currentId = available[validIndex]?.id;
22
+ return this.accounts.find(acc => acc.id === currentId) ?? null;
23
+ }
24
+ rotateAccount() {
25
+ const available = this.getAvailableAccounts();
26
+ if (available.length <= 1) {
27
+ return;
28
+ }
29
+ this.currentIndex = (this.currentIndex + 1) % available.length;
30
+ }
31
+ getAccountCount() {
32
+ return this.getAvailableAccounts().length;
33
+ }
34
+ updateRateLimitResetTime(accountId, resetTime) {
35
+ const account = this.getAccount(accountId);
36
+ if (account) {
37
+ account.rateLimitResetTime = resetTime;
38
+ }
39
+ }
40
+ getAvailableAccounts() {
41
+ const now = Date.now();
42
+ return this.accounts.filter(acc => {
43
+ if (!acc.enabled) {
44
+ return false;
45
+ }
46
+ if (acc.rateLimitResetTime && acc.rateLimitResetTime > now) {
47
+ return false;
48
+ }
49
+ return true;
50
+ });
51
+ }
52
+ }
53
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../../src/plugin/accounts.ts"],"names":[],"mappings":"AAUA,MAAM,OAAO,cAAc;IAClB,QAAQ,GAAmB,EAAE,CAAC;IAC9B,YAAY,GAAG,CAAC,CAAC;IAEzB,UAAU,CAAC,OAAqB;QAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5E,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC;YACvC,OAAO;QACR,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,UAAU,CAAC,EAAU;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,iBAAiB;QAChB,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC9C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC,MAAM,CAAC;QACxD,MAAM,SAAS,GAAG,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QAE5C,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,IAAI,IAAI,CAAC;IAChE,CAAC;IAED,aAAa;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC9C,IAAI,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC3B,OAAO;QACR,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC;IAChE,CAAC;IAED,eAAe;QACd,OAAO,IAAI,CAAC,oBAAoB,EAAE,CAAC,MAAM,CAAC;IAC3C,CAAC;IAED,wBAAwB,CAAC,SAAiB,EAAE,SAAiB;QAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QAC3C,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;QACxC,CAAC;IACF,CAAC;IAEO,oBAAoB;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;YACjC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO,KAAK,CAAC;YACd,CAAC;YACD,IAAI,GAAG,CAAC,kBAAkB,IAAI,GAAG,CAAC,kBAAkB,GAAG,GAAG,EAAE,CAAC;gBAC5D,OAAO,KAAK,CAAC;YACd,CAAC;YACD,OAAO,IAAI,CAAC;QACb,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Usage API response schema from ChatGPT backend
4
+ */
5
+ export declare const UsageResponseSchema: z.ZodObject<{
6
+ rate_limit: z.ZodObject<{
7
+ primary_window: z.ZodObject<{
8
+ used_percent: z.ZodNumber;
9
+ }, z.core.$strip>;
10
+ secondary_window: z.ZodObject<{
11
+ used_percent: z.ZodNumber;
12
+ }, z.core.$strip>;
13
+ }, z.core.$strip>;
14
+ }, z.core.$strip>;
15
+ export type UsageResponse = z.infer<typeof UsageResponseSchema>;
16
+ /**
17
+ * Usage cache file structure
18
+ */
19
+ export declare const UsageCacheSchema: z.ZodObject<{
20
+ accounts: z.ZodRecord<z.ZodString, z.ZodObject<{
21
+ primaryUsage: z.ZodNumber;
22
+ secondaryUsage: z.ZodNumber;
23
+ updatedAt: z.ZodNumber;
24
+ }, z.core.$strip>>;
25
+ }, z.core.$strip>;
26
+ export type UsageCache = z.infer<typeof UsageCacheSchema>;
27
+ /**
28
+ * Plugin configuration schema
29
+ */
30
+ export declare const PluginConfigSchema: z.ZodObject<{
31
+ strategy: z.ZodEnum<{
32
+ sticky: "sticky";
33
+ "round-robin": "round-robin";
34
+ }>;
35
+ pidOffset: z.ZodBoolean;
36
+ }, z.core.$strip>;
37
+ export type PluginConfig = z.infer<typeof PluginConfigSchema>;
38
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../src/plugin/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;iBAS9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;iBAS3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;iBAG7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Usage API response schema from ChatGPT backend
4
+ */
5
+ export const UsageResponseSchema = z.object({
6
+ rate_limit: z.object({
7
+ primary_window: z.object({
8
+ used_percent: z.number(),
9
+ }),
10
+ secondary_window: z.object({
11
+ used_percent: z.number(),
12
+ }),
13
+ }),
14
+ });
15
+ /**
16
+ * Usage cache file structure
17
+ */
18
+ export const UsageCacheSchema = z.object({
19
+ accounts: z.record(z.string(), z.object({
20
+ primaryUsage: z.number(),
21
+ secondaryUsage: z.number(),
22
+ updatedAt: z.number(),
23
+ })),
24
+ });
25
+ /**
26
+ * Plugin configuration schema
27
+ */
28
+ export const PluginConfigSchema = z.object({
29
+ strategy: z.enum(["sticky", "round-robin"]),
30
+ pidOffset: z.boolean(),
31
+ });
32
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/plugin/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,cAAc,EAAE,CAAC,CAAC,MAAM,CAAC;YACvB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;SACzB,CAAC;QACF,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC;YACzB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;SACzB,CAAC;KACH,CAAC;CACH,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAChB,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,MAAM,CAAC;QACP,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;QACxB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE;QAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;KACtB,CAAC,CACH;CACF,CAAC,CAAC;AAIH;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IAC3C,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;CACvB,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { CodexAccount } from "./accounts";
2
+ /**
3
+ * 테스트를 위해 저장 경로를 설정합니다.
4
+ */
5
+ export declare function setStoragePathForTest(pathVar: string): void;
6
+ /**
7
+ * 저장된 계정 목록을 로드합니다.
8
+ * 파일이 없거나 오류가 발생하면 빈 배열을 반환합니다.
9
+ */
10
+ export declare function loadAccounts(): Promise<CodexAccount[]>;
11
+ /**
12
+ * 계정 목록을 디스크에 저장합니다.
13
+ */
14
+ export declare function saveAccounts(accountsVar: CodexAccount[]): Promise<void>;
15
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/plugin/storage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3D;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAQ5D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAW7E"}
@@ -0,0 +1,38 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ let storagePathVar = join(homedir(), ".config/opencode/codex-accounts.json");
5
+ /**
6
+ * 테스트를 위해 저장 경로를 설정합니다.
7
+ */
8
+ export function setStoragePathForTest(pathVar) {
9
+ storagePathVar = pathVar;
10
+ }
11
+ /**
12
+ * 저장된 계정 목록을 로드합니다.
13
+ * 파일이 없거나 오류가 발생하면 빈 배열을 반환합니다.
14
+ */
15
+ export async function loadAccounts() {
16
+ try {
17
+ const contentVar = await readFile(storagePathVar, "utf-8");
18
+ const dataVar = JSON.parse(contentVar);
19
+ return dataVar.accounts || [];
20
+ }
21
+ catch (errorVar) {
22
+ return [];
23
+ }
24
+ }
25
+ /**
26
+ * 계정 목록을 디스크에 저장합니다.
27
+ */
28
+ export async function saveAccounts(accountsVar) {
29
+ const dirVar = dirname(storagePathVar);
30
+ await mkdir(dirVar, { recursive: true });
31
+ const dataVar = {
32
+ version: 1,
33
+ accounts: accountsVar,
34
+ activeIndex: 0
35
+ };
36
+ await writeFile(storagePathVar, JSON.stringify(dataVar, null, 2), "utf-8");
37
+ }
38
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/plugin/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,IAAI,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,sCAAsC,CAAC,CAAC;AAE7E;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACpD,cAAc,GAAG,OAAO,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IACjC,IAAI,CAAC;QACJ,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,QAAQ,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAA2B;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,MAAM,OAAO,GAAG;QACf,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,WAAW;QACrB,WAAW,EAAE,CAAC;KACd,CAAC;IAEF,MAAM,SAAS,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { UsageResponse, UsageCache } from "./config/schema";
2
+ import type { CodexAccount } from "./accounts";
3
+ export declare function fetchUsage(token: string, accountId: string): Promise<UsageResponse>;
4
+ export declare function loadUsageCache(pid: number): UsageCache | null;
5
+ export declare function saveUsageCache(pid: number, data: UsageCache): void;
6
+ export declare function getWeeklyBucket(percent: number): 0 | 1 | 2 | 3;
7
+ export declare function selectAccountByUsage(accounts: CodexAccount[], cache: UsageCache): number;
8
+ export declare function fetchUsageBackground(token: string, accountId: string, pid: number): void;
9
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/plugin/usage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAyC,MAAM,iBAAiB,CAAC;AACnG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAUzF;AAMD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAU7D;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAElE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAK9D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,UAAU,GAChB,MAAM,CAmBR;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,GACV,IAAI,CAYN"}
@@ -0,0 +1,76 @@
1
+ import { UsageResponseSchema, UsageCacheSchema } from "./config/schema";
2
+ import * as fs from "node:fs";
3
+ const USAGE_API_URL = "https://chatgpt.com/backend-api/wham/usage";
4
+ export async function fetchUsage(token, accountId) {
5
+ const res = await fetch(USAGE_API_URL, {
6
+ headers: {
7
+ Authorization: `Bearer ${token}`,
8
+ "oai-device-id": accountId,
9
+ },
10
+ });
11
+ if (!res.ok)
12
+ throw new Error(`Usage API failed: ${res.status}`);
13
+ const data = await res.json();
14
+ return UsageResponseSchema.parse(data);
15
+ }
16
+ function getCachePath(pid) {
17
+ return `/tmp/codex-usage-${pid}.json`;
18
+ }
19
+ export function loadUsageCache(pid) {
20
+ const path = getCachePath(pid);
21
+ if (!fs.existsSync(path))
22
+ return null;
23
+ try {
24
+ const data = JSON.parse(fs.readFileSync(path, "utf-8"));
25
+ return UsageCacheSchema.parse(data);
26
+ }
27
+ catch {
28
+ fs.unlinkSync(path);
29
+ return null;
30
+ }
31
+ }
32
+ export function saveUsageCache(pid, data) {
33
+ fs.writeFileSync(getCachePath(pid), JSON.stringify(data, null, 2));
34
+ }
35
+ export function getWeeklyBucket(percent) {
36
+ if (percent < 30)
37
+ return 0;
38
+ if (percent < 60)
39
+ return 1;
40
+ if (percent < 90)
41
+ return 2;
42
+ return 3;
43
+ }
44
+ export function selectAccountByUsage(accounts, cache) {
45
+ if (accounts.length === 0)
46
+ return -1;
47
+ if (accounts.length === 1)
48
+ return 0;
49
+ const accountsWithUsage = accounts.map((acc, index) => {
50
+ const usage = cache.accounts[acc.id];
51
+ return {
52
+ index,
53
+ primaryUsage: usage?.primaryUsage ?? 0,
54
+ secondaryUsage: usage?.secondaryUsage ?? 0,
55
+ weeklyBucket: getWeeklyBucket(usage?.secondaryUsage ?? 0),
56
+ };
57
+ });
58
+ const minBucket = Math.min(...accountsWithUsage.map(a => a.weeklyBucket));
59
+ const candidates = accountsWithUsage.filter(a => a.weeklyBucket === minBucket);
60
+ candidates.sort((a, b) => a.primaryUsage - b.primaryUsage);
61
+ return candidates[0]?.index ?? 0;
62
+ }
63
+ export function fetchUsageBackground(token, accountId, pid) {
64
+ fetchUsage(token, accountId)
65
+ .then(response => {
66
+ const cache = loadUsageCache(pid) ?? { accounts: {} };
67
+ cache.accounts[accountId] = {
68
+ primaryUsage: response.rate_limit.primary_window.used_percent,
69
+ secondaryUsage: response.rate_limit.secondary_window.used_percent,
70
+ updatedAt: Date.now(),
71
+ };
72
+ saveUsageCache(pid, cache);
73
+ })
74
+ .catch(() => { });
75
+ }
76
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/plugin/usage.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "opencode-codex-auth-rotation",
3
+ "version": "1.0.0",
4
+ "description": "OpenAI ChatGPT (Codex backend) OAuth auth plugin for opencode with multi-account rotation - use your ChatGPT Plus/Pro subscription instead of API credits",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "type": "module",
8
+ "license": "MIT",
9
+ "author": "professional-ALFIE",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/professional-ALFIE/opencode-codex-auth-rotation.git"
13
+ },
14
+ "keywords": [
15
+ "opencode",
16
+ "openai",
17
+ "codex",
18
+ "chatgpt",
19
+ "oauth",
20
+ "gpt-5",
21
+ "plugin",
22
+ "auth",
23
+ "chatgpt-plus",
24
+ "chatgpt-pro",
25
+ "multi-account",
26
+ "rotation"
27
+ ],
28
+ "homepage": "https://github.com/professional-ALFIE/opencode-codex-auth-rotation#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/professional-ALFIE/opencode-codex-auth-rotation/issues"
31
+ },
32
+ "scripts": {
33
+ "build": "tsc && cp lib/oauth-success.html dist/lib/",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest",
37
+ "test:ui": "vitest --ui",
38
+ "test:coverage": "vitest run --coverage"
39
+ },
40
+ "bin": {
41
+ "opencode-openai-codex-auth": "./scripts/install-opencode-codex-auth.js"
42
+ },
43
+ "files": [
44
+ "dist/",
45
+ "assets/",
46
+ "config/",
47
+ "scripts/",
48
+ "README.md",
49
+ "LICENSE"
50
+ ],
51
+ "engines": {
52
+ "node": ">=20.0.0"
53
+ },
54
+ "peerDependencies": {
55
+ "@opencode-ai/plugin": "^1.0.150"
56
+ },
57
+ "devDependencies": {
58
+ "@opencode-ai/plugin": "^1.0.150",
59
+ "@opencode-ai/sdk": "^1.0.150",
60
+ "@types/node": "^24.6.2",
61
+ "@vitest/ui": "^3.2.4",
62
+ "typescript": "^5.9.3",
63
+ "vitest": "^3.2.4"
64
+ },
65
+ "dependencies": {
66
+ "@openauthjs/openauth": "^0.4.3",
67
+ "hono": "^4.10.4",
68
+ "jsonc-parser": "^3.3.1"
69
+ },
70
+ "overrides": {
71
+ "hono": "^4.10.4",
72
+ "vite": "^7.1.12"
73
+ }
74
+ }