sneakoscope 8.1.2 → 8.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.
- package/README.md +96 -58
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +5 -51
- package/dist/cli/command-manifest-lite.js +2 -1
- package/dist/cli/command-registry.js +2 -1
- package/dist/cli/global-mode-router.js +1 -1
- package/dist/cli/install-helpers-codex-lb-config.js +112 -914
- package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
- package/dist/cli/install-helpers-install-support.js +4 -20
- package/dist/cli/install-helpers.js +36 -2716
- package/dist/cli/router.js +9 -9
- package/dist/commands/bridge-command-output.js +111 -0
- package/dist/commands/bridge.js +320 -0
- package/dist/commands/codex-app.js +39 -123
- package/dist/commands/doctor-helpers.js +380 -0
- package/dist/commands/doctor-profile.js +3 -0
- package/dist/commands/doctor.js +114 -873
- package/dist/commands/mad-sks.js +0 -4
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/agents/agent-effort-policy.js +11 -21
- package/dist/core/agents/agent-recursion-guard.js +26 -0
- package/dist/core/agents/agent-runner-codex-exec.js +7 -9
- package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
- package/dist/core/architecture-hardening/state/state-service.js +49 -13
- package/dist/core/auto-review.js +15 -9
- package/dist/core/codex/codex-config-guard.js +8 -0
- package/dist/core/codex-adapter.js +8 -10
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
- package/dist/core/codex-app/codex-app-launcher.js +10 -12
- package/dist/core/codex-app/codex-app-restart.js +10 -12
- package/dist/core/codex-app/menubar/constants.js +2 -5
- package/dist/core/codex-app/menubar/global-install.js +3 -2
- package/dist/core/codex-app/menubar/installer/result.js +23 -0
- package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
- package/dist/core/codex-app/menubar/installer.js +5 -96
- package/dist/core/codex-app/menubar/migration.js +1 -42
- package/dist/core/codex-app/openrouter-provider.js +0 -78
- package/dist/core/codex-app.js +97 -360
- package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
- package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
- package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
- package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
- package/dist/core/codex-control/codex-task-runner.js +16 -60
- package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
- package/dist/core/codex-exec-output-schema.js +11 -13
- package/dist/core/codex-lb/bridge-contracts.js +2 -0
- package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
- package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
- package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
- package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
- package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
- package/dist/core/codex-lb/capability-runner.js +505 -201
- package/dist/core/codex-lb/codex-lb-env.js +179 -12
- package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
- package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
- package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
- package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
- package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
- package/dist/core/codex-lb/combined-catalog.js +12 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
- package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
- package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
- package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
- package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
- package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
- package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
- package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
- package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
- package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
- package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
- package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
- package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
- package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
- package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
- package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
- package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
- package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
- package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
- package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
- package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
- package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
- package/dist/core/codex-lb/desktop-controller.js +2 -1730
- package/dist/core/codex-lb/desktop-service.js +462 -627
- package/dist/core/codex-lb/migration-receipt.js +560 -118
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
- package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
- package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
- package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
- package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
- package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
- package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
- package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
- package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
- package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
- package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
- package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
- package/dist/core/codex-lb/provider-credentials/types.js +1 -0
- package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
- package/dist/core/codex-lb/provider-credentials.js +5 -0
- package/dist/core/codex-lb/provider-registry.js +323 -0
- package/dist/core/codex-lb/provider-route-policy.js +118 -0
- package/dist/core/codex-lb/request-route-resolver.js +172 -0
- package/dist/core/codex-lb/route-index.js +148 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
- package/dist/core/commands/basic-cli.js +1 -1
- package/dist/core/commands/check-command.js +3 -10
- package/dist/core/commands/gate-result-contract.js +10 -14
- package/dist/core/commands/intent-normalization/normalizer.js +1 -1
- package/dist/core/commands/mad-sks-command.js +2 -6
- package/dist/core/commands/release-command.js +11 -1
- package/dist/core/commands/telegram-command.js +46 -6
- package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
- package/dist/core/doctor/skill-legacy-surface.js +5 -5
- package/dist/core/evidence/v2/evidence-key.js +30 -3
- package/dist/core/feature-fixtures.js +8 -1
- package/dist/core/feature-registry.js +3 -2
- package/dist/core/hooks-runtime/stop-finalization.js +11 -1
- package/dist/core/hooks-runtime/subagent-context.js +15 -1
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +73 -87
- package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
- package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
- package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
- package/dist/core/imagegen/imagegen-capability.js +43 -151
- package/dist/core/init/skills/filesystem.js +89 -0
- package/dist/core/init/skills/inventory.js +97 -0
- package/dist/core/init/skills/manifest.js +151 -0
- package/dist/core/init/skills.js +5 -325
- package/dist/core/init.js +0 -63
- package/dist/core/install/installed-package-smoke.js +1 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
- package/dist/core/policy/latest-version-guidance.js +15 -2
- package/dist/core/preflight/parallel-preflight-engine.js +27 -51
- package/dist/core/provider/provider-badge.js +9 -4
- package/dist/core/provider/provider-context.js +57 -107
- package/dist/core/providers/openrouter/openrouter-account.js +3 -1
- package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
- package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
- package/dist/core/release/gate-manifest.js +0 -1
- package/dist/core/release/main-push-guard.js +13 -0
- package/dist/core/release/main-push-receipt.js +11 -0
- package/dist/core/release/physical-release-gates.js +664 -61
- package/dist/core/release/publish-preflight.js +3 -3
- package/dist/core/release/release-gate-batch-runner.js +19 -6
- package/dist/core/release/release-gate-dag.js +33 -6
- package/dist/core/release/release-gate-node.js +1 -3
- package/dist/core/release/release-gate-output-contract.js +55 -0
- package/dist/core/release/release-pack-contract.js +1 -1
- package/dist/core/release/release-pack-receipt.js +209 -8
- package/dist/core/release/release-real-contract.js +1 -1
- package/dist/core/release/stage-publish.js +106 -28
- package/dist/core/retention/temp-lease.js +204 -0
- package/dist/core/retention.js +18 -195
- package/dist/core/routes.js +1 -2
- package/dist/core/safety/intent-contract/intent-contract.js +3 -3
- package/dist/core/subagents/naruto-host-credentials.js +6 -1
- package/dist/core/subagents/official-subagent-config.js +27 -9
- package/dist/core/subagents/official-subagent-runner.js +14 -31
- package/dist/core/subagents/wave-lifecycle.js +36 -8
- package/dist/core/subagents/wave-parent-guidance.js +2 -1
- package/dist/core/telegram/doctor.js +2 -2
- package/dist/core/telegram/liveness.js +10 -4
- package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
- package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
- package/dist/core/update/update-migration-state/session-state-split.js +247 -0
- package/dist/core/update/update-migration-state/simple-stages.js +46 -0
- package/dist/core/update/update-migration-state.js +4 -481
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
- package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
- package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
- package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
- package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-runtime-schemas.js +7 -2
- package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
- package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
- package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
- package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
- package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
- package/dist/scripts/desktop-bridge-transport-client.js +116 -0
- package/dist/scripts/desktop-bridge-unification-check.js +276 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
- package/dist/scripts/gate-policy-audit-check.js +52 -2
- package/dist/scripts/provider-badge-context-check.js +55 -12
- package/dist/scripts/publish-preflight.js +1 -2
- package/dist/scripts/release-affected-selector-check.js +1 -2
- package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
- package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
- package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
- package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
- package/dist/scripts/release-gate-batch-runner-check.js +9 -0
- package/dist/scripts/release-gate-dag-runner-check.js +6 -0
- package/dist/scripts/release-gate-dag-runner.js +4 -2
- package/dist/scripts/release-metadata-check.js +16 -3
- package/dist/scripts/release-pack-receipt.js +29 -6
- package/dist/scripts/release-physical-gates-check.js +39 -0
- package/dist/scripts/release-real-check.js +7 -5
- package/package.json +6 -8
- package/release-gates.v2.json +156 -157
- package/runtime-required-scripts.json +11 -11
- package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
- package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
- package/schemas/release/release-gate-node.schema.json +2 -3
- package/dist/cli/codex-lb-setup-warning-output.js +0 -17
- package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
- package/dist/commands/codex-lb.js +0 -1232
- package/dist/core/architecture-hardening/migration/migration.js +0 -111
- package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
- package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
- package/dist/core/codex-app/child-policy/child-policy.js +0 -35
- package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
- package/dist/core/codex-app/glm-model-profile.js +0 -1
- package/dist/core/codex-app/glm-profile-installer.js +0 -191
- package/dist/core/codex-app/glm-profile-schema.js +0 -42
- package/dist/core/codex-app/multi-provider-router.js +0 -391
- package/dist/core/codex-app/openrouter-activate.js +0 -405
- package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
- package/dist/core/codex-app/provider-child-policy.js +0 -64
- package/dist/core/codex-app/provider-mode.js +0 -91
- package/dist/core/codex-app/provider-session-policy.js +0 -85
- package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
- package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
- package/dist/core/codex-lb/codex-lb-setup.js +0 -293
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
- package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
- package/dist/core/codex-lb/desktop-mode.js +0 -32
- package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
- package/dist/core/codex-lb/legacy-migration.js +0 -576
- package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
- package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
- package/dist/core/codex-lb/routing-truth.js +0 -327
- package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +0 -231
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import fsp from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { writeCodexConfigGuarded } from '../../codex/codex-config-guard.js';
|
|
5
|
-
import { sha256 } from '../../fsx.js';
|
|
6
|
-
export function inspectArchitectureMigration(input) {
|
|
7
|
-
const findings = [];
|
|
8
|
-
const providerSections = [...input.configText.matchAll(/^\s*\[model_providers\.([A-Za-z0-9_-]+)\]\s*$/gm)].map((match) => match[1]).filter((value) => Boolean(value));
|
|
9
|
-
for (const provider of providerSections)
|
|
10
|
-
findings.push({ kind: 'custom_provider', code: 'legacy_custom_provider_injection', removable_path: `model_providers.${provider}` });
|
|
11
|
-
if (providerSections.length > 1)
|
|
12
|
-
findings.push({ kind: 'mixed_catalog', code: 'legacy_mixed_provider_catalog', removable_path: null });
|
|
13
|
-
if (!input.sessionMetadataPresent)
|
|
14
|
-
findings.push({ kind: 'missing_session_metadata', code: 'legacy_session_metadata_missing', removable_path: null });
|
|
15
|
-
if (input.command && /(?:\bux-review\b|\bvisual-review\b|--skip-evidence|--force-fast)/i.test(input.command)) {
|
|
16
|
-
findings.push({ kind: 'obsolete_command', code: 'legacy_command_or_option_obsolete', removable_path: null });
|
|
17
|
-
}
|
|
18
|
-
const ambiguous = findings.some((finding) => finding.kind === 'mixed_catalog' || finding.kind === 'missing_session_metadata');
|
|
19
|
-
return {
|
|
20
|
-
schema: 'sks.architecture-migration-plan.v1',
|
|
21
|
-
status: !findings.length ? 'no_op' : ambiguous ? 'migration_required' : 'ready',
|
|
22
|
-
source_hash: sha256(input.configText), findings,
|
|
23
|
-
removable_paths: findings.flatMap((finding) => finding.removable_path ? [finding.removable_path] : []),
|
|
24
|
-
blockers: ambiguous ? findings.filter((finding) => finding.kind === 'mixed_catalog' || finding.kind === 'missing_session_metadata').map((finding) => finding.code) : []
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export async function applyArchitectureMigration(input) {
|
|
28
|
-
if (!input.explicitApply)
|
|
29
|
-
throw new Error('architecture_migration_explicit_apply_required');
|
|
30
|
-
if (input.plan.status !== 'ready')
|
|
31
|
-
throw new Error('architecture_migration_plan_not_ready');
|
|
32
|
-
const current = await fsp.readFile(input.configPath, 'utf8');
|
|
33
|
-
if (sha256(current) !== input.plan.source_hash)
|
|
34
|
-
throw new Error('architecture_migration_user_edit_conflict');
|
|
35
|
-
const confirmed = new Set(input.confirmedRemovablePaths);
|
|
36
|
-
if (input.plan.removable_paths.some((entry) => !confirmed.has(entry)))
|
|
37
|
-
throw new Error('architecture_migration_reference_proof_required');
|
|
38
|
-
const stat = await fsp.stat(input.configPath);
|
|
39
|
-
const migrated = migrateConfigText(current, input.targetMode, input.loopbackBaseUrl || null, input.plan.removable_paths);
|
|
40
|
-
const write = await writeCodexConfigGuarded({
|
|
41
|
-
root: path.dirname(input.configPath),
|
|
42
|
-
configPath: input.configPath,
|
|
43
|
-
before: current,
|
|
44
|
-
mutate: () => migrated,
|
|
45
|
-
cause: 'architecture-migration',
|
|
46
|
-
backupTag: 'architecture-backup',
|
|
47
|
-
ownershipVerified: true,
|
|
48
|
-
verifyUnchangedBeforeWrite: true,
|
|
49
|
-
expectedBeforeExists: true,
|
|
50
|
-
expectedBeforeMode: stat.mode & 0o777,
|
|
51
|
-
preserveTextFormatting: true
|
|
52
|
-
});
|
|
53
|
-
if (!write.ok || !write.changed || !write.backup_path)
|
|
54
|
-
throw new Error(`architecture_migration_${write.status}`);
|
|
55
|
-
return {
|
|
56
|
-
schema: 'sks.architecture-migration-receipt.v1', status: 'applied', source_hash: input.plan.source_hash,
|
|
57
|
-
output_hash: sha256(migrated), backup_hash: sha256(current), backup_path_hash: sha256(path.resolve(write.backup_path)), target_mode: input.targetMode
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
export async function rollbackArchitectureMigration(input) {
|
|
61
|
-
if (!input.explicitRollback)
|
|
62
|
-
throw new Error('architecture_migration_explicit_rollback_required');
|
|
63
|
-
const current = await fsp.readFile(input.configPath, 'utf8');
|
|
64
|
-
if (sha256(current) !== input.receipt.output_hash)
|
|
65
|
-
throw new Error('architecture_migration_rollback_conflict');
|
|
66
|
-
const backup = await fsp.readFile(input.backupPath, 'utf8');
|
|
67
|
-
if (sha256(backup) !== input.receipt.backup_hash || sha256(path.resolve(input.backupPath)) !== input.receipt.backup_path_hash) {
|
|
68
|
-
throw new Error('architecture_migration_backup_mismatch');
|
|
69
|
-
}
|
|
70
|
-
const stat = await fsp.stat(input.configPath);
|
|
71
|
-
const write = await writeCodexConfigGuarded({
|
|
72
|
-
root: path.dirname(input.configPath),
|
|
73
|
-
configPath: input.configPath,
|
|
74
|
-
before: current,
|
|
75
|
-
mutate: () => backup,
|
|
76
|
-
cause: 'architecture-migration-rollback',
|
|
77
|
-
backupTag: `architecture-rollback-${randomUUID()}`,
|
|
78
|
-
ownershipVerified: true,
|
|
79
|
-
verifyUnchangedBeforeWrite: true,
|
|
80
|
-
expectedBeforeExists: true,
|
|
81
|
-
expectedBeforeMode: stat.mode & 0o777,
|
|
82
|
-
preserveTextFormatting: true
|
|
83
|
-
});
|
|
84
|
-
if (!write.ok || !write.changed)
|
|
85
|
-
throw new Error(`architecture_migration_${write.status}`);
|
|
86
|
-
return { ...input.receipt, status: 'rolled_back', output_hash: sha256(backup) };
|
|
87
|
-
}
|
|
88
|
-
function migrateConfigText(source, mode, loopbackBaseUrl, removablePaths) {
|
|
89
|
-
if (mode !== 'chatgpt-oauth') {
|
|
90
|
-
const parsed = loopbackBaseUrl ? new URL(loopbackBaseUrl) : null;
|
|
91
|
-
if (!parsed || parsed.protocol !== 'http:' || !['127.0.0.1', '::1', 'localhost'].includes(parsed.hostname.replace(/^\[|\]$/g, ''))) {
|
|
92
|
-
throw new Error('architecture_migration_loopback_required');
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const removable = new Set(removablePaths);
|
|
96
|
-
const lines = source.split(/\r?\n/);
|
|
97
|
-
const kept = [];
|
|
98
|
-
let skip = false;
|
|
99
|
-
for (const line of lines) {
|
|
100
|
-
const section = line.match(/^\s*\[([^\]]+)\]\s*$/)?.[1] || null;
|
|
101
|
-
if (section)
|
|
102
|
-
skip = removable.has(section);
|
|
103
|
-
if (!skip)
|
|
104
|
-
kept.push(line);
|
|
105
|
-
}
|
|
106
|
-
let text = kept.join('\n').replace(/^\s*#\s*sks-managed-provider-mode:.*$/gm, '').replace(/^\s*model_provider\s*=.*$/gm, '').replace(/^\s*openai_base_url\s*=.*$/gm, '').trim();
|
|
107
|
-
const header = [`# sks-managed-provider-mode:${mode}`, 'model_provider = "openai"'];
|
|
108
|
-
if (mode !== 'chatgpt-oauth')
|
|
109
|
-
header.push(`openai_base_url = ${JSON.stringify(loopbackBaseUrl)}`);
|
|
110
|
-
return `${header.join('\n')}\n${text ? `${text}\n` : ''}`;
|
|
111
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export function decideAuxiliaryOAuthRoute(input) {
|
|
2
|
-
const base = {
|
|
3
|
-
schema: 'sks.auxiliary-oauth-route-decision.v1',
|
|
4
|
-
session_mode: input.mode,
|
|
5
|
-
feature: input.contract.feature,
|
|
6
|
-
request_path: input.contract.request_path,
|
|
7
|
-
session_mode_changed: false
|
|
8
|
-
};
|
|
9
|
-
if (input.contract.proxy_supported) {
|
|
10
|
-
return { ...base, route: input.mode, auxiliary_oauth_used: false, status: 'proxy_supported', blockers: [] };
|
|
11
|
-
}
|
|
12
|
-
if (!input.contract.protocol_verified) {
|
|
13
|
-
return { ...base, route: null, auxiliary_oauth_used: false, status: 'blocked', blockers: ['auxiliary_oauth_feature_protocol_unverified'] };
|
|
14
|
-
}
|
|
15
|
-
if (!input.userAllowed) {
|
|
16
|
-
return { ...base, route: null, auxiliary_oauth_used: false, status: 'permission_required', blockers: ['auxiliary_oauth_user_permission_required'] };
|
|
17
|
-
}
|
|
18
|
-
if (!input.oauthConnected) {
|
|
19
|
-
return { ...base, route: null, auxiliary_oauth_used: false, status: 'oauth_required', blockers: ['auxiliary_oauth_connection_required'] };
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
...base,
|
|
23
|
-
route: 'chatgpt-oauth',
|
|
24
|
-
auxiliary_oauth_used: true,
|
|
25
|
-
status: 'auxiliary_oauth',
|
|
26
|
-
blockers: [],
|
|
27
|
-
audit_event: {
|
|
28
|
-
schema: 'sks.auxiliary-oauth-event.v1',
|
|
29
|
-
event: 'feature_request_routed_via_auxiliary_oauth',
|
|
30
|
-
feature: input.contract.feature,
|
|
31
|
-
reason: `${input.mode}_proxy_does_not_support_feature`,
|
|
32
|
-
credential_path: 'chatgpt-oauth',
|
|
33
|
-
session_mode: input.mode
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import fsp from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { stableArchitectureHash } from '../../architecture-hardening/contracts/contracts.js';
|
|
4
|
-
import { writeJsonAtomic } from '../../fsx.js';
|
|
5
|
-
export class CatalogCompatibilityService {
|
|
6
|
-
statePath;
|
|
7
|
-
constructor(statePath) {
|
|
8
|
-
this.statePath = path.resolve(statePath);
|
|
9
|
-
}
|
|
10
|
-
async refresh(input) {
|
|
11
|
-
const previous = await this.read();
|
|
12
|
-
const checkedAt = (input.now || new Date()).toISOString();
|
|
13
|
-
try {
|
|
14
|
-
if (input.credential.status !== 'ready')
|
|
15
|
-
throw new Error(`catalog_credential_${input.credential.status}`);
|
|
16
|
-
const nativeModels = [...new Set(await input.port.readNativeCatalog())].filter(Boolean).sort();
|
|
17
|
-
const modeCandidates = nativeModels.filter((model) => (input.mode === 'openrouter') === model.includes('/'));
|
|
18
|
-
const candidateSet = new Set(modeCandidates);
|
|
19
|
-
const validated = [...new Set(await input.port.validateModels(input.mode, modeCandidates))];
|
|
20
|
-
if (validated.some((model) => !candidateSet.has(model)))
|
|
21
|
-
throw new Error('catalog_validation_returned_unknown_model');
|
|
22
|
-
const filtered = validated.sort();
|
|
23
|
-
const snapshot = {
|
|
24
|
-
schema: 'sks.catalog-snapshot.v1',
|
|
25
|
-
version: stableArchitectureHash({ mode: input.mode, models: filtered }),
|
|
26
|
-
models: filtered,
|
|
27
|
-
checked_at: checkedAt
|
|
28
|
-
};
|
|
29
|
-
const changed = previous.last_good?.version !== snapshot.version;
|
|
30
|
-
const state = {
|
|
31
|
-
schema: 'sks.catalog-compatibility-state.v1', last_good: snapshot, changed,
|
|
32
|
-
last_checked_at: checkedAt, failure_reason: null,
|
|
33
|
-
cache_invalidation_required: changed, restart_required: changed && (input.pinnedSessions?.length || 0) > 0,
|
|
34
|
-
trigger: input.trigger
|
|
35
|
-
};
|
|
36
|
-
await this.write(state);
|
|
37
|
-
return state;
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
const state = {
|
|
41
|
-
schema: 'sks.catalog-compatibility-state.v1', last_good: previous.last_good, changed: false,
|
|
42
|
-
last_checked_at: checkedAt, failure_reason: safeReason(error), cache_invalidation_required: false,
|
|
43
|
-
restart_required: false, trigger: input.trigger
|
|
44
|
-
};
|
|
45
|
-
await this.write(state);
|
|
46
|
-
return state;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async read() {
|
|
50
|
-
try {
|
|
51
|
-
const value = JSON.parse(await fsp.readFile(this.statePath, 'utf8'));
|
|
52
|
-
if (value.schema !== 'sks.catalog-compatibility-state.v1')
|
|
53
|
-
throw new Error('catalog_state_invalid');
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
if (error.code !== 'ENOENT' && error.message !== 'catalog_state_invalid')
|
|
58
|
-
throw error;
|
|
59
|
-
return {
|
|
60
|
-
schema: 'sks.catalog-compatibility-state.v1', last_good: null, changed: false,
|
|
61
|
-
last_checked_at: new Date(0).toISOString(), failure_reason: null,
|
|
62
|
-
cache_invalidation_required: false, restart_required: false, trigger: 'startup'
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
async write(state) {
|
|
67
|
-
await fsp.mkdir(path.dirname(this.statePath), { recursive: true, mode: 0o700 });
|
|
68
|
-
await writeJsonAtomic(this.statePath, state, { mode: 0o600 });
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
export function computeFeatureCompatibility(input) {
|
|
72
|
-
if (input.directProxySupported)
|
|
73
|
-
return feature(input.feature, 'direct-proxy', false, null);
|
|
74
|
-
if (!input.protocolVerified)
|
|
75
|
-
return feature(input.feature, 'unavailable', false, 'feature_protocol_unverified');
|
|
76
|
-
if (!input.oauthAllowed)
|
|
77
|
-
return feature(input.feature, 'unavailable', true, 'feature_oauth_permission_required');
|
|
78
|
-
if (!input.oauthConnected)
|
|
79
|
-
return feature(input.feature, 'unavailable', true, 'feature_oauth_connection_required');
|
|
80
|
-
return feature(input.feature, 'oauth-auxiliary', true, null);
|
|
81
|
-
}
|
|
82
|
-
export function scheduleCatalogBackgroundRefresh(refresh, intervalMs, schedule = setInterval, onFailure) {
|
|
83
|
-
if (intervalMs < 60_000)
|
|
84
|
-
throw new Error('catalog_background_interval_too_short');
|
|
85
|
-
let failure = null;
|
|
86
|
-
const timer = schedule(() => {
|
|
87
|
-
void refresh().catch((error) => {
|
|
88
|
-
failure = safeReason(error);
|
|
89
|
-
onFailure?.(failure);
|
|
90
|
-
});
|
|
91
|
-
}, intervalMs);
|
|
92
|
-
timer.unref?.();
|
|
93
|
-
return {
|
|
94
|
-
stop: () => clearInterval(timer),
|
|
95
|
-
lastFailure: () => failure
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
function feature(name, route, oauth, reason) {
|
|
99
|
-
return { schema: 'sks.feature-compatibility.v1', feature: name, route, oauth_required: oauth, reason_code: reason };
|
|
100
|
-
}
|
|
101
|
-
function safeReason(error) {
|
|
102
|
-
const value = error instanceof Error ? error.message : '';
|
|
103
|
-
return /^[a-z][a-z0-9_]{2,99}$/.test(value) ? value : 'catalog_refresh_failed';
|
|
104
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { stableArchitectureHash } from '../../architecture-hardening/contracts/contracts.js';
|
|
2
|
-
import { sessionPinHash } from '../session-policy/session-pinning.js';
|
|
3
|
-
export function createChildPolicySnapshot(policy, registeredOpenRouterModels = []) {
|
|
4
|
-
const owner = policy.mode === 'chatgpt-oauth' ? 'codex-native' : policy.mode === 'codex-lb' ? 'codex-lb' : 'sks-center';
|
|
5
|
-
const allowed = policy.mode === 'openrouter'
|
|
6
|
-
? registeredOpenRouterModels.filter((model) => policy.allowed_models.includes(model) && model.includes('/'))
|
|
7
|
-
: policy.mode === 'codex-lb' ? policy.allowed_models.filter((model) => !model.includes('/')) : [];
|
|
8
|
-
const base = { schema: 'sks.child-policy-snapshot.v1', mode: policy.mode, owner, allowed_models: [...new Set(allowed)].sort() };
|
|
9
|
-
return { ...base, policy_hash: stableArchitectureHash(base) };
|
|
10
|
-
}
|
|
11
|
-
export function decideChildSelection(input) {
|
|
12
|
-
const parentHash = sessionPinHash(input.session);
|
|
13
|
-
const blocked = (code) => ({
|
|
14
|
-
schema: 'sks.child-selection-decision.v1', ok: false, owner: input.policy.owner, model: null,
|
|
15
|
-
parent_snapshot_hash: parentHash, blockers: [code]
|
|
16
|
-
});
|
|
17
|
-
if (input.session.mode !== input.policy.mode)
|
|
18
|
-
return blocked('child_policy_mode_mismatch');
|
|
19
|
-
if (input.session.child_policy_hash !== input.policy.policy_hash)
|
|
20
|
-
return blocked('child_policy_snapshot_mismatch');
|
|
21
|
-
const requested = String(input.requestedModel || '').trim();
|
|
22
|
-
if (input.policy.mode === 'chatgpt-oauth') {
|
|
23
|
-
if (requested)
|
|
24
|
-
return blocked('child_policy_oauth_override_forbidden');
|
|
25
|
-
return { schema: 'sks.child-selection-decision.v1', ok: true, owner: 'codex-native', model: null, parent_snapshot_hash: parentHash, blockers: [] };
|
|
26
|
-
}
|
|
27
|
-
if (input.policy.mode === 'codex-lb' && !requested) {
|
|
28
|
-
return { schema: 'sks.child-selection-decision.v1', ok: true, owner: 'codex-lb', model: null, parent_snapshot_hash: parentHash, blockers: [] };
|
|
29
|
-
}
|
|
30
|
-
if (!input.policy.allowed_models.includes(requested))
|
|
31
|
-
return blocked(input.policy.mode === 'openrouter' ? 'child_policy_openrouter_model_unregistered' : 'child_policy_lb_model_outside_family');
|
|
32
|
-
if (!input.session.allowed_models.includes(requested))
|
|
33
|
-
return blocked('child_policy_parent_model_mismatch');
|
|
34
|
-
return { schema: 'sks.child-selection-decision.v1', ok: true, owner: input.policy.owner, model: requested, parent_snapshot_hash: parentHash, blockers: [] };
|
|
35
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import { execFileSync } from 'node:child_process';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { nowIso, writeTextAtomic } from '../fsx.js';
|
|
6
|
-
import { codexHomePath, readTopLevelTomlString } from './codex-model-catalog.js';
|
|
7
|
-
import { ensureTrailingNewline, removeTopLevelTomlKeyIfValue, safeWriteCodexConfigToml, upsertTopLevelTomlString } from '../codex-runtime/codex-desktop-config-policy.js';
|
|
8
|
-
import { invalidateCodexModelsCache } from './codex-models-cache.js';
|
|
9
|
-
export const DESKTOP_ROUTING_SNAPSHOT_SCHEMA = 'sks.codex-desktop-routing-snapshot.v1';
|
|
10
|
-
export const DESKTOP_ROUTING_SNAPSHOT_FILENAME = 'sks-previous-desktop-routing.json';
|
|
11
|
-
function snapshotPath(input = {}) {
|
|
12
|
-
return path.join(codexHomePath(input), DESKTOP_ROUTING_SNAPSHOT_FILENAME);
|
|
13
|
-
}
|
|
14
|
-
export function desktopRoutingSnapshotPath(input = {}) {
|
|
15
|
-
return snapshotPath(input);
|
|
16
|
-
}
|
|
17
|
-
function threadCatalogDbPath(input = {}) {
|
|
18
|
-
return path.join(codexHomePath(input), 'sqlite', 'codex-dev.db');
|
|
19
|
-
}
|
|
20
|
-
function sqlQuote(value) {
|
|
21
|
-
return `'${String(value).replace(/'/g, "''")}'`;
|
|
22
|
-
}
|
|
23
|
-
function runSqlite3(dbPath, sql) {
|
|
24
|
-
return execFileSync('sqlite3', ['-batch', '-noheader', dbPath, sql], {
|
|
25
|
-
encoding: 'utf8',
|
|
26
|
-
timeout: 10_000,
|
|
27
|
-
maxBuffer: 2 * 1024 * 1024
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
export function captureDesktopRoutingSnapshot(configText, input) {
|
|
31
|
-
return {
|
|
32
|
-
schema: DESKTOP_ROUTING_SNAPSHOT_SCHEMA,
|
|
33
|
-
captured_at: nowIso(),
|
|
34
|
-
reason: input.reason,
|
|
35
|
-
model_provider: readTopLevelTomlString(configText, 'model_provider'),
|
|
36
|
-
model: readTopLevelTomlString(configText, 'model'),
|
|
37
|
-
model_catalog_json: readTopLevelTomlString(configText, 'model_catalog_json'),
|
|
38
|
-
openai_base_url: readTopLevelTomlString(configText, 'openai_base_url'),
|
|
39
|
-
...(input.threadSidebar ? { thread_sidebar: input.threadSidebar } : {})
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
export async function writeDesktopRoutingSnapshot(snapshot, input = {}) {
|
|
43
|
-
const filePath = snapshotPath(input);
|
|
44
|
-
try {
|
|
45
|
-
await writeTextAtomic(filePath, `${JSON.stringify(snapshot, null, 2)}\n`, { mode: 0o600 });
|
|
46
|
-
return { ok: true, path: filePath };
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
return { ok: false, path: filePath, error: err?.message || String(err) };
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export async function readDesktopRoutingSnapshot(input = {}) {
|
|
53
|
-
const filePath = snapshotPath(input);
|
|
54
|
-
try {
|
|
55
|
-
const raw = await fs.readFile(filePath, 'utf8');
|
|
56
|
-
const parsed = JSON.parse(raw);
|
|
57
|
-
if (!parsed || parsed.schema !== DESKTOP_ROUTING_SNAPSHOT_SCHEMA)
|
|
58
|
-
return null;
|
|
59
|
-
return parsed;
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
export function assessThreadVisibilityImpact(input) {
|
|
66
|
-
const catalogDb = threadCatalogDbPath(input);
|
|
67
|
-
const warnings = [];
|
|
68
|
-
const counts = {};
|
|
69
|
-
let checked = false;
|
|
70
|
-
try {
|
|
71
|
-
const raw = runSqlite3(catalogDb, 'SELECT model_provider, COUNT(*) FROM local_thread_catalog GROUP BY model_provider;');
|
|
72
|
-
for (const line of raw.split(/\n/).map((entry) => entry.trim()).filter(Boolean)) {
|
|
73
|
-
const sep = line.includes('|') ? '|' : '\t';
|
|
74
|
-
const [provider, count] = line.split(sep);
|
|
75
|
-
counts[String(provider || 'unknown')] = Number(count || 0);
|
|
76
|
-
}
|
|
77
|
-
checked = true;
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
warnings.push(`thread_catalog_unreadable:${err?.code || err?.message || 'unknown'}`);
|
|
81
|
-
}
|
|
82
|
-
const target = String(input.targetProvider || '').trim();
|
|
83
|
-
const hidden = Object.entries(counts)
|
|
84
|
-
.filter(([provider]) => provider !== target)
|
|
85
|
-
.reduce((sum, [, count]) => sum + count, 0);
|
|
86
|
-
if (checked && hidden > 0) {
|
|
87
|
-
warnings.push('desktop_hides_other_provider_threads_until_restore');
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
schema: 'sks.codex-desktop-thread-visibility.v1',
|
|
91
|
-
checked,
|
|
92
|
-
catalog_db: checked ? catalogDb : null,
|
|
93
|
-
current_provider: input.currentProvider,
|
|
94
|
-
target_provider: target,
|
|
95
|
-
counts_by_provider: counts,
|
|
96
|
-
hidden_if_switched: hidden,
|
|
97
|
-
warnings
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
export function remapThreadCatalogProvider(input) {
|
|
101
|
-
const catalogDb = threadCatalogDbPath(input);
|
|
102
|
-
const fromProvider = String(input.fromProvider || '').trim();
|
|
103
|
-
const toProvider = String(input.toProvider || '').trim();
|
|
104
|
-
if (!fromProvider || !toProvider || fromProvider === toProvider) {
|
|
105
|
-
return { ok: true, remapped: 0, thread_ids: [], catalog_db: catalogDb };
|
|
106
|
-
}
|
|
107
|
-
try {
|
|
108
|
-
const idRaw = runSqlite3(catalogDb, `SELECT thread_id FROM local_thread_catalog WHERE model_provider = ${sqlQuote(fromProvider)};`);
|
|
109
|
-
const ids = idRaw.split(/\n/).map((entry) => entry.trim()).filter(Boolean);
|
|
110
|
-
if (ids.length === 0) {
|
|
111
|
-
return { ok: true, remapped: 0, thread_ids: [], catalog_db: catalogDb };
|
|
112
|
-
}
|
|
113
|
-
runSqlite3(catalogDb, `UPDATE local_thread_catalog SET model_provider = ${sqlQuote(toProvider)} WHERE model_provider = ${sqlQuote(fromProvider)};`);
|
|
114
|
-
return {
|
|
115
|
-
ok: true,
|
|
116
|
-
remapped: ids.length,
|
|
117
|
-
thread_ids: ids,
|
|
118
|
-
catalog_db: catalogDb
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
catch (err) {
|
|
122
|
-
return {
|
|
123
|
-
ok: false,
|
|
124
|
-
remapped: 0,
|
|
125
|
-
thread_ids: [],
|
|
126
|
-
catalog_db: catalogDb,
|
|
127
|
-
error: err?.message || String(err)
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
export async function restoreDesktopRoutingSnapshot(input) {
|
|
132
|
-
const home = input.home || input.env?.HOME || os.homedir();
|
|
133
|
-
const env = { ...(input.env || process.env), HOME: home };
|
|
134
|
-
const snapshot = await readDesktopRoutingSnapshot({ home, env });
|
|
135
|
-
if (!snapshot) {
|
|
136
|
-
return {
|
|
137
|
-
schema: 'sks.codex-app-restore-desktop-routing.v1',
|
|
138
|
-
ok: false,
|
|
139
|
-
status: 'snapshot_missing',
|
|
140
|
-
blockers: ['desktop_routing_snapshot_missing'],
|
|
141
|
-
warnings: [],
|
|
142
|
-
hint: 'No previous Desktop routing snapshot. Use `sks codex-lb use-desktop-full` to enable managed routing or `sks codex-lb disable` to remove only SKS-managed routing.'
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
const configPath = input.configPath || path.join(codexHomePath({ home, env }), 'config.toml');
|
|
146
|
-
const before = await fs.readFile(configPath, 'utf8').catch(() => '');
|
|
147
|
-
let next = before;
|
|
148
|
-
if (snapshot.model_provider)
|
|
149
|
-
next = upsertTopLevelTomlString(next, 'model_provider', snapshot.model_provider);
|
|
150
|
-
else
|
|
151
|
-
next = removeTopLevelTomlKeyIfValue(next, 'model_provider', readTopLevelTomlString(next, 'model_provider') || '');
|
|
152
|
-
if (snapshot.model)
|
|
153
|
-
next = upsertTopLevelTomlString(next, 'model', snapshot.model);
|
|
154
|
-
else
|
|
155
|
-
next = removeTopLevelTomlKeyIfValue(next, 'model', readTopLevelTomlString(next, 'model') || '');
|
|
156
|
-
if (snapshot.model_catalog_json) {
|
|
157
|
-
next = upsertTopLevelTomlString(next, 'model_catalog_json', snapshot.model_catalog_json);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
next = removeTopLevelTomlKeyIfValue(next, 'model_catalog_json', readTopLevelTomlString(next, 'model_catalog_json') || '');
|
|
161
|
-
}
|
|
162
|
-
next = ensureTrailingNewline(next);
|
|
163
|
-
const write = await safeWriteCodexConfigToml(configPath, before, next, 'restore-desktop-routing', { verifyUnchangedBeforeWrite: true, expectedBeforeExists: Boolean(before) });
|
|
164
|
-
if (!write.ok) {
|
|
165
|
-
return {
|
|
166
|
-
schema: 'sks.codex-app-restore-desktop-routing.v1',
|
|
167
|
-
ok: false,
|
|
168
|
-
status: 'config_write_blocked',
|
|
169
|
-
snapshot,
|
|
170
|
-
write,
|
|
171
|
-
blockers: [String(write.status || 'restore_config_write_blocked')],
|
|
172
|
-
warnings: []
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
let sidebarRestore = null;
|
|
176
|
-
if (snapshot.thread_sidebar?.remapped) {
|
|
177
|
-
const remapped = remapThreadCatalogProvider({
|
|
178
|
-
home,
|
|
179
|
-
env,
|
|
180
|
-
fromProvider: snapshot.thread_sidebar.to_provider,
|
|
181
|
-
toProvider: snapshot.thread_sidebar.from_provider
|
|
182
|
-
});
|
|
183
|
-
sidebarRestore = { ...remapped, expected_ids: snapshot.thread_sidebar.thread_ids.length };
|
|
184
|
-
}
|
|
185
|
-
const cache = await invalidateCodexModelsCache({
|
|
186
|
-
home,
|
|
187
|
-
env,
|
|
188
|
-
catalogPath: snapshot.model_catalog_json,
|
|
189
|
-
seedMode: 'merge'
|
|
190
|
-
});
|
|
191
|
-
const restart = await (input.restartImpl
|
|
192
|
-
? input.restartImpl({ enabled: Boolean(input.restartApp) })
|
|
193
|
-
: Promise.resolve({ ok: true, blockers: [] }));
|
|
194
|
-
const sidebarRestoreOk = sidebarRestore === null || sidebarRestore.ok === true;
|
|
195
|
-
if (sidebarRestoreOk) {
|
|
196
|
-
try {
|
|
197
|
-
await fs.unlink(snapshotPath({ home, env }));
|
|
198
|
-
}
|
|
199
|
-
catch {
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
const sidebarBlocker = sidebarRestoreOk
|
|
203
|
-
? []
|
|
204
|
-
: [`thread_sidebar_restore_failed:${String(sidebarRestore?.error || 'unknown')}`];
|
|
205
|
-
const sidebarRemapped = Number(sidebarRestore?.remapped ?? 0);
|
|
206
|
-
const sidebarExpected = Number(sidebarRestore?.expected_ids ?? 0);
|
|
207
|
-
const sidebarPartial = sidebarRestoreOk && sidebarRestore !== null && sidebarRemapped < sidebarExpected;
|
|
208
|
-
const sidebarWarning = sidebarPartial
|
|
209
|
-
? [`thread_sidebar_restore_partial:${sidebarRemapped}_of_${sidebarExpected}`]
|
|
210
|
-
: [];
|
|
211
|
-
return {
|
|
212
|
-
schema: 'sks.codex-app-restore-desktop-routing.v1',
|
|
213
|
-
ok: Boolean(write.ok && restart.ok && sidebarRestoreOk),
|
|
214
|
-
status: !sidebarRestoreOk
|
|
215
|
-
? (restart.ok ? 'restored_sidebar_blocked' : 'restored_sidebar_and_restart_blocked')
|
|
216
|
-
: restart.ok ? 'restored' : 'restored_restart_blocked',
|
|
217
|
-
snapshot,
|
|
218
|
-
write,
|
|
219
|
-
thread_sidebar_restore: sidebarRestore,
|
|
220
|
-
thread_sidebar_restore_ok: sidebarRestoreOk,
|
|
221
|
-
snapshot_retained: !sidebarRestoreOk,
|
|
222
|
-
models_cache: cache,
|
|
223
|
-
restart_app: restart,
|
|
224
|
-
blockers: [
|
|
225
|
-
...sidebarBlocker,
|
|
226
|
-
...(restart.ok ? [] : (restart.blockers || ['restore_restart_blocked']))
|
|
227
|
-
],
|
|
228
|
-
warnings: [...sidebarWarning, ...(cache.warnings || [])],
|
|
229
|
-
hint: sidebarRestoreOk
|
|
230
|
-
? 'Codex Desktop may need a full quit/reopen for the sidebar and picker to refresh.'
|
|
231
|
-
: 'Routing was restored but prior-provider chats stay hidden. Fully quit Codex Desktop, then re-run sks codex-app restore-desktop-routing — the snapshot was kept for that retry.'
|
|
232
|
-
};
|
|
233
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { GLM_CODEX_APP_PROFILE_ID, GLM_CODEX_APP_PROFILE_LABEL, GLM_CODEX_CONFIG_PROFILE_ID, GLM_CODEX_CONFIG_PROVIDER_ID, GLM_CODEX_CONFIG_REASONING_PROFILES, GLM_CODEX_SELECTABLE_REASONING_EFFORTS, OPENROUTER_DEFAULT_MODEL, OPENROUTER_PROVIDER_ID, buildGlmCodexAppModelProfile, normalizeOpenRouterModelId } from './openrouter-provider.js';
|