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
@@ -13,7 +13,7 @@ import { localizedFinalizationReason } from './language-preference.js';
13
13
  import { classifyToolError } from './evaluation.js';
14
14
  import { dollarCommand, managedSkillNamesForPrompt, stripVisibleDecisionAnswerBlocks } from './routes.js';
15
15
  import { coreEngineeringDirectiveReferenceText } from './lean-engineering-policy.js';
16
- import { scanAgentTextForRecursion } from './agents/agent-recursion-guard.js';
16
+ import { agentWorkerHookContext, agentWorkerHookRecursionDecision } from './agents/agent-recursion-guard.js';
17
17
  import { evaluateLoopContinuation } from './loops/loop-continuation-enforcer.js';
18
18
  import { diagnosticPromptAllowedDuringNoQuestions } from './routes/diagnostic-allowlist.js';
19
19
  import { maybeReconcileProjectSkillsPreflight } from './hooks-runtime/skill-reconcile-preflight.js';
@@ -45,7 +45,7 @@ import { loadHookPayload, normalizeHookResult, visibleHookMessage } from './hook
45
45
  import { codexGitActionMetadataSignal, codexGitActionMetadataText, compactAnswerContext, conversationId, explicitConversationId, extractCommand, extractLastMessage, extractUserPrompt, hookTurnId, looksLikeCodexGitAction, looksLikeCodexGitActionStopCompletion, looksLikeCodexUiSettingsEvent, looksLikeMadSksConfirmationPrompt, observedParentModel, toolFailed } from './hooks-runtime/payload-signals.js';
46
46
  import { interruptedToolOutputRecoveryBlockReason, missingToolOutputCallId, missingToolOutputCallIdFromPayload, quarantineMissingToolOutput, readToolOutputQuarantine } from './hooks-runtime/tool-output-quarantine.js';
47
47
  import { activeAuthoritativeSksSkillRefresh, activeGoalOverlayContext, attachAuthoritativeSksSkillContext, attachOfficialSubagentSpawnCompatibilityContext, authoritativeSksSkillAdmission, hookActiveSkillContextRefresh, isBlockingClarificationAwaiting, looksLikeExplicitActiveWorkflowReplacementPrompt, looksLikeClarificationCancel, routeBypassesActiveContext, routeIsGitOnly, selectedSksSkillNamesForActiveState, shouldPrepareFreshRouteOnActivePrompt, standaloneParentManagedSkillNames } from './hooks-runtime/hook-context.js';
48
- import { sealedSubagentRoutingContext, subagentRouteContext } from './hooks-runtime/subagent-context.js';
48
+ import { officialSubagentSkillGuardBinding, sealedSubagentRoutingContext, subagentRouteContext } from './hooks-runtime/subagent-context.js';
49
49
  export { loadHookPayload, normalizeHookResult };
50
50
  export { refreshOfficialSubagentCompletionArtifacts };
51
51
  export { honestModeGapLines, honestModeLoopbackBudgetExhausted } from './hooks-runtime/stop-finalization.js';
@@ -141,29 +141,36 @@ export async function evaluateHookPayload(name, payload = {}, opts = {}) {
141
141
  async function hookSubagentStart(root, state, payload = {}, sessionKey = null) {
142
142
  const artifactDir = officialSubagentArtifactDir(root, state, sessionKey);
143
143
  const sessionArtifactDir = officialSubagentArtifactDir(root, {}, sessionKey);
144
+ const skillGuardBinding = officialSubagentSkillGuardBinding(state);
145
+ const bindingIncomplete = Boolean(skillGuardBinding && (!String(skillGuardBinding.missionId || '').trim()
146
+ || !String(skillGuardBinding.workflowRunId || '').trim()));
144
147
  const artifactDirBlockers = [];
145
- const artifactDirSafe = await ensureOfficialSubagentArtifactDirConfined(root, artifactDir)
146
- .then(() => true)
147
- .catch(() => false);
148
- if (!artifactDirSafe)
148
+ const artifactDirSafe = skillGuardBinding
149
+ ? await ensureOfficialSubagentArtifactDirConfined(root, artifactDir)
150
+ .then(() => true)
151
+ .catch(() => false)
152
+ : true;
153
+ if (skillGuardBinding && !artifactDirSafe) {
149
154
  artifactDirBlockers.push('subagent_skill_availability_artifact_dir_unsafe');
150
- await clearSubagentSkillAvailabilityGuards(root, payload, artifactDir, {
151
- missionId: state?.mission_id,
152
- workflowRunId: state?.official_subagent_run_id
153
- }).catch(() => null);
155
+ }
156
+ if (skillGuardBinding) {
157
+ await clearSubagentSkillAvailabilityGuards(root, payload, artifactDir, skillGuardBinding).catch(() => null);
158
+ }
154
159
  const config = await readOfficialSubagentConfig(root);
155
160
  const budget = resolveSubagentThreadBudget({ configuredMaxThreads: config.maxThreads });
156
161
  const active = subagentRouteContext(state);
157
- const routingContext = artifactDirSafe ? await sealedSubagentRoutingContext(artifactDir, payload) : '';
158
- const resourceGuard = [
162
+ const routingContext = skillGuardBinding && artifactDirSafe
163
+ ? await sealedSubagentRoutingContext(artifactDir, payload)
164
+ : '';
165
+ const resourceGuard = skillGuardBinding ? [
159
166
  `SKS Naruto policy: max_threads frame budget is ${budget.maxThreads} (cap, not a spawn target).`,
160
167
  'GPT-5.6 four profiles are routing lanes, not an agent-count cap.',
161
168
  'Use max_depth=1. Naruto children must not spawn children.',
162
169
  'Do not duplicate an already assigned slice.',
163
170
  'Parallel writes require disjoint paths; serialize overlapping paths.',
164
171
  'Finish only your assigned slice, return a concise result, then stop so the Naruto parent can close this thread.'
165
- ].join(' ');
166
- const skillNames = selectedSksSkillNamesForActiveState(state);
172
+ ].join(' ') : '';
173
+ const skillNames = skillGuardBinding ? selectedSksSkillNamesForActiveState(state) : [];
167
174
  const resolution = skillNames.length
168
175
  ? await resolveManagedSkillSourcesForAdmission({
169
176
  root,
@@ -172,33 +179,12 @@ async function hookSubagentStart(root, state, payload = {}, sessionKey = null) {
172
179
  }).catch(() => null)
173
180
  : null;
174
181
  const skillBlockers = [
182
+ ...(bindingIncomplete ? ['subagent_skill_availability_guard_invalid'] : []),
175
183
  ...artifactDirBlockers,
176
184
  ...(skillNames.length ? authoritativeSksSkillResolutionBlockers(resolution) : [])
177
185
  ];
178
- try {
179
- await persistSubagentSkillAvailabilityBlocker({
180
- root,
181
- artifactDir,
182
- sessionArtifactDir,
183
- state,
184
- payload,
185
- blockers: skillBlockers
186
- });
187
- }
188
- catch (error) {
189
- const blocker = error instanceof Error
190
- && error.message === 'subagent_skill_availability_blocker_artifact_write_failed'
191
- ? 'subagent_skill_availability_blocker_artifact_write_failed'
192
- : 'subagent_skill_availability_guard_persistence_failed';
193
- skillBlockers.push(blocker);
194
- }
195
- if (artifactDirSafe) {
186
+ if (skillGuardBinding) {
196
187
  try {
197
- await recordAndRefreshSubagentEvidence(root, state, payload, 'SubagentStart', sessionKey);
198
- }
199
- catch {
200
- const lifecycleBlocker = await recordOfficialSubagentLifecycleCaptureFailure(artifactDir, state, payload, 'SubagentStart').catch(() => 'official_subagent_lifecycle_capture_failure_unpersisted');
201
- skillBlockers.push(lifecycleBlocker);
202
188
  await persistSubagentSkillAvailabilityBlocker({
203
189
  root,
204
190
  artifactDir,
@@ -206,10 +192,36 @@ async function hookSubagentStart(root, state, payload = {}, sessionKey = null) {
206
192
  state,
207
193
  payload,
208
194
  blockers: skillBlockers
209
- }).catch(() => {
210
- skillBlockers.push('subagent_skill_availability_guard_persistence_failed');
211
195
  });
212
196
  }
197
+ catch (error) {
198
+ const blocker = error instanceof Error
199
+ && error.message === 'subagent_skill_availability_blocker_artifact_write_failed'
200
+ ? 'subagent_skill_availability_blocker_artifact_write_failed'
201
+ : 'subagent_skill_availability_guard_persistence_failed';
202
+ skillBlockers.push(blocker);
203
+ }
204
+ }
205
+ if (skillGuardBinding && artifactDirSafe) {
206
+ try {
207
+ await recordAndRefreshSubagentEvidence(root, state, payload, 'SubagentStart', sessionKey);
208
+ }
209
+ catch {
210
+ const lifecycleBlocker = await recordOfficialSubagentLifecycleCaptureFailure(artifactDir, state, payload, 'SubagentStart').catch(() => 'official_subagent_lifecycle_capture_failure_unpersisted');
211
+ skillBlockers.push(lifecycleBlocker);
212
+ if (skillGuardBinding) {
213
+ await persistSubagentSkillAvailabilityBlocker({
214
+ root,
215
+ artifactDir,
216
+ sessionArtifactDir,
217
+ state,
218
+ payload,
219
+ blockers: skillBlockers
220
+ }).catch(() => {
221
+ skillBlockers.push('subagent_skill_availability_guard_persistence_failed');
222
+ });
223
+ }
224
+ }
213
225
  }
214
226
  const skillContext = skillBlockers.length
215
227
  ? renderSubagentSkillAvailabilityHandoff(skillBlockers)
@@ -559,28 +571,28 @@ async function consumeActiveOfficialWorkflowQueue(root, missionId, workflowRunId
559
571
  }
560
572
  async function hookPreTool(root, state, payload, noQuestion, sessionKey = null) {
561
573
  const artifactDir = officialSubagentArtifactDir(root, state, sessionKey);
562
- const activeBinding = {
563
- missionId: state?.mission_id,
564
- workflowRunId: state?.official_subagent_run_id
565
- };
566
- const evaluateSkillAvailabilityBlock = () => subagentSkillAvailabilityPreToolBlockReason(root, payload, artifactDir, activeBinding).catch((error) => {
567
- const code = error instanceof Error && error.message === 'subagent_skill_availability_guard_invalid'
568
- ? 'subagent_skill_availability_guard_invalid'
569
- : 'subagent_skill_availability_guard_check_failed';
570
- return `SKS blocked this child tool call because managed skill availability failed (${code}). Return the blocker to the root parent without using tools.`;
571
- });
572
- let skillAvailabilityBlock = await evaluateSkillAvailabilityBlock();
573
- if (isSubagentSkillAvailabilityAdmissionMissingReason(skillAvailabilityBlock)) {
574
- const recovered = await recoverResumedOfficialSubagentSkillAvailabilityAdmission({
575
- root,
576
- payload,
577
- artifactDir,
578
- sessionArtifactDir: officialSubagentArtifactDir(root, {}, sessionKey),
579
- activeBinding,
580
- skillNames: selectedSksSkillNamesForActiveState(state)
581
- }).catch(() => false);
582
- if (recovered)
583
- skillAvailabilityBlock = await evaluateSkillAvailabilityBlock();
574
+ const activeBinding = officialSubagentSkillGuardBinding(state, { allowClosedOfficialChild: true });
575
+ let skillAvailabilityBlock = null;
576
+ if (activeBinding) {
577
+ const evaluateSkillAvailabilityBlock = () => subagentSkillAvailabilityPreToolBlockReason(root, payload, artifactDir, activeBinding).catch((error) => {
578
+ const code = error instanceof Error && error.message === 'subagent_skill_availability_guard_invalid'
579
+ ? 'subagent_skill_availability_guard_invalid'
580
+ : 'subagent_skill_availability_guard_check_failed';
581
+ return `SKS blocked this child tool call because managed skill availability failed (${code}). Return the blocker to the root parent without using tools.`;
582
+ });
583
+ skillAvailabilityBlock = await evaluateSkillAvailabilityBlock();
584
+ if (isSubagentSkillAvailabilityAdmissionMissingReason(skillAvailabilityBlock)) {
585
+ const recovered = await recoverResumedOfficialSubagentSkillAvailabilityAdmission({
586
+ root,
587
+ payload,
588
+ artifactDir,
589
+ sessionArtifactDir: officialSubagentArtifactDir(root, {}, sessionKey),
590
+ activeBinding,
591
+ skillNames: selectedSksSkillNamesForActiveState(state)
592
+ }).catch(() => false);
593
+ if (recovered)
594
+ skillAvailabilityBlock = await evaluateSkillAvailabilityBlock();
595
+ }
584
596
  }
585
597
  if (skillAvailabilityBlock) {
586
598
  return { decision: 'block', permissionDecision: 'deny', reason: skillAvailabilityBlock };
@@ -653,32 +665,6 @@ async function parentWaveGuidanceContext(root, state = {}, sessionKey = null) {
653
665
  return '';
654
666
  return renderWaveParentGuidance(guidance);
655
667
  }
656
- function agentWorkerHookRecursionDecision(state = {}, payload = {}, command = '') {
657
- if (!agentWorkerHookContext(state, payload))
658
- return null;
659
- const guard = scanAgentTextForRecursion(command);
660
- if (guard.ok)
661
- return null;
662
- return {
663
- decision: 'block',
664
- permissionDecision: 'deny',
665
- reason: `Agent command recursion guard blocked nested SKS route command in Codex PreToolUse hook: ${guard.violations.join(', ')}`
666
- };
667
- }
668
- function agentWorkerHookContext(state = {}, payload = {}) {
669
- const env = {
670
- ...(payload.env || {}),
671
- ...(payload.tool_input?.env || {}),
672
- ...(payload.toolInput?.env || {}),
673
- ...(payload.input?.env || {}),
674
- ...(payload.tool?.input?.env || {})
675
- };
676
- void state;
677
- return Boolean(String(env.SKS_AGENT_WORKER || '') === '1'
678
- || String(env.SKS_DISABLE_ROUTE_RECURSION || '') === '1'
679
- || payload.agent_worker === true
680
- || payload.agentWorker === true);
681
- }
682
668
  async function hookPostTool(root, state, payload, noQuestion, sessionKey = null) {
683
669
  state = { ...state, _session_key: state?._session_key || sessionKey };
684
670
  await Promise.all([
@@ -3,8 +3,8 @@ import fsp from 'node:fs/promises';
3
3
  import { ensureDir, exists, nowIso, projectRoot, readJson, writeJsonAtomic } from '../fsx.js';
4
4
  import { sha256File, imageDimensions } from '../wiki-image/image-hash.js';
5
5
  import { detectImagegenCapability } from '../imagegen/imagegen-capability.js';
6
- import { resolveCodexLbImagegenTarget } from '../imagegen/codex-lb-imagegen-target.js';
7
- import { CODEX_LB_PROVIDER_IMAGEGEN_EVIDENCE_CLASS, CODEX_LB_PROVIDER_OUTPUT_SOURCE, NON_CODEX_API_FALLBACK_EVIDENCE_CLASS } from '../imagegen/imagegen-evidence.js';
6
+ import { DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE, resolveDesktopBridgeImagegenTarget } from '../imagegen/desktop-bridge-imagegen-target.js';
7
+ import { CODEX_LB_PROVIDER_IMAGEGEN_EVIDENCE_CLASS, CODEX_LB_PROVIDER_OUTPUT_SOURCE, MOCK_FIXTURE_EVIDENCE_CLASS, NON_CODEX_API_FALLBACK_EVIDENCE_CLASS } from '../imagegen/imagegen-evidence.js';
8
8
  import { validateGptImage2Request } from '../imagegen/gpt-image-2-request-validator.js';
9
9
  import { parseResponsesSsePayload } from '../responses-stream.js';
10
10
  import { withResponsesRetry } from '../responses-retry-policy.js';
@@ -14,6 +14,7 @@ import { registerImageArtifact } from '../image/image-artifact-registry.js';
14
14
  const DEFAULT_OPENAI_IMAGE_EDITS_ENDPOINT = 'https://api.openai.com/v1/images/edits';
15
15
  export const DEFAULT_IMAGEGEN_FETCH_TIMEOUT_MS = 180000;
16
16
  const responseDeadlines = new WeakMap();
17
+ const runtimeDesktopBridgeTargets = new WeakSet();
17
18
  export function buildCalloutPrompt(sourceScreenId, context = {}) {
18
19
  return [
19
20
  'Review this UI screenshot as a senior Toss UI/UX product designer.',
@@ -298,12 +299,11 @@ export function createFakeImagegenAdapter(opts = {}) {
298
299
  }
299
300
  export function createOpenAIImagesApiAdapter(opts = {}) {
300
301
  const apiKey = opts.apiKey || process.env.OPENAI_API_KEY || null;
301
- const allowCodexLbApiFallback = opts.allowCodexLbApiFallback === true || process.env.SKS_IMAGEGEN_ALLOW_CODEX_LB_API_FALLBACK === '1';
302
- const codexLb = allowCodexLbApiFallback && opts.codexLb?.available === true ? opts.codexLb : null;
302
+ const desktopBridgeTarget = trustedDesktopBridgeTarget(opts.desktopBridgeTarget);
303
303
  return {
304
304
  surface: 'openai_images_api',
305
305
  model: 'gpt-image-2',
306
- available: Boolean(apiKey || codexLb),
306
+ available: Boolean(apiKey || desktopBridgeTarget?.selected || desktopBridgeTarget?.model),
307
307
  async generateCalloutReview(input) {
308
308
  const started = Date.now();
309
309
  await ensureDir(input.output_dir);
@@ -311,15 +311,19 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
311
311
  const responseArtifact = path.join(input.output_dir, 'image-ux-gpt-image-2-response.json');
312
312
  const sourcePath = path.resolve(input.source_image_path);
313
313
  const sourceSha = await sha256File(sourcePath);
314
- const auth = await resolveImagesApiAuth({ ...opts, apiKey, codexLb });
315
- const useResponsesImageTool = auth.auth_source === 'CODEX_LB_API_KEY' && Boolean(auth.responses_endpoint);
314
+ const auth = await resolveImagesApiAuth({ ...opts, apiKey, desktopBridgeTarget });
315
+ const useResponsesImageTool = auth.auth_source === 'DESKTOP_BRIDGE_LOOPBACK' && Boolean(auth.responses_endpoint);
316
316
  const effectiveEndpoint = useResponsesImageTool ? auth.responses_endpoint : auth.endpoint;
317
317
  const responsesModel = String(auth.responses_model || '');
318
- const codexLbProviderSelected = useResponsesImageTool && (opts.codexLbTarget?.selected === true || codexLb?.selected === true);
319
- const responsesEvidenceClass = codexLbProviderSelected
320
- ? CODEX_LB_PROVIDER_IMAGEGEN_EVIDENCE_CLASS
318
+ const desktopBridgeSelected = useResponsesImageTool && auth.desktop_bridge_selected === true;
319
+ const responsesEvidenceClass = desktopBridgeSelected
320
+ ? auth.live_evidence_allowed === true
321
+ ? CODEX_LB_PROVIDER_IMAGEGEN_EVIDENCE_CLASS
322
+ : MOCK_FIXTURE_EVIDENCE_CLASS
321
323
  : NON_CODEX_API_FALLBACK_EVIDENCE_CLASS;
322
- const responsesOutputSource = codexLbProviderSelected ? CODEX_LB_PROVIDER_OUTPUT_SOURCE : null;
324
+ const responsesOutputSource = desktopBridgeSelected && auth.live_evidence_allowed === true
325
+ ? CODEX_LB_PROVIDER_OUTPUT_SOURCE
326
+ : null;
323
327
  const validation = await validateGptImage2Request({
324
328
  provider: 'openai_images_api',
325
329
  endpoint: String(effectiveEndpoint || ''),
@@ -333,7 +337,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
333
337
  await writeJsonAtomic(requestArtifact, {
334
338
  schema: 'sks.image-ux-gpt-image-2-request.v1',
335
339
  created_at: nowIso(),
336
- provider: useResponsesImageTool ? 'openai_responses_image_generation' : 'openai_images_api',
340
+ provider: useResponsesImageTool ? 'desktop_bridge_responses_image_generation' : 'openai_images_api',
337
341
  endpoint: effectiveEndpoint,
338
342
  auth_source: auth.auth_source,
339
343
  auth_transport: auth.auth_transport,
@@ -363,7 +367,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
363
367
  });
364
368
  return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker: 'gpt_image_2_request_validation_failed', provider: 'openai_images_api', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
365
369
  }
366
- if (auth.blocker || !auth.apiKey) {
370
+ if (auth.blocker || (!useResponsesImageTool && !auth.apiKey)) {
367
371
  const blocked = {
368
372
  schema: 'sks.image-ux-gpt-image-2-response.v1',
369
373
  created_at: nowIso(),
@@ -373,8 +377,8 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
373
377
  ok: false,
374
378
  status: 'blocked',
375
379
  blocker: auth.blocker,
376
- setup_guidance: auth.auth_source === 'CODEX_LB_API_KEY'
377
- ? 'Repair the selected codex-lb credential binding. Completed output from a selected provider can satisfy full evidence; codex-lb used only as a fallback while another provider is selected cannot.'
380
+ setup_guidance: auth.auth_source === 'DESKTOP_BRIDGE_LOOPBACK'
381
+ ? auth.setup_guidance || DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE
378
382
  : 'Set OPENAI_API_KEY only for an explicit non-Codex Images API fallback, or attach a real Codex App $imagegen output image for full SKS verification.',
379
383
  local_only: true
380
384
  };
@@ -386,16 +390,16 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
386
390
  await writeJsonAtomic(responseArtifact, {
387
391
  schema: 'sks.image-ux-gpt-image-2-response.v1',
388
392
  created_at: nowIso(),
389
- provider: 'openai_responses_image_generation',
393
+ provider: 'desktop_bridge_responses_image_generation',
390
394
  evidence_class: 'non_codex_api_fallback',
391
395
  model: 'gpt-image-2',
392
396
  ok: false,
393
397
  status: 'blocked',
394
398
  blocker,
395
- setup_guidance: 'Set SKS_IMAGEGEN_RESPONSES_MODEL to a model available through the configured Responses provider; SKS does not hardcode a text model.',
399
+ setup_guidance: DESKTOP_BRIDGE_IMAGEGEN_RECOVERY_GUIDANCE,
396
400
  local_only: true
397
401
  });
398
- return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker, provider: 'openai_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
402
+ return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker, provider: 'desktop_bridge_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
399
403
  }
400
404
  try {
401
405
  if (useResponsesImageTool) {
@@ -404,9 +408,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
404
408
  const response = await fetchWithTimeout(effectiveEndpoint, {
405
409
  method: 'POST',
406
410
  headers: {
407
- ...(auth.auth_transport === 'x-codex-lb-api-key'
408
- ? { 'X-Codex-LB-API-Key': auth.apiKey }
409
- : { authorization: `Bearer ${auth.apiKey}` }),
411
+ 'x-sks-model': responsesModel,
410
412
  'content-type': 'application/json'
411
413
  },
412
414
  body: JSON.stringify({
@@ -427,40 +429,41 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
427
429
  }, imagegenRetryOptions(opts));
428
430
  const { response, payload } = attemptResult;
429
431
  if (!response.ok) {
430
- await writeJsonAtomic(responseArtifact, redactedImagegenResponse(payload, false, Date.now() - started, 'openai_responses_image_generation', { attempts, retry_log }));
431
- return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker: imagegenErrorKind(payload), provider: 'openai_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
432
+ await writeJsonAtomic(responseArtifact, redactedImagegenResponse(payload, false, Date.now() - started, 'desktop_bridge_responses_image_generation', { attempts, retry_log }));
433
+ return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker: imagegenErrorKind(payload), provider: 'desktop_bridge_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
432
434
  }
433
435
  if (payload?.error) {
434
- await writeJsonAtomic(responseArtifact, redactedImagegenResponse(payload, false, Date.now() - started, 'openai_responses_image_generation'));
435
- return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker: imagegenErrorKind(payload), provider: 'openai_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
436
+ await writeJsonAtomic(responseArtifact, redactedImagegenResponse(payload, false, Date.now() - started, 'desktop_bridge_responses_image_generation'));
437
+ return { ok: false, status: 'blocked', generated_image_path: null, output_id: null, blocker: imagegenErrorKind(payload), provider: 'desktop_bridge_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
436
438
  }
437
439
  const generated = findResponsesImageGenerationOutput(payload);
438
440
  if (!generated?.b64) {
439
- await writeJsonAtomic(responseArtifact, redactedImagegenResponse({ ...payload, blocker: 'missing_b64_image_output' }, false, Date.now() - started, 'openai_responses_image_generation'));
440
- return { ok: false, status: 'blocked', generated_image_path: null, output_id: generated?.id || null, blocker: 'missing_b64_image_output', provider: 'openai_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
441
+ await writeJsonAtomic(responseArtifact, redactedImagegenResponse({ ...payload, blocker: 'missing_b64_image_output' }, false, Date.now() - started, 'desktop_bridge_responses_image_generation'));
442
+ return { ok: false, status: 'blocked', generated_image_path: null, output_id: generated?.id || null, blocker: 'missing_b64_image_output', provider: 'desktop_bridge_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, latency_ms: Date.now() - started };
441
443
  }
442
444
  const out = path.join(input.output_dir, `gpt-image-2-callout-${Date.now()}.png`);
443
445
  await fsp.writeFile(out, Buffer.from(String(generated.b64), 'base64'));
444
446
  const meta = await generatedImageMetadata(process.cwd(), out, {
445
447
  source_screen_id: input.source_screen_id,
446
- provider_surface: 'openai_responses_image_generation',
448
+ provider_surface: 'desktop_bridge_responses_image_generation',
447
449
  output_id: generated.id || payload?.id || null,
448
450
  evidence_class: responsesEvidenceClass,
449
451
  output_source: responsesOutputSource,
450
- real_generated: true
452
+ real_generated: auth.live_evidence_allowed === true,
453
+ mock: auth.live_evidence_allowed !== true
451
454
  });
452
- const imageContract = await writeGeneratedImagePathContract(input, out, 'openai_responses_image_generation').catch(() => null);
455
+ const imageContract = await writeGeneratedImagePathContract(input, out, 'desktop_bridge_responses_image_generation').catch(() => null);
453
456
  await writeJsonAtomic(responseArtifact, {
454
457
  schema: 'sks.image-ux-gpt-image-2-response.v1',
455
458
  created_at: nowIso(),
456
- provider: 'openai_responses_image_generation',
459
+ provider: 'desktop_bridge_responses_image_generation',
457
460
  evidence_class: responsesEvidenceClass,
458
461
  model: 'gpt-image-2',
459
462
  responses_model: responsesModel,
460
463
  responses_model_source: auth.responses_model_source || null,
461
464
  auth_source: auth.auth_source,
462
- api_key_source: auth.api_key_source || null,
463
- codex_lb_provider_selected: codexLbProviderSelected,
465
+ desktop_bridge_selected: desktopBridgeSelected,
466
+ desktop_bridge_route_provider: auth.route_provider_id || null,
464
467
  ok: true,
465
468
  status: 'generated',
466
469
  output_image_path: out,
@@ -477,7 +480,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
477
480
  token_cost_metadata: payload?.usage || null,
478
481
  local_only: true
479
482
  });
480
- return { ok: true, status: 'generated', generated_image_path: out, output_id: meta.output_id, blocker: null, provider: 'openai_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, image_artifact_path_contract: imageContract?.artifact_path || null, latency_ms: Date.now() - started };
483
+ return { ok: true, status: 'generated', generated_image_path: out, output_id: meta.output_id, blocker: null, provider: 'desktop_bridge_responses_image_generation', request_artifact: requestArtifact, response_artifact: responseArtifact, image_artifact_path_contract: imageContract?.artifact_path || null, latency_ms: Date.now() - started };
481
484
  }
482
485
  const sourceBytes = await fsp.readFile(sourcePath);
483
486
  const qualityParam = imagegenQualityParam(opts);
@@ -538,7 +541,7 @@ export function createOpenAIImagesApiAdapter(opts = {}) {
538
541
  return { ok: true, status: 'generated', generated_image_path: out, output_id: meta.output_id, blocker: null, provider: 'openai_images_api', request_artifact: requestArtifact, response_artifact: responseArtifact, image_artifact_path_contract: imageContract?.artifact_path || null, latency_ms: Date.now() - started };
539
542
  }
540
543
  catch (err) {
541
- const provider = useResponsesImageTool ? 'openai_responses_image_generation' : 'openai_images_api';
544
+ const provider = useResponsesImageTool ? 'desktop_bridge_responses_image_generation' : 'openai_images_api';
542
545
  const payload = { error: { message: err instanceof Error ? err.message : String(err) } };
543
546
  const response = redactedImagegenResponse(payload, false, Date.now() - started, provider);
544
547
  await writeJsonAtomic(responseArtifact, response);
@@ -586,22 +589,20 @@ export async function generateGptImage2CalloutReview(input, opts = {}) {
586
589
  return createFakeImagegenAdapter({ ...(opts.fakeAdapter || {}), mockContext: true }).generateCalloutReview(input);
587
590
  }
588
591
  const capability = await detectImagegenCapability(opts.capability || {}).catch(() => null);
589
- const codexLbTarget = opts.codexLbTarget || await resolveCodexLbImagegenTarget(codexLbTargetInputs(opts.capability)).catch(() => null);
590
- const explicitDisableCodexLbFallback = opts.allowCodexLbApiFallback === false || process.env.SKS_IMAGEGEN_ALLOW_CODEX_LB_API_FALLBACK === '0';
591
- const allowCodexLbApiFallback = !explicitDisableCodexLbFallback && (opts.allowCodexLbApiFallback === true
592
- || process.env.SKS_IMAGEGEN_ALLOW_CODEX_LB_API_FALLBACK === '1'
593
- || codexLbTarget?.selected === true);
592
+ const suppliedTarget = opts.desktopBridgeTarget
593
+ ? trustedDesktopBridgeTarget(opts.desktopBridgeTarget)
594
+ : null;
595
+ const desktopBridgeTarget = suppliedTarget || await resolveDesktopBridgeImagegenTarget(desktopBridgeTargetInputs(opts.capability, opts.openai || opts)).catch(() => null);
596
+ if (!suppliedTarget && desktopBridgeTarget?.status_source === 'runtime') {
597
+ runtimeDesktopBridgeTargets.add(desktopBridgeTarget);
598
+ }
599
+ const managedBridgeRequested = Boolean(desktopBridgeTarget?.selected || desktopBridgeTarget?.model);
594
600
  const allowApiFallback = (opts.allowApiFallback === true
595
601
  || process.env.SKS_IMAGEGEN_ALLOW_API_FALLBACK === '1'
596
- || allowCodexLbApiFallback);
602
+ || managedBridgeRequested);
597
603
  const openaiOptions = {
598
604
  ...(opts.openai || {}),
599
- codexLb: allowCodexLbApiFallback ? opts.openai?.codexLb || capability?.codex_lb || null : null,
600
- codexLbTarget,
601
- codexLbAuthTransport: capability?.codex_lb?.cli_contract === true
602
- ? 'authorization-bearer'
603
- : codexLbTarget?.auth_transport,
604
- allowCodexLbApiFallback
605
+ desktopBridgeTarget
605
606
  };
606
607
  const codexAdapter = createCodexAppImagegenAdapter({
607
608
  ...(opts.codexApp || {}),
@@ -612,16 +613,18 @@ export async function generateGptImage2CalloutReview(input, opts = {}) {
612
613
  return codexResult;
613
614
  return createOpenAIImagesApiAdapter(openaiOptions).generateCalloutReview(input);
614
615
  }
615
- function codexLbTargetInputs(source = {}) {
616
- const inputs = {};
616
+ function desktopBridgeTargetInputs(source = {}, request = {}) {
617
+ const inputs = {
618
+ explicitModel: String(request.responsesModel || source?.env?.SKS_IMAGEGEN_RESPONSES_MODEL || '').trim() || null
619
+ };
617
620
  if (source?.home)
618
621
  inputs.home = source.home;
619
- if (source?.codexHome)
620
- inputs.codexHome = source.codexHome;
621
622
  if (source?.env)
622
623
  inputs.env = source.env;
623
- if (typeof source?.configText === 'string')
624
- inputs.configText = source.configText;
624
+ if (source?.desktopBridgeStatus !== undefined)
625
+ inputs.desktopBridgeStatus = source.desktopBridgeStatus;
626
+ if (source?.desktopBridgeStatusImpl)
627
+ inputs.desktopBridgeStatusImpl = source.desktopBridgeStatusImpl;
625
628
  return inputs;
626
629
  }
627
630
  function imagegenMockContext(opts = {}) {
@@ -638,64 +641,75 @@ export function imagegenCapabilityBlocker(surface = 'Codex App $imagegen') {
638
641
  blocker: 'imagegen_capability_missing',
639
642
  surface,
640
643
  model: 'gpt-image-2',
641
- guidance: 'Run the request with gpt-image-2 through Codex App $imagegen or a selected, ready codex-lb provider and bind the completed generated image path. OPENAI_API_KEY, or codex-lb used while another provider is selected, remains non-Codex fallback evidence. SKS must not fabricate or substitute a text-only review.'
644
+ guidance: 'Run the request with gpt-image-2 through Codex App $imagegen, or provide an explicit model routed by the verified managed Desktop Bridge. Direct provider credentials remain non-Codex fallback evidence. SKS must not fabricate or substitute a text-only review.'
642
645
  };
643
646
  }
644
647
  async function resolveImagesApiAuth(opts = {}) {
645
- const codexLb = opts.codexLb?.available === true ? opts.codexLb : null;
646
- const target = opts.codexLbTarget || (codexLb
647
- ? await resolveCodexLbImagegenTarget(codexLbTargetInputs(opts)).catch(() => null)
648
- : null);
649
- if (target?.selected === true)
650
- return codexLbImagesApiAuth(opts, codexLb, target);
648
+ const target = trustedDesktopBridgeTarget(opts.desktopBridgeTarget);
649
+ if (target && (target.selected || target.model))
650
+ return desktopBridgeImagesApiAuth(target);
651
651
  const openAiKey = String(opts.apiKey || process.env.OPENAI_API_KEY || '').trim();
652
652
  if (openAiKey) {
653
653
  return {
654
654
  apiKey: openAiKey,
655
655
  auth_source: 'OPENAI_API_KEY',
656
656
  auth_transport: 'authorization-bearer',
657
- api_key_source: null,
658
657
  responses_model: responsesImagegenModel(opts),
659
658
  responses_model_source: responsesImagegenModel(opts) ? 'explicit' : null,
660
659
  endpoint: imageEditsEndpoint(opts.baseUrl || 'https://api.openai.com/v1'),
661
660
  responses_endpoint: responsesEndpoint(opts.baseUrl || 'https://api.openai.com/v1'),
662
- blocker: null
663
- };
664
- }
665
- if (!codexLb) {
666
- return {
667
- apiKey: null,
668
- auth_source: null,
669
- auth_transport: 'authorization-bearer',
670
- api_key_source: null,
671
- responses_model: responsesImagegenModel(opts),
672
- responses_model_source: null,
673
- endpoint: imageEditsEndpoint(opts.baseUrl || 'https://api.openai.com/v1'),
674
- responses_endpoint: responsesEndpoint(opts.baseUrl || 'https://api.openai.com/v1'),
675
- blocker: 'openai_api_key_missing'
661
+ blocker: null,
662
+ desktop_bridge_selected: false,
663
+ route_provider_id: null,
664
+ live_evidence_allowed: false,
665
+ setup_guidance: null
676
666
  };
677
667
  }
678
- return codexLbImagesApiAuth(opts, codexLb, target);
668
+ return {
669
+ apiKey: null,
670
+ auth_source: null,
671
+ auth_transport: 'authorization-bearer',
672
+ responses_model: responsesImagegenModel(opts),
673
+ responses_model_source: null,
674
+ endpoint: imageEditsEndpoint(opts.baseUrl || 'https://api.openai.com/v1'),
675
+ responses_endpoint: responsesEndpoint(opts.baseUrl || 'https://api.openai.com/v1'),
676
+ blocker: 'openai_api_key_missing',
677
+ desktop_bridge_selected: false,
678
+ route_provider_id: null,
679
+ live_evidence_allowed: false,
680
+ setup_guidance: null
681
+ };
679
682
  }
680
- function codexLbImagesApiAuth(opts, codexLb, target) {
681
- const envKey = codexLb?.env_key || 'CODEX_LB_API_KEY';
682
- const codexLbKey = String(opts.codexLbApiKey || target?.api_key || '').trim();
683
- const baseUrl = target?.base_url || codexLb?.base_url || opts.baseUrl || '';
684
- const blocker = !baseUrl
685
- ? 'codex_lb_base_url_missing'
686
- : codexLbKey
687
- ? null
688
- : target?.blocker || 'codex_lb_api_key_missing';
683
+ function desktopBridgeImagesApiAuth(target) {
684
+ return {
685
+ apiKey: null,
686
+ auth_source: 'DESKTOP_BRIDGE_LOOPBACK',
687
+ auth_transport: 'loopback-route',
688
+ responses_model: target.model || '',
689
+ responses_model_source: target.model_source,
690
+ endpoint: null,
691
+ responses_endpoint: target.endpoint,
692
+ blocker: target.blocker,
693
+ desktop_bridge_selected: target.selected,
694
+ route_provider_id: target.provider_id,
695
+ live_evidence_allowed: target.live_evidence_allowed,
696
+ setup_guidance: target.setup_guidance
697
+ };
698
+ }
699
+ function trustedDesktopBridgeTarget(value) {
700
+ if (!value || typeof value !== 'object')
701
+ return null;
702
+ const target = value;
703
+ const runtimeTrusted = runtimeDesktopBridgeTargets.has(target);
704
+ if (runtimeTrusted
705
+ && target.status_source === 'runtime'
706
+ && target.bridge_verified === true
707
+ && target.live_evidence_allowed === true)
708
+ return target;
689
709
  return {
690
- apiKey: codexLbKey || null,
691
- auth_source: envKey,
692
- auth_transport: opts.codexLbAuthTransport || target?.auth_transport || 'authorization-bearer',
693
- api_key_source: target?.api_key_source || null,
694
- responses_model: responsesImagegenModel(opts) || target?.model || '',
695
- responses_model_source: responsesImagegenModel(opts) ? 'explicit' : target?.model_source || null,
696
- endpoint: baseUrl ? imageEditsEndpoint(baseUrl) : null,
697
- responses_endpoint: baseUrl ? responsesEndpoint(baseUrl) : null,
698
- blocker
710
+ ...target,
711
+ status_source: 'injected_fixture',
712
+ live_evidence_allowed: false
699
713
  };
700
714
  }
701
715
  function imageEditsEndpoint(baseUrl = '') {