oc-codex-multi-auth 6.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 (248) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -0
  3. package/assets/opencode-logo-ornate-dark.svg +18 -0
  4. package/assets/readme-hero.svg +31 -0
  5. package/config/README.md +96 -0
  6. package/config/minimal-opencode.json +13 -0
  7. package/config/opencode-legacy.json +871 -0
  8. package/config/opencode-modern.json +358 -0
  9. package/dist/index.d.ts +45 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +5008 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/accounts/rate-limits.d.ts +22 -0
  14. package/dist/lib/accounts/rate-limits.d.ts.map +1 -0
  15. package/dist/lib/accounts/rate-limits.js +63 -0
  16. package/dist/lib/accounts/rate-limits.js.map +1 -0
  17. package/dist/lib/accounts.d.ts +134 -0
  18. package/dist/lib/accounts.d.ts.map +1 -0
  19. package/dist/lib/accounts.js +795 -0
  20. package/dist/lib/accounts.js.map +1 -0
  21. package/dist/lib/audit.d.ts +45 -0
  22. package/dist/lib/audit.d.ts.map +1 -0
  23. package/dist/lib/audit.js +154 -0
  24. package/dist/lib/audit.js.map +1 -0
  25. package/dist/lib/auth/auth.d.ts +51 -0
  26. package/dist/lib/auth/auth.d.ts.map +1 -0
  27. package/dist/lib/auth/auth.js +191 -0
  28. package/dist/lib/auth/auth.js.map +1 -0
  29. package/dist/lib/auth/browser.d.ts +17 -0
  30. package/dist/lib/auth/browser.d.ts.map +1 -0
  31. package/dist/lib/auth/browser.js +90 -0
  32. package/dist/lib/auth/browser.js.map +1 -0
  33. package/dist/lib/auth/device-code.d.ts +28 -0
  34. package/dist/lib/auth/device-code.d.ts.map +1 -0
  35. package/dist/lib/auth/device-code.js +215 -0
  36. package/dist/lib/auth/device-code.js.map +1 -0
  37. package/dist/lib/auth/login-runner.d.ts +55 -0
  38. package/dist/lib/auth/login-runner.d.ts.map +1 -0
  39. package/dist/lib/auth/login-runner.js +631 -0
  40. package/dist/lib/auth/login-runner.js.map +1 -0
  41. package/dist/lib/auth/server.d.ts +10 -0
  42. package/dist/lib/auth/server.d.ts.map +1 -0
  43. package/dist/lib/auth/server.js +98 -0
  44. package/dist/lib/auth/server.js.map +1 -0
  45. package/dist/lib/auth/token-utils.d.ts +60 -0
  46. package/dist/lib/auth/token-utils.d.ts.map +1 -0
  47. package/dist/lib/auth/token-utils.js +416 -0
  48. package/dist/lib/auth/token-utils.js.map +1 -0
  49. package/dist/lib/auth-rate-limit.d.ts +20 -0
  50. package/dist/lib/auth-rate-limit.d.ts.map +1 -0
  51. package/dist/lib/auth-rate-limit.js +91 -0
  52. package/dist/lib/auth-rate-limit.js.map +1 -0
  53. package/dist/lib/auto-update-checker.d.ts +10 -0
  54. package/dist/lib/auto-update-checker.d.ts.map +1 -0
  55. package/dist/lib/auto-update-checker.js +129 -0
  56. package/dist/lib/auto-update-checker.js.map +1 -0
  57. package/dist/lib/circuit-breaker.d.ts +34 -0
  58. package/dist/lib/circuit-breaker.d.ts.map +1 -0
  59. package/dist/lib/circuit-breaker.js +124 -0
  60. package/dist/lib/circuit-breaker.js.map +1 -0
  61. package/dist/lib/cli.d.ts +46 -0
  62. package/dist/lib/cli.d.ts.map +1 -0
  63. package/dist/lib/cli.js +192 -0
  64. package/dist/lib/cli.js.map +1 -0
  65. package/dist/lib/config.d.ts +42 -0
  66. package/dist/lib/config.d.ts.map +1 -0
  67. package/dist/lib/config.js +314 -0
  68. package/dist/lib/config.js.map +1 -0
  69. package/dist/lib/constants.d.ts +90 -0
  70. package/dist/lib/constants.d.ts.map +1 -0
  71. package/dist/lib/constants.js +90 -0
  72. package/dist/lib/constants.js.map +1 -0
  73. package/dist/lib/context-overflow.d.ts +27 -0
  74. package/dist/lib/context-overflow.d.ts.map +1 -0
  75. package/dist/lib/context-overflow.js +124 -0
  76. package/dist/lib/context-overflow.js.map +1 -0
  77. package/dist/lib/errors.d.ts +113 -0
  78. package/dist/lib/errors.d.ts.map +1 -0
  79. package/dist/lib/errors.js +103 -0
  80. package/dist/lib/errors.js.map +1 -0
  81. package/dist/lib/health.d.ts +33 -0
  82. package/dist/lib/health.d.ts.map +1 -0
  83. package/dist/lib/health.js +70 -0
  84. package/dist/lib/health.js.map +1 -0
  85. package/dist/lib/index.d.ts +20 -0
  86. package/dist/lib/index.d.ts.map +1 -0
  87. package/dist/lib/index.js +20 -0
  88. package/dist/lib/index.js.map +1 -0
  89. package/dist/lib/logger.d.ts +40 -0
  90. package/dist/lib/logger.d.ts.map +1 -0
  91. package/dist/lib/logger.js +337 -0
  92. package/dist/lib/logger.js.map +1 -0
  93. package/dist/lib/oauth-success.html +712 -0
  94. package/dist/lib/parallel-probe.d.ts +28 -0
  95. package/dist/lib/parallel-probe.d.ts.map +1 -0
  96. package/dist/lib/parallel-probe.js +97 -0
  97. package/dist/lib/parallel-probe.js.map +1 -0
  98. package/dist/lib/proactive-refresh.d.ts +67 -0
  99. package/dist/lib/proactive-refresh.d.ts.map +1 -0
  100. package/dist/lib/proactive-refresh.js +161 -0
  101. package/dist/lib/proactive-refresh.js.map +1 -0
  102. package/dist/lib/prompts/codex-opencode-bridge.d.ts +20 -0
  103. package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
  104. package/dist/lib/prompts/codex-opencode-bridge.js +126 -0
  105. package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
  106. package/dist/lib/prompts/codex.d.ts +41 -0
  107. package/dist/lib/prompts/codex.d.ts.map +1 -0
  108. package/dist/lib/prompts/codex.js +400 -0
  109. package/dist/lib/prompts/codex.js.map +1 -0
  110. package/dist/lib/prompts/opencode-codex.d.ts +25 -0
  111. package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
  112. package/dist/lib/prompts/opencode-codex.js +223 -0
  113. package/dist/lib/prompts/opencode-codex.js.map +1 -0
  114. package/dist/lib/recovery/constants.d.ts +12 -0
  115. package/dist/lib/recovery/constants.d.ts.map +1 -0
  116. package/dist/lib/recovery/constants.js +25 -0
  117. package/dist/lib/recovery/constants.js.map +1 -0
  118. package/dist/lib/recovery/index.d.ts +12 -0
  119. package/dist/lib/recovery/index.d.ts.map +1 -0
  120. package/dist/lib/recovery/index.js +12 -0
  121. package/dist/lib/recovery/index.js.map +1 -0
  122. package/dist/lib/recovery/storage.d.ts +24 -0
  123. package/dist/lib/recovery/storage.d.ts.map +1 -0
  124. package/dist/lib/recovery/storage.js +362 -0
  125. package/dist/lib/recovery/storage.js.map +1 -0
  126. package/dist/lib/recovery/types.d.ts +116 -0
  127. package/dist/lib/recovery/types.d.ts.map +1 -0
  128. package/dist/lib/recovery/types.js +7 -0
  129. package/dist/lib/recovery/types.js.map +1 -0
  130. package/dist/lib/recovery.d.ts +31 -0
  131. package/dist/lib/recovery.d.ts.map +1 -0
  132. package/dist/lib/recovery.js +313 -0
  133. package/dist/lib/recovery.js.map +1 -0
  134. package/dist/lib/refresh-queue.d.ts +131 -0
  135. package/dist/lib/refresh-queue.d.ts.map +1 -0
  136. package/dist/lib/refresh-queue.js +297 -0
  137. package/dist/lib/refresh-queue.js.map +1 -0
  138. package/dist/lib/request/fetch-helpers.d.ts +142 -0
  139. package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
  140. package/dist/lib/request/fetch-helpers.js +749 -0
  141. package/dist/lib/request/fetch-helpers.js.map +1 -0
  142. package/dist/lib/request/helpers/input-utils.d.ts +7 -0
  143. package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
  144. package/dist/lib/request/helpers/input-utils.js +214 -0
  145. package/dist/lib/request/helpers/input-utils.js.map +1 -0
  146. package/dist/lib/request/helpers/model-map.d.ts +22 -0
  147. package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
  148. package/dist/lib/request/helpers/model-map.js +183 -0
  149. package/dist/lib/request/helpers/model-map.js.map +1 -0
  150. package/dist/lib/request/helpers/tool-utils.d.ts +29 -0
  151. package/dist/lib/request/helpers/tool-utils.d.ts.map +1 -0
  152. package/dist/lib/request/helpers/tool-utils.js +117 -0
  153. package/dist/lib/request/helpers/tool-utils.js.map +1 -0
  154. package/dist/lib/request/rate-limit-backoff.d.ts +17 -0
  155. package/dist/lib/request/rate-limit-backoff.d.ts.map +1 -0
  156. package/dist/lib/request/rate-limit-backoff.js +83 -0
  157. package/dist/lib/request/rate-limit-backoff.js.map +1 -0
  158. package/dist/lib/request/request-transformer.d.ts +107 -0
  159. package/dist/lib/request/request-transformer.d.ts.map +1 -0
  160. package/dist/lib/request/request-transformer.js +930 -0
  161. package/dist/lib/request/request-transformer.js.map +1 -0
  162. package/dist/lib/request/response-handler.d.ts +23 -0
  163. package/dist/lib/request/response-handler.d.ts.map +1 -0
  164. package/dist/lib/request/response-handler.js +245 -0
  165. package/dist/lib/request/response-handler.js.map +1 -0
  166. package/dist/lib/request/retry-budget.d.ts +19 -0
  167. package/dist/lib/request/retry-budget.d.ts.map +1 -0
  168. package/dist/lib/request/retry-budget.js +99 -0
  169. package/dist/lib/request/retry-budget.js.map +1 -0
  170. package/dist/lib/rotation.d.ts +130 -0
  171. package/dist/lib/rotation.d.ts.map +1 -0
  172. package/dist/lib/rotation.js +301 -0
  173. package/dist/lib/rotation.js.map +1 -0
  174. package/dist/lib/runtime-contracts.d.ts +16 -0
  175. package/dist/lib/runtime-contracts.d.ts.map +1 -0
  176. package/dist/lib/runtime-contracts.js +24 -0
  177. package/dist/lib/runtime-contracts.js.map +1 -0
  178. package/dist/lib/schemas.d.ts +457 -0
  179. package/dist/lib/schemas.d.ts.map +1 -0
  180. package/dist/lib/schemas.js +283 -0
  181. package/dist/lib/schemas.js.map +1 -0
  182. package/dist/lib/shutdown.d.ts +7 -0
  183. package/dist/lib/shutdown.d.ts.map +1 -0
  184. package/dist/lib/shutdown.js +43 -0
  185. package/dist/lib/shutdown.js.map +1 -0
  186. package/dist/lib/storage/migrations.d.ts +65 -0
  187. package/dist/lib/storage/migrations.d.ts.map +1 -0
  188. package/dist/lib/storage/migrations.js +44 -0
  189. package/dist/lib/storage/migrations.js.map +1 -0
  190. package/dist/lib/storage/paths.d.ts +16 -0
  191. package/dist/lib/storage/paths.d.ts.map +1 -0
  192. package/dist/lib/storage/paths.js +92 -0
  193. package/dist/lib/storage/paths.js.map +1 -0
  194. package/dist/lib/storage.d.ts +157 -0
  195. package/dist/lib/storage.d.ts.map +1 -0
  196. package/dist/lib/storage.js +1169 -0
  197. package/dist/lib/storage.js.map +1 -0
  198. package/dist/lib/table-formatter.d.ts +32 -0
  199. package/dist/lib/table-formatter.d.ts.map +1 -0
  200. package/dist/lib/table-formatter.js +44 -0
  201. package/dist/lib/table-formatter.js.map +1 -0
  202. package/dist/lib/types.d.ts +131 -0
  203. package/dist/lib/types.d.ts.map +1 -0
  204. package/dist/lib/types.js +2 -0
  205. package/dist/lib/types.js.map +1 -0
  206. package/dist/lib/ui/ansi.d.ts +22 -0
  207. package/dist/lib/ui/ansi.d.ts.map +1 -0
  208. package/dist/lib/ui/ansi.js +38 -0
  209. package/dist/lib/ui/ansi.js.map +1 -0
  210. package/dist/lib/ui/auth-menu.d.ts +39 -0
  211. package/dist/lib/ui/auth-menu.d.ts.map +1 -0
  212. package/dist/lib/ui/auth-menu.js +186 -0
  213. package/dist/lib/ui/auth-menu.js.map +1 -0
  214. package/dist/lib/ui/beginner.d.ts +62 -0
  215. package/dist/lib/ui/beginner.d.ts.map +1 -0
  216. package/dist/lib/ui/beginner.js +259 -0
  217. package/dist/lib/ui/beginner.js.map +1 -0
  218. package/dist/lib/ui/confirm.d.ts +2 -0
  219. package/dist/lib/ui/confirm.d.ts.map +1 -0
  220. package/dist/lib/ui/confirm.js +21 -0
  221. package/dist/lib/ui/confirm.js.map +1 -0
  222. package/dist/lib/ui/format.d.ts +9 -0
  223. package/dist/lib/ui/format.d.ts.map +1 -0
  224. package/dist/lib/ui/format.js +49 -0
  225. package/dist/lib/ui/format.js.map +1 -0
  226. package/dist/lib/ui/runtime.d.ts +11 -0
  227. package/dist/lib/ui/runtime.d.ts.map +1 -0
  228. package/dist/lib/ui/runtime.js +31 -0
  229. package/dist/lib/ui/runtime.js.map +1 -0
  230. package/dist/lib/ui/select.d.ts +20 -0
  231. package/dist/lib/ui/select.d.ts.map +1 -0
  232. package/dist/lib/ui/select.js +343 -0
  233. package/dist/lib/ui/select.js.map +1 -0
  234. package/dist/lib/ui/theme.d.ts +34 -0
  235. package/dist/lib/ui/theme.d.ts.map +1 -0
  236. package/dist/lib/ui/theme.js +84 -0
  237. package/dist/lib/ui/theme.js.map +1 -0
  238. package/dist/lib/utils.d.ts +29 -0
  239. package/dist/lib/utils.d.ts.map +1 -0
  240. package/dist/lib/utils.js +54 -0
  241. package/dist/lib/utils.js.map +1 -0
  242. package/package.json +113 -0
  243. package/scripts/audit-dev-allowlist.js +114 -0
  244. package/scripts/copy-oauth-success.js +37 -0
  245. package/scripts/install-oc-codex-multi-auth-core.js +381 -0
  246. package/scripts/install-oc-codex-multi-auth.js +15 -0
  247. package/scripts/test-all-models.sh +260 -0
  248. package/scripts/validate-model-map.sh +97 -0
@@ -0,0 +1,400 @@
1
+ import { promises as fs } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { logWarn, logError, logDebug } from "../logger.js";
6
+ const GITHUB_API_RELEASES = "https://api.github.com/repos/openai/codex/releases/latest";
7
+ const GITHUB_HTML_RELEASES = "https://github.com/openai/codex/releases/latest";
8
+ const CACHE_DIR = join(homedir(), ".opencode", "cache");
9
+ const CACHE_TTL_MS = 15 * 60 * 1000;
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ const MAX_CACHE_SIZE = 50;
13
+ const memoryCache = new Map();
14
+ const refreshPromises = new Map();
15
+ const RELEASE_TAG_TTL_MS = 5 * 60 * 1000;
16
+ let latestReleaseTagCache = null;
17
+ /**
18
+ * Clear the memory cache - exposed for testing
19
+ * @internal
20
+ */
21
+ export function __clearCacheForTesting() {
22
+ memoryCache.clear();
23
+ refreshPromises.clear();
24
+ latestReleaseTagCache = null;
25
+ }
26
+ function setCacheEntry(key, value) {
27
+ if (memoryCache.size >= MAX_CACHE_SIZE && !memoryCache.has(key)) {
28
+ const firstKey = memoryCache.keys().next().value;
29
+ // istanbul ignore next -- defensive: firstKey always exists when size >= MAX_CACHE_SIZE
30
+ if (firstKey)
31
+ memoryCache.delete(firstKey);
32
+ }
33
+ memoryCache.set(key, value);
34
+ }
35
+ /**
36
+ * All supported model families
37
+ * Used for per-family account rotation and rate limit tracking
38
+ */
39
+ export const MODEL_FAMILIES = [
40
+ "gpt-5-codex",
41
+ "codex-max",
42
+ "codex",
43
+ "gpt-5.4",
44
+ "gpt-5.4-mini",
45
+ "gpt-5.4-pro",
46
+ "gpt-5.2",
47
+ "gpt-5.1",
48
+ ];
49
+ /**
50
+ * Prompt file mapping for each model family
51
+ * Based on codex-rs/core/src/model_family.rs logic
52
+ */
53
+ const PROMPT_FILES = {
54
+ "gpt-5-codex": "gpt_5_codex_prompt.md",
55
+ "codex-max": "gpt-5.1-codex-max_prompt.md",
56
+ codex: "gpt_5_codex_prompt.md",
57
+ // As of Codex rust-v0.111.0, GPT-5.4 uses the same prompt file family as GPT-5.2.
58
+ "gpt-5.4": "gpt_5_2_prompt.md",
59
+ // GPT-5.4-mini uses the same core prompt file as GPT-5.4, but keeps isolated cache/family state.
60
+ "gpt-5.4-mini": "gpt_5_2_prompt.md",
61
+ // GPT-5.4-pro uses the same core prompt file as GPT-5.4, but keeps isolated cache/family state.
62
+ "gpt-5.4-pro": "gpt_5_2_prompt.md",
63
+ "gpt-5.2": "gpt_5_2_prompt.md",
64
+ "gpt-5.1": "gpt_5_1_prompt.md",
65
+ };
66
+ /**
67
+ * Cache file mapping for each model family
68
+ */
69
+ const CACHE_FILES = {
70
+ "gpt-5-codex": "gpt-5-codex-instructions.md",
71
+ "codex-max": "codex-max-instructions.md",
72
+ codex: "codex-instructions.md",
73
+ "gpt-5.4": "gpt-5.4-instructions.md",
74
+ "gpt-5.4-mini": "gpt-5.4-mini-instructions.md",
75
+ "gpt-5.4-pro": "gpt-5.4-pro-instructions.md",
76
+ "gpt-5.2": "gpt-5.2-instructions.md",
77
+ "gpt-5.1": "gpt-5.1-instructions.md",
78
+ };
79
+ /**
80
+ * Determine the model family based on the normalized model name
81
+ * @param normalizedModel - The normalized model name (e.g., "gpt-5-codex", "gpt-5.1-codex-max", "gpt-5.2", "gpt-5.1")
82
+ * @returns The model family for prompt selection
83
+ */
84
+ export function getModelFamily(normalizedModel) {
85
+ if (normalizedModel.includes("codex-max")) {
86
+ return "codex-max";
87
+ }
88
+ if (normalizedModel.includes("gpt-5-codex") ||
89
+ normalizedModel.includes("gpt 5 codex") ||
90
+ normalizedModel.includes("gpt-5.3-codex-spark") ||
91
+ normalizedModel.includes("gpt 5.3 codex spark") ||
92
+ normalizedModel.includes("gpt-5.3-codex") ||
93
+ normalizedModel.includes("gpt 5.3 codex") ||
94
+ normalizedModel.includes("gpt-5.2-codex") ||
95
+ normalizedModel.includes("gpt 5.2 codex") ||
96
+ normalizedModel.includes("gpt-5.1-codex") ||
97
+ normalizedModel.includes("gpt 5.1 codex")) {
98
+ return "gpt-5-codex";
99
+ }
100
+ if (normalizedModel.includes("codex") ||
101
+ normalizedModel.startsWith("codex-")) {
102
+ return "codex";
103
+ }
104
+ if (/\bgpt(?:-| )5\.4(?:-| )pro(?:\b|[- ])/i.test(normalizedModel)) {
105
+ return "gpt-5.4-pro";
106
+ }
107
+ if (/\bgpt(?:-| )5\.4(?:-| )mini(?:\b|[- ])/i.test(normalizedModel)) {
108
+ return "gpt-5.4-mini";
109
+ }
110
+ if (/\bgpt(?:-| )5\.4(?:\b|[- ])/i.test(normalizedModel)) {
111
+ return "gpt-5.4";
112
+ }
113
+ if (normalizedModel.includes("gpt-5.2")) {
114
+ return "gpt-5.2";
115
+ }
116
+ return "gpt-5.1";
117
+ }
118
+ async function readFileOrNull(path) {
119
+ try {
120
+ return await fs.readFile(path, "utf8");
121
+ }
122
+ catch {
123
+ return null;
124
+ }
125
+ }
126
+ /**
127
+ * Get the latest release tag from GitHub
128
+ * @returns Release tag name (e.g., "rust-v0.43.0")
129
+ */
130
+ async function getLatestReleaseTag() {
131
+ if (latestReleaseTagCache &&
132
+ Date.now() - latestReleaseTagCache.checkedAt < RELEASE_TAG_TTL_MS) {
133
+ return latestReleaseTagCache.tag;
134
+ }
135
+ try {
136
+ const response = await fetch(GITHUB_API_RELEASES);
137
+ if (response.ok) {
138
+ const data = (await response.json());
139
+ if (data.tag_name) {
140
+ latestReleaseTagCache = {
141
+ tag: data.tag_name,
142
+ checkedAt: Date.now(),
143
+ };
144
+ return data.tag_name;
145
+ }
146
+ }
147
+ }
148
+ catch {
149
+ // Fall through to HTML fallback
150
+ }
151
+ const htmlResponse = await fetch(GITHUB_HTML_RELEASES);
152
+ if (!htmlResponse.ok) {
153
+ throw new Error(`Failed to fetch latest release: ${htmlResponse.status}`);
154
+ }
155
+ const finalUrl = htmlResponse.url;
156
+ if (finalUrl) {
157
+ const parts = finalUrl.split("/tag/");
158
+ const last = parts[parts.length - 1];
159
+ if (last && !last.includes("/")) {
160
+ latestReleaseTagCache = {
161
+ tag: last,
162
+ checkedAt: Date.now(),
163
+ };
164
+ return last;
165
+ }
166
+ }
167
+ const html = await htmlResponse.text();
168
+ const match = html.match(/\/openai\/codex\/releases\/tag\/([^"]+)/);
169
+ if (match && match[1]) {
170
+ const tag = match[1];
171
+ latestReleaseTagCache = {
172
+ tag,
173
+ checkedAt: Date.now(),
174
+ };
175
+ return tag;
176
+ }
177
+ throw new Error("Failed to determine latest release tag from GitHub");
178
+ }
179
+ /**
180
+ * Fetch Codex instructions from GitHub with ETag-based caching
181
+ * Uses HTTP conditional requests to efficiently check for updates
182
+ * Always fetches from the latest release tag, not main branch
183
+ *
184
+ * Rate limit protection: Only checks GitHub if cache is older than 15 minutes
185
+ *
186
+ * @param normalizedModel - The normalized model name (optional, defaults to "gpt-5-codex")
187
+ * @returns Codex instructions for the specified model family
188
+ */
189
+ export async function getCodexInstructions(normalizedModel = "gpt-5-codex") {
190
+ const modelFamily = getModelFamily(normalizedModel);
191
+ const now = Date.now();
192
+ const cached = memoryCache.get(modelFamily);
193
+ if (cached && now - cached.timestamp < CACHE_TTL_MS) {
194
+ return cached.content;
195
+ }
196
+ const promptFile = PROMPT_FILES[modelFamily];
197
+ const cacheFile = join(CACHE_DIR, CACHE_FILES[modelFamily]);
198
+ const cacheMetaFile = join(CACHE_DIR, `${CACHE_FILES[modelFamily].replace(".md", "-meta.json")}`);
199
+ let cachedMetadata = null;
200
+ const [metaContent, diskContent] = await Promise.all([
201
+ readFileOrNull(cacheMetaFile),
202
+ readFileOrNull(cacheFile),
203
+ ]);
204
+ if (metaContent) {
205
+ try {
206
+ cachedMetadata = JSON.parse(metaContent);
207
+ }
208
+ catch {
209
+ cachedMetadata = null;
210
+ }
211
+ }
212
+ if (diskContent && cachedMetadata?.lastChecked) {
213
+ if (now - cachedMetadata.lastChecked < CACHE_TTL_MS) {
214
+ setCacheEntry(modelFamily, { content: diskContent, timestamp: now });
215
+ return diskContent;
216
+ }
217
+ // Stale-while-revalidate: return stale cache immediately and refresh in background.
218
+ setCacheEntry(modelFamily, { content: diskContent, timestamp: now });
219
+ void refreshInstructionsInBackground(modelFamily, promptFile, cacheFile, cacheMetaFile, cachedMetadata);
220
+ return diskContent;
221
+ }
222
+ if (cached && now - cached.timestamp >= CACHE_TTL_MS) {
223
+ // Keep session latency stable by serving stale memory cache while refreshing.
224
+ setCacheEntry(modelFamily, { content: cached.content, timestamp: now });
225
+ void refreshInstructionsInBackground(modelFamily, promptFile, cacheFile, cacheMetaFile, cachedMetadata);
226
+ return cached.content;
227
+ }
228
+ try {
229
+ return await fetchAndPersistInstructions(modelFamily, promptFile, cacheFile, cacheMetaFile, cachedMetadata);
230
+ }
231
+ catch (error) {
232
+ const err = error;
233
+ logError(`Failed to fetch ${modelFamily} instructions from GitHub: ${err.message}`);
234
+ if (diskContent) {
235
+ logWarn(`Using cached ${modelFamily} instructions`);
236
+ setCacheEntry(modelFamily, { content: diskContent, timestamp: now });
237
+ return diskContent;
238
+ }
239
+ logWarn(`Falling back to bundled instructions for ${modelFamily}`);
240
+ const bundled = await fs.readFile(join(__dirname, "codex-instructions.md"), "utf8");
241
+ setCacheEntry(modelFamily, { content: bundled, timestamp: now });
242
+ return bundled;
243
+ }
244
+ }
245
+ async function fetchAndPersistInstructions(modelFamily, promptFile, cacheFile, cacheMetaFile, cachedMetadata) {
246
+ let cachedETag = cachedMetadata?.etag ?? null;
247
+ const cachedTag = cachedMetadata?.tag ?? null;
248
+ const latestTag = await getLatestReleaseTag();
249
+ const instructionsUrl = `https://raw.githubusercontent.com/openai/codex/${latestTag}/codex-rs/core/${promptFile}`;
250
+ if (cachedTag !== latestTag) {
251
+ cachedETag = null;
252
+ }
253
+ const headers = {};
254
+ if (cachedETag) {
255
+ headers["If-None-Match"] = cachedETag;
256
+ }
257
+ const response = await fetch(instructionsUrl, { headers });
258
+ if (response.status === 304) {
259
+ const diskContent = await readFileOrNull(cacheFile);
260
+ if (diskContent) {
261
+ setCacheEntry(modelFamily, { content: diskContent, timestamp: Date.now() });
262
+ await fs.mkdir(CACHE_DIR, { recursive: true });
263
+ await fs.writeFile(cacheMetaFile, JSON.stringify({
264
+ etag: cachedETag,
265
+ tag: latestTag,
266
+ lastChecked: Date.now(),
267
+ url: instructionsUrl,
268
+ }), "utf8");
269
+ return diskContent;
270
+ }
271
+ }
272
+ if (!response.ok) {
273
+ throw new Error(`HTTP ${response.status}`);
274
+ }
275
+ const instructions = await response.text();
276
+ const newETag = response.headers.get("etag");
277
+ await fs.mkdir(CACHE_DIR, { recursive: true });
278
+ await Promise.all([
279
+ fs.writeFile(cacheFile, instructions, "utf8"),
280
+ fs.writeFile(cacheMetaFile, JSON.stringify({
281
+ etag: newETag,
282
+ tag: latestTag,
283
+ lastChecked: Date.now(),
284
+ url: instructionsUrl,
285
+ }), "utf8"),
286
+ ]);
287
+ setCacheEntry(modelFamily, { content: instructions, timestamp: Date.now() });
288
+ return instructions;
289
+ }
290
+ function refreshInstructionsInBackground(modelFamily, promptFile, cacheFile, cacheMetaFile, cachedMetadata) {
291
+ const existing = refreshPromises.get(modelFamily);
292
+ if (existing)
293
+ return existing;
294
+ const refreshPromise = fetchAndPersistInstructions(modelFamily, promptFile, cacheFile, cacheMetaFile, cachedMetadata)
295
+ .then(() => undefined)
296
+ .catch((error) => {
297
+ logDebug(`Background prompt refresh failed for ${modelFamily}`, {
298
+ error: String(error),
299
+ });
300
+ })
301
+ .finally(() => {
302
+ refreshPromises.delete(modelFamily);
303
+ });
304
+ refreshPromises.set(modelFamily, refreshPromise);
305
+ return refreshPromise;
306
+ }
307
+ /**
308
+ * Prewarm instruction caches for the provided models/families.
309
+ */
310
+ export function prewarmCodexInstructions(models = []) {
311
+ const candidates = models.length > 0 ? models : ["gpt-5-codex", "gpt-5.4", "gpt-5.4-mini", "gpt-5.4-pro", "gpt-5.2", "gpt-5.1"];
312
+ for (const model of candidates) {
313
+ void getCodexInstructions(model).catch((error) => {
314
+ logDebug("Codex instruction prewarm failed", {
315
+ model,
316
+ error: String(error),
317
+ });
318
+ });
319
+ }
320
+ }
321
+ /**
322
+ * Tool remapping instructions for opencode tools
323
+ */
324
+ export const TOOL_REMAP_MESSAGE = `<user_instructions priority="0">
325
+ <environment_override priority="0">
326
+ YOU ARE IN A DIFFERENT ENVIRONMENT. These instructions override ALL previous tool references.
327
+ </environment_override>
328
+
329
+ <tool_replacements priority="0">
330
+ <critical_rule priority="0">
331
+ Patch-edit tool names differ by runtime (for example: apply_patch, patch, edit).
332
+ - Always use the exact tool names listed in the active tool schema/manifest
333
+ - If the schema exposes apply_patch, call apply_patch directly
334
+ - If the schema exposes patch/edit instead, use patch/edit as listed
335
+ - Never invent aliases or auto-translate tool names
336
+ </critical_rule>
337
+
338
+ <critical_rule priority="0">
339
+ ❌ UPDATE_PLAN DOES NOT EXIST → ✅ USE "todowrite" INSTEAD
340
+ - NEVER use: update_plan, updatePlan
341
+ - ALWAYS use: todowrite for ALL task/plan operations
342
+ - Use todoread to read current plan
343
+ - Before plan operations: Verify you're using "todowrite", NOT "update_plan"
344
+ </critical_rule>
345
+ </tool_replacements>
346
+
347
+ <available_tools priority="0">
348
+ Note: This list is illustrative. Always defer to the active tool schema/manifest.
349
+ File Operations:
350
+ • write - Create new files
351
+ • edit - Modify existing files with string replacement
352
+ • patch - Apply diff patches
353
+ • apply_patch - Apply diff patches (alternate runtime name; use whichever the schema exposes)
354
+ • read - Read file contents
355
+
356
+ Search/Discovery:
357
+ • grep - Search file contents
358
+ • glob - Find files by pattern
359
+ • list - List directories
360
+
361
+ Execution:
362
+ • bash - Run shell commands
363
+
364
+ Network:
365
+ • webfetch - Fetch web content
366
+
367
+ Task Management:
368
+ • todowrite - Manage tasks/plans (REPLACES update_plan)
369
+ • todoread - Read current plan
370
+ </available_tools>
371
+
372
+ <tool_call_guardrails priority="0">
373
+ - Call only tool names listed in the active tool schema.
374
+ - Do not invent wrapper namespaces (for example functions.task or multi_tool_use.parallel) unless explicitly listed.
375
+ - Follow each tool's required path format instead of forcing absolute or relative paths globally.
376
+ </tool_call_guardrails>
377
+
378
+ <substitution_rules priority="0">
379
+ Base instruction says: Correct behaviour:
380
+ apply_patch/patch → use the exact tool name from the active schema (no renaming)
381
+ update_plan → todowrite
382
+ read_plan → todoread
383
+ </substitution_rules>
384
+
385
+ <verification_checklist priority="0">
386
+ Before file/plan modifications:
387
+ 1. Am I using the exact patch/edit (including apply_patch when exposed) tool name listed by the active schema?
388
+ 2. Am I using "todowrite" NOT "update_plan"?
389
+ 3. Is this tool in the approved list above?
390
+ 4. Am I following the active tool schema (including path format)?
391
+
392
+ If ANY answer is NO → STOP and correct before proceeding.
393
+ </verification_checklist>
394
+
395
+ <safety_rules priority="0">
396
+ - Never run destructive git commands (\`git reset --hard\`, \`git checkout --\`) unless explicitly requested by the user.
397
+ - Never call \`request_user_input\` unless collaboration mode is explicitly Plan mode.
398
+ </safety_rules>
399
+ </user_instructions>`;
400
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../lib/prompts/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * OpenCode Codex Prompt Fetcher
3
+ *
4
+ * Fetches and caches the codex.txt system prompt from OpenCode's GitHub repository.
5
+ * Uses ETag-based caching to efficiently track updates.
6
+ */
7
+ /**
8
+ * Fetch OpenCode's codex.txt prompt with ETag-based caching
9
+ * Uses HTTP conditional requests to efficiently check for updates
10
+ *
11
+ * Rate limit protection: Only checks GitHub if cache is older than 15 minutes
12
+ * @returns The codex.txt content
13
+ */
14
+ export declare function getOpenCodeCodexPrompt(): Promise<string>;
15
+ /**
16
+ * Get first N characters of the cached OpenCode prompt for verification
17
+ * @param chars Number of characters to get (default: 50)
18
+ * @returns First N characters or null if not cached
19
+ */
20
+ export declare function getCachedPromptPrefix(chars?: number): Promise<string | null>;
21
+ /**
22
+ * Prewarm the OpenCode prompt cache without blocking startup.
23
+ */
24
+ export declare function prewarmOpenCodeCodexPrompt(): void;
25
+ //# sourceMappingURL=opencode-codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode-codex.d.ts","sourceRoot":"","sources":["../../../lib/prompts/opencode-codex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqMH;;;;;;GAMG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC,CA+B9D;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAO9E;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAIjD"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * OpenCode Codex Prompt Fetcher
3
+ *
4
+ * Fetches and caches the codex.txt system prompt from OpenCode's GitHub repository.
5
+ * Uses ETag-based caching to efficiently track updates.
6
+ */
7
+ import { join } from "node:path";
8
+ import { homedir } from "node:os";
9
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
10
+ import { logDebug } from "../logger.js";
11
+ const DEFAULT_OPENCODE_CODEX_URLS = [
12
+ "https://raw.githubusercontent.com/anomalyco/opencode/dev/packages/opencode/src/session/prompt/codex.txt",
13
+ "https://raw.githubusercontent.com/sst/opencode/dev/packages/opencode/src/session/prompt/codex.txt",
14
+ "https://raw.githubusercontent.com/anomalyco/opencode/main/packages/opencode/src/session/prompt/codex.txt",
15
+ "https://raw.githubusercontent.com/sst/opencode/main/packages/opencode/src/session/prompt/codex.txt",
16
+ "https://raw.githubusercontent.com/anomalyco/opencode/dev/packages/opencode/src/session/prompt/codex.md",
17
+ "https://raw.githubusercontent.com/sst/opencode/dev/packages/opencode/src/session/prompt/codex.md",
18
+ "https://raw.githubusercontent.com/anomalyco/opencode/main/packages/opencode/src/session/prompt/codex.md",
19
+ "https://raw.githubusercontent.com/sst/opencode/main/packages/opencode/src/session/prompt/codex.md",
20
+ ];
21
+ const OPENCODE_CODEX_URL_OVERRIDE_ENV = "OPENCODE_CODEX_PROMPT_URL";
22
+ const CACHE_DIR = join(homedir(), ".opencode", "cache");
23
+ const CACHE_FILE = join(CACHE_DIR, "opencode-codex.txt");
24
+ const CACHE_META_FILE = join(CACHE_DIR, "opencode-codex-meta.json");
25
+ const CACHE_TTL_MS = 15 * 60 * 1000;
26
+ let memoryCache = null;
27
+ let refreshPromise = null;
28
+ function isFresh(lastChecked) {
29
+ return Date.now() - lastChecked < CACHE_TTL_MS;
30
+ }
31
+ function parseSourceUrl(source) {
32
+ if (!source)
33
+ return undefined;
34
+ const trimmed = source.trim();
35
+ if (!trimmed)
36
+ return undefined;
37
+ try {
38
+ const parsed = new URL(trimmed);
39
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
40
+ logDebug("Ignoring OpenCode codex prompt source override due to protocol", {
41
+ source: trimmed,
42
+ });
43
+ return undefined;
44
+ }
45
+ return trimmed;
46
+ }
47
+ catch {
48
+ logDebug("Ignoring invalid OpenCode codex prompt source override", {
49
+ source: trimmed,
50
+ });
51
+ return undefined;
52
+ }
53
+ }
54
+ function resolvePromptSources(cachedMeta) {
55
+ const sources = [];
56
+ const seen = new Set();
57
+ const add = (source) => {
58
+ const parsed = parseSourceUrl(source);
59
+ if (!parsed || seen.has(parsed))
60
+ return;
61
+ seen.add(parsed);
62
+ sources.push(parsed);
63
+ };
64
+ add(process.env[OPENCODE_CODEX_URL_OVERRIDE_ENV]);
65
+ add(cachedMeta?.sourceUrl);
66
+ for (const source of DEFAULT_OPENCODE_CODEX_URLS) {
67
+ add(source);
68
+ }
69
+ return sources;
70
+ }
71
+ async function readDiskCache() {
72
+ try {
73
+ const [content, metaContent] = await Promise.all([
74
+ readFile(CACHE_FILE, "utf-8"),
75
+ readFile(CACHE_META_FILE, "utf-8"),
76
+ ]);
77
+ const meta = JSON.parse(metaContent);
78
+ if (!meta.lastChecked) {
79
+ return null;
80
+ }
81
+ return { content, meta };
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ async function saveDiskCache(content, etag, sourceUrl) {
88
+ await mkdir(CACHE_DIR, { recursive: true });
89
+ const meta = {
90
+ etag,
91
+ lastFetch: new Date().toISOString(),
92
+ lastChecked: Date.now(),
93
+ sourceUrl,
94
+ };
95
+ await Promise.all([
96
+ writeFile(CACHE_FILE, content, "utf-8"),
97
+ writeFile(CACHE_META_FILE, JSON.stringify(meta, null, 2), "utf-8"),
98
+ ]);
99
+ return meta;
100
+ }
101
+ async function refreshPrompt(cachedMeta, cachedContent) {
102
+ const sources = resolvePromptSources(cachedMeta);
103
+ let lastFailure = null;
104
+ for (const sourceUrl of sources) {
105
+ const headers = {};
106
+ const canUseConditionalRequest = !!cachedMeta?.etag &&
107
+ (!cachedMeta.sourceUrl || cachedMeta.sourceUrl === sourceUrl);
108
+ if (canUseConditionalRequest) {
109
+ headers["If-None-Match"] = cachedMeta.etag;
110
+ }
111
+ let response;
112
+ try {
113
+ response = await fetch(sourceUrl, { headers });
114
+ }
115
+ catch (error) {
116
+ lastFailure = `${sourceUrl}: ${String(error)}`;
117
+ logDebug("OpenCode prompt source fetch failed", {
118
+ sourceUrl,
119
+ error: String(error),
120
+ });
121
+ continue;
122
+ }
123
+ if (response.status === 304 && cachedContent) {
124
+ const refreshedMeta = {
125
+ etag: cachedMeta?.etag ?? "",
126
+ lastFetch: cachedMeta?.lastFetch ?? new Date().toISOString(),
127
+ lastChecked: Date.now(),
128
+ sourceUrl,
129
+ };
130
+ memoryCache = { content: cachedContent, meta: refreshedMeta };
131
+ await mkdir(CACHE_DIR, { recursive: true });
132
+ await writeFile(CACHE_META_FILE, JSON.stringify(refreshedMeta, null, 2), "utf-8");
133
+ return cachedContent;
134
+ }
135
+ if (!response.ok) {
136
+ lastFailure = `${sourceUrl}: HTTP ${response.status}`;
137
+ logDebug("OpenCode prompt source returned non-OK response", {
138
+ sourceUrl,
139
+ status: response.status,
140
+ });
141
+ continue;
142
+ }
143
+ const content = await response.text();
144
+ const etag = response.headers.get("etag") || "";
145
+ const meta = await saveDiskCache(content, etag, sourceUrl);
146
+ memoryCache = { content, meta };
147
+ return content;
148
+ }
149
+ throw new Error(`Failed to fetch OpenCode codex prompt from all sources${lastFailure ? ` (${lastFailure})` : ""}`);
150
+ }
151
+ function scheduleRefresh(cachedMeta, cachedContent) {
152
+ if (refreshPromise)
153
+ return;
154
+ refreshPromise = refreshPrompt(cachedMeta, cachedContent)
155
+ .then(() => undefined)
156
+ .catch((error) => {
157
+ logDebug("OpenCode prompt background refresh failed", {
158
+ error: String(error),
159
+ });
160
+ })
161
+ .finally(() => {
162
+ refreshPromise = null;
163
+ });
164
+ }
165
+ /**
166
+ * Fetch OpenCode's codex.txt prompt with ETag-based caching
167
+ * Uses HTTP conditional requests to efficiently check for updates
168
+ *
169
+ * Rate limit protection: Only checks GitHub if cache is older than 15 minutes
170
+ * @returns The codex.txt content
171
+ */
172
+ export async function getOpenCodeCodexPrompt() {
173
+ if (memoryCache && isFresh(memoryCache.meta.lastChecked)) {
174
+ return memoryCache.content;
175
+ }
176
+ const diskCache = await readDiskCache();
177
+ if (diskCache) {
178
+ memoryCache = diskCache;
179
+ if (isFresh(diskCache.meta.lastChecked)) {
180
+ return diskCache.content;
181
+ }
182
+ // Serve stale content immediately and refresh in the background.
183
+ memoryCache = {
184
+ content: diskCache.content,
185
+ meta: { ...diskCache.meta, lastChecked: Date.now() },
186
+ };
187
+ scheduleRefresh(diskCache.meta, diskCache.content);
188
+ return diskCache.content;
189
+ }
190
+ try {
191
+ return await refreshPrompt(memoryCache?.meta ?? null, memoryCache?.content ?? null);
192
+ }
193
+ catch (error) {
194
+ const staleContent = memoryCache?.content;
195
+ if (staleContent) {
196
+ return staleContent;
197
+ }
198
+ throw new Error(`Failed to fetch OpenCode codex.txt and no cache available: ${error}`);
199
+ }
200
+ }
201
+ /**
202
+ * Get first N characters of the cached OpenCode prompt for verification
203
+ * @param chars Number of characters to get (default: 50)
204
+ * @returns First N characters or null if not cached
205
+ */
206
+ export async function getCachedPromptPrefix(chars = 50) {
207
+ try {
208
+ const content = await readFile(CACHE_FILE, "utf-8");
209
+ return content.substring(0, chars);
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ }
215
+ /**
216
+ * Prewarm the OpenCode prompt cache without blocking startup.
217
+ */
218
+ export function prewarmOpenCodeCodexPrompt() {
219
+ void getOpenCodeCodexPrompt().catch((error) => {
220
+ logDebug("OpenCode prompt prewarm failed", { error: String(error) });
221
+ });
222
+ }
223
+ //# sourceMappingURL=opencode-codex.js.map