sneakoscope 10.7.0 → 10.7.1

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 (37) hide show
  1. package/README.md +27 -5
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/cli/install-helpers-codex-lb-config.js +11 -8
  5. package/dist/config/skills-manifest.json +1 -1
  6. package/dist/core/agents/agent-role-config.js +6 -2
  7. package/dist/core/agents/sks-model-pin-hygiene.js +150 -0
  8. package/dist/core/codex/codex-config-guard.js +18 -13
  9. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +7 -1
  10. package/dist/core/codex-lb/bridge-contracts.js +5 -0
  11. package/dist/core/codex-lb/combined-catalog/builder.js +4 -2
  12. package/dist/core/codex-lb/combined-catalog/latest-generation.js +7 -34
  13. package/dist/core/codex-lb/combined-catalog/normalize.js +3 -1
  14. package/dist/core/codex-lb/desktop-bridge/codex-lb-turn-state.js +35 -0
  15. package/dist/core/codex-lb/desktop-bridge/compaction-adapter.js +3 -0
  16. package/dist/core/codex-lb/desktop-bridge/header-policy.js +10 -4
  17. package/dist/core/codex-lb/desktop-bridge/http-forward.js +92 -30
  18. package/dist/core/codex-lb/desktop-bridge/provider-handoff.js +79 -0
  19. package/dist/core/codex-lb/desktop-bridge/responses-websocket.js +57 -13
  20. package/dist/core/codex-lb/desktop-bridge/security.js +101 -55
  21. package/dist/core/codex-lb/desktop-bridge/server.js +10 -2
  22. package/dist/core/codex-lb/desktop-bridge/types.js +3 -0
  23. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +3 -0
  24. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +13 -0
  25. package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +0 -9
  26. package/dist/core/codex-lb/desktop-service.js +10 -13
  27. package/dist/core/codex-lb/request-route-resolver.js +1 -1
  28. package/dist/core/codex-runtime/codex-desktop-config-policy.js +0 -1
  29. package/dist/core/hooks-runtime/jev-spawn-routing.js +1 -5
  30. package/dist/core/hooks-runtime/parent-orchestration-gate.js +6 -8
  31. package/dist/core/hooks-runtime.js +13 -9
  32. package/dist/core/init/skills.js +22 -3
  33. package/dist/core/provider/provider-context.js +4 -1
  34. package/dist/core/search/context.js +2 -2
  35. package/dist/core/update/update-migration-state.js +10 -40
  36. package/dist/core/version.js +1 -1
  37. package/package.json +2 -2
package/README.md CHANGED
@@ -17,8 +17,9 @@
17
17
  Sneakoscope Codex (`sks`) is an open-source local tool for the Codex CLI and Codex desktop app. It adds a macOS control center, bounded agent workflows, repository context, and evidence checks for SKS releases.
18
18
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
19
19
 
20
- Current package: **SKS 10.7.0**, prepared for npm publication.
20
+ Current package: **SKS 10.7.1**, prepared for npm publication.
21
21
  [Latest release notes](https://github.com/mandarange/Sneakoscope-Codex/releases/latest)
22
+ · [npm package](https://www.npmjs.com/package/sneakoscope)
22
23
  · [Changelog](CHANGELOG.md). Install the latest stable release from npm.
23
24
 
24
25
  Ordinary work stays with the main agent. Optional Jev decisions use OpenRouter
@@ -132,9 +133,13 @@ sks doctor --json
132
133
 
133
134
  `sks update` updates the **global** SKS package, verifies the installed command,
134
135
  and reconciles SKS-managed skills, hooks, configuration and SKS Center where
135
- available. In 10.5.5 and later it also repairs the known ignored Codex settings
136
- and refreshes managed guidance. User-authored text and explicit preferences
137
- are preserved. If a step fails, follow the recovery action in its output.
136
+ available. Cleanup follows the current package's manifest and ownership markers
137
+ regardless of the previous version, including mixed leftovers from interrupted
138
+ installs or a missing old generation manifest. Running it again when already
139
+ current still repairs the managed setup. It also repairs the known ignored
140
+ Codex settings and refreshes managed guidance. User-authored text, credentials
141
+ and explicit preferences are preserved. A required cleanup failure blocks
142
+ completion and is reported with its recovery action.
138
143
 
139
144
  To check available updates first, run `sks update check`. For a repair without
140
145
  requesting a newer package, run `sks doctor --fix` yourself in the terminal.
@@ -155,7 +160,24 @@ references and rebuilds TriWiki. Update and user-run `sks doctor --fix` share
155
160
  that maintenance and repair known ignored configuration settings. User text
156
161
  and model choices are preserved. See [harness maintenance](docs/align-modernization.md).
157
162
 
158
- ### New in 10.5.7
163
+ ### New in 10.7.0
164
+
165
+ - **A smaller command surface:** duplicate and unused commands were removed;
166
+ use `sks help <command>` for the supported command path.
167
+ - **Project-aware verification:** Plans and Proof Field reports use the target
168
+ project's own package scripts and checks instead of SKS maintainer commands.
169
+ - **Project-owned marketing:** SEO/GEO research and apply flows describe the
170
+ project they run in and preserve an existing project description.
171
+ - **Essential-profile guidance:** read-only paths stay lightweight while
172
+ safety checks remain active; destructive defaults and misleading proof paths
173
+ are refused.
174
+ - **Faster read-only commands:** status and help paths no longer load unrelated
175
+ update-migration machinery.
176
+
177
+ These changes are product behavior and validation improvements; they do not
178
+ claim a measured model-quality or general speed increase.
179
+
180
+ ### Earlier highlights: 10.5.7
159
181
 
160
182
  - **Jev execution profiles:** a decision can propose a bounded execution plan.
161
183
  The default policy is `baseline`; fast profiles require `optimize` and an
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "10.7.0"
262
+ version = "10.7.1"
263
263
  dependencies = [
264
264
  "globset",
265
265
  "grep-matcher",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "10.7.0"
3
+ version = "10.7.1"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -4,13 +4,16 @@ import { escapeRegExp } from '../core/text/regex.js';
4
4
  export const DESKTOP_BRIDGE_MANAGED_MARKER = '# sks-desktop-bridge-managed';
5
5
  export const DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER = '# sks-desktop-bridge-managed-base-url';
6
6
  export const DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER = '# sks-desktop-bridge-managed-model-catalog';
7
- export function bindCodexClientProvider(text, provider) {
8
- const selected = topLevelTomlString(text, 'model_provider');
9
- if (selected && selected !== 'openai' && selected !== 'codex-lb')
10
- return text;
11
- if (selected === provider)
12
- return text;
13
- return upsertTopLevelTomlString(String(text || ''), 'model_provider', provider);
7
+ export function repairManagedCodexLbClientSelection(text) {
8
+ const source = String(text || '');
9
+ if (topLevelTomlString(source, 'model_provider') !== 'codex-lb')
10
+ return source;
11
+ if (!topLevelHasLine(source, DESKTOP_BRIDGE_MANAGED_MARKER) || hasCodexLbProviderTable(source))
12
+ return source;
13
+ return upsertTopLevelTomlString(source, 'model_provider', 'openai');
14
+ }
15
+ export function hasCodexLbProviderTable(text) {
16
+ return /^\s*\[model_providers\.(?:"codex-lb"|codex-lb)\]\s*(?:#.*)?$/m.test(text);
14
17
  }
15
18
  export function upsertDesktopBridgeManagedConfig(text, input) {
16
19
  const bridgeBaseUrl = normalizeManagedBridgeBaseUrl(input.bridgeBaseUrl);
@@ -39,7 +42,7 @@ export function upsertDesktopBridgeManagedConfig(text, input) {
39
42
  if (existingCatalog && !catalogOwned) {
40
43
  throw new Error('historical_user_owned_config_conflict:model_catalog_json');
41
44
  }
42
- const keepCodexLb = selectedProvider === 'codex-lb';
45
+ const keepCodexLb = selectedProvider === 'codex-lb' && hasCodexLbProviderTable(next);
43
46
  next = removeManagedBridgeTopLevelBindings(next);
44
47
  next = upsertTopLevelTomlString(next, 'model_provider', keepCodexLb ? 'codex-lb' : 'openai');
45
48
  next = addTopLevelMarkerBeforeKey(next, 'model_provider', DESKTOP_BRIDGE_MANAGED_MARKER);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "10.7.0",
3
+ "package_version": "10.7.1",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -5,6 +5,7 @@ import { nowIso, readText, writeJsonAtomic } from '../fsx.js';
5
5
  import { inspectConfinedPath, moveConfinedPath, removeConfinedDirectoryIfEmpty, removeManagedPathVerified, uniqueConfinedPath, walkConfinedEntries } from '../managed-path-safety.js';
6
6
  import { MANAGED_OFFICIAL_SUBAGENT_ROLES, RETIRED_MANAGED_AGENT_ROLE_TOMBSTONES, managedAgentRoleOwnsText } from '../managed-assets/managed-assets-manifest.js';
7
7
  import { installOfficialSubagentAgentConfigs, refreshGlobalOfficialSubagentAgentConfigs } from '../subagents/official-subagent-config.js';
8
+ import { reconcileStaleSksModelPins } from './sks-model-pin-hygiene.js';
8
9
  export const AGENT_ROLE_CONFIG_REPAIR_SCHEMA = 'sks.agent-role-config-repair.v1';
9
10
  export async function repairAgentRoleConfigs(input) {
10
11
  const root = path.resolve(input.root);
@@ -18,6 +19,7 @@ export async function repairAgentRoleConfigs(input) {
18
19
  ...(input.globalRuntimeRoot ? { globalRuntimeRoot: input.globalRuntimeRoot } : {}),
19
20
  fix: input.apply === true
20
21
  });
22
+ const modelPinHygiene = await reconcileStaleSksModelPins({ root, codexHome, fix: input.apply === true });
21
23
  const officialRepair = await installOfficialSubagentAgentConfigs(root, { apply: input.apply === true });
22
24
  const globalRepair = path.join(root, '.codex') === codexHome
23
25
  ? null
@@ -38,7 +40,7 @@ export async function repairAgentRoleConfigs(input) {
38
40
  schema: AGENT_ROLE_CONFIG_REPAIR_SCHEMA,
39
41
  generated_at: nowIso(),
40
42
  ok: input.apply
41
- ? requiredFixes === appliedFixes && manualBlockers.length === 0 && retiredRoleCleanup.ok
43
+ ? requiredFixes === appliedFixes && manualBlockers.length === 0 && retiredRoleCleanup.ok && modelPinHygiene.errors.length === 0
42
44
  : manualBlockers.length === 0 && retiredRoleCleanup.ok && (globalRepair?.stale.length || 0) === 0,
43
45
  apply: input.apply === true,
44
46
  missing,
@@ -51,12 +53,14 @@ export async function repairAgentRoleConfigs(input) {
51
53
  manual_blockers: manualBlockers,
52
54
  manifest_role_ids: MANAGED_OFFICIAL_SUBAGENT_ROLES.map((role) => role.id),
53
55
  retired_role_cleanup: retiredRoleCleanup,
56
+ model_pin_hygiene: modelPinHygiene,
54
57
  warnings_suppressed: true,
55
58
  blockers: [
56
59
  ...manualBlockers,
57
60
  ...(!input.apply ? (globalRepair?.stale.map((file) => `stale_global_official_subagent_agent:${globalPath(file)}`) || []) : []),
58
61
  ...(input.apply && requiredFixes !== appliedFixes ? ['agent_role_config_repair_incomplete'] : []),
59
- ...(!retiredRoleCleanup.ok ? ['retired_agent_role_cleanup_incomplete'] : [])
62
+ ...(!retiredRoleCleanup.ok ? ['retired_agent_role_cleanup_incomplete'] : []),
63
+ ...modelPinHygiene.errors.map((error) => `model_pin_hygiene_failed:${error}`)
60
64
  ]
61
65
  };
62
66
  if (input.reportPath)
@@ -0,0 +1,150 @@
1
+ import fsp from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { readText, writeTextAtomic } from '../fsx.js';
4
+ import { hasCodexLbProviderTable } from '../../cli/install-helpers-codex-lb-config.js';
5
+ import { hasSksManagedCodexConfigMarker, writeCodexConfigGuarded } from '../codex/codex-config-guard.js';
6
+ import { bridgeRouteIndexPath, combinedBridgeCatalogPath } from '../codex-lb/combined-catalog.js';
7
+ import { readActiveCombinedBridgeCatalog } from '../codex-lb/combined-catalog/persistence.js';
8
+ import { backupInvalidToml } from '../subagents/official-subagent-config.js';
9
+ export const MODEL_PIN_HYGIENE_SCHEMA = 'sks.model-pin-hygiene.v1';
10
+ const LEGACY_ROLE_NAMES = new Set(['sks-planner', 'sks-implementer', 'sks-explorer', 'sks-checker']);
11
+ async function catalogPinState(codexHome) {
12
+ const read = await readActiveCombinedBridgeCatalog(combinedBridgeCatalogPath(codexHome), bridgeRouteIndexPath(codexHome)).catch(() => null);
13
+ if (!read?.ok)
14
+ return null;
15
+ const rows = new Map();
16
+ for (const row of read.catalog.models) {
17
+ for (const id of [row.public_id, row.slug])
18
+ if (typeof id === 'string' && id)
19
+ rows.set(id, row);
20
+ }
21
+ return (model) => {
22
+ const row = rows.get(model);
23
+ if (!row)
24
+ return 'unlisted';
25
+ const visibility = String(row.visibility || 'list').toLowerCase();
26
+ const upgrade = row.upgrade && typeof row.upgrade === 'object' ? row.upgrade.model : null;
27
+ return visibility === 'hide' || visibility === 'hidden' || (typeof upgrade === 'string' && upgrade) ? 'superseded' : 'current';
28
+ };
29
+ }
30
+ function topLevelEnd(lines) {
31
+ const end = lines.findIndex((line) => /^\s*\[/.test(line) || /^\s*developer_instructions\s*=/.test(line));
32
+ return end === -1 ? lines.length : end;
33
+ }
34
+ function stalePinLines(text, pinState, codexLbProviderDefined) {
35
+ const lines = text.split('\n');
36
+ const indexes = [];
37
+ const labels = [];
38
+ for (let index = 0; index < topLevelEnd(lines); index += 1) {
39
+ const match = /^\s*(model|model_provider)\s*=\s*"([^"]*)"\s*(?:#.*)?$/.exec(lines[index] || '');
40
+ if (!match)
41
+ continue;
42
+ const [, key, value] = match;
43
+ const stale = key === 'model_provider'
44
+ ? value === 'codex-lb' && !codexLbProviderDefined
45
+ : pinState !== null && pinState(value) !== 'current';
46
+ if (!stale)
47
+ continue;
48
+ indexes.push(index);
49
+ labels.push(`${key} = "${value}"`);
50
+ }
51
+ return { indexes, labels };
52
+ }
53
+ function withoutLines(text, indexes) {
54
+ const drop = new Set(indexes);
55
+ return text.split('\n').filter((_, index) => !drop.has(index)).join('\n');
56
+ }
57
+ const CODEX_LB_SELECTION_EVIDENCE = [
58
+ /^\s*model_provider\s*=\s*["']codex-lb["']\s*(?:#.*)?$/,
59
+ /^\s*\[model_providers\.(?:"codex-lb"|codex-lb)\]\s*(?:#.*)?$/
60
+ ];
61
+ function sksOwnedProjectConfig(text) {
62
+ const withoutSelection = text.split('\n')
63
+ .filter((line) => !CODEX_LB_SELECTION_EVIDENCE.some((pattern) => pattern.test(line)))
64
+ .join('\n');
65
+ return hasSksManagedCodexConfigMarker(withoutSelection);
66
+ }
67
+ function isLegacySksRole(file, text) {
68
+ if (/sks_managed_body_sha256/.test(text))
69
+ return false;
70
+ const name = /^\s*name\s*=\s*"([^"]+)"/m.exec(text)?.[1] ?? path.basename(file, '.toml');
71
+ return /^\s*description\s*=\s*"SKS managed\b/m.test(text) || LEGACY_ROLE_NAMES.has(name);
72
+ }
73
+ async function regularFile(file) {
74
+ const stat = await fsp.lstat(file).catch(() => null);
75
+ return Boolean(stat?.isFile() && !stat.isSymbolicLink());
76
+ }
77
+ async function roleFiles(dir) {
78
+ const entries = await fsp.readdir(dir).catch(() => []);
79
+ return entries.filter((name) => name.endsWith('.toml')).sort().map((name) => path.join(dir, name));
80
+ }
81
+ export async function reconcileStaleSksModelPins(input) {
82
+ const root = path.resolve(input.root);
83
+ const codexHome = path.resolve(input.codexHome);
84
+ const pinState = await catalogPinState(codexHome);
85
+ const report = {
86
+ schema: MODEL_PIN_HYGIENE_SCHEMA,
87
+ fix: input.fix,
88
+ catalog_available: pinState !== null,
89
+ changes: [],
90
+ remaining: [],
91
+ errors: []
92
+ };
93
+ const projectConfig = path.join(root, '.codex', 'config.toml');
94
+ const projectText = projectConfig !== path.join(codexHome, 'config.toml') && await regularFile(projectConfig)
95
+ ? await readText(projectConfig, '')
96
+ : null;
97
+ const providerDefinedAbove = hasCodexLbProviderTable(await readText(path.join(codexHome, 'config.toml'), ''))
98
+ || (projectText !== null && hasCodexLbProviderTable(projectText));
99
+ const agentDirs = [...new Set([path.join(codexHome, 'agents'), path.join(root, '.codex', 'agents')])];
100
+ for (const dir of agentDirs) {
101
+ for (const file of await roleFiles(dir)) {
102
+ if (!(await regularFile(file)))
103
+ continue;
104
+ const text = await readText(file, '');
105
+ if (!isLegacySksRole(file, text))
106
+ continue;
107
+ const pins = stalePinLines(text, pinState, providerDefinedAbove || hasCodexLbProviderTable(text));
108
+ if (!pins.indexes.length)
109
+ continue;
110
+ if (!input.fix) {
111
+ report.remaining.push({ file, removed: pins.labels, backup_path: null });
112
+ continue;
113
+ }
114
+ try {
115
+ const backup = await backupInvalidToml(file, text, 'model-pin-hygiene');
116
+ const mode = (await fsp.stat(file)).mode & 0o777;
117
+ await writeTextAtomic(file, withoutLines(text, pins.indexes), { mode });
118
+ report.changes.push({ file, removed: pins.labels, backup_path: backup });
119
+ }
120
+ catch (error) {
121
+ report.errors.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);
122
+ report.remaining.push({ file, removed: pins.labels, backup_path: null });
123
+ }
124
+ }
125
+ }
126
+ if (projectText !== null) {
127
+ const text = projectText;
128
+ const pins = sksOwnedProjectConfig(text) ? stalePinLines(text, pinState, providerDefinedAbove) : { indexes: [], labels: [] };
129
+ if (pins.indexes.length && !input.fix)
130
+ report.remaining.push({ file: projectConfig, removed: pins.labels, backup_path: null });
131
+ else if (pins.indexes.length) {
132
+ const write = await writeCodexConfigGuarded({
133
+ root,
134
+ configPath: projectConfig,
135
+ before: text,
136
+ mutate: () => withoutLines(text, pins.indexes),
137
+ cause: 'model-pin-hygiene',
138
+ backupTag: 'model-pin-hygiene',
139
+ verifyUnchangedBeforeWrite: true
140
+ });
141
+ if (write.ok)
142
+ report.changes.push({ file: projectConfig, removed: pins.labels, backup_path: write.backup_path });
143
+ else {
144
+ report.errors.push(`${projectConfig}: ${write.status}`);
145
+ report.remaining.push({ file: projectConfig, removed: pins.labels, backup_path: null });
146
+ }
147
+ }
148
+ }
149
+ return report;
150
+ }
@@ -585,19 +585,24 @@ export function removeLegacyTopLevelCodexModeLocks(text = '') {
585
585
  const lines = String(ensureTrailingNewline(text) || '').split('\n');
586
586
  const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
587
587
  const end = firstTable === -1 ? lines.length : firstTable;
588
- return ensureTrailingNewline(lines.filter((line, index) => {
589
- if (index >= end)
590
- return true;
591
- if (!/^\s*(?:model|model_reasoning_effort)\s*=/.test(line))
592
- return true;
593
- return !hasSksModeLockProvenance(lines, index);
594
- }).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n'));
588
+ const drop = new Set();
589
+ for (let index = 0; index < end; index += 1) {
590
+ if (!/^\s*(?:model|model_reasoning_effort)\s*=/.test(lines[index] || ''))
591
+ continue;
592
+ const marker = sksModeLockProvenance(lines, index);
593
+ if (marker === null)
594
+ continue;
595
+ drop.add(index);
596
+ if (marker >= 0)
597
+ drop.add(marker);
598
+ }
599
+ return ensureTrailingNewline(lines.filter((_, index) => !drop.has(index)).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n'));
595
600
  }
596
- function hasSksModeLockProvenance(lines, index) {
601
+ function sksModeLockProvenance(lines, index) {
597
602
  const current = String(lines[index] || '');
598
603
  const inlineComment = current.includes('#') ? current.slice(current.indexOf('#')) : '';
599
604
  if (isSksModeLockMarker(inlineComment))
600
- return true;
605
+ return -1;
601
606
  const allowedManagedKeys = new Set([
602
607
  'service_tier', 'model', 'model_reasoning_effort', 'model_provider',
603
608
  'approval_policy', 'sandbox_mode', 'web_search', 'notify', 'preferred_auth_method'
@@ -609,17 +614,17 @@ function hasSksModeLockProvenance(lines, index) {
609
614
  continue;
610
615
  if (candidate.startsWith('#')) {
611
616
  if (isSksModeLockMarker(candidate))
612
- return true;
617
+ return cursor;
613
618
  continue;
614
619
  }
615
620
  const key = candidate.match(/^([A-Za-z0-9_-]+)\s*=/)?.[1] || '';
616
621
  if (!allowedManagedKeys.has(key))
617
- return false;
622
+ return null;
618
623
  }
619
- return false;
624
+ return null;
620
625
  }
621
626
  function isSksModeLockMarker(value = '') {
622
- return /^#\s*(?:SKS|Sneakoscope)\b.*(?:moved machine-local Codex config|forced fast UI|managed (?:Codex )?(?:model|reasoning)|codex-lb (?:model|reasoning))/i.test(String(value || '').trim());
627
+ return /^#\s*(?:SKS|Sneakoscope)\b.*(?:forced fast UI|managed (?:Codex )?(?:model|reasoning)|codex-lb (?:model|reasoning))/i.test(String(value || '').trim());
623
628
  }
624
629
  function mergeLostFastUiKeys(before, nextInput) {
625
630
  let next = String(nextInput || '');
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { exists, nowIso, readText, sha256, writeJsonAtomic } from '../fsx.js';
5
+ import { HISTORICAL_DESKTOP_COMPAT_MARKER, HISTORICAL_OAUTH_SELECTION_MARKER, HISTORICAL_PROVIDER_SELECTION_MARKER } from '../codex-lb/desktop-bridge-migration/historical-toml.js';
5
6
  export const CODEX_APP_UI_STATE_SNAPSHOT_SCHEMA = 'sks.codex-app-ui-state-snapshot.v1';
6
7
  export const PROJECT_LOCAL_FORBIDDEN_CODEX_KEYS = [
7
8
  'openai_base_url',
@@ -14,6 +15,9 @@ export const PROJECT_LOCAL_FORBIDDEN_CODEX_KEYS = [
14
15
  const HOST_OWNED_KEY_RE = /^(?:model|model_reasoning_effort|openai_base_url|chatgpt_base_url|apps_mcp_product_sku|model_provider|model_providers(?:\.|$)|notify|profile|profiles(?:\.|$)|experimental_realtime_ws_base_url|otel(?:\.|$)|features\.fast_mode|service_tier|user\.fast_mode(?:\.|$))/;
15
16
  const SECRET_KEY_RE = /(?:key|token|secret|password|credential|cookie|authorization|auth|bearer|refresh|access|headers?|env)/i;
16
17
  const SKS_GLOBAL_UI_LOCK_KEYS = new Set(['model_provider', 'model', 'model_reasoning_effort']);
18
+ const RETIRED_SKS_SELECTION_MARKERS = new Set([
19
+ HISTORICAL_DESKTOP_COMPAT_MARKER, HISTORICAL_PROVIDER_SELECTION_MARKER, HISTORICAL_OAUTH_SELECTION_MARKER
20
+ ]);
17
21
  const SKS_GLOBAL_UI_LOCK_CONTEXT_KEYS = new Set([
18
22
  'service_tier', 'model_provider', 'model', 'model_reasoning_effort',
19
23
  'approval_policy', 'sandbox_mode', 'web_search', 'notify', 'preferred_auth_method'
@@ -155,6 +159,8 @@ export function isSksOwnedGlobalUiLock(lines, index) {
155
159
  const inlineComment = current.includes('#') ? current.slice(current.indexOf('#')) : '';
156
160
  if (isSksGlobalUiLockMarker(inlineComment))
157
161
  return true;
162
+ if (key === 'model_provider' && RETIRED_SKS_SELECTION_MARKERS.has(String(lines[index - 1] || '').trim()))
163
+ return true;
158
164
  const lowerBound = Math.max(0, index - 16);
159
165
  for (let cursor = index - 1; cursor >= lowerBound; cursor -= 1) {
160
166
  const candidate = String(lines[cursor] || '').trim();
@@ -174,7 +180,7 @@ export function isSksOwnedGlobalUiLock(lines, index) {
174
180
  return false;
175
181
  }
176
182
  function isSksGlobalUiLockMarker(value) {
177
- return /^#\s*(?:SKS|Sneakoscope)\b.*(?:moved machine-local Codex config|forced fast UI|legacy (?:provider|model|reasoning) lock|managed (?:Codex )?(?:provider|model|reasoning)|codex-lb (?:provider|model|reasoning))/i.test(String(value || '').trim());
183
+ return /^#\s*(?:SKS|Sneakoscope)\b.*(?:forced fast UI|legacy (?:provider|model|reasoning) lock|managed (?:Codex )?(?:provider|model|reasoning)|codex-lb (?:provider|model|reasoning))/i.test(String(value || '').trim());
178
184
  }
179
185
  export function scanProjectLocalForbiddenKeys(text) {
180
186
  const { signals } = scanTomlSignals(text);
@@ -1,3 +1,8 @@
1
1
  export const MANAGED_ROUTING_RUNTIME = 'desktop-bridge';
2
2
  export const BRIDGE_PROVIDER_IDS = ['codex-lb', 'openrouter'];
3
3
  export const BRIDGE_OFFICIAL_ROUTE_ID = 'openai';
4
+ export const BRIDGE_REMOTE_COMPACTION = Object.freeze({
5
+ openai: 'native',
6
+ 'codex-lb': 'native',
7
+ openrouter: 'bridge_summary',
8
+ });
@@ -1,6 +1,6 @@
1
1
  import { buildBridgeRouteIndex, sha256Stable } from '../route-index.js';
2
2
  import { COMBINED_BRIDGE_CATALOG_SCHEMA } from './contracts.js';
3
- import { normalizeProviderCatalog, providerCatalogStatus, routeProviderState } from './normalize.js';
3
+ import { OPENROUTER_PRIORITY_BASE, normalizeProviderCatalog, providerCatalogStatus, routeProviderState } from './normalize.js';
4
4
  import { pinCatalogToLatestGenerations } from './latest-generation.js';
5
5
  import { compareModels, unique } from './shared.js';
6
6
  import { applyBridgeModelSelection, availableModelRows, emptyBridgeModelSelection } from './model-selection.js';
@@ -11,7 +11,9 @@ export function buildCombinedBridgeCatalog(registry, options) {
11
11
  openrouter: normalizeProviderCatalog(options.catalogs.openrouter)
12
12
  };
13
13
  const selection = options.selection || emptyBridgeModelSelection(createdAt);
14
- const allModels = pinCatalogToLatestGenerations([...normalized['codex-lb'].models, ...normalized.openrouter.models].sort(compareModels));
14
+ let openRouterIndex = 0;
15
+ const allModels = pinCatalogToLatestGenerations([...normalized['codex-lb'].models, ...normalized.openrouter.models].sort(compareModels)).map((model) => model.provider_id === 'openrouter' ? { ...model, priority: OPENROUTER_PRIORITY_BASE + openRouterIndex++ } : model)
16
+ .sort((left, right) => left.priority - right.priority || left.slug.localeCompare(right.slug) || compareModels(left, right));
15
17
  const availableOpenRouterModels = availableModelRows(allModels, selection);
16
18
  const models = options.selection ? applyBridgeModelSelection(allModels, selection) : allModels;
17
19
  const routeBuild = buildBridgeRouteIndex({
@@ -3,13 +3,6 @@ function isListed(model) {
3
3
  const visibility = String(model.visibility || 'list').toLowerCase();
4
4
  return visibility !== 'hide' && visibility !== 'hidden';
5
5
  }
6
- function escapeRegExp(text) {
7
- return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
8
- }
9
- function displayNamePattern(displayName) {
10
- const body = escapeRegExp(displayName.trim()).replace(/\\?-|\s+/g, '[-\\s]');
11
- return new RegExp(`(?<![\\w-])${body}(?![\\w-])`, 'gi');
12
- }
13
6
  export function pinCatalogToLatestGenerations(models) {
14
7
  const newest = new Map();
15
8
  for (const model of models) {
@@ -20,34 +13,14 @@ export function pinCatalogToLatestGenerations(models) {
20
13
  if (!best || compareModelVersions(id.version, parseGptModelId(best.public_id).version) > 0)
21
14
  newest.set(id.family, model);
22
15
  }
23
- const byId = new Map(models.map((model) => [model.public_id, model]));
24
16
  return models.map((model) => {
25
17
  const id = parseGptModelId(model.public_id);
26
- let next = model;
27
- if (id && isListed(model)) {
28
- const best = newest.get(id.family);
29
- if (best && compareModelVersions(parseGptModelId(best.public_id).version, id.version) > 0)
30
- next = { ...next, visibility: 'hide' };
31
- }
32
- const upgrade = model.upgrade;
33
- const target = upgrade && typeof upgrade === 'object' ? String(upgrade.model || '') : '';
34
- const targetId = parseGptModelId(target);
35
- const replacement = targetId ? newest.get(targetId.family) : undefined;
36
- if (targetId && replacement && replacement.public_id !== target
37
- && compareModelVersions(parseGptModelId(replacement.public_id).version, targetId.version) > 0) {
38
- const old = byId.get(target);
39
- const markdown = upgrade.migration_markdown;
40
- next = {
41
- ...next,
42
- upgrade: {
43
- ...upgrade,
44
- model: replacement.public_id,
45
- ...(typeof markdown === 'string' && old?.display_name
46
- ? { migration_markdown: markdown.replace(displayNamePattern(old.display_name), () => replacement.display_name) }
47
- : {})
48
- }
49
- };
50
- }
51
- return next;
18
+ if (!id || !isListed(model))
19
+ return model;
20
+ const best = newest.get(id.family);
21
+ if (!best || compareModelVersions(parseGptModelId(best.public_id).version, id.version) <= 0)
22
+ return model;
23
+ const { upgrade: _retired, ...rest } = model;
24
+ return { ...rest, visibility: 'hide' };
52
25
  });
53
26
  }
@@ -130,7 +130,7 @@ function normalizeCodexLbBridgeCatalogModels(payload, sourceCatalogGeneration) {
130
130
  ...codexModelInfoFields(publicId, row, {
131
131
  tools: row.supports_tools === true || row.supports_tool_choice === true
132
132
  }),
133
- ...(typeof row.priority === 'number' ? {} : { priority: 100 })
133
+ ...(typeof row.priority === 'number' ? {} : { priority: CODEX_LB_DEFAULT_PRIORITY })
134
134
  });
135
135
  }
136
136
  catch (error) {
@@ -164,6 +164,8 @@ export const OPENROUTER_REASONING_LEVELS = [
164
164
  { effort: 'xhigh', description: 'Extra high reasoning depth for complex problems' }
165
165
  ];
166
166
  export const OPENROUTER_DEFAULT_REASONING_LEVEL = 'medium';
167
+ export const CODEX_LB_DEFAULT_PRIORITY = 500;
168
+ export const OPENROUTER_PRIORITY_BASE = 1000;
167
169
  function openRouterReasoningLevels() {
168
170
  return OPENROUTER_REASONING_LEVELS.map((level) => ({ ...level }));
169
171
  }
@@ -0,0 +1,35 @@
1
+ const MAX_THREADS = 4_096;
2
+ const MAX_VALUES_PER_THREAD = 8;
3
+ const issued = new Map();
4
+ function scope(threadId, keyFingerprint) {
5
+ return `${keyFingerprint}\u0000${threadId}`;
6
+ }
7
+ function headerValues(value) {
8
+ const values = Array.isArray(value) ? value : value === undefined ? [] : [String(value)];
9
+ return values.map((entry) => entry.trim()).filter(Boolean);
10
+ }
11
+ export function rememberCodexLbTurnState(threadId, keyFingerprint, headers) {
12
+ const values = headerValues(headers['x-codex-turn-state']);
13
+ if (!threadId || !values.length)
14
+ return;
15
+ const key = scope(threadId, keyFingerprint);
16
+ const kept = (issued.get(key) ?? []).filter((value) => !values.includes(value));
17
+ issued.delete(key);
18
+ issued.set(key, [...kept, ...values].slice(-MAX_VALUES_PER_THREAD));
19
+ while (issued.size > MAX_THREADS)
20
+ issued.delete(issued.keys().next().value);
21
+ }
22
+ export function admitCodexLbTurnState(headers, threadId, keyFingerprint) {
23
+ const values = headerValues(headers['x-codex-turn-state']);
24
+ if (!values.length) {
25
+ delete headers['x-codex-turn-state'];
26
+ return;
27
+ }
28
+ const known = threadId ? issued.get(scope(threadId, keyFingerprint)) : undefined;
29
+ if (values.length === 1 && known?.includes(values[0]))
30
+ return;
31
+ delete headers['x-codex-turn-state'];
32
+ }
33
+ export function forgetCodexLbTurnStates() {
34
+ issued.clear();
35
+ }
@@ -43,6 +43,9 @@ export function decodeBridgeCompaction(encrypted) {
43
43
  return null;
44
44
  }
45
45
  }
46
+ export function isNativeCompactionItem(item) {
47
+ return isObject(item) && COMPACTION_ITEM_TYPES.has(String(item.type)) && decodeBridgeCompaction(item.encrypted_content) === null;
48
+ }
46
49
  function summaryMessage(summary) {
47
50
  return { type: 'message', role: 'user', content: [{ type: 'input_text', text: `${CODEX_SUMMARY_PREFIX}\n${summary}` }] };
48
51
  }
@@ -7,9 +7,10 @@ const REQUEST_HEADER_ALLOWLIST = new Set([
7
7
  ]);
8
8
  const CODEX_LOCAL_HEADERS = new Set([
9
9
  'thread-id', 'thread_id', 'session-id', 'session_id', 'x-client-request-id',
10
- 'x-codex-installation-id', 'x-codex-turn-metadata', 'x-codex-window-id',
10
+ 'x-codex-installation-id', 'x-codex-turn-metadata', 'x-codex-window-id', 'x-codex-turn-state',
11
11
  'originator', 'openai-beta',
12
12
  ]);
13
+ const CLIENT_IDENTITY_HEADERS = new Set(['authorization', 'cookie', 'chatgpt-account-id']);
13
14
  const NEVER_FORWARD_FROM_CLIENT = new Set([
14
15
  'authorization', 'cookie', 'forwarded', 'proxy-authorization', 'x-api-key', 'x-codex-lb-api-key',
15
16
  'x-forwarded-for', 'x-forwarded-host', 'x-forwarded-port', 'x-forwarded-proto', 'x-real-ip',
@@ -39,14 +40,19 @@ function injectCredential(result, providerId, transport, credential) {
39
40
  result.authorization = `Bearer ${credential.value}`;
40
41
  }
41
42
  export function buildProviderUpstreamHeaders(inbound, context, upstreamHost) {
43
+ if (context.providerId === 'codex-lb') {
44
+ const result = buildOfficialPassthroughHeaders(inbound, upstreamHost);
45
+ for (const name of CLIENT_IDENTITY_HEADERS)
46
+ delete result[name];
47
+ injectCredential(result, context.providerId, context.authTransport, context.credential);
48
+ return result;
49
+ }
42
50
  const result = {};
43
51
  for (const [rawName, rawValue] of Object.entries(inbound)) {
44
52
  if (rawValue === undefined)
45
53
  continue;
46
54
  const name = rawName.toLowerCase();
47
- const providerAllowed = (context.providerId === 'openrouter' && OPENROUTER_CLIENT_HEADERS.has(name))
48
- || (context.providerId === 'codex-lb' && CODEX_LOCAL_HEADERS.has(name));
49
- if (!REQUEST_HEADER_ALLOWLIST.has(name) && !providerAllowed)
55
+ if (!REQUEST_HEADER_ALLOWLIST.has(name) && !(context.providerId === 'openrouter' && OPENROUTER_CLIENT_HEADERS.has(name)))
50
56
  continue;
51
57
  result[name] = rawValue;
52
58
  }