sneakoscope 2.0.9 → 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 +21 -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/core/agents/agent-orchestrator.js +198 -7
- package/dist/core/agents/agent-role-config.js +92 -0
- package/dist/core/agents/native-cli-session-swarm.js +186 -71
- package/dist/core/commands/naruto-command.js +59 -4
- 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 +35 -2
- package/dist/core/naruto/naruto-concurrency-governor.js +1 -1
- 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/version.js +1 -1
- package/dist/core/zellij/zellij-right-column-manager.js +66 -7
- 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 +38 -8
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- 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/mutation-callsite-coverage-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +1 -1
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
- package/dist/scripts/naruto-real-active-pool-check.js +3 -2
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +29 -2
- package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
- 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-dynamic-performance-check.js +31 -1
- package/dist/scripts/release-gate-existence-audit.js +29 -33
- package/dist/scripts/release-readiness-report.js +13 -2
- package/dist/scripts/zellij-right-column-geometry-proof.js +155 -22
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
- package/dist/scripts/zellij-right-column-manager-check.js +4 -4
- package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/package.json +12 -4
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
7
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
8
|
+
import { decideNarutoConcurrency } from '../core/naruto/naruto-concurrency-governor.js';
|
|
9
|
+
import { runNarutoRealActivePool } from '../core/naruto/naruto-active-pool.js';
|
|
10
|
+
import { collectActualNarutoWorker, spawnActualNarutoWorker } from '../core/naruto/naruto-real-worker-runtime.js';
|
|
11
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 12, totalWorkItems: 24, writeCapable: false, maxActiveWorkers: 6 });
|
|
12
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-real-runtime-'));
|
|
13
|
+
const missionId = `M-naruto-real-runtime-${process.pid}`;
|
|
14
|
+
const governor = decideNarutoConcurrency({
|
|
15
|
+
requestedClones: 12,
|
|
16
|
+
totalWorkItems: graph.total_work_items,
|
|
17
|
+
pendingWorkQueueSize: graph.total_work_items,
|
|
18
|
+
backend: 'codex-sdk',
|
|
19
|
+
hardware: { cores: 8, freeMemoryBytes: 32 * 1024 * 1024 * 1024, totalMemoryBytes: 64 * 1024 * 1024 * 1024, fileDescriptorLimit: 4096, processCount: 100, terminalRows: 40, remoteApiRateLimitBudget: 8 }
|
|
20
|
+
});
|
|
21
|
+
let spawned = 0;
|
|
22
|
+
let collected = 0;
|
|
23
|
+
const target = { ...governor, safe_active_workers: Math.min(6, governor.safe_active_workers), safe_zellij_visible_panes: 3 };
|
|
24
|
+
const report = await runNarutoRealActivePool({
|
|
25
|
+
graph,
|
|
26
|
+
governor: target,
|
|
27
|
+
spawnWorker: async (item, placement) => {
|
|
28
|
+
spawned += 1;
|
|
29
|
+
return spawnActualNarutoWorker({
|
|
30
|
+
root: tempRoot,
|
|
31
|
+
missionId,
|
|
32
|
+
item,
|
|
33
|
+
placement,
|
|
34
|
+
backend: 'codex-sdk',
|
|
35
|
+
visiblePaneCap: target.safe_zellij_visible_panes,
|
|
36
|
+
zellijSessionName: `sks-${missionId}`
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
collectWorker: async (handle) => {
|
|
40
|
+
collected += 1;
|
|
41
|
+
return collectActualNarutoWorker(handle);
|
|
42
|
+
},
|
|
43
|
+
enqueueVerification: async () => undefined,
|
|
44
|
+
updateDashboard: async () => undefined
|
|
45
|
+
});
|
|
46
|
+
const processEvidence = report.worker_lifecycle.every((row) => row.pid && row.worker_artifact_dir);
|
|
47
|
+
const artifactEvidence = report.worker_lifecycle.every((row) => row.worker_artifact_dir
|
|
48
|
+
&& fs.existsSync(path.join(row.worker_artifact_dir, 'worker-heartbeat.jsonl'))
|
|
49
|
+
&& fs.existsSync(path.join(row.worker_artifact_dir, 'worker-result.json')));
|
|
50
|
+
const ok = report.ok && spawned === graph.total_work_items && collected === graph.total_work_items && report.max_observed_active_workers >= target.safe_active_workers && report.active_pool_utilization >= 0.8 && processEvidence && artifactEvidence;
|
|
51
|
+
assertGate(ok, 'Naruto real active pool runtime must include actual child process, heartbeat, and result evidence', { report, spawned, collected, processEvidence, artifactEvidence, tempRoot });
|
|
52
|
+
emitGate('naruto:real-active-pool-runtime', report);
|
|
53
|
+
//# sourceMappingURL=naruto-real-active-pool-runtime-check.js.map
|
|
@@ -2,20 +2,47 @@
|
|
|
2
2
|
// @ts-nocheck
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
5
6
|
import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
|
|
7
|
+
const requireReal = process.argv.includes('--require-real') || process.env.SKS_REQUIRE_ZELLIJ === '1';
|
|
6
8
|
const naruto = fs.readFileSync(path.join(root, 'src/core/commands/naruto-command.ts'), 'utf8');
|
|
7
9
|
const worker = fs.readFileSync(path.join(root, 'src/core/zellij/zellij-worker-pane-manager.ts'), 'utf8');
|
|
8
10
|
const swarm = fs.readFileSync(path.join(root, 'src/core/agents/native-cli-session-swarm.ts'), 'utf8');
|
|
11
|
+
const realGeometryProof = requireReal ? runRealGeometryProof() : null;
|
|
9
12
|
const report = {
|
|
10
13
|
schema: 'sks.naruto-zellij-dynamic-right-column-check.v1',
|
|
11
14
|
ok: true,
|
|
15
|
+
require_real: requireReal,
|
|
12
16
|
initial_main_only: /slotCount:\s*0/.test(naruto),
|
|
13
17
|
passes_session_name: naruto.includes('zellijSessionName: liveZellij?.session_name'),
|
|
14
18
|
passes_worker_placement: naruto.includes("workerPlacement: parsed.json || parsed.noOpenZellij ? 'process' : 'zellij-pane'"),
|
|
15
19
|
passes_visible_cap: naruto.includes('zellijVisiblePaneCap: zellijVisiblePanes'),
|
|
16
|
-
worker_uses_right_column: worker.includes("rightColumnMode: 'spawn-on-first-worker'") || swarm.includes("rightColumnMode: 'spawn-on-first-worker'")
|
|
20
|
+
worker_uses_right_column: worker.includes("rightColumnMode: 'spawn-on-first-worker'") || swarm.includes("rightColumnMode: 'spawn-on-first-worker'"),
|
|
21
|
+
real_geometry_proof: realGeometryProof
|
|
17
22
|
};
|
|
18
|
-
report.ok = report.initial_main_only
|
|
23
|
+
report.ok = report.initial_main_only
|
|
24
|
+
&& report.passes_session_name
|
|
25
|
+
&& report.passes_worker_placement
|
|
26
|
+
&& report.passes_visible_cap
|
|
27
|
+
&& report.worker_uses_right_column
|
|
28
|
+
&& (!requireReal || realGeometryProof?.ok === true);
|
|
19
29
|
assertGate(report.ok, 'Naruto must use dynamic right-column worker panes in interactive mode', report);
|
|
20
30
|
emitGate('naruto:zellij-dynamic-right-column', report);
|
|
31
|
+
function runRealGeometryProof() {
|
|
32
|
+
const res = spawnSync('npm', ['run', 'zellij:right-column-real-geometry', '--silent', '--', '--require-real'], {
|
|
33
|
+
cwd: root,
|
|
34
|
+
env: { ...process.env, SKS_REQUIRE_ZELLIJ: '1' },
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
maxBuffer: 20 * 1024 * 1024
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
ok: res.status === 0,
|
|
40
|
+
exit_code: res.status,
|
|
41
|
+
stdout_tail: tail(res.stdout),
|
|
42
|
+
stderr_tail: tail(res.stderr)
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function tail(text) {
|
|
46
|
+
return String(text || '').split('\n').slice(-30).join('\n');
|
|
47
|
+
}
|
|
21
48
|
//# sourceMappingURL=naruto-zellij-dynamic-right-column-check.js.map
|
|
@@ -5,6 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
7
7
|
import { execFileSync } from 'node:child_process';
|
|
8
|
+
import { writeTextAtomic } from '../core/fsx.js';
|
|
8
9
|
const root = process.cwd();
|
|
9
10
|
const args = process.argv.slice(2);
|
|
10
11
|
const reportPath = path.join(root, '.sneakoscope', 'reports', 'readme-architecture-imagegen-attempt-1.18.8.json');
|
|
@@ -139,12 +140,12 @@ else {
|
|
|
139
140
|
}
|
|
140
141
|
async function ensurePromptContract() {
|
|
141
142
|
if (!promptExistedBeforeRun) {
|
|
142
|
-
await
|
|
143
|
+
await writeTextAtomic(promptPath, prompt);
|
|
143
144
|
return { changed: true, reason: 'created' };
|
|
144
145
|
}
|
|
145
146
|
const existing = await fs.promises.readFile(promptPath, 'utf8').catch(() => null);
|
|
146
147
|
if (existing !== prompt) {
|
|
147
|
-
await
|
|
148
|
+
await writeTextAtomic(promptPath, prompt);
|
|
148
149
|
return { changed: true, reason: 'refreshed_prompt_changed' };
|
|
149
150
|
}
|
|
150
151
|
return { changed: false, reason: 'unchanged' };
|
|
@@ -334,7 +335,7 @@ async function textArtifactMeta(file, promptWrite = null) {
|
|
|
334
335
|
};
|
|
335
336
|
}
|
|
336
337
|
async function writeReport(report) {
|
|
337
|
-
await
|
|
338
|
+
await writeTextAtomic(reportPath, `${JSON.stringify(report, null, 2)}\n`);
|
|
338
339
|
}
|
|
339
340
|
async function sha256File(file) {
|
|
340
341
|
return new Promise((resolve, reject) => {
|
|
@@ -40,7 +40,7 @@ const invariants = {
|
|
|
40
40
|
};
|
|
41
41
|
const distHash = distHashValue();
|
|
42
42
|
const gitCommit = gitHead();
|
|
43
|
-
const manifestHash = fileHash('release-gates.json');
|
|
43
|
+
const manifestHash = fileHash(fs.existsSync(path.join(root, 'release-gates.v2.json')) ? 'release-gates.v2.json' : 'release-gates.json');
|
|
44
44
|
const packageScriptsHash = sha256(JSON.stringify(pkg.scripts || {}));
|
|
45
45
|
const nodeVersion = process.version;
|
|
46
46
|
const npmVersion = npmVersionValue();
|
|
@@ -134,6 +134,25 @@ emitGate('release:check:dynamic:execute', {
|
|
|
134
134
|
});
|
|
135
135
|
// ---- helpers ----------------------------------------------------------------
|
|
136
136
|
function loadManifest() {
|
|
137
|
+
const v2Path = path.join(root, 'release-gates.v2.json');
|
|
138
|
+
if (fs.existsSync(v2Path)) {
|
|
139
|
+
const parsed = JSON.parse(fs.readFileSync(v2Path, 'utf8'));
|
|
140
|
+
const releaseNodes = (Array.isArray(parsed.gates) ? parsed.gates : []).filter((gate) => Array.isArray(gate.preset) && gate.preset.includes('release'));
|
|
141
|
+
const byId = new Map(releaseNodes.map((gate) => [gate.id, gate]));
|
|
142
|
+
const dynamic = buildGateManifest(releaseNodes.map((gate) => gate.id));
|
|
143
|
+
return {
|
|
144
|
+
schema: 'sks.release-gate-manifest.v1.from-v2',
|
|
145
|
+
gates: dynamic.gates.map((entry) => {
|
|
146
|
+
const node = byId.get(entry.id);
|
|
147
|
+
const resource = Array.isArray(node?.resource) ? node.resource.join(',') : '';
|
|
148
|
+
return {
|
|
149
|
+
...entry,
|
|
150
|
+
affected_by: usefulCacheInputs(node?.cache?.inputs, entry.affected_by),
|
|
151
|
+
cost: node?.side_effect === 'real-env' || resource.includes('real') ? 'real' : entry.cost
|
|
152
|
+
};
|
|
153
|
+
})
|
|
154
|
+
};
|
|
155
|
+
}
|
|
137
156
|
const p = path.join(root, 'release-gates.json');
|
|
138
157
|
if (fs.existsSync(p))
|
|
139
158
|
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
@@ -143,6 +162,13 @@ function loadManifest() {
|
|
|
143
162
|
const ids = [...new Set([...dagIds, ...releaseCheckIds])].filter((id) => id && id !== 'build' && id !== 'release:check:parallel');
|
|
144
163
|
return buildGateManifest(ids);
|
|
145
164
|
}
|
|
165
|
+
function usefulCacheInputs(inputs, fallback) {
|
|
166
|
+
if (!Array.isArray(inputs) || !inputs.length)
|
|
167
|
+
return fallback;
|
|
168
|
+
if (inputs.some((input) => ['src/**', 'package.json', 'release-gates.v2.json', 'schemas/**'].includes(input)))
|
|
169
|
+
return fallback;
|
|
170
|
+
return inputs;
|
|
171
|
+
}
|
|
146
172
|
function hashAffectedFiles(globs) {
|
|
147
173
|
const regexes = (globs || []).map(globToRegExp);
|
|
148
174
|
const hashes = [];
|
|
@@ -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))
|
|
@@ -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
|
|
@@ -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']);
|
|
@@ -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');
|