sneakoscope 9.1.0 → 9.2.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 (33) hide show
  1. package/README.md +1 -1
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/commands/bridge.js +11 -0
  5. package/dist/config/skills-manifest.json +1 -1
  6. package/dist/core/codex-app.js +1 -1
  7. package/dist/core/codex-control/codex-sdk-env-policy.js +44 -9
  8. package/dist/core/codex-lb/bridge-contracts.js +1 -0
  9. package/dist/core/codex-lb/desktop-bridge/header-policy.js +38 -0
  10. package/dist/core/codex-lb/desktop-bridge/http-forward.js +135 -49
  11. package/dist/core/codex-lb/desktop-bridge/rejection-log.js +1 -0
  12. package/dist/core/codex-lb/desktop-bridge/security.js +55 -3
  13. package/dist/core/codex-lb/desktop-bridge/server.js +7 -15
  14. package/dist/core/codex-lb/desktop-bridge/types.js +1 -0
  15. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +35 -14
  16. package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +1 -3
  17. package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +1 -1
  18. package/dist/core/codex-lb/desktop-bridge-migration.js +2 -4
  19. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +6 -4
  20. package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +36 -2
  21. package/dist/core/codex-lb/desktop-controller-v3.js +3 -1
  22. package/dist/core/codex-lb/desktop-service.js +95 -11
  23. package/dist/core/codex-lb/provider-route-policy.js +30 -1
  24. package/dist/core/codex-lb/request-route-resolver.js +14 -0
  25. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +28 -0
  26. package/dist/core/hooks-runtime.js +2 -2
  27. package/dist/core/imagegen/desktop-bridge-imagegen-target.js +2 -2
  28. package/dist/core/init/skills.js +19 -4
  29. package/dist/core/provider/provider-context.js +2 -1
  30. package/dist/core/release/gate-affected-globs.js +9 -0
  31. package/dist/core/update/update-migration-state/simple-stages.js +22 -16
  32. package/dist/core/version.js +1 -1
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -22,7 +22,7 @@ Proof-first orchestration for Codex CLI, ChatGPT Desktop, AI coding agents, mult
22
22
  Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
23
23
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
24
24
 
25
- This README documents package **SKS 9.1.0** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
25
+ This README documents package **SKS 9.2.0** — its own identity, read from `package.json` and subject to release-gate verification, not advice about what to install.
26
26
 
27
27
  Use the official latest stable SKS and Codex CLI releases. The Codex compatibility SSOT is always the **current latest stable** host; capability probes measure what that host can actually do. Product docs do not crown a fixed `0.x.y` string as SSOT (release pins and schema directories are measured artifacts for the current package, not a permanent product version claim). Menu Bar / Center induce updates to the latest stable build. Run `sks update-check` for what is installed and read the capability report for what is supported. Install SSOT is npm `sneakoscope@latest`; PATH `sks` and Menu Bar stamped generation must match that version or gates fail. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it (Codex official multi-agent wrap-only; SKS does not reimplement a parallel runtime). Local code search is mode-separated (`sks search files|text|structure|symbol|context`); `context` is answered by the compiled TriWiki Context Graph (`context-graph.json` is exhaustive authority; `context-pack.json` and managed `AGENTS.md` are bounded projections) — see [docs/architecture/context-graph.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/docs/architecture/context-graph.md) and [docs/PRODUCT-CONTRACT.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/docs/PRODUCT-CONTRACT.md). See [CHANGELOG.md](https://github.com/mandarange/Sneakoscope-Codex/blob/main/CHANGELOG.md).
28
28
 
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "9.1.0"
262
+ version = "9.2.0"
263
263
  dependencies = [
264
264
  "globset",
265
265
  "grep-matcher",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "9.1.0"
3
+ version = "9.2.0"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -27,6 +27,7 @@ export function usage(command = 'bridge') {
27
27
  ` sks ${command} models select --set <public-id,...> [--json]`,
28
28
  ` sks ${command} route list [--json]`,
29
29
  ` sks ${command} route set-default <codex-lb|openrouter> [--json]`,
30
+ ` sks ${command} route official-models <passthrough|gateway|auto> [--json]`,
30
31
  ` sks ${command} route explain <model> [--json]`,
31
32
  ` sks ${command} unmanage --confirm [--json]`,
32
33
  ` sks ${command} rollback <receipt-id> --confirm [--json]`,
@@ -236,6 +237,16 @@ async function parseInvocation(args, io) {
236
237
  label: `Default bridge provider set to ${providerId}`
237
238
  };
238
239
  }
240
+ if (action === 'official-models' && target !== undefined && extra === undefined) {
241
+ allowOnly(parsed, ['--json'], []);
242
+ if (target !== 'passthrough' && target !== 'gateway' && target !== 'auto')
243
+ throw new BridgeCliError('bridge_route_official_models_mode_invalid');
244
+ return {
245
+ ...base,
246
+ request: { operation: 'route.official-models', mode: target },
247
+ label: `Official models routing set to ${target}`
248
+ };
249
+ }
239
250
  if (action === 'explain' && target !== undefined && extra === undefined) {
240
251
  allowOnly(parsed, ['--json'], []);
241
252
  return {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "9.1.0",
3
+ "package_version": "9.2.0",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -894,7 +894,7 @@ function providerModelUiStatusFromDesktopBridge(status) {
894
894
  || status.routing.policy?.default_provider_id
895
895
  || status.routing.session_pin?.provider_id
896
896
  || null;
897
- const selectedProfile = selectedProvider ? status.providers[selectedProvider] : null;
897
+ const selectedProfile = selectedProvider && selectedProvider !== 'openai' ? status.providers[selectedProvider] : null;
898
898
  const selectedProviderBlockers = uniqueStrings([
899
899
  ...status.readiness.blockers,
900
900
  ...status.routing.blockers,
@@ -160,16 +160,51 @@ export async function prepareNativeCodexAuthBridge(env, opts = {}) {
160
160
  applyCleanupProof(bridgeProof, result);
161
161
  return result;
162
162
  }
163
- await assertSourceAuthUnchanged(sourceAuthCandidate, sourceAuthIdentity, sourceAuthFingerprint);
164
- const hostAuth = { ...tempAuth, ...originalApiKeyFields };
165
- const hostAuthText = `${JSON.stringify(hostAuth, null, 2)}\n`;
166
- await writeAuthFileAtomic(sourceAuthCandidate, hostAuthText, async () => {
163
+ try {
167
164
  await assertSourceAuthUnchanged(sourceAuthCandidate, sourceAuthIdentity, sourceAuthFingerprint);
168
- });
169
- await removeOwnedTempRoot();
170
- const result = { ok: true, status: 'cleaned', outcome: 'refreshed_persisted', cleanup_required: false, blockers: [] };
171
- applyCleanupProof(bridgeProof, result);
172
- return result;
165
+ const hostAuth = { ...tempAuth, ...originalApiKeyFields };
166
+ const hostAuthText = `${JSON.stringify(hostAuth, null, 2)}\n`;
167
+ await writeAuthFileAtomic(sourceAuthCandidate, hostAuthText, async () => {
168
+ await assertSourceAuthUnchanged(sourceAuthCandidate, sourceAuthIdentity, sourceAuthFingerprint);
169
+ });
170
+ await removeOwnedTempRoot();
171
+ const result = { ok: true, status: 'cleaned', outcome: 'refreshed_persisted', cleanup_required: false, blockers: [] };
172
+ applyCleanupProof(bridgeProof, result);
173
+ return result;
174
+ }
175
+ catch (error) {
176
+ if (String(error?.message || error) !== 'native_codex_auth_source_conflict')
177
+ throw error;
178
+ const currentText = await readValidatedAuthFile(sourceAuthCandidate, {
179
+ requirePrivateMode: true,
180
+ requireSingleLink: true,
181
+ errorPrefix: 'native_codex_auth_source'
182
+ });
183
+ const currentAuth = parseStrictChatGptAuth(currentText);
184
+ const sameAccount = String(currentAuth.tokens?.account_id || '') === String(tempAuth.tokens?.account_id || '');
185
+ const hostRefreshedAt = Date.parse(String(currentAuth.last_refresh || ''));
186
+ const oursRefreshedAt = Date.parse(String(tempAuth.last_refresh || ''));
187
+ const hostWins = !sameAccount
188
+ || !Number.isFinite(oursRefreshedAt)
189
+ || (Number.isFinite(hostRefreshedAt) && hostRefreshedAt >= oursRefreshedAt);
190
+ if (hostWins) {
191
+ await removeOwnedTempRoot();
192
+ const result = { ok: true, status: 'cleaned', outcome: 'host_newer_kept', cleanup_required: false, blockers: [] };
193
+ applyCleanupProof(bridgeProof, result);
194
+ return result;
195
+ }
196
+ const currentStat = await fsp.lstat(sourceAuthCandidate);
197
+ const retryIdentity = { dev: currentStat.dev, ino: currentStat.ino };
198
+ const retryFingerprint = fingerprintText(currentText);
199
+ const mergedAuth = { ...currentAuth, tokens: tempAuth.tokens, last_refresh: tempAuth.last_refresh };
200
+ await writeAuthFileAtomic(sourceAuthCandidate, `${JSON.stringify(mergedAuth, null, 2)}\n`, async () => {
201
+ await assertSourceAuthUnchanged(sourceAuthCandidate, retryIdentity, retryFingerprint);
202
+ });
203
+ await removeOwnedTempRoot();
204
+ const result = { ok: true, status: 'cleaned', outcome: 'refreshed_persisted_after_conflict', cleanup_required: false, blockers: [] };
205
+ applyCleanupProof(bridgeProof, result);
206
+ return result;
207
+ }
173
208
  }
174
209
  catch (error) {
175
210
  const reason = String(error?.message || error || 'native_codex_auth_cleanup_failed');
@@ -1,2 +1,3 @@
1
1
  export const MANAGED_ROUTING_RUNTIME = 'desktop-bridge';
2
2
  export const BRIDGE_PROVIDER_IDS = ['codex-lb', 'openrouter'];
3
+ export const BRIDGE_OFFICIAL_ROUTE_ID = 'openai';
@@ -54,6 +54,44 @@ export function buildProviderUpstreamHeaders(inbound, context, upstreamHost) {
54
54
  injectCredential(result, context.providerId, context.authTransport, context.credential);
55
55
  return result;
56
56
  }
57
+ const OFFICIAL_PASSTHROUGH_STRIP = new Set([
58
+ 'forwarded', 'proxy-authorization', 'x-api-key', 'x-codex-lb-api-key',
59
+ 'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-port', 'x-forwarded-proto', 'x-real-ip',
60
+ 'host',
61
+ ]);
62
+ export function buildOfficialPassthroughHeaders(inbound, upstreamHost) {
63
+ const result = {};
64
+ const dynamic = connectionTokens(inbound);
65
+ for (const [rawName, rawValue] of Object.entries(inbound)) {
66
+ if (rawValue === undefined)
67
+ continue;
68
+ const name = rawName.toLowerCase();
69
+ if (HOP_BY_HOP.has(name) || dynamic.has(name))
70
+ continue;
71
+ if (name.startsWith(INTERNAL_PREFIX))
72
+ continue;
73
+ if (OFFICIAL_PASSTHROUGH_STRIP.has(name))
74
+ continue;
75
+ result[name] = rawValue;
76
+ }
77
+ result.host = upstreamHost;
78
+ if (result['x-codex-lb-api-key'] !== undefined)
79
+ throw new DesktopBridgeError('bridge_provider_credential_invalid');
80
+ return result;
81
+ }
82
+ export function buildOfficialPassthroughWebSocketHeaders(inbound, upstreamHost) {
83
+ const result = buildOfficialPassthroughHeaders(inbound, upstreamHost);
84
+ for (const [rawName, rawValue] of Object.entries(inbound)) {
85
+ if (rawValue === undefined)
86
+ continue;
87
+ const name = rawName.toLowerCase();
88
+ if (WEBSOCKET_HEADER_ALLOWLIST.has(name))
89
+ result[name] = rawValue;
90
+ }
91
+ result.connection = 'Upgrade';
92
+ result.upgrade = 'websocket';
93
+ return result;
94
+ }
57
95
  export function buildProviderWebSocketHeaders(inbound, context, upstreamHost) {
58
96
  const result = buildProviderUpstreamHeaders(inbound, context, upstreamHost);
59
97
  for (const [rawName, rawValue] of Object.entries(inbound)) {
@@ -2,7 +2,8 @@ import http, {} from 'node:http';
2
2
  import https from 'node:https';
3
3
  import zlib from 'node:zlib';
4
4
  import { pipeline } from 'node:stream/promises';
5
- import { buildProviderUpstreamHeaders, rewriteResponseHeaders } from './header-policy.js';
5
+ import { BRIDGE_OFFICIAL_ROUTE_ID } from '../bridge-contracts.js';
6
+ import { buildOfficialPassthroughHeaders, buildProviderUpstreamHeaders, rewriteResponseHeaders } from './header-policy.js';
6
7
  import { createDesktopBridgeRejectionLogger } from './rejection-log.js';
7
8
  import { resolveAndBindDesktopBridgeRouteContext, resolveCodexSessionIdentity, resolveDesktopBridgeTarget, safeBridgeErrorCode, singleBridgeHeader } from './security.js';
8
9
  import { desktopBridgeListenOrigin } from './state.js';
@@ -60,6 +61,8 @@ async function readBoundedBody(req, maximum) {
60
61
  return Buffer.concat(chunks);
61
62
  }
62
63
  async function resolveCredential(config, route) {
64
+ if (route.provider_id === BRIDGE_OFFICIAL_ROUTE_ID)
65
+ throw new DesktopBridgeError('bridge_provider_route_unavailable');
63
66
  const provider = config.providers[route.provider_id];
64
67
  if (!provider)
65
68
  throw new DesktopBridgeError('bridge_provider_route_unavailable');
@@ -107,7 +110,7 @@ export async function prepareDesktopBridgeRequest(req, config) {
107
110
  payload.model = route.upstream_model;
108
111
  body = Buffer.from(JSON.stringify(payload));
109
112
  }
110
- const credential = await resolveCredential(config, route);
113
+ const credential = route.provider_id === BRIDGE_OFFICIAL_ROUTE_ID ? null : await resolveCredential(config, route);
111
114
  return { body, route, credential, contentEncodingStripped };
112
115
  }
113
116
  function connectTimeout(request, config) {
@@ -148,6 +151,34 @@ function safeUpstreamErrorId(value) {
148
151
  const text = String(value ?? '').trim();
149
152
  return /^[A-Za-z0-9_.:-]{1,64}$/.test(text) ? text : null;
150
153
  }
154
+ const TRANSIENT_UPSTREAM_STATUSES = new Set([500, 502, 503, 524]);
155
+ const TRANSIENT_UPSTREAM_IDENTIFIERS = new Set(['upstream_error', 'upstream_request_timeout']);
156
+ export const TRANSIENT_UPSTREAM_REPLAY_LIMIT = 3;
157
+ const TRANSIENT_UPSTREAM_REPLAY_BACKOFF_MS = [200, 400, 800];
158
+ function isTransientUpstreamIdentifier(value) {
159
+ return Boolean(value && TRANSIENT_UPSTREAM_IDENTIFIERS.has(value));
160
+ }
161
+ function delay(ms) {
162
+ return new Promise((resolve) => {
163
+ const timer = setTimeout(resolve, ms);
164
+ timer.unref();
165
+ });
166
+ }
167
+ function isTransientUpstreamFailure(statusCode, upstreamType, upstreamCode) {
168
+ if (statusCode === 429)
169
+ return false;
170
+ if (statusCode === 404) {
171
+ return isTransientUpstreamIdentifier(upstreamType) || isTransientUpstreamIdentifier(upstreamCode);
172
+ }
173
+ return TRANSIENT_UPSTREAM_STATUSES.has(statusCode);
174
+ }
175
+ function redactedUpstreamClientMessage(statusCode, transient) {
176
+ if (statusCode === 429)
177
+ return 'rate_limited';
178
+ if (transient)
179
+ return 'temporary_upstream_failure';
180
+ return 'bridge_upstream_request_failed';
181
+ }
151
182
  async function readRedactedUpstreamError(response) {
152
183
  let total = 0;
153
184
  const chunks = [];
@@ -169,19 +200,18 @@ async function readRedactedUpstreamError(response) {
169
200
  }
170
201
  catch {
171
202
  }
172
- return {
173
- upstreamCode,
174
- upstreamType,
175
- body: Buffer.from(JSON.stringify({
176
- error: {
177
- type: 'upstream_error',
178
- code: 'bridge_upstream_request_failed',
179
- message: 'Upstream request failed',
180
- ...(upstreamType ? { upstream_type: upstreamType } : {}),
181
- ...(upstreamCode ? { upstream_code: upstreamCode } : {})
182
- }
183
- }))
184
- };
203
+ return { upstreamCode, upstreamType };
204
+ }
205
+ function buildRedactedUpstreamErrorBody(statusCode, upstreamCode, upstreamType, transient) {
206
+ return Buffer.from(JSON.stringify({
207
+ error: {
208
+ type: 'upstream_error',
209
+ code: 'bridge_upstream_request_failed',
210
+ message: redactedUpstreamClientMessage(statusCode, transient),
211
+ ...(upstreamType ? { upstream_type: upstreamType } : {}),
212
+ ...(upstreamCode ? { upstream_code: upstreamCode } : {}),
213
+ },
214
+ }));
185
215
  }
186
216
  const upstreamAgents = new Map();
187
217
  function upstreamAgent(secure, key, idleTimeoutMs) {
@@ -224,23 +254,32 @@ class StalePooledSocketFailure extends Error {
224
254
  export async function forwardHttp(req, res, config, prepared, authenticatedLocalBaseUrl = desktopBridgeListenOrigin(config)) {
225
255
  try {
226
256
  const request = prepared || await prepareDesktopBridgeRequest(req, config);
227
- const provider = config.providers[request.route.provider_id];
228
- if (!provider)
257
+ const official = request.route.provider_id === BRIDGE_OFFICIAL_ROUTE_ID;
258
+ const provider = official ? null : config.providers[request.route.provider_id];
259
+ if (!official && !provider)
229
260
  throw new DesktopBridgeError('bridge_provider_route_unavailable');
230
- const target = resolveDesktopBridgeTarget(req.url, provider.remote);
231
- const transport = provider.remote.secure ? https : http;
232
- const headers = buildProviderUpstreamHeaders(req.headers, {
233
- providerId: provider.provider_id, authTransport: provider.auth_transport, credential: request.credential,
234
- }, target.host);
261
+ const remote = official ? config.officialRemote : provider?.remote;
262
+ if (!remote)
263
+ throw new DesktopBridgeError('bridge_official_passthrough_unavailable');
264
+ const upstreamBaseUrl = official ? remote.baseUrl : provider.base_url;
265
+ if (!official && !request.credential)
266
+ throw new DesktopBridgeError('bridge_provider_credential_invalid');
267
+ const target = resolveDesktopBridgeTarget(req.url, remote);
268
+ const transport = remote.secure ? https : http;
269
+ const headers = official
270
+ ? buildOfficialPassthroughHeaders(req.headers, target.host)
271
+ : buildProviderUpstreamHeaders(req.headers, {
272
+ providerId: provider.provider_id, authTransport: provider.auth_transport, credential: request.credential,
273
+ }, target.host);
235
274
  if (request.body)
236
275
  headers['content-length'] = String(request.body.length);
237
276
  else
238
277
  delete headers['content-length'];
239
278
  if (request.contentEncodingStripped)
240
279
  delete headers['content-encoding'];
241
- const agent = upstreamAgent(provider.remote.secure, `${provider.remote.address}:${provider.remote.port}`, config.idleTimeoutMs);
280
+ const agent = upstreamAgent(remote.secure, `${remote.address}:${remote.port}`, config.idleTimeoutMs);
242
281
  const replayable = Buffer.isBuffer(request.body);
243
- const attempt = (useFreshConnection) => new Promise((resolve, reject) => {
282
+ const attempt = (useFreshConnection, canReplay) => new Promise((resolve, reject) => {
244
283
  let responseStarted = false;
245
284
  let settled = false;
246
285
  const abort = () => { if (!res.writableEnded)
@@ -254,10 +293,10 @@ export async function forwardHttp(req, res, config, prepared, authenticatedLocal
254
293
  error ? reject(error) : resolve();
255
294
  };
256
295
  const upstream = transport.request({
257
- protocol: target.protocol, hostname: provider.remote.address, family: provider.remote.family,
258
- port: provider.remote.port, method: req.method, path: `${target.pathname}${target.search}`, headers,
296
+ protocol: target.protocol, hostname: remote.address, family: remote.family,
297
+ port: remote.port, method: req.method, path: `${target.pathname}${target.search}`, headers,
259
298
  agent: useFreshConnection ? false : agent,
260
- ...(provider.remote.tlsServername ? { servername: provider.remote.tlsServername } : {}),
299
+ ...(remote.tlsServername ? { servername: remote.tlsServername } : {}),
261
300
  });
262
301
  connectTimeout(upstream, config);
263
302
  upstream.setTimeout(config.idleTimeoutMs, () => upstream.destroy(new DesktopBridgeError('bridge_upstream_idle_timeout')));
@@ -272,16 +311,48 @@ export async function forwardHttp(req, res, config, prepared, authenticatedLocal
272
311
  });
273
312
  upstream.once('response', (response) => {
274
313
  const statusCode = response.statusCode || 502;
314
+ if (official) {
315
+ if (statusCode >= 400 && TRANSIENT_UPSTREAM_STATUSES.has(statusCode) && replayable && canReplay) {
316
+ response.resume();
317
+ responseStarted = true;
318
+ finish(new StalePooledSocketFailure(new DesktopBridgeError('bridge_upstream_transient_mislabel')));
319
+ return;
320
+ }
321
+ if (statusCode >= 400) {
322
+ logHttpRejection({
323
+ code: `bridge_upstream_status_${statusCode}`,
324
+ transport: 'http',
325
+ ...(req.method === undefined ? {} : { method: req.method }),
326
+ ...(req.url === undefined ? {} : { url: req.url }),
327
+ status: statusCode,
328
+ provider_id: BRIDGE_OFFICIAL_ROUTE_ID,
329
+ public_model: request.route.public_model,
330
+ });
331
+ }
332
+ responseStarted = true;
333
+ try {
334
+ res.writeHead(statusCode, rewriteResponseHeaders(response.headers, upstreamBaseUrl, authenticatedLocalBaseUrl));
335
+ }
336
+ catch (error) {
337
+ response.destroy(error instanceof Error ? error : undefined);
338
+ finish(error);
339
+ return;
340
+ }
341
+ void pipeline(response, res).then(() => finish(), finish);
342
+ return;
343
+ }
275
344
  if (statusCode >= 400) {
276
- void readRedactedUpstreamError(response).then(({ body, upstreamCode, upstreamType }) => {
277
- const transientMislabel = statusCode === 404
278
- && (upstreamType === 'upstream_error' || upstreamCode === 'upstream_error');
279
- if (transientMislabel && replayable && !useFreshConnection) {
345
+ void readRedactedUpstreamError(response).then(({ upstreamCode, upstreamType }) => {
346
+ const transientMislabel = isTransientUpstreamFailure(statusCode, upstreamType, upstreamCode);
347
+ if (transientMislabel && replayable && canReplay) {
280
348
  responseStarted = true;
281
- finish(new StalePooledSocketFailure(new DesktopBridgeError('bridge_upstream_transient_mislabel')));
349
+ finish(new StalePooledSocketFailure(new DesktopBridgeError(upstreamCode === 'upstream_request_timeout'
350
+ ? 'bridge_upstream_request_timeout'
351
+ : 'bridge_upstream_transient_mislabel')));
282
352
  return;
283
353
  }
284
354
  const clientStatus = transientMislabel ? 503 : statusCode;
355
+ const body = buildRedactedUpstreamErrorBody(statusCode, upstreamCode, upstreamType, transientMislabel);
285
356
  logHttpRejection({
286
357
  code: transientMislabel
287
358
  ? `bridge_upstream_status_${statusCode}_translated_503`
@@ -294,10 +365,12 @@ export async function forwardHttp(req, res, config, prepared, authenticatedLocal
294
365
  public_model: request.route.public_model,
295
366
  });
296
367
  responseStarted = true;
297
- const responseHeaders = rewriteResponseHeaders(response.headers, provider.base_url, authenticatedLocalBaseUrl);
368
+ const responseHeaders = rewriteResponseHeaders(response.headers, upstreamBaseUrl, authenticatedLocalBaseUrl);
298
369
  responseHeaders['content-length'] = String(body.length);
299
370
  delete responseHeaders['transfer-encoding'];
300
371
  if (transientMislabel)
372
+ responseHeaders['retry-after'] = String(responseHeaders['retry-after'] || '10');
373
+ if (statusCode === 429 && !responseHeaders['retry-after'])
301
374
  responseHeaders['retry-after'] = '10';
302
375
  res.writeHead(clientStatus, responseHeaders);
303
376
  res.end(body, () => finish());
@@ -306,7 +379,7 @@ export async function forwardHttp(req, res, config, prepared, authenticatedLocal
306
379
  }
307
380
  responseStarted = true;
308
381
  try {
309
- res.writeHead(statusCode, rewriteResponseHeaders(response.headers, provider.base_url, authenticatedLocalBaseUrl));
382
+ res.writeHead(statusCode, rewriteResponseHeaders(response.headers, upstreamBaseUrl, authenticatedLocalBaseUrl));
310
383
  }
311
384
  catch (error) {
312
385
  response.destroy(error instanceof Error ? error : undefined);
@@ -321,21 +394,34 @@ export async function forwardHttp(req, res, config, prepared, authenticatedLocal
321
394
  void pipeline(req, upstream).catch((error) => { if (!responseStarted)
322
395
  finish(error); });
323
396
  });
324
- try {
325
- await attempt(false);
326
- }
327
- catch (error) {
328
- if (!(error instanceof StalePooledSocketFailure))
329
- throw error;
330
- agent.destroy();
331
- upstreamAgents.delete(`${provider.remote.secure ? 'https' : 'http'}:${provider.remote.address}:${provider.remote.port}`);
332
- logHttpRejection({
333
- code: `bridge_upstream_socket_stale_replayed:${underlyingErrorCode(error.reason) || 'unknown'}`,
334
- transport: 'http',
335
- ...(req.method === undefined ? {} : { method: req.method }),
336
- ...(req.url === undefined ? {} : { url: req.url }),
337
- });
338
- await attempt(true);
397
+ let remainingReplays = replayable ? TRANSIENT_UPSTREAM_REPLAY_LIMIT : 0;
398
+ let useFreshConnection = false;
399
+ for (;;) {
400
+ try {
401
+ await attempt(useFreshConnection, remainingReplays > 0);
402
+ return;
403
+ }
404
+ catch (error) {
405
+ if (!(error instanceof StalePooledSocketFailure) || remainingReplays <= 0)
406
+ throw error;
407
+ remainingReplays -= 1;
408
+ if (!useFreshConnection) {
409
+ agent.destroy();
410
+ upstreamAgents.delete(`${remote.secure ? 'https' : 'http'}:${remote.address}:${remote.port}`);
411
+ }
412
+ logHttpRejection({
413
+ code: `bridge_upstream_socket_stale_replayed:${underlyingErrorCode(error.reason) || 'unknown'}`,
414
+ transport: 'http',
415
+ ...(req.method === undefined ? {} : { method: req.method }),
416
+ ...(req.url === undefined ? {} : { url: req.url }),
417
+ });
418
+ useFreshConnection = true;
419
+ const backoffIndex = TRANSIENT_UPSTREAM_REPLAY_LIMIT - remainingReplays - 1;
420
+ const backoffMs = TRANSIENT_UPSTREAM_REPLAY_BACKOFF_MS[Math.max(0, backoffIndex)]
421
+ ?? TRANSIENT_UPSTREAM_REPLAY_BACKOFF_MS[TRANSIENT_UPSTREAM_REPLAY_BACKOFF_MS.length - 1];
422
+ if (backoffMs)
423
+ await delay(backoffMs);
424
+ }
339
425
  }
340
426
  }
341
427
  catch (error) {
@@ -33,6 +33,7 @@ export function createDesktopBridgeRejectionLogger(options = {}) {
33
33
  write(`${JSON.stringify({
34
34
  schema: DESKTOP_BRIDGE_LOG_SCHEMA,
35
35
  sks_version: PACKAGE_VERSION,
36
+ at: new Date(now()).toISOString(),
36
37
  secret_fields_redacted: true,
37
38
  ...payload,
38
39
  })}\n`);
@@ -1,5 +1,6 @@
1
1
  import dns from 'node:dns/promises';
2
2
  import net from 'node:net';
3
+ import { BRIDGE_OFFICIAL_ROUTE_ID } from '../bridge-contracts.js';
3
4
  import { canonicalizeBridgeModelId, normalizeBridgeUpstreamModelId, } from '../route-index.js';
4
5
  import { DESKTOP_BRIDGE_CLIENT_PATH_PREFIX, DesktopBridgeError } from './types.js';
5
6
  const MIN_HIGH_PORT = 49_152;
@@ -150,6 +151,19 @@ function canonicalPublicModel(value) {
150
151
  throw new DesktopBridgeError('catalog_model_route_missing');
151
152
  return model;
152
153
  }
154
+ export function desktopBridgeOfficialPassthroughEnabled(config) {
155
+ return Boolean(config.officialPassthrough?.baseUrl);
156
+ }
157
+ function officialRouteContext(publicModel, policy, upstreamModel) {
158
+ return {
159
+ provider_id: BRIDGE_OFFICIAL_ROUTE_ID,
160
+ public_model: publicModel,
161
+ upstream_model: upstreamModel || publicModel,
162
+ catalog_generation: policy.catalog_generation,
163
+ route_policy_generation: policy.policy_generation,
164
+ session_pin: null,
165
+ };
166
+ }
153
167
  export function resolveBridgeRequestRoute(request, policy, pins) {
154
168
  const publicModel = canonicalPublicModel(request.public_model);
155
169
  const sessionId = request.session_id ? canonicalSessionId(request.session_id) : null;
@@ -179,6 +193,8 @@ export function resolveBridgeRequestRoute(request, policy, pins) {
179
193
  const route = policy.model_routes[publicModel];
180
194
  if (!route)
181
195
  throw new DesktopBridgeError('catalog_model_route_missing');
196
+ if (route.provider_id === BRIDGE_OFFICIAL_ROUTE_ID)
197
+ return officialRouteContext(publicModel, policy, route.upstream_model);
182
198
  const nextPin = sessionId ? {
183
199
  thread_id: sessionId,
184
200
  provider_id: route.provider_id,
@@ -199,8 +215,36 @@ export function resolveBridgeRequestRoute(request, policy, pins) {
199
215
  }
200
216
  export function assertDesktopBridgeRouteContext(request, config) {
201
217
  const resolver = config.resolveRequestRoute || resolveBridgeRequestRoute;
202
- const route = resolver(request, config.routePolicy, config.providerSessionPins);
203
218
  const policy = config.routePolicy;
219
+ let route;
220
+ try {
221
+ route = resolver(request, policy, config.providerSessionPins);
222
+ }
223
+ catch (error) {
224
+ if (desktopBridgeOfficialPassthroughEnabled(config)
225
+ && error instanceof DesktopBridgeError
226
+ && (error.code === 'catalog_model_route_missing' || error.code === 'session_pin_route_unavailable')) {
227
+ const model = canonicalizeBridgeModelId(request.public_model) || '';
228
+ const live = model ? policy.model_routes[model] : undefined;
229
+ if (!live || live.provider_id === BRIDGE_OFFICIAL_ROUTE_ID) {
230
+ route = officialRouteContext(model, policy, live?.upstream_model);
231
+ }
232
+ else
233
+ throw error;
234
+ }
235
+ else
236
+ throw error;
237
+ }
238
+ if (route.provider_id === BRIDGE_OFFICIAL_ROUTE_ID) {
239
+ if (!desktopBridgeOfficialPassthroughEnabled(config))
240
+ throw new DesktopBridgeError('bridge_official_passthrough_unavailable');
241
+ if (route.catalog_generation !== policy.catalog_generation || route.route_policy_generation !== policy.policy_generation) {
242
+ throw new DesktopBridgeError('session_pin_route_unavailable');
243
+ }
244
+ if (route.session_pin)
245
+ throw new DesktopBridgeError('bridge_session_pin_invalid');
246
+ return route;
247
+ }
204
248
  const expected = policy.model_routes[route.public_model];
205
249
  if (!expected || expected.provider_id !== route.provider_id || expected.upstream_model !== route.upstream_model) {
206
250
  throw new DesktopBridgeError('catalog_model_route_missing');
@@ -399,9 +443,12 @@ function assertRegistryAndPolicy(config, registry) {
399
443
  if (policy.schema !== 'sks.bridge-routing-policy.v1' || policy.fallback !== 'none' || !policy.catalog_generation || !policy.policy_generation) {
400
444
  throw new DesktopBridgeError('bridge_route_policy_invalid');
401
445
  }
446
+ const officialConfigured = desktopBridgeOfficialPassthroughEnabled(config);
402
447
  for (const [model, route] of Object.entries(policy.model_routes)) {
448
+ const routeTargetAllowed = ids.includes(route.provider_id)
449
+ || (route.provider_id === BRIDGE_OFFICIAL_ROUTE_ID && officialConfigured);
403
450
  if (canonicalizeBridgeModelId(model) !== model
404
- || !ids.includes(route.provider_id)
451
+ || !routeTargetAllowed
405
452
  || normalizeBridgeUpstreamModelId(route.upstream_model) !== route.upstream_model) {
406
453
  throw new DesktopBridgeError('bridge_route_policy_invalid');
407
454
  }
@@ -460,6 +507,8 @@ export function validateDesktopBridgeConfig(config) {
460
507
  throw new DesktopBridgeError('bridge_client_capability_invalid');
461
508
  if (typeof config.resolveProviderCredential !== 'function')
462
509
  throw new DesktopBridgeError('bridge_provider_credential_resolver_missing');
510
+ if (config.officialPassthrough)
511
+ validateRemoteUrl(config.officialPassthrough.baseUrl);
463
512
  assertRegistryAndPolicy(config, config.providerRegistry);
464
513
  if (!Object.values(config.providerRegistry.providers).some((provider) => provider.enabled)) {
465
514
  throw new DesktopBridgeError('bridge_provider_registry_no_enabled_provider');
@@ -475,7 +524,10 @@ export async function prepareDesktopBridgeConfig(config, lookup = defaultLookup)
475
524
  return [id, prepared];
476
525
  }));
477
526
  const providers = Object.fromEntries(entries);
478
- return { ...config, providers };
527
+ const officialRemote = config.officialPassthrough
528
+ ? await resolveDesktopBridgeRemoteTarget(config.officialPassthrough.baseUrl, lookup)
529
+ : null;
530
+ return { ...config, providers, officialRemote };
479
531
  }
480
532
  export function validatePreparedDesktopBridgeConfig(config) {
481
533
  validateDesktopBridgeConfig(config);
@@ -8,7 +8,7 @@ import { createDesktopBridgePublicState, desktopBridgeListenOrigin, desktopBridg
8
8
  import { DesktopBridgeError } from './types.js';
9
9
  import { PACKAGE_VERSION } from '../../version.js';
10
10
  import { DESKTOP_BRIDGE_CLIENT_PATH_PREFIX, DESKTOP_BRIDGE_DIAGNOSTIC_HEALTH_PATH, DESKTOP_BRIDGE_DIAGNOSTIC_PATH, DESKTOP_BRIDGE_DIAGNOSTIC_PROTOCOL } from './types.js';
11
- import { forwardWebSocket } from './websocket-forward.js';
11
+ import { forwardWebSocket, safeEndUpgradeSocket } from './websocket-forward.js';
12
12
  function authenticateDesktopBridgeClient(req, input) {
13
13
  const raw = String(req.url || '/');
14
14
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw) || raw.startsWith('//') || /[\r\n\0]/.test(raw)) {
@@ -135,22 +135,14 @@ function writeUpgradeRejection(socket, error, req) {
135
135
  url: req?.url,
136
136
  status: rejectionStatus(safeBridgeErrorCode(error)),
137
137
  });
138
- socket.on('error', () => undefined);
139
- if (socket.destroyed || socket.writableEnded)
140
- return;
141
138
  const code = safeBridgeErrorCode(error);
142
139
  const status = rejectionStatus(code);
143
- try {
144
- socket.end(`HTTP/1.1 ${status} ${rejectionStatusText(status)}\r\n`
145
- + 'Content-Type: application/json\r\n'
146
- + 'Cache-Control: no-store\r\n'
147
- + 'Connection: close\r\n'
148
- + '\r\n'
149
- + JSON.stringify({ error: { type: 'sks_bridge_rejection', code, message: code } }));
150
- }
151
- catch {
152
- socket.destroy();
153
- }
140
+ safeEndUpgradeSocket(socket, `HTTP/1.1 ${status} ${rejectionStatusText(status)}\r\n`
141
+ + 'Content-Type: application/json\r\n'
142
+ + 'Cache-Control: no-store\r\n'
143
+ + 'Connection: close\r\n'
144
+ + '\r\n'
145
+ + JSON.stringify({ error: { type: 'sks_bridge_rejection', code, message: code } }));
154
146
  }
155
147
  function writeDiagnosticHealth(req, res, input) {
156
148
  if (req.method !== 'GET')
@@ -12,6 +12,7 @@ export const DESKTOP_BRIDGE_ALLOWED_PATH_PREFIXES = [
12
12
  '/api/v1/',
13
13
  '/v1/',
14
14
  ];
15
+ export const DESKTOP_BRIDGE_OFFICIAL_UPSTREAM_BASE_URL = 'https://chatgpt.com/backend-api/codex';
15
16
  export class DesktopBridgeError extends Error {
16
17
  code;
17
18
  constructor(code, options) {