sneakoscope 7.1.0 → 7.3.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 (534) hide show
  1. package/README.md +9 -1
  2. package/config/architecture-budgets.v1.json +1 -8
  3. package/crates/sks-core/Cargo.lock +225 -1
  4. package/crates/sks-core/Cargo.toml +8 -1
  5. package/crates/sks-core/src/main.rs +7 -1
  6. package/crates/sks-core/src/search/files.rs +114 -0
  7. package/crates/sks-core/src/search/mod.rs +274 -0
  8. package/crates/sks-core/src/search/text.rs +175 -0
  9. package/dist/bin/sks-dispatch.js +4 -3
  10. package/dist/cli/command-manifest-lite.js +177 -6
  11. package/dist/cli/command-registry.js +42 -8
  12. package/dist/cli/help.js +30 -0
  13. package/dist/cli/install-helpers-codex-lb-config.js +9 -6
  14. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +1 -1
  15. package/dist/cli/install-helpers-install-support.js +1 -1
  16. package/dist/cli/install-helpers.js +19 -9
  17. package/dist/cli/router.js +16 -3
  18. package/dist/commands/codex-app.js +40 -5
  19. package/dist/commands/doctor-profile.js +78 -0
  20. package/dist/commands/doctor.js +29 -69
  21. package/dist/commands/search.js +4 -0
  22. package/dist/config/skills-manifest.json +53 -60
  23. package/dist/core/agent-bridge/agent-manifest.js +22 -26
  24. package/dist/core/agent-bridge/host-capability-policy.js +109 -8
  25. package/dist/core/agent-bridge/host-capability-runtime.js +178 -50
  26. package/dist/core/agent-guidance/directive-registry.js +123 -0
  27. package/dist/core/agents/agent-effort-policy.js +45 -6
  28. package/dist/core/agents/agent-worker-pipeline.js +1 -3
  29. package/dist/core/agents/native-worker-backend-router.js +43 -19
  30. package/dist/core/auto-review.js +1 -3
  31. package/dist/core/code-structure.js +282 -19
  32. package/dist/core/codex/codex-config-guard.js +14 -4
  33. package/dist/core/codex/codex-config-toml.js +1 -3
  34. package/dist/core/codex-app/codex-agent-role-sync.js +1 -3
  35. package/dist/core/codex-app/codex-app-fast-ui-repair.js +14 -1
  36. package/dist/core/codex-app/codex-app-types.js +2 -3
  37. package/dist/core/codex-app/codex-desktop-routing-ownership.js +91 -0
  38. package/dist/core/codex-app/codex-hook-approval-probe.js +1 -3
  39. package/dist/core/codex-app/codex-hook-lifecycle.js +1 -3
  40. package/dist/core/codex-app/codex-init-deep.js +22 -10
  41. package/dist/core/codex-app/codex-model-catalog.js +384 -0
  42. package/dist/core/codex-app/codex-models-cache.js +160 -0
  43. package/dist/core/codex-app/desktop-routing-snapshot.js +233 -0
  44. package/dist/core/codex-app/glm-profile-installer.js +1 -3
  45. package/dist/core/codex-app/mcp-manager.js +1 -3
  46. package/dist/core/codex-app/menubar/constants.js +3 -0
  47. package/dist/core/codex-app/menubar/installer.js +11 -1
  48. package/dist/core/codex-app/multi-provider-router-support.js +202 -0
  49. package/dist/core/codex-app/multi-provider-router.js +379 -0
  50. package/dist/core/codex-app/openrouter-activate.js +189 -26
  51. package/dist/core/codex-app/openrouter-base-instructions.js +1 -0
  52. package/dist/core/codex-app/openrouter-model-catalog.js +217 -0
  53. package/dist/core/codex-app/role-model-catalog-priority.js +61 -0
  54. package/dist/core/codex-app.js +30 -6
  55. package/dist/core/codex-compat/codex-hook-semantic-validator.js +1 -3
  56. package/dist/core/codex-control/codex-app-server-v2-client.js +39 -2
  57. package/dist/core/codex-lb/codex-lb-env.js +1 -3
  58. package/dist/core/codex-lb/codex-lb-tool-catalog.js +6 -1
  59. package/dist/core/codex-native/codex-native-feature-broker.js +2 -6
  60. package/dist/core/codex-native/codex-native-interop-policy.js +1 -3
  61. package/dist/core/codex-native/codex-native-reference-cache.js +1 -3
  62. package/dist/core/codex-native/codex-native-reference-source.js +1 -3
  63. package/dist/core/codex-native/codex-native-repair-transaction.js +1 -3
  64. package/dist/core/codex-native/core-skill-manifest.js +3 -2
  65. package/dist/core/codex-native/native-capability-repair-matrix.js +1 -3
  66. package/dist/core/codex-plugins/codex-plugin-repair.js +1 -3
  67. package/dist/core/codex-runtime/codex-desktop-config-policy.js +4 -4
  68. package/dist/core/commands/agent-bridge-command.js +24 -3
  69. package/dist/core/commands/image-ux-review-command.js +5 -11
  70. package/dist/core/commands/menubar-command.js +1 -1
  71. package/dist/core/commands/naruto-command.js +40 -13
  72. package/dist/core/commands/pipeline-command.js +5 -2
  73. package/dist/core/commands/release-command.js +63 -1
  74. package/dist/core/commands/remote-command.js +18 -0
  75. package/dist/core/commands/search-command.js +151 -0
  76. package/dist/core/commands/telegram-command.js +251 -108
  77. package/dist/core/commands/uninstall-command.js +1 -1
  78. package/dist/core/config/secret-preservation.js +1 -3
  79. package/dist/core/context7-client.js +2 -1
  80. package/dist/core/db-review.js +704 -0
  81. package/dist/core/db-safety.js +17 -23
  82. package/dist/core/doctor/browser-use-repair.js +1 -3
  83. package/dist/core/doctor/codex-startup-config-repair.js +1 -3
  84. package/dist/core/doctor/computer-use-repair.js +1 -3
  85. package/dist/core/doctor/context7-mcp-repair.js +1 -3
  86. package/dist/core/doctor/current-project-guidance.js +1 -3
  87. package/dist/core/doctor/doctor-codex-startup-repair.js +1 -3
  88. package/dist/core/doctor/doctor-dirty-planner.js +2 -2
  89. package/dist/core/doctor/doctor-native-capability-repair.js +1 -3
  90. package/dist/core/doctor/doctor-transaction.js +1 -3
  91. package/dist/core/doctor/imagegen-repair.js +1 -3
  92. package/dist/core/doctor/legacy-global-hook-cleanup.js +1 -3
  93. package/dist/core/doctor/mcp-transport-collision-repair.js +1 -3
  94. package/dist/core/doctor/retired-managed-residue-private.js +1 -3
  95. package/dist/core/doctor/supabase-mcp-repair.js +1 -3
  96. package/dist/core/engineering-sanity-review.js +186 -0
  97. package/dist/core/errors/message.js +3 -0
  98. package/dist/core/evidence/evidence-schema.js +1 -3
  99. package/dist/core/feature-fixtures.js +1 -0
  100. package/dist/core/feature-registry.js +1 -3
  101. package/dist/core/fsx.js +13 -0
  102. package/dist/core/git-hygiene/shared-memory-publish.js +1 -3
  103. package/dist/core/git-hygiene/validators.js +1 -3
  104. package/dist/core/harness-guard.js +21 -3
  105. package/dist/core/hooks-runtime/hook-context.js +2 -2
  106. package/dist/core/image-ux-review/imagegen-adapter.js +52 -56
  107. package/dist/core/image-ux-review/real-callout-extractor.js +6 -1
  108. package/dist/core/image-ux-review.js +3 -5
  109. package/dist/core/imagegen/codex-lb-imagegen-target.js +70 -0
  110. package/dist/core/imagegen/imagegen-capability.js +11 -11
  111. package/dist/core/imagegen/imagegen-evidence.js +32 -0
  112. package/dist/core/init/skills.js +9 -11
  113. package/dist/core/init.js +4 -6
  114. package/dist/core/json/records.js +9 -0
  115. package/dist/core/json-schema-validator.js +1 -3
  116. package/dist/core/lean-engineering-policy.js +54 -0
  117. package/dist/core/loops/loop-continuation-enforcer.js +1 -3
  118. package/dist/core/mad-sks/sql-plane/mcp-executor.js +2 -1
  119. package/dist/core/mad-sks/sql-plane/policy.js +2 -1
  120. package/dist/core/managed-assets/managed-assets-manifest.js +4 -3
  121. package/dist/core/mcp-config/codex-cli-adapter.js +1 -3
  122. package/dist/core/mcp-config/config-reader.js +2 -3
  123. package/dist/core/mcp-config/guarded-patch.js +1 -1
  124. package/dist/core/mcp-config/health-check.js +2 -1
  125. package/dist/core/mcp-config/mutation.js +1 -1
  126. package/dist/core/mcp-config/restore.js +1 -1
  127. package/dist/core/mcp-config/secret-policy.js +1 -3
  128. package/dist/core/migration/migration-transaction-journal.js +3 -3
  129. package/dist/core/naruto/naruto-concurrency-governor.js +2 -2
  130. package/dist/core/perf/import-graph-budget.js +91 -1
  131. package/dist/core/pipeline/pipeline-plan-writer.js +1 -1
  132. package/dist/core/pipeline-internals/runtime-core.js +121 -23
  133. package/dist/core/pipeline-internals/runtime-gates.js +193 -4
  134. package/dist/core/pipeline.js +1 -1
  135. package/dist/core/ppt-review/slide-imagegen-review.js +7 -7
  136. package/dist/core/ppt.js +3 -3
  137. package/dist/core/product-design-app-server.js +2 -1
  138. package/dist/core/proof/fake-real-proof-policy.js +1 -3
  139. package/dist/core/proof/root-cause-policy.js +1 -3
  140. package/dist/core/proof/validation.js +1 -3
  141. package/dist/core/provider/model-router.js +4 -0
  142. package/dist/core/provider/provider-context.js +1 -3
  143. package/dist/core/providers/openrouter/openrouter-account.js +1 -3
  144. package/dist/core/quality/helper-dedup.js +0 -0
  145. package/dist/core/recallpulse.js +1 -1
  146. package/dist/core/release/file-ownership.js +26 -17
  147. package/dist/core/release/macos-menubar-proof.js +59 -1
  148. package/dist/core/release/main-push-guard.js +288 -24
  149. package/dist/core/release/main-push-receipt.js +10 -45
  150. package/dist/core/release/package-size-budget.js +1 -1
  151. package/dist/core/release/release-gate-contract.js +2 -0
  152. package/dist/core/release/release-pack-receipt.js +1 -1
  153. package/dist/core/release/release-proof-io.js +33 -0
  154. package/dist/core/release/release-upgrade-baseline.js +9 -0
  155. package/dist/core/release/runtime-script-pack-closure.js +153 -4
  156. package/dist/core/release/stage-publish.js +194 -0
  157. package/dist/core/remote/index.js +2 -0
  158. package/dist/core/remote/local-worker-client.js +35 -0
  159. package/dist/core/remote/machine-registry.js +18 -13
  160. package/dist/core/remote/owner-proof.js +1 -3
  161. package/dist/core/remote/protocol.js +1 -3
  162. package/dist/core/remote/readiness.js +1 -3
  163. package/dist/core/remote/session-binding.js +153 -0
  164. package/dist/core/remote/session-index.js +1 -3
  165. package/dist/core/remote/types.js +1 -0
  166. package/dist/core/remote/worker.js +228 -14
  167. package/dist/core/responses-stream.js +151 -0
  168. package/dist/core/routes/dollar-manifest-lite.js +1 -1
  169. package/dist/core/routes.js +8 -8
  170. package/dist/core/rust-accelerator.js +12 -2
  171. package/dist/core/safety/ssot-guard.js +1 -3
  172. package/dist/core/search/benchmark.js +358 -0
  173. package/dist/core/search/cache.js +65 -0
  174. package/dist/core/search/context.js +144 -0
  175. package/dist/core/search/doctor.js +74 -0
  176. package/dist/core/search/files.js +192 -0
  177. package/dist/core/search/index.js +5 -0
  178. package/dist/core/search/ipc.js +64 -0
  179. package/dist/core/search/provider.js +142 -0
  180. package/dist/core/search/rust-bridge.js +24 -0
  181. package/dist/core/search/structure.js +230 -0
  182. package/dist/core/search/symbol.js +272 -0
  183. package/dist/core/search/text.js +146 -0
  184. package/dist/core/search/types.js +22 -0
  185. package/dist/core/search/typescript-ls.js +215 -0
  186. package/dist/core/search-visibility/discovery.js +1 -3
  187. package/dist/core/skill-forge.js +1 -1
  188. package/dist/core/stop-gate/gate-evaluator.js +3 -3
  189. package/dist/core/stop-gate/stop-gate-check.js +1 -3
  190. package/dist/core/structured-output-adapter.js +62 -2
  191. package/dist/core/subagents/agent-catalog.js +56 -43
  192. package/dist/core/subagents/model-policy.js +17 -7
  193. package/dist/core/subagents/naruto-proof-projection.js +2 -6
  194. package/dist/core/subagents/official-subagent-config.js +1 -3
  195. package/dist/core/subagents/official-subagent-preparation.js +73 -10
  196. package/dist/core/subagents/official-subagent-prompt.js +85 -18
  197. package/dist/core/subagents/official-subagent-runner.js +10 -5
  198. package/dist/core/subagents/role-model-preferences.js +202 -44
  199. package/dist/core/subagents/subagent-evidence.js +1 -3
  200. package/dist/core/subagents/thread-budget.js +1 -1
  201. package/dist/core/subagents/triwiki-attention.js +1 -5
  202. package/dist/core/telegram/config.js +29 -12
  203. package/dist/core/telegram/hub.js +8 -2
  204. package/dist/core/telegram/index.js +2 -0
  205. package/dist/core/telegram/messages.js +8 -2
  206. package/dist/core/telegram/runtime-projection.js +8 -5
  207. package/dist/core/telegram/runtime.js +19 -9
  208. package/dist/core/telegram/service.js +181 -0
  209. package/dist/core/telegram/setup.js +220 -0
  210. package/dist/core/text/regex.js +3 -0
  211. package/dist/core/text/strings.js +6 -0
  212. package/dist/core/triwiki-wrongness/image-wrongness.js +1 -3
  213. package/dist/core/triwiki-wrongness/wrongness-ledger.js +1 -3
  214. package/dist/core/triwiki-wrongness/wrongness-proof-linker.js +1 -3
  215. package/dist/core/triwiki-wrongness/wrongness-retrieval.js +1 -3
  216. package/dist/core/triwiki-wrongness/wrongness-schema.js +1 -3
  217. package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +1 -3
  218. package/dist/core/trust-kernel/completion-contract.js +1 -3
  219. package/dist/core/trust-kernel/route-contract.js +1 -3
  220. package/dist/core/update/update-migration-state.js +1 -3
  221. package/dist/core/update-check.js +20 -6
  222. package/dist/core/verification/diff-quality.js +3 -4
  223. package/dist/core/verification/impact-scan.js +36 -89
  224. package/dist/core/verification/mistake-rule-compiler.js +17 -4
  225. package/dist/core/version-manager.js +3 -20
  226. package/dist/core/version.js +1 -1
  227. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +23 -3
  228. package/dist/native/sks-menubar/Sources/ControlKit.swift +102 -0
  229. package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +23 -11
  230. package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +7 -3
  231. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +17 -1
  232. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +22 -15
  233. package/dist/native/sks-menubar/Sources/ProcessClient.swift +15 -5
  234. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +324 -0
  235. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +154 -214
  236. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +252 -0
  237. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +77 -71
  238. package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +167 -51
  239. package/dist/native/sks-menubar/Sources/SettingsViewController.swift +14 -5
  240. package/dist/native/sks-menubar/Sources/SidebarItem.swift +15 -1
  241. package/dist/native/sks-menubar/Sources/StatusItemController.swift +2 -2
  242. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +16 -12
  243. package/dist/scripts/agent-guidance-dedup-check.js +23 -0
  244. package/dist/scripts/agent-message-bus-reader-check.js +1 -1
  245. package/dist/scripts/all-feature-deep-completion-check.js +1 -1
  246. package/dist/scripts/appshots-thread-attachment-discovery-check.js +1 -1
  247. package/dist/scripts/architecture-guard-check.js +1 -2
  248. package/dist/scripts/certificate-sla-check.js +1 -1
  249. package/dist/scripts/cli-output-consistency-check.js +1 -1
  250. package/dist/scripts/codex-0-134-runner-truth-check.js +1 -1
  251. package/dist/scripts/codex-0138-capability-artifact-check.js +1 -1
  252. package/dist/scripts/codex-0138-capability-check.js +1 -1
  253. package/dist/scripts/codex-0138-doctor-check.js +1 -1
  254. package/dist/scripts/codex-0138-feature-probes-check.js +1 -1
  255. package/dist/scripts/codex-0144-app-server-v2-check.js +1 -1
  256. package/dist/scripts/codex-0144-binary-identity-check.js +1 -1
  257. package/dist/scripts/codex-0144-capability-check.js +1 -1
  258. package/dist/scripts/codex-0144-core-real-probes-check.js +1 -1
  259. package/dist/scripts/codex-0144-manifest-check.js +1 -1
  260. package/dist/scripts/codex-0144-policy-check.js +1 -1
  261. package/dist/scripts/codex-0144-thread-store-check.js +1 -1
  262. package/dist/scripts/codex-agent-role-rich-content-check.js +2 -2
  263. package/dist/scripts/codex-agent-role-sync-check.js +2 -2
  264. package/dist/scripts/codex-agent-type-routing-check.js +2 -2
  265. package/dist/scripts/codex-app-execution-profile-check.js +2 -2
  266. package/dist/scripts/codex-app-handoff-check.js +1 -1
  267. package/dist/scripts/codex-app-handoff-launch-check.js +1 -1
  268. package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +1 -1
  269. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +1 -3
  270. package/dist/scripts/codex-native-feature-broker-blackbox.js +2 -2
  271. package/dist/scripts/codex-native-feature-broker-check.js +2 -2
  272. package/dist/scripts/{sks-3-1-6-directive-check-lib.js → codex-native-gate-lib.js} +5 -5
  273. package/dist/scripts/codex-native-harness-compat-check.js +2 -2
  274. package/dist/scripts/codex-native-hook-lifecycle-proof-check.js +2 -2
  275. package/dist/scripts/codex-plugin-app-template-policy-check.js +1 -1
  276. package/dist/scripts/codex-sdk-backend-router-check.js +1 -1
  277. package/dist/scripts/codex-sdk-capability-check.js +1 -1
  278. package/dist/scripts/context7-evidence-dedupe-check.js +1 -1
  279. package/dist/scripts/core-skill-card-schema-check.js +1 -1
  280. package/dist/scripts/core-skill-deployment-snapshot-check.js +1 -1
  281. package/dist/scripts/core-skill-heldout-validation-check.js +1 -1
  282. package/dist/scripts/core-skill-no-inference-optimizer-check.js +1 -1
  283. package/dist/scripts/core-skill-patch-check.js +1 -1
  284. package/dist/scripts/core-skill-route-runtime-integration-check.js +1 -1
  285. package/dist/scripts/current-command-surface-check.js +1 -1
  286. package/dist/scripts/current-surface-update-e2e-check.js +4 -1
  287. package/dist/scripts/current-upgrade-matrix-check.js +1 -1
  288. package/dist/scripts/dfix-fixture-check.js +1 -1
  289. package/dist/scripts/dfix-patch-handoff-check.js +1 -1
  290. package/dist/scripts/dfix-verification-check.js +1 -1
  291. package/dist/scripts/dfix-verification-recommendation-check.js +1 -1
  292. package/dist/scripts/docs-truthfulness-check.js +16 -3
  293. package/dist/scripts/doctor-codex-app-harness-check.js +2 -2
  294. package/dist/scripts/evidence-flagship-coverage-check.js +1 -1
  295. package/dist/scripts/{sks-1-18-gate-lib.js → gate-lib.js} +1 -1
  296. package/dist/scripts/gate-policy-audit-check.js +4 -1
  297. package/dist/scripts/git-worktree-checkpoint-check.js +1 -1
  298. package/dist/scripts/git-worktree-cross-rebase-check.js +1 -1
  299. package/dist/scripts/git-worktree-diff-envelope-check.js +1 -1
  300. package/dist/scripts/git-worktree-dirty-lock-check.js +1 -1
  301. package/dist/scripts/git-worktree-dirty-main-detection-check.js +1 -1
  302. package/dist/scripts/git-worktree-integration-primary-check.js +1 -1
  303. package/dist/scripts/git-worktree-manifest-append-check.js +1 -1
  304. package/dist/scripts/git-worktree-untracked-diff-check.js +1 -1
  305. package/dist/scripts/harness-benchmark-check.js +1 -1
  306. package/dist/scripts/helper-dedup-check.js +62 -0
  307. package/dist/scripts/hook-latency-budget-check.js +1 -1
  308. package/dist/scripts/image-artifact-path-contract-check.js +1 -1
  309. package/dist/scripts/imagegen-real-smoke-check.js +2 -5
  310. package/dist/scripts/installed-package-smoke-check.js +1 -1
  311. package/dist/scripts/legacy-gate-inventory-check.js +1 -1
  312. package/dist/scripts/legacy-gate-purge-check.js +1 -1
  313. package/dist/scripts/legacy-strong-inventory-check.js +1 -1
  314. package/dist/scripts/lib/codex-sdk-gate-lib.js +1 -1
  315. package/dist/scripts/mad-sks-launch-sql-plane-boundary-check.js +1 -1
  316. package/dist/scripts/mad-sks-sql-plane-capability-check.js +1 -1
  317. package/dist/scripts/mad-sks-sql-plane-lifecycle-hook-decision-check.js +1 -1
  318. package/dist/scripts/mad-sks-sql-plane-result-lifecycle-check.js +1 -1
  319. package/dist/scripts/managed-config-merge-check.js +1 -1
  320. package/dist/scripts/mcp-plugin-inventory-check.js +1 -1
  321. package/dist/scripts/model-call-concurrency-check.js +1 -1
  322. package/dist/scripts/mutation-callsite-coverage-check.js +1 -1
  323. package/dist/scripts/naruto-ssot-gate-aliases-check.js +1 -1
  324. package/dist/scripts/naruto-ssot-pipeline-default-check.js +1 -1
  325. package/dist/scripts/naruto-ssot-route-normalization-check.js +1 -1
  326. package/dist/scripts/naruto-ssot-routing-check.js +1 -1
  327. package/dist/scripts/naruto-worktree-coding-blackbox.js +1 -1
  328. package/dist/scripts/native-capability-repair-matrix-check.js +1 -1
  329. package/dist/scripts/native-image-generation-repair-check.js +1 -1
  330. package/dist/scripts/official-subagent-workflow-check.js +3 -3
  331. package/dist/scripts/package-published-contract-check.js +37 -4
  332. package/dist/scripts/packlist-performance-check.js +17 -1
  333. package/dist/scripts/pipeline-codex-native-doctor-mad-routing-real-blackbox.js +1 -3
  334. package/dist/scripts/ppt-real-export-adapter-check.js +1 -1
  335. package/dist/scripts/ppt-real-imagegen-wiring-check.js +1 -1
  336. package/dist/scripts/ppt-reexport-rereview-check.js +1 -1
  337. package/dist/scripts/prepublish-fast-check.js +1 -1
  338. package/dist/scripts/probe-memoization-check.js +2 -2
  339. package/dist/scripts/prompt-placeholder-guard-check.js +1 -1
  340. package/dist/scripts/qa-loop-app-handoff-capability-check.js +1 -1
  341. package/dist/scripts/qa-loop-app-handoff-check.js +1 -1
  342. package/dist/scripts/qa-loop-app-handoff-cli-check.js +1 -1
  343. package/dist/scripts/qa-loop-app-handoff-confirmation-check.js +1 -1
  344. package/dist/scripts/qa-loop-app-handoff-gate-lifecycle-check.js +1 -1
  345. package/dist/scripts/qa-loop-app-handoff-launch-check.js +1 -1
  346. package/dist/scripts/qa-loop-app-handoff-status-lifecycle-check.js +1 -1
  347. package/dist/scripts/qa-loop-budget-policy-check.js +1 -1
  348. package/dist/scripts/qa-loop-effort-escalation-check.js +1 -1
  349. package/dist/scripts/qa-loop-execution-profile-routing-check.js +2 -2
  350. package/dist/scripts/qa-loop-image-path-exposure-check.js +1 -1
  351. package/dist/scripts/qa-loop-image-path-prompt-injection-check.js +1 -1
  352. package/dist/scripts/{sks-1-12-real-execution-check-lib.js → real-execution-check-lib.js} +1 -1
  353. package/dist/scripts/release-affected-selector-check.js +1 -1
  354. package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
  355. package/dist/scripts/release-cache-glob-hashing-check.js +1 -1
  356. package/dist/scripts/release-cache-input-classifier-check.js +1 -1
  357. package/dist/scripts/release-cache-neutralization-report-check.js +1 -1
  358. package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -1
  359. package/dist/scripts/release-dynamic-presets-check.js +2 -2
  360. package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
  361. package/dist/scripts/release-gate-batch-runner-check.js +1 -1
  362. package/dist/scripts/release-gate-budget-check.js +1 -1
  363. package/dist/scripts/release-gate-dag-runner-check.js +1 -1
  364. package/dist/scripts/release-latency-slo-check.js +1 -1
  365. package/dist/scripts/release-metadata-check.js +256 -2
  366. package/dist/scripts/release-parallel-speed-budget-check.js +1 -1
  367. package/dist/scripts/release-proof-truth-check.js +1 -1
  368. package/dist/scripts/release-provenance-check.js +4 -2
  369. package/dist/scripts/release-runtime-truth-matrix-check.js +1 -1
  370. package/dist/scripts/research-blueprint-densifier-check.js +1 -1
  371. package/dist/scripts/research-claim-builder-check.js +1 -1
  372. package/dist/scripts/research-complete-package-fixture-check.js +1 -1
  373. package/dist/scripts/research-execution-profile-routing-check.js +2 -2
  374. package/dist/scripts/research-final-reviewer-blackbox.js +1 -1
  375. package/dist/scripts/{sks-3-1-4-directive-check-lib.js → runtime-domain-gate-lib.js} +2 -2
  376. package/dist/scripts/runtime-proof-summary-check.js +1 -1
  377. package/dist/scripts/runtime-script-pack-closure-check.js +7 -1
  378. package/dist/scripts/scheduler-batch-dispatch-check.js +1 -1
  379. package/dist/scripts/scheduler-parallel-proof-consistency-check.js +1 -1
  380. package/dist/scripts/scheduler-utilization-integral-check.js +1 -1
  381. package/dist/scripts/search-visibility-gate-lib.js +1 -1
  382. package/dist/scripts/secret-preservation-check.js +1 -1
  383. package/dist/scripts/seo-geo-geo-disambiguation-check.js +1 -1
  384. package/dist/scripts/seo-geo-skill-rich-content-check.js +1 -1
  385. package/dist/scripts/side-effect-runtime-report-check.js +1 -1
  386. package/dist/scripts/{sks-3-1-8-check-lib.js → skill-fixture-check-lib.js} +1 -1
  387. package/dist/scripts/skill-name-canonicalizer-check.js +1 -1
  388. package/dist/scripts/skills-manifest-continuity-check.js +1 -1
  389. package/dist/scripts/sks-uninstall-regression-check.js +1 -1
  390. package/dist/scripts/sksd-daemon-check.js +1 -1
  391. package/dist/scripts/super-search-provider-interface-check.js +1 -1
  392. package/dist/scripts/triwiki-cache-key-check.js +1 -1
  393. package/dist/scripts/triwiki-proof-bank-blackbox.js +2 -2
  394. package/dist/scripts/triwiki-proof-bank-check.js +1 -1
  395. package/dist/scripts/triwiki-proof-card-check.js +1 -1
  396. package/dist/scripts/type-surface-codex-app-check.js +2 -2
  397. package/dist/scripts/{sks-3-1-5-directive-check-lib.js → typed-routing-gate-lib.js} +2 -2
  398. package/dist/scripts/ultra-router-auto-router-check.js +1 -1
  399. package/dist/scripts/ux-review-extract-wires-real-extractor-check.js +1 -1
  400. package/dist/scripts/ux-review-patch-diff-recheck-check.js +1 -1
  401. package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -2
  402. package/package.json +5 -7
  403. package/release-gates.v2.json +66 -11
  404. package/runtime-required-scripts.json +138 -14
  405. package/config/bench-baseline.json +0 -7
  406. package/dist/core/codex-app/sks-menubar.js +0 -1
  407. package/dist/core/release/release-closure-contract.js +0 -30
  408. package/dist/core/release/release-closure-helpers.js +0 -293
  409. package/dist/core/release/release-closure-validation.js +0 -284
  410. package/dist/core/release/release-closure.js +0 -163
  411. package/dist/scripts/build-dist.js +0 -124
  412. package/dist/scripts/build-once-runner-check.js +0 -6
  413. package/dist/scripts/canonical-test-runner.js +0 -234
  414. package/dist/scripts/changelog-check.js +0 -45
  415. package/dist/scripts/check-architecture.js +0 -295
  416. package/dist/scripts/check-cli-entrypoint.js +0 -41
  417. package/dist/scripts/check-command-module-budget.js +0 -77
  418. package/dist/scripts/check-feature-quality.js +0 -51
  419. package/dist/scripts/check-legacy-free.js +0 -64
  420. package/dist/scripts/check-pipeline-budget.js +0 -49
  421. package/dist/scripts/check-pipeline-runtime.js +0 -16
  422. package/dist/scripts/check-publish-tag.js +0 -56
  423. package/dist/scripts/check-route-modularity.js +0 -72
  424. package/dist/scripts/codex-0140-capability-check.js +0 -14
  425. package/dist/scripts/codex-0140-feature-probes-check.js +0 -23
  426. package/dist/scripts/codex-permission-profiles-check.js +0 -34
  427. package/dist/scripts/codex-project-config-policy-splitter-check.js +0 -49
  428. package/dist/scripts/competitor-scorecard-check.js +0 -24
  429. package/dist/scripts/core-skill-no-drift-check.js +0 -23
  430. package/dist/scripts/db-route-materialization-check.js +0 -32
  431. package/dist/scripts/doctor-context7-mcp-repair-blackbox.js +0 -15
  432. package/dist/scripts/doctor-fastpath-check.js +0 -25
  433. package/dist/scripts/doctor-fix-production-blackbox.js +0 -35
  434. package/dist/scripts/doctor-idempotence-check.js +0 -6
  435. package/dist/scripts/doctor-ops-semantics-check.js +0 -83
  436. package/dist/scripts/doctor-startup-config-repair-blackbox.js +0 -18
  437. package/dist/scripts/doctor-supabase-mcp-repair-blackbox.js +0 -13
  438. package/dist/scripts/ensure-bin-executable.js +0 -16
  439. package/dist/scripts/fsx-hotpath-check.js +0 -9
  440. package/dist/scripts/high-risk-contracts-check.js +0 -183
  441. package/dist/scripts/hook-latency-quantum-check.js +0 -120
  442. package/dist/scripts/import-graph-budget-check.js +0 -9
  443. package/dist/scripts/mcp-tool-naming-parity-check.js +0 -14
  444. package/dist/scripts/naruto-codex-e2e-check.js +0 -105
  445. package/dist/scripts/naruto-write-e2e-check.js +0 -31
  446. package/dist/scripts/native-capability-postcheck-check.js +0 -16
  447. package/dist/scripts/ops-diagnostics-bundle-check.js +0 -11
  448. package/dist/scripts/parallel-production-smoke-check.js +0 -20
  449. package/dist/scripts/perf-budget-check.js +0 -12
  450. package/dist/scripts/project-skill-dedupe-blackbox.js +0 -62
  451. package/dist/scripts/release-dag-full-coverage-check.js +0 -98
  452. package/dist/scripts/release-dist-freshness-check.js +0 -6
  453. package/dist/scripts/release-file-ownership-check.js +0 -35
  454. package/dist/scripts/release-gate-script-parity-check.js +0 -148
  455. package/dist/scripts/release-macos-menubar-proof.js +0 -167
  456. package/dist/scripts/release-main-push-guard.js +0 -37
  457. package/dist/scripts/release-main-push-receipt.js +0 -43
  458. package/dist/scripts/release-metadata-1-19-check.js +0 -257
  459. package/dist/scripts/release-version-truth-check.js +0 -138
  460. package/dist/scripts/retention-apply-smoke-check.js +0 -19
  461. package/dist/scripts/retention-budget-check.js +0 -6
  462. package/dist/scripts/retention-dry-run-check.js +0 -8
  463. package/dist/scripts/rollback-recovery-smoke-check.js +0 -70
  464. package/dist/scripts/route-intent-regression-check.js +0 -42
  465. package/dist/scripts/runtime-current-terminal-check.js +0 -108
  466. package/dist/scripts/runtime-dist-parity-check.js +0 -76
  467. package/dist/scripts/runtime-no-src-mjs-check.js +0 -30
  468. package/dist/scripts/runtime-ts-rust-boundary-check.js +0 -58
  469. package/dist/scripts/runtime-ts-source-of-truth-check.js +0 -53
  470. package/dist/scripts/secret-preservation-guard-check.js +0 -36
  471. package/dist/scripts/seo-marketing-truthfulness-check.js +0 -98
  472. package/dist/scripts/seo-metadata-sync-check.js +0 -60
  473. package/dist/scripts/sizecheck.js +0 -148
  474. package/dist/scripts/sks-menubar-install-check.js +0 -333
  475. package/dist/scripts/supabase-secret-preservation-blackbox.js +0 -28
  476. package/dist/scripts/super-search-live-smoke-check.js +0 -115
  477. package/dist/scripts/super-search-local-http-smoke-check.js +0 -16
  478. package/dist/scripts/super-search-offline-contract-check.js +0 -43
  479. package/dist/scripts/update-fastpath-check.js +0 -28
  480. package/dist/scripts/update-preserves-supabase-keys-blackbox.js +0 -26
  481. package/dist/scripts/upgrade-migration-matrix-check.js +0 -351
  482. package/dist/scripts/write-build-manifest.js +0 -70
  483. package/dist/scripts/zellij-capability-check.js +0 -13
  484. package/dist/scripts/zellij-developer-controls-check.js +0 -16
  485. package/dist/scripts/zellij-doctor-readiness-check.js +0 -49
  486. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +0 -19
  487. package/dist/scripts/zellij-fake-adapter-check.js +0 -31
  488. package/dist/scripts/zellij-first-slot-down-stack-check.js +0 -20
  489. package/dist/scripts/zellij-first-slot-down-stack-real-check.js +0 -348
  490. package/dist/scripts/zellij-homebrew-policy-check.js +0 -3
  491. package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -21
  492. package/dist/scripts/zellij-lane-renderer-check.js +0 -78
  493. package/dist/scripts/zellij-launch-command-truth-check.js +0 -62
  494. package/dist/scripts/zellij-layout-valid-check.js +0 -120
  495. package/dist/scripts/zellij-pane-creation-lock-metrics-check.js +0 -10
  496. package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -78
  497. package/dist/scripts/zellij-pane-lock-does-not-block-worker-check.js +0 -12
  498. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -134
  499. package/dist/scripts/zellij-qa-app-handoff-status-check.js +0 -7
  500. package/dist/scripts/zellij-right-column-geometry-proof.js +0 -158
  501. package/dist/scripts/zellij-right-column-headless-overflow-check.js +0 -20
  502. package/dist/scripts/zellij-right-column-manager-check.js +0 -24
  503. package/dist/scripts/zellij-self-heal-check.js +0 -3
  504. package/dist/scripts/zellij-self-heal-dry-run-check.js +0 -3
  505. package/dist/scripts/zellij-self-heal-status-contract-check.js +0 -3
  506. package/dist/scripts/zellij-self-heal-typed-blackbox.js +0 -3
  507. package/dist/scripts/zellij-slot-column-anchor-check.js +0 -65
  508. package/dist/scripts/zellij-slot-column-anchor-telemetry-check.js +0 -8
  509. package/dist/scripts/zellij-slot-only-ui-check.js +0 -29
  510. package/dist/scripts/zellij-slot-pane-renderer-check.js +0 -149
  511. package/dist/scripts/zellij-slot-pane-stale-detection-check.js +0 -65
  512. package/dist/scripts/zellij-slot-pane-telemetry-renderer-check.js +0 -11
  513. package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +0 -58
  514. package/dist/scripts/zellij-slot-telemetry-check.js +0 -38
  515. package/dist/scripts/zellij-slot-telemetry-incremental-check.js +0 -46
  516. package/dist/scripts/zellij-slot-telemetry-live-flush-check.js +0 -55
  517. package/dist/scripts/zellij-slot-telemetry-performance-check.js +0 -32
  518. package/dist/scripts/zellij-slot-telemetry-real-blackbox.js +0 -19
  519. package/dist/scripts/zellij-slot-telemetry-renderer-check.js +0 -11
  520. package/dist/scripts/zellij-slot-telemetry-runtime-check.js +0 -23
  521. package/dist/scripts/zellij-spawn-on-demand-layout-check.js +0 -45
  522. package/dist/scripts/zellij-stacked-capability-routing-check.js +0 -9
  523. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -78
  524. package/dist/scripts/zellij-stacked-version-matrix-check.js +0 -29
  525. package/dist/scripts/zellij-stacked-version-parser-check.js +0 -19
  526. package/dist/scripts/zellij-ui-design-check.js +0 -92
  527. package/dist/scripts/zellij-update-missing-self-heal-check.js +0 -3
  528. package/dist/scripts/zellij-update-prompt-matrix-check.js +0 -16
  529. package/dist/scripts/zellij-update-prompt-mode-check.js +0 -18
  530. package/dist/scripts/zellij-update-prompt-safety-check.js +0 -8
  531. package/dist/scripts/zellij-worker-pane-manager-check.js +0 -108
  532. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +0 -47
  533. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -199
  534. /package/dist/scripts/{sks-1-11-gate-lib.js → sks-cli-gate-lib.js} +0 -0
@@ -1,7 +1,32 @@
1
1
  import Cocoa
2
2
 
3
3
  extension ProvidersViewController {
4
+ func makeActiveProviderCard() -> NSBox {
5
+ NativeView.card(
6
+ title: "Active Provider",
7
+ subtitle: "The provider Codex Desktop is using right now. Activation buttons below switch it explicitly.",
8
+ views: [activeProviderBadge]
9
+ )
10
+ }
11
+
12
+ /// One-line truth for "what is Codex using right now", fed by the three
13
+ /// independent status probes as their responses arrive.
14
+ func renderActiveProviderSummary() {
15
+ if openRouterSelectedNow {
16
+ let model = openRouterActiveModel.isEmpty || openRouterActiveModel == "unset" ? "model unset" : openRouterActiveModel
17
+ ControlKit.setBadge(activeProviderBadge, text: "OpenRouter · \(model)", tone: .ok)
18
+ } else if routerSelectedNow {
19
+ let model = routerActiveModel.isEmpty ? "model unset" : routerActiveModel
20
+ ControlKit.setBadge(activeProviderBadge, text: "Multi-Provider Router · \(model)", tone: .ok)
21
+ } else if codexLbSelectedNow {
22
+ ControlKit.setBadge(activeProviderBadge, text: "codex-lb (GPT-5.6 via load balancer)", tone: .ok)
23
+ } else {
24
+ ControlKit.setBadge(activeProviderBadge, text: "ChatGPT OAuth · built-in OpenAI models", tone: .neutral)
25
+ }
26
+ }
27
+
4
28
  func makeOpenRouterCard() -> NSBox {
29
+ openRouterModelField.delegate = self
5
30
  openRouterModelPopup.addItem(withTitle: "Choose from catalog…")
6
31
  openRouterModelPopup.target = self
7
32
  openRouterModelPopup.action = #selector(selectOpenRouterModel(_:))
@@ -12,10 +37,18 @@ extension ProvidersViewController {
12
37
  let refreshModels = NativeView.button("Refresh Models", target: self, action: #selector(refreshOpenRouterModelsAction(_:)))
13
38
  openRouterRefreshButton = refreshModels
14
39
  let saveKey = NativeView.button("Save OpenRouter key…", target: self, action: #selector(saveOpenRouterKey))
15
- let test = NativeView.button("Test Connection", target: self, action: #selector(testOpenRouterConnection))
16
- let activate = NativeView.button("Activate Selected Model", target: self, action: #selector(useOpenRouter))
40
+ let test = NativeView.button("Test Model", target: self, action: #selector(testOpenRouterConnection))
41
+ test.setAccessibilityLabel("Test the selected OpenRouter model")
42
+ let activate = ControlKit.primaryButton("Activate Selected Model", target: self, action: #selector(useOpenRouter))
17
43
  activate.setAccessibilityLabel("Activate selected OpenRouter model and restart Codex App")
18
- actionButtons += [refreshModels, saveKey, test, activate]
44
+ let restorePrevious = NativeView.button("Restore previous provider", target: self, action: #selector(restorePreviousDesktopRouting))
45
+ restorePrevious.setAccessibilityLabel("Restore the previous Codex provider so hidden chats and picker state return")
46
+ // Stays disabled until openrouter-status reports a restorable
47
+ // cross-provider snapshot, so the button never promises a restore the
48
+ // CLI would reject with snapshot_missing.
49
+ restorePrevious.isEnabled = false
50
+ openRouterRestoreButton = restorePrevious
51
+ actionButtons += [refreshModels, saveKey, test, activate, restorePrevious]
19
52
 
20
53
  let catalogLabel = NSTextField(labelWithString: "Catalog")
21
54
  catalogLabel.setContentHuggingPriority(.required, for: .horizontal)
@@ -23,7 +56,7 @@ extension ProvidersViewController {
23
56
  manualLabel.setContentHuggingPriority(.required, for: .horizontal)
24
57
  return NativeView.card(
25
58
  title: "OpenRouter",
26
- subtitle: "Saving the key prepares OpenRouter but does not switch providers. Choose a catalog model or enter any valid provider/model id, test it, then activate it.",
59
+ subtitle: "Saving the key prepares OpenRouter but does not switch providers. Activate switches Desktop routing; SKS remaps the local thread sidebar so prior provider chats stay visible, and keeps a one-click restore snapshot.",
27
60
  views: [
28
61
  openRouterCredentialStatus,
29
62
  openRouterActiveStatus,
@@ -31,64 +64,12 @@ extension ProvidersViewController {
31
64
  openRouterCatalogStatus,
32
65
  NativeView.row([manualLabel, openRouterModelField]),
33
66
  NativeView.row([saveKey, test, activate]),
67
+ NativeView.row([restorePrevious]),
34
68
  openRouterStatus
35
69
  ]
36
70
  )
37
71
  }
38
72
 
39
- func makeRoleModelsCard() -> NSBox {
40
- let definitions = [
41
- ("ui_implementer", "UI implementation"),
42
- ("native_app_specialist", "Native app"),
43
- ("implementation_specialist", "Implementation"),
44
- ("test_engineer", "Testing")
45
- ]
46
- var views: [NSView] = [roleStatus]
47
- for (role, title) in definitions {
48
- let controls = RoleModelControls(role: role, target: self)
49
- controls.model.addItem(withTitle: "Loading profiles…")
50
- controls.model.setAccessibilityLabel("\(title) model")
51
- controls.model.widthAnchor.constraint(greaterThanOrEqualToConstant: 210).isActive = true
52
- controls.model.identifier = NSUserInterfaceItemIdentifier(role)
53
- controls.model.target = self
54
- controls.model.action = #selector(roleModelSelectionChanged(_:))
55
- controls.reasoning.addItem(withTitle: "Loading…")
56
- controls.reasoning.setAccessibilityLabel("\(title) reasoning effort")
57
- controls.current.setAccessibilityLabel("\(title) current and effective model")
58
- controls.save.setAccessibilityLabel("Save \(title) model override")
59
- controls.reset.setAccessibilityLabel("Reset \(title) model override")
60
- controls.model.isEnabled = false
61
- controls.reasoning.isEnabled = false
62
- controls.save.isEnabled = false
63
- controls.reset.isEnabled = false
64
- roleRows[role] = controls
65
- actionButtons += [controls.save, controls.reset]
66
-
67
- let heading = NativeView.sectionTitle(title)
68
- let roleId = NativeView.detail(role)
69
- let modelLabel = NSTextField(labelWithString: "Model")
70
- let reasoningLabel = NSTextField(labelWithString: "Reasoning")
71
- views.append(NativeView.row([heading, roleId]))
72
- views.append(controls.current)
73
- views.append(NativeView.row([modelLabel, controls.model, reasoningLabel, controls.reasoning]))
74
- views.append(NativeView.row([controls.save, controls.reset]))
75
- if role != definitions.last?.0 {
76
- let separator = NSBox()
77
- separator.boxType = .separator
78
- views.append(separator)
79
- }
80
- }
81
- let refresh = NativeView.button("Refresh Role Settings", target: self, action: #selector(refreshRoleModelsAction(_:)))
82
- roleRefreshButton = refresh
83
- actionButtons.append(refresh)
84
- views.append(refresh)
85
- return NativeView.card(
86
- title: "Models by Work Type",
87
- subtitle: "Overrides apply only to the selected agent role. Reset removes the override and restores the effective project/global default.",
88
- views: views
89
- )
90
- }
91
-
92
73
  func refreshOpenRouterStatus() {
93
74
  processClient.run(["codex-app", "openrouter-status", "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
94
75
  guard let self = self else { return }
@@ -97,6 +78,11 @@ extension ProvidersViewController {
97
78
  self.openRouterCredentialStatus.stringValue = "Credential: status unavailable — no saved key was assumed."
98
79
  self.openRouterActiveStatus.stringValue = "Active provider: status unavailable — no active provider was assumed."
99
80
  }
81
+ // An unreadable status cannot vouch for a restore point, so the
82
+ // button must not keep an enabled state from an earlier reply.
83
+ self.openRouterRestoreAvailable = false
84
+ self.openRouterRestoreButton?.isEnabled = false
85
+ self.openRouterRestoreButton?.toolTip = "Restore availability is unknown — refresh the OpenRouter status first."
100
86
  return
101
87
  }
102
88
  let keyPresent = json["key_present"] as? Bool == true
@@ -104,16 +90,20 @@ extension ProvidersViewController {
104
90
  let selected = json["selected"] as? Bool == true
105
91
  let activeModel = json["model"] as? String ?? "unset"
106
92
  let current = self.openRouterModelField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
107
- if selected, activeModel != "unset", current.isEmpty || current == "z-ai/glm-5.2" {
93
+ if selected, activeModel != "unset", !self.openRouterModelSelectionPending, current.isEmpty {
108
94
  self.openRouterModelField.stringValue = activeModel
109
95
  }
96
+ self.synchronizeOpenRouterPopupSelection()
97
+ self.openRouterSelectedNow = selected
98
+ self.openRouterActiveModel = activeModel
99
+ self.renderActiveProviderSummary()
110
100
  self.openRouterCredentialStatus.stringValue = keyPresent
111
101
  ? "Credential: saved securely\(providerPresent ? " · provider block ready" : " · provider setup needs repair")"
112
102
  : "Credential: missing · save a key before testing or activation"
113
103
  self.openRouterActiveStatus.stringValue = selected
114
104
  ? "Active provider: OpenRouter · main model \(activeModel)"
115
105
  : "Active provider: not OpenRouter · saved credentials remain available"
116
- if self.openRouterStatus.stringValue == "No OpenRouter action has run yet." {
106
+ if !self.openRouterActionRan {
117
107
  let summary = self.describeOpenRouterStatus(json)
118
108
  self.openRouterStatus.stringValue = result.code == 0
119
109
  ? summary
@@ -121,6 +111,11 @@ extension ProvidersViewController {
121
111
  }
122
112
  self.openRouterCredentialStatus.textColor = keyPresent ? .secondaryLabelColor : .systemOrange
123
113
  self.openRouterActiveStatus.textColor = selected ? .systemGreen : .secondaryLabelColor
114
+ self.openRouterRestoreAvailable = json["previous_routing_restore_available"] as? Bool == true
115
+ self.openRouterRestoreButton?.isEnabled = !self.busy && self.openRouterRestoreAvailable
116
+ self.openRouterRestoreButton?.toolTip = self.openRouterRestoreAvailable
117
+ ? "Restore the snapshotted pre-OpenRouter provider, model, and catalog."
118
+ : "No previous provider snapshot to restore."
124
119
  }
125
120
  }
126
121
 
@@ -135,9 +130,7 @@ extension ProvidersViewController {
135
130
  return "OpenRouter: key stored · activation model \(selectedOpenRouterModel()) · not selected. Next: test, then activate the selected model."
136
131
  }
137
132
 
138
- @objc func refreshOpenRouterModelsAction(_ sender: NSButton) {
139
- refreshOpenRouterModels()
140
- }
133
+ @objc func refreshOpenRouterModelsAction(_ sender: NSButton) { refreshOpenRouterModels() }
141
134
 
142
135
  func refreshOpenRouterModels() {
143
136
  guard !catalogRefreshInFlight else { return }
@@ -165,7 +158,7 @@ extension ProvidersViewController {
165
158
  self.openRouterModelPopup.removeAllItems()
166
159
  self.openRouterModelPopup.addItem(withTitle: "Choose from \(models.count) models…")
167
160
  self.openRouterModelPopup.addItems(withTitles: models)
168
- self.openRouterModelPopup.selectItem(at: 0)
161
+ self.synchronizeOpenRouterPopupSelection()
169
162
  self.openRouterModelPopup.isEnabled = !self.busy
170
163
  let authenticated = json["authenticated"] as? Bool == true
171
164
  self.openRouterCatalogStatus.stringValue = authenticated
@@ -189,12 +182,39 @@ extension ProvidersViewController {
189
182
 
190
183
  @objc private func selectOpenRouterModel(_ sender: NSPopUpButton) {
191
184
  guard sender.indexOfSelectedItem > 0, let model = sender.titleOfSelectedItem else { return }
185
+ openRouterModelSelectionPending = true
186
+ openRouterActionRan = true
192
187
  openRouterModelField.stringValue = model
193
188
  openRouterStatus.stringValue = "Selected \(model) from the catalog. Next: test the connection; activation remains unchanged."
194
189
  }
195
190
 
191
+ func controlTextDidChange(_ notification: Notification) {
192
+ guard let field = notification.object as? NSTextField else { return }
193
+ if field === openRouterModelField {
194
+ openRouterModelSelectionPending = true
195
+ openRouterActionRan = true
196
+ synchronizeOpenRouterPopupSelection()
197
+ openRouterStatus.stringValue = "Manual model selection changed. Next: test the connection; activation remains unchanged."
198
+ } else if field === multiProvider.model {
199
+ multiProvider.modelSelectionPending = true
200
+ synchronizeMultiProviderPopupSelection()
201
+ multiProvider.status.stringValue = "Manual routed model selection changed. Check the router before activation."
202
+ multiProvider.status.textColor = .secondaryLabelColor
203
+ }
204
+ }
205
+
206
+ private func synchronizeOpenRouterPopupSelection() {
207
+ let current = selectedOpenRouterModel()
208
+ if let index = openRouterModels.firstIndex(of: current) {
209
+ openRouterModelPopup.selectItem(at: index + 1)
210
+ } else {
211
+ openRouterModelPopup.selectItem(at: 0)
212
+ }
213
+ }
214
+
196
215
  @objc func saveOpenRouterKey() {
197
216
  guard let window = view.window else { return }
217
+ openRouterActionRan = true
198
218
  promptForSecretKey(
199
219
  window: window,
200
220
  sheetTitle: "OpenRouter API Key",
@@ -211,6 +231,7 @@ extension ProvidersViewController {
211
231
 
212
232
  @objc private func testOpenRouterConnection() {
213
233
  let model = selectedOpenRouterModel()
234
+ openRouterActionRan = true
214
235
  guard !model.isEmpty else {
215
236
  openRouterStatus.stringValue = "Connection test blocked · model id is empty. Next: choose or enter a model."
216
237
  return
@@ -240,11 +261,69 @@ extension ProvidersViewController {
240
261
 
241
262
  @objc func useOpenRouter() {
242
263
  let model = selectedOpenRouterModel()
264
+ openRouterActionRan = true
243
265
  guard !model.isEmpty else {
244
266
  openRouterStatus.stringValue = "Enter an OpenRouter model id, then click Activate Selected Model."
245
267
  return
246
268
  }
247
269
  guard !busy else { openRouterStatus.stringValue = "Another provider action is already running."; return }
270
+ guard let window = view.window else { return }
271
+ AlertFactory.confirmSheet(
272
+ window: window,
273
+ title: "Activate OpenRouter?",
274
+ message: "\(model) becomes the Codex main model and Codex App restarts. SKS remaps the Desktop thread sidebar so prior provider chats stay listed, snapshots the previous provider for Restore, and merges the model cache instead of wiping it. Codex Desktop may still label third-party models as Custom.",
275
+ destructive: false
276
+ ) { [weak self] approved in
277
+ guard let self = self, approved else { return }
278
+ self.performUseOpenRouter(model: model)
279
+ }
280
+ }
281
+
282
+ @objc func restorePreviousDesktopRouting() {
283
+ openRouterActionRan = true
284
+ guard !busy else { openRouterStatus.stringValue = "Another provider action is already running."; return }
285
+ guard let window = view.window else { return }
286
+ AlertFactory.confirmSheet(
287
+ window: window,
288
+ title: "Restore previous provider?",
289
+ message: "Restores the last pre-OpenRouter Desktop provider/model/catalog snapshot, reverses sidebar remap when present, and restarts Codex App.",
290
+ destructive: false
291
+ ) { [weak self] approved in
292
+ guard let self = self, approved else { return }
293
+ self.performRestorePreviousDesktopRouting()
294
+ }
295
+ }
296
+
297
+ private func performRestorePreviousDesktopRouting() {
298
+ guard let snapshot = operations.begin(kind: "desktop-routing-restore", mutationGroup: "codex-config", summary: "Restore previous Desktop provider") else {
299
+ openRouterStatus.stringValue = "Another guarded mutation is already running. Wait or open Diagnostics."
300
+ return
301
+ }
302
+ setBusy(true)
303
+ openRouterStatus.stringValue = "Restoring previous Desktop provider and restarting Codex App…"
304
+ _ = operations.update(snapshot, state: .running, stage: "restoring", progress: nil, summary: "Restore previous Desktop provider")
305
+ processClient.run(["codex-app", "restore-desktop-routing", "--restart-app", "--json"], timeout: NativeView.mutationTimeout) { [weak self] result in
306
+ guard let self = self else { return }
307
+ self.setBusy(false)
308
+ let json = self.json(result.output)
309
+ let ok = result.code == 0 && json?["ok"] as? Bool == true
310
+ let status = json?["status"] as? String ?? (ok ? "restored" : "failed")
311
+ let detail = self.structuredPublicDetail(json, fallback: result.output)
312
+ // Routing rolls back before the sidebar retag, so a blocked retag is
313
+ // partial success: the snapshot is kept and re-running finishes it.
314
+ let sidebarBlocked = status.hasPrefix("restored_sidebar")
315
+ _ = self.operations.update(snapshot, state: ok ? .succeeded : .failed, stage: "complete", progress: 1, summary: ok ? "Previous Desktop provider restored" : sidebarBlocked ? "Desktop provider restored; sidebar retag pending" : "Desktop provider restore needs action")
316
+ self.openRouterStatus.stringValue = ok
317
+ ? "Previous provider restored · \(status). Fully quit and reopen Codex App if chats or the picker still look stale."
318
+ : sidebarBlocked
319
+ ? "Provider restored, but prior-provider chats stay hidden · fully quit Codex App, then run Restore previous provider again."
320
+ : "Restore failed · \(status) · \(detail)"
321
+ self.refreshOpenRouterStatus()
322
+ self.refresh()
323
+ }
324
+ }
325
+
326
+ private func performUseOpenRouter(model: String) {
248
327
  guard let snapshot = operations.begin(kind: "openrouter-use", mutationGroup: "codex-config", summary: "Use OpenRouter") else {
249
328
  openRouterStatus.stringValue = "Another guarded mutation is already running. Wait or open Diagnostics."
250
329
  return
@@ -266,11 +345,20 @@ extension ProvidersViewController {
266
345
  && activationJson?["config_applied"] as? Bool == true
267
346
  && selected
268
347
  && activeModel == model
348
+ if configApplied {
349
+ self.openRouterModelSelectionPending = false
350
+ }
269
351
  let restartOK = activationJson?["restart_ok"] as? Bool == true
352
+ let remapped = (activationJson?["thread_sidebar_remap"] as? [String: Any])?["remapped"] as? Int ?? 0
353
+ let restoreAvailable = activationJson?["previous_routing_restore_available"] as? Bool == true
270
354
  let complete = configApplied && restartOK
271
355
  _ = self.operations.update(snapshot, state: complete ? .succeeded : .failed, stage: "complete", progress: 1, summary: complete ? "OpenRouter main model active" : configApplied ? "OpenRouter saved; restart required" : "OpenRouter activation needs action")
272
356
  if complete {
273
- self.openRouterStatus.stringValue = "Activation complete · OpenRouter is active · main model \(model)."
357
+ var parts = ["Activation complete · OpenRouter is active · main model \(model)"]
358
+ if remapped > 0 { parts.append("sidebar kept \(remapped) prior-provider chats visible") }
359
+ if restoreAvailable { parts.append("Restore previous provider is available") }
360
+ parts.append("Desktop may still show Custom for third-party models")
361
+ self.openRouterStatus.stringValue = parts.joined(separator: " · ") + "."
274
362
  } else if configApplied {
275
363
  self.openRouterStatus.stringValue = "Configuration saved · main model \(model) is selected, but Codex App did not restart. Next: reopen Codex App, then verify status."
276
364
  } else {
@@ -285,7 +373,7 @@ extension ProvidersViewController {
285
373
  openRouterModelField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
286
374
  }
287
375
 
288
- private func structuredPublicDetail(_ json: [String: Any]?, fallback: String) -> String {
376
+ func structuredPublicDetail(_ json: [String: Any]?, fallback: String) -> String {
289
377
  if let blockers = json?["blockers"] as? [String], !blockers.isEmpty {
290
378
  let error = publicError(json).map { " · \($0)" } ?? ""
291
379
  return "Reason: \(blockers.joined(separator: ", ").replacingOccurrences(of: "_", with: " "))\(error). Next: \((json?["hint"] as? String) ?? "review the key, model id, and network, then retry")."
@@ -295,7 +383,7 @@ extension ProvidersViewController {
295
383
  return "Next: \(NativeView.redactPreview(fallback))"
296
384
  }
297
385
 
298
- private func publicError(_ json: [String: Any]?) -> String? {
386
+ func publicError(_ json: [String: Any]?) -> String? {
299
387
  if let value = json?["error"] as? String { return value }
300
388
  guard let value = json?["error"] as? [String: Any] else { return nil }
301
389
  let code = value["code"] as? String
@@ -303,152 +391,4 @@ extension ProvidersViewController {
303
391
  return [code, message].compactMap { $0 }.joined(separator: ": ")
304
392
  }
305
393
 
306
- @objc func refreshRoleModelsAction(_ sender: NSButton) {
307
- refreshRoleModels()
308
- }
309
-
310
- func refreshRoleModels() {
311
- guard !roleRefreshInFlight else { return }
312
- roleRefreshInFlight = true
313
- roleRefreshButton?.isEnabled = false
314
- roleStatus.stringValue = "Loading role model settings…"
315
- processClient.run(["codex-app", "role-models", "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
316
- guard let self = self else { return }
317
- self.roleRefreshInFlight = false
318
- self.roleRefreshButton?.isEnabled = !self.busy
319
- guard result.code == 0, let json = self.json(result.output) else {
320
- self.roleProfilesLoaded = false
321
- self.updateRoleControlAvailability()
322
- self.roleStatus.stringValue = "Role settings unavailable · existing configuration was not changed."
323
- return
324
- }
325
- self.configureSupportedRoleProfiles(json)
326
- var loaded = 0
327
- for (role, controls) in self.roleRows {
328
- guard let payload = self.rolePayload(json, role: role) else {
329
- controls.current.stringValue = "Current: unavailable · Effective: unavailable"
330
- continue
331
- }
332
- let configured = (payload["configured"] as? [String: Any]) ?? (payload["override"] as? [String: Any])
333
- let effective = (payload["effective"] as? [String: Any]) ?? payload
334
- let configuredModel = (configured?["model"] as? String) ?? (payload["configured_model"] as? String)
335
- let configuredReasoning = self.reasoningValue(configured) ?? (payload["configured_reasoning"] as? String)
336
- let effectiveModel = (effective["model"] as? String) ?? (payload["effective_model"] as? String) ?? "unavailable"
337
- let effectiveReasoning = self.reasoningValue(effective)
338
- ?? (payload["effective_reasoning_effort"] as? String)
339
- ?? (payload["effective_reasoning"] as? String)
340
- ?? "unavailable"
341
- self.selectRoleProfile(model: configuredModel ?? effectiveModel, reasoning: configuredReasoning ?? effectiveReasoning, controls: controls)
342
- let current = configuredModel.map { "\($0) / \(configuredReasoning ?? "default")" } ?? "default (no override)"
343
- controls.current.stringValue = "Current: \(current) · Effective: \(effectiveModel) / \(effectiveReasoning)"
344
- loaded += 1
345
- }
346
- self.roleProfilesLoaded = !self.supportedRoleProfiles.isEmpty
347
- self.updateRoleControlAvailability()
348
- self.roleStatus.stringValue = "Loaded \(loaded) of \(self.roleRows.count) role settings. Save creates an override; Reset removes it."
349
- }
350
- }
351
-
352
- func updateRoleControlAvailability() {
353
- let enabled = !busy && roleProfilesLoaded
354
- for controls in roleRows.values {
355
- controls.model.isEnabled = enabled
356
- controls.reasoning.isEnabled = enabled
357
- controls.save.isEnabled = enabled
358
- controls.reset.isEnabled = enabled
359
- }
360
- }
361
-
362
- private func configureSupportedRoleProfiles(_ json: [String: Any]) {
363
- let rows = json["supported_profiles"] as? [[String: Any]] ?? []
364
- supportedRoleProfiles = rows.compactMap { row in
365
- guard let model = row["model"] as? String,
366
- let reasoning = row["reasoning_effort"] as? String,
367
- !model.isEmpty, !reasoning.isEmpty else { return nil }
368
- return (model, reasoning)
369
- }
370
- let models = Array(Set(supportedRoleProfiles.map(\.model))).sorted()
371
- for controls in roleRows.values {
372
- controls.model.removeAllItems()
373
- controls.model.addItems(withTitles: models)
374
- controls.reasoning.removeAllItems()
375
- }
376
- }
377
-
378
- private func rolePayload(_ json: [String: Any], role: String) -> [String: Any]? {
379
- if let roles = json["roles"] as? [String: Any], let payload = roles[role] as? [String: Any] { return payload }
380
- if let payload = json[role] as? [String: Any] { return payload }
381
- if let roles = json["roles"] as? [[String: Any]] {
382
- return roles.first { ($0["role"] as? String) == role || ($0["id"] as? String) == role }
383
- }
384
- return nil
385
- }
386
-
387
- private func reasoningValue(_ json: [String: Any]?) -> String? {
388
- (json?["reasoning"] as? String) ?? (json?["reasoning_effort"] as? String) ?? (json?["model_reasoning_effort"] as? String)
389
- }
390
-
391
- private func selectRoleProfile(model: String, reasoning: String, controls: RoleModelControls) {
392
- let selectedModel = controls.model.itemTitles.contains(model) ? model : (controls.model.itemTitles.first ?? "")
393
- controls.model.selectItem(withTitle: selectedModel)
394
- updateReasoningChoices(controls, preferred: reasoning)
395
- }
396
-
397
- @objc private func roleModelSelectionChanged(_ sender: NSPopUpButton) {
398
- guard let role = sender.identifier?.rawValue, let controls = roleRows[role] else { return }
399
- updateReasoningChoices(controls, preferred: nil)
400
- }
401
-
402
- private func updateReasoningChoices(_ controls: RoleModelControls, preferred: String?) {
403
- let model = controls.model.titleOfSelectedItem ?? ""
404
- let efforts = supportedRoleProfiles.filter { $0.model == model }.map(\.reasoning)
405
- controls.reasoning.removeAllItems()
406
- controls.reasoning.addItems(withTitles: efforts)
407
- if let preferred = preferred, efforts.contains(preferred) { controls.reasoning.selectItem(withTitle: preferred) }
408
- }
409
-
410
- @objc func saveRoleModel(_ sender: NSButton) {
411
- guard let role = sender.identifier?.rawValue, let controls = roleRows[role] else { return }
412
- let model = controls.model.titleOfSelectedItem ?? ""
413
- let reasoning = controls.reasoning.titleOfSelectedItem ?? "medium"
414
- guard !model.isEmpty else { roleStatus.stringValue = "Save blocked for \(role) · enter a model id."; return }
415
- runRoleMutation(
416
- ["codex-app", "set-role-model", "--role", role, "--model", model, "--reasoning", reasoning, "--json"],
417
- role: role,
418
- kind: "role-model-set",
419
- running: "Saving \(role) override…",
420
- success: "Saved \(role) · \(model) / \(reasoning). Next: new tasks for this role use the effective override."
421
- )
422
- }
423
-
424
- @objc func resetRoleModel(_ sender: NSButton) {
425
- guard let role = sender.identifier?.rawValue else { return }
426
- runRoleMutation(
427
- ["codex-app", "reset-role-model", "--role", role, "--json"],
428
- role: role,
429
- kind: "role-model-reset",
430
- running: "Resetting \(role) override…",
431
- success: "Reset \(role). Next: new tasks use the effective default shown below."
432
- )
433
- }
434
-
435
- private func runRoleMutation(_ args: [String], role: String, kind: String, running: String, success: String) {
436
- guard !busy else { roleStatus.stringValue = "Another provider action is already running."; return }
437
- guard let snapshot = operations.begin(kind: kind, mutationGroup: "codex-config", summary: running) else {
438
- roleStatus.stringValue = "Another guarded mutation is already running. Wait or open Diagnostics."
439
- return
440
- }
441
- setBusy(true)
442
- roleStatus.stringValue = running
443
- _ = operations.update(snapshot, state: .running, stage: "saving", progress: nil, summary: running)
444
- processClient.run(args, timeout: NativeView.mutationTimeout) { [weak self] result in
445
- guard let self = self else { return }
446
- self.setBusy(false)
447
- let json = self.json(result.output)
448
- let ok = result.code == 0 && json?["ok"] as? Bool == true
449
- _ = self.operations.update(snapshot, state: ok ? .succeeded : .failed, stage: "complete", progress: 1, summary: ok ? "Role model setting saved" : "Role model setting needs action")
450
- self.roleStatus.stringValue = ok ? success : "\(role) change failed · \(self.structuredPublicDetail(json, fallback: result.output))"
451
- self.refreshRoleModels()
452
- }
453
- }
454
394
  }