@stage-labs/metro 0.1.0-beta.209 → 0.1.0-beta.210
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.210",
|
|
4
4
|
"description": "Metro for Claude Code, installed by the metro daemon on this machine: every connector the agent holds as its own MCP server relayed through the daemon, the orchestrator-only guard on the main thread, and the standing rules loaded at each session start. No vendor credential ever sits in a config file.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bonustrack",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { errMsg, log } from '@metro-labs/core/log';
|
|
2
|
+
|
|
3
|
+
const BUILT_IN = '0.157.1';
|
|
4
|
+
const REGISTRY = 'https://registry.npmjs.org/@openai/codex/latest';
|
|
5
|
+
const OVERRIDE_RE = /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.]+)?$/;
|
|
6
|
+
const STABLE_RE = /^\d+\.\d+\.\d+$/;
|
|
7
|
+
const FRESH_MS = 6 * 3_600_000;
|
|
8
|
+
const FETCH_MS = 5_000;
|
|
9
|
+
|
|
10
|
+
let learned: { version: string; at: number } | null = null;
|
|
11
|
+
|
|
12
|
+
const parts = (version: string): number[] => version.split('.').map(Number);
|
|
13
|
+
|
|
14
|
+
function newer(a: string, b: string): boolean {
|
|
15
|
+
const [x, y] = [parts(a), parts(b)];
|
|
16
|
+
for (let i = 0; i < 3; i++) if ((x[i] ?? 0) !== (y[i] ?? 0)) return (x[i] ?? 0) > (y[i] ?? 0);
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function codexVersion(): string {
|
|
21
|
+
const wanted = process.env.METRO_CODEX_VERSION?.trim() ?? '';
|
|
22
|
+
if (wanted !== '' && OVERRIDE_RE.test(wanted)) return wanted;
|
|
23
|
+
if (wanted !== '') log.warn({ value: wanted }, 'gateway: METRO_CODEX_VERSION is not a version like 0.157.1; using the known one');
|
|
24
|
+
return learned !== null && newer(learned.version, BUILT_IN) ? learned.version : BUILT_IN;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function latestOnNpm(): Promise<string> {
|
|
28
|
+
const res = await fetch(process.env.METRO_CODEX_REGISTRY ?? REGISTRY, { signal: AbortSignal.timeout(FETCH_MS) });
|
|
29
|
+
const body: unknown = await res.json();
|
|
30
|
+
const version = typeof body === 'object' && body !== null ? (body as { version?: unknown }).version : undefined;
|
|
31
|
+
if (!res.ok || typeof version !== 'string' || !STABLE_RE.test(version)) throw new Error(`npm answered ${String(res.status)} without a stable version`);
|
|
32
|
+
return version;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function learnCodexVersion(now = Date.now()): Promise<string> {
|
|
36
|
+
if (learned !== null && now - learned.at < FRESH_MS) return codexVersion();
|
|
37
|
+
try {
|
|
38
|
+
learned = { version: await latestOnNpm(), at: now };
|
|
39
|
+
} catch (err) {
|
|
40
|
+
log.warn({ err: errMsg(err) }, 'gateway: the latest Codex version could not be read from npm; using the known one');
|
|
41
|
+
learned = { version: learned?.version ?? BUILT_IN, at: now };
|
|
42
|
+
}
|
|
43
|
+
return codexVersion();
|
|
44
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
3
3
|
import { arch, platform, release } from 'node:os';
|
|
4
|
-
import {
|
|
4
|
+
import { codexVersion, learnCodexVersion } from './codex-version.js';
|
|
5
5
|
import { refreshTokens, tokensStale, type CodexTokens } from './codex-auth.js';
|
|
6
6
|
import { CodexEventTranslator } from './codex-stream.js';
|
|
7
7
|
import { ToolNames, toResponsesRequest } from './codex-translate.js';
|
|
@@ -12,8 +12,6 @@ import { answerWhole, currentOf, errorKind, reach, refreshed, relayTranslated, s
|
|
|
12
12
|
import { noteUsageHeaders } from './usage.js';
|
|
13
13
|
|
|
14
14
|
const CODEX_BASE = 'https://chatgpt.com/backend-api/codex';
|
|
15
|
-
const CODEX_VERSION = '0.153.4';
|
|
16
|
-
const VERSION_RE = /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.]+)?$/;
|
|
17
15
|
const INVALID = [400, 404, 422];
|
|
18
16
|
|
|
19
17
|
export interface CodexDeps {
|
|
@@ -36,14 +34,6 @@ const sourceOf = (deps: CodexDeps): TokenSource<CodexTokens> => ({
|
|
|
36
34
|
|
|
37
35
|
const OS_NAMES: Record<string, string> = { darwin: 'Mac OS', linux: 'Linux', win32: 'Windows' };
|
|
38
36
|
|
|
39
|
-
export function codexVersion(): string {
|
|
40
|
-
const wanted = process.env.METRO_CODEX_VERSION?.trim() ?? '';
|
|
41
|
-
if (wanted === '') return CODEX_VERSION;
|
|
42
|
-
if (VERSION_RE.test(wanted)) return wanted;
|
|
43
|
-
log.warn({ value: wanted }, 'gateway: METRO_CODEX_VERSION is not a version like 0.153.4; using the built-in one');
|
|
44
|
-
return CODEX_VERSION;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
37
|
export const userAgent = (): string => `codex_cli_rs/${codexVersion()} (${OS_NAMES[platform()] ?? platform()} ${release()}; ${arch()}) metro`;
|
|
48
38
|
|
|
49
39
|
function headersFor(tokens: CodexTokens, sessionId: string): Record<string, string> {
|
|
@@ -118,7 +108,8 @@ export async function codexMessages(
|
|
|
118
108
|
}
|
|
119
109
|
|
|
120
110
|
export async function codexModels(tokens: CodexTokens, deps: Omit<CodexDeps, 'save'>): Promise<string[]> {
|
|
121
|
-
const
|
|
111
|
+
const version = await learnCodexVersion();
|
|
112
|
+
const res = await (deps.fetchImpl ?? fetch)(`${deps.base ?? CODEX_BASE}/models?client_version=${version}`, {
|
|
122
113
|
headers: { ...headersFor(tokens, randomUUID()), accept: 'application/json' },
|
|
123
114
|
redirect: 'manual',
|
|
124
115
|
});
|
package/runtime/runtime.json
CHANGED