@bitkyc08/opencodex 2.5.6 → 2.6.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/README.ko.md +17 -6
- package/README.md +19 -7
- package/README.zh-CN.md +12 -3
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +88 -2
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BS4X1QDi.js +9 -0
- package/gui/dist/assets/{index-CKqUwc02.css → index-BwvDb198.css} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +20 -6
- package/src/adapters/anthropic.ts +16 -5
- package/src/adapters/google.ts +9 -2
- package/src/adapters/openai-chat.ts +13 -5
- package/src/bun-runtime.ts +22 -1
- package/src/cli-help.ts +111 -0
- package/src/cli-status.ts +164 -0
- package/src/cli.ts +77 -186
- package/src/codex-account-store.ts +47 -8
- package/src/codex-auth-api.ts +111 -54
- package/src/codex-auth-collision.ts +5 -0
- package/src/codex-catalog.ts +24 -12
- package/src/codex-history-provider.ts +29 -13
- package/src/codex-inject.ts +46 -29
- package/src/codex-journal.ts +77 -13
- package/src/codex-quota.ts +11 -3
- package/src/codex-routing.ts +14 -4
- package/src/codex-shim.ts +71 -24
- package/src/codex-websocket-registry.ts +20 -4
- package/src/config.ts +138 -4
- package/src/init.ts +7 -2
- package/src/oauth/callback-server.ts +22 -15
- package/src/oauth/index.ts +18 -4
- package/src/oauth/login-cli.ts +8 -1
- package/src/oauth/store.ts +2 -1
- package/src/process-control.ts +36 -0
- package/src/provider-label.ts +8 -0
- package/src/responses/parser.ts +18 -1
- package/src/router.ts +61 -5
- package/src/server.ts +878 -94
- package/src/service-secrets.ts +6 -0
- package/src/service.ts +293 -28
- package/src/types.ts +26 -1
- package/src/update.ts +16 -9
- package/src/usage-debug.ts +65 -0
- package/src/usage-log.ts +62 -0
- package/src/usage-summary.ts +0 -0
- package/src/ws-bridge.ts +2 -2
- package/gui/README.md +0 -73
- package/gui/dist/assets/index-CSUvRNAX.js +0 -9
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { appendFileSync, chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getConfigDir } from "./config";
|
|
4
|
+
import type { OcxUsage } from "./types";
|
|
5
|
+
|
|
6
|
+
export const USAGE_DEBUG_ENV = "OPENCODEX_USAGE_DEBUG";
|
|
7
|
+
export const USAGE_DEBUG_BODY_SAMPLE_BYTES = 2048;
|
|
8
|
+
export const USAGE_DEBUG_MAX_LINES = 200;
|
|
9
|
+
export const USAGE_DEBUG_KEEP_LINES = 100;
|
|
10
|
+
|
|
11
|
+
export type UsageDebugBodyKind = "sse" | "json" | "other" | "none";
|
|
12
|
+
|
|
13
|
+
export interface UsageDebugRecord {
|
|
14
|
+
ts: number;
|
|
15
|
+
requestId: string;
|
|
16
|
+
provider: string;
|
|
17
|
+
model: string;
|
|
18
|
+
upstreamContentType: string | null;
|
|
19
|
+
upstreamStatus: number;
|
|
20
|
+
bodyKind: UsageDebugBodyKind;
|
|
21
|
+
bodySample: string;
|
|
22
|
+
extractedUsage: OcxUsage | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isUsageDebugEnabled(): boolean {
|
|
26
|
+
return process.env[USAGE_DEBUG_ENV] === "1";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function usageDebugPath(): string {
|
|
30
|
+
return join(getConfigDir(), "usage-debug.jsonl");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function truncateForDebug(text: string, max = USAGE_DEBUG_BODY_SAMPLE_BYTES): string {
|
|
34
|
+
if (text.length <= max) return text;
|
|
35
|
+
const cut = text.slice(0, max);
|
|
36
|
+
const remaining = text.length - max;
|
|
37
|
+
return `${cut}... [+${remaining} more]`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ensureUsageDebugDir(): void {
|
|
41
|
+
const dir = getConfigDir();
|
|
42
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
43
|
+
try { chmodSync(dir, 0o700); } catch { /* best-effort */ }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function trimRollingFile(path: string): void {
|
|
47
|
+
const text = readFileSync(path, "utf-8");
|
|
48
|
+
const lines = text.split(/\r?\n/).filter(line => line.length > 0);
|
|
49
|
+
if (lines.length <= USAGE_DEBUG_MAX_LINES) return;
|
|
50
|
+
const kept = lines.slice(-USAGE_DEBUG_KEEP_LINES).join("\n") + "\n";
|
|
51
|
+
writeFileSync(path, kept, { encoding: "utf-8", mode: 0o600 });
|
|
52
|
+
try { chmodSync(path, 0o600); } catch { /* best-effort */ }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function appendUsageDebug(record: UsageDebugRecord): void {
|
|
56
|
+
try {
|
|
57
|
+
ensureUsageDebugDir();
|
|
58
|
+
const path = usageDebugPath();
|
|
59
|
+
appendFileSync(path, `${JSON.stringify(record)}\n`, { encoding: "utf-8", mode: 0o600 });
|
|
60
|
+
try { chmodSync(path, 0o600); } catch { /* best-effort */ }
|
|
61
|
+
if (existsSync(path)) trimRollingFile(path);
|
|
62
|
+
} catch {
|
|
63
|
+
/* debug capture must never break the proxy */
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/usage-log.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, appendFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getConfigDir } from "./config";
|
|
4
|
+
import type { OcxUsage } from "./types";
|
|
5
|
+
|
|
6
|
+
export type UsageStatus = "reported" | "unreported" | "unsupported" | "estimated";
|
|
7
|
+
|
|
8
|
+
export interface PersistedUsageEntry {
|
|
9
|
+
requestId: string;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
provider: string;
|
|
12
|
+
model: string;
|
|
13
|
+
resolvedModel?: string;
|
|
14
|
+
status: number;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
usageStatus: UsageStatus;
|
|
17
|
+
usage?: OcxUsage;
|
|
18
|
+
totalTokens?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function usageLogPath(): string {
|
|
22
|
+
return join(getConfigDir(), "usage.jsonl");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function usageTotalTokens(usage: OcxUsage | undefined): number | undefined {
|
|
26
|
+
if (!usage) return undefined;
|
|
27
|
+
return usage.inputTokens + usage.outputTokens;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function usageStatusForFinalLog(usage: OcxUsage | undefined): UsageStatus {
|
|
31
|
+
return usage ? "reported" : "unreported";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function ensureUsageLogDir(): void {
|
|
35
|
+
const dir = getConfigDir();
|
|
36
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
37
|
+
try { chmodSync(dir, 0o700); } catch { /* best-effort on platforms that ignore chmod */ }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function appendUsageEntry(entry: PersistedUsageEntry): void {
|
|
41
|
+
ensureUsageLogDir();
|
|
42
|
+
const path = usageLogPath();
|
|
43
|
+
appendFileSync(path, `${JSON.stringify(entry)}\n`, { encoding: "utf-8", mode: 0o600 });
|
|
44
|
+
try { chmodSync(path, 0o600); } catch { /* best-effort on platforms that ignore chmod */ }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function readUsageEntries(): PersistedUsageEntry[] {
|
|
48
|
+
const path = usageLogPath();
|
|
49
|
+
if (!existsSync(path)) return [];
|
|
50
|
+
const lines = readFileSync(path, "utf-8").split(/\r?\n/);
|
|
51
|
+
const entries: PersistedUsageEntry[] = [];
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
if (!line.trim()) continue;
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(line) as PersistedUsageEntry;
|
|
56
|
+
if (parsed && typeof parsed === "object" && typeof parsed.requestId === "string") entries.push(parsed);
|
|
57
|
+
} catch {
|
|
58
|
+
/* keep reading after a partially written or hand-edited line */
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return entries;
|
|
62
|
+
}
|
|
Binary file
|
package/src/ws-bridge.ts
CHANGED
|
@@ -17,8 +17,8 @@ const SAFE_RESPONSE_HEADER_EXACT = new Set([
|
|
|
17
17
|
]);
|
|
18
18
|
|
|
19
19
|
export interface WsData {
|
|
20
|
-
headers?: Headers; //
|
|
21
|
-
authContext?: CodexAuthContext; //
|
|
20
|
+
headers?: Headers; // base inbound forward headers only; per-turn auth refresh injects current pool tokens
|
|
21
|
+
authContext?: CodexAuthContext; // last resolved account decision for observability/registry cleanup
|
|
22
22
|
cancel?: () => void; // cancels the in-flight stream reader/fetch
|
|
23
23
|
turnId?: number; // monotonically increasing per socket; prevents stale frames after replacement turns
|
|
24
24
|
}
|
package/gui/README.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# React + TypeScript + Vite
|
|
2
|
-
|
|
3
|
-
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
-
|
|
5
|
-
Currently, two official plugins are available:
|
|
6
|
-
|
|
7
|
-
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
|
8
|
-
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
|
9
|
-
|
|
10
|
-
## React Compiler
|
|
11
|
-
|
|
12
|
-
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
|
13
|
-
|
|
14
|
-
## Expanding the ESLint configuration
|
|
15
|
-
|
|
16
|
-
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
|
17
|
-
|
|
18
|
-
```js
|
|
19
|
-
export default defineConfig([
|
|
20
|
-
globalIgnores(['dist']),
|
|
21
|
-
{
|
|
22
|
-
files: ['**/*.{ts,tsx}'],
|
|
23
|
-
extends: [
|
|
24
|
-
// Other configs...
|
|
25
|
-
|
|
26
|
-
// Remove tseslint.configs.recommended and replace with this
|
|
27
|
-
tseslint.configs.recommendedTypeChecked,
|
|
28
|
-
// Alternatively, use this for stricter rules
|
|
29
|
-
tseslint.configs.strictTypeChecked,
|
|
30
|
-
// Optionally, add this for stylistic rules
|
|
31
|
-
tseslint.configs.stylisticTypeChecked,
|
|
32
|
-
|
|
33
|
-
// Other configs...
|
|
34
|
-
],
|
|
35
|
-
languageOptions: {
|
|
36
|
-
parserOptions: {
|
|
37
|
-
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
38
|
-
tsconfigRootDir: import.meta.dirname,
|
|
39
|
-
},
|
|
40
|
-
// other options...
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
])
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
|
47
|
-
|
|
48
|
-
```js
|
|
49
|
-
// eslint.config.js
|
|
50
|
-
import reactX from 'eslint-plugin-react-x'
|
|
51
|
-
import reactDom from 'eslint-plugin-react-dom'
|
|
52
|
-
|
|
53
|
-
export default defineConfig([
|
|
54
|
-
globalIgnores(['dist']),
|
|
55
|
-
{
|
|
56
|
-
files: ['**/*.{ts,tsx}'],
|
|
57
|
-
extends: [
|
|
58
|
-
// Other configs...
|
|
59
|
-
// Enable lint rules for React
|
|
60
|
-
reactX.configs['recommended-typescript'],
|
|
61
|
-
// Enable lint rules for React DOM
|
|
62
|
-
reactDom.configs.recommended,
|
|
63
|
-
],
|
|
64
|
-
languageOptions: {
|
|
65
|
-
parserOptions: {
|
|
66
|
-
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
67
|
-
tsconfigRootDir: import.meta.dirname,
|
|
68
|
-
},
|
|
69
|
-
// other options...
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
])
|
|
73
|
-
```
|