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,8 +1,9 @@
1
1
  import fsp from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { writeJsonAtomic } from '../../fsx.js';
4
- import { validateArchitectureConfiguration } from '../contracts/contracts.js';
5
4
  export const ARCHITECTURE_STATE_SCHEMA = 'sks.architecture-state.v1';
5
+ export const APPLY_RECEIPTS_SCHEMA = 'sks.apply-receipts.v1';
6
+ export const APPLY_STAGE_RECEIPT_SCHEMA = 'sks.apply-stage-receipt.v1';
6
7
  export const APPLY_STAGE_ORDER = [
7
8
  'config_saved',
8
9
  'proxy_applied',
@@ -21,18 +22,18 @@ export class ArchitectureStateService {
21
22
  this.receiptPath = path.join(this.root, 'apply-receipt.json');
22
23
  }
23
24
  async stage(configuration) {
24
- const validated = validateArchitectureConfiguration(configuration);
25
+ const validated = cloneJsonState(configuration);
25
26
  await fsp.mkdir(this.root, { recursive: true, mode: 0o700 });
26
27
  await writeJsonAtomic(this.draftPath, validated, { mode: 0o600 });
27
28
  return validated;
28
29
  }
29
30
  async commit(ports, now = () => new Date()) {
30
- const draft = await readConfiguration(this.draftPath);
31
+ const draft = await readState(this.draftPath);
31
32
  if (!draft)
32
33
  return { ok: false, status: 'failed', receipts: [], blocker: 'state_draft_missing' };
33
34
  const receipts = APPLY_STAGE_ORDER.map((stage) => receipt(stage, 'pending', null, now));
34
35
  const persist = async () => {
35
- await writeJsonAtomic(this.receiptPath, { schema: 'sks.apply-receipts.v1', stages: receipts }, { mode: 0o600 });
36
+ await writeJsonAtomic(this.receiptPath, { schema: APPLY_RECEIPTS_SCHEMA, stages: receipts }, { mode: 0o600 });
36
37
  };
37
38
  await persist();
38
39
  const runStage = async (stage, action) => {
@@ -76,10 +77,10 @@ export class ArchitectureStateService {
76
77
  throw error;
77
78
  }
78
79
  }
79
- async read(existingSession = null) {
80
+ async read() {
80
81
  const [draft, lastKnownGood, receipts] = await Promise.all([
81
- readConfiguration(this.draftPath),
82
- readConfiguration(this.lastKnownGoodPath),
82
+ readState(this.draftPath),
83
+ readState(this.lastKnownGoodPath),
83
84
  readReceipts(this.receiptPath)
84
85
  ]);
85
86
  return {
@@ -87,7 +88,6 @@ export class ArchitectureStateService {
87
88
  draft,
88
89
  last_known_good: lastKnownGood,
89
90
  receipts,
90
- existing_session: existingSession,
91
91
  new_session_default: lastKnownGood
92
92
  };
93
93
  }
@@ -99,7 +99,7 @@ class StateApplyError extends Error {
99
99
  this.code = code;
100
100
  }
101
101
  }
102
- async function readConfiguration(file) {
102
+ async function readState(file) {
103
103
  let raw;
104
104
  try {
105
105
  raw = await fsp.readFile(file, 'utf8');
@@ -109,12 +109,12 @@ async function readConfiguration(file) {
109
109
  return null;
110
110
  throw error;
111
111
  }
112
- return validateArchitectureConfiguration(JSON.parse(raw));
112
+ return cloneJsonState(JSON.parse(raw));
113
113
  }
114
114
  async function readReceipts(file) {
115
115
  try {
116
116
  const parsed = JSON.parse(await fsp.readFile(file, 'utf8'));
117
- if (parsed.schema !== 'sks.apply-receipts.v1' || !Array.isArray(parsed.stages))
117
+ if (parsed.schema !== APPLY_RECEIPTS_SCHEMA || !Array.isArray(parsed.stages))
118
118
  return [];
119
119
  return parsed.stages.filter(isReceipt);
120
120
  }
@@ -126,7 +126,7 @@ async function readReceipts(file) {
126
126
  }
127
127
  function receipt(stage, status, reasonCode, now) {
128
128
  return {
129
- schema: 'sks.apply-stage-receipt.v1',
129
+ schema: APPLY_STAGE_RECEIPT_SCHEMA,
130
130
  stage,
131
131
  status,
132
132
  reason_code: reasonCode,
@@ -143,12 +143,48 @@ function isReceipt(value) {
143
143
  if (!value || typeof value !== 'object')
144
144
  return false;
145
145
  const row = value;
146
- return row.schema === 'sks.apply-stage-receipt.v1'
146
+ return row.schema === APPLY_STAGE_RECEIPT_SCHEMA
147
147
  && APPLY_STAGE_ORDER.includes(row.stage)
148
148
  && ['pending', 'running', 'succeeded', 'failed'].includes(String(row.status))
149
149
  && (row.reason_code === null || typeof row.reason_code === 'string')
150
150
  && typeof row.updated_at === 'string';
151
151
  }
152
+ function cloneJsonState(value) {
153
+ validateJsonValue(value, true, new Set());
154
+ return JSON.parse(JSON.stringify(value));
155
+ }
156
+ function validateJsonValue(value, root, ancestors) {
157
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
158
+ return;
159
+ if (typeof value === 'number') {
160
+ if (Number.isFinite(value))
161
+ return;
162
+ throw new StateApplyError('state_configuration_not_json_safe');
163
+ }
164
+ if (typeof value !== 'object')
165
+ throw new StateApplyError('state_configuration_not_json_safe');
166
+ if (root && Array.isArray(value))
167
+ throw new StateApplyError('state_configuration_not_json_object');
168
+ if (ancestors.has(value))
169
+ throw new StateApplyError('state_configuration_not_json_safe');
170
+ ancestors.add(value);
171
+ if (Array.isArray(value)) {
172
+ for (const entry of value)
173
+ validateJsonValue(entry, false, ancestors);
174
+ }
175
+ else {
176
+ const prototype = Object.getPrototypeOf(value);
177
+ if (prototype !== Object.prototype && prototype !== null) {
178
+ throw new StateApplyError('state_configuration_not_json_safe');
179
+ }
180
+ if (Reflect.ownKeys(value).some((key) => typeof key === 'symbol')) {
181
+ throw new StateApplyError('state_configuration_not_json_safe');
182
+ }
183
+ for (const entry of Object.values(value))
184
+ validateJsonValue(entry, false, ancestors);
185
+ }
186
+ ancestors.delete(value);
187
+ }
152
188
  function safeFailureCode(error) {
153
189
  const candidate = error instanceof Error ? error.message : '';
154
190
  return /^[a-z][a-z0-9_]{2,99}$/.test(candidate) ? candidate : 'state_apply_failed';
@@ -1,10 +1,10 @@
1
1
  import os from 'node:os';
2
2
  import path from 'node:path';
3
+ import { createHash } from 'node:crypto';
3
4
  import { ensureDir, exists, readText, writeTextAtomic } from './fsx.js';
4
5
  import { writeCodexConfigGuarded } from './codex/codex-config-guard.js';
5
6
  import { inspectConfinedPath, removeManagedPathVerified } from './managed-path-safety.js';
6
7
  import { RETIRED_AUTO_REVIEW_POLICY_TEXTS, RETIRED_SKS_CONFIG_PROFILE_NAMES } from './doctor/retired-auto-review-config.js';
7
- import { retiredGlmDesktopProfileBody } from './codex-app/openrouter-provider.js';
8
8
  import { escapeRegExp } from './text/regex.js';
9
9
  export { RETIRED_SKS_CONFIG_PROFILE_NAMES } from './doctor/retired-auto-review-config.js';
10
10
  export const AUTO_REVIEW_REVIEWER = 'auto_review';
@@ -201,7 +201,8 @@ export function reconcileRetiredSksConfigText(text) {
201
201
  }
202
202
  export function isSksGeneratedRetiredProfileText(text) {
203
203
  const normalized = normalizeGeneratedProfileText(text);
204
- return managedRetiredProfileBodies().has(normalized);
204
+ return managedRetiredProfileBodies().has(normalized)
205
+ || HISTORICAL_OPENROUTER_PROFILE_SHA256.has(sha256(normalized));
205
206
  }
206
207
  export function buildMadHighLaunchProfileNoWrite(opts = {}) {
207
208
  const env = opts.env || process.env;
@@ -461,12 +462,17 @@ function managedRetiredProfileBodies() {
461
462
  'approval_policy = "on-request"',
462
463
  'sandbox_mode = "workspace-write"',
463
464
  'model_reasoning_effort = "medium"'
464
- ].join('\n'),
465
- retiredGlmDesktopProfileBody('none'),
466
- retiredGlmDesktopProfileBody('minimal'),
467
- retiredGlmDesktopProfileBody('low'),
468
- retiredGlmDesktopProfileBody('medium'),
469
- retiredGlmDesktopProfileBody('high'),
470
- retiredGlmDesktopProfileBody('xhigh')
465
+ ].join('\n')
471
466
  ].map(normalizeGeneratedProfileText));
472
467
  }
468
+ const HISTORICAL_OPENROUTER_PROFILE_SHA256 = new Set([
469
+ '8405d346127e87805f284caa6c2f20a67cbd96595c4f3b194a46212c650837c4',
470
+ 'ff97ebf844785bdd21e5b28dd109ec5684873fe52e75386c1bd1bd19c7cedcc8',
471
+ 'be337e958e9379e72ccf8dd5576c1e4d8d348c338cebc4d68690bfb9d94a3048',
472
+ 'feb9f6be9e4596a2a897f3c6b5b735fa838e64227a0fba1051d1ac93c0613e8c',
473
+ '0a482903a52392434f3746451166ad54e95053e6777c5013edf9fec2da23692e',
474
+ '364fbce652087e4ae8284bdb51e664e9c4e37eafee146123c68d5a6fb036c347'
475
+ ]);
476
+ function sha256(text) {
477
+ return createHash('sha256').update(text).digest('hex');
478
+ }
@@ -5,6 +5,7 @@ import { appendJsonl, ensureDir, nowIso, readText, sha256, writeTextAtomic } fro
5
5
  import { diffCodexAppUiSnapshots, snapshotCodexAppUiState } from '../codex-app/codex-app-ui-state-snapshot.js';
6
6
  import { cleanupCodexConfigBackups, validateCodexConfigRoundTrip } from './codex-config-toml.js';
7
7
  import { escapeRegExp } from '../text/regex.js';
8
+ import { withFileLock } from '../locks/file-lock.js';
8
9
  export const SKS_MANAGED_CODEX_CONFIG_MARKER = '# SKS-MANAGED-CODEX-CONFIG';
9
10
  const FAST_FEATURE_KEYS = [
10
11
  'fast_mode',
@@ -21,6 +22,13 @@ const FAST_FEATURE_KEYS = [
21
22
  ];
22
23
  export async function writeCodexConfigGuarded(input) {
23
24
  const configPath = path.resolve(input.configPath);
25
+ return withFileLock({
26
+ lockPath: `${configPath}.lock`,
27
+ timeoutMs: 10_000,
28
+ staleMs: 60_000
29
+ }, () => writeCodexConfigGuardedUnlocked(input, configPath));
30
+ }
31
+ async function writeCodexConfigGuardedUnlocked(input, configPath) {
24
32
  const root = path.resolve(input.root || process.cwd());
25
33
  const cause = input.cause || 'codex-config';
26
34
  const before = input.before === undefined ? String(await readText(configPath, '')) : String(input.before || '');
@@ -3,7 +3,7 @@ import { runProcess } from './fsx.js';
3
3
  import { preserveCodexModelArgs } from './codex-model-guard.js';
4
4
  import { managedProxyEnvForChild } from './codex/managed-proxy-env.js';
5
5
  import { resolveCodexRuntime } from './codex-runtime/resolve-codex-runtime.js';
6
- import { codexLbRecoveryBlockedProcessResult, withCodexLbCliLaunchRecovery } from './codex-control/codex-lb-launch-recovery.js';
6
+ import { desktopBridgeLaunchBlockedProcessResult, withDesktopBridgeCliLaunchGuard } from './codex-control/desktop-bridge-launch-guard.js';
7
7
  import { prepareCodexAppServerRuntimeEnv } from './codex-control/codex-app-server-runtime-env.js';
8
8
  export async function findCodexBinary() {
9
9
  const resolved = await resolveCodexRuntime({
@@ -41,18 +41,16 @@ export function buildCodexExecArgs({ root, prompt, outputFile, json = true, prof
41
41
  args.push(prompt);
42
42
  return args;
43
43
  }
44
- export async function runCodexExec({ root, recoveryRoot = root, prompt, outputFile, json = true, profile = null, extraArgs = [], onStdout, onStderr, logDir = null, stdoutFile = null, stderrFile = null, maxBufferBytes = 256 * 1024, timeoutMs = null, env = process.env, codexBin = null, findCodexBinaryImpl = findCodexBinary, runProcessImpl = runProcess, prepareCodexRuntimeEnvImpl = prepareCodexAppServerRuntimeEnv, recoveryFetch = undefined, recoveryTimeoutMs = undefined }) {
44
+ export async function runCodexExec({ root, recoveryRoot = root, prompt, outputFile, json = true, profile = null, extraArgs = [], onStdout, onStderr, logDir = null, stdoutFile = null, stderrFile = null, maxBufferBytes = 256 * 1024, timeoutMs = null, env = process.env, codexBin = null, findCodexBinaryImpl = findCodexBinary, runProcessImpl = runProcess, prepareCodexRuntimeEnvImpl = prepareCodexAppServerRuntimeEnv }) {
45
45
  const args = buildCodexExecArgs({ root, prompt, outputFile, json, profile, extraArgs });
46
46
  const effectiveTimeoutMs = Number(timeoutMs || process.env.SKS_CODEX_TIMEOUT_MS || process.env.DCODEX_CODEX_TIMEOUT_MS || 30 * 60 * 1000);
47
47
  const recoveryArgs = args.slice(1, -1);
48
48
  const runtimeEnv = await prepareCodexRuntimeEnvImpl({ env });
49
- const guarded = await withCodexLbCliLaunchRecovery({
49
+ const guarded = await withDesktopBridgeCliLaunchGuard({
50
50
  root: recoveryRoot,
51
51
  env: runtimeEnv,
52
- cliArgs: recoveryArgs,
53
- ...(typeof recoveryFetch === 'function' ? { fetchImpl: recoveryFetch } : {}),
54
- ...(recoveryTimeoutMs === undefined ? {} : { timeoutMs: recoveryTimeoutMs })
55
- }, async () => {
52
+ cliArgs: recoveryArgs
53
+ }, async (sanitizedEnv) => {
56
54
  const bin = codexBin || await findCodexBinaryImpl();
57
55
  if (!bin) {
58
56
  return {
@@ -67,7 +65,7 @@ export async function runCodexExec({ root, recoveryRoot = root, prompt, outputFi
67
65
  }
68
66
  return runProcessImpl(bin, args, {
69
67
  cwd: root,
70
- env: { ...runtimeEnv, ...managedProxyEnvForChild(runtimeEnv) },
68
+ env: { ...sanitizedEnv, ...managedProxyEnvForChild(sanitizedEnv) },
71
69
  onStdout,
72
70
  onStderr,
73
71
  timeoutMs: effectiveTimeoutMs,
@@ -77,6 +75,6 @@ export async function runCodexExec({ root, recoveryRoot = root, prompt, outputFi
77
75
  });
78
76
  });
79
77
  return guarded.launched
80
- ? guarded.value
81
- : codexLbRecoveryBlockedProcessResult(guarded.toolOutputRecovery);
78
+ ? { ...guarded.value, desktop_bridge_launch_guard: guarded.desktopBridgeLaunchGuard }
79
+ : desktopBridgeLaunchBlockedProcessResult(guarded.desktopBridgeLaunchGuard);
82
80
  }
@@ -74,6 +74,12 @@ export async function repairCodexAppFastUi(root = process.cwd(), input = {}) {
74
74
  home: path.dirname(home),
75
75
  configPath: path.join(home, 'config.toml'),
76
76
  codexLbEnvPath: path.join(home, 'sks-codex-lb.env'),
77
+ desktopBridgeStatusOptions: {
78
+ home: path.dirname(home),
79
+ env: input.env || process.env,
80
+ configPath: path.join(home, 'config.toml'),
81
+ authPath: path.join(home, 'auth.json')
82
+ },
77
83
  ...(input.codexLbModelCatalog ? { codexLbModelCatalog: input.codexLbModelCatalog } : {}),
78
84
  ...(input.desktopPickerEvidence ? { desktopPickerEvidence: input.desktopPickerEvidence } : {})
79
85
  });
@@ -122,7 +128,7 @@ export async function repairCodexAppFastUi(root = process.cwd(), input = {}) {
122
128
  auth_mode: after.indicators.auth_mode,
123
129
  chat_surface: after.indicators.chat_surface,
124
130
  chatgpt_oauth_backup_available: after.indicators.chatgpt_oauth_backup_available,
125
- next_action: requiresConfirmation ? 'Run `sks doctor --fix --repair-codex-app-ui` after reviewing the repair plan.' : manual && safeAutoApply ? 'Run `sks doctor --fix` to apply the safe Codex App UI repair.' : manual ? 'Run `sks doctor --fix --repair-codex-app-ui` after reviewing the repair plan.' : chatgptOauthInactive ? 'Run `sks codex-lb migrate-legacy-desktop --restart-app`; if no valid OAuth backup exists, run `codex login` first. Ordinary codex-lb routing commands never replace ChatGPT OAuth.' : changed ? 'Restart Codex App if the selector was already hidden.' : 'No Codex App UI repair needed.',
131
+ next_action: requiresConfirmation ? 'Run `sks doctor --fix --repair-codex-app-ui` after reviewing the repair plan.' : manual && safeAutoApply ? 'Run `sks doctor --fix` to apply the safe Codex App UI repair.' : manual ? 'Run `sks doctor --fix --repair-codex-app-ui` after reviewing the repair plan.' : chatgptOauthInactive ? 'Run `codex login` if ChatGPT OAuth is unavailable, then run `sks bridge ensure`; Desktop Bridge provider commands do not replace ChatGPT OAuth.' : changed ? 'Restart Codex App if the selector was already hidden.' : 'No Codex App UI repair needed.',
126
132
  blockers
127
133
  };
128
134
  if (input.reportPath)
@@ -173,42 +179,14 @@ function stripProjectLocalForbiddenKeys(text) {
173
179
  }
174
180
  function stripSksCausedHostOwnedLines(text) {
175
181
  const sourceLines = String(text || '').split(/\r?\n/);
176
- const preserveCodexLbSelection = hasActiveCodexLbProviderSelection(text);
177
- const preserveOpenRouterSelection = hasActiveOpenRouterProviderSelection(text);
178
182
  const stripped = stripMatchingLines(text, (line, table, _previous, _next, index) => {
179
183
  const isLegacyFastTable = table ? FAST_UI_LEGACY_TABLES.has(table) : false;
180
184
  if (isLegacyFastTable)
181
185
  return true;
182
- if (!table && preserveCodexLbSelection && /^\s*model_provider\s*=\s*"codex-lb"\s*(?:#.*)?$/.test(line))
183
- return false;
184
- if (!table && preserveOpenRouterSelection && /^\s*(?:model_provider\s*=\s*"openrouter"|model\s*=)/.test(line))
185
- return false;
186
186
  return !table && FAST_UI_TOP_LEVEL_RE.test(line) && isSksOwnedGlobalUiLock(sourceLines, index);
187
187
  });
188
188
  return stripped;
189
189
  }
190
- function hasActiveOpenRouterProviderSelection(text) {
191
- const source = String(text || '');
192
- if (!/(?:^|\n)\s*model_provider\s*=\s*"openrouter"\s*(?:#.*)?(?=\n|$)/.test(source))
193
- return false;
194
- const body = source.match(/(?:^|\n)\[model_providers\.openrouter\]([^\n]*(?:\n(?!\s*\[)[^\n]*)*)/)?.[1] || '';
195
- return /(?:^|\n)\s*base_url\s*=\s*"https:\/\/openrouter\.ai\/api\/v1"\s*(?:#.*)?(?=\n|$)/.test(body)
196
- && /(?:^|\n)\s*wire_api\s*=\s*"responses"\s*(?:#.*)?(?=\n|$)/.test(body);
197
- }
198
- function hasActiveCodexLbProviderSelection(text) {
199
- const source = String(text || '');
200
- if (!/(?:^|\n)\s*model_provider\s*=\s*"codex-lb"\s*(?:#.*)?(?=\n|$)/.test(source))
201
- return false;
202
- const body = source.match(/(?:^|\n)\[model_providers\.codex-lb\]([^\n]*(?:\n(?!\s*\[)[^\n]*)*)/)?.[1] || '';
203
- const providerIdentity = /(?:^|\n)\s*name\s*=\s*"(?:openai|codex-lb)"\s*(?:#.*)?(?=\n|$)/i.test(body);
204
- const baseUrl = /(?:^|\n)\s*base_url\s*=\s*"https?:\/\/[^"]+"\s*(?:#.*)?(?=\n|$)/.test(body);
205
- const responsesWire = /(?:^|\n)\s*wire_api\s*=\s*"responses"\s*(?:#.*)?(?=\n|$)/.test(body);
206
- const cliProviderAuth = /(?:^|\n)\s*env_key\s*=\s*"CODEX_LB_API_KEY"\s*(?:#.*)?(?=\n|$)/.test(body)
207
- && /(?:^|\n)\s*requires_openai_auth\s*=\s*false\s*(?:#.*)?(?=\n|$)/.test(body);
208
- const desktopCompatAuth = /(?:^|\n)\s*env_http_headers\s*=\s*\{[^}\n]*"X-Codex-LB-API-Key"\s*=\s*"CODEX_LB_API_KEY"[^}\n]*\}\s*(?:#.*)?(?=\n|$)/.test(body)
209
- && /(?:^|\n)\s*requires_openai_auth\s*=\s*true\s*(?:#.*)?(?=\n|$)/.test(body);
210
- return providerIdentity && baseUrl && responsesWire && (cliProviderAuth || desktopCompatAuth);
211
- }
212
190
  function stripMatchingLines(text, shouldRemove) {
213
191
  const lines = text.split(/\r?\n/);
214
192
  let table = null;
@@ -1,6 +1,6 @@
1
1
  import { findCodexBinary } from '../codex-adapter.js';
2
2
  import { runProcess } from '../fsx.js';
3
- import { inspectCodexLbCliLaunchRecovery } from '../codex-control/codex-lb-launch-recovery.js';
3
+ import { inspectDesktopBridgeCliLaunchGuard, stripRetiredDirectProviderEnv } from '../codex-control/desktop-bridge-launch-guard.js';
4
4
  export async function attemptCodexAppLaunch(input) {
5
5
  const platform = input.platform || process.platform;
6
6
  const timeoutMs = Math.max(1, Math.min(Number(input.timeoutMs || 3000), 3000));
@@ -46,16 +46,14 @@ export async function attemptCodexAppLaunch(input) {
46
46
  blockers: launched ? [] : ['codex_app_launch_failed']
47
47
  });
48
48
  }
49
- const env = input.env || process.env;
49
+ const env = stripRetiredDirectProviderEnv(input.env || process.env);
50
50
  const execute = input.runProcessImpl || runProcess;
51
- const toolOutputRecovery = await inspectCodexLbCliLaunchRecovery({
51
+ const launchGuard = await inspectDesktopBridgeCliLaunchGuard({
52
52
  root: input.cwd,
53
53
  env,
54
- cliArgs: ['/app'],
55
- ...(input.recoveryFetch ? { fetchImpl: input.recoveryFetch } : {}),
56
- ...(input.recoveryTimeoutMs === undefined ? {} : { timeoutMs: input.recoveryTimeoutMs })
54
+ cliArgs: ['/app']
57
55
  });
58
- if (!toolOutputRecovery.ok) {
56
+ if (!launchGuard.ok) {
59
57
  return launchAttempt({
60
58
  attempted: false,
61
59
  launched: false,
@@ -63,9 +61,9 @@ export async function attemptCodexAppLaunch(input) {
63
61
  mode: input.mode,
64
62
  command_line: commandLine,
65
63
  exit_code: null,
66
- fallback_reason: 'codex_lb_tool_output_recovery_blocked',
67
- blockers: toolOutputRecovery.blockers,
68
- tool_output_recovery: toolOutputRecovery
64
+ fallback_reason: 'desktop_bridge_launch_guard_blocked',
65
+ blockers: launchGuard.blockers,
66
+ desktop_bridge_launch_guard: launchGuard
69
67
  });
70
68
  }
71
69
  codexBin ||= await (input.findCodexBinaryImpl || findCodexBinary)();
@@ -80,7 +78,7 @@ export async function attemptCodexAppLaunch(input) {
80
78
  exit_code: null,
81
79
  fallback_reason: 'codex_cli_missing_artifact_only_fallback',
82
80
  blockers: ['codex_cli_missing'],
83
- tool_output_recovery: toolOutputRecovery
81
+ desktop_bridge_launch_guard: launchGuard
84
82
  });
85
83
  }
86
84
  const result = await execute(codexBin, ['/app'], {
@@ -120,7 +118,7 @@ export async function attemptCodexAppLaunch(input) {
120
118
  stderr_tail: stderr.slice(-4000),
121
119
  fallback_reason: fallbackReason,
122
120
  blockers: launched ? [] : [timedOut ? 'codex_app_launch_interactive_or_timeout' : 'codex_app_launch_failed'],
123
- tool_output_recovery: toolOutputRecovery
121
+ desktop_bridge_launch_guard: launchGuard
124
122
  });
125
123
  }
126
124
  function launchAttempt(input) {
@@ -1,5 +1,5 @@
1
1
  import { exists, runProcess, which } from '../fsx.js';
2
- import { inspectCodexLbCliLaunchRecovery } from '../codex-control/codex-lb-launch-recovery.js';
2
+ import { inspectDesktopBridgeCliLaunchGuard, stripRetiredDirectProviderEnv } from '../codex-control/desktop-bridge-launch-guard.js';
3
3
  export async function quitCodexApp(opts = {}) {
4
4
  const env = opts.env || process.env;
5
5
  const appName = String(opts.appName || env.SKS_CODEX_APP_NAME || 'ChatGPT');
@@ -73,7 +73,7 @@ export async function quitCodexApp(opts = {}) {
73
73
  };
74
74
  }
75
75
  export async function restartCodexApp(opts = {}) {
76
- const env = opts.env || process.env;
76
+ const env = stripRetiredDirectProviderEnv(opts.env || process.env);
77
77
  const appName = String(opts.appName || env.SKS_CODEX_APP_NAME || 'ChatGPT');
78
78
  const bundleId = String(opts.bundleId || env.SKS_CODEX_APP_BUNDLE_ID || 'com.openai.codex');
79
79
  if (opts.enabled === false || env.SKS_SKIP_CODEX_APP_RESTART === '1') {
@@ -96,22 +96,20 @@ export async function restartCodexApp(opts = {}) {
96
96
  ]
97
97
  };
98
98
  }
99
- const toolOutputRecovery = await inspectCodexLbCliLaunchRecovery({
99
+ const launchGuard = await inspectDesktopBridgeCliLaunchGuard({
100
100
  root: opts.root || process.cwd(),
101
101
  env,
102
- cliArgs: ['/app'],
103
- ...(opts.recoveryFetch ? { fetchImpl: opts.recoveryFetch } : {}),
104
- ...(opts.recoveryTimeoutMs === undefined ? {} : { timeoutMs: opts.recoveryTimeoutMs })
102
+ cliArgs: ['/app']
105
103
  });
106
- if (!toolOutputRecovery.ok) {
104
+ if (!launchGuard.ok) {
107
105
  return {
108
106
  schema: 'sks.codex-app-restart.v1',
109
107
  ok: false,
110
- status: 'tool_output_recovery_blocked',
108
+ status: 'desktop_bridge_launch_guard_blocked',
111
109
  app_name: appName,
112
110
  bundle_id: bundleId,
113
- blockers: toolOutputRecovery.blockers,
114
- tool_output_recovery: toolOutputRecovery
111
+ blockers: launchGuard.blockers,
112
+ desktop_bridge_launch_guard: launchGuard
115
113
  };
116
114
  }
117
115
  const appTarget = bundleId ? `application id ${JSON.stringify(bundleId)}` : `application ${JSON.stringify(appName)}`;
@@ -145,7 +143,7 @@ export async function restartCodexApp(opts = {}) {
145
143
  quit: { ok: true, code: quit.code, error: null },
146
144
  exit_wait: { ok: false, attempts, error: 'codex_app_exit_timeout' },
147
145
  blockers: ['codex_app_exit_timeout'],
148
- tool_output_recovery: toolOutputRecovery
146
+ desktop_bridge_launch_guard: launchGuard
149
147
  };
150
148
  }
151
149
  await sleep(Number(opts.delayMs ?? env.SKS_CODEX_APP_RESTART_DELAY_MS ?? 150));
@@ -168,7 +166,7 @@ export async function restartCodexApp(opts = {}) {
168
166
  ...(quitOk ? [] : ['codex_app_quit_failed']),
169
167
  ...(openOk ? [] : ['codex_app_open_failed'])
170
168
  ],
171
- tool_output_recovery: toolOutputRecovery
169
+ desktop_bridge_launch_guard: launchGuard
172
170
  };
173
171
  }
174
172
  function skipped(appName, reason) {
@@ -1,7 +1,6 @@
1
1
  export const SKS_MENUBAR_LABEL = 'com.sneakoscope.sks-menubar';
2
2
  export const CONTROL_CENTER_DOMAIN = 'com.apple.controlcenter';
3
3
  export const CONTROL_CENTER_PREFERRED_POSITION = 360;
4
- export const SECRET_LAUNCH_ENV_KEYS = ['CODEX_LB_API_KEY', 'OPENROUTER_API_KEY'];
5
4
  export const MENU_ITEMS = [
6
5
  'Open SKS Control Center',
7
6
  'Pending approvals',
@@ -22,16 +21,14 @@ export const NATIVE_SOURCE_FILES = [
22
21
  'MCPServersViewController.swift',
23
22
  'ProvidersViewController.swift',
24
23
  'ProvidersReliability.swift',
25
- 'ProvidersConnectTest.swift',
26
24
  'ProvidersRoutingTruth.swift',
27
- 'ProvidersFastMode.swift',
28
25
  'ProvidersOpenRouter.swift',
29
- 'ProvidersRoleModels.swift',
30
- 'ProvidersMultiProvider.swift',
26
+ 'ProvidersBridgeCatalog.swift',
31
27
  'RemoteCodingViewController.swift',
32
28
  'DiagnosticsViewController.swift',
33
29
  'SettingsViewController.swift',
34
30
  'OperationModels.swift',
31
+ 'ProviderRouteExplanation.swift',
35
32
  'OperationCoordinator.swift',
36
33
  'ProcessClient.swift',
37
34
  'ProcessExecutionState.swift',
@@ -2,6 +2,7 @@ import path from 'node:path';
2
2
  import { exists, nowIso, readJson, readText, runProcess, writeJsonAtomic } from '../../fsx.js';
3
3
  import { ensureConfinedDirectory, inspectConfinedPath, removeManagedPathVerified } from '../../managed-path-safety.js';
4
4
  const MENU_BAR_EXECUTABLE_SUFFIX = path.join('SKSMenuBar.app', 'Contents', 'MacOS', 'SKSMenuBar');
5
+ const MENU_BAR_PROCESS_DISCOVERY_TIMEOUT_MS = 5_000;
5
6
  export function projectMenuBarDuplicateInstallDirs(input) {
6
7
  const root = path.resolve(input.root);
7
8
  const home = path.resolve(input.paths.home);
@@ -187,7 +188,7 @@ async function runningMenuBarDuplicateInstallDirs(canonicalInstallDir, env) {
187
188
  ...(uid === null ? [] : ['-U', String(uid)]),
188
189
  '-f',
189
190
  'SKSMenuBar\\.app/Contents/MacOS/SKSMenuBar'
190
- ], { timeoutMs: 2_000, maxOutputBytes: 32 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
191
+ ], { timeoutMs: MENU_BAR_PROCESS_DISCOVERY_TIMEOUT_MS, maxOutputBytes: 32 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
191
192
  if (result.code !== 0)
192
193
  return [];
193
194
  const rows = String(result.stdout || '').split(/\r?\n/).filter(Boolean).map((line) => ({
@@ -208,7 +209,7 @@ async function runningMenuBarDuplicateInstallDirs(canonicalInstallDir, env) {
208
209
  unresolvedPids.join(','),
209
210
  '-o',
210
211
  'pid=,command='
211
- ], { timeoutMs: 2_000, maxOutputBytes: 64 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
212
+ ], { timeoutMs: MENU_BAR_PROCESS_DISCOVERY_TIMEOUT_MS, maxOutputBytes: 64 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
212
213
  if (processList.code === 0) {
213
214
  executablePaths.push(...String(processList.stdout || '')
214
215
  .split(/\r?\n/)
@@ -0,0 +1,23 @@
1
+ import { writeJsonAtomic } from '../../../fsx.js';
2
+ import { MENU_ITEMS } from '../constants.js';
3
+ import { sksMenuBarPaths } from '../paths.js';
4
+ import { defaultNextActions } from '../status.js';
5
+ export function baseResult(paths, apply, status, ok, actions, warnings) {
6
+ return {
7
+ schema: 'sks.codex-app-sks-menubar.v1', ok, apply, status, platform: process.platform,
8
+ app_path: paths.app_path, executable_path: paths.executable_path,
9
+ launch_agent_path: paths.launch_agent_path, action_script_path: paths.action_script_path,
10
+ build_stamp_path: paths.build_stamp_path, config_path: paths.config_path,
11
+ report_path: paths.report_path, menu_items: [...MENU_ITEMS], actions,
12
+ tcc_automation_status: 'unknown', next_actions: defaultNextActions(), blockers: [], warnings
13
+ };
14
+ }
15
+ export async function writeReport(reportPath, result) {
16
+ try {
17
+ await writeJsonAtomic(reportPath, result);
18
+ }
19
+ catch {
20
+ result.report_write_failed = true;
21
+ result.warnings.push('menubar_report_write_failed');
22
+ }
23
+ }
@@ -0,0 +1,28 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { exists, runProcess } from '../../../fsx.js';
5
+ export async function resolveSksEntryForInstall(explicit, root) {
6
+ const packaged = fileURLToPath(new URL('../../../../bin/sks.js', import.meta.url));
7
+ const requested = explicit ? path.resolve(explicit) : null;
8
+ const candidate = requested || packaged;
9
+ const found = await exists(candidate);
10
+ const relative = path.relative(path.resolve(root), candidate);
11
+ return {
12
+ requested, resolved: found ? candidate : null, packaged, exists: found,
13
+ project_local: relative === '' || (Boolean(relative) && !relative.startsWith('..') && !path.isAbsolute(relative)),
14
+ used_previous_script: false
15
+ };
16
+ }
17
+ export async function toolVersion(tool, args) {
18
+ const result = await runProcess(tool, args, { timeoutMs: 5_000, maxOutputBytes: 16 * 1024 }).catch(() => ({ code: 1, stdout: '', stderr: '' }));
19
+ return result.code === 0 ? String(result.stdout || result.stderr).trim().split(/\r?\n/)[0] || 'unknown' : 'unknown';
20
+ }
21
+ export function realUserHome() {
22
+ try {
23
+ return path.resolve(os.userInfo().homedir);
24
+ }
25
+ catch {
26
+ return path.resolve(os.homedir());
27
+ }
28
+ }