sneakoscope 7.0.2 → 7.0.5

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 (598) hide show
  1. package/README.md +9 -7
  2. package/config/codex-releases/{rust-v0.144.5.json → rust-v0.145.0.json} +14 -8
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/bin/sks-dispatch.js +0 -3
  6. package/dist/cli/command-manifest-lite.js +1 -2
  7. package/dist/cli/command-registry.js +0 -4
  8. package/dist/cli/global-mode-router.js +5 -12
  9. package/dist/cli/install-helpers-codex-lb-chain.js +24 -2
  10. package/dist/cli/install-helpers-codex-lb-config.js +10 -25
  11. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -3
  12. package/dist/cli/install-helpers-codex-lb-selftest.js +0 -17
  13. package/dist/cli/install-helpers-install-support.js +1 -2
  14. package/dist/cli/install-helpers.js +83 -99
  15. package/dist/cli/router.js +22 -31
  16. package/dist/commands/codex-app.js +20 -2
  17. package/dist/commands/codex-lb.js +176 -22
  18. package/dist/commands/codex.js +3 -8
  19. package/dist/commands/conflicts.js +26 -3
  20. package/dist/commands/doctor.js +26 -31
  21. package/dist/commands/perf.js +5 -1
  22. package/dist/commands/zellij-slot-column-anchor.js +0 -2
  23. package/dist/commands/zellij-slot-pane.js +0 -7
  24. package/dist/commands/zellij.js +0 -2
  25. package/dist/config/skills-manifest.json +52 -52
  26. package/dist/core/agent-bridge/agent-manifest.js +192 -1
  27. package/dist/core/agent-bridge/agent-mode.js +0 -5
  28. package/dist/core/agent-bridge/host-capability-policy.js +189 -0
  29. package/dist/core/agent-bridge/host-capability-runtime.js +1395 -0
  30. package/dist/core/agent-bridge/mcp-server.js +1 -11
  31. package/dist/core/agents/agent-effort-policy.js +7 -10
  32. package/dist/core/agents/agent-orchestrator.js +0 -4
  33. package/dist/core/agents/agent-proof-evidence.js +0 -2
  34. package/dist/core/agents/agent-roster.js +6 -5
  35. package/dist/core/agents/agent-runner-ollama.js +0 -3
  36. package/dist/core/agents/agent-scheduler.js +7 -10
  37. package/dist/core/agents/agent-schema.js +3 -1
  38. package/dist/core/agents/agent-task-graph.js +4 -1
  39. package/dist/core/agents/agent-work-partition.js +4 -2
  40. package/dist/core/agents/native-cli-worker-runtime.js +5 -17
  41. package/dist/core/agents/work-partition/repo-inventory.js +0 -2
  42. package/dist/core/auto-review.js +8 -14
  43. package/dist/core/bench.js +0 -14
  44. package/dist/core/code-structure.js +0 -3
  45. package/dist/core/codex/agent-config-file-repair.js +0 -8
  46. package/dist/core/codex/codex-cli-update.js +122 -20
  47. package/dist/core/codex/codex-config-eperm-repair.js +0 -4
  48. package/dist/core/codex/codex-config-guard.js +0 -3
  49. package/dist/core/codex/codex-config-readability.js +0 -13
  50. package/dist/core/codex/codex-project-config-policy.js +0 -33
  51. package/dist/core/codex/codex-startup-config-postcheck.js +5 -0
  52. package/dist/core/codex/official-goal-mode.js +0 -2
  53. package/dist/core/codex-app/codex-agent-type-probe.js +31 -24
  54. package/dist/core/codex-app/codex-app-fast-ui-repair.js +5 -7
  55. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +44 -7
  56. package/dist/core/codex-app/glm-model-profile.js +1 -1
  57. package/dist/core/codex-app/glm-profile-installer.js +40 -41
  58. package/dist/core/codex-app/glm-profile-schema.js +7 -11
  59. package/dist/core/codex-app/menubar/constants.js +1 -0
  60. package/dist/core/codex-app/menubar/launch-agent.js +37 -1
  61. package/dist/core/codex-app/openrouter-activate.js +152 -0
  62. package/dist/core/codex-app/openrouter-provider.js +82 -0
  63. package/dist/core/codex-app/sks-menubar.js +0 -1
  64. package/dist/core/codex-app.js +14 -32
  65. package/dist/core/codex-compat/codex-capability-matrix.js +208 -0
  66. package/dist/core/codex-compat/codex-hook-output-builders.js +9 -1
  67. package/dist/core/codex-compat/codex-hook-output-normalizer.js +1 -1
  68. package/dist/core/codex-compat/codex-hook-semantic-validator.js +3 -2
  69. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -2
  70. package/dist/core/codex-compat/codex-release-manifest.js +15 -8
  71. package/dist/core/codex-compat/codex-version-policy.js +77 -15
  72. package/dist/core/codex-control/codex-0144-capability.js +1 -1
  73. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -3
  74. package/dist/core/codex-control/codex-reliability-shield.js +0 -8
  75. package/dist/core/codex-control/codex-sdk-adapter.js +0 -3
  76. package/dist/core/codex-control/codex-sdk-config-policy.js +0 -2
  77. package/dist/core/codex-control/codex-sdk-env-policy.js +61 -16
  78. package/dist/core/codex-control/codex-task-runner.js +0 -7
  79. package/dist/core/codex-control/codex-thread-registry.js +0 -4
  80. package/dist/core/codex-lb/codex-lb-env.js +133 -24
  81. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -4
  82. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
  83. package/dist/core/codex-model-guard.js +0 -14
  84. package/dist/core/codex-native/codex-native-feature-broker.js +67 -22
  85. package/dist/core/codex-native/codex-native-interop-policy.js +81 -9
  86. package/dist/core/codex-native/confined-report-writer.js +21 -0
  87. package/dist/core/codex-native/core-skill-integrity.js +169 -20
  88. package/dist/core/codex-native/project-skill-dedupe.js +55 -13
  89. package/dist/core/codex-native/skill-registry-ledger.js +137 -16
  90. package/dist/core/codex-native/sks-skill-paths.js +185 -0
  91. package/dist/core/codex-runtime/codex-desktop-config-policy.js +3 -3
  92. package/dist/core/commands/agent-bridge-command.js +28 -8
  93. package/dist/core/commands/basic-cli.js +89 -42
  94. package/dist/core/commands/bench-command.js +5 -1
  95. package/dist/core/commands/command-utils.js +0 -5
  96. package/dist/core/commands/image-ux-review-command.js +0 -9
  97. package/dist/core/commands/mad-sks-command.js +55 -208
  98. package/dist/core/commands/naruto-command.js +55 -21
  99. package/dist/core/commands/ppt-command.js +0 -9
  100. package/dist/core/commands/run-command.js +8 -2
  101. package/dist/core/commands/seo-command.js +0 -6
  102. package/dist/core/commands/wiki-command.js +0 -14
  103. package/dist/core/computer-use-live-evidence.js +0 -5
  104. package/dist/core/config/secret-preservation.js +0 -11
  105. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +0 -2
  106. package/dist/core/daemon/sksd-hook-daemon.js +1 -29
  107. package/dist/core/daemon/sksd-hook-dispatch.js +0 -17
  108. package/dist/core/db-safety.js +0 -7
  109. package/dist/core/doctor/browser-use-repair.js +0 -2
  110. package/dist/core/doctor/command-alias-cleanup.js +37 -9
  111. package/dist/core/doctor/current-project-guidance.js +6 -3
  112. package/dist/core/doctor/doctor-codex-startup-repair.js +0 -3
  113. package/dist/core/doctor/doctor-dirty-planner.js +1 -1
  114. package/dist/core/doctor/doctor-readiness-matrix.js +12 -0
  115. package/dist/core/doctor/doctor-skill-reconcile.js +32 -0
  116. package/dist/core/doctor/imagegen-repair.js +0 -2
  117. package/dist/core/doctor/mcp-transport-collision-repair.js +0 -3
  118. package/dist/core/doctor/retired-auto-review-config.js +9 -1
  119. package/dist/core/doctor/retired-managed-residue-private.js +5 -4
  120. package/dist/core/doctor/retired-managed-residue-runtime.js +9 -1
  121. package/dist/core/doctor/skill-legacy-surface.js +351 -0
  122. package/dist/core/doctor/supabase-mcp-repair.js +0 -11
  123. package/dist/core/evaluation.js +3 -0
  124. package/dist/core/feature-fixture-executor.js +0 -48
  125. package/dist/core/feature-fixtures.js +0 -6
  126. package/dist/core/fsx.js +11 -12
  127. package/dist/core/harness-conflicts.js +177 -18
  128. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +0 -5
  129. package/dist/core/hooks-runtime/hook-context.js +202 -0
  130. package/dist/core/hooks-runtime/hook-io.js +1 -12
  131. package/dist/core/hooks-runtime/light-turn.js +0 -2
  132. package/dist/core/hooks-runtime/naruto-decision-gate.js +4 -1
  133. package/dist/core/hooks-runtime/naruto-terminal-finalization.js +91 -0
  134. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +369 -0
  135. package/dist/core/hooks-runtime/standalone-parent-host-capability.js +98 -0
  136. package/dist/core/hooks-runtime/subagent-context.js +59 -0
  137. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +29 -0
  138. package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +195 -0
  139. package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +316 -0
  140. package/dist/core/hooks-runtime/subagent-skill-availability.js +217 -0
  141. package/dist/core/hooks-runtime.js +275 -540
  142. package/dist/core/image-ux-review/codex-app-generated-image-discovery.js +0 -17
  143. package/dist/core/image-ux-review/imagegen-adapter.js +0 -14
  144. package/dist/core/imagegen/imagegen-auth-readiness.js +0 -9
  145. package/dist/core/imagegen/imagegen-capability.js +0 -3
  146. package/dist/core/init/managed-skill-install.js +42 -0
  147. package/dist/core/init/skills.js +248 -75
  148. package/dist/core/init.js +19 -45
  149. package/dist/core/lean-engineering-policy.js +0 -2
  150. package/dist/core/locks/file-lock.js +0 -21
  151. package/dist/core/loops/loop-planner.js +0 -6
  152. package/dist/core/loops/loop-runtime.js +0 -1
  153. package/dist/core/loops/loop-worker-runtime.js +0 -19
  154. package/dist/core/mad-sks/executors/db-write-executor.js +0 -4
  155. package/dist/core/mad-sks/executors/executor-base.js +0 -10
  156. package/dist/core/mad-sks/immutable-harness-guard.js +0 -5
  157. package/dist/core/mad-sks/sql-plane/coordinator.js +0 -5
  158. package/dist/core/mad-sks/sql-plane/ledger.js +0 -4
  159. package/dist/core/mad-sks/sql-plane/lock.js +0 -4
  160. package/dist/core/mad-sks/sql-plane/mcp-executor.js +0 -9
  161. package/dist/core/mad-sks/sql-plane/policy-resolver.js +0 -2
  162. package/dist/core/mad-sks/sql-plane/postconditions.js +0 -4
  163. package/dist/core/mad-sks/sql-plane/recovery.js +0 -2
  164. package/dist/core/mad-sks/sql-plane/runtime-profile.js +0 -8
  165. package/dist/core/managed-assets/managed-assets-manifest.js +1 -7
  166. package/dist/core/mcp-config/health-check.js +10 -3
  167. package/dist/core/migration/migration-transaction-journal.js +0 -8
  168. package/dist/core/mission.js +0 -2
  169. package/dist/core/naruto/naruto-active-pool.js +0 -2
  170. package/dist/core/naruto/naruto-concurrency-governor.js +18 -11
  171. package/dist/core/naruto/naruto-real-write-proof.js +0 -4
  172. package/dist/core/naruto/naruto-write-e2e.js +0 -1
  173. package/dist/core/perf/perf-budget.js +0 -5
  174. package/dist/core/permission-gates.js +0 -2
  175. package/dist/core/pipeline-internals/runtime-core.js +15 -5
  176. package/dist/core/pipeline-internals/runtime-gates.js +7 -19
  177. package/dist/core/preflight/parallel-preflight-engine.js +1 -12
  178. package/dist/core/proof/evidence-collector.js +0 -2
  179. package/dist/core/proof/route-finalizer.js +0 -1
  180. package/dist/core/proof/selftest-proof-fixtures.js +0 -5
  181. package/dist/core/providers/openrouter/openrouter-client.js +2 -2
  182. package/dist/core/providers/openrouter/openrouter-provider-health.js +1 -1
  183. package/dist/core/providers/{glm/glm-request-cache.js → openrouter/openrouter-request-cache.js} +5 -6
  184. package/dist/core/providers/openrouter/openrouter-secret-store.js +0 -1
  185. package/dist/core/providers/openrouter/openrouter-stream.js +2 -4
  186. package/dist/core/questions.js +3 -3
  187. package/dist/core/release/gate-manifest.js +0 -5
  188. package/dist/core/release/package-size-budget.js +2 -2
  189. package/dist/core/release/release-gate-batch-runner.js +11 -2
  190. package/dist/core/release/release-gate-cache-v2.js +0 -4
  191. package/dist/core/release/release-gate-contract.js +0 -7
  192. package/dist/core/release/release-gate-hermetic-env.js +0 -5
  193. package/dist/core/release/release-pack-receipt.js +1 -0
  194. package/dist/core/release-parallel-full-coverage.js +0 -2
  195. package/dist/core/remote/ssh-worker-client.js +0 -3
  196. package/dist/core/research/research-adversarial-review.js +6 -2
  197. package/dist/core/responses-retry-policy.js +0 -10
  198. package/dist/core/retention.js +0 -7
  199. package/dist/core/routes/constants.js +0 -3
  200. package/dist/core/routes/model-mode-router.js +10 -19
  201. package/dist/core/routes.js +91 -17
  202. package/dist/core/safety/command-contract/contracts.js +2 -0
  203. package/dist/core/safety/mutation-guard.js +0 -25
  204. package/dist/core/safety/mutation-ledger.js +0 -9
  205. package/dist/core/safety/requested-scope-contract.js +0 -0
  206. package/dist/core/security/high-risk-contracts.js +0 -1
  207. package/dist/core/skills/core-skill-card.js +0 -0
  208. package/dist/core/skills/core-skill-deployment.js +0 -13
  209. package/dist/core/skills/core-skill-epoch.js +0 -11
  210. package/dist/core/skills/core-skill-meta-update.js +0 -6
  211. package/dist/core/skills/core-skill-patch-apply.js +0 -7
  212. package/dist/core/skills/core-skill-patch.js +0 -8
  213. package/dist/core/skills/core-skill-reflection.js +0 -16
  214. package/dist/core/skills/core-skill-runtime.js +0 -6
  215. package/dist/core/skills/core-skill-scorer.js +0 -7
  216. package/dist/core/skills/core-skill-trainer.js +0 -11
  217. package/dist/core/skills/core-skill-types.js +0 -9
  218. package/dist/core/skills/core-skill-validation.js +0 -5
  219. package/dist/core/skills/rejected-skill-patch-buffer.js +0 -2
  220. package/dist/core/stop-gate/stop-gate-check.js +0 -8
  221. package/dist/core/stop-gate/stop-gate-resolver.js +0 -7
  222. package/dist/core/stop-gate/stop-gate-writer.js +0 -5
  223. package/dist/core/subagents/model-policy.js +0 -7
  224. package/dist/core/subagents/naruto-help-contract.js +3 -2
  225. package/dist/core/subagents/naruto-proof-projection.js +580 -12
  226. package/dist/core/subagents/official-subagent-config.js +256 -40
  227. package/dist/core/subagents/official-subagent-preparation.js +11 -7
  228. package/dist/core/subagents/official-subagent-prompt.js +29 -0
  229. package/dist/core/subagents/official-subagent-runner.js +379 -39
  230. package/dist/core/subagents/subagent-evidence.js +378 -9
  231. package/dist/core/subagents/terminology.js +11 -6
  232. package/dist/core/subagents/thread-budget.js +6 -3
  233. package/dist/core/subagents/triwiki-attention.js +0 -4
  234. package/dist/core/subagents/wave-parent-guidance.js +54 -9
  235. package/dist/core/telegram/runtime.js +0 -1
  236. package/dist/core/triwiki/code-index-scanner.js +0 -3
  237. package/dist/core/triwiki/code-pack-head-freshness.js +0 -10
  238. package/dist/core/triwiki/code-pack.js +0 -2
  239. package/dist/core/triwiki/triwiki-cache-key.js +0 -1
  240. package/dist/core/triwiki/triwiki-proof-bank.js +0 -1
  241. package/dist/core/triwiki-attention.js +0 -10
  242. package/dist/core/triwiki-provenance.js +0 -5
  243. package/dist/core/triwiki-runtime.js +0 -12
  244. package/dist/core/triwiki-wrongness/wrongness-ledger.js +0 -7
  245. package/dist/core/triwiki-wrongness/wrongness-schema.js +0 -3
  246. package/dist/core/trust-kernel/trust-report.js +0 -7
  247. package/dist/core/update/update-migration-state.js +113 -61
  248. package/dist/core/update-check.js +2 -14
  249. package/dist/core/version-manager.js +43 -4
  250. package/dist/core/version.js +1 -1
  251. package/dist/core/work-order-ledger.js +0 -17
  252. package/dist/core/zellij/zellij-clipboard-config.js +0 -18
  253. package/dist/core/zellij/zellij-fake-adapter.js +16 -0
  254. package/dist/core/zellij/zellij-lane-renderer.js +5 -46
  255. package/dist/core/zellij/zellij-lane-runtime.js +0 -1
  256. package/dist/core/zellij/zellij-launcher.js +35 -35
  257. package/dist/core/zellij/zellij-official-subagent-activity.js +0 -5
  258. package/dist/core/zellij/zellij-official-subagent-telemetry.js +0 -5
  259. package/dist/core/zellij/zellij-pane-proof.js +3 -3
  260. package/dist/core/zellij/zellij-screen-proof.js +0 -7
  261. package/dist/core/zellij/zellij-slot-column-anchor.js +0 -1
  262. package/dist/core/zellij/zellij-slot-pane-renderer.js +0 -9
  263. package/dist/core/zellij/zellij-slot-telemetry.js +6 -16
  264. package/dist/core/zellij/zellij-ui-mode.js +0 -7
  265. package/dist/core/zellij/zellij-update.js +0 -29
  266. package/dist/core/zellij/zellij-worker-pane-manager.js +0 -39
  267. package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +61 -2
  268. package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +10 -3
  269. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +55 -3
  270. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +76 -0
  271. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +273 -54
  272. package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +5 -1
  273. package/dist/native/sks-menubar/Sources/SettingsViewController.swift +2 -2
  274. package/dist/native/sks-menubar/Sources/StatusItemController.swift +28 -2
  275. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +96 -13
  276. package/dist/scripts/agent-message-bus-reader-check.js +0 -1
  277. package/dist/scripts/all-feature-deep-completion-check.js +0 -1
  278. package/dist/scripts/appshots-thread-attachment-discovery-check.js +0 -1
  279. package/dist/scripts/architecture-guard-check.js +0 -1
  280. package/dist/scripts/build-dist.js +0 -1
  281. package/dist/scripts/build-once-runner-check.js +0 -1
  282. package/dist/scripts/canonical-test-runner.js +0 -2
  283. package/dist/scripts/certificate-sla-check.js +0 -1
  284. package/dist/scripts/changelog-check.js +0 -1
  285. package/dist/scripts/check-cli-entrypoint.js +0 -1
  286. package/dist/scripts/check-command-module-budget.js +0 -7
  287. package/dist/scripts/check-feature-quality.js +0 -1
  288. package/dist/scripts/check-legacy-free.js +0 -1
  289. package/dist/scripts/check-pipeline-runtime.js +0 -1
  290. package/dist/scripts/check-runtime-schemas.js +0 -1
  291. package/dist/scripts/codex-0-134-runner-truth-check.js +0 -1
  292. package/dist/scripts/codex-0-137-compat-check.js +0 -1
  293. package/dist/scripts/codex-0138-capability-artifact-check.js +0 -1
  294. package/dist/scripts/codex-0138-capability-check.js +0 -1
  295. package/dist/scripts/codex-0138-doctor-check.js +0 -1
  296. package/dist/scripts/codex-0138-feature-probes-check.js +0 -1
  297. package/dist/scripts/codex-0144-app-server-v2-check.js +5 -5
  298. package/dist/scripts/codex-0144-core-real-probes-check.js +0 -1
  299. package/dist/scripts/codex-app-handoff-check.js +0 -1
  300. package/dist/scripts/codex-app-handoff-launch-check.js +0 -1
  301. package/dist/scripts/codex-config-load-probe.js +0 -5
  302. package/dist/scripts/codex-control-all-pipelines-check.js +0 -1
  303. package/dist/scripts/codex-control-event-stream-ledger-check.js +0 -1
  304. package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +0 -1
  305. package/dist/scripts/codex-permission-profiles-check.js +0 -1
  306. package/dist/scripts/codex-plugin-app-template-policy-check.js +0 -1
  307. package/dist/scripts/codex-project-config-policy-splitter-check.js +0 -1
  308. package/dist/scripts/codex-sdk-all-pipelines-check.js +0 -1
  309. package/dist/scripts/codex-sdk-backend-router-check.js +0 -1
  310. package/dist/scripts/codex-sdk-capability-check.js +0 -1
  311. package/dist/scripts/codex-sdk-event-stream-ledger-check.js +0 -1
  312. package/dist/scripts/codex-sdk-real-smoke-check.js +0 -1
  313. package/dist/scripts/concurrent-session-collision-check.js +9 -0
  314. package/dist/scripts/context7-evidence-dedupe-check.js +0 -1
  315. package/dist/scripts/core-skill-card-schema-check.js +0 -11
  316. package/dist/scripts/core-skill-deployment-snapshot-check.js +0 -10
  317. package/dist/scripts/core-skill-heldout-validation-check.js +0 -11
  318. package/dist/scripts/core-skill-no-inference-optimizer-check.js +0 -11
  319. package/dist/scripts/core-skill-patch-check.js +0 -11
  320. package/dist/scripts/core-skill-route-runtime-integration-check.js +0 -11
  321. package/dist/scripts/current-command-surface-check.js +1 -1
  322. package/dist/scripts/current-surface-update-e2e-check.js +2 -4
  323. package/dist/scripts/current-upgrade-matrix-check.js +0 -1
  324. package/dist/scripts/dfix-fixture-check.js +0 -1
  325. package/dist/scripts/dfix-patch-handoff-check.js +0 -1
  326. package/dist/scripts/dfix-verification-check.js +0 -1
  327. package/dist/scripts/dfix-verification-recommendation-check.js +0 -1
  328. package/dist/scripts/docs-truthfulness-check.js +7 -7
  329. package/dist/scripts/doctor-fastpath-check.js +0 -1
  330. package/dist/scripts/doctor-fix-production-blackbox.js +1 -1
  331. package/dist/scripts/doctor-fix-proves-codex-read-check.js +0 -11
  332. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +0 -4
  333. package/dist/scripts/doctor-idempotence-check.js +0 -1
  334. package/dist/scripts/doctor-ops-semantics-check.js +0 -1
  335. package/dist/scripts/doctor-startup-config-repair-blackbox.js +1 -1
  336. package/dist/scripts/ensure-bin-executable.js +0 -1
  337. package/dist/scripts/evidence-flagship-coverage-check.js +0 -1
  338. package/dist/scripts/fast-codex-service-tier-proof-check.js +0 -1
  339. package/dist/scripts/fixtures/fake-codex-config-loader.js +0 -5
  340. package/dist/scripts/fsx-hotpath-check.js +0 -1
  341. package/dist/scripts/gate-policy-audit-check.js +1 -1
  342. package/dist/scripts/geo-claim-evidence-check.js +0 -1
  343. package/dist/scripts/geo-cli-blackbox-check.js +0 -1
  344. package/dist/scripts/geo-crawler-policy-check.js +0 -1
  345. package/dist/scripts/git-worktree-diff-envelope-check.js +0 -1
  346. package/dist/scripts/git-worktree-dirty-lock-check.js +0 -1
  347. package/dist/scripts/git-worktree-dirty-main-detection-check.js +0 -1
  348. package/dist/scripts/git-worktree-integration-primary-check.js +0 -1
  349. package/dist/scripts/git-worktree-manifest-append-check.js +0 -1
  350. package/dist/scripts/git-worktree-untracked-diff-check.js +0 -1
  351. package/dist/scripts/high-risk-contracts-check.js +0 -1
  352. package/dist/scripts/hook-latency-budget-check.js +0 -1
  353. package/dist/scripts/hook-latency-quantum-check.js +0 -1
  354. package/dist/scripts/image-artifact-path-contract-check.js +0 -1
  355. package/dist/scripts/imagegen-real-smoke-check.js +0 -1
  356. package/dist/scripts/import-graph-budget-check.js +0 -1
  357. package/dist/scripts/installed-package-smoke-check.js +0 -1
  358. package/dist/scripts/legacy-gate-purge-check.js +0 -1
  359. package/dist/scripts/lib/codex-sdk-gate-lib.js +0 -3
  360. package/dist/scripts/lib/ensure-dist-fresh.js +0 -1
  361. package/dist/scripts/lib/valid-png-fixture.js +0 -1
  362. package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +0 -1
  363. package/dist/scripts/loop-directive-check-lib.js +0 -1
  364. package/dist/scripts/loop-worker-fixture-child.js +0 -1
  365. package/dist/scripts/mad-preflight-blocks-unreadable-config-check.js +0 -10
  366. package/dist/scripts/mad-sks-sql-plane-lifecycle-hook-decision-check.js +0 -1
  367. package/dist/scripts/mad-sks-sql-plane-result-lifecycle-check.js +0 -1
  368. package/dist/scripts/mcp-plugin-inventory-check.js +0 -1
  369. package/dist/scripts/mcp-tool-naming-parity-check.js +0 -1
  370. package/dist/scripts/model-call-concurrency-check.js +0 -1
  371. package/dist/scripts/mutation-callsite-coverage-check.js +0 -5
  372. package/dist/scripts/naruto-codex-e2e-check.js +0 -1
  373. package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -1
  374. package/dist/scripts/official-subagent-workflow-check.js +4 -2
  375. package/dist/scripts/ops-diagnostics-bundle-check.js +0 -1
  376. package/dist/scripts/packlist-performance-check.js +1 -3
  377. package/dist/scripts/perf-budget-check.js +0 -1
  378. package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -1
  379. package/dist/scripts/ppt-real-export-adapter-check.js +0 -1
  380. package/dist/scripts/ppt-real-imagegen-smoke-check.js +0 -1
  381. package/dist/scripts/ppt-real-imagegen-wiring-check.js +0 -1
  382. package/dist/scripts/ppt-reexport-rereview-check.js +0 -1
  383. package/dist/scripts/prepublish-fast-check.js +0 -23
  384. package/dist/scripts/prepublish-release-check-or-fast.js +0 -7
  385. package/dist/scripts/probe-memoization-check.js +0 -1
  386. package/dist/scripts/product-design-plugin-routing-check.js +0 -1
  387. package/dist/scripts/project-skill-dedupe-blackbox.js +36 -9
  388. package/dist/scripts/prompt-placeholder-guard-check.js +0 -1
  389. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +0 -3
  390. package/dist/scripts/qa-loop-app-handoff-capability-check.js +0 -1
  391. package/dist/scripts/qa-loop-app-handoff-check.js +0 -1
  392. package/dist/scripts/qa-loop-app-handoff-cli-check.js +0 -1
  393. package/dist/scripts/qa-loop-app-handoff-confirmation-check.js +0 -1
  394. package/dist/scripts/qa-loop-app-handoff-gate-lifecycle-check.js +0 -1
  395. package/dist/scripts/qa-loop-app-handoff-launch-check.js +0 -1
  396. package/dist/scripts/qa-loop-app-handoff-status-lifecycle-check.js +0 -1
  397. package/dist/scripts/qa-loop-budget-policy-check.js +0 -1
  398. package/dist/scripts/qa-loop-effort-escalation-check.js +0 -1
  399. package/dist/scripts/qa-loop-image-path-exposure-check.js +0 -1
  400. package/dist/scripts/qa-loop-image-path-prompt-injection-check.js +0 -1
  401. package/dist/scripts/release-cache-glob-hashing-check.js +0 -1
  402. package/dist/scripts/release-cache-input-classifier-check.js +0 -1
  403. package/dist/scripts/release-cache-neutralization-report-check.js +0 -1
  404. package/dist/scripts/release-cache-version-neutral-fixture-check.js +0 -1
  405. package/dist/scripts/release-check-stamp.js +0 -4
  406. package/dist/scripts/release-dist-freshness-check.js +0 -1
  407. package/dist/scripts/release-full-parallelism-blackbox.js +3 -3
  408. package/dist/scripts/release-gate-batch-runner-check.js +22 -0
  409. package/dist/scripts/release-gate-budget-check.js +0 -6
  410. package/dist/scripts/release-gate-dag-runner-check.js +0 -1
  411. package/dist/scripts/release-latency-slo-check.js +0 -1
  412. package/dist/scripts/release-metadata-1-19-check.js +0 -2
  413. package/dist/scripts/release-metadata-check.js +0 -3
  414. package/dist/scripts/release-parallel-speed-budget-check.js +0 -5
  415. package/dist/scripts/release-proof-truth-check.js +0 -1
  416. package/dist/scripts/release-provenance-check.js +0 -1
  417. package/dist/scripts/release-real-check.js +0 -1
  418. package/dist/scripts/release-runtime-truth-matrix-check.js +0 -1
  419. package/dist/scripts/release-version-truth-check.js +0 -1
  420. package/dist/scripts/research-blueprint-densifier-check.js +0 -1
  421. package/dist/scripts/research-claim-builder-check.js +0 -1
  422. package/dist/scripts/research-complete-package-fixture-check.js +0 -1
  423. package/dist/scripts/research-final-reviewer-blackbox.js +0 -1
  424. package/dist/scripts/responses-retry-policy-centralized-check.js +0 -1
  425. package/dist/scripts/retention-apply-smoke-check.js +0 -1
  426. package/dist/scripts/retention-budget-check.js +0 -1
  427. package/dist/scripts/retention-dry-run-check.js +0 -1
  428. package/dist/scripts/rollback-recovery-smoke-check.js +0 -1
  429. package/dist/scripts/route-intent-regression-check.js +0 -1
  430. package/dist/scripts/runtime-current-terminal-check.js +0 -1
  431. package/dist/scripts/runtime-dist-parity-check.js +0 -1
  432. package/dist/scripts/runtime-no-src-mjs-check.js +0 -1
  433. package/dist/scripts/runtime-proof-summary-check.js +0 -1
  434. package/dist/scripts/runtime-ts-rust-boundary-check.js +0 -15
  435. package/dist/scripts/runtime-ts-source-of-truth-check.js +0 -1
  436. package/dist/scripts/scheduler-batch-dispatch-check.js +0 -1
  437. package/dist/scripts/scheduler-parallel-proof-consistency-check.js +0 -1
  438. package/dist/scripts/scheduler-utilization-integral-check.js +0 -1
  439. package/dist/scripts/search-visibility-gate-lib.js +0 -1
  440. package/dist/scripts/seo-audit-fixture-check.js +0 -1
  441. package/dist/scripts/seo-cli-blackbox-check.js +0 -1
  442. package/dist/scripts/seo-geo-geo-disambiguation-check.js +0 -1
  443. package/dist/scripts/seo-geo-route-identity-check.js +0 -1
  444. package/dist/scripts/seo-geo-skill-rich-content-check.js +0 -1
  445. package/dist/scripts/seo-marketing-truthfulness-check.js +0 -1
  446. package/dist/scripts/seo-metadata-sync-check.js +0 -1
  447. package/dist/scripts/seo-no-mutation-by-default-check.js +0 -1
  448. package/dist/scripts/shared-memory-fixture-check.js +0 -1
  449. package/dist/scripts/side-effect-runtime-report-check.js +0 -1
  450. package/dist/scripts/sizecheck.js +2 -3
  451. package/dist/scripts/sks-1-11-gate-lib.js +0 -1
  452. package/dist/scripts/sks-1-12-real-execution-check-lib.js +0 -1
  453. package/dist/scripts/sks-1-18-gate-lib.js +0 -1
  454. package/dist/scripts/sks-menubar-install-check.js +0 -3
  455. package/dist/scripts/sksd-daemon-check.js +0 -1
  456. package/dist/scripts/super-search-live-smoke-check.js +0 -1
  457. package/dist/scripts/super-search-local-http-smoke-check.js +0 -1
  458. package/dist/scripts/super-search-offline-contract-check.js +0 -1
  459. package/dist/scripts/super-search-provider-interface-check.js +0 -1
  460. package/dist/scripts/triwiki-cache-key-check.js +0 -1
  461. package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -1
  462. package/dist/scripts/triwiki-proof-bank-check.js +0 -1
  463. package/dist/scripts/triwiki-proof-card-check.js +0 -1
  464. package/dist/scripts/trust-fixture-check.js +0 -1
  465. package/dist/scripts/ultra-router-auto-router-check.js +0 -1
  466. package/dist/scripts/update-fastpath-check.js +0 -1
  467. package/dist/scripts/upgrade-migration-matrix-check.js +0 -1
  468. package/dist/scripts/ux-review-extract-wires-real-extractor-check.js +0 -1
  469. package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -1
  470. package/dist/scripts/ux-review-patch-diff-recheck-check.js +0 -1
  471. package/dist/scripts/ux-review-real-imagegen-smoke-check.js +0 -1
  472. package/dist/scripts/ux-review-run-wires-imagegen-check.js +0 -1
  473. package/dist/scripts/write-build-manifest.js +0 -1
  474. package/dist/scripts/wrongness-fixture-check.js +0 -1
  475. package/dist/scripts/zellij-capability-check.js +0 -1
  476. package/dist/scripts/zellij-developer-controls-check.js +0 -1
  477. package/dist/scripts/zellij-doctor-readiness-check.js +0 -13
  478. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +0 -1
  479. package/dist/scripts/zellij-fake-adapter-check.js +0 -1
  480. package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -1
  481. package/dist/scripts/zellij-lane-renderer-check.js +0 -1
  482. package/dist/scripts/zellij-launch-command-truth-check.js +0 -12
  483. package/dist/scripts/zellij-layout-valid-check.js +0 -1
  484. package/dist/scripts/zellij-pane-creation-lock-metrics-check.js +0 -1
  485. package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -1
  486. package/dist/scripts/zellij-pane-lock-does-not-block-worker-check.js +0 -1
  487. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -1
  488. package/dist/scripts/zellij-pane-proof-check.js +0 -1
  489. package/dist/scripts/zellij-qa-app-handoff-status-check.js +0 -1
  490. package/dist/scripts/zellij-real-session-cleanup-check.js +0 -1
  491. package/dist/scripts/zellij-real-session-launch-check.js +0 -1
  492. package/dist/scripts/zellij-right-column-geometry-proof.js +0 -1
  493. package/dist/scripts/zellij-right-column-headless-overflow-check.js +0 -1
  494. package/dist/scripts/zellij-right-column-manager-check.js +0 -1
  495. package/dist/scripts/zellij-screen-proof-check.js +0 -1
  496. package/dist/scripts/zellij-slot-only-ui-check.js +0 -1
  497. package/dist/scripts/zellij-slot-pane-renderer-check.js +0 -1
  498. package/dist/scripts/zellij-slot-pane-stale-detection-check.js +0 -7
  499. package/dist/scripts/zellij-slot-telemetry-incremental-check.js +0 -1
  500. package/dist/scripts/zellij-slot-telemetry-live-flush-check.js +0 -1
  501. package/dist/scripts/zellij-slot-telemetry-performance-check.js +0 -1
  502. package/dist/scripts/zellij-stacked-capability-routing-check.js +0 -1
  503. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -1
  504. package/dist/scripts/zellij-stacked-version-matrix-check.js +0 -1
  505. package/dist/scripts/zellij-stacked-version-parser-check.js +0 -1
  506. package/dist/scripts/zellij-ui-design-check.js +0 -12
  507. package/dist/scripts/zellij-update-prompt-matrix-check.js +0 -1
  508. package/dist/scripts/zellij-update-prompt-mode-check.js +0 -1
  509. package/dist/scripts/zellij-update-prompt-safety-check.js +0 -1
  510. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -2
  511. package/package.json +6 -7
  512. package/release-gates.v2.json +426 -93
  513. package/schemas/codex/app-server-0.145/codex_app_server_protocol.v2.schemas.json +19611 -0
  514. package/dist/core/commands/glm-command.js +0 -93
  515. package/dist/core/providers/glm/bench/glm-bench-comparison.js +0 -47
  516. package/dist/core/providers/glm/bench/glm-bench-fixture.js +0 -64
  517. package/dist/core/providers/glm/bench/glm-bench-model-lock-proof.js +0 -52
  518. package/dist/core/providers/glm/bench/glm-bench-report.js +0 -74
  519. package/dist/core/providers/glm/bench/glm-benchmark-runner.js +0 -243
  520. package/dist/core/providers/glm/bench/glm-benchmark-types.js +0 -1
  521. package/dist/core/providers/glm/bench/glm-direct-bench-runner.js +0 -72
  522. package/dist/core/providers/glm/glm-52-profile.js +0 -82
  523. package/dist/core/providers/glm/glm-52-request.js +0 -73
  524. package/dist/core/providers/glm/glm-52-response-guard.js +0 -32
  525. package/dist/core/providers/glm/glm-52-settings.js +0 -67
  526. package/dist/core/providers/glm/glm-context-budget.js +0 -14
  527. package/dist/core/providers/glm/glm-context-cache.js +0 -8
  528. package/dist/core/providers/glm/glm-direct-run.js +0 -140
  529. package/dist/core/providers/glm/glm-interactive-launch.js +0 -4
  530. package/dist/core/providers/glm/glm-latency-trace.js +0 -39
  531. package/dist/core/providers/glm/glm-loop-guard.js +0 -30
  532. package/dist/core/providers/glm/glm-mad-launch.js +0 -128
  533. package/dist/core/providers/glm/glm-mad-mode.js +0 -269
  534. package/dist/core/providers/glm/glm-model-meta-cache.js +0 -18
  535. package/dist/core/providers/glm/glm-patch-apply.js +0 -72
  536. package/dist/core/providers/glm/glm-patch-parser.js +0 -18
  537. package/dist/core/providers/glm/glm-profile-resolver.js +0 -168
  538. package/dist/core/providers/glm/glm-readiness.js +0 -4
  539. package/dist/core/providers/glm/glm-reasoning-policy.js +0 -14
  540. package/dist/core/providers/glm/glm-run-controller.js +0 -65
  541. package/dist/core/providers/glm/glm-run-state.js +0 -10
  542. package/dist/core/providers/glm/glm-run-timeout.js +0 -30
  543. package/dist/core/providers/glm/glm-speed-context.js +0 -81
  544. package/dist/core/providers/glm/glm-speed-gate.js +0 -39
  545. package/dist/core/providers/glm/glm-speed-output-parser.js +0 -39
  546. package/dist/core/providers/glm/glm-tool-schema-cache.js +0 -18
  547. package/dist/core/providers/glm/naruto/glm-naruto-apply-transaction.js +0 -135
  548. package/dist/core/providers/glm/naruto/glm-naruto-artifacts.js +0 -1
  549. package/dist/core/providers/glm/naruto/glm-naruto-bench.js +0 -6
  550. package/dist/core/providers/glm/naruto/glm-naruto-budget.js +0 -44
  551. package/dist/core/providers/glm/naruto/glm-naruto-combined-patch.js +0 -48
  552. package/dist/core/providers/glm/naruto/glm-naruto-command.js +0 -101
  553. package/dist/core/providers/glm/naruto/glm-naruto-concurrency-governor.js +0 -37
  554. package/dist/core/providers/glm/naruto/glm-naruto-conflict-graph.js +0 -79
  555. package/dist/core/providers/glm/naruto/glm-naruto-critical-path.js +0 -50
  556. package/dist/core/providers/glm/naruto/glm-naruto-decomposer.js +0 -148
  557. package/dist/core/providers/glm/naruto/glm-naruto-file-lease.js +0 -22
  558. package/dist/core/providers/glm/naruto/glm-naruto-final-seal.js +0 -81
  559. package/dist/core/providers/glm/naruto/glm-naruto-finalizer.js +0 -22
  560. package/dist/core/providers/glm/naruto/glm-naruto-hunk-conflict.js +0 -15
  561. package/dist/core/providers/glm/naruto/glm-naruto-hunk-parser.js +0 -35
  562. package/dist/core/providers/glm/naruto/glm-naruto-isolation-policy.js +0 -37
  563. package/dist/core/providers/glm/naruto/glm-naruto-judge.js +0 -83
  564. package/dist/core/providers/glm/naruto/glm-naruto-merge-planner.js +0 -61
  565. package/dist/core/providers/glm/naruto/glm-naruto-metrics.js +0 -33
  566. package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +0 -486
  567. package/dist/core/providers/glm/naruto/glm-naruto-parallelism-summary.js +0 -54
  568. package/dist/core/providers/glm/naruto/glm-naruto-patch-candidate-gate.js +0 -41
  569. package/dist/core/providers/glm/naruto/glm-naruto-patch-candidate-parser.js +0 -61
  570. package/dist/core/providers/glm/naruto/glm-naruto-patch-envelope.js +0 -54
  571. package/dist/core/providers/glm/naruto/glm-naruto-quorum.js +0 -36
  572. package/dist/core/providers/glm/naruto/glm-naruto-rate-limiter.js +0 -17
  573. package/dist/core/providers/glm/naruto/glm-naruto-repair-wave.js +0 -20
  574. package/dist/core/providers/glm/naruto/glm-naruto-requirement-coverage.js +0 -108
  575. package/dist/core/providers/glm/naruto/glm-naruto-requirement-ledger.js +0 -57
  576. package/dist/core/providers/glm/naruto/glm-naruto-scoreboard.js +0 -74
  577. package/dist/core/providers/glm/naruto/glm-naruto-secret-audit.js +0 -90
  578. package/dist/core/providers/glm/naruto/glm-naruto-session-id.js +0 -9
  579. package/dist/core/providers/glm/naruto/glm-naruto-shard-planner.js +0 -31
  580. package/dist/core/providers/glm/naruto/glm-naruto-stage-scheduler.js +0 -84
  581. package/dist/core/providers/glm/naruto/glm-naruto-targeted-checks.js +0 -75
  582. package/dist/core/providers/glm/naruto/glm-naruto-task-size-classifier.js +0 -11
  583. package/dist/core/providers/glm/naruto/glm-naruto-terminal.js +0 -43
  584. package/dist/core/providers/glm/naruto/glm-naruto-trace.js +0 -173
  585. package/dist/core/providers/glm/naruto/glm-naruto-types.js +0 -36
  586. package/dist/core/providers/glm/naruto/glm-naruto-usage-extractor.js +0 -30
  587. package/dist/core/providers/glm/naruto/glm-naruto-verifier-output.js +0 -30
  588. package/dist/core/providers/glm/naruto/glm-naruto-work-graph.js +0 -1
  589. package/dist/core/providers/glm/naruto/glm-naruto-worker-artifacts.js +0 -55
  590. package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +0 -275
  591. package/dist/core/providers/glm/naruto/glm-naruto-worker-runtime.js +0 -421
  592. package/dist/core/providers/glm/naruto/glm-naruto-worker-scheduler.js +0 -177
  593. package/dist/core/providers/glm/naruto/glm-naruto-worker.js +0 -1
  594. package/dist/core/providers/glm/naruto/glm-naruto-worktree-cleanup.js +0 -19
  595. package/dist/core/providers/glm/naruto/glm-naruto-worktree-manager.js +0 -71
  596. package/dist/core/providers/glm/naruto/glm-naruto-worktree-worker.js +0 -73
  597. package/dist/core/providers/glm/naruto/glm-naruto-worktree.js +0 -62
  598. package/schemas/codex/app-server-0.144/codex_app_server_protocol.v2.schemas.json +0 -1
@@ -4,6 +4,8 @@ import { appendJsonlBounded, ensureDir, nowIso, readJson, readText, writeTextAto
4
4
  import { withFileLock } from '../locks/file-lock.js';
5
5
  export const ZELLIJ_SLOT_TELEMETRY_EVENT_SCHEMA = 'sks.zellij-slot-telemetry-event.v1';
6
6
  export const ZELLIJ_SLOT_TELEMETRY_SNAPSHOT_SCHEMA = 'sks.zellij-slot-telemetry-snapshot.v1';
7
+ export const ZELLIJ_SLOT_TELEMETRY_LOCK_TIMEOUT_MS = 2_000;
8
+ export const ZELLIJ_SLOT_TELEMETRY_LOCK_STALE_MS = 15_000;
7
9
  const telemetrySnapshotCache = new Map();
8
10
  const telemetrySnapshotWriteCounts = new Map();
9
11
  const telemetrySnapshotFlushCounts = new Map();
@@ -24,8 +26,8 @@ export async function appendZellijSlotTelemetry(root, event) {
24
26
  await ensureDir(path.dirname(file));
25
27
  await withFileLock({
26
28
  lockPath: `${file}.append.lock`,
27
- timeoutMs: 30_000,
28
- staleMs: 2 * 60 * 1000
29
+ timeoutMs: ZELLIJ_SLOT_TELEMETRY_LOCK_TIMEOUT_MS,
30
+ staleMs: ZELLIJ_SLOT_TELEMETRY_LOCK_STALE_MS
29
31
  }, async () => appendJsonlBounded(file, normalized));
30
32
  const previous = await readZellijSlotTelemetrySnapshotNoRebuild(root, missionId);
31
33
  if (previous) {
@@ -50,10 +52,6 @@ export async function readZellijSlotTelemetrySnapshotNoRebuild(root, missionId)
50
52
  const stat = await statTelemetryFile(snapshotPath);
51
53
  const recorded = telemetrySnapshotDiskStat.get(snapshotPath);
52
54
  const diskChanged = Boolean(stat) && (!recorded || recorded.mtimeMs !== stat.mtimeMs || recorded.size !== stat.size);
53
- // CRITICAL: never serve a process-local cache forever. Long-lived reader
54
- // processes (zellij slot pane renderers in --watch mode) must observe
55
- // snapshot flushes performed by the orchestrator and worker processes,
56
- // otherwise the pane renders the same frame for the entire mission.
57
55
  if (!diskChanged && cached?.schema === ZELLIJ_SLOT_TELEMETRY_SNAPSHOT_SCHEMA)
58
56
  return cached;
59
57
  const existing = await readJson(snapshotPath, null);
@@ -63,11 +61,6 @@ export async function readZellijSlotTelemetrySnapshotNoRebuild(root, missionId)
63
61
  return cached?.schema === ZELLIJ_SLOT_TELEMETRY_SNAPSHOT_SCHEMA ? cached : null;
64
62
  }
65
63
  const disk = existing;
66
- // Merge with any locally cached (possibly not-yet-flushed) slot state so a
67
- // writer process does not lose its pending events when another process
68
- // flushed the snapshot file in the meantime. The DISK updated_at stays
69
- // authoritative on the read path: it reflects the last real flush, which is
70
- // what stale-telemetry detection must measure.
71
64
  const merged = cached?.schema === ZELLIJ_SLOT_TELEMETRY_SNAPSHOT_SCHEMA ? mergeTelemetrySnapshots(disk, cached, { updatedAt: 'base' }) : disk;
72
65
  telemetrySnapshotCache.set(snapshotPath, merged);
73
66
  return merged;
@@ -328,15 +321,12 @@ async function writeTelemetrySnapshotFast(file, snapshot) {
328
321
  await ensureDir(path.dirname(file));
329
322
  await withFileLock({
330
323
  lockPath: `${file}.lock`,
331
- timeoutMs: 30000,
332
- staleMs: 2 * 60 * 1000
324
+ timeoutMs: ZELLIJ_SLOT_TELEMETRY_LOCK_TIMEOUT_MS,
325
+ staleMs: ZELLIJ_SLOT_TELEMETRY_LOCK_STALE_MS
333
326
  }, async () => {
334
327
  const flushCount = Number(telemetrySnapshotFlushCounts.get(file) || 0) + 1;
335
328
  telemetrySnapshotFlushCounts.set(file, flushCount);
336
329
  telemetrySnapshotLastFlushMs.set(file, Date.now());
337
- // Multiple processes (orchestrator + worker children) flush this file.
338
- // Serialize the read/merge/write critical section so a slower writer
339
- // cannot overwrite a newer slot observed by a different process.
340
330
  const disk = await readJson(file, null);
341
331
  const merged = disk?.schema === ZELLIJ_SLOT_TELEMETRY_SNAPSHOT_SCHEMA ? mergeTelemetrySnapshots(disk, snapshot) : snapshot;
342
332
  const next = { ...merged, flush_count: Math.max(flushCount, Number(merged.flush_count || 0)) };
@@ -13,13 +13,6 @@ export function resolveZellijUiMode(args = [], env = process.env) {
13
13
  return resolveExplicitZellijUiMode(args, env) || 'compact-slots';
14
14
  }
15
15
  export function resolveZellijWorkerPaneUiMode(args = [], env = process.env) {
16
- // Default worker panes to the live slot renderer (compact-slots). In
17
- // 'full-debug' the pane runs the worker process itself, but the worker is
18
- // invoked with --json and the codex SDK streams events to JSONL files — so
19
- // the pane stays blank until the worker exits. The slot renderer re-reads
20
- // heartbeat/event/stdout artifacts every second and actually shows what each
21
- // parallel worker is doing in real time. 'full-debug' remains available via
22
- // --zellij-full-debug or SKS_ZELLIJ_UI_MODE=full-debug.
23
16
  return resolveExplicitZellijUiMode(args, env) || 'compact-slots';
24
17
  }
25
18
  function resolveExplicitZellijUiMode(args = [], env = process.env) {
@@ -28,13 +28,6 @@ export function zellijUpgradeCommandHint(missing = false) {
28
28
  return 'cargo install --locked zellij # or your distro package manager';
29
29
  return 'See https://zellij.dev/documentation/installation';
30
30
  }
31
- /**
32
- * Resolve the latest STABLE zellij version. GitHub's /releases/latest endpoint
33
- * already excludes prereleases and drafts. Results are cached on disk
34
- * (default TTL 6h, override with SKS_ZELLIJ_UPDATE_TTL_MS) so command launches
35
- * stay fast and offline-safe. SKS_ZELLIJ_LATEST_VERSION pins the value for
36
- * tests and air-gapped environments.
37
- */
38
31
  export async function fetchLatestZellijVersion(input = {}) {
39
32
  const env = input.env || process.env;
40
33
  const pinned = stripVersionPrefix(String(env.SKS_ZELLIJ_LATEST_VERSION || '').trim());
@@ -48,8 +41,6 @@ export async function fetchLatestZellijVersion(input = {}) {
48
41
  }
49
42
  try {
50
43
  const tag = await githubLatestTag(input.timeoutMs || normalizePositiveInt(env.SKS_ZELLIJ_UPDATE_TIMEOUT_MS, 2500));
51
- // GitHub release tags carry a leading "v" (v0.44.3); \b-based version
52
- // parsing cannot start inside "v0", so strip the prefix first.
53
44
  const version = parseZellijVersionText(stripVersionPrefix(tag));
54
45
  if (!version)
55
46
  throw new Error(`zellij_latest_tag_unparsed:${tag}`);
@@ -111,11 +102,6 @@ export async function checkZellijUpdateNotice(input = {}) {
111
102
  }
112
103
  return persistNotice(input.missionDir, notice);
113
104
  }
114
- /**
115
- * Upgrade zellij to the latest stable release. Only Homebrew automation is
116
- * attempted (macOS / Linuxbrew); everything else returns manual_required with
117
- * the exact operator command, mirroring how the Codex CLI update flow behaves.
118
- */
119
105
  export async function upgradeZellijToLatest(input = {}) {
120
106
  const before = await checkZellijCapability({ require: false, writeReport: false, env: input.env || process.env }).catch(() => null);
121
107
  const beforeVersion = before?.version || null;
@@ -133,11 +119,6 @@ export async function upgradeZellijToLatest(input = {}) {
133
119
  };
134
120
  }
135
121
  const upgradeArgs = missing ? ['install', 'zellij'] : ['upgrade', 'zellij'];
136
- // Package installs go through the mutation guard with an explicit
137
- // zellij_install scope contract (same path ensureZellijCliTool uses), so the
138
- // mutation ledger records the install and safety gates can audit it. The
139
- // upgrade only runs after the operator confirmed the [Y/n] prompt or passed
140
- // --yes / `sks zellij update --yes`.
141
122
  const guardRoot = globalSksRoot();
142
123
  const guardCommand = `brew ${upgradeArgs.join(' ')}`;
143
124
  const contract = createRequestedScopeContract({
@@ -155,8 +136,6 @@ export async function upgradeZellijToLatest(input = {}) {
155
136
  maxOutputBytes: 256 * 1024
156
137
  }).catch((err) => ({ code: 1, stdout: '', stderr: String(err?.message || err) }));
157
138
  if (run.code !== 0 && !missing && /No such keg|No available formula|not installed/i.test(`${run.stderr}\n${run.stdout}`)) {
158
- // zellij exists on PATH but was not installed through Homebrew (e.g. cargo
159
- // or a manual binary). Installing the brew formula gives a managed copy.
160
139
  run = await guardedPackageInstall(guardCtx, 'zellij', {
161
140
  confirmed: true,
162
141
  command: 'brew',
@@ -195,14 +174,6 @@ export async function upgradeZellijToLatest(input = {}) {
195
174
  error: null
196
175
  };
197
176
  }
198
- /**
199
- * Launch-time prompt, mirroring maybePromptCodexUpdateForLaunch: check the
200
- * installed zellij version against the latest stable release and offer an
201
- * upgrade before opening the live session. Never blocks the launch.
202
- *
203
- * Skips: --json, --skip-cli-tools, --skip-zellij-update, SKS_SKIP_ZELLIJ_UPDATE=1.
204
- * Auto-approves: --yes / -y.
205
- */
206
177
  export async function maybePromptZellijUpdateForLaunch(args = [], opts = {}) {
207
178
  const env = opts.env || process.env;
208
179
  const list = (args || []).map((arg) => String(arg));
@@ -15,11 +15,6 @@ export function buildWorkerPaneName(slotId, generationIndex) {
15
15
  return `${slotId}/gen-${Math.max(1, Math.floor(Number(generationIndex) || 1))}`;
16
16
  }
17
17
  export function buildWorkerPaneTitle(slotId, generationIndex, context, serviceTier, backend, status, worktree, taskTitle) {
18
- // When a task label is available, the pane title is JUST the label + status:
19
- // users identify panes by what they are doing, not by slot ids. Slot/gen,
20
- // backend, provider, and worktree details stay inside the pane body and the
21
- // SLOTS anchor rows. The verbose format remains the fallback for callers
22
- // that have no task context.
23
18
  const task = shortWorkerTaskLabel(taskTitle);
24
19
  if (task)
25
20
  return `${task} · ${workerBackendTag(backend, context?.provider)} · ${status || 'launching'}`;
@@ -28,9 +23,6 @@ export function buildWorkerPaneTitle(slotId, generationIndex, context, serviceTi
28
23
  const wt = worktree ? ` · WT:${worktree.id} · branch:${worktree.branch}` : '';
29
24
  return `${base}${wt} · ${backend || 'codex-sdk'} · ${providerPaneLabel(normalized)} · ${status || 'launching'}`;
30
25
  }
31
- // Local-LLM workers must be visually distinguishable from GPT/codex workers:
32
- // only trivial long-running edits belong on local models, while web research
33
- // and code review must run on GPT. The tag makes a misrouted task obvious.
34
26
  export function workerBackendTag(backend, provider) {
35
27
  const text = `${String(backend || '')} ${String(provider || '')}`.toLowerCase();
36
28
  if (/ollama|local/.test(text))
@@ -39,8 +31,6 @@ export function workerBackendTag(backend, provider) {
39
31
  return 'fixture';
40
32
  return 'GPT';
41
33
  }
42
- // Lead the pane title with a 1-3 word task label so users can tell WHAT each
43
- // slot is doing at a glance instead of an anonymous "slot-002/gen-1".
44
34
  export function shortWorkerTaskLabel(value, maxChars = 24) {
45
35
  const text = String(value || '').replace(/\s+/g, ' ').trim();
46
36
  if (!text)
@@ -233,15 +223,7 @@ export async function openWorkerPane(input) {
233
223
  return record;
234
224
  }
235
225
  const paneName = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || 'running', input.worktree || null, input.taskTitle || null);
236
- // CRITICAL: serialize anchor + worker pane creation per session. Workers
237
- // launch concurrently, and without this lock every worker raced past the
238
- // "does the SLOTS anchor exist yet?" check and created its OWN anchor with
239
- // --direction right — splitting the screen into N side-by-side columns
240
- // (observed in agent-zellij-pane-launch-ledger: terminal_1..terminal_5 all
241
- // recorded as separate slot_column_anchor_pane_id values in one mission).
242
226
  return withZellijPaneCreationLock(input, async () => {
243
- // Re-read the right-column state now that we hold the lock: a previously
244
- // serialized worker may have created the anchor and/or its own pane.
245
227
  const freshState = rightColumn
246
228
  ? await readRightColumnState(root, input.missionId, input.projectRoot).catch(() => null)
247
229
  : null;
@@ -259,18 +241,10 @@ export async function openWorkerPane(input) {
259
241
  let columnCreationDirectionRequested = null;
260
242
  let columnCreationDirectionApplied = null;
261
243
  if (rightColumn && !freshFocusCandidate) {
262
- // Single right-column invariant: if this zellij session was reused (stable
263
- // per-cwd name) and already carries a SLOTS anchor from a prior mission, adopt
264
- // it and stack workers underneath instead of splitting ANOTHER `--direction
265
- // right` column — repeated right-splits are exactly what fragments the screen
266
- // into side-by-side columns. A fresh column is only split when none exists yet.
267
244
  const adoptedAnchorPaneId = createSession.ok
268
245
  ? await findExistingSlotsAnchorPaneId(input.sessionName, cwd).catch(() => null)
269
246
  : null;
270
247
  if (adoptedAnchorPaneId) {
271
- // Adopted an existing column: no creation was requested, so leave the
272
- // column-creation direction fields null (avoids a false
273
- // `zellij_worker_slot_column_anchor_not_created` blocker).
274
248
  slotColumnAnchorPaneId = adoptedAnchorPaneId;
275
249
  await recordSlotColumnAnchorInRightColumn({
276
250
  root,
@@ -314,11 +288,6 @@ export async function openWorkerPane(input) {
314
288
  const focus = focusPaneId
315
289
  ? await focusZellijPaneById(input.sessionName, focusPaneId, cwd)
316
290
  : null;
317
- // Vertical stack policy: the first worker splits DOWN from the SLOTS anchor;
318
- // every following worker joins a zellij stacked-pane group with the previous
319
- // worker (`new-pane --stacked`, zellij >= 0.43) so the right column stays a
320
- // clean vertical stack instead of fragmenting the screen. Opt out with
321
- // SKS_ZELLIJ_WORKER_STACKED=0.
322
291
  const stackIntent = process.env.SKS_ZELLIJ_WORKER_STACKED !== '0'
323
292
  && Boolean(lastVisibleWorkerPaneId)
324
293
  && focus?.ok === true;
@@ -651,9 +620,6 @@ async function reconcileZellijWorkerPaneId(sessionName, paneName, resultPath, cw
651
620
  blockers: paneId == null ? ['zellij_worker_pane_id_not_reconciled'] : []
652
621
  };
653
622
  }
654
- // Look up an already-open SLOTS anchor pane in a (possibly reused) session so a
655
- // new mission can stack its workers under the existing right column instead of
656
- // splitting another one. Returns the live pane id (terminal_<n>) or null.
657
623
  async function findExistingSlotsAnchorPaneId(sessionName, cwd) {
658
624
  const listed = await runZellij(['--session', sessionName, 'action', 'list-panes', '--json', '--all'], {
659
625
  cwd,
@@ -775,11 +741,6 @@ async function focusZellijPaneById(sessionName, paneId, cwd) {
775
741
  last = focus;
776
742
  if (focus.ok)
777
743
  return focus;
778
- // zellij exits non-zero with "Pane Terminal(N) is already focused" when the
779
- // target pane already holds focus (common: new-pane auto-focuses the pane
780
- // it created, so the previous worker pane is usually still focused). That
781
- // is a success for our purposes — without this, stacked placement would
782
- // silently fall back to a plain down-split on every consecutive worker.
783
744
  if (/already focused/i.test(`${focus.stdout_tail || ''} ${focus.stderr_tail || ''}`)) {
784
745
  return { ...focus, ok: true, blockers: [], warnings: [...focus.warnings, 'zellij_pane_already_focused'] };
785
746
  }
@@ -4,6 +4,7 @@ final class DiagnosticsViewController: NSViewController, ControlCenterPage {
4
4
  private let processClient: ProcessClient
5
5
  private let operations: OperationCoordinator
6
6
  private let status = NativeView.detail("Diagnostics are idle.")
7
+ private let codexGuidance = NativeView.detail("Codex CLI: prefer the latest channel. Use Updates → Update Codex CLI when status reports an update.")
7
8
  private var busy = false
8
9
 
9
10
  init(processClient: ProcessClient, operations: OperationCoordinator) {
@@ -16,14 +17,15 @@ final class DiagnosticsViewController: NSViewController, ControlCenterPage {
16
17
  override func loadView() {
17
18
  let buttons = NSStackView(views: [
18
19
  NativeView.button("Run Doctor", target: self, action: #selector(doctor)),
20
+ NativeView.button("Update Codex CLI", target: self, action: #selector(updateCodexCLI)),
19
21
  NativeView.button("Open Last Log", target: self, action: #selector(openLog)),
20
22
  NativeView.button("Restart Menu Bar", target: self, action: #selector(restart))
21
23
  ])
22
24
  buttons.orientation = .horizontal; buttons.spacing = 8
23
25
  view = NativeView.stack([
24
26
  NativeView.title("Diagnostics"),
25
- NativeView.detail("Diagnostic output is bounded, redacted, and written with owner-only permissions. Use this page when another Center action reports a blocker."),
26
- status, buttons
27
+ NativeView.detail("Diagnostic output is bounded, redacted, and written with owner-only permissions. Use this page when another Center action reports a blocker. Feature routes that need newer Codex fail with an update CTA instead of locking all of SKS."),
28
+ status, codexGuidance, buttons
27
29
  ])
28
30
  refreshOnAppear()
29
31
  }
@@ -37,6 +39,22 @@ final class DiagnosticsViewController: NSViewController, ControlCenterPage {
37
39
  } else {
38
40
  status.stringValue = "Diagnostics are idle. No operation log exists yet."
39
41
  }
42
+ refreshCodexGuidance()
43
+ }
44
+
45
+ private func refreshCodexGuidance() {
46
+ let update = readJson(path: FileManager.default.homeDirectoryForCurrentUser
47
+ .appendingPathComponent(".sneakoscope-global/cache/update-status.json").path)
48
+ let codex = update?["codex_cli"] as? [String: Any]
49
+ if codex?["update_available"] as? Bool == true {
50
+ let current = codex?["current"] as? String ?? "installed"
51
+ let latest = codex?["latest"] as? String ?? "preferred latest"
52
+ codexGuidance.stringValue = "Codex CLI update available: \(current) → \(latest). Prefer latest via Update Codex CLI, or run sks codex update."
53
+ } else if let current = codex?["current"] as? String {
54
+ codexGuidance.stringValue = "Codex CLI \(current) looks current in the shared snapshot. Prefer latest continuously; Naruto and other capability routes still probe features before use."
55
+ } else {
56
+ codexGuidance.stringValue = "Codex CLI: prefer the latest channel. Use Updates → Update Codex CLI when status reports an update, or run sks codex update."
57
+ }
40
58
  }
41
59
 
42
60
  @objc private func doctor() {
@@ -47,6 +65,7 @@ final class DiagnosticsViewController: NSViewController, ControlCenterPage {
47
65
  self.busy = false
48
66
  if result.code == 0 {
49
67
  self.status.stringValue = "Doctor completed with no blocking issue."
68
+ self.refreshCodexGuidance()
50
69
  return
51
70
  }
52
71
  if let json = self.json(result.output) {
@@ -54,14 +73,49 @@ final class DiagnosticsViewController: NSViewController, ControlCenterPage {
54
73
  let blockers = (json["blockers"] as? [String])?.count ?? (json["issues"] as? [Any])?.count
55
74
  if let blockers = blockers {
56
75
  self.status.stringValue = "Doctor reported \(blockers) issue\(blockers == 1 ? "" : "s"). Open Last Log for redacted detail."
76
+ self.refreshCodexGuidance()
57
77
  return
58
78
  }
59
79
  if ok == false {
60
80
  self.status.stringValue = "Doctor reported a blocker. Open Last Log for redacted detail."
81
+ self.refreshCodexGuidance()
61
82
  return
62
83
  }
63
84
  }
64
85
  self.status.stringValue = "Doctor reported a blocker · \(NativeView.redactPreview(result.output))"
86
+ self.refreshCodexGuidance()
87
+ }
88
+ }
89
+
90
+ @objc private func updateCodexCLI() {
91
+ guard let operation = operations.begin(kind: "codex-cli-update", mutationGroup: "update", summary: "Update Codex CLI") else {
92
+ status.stringValue = "Another update or MCP mutation is already running."
93
+ return
94
+ }
95
+ busy = true
96
+ status.stringValue = "Updating Codex CLI…"
97
+ _ = operations.update(operation, state: .running, stage: "running", progress: nil, summary: status.stringValue)
98
+ processClient.run(["codex", "update", "--json"], timeout: nil) { [weak self] result in
99
+ guard let self = self else { return }
100
+ self.busy = false
101
+ let payload = self.json(result.output)
102
+ let ok = result.code == 0
103
+ && !result.truncated
104
+ && payload?["schema"] as? String == "sks.codex-cli-update-result.v1"
105
+ && payload?["ok"] as? Bool == true
106
+ _ = self.operations.update(
107
+ operation,
108
+ state: ok ? .succeeded : .failed,
109
+ stage: "complete",
110
+ progress: 1,
111
+ summary: ok ? "Codex CLI update completed" : "Codex CLI update failed"
112
+ )
113
+ if ok {
114
+ self.status.stringValue = "Codex CLI update completed. Shared update status will refresh on the next Overview/Updates load."
115
+ } else {
116
+ self.status.stringValue = "Codex CLI update needs attention. Open Updates for structured guidance, or run sks codex update."
117
+ }
118
+ self.refreshCodexGuidance()
65
119
  }
66
120
  }
67
121
 
@@ -90,4 +144,9 @@ final class DiagnosticsViewController: NSViewController, ControlCenterPage {
90
144
  guard let data = text.data(using: .utf8) else { return nil }
91
145
  return try? JSONSerialization.jsonObject(with: data) as? [String: Any]
92
146
  }
147
+
148
+ private func readJson(path: String) -> [String: Any]? {
149
+ guard let data = FileManager.default.contents(atPath: path) else { return nil }
150
+ return try? JSONSerialization.jsonObject(with: data) as? [String: Any]
151
+ }
93
152
  }
@@ -140,7 +140,7 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
140
140
 
141
141
  @objc private func refresh() {
142
142
  let scope = selectedScope(); status.stringValue = "Loading \(scope) MCP configuration…"
143
- processClient.run(["mcp", "config", "list", "--scope", scope] + scopeContext(scope, mutation: false) + ["--json"]) { [weak self] result in
143
+ processClient.run(["mcp", "config", "list", "--scope", scope] + scopeContext(scope, mutation: false) + ["--json"], timeout: NativeView.statusTimeout) { [weak self] result in
144
144
  guard let self = self else { return }
145
145
  guard let json = self.json(result.output), let servers = json["servers"] as? [[String: Any]] else {
146
146
  self.rows = []; self.table.reloadData(); self.status.stringValue = "MCP inventory unavailable. No configuration was changed."
@@ -293,7 +293,7 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
293
293
  private func mutate(_ args: [String], stdin: String? = nil) {
294
294
  guard !mutating, let operation = operations.begin(kind: "mcp-config", mutationGroup: "mcp", summary: "MCP configuration change") else { status.stringValue = "An update or MCP mutation is already running."; return }
295
295
  mutating = true; updateButtons(); _ = operations.update(operation, state: .running, stage: "apply", progress: nil, summary: "Applying scoped MCP change")
296
- processClient.run(args, stdin: stdin) { [weak self] result in
296
+ processClient.run(args, stdin: stdin, timeout: NativeView.mutationTimeout) { [weak self] result in
297
297
  guard let self = self else { return }
298
298
  self.mutating = false
299
299
  _ = self.operations.update(operation, state: result.code == 0 ? .succeeded : .failed, stage: "complete", progress: 1, summary: result.code == 0 ? "MCP change complete" : "MCP change failed")
@@ -310,7 +310,14 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
310
310
  private func writableScopeForBackup() -> String? { let scope = selectedScope(); return scope == "global" || scope == "project" ? scope : nil }
311
311
  private func scopeContext(_ scope: String, mutation: Bool) -> [String] { scope == "project" ? projectContext(mutation: mutation) : [] }
312
312
  private func projectContext(mutation: Bool) -> [String] { var args = ["--project-root", AppRuntime.projectRoot, "--trusted-project"]; if mutation { args.append("--confirm-project") }; return args }
313
- private func json(_ text: String) -> [String: Any]? { guard let data = text.data(using: .utf8) else { return nil }; return try? JSONSerialization.jsonObject(with: data) as? [String: Any] }
313
+ private func json(_ text: String) -> [String: Any]? {
314
+ guard let data = text.data(using: .utf8) else { return nil }
315
+ if let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { return object }
316
+ guard let start = text.range(of: "{", options: [.backwards])?.lowerBound else { return nil }
317
+ let slice = String(text[start...])
318
+ guard let sliced = slice.data(using: .utf8) else { return nil }
319
+ return try? JSONSerialization.jsonObject(with: sliced) as? [String: Any]
320
+ }
314
321
  private func jsonText(_ payload: [String: Any]) -> String? { guard let data = try? JSONSerialization.data(withJSONObject: payload) else { return nil }; return String(data: data, encoding: .utf8).map { $0 + "\n" } }
315
322
  private func actionButton(_ title: String, _ action: Selector) -> NSButton { NativeView.button(title, target: self, action: action) }
316
323
  private func updateButtons() {
@@ -89,6 +89,9 @@ enum OverviewSummary {
89
89
  let menu = update["menubar"] as? [String: Any]
90
90
  lines.append("SKS install: \(versionSummary(sks))")
91
91
  lines.append("Codex CLI: \(versionSummary(codex)) · Codex app: \(codexAppState)")
92
+ if let inducement = codexUpdateInducement(codex) {
93
+ lines.append(inducement)
94
+ }
92
95
 
93
96
  var menuParts = ["running build \(menuBarBuild)"]
94
97
  if let expected = menu?["expected_version"] as? String { menuParts.append("expected \(expected)") }
@@ -185,6 +188,13 @@ enum OverviewSummary {
185
188
  return "\(current) · latest \(latest)"
186
189
  }
187
190
 
191
+ private static func codexUpdateInducement(_ value: [String: Any]?) -> String? {
192
+ guard value?["update_available"] as? Bool == true else { return nil }
193
+ let current = nonEmpty(value?["current"] as? String) ?? "installed"
194
+ let latest = nonEmpty(value?["latest"] as? String) ?? "preferred latest"
195
+ return "Action: update Codex CLI (\(current) → \(latest)) from Updates, or choose Update Codex CLI Now in the menu bar."
196
+ }
197
+
188
198
  private static func verificationState(_ value: Any?) -> String {
189
199
  guard let value = value as? Bool else { return "unknown" }
190
200
  return value ? "verified" : "needs attention"
@@ -227,6 +237,7 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
227
237
  private var generation = 0
228
238
  private var doctorButton: NSButton!
229
239
  private var refreshButton: NSButton!
240
+ private var updateCodexButton: NSButton!
230
241
 
231
242
  init(processClient: ProcessClient, operations: OperationCoordinator) {
232
243
  self.processClient = processClient
@@ -238,12 +249,14 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
238
249
  override func loadView() {
239
250
  doctorButton = NativeView.button("Run Doctor", target: self, action: #selector(doctor))
240
251
  refreshButton = NativeView.button("Refresh", target: self, action: #selector(refreshStatus))
241
- let buttons = NSStackView(views: [doctorButton, refreshButton])
252
+ updateCodexButton = NativeView.button("Update Codex CLI", target: self, action: #selector(updateCodexCLI))
253
+ updateCodexButton.setAccessibilityHelp("Update the operator Codex CLI to the preferred latest channel.")
254
+ let buttons = NSStackView(views: [doctorButton, refreshButton, updateCodexButton])
242
255
  buttons.orientation = .horizontal
243
256
  buttons.spacing = 8
244
257
  view = NativeView.stack([
245
258
  NativeView.title("Overview"),
246
- NativeView.detail("Menu Bar build \(AppRuntime.packageVersion) · Local health for SKS, Codex CLI, MCP, Remote, and operations."),
259
+ NativeView.detail("Menu Bar build \(AppRuntime.packageVersion) · Local health for SKS, Codex CLI, MCP, Remote, and operations. Prefer the latest Codex CLI; SKS stays version-agnostic and capability-gates features."),
247
260
  status,
248
261
  notificationInbox,
249
262
  buttons
@@ -265,6 +278,39 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
265
278
  loadStatus(forceUpdateRefresh: true)
266
279
  }
267
280
 
281
+ @objc private func updateCodexCLI() {
282
+ guard let operation = operations.begin(kind: "codex-cli-update", mutationGroup: "update", summary: "Update Codex CLI") else {
283
+ status.stringValue = "Another update or MCP mutation is already running. Open Updates to review it."
284
+ return
285
+ }
286
+ updateCodexButton?.isEnabled = false
287
+ doctorButton?.isEnabled = false
288
+ refreshButton?.isEnabled = false
289
+ status.stringValue = "Updating Codex CLI to the preferred latest…"
290
+ _ = operations.update(operation, state: .running, stage: "running", progress: nil, summary: status.stringValue)
291
+ processClient.run(["codex", "update", "--json"], timeout: nil) { [weak self] result in
292
+ guard let self = self else { return }
293
+ let ok = result.code == 0
294
+ && !result.truncated
295
+ && (self.json(result.output)?["ok"] as? Bool == true)
296
+ && (self.json(result.output)?["schema"] as? String == "sks.codex-cli-update-result.v1")
297
+ _ = self.operations.update(
298
+ operation,
299
+ state: ok ? .succeeded : .failed,
300
+ stage: "complete",
301
+ progress: 1,
302
+ summary: ok ? "Codex CLI update completed" : "Codex CLI update failed"
303
+ )
304
+ self.updateCodexButton?.isEnabled = true
305
+ self.doctorButton?.isEnabled = true
306
+ self.refreshButton?.isEnabled = true
307
+ self.status.stringValue = ok
308
+ ? "Codex CLI update completed. Refreshing shared update status…"
309
+ : "Codex CLI update needs attention. Open Updates or Diagnostics for structured guidance."
310
+ self.loadStatus(forceUpdateRefresh: true)
311
+ }
312
+ }
313
+
268
314
  private func loadStatus(forceUpdateRefresh: Bool) {
269
315
  generation += 1
270
316
  let requestGeneration = generation
@@ -353,6 +399,12 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
353
399
 
354
400
  private func json(_ text: String) -> [String: Any]? {
355
401
  guard let data = text.data(using: .utf8) else { return nil }
356
- return try? JSONSerialization.jsonObject(with: data) as? [String: Any]
402
+ if let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { return object }
403
+ // Child processes may print banner lines before JSON (for example a
404
+ // migration gate message). Prefer the last top-level object payload.
405
+ guard let start = text.range(of: "{", options: [.backwards])?.lowerBound else { return nil }
406
+ let slice = String(text[start...])
407
+ guard let sliced = slice.data(using: .utf8) else { return nil }
408
+ return try? JSONSerialization.jsonObject(with: sliced) as? [String: Any]
357
409
  }
358
410
  }
@@ -0,0 +1,76 @@
1
+ import Cocoa
2
+
3
+ extension ProvidersViewController {
4
+ func refreshOpenRouterStatus() {
5
+ processClient.run(["codex-app", "openrouter-status", "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
6
+ guard let self = self else { return }
7
+ guard result.code == 0, let json = self.json(result.output) else {
8
+ if !self.busy { self.openRouterStatus.stringValue = "OpenRouter: status unavailable." }
9
+ return
10
+ }
11
+ let current = self.openRouterModelField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
12
+ if let model = json["model"] as? String, !model.isEmpty, current.isEmpty || current == "z-ai/glm-5.2" {
13
+ self.openRouterModelField.stringValue = model
14
+ }
15
+ if !self.busy { self.openRouterStatus.stringValue = self.describeOpenRouterStatus(json) }
16
+ }
17
+ }
18
+
19
+ func describeOpenRouterStatus(_ json: [String: Any]) -> String {
20
+ let keyPresent = json["key_present"] as? Bool == true
21
+ let providerPresent = json["provider_present"] as? Bool == true
22
+ let selected = json["selected"] as? Bool == true
23
+ let model = json["model"] as? String ?? "unset"
24
+ if !keyPresent { return "OpenRouter: key missing. Save OpenRouter key, then Use OpenRouter." }
25
+ if !providerPresent { return "OpenRouter: provider missing. Save OpenRouter key to install the provider block." }
26
+ if selected { return "OpenRouter: active · model \(model). Restore Chat / Pro or Use codex-lb to switch away." }
27
+ return "OpenRouter: key stored · model \(model) · not selected. Click Use OpenRouter."
28
+ }
29
+
30
+ @objc func saveOpenRouterKey() {
31
+ guard let window = view.window else { return }
32
+ promptForSecretKey(
33
+ window: window,
34
+ sheetTitle: "OpenRouter API Key",
35
+ sheetMessage: "Paste your OpenRouter API key. It is sent through stdin and never logged. Saving does not switch the active provider.",
36
+ placeholder: "sk-or-…",
37
+ args: ["codex-app", "set-openrouter-key", "--api-key-stdin", "--json"],
38
+ kind: "openrouter-set-key",
39
+ title: "Save OpenRouter key",
40
+ statusLabel: openRouterStatus,
41
+ successSummary: "OpenRouter key saved",
42
+ failSummary: "OpenRouter key save failed"
43
+ )
44
+ }
45
+
46
+ @objc func useOpenRouter() {
47
+ let model = openRouterModelField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
48
+ guard !model.isEmpty else {
49
+ openRouterStatus.stringValue = "Enter an OpenRouter model id, then click Use OpenRouter."
50
+ return
51
+ }
52
+ guard !busy else {
53
+ openRouterStatus.stringValue = "Another provider action is already running."
54
+ return
55
+ }
56
+ guard let snapshot = operations.begin(kind: "openrouter-use", mutationGroup: "codex-config", summary: "Use OpenRouter") else {
57
+ openRouterStatus.stringValue = "Another guarded mutation is already running. Wait or open Diagnostics."
58
+ return
59
+ }
60
+ setBusy(true)
61
+ openRouterStatus.stringValue = "Activating OpenRouter (\(model)) and restarting Codex App…"
62
+ _ = operations.update(snapshot, state: .running, stage: "activating", progress: nil, summary: "Use OpenRouter")
63
+ processClient.run(["codex-app", "use-openrouter", "--model", model, "--restart-app", "--json"], timeout: NativeView.mutationTimeout) { [weak self] result in
64
+ guard let self = self else { return }
65
+ self.setBusy(false)
66
+ let json = self.json(result.output)
67
+ let ok = result.code == 0 && json?["ok"] as? Bool == true
68
+ let activeModel = (json?["model"] as? String) ?? model
69
+ _ = self.operations.update(snapshot, state: ok ? .succeeded : .failed, stage: "complete", progress: 1, summary: ok ? "OpenRouter active after restart" : "OpenRouter activation needs action")
70
+ self.openRouterStatus.stringValue = ok
71
+ ? "OpenRouter: active · model \(activeModel)."
72
+ : "Use OpenRouter failed · \(NativeView.redactPreview(result.output))"
73
+ self.refresh()
74
+ }
75
+ }
76
+ }