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.
- package/README.md +27 -5
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +11 -8
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/agent-role-config.js +6 -2
- package/dist/core/agents/sks-model-pin-hygiene.js +150 -0
- package/dist/core/codex/codex-config-guard.js +18 -13
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +7 -1
- package/dist/core/codex-lb/bridge-contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/builder.js +4 -2
- package/dist/core/codex-lb/combined-catalog/latest-generation.js +7 -34
- package/dist/core/codex-lb/combined-catalog/normalize.js +3 -1
- package/dist/core/codex-lb/desktop-bridge/codex-lb-turn-state.js +35 -0
- package/dist/core/codex-lb/desktop-bridge/compaction-adapter.js +3 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +10 -4
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +92 -30
- package/dist/core/codex-lb/desktop-bridge/provider-handoff.js +79 -0
- package/dist/core/codex-lb/desktop-bridge/responses-websocket.js +57 -13
- package/dist/core/codex-lb/desktop-bridge/security.js +101 -55
- package/dist/core/codex-lb/desktop-bridge/server.js +10 -2
- package/dist/core/codex-lb/desktop-bridge/types.js +3 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +3 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +13 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +0 -9
- package/dist/core/codex-lb/desktop-service.js +10 -13
- package/dist/core/codex-lb/request-route-resolver.js +1 -1
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +0 -1
- package/dist/core/hooks-runtime/jev-spawn-routing.js +1 -5
- package/dist/core/hooks-runtime/parent-orchestration-gate.js +6 -8
- package/dist/core/hooks-runtime.js +13 -9
- package/dist/core/init/skills.js +22 -3
- package/dist/core/provider/provider-context.js +4 -1
- package/dist/core/search/context.js +2 -2
- package/dist/core/update/update-migration-state.js +10 -40
- package/dist/core/version.js +1 -1
- 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.
|
|
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.
|
|
136
|
-
|
|
137
|
-
|
|
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.
|
|
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
|
|
@@ -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
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
return
|
|
11
|
-
if (
|
|
12
|
-
return
|
|
13
|
-
return upsertTopLevelTomlString(
|
|
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);
|
|
@@ -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
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
622
|
+
return null;
|
|
618
623
|
}
|
|
619
|
-
return
|
|
624
|
+
return null;
|
|
620
625
|
}
|
|
621
626
|
function isSksModeLockMarker(value = '') {
|
|
622
|
-
return /^#\s*(?:SKS|Sneakoscope)\b.*(?:
|
|
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.*(?:
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
}
|