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.
- package/README.md +8 -4
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/build-manifest.json +33 -8
- package/dist/cli/command-registry.js +1 -0
- package/dist/commands/doctor.js +18 -1
- package/dist/commands/zellij-slot-pane.js +26 -0
- package/dist/commands/zellij.js +144 -1
- package/dist/core/agents/agent-orchestrator.js +202 -9
- package/dist/core/agents/agent-role-config.js +92 -0
- package/dist/core/agents/native-cli-session-swarm.js +230 -48
- package/dist/core/commands/mad-sks-command.js +17 -26
- package/dist/core/commands/naruto-command.js +155 -37
- package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +4 -0
- package/dist/core/init.js +1 -0
- package/dist/core/naruto/naruto-active-pool.js +141 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +17 -2
- package/dist/core/naruto/naruto-real-worker-child.js +35 -0
- package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
- package/dist/core/naruto/naruto-work-graph.js +2 -1
- package/dist/core/release/release-gate-cache-v2.js +58 -4
- package/dist/core/release/release-gate-dag.js +36 -25
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-dashboard-renderer.js +22 -6
- package/dist/core/zellij/zellij-launcher.js +3 -3
- package/dist/core/zellij/zellij-layout-builder.js +1 -1
- package/dist/core/zellij/zellij-right-column-layout-proof.js +42 -0
- package/dist/core/zellij/zellij-right-column-manager.js +304 -0
- package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
- package/dist/core/zellij/zellij-ui-mode.js +16 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +152 -17
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- package/dist/scripts/codex-sdk-release-review-pipeline-check.js +5 -5
- package/dist/scripts/doctor-fix-proves-codex-read-check.js +26 -5
- package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
- package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
- package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
- package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +2 -2
- package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
- package/dist/scripts/naruto-concurrency-governor-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
- package/dist/scripts/naruto-real-active-pool-check.js +39 -0
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
- package/dist/scripts/naruto-work-graph-check.js +1 -1
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +48 -0
- package/dist/scripts/product-design-auto-install-check.js +3 -3
- package/dist/scripts/product-design-plugin-routing-check.js +3 -3
- package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
- package/dist/scripts/release-cache-glob-hashing-check.js +42 -0
- package/dist/scripts/release-check-dynamic-execute.js +27 -1
- package/dist/scripts/release-check-dynamic.js +38 -11
- package/dist/scripts/release-check-stamp.js +7 -2
- package/dist/scripts/release-dag-full-coverage-check.js +35 -0
- package/dist/scripts/release-dynamic-performance-check.js +31 -1
- package/dist/scripts/release-gate-existence-audit.js +29 -33
- package/dist/scripts/release-parallel-speed-budget-check.js +67 -13
- package/dist/scripts/release-readiness-report.js +14 -3
- package/dist/scripts/zellij-dashboard-pane-check.js +6 -4
- package/dist/scripts/zellij-developer-controls-check.js +20 -0
- package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +21 -0
- package/dist/scripts/zellij-initial-main-only-blackbox.js +28 -0
- package/dist/scripts/zellij-right-column-geometry-proof.js +162 -0
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
- package/dist/scripts/zellij-right-column-manager-check.js +22 -0
- package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +2 -1
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +7 -6
- package/package.json +23 -5
- 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
|
-
|
|
16
|
-
const
|
|
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
|
|
70
|
-
|
|
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
|
|
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
|
|
8
|
-
const
|
|
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:
|
|
18
|
-
'zellij:
|
|
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
|
-
'
|
|
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
|
|
96
|
-
assertGate(
|
|
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,
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
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:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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:
|
|
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(
|
|
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', '
|
|
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(
|
|
14
|
-
|
|
15
|
-
|
|
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('
|
|
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
|