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.
Files changed (261) hide show
  1. package/README.md +96 -58
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/bin/fast-inline.js +5 -51
  5. package/dist/cli/command-manifest-lite.js +2 -1
  6. package/dist/cli/command-registry.js +2 -1
  7. package/dist/cli/global-mode-router.js +1 -1
  8. package/dist/cli/install-helpers-codex-lb-config.js +112 -914
  9. package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
  10. package/dist/cli/install-helpers-install-support.js +4 -20
  11. package/dist/cli/install-helpers.js +36 -2716
  12. package/dist/cli/router.js +9 -9
  13. package/dist/commands/bridge-command-output.js +111 -0
  14. package/dist/commands/bridge.js +320 -0
  15. package/dist/commands/codex-app.js +39 -123
  16. package/dist/commands/doctor-helpers.js +380 -0
  17. package/dist/commands/doctor-profile.js +3 -0
  18. package/dist/commands/doctor.js +114 -873
  19. package/dist/commands/mad-sks.js +0 -4
  20. package/dist/config/skills-manifest.json +1 -1
  21. package/dist/core/agents/agent-effort-policy.js +11 -21
  22. package/dist/core/agents/agent-recursion-guard.js +26 -0
  23. package/dist/core/agents/agent-runner-codex-exec.js +7 -9
  24. package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
  25. package/dist/core/architecture-hardening/state/state-service.js +49 -13
  26. package/dist/core/auto-review.js +15 -9
  27. package/dist/core/codex/codex-config-guard.js +8 -0
  28. package/dist/core/codex-adapter.js +8 -10
  29. package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
  30. package/dist/core/codex-app/codex-app-launcher.js +10 -12
  31. package/dist/core/codex-app/codex-app-restart.js +10 -12
  32. package/dist/core/codex-app/menubar/constants.js +2 -5
  33. package/dist/core/codex-app/menubar/global-install.js +3 -2
  34. package/dist/core/codex-app/menubar/installer/result.js +23 -0
  35. package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
  36. package/dist/core/codex-app/menubar/installer.js +5 -96
  37. package/dist/core/codex-app/menubar/migration.js +1 -42
  38. package/dist/core/codex-app/openrouter-provider.js +0 -78
  39. package/dist/core/codex-app.js +97 -360
  40. package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
  41. package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
  42. package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
  43. package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
  44. package/dist/core/codex-control/codex-task-runner.js +16 -60
  45. package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
  46. package/dist/core/codex-exec-output-schema.js +11 -13
  47. package/dist/core/codex-lb/bridge-contracts.js +2 -0
  48. package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
  49. package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
  50. package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
  51. package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
  52. package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
  53. package/dist/core/codex-lb/capability-runner.js +505 -201
  54. package/dist/core/codex-lb/codex-lb-env.js +179 -12
  55. package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
  56. package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
  57. package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
  58. package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
  59. package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
  60. package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
  61. package/dist/core/codex-lb/combined-catalog.js +12 -0
  62. package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
  63. package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
  64. package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
  65. package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
  66. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
  67. package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
  68. package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
  69. package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
  70. package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
  71. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
  72. package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
  73. package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
  74. package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
  75. package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
  76. package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
  77. package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
  78. package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
  79. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
  80. package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
  81. package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
  82. package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
  83. package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
  84. package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
  85. package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
  86. package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
  87. package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
  88. package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
  89. package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
  90. package/dist/core/codex-lb/desktop-controller.js +2 -1730
  91. package/dist/core/codex-lb/desktop-service.js +462 -627
  92. package/dist/core/codex-lb/migration-receipt.js +560 -118
  93. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
  94. package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
  95. package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
  96. package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
  97. package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
  98. package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
  99. package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
  100. package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
  101. package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
  102. package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
  103. package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
  104. package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
  105. package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
  106. package/dist/core/codex-lb/provider-credentials/types.js +1 -0
  107. package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
  108. package/dist/core/codex-lb/provider-credentials.js +5 -0
  109. package/dist/core/codex-lb/provider-registry.js +323 -0
  110. package/dist/core/codex-lb/provider-route-policy.js +118 -0
  111. package/dist/core/codex-lb/request-route-resolver.js +172 -0
  112. package/dist/core/codex-lb/route-index.js +148 -0
  113. package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
  114. package/dist/core/commands/basic-cli.js +1 -1
  115. package/dist/core/commands/check-command.js +3 -10
  116. package/dist/core/commands/gate-result-contract.js +10 -14
  117. package/dist/core/commands/intent-normalization/normalizer.js +1 -1
  118. package/dist/core/commands/mad-sks-command.js +2 -6
  119. package/dist/core/commands/release-command.js +11 -1
  120. package/dist/core/commands/telegram-command.js +46 -6
  121. package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
  122. package/dist/core/doctor/skill-legacy-surface.js +5 -5
  123. package/dist/core/evidence/v2/evidence-key.js +30 -3
  124. package/dist/core/feature-fixtures.js +8 -1
  125. package/dist/core/feature-registry.js +3 -2
  126. package/dist/core/hooks-runtime/stop-finalization.js +11 -1
  127. package/dist/core/hooks-runtime/subagent-context.js +15 -1
  128. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
  129. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  130. package/dist/core/hooks-runtime.js +73 -87
  131. package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
  132. package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
  133. package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
  134. package/dist/core/imagegen/imagegen-capability.js +43 -151
  135. package/dist/core/init/skills/filesystem.js +89 -0
  136. package/dist/core/init/skills/inventory.js +97 -0
  137. package/dist/core/init/skills/manifest.js +151 -0
  138. package/dist/core/init/skills.js +5 -325
  139. package/dist/core/init.js +0 -63
  140. package/dist/core/install/installed-package-smoke.js +1 -1
  141. package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
  142. package/dist/core/policy/latest-version-guidance.js +15 -2
  143. package/dist/core/preflight/parallel-preflight-engine.js +27 -51
  144. package/dist/core/provider/provider-badge.js +9 -4
  145. package/dist/core/provider/provider-context.js +57 -107
  146. package/dist/core/providers/openrouter/openrouter-account.js +3 -1
  147. package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
  148. package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
  149. package/dist/core/release/gate-manifest.js +0 -1
  150. package/dist/core/release/main-push-guard.js +13 -0
  151. package/dist/core/release/main-push-receipt.js +11 -0
  152. package/dist/core/release/physical-release-gates.js +664 -61
  153. package/dist/core/release/publish-preflight.js +3 -3
  154. package/dist/core/release/release-gate-batch-runner.js +19 -6
  155. package/dist/core/release/release-gate-dag.js +33 -6
  156. package/dist/core/release/release-gate-node.js +1 -3
  157. package/dist/core/release/release-gate-output-contract.js +55 -0
  158. package/dist/core/release/release-pack-contract.js +1 -1
  159. package/dist/core/release/release-pack-receipt.js +209 -8
  160. package/dist/core/release/release-real-contract.js +1 -1
  161. package/dist/core/release/stage-publish.js +106 -28
  162. package/dist/core/retention/temp-lease.js +204 -0
  163. package/dist/core/retention.js +18 -195
  164. package/dist/core/routes.js +1 -2
  165. package/dist/core/safety/intent-contract/intent-contract.js +3 -3
  166. package/dist/core/subagents/naruto-host-credentials.js +6 -1
  167. package/dist/core/subagents/official-subagent-config.js +27 -9
  168. package/dist/core/subagents/official-subagent-runner.js +14 -31
  169. package/dist/core/subagents/wave-lifecycle.js +36 -8
  170. package/dist/core/subagents/wave-parent-guidance.js +2 -1
  171. package/dist/core/telegram/doctor.js +2 -2
  172. package/dist/core/telegram/liveness.js +10 -4
  173. package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
  174. package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
  175. package/dist/core/update/update-migration-state/session-state-split.js +247 -0
  176. package/dist/core/update/update-migration-state/simple-stages.js +46 -0
  177. package/dist/core/update/update-migration-state.js +4 -481
  178. package/dist/core/version.js +1 -1
  179. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
  180. package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
  181. package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
  182. package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
  183. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
  184. package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
  185. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
  186. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
  187. package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
  188. package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
  189. package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
  190. package/dist/scripts/canonical-test-runner.js +7 -1
  191. package/dist/scripts/check-runtime-schemas.js +7 -2
  192. package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
  193. package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
  194. package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
  195. package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
  196. package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
  197. package/dist/scripts/desktop-bridge-transport-client.js +116 -0
  198. package/dist/scripts/desktop-bridge-unification-check.js +276 -0
  199. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
  200. package/dist/scripts/gate-policy-audit-check.js +52 -2
  201. package/dist/scripts/provider-badge-context-check.js +55 -12
  202. package/dist/scripts/publish-preflight.js +1 -2
  203. package/dist/scripts/release-affected-selector-check.js +1 -2
  204. package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
  205. package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
  206. package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
  207. package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
  208. package/dist/scripts/release-gate-batch-runner-check.js +9 -0
  209. package/dist/scripts/release-gate-dag-runner-check.js +6 -0
  210. package/dist/scripts/release-gate-dag-runner.js +4 -2
  211. package/dist/scripts/release-metadata-check.js +16 -3
  212. package/dist/scripts/release-pack-receipt.js +29 -6
  213. package/dist/scripts/release-physical-gates-check.js +39 -0
  214. package/dist/scripts/release-real-check.js +7 -5
  215. package/package.json +6 -8
  216. package/release-gates.v2.json +156 -157
  217. package/runtime-required-scripts.json +11 -11
  218. package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
  219. package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
  220. package/schemas/release/release-gate-node.schema.json +2 -3
  221. package/dist/cli/codex-lb-setup-warning-output.js +0 -17
  222. package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
  223. package/dist/commands/codex-lb.js +0 -1232
  224. package/dist/core/architecture-hardening/migration/migration.js +0 -111
  225. package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
  226. package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
  227. package/dist/core/codex-app/child-policy/child-policy.js +0 -35
  228. package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
  229. package/dist/core/codex-app/glm-model-profile.js +0 -1
  230. package/dist/core/codex-app/glm-profile-installer.js +0 -191
  231. package/dist/core/codex-app/glm-profile-schema.js +0 -42
  232. package/dist/core/codex-app/multi-provider-router.js +0 -391
  233. package/dist/core/codex-app/openrouter-activate.js +0 -405
  234. package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
  235. package/dist/core/codex-app/provider-child-policy.js +0 -64
  236. package/dist/core/codex-app/provider-mode.js +0 -91
  237. package/dist/core/codex-app/provider-session-policy.js +0 -85
  238. package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
  239. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
  240. package/dist/core/codex-lb/codex-lb-setup.js +0 -293
  241. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
  242. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
  243. package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
  244. package/dist/core/codex-lb/desktop-mode.js +0 -32
  245. package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
  246. package/dist/core/codex-lb/legacy-migration.js +0 -576
  247. package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
  248. package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
  249. package/dist/core/codex-lb/routing-truth.js +0 -327
  250. package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
  251. package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
  252. package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
  253. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
  254. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
  255. package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
  256. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
  257. package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
  258. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
  259. package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
  260. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
  261. 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';