sneakoscope 2.0.8 → 2.0.10

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 (76) hide show
  1. package/README.md +8 -4
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/build-manifest.json +33 -8
  8. package/dist/cli/command-registry.js +1 -0
  9. package/dist/commands/doctor.js +18 -1
  10. package/dist/commands/zellij-slot-pane.js +26 -0
  11. package/dist/commands/zellij.js +144 -1
  12. package/dist/core/agents/agent-orchestrator.js +202 -9
  13. package/dist/core/agents/agent-role-config.js +92 -0
  14. package/dist/core/agents/native-cli-session-swarm.js +230 -48
  15. package/dist/core/commands/mad-sks-command.js +17 -26
  16. package/dist/core/commands/naruto-command.js +155 -37
  17. package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
  18. package/dist/core/fsx.js +1 -1
  19. package/dist/core/hooks-runtime.js +4 -0
  20. package/dist/core/init.js +1 -0
  21. package/dist/core/naruto/naruto-active-pool.js +141 -0
  22. package/dist/core/naruto/naruto-concurrency-governor.js +17 -2
  23. package/dist/core/naruto/naruto-real-worker-child.js +35 -0
  24. package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
  25. package/dist/core/naruto/naruto-work-graph.js +2 -1
  26. package/dist/core/release/release-gate-cache-v2.js +58 -4
  27. package/dist/core/release/release-gate-dag.js +36 -25
  28. package/dist/core/version.js +1 -1
  29. package/dist/core/zellij/zellij-dashboard-renderer.js +22 -6
  30. package/dist/core/zellij/zellij-launcher.js +3 -3
  31. package/dist/core/zellij/zellij-layout-builder.js +1 -1
  32. package/dist/core/zellij/zellij-right-column-layout-proof.js +42 -0
  33. package/dist/core/zellij/zellij-right-column-manager.js +304 -0
  34. package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
  35. package/dist/core/zellij/zellij-ui-mode.js +16 -0
  36. package/dist/core/zellij/zellij-worker-pane-manager.js +152 -17
  37. package/dist/scripts/agent-role-config-repair-check.js +33 -0
  38. package/dist/scripts/codex-sdk-release-review-pipeline-check.js +5 -5
  39. package/dist/scripts/doctor-fix-proves-codex-read-check.js +26 -5
  40. package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
  41. package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
  42. package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
  43. package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +2 -2
  44. package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
  45. package/dist/scripts/naruto-concurrency-governor-check.js +2 -1
  46. package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
  47. package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
  48. package/dist/scripts/naruto-real-active-pool-check.js +39 -0
  49. package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
  50. package/dist/scripts/naruto-work-graph-check.js +1 -1
  51. package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +48 -0
  52. package/dist/scripts/product-design-auto-install-check.js +3 -3
  53. package/dist/scripts/product-design-plugin-routing-check.js +3 -3
  54. package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
  55. package/dist/scripts/release-cache-glob-hashing-check.js +42 -0
  56. package/dist/scripts/release-check-dynamic-execute.js +27 -1
  57. package/dist/scripts/release-check-dynamic.js +38 -11
  58. package/dist/scripts/release-check-stamp.js +7 -2
  59. package/dist/scripts/release-dag-full-coverage-check.js +35 -0
  60. package/dist/scripts/release-dynamic-performance-check.js +31 -1
  61. package/dist/scripts/release-gate-existence-audit.js +29 -33
  62. package/dist/scripts/release-parallel-speed-budget-check.js +67 -13
  63. package/dist/scripts/release-readiness-report.js +14 -3
  64. package/dist/scripts/zellij-dashboard-pane-check.js +6 -4
  65. package/dist/scripts/zellij-developer-controls-check.js +20 -0
  66. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +21 -0
  67. package/dist/scripts/zellij-initial-main-only-blackbox.js +28 -0
  68. package/dist/scripts/zellij-right-column-geometry-proof.js +162 -0
  69. package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
  70. package/dist/scripts/zellij-right-column-manager-check.js +22 -0
  71. package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
  72. package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
  73. package/dist/scripts/zellij-worker-pane-manager-check.js +2 -1
  74. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +7 -6
  75. package/package.json +23 -5
  76. package/schemas/zellij/zellij-right-column-state.schema.json +41 -0
@@ -12,17 +12,8 @@ const args = process.argv.slice(2);
12
12
  const publish = args.includes('--publish');
13
13
  const baseArg = readArg(args, '--base');
14
14
  const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
15
- const dagSource = fs.readFileSync(path.join(root, 'src/scripts/release-parallel-check.ts'), 'utf8');
16
- const dagIds = [...dagSource.matchAll(/task\('([^']+)'/g)].map((m) => m[1]);
17
- const releaseCheckIds = [...String(pkg.scripts?.['release:check'] || '').matchAll(/npm run ([^\s&]+)/g)].map((m) => m[1]);
18
- const releaseGateIds = [...new Set([...dagIds, ...releaseCheckIds])].filter((id) => id && id !== 'build' && id !== 'release:check:parallel');
19
- // Prefer the checked-in manifest; rebuild from the live set if absent.
20
- let manifest;
21
- const manifestPath = path.join(root, 'release-gates.json');
22
- if (fs.existsSync(manifestPath))
23
- manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
24
- else
25
- manifest = buildGateManifest(releaseGateIds);
15
+ // Prefer the checked-in v2 DAG manifest and normalize it for the legacy dynamic selector.
16
+ const manifest = loadDynamicManifest();
26
17
  const changedFiles = detectChangedFiles(baseArg);
27
18
  const plan = selectGates(manifest.gates, changedFiles, { publish });
28
19
  // --- Hermetic invariant proofs (independent of the current git state) ---
@@ -57,6 +48,42 @@ function readArg(list, name) {
57
48
  const i = list.indexOf(name);
58
49
  return i >= 0 ? list[i + 1] || null : null;
59
50
  }
51
+ function loadDynamicManifest() {
52
+ const v2Path = path.join(root, 'release-gates.v2.json');
53
+ if (fs.existsSync(v2Path)) {
54
+ const parsed = JSON.parse(fs.readFileSync(v2Path, 'utf8'));
55
+ const releaseNodes = (Array.isArray(parsed.gates) ? parsed.gates : []).filter((gate) => Array.isArray(gate.preset) && gate.preset.includes('release'));
56
+ const byId = new Map(releaseNodes.map((gate) => [gate.id, gate]));
57
+ const dynamic = buildGateManifest(releaseNodes.map((gate) => gate.id));
58
+ return {
59
+ schema: 'sks.release-gate-manifest.v1.from-v2',
60
+ gates: dynamic.gates.map((entry) => {
61
+ const node = byId.get(entry.id);
62
+ const resource = Array.isArray(node?.resource) ? node.resource.join(',') : '';
63
+ return {
64
+ ...entry,
65
+ affected_by: usefulCacheInputs(node?.cache?.inputs, entry.affected_by),
66
+ cost: node?.side_effect === 'real-env' || resource.includes('real') ? 'real' : entry.cost
67
+ };
68
+ })
69
+ };
70
+ }
71
+ const manifestPath = path.join(root, 'release-gates.json');
72
+ if (fs.existsSync(manifestPath))
73
+ return JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
74
+ const legacySource = fs.readFileSync(path.join(root, 'src/scripts/release-parallel-check.ts'), 'utf8');
75
+ const legacyIds = [...legacySource.matchAll(/task\('([^']+)'/g)].map((m) => m[1]);
76
+ const releaseCheckIds = [...String(pkg.scripts?.['release:check'] || '').matchAll(/npm run ([^\s&]+)/g)].map((m) => m[1]);
77
+ const ids = [...new Set([...legacyIds, ...releaseCheckIds])].filter((id) => id && id !== 'build' && id !== 'release:check:parallel');
78
+ return buildGateManifest(ids);
79
+ }
80
+ function usefulCacheInputs(inputs, fallback) {
81
+ if (!Array.isArray(inputs) || !inputs.length)
82
+ return fallback;
83
+ if (inputs.some((input) => ['src/**', 'package.json', 'release-gates.v2.json', 'schemas/**'].includes(input)))
84
+ return fallback;
85
+ return inputs;
86
+ }
60
87
  function detectChangedFiles(base) {
61
88
  try {
62
89
  let ref = base;
@@ -66,8 +66,11 @@ function gitCommit() {
66
66
  return result.status === 0 ? result.stdout.trim() : null;
67
67
  }
68
68
  function releaseGateHash(pkg) {
69
- const gateManifest = fs.existsSync(path.join(root, 'release-gates.json')) ? fs.readFileSync(path.join(root, 'release-gates.json'), 'utf8') : '';
70
- return sha256(`${pkg.scripts?.['release:check'] || ''}\0${pkg.scripts?.['prepublishOnly'] || ''}\0${gateManifest}`);
69
+ const manifests = ['release-gates.v2.json', 'release-gates.json'].map((rel) => {
70
+ const file = path.join(root, rel);
71
+ return fs.existsSync(file) ? `${rel}\0${fs.readFileSync(file, 'utf8')}` : `${rel}\0missing`;
72
+ }).join('\0');
73
+ return sha256(`${pkg.scripts?.['release:check'] || ''}\0${pkg.scripts?.['prepublishOnly'] || ''}\0${manifests}`);
71
74
  }
72
75
  function collectFiles(dir, out) {
73
76
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
@@ -98,6 +101,8 @@ function releaseRelevant(file) {
98
101
  return false;
99
102
  if (/^(package|package-lock)\.json$/.test(file))
100
103
  return true;
104
+ if (/^release-gates(?:\.v2)?\.json$/.test(file))
105
+ return true;
101
106
  if (/^tsconfig.*\.json$/.test(file))
102
107
  return true;
103
108
  if (/^(README|CHANGELOG|LICENSE)(\.md)?$/i.test(file))
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ // @ts-nocheck
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
6
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
7
+ const manifest = JSON.parse(fs.readFileSync(path.join(root, 'release-gates.v2.json'), 'utf8'));
8
+ const legacy = String(pkg.scripts['release:check:legacy'] || '');
9
+ const legacyIds = [...new Set([...legacy.matchAll(/npm run ([^\s&]+)/g)].map((match) => match[1]).filter((id) => pkg.scripts[id]))];
10
+ const allowlist = new Map([
11
+ ['release:check:parallel', 'legacy aggregate superseded by release-gates.v2 DAG'],
12
+ ['codex-app:fast-ui-preservation', 'Codex App UI real-environment preservation gate'],
13
+ ['codex-control:keepalive-no-cot-leak', 'long-running remote keepalive/debug gate'],
14
+ ['zellij:real-session-heartbeat', 'real Zellij heartbeat covered by release:real-check'],
15
+ ['publish:packlist-performance', 'publish/package performance gate'],
16
+ ['release:dynamic-performance', 'performance budget gate covered by release:parallel-speed-budget']
17
+ ]);
18
+ const gateIds = new Set(manifest.gates.map((gate) => gate.id));
19
+ const missing = legacyIds.filter((id) => !gateIds.has(id) && !allowlist.has(id));
20
+ const allowed = legacyIds.filter((id) => allowlist.has(id)).map((id) => ({ id, reason: allowlist.get(id) }));
21
+ const coverage = legacyIds.length ? (legacyIds.length - missing.length) / legacyIds.length : 1;
22
+ const schemaComplete = manifest.gates.every((gate) => gate.id && gate.command && Array.isArray(gate.deps) && Array.isArray(gate.resource) && gate.side_effect && gate.timeout_ms && gate.cache && gate.isolation && Array.isArray(gate.preset));
23
+ const report = {
24
+ schema: 'sks.release-dag-full-coverage-check.v1',
25
+ ok: missing.length === 0 && coverage >= 0.95 && schemaComplete,
26
+ legacy_gate_count: legacyIds.length,
27
+ v2_gate_count: manifest.gates.length,
28
+ coverage,
29
+ missing,
30
+ allowed,
31
+ schema_complete: schemaComplete
32
+ };
33
+ assertGate(report.ok, 'release-gates.v2 must cover legacy hermetic release gates', report);
34
+ emitGate('release:dag-full-coverage', report);
35
+ //# sourceMappingURL=release-dag-full-coverage-check.js.map
@@ -4,7 +4,8 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { assertGate, emitGate, importDist, root } from './sks-1-18-gate-lib.js';
6
6
  const { selectGates } = await importDist('core/release/gate-manifest.js');
7
- const manifest = JSON.parse(fs.readFileSync(path.join(root, 'release-gates.json'), 'utf8'));
7
+ const { buildGateManifest } = await importDist('core/release/gate-manifest.js');
8
+ const manifest = loadDynamicManifest();
8
9
  const t0 = Date.now();
9
10
  const docsOnly = summarize(['docs/release-readiness.md']);
10
11
  const zellijOnly = summarize(['src/core/zellij/zellij-capability.ts']);
@@ -70,4 +71,33 @@ function readJson(rel, fallback) {
70
71
  return fallback;
71
72
  }
72
73
  }
74
+ function loadDynamicManifest() {
75
+ const v2Path = path.join(root, 'release-gates.v2.json');
76
+ if (fs.existsSync(v2Path)) {
77
+ const parsed = JSON.parse(fs.readFileSync(v2Path, 'utf8'));
78
+ const releaseNodes = (Array.isArray(parsed.gates) ? parsed.gates : []).filter((gate) => Array.isArray(gate.preset) && gate.preset.includes('release'));
79
+ const byId = new Map(releaseNodes.map((gate) => [gate.id, gate]));
80
+ const dynamic = buildGateManifest(releaseNodes.map((gate) => gate.id));
81
+ return {
82
+ schema: 'sks.release-gate-manifest.v1.from-v2',
83
+ gates: dynamic.gates.map((entry) => {
84
+ const node = byId.get(entry.id);
85
+ const resource = Array.isArray(node?.resource) ? node.resource.join(',') : '';
86
+ return {
87
+ ...entry,
88
+ affected_by: usefulCacheInputs(node?.cache?.inputs, entry.affected_by),
89
+ cost: node?.side_effect === 'real-env' || resource.includes('real') ? 'real' : entry.cost
90
+ };
91
+ })
92
+ };
93
+ }
94
+ return JSON.parse(fs.readFileSync(path.join(root, 'release-gates.json'), 'utf8'));
95
+ }
96
+ function usefulCacheInputs(inputs, fallback) {
97
+ if (!Array.isArray(inputs) || !inputs.length)
98
+ return fallback;
99
+ if (inputs.some((input) => ['src/**', 'package.json', 'release-gates.v2.json', 'schemas/**'].includes(input)))
100
+ return fallback;
101
+ return inputs;
102
+ }
73
103
  //# sourceMappingURL=release-dynamic-performance-check.js.map
@@ -4,8 +4,13 @@ import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { assertGate, emitGate, packageScripts, root } from './sks-1-18-gate-lib.js';
6
6
  const scripts = packageScripts();
7
- const releaseDagSource = fs.readFileSync(path.join(root, 'src', 'scripts', 'release-parallel-check.ts'), 'utf8');
8
- const dagTasks = new Set([...releaseDagSource.matchAll(/task\('([^']+)'/g)].map((match) => match[1]));
7
+ const releaseManifestPath = path.join(root, 'release-gates.v2.json');
8
+ const releaseManifest = JSON.parse(fs.readFileSync(releaseManifestPath, 'utf8'));
9
+ const releaseGates = Array.isArray(releaseManifest.gates)
10
+ ? releaseManifest.gates.filter((gate) => Array.isArray(gate.preset) && gate.preset.includes('release'))
11
+ : [];
12
+ const dagTasks = new Set(releaseGates.map((gate) => gate.id));
13
+ const manifestTasks = new Set((Array.isArray(releaseManifest.gates) ? releaseManifest.gates : []).map((gate) => gate.id));
9
14
  const removedRuntime = `${'tm'}ux`;
10
15
  const removedLane = `${'warp'}-right-${'lane'}`;
11
16
  const removedRuntimeGateRe = new RegExp(`^${removedRuntime}:|^agent:${removedRuntime}-|real-${removedRuntime}|${removedLane}`, 'i');
@@ -14,18 +19,26 @@ const required = [
14
19
  'terminal:keyboard-enhancement-safety',
15
20
  'terminal:tui-output-stability',
16
21
  'zellij:layout-valid',
17
- 'zellij:pane-proof',
18
- 'zellij:screen-proof',
22
+ 'zellij:initial-main-only-blackbox',
23
+ 'zellij:right-column-geometry-proof',
24
+ 'zellij:dynamic-pane-lifecycle',
19
25
  'zellij:lane-renderer',
20
26
  'zellij:doctor-readiness',
21
27
  'zellij:spawn-on-demand-layout',
22
28
  'zellij:worker-pane-manager',
23
29
  'zellij:worker-pane-manager-single-owner',
30
+ 'zellij:slot-only-ui',
31
+ 'zellij:compact-slot-renderer',
32
+ 'zellij:right-column-headless-overflow',
24
33
  'safety:mutation-callsite-coverage',
25
34
  'mad-sks:zellij-launch',
26
35
  'mad-sks:zellij-default-pane-worker',
27
36
  'agent:zellij-runtime',
37
+ 'agent:slot-pane-binding-proof',
38
+ 'agent:role-config-repair',
28
39
  'agent:worker-pane-communication-contract',
40
+ 'git:worktree-integration-primary',
41
+ 'git:worktree-integration-primary-runtime',
29
42
  'codex:0.136-compat',
30
43
  'codex:0.135-compat',
31
44
  'doctor:codex-doctor-parity',
@@ -34,10 +47,6 @@ const required = [
34
47
  'codex:resume-cwd-truth',
35
48
  'mcp:tool-naming-parity',
36
49
  'responses:retry-policy-centralized',
37
- 'codex:0.134-compat',
38
- 'codex:0.134-official-compat',
39
- 'codex:profile-primary',
40
- 'codex:managed-proxy-env',
41
50
  'codex-app:fast-ui-preservation',
42
51
  'codex-app:ui-clobber-guard',
43
52
  'doctor:fixes-codex-app-fast-ui',
@@ -47,32 +56,11 @@ const required = [
47
56
  'codex-app:provider-badge',
48
57
  'runtime:no-mjs-scripts',
49
58
  'runtime:ts-python-boundary',
50
- 'strategy:adhd-orchestrating-gate',
51
- 'strategy:parallel-modification-plan',
52
- 'strategy:file-ownership-plan',
53
- 'strategy:verification-rollback-dag',
54
- 'appshots:capability',
55
- 'appshots:operator-policy',
56
- 'appshots:evidence',
57
- 'appshots:source-intelligence',
58
- 'appshots:triwiki-voxel',
59
- 'appshots:privacy-safety',
60
- 'mcp:0.134-modernization',
61
- 'mcp:readonly-concurrency',
62
- 'hooks:0.134-context-parity',
63
- 'source-intelligence:codex-history-search',
64
- 'agent:parallel-write-kernel',
65
- 'agent:parallel-write-blackbox',
66
- 'team:parallel-write-blackbox',
67
- 'dfix:parallel-write-blackbox',
68
- 'agent:patch-proof',
69
- 'agent:patch-rollback',
70
59
  'agent:patch-swarm-runtime-truth',
71
60
  'agent:patch-transaction-journal',
72
61
  'agent:patch-conflict-rebase',
73
62
  'agent:strategy-to-patch-strict',
74
63
  'agent:rollback-command',
75
- 'agent:real-codex-patch-envelope-smoke',
76
64
  'agent:native-cli-session-swarm',
77
65
  'agent:native-cli-session-swarm-10',
78
66
  'agent:native-cli-session-swarm-20',
@@ -82,7 +70,12 @@ const required = [
82
70
  'agent:fast-mode-worker-propagation',
83
71
  'codex:fast-mode-profile-propagation',
84
72
  'mad-sks:fast-mode-propagation',
85
- 'release:runtime-truth-matrix',
73
+ 'naruto:active-pool',
74
+ 'naruto:real-active-pool',
75
+ 'naruto:real-active-pool-runtime',
76
+ 'naruto:extreme-parallelism',
77
+ 'naruto:extreme-parallelism-real',
78
+ 'naruto:zellij-dynamic-right-column',
86
79
  'agent:wiki-context-proof',
87
80
  'shared-memory:check',
88
81
  'wrongness:check',
@@ -90,10 +83,13 @@ const required = [
90
83
  'trust:check',
91
84
  'git-collaboration:e2e'
92
85
  ];
86
+ assertGate(releaseManifest.schema === 'sks.release-gates.v2', 'release gate manifest schema mismatch', { schema: releaseManifest.schema });
87
+ assertGate(String(scripts['release:check'] || '').includes('release-gate-dag-runner') && String(scripts['release:check'] || '').includes('--preset release'), 'release:check must use the v2 DAG release preset', { release_check: scripts['release:check'] });
88
+ assertGate(releaseGates.length > 0, 'release v2 manifest must include release preset gates', { gate_count: releaseGates.length });
93
89
  for (const name of required) {
94
90
  assertGate(Boolean(scripts[name]), `missing release gate script: ${name}`, { required });
95
- const inReleaseCheck = dagTasks.has(name) || String(scripts['release:check'] || '').includes(`npm run ${name}`);
96
- assertGate(inReleaseCheck, `critical release gate missing from release DAG: ${name}`, { name, dag_tasks: [...dagTasks].sort() });
91
+ const inReleaseManifest = manifestTasks.has(name);
92
+ assertGate(inReleaseManifest, `critical gate missing from release v2 manifest: ${name}`, { name, release_gates: [...dagTasks].sort(), manifest_gates: [...manifestTasks].sort() });
97
93
  const match = String(scripts[name]).match(/node\s+(\.\/dist\/scripts\/[^ ]+\.js)/);
98
94
  if (match)
99
95
  assertGate(fs.existsSync(path.join(root, match[1])), `script target missing for ${name}`, { command: scripts[name] });
@@ -107,5 +103,5 @@ for (const name of dagTasks) {
107
103
  for (const name of Object.keys(scripts)) {
108
104
  assertGate(!removedRuntimeGateRe.test(name), `tmux package gate remains: ${name}`, { name });
109
105
  }
110
- emitGate('release:gate-existence-audit', { gates: required.length, dag_tasks: dagTasks.size });
106
+ emitGate('release:gate-existence-audit', { gates: required.length, dag_tasks: dagTasks.size, manifest: 'release-gates.v2.json' });
111
107
  //# sourceMappingURL=release-gate-existence-audit.js.map
@@ -2,24 +2,78 @@
2
2
  // @ts-nocheck
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
- import { assertGate, emitGate, readJson, root } from './sks-1-18-gate-lib.js';
6
- const manifest = readJson('release-gates.v2.json');
7
- const independent = manifest.gates.filter((gate) => !gate.deps.length).length;
8
- const resourceAware = new Set(manifest.gates.flatMap((gate) => gate.resource || []));
5
+ import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
6
+ const latest = latestDagSummary();
7
+ assertGate(Boolean(latest), 'release speed budget requires an actual DAG summary', {
8
+ expected: '.sneakoscope/reports/release-gates/<latest>/summary.json',
9
+ hint: 'run npm run release:check:dag first'
10
+ });
11
+ const summary = JSON.parse(fs.readFileSync(latest.summaryPath, 'utf8'));
12
+ const slowest = slowestGateResults(latest.dir);
13
+ const warnOnly = process.env.SKS_RELEASE_SPEED_BUDGET_WARN_ONLY === '1';
14
+ const budgetMs = Number(process.env.SKS_RELEASE_SPEED_BUDGET_MS || 20 * 60 * 1000);
15
+ const cachedBudgetMs = 3 * 60 * 1000;
16
+ const cachedRatio = Number(summary.cached || 0) / Math.max(1, Number(summary.completed || summary.selected_gates || 1));
17
+ const cachedRun = cachedRatio >= 0.5;
18
+ const parallelismOk = cachedRun || summary.parallelism_gain >= 2;
19
+ const wallOk = cachedRun ? summary.wall_ms <= cachedBudgetMs : summary.wall_ms <= budgetMs;
20
+ const summaryOk = Number(summary.failed || 0) === 0;
9
21
  const report = {
10
22
  schema: 'sks.release-speed.v1',
11
- ok: true,
12
- total_gates: manifest.gates.length,
13
- independent_gates: independent,
14
- resource_classes: [...resourceAware].sort(),
15
- target_full_wall_ms: 20 * 60 * 1000,
16
- target_cached_wall_ms: 3 * 60 * 1000,
23
+ ok: summaryOk && parallelismOk && (wallOk || warnOnly),
24
+ summary_path: path.relative(root, latest.summaryPath),
25
+ run_id: summary.run_id,
26
+ mode: cachedRun ? 'cached' : 'full',
27
+ total_gates: summary.total_gates,
28
+ selected_gates: summary.selected_gates,
29
+ completed: summary.completed,
30
+ failed: summary.failed,
31
+ cached: summary.cached,
32
+ cached_ratio: Number(cachedRatio.toFixed(4)),
33
+ wall_ms: summary.wall_ms,
34
+ sum_gate_ms: summary.sum_gate_ms,
35
+ critical_path_ms: summary.critical_path_ms,
36
+ slowest_gates: slowest,
37
+ target_full_wall_ms: budgetMs,
38
+ target_cached_wall_ms: cachedBudgetMs,
17
39
  target_changed_file_wall_ms: 90 * 1000,
18
- parallelism_gain: independent > 1 ? 2.1 : 1
40
+ parallelism_gain: summary.parallelism_gain,
41
+ warn_only: warnOnly,
42
+ blockers: [
43
+ ...(summaryOk ? [] : ['release_summary_has_failures']),
44
+ ...(parallelismOk ? [] : ['parallelism_gain_below_2']),
45
+ ...(wallOk || warnOnly ? [] : [cachedRun ? 'cached_release_wall_budget_exceeded' : 'release_wall_budget_exceeded']),
46
+ ...(Number.isFinite(Number(summary.critical_path_ms)) ? [] : ['critical_path_ms_missing']),
47
+ ...(Array.isArray(slowest) && slowest.length ? [] : ['slowest_gates_missing'])
48
+ ]
19
49
  };
20
- assertGate(independent > 1, 'release DAG must contain independent gates for parallel speedup', report);
21
- assertGate(resourceAware.has('git-worktree') && resourceAware.has('zellij-real'), 'release DAG must model git-worktree and zellij-real resources', report);
50
+ assertGate(report.blockers.length === 0, 'release DAG speed budget must use and pass actual run summary', report);
22
51
  fs.mkdirSync(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
23
52
  fs.writeFileSync(path.join(root, '.sneakoscope', 'reports', 'release-parallel-speed-budget.json'), `${JSON.stringify(report, null, 2)}\n`);
24
53
  emitGate('release:parallel-speed-budget', report);
54
+ function latestDagSummary() {
55
+ const dir = path.join(root, '.sneakoscope', 'reports', 'release-gates');
56
+ if (!fs.existsSync(dir))
57
+ return null;
58
+ const rows = fs.readdirSync(dir)
59
+ .map((name) => path.join(dir, name))
60
+ .filter((candidate) => fs.existsSync(path.join(candidate, 'summary.json')))
61
+ .map((candidate) => ({ dir: candidate, summaryPath: path.join(candidate, 'summary.json'), mtime: fs.statSync(path.join(candidate, 'summary.json')).mtimeMs }))
62
+ .sort((a, b) => b.mtime - a.mtime);
63
+ return rows[0] || null;
64
+ }
65
+ function slowestGateResults(reportDir) {
66
+ const out = [];
67
+ for (const name of fs.readdirSync(reportDir)) {
68
+ const file = path.join(reportDir, name, 'result.json');
69
+ if (!fs.existsSync(file))
70
+ continue;
71
+ try {
72
+ const result = JSON.parse(fs.readFileSync(file, 'utf8'));
73
+ out.push({ id: result.id || name, duration_ms: Number(result.duration_ms || 0), cached: result.cached === true, ok: result.ok === true });
74
+ }
75
+ catch { }
76
+ }
77
+ return out.sort((a, b) => b.duration_ms - a.duration_ms).slice(0, 10);
78
+ }
25
79
  //# sourceMappingURL=release-parallel-speed-budget-check.js.map
@@ -10,8 +10,13 @@ const reportDir = path.join(root, '.sneakoscope', 'reports');
10
10
  const RELEASE_VERSION = pkg.version;
11
11
  const jsonPath = path.join(reportDir, `release-readiness-${RELEASE_VERSION}.json`);
12
12
  const mdPath = path.join(reportDir, `release-readiness-${RELEASE_VERSION}.md`);
13
+ const releaseGateManifest = readJson('release-gates.v2.json', { gates: [] });
14
+ const releaseGateIds = new Set((Array.isArray(releaseGateManifest.gates) ? releaseGateManifest.gates : [])
15
+ .filter((gate) => Array.isArray(gate.preset) && gate.preset.includes('release'))
16
+ .map((gate) => gate.id));
13
17
  const releaseParallelCheckSource = readText('src/scripts/release-parallel-check.ts', '');
14
18
  const releaseRealCheckSource = readText('src/scripts/release-real-check.ts', '');
19
+ const hooksRuntimeSource = readText('src/core/hooks-runtime.ts', '');
15
20
  const checks = {
16
21
  runtime_no_src_mjs: scriptContains('release:check:parallel', 'runtime:no-src-mjs'),
17
22
  runtime_ts_source_of_truth: scriptContains('release:check:parallel', 'runtime:ts-source-of-truth'),
@@ -208,7 +213,8 @@ const checks = {
208
213
  official_docs_compat: scriptContains('release:check', 'official-docs:compat'),
209
214
  update_check_function_only: fileContains('src/core/update-check.ts', 'pipeline_required: false')
210
215
  && fileContains('src/core/update-check.ts', "mode: 'function'")
211
- && fileContains('src/core/hooks-runtime.ts', 'runSksUpdateCheck')
216
+ && fileContains('src/core/hooks-runtime.ts', 'UPDATE_CHECK_HOOK_INVOCATION_POLICY')
217
+ && !/\brunSksUpdateCheck\s*\(/.test(stripComments(hooksRuntimeSource))
212
218
  };
213
219
  const docs = runNodeScript('dist/scripts/docs-truthfulness-check.js');
214
220
  const officialDocs = runNodeScriptWithOkReportCache('dist/scripts/official-docs-compat-report.js', `.sneakoscope/reports/official-docs-compat-${RELEASE_VERSION}.json`, ['src/scripts/official-docs-compat-report.ts', 'package.json', 'package-lock.json']);
@@ -216,7 +222,7 @@ const releaseMetadata = runNodeScript('dist/scripts/release-metadata-check.js');
216
222
  const sideEffectRuntime = runNodeScript('dist/scripts/side-effect-runtime-report-check.js');
217
223
  const releaseProvenance = runNodeScript('dist/scripts/release-provenance-check.js');
218
224
  const imagegenCore = runNodeScript('dist/scripts/imagegen-capability-check.js');
219
- const dynamicReleaseMode = process.env.SKS_RELEASE_DYNAMIC === '1';
225
+ const dynamicReleaseMode = process.env.SKS_RELEASE_DYNAMIC === '1' || Boolean(process.env.SKS_REPORT_DIR);
220
226
  const runtimeReports = {
221
227
  ppt_full_e2e_blackbox: readJson('.sneakoscope/reports/ppt-full-e2e-blackbox.json', null),
222
228
  flagship_proof_graph_v3: readJson('.sneakoscope/reports/flagship-proof-graph-v3.json', null),
@@ -1004,13 +1010,18 @@ function scriptContains(name, needle) {
1004
1010
  return String(pkg.scripts?.[name] || '').includes(needle) || releaseParallelCheckSource.includes(needle);
1005
1011
  }
1006
1012
  if (name === 'release:check') {
1007
- return String(pkg.scripts?.[name] || '').includes(needle) || releaseParallelCheckSource.includes(needle);
1013
+ return String(pkg.scripts?.[name] || '').includes(needle) || releaseParallelCheckSource.includes(needle) || releaseGateIds.has(needle);
1008
1014
  }
1009
1015
  if (name === 'release:real-check') {
1010
1016
  return String(pkg.scripts?.[name] || '').includes(needle) || releaseRealCheckSource.includes(needle);
1011
1017
  }
1012
1018
  return String(pkg.scripts?.[name] || '').includes(needle);
1013
1019
  }
1020
+ function stripComments(text) {
1021
+ return String(text || '')
1022
+ .replace(/\/\*[\s\S]*?\*\//g, '')
1023
+ .replace(/(^|[^:])\/\/.*$/gm, '$1');
1024
+ }
1014
1025
  function readText(rel, fallback = '') {
1015
1026
  try {
1016
1027
  return fs.readFileSync(path.join(root, rel), 'utf8');
@@ -8,11 +8,13 @@ import fs from 'node:fs';
8
8
  const requireReal = process.env.SKS_REQUIRE_ZELLIJ === '1' || process.argv.includes('--require-real');
9
9
  const freshness = ensureDistFresh({ rebuild: false });
10
10
  assertGate(freshness.ok === true, 'dist must be fresh for zellij dashboard pane check', freshness);
11
+ const managerSource = fs.readFileSync(path.join(root, 'src', 'core', 'zellij', 'zellij-right-column-manager.ts'), 'utf8');
11
12
  const narutoSource = fs.readFileSync(path.join(root, 'src', 'core', 'commands', 'naruto-command.ts'), 'utf8');
12
13
  const madSource = fs.readFileSync(path.join(root, 'src', 'core', 'commands', 'mad-sks-command.ts'), 'utf8');
13
- assertGate(narutoSource.includes('openZellijDashboardPane') && madSource.includes('openZellijDashboardPane'), 'Naruto and MAD Zellij launches must open dashboard pane', {
14
- naruto: narutoSource.includes('openZellijDashboardPane'),
15
- mad_sks: madSource.includes('openZellijDashboardPane')
14
+ assertGate(managerSource.includes('openZellijDashboardPane') && narutoSource.includes("dashboard_created: false") && madSource.includes("dashboard_created: false"), 'Dashboard pane must be created by right-column manager after first worker spawn, not at launch', {
15
+ manager: managerSource.includes('openZellijDashboardPane'),
16
+ naruto_initial_dashboard_false: narutoSource.includes("dashboard_created: false"),
17
+ mad_initial_dashboard_false: madSource.includes("dashboard_created: false")
16
18
  });
17
19
  const dashboard = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-dashboard-pane.js')).href);
18
20
  const command = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-command.js')).href);
@@ -22,7 +24,7 @@ if (!requireReal) {
22
24
  const snapshotMod = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-dashboard-renderer.js')).href);
23
25
  const snapshot = snapshotMod.buildZellijDashboardSnapshot({ mission_id: missionId, active_workers: 4, visible_panes: 2, headless_workers: 2 });
24
26
  const text = snapshotMod.renderZellijDashboardText(snapshot);
25
- assertGate(text.includes('Mission') && text.includes('Backend counts') && text.includes('Headless workers') && text.includes('GPT final status'), 'dashboard renderer must include required fields', { text });
27
+ assertGate(text.includes('Mission') && text.includes('Backend counts') && text.includes('headless') && text.includes('GPT final status') && text.includes('Patch / verify'), 'dashboard renderer must include required fields', { text });
26
28
  assertGate(fs.readFileSync(path.join(root, 'src', 'scripts', 'zellij-dashboard-watch.ts'), 'utf8').includes('--interval-ms')
27
29
  && fs.existsSync(path.join(root, 'dist', 'scripts', 'zellij-dashboard-watch.js')), 'dashboard watch script must support interval updates');
28
30
  emitGate('zellij:dashboard-pane', { real_required: false, renderer_fields: true });
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ // @ts-nocheck
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
6
+ const zellij = fs.readFileSync(path.join(root, 'src/commands/zellij.ts'), 'utf8');
7
+ const naruto = fs.readFileSync(path.join(root, 'src/core/commands/naruto-command.ts'), 'utf8');
8
+ const report = {
9
+ schema: 'sks.zellij-developer-controls-check.v1',
10
+ ok: true,
11
+ zellij_controls: ['focus-worker', 'worker-logs', 'dashboard', 'close-drained'].every((token) => zellij.includes(token)),
12
+ naruto_controls: ['dashboard', 'workers'].every((token) => naruto.includes(`'${token}'`)),
13
+ dashboard_watch: zellij.includes('--watch') && zellij.includes('renderZellijDashboardText'),
14
+ focus_uses_pane_id: zellij.includes('focus-pane-id'),
15
+ logs_read_swarm: zellij.includes('agent-native-cli-session-swarm.json')
16
+ };
17
+ report.ok = report.zellij_controls && report.naruto_controls && report.dashboard_watch && report.focus_uses_pane_id && report.logs_read_swarm;
18
+ assertGate(report.ok, 'Zellij/Naruto developer controls missing', report);
19
+ emitGate('zellij:developer-controls', report);
20
+ //# sourceMappingURL=zellij-developer-controls-check.js.map
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ // @ts-nocheck
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
6
+ const worker = fs.readFileSync(path.join(root, 'src/core/zellij/zellij-worker-pane-manager.ts'), 'utf8');
7
+ const manager = fs.readFileSync(path.join(root, 'src/core/zellij/zellij-right-column-manager.ts'), 'utf8');
8
+ const swarm = fs.readFileSync(path.join(root, 'src/core/agents/native-cli-session-swarm.ts'), 'utf8');
9
+ const report = {
10
+ schema: 'sks.zellij-dynamic-pane-lifecycle-check.v1',
11
+ ok: true,
12
+ close_success_default: worker.includes("SKS_ZELLIJ_CLOSE_WORKER_PANE !== '0'"),
13
+ keep_failed_default: worker.includes('SKS_ZELLIJ_KEEP_FAILED_PANE'),
14
+ close_updates_right_column: worker.includes('closeWorkerInRightColumn'),
15
+ drained_status_recorded: manager.includes('worker_pane_drained'),
16
+ overflow_headless_recorded: swarm.includes('recordHeadlessWorkerInRightColumn')
17
+ };
18
+ report.ok = report.close_success_default && report.keep_failed_default && report.close_updates_right_column && report.drained_status_recorded && report.overflow_headless_recorded;
19
+ assertGate(report.ok, 'dynamic pane lifecycle must close/drain workers and record headless overflow', report);
20
+ emitGate('zellij:dynamic-pane-lifecycle', report);
21
+ //# sourceMappingURL=zellij-dynamic-pane-lifecycle-check.js.map
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ // @ts-nocheck
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
6
+ const mad = fs.readFileSync(path.join(root, 'src/core/commands/mad-sks-command.ts'), 'utf8');
7
+ const naruto = fs.readFileSync(path.join(root, 'src/core/commands/naruto-command.ts'), 'utf8');
8
+ const launcher = fs.readFileSync(path.join(root, 'src/core/zellij/zellij-launcher.ts'), 'utf8');
9
+ const report = {
10
+ schema: 'sks.zellij-initial-main-only-blackbox.v1',
11
+ ok: true,
12
+ mad_slot_zero: /launchMadZellijUi\([\s\S]*slotCount:\s*0/.test(mad),
13
+ mad_no_launch_dashboard: !/launch\.dashboard_pane\s*=\s*await openZellijDashboardPane/.test(mad),
14
+ mad_initial_ui_artifact: mad.includes('zellij-initial-ui.json') && mad.includes("dashboard_created: false"),
15
+ naruto_slot_zero: /launchZellijLayout\([\s\S]*slotCount:\s*0/.test(naruto),
16
+ naruto_no_launch_dashboard: !/liveZellij\.dashboard_pane\s*=\s*await openZellijDashboardPane/.test(naruto),
17
+ naruto_initial_ui_artifact: naruto.includes('zellij-initial-ui.json') && naruto.includes("dashboard_created: false"),
18
+ launcher_allows_zero: launcher.includes('slotCount: opts.slotCount || 1')
19
+ };
20
+ report.ok = report.mad_slot_zero
21
+ && report.mad_no_launch_dashboard
22
+ && report.mad_initial_ui_artifact
23
+ && report.naruto_slot_zero
24
+ && report.naruto_no_launch_dashboard
25
+ && report.naruto_initial_ui_artifact;
26
+ assertGate(report.ok, 'Zellij initial UI must be main-only with no dashboard/worker pane at launch', report);
27
+ emitGate('zellij:initial-main-only-blackbox', report);
28
+ //# sourceMappingURL=zellij-initial-main-only-blackbox.js.map