sneakoscope 6.1.0 → 6.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 (246) hide show
  1. package/README.md +35 -11
  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 +18 -9
  5. package/dist/bin/sks-dispatch.js +2 -2
  6. package/dist/cli/args.js +2 -0
  7. package/dist/cli/command-manifest-lite.js +2 -3
  8. package/dist/cli/command-registry.js +3 -4
  9. package/dist/cli/help-fast.js +1 -1
  10. package/dist/cli/install-helpers.js +116 -306
  11. package/dist/cli/install-tool-helpers.js +287 -0
  12. package/dist/cli/router.js +40 -4
  13. package/dist/commands/codex-lb.js +51 -20
  14. package/dist/commands/codex.js +39 -1
  15. package/dist/commands/doctor.js +242 -20
  16. package/dist/commands/tmux.js +5 -1
  17. package/dist/commands/zellij-monitor-pane.js +2 -0
  18. package/dist/commands/zellij-viewport-pane.js +3 -1
  19. package/dist/commands/zellij.js +1 -1
  20. package/dist/config/skills-manifest.json +59 -59
  21. package/dist/core/agent-bridge/agent-manifest.js +48 -0
  22. package/dist/core/agents/agent-command-surface.js +2 -1
  23. package/dist/core/agents/agent-effort-policy.js +38 -35
  24. package/dist/core/agents/agent-plan.js +100 -21
  25. package/dist/core/agents/agent-role-config.js +43 -46
  26. package/dist/core/agents/agent-runner-codex-exec.js +16 -3
  27. package/dist/core/agents/agent-schema.js +3 -2
  28. package/dist/core/agents/native-cli-session-swarm.js +1 -1
  29. package/dist/core/agents/zellij-right-lane-cockpit.js +2 -2
  30. package/dist/core/codex/agent-config-file-repair.js +94 -193
  31. package/dist/core/codex/codex-cli-update.js +723 -0
  32. package/dist/core/codex/codex-config-guard.js +185 -9
  33. package/dist/core/codex/codex-config-readability.js +21 -8
  34. package/dist/core/codex/codex-config-toml.js +14 -11
  35. package/dist/core/codex/codex-project-config-policy.js +3 -6
  36. package/dist/core/codex/codex-startup-config-postcheck.js +52 -42
  37. package/dist/core/codex-adapter.js +35 -22
  38. package/dist/core/codex-app/codex-agent-role-sync.js +13 -54
  39. package/dist/core/codex-app/codex-app-launcher.js +48 -17
  40. package/dist/core/codex-app/codex-app-restart.js +23 -2
  41. package/dist/core/codex-app/mcp-manager.js +679 -0
  42. package/dist/core/codex-app/sks-menubar.js +533 -8
  43. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +15 -4
  44. package/dist/core/codex-control/codex-0139-web-search-probe.js +17 -6
  45. package/dist/core/codex-control/codex-lb-launch-recovery.js +293 -0
  46. package/dist/core/codex-control/codex-reliability-shield.js +89 -29
  47. package/dist/core/codex-control/codex-sdk-adapter.js +44 -8
  48. package/dist/core/codex-control/codex-task-runner.js +62 -9
  49. package/dist/core/codex-control/python-codex-sdk-adapter.js +30 -3
  50. package/dist/core/codex-exec-output-schema.js +35 -6
  51. package/dist/core/codex-lb/codex-lb-env.js +1 -1
  52. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +291 -0
  53. package/dist/core/codex-native/codex-native-feature-broker.js +9 -16
  54. package/dist/core/codex-native/codex-native-repair-transaction.js +1 -1
  55. package/dist/core/codex-native/core-skill-manifest.js +8 -4
  56. package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -3
  57. package/dist/core/commands/agent-bridge-command.js +23 -2
  58. package/dist/core/commands/agent-command.js +19 -5
  59. package/dist/core/commands/basic-cli.js +47 -6
  60. package/dist/core/commands/command-utils.js +1 -1
  61. package/dist/core/commands/mad-sks-command.js +76 -10
  62. package/dist/core/commands/menubar-command.js +94 -0
  63. package/dist/core/commands/naruto-command.js +645 -1156
  64. package/dist/core/commands/research-command.js +293 -231
  65. package/dist/core/commands/run-command.js +100 -23
  66. package/dist/core/commands/team-command.js +2 -3
  67. package/dist/core/commands/team-legacy-observe-command.js +94 -359
  68. package/dist/core/commands/wiki-command.js +11 -5
  69. package/dist/core/db-safety.js +2 -2
  70. package/dist/core/decision-lattice.js +6 -6
  71. package/dist/core/doctor/codex-startup-config-repair.js +8 -3
  72. package/dist/core/doctor/doctor-codex-startup-repair.js +6 -141
  73. package/dist/core/feature-fixture-executor.js +71 -7
  74. package/dist/core/feature-fixture-runner.js +53 -12
  75. package/dist/core/feature-fixtures.js +47 -14
  76. package/dist/core/feature-registry.js +28 -27
  77. package/dist/core/fsx.js +1 -0
  78. package/dist/core/harness-conflicts.js +18 -9
  79. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +14 -8
  80. package/dist/core/hooks-runtime/hook-io.js +8 -4
  81. package/dist/core/hooks-runtime/light-turn.js +70 -0
  82. package/dist/core/hooks-runtime/naruto-decision-gate.js +184 -0
  83. package/dist/core/hooks-runtime/payload-signals.js +270 -0
  84. package/dist/core/hooks-runtime/stop-repeat-guard.js +89 -0
  85. package/dist/core/hooks-runtime/team-digest.js +0 -1
  86. package/dist/core/hooks-runtime/tool-output-quarantine.js +93 -0
  87. package/dist/core/hooks-runtime.js +438 -354
  88. package/dist/core/init/skills.js +16 -30
  89. package/dist/core/init.js +144 -36
  90. package/dist/core/managed-assets/managed-assets-manifest.js +566 -10
  91. package/dist/core/mission.js +24 -1
  92. package/dist/core/pipeline-internals/runtime-core.js +570 -177
  93. package/dist/core/pipeline-internals/runtime-gates.js +174 -48
  94. package/dist/core/preflight/parallel-preflight-engine.js +66 -4
  95. package/dist/core/proof/route-adapter.js +1 -1
  96. package/dist/core/proof/route-proof-gate.js +7 -2
  97. package/dist/core/proof/selftest-proof-fixtures.js +3 -5
  98. package/dist/core/proof-field.js +1 -1
  99. package/dist/core/provider/model-router.js +42 -31
  100. package/dist/core/recallpulse/policy.js +12 -28
  101. package/dist/core/recallpulse.js +11 -6
  102. package/dist/core/release/npm-pack-proof.js +247 -0
  103. package/dist/core/release/package-dist-snapshot.js +151 -0
  104. package/dist/core/release/package-size-budget.js +4 -1
  105. package/dist/core/release/release-authorization-snapshot.js +115 -0
  106. package/dist/core/release/release-gate-affected-selector.js +14 -2
  107. package/dist/core/release/release-gate-cache-v2.js +30 -0
  108. package/dist/core/release/release-gate-contract.js +161 -0
  109. package/dist/core/release/release-gate-dag.js +1 -0
  110. package/dist/core/release/release-real-contract.js +90 -10
  111. package/dist/core/release-parallel-full-coverage.js +31 -143
  112. package/dist/core/research/claim-evidence-matrix.js +41 -6
  113. package/dist/core/research/experiment-plan.js +14 -10
  114. package/dist/core/research/falsification.js +9 -2
  115. package/dist/core/research/implementation-blueprint-densifier.js +82 -60
  116. package/dist/core/research/implementation-blueprint.js +32 -26
  117. package/dist/core/research/mock-result.js +122 -11
  118. package/dist/core/research/replication-pack.js +15 -8
  119. package/dist/core/research/research-adversarial-review.js +1068 -0
  120. package/dist/core/research/research-claim-builder.js +69 -17
  121. package/dist/core/research/research-claim-synthesizer.js +343 -0
  122. package/dist/core/research/research-cycle-runner.js +53 -3
  123. package/dist/core/research/research-falsification-runner.js +176 -0
  124. package/dist/core/research/research-final-reviewer.js +44 -125
  125. package/dist/core/research/research-plan-markdown.js +123 -0
  126. package/dist/core/research/research-realistic-report.js +14 -6
  127. package/dist/core/research/research-review-artifact-digest.js +66 -0
  128. package/dist/core/research/research-source-evidence.js +144 -0
  129. package/dist/core/research/research-source-layer-catalog.js +68 -0
  130. package/dist/core/research/research-source-ledger-merge.js +250 -12
  131. package/dist/core/research/research-source-shards.js +26 -70
  132. package/dist/core/research/research-stage-runner.js +237 -247
  133. package/dist/core/research/research-super-search.js +188 -0
  134. package/dist/core/research/research-synthesis-prompt.js +20 -1
  135. package/dist/core/research/research-synthesis-writer.js +86 -5
  136. package/dist/core/research/research-work-graph.js +25 -18
  137. package/dist/core/research/source-quality-report.js +21 -0
  138. package/dist/core/research.js +424 -390
  139. package/dist/core/retention.js +70 -2
  140. package/dist/core/routes/constants.js +1 -1
  141. package/dist/core/routes/dollar-manifest-lite.js +11 -11
  142. package/dist/core/routes.js +149 -69
  143. package/dist/core/runtime/task-profile.js +66 -0
  144. package/dist/core/runtime/verification-budget.js +12 -0
  145. package/dist/core/security/high-risk-contracts.js +6 -6
  146. package/dist/core/stop-gate/stop-gate-check.js +49 -12
  147. package/dist/core/subagents/agent-catalog.js +287 -0
  148. package/dist/core/subagents/model-policy.js +259 -0
  149. package/dist/core/subagents/naruto-help-contract.js +47 -0
  150. package/dist/core/subagents/official-subagent-config.js +488 -0
  151. package/dist/core/subagents/official-subagent-preparation.js +297 -0
  152. package/dist/core/subagents/official-subagent-prompt.js +159 -0
  153. package/dist/core/subagents/official-subagent-runner.js +129 -0
  154. package/dist/core/subagents/subagent-evidence.js +663 -0
  155. package/dist/core/subagents/terminology.js +16 -0
  156. package/dist/core/subagents/thread-budget.js +21 -0
  157. package/dist/core/subagents/triwiki-attention.js +168 -0
  158. package/dist/core/super-search/runtime-helpers.js +173 -19
  159. package/dist/core/super-search/runtime.js +140 -15
  160. package/dist/core/super-search/source-records.js +49 -8
  161. package/dist/core/team-review-policy.js +15 -0
  162. package/dist/core/triwiki/code-pack-head-freshness.js +291 -0
  163. package/dist/core/triwiki/triwiki-module-card.js +1 -1
  164. package/dist/core/triwiki-wrongness/wrongness-ledger.js +9 -2
  165. package/dist/core/version-manager.js +51 -1
  166. package/dist/core/version.js +1 -1
  167. package/dist/core/work-order-ledger.js +40 -1
  168. package/dist/core/zellij/zellij-fake-adapter.js +3 -1
  169. package/dist/core/zellij/zellij-launcher.js +49 -10
  170. package/dist/core/zellij/zellij-layout-builder.js +14 -5
  171. package/dist/core/zellij/zellij-official-subagent-activity.js +477 -0
  172. package/dist/core/zellij/zellij-official-subagent-telemetry.js +264 -0
  173. package/dist/core/zellij/zellij-pane-proof.js +9 -1
  174. package/dist/core/zellij/zellij-slot-pane-renderer.js +17 -5
  175. package/dist/core/zellij/zellij-slot-telemetry.js +15 -3
  176. package/dist/core/zellij/zellij-ui-mode.js +1 -1
  177. package/dist/core/zellij/zellij-update.js +14 -1
  178. package/dist/core/zellij/zellij-viewport-binder.js +3 -0
  179. package/dist/scripts/agent-role-config-repair-check.js +14 -16
  180. package/dist/scripts/architecture-guard-check.js +8 -1
  181. package/dist/scripts/canonical-test-runner.js +7 -1
  182. package/dist/scripts/check-route-modularity.js +0 -1
  183. package/dist/scripts/check-ts-contracts.js +1 -1
  184. package/dist/scripts/codex-control-all-pipelines-check.js +7 -3
  185. package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +27 -0
  186. package/dist/scripts/codex-lb-fast-mode-truth-check.js +11 -1
  187. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +9 -2
  188. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +13 -2
  189. package/dist/scripts/codex-native-agent-role-content-check.js +27 -7
  190. package/dist/scripts/codex-native-repair-transaction-check.js +3 -1
  191. package/dist/scripts/codex-sdk-all-pipelines-check.js +7 -4
  192. package/dist/scripts/codex-sdk-backend-router-check.js +2 -0
  193. package/dist/scripts/codex-sdk-research-pipeline-check.js +30 -8
  194. package/dist/scripts/db-route-materialization-check.js +33 -0
  195. package/dist/scripts/docs-truthfulness-check.js +3 -1
  196. package/dist/scripts/doctor-codex-startup-repair-check.js +12 -15
  197. package/dist/scripts/doctor-fix-production-blackbox.js +12 -2
  198. package/dist/scripts/doctor-startup-config-repair-blackbox.js +8 -2
  199. package/dist/scripts/doctor-startup-config-repair-check.js +12 -2
  200. package/dist/scripts/install-update-preserves-config-check.js +6 -1
  201. package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
  202. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +0 -1
  203. package/dist/scripts/managed-role-manifest-parity-check.js +5 -4
  204. package/dist/scripts/naruto-codex-e2e-check.js +14 -7
  205. package/dist/scripts/naruto-shadow-clone-swarm-check.js +4 -201
  206. package/dist/scripts/npm-publish-performance-check.js +20 -12
  207. package/dist/scripts/official-subagent-workflow-check.js +145 -0
  208. package/dist/scripts/package-published-contract-check.js +6 -29
  209. package/dist/scripts/packlist-performance-check.js +18 -21
  210. package/dist/scripts/parallel-verification-engine-check.js +2 -2
  211. package/dist/scripts/prepublish-release-check-or-fast.js +23 -86
  212. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +8 -0
  213. package/dist/scripts/release-affected-selector-check.js +74 -1
  214. package/dist/scripts/release-check-stamp.js +153 -248
  215. package/dist/scripts/release-dag-full-coverage-check.js +7 -15
  216. package/dist/scripts/release-dynamic-presets-check.js +2 -1
  217. package/dist/scripts/release-gate-dag-runner-check.js +0 -1
  218. package/dist/scripts/release-gate-dag-runner.js +12 -1
  219. package/dist/scripts/release-gate-existence-audit.js +1 -2
  220. package/dist/scripts/release-parallel-full-coverage-check.js +12 -6
  221. package/dist/scripts/release-parallel-speed-budget-check.js +18 -2
  222. package/dist/scripts/release-real-check.js +26 -4
  223. package/dist/scripts/release-registry-check.js +61 -16
  224. package/dist/scripts/research-blueprint-densifier-check.js +2 -2
  225. package/dist/scripts/research-real-cycle-no-legacy-final-md-check.js +11 -7
  226. package/dist/scripts/sizecheck.js +2 -2
  227. package/dist/scripts/sks-3-1-4-directive-check-lib.js +8 -2
  228. package/dist/scripts/sks-3-1-5-directive-check-lib.js +3 -2
  229. package/dist/scripts/sks-3-1-6-directive-check-lib.js +5 -3
  230. package/dist/scripts/sks-menubar-install-check.js +14 -1
  231. package/dist/scripts/super-search-provider-interface-check.js +31 -18
  232. package/dist/scripts/trust-fixture-check.js +32 -10
  233. package/dist/scripts/wrongness-fixture-check.js +1 -1
  234. package/dist/scripts/zellij-layout-valid-check.js +5 -5
  235. package/dist/scripts/zellij-spawn-on-demand-layout-check.js +3 -3
  236. package/docs/demo.tape +1 -1
  237. package/infra-harness-gates.json +1486 -0
  238. package/package.json +15 -10
  239. package/release-gates.v2.json +4060 -0
  240. package/runtime-required-scripts.json +9 -0
  241. package/dist/commands/db.js +0 -6
  242. package/dist/core/commands/db-command.js +0 -146
  243. package/dist/core/research/prompt.js +0 -15
  244. package/dist/scripts/codex-0139-feature-probes-check.js +0 -30
  245. package/dist/scripts/codex-0139-marketplace-source-check.js +0 -13
  246. package/dist/scripts/codex-control-tool-call-sequence-repair-check.js +0 -14
@@ -17,6 +17,7 @@ import { cleanupMacLaunchSecretEnvironment } from '../core/codex-app/sks-menubar
17
17
  import { recordCodexLbHealthEvent } from '../core/codex-lb-circuit.js';
18
18
  import { loadCodexLbEnv, writeCodexLbKeychain, codexLbMetadataPath } from '../core/codex-lb/codex-lb-env.js';
19
19
  import { codexLbToolCatalogPath, ensureCodexLbToolCatalog } from '../core/codex-lb/codex-lb-tool-catalog.js';
20
+ import { codexLbToolOutputRecoveryNotChecked, codexLbToolOutputRecoveryNotSelected, codexLbToolOutputRecoveryOverrideAcknowledged, probeCodexLbToolOutputRecovery } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
20
21
  import { GLM_CODEX_CONFIG_PROFILE_ID, GLM_CODEX_CONFIG_PROVIDER_ID, GLM_CODEX_CONFIG_REASONING_PROFILES } from '../core/providers/glm/glm-52-profile.js';
21
22
  import { GLM_52_OPENROUTER_MODEL } from '../core/providers/glm/glm-52-settings.js';
22
23
  import { buildCodexLbSetupPlan, codexLbPersistenceSummary, installCodexLbShellProfileSnippet, selectedCodexLbPersistenceModes } from '../core/codex-lb/codex-lb-setup.js';
@@ -24,6 +25,8 @@ import { extractTomlTable, writeCodexConfigGuarded } from '../core/codex/codex-c
24
25
  import { ensureGlobalCodexFastModeDuringInstall, ensureTrailingNewline, normalizeCodexFastModeUiConfig, removeTopLevelTomlKeyIfValue, safeWriteCodexConfigToml, upsertTopLevelTomlString, upsertTomlTable } from '../core/codex-runtime/codex-desktop-config-policy.js';
25
26
  import { runPostinstallGlobalDoctorAndMarkPending } from '../core/update/update-migration-state.js';
26
27
  import { repairCodexImagegen } from '../core/doctor/imagegen-repair.js';
28
+ import { canAskYesNo, compareVersions, hasCodexUnstableFeatureWarningSuppression, hasDeprecatedCodexHooksFeatureFlag, hasTopLevelCodexModeLock, isProjectSetupCandidate } from './install-tool-helpers.js';
29
+ export { checkContext7, ensureCodexCliTool, ensureMadLaunchDependencies, ensureRelatedCliTools, ensureZellijCliTool, formatMadLaunchDependencyAction, maybePromptCodexUpdateForLaunch, maybePromptSksUpdateForLaunch, shouldAutoApproveInstall } from './install-tool-helpers.js';
27
30
  export { codexFastModeDesktopStatus, ensureGlobalCodexFastModeDuringInstall, normalizeCodexFastModeUiConfig, safeWriteCodexConfigToml } from '../core/codex-runtime/codex-desktop-config-policy.js';
28
31
  const CODEX_LB_PROVIDER_NAME = 'openai';
29
32
  const CODEX_LB_PROVIDER_ENV_KEY = 'CODEX_LB_API_KEY';
@@ -515,6 +518,26 @@ export async function configureCodexLb(opts = {}) {
515
518
  return { ok: false, status: 'invalid_host_or_base_url', config_path: configPath, env_path: envPath, error: 'host_or_base_url_contains_whitespace_or_control_character' };
516
519
  if (!apiKey)
517
520
  return { ok: false, status: 'missing_api_key', config_path: configPath, env_path: envPath };
521
+ const toolOutputRecovery = await probeCodexLbToolOutputRecovery({
522
+ baseUrl,
523
+ ...(typeof opts.toolOutputRecoveryFetch === 'function' ? { fetchImpl: opts.toolOutputRecoveryFetch } : {}),
524
+ timeoutMs: Number(opts.toolOutputRecoveryTimeoutMs || 4_000),
525
+ allowUnverified: opts.allowUnverifiedToolOutputRecovery === true
526
+ || codexLbToolOutputRecoveryOverrideAcknowledged({ env: opts.env || process.env })
527
+ });
528
+ if (!toolOutputRecovery.ok) {
529
+ return {
530
+ ok: false,
531
+ status: 'tool_output_recovery_blocked',
532
+ plan: plan,
533
+ config_path: configPath,
534
+ env_path: envPath,
535
+ base_url: baseUrl,
536
+ tool_output_recovery: toolOutputRecovery,
537
+ drift: toolOutputRecovery.blockers,
538
+ warnings: toolOutputRecovery.warnings
539
+ };
540
+ }
518
541
  const insecureLocalWarning = /^http:\/\//i.test(baseUrl) && !/^http:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::|\/|$)/i.test(baseUrl) && !opts.allowInsecureHttp
519
542
  ? ['codex-lb base URL uses http outside localhost; prefer https or pass an explicit allow flag in the calling surface.']
520
543
  : [];
@@ -628,6 +651,7 @@ export async function configureCodexLb(opts = {}) {
628
651
  codex_environment: codexEnvironment,
629
652
  codex_login: codexLogin,
630
653
  tool_catalog: toolCatalog,
654
+ tool_output_recovery: toolOutputRecovery,
631
655
  error: authReconcile.error || codexEnvironment.error || codexLogin.error || null
632
656
  };
633
657
  }
@@ -667,8 +691,22 @@ export async function codexLbStatus(opts = {}) {
667
691
  status: 'inspect_failed',
668
692
  error: err.message
669
693
  }));
694
+ const providerReady = providerContractOk && envKeyConfigured && Boolean(baseUrl) && authMode.codex_app_usable;
695
+ const probeToolOutputRecovery = opts.probeToolOutputRecovery === true;
696
+ const toolOutputRecovery = !selected
697
+ ? codexLbToolOutputRecoveryNotSelected()
698
+ : !probeToolOutputRecovery
699
+ ? codexLbToolOutputRecoveryNotChecked(true)
700
+ : await probeCodexLbToolOutputRecovery({
701
+ baseUrl,
702
+ ...(typeof opts.toolOutputRecoveryFetch === 'function' ? { fetchImpl: opts.toolOutputRecoveryFetch } : {}),
703
+ timeoutMs: Number(opts.toolOutputRecoveryTimeoutMs || 4_000),
704
+ allowUnverified: opts.allowUnverifiedToolOutputRecovery === true
705
+ || codexLbToolOutputRecoveryOverrideAcknowledged({ env: opts.env || process.env })
706
+ });
670
707
  return {
671
- ok: providerContractOk && envKeyConfigured && Boolean(baseUrl) && authMode.codex_app_usable,
708
+ ok: providerReady && (!selected || !probeToolOutputRecovery || toolOutputRecovery.ok),
709
+ provider_ready: providerReady,
672
710
  config_path: configPath,
673
711
  env_path: envPath,
674
712
  provider_configured: providerConfigured,
@@ -699,7 +737,8 @@ export async function codexLbStatus(opts = {}) {
699
737
  auth_usable_for_codex_app: authMode.codex_app_usable || codexAppUsableWithCodexLb,
700
738
  auth_summary: codexAppUsableWithCodexLb ? `codex-lb provider uses ${authMode.mode} OpenAI-style auth through Codex App` : authMode.summary,
701
739
  fast_mode: fastMode,
702
- launch_environment: launchEnvironment
740
+ launch_environment: launchEnvironment,
741
+ tool_output_recovery: toolOutputRecovery
703
742
  };
704
743
  }
705
744
  export function formatCodexLbStatusText(status = {}, opts = {}) {
@@ -714,6 +753,14 @@ export function formatCodexLbStatusText(status = {}, opts = {}) {
714
753
  `Provider OpenAI Auth: ${status.provider_requires_openai_auth ? 'required' : 'not required/drifted'} (${status.provider_name || 'missing'})`,
715
754
  `Codex App auth: ${status.auth_usable_for_codex_app ? 'ok' : 'needs sign-in/repair'} (${status.auth_mode || 'unknown'})`
716
755
  ];
756
+ if (status.tool_output_recovery?.status && status.tool_output_recovery.status !== 'not_selected') {
757
+ const recovery = status.tool_output_recovery;
758
+ lines.push(`Interrupted tool-output recovery: ${recovery.ok ? 'ready' : 'blocked'} (${recovery.observed_version || recovery.status}; minimum ${recovery.minimum_version})`);
759
+ if (!recovery.ok) {
760
+ for (const action of recovery.operator_actions || [])
761
+ lines.push(` action: ${action}`);
762
+ }
763
+ }
717
764
  if (status.auth_summary)
718
765
  lines.push(`Auth detail: ${status.auth_summary}`);
719
766
  if (status.fast_mode) {
@@ -1088,17 +1135,39 @@ function tomlTableString(text = '', table, key) {
1088
1135
  return block.match(new RegExp(`(^|\\n)\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]+)"\\s*(?:#.*)?(?=\\n|$)`))?.[2] || '';
1089
1136
  }
1090
1137
  export async function repairCodexLbAuth(opts = {}) {
1091
- let status = await codexLbStatus(opts);
1138
+ let status = await codexLbStatus({
1139
+ ...opts,
1140
+ probeToolOutputRecovery: true,
1141
+ allowUnverifiedToolOutputRecovery: opts.allowUnverifiedToolOutputRecovery === true
1142
+ });
1092
1143
  let configRepaired = false;
1093
1144
  let legacyAuthMigrated = false;
1094
1145
  let legacyAuthPath = null;
1146
+ const toolOutputRecovery = status.base_url
1147
+ ? await probeCodexLbToolOutputRecovery({
1148
+ baseUrl: status.base_url,
1149
+ ...(typeof opts.toolOutputRecoveryFetch === 'function' ? { fetchImpl: opts.toolOutputRecoveryFetch } : {}),
1150
+ timeoutMs: Number(opts.toolOutputRecoveryTimeoutMs || 4_000),
1151
+ allowUnverified: opts.allowUnverifiedToolOutputRecovery === true
1152
+ || codexLbToolOutputRecoveryOverrideAcknowledged({ env: opts.env || process.env })
1153
+ })
1154
+ : status.tool_output_recovery;
1155
+ if (status.base_url && toolOutputRecovery?.ok !== true) {
1156
+ return {
1157
+ ok: false,
1158
+ status: 'tool_output_recovery_blocked',
1159
+ codex_lb: status,
1160
+ tool_output_recovery: toolOutputRecovery,
1161
+ error: toolOutputRecovery?.blockers?.join(', ') || 'codex-lb interrupted tool-output recovery is unverified'
1162
+ };
1163
+ }
1095
1164
  const currentConfig = await readText(status.config_path, '');
1096
1165
  if (!status.env_key_configured && status.base_url && (status.provider_configured || status.selected || status.env_base_url_configured)) {
1097
1166
  const legacyAuth = await restoreCodexLbEnvFromSharedLogin(status, opts);
1098
1167
  if (legacyAuth.ok) {
1099
1168
  legacyAuthMigrated = true;
1100
1169
  legacyAuthPath = legacyAuth.auth_path;
1101
- status = await codexLbStatus(opts);
1170
+ status = await codexLbStatus({ ...opts, probeToolOutputRecovery: true });
1102
1171
  }
1103
1172
  }
1104
1173
  if (status.env_key_configured && status.base_url && (!status.provider_contract_ok || !status.selected || legacyAuthMigrated || hasTopLevelCodexModeLock(currentConfig) || (opts.forceCodexLbApiKeyAuth === true && !status.ok))) {
@@ -1109,7 +1178,7 @@ export async function repairCodexLbAuth(opts = {}) {
1109
1178
  });
1110
1179
  const safeWrite = await safeWriteCodexConfigToml(status.config_path, currentConfig, next, 'codex-lb-repair');
1111
1180
  configRepaired = safeWrite.ok && safeWrite.changed === true;
1112
- status = await codexLbStatus(opts);
1181
+ status = await codexLbStatus({ ...opts, probeToolOutputRecovery: true });
1113
1182
  }
1114
1183
  const canRepairAuthMode = opts.forceCodexLbApiKeyAuth === true && status.provider_contract_ok && status.env_key_configured && Boolean(status.base_url);
1115
1184
  if (!status.ok && !canRepairAuthMode) {
@@ -1135,7 +1204,7 @@ export async function repairCodexLbAuth(opts = {}) {
1135
1204
  const codexLogin = forceCodexLbApiKeyAuth
1136
1205
  ? { ok: ['apikey_forced', 'apikey_auth_active'].includes(authReconcile.status), status: authReconcile.status, ...(authReconcile.reason ? { reason: authReconcile.reason } : {}), error: authReconcile.error || null }
1137
1206
  : await maybeSyncCodexLbSharedLogin(apiKey, { ...opts, home: opts.home || process.env.HOME || os.homedir(), force: true });
1138
- const finalStatus = await codexLbStatus(opts);
1207
+ const finalStatus = await codexLbStatus({ ...opts, probeToolOutputRecovery: true });
1139
1208
  const ok = Boolean(codexEnvironment.ok && codexLogin.ok && (toolCatalog.required === false || toolCatalog.ok === true));
1140
1209
  return {
1141
1210
  ok,
@@ -1666,7 +1735,24 @@ async function rollbackCodexAuthRestore(input) {
1666
1735
  export async function maybePromptCodexLbSetupForLaunch(args = [], opts = {}) {
1667
1736
  if (args.includes('--json') || args.includes('--skip-codex-lb') || process.env.SKS_SKIP_CODEX_LB_PROMPT === '1')
1668
1737
  return { status: 'skipped' };
1669
- let status = await codexLbStatus(opts);
1738
+ const allowUnverifiedToolOutputRecovery = opts.allowUnverifiedToolOutputRecovery === true
1739
+ || codexLbToolOutputRecoveryOverrideAcknowledged({ args, env: opts.env || process.env });
1740
+ let status = await codexLbStatus({
1741
+ ...opts,
1742
+ probeToolOutputRecovery: true,
1743
+ allowUnverifiedToolOutputRecovery
1744
+ });
1745
+ if (status.selected && status.tool_output_recovery?.ok !== true) {
1746
+ return {
1747
+ status: 'tool_output_recovery_blocked',
1748
+ ok: false,
1749
+ codex_lb: status,
1750
+ tool_output_recovery: status.tool_output_recovery,
1751
+ blockers: status.tool_output_recovery.blockers,
1752
+ operator_actions: status.tool_output_recovery.operator_actions,
1753
+ bypass_codex_lb: false
1754
+ };
1755
+ }
1670
1756
  if (status.env_key_configured && status.base_url && !status.selected && status.auth_mode === 'chatgpt_oauth') {
1671
1757
  return { status: 'continued_to_codex', ok: false, chain_health: null, codex_lb: status, reason: 'chatgpt_oauth_active_codex_lb_unselected' };
1672
1758
  }
@@ -1678,8 +1764,20 @@ export async function maybePromptCodexLbSetupForLaunch(args = [], opts = {}) {
1678
1764
  if (/^(n|no|아니|아니요|ㄴ)$/i.test(restore))
1679
1765
  return { status: 'continued_to_codex', codex_lb: status };
1680
1766
  }
1681
- const repaired = await repairCodexLbAuth(opts);
1682
- status = await codexLbStatus(opts);
1767
+ const repaired = await repairCodexLbAuth({ ...opts, allowUnverifiedToolOutputRecovery });
1768
+ status = await codexLbStatus({ ...opts, probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
1769
+ if (status.selected && status.tool_output_recovery?.ok !== true) {
1770
+ return {
1771
+ status: 'tool_output_recovery_blocked',
1772
+ ok: false,
1773
+ repair: repaired,
1774
+ codex_lb: status,
1775
+ tool_output_recovery: status.tool_output_recovery,
1776
+ blockers: status.tool_output_recovery.blockers,
1777
+ operator_actions: status.tool_output_recovery.operator_actions,
1778
+ bypass_codex_lb: false
1779
+ };
1780
+ }
1683
1781
  if (!status.ok)
1684
1782
  return { status: 'repair_failed', ok: false, repair: repaired, codex_lb: status };
1685
1783
  if (!repaired.ok && repaired.error && promptedRestore)
@@ -1746,7 +1844,7 @@ export async function maybePromptCodexLbSetupForLaunch(args = [], opts = {}) {
1746
1844
  return { status: 'continued_to_codex' };
1747
1845
  const host = (await askPostinstallQuestion('codex-lb host domain [http://127.0.0.1:2455]: ')).trim() || 'http://127.0.0.1:2455';
1748
1846
  const apiKey = (await askPostinstallQuestion('codex-lb API key: ')).trim();
1749
- const configured = await configureCodexLb({ ...opts, host, apiKey });
1847
+ const configured = await configureCodexLb({ ...opts, host, apiKey, allowUnverifiedToolOutputRecovery });
1750
1848
  if (configured.ok)
1751
1849
  console.log(`codex-lb configured: ${configured.base_url}`);
1752
1850
  else
@@ -1822,9 +1920,14 @@ async function inspectCodexLbMacLaunchEnvironment(baseUrl = '', opts = {}) {
1822
1920
  const result = await runProcess(launchctl, ['getenv', key], { timeoutMs: 3000, maxOutputBytes: 8192 });
1823
1921
  return result.code === 0 ? String(result.stdout || '').trim() : '';
1824
1922
  };
1825
- const currentBaseUrl = await readVar('CODEX_LB_BASE_URL');
1826
- const currentApiKey = await readVar('CODEX_LB_API_KEY');
1827
- const currentOpenRouterKey = await readVar('OPENROUTER_API_KEY');
1923
+ // launchctl can stall behind the same launchd/TCC boundary for every key.
1924
+ // These reads are independent, so keep the worst case to one timeout window
1925
+ // instead of three serial windows on `sks --mad` preflight.
1926
+ const [currentBaseUrl, currentApiKey, currentOpenRouterKey] = await Promise.all([
1927
+ readVar('CODEX_LB_BASE_URL'),
1928
+ readVar('CODEX_LB_API_KEY'),
1929
+ readVar('OPENROUTER_API_KEY')
1930
+ ]);
1828
1931
  const baseMatches = !baseUrl || currentBaseUrl === String(baseUrl || '').trim();
1829
1932
  const basePresent = Boolean(currentBaseUrl);
1830
1933
  const keyPresent = Boolean(currentApiKey);
@@ -2342,273 +2445,6 @@ export async function ensureCodexImagegenDuringInstall(opts = {}) {
2342
2445
  return { status: 'recovered', report };
2343
2446
  return { status: 'blocked', blockers: report.blockers || ['codex_imagegen_unavailable'], report };
2344
2447
  }
2345
- export async function ensureRelatedCliTools(args = []) {
2346
- const skip = args.includes('--skip-cli-tools') || process.env.SKS_SKIP_CLI_TOOLS === '1';
2347
- const codex = await ensureCodexCliTool({ skip, args });
2348
- const zellijRepair = skip ? { status: 'skipped', reason: 'SKS_SKIP_CLI_TOOLS=1 or --skip-cli-tools' } : await ensureZellijCliTool(args);
2349
- const zellij = await checkZellijCapability({ require: false, writeReport: false });
2350
- return {
2351
- codex,
2352
- zellij: {
2353
- ok: zellij.status === 'ok',
2354
- bin: zellij.bin,
2355
- version: zellij.version,
2356
- min_version: zellij.min_version,
2357
- current_session: false,
2358
- repair: zellijRepair,
2359
- install_hint: zellij.status === 'ok' ? null : zellijInstallHint(),
2360
- error: zellijRepair.error || zellij.blockers[0] || zellij.warnings[0] || null
2361
- }
2362
- };
2363
- }
2364
- export async function ensureMadLaunchDependencies(args = []) {
2365
- const skip = args.includes('--skip-cli-tools') || process.env.SKS_SKIP_CLI_TOOLS === '1';
2366
- const zellijRepair = skip ? { target: 'zellij', status: 'skipped', reason: 'SKS_SKIP_CLI_TOOLS=1 or --skip-cli-tools' } : await ensureZellijCliTool(args);
2367
- const zellij = await checkZellijCapability({ require: false, writeReport: false });
2368
- const ready = zellij.status === 'ok';
2369
- return {
2370
- ready,
2371
- actions: ready ? [] : [{
2372
- target: 'zellij',
2373
- status: zellijRepair.status,
2374
- command: zellijRepair.command || zellijInstallHint(),
2375
- error: zellijRepair.error || zellij.blockers[0] || zellij.warnings[0] || null,
2376
- repair: zellijRepair
2377
- }],
2378
- status: {
2379
- zellij: {
2380
- ok: ready,
2381
- status: zellij.status,
2382
- version: zellij.version,
2383
- min_version: zellij.min_version,
2384
- repair: zellijRepair,
2385
- install_hint: ready ? null : zellijInstallHint()
2386
- }
2387
- }
2388
- };
2389
- }
2390
- export function formatMadLaunchDependencyAction(action = {}) {
2391
- const command = action.command ? ` Run: ${action.command}.` : '';
2392
- const error = action.error ? ` ${action.error}` : '';
2393
- return `${action.target || 'dependency'} ${action.status || 'blocked'}.${command}${error}`.trim();
2394
- }
2395
- export async function ensureCodexCliTool({ skip = false, args = [] } = {}) {
2396
- if (skip)
2397
- return { status: 'skipped', reason: 'SKS_SKIP_CLI_TOOLS=1 or --skip-cli-tools' };
2398
- const before = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
2399
- if (before.bin)
2400
- return { status: 'present', bin: before.bin, version: before.version || null };
2401
- const npmBin = await which('npm');
2402
- if (!npmBin)
2403
- return { status: 'failed', error: 'npm not found on PATH; install Codex CLI manually with npm i -g @openai/codex@latest.' };
2404
- const command = 'npm i -g @openai/codex@latest';
2405
- if (args.includes('--dry-run'))
2406
- return { status: 'dry_run', command, error: 'Codex CLI not found on PATH.' };
2407
- if (!await confirmInstallYesDefault(`Codex CLI is missing. Install latest Codex CLI with ${command}?`, args)) {
2408
- return { status: 'needs_approval', command, error: 'Codex CLI not found on PATH.' };
2409
- }
2410
- // Global package install is a confirmation-required mutation: route it through
2411
- // the mutation guard so it is scope-checked and recorded in the ledger. The
2412
- // user already approved via confirmInstallYesDefault above (confirmed:true).
2413
- const installRoot = globalSksRoot();
2414
- const installContract = createRequestedScopeContract({
2415
- route: 'install', userRequest: command, projectRoot: installRoot, overrides: { package_install: true }
2416
- });
2417
- const install = await guardedPackageInstall(guardContextForRoute(installRoot, installContract, command), '@openai/codex@latest', { confirmed: true, command: npmBin, args: ['i', '-g', '@openai/codex@latest'], timeoutMs: 120000 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
2418
- if (install.code !== 0) {
2419
- return { status: 'failed', error: `${install.stderr || install.stdout || 'npm i -g @openai/codex@latest failed'}`.trim() };
2420
- }
2421
- const after = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
2422
- return {
2423
- status: after.bin ? 'installed' : 'installed_not_on_path',
2424
- bin: after.bin || null,
2425
- version: after.version || null,
2426
- hint: after.bin ? null : 'npm completed, but codex is not on PATH. Restart the shell or set SKS_CODEX_BIN.'
2427
- };
2428
- }
2429
- export async function ensureZellijCliTool(args = [], opts = {}) {
2430
- const before = await checkZellijCapability({ require: false, writeReport: false });
2431
- if (before.status === 'ok')
2432
- return { target: 'zellij', status: 'present', bin: before.bin, version: before.version || null };
2433
- const command = zellijInstallHint();
2434
- if (process.platform !== 'darwin')
2435
- return { target: 'zellij', status: 'manual_required', command, error: before.blockers[0] || before.warnings[0] || 'zellij not found' };
2436
- const brew = await which('brew').catch(() => null);
2437
- if (!brew)
2438
- return { target: 'zellij', status: 'manual_required', command: 'Install Homebrew, then run: brew install zellij', error: before.blockers[0] || before.warnings[0] || 'zellij not found' };
2439
- const repairCommand = command;
2440
- if (args.includes('--dry-run') || opts.dryRun)
2441
- return { target: 'zellij', status: 'dry_run', command: repairCommand, error: before.blockers[0] || before.warnings[0] || null };
2442
- const hasInstalledZellij = Boolean(before.version);
2443
- const question = hasInstalledZellij
2444
- ? `Homebrew Zellij ${before.version || 'unknown'} is not ready. Upgrade to latest Zellij with ${repairCommand}?`
2445
- : `Zellij is missing. Install latest Zellij with ${repairCommand}?`;
2446
- if (!await confirmInstallYesDefault(question, args))
2447
- return { target: 'zellij', status: 'needs_approval', command: repairCommand, error: before.blockers[0] || before.warnings[0] || null };
2448
- const brewArgs = hasInstalledZellij ? ['upgrade', 'zellij'] : ['install', 'zellij'];
2449
- const zellijRoot = globalSksRoot();
2450
- const zellijContract = createRequestedScopeContract({
2451
- route: 'install', userRequest: repairCommand, projectRoot: zellijRoot, overrides: { package_install: true, zellij_install: true }
2452
- });
2453
- const install = await guardedPackageInstall(guardContextForRoute(zellijRoot, zellijContract, repairCommand), 'zellij', { confirmed: true, command: brew, args: brewArgs, timeoutMs: 180000 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
2454
- if (install.code !== 0)
2455
- return { target: 'zellij', status: 'failed', command: repairCommand, error: `${install.stderr || install.stdout || repairCommand + ' failed'}`.trim() };
2456
- const after = await checkZellijCapability({ require: false, writeReport: false });
2457
- if (after.status !== 'ok')
2458
- return { target: 'zellij', status: 'installed_not_ready', command: repairCommand, error: after.blockers[0] || after.warnings[0] || 'zellij installed but not ready' };
2459
- return { target: 'zellij', status: hasInstalledZellij ? 'upgraded' : 'installed', command: repairCommand, bin: after.bin, version: after.version || null };
2460
- }
2461
- function zellijInstallHint() {
2462
- return process.platform === 'darwin' ? 'brew install zellij' : 'Install Zellij from https://zellij.dev/documentation/installation.html';
2463
- }
2464
- async function confirmInstallYesDefault(question, args = []) {
2465
- if (hasFlag(args, '--from-postinstall') && process.env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS !== '1')
2466
- return false;
2467
- if (shouldAutoApproveInstall(args))
2468
- return true;
2469
- if (!canAskYesNo())
2470
- return false;
2471
- const answer = (await askPostinstallQuestion(`${question} [Y/n] `)).trim();
2472
- return answer === '' || /^(y|yes|예|네|응)$/i.test(answer);
2473
- }
2474
- export async function maybePromptCodexUpdateForLaunch(args = [], opts = {}) {
2475
- if (hasFlag(args, '--json') || hasFlag(args, '--skip-cli-tools') || hasFlag(args, '--skip-codex-update') || process.env.SKS_SKIP_CODEX_UPDATE === '1')
2476
- return { status: 'skipped' };
2477
- const latest = await npmPackageVersion('@openai/codex');
2478
- const codex = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
2479
- const current = codexCliVersionNumber(codex.version);
2480
- const command = 'npm i -g @openai/codex@latest';
2481
- const label = opts.label || 'Zellij launch';
2482
- const missing = !codex.bin;
2483
- const updateAvailable = Boolean(latest.version && current && compareVersions(latest.version, current) > 0);
2484
- if (!missing && !updateAvailable)
2485
- return { status: 'current', latest: latest.version || null, current, bin: codex.bin || null, error: latest.error || null };
2486
- const prompt = missing
2487
- ? `Codex CLI missing. Install @openai/codex${latest.version ? ` ${latest.version}` : '@latest'} before ${label}? [Y/n] `
2488
- : `Codex CLI ${current} -> ${latest.version} update before ${label}? [Y/n] `;
2489
- if (shouldAutoApproveInstall(args))
2490
- return installCodexLatest(command, latest.version, current);
2491
- if (!canAskYesNo()) {
2492
- const reason = missing ? 'Codex CLI missing' : `Codex CLI update available: ${current} -> ${latest.version}`;
2493
- console.log(`${reason}. Run: ${command}`);
2494
- return { status: missing ? 'missing' : 'available', latest: latest.version || null, current, command, bin: codex.bin || null };
2495
- }
2496
- const answer = (await askPostinstallQuestion(prompt)).trim();
2497
- const yes = answer === '' || /^(y|yes|예|네|응)$/i.test(answer);
2498
- if (!yes)
2499
- return { status: 'skipped_by_user', latest: latest.version || null, current, command, bin: codex.bin || null };
2500
- return installCodexLatest(command, latest.version, current);
2501
- }
2502
- export async function maybePromptSksUpdateForLaunch(args = [], opts = {}) {
2503
- void args;
2504
- void opts;
2505
- return {
2506
- status: 'skipped',
2507
- reason: 'manual_update_commands_only',
2508
- current: PACKAGE_VERSION,
2509
- latest: null,
2510
- command: null
2511
- };
2512
- }
2513
- export function shouldAutoApproveInstall(args = [], env = process.env) {
2514
- if (hasFlag(args, '--from-postinstall') && env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS !== '1')
2515
- return false;
2516
- if (hasFlag(args, '--from-postinstall') && env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS === '1')
2517
- return true;
2518
- return hasFlag(args, '--yes') || hasFlag(args, '-y') || isAgentRuntime(env);
2519
- }
2520
- function canAskYesNo() {
2521
- return Boolean(input.isTTY && output.isTTY && process.env.CI !== 'true');
2522
- }
2523
- function hasFlag(args = [], name) {
2524
- return args.includes(name);
2525
- }
2526
- function isAgentRuntime(env = process.env) {
2527
- return [
2528
- 'SKS_OPENCLAW',
2529
- 'OPENCLAW',
2530
- 'OPENCLAW_AGENT',
2531
- 'OPENCLAW_RUN_ID',
2532
- 'OPENCLAW_SESSION_ID',
2533
- 'SKS_HERMES',
2534
- 'HERMES_AGENT',
2535
- 'HERMES_RUN_ID',
2536
- 'HERMES_SESSION_ID'
2537
- ]
2538
- .some((key) => /^(1|true|yes|y)$/i.test(String(env[key] || '').trim()));
2539
- }
2540
- async function installCodexLatest(command, latestVersion, previousVersion = null) {
2541
- const npm = await which('npm').catch(() => null);
2542
- if (!npm)
2543
- return { status: 'failed', latest: latestVersion || null, previous: previousVersion || null, command, error: 'npm not found on PATH' };
2544
- const install = await runProcess(npm, ['i', '-g', '@openai/codex@latest'], { timeoutMs: 180000, maxOutputBytes: 128 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
2545
- if (install.code !== 0)
2546
- return { status: 'failed', latest: latestVersion || null, previous: previousVersion || null, command, error: `${install.stderr || install.stdout || command + ' failed'}`.trim() };
2547
- const after = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
2548
- const afterVersion = codexCliVersionNumber(after.version);
2549
- if (!after.bin)
2550
- return { status: 'updated_not_reflected', latest: latestVersion || null, previous: previousVersion || null, version: afterVersion || null, command, error: 'npm completed, but codex is not on PATH. Restart the shell or set SKS_CODEX_BIN.' };
2551
- if (latestVersion && afterVersion && compareVersions(afterVersion, latestVersion) < 0) {
2552
- return { status: 'updated_not_reflected', latest: latestVersion, previous: previousVersion || null, version: afterVersion, bin: after.bin, command, error: `npm completed, but PATH still resolves Codex CLI ${afterVersion}; expected ${latestVersion}.` };
2553
- }
2554
- console.log(`Codex CLI ready: ${previousVersion || 'missing'} -> ${after.version || after.bin}`);
2555
- return { status: previousVersion ? 'updated' : 'installed', latest: latestVersion || null, previous: previousVersion || null, version: afterVersion || null, raw_version: after.version || null, bin: after.bin || null, command };
2556
- }
2557
- function codexCliVersionNumber(versionText = '') {
2558
- const match = String(versionText || '').match(/(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/);
2559
- return match ? match[1] : null;
2560
- }
2561
- async function npmPackageVersion(name) {
2562
- const envName = `SKS_NPM_VIEW_${String(name || '').replace(/[^A-Za-z0-9]+/g, '_').toUpperCase()}_VERSION`;
2563
- if (process.env[envName])
2564
- return { version: process.env[envName] };
2565
- const npm = await which('npm').catch(() => null);
2566
- if (!npm)
2567
- return { error: 'npm not found' };
2568
- const result = await runProcess(npm, ['view', name, 'version'], { timeoutMs: 5000, maxOutputBytes: 4096 });
2569
- if (result.code !== 0)
2570
- return { error: `${result.stderr || result.stdout || 'npm view failed'}`.trim() };
2571
- return { version: result.stdout.trim().split(/\s+/).pop() };
2572
- }
2573
- function compareVersions(a, b) {
2574
- const pa = String(a || '').split(/[.-]/).map((x) => Number.parseInt(x, 10) || 0);
2575
- const pb = String(b || '').split(/[.-]/).map((x) => Number.parseInt(x, 10) || 0);
2576
- for (let i = 0; i < Math.max(pa.length, pb.length, 3); i++) {
2577
- if ((pa[i] || 0) > (pb[i] || 0))
2578
- return 1;
2579
- if ((pa[i] || 0) < (pb[i] || 0))
2580
- return -1;
2581
- }
2582
- return 0;
2583
- }
2584
- async function isProjectSetupCandidate(root) {
2585
- const markers = ['package.json', '.git', 'AGENTS.md', '.codex', '.sneakoscope'];
2586
- for (const marker of markers) {
2587
- if (await exists(path.join(root, marker)))
2588
- return true;
2589
- }
2590
- return false;
2591
- }
2592
- export async function checkContext7(root) {
2593
- const projectPath = path.join(root, '.codex', 'config.toml');
2594
- const globalPath = path.join(process.env.HOME || '', '.codex', 'config.toml');
2595
- const projectText = await safeReadText(projectPath);
2596
- const globalText = await safeReadText(globalPath);
2597
- const codex = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
2598
- let list = { checked: false, ok: false, stdout: '', stderr: '' };
2599
- if (codex.bin) {
2600
- const out = await runProcess(codex.bin, ['mcp', 'list'], { timeoutMs: 8000, maxOutputBytes: 32 * 1024 }).catch((err) => ({ code: 1, stderr: err.message, stdout: '' }));
2601
- list = { checked: true, ok: out.code === 0 && /context7/i.test(`${out.stdout}\n${out.stderr}`), stdout: out.stdout || '', stderr: out.stderr || '' };
2602
- }
2603
- const result = {
2604
- ok: false,
2605
- project: { path: projectPath, ok: hasContext7ConfigText(projectText) },
2606
- global: { path: globalPath, ok: hasContext7ConfigText(globalText) },
2607
- codex_mcp_list: list
2608
- };
2609
- result.ok = result.project.ok || result.codex_mcp_list.ok || (result.global.ok && !list.checked);
2610
- return result;
2611
- }
2612
2448
  export async function ensureProjectContext7Config(root, transport = 'local') {
2613
2449
  const configPath = path.join(root, '.codex', 'config.toml');
2614
2450
  await ensureDir(path.dirname(configPath));
@@ -3234,30 +3070,4 @@ export async function selftestCodexLb(tmp) {
3234
3070
  if (!madLaunchSource.includes('const lb = await deps.maybePromptCodexLbSetupForLaunch(args)') || !madLaunchSource.includes("const launchLb = lb.status === 'present'") || !madLaunchSource.includes('codexLbImmediateLaunchOpts(cleanArgs, launchLb') || !madLaunchSource.includes('bypass_codex_lb') || !madLaunchSource.includes('model_provider="openai"') || !madLaunchSource.includes('codexLbFreshSession: true'))
3235
3071
  throw new Error('selftest: MAD launch does not sync codex-lb auth and fresh-session launch options');
3236
3072
  }
3237
- function hasTopLevelCodexModeLock(text = '') {
3238
- const lines = String(text || '').split('\n');
3239
- const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
3240
- const top = (firstTable === -1 ? lines : lines.slice(0, firstTable)).join('\n');
3241
- return /(^|\n)\s*model_reasoning_effort\s*=/.test(top);
3242
- }
3243
- function hasDeprecatedCodexHooksFeatureFlag(text = '') {
3244
- const lines = String(text || '').split('\n');
3245
- const start = lines.findIndex((line) => line.trim() === '[features]');
3246
- if (start === -1)
3247
- return false;
3248
- let end = lines.length;
3249
- for (let i = start + 1; i < lines.length; i += 1) {
3250
- const line = lines[i];
3251
- if (line === undefined)
3252
- continue;
3253
- if (/^\s*\[.+\]\s*$/.test(line)) {
3254
- end = i;
3255
- break;
3256
- }
3257
- }
3258
- return lines.slice(start + 1, end).some((line) => /^\s*codex_hooks\s*=/.test(line));
3259
- }
3260
- function hasCodexUnstableFeatureWarningSuppression(text = '') {
3261
- return /(^|\n)\s*suppress_unstable_features_warning\s*=\s*true\s*(?:#.*)?(?=\n|$)/.test(String(text || ''));
3262
- }
3263
3073
  //# sourceMappingURL=install-helpers.js.map