sneakoscope 6.0.2 → 6.1.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 (242) hide show
  1. package/README.md +5 -3
  2. package/config/codex-releases/{rust-v0.142.0.json → rust-v0.144.1.json} +6 -6
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/cli/install-helpers.js +255 -440
  6. package/dist/cli/router.js +53 -4
  7. package/dist/commands/codex-app.js +8 -3
  8. package/dist/commands/codex-lb.js +169 -40
  9. package/dist/commands/codex.js +6 -5
  10. package/dist/commands/doctor.js +60 -26
  11. package/dist/commands/versioning.js +7 -0
  12. package/dist/config/skills-manifest.json +57 -57
  13. package/dist/core/agents/agent-central-ledger.js +9 -0
  14. package/dist/core/agents/agent-cleanup-executor.js +334 -41
  15. package/dist/core/agents/agent-cleanup.js +20 -1
  16. package/dist/core/agents/agent-command-surface.js +2 -1
  17. package/dist/core/agents/agent-effort-policy.js +46 -33
  18. package/dist/core/agents/agent-janitor.js +9 -10
  19. package/dist/core/agents/agent-namespace-safety.js +56 -0
  20. package/dist/core/agents/agent-orchestrator.js +26 -4
  21. package/dist/core/agents/agent-output-validator.js +1 -1
  22. package/dist/core/agents/agent-proof-evidence.js +16 -2
  23. package/dist/core/agents/agent-role-config.js +3 -6
  24. package/dist/core/agents/agent-roster.js +2 -2
  25. package/dist/core/agents/agent-runner-codex-exec.js +2 -0
  26. package/dist/core/agents/agent-runner-process.js +1 -0
  27. package/dist/core/agents/fast-mode-policy.js +3 -5
  28. package/dist/core/agents/native-cli-session-swarm.js +18 -1
  29. package/dist/core/agents/native-worker-backend-router.js +180 -108
  30. package/dist/core/agents/parallel-write-fixture.js +15 -10
  31. package/dist/core/agents/runtime-proof-summary.js +21 -3
  32. package/dist/core/agents/work-partition/repo-inventory.js +68 -7
  33. package/dist/core/code-structure.js +5 -4
  34. package/dist/core/codex/codex-config-guard.js +31 -9
  35. package/dist/core/codex-app/codex-app-fast-ui-repair.js +51 -20
  36. package/dist/core/codex-app/codex-app-restart.js +38 -8
  37. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +11 -3
  38. package/dist/core/codex-app/sks-menubar.js +100 -40
  39. package/dist/core/codex-app.js +60 -17
  40. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -1
  41. package/dist/core/codex-compat/codex-release-manifest.js +6 -6
  42. package/dist/core/codex-control/codex-0139-doctor-real-probe.js +7 -1
  43. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +14 -8
  44. package/dist/core/codex-control/codex-0139-probe-runner.js +103 -28
  45. package/dist/core/codex-control/codex-0139-real-probe-summary.js +7 -3
  46. package/dist/core/codex-control/codex-0139-real-probes.js +21 -6
  47. package/dist/core/codex-control/codex-0139-sandbox-real-probe.js +39 -13
  48. package/dist/core/codex-control/codex-0139-web-search-probe.js +11 -8
  49. package/dist/core/codex-control/{codex-0142-capability.js → codex-0144-capability.js} +22 -22
  50. package/dist/core/codex-control/codex-0144-collab-agent-real-probe.js +63 -0
  51. package/dist/core/codex-control/codex-model-metadata.js +8 -4
  52. package/dist/core/codex-control/codex-multi-agent-event-normalizer.js +5 -1
  53. package/dist/core/codex-control/codex-reliability-shield.js +4 -1
  54. package/dist/core/codex-control/codex-sdk-adapter.js +53 -6
  55. package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
  56. package/dist/core/codex-control/codex-sdk-sandbox-policy.js +6 -3
  57. package/dist/core/codex-lb/codex-lb-env.js +107 -0
  58. package/dist/core/codex-lb/codex-lb-tool-catalog.js +478 -0
  59. package/dist/core/codex-native/codex-native-feature-broker.js +22 -22
  60. package/dist/core/codex-native/codex-native-feature-matrix.js +2 -2
  61. package/dist/core/codex-native/native-capability-postcheck.js +16 -8
  62. package/dist/core/codex-native/native-capability-repair-matrix.js +76 -27
  63. package/dist/core/codex-plugins/codex-plugin-json.js +67 -21
  64. package/dist/core/codex-plugins/codex-plugin-repair.js +118 -0
  65. package/dist/core/codex-runtime/codex-desktop-config-policy.js +306 -0
  66. package/dist/core/commands/agent-command.js +19 -0
  67. package/dist/core/commands/basic-cli.js +45 -24
  68. package/dist/core/commands/gc-command.js +27 -4
  69. package/dist/core/commands/image-ux-review-command.js +55 -24
  70. package/dist/core/commands/mad-sks-command.js +152 -132
  71. package/dist/core/commands/naruto-command.js +41 -10
  72. package/dist/core/commands/pipeline-command.js +1 -0
  73. package/dist/core/commands/wiki-command.js +179 -83
  74. package/dist/core/computer-use-live-evidence.js +166 -3
  75. package/dist/core/computer-use-status.js +5 -2
  76. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +2 -2
  77. package/dist/core/daemon/sksd-hook-daemon.js +171 -28
  78. package/dist/core/daemon/sksd-hook-dispatch.js +2 -2
  79. package/dist/core/dfix/verification-selector.js +6 -4
  80. package/dist/core/doctor/browser-use-repair.js +54 -13
  81. package/dist/core/doctor/codex-0139-doctor.js +3 -2
  82. package/dist/core/doctor/computer-use-repair.js +28 -39
  83. package/dist/core/doctor/doctor-codex-startup-repair.js +19 -9
  84. package/dist/core/doctor/doctor-context7-repair.js +1 -1
  85. package/dist/core/doctor/doctor-dirty-planner.js +1 -1
  86. package/dist/core/doctor/doctor-native-capability-repair.js +74 -3
  87. package/dist/core/doctor/imagegen-repair.js +47 -12
  88. package/dist/core/doctor/legacy-global-hook-cleanup.js +179 -0
  89. package/dist/core/feature-registry.js +25 -31
  90. package/dist/core/fsx.js +54 -6
  91. package/dist/core/harness-conflicts.js +1 -1
  92. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +5 -4
  93. package/dist/core/hooks-runtime/hook-invocation-dedupe.js +147 -0
  94. package/dist/core/hooks-runtime/hook-io.js +6 -0
  95. package/dist/core/hooks-runtime.js +17 -2
  96. package/dist/core/image/image-artifact-path-contract.js +8 -6
  97. package/dist/core/image/image-artifact-registry.js +5 -1
  98. package/dist/core/image-ux-review/imagegen-adapter.js +5 -2
  99. package/dist/core/imagegen/imagegen-capability.js +10 -13
  100. package/dist/core/imagegen/require-imagegen.js +37 -11
  101. package/dist/core/managed-assets/managed-assets-manifest.js +1 -5
  102. package/dist/core/naruto/naruto-work-graph.js +70 -4
  103. package/dist/core/naruto/naruto-write-e2e.js +3 -4
  104. package/dist/core/ops/reporting.js +3 -0
  105. package/dist/core/pipeline-internals/runtime-core.js +12 -7
  106. package/dist/core/pipeline-internals/runtime-gates.js +17 -1
  107. package/dist/core/ppt/style-tokens.js +1 -1
  108. package/dist/core/ppt-review/index.js +1 -1
  109. package/dist/core/ppt-review/slide-exporter.js +23 -17
  110. package/dist/core/ppt-review/slide-imagegen-review.js +1 -1
  111. package/dist/core/ppt-review/slide-issue-extraction.js +4 -2
  112. package/dist/core/product-design-plugin.js +2 -2
  113. package/dist/core/proof/route-finalizer.js +1 -1
  114. package/dist/core/proof-field.js +3 -3
  115. package/dist/core/provider/model-router.js +68 -3
  116. package/dist/core/release/gate-manifest.js +18 -12
  117. package/dist/core/release/gate-pack-manifest.js +1 -1
  118. package/dist/core/release/package-size-budget.js +2 -0
  119. package/dist/core/release/release-gate-affected-selector.js +1 -1
  120. package/dist/core/release/release-gate-dag.js +43 -3
  121. package/dist/core/release/release-gate-hermetic-env.js +28 -17
  122. package/dist/core/release/release-real-contract.js +416 -0
  123. package/dist/core/retention/retention-budget.js +25 -6
  124. package/dist/core/retention.js +980 -101
  125. package/dist/core/routes/constants.js +1 -1
  126. package/dist/core/routes/evidence.js +4 -4
  127. package/dist/core/routes/model-mode-router.js +3 -0
  128. package/dist/core/routes/ppt-policy.js +1 -1
  129. package/dist/core/routes.js +11 -12
  130. package/dist/core/secret-redaction.js +4 -0
  131. package/dist/core/triwiki/code-pack.js +8 -2
  132. package/dist/core/triwiki/triwiki-cache-key.js +108 -29
  133. package/dist/core/triwiki-attention.js +13 -6
  134. package/dist/core/triwiki-provenance.js +274 -0
  135. package/dist/core/triwiki-runtime.js +21 -7
  136. package/dist/core/triwiki-wrongness/wrongness-ledger.js +178 -59
  137. package/dist/core/triwiki-wrongness/wrongness-retrieval.js +11 -2
  138. package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +2 -0
  139. package/dist/core/update/update-migration-state.js +1 -1
  140. package/dist/core/update/update-notice.js +23 -0
  141. package/dist/core/update-check.js +69 -25
  142. package/dist/core/version.js +1 -1
  143. package/dist/core/wiki-coordinate.js +128 -12
  144. package/dist/core/work-order-ledger.js +168 -9
  145. package/dist/core/zellij/zellij-command.js +12 -1
  146. package/dist/core/zellij/zellij-dashboard-pane.js +3 -3
  147. package/dist/core/zellij/zellij-launcher.js +15 -14
  148. package/dist/core/zellij/zellij-pane-proof.js +32 -6
  149. package/dist/core/zellij/zellij-worker-pane-manager.js +5 -3
  150. package/dist/scripts/agent-fast-mode-default-check.js +48 -29
  151. package/dist/scripts/agent-role-config-repair-check.js +25 -4
  152. package/dist/scripts/agent-wiki-context-proof-check.js +16 -2
  153. package/dist/scripts/all-feature-deep-completion-check.js +14 -4
  154. package/dist/scripts/build-dist.js +17 -5
  155. package/dist/scripts/canonical-test-runner.js +188 -0
  156. package/dist/scripts/check-command-module-budget.js +38 -16
  157. package/dist/scripts/check-legacy-free.js +1 -1
  158. package/dist/scripts/codex-0139-interrupt-agent-check.js +5 -1
  159. package/dist/scripts/{codex-0142-app-server-v2-check.js → codex-0144-app-server-v2-check.js} +11 -10
  160. package/dist/scripts/{codex-0142-binary-identity-check.js → codex-0144-binary-identity-check.js} +4 -4
  161. package/dist/scripts/codex-0144-capability-check.js +21 -0
  162. package/dist/scripts/{codex-0139-real-probes-check.js → codex-0144-core-real-probes-check.js} +19 -5
  163. package/dist/scripts/{codex-0142-doctor-wiring-check.js → codex-0144-doctor-wiring-check.js} +6 -6
  164. package/dist/scripts/{codex-0142-manifest-check.js → codex-0144-manifest-check.js} +11 -3
  165. package/dist/scripts/{codex-0142-policy-check.js → codex-0144-policy-check.js} +2 -2
  166. package/dist/scripts/{codex-0142-thread-store-check.js → codex-0144-thread-store-check.js} +3 -3
  167. package/dist/scripts/codex-app-provider-model-ui-check.js +57 -8
  168. package/dist/scripts/codex-app-ui-preservation-check.js +35 -4
  169. package/dist/scripts/codex-control-side-effect-scope-check.js +2 -2
  170. package/dist/scripts/codex-effort-auto-discovery-check.js +1 -1
  171. package/dist/scripts/codex-lb-fast-mode-truth-check.js +1 -0
  172. package/dist/scripts/{codex-lb-gpt55-fast-profile-check.js → codex-lb-gpt56-fast-profile-check.js} +56 -5
  173. package/dist/scripts/codex-model-metadata-check.js +1 -1
  174. package/dist/scripts/codex-sdk-sandbox-policy-check.js +5 -1
  175. package/dist/scripts/codex-sdk-version-compat-check.js +2 -1
  176. package/dist/scripts/dfix-fixture-check.js +1 -1
  177. package/dist/scripts/docs-truthfulness-check.js +1 -1
  178. package/dist/scripts/doctor-codex-startup-repair-check.js +35 -10
  179. package/dist/scripts/doctor-context7-repair-check.js +2 -1
  180. package/dist/scripts/doctor-fix-proves-codex-read-check.js +1 -1
  181. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +34 -7
  182. package/dist/scripts/doctor-imagegen-repair-check.js +14 -4
  183. package/dist/scripts/doctor-startup-config-repair-blackbox.js +1 -1
  184. package/dist/scripts/doctor-startup-config-repair-check.js +1 -1
  185. package/dist/scripts/gate-policy-audit-check.js +2 -2
  186. package/dist/scripts/install-update-preserves-config-check.js +1 -1
  187. package/dist/scripts/legacy-gate-inventory-check.js +7 -5
  188. package/dist/scripts/legacy-strong-inventory-check.js +7 -5
  189. package/dist/scripts/legacy-upgrade-matrix-check.js +5 -5
  190. package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +175 -14
  191. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +166 -6
  192. package/dist/scripts/mutation-callsite-coverage-check.js +0 -11
  193. package/dist/scripts/naruto-shadow-clone-swarm-check.js +88 -50
  194. package/dist/scripts/npm-publish-performance-check.js +2 -1
  195. package/dist/scripts/package-published-contract-check.js +9 -0
  196. package/dist/scripts/packlist-performance-check.js +5 -2
  197. package/dist/scripts/postinstall-safe-side-effects-check.js +8 -3
  198. package/dist/scripts/ppt-no-mock-as-real-check.js +3 -1
  199. package/dist/scripts/product-design-plugin-routing-check.js +1 -1
  200. package/dist/scripts/release-check-stamp.js +182 -2
  201. package/dist/scripts/release-dag-full-coverage-check.js +7 -7
  202. package/dist/scripts/release-dynamic-presets-check.js +8 -0
  203. package/dist/scripts/release-gate-dag-runner-check.js +3 -2
  204. package/dist/scripts/release-gate-dag-runner.js +24 -11
  205. package/dist/scripts/release-gate-existence-audit.js +8 -9
  206. package/dist/scripts/release-gate-script-parity-check.js +1 -1
  207. package/dist/scripts/release-real-check.js +368 -157
  208. package/dist/scripts/release-runtime-truth-matrix-check.js +22 -0
  209. package/dist/scripts/route-proof-artifact-structure-check.js +1 -0
  210. package/dist/scripts/scheduler-batch-dispatch-check.js +1 -1
  211. package/dist/scripts/search-visibility-gate-lib.js +1 -1
  212. package/dist/scripts/seo-geo-route-identity-check.js +30 -4
  213. package/dist/scripts/sizecheck.js +7 -2
  214. package/dist/scripts/sks-1-11-gate-lib.js +53 -6
  215. package/dist/scripts/sks-menubar-install-check.js +7 -0
  216. package/dist/scripts/sks-uninstall-regression-check.js +1 -1
  217. package/dist/scripts/sksd-daemon-check.js +16 -6
  218. package/dist/scripts/update-default-command-check.js +4 -2
  219. package/dist/scripts/write-build-manifest.js +2 -1
  220. package/dist/scripts/zellij-layout-valid-check.js +31 -6
  221. package/dist/scripts/zellij-pane-proof-check.js +33 -2
  222. package/dist/scripts/zellij-real-session-cleanup-check.js +122 -2
  223. package/dist/scripts/zellij-real-session-launch-check.js +76 -5
  224. package/dist/scripts/zellij-slot-pane-renderer-check.js +4 -4
  225. package/package.json +27 -30
  226. package/schemas/codex/{app-server-0.142 → app-server-0.144}/codex_app_server_protocol.v2.schemas.json +1146 -781
  227. package/schemas/codex/codex-0139-real-probe-result.schema.json +39 -5
  228. package/schemas/codex/ppt-slide-issue-ledger.schema.json +2 -1
  229. package/dist/core/codex-control/codex-0139-multi-agent-real-probe.js +0 -107
  230. package/dist/scripts/agent-native-release-gate.js +0 -274
  231. package/dist/scripts/codex-0142-capability-check.js +0 -21
  232. package/dist/scripts/command-performance-scorecard-check.js +0 -204
  233. package/dist/scripts/config-managed-merge-callsite-coverage-check.js +0 -212
  234. package/dist/scripts/dollar-performance-scorecard-check.js +0 -257
  235. package/dist/scripts/gate-timing-check.js +0 -16
  236. package/dist/scripts/ops-maturity-scorecard-check.js +0 -12
  237. package/dist/scripts/performance-baseline-check.js +0 -12
  238. package/dist/scripts/performance-improvement-report-check.js +0 -58
  239. package/dist/scripts/release-parallel-check.js +0 -389
  240. package/dist/scripts/release-runner-efficiency-check.js +0 -15
  241. package/dist/scripts/retention-long-run-smoke-check.js +0 -299
  242. package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ // @ts-nocheck
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { buildRuntimeTruthMatrix, writeRuntimeTruthMatrix } from '../core/proof/runtime-truth-matrix.js';
6
+ import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
7
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
8
+ const matrix = await buildRuntimeTruthMatrix({
9
+ root,
10
+ releaseVersion: String(pkg.version || '')
11
+ });
12
+ await writeRuntimeTruthMatrix(root, matrix);
13
+ assertGate(matrix.ok === true, 'runtime truth matrix contains blocking evidence', {
14
+ blockers: matrix.blockers,
15
+ required_rows: matrix.rows.filter((row) => row.required_mode)
16
+ });
17
+ emitGate('release:runtime-truth-matrix', {
18
+ report: `.sneakoscope/reports/runtime-truth-matrix-${pkg.version}.json`,
19
+ rows: matrix.rows.length,
20
+ priorities: matrix.priorities
21
+ });
22
+ //# sourceMappingURL=release-runtime-truth-matrix-check.js.map
@@ -69,6 +69,7 @@ async function runNegativeFixture() {
69
69
  mission_id: mission,
70
70
  status: 'verified',
71
71
  route: '$Team',
72
+ execution_class: 'real',
72
73
  summary: { files_changed: 0, commands_run: 0, tests_passed: 0, tests_failed: 0, manual_review_required: false },
73
74
  evidence: {
74
75
  agents: {
@@ -12,6 +12,6 @@ const count = 6;
12
12
  const roster = { agent_count: count, roster: Array.from({ length: count }, (_, i) => ({ id: `a${i + 1}`, persona_id: `p${i + 1}`, role: 'verifier' })) };
13
13
  const partition = { slices: Array.from({ length: count }, (_, i) => ({ id: `w${i + 1}`, description: 'batch', write_paths: [], readonly_paths: [] })) };
14
14
  const result = await runAgentScheduler({ root: ledgerRoot, missionId, rootHash: 'fixture', roster, partition, targetActiveSlots: count, maxActiveSlots: count, launchSession: async ({ generation, agent, workItem }) => ({ schema: 'sks.agent-result.v1', mission_id: missionId, agent_id: agent.id, session_id: generation.session_id, persona_id: agent.persona_id, task_slice_id: workItem.id, status: 'done', backend: 'fake', summary: 'ok', findings: [], proposed_changes: [], changed_files: [], lease_compliance: { ok: true, violations: [] }, artifacts: [], blockers: [], confidence: 'high', handoff_notes: '', unverified: [], writes: [], recursion_guard: { ok: true, violations: [] }, verification: { status: 'passed', checks: [] } }) });
15
- assertGate(result.state.batch_dispatch_count >= 1 && result.state.largest_batch_size >= count, 'scheduler did not dispatch a full launch batch', result.state);
15
+ assertGate(result.state.batch_dispatch_count >= 1 && result.state.largest_batch_size >= result.state.target_active_slots, 'scheduler did not dispatch a full effective launch batch', result.state);
16
16
  emitGate('scheduler:batch-dispatch', result.state);
17
17
  //# sourceMappingURL=scheduler-batch-dispatch-check.js.map
@@ -36,7 +36,7 @@ export function makeSearchVisibilityFixture(name = 'search-visibility', options
36
36
  }
37
37
  export function runSks(args, options = {}) {
38
38
  const result = spawnSync(process.execPath, [path.join(root, 'dist', 'bin', 'sks.js'), ...args], {
39
- cwd: root,
39
+ cwd: options.cwd || root,
40
40
  encoding: 'utf8',
41
41
  stdio: 'pipe',
42
42
  env: {
@@ -1,12 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  // @ts-nocheck
3
- import { assertGate, emitGate, runSksJson } from './search-visibility-gate-lib.js';
4
- const seo = runSksJson(['run', '$SEO-GEO-OPTIMIZER SEO audit this fixture', '--execute', '--json']).json;
5
- const geo = runSksJson(['run', '$SEO-GEO-OPTIMIZER Generative Engine Optimization audit AI search visibility', '--execute', '--json']).json;
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate, makeSearchVisibilityFixture, runSksJson } from './search-visibility-gate-lib.js';
6
+ const fixture = makeSearchVisibilityFixture('seo-geo-route-identity');
7
+ fs.mkdirSync(path.join(fixture, '.sneakoscope'), { recursive: true });
8
+ let seo;
9
+ let geo;
10
+ let seoMissionIsolated = false;
11
+ let geoMissionIsolated = false;
12
+ const cleanupFixture = () => fs.rmSync(fixture, { recursive: true, force: true });
13
+ process.once('exit', cleanupFixture);
14
+ try {
15
+ seo = runSksJson(['run', '$SEO-GEO-OPTIMIZER SEO audit this fixture', '--execute', '--json'], { cwd: fixture }).json;
16
+ seoMissionIsolated = fs.existsSync(path.join(fixture, '.sneakoscope', 'missions', seo.mission_id));
17
+ geo = runSksJson(['run', '$SEO-GEO-OPTIMIZER Generative Engine Optimization audit AI search visibility', '--execute', '--json'], { cwd: fixture }).json;
18
+ geoMissionIsolated = fs.existsSync(path.join(fixture, '.sneakoscope', 'missions', geo.mission_id));
19
+ }
20
+ finally {
21
+ cleanupFixture();
22
+ process.removeListener('exit', cleanupFixture);
23
+ }
6
24
  const seoText = JSON.stringify(seo);
7
25
  const geoText = JSON.stringify(geo);
26
+ assertGate(seoMissionIsolated && geoMissionIsolated, 'SEO/GEO route identity missions must stay inside the hermetic fixture', {
27
+ fixture,
28
+ seo_mission_id: seo.mission_id,
29
+ geo_mission_id: geo.mission_id,
30
+ seo_mission_isolated: seoMissionIsolated,
31
+ geo_mission_isolated: geoMissionIsolated
32
+ });
8
33
  assertGate(/\$SEO-GEO-OPTIMIZER/.test(seoText) && /sks seo-geo-optimizer/.test(seoText) && /--mode seo/.test(seoText), 'sks run --execute must preserve unified optimizer route and execute seo mode path', seo);
9
34
  assertGate(/\$SEO-GEO-OPTIMIZER/.test(geoText) && /sks seo-geo-optimizer/.test(geoText) && /--mode geo/.test(geoText), 'sks run --execute must preserve unified optimizer route and execute geo mode path', geo);
10
35
  assertGate(!/\$AutoResearch/.test(seoText) && !/\$AutoResearch/.test(geoText), 'SEO/GEO route identity must not collapse into AutoResearch', { seo, geo });
11
- emitGate('seo-geo:route-identity', { seo_status: seo.status, geo_status: geo.status });
36
+ assertGate(!fs.existsSync(fixture), 'SEO/GEO route identity fixture must be removed after the check', { fixture });
37
+ emitGate('seo-geo:route-identity', { seo_status: seo.status, geo_status: geo.status, hermetic_fixture_removed: true });
12
38
  //# sourceMappingURL=seo-geo-route-identity-check.js.map
@@ -5,9 +5,10 @@ import fs from 'node:fs';
5
5
  import os from 'node:os';
6
6
  import path from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
+ import { DEFAULT_MAX_PACK_BYTES } from '../core/release/package-size-budget.js';
8
9
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
9
10
  const limits = {
10
- packedBytes: Number(process.env.SKS_MAX_PACK_BYTES || 2410 * 1024),
11
+ packedBytes: Number(process.env.SKS_MAX_PACK_BYTES || DEFAULT_MAX_PACK_BYTES),
11
12
  unpackedBytes: Number(process.env.SKS_MAX_UNPACKED_BYTES || 10 * 1024 * 1024),
12
13
  packFiles: Number(process.env.SKS_MAX_PACK_FILES || 2100),
13
14
  trackedFileBytes: Number(process.env.SKS_MAX_TRACKED_FILE_BYTES || 384 * 1024)
@@ -16,7 +17,11 @@ const trackedFileSizeAllowlist = new Set([
16
17
  // Historical source documentation export; not included in the npm package payload.
17
18
  'docs/sks-local-llm-mode/exports/sks-local-llm-mode-deck.pdf',
18
19
  // Central release DAG manifest; package footprint limits still apply below.
19
- 'release-gates.v2.json'
20
+ 'release-gates.v2.json',
21
+ // Generated Codex App Server protocol schemas; handwritten sources remain
22
+ // subject to the 384 KiB split-review limit.
23
+ 'schemas/codex/app-server-0.144/codex_app_server_protocol.schemas.json',
24
+ 'schemas/codex/app-server-0.144/codex_app_server_protocol.v2.schemas.json'
20
25
  ]);
21
26
  const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
22
27
  function fail(message, detail = '') {
@@ -4,7 +4,11 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import { fileURLToPath } from 'node:url';
7
+ import { tmpdir } from '../core/fsx.js';
7
8
  export const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
9
+ const fixtureMissionRoots = new Map();
10
+ const fixtureRoots = new Set();
11
+ let fixtureCleanupRegistered = false;
8
12
  export function assertGate(condition, message, detail = {}) {
9
13
  if (condition)
10
14
  return;
@@ -14,14 +18,15 @@ export function assertGate(condition, message, detail = {}) {
14
18
  export function emitGate(name, detail = {}) {
15
19
  console.log(JSON.stringify({ schema: 'sks.release-gate.v1', ok: true, gate: name, ...detail }, null, 2));
16
20
  }
17
- export function runSksJson(args) {
21
+ export function runSksJson(args, options = {}) {
18
22
  const entrypoint = path.join(root, 'dist', 'bin', 'sks.js');
19
23
  assertGate(fs.existsSync(entrypoint), 'dist entrypoint missing; run npm run build first', { entrypoint });
24
+ const mappedMissionRoot = args.map((arg) => fixtureMissionRoots.get(String(arg))).find(Boolean);
20
25
  const result = spawnSync(process.execPath, [entrypoint, ...args], {
21
- cwd: root,
26
+ cwd: options.cwd || mappedMissionRoot || root,
22
27
  encoding: 'utf8',
23
28
  timeout: Number(process.env.SKS_GATE_TIMEOUT_MS || 120_000),
24
- env: { ...process.env, SKS_SKIP_NPM_FRESHNESS_CHECK: '1', CI: 'true' }
29
+ env: { ...process.env, SKS_SKIP_NPM_FRESHNESS_CHECK: '1', CI: 'true', ...(options.env || {}) }
25
30
  });
26
31
  let parsed = null;
27
32
  try {
@@ -36,7 +41,10 @@ export function runSksJson(args) {
36
41
  return { ...parsed, _process_status: result.status, _stderr_tail: String(result.stderr || '').slice(-600) };
37
42
  }
38
43
  export function runPptReview(action = 'review') {
39
- const json = runSksJson(['ppt', 'fixture', '--mock', '--json']);
44
+ const json = runHermeticRouteFixture('ppt', ['ppt', 'fixture', '--mock', '--json'], {
45
+ SKS_TEST_FAKE_IMAGEGEN: '1',
46
+ SKS_TEST_FAKE_EXTRACTOR: '1'
47
+ });
40
48
  const proof = readMissionJson(json.mission_id, 'completion-proof.json');
41
49
  const review = json.artifacts || json.imagegen_review || {};
42
50
  json.proof_evidence = proof.evidence?.ppt_review || json.artifacts?.proof_evidence || {};
@@ -54,7 +62,7 @@ export function runPptReview(action = 'review') {
54
62
  return json;
55
63
  }
56
64
  export function runDfixFixture() {
57
- const json = runSksJson(['dfix', 'fixture', '--json']);
65
+ const json = runHermeticRouteFixture('dfix', ['dfix', 'fixture', '--json']);
58
66
  json.gate = json.gate || json.artifacts?.gate;
59
67
  assertGate(json.ok === true, 'dfix fixture blocked', json);
60
68
  assertGate(json.gate?.passed === true, 'dfix gate did not pass', json.gate);
@@ -66,7 +74,8 @@ export function runUxFixture() {
66
74
  return json;
67
75
  }
68
76
  export function missionFile(missionId, file) {
69
- return path.join(root, '.sneakoscope', 'missions', missionId, file);
77
+ const missionRoot = fixtureMissionRoots.get(missionId) || root;
78
+ return path.join(missionRoot, '.sneakoscope', 'missions', missionId, file);
70
79
  }
71
80
  export function readMissionJson(missionId, file) {
72
81
  const absolute = missionFile(missionId, file);
@@ -77,4 +86,42 @@ export function hasRelationType(missionId, type) {
77
86
  const ledger = readMissionJson(missionId, 'image-voxel-ledger.json');
78
87
  return (ledger.relations || []).some((relation) => relation.type === type);
79
88
  }
89
+ function createHermeticRouteFixtureRoot(label) {
90
+ const fixtureRoot = tmpdir(`${label}-release-fixture-`);
91
+ fs.writeFileSync(path.join(fixtureRoot, 'package.json'), `${JSON.stringify({ name: `sks-${label}-release-fixture`, private: true })}\n`);
92
+ fixtureRoots.add(fixtureRoot);
93
+ if (!fixtureCleanupRegistered) {
94
+ fixtureCleanupRegistered = true;
95
+ process.once('exit', () => {
96
+ for (const candidate of fixtureRoots)
97
+ fs.rmSync(candidate, { recursive: true, force: true });
98
+ });
99
+ }
100
+ return fixtureRoot;
101
+ }
102
+ function runHermeticRouteFixture(label, args, env = {}) {
103
+ const fixtureRoot = createHermeticRouteFixtureRoot(label);
104
+ const fixtureHome = path.join(fixtureRoot, 'home');
105
+ const json = runSksJson(args, {
106
+ cwd: fixtureRoot,
107
+ env: {
108
+ HOME: fixtureHome,
109
+ CODEX_HOME: path.join(fixtureHome, '.codex'),
110
+ SKS_GLOBAL_ROOT: path.join(fixtureHome, '.sneakoscope-global'),
111
+ TMPDIR: fixtureRoot,
112
+ TMP: fixtureRoot,
113
+ TEMP: fixtureRoot,
114
+ PWD: fixtureRoot,
115
+ SKS_TEST_ISOLATION: '1',
116
+ SKS_UPDATE_MIGRATION_GATE_DISABLED: '1',
117
+ NODE_ENV: 'test',
118
+ CI: 'true',
119
+ ...env
120
+ }
121
+ });
122
+ if (json.mission_id)
123
+ fixtureMissionRoots.set(json.mission_id, fixtureRoot);
124
+ json.fixture_root = fixtureRoot;
125
+ return json;
126
+ }
80
127
  //# sourceMappingURL=sks-1-11-gate-lib.js.map
@@ -126,6 +126,11 @@ const hasActionFallbacks = actionScript.includes('command -v sks')
126
126
  && actionScript.includes('/bin/zsh -lc')
127
127
  && actionScript.includes('exit 127')
128
128
  && actionScript.includes('display notification');
129
+ const pinnedEntryIndex = actionScript.indexOf('run_node_entry "$SKS_ENTRY" "$@"');
130
+ const hasPinnedEntryPriority = pinnedEntryIndex >= 0
131
+ && pinnedEntryIndex < actionScript.indexOf('command -v sks')
132
+ && pinnedEntryIndex < actionScript.indexOf('npm root -g')
133
+ && actionScript.lastIndexOf('run_node_entry "$SKS_ENTRY" "$@"') === pinnedEntryIndex;
129
134
  const hasEntryWarning = result.warnings.includes('sks_entry_project_local');
130
135
  const hasBuildStamp = buildStampExists
131
136
  && result.build_stamp?.package_version === PACKAGE_VERSION
@@ -203,6 +208,7 @@ const darwinOk = cltMissing
203
208
  && hasInteractiveProcessType
204
209
  && hasPackagePlistVersion
205
210
  && hasActionFallbacks
211
+ && hasPinnedEntryPriority
206
212
  && hasEntryWarning
207
213
  && hasBuildStamp
208
214
  && swiftParse.ok === true
@@ -249,6 +255,7 @@ const report = {
249
255
  has_interactive_process_type: hasInteractiveProcessType,
250
256
  has_package_plist_version: hasPackagePlistVersion,
251
257
  has_action_fallbacks: hasActionFallbacks,
258
+ has_pinned_entry_priority: hasPinnedEntryPriority,
252
259
  has_entry_warning: hasEntryWarning,
253
260
  has_build_stamp: hasBuildStamp,
254
261
  swift_parse: swiftParse,
@@ -17,7 +17,7 @@ await writeText(path.join(home, '.codex', 'config.toml'), [
17
17
  'default_profile = "sks-fast-high"',
18
18
  'service_tier = "fast"',
19
19
  '[profiles.sks-fast-high]',
20
- 'model = "gpt-5.5"',
20
+ 'model = "gpt-5.6-terra"',
21
21
  '[user.fast_mode]',
22
22
  'enabled = true',
23
23
  '[mcp_servers.user]',
@@ -1,9 +1,19 @@
1
1
  // @ts-nocheck
2
- import { assertGate, emitGate, importDist, root } from './sks-1-18-gate-lib.js';
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate, importDist } from './sks-1-18-gate-lib.js';
3
6
  const mod = await importDist('core/daemon/sksd-client.js');
4
- const state = mod.runSksdClient(root, 'status');
5
- const start = mod.runSksdClient(root, 'start');
6
- assertGate(state.schema === 'sks.sksd-state.v1', 'sksd status schema mismatch', state);
7
- assertGate(start.protocol_ok === true && start.status === 'running', 'sksd start must record protocol-ready state', start);
8
- emitGate('sksd:daemon', { status: start.status });
7
+ const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-sksd-daemon-check-'));
8
+ try {
9
+ const state = mod.runSksdClient(fixtureRoot, 'status');
10
+ const start = mod.runSksdClient(fixtureRoot, 'start');
11
+ assertGate(state.schema === 'sks.sksd-state.v1', 'sksd status schema mismatch', state);
12
+ assertGate(start.protocol_ok === true && start.status === 'running', 'sksd start must record protocol-ready state', start);
13
+ assertGate(start.build_proof_ready === false, 'hermetic sksd protocol fixture must not build or mutate the source checkout', start);
14
+ emitGate('sksd:daemon', { status: start.status, hermetic_fixture: true, build_started: false });
15
+ }
16
+ finally {
17
+ await fs.rm(fixtureRoot, { recursive: true, force: true });
18
+ }
9
19
  //# sourceMappingURL=sksd-daemon-check.js.map
@@ -12,7 +12,9 @@ const routes = fs.readFileSync('src/core/routes.ts', 'utf8');
12
12
  assertGate(registry.includes("subcommand(() => import(basicModule), 'updateCommand', 'dist/core/commands/basic-cli.js', 'now')"), 'bare sks update must default to update now');
13
13
  assertGate(basicCli.includes("export async function updateCommand(sub: any = 'now'"), 'updateCommand default must be now');
14
14
  assertGate(basicCli.includes("action.startsWith('-')") && basicCli.includes('effectiveArgs = [String(sub), ...args]'), 'sks update --json/--dry-run must be treated as update now with flags');
15
- assertGate(update.includes('installSksMenuBar') && update.includes('sks_menubar'), 'update now must refresh the SKS menu bar companion stage');
15
+ assertGate(update.includes("[entrypoint, 'menubar', 'install', '--json']")
16
+ && update.includes('entrypoint: newBinary')
17
+ && update.includes('sks_menubar'), 'update now must refresh the SKS menu bar through the updated package-local entrypoint');
16
18
  assertGate(routes.includes('sks update [check|now]'), 'command catalog must document bare sks update as the default update path');
17
19
  console.log(JSON.stringify({
18
20
  schema: 'sks.update-default-command-check.v1',
@@ -21,7 +23,7 @@ console.log(JSON.stringify({
21
23
  'registry_default_now',
22
24
  'basic_cli_default_now',
23
25
  'flag_first_default_now',
24
- 'update_menubar_stage',
26
+ 'updated_package_local_menubar_stage',
25
27
  'command_catalog_usage'
26
28
  ]
27
29
  }, null, 2));
@@ -5,6 +5,7 @@ import fsp from 'node:fs/promises';
5
5
  import path from 'node:path';
6
6
  import crypto from 'node:crypto';
7
7
  import { fileURLToPath } from 'node:url';
8
+ import { writeTextAtomic } from '../core/fsx.js';
8
9
  import { writeDistFreshStamp, sourceSnapshot } from './lib/ensure-dist-fresh.js';
9
10
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
10
11
  const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
@@ -22,7 +23,7 @@ const compiledDtsCount = sorted.filter((f) => f.endsWith('.d.ts')).length;
22
23
  const source = sourceSnapshot();
23
24
  const distStamp = writeDistFreshStamp();
24
25
  const srcMjsRuntimeFiles = await collectSrcMjsRuntimeFiles();
25
- await fsp.writeFile(path.join(distRoot, 'build-manifest.json'), `${JSON.stringify({
26
+ await writeTextAtomic(path.join(distRoot, 'build-manifest.json'), `${JSON.stringify({
26
27
  schema: 'sks.dist-build.v2',
27
28
  version: pkg.version,
28
29
  package_version: pkg.version,
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // @ts-nocheck
3
3
  import fs from 'node:fs/promises';
4
+ import { randomBytes } from 'node:crypto';
4
5
  import os from 'node:os';
5
6
  import path from 'node:path';
6
7
  import { pathToFileURL } from 'node:url';
@@ -55,19 +56,27 @@ const layoutPath = path.join(tmp, 'layout.kdl');
55
56
  await fs.writeFile(layoutPath, built.layout_kdl, 'utf8');
56
57
  const requireReal = process.env.SKS_REQUIRE_ZELLIJ === '1' || process.argv.includes('--require-real');
57
58
  const capability = await capabilityMod.checkZellijCapability({ root, require: requireReal, writeReport: true });
58
- const sessionName = 'sks-layout-check';
59
- if (capability.status === 'ok')
60
- await commandMod.runZellij(['kill-session', sessionName], { cwd: root, timeoutMs: 2500, optional: true });
59
+ const runId = `${process.pid}-${Date.now().toString(36)}-${randomBytes(3).toString('hex')}`;
60
+ const sessionName = `sks-layout-check-${runId}`;
61
+ const socketDir = path.join('/tmp', `sks-zj-layout-${runId}`);
62
+ const zellijEnv = { ZELLIJ_SOCKET_DIR: socketDir };
61
63
  const realRun = capability.status === 'ok'
62
64
  ? {
63
- create_background: await commandMod.runZellij(['attach', '--create-background', sessionName, 'options', '--default-layout', layoutPath], { cwd: root, timeoutMs: 5000, optional: !requireReal }),
65
+ create_background: await commandMod.runZellij(['attach', '--create-background', sessionName, 'options', '--default-layout', layoutPath], { cwd: root, env: zellijEnv, timeoutMs: 5000, optional: !requireReal }),
64
66
  cleanup: null,
67
+ session_removed: false,
68
+ socket_dir_removed: false,
65
69
  ok: false
66
70
  }
67
71
  : null;
68
72
  if (realRun) {
69
- realRun.cleanup = await commandMod.runZellij(['kill-session', sessionName], { cwd: root, timeoutMs: 5000, optional: true });
70
- realRun.ok = realRun.create_background.ok === true;
73
+ realRun.cleanup = await commandMod.runZellij(['kill-session', sessionName], { cwd: root, env: zellijEnv, timeoutMs: 5000, optional: true });
74
+ const remaining = await waitForSocketEntriesToClear(socketDir, 2000);
75
+ realRun.session_removed = !remaining.includes(sessionName);
76
+ if (remaining.length === 0)
77
+ await fs.rm(socketDir, { recursive: true, force: true });
78
+ realRun.socket_dir_removed = !(await exists(socketDir));
79
+ realRun.ok = realRun.create_background.ok === true && realRun.session_removed && realRun.socket_dir_removed;
71
80
  }
72
81
  const ok = staticValidation.ok
73
82
  && viewportLayoutOk
@@ -77,6 +86,7 @@ const ok = staticValidation.ok
77
86
  && invalidValidation.ok === false
78
87
  && capability.ok
79
88
  && (requireReal ? realRun?.ok === true : true);
89
+ await fs.rm(tmp, { recursive: true, force: true });
80
90
  emit({
81
91
  schema: 'sks.zellij-layout-valid-check.v1',
82
92
  ok,
@@ -88,10 +98,25 @@ emit({
88
98
  invalid_fixture: invalidValidation,
89
99
  capability,
90
100
  real_run: realRun,
101
+ isolated_session: true,
102
+ socket_dir: socketDir,
103
+ temporary_layout_removed: !(await exists(tmp)),
91
104
  integration_optional: !requireReal,
92
105
  blockers: ok ? [] : ['zellij_layout_valid_check_failed']
93
106
  });
94
107
  function emit(report) { console.log(JSON.stringify(report, null, 2)); if (!report.ok)
95
108
  process.exitCode = 1; }
96
109
  function fail(blocker, detail) { emit({ schema: 'sks.zellij-layout-valid-check.v1', ok: false, blockers: [blocker], detail }); process.exit(1); }
110
+ async function waitForSocketEntriesToClear(socketDir, timeoutMs) {
111
+ const deadline = Date.now() + timeoutMs;
112
+ for (;;) {
113
+ const entries = await fs.readdir(path.join(socketDir, 'contract_version_1')).catch(() => []);
114
+ if (entries.length === 0 || Date.now() >= deadline)
115
+ return entries;
116
+ await new Promise((resolve) => setTimeout(resolve, 50));
117
+ }
118
+ }
119
+ async function exists(value) {
120
+ return fs.access(value).then(() => true).catch(() => false);
121
+ }
97
122
  //# sourceMappingURL=zellij-layout-valid-check.js.map
@@ -42,13 +42,44 @@ const codexLbOnlyMain = mod.evaluateZellijPaneProofRows(mod.normalizeZellijPaneR
42
42
  { pane_id: '1', name: 'orchestrator', command: 'sh -lc model_provider="codex-lb"', cwd: root, exited: false },
43
43
  { pane_id: '2', name: 'slot-001', command: 'sks zellij-lane --mission M --slot slot-001', cwd: root, exited: false }
44
44
  ]), { expectedLaneCount: 1, expectedCwd: root, expectedMainCommandIncludes: 'codex' });
45
+ const zellij044Rows = [
46
+ ...Array.from({ length: 120 }, (_, index) => ({
47
+ id: index + 10,
48
+ is_plugin: true,
49
+ title: `zellij:fixture-${String(index).padStart(3, '0')}`,
50
+ terminal_command: null,
51
+ plugin_url: 'zellij:fixture',
52
+ tab_name: 'SKS fixture'
53
+ })),
54
+ {
55
+ id: 0,
56
+ is_plugin: false,
57
+ title: 'orchestrator',
58
+ exited: false,
59
+ exit_status: null,
60
+ pane_x: 0,
61
+ pane_y: 1,
62
+ pane_columns: 80,
63
+ pane_rows: 24,
64
+ terminal_command: "sh -lc exec 'codex' '--no-alt-screen'",
65
+ pane_command: `${path.join(root, 'node_modules', '.bin', 'codex')} --no-alt-screen`,
66
+ pane_cwd: root,
67
+ tab_name: 'SKS fixture'
68
+ }
69
+ ];
70
+ const zellij044Json = JSON.stringify(zellij044Rows);
71
+ const zellij044Parsed = mod.parseZellijPaneRows(zellij044Json);
72
+ const zellij044Evaluation = mod.evaluateZellijPaneProofRows(mod.normalizeZellijPaneRows(zellij044Parsed), { expectedLaneCount: 0, expectedCwd: root, expectedMainCommandIncludes: 'codex' });
45
73
  const fixtureOk = positive.blockers.length === 0
46
74
  && missingLane.blockers.includes('zellij_lane_pane_missing')
47
75
  && exitedLane.blockers.some((blocker) => blocker.startsWith('zellij_lane_pane_exited'))
48
76
  && madCodexMain.blockers.length === 0
49
77
  && madShellMain.blockers.includes('zellij_main_pane_unexpected_command:codex')
50
- && codexLbOnlyMain.blockers.includes('zellij_main_pane_unexpected_command:codex');
51
- emit({ ...report, fixture_ok: fixtureOk, fixture_results: { positive, missingLane, exitedLane, madCodexMain, madShellMain, codexLbOnlyMain }, ok: report.ok && fixtureOk });
78
+ && codexLbOnlyMain.blockers.includes('zellij_main_pane_unexpected_command:codex')
79
+ && zellij044Json.length > 8192
80
+ && zellij044Parsed.length === zellij044Rows.length
81
+ && zellij044Evaluation.blockers.length === 0;
82
+ emit({ ...report, fixture_ok: fixtureOk, fixture_results: { positive, missingLane, exitedLane, madCodexMain, madShellMain, codexLbOnlyMain, zellij044: { json_bytes: Buffer.byteLength(zellij044Json), parsed_rows: zellij044Parsed.length, evaluation: zellij044Evaluation } }, ok: report.ok && fixtureOk });
52
83
  function emit(report) { console.log(JSON.stringify(report, null, 2)); if (!report.ok)
53
84
  process.exitCode = 1; }
54
85
  function fail(blocker, detail) { emit({ schema: 'sks.zellij-pane-proof-check.v1', ok: false, blockers: [blocker], detail }); process.exit(1); }
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // @ts-nocheck
3
+ import fs from 'node:fs/promises';
4
+ import { createHash } from 'node:crypto';
3
5
  import path from 'node:path';
4
6
  import { pathToFileURL } from 'node:url';
5
7
  import { ensureDistFresh, root } from './lib/ensure-dist-fresh.js';
@@ -7,10 +9,96 @@ const freshness = ensureDistFresh({ rebuild: false });
7
9
  if (!freshness.ok)
8
10
  fail('dist_not_fresh', { freshness });
9
11
  const args = process.argv.slice(2);
12
+ const missionId = readArg(args, '--mission');
10
13
  const sessionName = readArg(args, '--session') || 'sks-real';
14
+ const socketDir = readArg(args, '--owned-socket-dir');
15
+ const ownerToken = String(process.env.SKS_ZELLIJ_CHECK_OWNER_TOKEN || '');
11
16
  const command = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-command.js')).href);
12
- const result = await command.runZellij(['kill-session', sessionName], { cwd: root, timeoutMs: 5000, optional: true });
13
- emit({ schema: 'sks.zellij-real-session-cleanup-check.v1', ok: result.ok === true || result.exit_code !== 0, session_name: sessionName, result });
17
+ const ownershipPath = missionId ? path.join(root, '.sneakoscope', 'missions', missionId, 'zellij-real-session-ownership.json') : null;
18
+ const expectedLayoutPath = missionId ? path.join(root, '.sneakoscope', 'layouts', `mad-${missionId}.kdl`) : null;
19
+ const ownership = ownershipPath ? await readJson(ownershipPath) : null;
20
+ const ownershipBlockers = [
21
+ ...(!missionId ? ['zellij_cleanup_mission_missing'] : []),
22
+ ...(!isSafeOwnedSocketDir(socketDir) ? ['zellij_cleanup_owned_socket_dir_invalid'] : []),
23
+ ...(ownerToken.length < 32 ? ['zellij_cleanup_owner_token_missing'] : []),
24
+ ...(!ownership ? ['zellij_cleanup_ownership_marker_missing'] : []),
25
+ ...(ownership && ownership.schema !== 'sks.zellij-real-session-ownership.v1' ? ['zellij_cleanup_ownership_schema_invalid'] : []),
26
+ ...(ownership && ownership.mission_id !== missionId ? ['zellij_cleanup_mission_mismatch'] : []),
27
+ ...(ownership && ownership.session_name !== sessionName ? ['zellij_cleanup_session_mismatch'] : []),
28
+ ...(ownership && path.resolve(String(ownership.socket_dir || '')) !== path.resolve(String(socketDir || '')) ? ['zellij_cleanup_socket_dir_mismatch'] : []),
29
+ ...(ownership && ownership.owner_token_sha256 !== hashOwnerToken(ownerToken) ? ['zellij_cleanup_owner_token_mismatch'] : []),
30
+ ...(ownership && ownership.cleanup_authorized !== true ? ['zellij_cleanup_not_authorized'] : []),
31
+ ...(ownership && ownership.layout_cleanup_authorized !== true ? ['zellij_cleanup_layout_not_authorized'] : []),
32
+ ...(ownership && path.resolve(String(ownership.layout_path || '')) !== path.resolve(String(expectedLayoutPath || '')) ? ['zellij_cleanup_layout_path_mismatch'] : [])
33
+ ];
34
+ if (ownershipBlockers.length > 0) {
35
+ emit({
36
+ schema: 'sks.zellij-real-session-cleanup-check.v1',
37
+ ok: false,
38
+ mutation_attempted: false,
39
+ mission_id: missionId,
40
+ session_name: sessionName,
41
+ socket_dir: socketDir,
42
+ ownership_path: ownershipPath,
43
+ blockers: ownershipBlockers
44
+ });
45
+ }
46
+ else {
47
+ const beforeEntries = await socketEntries(socketDir);
48
+ const result = await command.runZellij(['kill-session', sessionName], {
49
+ cwd: root,
50
+ env: { ZELLIJ_SOCKET_DIR: socketDir },
51
+ timeoutMs: 5000,
52
+ optional: true
53
+ });
54
+ const remainingEntries = await waitForSocketEntriesToClear(socketDir, 2000);
55
+ const sessionRemoved = !remainingEntries.includes(sessionName);
56
+ const socketExclusive = remainingEntries.length === 0;
57
+ const layoutPresentBefore = await exists(expectedLayoutPath);
58
+ const layoutSha256Before = layoutPresentBefore ? await sha256File(expectedLayoutPath) : null;
59
+ const layoutHashMatches = !layoutPresentBefore || !ownership.layout_sha256 || layoutSha256Before === ownership.layout_sha256;
60
+ let socketDirRemoved = false;
61
+ let layoutRemoved = false;
62
+ if (sessionRemoved && socketExclusive) {
63
+ await fs.rm(socketDir, { recursive: true, force: true });
64
+ socketDirRemoved = !(await exists(socketDir));
65
+ if (socketDirRemoved && layoutHashMatches) {
66
+ await fs.rm(expectedLayoutPath, { force: true });
67
+ layoutRemoved = !(await exists(expectedLayoutPath));
68
+ }
69
+ }
70
+ const blockers = [
71
+ ...(!sessionRemoved ? ['zellij_cleanup_session_still_present'] : []),
72
+ ...(!socketExclusive ? ['zellij_cleanup_owned_socket_dir_not_empty'] : []),
73
+ ...(!socketDirRemoved ? ['zellij_cleanup_socket_dir_not_removed'] : []),
74
+ ...(!layoutHashMatches ? ['zellij_cleanup_layout_hash_mismatch'] : []),
75
+ ...(!layoutRemoved ? ['zellij_cleanup_layout_not_removed'] : [])
76
+ ];
77
+ const report = {
78
+ schema: 'sks.zellij-real-session-cleanup-check.v1',
79
+ ok: blockers.length === 0,
80
+ mutation_attempted: true,
81
+ mission_id: missionId,
82
+ session_name: sessionName,
83
+ socket_dir: socketDir,
84
+ ownership_path: ownershipPath,
85
+ session_present_before: beforeEntries.includes(sessionName),
86
+ session_removed: sessionRemoved,
87
+ socket_dir_exclusive: socketExclusive,
88
+ socket_dir_removed: socketDirRemoved,
89
+ layout_path: expectedLayoutPath,
90
+ layout_sha256: ownership.layout_sha256 || null,
91
+ layout_sha256_before_cleanup: layoutSha256Before,
92
+ layout_hash_matches: layoutHashMatches,
93
+ layout_removed: layoutRemoved,
94
+ remaining_socket_entries: remainingEntries,
95
+ result,
96
+ blockers,
97
+ warnings: result.ok ? [] : ['zellij_kill_session_nonzero_but_absence_verified']
98
+ };
99
+ await fs.writeFile(path.join(root, '.sneakoscope', 'missions', missionId, 'zellij-real-session-cleanup.json'), `${JSON.stringify(report, null, 2)}\n`);
100
+ emit(report);
101
+ }
14
102
  function emit(report) { console.log(JSON.stringify(report, null, 2)); if (!report.ok)
15
103
  process.exitCode = 1; }
16
104
  function fail(blocker, detail) { emit({ schema: 'sks.zellij-real-session-cleanup-check.v1', ok: false, blockers: [blocker], detail }); process.exit(1); }
@@ -18,4 +106,36 @@ function readArg(args, name) {
18
106
  const index = args.indexOf(name);
19
107
  return index >= 0 ? args[index + 1] || null : null;
20
108
  }
109
+ function hashOwnerToken(value) {
110
+ return createHash('sha256').update(String(value)).digest('hex');
111
+ }
112
+ async function sha256File(file) {
113
+ return fs.readFile(file).then((data) => createHash('sha256').update(data).digest('hex')).catch(() => null);
114
+ }
115
+ function isSafeOwnedSocketDir(value) {
116
+ if (!value)
117
+ return false;
118
+ const resolved = path.resolve(String(value));
119
+ return path.dirname(resolved) === '/tmp' && /^sks-zj-rr-[A-Za-z0-9-]+$/.test(path.basename(resolved));
120
+ }
121
+ async function readJson(file) {
122
+ return fs.readFile(file, 'utf8').then((text) => JSON.parse(text)).catch(() => null);
123
+ }
124
+ async function socketEntries(socketDir) {
125
+ if (!socketDir)
126
+ return [];
127
+ return fs.readdir(path.join(socketDir, 'contract_version_1')).catch(() => []);
128
+ }
129
+ async function waitForSocketEntriesToClear(socketDir, timeoutMs) {
130
+ const deadline = Date.now() + timeoutMs;
131
+ for (;;) {
132
+ const entries = await socketEntries(socketDir);
133
+ if (entries.length === 0 || Date.now() >= deadline)
134
+ return entries;
135
+ await new Promise((resolve) => setTimeout(resolve, 50));
136
+ }
137
+ }
138
+ async function exists(value) {
139
+ return fs.access(value).then(() => true).catch(() => false);
140
+ }
21
141
  //# sourceMappingURL=zellij-real-session-cleanup-check.js.map