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.
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/assets/opencode-logo-ornate-dark.svg +18 -0
- package/assets/readme-hero.svg +31 -0
- package/config/README.md +96 -0
- package/config/minimal-opencode.json +13 -0
- package/config/opencode-legacy.json +871 -0
- package/config/opencode-modern.json +358 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5008 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/accounts/rate-limits.d.ts +22 -0
- package/dist/lib/accounts/rate-limits.d.ts.map +1 -0
- package/dist/lib/accounts/rate-limits.js +63 -0
- package/dist/lib/accounts/rate-limits.js.map +1 -0
- package/dist/lib/accounts.d.ts +134 -0
- package/dist/lib/accounts.d.ts.map +1 -0
- package/dist/lib/accounts.js +795 -0
- package/dist/lib/accounts.js.map +1 -0
- package/dist/lib/audit.d.ts +45 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +154 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/auth/auth.d.ts +51 -0
- package/dist/lib/auth/auth.d.ts.map +1 -0
- package/dist/lib/auth/auth.js +191 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/browser.d.ts +17 -0
- package/dist/lib/auth/browser.d.ts.map +1 -0
- package/dist/lib/auth/browser.js +90 -0
- package/dist/lib/auth/browser.js.map +1 -0
- package/dist/lib/auth/device-code.d.ts +28 -0
- package/dist/lib/auth/device-code.d.ts.map +1 -0
- package/dist/lib/auth/device-code.js +215 -0
- package/dist/lib/auth/device-code.js.map +1 -0
- package/dist/lib/auth/login-runner.d.ts +55 -0
- package/dist/lib/auth/login-runner.d.ts.map +1 -0
- package/dist/lib/auth/login-runner.js +631 -0
- package/dist/lib/auth/login-runner.js.map +1 -0
- package/dist/lib/auth/server.d.ts +10 -0
- package/dist/lib/auth/server.d.ts.map +1 -0
- package/dist/lib/auth/server.js +98 -0
- package/dist/lib/auth/server.js.map +1 -0
- package/dist/lib/auth/token-utils.d.ts +60 -0
- package/dist/lib/auth/token-utils.d.ts.map +1 -0
- package/dist/lib/auth/token-utils.js +416 -0
- package/dist/lib/auth/token-utils.js.map +1 -0
- package/dist/lib/auth-rate-limit.d.ts +20 -0
- package/dist/lib/auth-rate-limit.d.ts.map +1 -0
- package/dist/lib/auth-rate-limit.js +91 -0
- package/dist/lib/auth-rate-limit.js.map +1 -0
- package/dist/lib/auto-update-checker.d.ts +10 -0
- package/dist/lib/auto-update-checker.d.ts.map +1 -0
- package/dist/lib/auto-update-checker.js +129 -0
- package/dist/lib/auto-update-checker.js.map +1 -0
- package/dist/lib/circuit-breaker.d.ts +34 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.js +124 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/cli.d.ts +46 -0
- package/dist/lib/cli.d.ts.map +1 -0
- package/dist/lib/cli.js +192 -0
- package/dist/lib/cli.js.map +1 -0
- package/dist/lib/config.d.ts +42 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +314 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +90 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +90 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/context-overflow.d.ts +27 -0
- package/dist/lib/context-overflow.d.ts.map +1 -0
- package/dist/lib/context-overflow.js +124 -0
- package/dist/lib/context-overflow.js.map +1 -0
- package/dist/lib/errors.d.ts +113 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +103 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/health.d.ts +33 -0
- package/dist/lib/health.d.ts.map +1 -0
- package/dist/lib/health.js +70 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/index.d.ts +20 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +20 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/logger.d.ts +40 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +337 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/oauth-success.html +712 -0
- package/dist/lib/parallel-probe.d.ts +28 -0
- package/dist/lib/parallel-probe.d.ts.map +1 -0
- package/dist/lib/parallel-probe.js +97 -0
- package/dist/lib/parallel-probe.js.map +1 -0
- package/dist/lib/proactive-refresh.d.ts +67 -0
- package/dist/lib/proactive-refresh.d.ts.map +1 -0
- package/dist/lib/proactive-refresh.js +161 -0
- package/dist/lib/proactive-refresh.js.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts +20 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.js +126 -0
- package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
- package/dist/lib/prompts/codex.d.ts +41 -0
- package/dist/lib/prompts/codex.d.ts.map +1 -0
- package/dist/lib/prompts/codex.js +400 -0
- package/dist/lib/prompts/codex.js.map +1 -0
- package/dist/lib/prompts/opencode-codex.d.ts +25 -0
- package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
- package/dist/lib/prompts/opencode-codex.js +223 -0
- package/dist/lib/prompts/opencode-codex.js.map +1 -0
- package/dist/lib/recovery/constants.d.ts +12 -0
- package/dist/lib/recovery/constants.d.ts.map +1 -0
- package/dist/lib/recovery/constants.js +25 -0
- package/dist/lib/recovery/constants.js.map +1 -0
- package/dist/lib/recovery/index.d.ts +12 -0
- package/dist/lib/recovery/index.d.ts.map +1 -0
- package/dist/lib/recovery/index.js +12 -0
- package/dist/lib/recovery/index.js.map +1 -0
- package/dist/lib/recovery/storage.d.ts +24 -0
- package/dist/lib/recovery/storage.d.ts.map +1 -0
- package/dist/lib/recovery/storage.js +362 -0
- package/dist/lib/recovery/storage.js.map +1 -0
- package/dist/lib/recovery/types.d.ts +116 -0
- package/dist/lib/recovery/types.d.ts.map +1 -0
- package/dist/lib/recovery/types.js +7 -0
- package/dist/lib/recovery/types.js.map +1 -0
- package/dist/lib/recovery.d.ts +31 -0
- package/dist/lib/recovery.d.ts.map +1 -0
- package/dist/lib/recovery.js +313 -0
- package/dist/lib/recovery.js.map +1 -0
- package/dist/lib/refresh-queue.d.ts +131 -0
- package/dist/lib/refresh-queue.d.ts.map +1 -0
- package/dist/lib/refresh-queue.js +297 -0
- package/dist/lib/refresh-queue.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +142 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
- package/dist/lib/request/fetch-helpers.js +749 -0
- package/dist/lib/request/fetch-helpers.js.map +1 -0
- package/dist/lib/request/helpers/input-utils.d.ts +7 -0
- package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/input-utils.js +214 -0
- package/dist/lib/request/helpers/input-utils.js.map +1 -0
- package/dist/lib/request/helpers/model-map.d.ts +22 -0
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
- package/dist/lib/request/helpers/model-map.js +183 -0
- package/dist/lib/request/helpers/model-map.js.map +1 -0
- package/dist/lib/request/helpers/tool-utils.d.ts +29 -0
- package/dist/lib/request/helpers/tool-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/tool-utils.js +117 -0
- package/dist/lib/request/helpers/tool-utils.js.map +1 -0
- package/dist/lib/request/rate-limit-backoff.d.ts +17 -0
- package/dist/lib/request/rate-limit-backoff.d.ts.map +1 -0
- package/dist/lib/request/rate-limit-backoff.js +83 -0
- package/dist/lib/request/rate-limit-backoff.js.map +1 -0
- package/dist/lib/request/request-transformer.d.ts +107 -0
- package/dist/lib/request/request-transformer.d.ts.map +1 -0
- package/dist/lib/request/request-transformer.js +930 -0
- package/dist/lib/request/request-transformer.js.map +1 -0
- package/dist/lib/request/response-handler.d.ts +23 -0
- package/dist/lib/request/response-handler.d.ts.map +1 -0
- package/dist/lib/request/response-handler.js +245 -0
- package/dist/lib/request/response-handler.js.map +1 -0
- package/dist/lib/request/retry-budget.d.ts +19 -0
- package/dist/lib/request/retry-budget.d.ts.map +1 -0
- package/dist/lib/request/retry-budget.js +99 -0
- package/dist/lib/request/retry-budget.js.map +1 -0
- package/dist/lib/rotation.d.ts +130 -0
- package/dist/lib/rotation.d.ts.map +1 -0
- package/dist/lib/rotation.js +301 -0
- package/dist/lib/rotation.js.map +1 -0
- package/dist/lib/runtime-contracts.d.ts +16 -0
- package/dist/lib/runtime-contracts.d.ts.map +1 -0
- package/dist/lib/runtime-contracts.js +24 -0
- package/dist/lib/runtime-contracts.js.map +1 -0
- package/dist/lib/schemas.d.ts +457 -0
- package/dist/lib/schemas.d.ts.map +1 -0
- package/dist/lib/schemas.js +283 -0
- package/dist/lib/schemas.js.map +1 -0
- package/dist/lib/shutdown.d.ts +7 -0
- package/dist/lib/shutdown.d.ts.map +1 -0
- package/dist/lib/shutdown.js +43 -0
- package/dist/lib/shutdown.js.map +1 -0
- package/dist/lib/storage/migrations.d.ts +65 -0
- package/dist/lib/storage/migrations.d.ts.map +1 -0
- package/dist/lib/storage/migrations.js +44 -0
- package/dist/lib/storage/migrations.js.map +1 -0
- package/dist/lib/storage/paths.d.ts +16 -0
- package/dist/lib/storage/paths.d.ts.map +1 -0
- package/dist/lib/storage/paths.js +92 -0
- package/dist/lib/storage/paths.js.map +1 -0
- package/dist/lib/storage.d.ts +157 -0
- package/dist/lib/storage.d.ts.map +1 -0
- package/dist/lib/storage.js +1169 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/lib/table-formatter.d.ts +32 -0
- package/dist/lib/table-formatter.d.ts.map +1 -0
- package/dist/lib/table-formatter.js +44 -0
- package/dist/lib/table-formatter.js.map +1 -0
- package/dist/lib/types.d.ts +131 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/ui/ansi.d.ts +22 -0
- package/dist/lib/ui/ansi.d.ts.map +1 -0
- package/dist/lib/ui/ansi.js +38 -0
- package/dist/lib/ui/ansi.js.map +1 -0
- package/dist/lib/ui/auth-menu.d.ts +39 -0
- package/dist/lib/ui/auth-menu.d.ts.map +1 -0
- package/dist/lib/ui/auth-menu.js +186 -0
- package/dist/lib/ui/auth-menu.js.map +1 -0
- package/dist/lib/ui/beginner.d.ts +62 -0
- package/dist/lib/ui/beginner.d.ts.map +1 -0
- package/dist/lib/ui/beginner.js +259 -0
- package/dist/lib/ui/beginner.js.map +1 -0
- package/dist/lib/ui/confirm.d.ts +2 -0
- package/dist/lib/ui/confirm.d.ts.map +1 -0
- package/dist/lib/ui/confirm.js +21 -0
- package/dist/lib/ui/confirm.js.map +1 -0
- package/dist/lib/ui/format.d.ts +9 -0
- package/dist/lib/ui/format.d.ts.map +1 -0
- package/dist/lib/ui/format.js +49 -0
- package/dist/lib/ui/format.js.map +1 -0
- package/dist/lib/ui/runtime.d.ts +11 -0
- package/dist/lib/ui/runtime.d.ts.map +1 -0
- package/dist/lib/ui/runtime.js +31 -0
- package/dist/lib/ui/runtime.js.map +1 -0
- package/dist/lib/ui/select.d.ts +20 -0
- package/dist/lib/ui/select.d.ts.map +1 -0
- package/dist/lib/ui/select.js +343 -0
- package/dist/lib/ui/select.js.map +1 -0
- package/dist/lib/ui/theme.d.ts +34 -0
- package/dist/lib/ui/theme.d.ts.map +1 -0
- package/dist/lib/ui/theme.js +84 -0
- package/dist/lib/ui/theme.js.map +1 -0
- package/dist/lib/utils.d.ts +29 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +54 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +113 -0
- package/scripts/audit-dev-allowlist.js +114 -0
- package/scripts/copy-oauth-success.js +37 -0
- package/scripts/install-oc-codex-multi-auth-core.js +381 -0
- package/scripts/install-oc-codex-multi-auth.js +15 -0
- package/scripts/test-all-models.sh +260 -0
- 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
|