sneakoscope 4.8.7 → 5.3.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 +51 -726
  2. package/config/bench-baseline.json +7 -0
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/crates/sks-core/src/main.rs +1 -1
  6. package/dist/bin/install.js +35 -0
  7. package/dist/bin/sks.js +1 -1
  8. package/dist/cli/cli-theme.js +51 -0
  9. package/dist/cli/command-registry.js +15 -4
  10. package/dist/cli/help-fast.js +18 -8
  11. package/dist/cli/insane-search-command.js +36 -8
  12. package/dist/cli/install-helpers.js +32 -0
  13. package/dist/commands/codex-lb.js +2 -0
  14. package/dist/commands/doctor.js +94 -9
  15. package/dist/commands/proof.js +6 -3
  16. package/dist/config/skills-manifest.json +82 -54
  17. package/dist/core/agents/agent-conflict-graph.js +5 -0
  18. package/dist/core/agents/agent-lease.js +5 -0
  19. package/dist/core/agents/agent-ledger-schemas.js +1 -0
  20. package/dist/core/agents/agent-lifecycle.js +5 -3
  21. package/dist/core/agents/agent-orchestrator.js +268 -62
  22. package/dist/core/agents/agent-output-validator.js +14 -3
  23. package/dist/core/agents/agent-patch-queue-store.js +95 -2
  24. package/dist/core/agents/agent-patch-queue.js +6 -3
  25. package/dist/core/agents/agent-patch-schema.js +13 -0
  26. package/dist/core/agents/agent-proof-evidence.js +6 -1
  27. package/dist/core/agents/agent-runner-fake.js +40 -0
  28. package/dist/core/agents/agent-worker-pipeline.js +36 -2
  29. package/dist/core/agents/codex-exec-worker-adapter.js +2 -0
  30. package/dist/core/agents/native-cli-worker.js +0 -1
  31. package/dist/core/agents/native-worker-backend-router.js +58 -1
  32. package/dist/core/codex-app/sks-menubar.js +477 -132
  33. package/dist/core/codex-app.js +1 -0
  34. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  35. package/dist/core/codex-control/codex-sdk-env-policy.js +1 -1
  36. package/dist/core/codex-control/schemas/agent-worker-result.schema.js +12 -3
  37. package/dist/core/codex-hooks/codex-hook-managed-install.js +5 -0
  38. package/dist/core/codex-hooks/codex-hook-state-writer.js +70 -11
  39. package/dist/core/codex-hooks/codex-hook-trust-doctor.js +2 -2
  40. package/dist/core/codex-lb/codex-lb-env.js +20 -1
  41. package/dist/core/commands/basic-cli.js +18 -1
  42. package/dist/core/commands/check-command.js +37 -5
  43. package/dist/core/commands/computer-use-command.js +62 -7
  44. package/dist/core/commands/db-command.js +31 -5
  45. package/dist/core/commands/fast-mode-command.js +3 -0
  46. package/dist/core/commands/gate-result-contract.js +43 -0
  47. package/dist/core/commands/gates-command.js +6 -1
  48. package/dist/core/commands/gc-command.js +29 -2
  49. package/dist/core/commands/goal-command.js +9 -2
  50. package/dist/core/commands/gx-command.js +79 -7
  51. package/dist/core/commands/image-ux-review-command.js +188 -13
  52. package/dist/core/commands/mad-db-command.js +85 -176
  53. package/dist/core/commands/mad-sks-command.js +230 -29
  54. package/dist/core/commands/menubar-command.js +24 -2
  55. package/dist/core/commands/naruto-command.js +64 -10
  56. package/dist/core/commands/plan-command.js +76 -0
  57. package/dist/core/commands/ppt-command.js +159 -24
  58. package/dist/core/commands/qa-loop-command.js +6 -2
  59. package/dist/core/commands/release-command.js +55 -2
  60. package/dist/core/commands/research-command.js +1 -1
  61. package/dist/core/commands/review-command.js +217 -0
  62. package/dist/core/commands/route-success-helpers.js +59 -0
  63. package/dist/core/commands/run-command.js +19 -7
  64. package/dist/core/commands/seo-command.js +49 -1
  65. package/dist/core/commands/ui-command.js +161 -0
  66. package/dist/core/commands/uninstall-command.js +15 -1
  67. package/dist/core/db-safety.js +2 -2
  68. package/dist/core/doctor/doctor-dirty-planner.js +51 -7
  69. package/dist/core/doctor/doctor-transaction.js +8 -0
  70. package/dist/core/doctor/doctor-zellij-repair.js +1 -0
  71. package/dist/core/doctor/imagegen-repair.js +161 -0
  72. package/dist/core/feature-fixture-runner.js +2 -2
  73. package/dist/core/feature-fixtures.js +58 -37
  74. package/dist/core/feature-registry.js +102 -2
  75. package/dist/core/fsx.js +39 -6
  76. package/dist/core/image-ux-review/imagegen-adapter.js +48 -11
  77. package/dist/core/image-ux-review.js +16 -0
  78. package/dist/core/imagegen/imagegen-capability.js +11 -5
  79. package/dist/core/imagegen/require-imagegen.js +57 -0
  80. package/dist/core/init/skills.js +10 -5
  81. package/dist/core/mad-db/mad-db-coordinator.js +94 -18
  82. package/dist/core/mad-db/mad-db-policy.js +12 -10
  83. package/dist/core/mad-sks/executors/executor-base.js +8 -2
  84. package/dist/core/mad-sks/executors/index.js +4 -0
  85. package/dist/core/mad-sks/executors/sql-plane-executor.js +194 -0
  86. package/dist/core/naruto/naruto-active-pool.js +15 -4
  87. package/dist/core/naruto/naruto-real-worker-child.js +11 -1
  88. package/dist/core/naruto/naruto-role-policy.js +3 -0
  89. package/dist/core/naruto/naruto-task-hints.js +10 -0
  90. package/dist/core/naruto/naruto-work-graph.js +8 -2
  91. package/dist/core/naruto/naruto-work-item.js +6 -0
  92. package/dist/core/naruto/solution-tournament.js +101 -0
  93. package/dist/core/permission-gates.js +30 -0
  94. package/dist/core/pipeline-internals/runtime-core.js +11 -3
  95. package/dist/core/pipeline-internals/runtime-gates.js +27 -0
  96. package/dist/core/ppt-review/index.js +6 -1
  97. package/dist/core/ppt-review/slide-imagegen-review.js +75 -10
  98. package/dist/core/ppt.js +70 -2
  99. package/dist/core/proof/auto-finalize.js +70 -11
  100. package/dist/core/proof/proof-schema.js +2 -0
  101. package/dist/core/proof/route-adapter.js +5 -1
  102. package/dist/core/proof/route-finalizer.js +8 -5
  103. package/dist/core/proof/selftest-proof-fixtures.js +18 -5
  104. package/dist/core/proof/validation.js +2 -0
  105. package/dist/core/provider/model-router.js +53 -0
  106. package/dist/core/release/release-gate-node.js +3 -0
  107. package/dist/core/release/release-gate-resource-governor.js +1 -0
  108. package/dist/core/routes/constants.js +1 -1
  109. package/dist/core/routes.js +65 -18
  110. package/dist/core/safety/mutation-guard.js +5 -1
  111. package/dist/core/stop-gate/gate-evaluator.js +102 -0
  112. package/dist/core/stop-gate/stop-gate-check.js +16 -1
  113. package/dist/core/stop-gate/stop-gate-writer.js +4 -0
  114. package/dist/core/triwiki/agents-md-projector.js +184 -0
  115. package/dist/core/triwiki-wrongness/wrongness-schema.js +3 -1
  116. package/dist/core/trust-kernel/trust-kernel-schema.js +1 -0
  117. package/dist/core/trust-kernel/trust-report.js +1 -1
  118. package/dist/core/trust-kernel/trust-status.js +2 -0
  119. package/dist/core/ui/dashboard-html.js +111 -0
  120. package/dist/core/update/update-migration-state.js +386 -15
  121. package/dist/core/update-check.js +178 -81
  122. package/dist/core/verification/diff-quality.js +100 -0
  123. package/dist/core/verification/impact-scan.js +164 -0
  124. package/dist/core/verification/machine-feedback.js +146 -0
  125. package/dist/core/verification/mistake-rule-compiler.js +195 -0
  126. package/dist/core/version.js +1 -1
  127. package/dist/core/zellij/zellij-self-heal.js +9 -6
  128. package/dist/core/zellij/zellij-slot-telemetry.js +1 -1
  129. package/dist/scripts/check-feature-quality.js +2 -2
  130. package/dist/scripts/cli-output-consistency-check.js +57 -0
  131. package/dist/scripts/coding-bench-check.js +136 -0
  132. package/dist/scripts/doctor-imagegen-repair-check.js +62 -0
  133. package/dist/scripts/ensure-bin-executable.js +11 -3
  134. package/dist/scripts/harness-benchmark-check.js +104 -0
  135. package/dist/scripts/legacy-update-e2e-check.js +228 -0
  136. package/dist/scripts/mad-db-command-check.js +11 -8
  137. package/dist/scripts/mad-db-route-identity-check.js +8 -6
  138. package/dist/scripts/mad-db-safety-conflict-matrix-check.js +31 -8
  139. package/dist/scripts/mad-db-skill-policy-snapshot-check.js +4 -5
  140. package/dist/scripts/naruto-real-active-pool-runtime-check.js +26 -1
  141. package/dist/scripts/ppt-real-imagegen-wiring-check.js +5 -1
  142. package/dist/scripts/proof-root-cause-policy-check.js +2 -0
  143. package/dist/scripts/release-dag-full-coverage-check.js +13 -4
  144. package/dist/scripts/release-gate-dag-runner.js +14 -0
  145. package/dist/scripts/release-gate-existence-audit.js +2 -1
  146. package/dist/scripts/release-gate-planner.js +2 -1
  147. package/dist/scripts/release-gate-script-parity-check.js +45 -17
  148. package/dist/scripts/release-metadata-1-19-check.js +2 -1
  149. package/dist/scripts/seo-geo-feature-fixture-quality-check.js +1 -1
  150. package/dist/scripts/sks-1-11-gate-lib.js +8 -6
  151. package/dist/scripts/sks-menubar-install-check.js +57 -20
  152. package/dist/scripts/ux-review-real-loop-fixture-check.js +9 -4
  153. package/dist/scripts/ux-review-run-wires-imagegen-check.js +4 -0
  154. package/dist/scripts/zellij-slot-telemetry-runtime-check.js +1 -0
  155. package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
  156. package/docs/demo.tape +28 -0
  157. package/package.json +31 -24
  158. package/schemas/codex/completion-proof.schema.json +3 -2
  159. package/schemas/release/release-gate-node.schema.json +2 -1
  160. package/dist/scripts/agent-backfill-route-blackbox.js +0 -5
  161. package/dist/scripts/agent-dynamic-pool-route-blackbox.js +0 -5
  162. package/dist/scripts/agent-parallel-write-blackbox.js +0 -56
  163. package/dist/scripts/agent-patch-swarm-route-blackbox.js +0 -10
  164. package/dist/scripts/agent-route-blackbox-lib.js +0 -132
  165. package/dist/scripts/blackbox-command-import-smoke.js +0 -143
  166. package/dist/scripts/blackbox-global-shim.js +0 -77
  167. package/dist/scripts/blackbox-matrix.js +0 -70
  168. package/dist/scripts/blackbox-npx-one-shot.js +0 -69
  169. package/dist/scripts/blackbox-pack-install.js +0 -174
  170. package/dist/scripts/brand-neutrality-zero-leakage-blackbox.js +0 -4
  171. package/dist/scripts/build-once-runner-blackbox.js +0 -34
  172. package/dist/scripts/codex-0140-integration-blackbox.js +0 -13
  173. package/dist/scripts/codex-agent-type-blackbox.js +0 -4
  174. package/dist/scripts/codex-app-harness-blackbox.js +0 -4
  175. package/dist/scripts/codex-app-skill-agent-blackbox.js +0 -4
  176. package/dist/scripts/codex-hook-approval-blackbox.js +0 -4
  177. package/dist/scripts/codex-init-deep-directory-local-blackbox.js +0 -4
  178. package/dist/scripts/codex-native-feature-broker-blackbox.js +0 -4
  179. package/dist/scripts/codex-native-pattern-analysis-blackbox.js +0 -4
  180. package/dist/scripts/codex-native-read-repair-split-blackbox.js +0 -55
  181. package/dist/scripts/codex-native-reference-cache-blackbox.js +0 -41
  182. package/dist/scripts/core-skill-integrity-blackbox.js +0 -32
  183. package/dist/scripts/dfix-fast-blackbox-check.js +0 -37
  184. package/dist/scripts/dfix-parallel-write-blackbox.js +0 -48
  185. package/dist/scripts/dfix-patch-swarm-route-blackbox.js +0 -10
  186. package/dist/scripts/doctor-dirty-repair-blackbox.js +0 -22
  187. package/dist/scripts/doctor-dirty-semantic-blackbox.js +0 -8
  188. package/dist/scripts/doctor-native-capability-repair-blackbox.js +0 -39
  189. package/dist/scripts/doctor-transaction-engine-blackbox.js +0 -28
  190. package/dist/scripts/doctor-zellij-fix-blackbox.js +0 -4
  191. package/dist/scripts/doctor-zellij-no-homebrew-blackbox.js +0 -4
  192. package/dist/scripts/doctor-zellij-upgrade-blackbox.js +0 -4
  193. package/dist/scripts/gate-pack-runner-blackbox.js +0 -27
  194. package/dist/scripts/gate-pack-v2-blackbox.js +0 -18
  195. package/dist/scripts/geo-cli-blackbox-check.js +0 -18
  196. package/dist/scripts/loop-collision-blackbox.js +0 -3
  197. package/dist/scripts/loop-concurrency-oversubscription-blackbox.js +0 -3
  198. package/dist/scripts/loop-fixture-production-misuse-blackbox.js +0 -3
  199. package/dist/scripts/loop-kill-interrupt-real-blackbox.js +0 -3
  200. package/dist/scripts/loop-merge-strategy-blackbox.js +0 -3
  201. package/dist/scripts/loop-mesh-production-e2e-blackbox.js +0 -3
  202. package/dist/scripts/loop-side-effect-blackbox.js +0 -3
  203. package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +0 -29
  204. package/dist/scripts/mad-sks-actual-executor-blackbox.js +0 -5
  205. package/dist/scripts/mad-zellij-headless-fallback-blackbox.js +0 -4
  206. package/dist/scripts/mad-zellij-self-heal-blackbox.js +0 -4
  207. package/dist/scripts/naruto-loop-mesh-blackbox.js +0 -3
  208. package/dist/scripts/naruto-real-parallelism-blackbox.js +0 -307
  209. package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -29
  210. package/dist/scripts/parallel-runtime-real-blackbox.js +0 -44
  211. package/dist/scripts/pipeline-codex-native-doctor-mad-routing-real-blackbox.js +0 -77
  212. package/dist/scripts/pipeline-codex-native-e2e-blackbox.js +0 -13
  213. package/dist/scripts/pipeline-codex-native-image-routing-real-blackbox.js +0 -50
  214. package/dist/scripts/pipeline-codex-native-loop-routing-real-blackbox.js +0 -74
  215. package/dist/scripts/pipeline-codex-native-qa-routing-real-blackbox.js +0 -51
  216. package/dist/scripts/pipeline-codex-native-research-routing-real-blackbox.js +0 -45
  217. package/dist/scripts/pipeline-execution-profile-routing-blackbox.js +0 -4
  218. package/dist/scripts/postinstall-global-doctor-blackbox.js +0 -12
  219. package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -109
  220. package/dist/scripts/ppt-imagegen-blackbox-check.js +0 -46
  221. package/dist/scripts/qa-backfill-route-blackbox.js +0 -5
  222. package/dist/scripts/qa-patch-swarm-route-blackbox.js +0 -10
  223. package/dist/scripts/release-full-parallelism-blackbox.js +0 -41
  224. package/dist/scripts/release-triwiki-first-runner-blackbox.js +0 -48
  225. package/dist/scripts/release-wiring-3110-blackbox.js +0 -27
  226. package/dist/scripts/release-wiring-3112-blackbox.js +0 -17
  227. package/dist/scripts/release-wiring-3113-blackbox.js +0 -17
  228. package/dist/scripts/research-backfill-route-blackbox.js +0 -5
  229. package/dist/scripts/research-final-reviewer-blackbox.js +0 -70
  230. package/dist/scripts/research-stage-cycle-runtime-blackbox.js +0 -40
  231. package/dist/scripts/research-synthesis-writer-blackbox.js +0 -24
  232. package/dist/scripts/route-blackbox-realism-check.js +0 -21
  233. package/dist/scripts/scheduler-resource-claim-blackbox.js +0 -24
  234. package/dist/scripts/seo-cli-blackbox-check.js +0 -18
  235. package/dist/scripts/sks-3110-all-feature-regression-blackbox.js +0 -116
  236. package/dist/scripts/sks-3112-all-feature-regression-blackbox.js +0 -29
  237. package/dist/scripts/sks-3113-all-feature-regression-blackbox.js +0 -17
  238. package/dist/scripts/sks-400-all-feature-regression-blackbox.js +0 -21
  239. package/dist/scripts/sks-400-extreme-parallel-blackbox.js +0 -8
  240. package/dist/scripts/sks-400-five-minute-blackbox.js +0 -9
  241. package/dist/scripts/sks-400-legacy-purge-blackbox.js +0 -8
  242. package/dist/scripts/sks-401-all-feature-regression-blackbox.js +0 -46
  243. package/dist/scripts/sks-401-five-minute-actual-blackbox.js +0 -23
  244. package/dist/scripts/sks-402-all-feature-regression-blackbox.js +0 -9
  245. package/dist/scripts/sks-402-five-minute-real-blackbox.js +0 -22
  246. package/dist/scripts/sksd-warm-cache-blackbox.js +0 -12
  247. package/dist/scripts/team-backfill-route-blackbox.js +0 -5
  248. package/dist/scripts/team-parallel-write-blackbox.js +0 -55
  249. package/dist/scripts/team-patch-swarm-route-blackbox.js +0 -10
  250. package/dist/scripts/triwiki-affected-graph-blackbox.js +0 -28
  251. package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -30
  252. package/dist/scripts/triwiki-proof-bank-lock-blackbox.js +0 -7
  253. package/dist/scripts/ux-patch-swarm-route-blackbox.js +0 -10
  254. package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -67
  255. package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -28
  256. package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -80
  257. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -137
  258. package/dist/scripts/zellij-self-heal-typed-blackbox.js +0 -4
  259. package/dist/scripts/zellij-slot-telemetry-real-blackbox.js +0 -20
  260. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -81
  261. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -202
@@ -582,6 +582,7 @@ export function codexAppGuidance({ appInstalled, codex, mcpList, featureList, re
582
582
  }
583
583
  else if (appInstalled || codex?.bin) {
584
584
  lines.push('Codex image_generation was not visible from `codex features list`. Required imagegen/gpt-image-2 evidence must stay blocked or unverified until $imagegen is available in Codex App.');
585
+ lines.push('Run: sks doctor --fix to attempt Codex CLI/App image_generation repair, then rerun the blocked visual route.');
585
586
  }
586
587
  if (computerUseReady && !computerUseMcpListed) {
587
588
  lines.push('Computer Use plugin files are installed, but this check cannot prove the current thread exposes the live Computer Use tools. Start a new Codex App thread and invoke @Computer or @AppName only for native Mac/non-web target apps or screens; web/browser/webapp verification must use the Chrome Extension gate.');
@@ -1,8 +1,9 @@
1
1
  export function buildCodexSdkConfig(input) {
2
2
  const model = String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || 'gpt-5.5');
3
+ const serviceTier = String(input.serviceTier || process.env.SKS_SERVICE_TIER || 'fast');
3
4
  const config = {
4
5
  model,
5
- service_tier: 'fast',
6
+ service_tier: serviceTier === 'standard' ? 'standard' : 'fast',
6
7
  model_reasoning_effort: String(input.modelReasoningEffort || input.reasoningEffort || process.env.SKS_CODEX_REASONING || process.env.CODEX_MODEL_REASONING_EFFORT || 'medium'),
7
8
  mcp_servers: {},
8
9
  sks: {
@@ -30,7 +30,7 @@ export function buildCodexSdkEnv(input) {
30
30
  env.SKS_AGENT_SESSION_ID = input.sessionId;
31
31
  if (input.generationIndex !== undefined)
32
32
  env.SKS_AGENT_GENERATION_INDEX = String(input.generationIndex);
33
- env.SKS_SERVICE_TIER = 'fast';
33
+ env.SKS_SERVICE_TIER = String(input.serviceTier || 'fast');
34
34
  const isolatedRoot = path.resolve(input.mutationLedgerRoot, 'codex-sdk-home');
35
35
  env.HOME = path.join(isolatedRoot, 'home');
36
36
  env.CODEX_HOME = path.join(isolatedRoot, 'codex');
@@ -3,7 +3,7 @@ const patchOperationSchema = {
3
3
  type: 'object',
4
4
  required: ['op', 'path', 'search', 'replace', 'content', 'diff'],
5
5
  properties: {
6
- op: { type: 'string', enum: ['replace', 'write', 'unified_diff'] },
6
+ op: { type: 'string', enum: ['replace', 'write', 'unified_diff', 'git_apply_patch'] },
7
7
  path: { type: 'string' },
8
8
  search: { type: 'string' },
9
9
  replace: { type: 'string' },
@@ -38,7 +38,12 @@ const patchEnvelopeSchema = {
38
38
  lease_id: { type: 'string' },
39
39
  allowed_paths: { type: 'array', items: { type: 'string' } },
40
40
  operations: { type: 'array', items: patchOperationSchema },
41
- rationale: { type: 'string' }
41
+ rationale: { type: 'string' },
42
+ cochange_acknowledged: { type: 'boolean' },
43
+ cochange_acknowledged_reason: { type: 'string' },
44
+ regression_proof: { type: 'object', additionalProperties: true },
45
+ repair_hypothesis: { type: 'object', additionalProperties: true },
46
+ tournament: { type: 'object', additionalProperties: true }
42
47
  },
43
48
  additionalProperties: false
44
49
  };
@@ -70,7 +75,11 @@ export const codexAgentWorkerResultSchema = {
70
75
  additionalProperties: false
71
76
  },
72
77
  rollback_notes: { type: 'array', items: { type: 'string' } },
73
- blockers: { type: 'array', items: { type: 'string' } }
78
+ blockers: { type: 'array', items: { type: 'string' } },
79
+ work_item_kind: { type: 'string' },
80
+ regression_proof: { type: 'object', additionalProperties: true },
81
+ repair_hypothesis: { type: 'object', additionalProperties: true },
82
+ tournament: { type: 'object', additionalProperties: true }
74
83
  },
75
84
  additionalProperties: false
76
85
  };
@@ -3,6 +3,7 @@ import { ensureDir, nowIso, readText, writeTextAtomic } from '../fsx.js';
3
3
  import { CODEX_HOOK_EVENTS } from '../codex-compat/codex-hook-events.js';
4
4
  import { buildCodexCommandHookToml, matcherApplies } from './codex-hook-config-writer.js';
5
5
  import { readCodexHookActualState } from './codex-hook-actual-discovery.js';
6
+ import { writeTrustedHashStateForHooksFile } from './codex-hook-state-writer.js';
6
7
  const HOOK_SUBCOMMANDS = {
7
8
  SessionStart: 'session-start',
8
9
  UserPromptSubmit: 'user-prompt-submit',
@@ -39,6 +40,9 @@ export async function installManagedCodexHooks(root, opts = {}) {
39
40
  await writeTextAtomic(tomlPath, hooksToml);
40
41
  await writeTextAtomic(requirementsPath, requirementsToml);
41
42
  }
43
+ const trust = opts.dryRun === true
44
+ ? null
45
+ : await writeTrustedHashStateForHooksFile({ hooksFilePath: tomlPath, managed: true }, { allowSksHashFallback: true });
42
46
  const actual = opts.dryRun === true
43
47
  ? null
44
48
  : await readCodexHookActualState(root);
@@ -62,6 +66,7 @@ export async function installManagedCodexHooks(root, opts = {}) {
62
66
  dual_representation: actual.dual_representation.length,
63
67
  blockers: actual.blockers
64
68
  } : null,
69
+ trust,
65
70
  policy: {
66
71
  official_hash_available: false,
67
72
  trusted_hash_writer_policy: 'managed_install_required_when_official_hash_is_unavailable',
@@ -2,35 +2,94 @@ import path from 'node:path';
2
2
  import { readJson, readText, writeTextAtomic } from '../fsx.js';
3
3
  import { CODEX_HOOK_EVENTS } from '../codex-compat/codex-hook-events.js';
4
4
  import { codexCommandHookCurrentHash, codexHookStateKey } from './codex-hook-hash.js';
5
- export async function writeTrustedHashStateForHooksFile(root, hooksPath = path.join(root, '.codex', 'hooks.json'), statePath = path.join(root, '.codex', 'config.toml'), opts = {}) {
6
- if (opts.allowSksHashFallback !== true) {
5
+ import { entriesFromInlineHooksToml } from './codex-hook-actual-discovery.js';
6
+ export async function writeTrustedHashStateForHooksFile(input, hooksPathOrOpts, statePath, opts = {}) {
7
+ const resolved = resolveWriterInput(input, hooksPathOrOpts, statePath, opts);
8
+ const isSksManagedHook = resolved.managed === true || resolved.hooksPath.includes('sks-managed-hooks');
9
+ if (resolved.opts.allowSksHashFallback !== true && !isSksManagedHook) {
7
10
  return {
8
11
  schema: 'sks.codex-hook-state-writer.v2',
9
12
  ok: false,
10
- hooks_path: hooksPath,
11
- state_path: statePath,
13
+ hooks_path: resolved.hooksPath,
14
+ state_path: resolved.statePath,
12
15
  updated: 0,
13
16
  blocks: [],
14
17
  blocked: true,
15
18
  blocker: 'official_codex_hook_hash_unavailable',
16
19
  policy: 'use_sks_hooks_install_managed_instead_of_writing_sks_only_trusted_hashes',
17
20
  repair_action: 'sks hooks install --managed --json',
18
- reason: opts.reason || 'SKS refuses to write trusted_hash values from its own canonicalJson hash unless official Codex hash parity is proven.'
21
+ reason: resolved.opts.reason || 'SKS refuses to write trusted_hash values from its own canonicalJson hash unless official Codex hash parity is proven.'
19
22
  };
20
23
  }
21
- const hooksFile = await readJson(hooksPath, {});
22
- const blocks = trustedHashBlocksForHooksFile(hooksPath, hooksFile);
23
- const next = upsertTrustBlocks(await readText(statePath, ''), blocks);
24
- await writeTextAtomic(statePath, next);
24
+ const blocks = await trustedHashBlocksForHooksPath(resolved.hooksPath, isSksManagedHook);
25
+ const next = upsertTrustBlocks(await readText(resolved.statePath, ''), blocks);
26
+ await writeTextAtomic(resolved.statePath, next);
25
27
  return {
26
28
  schema: 'sks.codex-hook-state-writer.v1',
27
29
  ok: true,
28
- hooks_path: hooksPath,
29
- state_path: statePath,
30
+ hooks_path: resolved.hooksPath,
31
+ state_path: resolved.statePath,
30
32
  updated: blocks.length,
31
33
  blocks
32
34
  };
33
35
  }
36
+ function resolveWriterInput(input, hooksPathOrOpts, statePath, opts) {
37
+ if (typeof input === 'string') {
38
+ const root = path.resolve(input);
39
+ const resolvedOpts = typeof hooksPathOrOpts === 'object' && hooksPathOrOpts !== null
40
+ ? hooksPathOrOpts
41
+ : opts;
42
+ const hooksPath = typeof hooksPathOrOpts === 'string'
43
+ ? hooksPathOrOpts
44
+ : path.join(root, '.codex', 'hooks.json');
45
+ return {
46
+ root,
47
+ hooksPath: path.resolve(hooksPath),
48
+ statePath: path.resolve(statePath || path.join(root, '.codex', 'config.toml')),
49
+ managed: resolvedOpts.managed === true,
50
+ opts: resolvedOpts
51
+ };
52
+ }
53
+ const hooksPath = path.resolve(input.hooksFilePath || input.hooksPath || path.join(input.root || process.cwd(), '.codex', 'hooks.json'));
54
+ const root = path.resolve(input.root || rootFromHooksPath(hooksPath));
55
+ const resolvedOpts = typeof hooksPathOrOpts === 'object' && hooksPathOrOpts !== null
56
+ ? hooksPathOrOpts
57
+ : opts;
58
+ return {
59
+ root,
60
+ hooksPath,
61
+ statePath: path.resolve(input.statePath || statePathForHooksPath(root, hooksPath)),
62
+ managed: input.managed === true || resolvedOpts.managed === true,
63
+ opts: resolvedOpts
64
+ };
65
+ }
66
+ function rootFromHooksPath(hooksPath) {
67
+ const dir = path.dirname(hooksPath);
68
+ if (path.basename(dir) === '.codex')
69
+ return path.dirname(dir);
70
+ if (path.basename(dir) === 'managed-hooks')
71
+ return path.dirname(path.dirname(dir));
72
+ return process.cwd();
73
+ }
74
+ function statePathForHooksPath(root, hooksPath) {
75
+ const dir = path.dirname(hooksPath);
76
+ if (path.basename(dir) === '.codex' || path.basename(dir) === 'managed-hooks') {
77
+ return path.join(path.basename(dir) === '.codex' ? dir : path.dirname(dir), 'config.toml');
78
+ }
79
+ return path.join(root, '.codex', 'config.toml');
80
+ }
81
+ async function trustedHashBlocksForHooksPath(hooksPath, managed) {
82
+ if (/\.toml$/i.test(hooksPath)) {
83
+ const parsed = entriesFromInlineHooksToml(hooksPath, 'project', await readText(hooksPath, ''), {}, managed, managed ? 'managed_dir_toml' : 'config_toml');
84
+ return parsed.entries.map((entry) => ({
85
+ key: entry.key,
86
+ trusted_hash: entry.current_hash,
87
+ block: `[hooks.state."${tomlQuotedKey(entry.key)}"]\ntrusted_hash = "${entry.current_hash}"`
88
+ }));
89
+ }
90
+ const hooksFile = await readJson(hooksPath, {});
91
+ return trustedHashBlocksForHooksFile(hooksPath, hooksFile);
92
+ }
34
93
  export function trustedHashBlocksForHooksFile(hooksPath, hooksFile) {
35
94
  const blocks = [];
36
95
  const hooksRoot = hooksFile?.hooks && typeof hooksFile.hooks === 'object' && !Array.isArray(hooksFile.hooks) ? hooksFile.hooks : {};
@@ -8,7 +8,7 @@ export async function codexHookTrustDoctor(root, opts = {}) {
8
8
  const fix = opts.fix === true;
9
9
  const trustOpts = opts.managed === undefined ? {} : { managed: opts.managed };
10
10
  const before = await readCodexHookTrustEntries(root, trustOpts);
11
- const fixed = fix ? await writeTrustedHashStateForHooksFile(root, undefined, undefined, { allowSksHashFallback: false }).catch((err) => ({
11
+ const fixed = fix ? await writeTrustedHashStateForHooksFile({ root, managed: opts.managed === true }, { allowSksHashFallback: opts.managed === true }).catch((err) => ({
12
12
  ok: false,
13
13
  error: err instanceof Error ? err.message : String(err)
14
14
  })) : null;
@@ -74,7 +74,7 @@ async function codexHookActualTrustDoctor(root, opts = {}) {
74
74
  policy: {
75
75
  official_hash_available: false,
76
76
  trusted_hash_writer_policy: 'managed_install_required_when_official_hash_is_unavailable',
77
- sks_hash_fallback_allowed: false
77
+ sks_hash_fallback_allowed: opts.managed === true
78
78
  }
79
79
  };
80
80
  }
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import os from 'node:os';
3
- import { exists, readText, runProcess, which } from '../fsx.js';
3
+ import { exists, readJson, readText, runProcess, which } from '../fsx.js';
4
4
  export function codexLbEnvPath(home = process.env.HOME || os.homedir()) {
5
5
  return path.join(String(home || os.homedir()), '.codex', 'sks-codex-lb.env');
6
6
  }
@@ -10,6 +10,25 @@ export function legacyCodexLbEnvPath(home = process.env.HOME || os.homedir()) {
10
10
  export function codexLbMetadataPath(home = process.env.HOME || os.homedir()) {
11
11
  return path.join(String(home || os.homedir()), '.codex', 'sks-codex-lb.json');
12
12
  }
13
+ export function codexLbHealthPath(home = process.env.HOME || os.homedir()) {
14
+ return path.join(String(home || os.homedir()), '.codex', 'sks-codex-lb-health.json');
15
+ }
16
+ export async function readLbHealth(home = process.env.HOME || os.homedir()) {
17
+ const file = codexLbHealthPath(home);
18
+ const raw = await readJson(file, null);
19
+ if (!raw || typeof raw !== 'object')
20
+ return null;
21
+ const degraded = Array.isArray(raw.degraded_models)
22
+ ? raw.degraded_models.map((model) => String(model)).filter(Boolean)
23
+ : [];
24
+ return {
25
+ ok: raw.ok !== false,
26
+ degraded_models: degraded,
27
+ quota_low: raw.quota_low === true,
28
+ source: file,
29
+ updated_at: typeof raw.updated_at === 'string' ? raw.updated_at : null
30
+ };
31
+ }
13
32
  export function normalizeCodexLbBaseUrl(input = '') {
14
33
  let host = String(input || '').trim();
15
34
  if (!host)
@@ -3,6 +3,7 @@ import { spawnSync } from 'node:child_process';
3
3
  import { COMMANDS, LEGACY_COMMAND_ALIASES } from '../../cli/command-registry.js';
4
4
  import { flag } from '../../cli/args.js';
5
5
  import { printJson, sksTextLogo } from '../../cli/output.js';
6
+ import { ui as cliUi } from '../../cli/cli-theme.js';
6
7
  import { PACKAGE_VERSION, ensureDir, exists, nowIso, projectRoot, readJson, sksRoot, tmpdir, writeJsonAtomic } from '../fsx.js';
7
8
  import { COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, USAGE_TOPICS, routePrompt, routeReasoning, reasoningInstruction } from '../routes.js';
8
9
  import { initProject, normalizeInstallScope, sksCommandPrefix } from '../init.js';
@@ -111,6 +112,8 @@ export async function updateCheckCommand(args = []) {
111
112
  const result = await runSksUpdateCheck();
112
113
  if (flag(args, '--json'))
113
114
  return printJson(result);
115
+ cliUi.banner('update');
116
+ result.update_available ? cliUi.warn('update available') : cliUi.ok('already current or no update required');
114
117
  console.log(`${sksTextLogo()}\n\n${formatSksUpdateCheckText(result)}`);
115
118
  }
116
119
  export async function updateCommand(sub = 'now', args = []) {
@@ -132,11 +135,15 @@ export async function updateCommand(sub = 'now', args = []) {
132
135
  version: valueAfter(effectiveArgs, '--version') || valueAfter(effectiveArgs, '-v'),
133
136
  dryRun: flag(effectiveArgs, '--dry-run'),
134
137
  projectRoot: root,
138
+ json: flag(effectiveArgs, '--json'),
139
+ quiet: flag(effectiveArgs, '--quiet'),
135
140
  timeoutMs: 10 * 60 * 1000,
136
141
  maxOutputBytes: 128 * 1024
137
142
  }));
138
143
  if (flag(effectiveArgs, '--json'))
139
144
  return printJson(result);
145
+ cliUi.banner('update');
146
+ result.ok ? cliUi.ok(result.status) : result.status === 'updated_with_issues' ? cliUi.warn(result.status) : cliUi.fail(result.status || 'failed');
140
147
  console.log(`${sksTextLogo()}\n`);
141
148
  console.log(`SKS update ${result.status}`);
142
149
  if (result.command)
@@ -153,6 +160,16 @@ export async function updateCommand(sub = 'now', args = []) {
153
160
  console.log(`SKS menu bar: ${result.sks_menubar.status}${result.sks_menubar.app_path ? ` (${result.sks_menubar.app_path})` : ''}`);
154
161
  for (const stage of result.stages || [])
155
162
  console.log(`Stage ${stage.id}: ${stage.ok ? 'ok' : 'failed'} ${stage.status}`);
163
+ if (result.verification?.length) {
164
+ console.log('Self verification:');
165
+ cliUi.table([
166
+ ['check', 'status', 'detail'],
167
+ ...result.verification.map((item) => [item.id, item.ok ? 'ok' : 'failed', item.detail || ''])
168
+ ]);
169
+ const remediation = [...new Set(result.verification.filter((item) => !item.ok).map((item) => item.remediation).filter((value) => Boolean(value)))];
170
+ for (const action of remediation)
171
+ console.log(`Remediation: ${action}`);
172
+ }
156
173
  if (result.error)
157
174
  console.log(`Error: ${result.error}`);
158
175
  if (!result.ok)
@@ -264,7 +281,7 @@ export async function postinstallCommand(args = []) {
264
281
  export async function selftestCommand(args = []) {
265
282
  process.env.CI = 'true';
266
283
  const root = await projectRoot();
267
- const tmp = tmpdir();
284
+ const tmp = tmpdir('sks-selftest-');
268
285
  await ensureDir(tmp);
269
286
  const registry = await buildFeatureRegistry({ root });
270
287
  const coverage = validateFeatureRegistry(registry);
@@ -4,6 +4,7 @@ import { spawnSync } from 'node:child_process';
4
4
  import { flag } from '../../cli/args.js';
5
5
  import { printJson } from '../../cli/output.js';
6
6
  import { projectRoot } from '../fsx.js';
7
+ import { evaluateGateProcessOutput } from './gate-result-contract.js';
7
8
  const CHECK_SCHEMA = 'sks.check.v1';
8
9
  export async function checkCommand(args = []) {
9
10
  const root = await projectRoot();
@@ -31,10 +32,41 @@ export async function checkCommand(args = []) {
31
32
  shell: false,
32
33
  env: { ...process.env, CI: process.env.CI || 'true' }
33
34
  });
34
- const ok = result.status === 0;
35
- if (step.name === 'proof-bank-summary')
36
- proofBankSummary = parseJsonObject(String(result.stdout || ''));
37
- steps.push({ name: step.name, ok, status: result.status, stderr_tail: tail(String(result.stderr || '')) });
35
+ const stdout = String(result.stdout || '');
36
+ let ok = result.status === 0;
37
+ let reason;
38
+ let contract;
39
+ let gateResult = null;
40
+ if (step.name === 'proof-bank-summary') {
41
+ proofBankSummary = parseJsonObject(stdout);
42
+ if (!proofBankSummary) {
43
+ ok = false;
44
+ reason = 'invalid_json_output';
45
+ }
46
+ }
47
+ if (step.output_contract === 'sks.gate-result.v1') {
48
+ const gateEval = evaluateGateProcessOutput({ status: result.status, stdout, requiresContract: true });
49
+ ok = gateEval.ok;
50
+ reason = gateEval.reason;
51
+ contract = gateEval.contract;
52
+ gateResult = gateEval.gate_result;
53
+ }
54
+ else if (step.name.startsWith('release:')) {
55
+ const gateEval = evaluateGateProcessOutput({ status: result.status, stdout });
56
+ ok = gateEval.ok;
57
+ reason = gateEval.reason;
58
+ contract = gateEval.contract;
59
+ gateResult = gateEval.gate_result;
60
+ }
61
+ steps.push({
62
+ name: step.name,
63
+ ok,
64
+ status: result.status,
65
+ stderr_tail: tail(String(result.stderr || '')),
66
+ ...(reason ? { reason } : {}),
67
+ ...(contract ? { contract } : {}),
68
+ ...(gateResult ? { gate_result: gateResult } : {})
69
+ });
38
70
  if (!json) {
39
71
  if (result.stdout)
40
72
  process.stdout.write(result.stdout);
@@ -69,7 +101,7 @@ function buildCheckPlan(input) {
69
101
  }
70
102
  else {
71
103
  steps.push({ name: buildScript, command: 'npm', args: ['run', buildScript, '--silent'] });
72
- steps.push({ name: `release:${tier}`, command: process.execPath, args: dagArgs(tier, input.changedSince, input.sla) });
104
+ steps.push({ name: `release:${tier}`, command: process.execPath, args: dagArgs(tier, input.changedSince, input.sla), output_contract: 'sks.gate-result.v1' });
73
105
  }
74
106
  return {
75
107
  tier,
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
- import { nowIso, projectRoot, writeJsonAtomic } from '../fsx.js';
2
+ import fsp from 'node:fs/promises';
3
+ import { nowIso, projectRoot, readJson, writeJsonAtomic } from '../fsx.js';
3
4
  import { createMission, findLatestMission } from '../mission.js';
4
5
  import { flag, readOption } from '../../cli/args.js';
5
6
  import { printJson } from '../../cli/output.js';
@@ -130,17 +131,23 @@ export async function computerUseCommand(command, args = []) {
130
131
  return;
131
132
  }
132
133
  const route = command === 'cu' ? '$CU' : '$Computer-Use';
134
+ const gate = await evaluateComputerUseGate(root, missionId);
135
+ await writeJsonAtomic(path.join(root, '.sneakoscope', 'missions', missionId, 'computer-use-gate.json'), gate);
133
136
  const proof = await maybeFinalizeRoute(root, {
134
137
  missionId,
135
138
  route,
139
+ gateFile: 'computer-use-gate.json',
140
+ gate,
136
141
  mock: flag(args, '--mock'),
137
142
  visual: true,
138
143
  requireRelation: flag(args, '--fix-claim') || flag(args, '--require-relation'),
139
144
  artifacts: ['computer-use-evidence-ledger.json', 'screen-capture-ledger.json', 'image-voxel-ledger.json', 'visual-anchors.json'],
140
145
  claims: [{ id: 'computer-use-evidence', status: flag(args, '--mock') ? 'verified_partial' : 'supported' }],
141
- command: { cmd: `sks ${command} ${args.join(' ')}`.trim(), status: 0 }
146
+ blockers: gate.blockers || [],
147
+ statusHint: gate.passed ? undefined : 'blocked',
148
+ command: { cmd: `sks ${command} ${args.join(' ')}`.trim(), status: gate.passed ? 0 : 1 }
142
149
  });
143
- const result = { schema: 'sks.computer-use-evidence.v1', ok: proof.ok, mission_id: missionId, route, proof: proof.validation };
150
+ const result = { schema: 'sks.computer-use-evidence.v1', ok: proof.ok && gate.passed === true, mission_id: missionId, route, gate, proof: proof.validation };
144
151
  if (flag(args, '--json'))
145
152
  return printJson(result);
146
153
  console.log(`Computer Use evidence: ${proof.ok ? 'ok' : 'blocked'} ${missionId}`);
@@ -170,7 +177,18 @@ async function importFixture(root, command, args) {
170
177
  };
171
178
  await writeJsonAtomic(path.join(dir, 'computer-use-evidence-ledger.json'), evidence);
172
179
  await writeJsonAtomic(path.join(dir, 'screen-capture-ledger.json'), captures);
173
- const gate = { schema_version: 1, passed: true, ok: true, computer_use_evidence: true, screen_capture_evidence: true, mock: true };
180
+ const gate = {
181
+ schema: 'sks.computer-use-gate.v1',
182
+ schema_version: 1,
183
+ passed: false,
184
+ ok: false,
185
+ status: 'blocked',
186
+ execution_class: 'mock_fixture',
187
+ computer_use_evidence: false,
188
+ screen_capture_evidence: false,
189
+ mock: true,
190
+ blockers: ['computer_use_fixture_mode_cannot_claim_real']
191
+ };
174
192
  await writeJsonAtomic(path.join(dir, 'computer-use-gate.json'), gate);
175
193
  const proof = await maybeFinalizeRoute(root, {
176
194
  missionId: id,
@@ -182,11 +200,48 @@ async function importFixture(root, command, args) {
182
200
  requireRelation: flag(args, '--fix-claim') || flag(args, '--require-relation'),
183
201
  artifacts: ['computer-use-evidence-ledger.json', 'screen-capture-ledger.json', 'image-voxel-ledger.json', 'visual-anchors.json', 'completion-proof.json'],
184
202
  claims: [{ id: 'computer-use-import-fixture', status: 'verified_partial' }],
185
- command: { cmd: `sks ${command} import-fixture --mock`, status: 0 }
203
+ statusHint: 'blocked',
204
+ blockers: gate.blockers,
205
+ command: { cmd: `sks ${command} import-fixture --mock`, status: 1 }
186
206
  });
187
- const result = { schema: 'sks.computer-use-import-fixture.v1', ok: proof.ok, mission_id: id, route, proof: proof.validation };
207
+ const result = { schema: 'sks.computer-use-import-fixture.v1', ok: false, mission_id: id, route, gate, proof: proof.validation };
208
+ process.exitCode = 1;
188
209
  if (flag(args, '--json'))
189
210
  return printJson(result);
190
- console.log(`Computer Use fixture imported: ${proof.ok ? 'ok' : 'blocked'} ${id}`);
211
+ console.log(`Computer Use fixture imported: blocked ${id}`);
212
+ }
213
+ async function evaluateComputerUseGate(root, missionId) {
214
+ const dir = path.join(root, '.sneakoscope', 'missions', missionId);
215
+ const evidence = await readJson(path.join(dir, 'computer-use-evidence-ledger.json'), null);
216
+ const captures = await readJson(path.join(dir, 'screen-capture-ledger.json'), null);
217
+ const blockers = new Set();
218
+ const actions = Array.isArray(evidence?.actions) ? evidence.actions : [];
219
+ const captureRows = Array.isArray(captures?.captures) ? captures.captures : [];
220
+ if (!actions.length)
221
+ blockers.add('computer_use_actions_missing');
222
+ if (actions.some((action) => action?.status === 'mocked' || action?.mock === true) || evidence?.mock === true)
223
+ blockers.add('computer_use_mock_actions_not_evidence');
224
+ if (!captureRows.length)
225
+ blockers.add('screen_capture_evidence_missing');
226
+ for (const capture of captureRows) {
227
+ const rel = String(capture?.path || '');
228
+ const abs = path.isAbsolute(rel) ? rel : path.join(root, rel);
229
+ const stat = await fsp.stat(abs).catch(() => null);
230
+ if (!stat || stat.size < 256)
231
+ blockers.add(`screen_capture_file_missing_or_too_small:${capture?.id || rel || 'unknown'}`);
232
+ if (capture?.status === 'mocked' || capture?.mock === true || captures?.mock === true)
233
+ blockers.add('screen_capture_mock_not_evidence');
234
+ }
235
+ const passed = blockers.size === 0;
236
+ return {
237
+ schema: 'sks.computer-use-gate.v1',
238
+ schema_version: 1,
239
+ passed,
240
+ ok: passed,
241
+ status: passed ? 'pass' : 'blocked',
242
+ computer_use_evidence: actions.length > 0 && ![...blockers].includes('computer_use_mock_actions_not_evidence'),
243
+ screen_capture_evidence: captureRows.length > 0 && ![...blockers].some((blocker) => blocker.startsWith('screen_capture_')),
244
+ blockers: [...blockers]
245
+ };
191
246
  }
192
247
  //# sourceMappingURL=computer-use-command.js.map
@@ -6,6 +6,7 @@ import { maybeFinalizeRoute } from '../proof/auto-finalize.js';
6
6
  import { recordDbSafetyMismatchWrongness } from '../triwiki-wrongness/wrongness-ledger.js';
7
7
  import { flag, readOption } from './command-utils.js';
8
8
  import { writeRouteCollaborationArtifacts } from '../agents/route-collaboration-ledger.js';
9
+ import { context7EvidenceStatus } from './route-success-helpers.js';
9
10
  export async function dbCommand(sub, args = []) {
10
11
  const root = await sksRoot();
11
12
  if (sub === 'policy') {
@@ -79,7 +80,9 @@ async function recordDbExpectation(root, input = {}) {
79
80
  async function finalizeDbCheck(root, { action, args, result, exitCode }) {
80
81
  const prompt = `sks db ${action} ${args.join(' ')}`.trim();
81
82
  const { id, dir } = await createMission(root, { mode: 'db', prompt });
82
- const blocked = exitCode !== 0 || result.action === 'block' || result.level === 'destructive';
83
+ const context7 = await context7EvidenceStatus(root, id);
84
+ const destructiveOperationZero = result.level !== 'destructive';
85
+ const blocked = exitCode !== 0 || result.action === 'block' || result.level === 'destructive' || !context7.ok;
83
86
  const report = {
84
87
  schema: 'sks.db-operation-report.v1',
85
88
  mission_id: id,
@@ -91,11 +94,34 @@ async function finalizeDbCheck(root, { action, args, result, exitCode }) {
91
94
  ok: !blocked,
92
95
  level: result.level || result.risk || result.status || null,
93
96
  action: result.action || action,
94
- destructive_blocked: blocked && /drop|delete|truncate|reset|destructive/i.test(JSON.stringify(result))
95
- }
97
+ destructive_operation_zero: destructiveOperationZero,
98
+ destructive_blocked: !destructiveOperationZero || (blocked && /drop|delete|truncate|reset|destructive/i.test(JSON.stringify(result))),
99
+ context7_policy: context7.policy,
100
+ context7_evidence: context7.evidence
101
+ },
102
+ blockers: [
103
+ ...(!destructiveOperationZero ? ['destructive_operation_found'] : []),
104
+ ...(context7.ok ? [] : [context7.blocker])
105
+ ]
96
106
  };
97
107
  await writeJsonAtomic(path.join(dir, 'db-operation-report.json'), report);
98
- const gate = { schema_version: 1, passed: !blocked, ok: !blocked, status: blocked ? 'blocked' : 'pass', db_operation_report: 'db-operation-report.json' };
108
+ const gateBlockers = [
109
+ ...(blocked && destructiveOperationZero ? ['db_operation_blocked'] : []),
110
+ ...(!destructiveOperationZero ? ['destructive_operation_found'] : []),
111
+ ...(context7.ok ? [] : [context7.blocker])
112
+ ];
113
+ const gate = {
114
+ schema: 'sks.db-gate.v1',
115
+ schema_version: 1,
116
+ passed: !blocked,
117
+ ok: !blocked,
118
+ status: blocked ? 'blocked' : 'pass',
119
+ db_operation_report: 'db-operation-report.json',
120
+ destructive_operation_zero: destructiveOperationZero,
121
+ context7_policy: context7.policy,
122
+ context7_evidence: context7.evidence,
123
+ blockers: [...new Set(gateBlockers)]
124
+ };
99
125
  await writeJsonAtomic(path.join(dir, 'db-gate.json'), gate);
100
126
  const native = await writeRouteCollaborationArtifacts(root, {
101
127
  missionId: id,
@@ -112,7 +138,7 @@ async function finalizeDbCheck(root, { action, args, result, exitCode }) {
112
138
  artifacts: ['db-operation-report.json', 'completion-proof.json', ...Object.values(native.artifacts || {})],
113
139
  dbEvidence: report.db_safety,
114
140
  statusHint: blocked ? 'blocked' : 'verified_partial',
115
- blockers: blocked ? ['db_operation_blocked'] : [],
141
+ blockers: gate.blockers,
116
142
  command: { cmd: prompt, status: exitCode }
117
143
  });
118
144
  return { ...completion, native_agent_collaboration: native };
@@ -1,6 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { flag } from '../../cli/args.js';
3
3
  import { printJson } from '../../cli/output.js';
4
+ import { ui as cliUi } from '../../cli/cli-theme.js';
4
5
  import { projectRoot, readText } from '../fsx.js';
5
6
  import { clearFastModePreference, fastModePreferencePath, readFastModePreference, resolveFastModePolicy, writeFastModePreference } from '../agents/fast-mode-policy.js';
6
7
  import { codexFastModeDesktopStatus, codexLbConfigPath, ensureGlobalCodexFastModeDuringInstall } from '../../cli/install-helpers.js';
@@ -76,6 +77,8 @@ export async function fastModeCommand(args = []) {
76
77
  };
77
78
  if (flag(args, '--json'))
78
79
  return printJson(result);
80
+ cliUi.banner('fast-mode');
81
+ cliUi.ok(`project workers ${result.fast_mode ? 'fast' : 'standard'}`);
79
82
  console.log('SKS Fast Mode');
80
83
  console.log(`Root: ${root}`);
81
84
  console.log(`Global (desktop): ${globalStatus.on ? 'on' : 'off'} (default_profile=${globalStatus.default_profile || 'none'}, top-level ${globalStatus.top_level_default_profile ? 'OK' : 'none'})`);
@@ -0,0 +1,43 @@
1
+ export const GATE_RESULT_CONTRACT = 'sks.gate-result.v1';
2
+ export function parseGateResultFromStdout(stdout) {
3
+ const lines = String(stdout || '').trim().split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
4
+ const last = lines.at(-1);
5
+ if (!last)
6
+ return null;
7
+ try {
8
+ const parsed = JSON.parse(last);
9
+ if (parsed?.schema === GATE_RESULT_CONTRACT && typeof parsed.ok === 'boolean' && Array.isArray(parsed.blockers)) {
10
+ return parsed;
11
+ }
12
+ return null;
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ export function evaluateGateProcessOutput({ status, stdout, requiresContract = false }) {
19
+ const gateResult = parseGateResultFromStdout(stdout);
20
+ if (!gateResult) {
21
+ if (requiresContract) {
22
+ return {
23
+ ok: false,
24
+ contract: GATE_RESULT_CONTRACT,
25
+ gate_result: null,
26
+ reason: 'gate_output_contract_violation'
27
+ };
28
+ }
29
+ return {
30
+ ok: status === 0,
31
+ contract: 'legacy_exit_code_only',
32
+ gate_result: null,
33
+ ...(status === 0 ? { reason: 'legacy_exit_code_only' } : {})
34
+ };
35
+ }
36
+ return {
37
+ ok: status === 0 && gateResult.ok === true,
38
+ contract: GATE_RESULT_CONTRACT,
39
+ gate_result: gateResult,
40
+ ...(gateResult.ok === true ? {} : { reason: 'gate_result_not_ok' })
41
+ };
42
+ }
43
+ //# sourceMappingURL=gate-result-contract.js.map
@@ -2,6 +2,7 @@ import { spawnSync } from 'node:child_process';
2
2
  import { flag } from '../../cli/args.js';
3
3
  import { printJson } from '../../cli/output.js';
4
4
  import { projectRoot } from '../fsx.js';
5
+ import { evaluateGateProcessOutput } from './gate-result-contract.js';
5
6
  export async function gatesCommand(args = []) {
6
7
  const root = await projectRoot();
7
8
  const sub = args[0] && !args[0].startsWith('-') ? args[0] : 'run';
@@ -29,12 +30,16 @@ export async function gatesCommand(args = []) {
29
30
  maxBuffer: 1024 * 1024 * 20,
30
31
  env: { ...process.env, CI: process.env.CI || 'true' }
31
32
  });
33
+ const gateEval = evaluateGateProcessOutput({ status: result.status, stdout: String(result.stdout || '') });
32
34
  const report = {
33
35
  schema: 'sks.gates-command.v1',
34
- ok: result.status === 0,
36
+ ok: gateEval.ok,
35
37
  target,
36
38
  mode: isPreset ? 'preset' : 'gate',
37
39
  status: result.status,
40
+ contract: gateEval.contract,
41
+ gate_result: gateEval.gate_result,
42
+ ...(gateEval.reason ? { reason: gateEval.reason } : {}),
38
43
  stdout_tail: tail(String(result.stdout || '')),
39
44
  stderr_tail: tail(String(result.stderr || ''))
40
45
  };