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
@@ -0,0 +1,287 @@
1
+ import fsp from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import readline from 'node:readline/promises';
4
+ import { stdin as input, stdout as output } from 'node:process';
5
+ import { EMPTY_CODEX_INFO, getCodexInfo } from '../core/codex-adapter.js';
6
+ import { exists, globalSksRoot, PACKAGE_VERSION, runProcess, which } from '../core/fsx.js';
7
+ import { hasContext7ConfigText } from '../core/routes.js';
8
+ import { createRequestedScopeContract } from '../core/safety/requested-scope-contract.js';
9
+ import { guardedPackageInstall, guardContextForRoute } from '../core/safety/mutation-guard.js';
10
+ import { checkZellijCapability } from '../core/zellij/zellij-capability.js';
11
+ export async function ensureRelatedCliTools(args = []) {
12
+ const skip = args.includes('--skip-cli-tools') || process.env.SKS_SKIP_CLI_TOOLS === '1';
13
+ const codex = await ensureCodexCliTool({ skip, args });
14
+ const zellijRepair = skip ? { status: 'skipped', reason: 'SKS_SKIP_CLI_TOOLS=1 or --skip-cli-tools' } : await ensureZellijCliTool(args);
15
+ const zellij = await checkZellijCapability({ require: false, writeReport: false });
16
+ return {
17
+ codex,
18
+ zellij: {
19
+ ok: zellij.status === 'ok',
20
+ bin: zellij.bin,
21
+ version: zellij.version,
22
+ min_version: zellij.min_version,
23
+ current_session: false,
24
+ repair: zellijRepair,
25
+ install_hint: zellij.status === 'ok' ? null : zellijInstallHint(),
26
+ error: zellijRepair.error || zellij.blockers[0] || zellij.warnings[0] || null
27
+ }
28
+ };
29
+ }
30
+ export async function ensureMadLaunchDependencies(args = []) {
31
+ const skip = args.includes('--skip-cli-tools') || process.env.SKS_SKIP_CLI_TOOLS === '1';
32
+ const zellijRepair = skip ? { target: 'zellij', status: 'skipped', reason: 'SKS_SKIP_CLI_TOOLS=1 or --skip-cli-tools' } : await ensureZellijCliTool(args);
33
+ const zellij = await checkZellijCapability({ require: false, writeReport: false });
34
+ const ready = zellij.status === 'ok';
35
+ return {
36
+ ready,
37
+ actions: ready ? [] : [{
38
+ target: 'zellij',
39
+ status: zellijRepair.status,
40
+ command: zellijRepair.command || zellijInstallHint(),
41
+ error: zellijRepair.error || zellij.blockers[0] || zellij.warnings[0] || null,
42
+ repair: zellijRepair
43
+ }],
44
+ status: {
45
+ zellij: {
46
+ ok: ready,
47
+ status: zellij.status,
48
+ version: zellij.version,
49
+ min_version: zellij.min_version,
50
+ repair: zellijRepair,
51
+ install_hint: ready ? null : zellijInstallHint()
52
+ }
53
+ }
54
+ };
55
+ }
56
+ export function formatMadLaunchDependencyAction(action = {}) {
57
+ const command = action.command ? ` Run: ${action.command}.` : '';
58
+ const error = action.error ? ` ${action.error}` : '';
59
+ return `${action.target || 'dependency'} ${action.status || 'blocked'}.${command}${error}`.trim();
60
+ }
61
+ export async function ensureCodexCliTool({ skip = false, args = [] } = {}) {
62
+ if (skip)
63
+ return { status: 'skipped', reason: 'SKS_SKIP_CLI_TOOLS=1 or --skip-cli-tools' };
64
+ const before = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
65
+ if (before.bin)
66
+ return { status: 'present', bin: before.bin, version: before.version || null };
67
+ const npmBin = await which('npm');
68
+ if (!npmBin)
69
+ return { status: 'failed', error: 'npm not found on PATH; install Codex CLI manually with npm i -g @openai/codex@latest.' };
70
+ const command = 'npm i -g @openai/codex@latest';
71
+ if (args.includes('--dry-run'))
72
+ return { status: 'dry_run', command, error: 'Codex CLI not found on PATH.' };
73
+ if (!await confirmInstallYesDefault(`Codex CLI is missing. Install latest Codex CLI with ${command}?`, args)) {
74
+ return { status: 'needs_approval', command, error: 'Codex CLI not found on PATH.' };
75
+ }
76
+ const installRoot = globalSksRoot();
77
+ const installContract = createRequestedScopeContract({
78
+ route: 'install', userRequest: command, projectRoot: installRoot, overrides: { package_install: true }
79
+ });
80
+ 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 }));
81
+ if (install.code !== 0)
82
+ return { status: 'failed', error: `${install.stderr || install.stdout || 'npm i -g @openai/codex@latest failed'}`.trim() };
83
+ const after = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
84
+ return {
85
+ status: after.bin ? 'installed' : 'installed_not_on_path',
86
+ bin: after.bin || null,
87
+ version: after.version || null,
88
+ hint: after.bin ? null : 'npm completed, but codex is not on PATH. Restart the shell or set SKS_CODEX_BIN.'
89
+ };
90
+ }
91
+ export async function ensureZellijCliTool(args = [], opts = {}) {
92
+ const before = await checkZellijCapability({ require: false, writeReport: false });
93
+ if (before.status === 'ok')
94
+ return { target: 'zellij', status: 'present', bin: before.bin, version: before.version || null };
95
+ const command = zellijInstallHint();
96
+ if (process.platform !== 'darwin')
97
+ return { target: 'zellij', status: 'manual_required', command, error: before.blockers[0] || before.warnings[0] || 'zellij not found' };
98
+ const brew = await which('brew').catch(() => null);
99
+ if (!brew)
100
+ return { target: 'zellij', status: 'manual_required', command: 'Install Homebrew, then run: brew install zellij', error: before.blockers[0] || before.warnings[0] || 'zellij not found' };
101
+ if (args.includes('--dry-run') || opts.dryRun)
102
+ return { target: 'zellij', status: 'dry_run', command, error: before.blockers[0] || before.warnings[0] || null };
103
+ const hasInstalledZellij = Boolean(before.version);
104
+ const question = hasInstalledZellij
105
+ ? `Homebrew Zellij ${before.version || 'unknown'} is not ready. Upgrade to latest Zellij with ${command}?`
106
+ : `Zellij is missing. Install latest Zellij with ${command}?`;
107
+ if (!await confirmInstallYesDefault(question, args))
108
+ return { target: 'zellij', status: 'needs_approval', command, error: before.blockers[0] || before.warnings[0] || null };
109
+ const brewArgs = hasInstalledZellij ? ['upgrade', 'zellij'] : ['install', 'zellij'];
110
+ const zellijRoot = globalSksRoot();
111
+ const zellijContract = createRequestedScopeContract({
112
+ route: 'install', userRequest: command, projectRoot: zellijRoot, overrides: { package_install: true, zellij_install: true }
113
+ });
114
+ const install = await guardedPackageInstall(guardContextForRoute(zellijRoot, zellijContract, command), 'zellij', { confirmed: true, command: brew, args: brewArgs, timeoutMs: 180000 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
115
+ if (install.code !== 0)
116
+ return { target: 'zellij', status: 'failed', command, error: `${install.stderr || install.stdout || command + ' failed'}`.trim() };
117
+ const after = await checkZellijCapability({ require: false, writeReport: false });
118
+ if (after.status !== 'ok')
119
+ return { target: 'zellij', status: 'installed_not_ready', command, error: after.blockers[0] || after.warnings[0] || 'zellij installed but not ready' };
120
+ return { target: 'zellij', status: hasInstalledZellij ? 'upgraded' : 'installed', command, bin: after.bin, version: after.version || null };
121
+ }
122
+ export async function maybePromptCodexUpdateForLaunch(args = [], opts = {}) {
123
+ if (hasFlag(args, '--json') || hasFlag(args, '--skip-cli-tools') || hasFlag(args, '--skip-codex-update') || process.env.SKS_SKIP_CODEX_UPDATE === '1')
124
+ return { status: 'skipped' };
125
+ const latest = await npmPackageVersion('@openai/codex');
126
+ const codex = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
127
+ const current = codexCliVersionNumber(codex.version);
128
+ const command = 'npm i -g @openai/codex@latest';
129
+ const label = opts.label || 'Zellij launch';
130
+ const missing = !codex.bin;
131
+ const updateAvailable = Boolean(latest.version && current && compareVersions(latest.version, current) > 0);
132
+ if (!missing && !updateAvailable)
133
+ return { status: 'current', latest: latest.version || null, current, bin: codex.bin || null, error: latest.error || null };
134
+ const prompt = missing
135
+ ? `Codex CLI missing. Install @openai/codex${latest.version ? ` ${latest.version}` : '@latest'} before ${label}? [Y/n] `
136
+ : `Codex CLI ${current} -> ${latest.version} update before ${label}? [Y/n] `;
137
+ if (shouldAutoApproveInstall(args))
138
+ return installCodexLatest(command, latest.version, current);
139
+ if (!canAskYesNo()) {
140
+ const reason = missing ? 'Codex CLI missing' : `Codex CLI update available: ${current} -> ${latest.version}`;
141
+ console.log(`${reason}. Run: ${command}`);
142
+ return { status: missing ? 'missing' : 'available', latest: latest.version || null, current, command, bin: codex.bin || null };
143
+ }
144
+ const answer = (await askQuestion(prompt)).trim();
145
+ if (!(answer === '' || /^(y|yes|예|네|응)$/i.test(answer)))
146
+ return { status: 'skipped_by_user', latest: latest.version || null, current, command, bin: codex.bin || null };
147
+ return installCodexLatest(command, latest.version, current);
148
+ }
149
+ export async function maybePromptSksUpdateForLaunch(args = [], opts = {}) {
150
+ void args;
151
+ void opts;
152
+ return { status: 'skipped', reason: 'manual_update_commands_only', current: PACKAGE_VERSION, latest: null, command: null };
153
+ }
154
+ export function shouldAutoApproveInstall(args = [], env = process.env) {
155
+ if (hasFlag(args, '--from-postinstall') && env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS !== '1')
156
+ return false;
157
+ if (hasFlag(args, '--from-postinstall') && env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS === '1')
158
+ return true;
159
+ return hasFlag(args, '--yes') || hasFlag(args, '-y') || isAgentRuntime(env);
160
+ }
161
+ export function canAskYesNo() {
162
+ return Boolean(input.isTTY && output.isTTY && process.env.CI !== 'true');
163
+ }
164
+ export function compareVersions(a, b) {
165
+ const pa = String(a || '').split(/[.-]/).map((value) => Number.parseInt(value, 10) || 0);
166
+ const pb = String(b || '').split(/[.-]/).map((value) => Number.parseInt(value, 10) || 0);
167
+ for (let index = 0; index < Math.max(pa.length, pb.length, 3); index += 1) {
168
+ if ((pa[index] || 0) > (pb[index] || 0))
169
+ return 1;
170
+ if ((pa[index] || 0) < (pb[index] || 0))
171
+ return -1;
172
+ }
173
+ return 0;
174
+ }
175
+ export async function isProjectSetupCandidate(root) {
176
+ for (const marker of ['package.json', '.git', 'AGENTS.md', '.codex', '.sneakoscope']) {
177
+ if (await exists(path.join(root, marker)))
178
+ return true;
179
+ }
180
+ return false;
181
+ }
182
+ export function hasTopLevelCodexModeLock(text = '') {
183
+ const lines = String(text || '').split('\n');
184
+ const firstTable = lines.findIndex((line) => /^\s*\[.+\]\s*$/.test(line));
185
+ const top = (firstTable === -1 ? lines : lines.slice(0, firstTable)).join('\n');
186
+ return /(^|\n)\s*model_reasoning_effort\s*=/.test(top);
187
+ }
188
+ export function hasDeprecatedCodexHooksFeatureFlag(text = '') {
189
+ const lines = String(text || '').split('\n');
190
+ const start = lines.findIndex((line) => line.trim() === '[features]');
191
+ if (start === -1)
192
+ return false;
193
+ const end = lines.findIndex((line, index) => index > start && /^\s*\[.+\]\s*$/.test(line));
194
+ return lines.slice(start + 1, end === -1 ? lines.length : end).some((line) => /^\s*codex_hooks\s*=/.test(line));
195
+ }
196
+ export function hasCodexUnstableFeatureWarningSuppression(text = '') {
197
+ return /(^|\n)\s*suppress_unstable_features_warning\s*=\s*true\s*(?:#.*)?(?=\n|$)/.test(String(text || ''));
198
+ }
199
+ export async function checkContext7(root) {
200
+ const projectPath = path.join(root, '.codex', 'config.toml');
201
+ const globalPath = path.join(process.env.HOME || '', '.codex', 'config.toml');
202
+ const [projectText, globalText] = await Promise.all([safeReadText(projectPath), safeReadText(globalPath)]);
203
+ const codex = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
204
+ let list = { checked: false, ok: false, stdout: '', stderr: '' };
205
+ if (codex.bin) {
206
+ const out = await runProcess(codex.bin, ['mcp', 'list'], { timeoutMs: 8000, maxOutputBytes: 32 * 1024 }).catch((err) => ({ code: 1, stderr: err.message, stdout: '' }));
207
+ list = { checked: true, ok: out.code === 0 && /context7/i.test(`${out.stdout}\n${out.stderr}`), stdout: out.stdout || '', stderr: out.stderr || '' };
208
+ }
209
+ const result = {
210
+ ok: false,
211
+ project: { path: projectPath, ok: hasContext7ConfigText(projectText) },
212
+ global: { path: globalPath, ok: hasContext7ConfigText(globalText) },
213
+ codex_mcp_list: list
214
+ };
215
+ result.ok = result.project.ok || result.codex_mcp_list.ok || (result.global.ok && !list.checked);
216
+ return result;
217
+ }
218
+ function zellijInstallHint() {
219
+ return process.platform === 'darwin' ? 'brew install zellij' : 'Install Zellij from https://zellij.dev/documentation/installation.html';
220
+ }
221
+ async function confirmInstallYesDefault(question, args = []) {
222
+ if (hasFlag(args, '--from-postinstall') && process.env.SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS !== '1')
223
+ return false;
224
+ if (shouldAutoApproveInstall(args))
225
+ return true;
226
+ if (!canAskYesNo())
227
+ return false;
228
+ const answer = (await askQuestion(`${question} [Y/n] `)).trim();
229
+ return answer === '' || /^(y|yes|예|네|응)$/i.test(answer);
230
+ }
231
+ async function askQuestion(question) {
232
+ const rl = readline.createInterface({ input, output });
233
+ try {
234
+ return await rl.question(question);
235
+ }
236
+ finally {
237
+ rl.close();
238
+ }
239
+ }
240
+ function hasFlag(args = [], name) {
241
+ return args.includes(name);
242
+ }
243
+ function isAgentRuntime(env = process.env) {
244
+ return ['SKS_OPENCLAW', 'OPENCLAW', 'OPENCLAW_AGENT', 'OPENCLAW_RUN_ID', 'OPENCLAW_SESSION_ID', 'SKS_HERMES', 'HERMES_AGENT', 'HERMES_RUN_ID', 'HERMES_SESSION_ID']
245
+ .some((key) => /^(1|true|yes|y)$/i.test(String(env[key] || '').trim()));
246
+ }
247
+ async function installCodexLatest(command, latestVersion, previousVersion = null) {
248
+ const npm = await which('npm').catch(() => null);
249
+ if (!npm)
250
+ return { status: 'failed', latest: latestVersion || null, previous: previousVersion || null, command, error: 'npm not found on PATH' };
251
+ const install = await runProcess(npm, ['i', '-g', '@openai/codex@latest'], { timeoutMs: 180000, maxOutputBytes: 128 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
252
+ if (install.code !== 0)
253
+ return { status: 'failed', latest: latestVersion || null, previous: previousVersion || null, command, error: `${install.stderr || install.stdout || command + ' failed'}`.trim() };
254
+ const after = await getCodexInfo().catch(() => EMPTY_CODEX_INFO);
255
+ const afterVersion = codexCliVersionNumber(after.version);
256
+ if (!after.bin)
257
+ 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.' };
258
+ if (latestVersion && afterVersion && compareVersions(afterVersion, latestVersion) < 0) {
259
+ 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}.` };
260
+ }
261
+ console.log(`Codex CLI ready: ${previousVersion || 'missing'} -> ${after.version || after.bin}`);
262
+ return { status: previousVersion ? 'updated' : 'installed', latest: latestVersion || null, previous: previousVersion || null, version: afterVersion || null, raw_version: after.version || null, bin: after.bin || null, command };
263
+ }
264
+ function codexCliVersionNumber(versionText = '') {
265
+ return String(versionText || '').match(/(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/)?.[1] || null;
266
+ }
267
+ async function npmPackageVersion(name) {
268
+ const envName = `SKS_NPM_VIEW_${String(name || '').replace(/[^A-Za-z0-9]+/g, '_').toUpperCase()}_VERSION`;
269
+ if (process.env[envName])
270
+ return { version: process.env[envName] };
271
+ const npm = await which('npm').catch(() => null);
272
+ if (!npm)
273
+ return { error: 'npm not found' };
274
+ const result = await runProcess(npm, ['view', name, 'version'], { timeoutMs: 5000, maxOutputBytes: 4096 });
275
+ if (result.code !== 0)
276
+ return { error: `${result.stderr || result.stdout || 'npm view failed'}`.trim() };
277
+ return { version: result.stdout.trim().split(/\s+/).pop() };
278
+ }
279
+ async function safeReadText(file) {
280
+ try {
281
+ return await fsp.readFile(file, 'utf8');
282
+ }
283
+ catch {
284
+ return '';
285
+ }
286
+ }
287
+ //# sourceMappingURL=install-tool-helpers.js.map
@@ -73,6 +73,8 @@ async function dispatchInner(argv) {
73
73
  command: raw,
74
74
  reason: 'unknown_command',
75
75
  };
76
+ if (argv.includes('--json'))
77
+ console.log(JSON.stringify(result, null, 2));
76
78
  return result;
77
79
  }
78
80
  const entry = COMMAND_MANIFEST_BY_NAME[command];
@@ -102,7 +104,11 @@ async function dispatchInner(argv) {
102
104
  const migrationGate = await ensureCurrentMigrationBeforeCommand({
103
105
  command,
104
106
  args: rest,
105
- skipMigrationGate: entry.skipMigrationGate === true || entry.readonly === true || safeActiveRouteVisualQuery(command, rest)
107
+ skipMigrationGate: entry.skipMigrationGate === true
108
+ || entry.readonly === true
109
+ || safeReadOnlySubcommand(command, rest)
110
+ || safeActiveRouteVisualQuery(command, rest)
111
+ || safeActiveRouteRecoverySubcommand(command, rest)
106
112
  });
107
113
  if (!migrationGate.ok) {
108
114
  console.error('SKS project migration blocked.');
@@ -146,7 +152,7 @@ async function ensureActiveRouteCommandGate(command, args) {
146
152
  }
147
153
  if (entry.mutatesRouteState !== true)
148
154
  return { ok: true, status: 'allowed' };
149
- if (safeReadOnlySubcommand(args))
155
+ if (safeReadOnlySubcommand(command, args))
150
156
  return { ok: true, status: 'allowed_status_subcommand' };
151
157
  if (safeActiveRouteVisualQuery(command, args))
152
158
  return { ok: true, status: 'allowed_visual_query' };
@@ -158,6 +164,8 @@ async function ensureActiveRouteCommandGate(command, args) {
158
164
  ]);
159
165
  const root = await projectRoot(process.cwd()).catch(() => process.cwd());
160
166
  const state = await readJson(stateFile(root), {}).catch(() => ({}));
167
+ if (safeActiveRouteContinuation(command, args, state))
168
+ return { ok: true, status: 'allowed_active_route_continuation' };
161
169
  if (!activeRouteStateBlocksCommand(state))
162
170
  return { ok: true, status: 'allowed' };
163
171
  const visualPreflight = await blockedVisualSourcePreflight(command, args);
@@ -201,8 +209,11 @@ function printHandledCommandBlock(result) {
201
209
  for (const line of Array.isArray(result?.guidance) ? result.guidance : [])
202
210
  console.error(`- ${line}`);
203
211
  }
204
- function safeReadOnlySubcommand(args) {
205
- const sub = String(args.find((arg) => !String(arg).startsWith('-')) || '').toLowerCase();
212
+ export function safeReadOnlySubcommand(command, args) {
213
+ const sub = String(args[0] || '').toLowerCase();
214
+ if (command === 'naruto' && ['status', 'subagents', 'workers', 'proof'].includes(sub)) {
215
+ return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
216
+ }
206
217
  if (!['status', 'show', 'list', 'observe', 'watch', 'doctor', 'help'].includes(sub))
207
218
  return false;
208
219
  return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
@@ -213,6 +224,31 @@ function safeActiveRouteRecoverySubcommand(command, args) {
213
224
  const sub = String(args.find((arg) => !String(arg).startsWith('-')) || '').toLowerCase();
214
225
  return ['close', 'cleanup', 'rollback-patches'].includes(sub);
215
226
  }
227
+ function safeActiveRouteContinuation(command, args, state = {}) {
228
+ const expectedRoutes = new Map([
229
+ ['research', ['RESEARCH']],
230
+ ['autoresearch', ['AUTORESEARCH', 'RESEARCH']],
231
+ ['qa-loop', ['QALOOP']]
232
+ ]).get(command);
233
+ if (!expectedRoutes)
234
+ return false;
235
+ const subcommand = String(args[0] || '').toLowerCase();
236
+ const activeRoute = String(state.route || state.route_command || state.mode || '').replace(/^\$/, '').replace(/[-_]/g, '').toUpperCase();
237
+ if (!expectedRoutes.includes(activeRoute))
238
+ return false;
239
+ if (subcommand === 'prepare') {
240
+ const parentMissionId = String(process.env.SKS_RUN_PARENT_MISSION_ID || '').trim();
241
+ return command !== 'autoresearch'
242
+ && String(state.mode || '').toUpperCase() === 'RUN'
243
+ && String(state.phase || '').toUpperCase() === 'RUN_ROUTE_SELECTED'
244
+ && Boolean(parentMissionId)
245
+ && parentMissionId === String(state.mission_id || '');
246
+ }
247
+ if (subcommand !== 'run')
248
+ return false;
249
+ const requestedMission = String(args[1] || '').trim();
250
+ return Boolean(state.mission_id) && (requestedMission === String(state.mission_id) || requestedMission === 'latest');
251
+ }
216
252
  function activeRouteStateBlocksCommand(state = {}) {
217
253
  if (!state?.mission_id || state.route_closed === true)
218
254
  return false;
@@ -7,6 +7,7 @@ import { printJson } from '../cli/output.js';
7
7
  import { codexLbMetrics, readCodexLbCircuit, recordCodexLbHealthEvent, resetCodexLbCircuit, codexLbProofEvidence } from '../core/codex-lb-circuit.js';
8
8
  import { checkCodexLbResponseChain, codexLbStatus, configureCodexLb, formatCodexLbStatusText, releaseCodexLbAuthHold, repairCodexLbAuth, unselectCodexLbProvider } from '../cli/install-helpers.js';
9
9
  import { buildCodexLbSetupPlan, codexLbPersistenceSummary, renderCodexLbSetupPlan } from '../core/codex-lb/codex-lb-setup.js';
10
+ import { CODEX_LB_TOOL_OUTPUT_RECOVERY_OVERRIDE_FLAG, codexLbToolOutputRecoveryOverrideAcknowledged } from '../core/codex-lb/codex-lb-tool-output-recovery.js';
10
11
  import { restartCodexApp } from '../core/codex-app/codex-app-restart.js';
11
12
  import { repairCodexAppFastUi } from '../core/codex-app/codex-app-fast-ui-repair.js';
12
13
  export async function run(command, args = []) {
@@ -22,15 +23,19 @@ export async function run(command, args = []) {
22
23
  return;
23
24
  }
24
25
  if (action === 'status' || action === 'check') {
25
- const result = await codexLbStatus();
26
+ const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
27
+ const result = await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
26
28
  const shaped = shapeCodexLbStatus(result);
29
+ if (result.selected && result.tool_output_recovery?.ok !== true)
30
+ process.exitCode = 1;
27
31
  if (flag(args, '--json'))
28
32
  return printJson(shaped);
29
33
  process.stdout.write(formatCodexLbStatusText(result));
30
34
  return;
31
35
  }
32
36
  if (action === 'doctor') {
33
- const status = shapeCodexLbStatus(await codexLbStatus());
37
+ const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
38
+ const status = shapeCodexLbStatus(await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery }));
34
39
  const metrics = codexLbMetrics(await readCodexLbCircuit(root));
35
40
  const result = { schema: 'sks.codex-lb-doctor.v1', ok: Boolean(status.ok && metrics.ok), deep: flag(args, '--deep'), status, metrics };
36
41
  if (flag(args, '--json'))
@@ -41,9 +46,14 @@ export async function run(command, args = []) {
41
46
  return;
42
47
  }
43
48
  if (action === 'health' || action === 'verify-chain' || action === 'chain') {
44
- const status = await codexLbStatus();
49
+ const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
50
+ const status = await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
45
51
  const blocker = !status.env_key_configured ? 'missing_env_key' : !status.base_url ? 'missing_base_url' : 'not_configured';
46
- const result = status.ok ? await checkCodexLbResponseChain(status, { force: true, root, fastMode: flag(args, '--fast') || flag(args, '--priority') }) : { ok: false, status: blocker, codex_lb: status };
52
+ const result = status.selected && status.tool_output_recovery?.ok !== true
53
+ ? { ok: false, status: 'tool_output_recovery_blocked', codex_lb: status, tool_output_recovery: status.tool_output_recovery }
54
+ : status.ok
55
+ ? await checkCodexLbResponseChain(status, { force: true, root, fastMode: flag(args, '--fast') || flag(args, '--priority') })
56
+ : { ok: false, status: blocker, codex_lb: status };
47
57
  if (flag(args, '--json'))
48
58
  return printJson(result);
49
59
  console.log(`codex-lb response chain: ${result.ok ? 'ok' : `failed (${result.status})`}`);
@@ -52,12 +62,15 @@ export async function run(command, args = []) {
52
62
  return;
53
63
  }
54
64
  if (action === 'fast-check' || action === 'fast' || action === 'verify-fast') {
55
- const status = await codexLbStatus();
65
+ const allowUnverifiedToolOutputRecovery = codexLbToolOutputRecoveryOverrideAcknowledged({ args });
66
+ const status = await codexLbStatus({ probeToolOutputRecovery: true, allowUnverifiedToolOutputRecovery });
56
67
  const blocker = !status.env_key_configured ? 'missing_env_key' : !status.base_url ? 'missing_base_url' : !status.provider_contract_ok ? 'provider_contract_drift' : 'not_configured';
57
68
  const modelSelection = await resolveCodexLbFastCheckModel(status);
58
- const chain = status.env_key_configured && status.base_url && modelSelection.model
59
- ? await checkCodexLbResponseChain(status, { force: true, cache: false, root, fastMode: true, model: modelSelection.model })
60
- : { ok: false, status: modelSelection.model ? blocker : 'model_unselected', codex_lb: status };
69
+ const chain = status.selected && status.tool_output_recovery?.ok !== true
70
+ ? { ok: false, status: 'tool_output_recovery_blocked', codex_lb: status, tool_output_recovery: status.tool_output_recovery }
71
+ : status.env_key_configured && status.base_url && modelSelection.model
72
+ ? await checkCodexLbResponseChain(status, { force: true, cache: false, root, fastMode: true, model: modelSelection.model })
73
+ : { ok: false, status: modelSelection.model ? blocker : 'model_unselected', codex_lb: status };
61
74
  const evidence = await fastEvidenceFromChain(chain, readOption(args, '--request-log', readOption(args, '--request-log-json', null)));
62
75
  const providerReady = status.provider_contract_ok === true;
63
76
  const chainVerified = isCodexLbFastChainVerified(chain);
@@ -103,7 +116,9 @@ export async function run(command, args = []) {
103
116
  return;
104
117
  }
105
118
  if (action === 'repair' || action === 'resync' || action === 'login') {
106
- const result = await repairCodexLbAuth();
119
+ const result = await repairCodexLbAuth({
120
+ allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
121
+ });
107
122
  const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
108
123
  const shaped = { ...result, ok: Boolean(result.ok && fastUi.ok), codex_app_fast_ui: fastUi };
109
124
  if (!shaped.ok)
@@ -156,7 +171,13 @@ export async function run(command, args = []) {
156
171
  process.exitCode = 1;
157
172
  return;
158
173
  }
159
- const result = await configureCodexLb({ host, apiKey: newKey, authMode: flag(args, '--preserve-auth') ? 'preserve' : 'codex-lb', forceCodexLbApiKeyAuth: !flag(args, '--preserve-auth') });
174
+ const result = await configureCodexLb({
175
+ host,
176
+ apiKey: newKey,
177
+ authMode: flag(args, '--preserve-auth') ? 'preserve' : 'codex-lb',
178
+ forceCodexLbApiKeyAuth: !flag(args, '--preserve-auth'),
179
+ allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
180
+ });
160
181
  const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
161
182
  const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(result.ok && fastUi.ok));
162
183
  const ok = Boolean(result.ok && fastUi.ok && restart?.ok !== false);
@@ -174,7 +195,12 @@ export async function run(command, args = []) {
174
195
  }
175
196
  if (action === 'use-codex-lb' || action === 'use-lb') {
176
197
  // Switch auth mode -> codex-lb (API key). Re-selects the provider and re-syncs auth.
177
- const result = await repairCodexLbAuth({ forceCodexLbApiKeyAuth: true, authMode: 'codex-lb', forceFastMode: !flag(args, '--no-fast') });
198
+ const result = await repairCodexLbAuth({
199
+ forceCodexLbApiKeyAuth: true,
200
+ authMode: 'codex-lb',
201
+ forceFastMode: !flag(args, '--no-fast'),
202
+ allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
203
+ });
178
204
  const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
179
205
  const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(result.ok && fastUi.ok));
180
206
  const ok = Boolean(result.ok && fastUi.ok && restart?.ok !== false);
@@ -325,7 +351,8 @@ export async function run(command, args = []) {
325
351
  shellProfile: options.shellProfile,
326
352
  runHealth: options.health,
327
353
  apiKeySource: options.apiKeySource,
328
- allowInsecureHttp: options.allowInsecureLocalhost
354
+ allowInsecureHttp: options.allowInsecureLocalhost,
355
+ allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
329
356
  });
330
357
  const fastUi = await repairCodexAppFastUiAfterMutation(root, Boolean(result.ok));
331
358
  const restart = await maybeRestartCodexAppForAuthSwitch(args, Boolean(result.ok && fastUi.ok) && !flag(args, '--preserve-auth'));
@@ -378,6 +405,7 @@ export async function run(command, args = []) {
378
405
  return;
379
406
  }
380
407
  console.error('Usage: sks codex-lb status|metrics|doctor --deep|health|setup|set-key|use-codex-lb|use-oauth|repair|release|unselect|circuit reset|circuit record-fixture|proof-evidence [--json]');
408
+ console.error(` ${CODEX_LB_TOOL_OUTPUT_RECOVERY_OVERRIDE_FLAG} explicitly acknowledge an old/unverified proxy for this command (unsafe)`);
381
409
  console.error(' set-key swap the codex-lb API key (reuses the stored host): sks codex-lb set-key --api-key-stdin');
382
410
  console.error(' use-codex-lb switch auth mode to codex-lb (API key)');
383
411
  console.error(' use-oauth switch auth mode to ChatGPT OAuth (restores saved login, else: codex login)');
@@ -587,9 +615,10 @@ function shapeCodexLbStatus(status = {}) {
587
615
  return {
588
616
  schema: 'sks.codex-lb-status.v1',
589
617
  ...status,
590
- configured: Boolean(status.ok),
591
- setup_needed: !status.ok,
592
- repair_available: !status.ok,
618
+ configured: Boolean(status.provider_ready ?? status.ok),
619
+ setup_needed: !Boolean(status.provider_ready ?? status.ok),
620
+ upgrade_needed: Boolean(status.selected && status.tool_output_recovery?.ok !== true),
621
+ repair_available: !Boolean(status.provider_ready ?? status.ok),
593
622
  api_key: {
594
623
  present: Boolean(status.env_key_configured),
595
624
  source: status.env_loader?.api_key?.source || null,
@@ -598,11 +627,13 @@ function shapeCodexLbStatus(status = {}) {
598
627
  persistence,
599
628
  env_loader: status.env_loader || null,
600
629
  env_auto_load: Boolean(status.env_file && status.env_key_configured),
601
- guidance: status.ok ? [] : [
602
- 'codex-lb API key is not configured.',
603
- 'Run: sks codex-lb setup',
604
- 'Or: sks codex-lb setup --host <domain> --api-key-stdin --yes'
605
- ]
630
+ guidance: status.selected && status.tool_output_recovery?.ok !== true
631
+ ? status.tool_output_recovery.operator_actions || []
632
+ : status.ok ? [] : [
633
+ 'codex-lb API key is not configured.',
634
+ 'Run: sks codex-lb setup',
635
+ 'Or: sks codex-lb setup --host <domain> --api-key-stdin --yes'
636
+ ]
606
637
  };
607
638
  }
608
639
  async function codexLbSetupOptions(args = []) {
@@ -6,6 +6,7 @@ import { codexSchemaSnapshotReport } from '../core/codex-compat/codex-schema-sna
6
6
  import { detectCodex0141Capability } from '../core/codex-control/codex-0141-capability.js';
7
7
  import { detectCodex0144Capability } from '../core/codex-control/codex-0144-capability.js';
8
8
  import { CURRENT_CODEX_RELEASE_MANIFEST } from '../core/codex-compat/codex-release-manifest.js';
9
+ import { inspectCodexCliUpdate, updateCodexCliNow } from '../core/codex/codex-cli-update.js';
9
10
  export async function run(_command, args = []) {
10
11
  const action = args[0] || 'compatibility';
11
12
  if (action === 'compatibility' || action === 'compat') {
@@ -27,6 +28,43 @@ export async function run(_command, args = []) {
27
28
  console.log(`Codex detected: ${result.detected.version || 'not installed'} (${result.policy.status})`);
28
29
  return;
29
30
  }
31
+ if (action === 'update-status' || action === 'update-check') {
32
+ const result = await inspectCodexCliUpdate({ force: flag(args, '--refresh') || flag(args, '--force') });
33
+ if (flag(args, '--json')) {
34
+ printJson(result);
35
+ if (!result.ok)
36
+ process.exitCode = 1;
37
+ return;
38
+ }
39
+ console.log(`Codex CLI: ${result.current_version || 'not installed'}${result.latest_version ? ` (latest ${result.latest_version})` : ''}`);
40
+ console.log(`Update: ${result.update_available === true ? 'available' : result.update_available === false ? 'current' : 'unverified'}`);
41
+ for (const warning of result.warnings)
42
+ console.log(`- warning: ${warning}`);
43
+ for (const actionLine of result.guidance)
44
+ console.log(`- ${actionLine}`);
45
+ if (!result.ok)
46
+ process.exitCode = 1;
47
+ return;
48
+ }
49
+ if (action === 'update' || action === 'update-now') {
50
+ const result = await updateCodexCliNow();
51
+ if (flag(args, '--json')) {
52
+ printJson(result);
53
+ if (!result.ok)
54
+ process.exitCode = 1;
55
+ return;
56
+ }
57
+ console.log(`Codex CLI update: ${result.status}${result.after_version ? ` (${result.before_version || 'unknown'} -> ${result.after_version})` : ''}`);
58
+ if (result.raw_output)
59
+ console.log(result.raw_output);
60
+ for (const blocker of result.blockers)
61
+ console.log(`- blocker: ${blocker}`);
62
+ for (const actionLine of result.guidance)
63
+ console.log(`- ${actionLine}`);
64
+ if (!result.ok)
65
+ process.exitCode = 1;
66
+ return;
67
+ }
30
68
  if (action === '0.141' || action === '0141' || action === 'rust-v0.141.0') {
31
69
  const result = await detectCodex0141Capability();
32
70
  if (flag(args, '--json'))
@@ -71,7 +109,7 @@ export async function run(_command, args = []) {
71
109
  process.exitCode = 1;
72
110
  return;
73
111
  }
74
- console.error('Usage: sks codex compatibility|version|doctor|schema|0.144|0.141 [--json]');
112
+ console.error('Usage: sks codex compatibility|version|update-status [--refresh]|update|doctor|schema|0.144|0.141 [--json]');
75
113
  process.exitCode = 1;
76
114
  }
77
115
  //# sourceMappingURL=codex.js.map