sneakoscope 8.1.2 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/README.md +96 -58
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/bin/fast-inline.js +5 -51
  5. package/dist/cli/command-manifest-lite.js +2 -1
  6. package/dist/cli/command-registry.js +2 -1
  7. package/dist/cli/global-mode-router.js +1 -1
  8. package/dist/cli/install-helpers-codex-lb-config.js +112 -914
  9. package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
  10. package/dist/cli/install-helpers-install-support.js +4 -20
  11. package/dist/cli/install-helpers.js +36 -2716
  12. package/dist/cli/router.js +9 -9
  13. package/dist/commands/bridge-command-output.js +111 -0
  14. package/dist/commands/bridge.js +320 -0
  15. package/dist/commands/codex-app.js +39 -123
  16. package/dist/commands/doctor-helpers.js +380 -0
  17. package/dist/commands/doctor-profile.js +3 -0
  18. package/dist/commands/doctor.js +114 -873
  19. package/dist/commands/mad-sks.js +0 -4
  20. package/dist/config/skills-manifest.json +1 -1
  21. package/dist/core/agents/agent-effort-policy.js +11 -21
  22. package/dist/core/agents/agent-recursion-guard.js +26 -0
  23. package/dist/core/agents/agent-runner-codex-exec.js +7 -9
  24. package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
  25. package/dist/core/architecture-hardening/state/state-service.js +49 -13
  26. package/dist/core/auto-review.js +15 -9
  27. package/dist/core/codex/codex-config-guard.js +8 -0
  28. package/dist/core/codex-adapter.js +8 -10
  29. package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
  30. package/dist/core/codex-app/codex-app-launcher.js +10 -12
  31. package/dist/core/codex-app/codex-app-restart.js +10 -12
  32. package/dist/core/codex-app/menubar/constants.js +2 -5
  33. package/dist/core/codex-app/menubar/global-install.js +3 -2
  34. package/dist/core/codex-app/menubar/installer/result.js +23 -0
  35. package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
  36. package/dist/core/codex-app/menubar/installer.js +5 -96
  37. package/dist/core/codex-app/menubar/migration.js +1 -42
  38. package/dist/core/codex-app/openrouter-provider.js +0 -78
  39. package/dist/core/codex-app.js +97 -360
  40. package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
  41. package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
  42. package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
  43. package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
  44. package/dist/core/codex-control/codex-task-runner.js +16 -60
  45. package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
  46. package/dist/core/codex-exec-output-schema.js +11 -13
  47. package/dist/core/codex-lb/bridge-contracts.js +2 -0
  48. package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
  49. package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
  50. package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
  51. package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
  52. package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
  53. package/dist/core/codex-lb/capability-runner.js +505 -201
  54. package/dist/core/codex-lb/codex-lb-env.js +179 -12
  55. package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
  56. package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
  57. package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
  58. package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
  59. package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
  60. package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
  61. package/dist/core/codex-lb/combined-catalog.js +12 -0
  62. package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
  63. package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
  64. package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
  65. package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
  66. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
  67. package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
  68. package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
  69. package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
  70. package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
  71. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
  72. package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
  73. package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
  74. package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
  75. package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
  76. package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
  77. package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
  78. package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
  79. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
  80. package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
  81. package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
  82. package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
  83. package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
  84. package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
  85. package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
  86. package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
  87. package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
  88. package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
  89. package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
  90. package/dist/core/codex-lb/desktop-controller.js +2 -1730
  91. package/dist/core/codex-lb/desktop-service.js +462 -627
  92. package/dist/core/codex-lb/migration-receipt.js +560 -118
  93. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
  94. package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
  95. package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
  96. package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
  97. package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
  98. package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
  99. package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
  100. package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
  101. package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
  102. package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
  103. package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
  104. package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
  105. package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
  106. package/dist/core/codex-lb/provider-credentials/types.js +1 -0
  107. package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
  108. package/dist/core/codex-lb/provider-credentials.js +5 -0
  109. package/dist/core/codex-lb/provider-registry.js +323 -0
  110. package/dist/core/codex-lb/provider-route-policy.js +118 -0
  111. package/dist/core/codex-lb/request-route-resolver.js +172 -0
  112. package/dist/core/codex-lb/route-index.js +148 -0
  113. package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
  114. package/dist/core/commands/basic-cli.js +1 -1
  115. package/dist/core/commands/check-command.js +3 -10
  116. package/dist/core/commands/gate-result-contract.js +10 -14
  117. package/dist/core/commands/intent-normalization/normalizer.js +1 -1
  118. package/dist/core/commands/mad-sks-command.js +2 -6
  119. package/dist/core/commands/release-command.js +11 -1
  120. package/dist/core/commands/telegram-command.js +46 -6
  121. package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
  122. package/dist/core/doctor/skill-legacy-surface.js +5 -5
  123. package/dist/core/evidence/v2/evidence-key.js +30 -3
  124. package/dist/core/feature-fixtures.js +8 -1
  125. package/dist/core/feature-registry.js +3 -2
  126. package/dist/core/hooks-runtime/stop-finalization.js +11 -1
  127. package/dist/core/hooks-runtime/subagent-context.js +15 -1
  128. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
  129. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  130. package/dist/core/hooks-runtime.js +73 -87
  131. package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
  132. package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
  133. package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
  134. package/dist/core/imagegen/imagegen-capability.js +43 -151
  135. package/dist/core/init/skills/filesystem.js +89 -0
  136. package/dist/core/init/skills/inventory.js +97 -0
  137. package/dist/core/init/skills/manifest.js +151 -0
  138. package/dist/core/init/skills.js +5 -325
  139. package/dist/core/init.js +0 -63
  140. package/dist/core/install/installed-package-smoke.js +1 -1
  141. package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
  142. package/dist/core/policy/latest-version-guidance.js +15 -2
  143. package/dist/core/preflight/parallel-preflight-engine.js +27 -51
  144. package/dist/core/provider/provider-badge.js +9 -4
  145. package/dist/core/provider/provider-context.js +57 -107
  146. package/dist/core/providers/openrouter/openrouter-account.js +3 -1
  147. package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
  148. package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
  149. package/dist/core/release/gate-manifest.js +0 -1
  150. package/dist/core/release/main-push-guard.js +13 -0
  151. package/dist/core/release/main-push-receipt.js +11 -0
  152. package/dist/core/release/physical-release-gates.js +664 -61
  153. package/dist/core/release/publish-preflight.js +3 -3
  154. package/dist/core/release/release-gate-batch-runner.js +19 -6
  155. package/dist/core/release/release-gate-dag.js +33 -6
  156. package/dist/core/release/release-gate-node.js +1 -3
  157. package/dist/core/release/release-gate-output-contract.js +55 -0
  158. package/dist/core/release/release-pack-contract.js +1 -1
  159. package/dist/core/release/release-pack-receipt.js +209 -8
  160. package/dist/core/release/release-real-contract.js +1 -1
  161. package/dist/core/release/stage-publish.js +106 -28
  162. package/dist/core/retention/temp-lease.js +204 -0
  163. package/dist/core/retention.js +18 -195
  164. package/dist/core/routes.js +1 -2
  165. package/dist/core/safety/intent-contract/intent-contract.js +3 -3
  166. package/dist/core/subagents/naruto-host-credentials.js +6 -1
  167. package/dist/core/subagents/official-subagent-config.js +27 -9
  168. package/dist/core/subagents/official-subagent-runner.js +14 -31
  169. package/dist/core/subagents/wave-lifecycle.js +36 -8
  170. package/dist/core/subagents/wave-parent-guidance.js +2 -1
  171. package/dist/core/telegram/doctor.js +2 -2
  172. package/dist/core/telegram/liveness.js +10 -4
  173. package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
  174. package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
  175. package/dist/core/update/update-migration-state/session-state-split.js +247 -0
  176. package/dist/core/update/update-migration-state/simple-stages.js +46 -0
  177. package/dist/core/update/update-migration-state.js +4 -481
  178. package/dist/core/version.js +1 -1
  179. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
  180. package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
  181. package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
  182. package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
  183. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
  184. package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
  185. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
  186. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
  187. package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
  188. package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
  189. package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
  190. package/dist/scripts/canonical-test-runner.js +7 -1
  191. package/dist/scripts/check-runtime-schemas.js +7 -2
  192. package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
  193. package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
  194. package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
  195. package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
  196. package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
  197. package/dist/scripts/desktop-bridge-transport-client.js +116 -0
  198. package/dist/scripts/desktop-bridge-unification-check.js +276 -0
  199. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
  200. package/dist/scripts/gate-policy-audit-check.js +52 -2
  201. package/dist/scripts/provider-badge-context-check.js +55 -12
  202. package/dist/scripts/publish-preflight.js +1 -2
  203. package/dist/scripts/release-affected-selector-check.js +1 -2
  204. package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
  205. package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
  206. package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
  207. package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
  208. package/dist/scripts/release-gate-batch-runner-check.js +9 -0
  209. package/dist/scripts/release-gate-dag-runner-check.js +6 -0
  210. package/dist/scripts/release-gate-dag-runner.js +4 -2
  211. package/dist/scripts/release-metadata-check.js +16 -3
  212. package/dist/scripts/release-pack-receipt.js +29 -6
  213. package/dist/scripts/release-physical-gates-check.js +39 -0
  214. package/dist/scripts/release-real-check.js +7 -5
  215. package/package.json +6 -8
  216. package/release-gates.v2.json +156 -157
  217. package/runtime-required-scripts.json +11 -11
  218. package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
  219. package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
  220. package/schemas/release/release-gate-node.schema.json +2 -3
  221. package/dist/cli/codex-lb-setup-warning-output.js +0 -17
  222. package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
  223. package/dist/commands/codex-lb.js +0 -1232
  224. package/dist/core/architecture-hardening/migration/migration.js +0 -111
  225. package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
  226. package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
  227. package/dist/core/codex-app/child-policy/child-policy.js +0 -35
  228. package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
  229. package/dist/core/codex-app/glm-model-profile.js +0 -1
  230. package/dist/core/codex-app/glm-profile-installer.js +0 -191
  231. package/dist/core/codex-app/glm-profile-schema.js +0 -42
  232. package/dist/core/codex-app/multi-provider-router.js +0 -391
  233. package/dist/core/codex-app/openrouter-activate.js +0 -405
  234. package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
  235. package/dist/core/codex-app/provider-child-policy.js +0 -64
  236. package/dist/core/codex-app/provider-mode.js +0 -91
  237. package/dist/core/codex-app/provider-session-policy.js +0 -85
  238. package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
  239. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
  240. package/dist/core/codex-lb/codex-lb-setup.js +0 -293
  241. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
  242. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
  243. package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
  244. package/dist/core/codex-lb/desktop-mode.js +0 -32
  245. package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
  246. package/dist/core/codex-lb/legacy-migration.js +0 -576
  247. package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
  248. package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
  249. package/dist/core/codex-lb/routing-truth.js +0 -327
  250. package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
  251. package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
  252. package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
  253. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
  254. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
  255. package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
  256. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
  257. package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
  258. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
  259. package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
  260. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
  261. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +0 -231
@@ -9,15 +9,12 @@ import { MANAGED_ASSET_VERSION } from '../managed-assets/managed-assets-manifest
9
9
  import { enforceRetention } from '../retention.js';
10
10
  import { COMMANDS } from '../../cli/command-registry.js';
11
11
  import { reconcileLegacyManagedGeneration } from '../init/legacy-generation-convergence.js';
12
- import { codexHookTrustDoctor } from '../codex-hooks/codex-hook-trust-doctor.js';
13
- import { writeCodexConfigGuarded } from '../codex/codex-config-guard.js';
12
+ import { runConfigFastModeNormalizeStage } from './update-migration-state/fast-mode-config.js';
13
+ import { runSessionStateSplitStage } from './update-migration-state/session-state-split.js';
14
+ import { runHookTrustRefreshStage, runOtherHarnessCleanupStage } from './update-migration-state/simple-stages.js';
14
15
  import { compareSemVer } from './semver.js';
15
- import { escapeRegExp } from '../text/regex.js';
16
- import { sessionStateKey } from '../mission.js';
17
- import { ensureConfinedDirectory, inspectConfinedPath, moveConfinedPath, uniqueConfinedPath } from '../managed-path-safety.js';
18
16
  export const UPDATE_MIGRATION_SCHEMA = 'sks.project-migration-receipt.v2';
19
17
  export const INSTALLATION_EPOCH_SCHEMA = 'sks.installation-epoch.v1';
20
- const LEGACY_CURRENT_STATE_MAX_BYTES = 1024 * 1024;
21
18
  export function installationEpochPath() {
22
19
  return path.join(globalSksRoot(), 'update', 'installation-epoch.json');
23
20
  }
@@ -191,6 +188,7 @@ export async function runUpdateRetentionCleanup(root, source = 'update-migration
191
188
  const result = await enforceRetention(root, {
192
189
  mode: 'update_migration',
193
190
  pruneReportLogs: true,
191
+ skipSksTempSweep: true,
194
192
  policy: { max_tmp_age_hours: 0 }
195
193
  });
196
194
  return {
@@ -262,37 +260,6 @@ const UPDATE_MIGRATION_STAGES = [
262
260
  run: runReceiptRotationStage
263
261
  }
264
262
  ];
265
- async function runOtherHarnessCleanupStage(root) {
266
- const { scanHarnessConflicts } = await import('../harness-conflicts.js');
267
- const scan = await scanHarnessConflicts(root);
268
- if (scan.hard_block) {
269
- return {
270
- ok: false,
271
- status: 'failed',
272
- actions: ['other_harness_conflict_detected'],
273
- blockers: scan.hard.map((row) => `other_harness_conflict:${row.path}`),
274
- warnings: [],
275
- detail: {
276
- cleaned_count: 0,
277
- remaining_count: scan.hard.length,
278
- error_count: 0,
279
- cleanup_prompt_command: 'sks conflicts cleanup --yes'
280
- }
281
- };
282
- }
283
- return {
284
- ok: true,
285
- status: 'ok',
286
- actions: ['other_harness_conflict_check_clean'],
287
- blockers: [],
288
- warnings: [],
289
- detail: {
290
- cleaned_count: 0,
291
- remaining_count: 0,
292
- error_count: 0
293
- }
294
- };
295
- }
296
263
  async function runCurrentPublicSurfaceReconcileStage(root) {
297
264
  const [{ runDoctorCommandAliasCleanup }, { migrateSksProfilesToPerFile }, { cleanupRetiredRemoteBridgeLaunchAgent, quarantineRetiredRemoteBridgeBindings }] = await Promise.all([
298
265
  import('../doctor/command-alias-cleanup.js'),
@@ -402,242 +369,6 @@ async function runUpdateMigrationStages(root, opts = {}) {
402
369
  }
403
370
  return runs;
404
371
  }
405
- async function runSessionStateSplitStage(root) {
406
- const legacyCurrent = path.join(root, '.sneakoscope', 'current.json');
407
- const stateCurrent = path.join(root, '.sneakoscope', 'state', 'current.json');
408
- const sessionsDir = path.join(root, '.sneakoscope', 'state', 'sessions');
409
- await ensureConfinedDirectory(root, sessionsDir);
410
- const actions = [];
411
- const legacyRead = await readBoundedUpdateState(root, legacyCurrent, { requireLegacyShape: true });
412
- if (legacyRead.blocker) {
413
- return {
414
- ok: false,
415
- status: 'failed',
416
- actions: ['legacy_current_state_preserved'],
417
- blockers: [legacyRead.blocker],
418
- warnings: [],
419
- detail: { legacy_present: legacyRead.present }
420
- };
421
- }
422
- const currentRead = await readBoundedUpdateState(root, stateCurrent);
423
- if (currentRead.blocker) {
424
- return {
425
- ok: false,
426
- status: 'failed',
427
- actions: ['current_state_preserved'],
428
- blockers: [currentRead.blocker],
429
- warnings: [],
430
- detail: { legacy_present: legacyRead.present }
431
- };
432
- }
433
- let current = currentRead.value;
434
- if (!current && legacyRead.value) {
435
- current = legacyRead.value;
436
- await writeJsonAtomic(stateCurrent, current);
437
- const verified = await readBoundedUpdateState(root, stateCurrent);
438
- if (verified.blocker || !verified.value || updateStateDigest(verified.value) !== legacyRead.sha256) {
439
- return {
440
- ok: false,
441
- status: 'failed',
442
- actions: ['copy_legacy_current_json_failed_verification'],
443
- blockers: [verified.blocker || 'legacy_current_state_copy_verification_failed'],
444
- warnings: [],
445
- detail: { legacy_present: true }
446
- };
447
- }
448
- actions.push('copied_legacy_current_json_to_state_current');
449
- }
450
- const missionId = typeof current?.mission_id === 'string' ? current.mission_id : typeof current?.mission === 'string' ? current.mission : null;
451
- const rawSessionKey = typeof current?._session_key === 'string' && current._session_key.trim()
452
- ? current._session_key
453
- : null;
454
- const canonicalSessionKey = rawSessionKey ? sessionStateKey(rawSessionKey) : null;
455
- if (canonicalSessionKey) {
456
- const sessionPath = path.join(sessionsDir, `${canonicalSessionKey}.json`);
457
- const sessionRead = await readBoundedUpdateState(root, sessionPath);
458
- if (sessionRead.blocker) {
459
- return {
460
- ok: false,
461
- status: 'failed',
462
- actions,
463
- blockers: [sessionRead.blocker],
464
- warnings: [],
465
- detail: { legacy_present: legacyRead.present, mission_id: missionId, session_key: canonicalSessionKey }
466
- };
467
- }
468
- if (!sessionRead.present) {
469
- await writeJsonAtomic(sessionPath, {
470
- ...current,
471
- _session_key: canonicalSessionKey,
472
- migrated_from: path.relative(root, stateCurrent),
473
- migrated_at: nowIso()
474
- });
475
- const verifiedSession = await readBoundedUpdateState(root, sessionPath);
476
- if (verifiedSession.blocker
477
- || verifiedSession.value?._session_key !== canonicalSessionKey
478
- || verifiedSession.value?.mission_id !== current?.mission_id) {
479
- return {
480
- ok: false,
481
- status: 'failed',
482
- actions,
483
- blockers: [verifiedSession.blocker || 'legacy_session_state_copy_verification_failed'],
484
- warnings: [],
485
- detail: { legacy_present: legacyRead.present, mission_id: missionId, session_key: canonicalSessionKey }
486
- };
487
- }
488
- actions.push('wrote_state_session_alias');
489
- }
490
- }
491
- let quarantinePath = null;
492
- if (legacyRead.present) {
493
- const quarantineBase = path.join(root, '.sneakoscope', 'quarantine', 'update-legacy-state', `current-${legacyRead.sha256?.slice(0, 12) || 'unknown'}.json`);
494
- quarantinePath = await uniqueConfinedPath(root, quarantineBase);
495
- await moveConfinedPath(root, legacyCurrent, quarantinePath);
496
- const quarantined = await readBoundedUpdateState(root, quarantinePath, { requireLegacyShape: true });
497
- const legacyAfter = await inspectConfinedPath(root, legacyCurrent);
498
- if (legacyAfter.exists
499
- || quarantined.blocker
500
- || !quarantined.value
501
- || quarantined.sha256 !== legacyRead.sha256) {
502
- const sourceAfter = await inspectConfinedPath(root, legacyCurrent);
503
- if (!sourceAfter.exists && (await inspectConfinedPath(root, quarantinePath)).exists) {
504
- await moveConfinedPath(root, quarantinePath, legacyCurrent).catch(() => undefined);
505
- }
506
- return {
507
- ok: false,
508
- status: 'failed',
509
- actions: [...actions, 'legacy_current_state_quarantine_rolled_back'],
510
- blockers: [quarantined.blocker || 'legacy_current_state_quarantine_verification_failed'],
511
- warnings: [],
512
- detail: { legacy_present: true, mission_id: missionId }
513
- };
514
- }
515
- actions.push('quarantined_legacy_current_json');
516
- }
517
- if (!actions.length)
518
- actions.push('session_state_current');
519
- return {
520
- ok: true,
521
- status: 'ok',
522
- actions,
523
- blockers: [],
524
- warnings: [],
525
- detail: {
526
- legacy_present: legacyRead.present,
527
- mission_id: missionId,
528
- session_key: canonicalSessionKey,
529
- legacy_quarantine_path: quarantinePath ? path.relative(root, quarantinePath) : null
530
- }
531
- };
532
- }
533
- async function readBoundedUpdateState(root, file, opts = {}) {
534
- let inspected;
535
- try {
536
- inspected = await inspectConfinedPath(root, file);
537
- }
538
- catch (error) {
539
- return {
540
- present: true,
541
- value: null,
542
- sha256: null,
543
- blocker: `update_state_path_unsafe:${error?.code || error?.message || String(error)}`
544
- };
545
- }
546
- if (!inspected.exists)
547
- return { present: false, value: null, sha256: null, blocker: null };
548
- if (inspected.leafSymlink) {
549
- return { present: true, value: null, sha256: null, blocker: 'update_state_symlink_refused' };
550
- }
551
- if (!inspected.stat?.isFile()) {
552
- return { present: true, value: null, sha256: null, blocker: 'update_state_non_regular_refused' };
553
- }
554
- if (inspected.stat.size > LEGACY_CURRENT_STATE_MAX_BYTES) {
555
- return { present: true, value: null, sha256: null, blocker: 'update_state_size_limit_exceeded' };
556
- }
557
- let text;
558
- let handle = null;
559
- try {
560
- const noFollow = process.platform === 'win32' ? 0 : fsConstants.O_NOFOLLOW;
561
- handle = await fsp.open(file, fsConstants.O_RDONLY | noFollow);
562
- const before = await handle.stat();
563
- if (!before.isFile()) {
564
- return { present: true, value: null, sha256: null, blocker: 'update_state_non_regular_refused' };
565
- }
566
- if (before.size > LEGACY_CURRENT_STATE_MAX_BYTES) {
567
- return { present: true, value: null, sha256: null, blocker: 'update_state_size_limit_exceeded' };
568
- }
569
- const buffer = Buffer.alloc(LEGACY_CURRENT_STATE_MAX_BYTES + 1);
570
- const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
571
- const after = await handle.stat();
572
- const pathAfter = await inspectConfinedPath(root, file);
573
- if (bytesRead > LEGACY_CURRENT_STATE_MAX_BYTES
574
- || bytesRead !== before.size
575
- || after.size !== before.size
576
- || after.dev !== before.dev
577
- || after.ino !== before.ino
578
- || !pathAfter.exists
579
- || pathAfter.leafSymlink
580
- || pathAfter.stat?.dev !== after.dev
581
- || pathAfter.stat?.ino !== after.ino) {
582
- return { present: true, value: null, sha256: null, blocker: 'update_state_changed_during_safe_read' };
583
- }
584
- text = buffer.subarray(0, bytesRead).toString('utf8');
585
- }
586
- catch (error) {
587
- return {
588
- present: true,
589
- value: null,
590
- sha256: null,
591
- blocker: `update_state_read_failed:${error?.code || error?.message || String(error)}`
592
- };
593
- }
594
- finally {
595
- await handle?.close().catch(() => undefined);
596
- }
597
- let value;
598
- try {
599
- value = JSON.parse(text);
600
- }
601
- catch {
602
- return { present: true, value: null, sha256: null, blocker: 'update_state_json_invalid' };
603
- }
604
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
605
- return { present: true, value: null, sha256: null, blocker: 'update_state_object_required' };
606
- }
607
- const record = value;
608
- if (opts.requireLegacyShape && !isRecognizedLegacyCurrentState(record)) {
609
- return { present: true, value: null, sha256: null, blocker: 'legacy_current_state_ownership_unproven' };
610
- }
611
- return {
612
- present: true,
613
- value: record,
614
- sha256: updateStateDigest(record),
615
- blocker: null
616
- };
617
- }
618
- function isRecognizedLegacyCurrentState(value) {
619
- const mission = typeof value.mission_id === 'string'
620
- ? value.mission_id.trim()
621
- : typeof value.mission === 'string'
622
- ? value.mission.trim()
623
- : '';
624
- if (/^M-[A-Za-z0-9][A-Za-z0-9._-]{2,127}$/.test(mission))
625
- return true;
626
- const mode = typeof value.mode === 'string' ? value.mode.trim() : '';
627
- const phase = typeof value.phase === 'string' ? value.phase.trim() : '';
628
- if (mode === 'IDLE' && phase === 'IDLE')
629
- return true;
630
- if (!mode || !phase)
631
- return false;
632
- const sessionKey = typeof value._session_key === 'string' && value._session_key.trim().length > 0;
633
- const routeCommand = typeof value.route_command === 'string' && value.route_command.trim().startsWith('$');
634
- const managedStopGate = ['stop_gate', 'stop_gate_abs_path']
635
- .some((key) => typeof value[key] === 'string' && String(value[key]).trim().length > 0);
636
- return sessionKey || routeCommand || managedStopGate;
637
- }
638
- function updateStateDigest(value) {
639
- return sha256(JSON.stringify(value));
640
- }
641
372
  async function runSkillsReconcileStage(root) {
642
373
  if (process.env.SKS_TEST_UPDATE_GLOBAL_SKILLS_FAIL === '1') {
643
374
  return {
@@ -754,83 +485,6 @@ async function runMenubarRetargetStage(root) {
754
485
  }
755
486
  };
756
487
  }
757
- async function runConfigFastModeNormalizeStage() {
758
- const { reconcileRetiredSksConfigText } = await import('../auto-review.js');
759
- const configPath = path.join(os.homedir(), '.codex', 'config.toml');
760
- const text = await readText(configPath, null);
761
- if (typeof text !== 'string')
762
- return { ok: true, status: 'ok', actions: ['codex_config_absent'], blockers: [], warnings: [] };
763
- const normalized = normalizeLegacyFastModeConfigForUpdate(text);
764
- const retired = reconcileRetiredSksConfigText(normalized.text);
765
- const nextText = ensureTrailingNewline(retired.text);
766
- const actions = [
767
- ...normalized.actions,
768
- ...(retired.detected_count > 0 ? ['stripped_retired_sks_config_profiles_and_policies'] : [])
769
- ];
770
- if (nextText === ensureTrailingNewline(text)) {
771
- return {
772
- ok: true,
773
- status: 'ok',
774
- actions: actions.length ? actions : ['fastmode_config_current'],
775
- blockers: [],
776
- warnings: [],
777
- detail: {
778
- config_path: configPath,
779
- default_profile: normalized.defaultProfile,
780
- retired_config_detected_count: retired.detected_count
781
- }
782
- };
783
- }
784
- let guardResult = null;
785
- guardResult = await writeCodexConfigGuarded({
786
- configPath,
787
- before: text,
788
- mutate: () => nextText,
789
- cause: 'project-update-fastmode-normalize',
790
- backupTag: 'project-update-fastmode-normalize',
791
- preserveFastUiKeys: true
792
- });
793
- if (!guardResult.ok) {
794
- return {
795
- ok: false,
796
- status: 'failed',
797
- actions: ['normalize_fastmode_config_blocked'],
798
- blockers: [`codex_config_guard:${guardResult.status}`],
799
- warnings: [],
800
- detail: {
801
- config_path: configPath,
802
- default_profile: normalized.defaultProfile,
803
- retired_config_detected_count: retired.detected_count,
804
- guard: guardResult
805
- }
806
- };
807
- }
808
- return {
809
- ok: true,
810
- status: 'ok',
811
- actions: actions.length ? actions : ['fastmode_config_current'],
812
- blockers: [],
813
- warnings: [],
814
- detail: {
815
- config_path: configPath,
816
- default_profile: normalized.defaultProfile,
817
- retired_config_detected_count: retired.detected_count,
818
- guard: guardResult
819
- }
820
- };
821
- }
822
- async function runHookTrustRefreshStage(root) {
823
- const result = await codexHookTrustDoctor(root, { fix: true, managed: true, actual: true });
824
- const blockers = result.ok === false ? (result.blockers || ['hook_trust_refresh_failed']) : [];
825
- return {
826
- ok: blockers.length === 0,
827
- status: blockers.length ? 'failed' : 'ok',
828
- actions: ['refreshed_hook_trust'],
829
- blockers,
830
- warnings: result.warnings || [],
831
- detail: { entries: result.current_hash_count ?? null }
832
- };
833
- }
834
488
  async function runReceiptRotationStage(root) {
835
489
  const receiptPath = projectUpdateMigrationReceiptPath(root);
836
490
  const dir = path.dirname(receiptPath);
@@ -866,137 +520,6 @@ function legacyStageApplies(fromVersion, minFromVersion) {
866
520
  function compareVersionLike(a, b) {
867
521
  return compareSemVer(a, b) ?? 0;
868
522
  }
869
- function insertTopLevelTomlKey(text, line) {
870
- const raw = String(text || '').trimEnd();
871
- const firstTable = raw.search(/^\s*\[/m);
872
- if (firstTable < 0)
873
- return `${line}\n${raw}`.trim() + '\n';
874
- return `${raw.slice(0, firstTable).trimEnd()}\n${line}\n\n${raw.slice(firstTable).trimStart()}`.trim() + '\n';
875
- }
876
- function normalizeLegacyFastModeConfigForUpdate(text) {
877
- let next = String(text || '');
878
- const actions = [];
879
- const misplaced = tomlTableString(next, 'user.fast_mode', 'default_profile');
880
- const topLevel = topLevelTomlString(next, 'default_profile');
881
- const legacyFastDefault = misplaced === 'sks-fast-high' || topLevel === 'sks-fast-high';
882
- const before = next;
883
- next = removeTopLevelTomlKeyLocal(next, 'default_profile');
884
- next = removeTomlTableLocal(next, 'user.fast_mode');
885
- next = removeTomlTableLocal(next, 'profiles.sks-fast-high');
886
- next = removeTomlTableKeyLocal(next, 'notice', 'fast_default_opt_out');
887
- if (next !== before)
888
- actions.push('stripped_removed_fastmode_config_schema_keys');
889
- if (legacyFastDefault && !topLevelTomlString(next, 'service_tier')) {
890
- next = insertTopLevelTomlKey(next, 'service_tier = "fast"');
891
- actions.push('migrated_legacy_fast_default_to_service_tier');
892
- }
893
- return { text: ensureTrailingNewline(next), actions, defaultProfile: misplaced || topLevel };
894
- }
895
- function removeTopLevelTomlKeyLocal(text, key) {
896
- const lines = String(text || '').split('\n');
897
- const firstTable = lines.findIndex((x) => /^\s*\[.+\]\s*$/.test(x));
898
- const end = firstTable === -1 ? lines.length : firstTable;
899
- const keyPattern = new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`);
900
- return lines.filter((line, index) => index >= end || !keyPattern.test(line)).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
901
- }
902
- function removeTomlTableLocal(text, table) {
903
- const lines = String(text || '').trimEnd().split('\n');
904
- const header = `[${table}]`;
905
- const start = lines.findIndex((x) => x.trim() === header);
906
- if (start === -1)
907
- return String(text || '');
908
- let end = lines.length;
909
- for (let i = start + 1; i < lines.length; i += 1) {
910
- const ln = lines[i];
911
- if (ln !== undefined && /^\s*\[.+\]\s*$/.test(ln)) {
912
- end = i;
913
- break;
914
- }
915
- }
916
- return lines.filter((_, index) => index < start || index >= end).join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
917
- }
918
- function tomlTableString(text, table, key) {
919
- const block = tomlTableBlock(text, table);
920
- const match = block?.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, 'm'));
921
- return match?.[1] || null;
922
- }
923
- function topLevelTomlString(text, key) {
924
- const source = String(text || '');
925
- const firstTable = source.search(/^\s*\[/m);
926
- const top = firstTable < 0 ? source : source.slice(0, firstTable);
927
- const match = top.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, 'm'));
928
- return match?.[1] || null;
929
- }
930
- function tomlTableBlock(text, table) {
931
- const lines = String(text || '').split(/\r?\n/);
932
- const start = lines.findIndex((line) => tableHeaderMatches(line, table));
933
- if (start < 0)
934
- return null;
935
- let end = lines.length;
936
- for (let index = start + 1; index < lines.length; index += 1) {
937
- if (/^\s*\[[^\]]+\]\s*$/.test(lines[index] || '')) {
938
- end = index;
939
- break;
940
- }
941
- }
942
- return lines.slice(start, end).join('\n');
943
- }
944
- function removeTomlTableKeyLocal(text, table, key) {
945
- const lines = String(text || '').split(/\r?\n/);
946
- let inTable = false;
947
- const out = [];
948
- for (const line of lines) {
949
- if (/^\s*\[[^\]]+\]\s*$/.test(line))
950
- inTable = tableHeaderMatches(line, table);
951
- if (inTable && new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(line))
952
- continue;
953
- out.push(line);
954
- }
955
- return out.join('\n');
956
- }
957
- function upsertTomlTableKeyIfAbsentLocal(text, table, line) {
958
- const key = tomlLineKey(line);
959
- return tomlTableHasKey(text, table, key) ? text : upsertTomlTableKeyLocal(text, table, line);
960
- }
961
- function upsertTomlTableKeyLocal(text, table, line) {
962
- const raw = String(text || '').trimEnd();
963
- const key = tomlLineKey(line);
964
- const lines = raw ? raw.split(/\r?\n/) : [];
965
- const start = lines.findIndex((candidate) => tableHeaderMatches(candidate, table));
966
- if (start < 0) {
967
- return `${raw}${raw ? '\n\n' : ''}[${table}]\n${line}\n`;
968
- }
969
- let end = lines.length;
970
- for (let index = start + 1; index < lines.length; index += 1) {
971
- if (/^\s*\[[^\]]+\]\s*$/.test(lines[index] || '')) {
972
- end = index;
973
- break;
974
- }
975
- }
976
- for (let index = start + 1; index < end; index += 1) {
977
- if (new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(lines[index] || '')) {
978
- if (lines[index] === line)
979
- return `${lines.join('\n')}\n`;
980
- lines[index] = line;
981
- return `${lines.join('\n')}\n`;
982
- }
983
- }
984
- lines.splice(end, 0, line);
985
- return `${lines.join('\n')}\n`;
986
- }
987
- function tomlTableHasKey(text, table, key) {
988
- const block = tomlTableBlock(text, table);
989
- return Boolean(block && new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`, 'm').test(block));
990
- }
991
- function tableHeaderMatches(line, table) {
992
- return new RegExp(`^\\s*\\[${escapeRegExp(table)}\\]\\s*$`).test(line || '');
993
- }
994
- function tomlLineKey(line) {
995
- return String(line || '').split('=')[0]?.trim() || '';
996
- }
997
- function ensureTrailingNewline(text) {
998
- return `${String(text || '').trim()}\n`;
999
- }
1000
523
  export async function ensureCurrentMigrationBeforeCommand(input) {
1001
524
  const env = input.env || process.env;
1002
525
  const command = input.command;
@@ -1 +1 @@
1
- export const PACKAGE_VERSION = '8.1.2';
1
+ export const PACKAGE_VERSION = '8.2.0';
@@ -40,7 +40,7 @@ final class OperationCoordinator {
40
40
  state: .queued, stage: "queued", progress: 0, startedAt: now,
41
41
  updatedAt: now, publicSummary: summary, logPath: AppRuntime.lastActionLogPath,
42
42
  retryable: true, targetVersion: targetVersion, projectRoot: projectRoot,
43
- registry: registry, recovery: nil, providerApply: providerApply
43
+ registry: registry, recovery: nil, providerApply: providerApply, diagnostic: nil
44
44
  )
45
45
  if let group = mutationGroup { activeMutation = (snapshot.id, group) }
46
46
  write(snapshot)
@@ -65,7 +65,7 @@ final class OperationCoordinator {
65
65
  publicSummary: summary, logPath: snapshot.logPath, retryable: retryable,
66
66
  targetVersion: snapshot.targetVersion, projectRoot: snapshot.projectRoot,
67
67
  registry: snapshot.registry, recovery: snapshot.recovery,
68
- providerApply: snapshot.providerApply
68
+ providerApply: snapshot.providerApply, diagnostic: snapshot.diagnostic
69
69
  )
70
70
  write(next)
71
71
  if releaseMutationGuard, [.succeeded, .failed, .cancelled, .terminalUncertain].contains(state) {
@@ -118,7 +118,7 @@ final class OperationCoordinator {
118
118
  retryable: status.state == .autoResumePending || status.state == .pausedResumable,
119
119
  targetVersion: snapshot.targetVersion, projectRoot: snapshot.projectRoot,
120
120
  registry: snapshot.registry, recovery: status,
121
- providerApply: snapshot.providerApply
121
+ providerApply: snapshot.providerApply, diagnostic: snapshot.diagnostic
122
122
  )
123
123
  write(next)
124
124
  if status.state == .pausedResumable, activeMutation?.id == snapshot.id {
@@ -153,7 +153,7 @@ final class OperationCoordinator {
153
153
  retryable: projection.failedStage != nil,
154
154
  targetVersion: snapshot.targetVersion, projectRoot: snapshot.projectRoot,
155
155
  registry: snapshot.registry, recovery: snapshot.recovery,
156
- providerApply: projection
156
+ providerApply: projection, diagnostic: snapshot.diagnostic
157
157
  )
158
158
  write(next)
159
159
  if (nextState == .waitingForConfirmation || nextState == .succeeded)
@@ -164,6 +164,30 @@ final class OperationCoordinator {
164
164
  }
165
165
  }
166
166
 
167
+ /// Persists only the non-secret diagnostic identity/readiness projection on
168
+ /// the operation receipt. The CLI report body and provider credentials never
169
+ /// enter the operation store.
170
+ func recordDiagnostic(
171
+ _ snapshot: OperationSnapshot,
172
+ metadata: DiagnosticOperationMetadata
173
+ ) -> OperationSnapshot {
174
+ queue.sync {
175
+ let next = OperationSnapshot(
176
+ schema: snapshot.schema, id: snapshot.id, kind: snapshot.kind,
177
+ state: snapshot.state, stage: snapshot.stage, progress: snapshot.progress,
178
+ startedAt: snapshot.startedAt,
179
+ updatedAt: ISO8601DateFormatter().string(from: Date()),
180
+ publicSummary: snapshot.publicSummary, logPath: snapshot.logPath,
181
+ retryable: snapshot.retryable, targetVersion: snapshot.targetVersion,
182
+ projectRoot: snapshot.projectRoot, registry: snapshot.registry,
183
+ recovery: snapshot.recovery, providerApply: snapshot.providerApply,
184
+ diagnostic: metadata
185
+ )
186
+ write(next)
187
+ return next
188
+ }
189
+ }
190
+
167
191
  /// Executes one caller-declared retry-safe operation. The exact same closure
168
192
  /// may be re-entered only for a transient network classification and at most
169
193
  /// twice. Authentication, provider mode, account binding, external settings,