sneakoscope 2.0.7 → 2.0.9
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 +1 -1
- 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 +44 -8
- package/dist/commands/zellij.js +144 -1
- package/dist/core/agents/agent-command-surface.js +4 -2
- package/dist/core/agents/agent-orchestrator.js +5 -2
- package/dist/core/agents/agent-patch-schema.js +4 -2
- package/dist/core/agents/native-cli-session-swarm.js +81 -9
- package/dist/core/commands/mad-sks-command.js +17 -1
- package/dist/core/commands/naruto-command.js +99 -7
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-repo-detection.js +7 -0
- package/dist/core/git/git-worktree-cleanup.js +14 -3
- package/dist/core/git/git-worktree-diff.js +7 -2
- package/dist/core/git/git-worktree-manager.js +9 -2
- package/dist/core/git/git-worktree-patch-envelope.js +5 -5
- package/dist/core/naruto/naruto-active-pool.js +108 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +16 -1
- package/dist/core/naruto/naruto-work-graph.js +2 -1
- package/dist/core/release/release-gate-cache-v2.js +117 -0
- package/dist/core/release/release-gate-dag.js +190 -0
- package/dist/core/release/release-gate-hermetic-env.js +32 -0
- package/dist/core/release/release-gate-node.js +62 -0
- package/dist/core/release/release-gate-report.js +11 -0
- package/dist/core/release/release-gate-resource-governor.js +54 -0
- package/dist/core/release/release-gate-scheduler.js +15 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-dashboard-pane.js +71 -0
- package/dist/core/zellij/zellij-dashboard-renderer.js +58 -0
- 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 +245 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +180 -15
- 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-diff-envelope-check.js +17 -0
- package/dist/scripts/git-worktree-dirty-lock-check.js +17 -0
- package/dist/scripts/git-worktree-dirty-main-detection-check.js +14 -0
- package/dist/scripts/git-worktree-integration-primary-check.js +22 -0
- package/dist/scripts/git-worktree-manifest-append-check.js +18 -0
- package/dist/scripts/git-worktree-untracked-diff-check.js +18 -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/naruto-concurrency-governor-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
- package/dist/scripts/naruto-real-active-pool-check.js +38 -0
- package/dist/scripts/naruto-work-graph-check.js +1 -1
- package/dist/scripts/naruto-worktree-coding-blackbox.js +29 -0
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +21 -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/release-cache-glob-hashing-check.js +42 -0
- package/dist/scripts/release-dag-full-coverage-check.js +35 -0
- package/dist/scripts/release-gate-dag-runner-check.js +17 -0
- package/dist/scripts/release-gate-dag-runner.js +32 -0
- package/dist/scripts/release-gate-worker.js +10 -0
- package/dist/scripts/release-metadata-1-19-check.js +8 -2
- package/dist/scripts/release-parallel-speed-budget-check.js +79 -0
- package/dist/scripts/release-readiness-report.js +1 -1
- package/dist/scripts/release-stability-report-check.js +99 -0
- package/dist/scripts/zellij-dashboard-pane-check.js +70 -0
- package/dist/scripts/zellij-dashboard-watch.js +41 -0
- 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 +29 -0
- package/dist/scripts/zellij-right-column-manager-check.js +22 -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/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +185 -0
- package/package.json +32 -5
- package/schemas/release/release-gate-node.schema.json +52 -0
- package/schemas/zellij/zellij-right-column-state.schema.json +41 -0
|
@@ -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 naruto = fs.readFileSync(path.join(root, 'src/core/commands/naruto-command.ts'), 'utf8');
|
|
7
|
+
const worker = fs.readFileSync(path.join(root, 'src/core/zellij/zellij-worker-pane-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.naruto-zellij-dynamic-right-column-check.v1',
|
|
11
|
+
ok: true,
|
|
12
|
+
initial_main_only: /slotCount:\s*0/.test(naruto),
|
|
13
|
+
passes_session_name: naruto.includes('zellijSessionName: liveZellij?.session_name'),
|
|
14
|
+
passes_worker_placement: naruto.includes("workerPlacement: parsed.json || parsed.noOpenZellij ? 'process' : 'zellij-pane'"),
|
|
15
|
+
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'")
|
|
17
|
+
};
|
|
18
|
+
report.ok = report.initial_main_only && report.passes_session_name && report.passes_worker_placement && report.passes_visible_cap && report.worker_uses_right_column;
|
|
19
|
+
assertGate(report.ok, 'Naruto must use dynamic right-column worker panes in interactive mode', report);
|
|
20
|
+
emitGate('naruto:zellij-dynamic-right-column', report);
|
|
21
|
+
//# sourceMappingURL=naruto-zellij-dynamic-right-column-check.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @ts-nocheck
|
|
3
3
|
import { ensureProductDesignPluginInstalledWithRequest, findProductDesignPluginSummaryFromMarketplaces, productDesignAutoInstallRequested } from '../core/product-design-app-server.js';
|
|
4
4
|
import { PRODUCT_DESIGN_PLUGIN, PRODUCT_DESIGN_REQUIRED_SKILLS } from '../core/product-design-plugin.js';
|
|
5
|
-
import { assertGate, emitGate, readText } from './lib/codex-sdk-gate-lib.js';
|
|
5
|
+
import { assertGate, emitGate, readText, releaseGateIds } from './lib/codex-sdk-gate-lib.js';
|
|
6
6
|
function pluginReadResponse({ installed, enabled }) {
|
|
7
7
|
return {
|
|
8
8
|
plugin: {
|
|
@@ -92,7 +92,7 @@ const codexAppSource = readText('src/core/codex-app.ts');
|
|
|
92
92
|
const commandSource = readText('src/commands/codex-app.ts');
|
|
93
93
|
const appServerSource = readText('src/core/product-design-app-server.ts');
|
|
94
94
|
const pkg = JSON.parse(readText('package.json'));
|
|
95
|
-
const
|
|
95
|
+
const releaseGates = releaseGateIds();
|
|
96
96
|
for (const token of [
|
|
97
97
|
'ensureProductDesignPluginInstalled',
|
|
98
98
|
'PRODUCT_DESIGN_AUTO_INSTALL_ENV',
|
|
@@ -109,7 +109,7 @@ for (const token of [
|
|
|
109
109
|
assertGate(commandSource.includes(token), `sks codex-app command missing Product Design token: ${token}`);
|
|
110
110
|
}
|
|
111
111
|
assertGate(Boolean(pkg.scripts?.['codex:product-design-auto-install']), 'package script missing codex:product-design-auto-install');
|
|
112
|
-
assertGate(
|
|
112
|
+
assertGate(releaseGates.has('codex:product-design-auto-install'), 'release gate DAG must include Product Design auto-install gate');
|
|
113
113
|
emitGate('codex:product-design-auto-install', {
|
|
114
114
|
install_calls: installCalls.map((call) => call.method),
|
|
115
115
|
dry_calls: dryCalls.map((call) => call.method),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @ts-nocheck
|
|
3
3
|
import { PRODUCT_DESIGN_PIPELINE_STAGES, PRODUCT_DESIGN_PLUGIN, PRODUCT_DESIGN_REQUIRED_SKILLS, normalizeProductDesignPluginEvidence, productDesignPluginVisibilityFromCodexPluginList } from '../core/product-design-plugin.js';
|
|
4
|
-
import { assertGate, emitGate, readText } from './lib/codex-sdk-gate-lib.js';
|
|
4
|
+
import { assertGate, emitGate, readText, releaseGateIds } from './lib/codex-sdk-gate-lib.js';
|
|
5
5
|
const routesSource = readText('src/core/routes.ts');
|
|
6
6
|
const productDesignSource = readText('src/core/product-design-plugin.ts');
|
|
7
7
|
const runtimeSource = readText('src/core/pipeline-internals/runtime-core.ts');
|
|
@@ -9,7 +9,7 @@ const pptSource = readText('src/core/ppt.ts');
|
|
|
9
9
|
const codexAppSource = readText('src/core/codex-app.ts');
|
|
10
10
|
const initSource = readText('src/core/init.ts');
|
|
11
11
|
const pkg = JSON.parse(readText('package.json'));
|
|
12
|
-
const
|
|
12
|
+
const releaseGates = releaseGateIds();
|
|
13
13
|
assertGate(PRODUCT_DESIGN_PLUGIN.id === 'product-design@openai-curated-remote', 'Product Design plugin id must use the remote marketplace');
|
|
14
14
|
assertGate(PRODUCT_DESIGN_PLUGIN.marketplace === 'openai-curated-remote', 'Product Design marketplace must be openai-curated-remote');
|
|
15
15
|
assertGate(PRODUCT_DESIGN_PLUGIN.marketplace_kind === 'vertical', 'Product Design marketplace kind must be vertical');
|
|
@@ -90,7 +90,7 @@ for (const token of [
|
|
|
90
90
|
assertGate(codexAppSource.includes(token), `codex-app.ts missing Product Design readiness token: ${token}`);
|
|
91
91
|
}
|
|
92
92
|
assertGate(Boolean(pkg.scripts?.['codex:product-design-plugin-routing']), 'package script missing codex:product-design-plugin-routing');
|
|
93
|
-
assertGate(
|
|
93
|
+
assertGate(releaseGates.has('codex:product-design-plugin-routing'), 'release gate DAG must include Product Design routing gate');
|
|
94
94
|
emitGate('codex:product-design-plugin-routing', {
|
|
95
95
|
plugin_id: PRODUCT_DESIGN_PLUGIN.id,
|
|
96
96
|
remote_plugin_id: PRODUCT_DESIGN_PLUGIN.remote_plugin_id,
|
|
@@ -0,0 +1,42 @@
|
|
|
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 { expandGlob, releaseGateCacheKey } from '../core/release/release-gate-cache-v2.js';
|
|
8
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-cache-glob-'));
|
|
9
|
+
fs.mkdirSync(path.join(tmp, 'src/core/release'), { recursive: true });
|
|
10
|
+
fs.writeFileSync(path.join(tmp, 'package.json'), JSON.stringify({ version: '0.0.0' }));
|
|
11
|
+
fs.writeFileSync(path.join(tmp, 'release-gates.v2.json'), JSON.stringify({ schema: 'sks.release-gates.v2', gates: [] }));
|
|
12
|
+
fs.writeFileSync(path.join(tmp, 'src/core/release/a.ts'), 'a');
|
|
13
|
+
const gate = {
|
|
14
|
+
id: 'release:cache-glob-hashing-fixture',
|
|
15
|
+
command: 'node fixture',
|
|
16
|
+
deps: [],
|
|
17
|
+
resource: ['cpu-light'],
|
|
18
|
+
side_effect: 'hermetic',
|
|
19
|
+
timeout_ms: 1000,
|
|
20
|
+
cache: { enabled: true, inputs: ['src/core/release/**'] },
|
|
21
|
+
isolation: { home: 'temp', codex_home: 'temp', report_dir: 'per-gate' },
|
|
22
|
+
preset: ['release']
|
|
23
|
+
};
|
|
24
|
+
const before = releaseGateCacheKey(tmp, gate);
|
|
25
|
+
const expandedBefore = expandGlob(tmp, 'src/core/release/**');
|
|
26
|
+
fs.writeFileSync(path.join(tmp, 'src/core/release/b.ts'), 'b');
|
|
27
|
+
const afterAdd = releaseGateCacheKey(tmp, gate);
|
|
28
|
+
fs.writeFileSync(path.join(tmp, 'src/core/release/a.ts'), 'changed');
|
|
29
|
+
const afterChange = releaseGateCacheKey(tmp, gate);
|
|
30
|
+
const expandedAfter = expandGlob(tmp, 'src/core/release/**');
|
|
31
|
+
const report = {
|
|
32
|
+
schema: 'sks.release-cache-glob-hashing-check.v1',
|
|
33
|
+
ok: expandedBefore.length === 1 && expandedAfter.length === 2 && before !== afterAdd && afterAdd !== afterChange,
|
|
34
|
+
expanded_before: expandedBefore.map((file) => path.basename(file)),
|
|
35
|
+
expanded_after: expandedAfter.map((file) => path.basename(file)),
|
|
36
|
+
before,
|
|
37
|
+
after_add: afterAdd,
|
|
38
|
+
after_change: afterChange
|
|
39
|
+
};
|
|
40
|
+
assertGate(report.ok, 'release cache key must hash recursive glob file paths and contents', report);
|
|
41
|
+
emitGate('release:cache-glob-hashing', report);
|
|
42
|
+
//# sourceMappingURL=release-cache-glob-hashing-check.js.map
|
|
@@ -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
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { assertGate, emitGate, readJson, readText } from './sks-1-18-gate-lib.js';
|
|
4
|
+
const pkg = readJson('package.json');
|
|
5
|
+
const manifest = readJson('release-gates.v2.json');
|
|
6
|
+
const runner = readText('src/core/release/release-gate-dag.ts');
|
|
7
|
+
const scheduler = readText('src/core/release/release-gate-scheduler.ts');
|
|
8
|
+
const cache = readText('src/core/release/release-gate-cache-v2.ts');
|
|
9
|
+
assertGate(pkg.scripts['release:check'].includes('release-gate-dag-runner.js'), 'release:check must execute DAG runner', pkg.scripts['release:check']);
|
|
10
|
+
assertGate(!/&&\s*npm run\s+\w/.test(pkg.scripts['release:check'].replace('npm run build --silent &&', '')), 'release:check must not be a giant npm-run chain', pkg.scripts['release:check']);
|
|
11
|
+
assertGate(pkg.scripts['release:check:legacy'], 'release:check:legacy must exist for explicit debugging');
|
|
12
|
+
assertGate(manifest.schema === 'sks.release-gates.v2' && manifest.gates.length >= 10, 'release-gates.v2 manifest must exist with nodes', manifest);
|
|
13
|
+
assertGate(runner.includes('Promise.race') && scheduler.includes('pickLaunchableReleaseGates'), 'DAG runner must schedule independent gates concurrently');
|
|
14
|
+
assertGate(runner.includes('readReleaseGateCacheHit') && cache.includes('RELEASE_GATE_CACHE_V2_SCHEMA'), 'DAG runner must use release gate cache v2 module');
|
|
15
|
+
assertGate(runner.includes('cpu_time_saved_ms') && runner.includes('peak_running') && runner.includes('budget_snapshot'), 'DAG summary must include CPU time saved, peak running gates, and resource budget proof');
|
|
16
|
+
emitGate('release:dag-runner', { gates: manifest.gates.length, default_script: pkg.scripts['release:check'] });
|
|
17
|
+
//# sourceMappingURL=release-gate-dag-runner-check.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { runReleaseGateDag } from '../core/release/release-gate-dag.js';
|
|
5
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
const presetIndex = args.indexOf('--preset');
|
|
8
|
+
const preset = presetIndex >= 0 ? args[presetIndex + 1] : 'release';
|
|
9
|
+
const result = await runReleaseGateDag({
|
|
10
|
+
root,
|
|
11
|
+
...(preset === undefined ? {} : { preset }),
|
|
12
|
+
explain: args.includes('--explain'),
|
|
13
|
+
noCache: args.includes('--no-cache'),
|
|
14
|
+
failFast: args.includes('--fail-fast')
|
|
15
|
+
});
|
|
16
|
+
console.log(`SKS Release DAG
|
|
17
|
+
gates: ${result.total_gates} total, ${result.selected_gates} selected, ${result.cached} cached
|
|
18
|
+
concurrency: ${result.budget_summary}
|
|
19
|
+
peak_running: ${result.peak_running}
|
|
20
|
+
completed: ${result.completed} pass, ${result.failed} fail
|
|
21
|
+
wall: ${(result.wall_ms / 1000).toFixed(1)}s
|
|
22
|
+
parallelism_gain: ${result.parallelism_gain}
|
|
23
|
+
cpu_time_saved: ${(result.cpu_time_saved_ms / 1000).toFixed(1)}s
|
|
24
|
+
critical_path: ${(result.critical_path_ms / 1000).toFixed(1)}s
|
|
25
|
+
report: ${result.report_dir}`);
|
|
26
|
+
if (!result.ok) {
|
|
27
|
+
for (const failure of result.failures) {
|
|
28
|
+
console.error(`[fail] ${failure.id} exit=${failure.exit_code}\n${failure.stderr_tail}`);
|
|
29
|
+
}
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=release-gate-dag-runner.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
const command = process.argv.slice(2).join(' ');
|
|
4
|
+
if (!command) {
|
|
5
|
+
console.error('usage: release-gate-worker <command>');
|
|
6
|
+
process.exit(2);
|
|
7
|
+
}
|
|
8
|
+
const result = spawnSync(command, { shell: true, stdio: 'inherit', env: process.env });
|
|
9
|
+
process.exit(result.status ?? 1);
|
|
10
|
+
//# sourceMappingURL=release-gate-worker.js.map
|
|
@@ -10,6 +10,11 @@ const distManifestPath = path.join(root, 'dist/build-manifest.json');
|
|
|
10
10
|
const distManifest = fs.existsSync(distManifestPath) ? JSON.parse(fs.readFileSync(distManifestPath, 'utf8')) : null;
|
|
11
11
|
const parallelCheckPath = path.join(root, 'src/scripts/release-parallel-check.ts');
|
|
12
12
|
const parallelCheckSource = fs.existsSync(parallelCheckPath) ? fs.readFileSync(parallelCheckPath, 'utf8') : '';
|
|
13
|
+
const releaseCheckScriptSource = [
|
|
14
|
+
String(pkg.scripts?.['release:check'] || ''),
|
|
15
|
+
String(pkg.scripts?.['release:check:legacy'] || ''),
|
|
16
|
+
parallelCheckSource
|
|
17
|
+
].join('\n');
|
|
13
18
|
const releaseRealCheckPath = path.join(root, 'src/scripts/release-real-check.ts');
|
|
14
19
|
const releaseRealCheckSource = fs.existsSync(releaseRealCheckPath) ? fs.readFileSync(releaseRealCheckPath, 'utf8') : '';
|
|
15
20
|
const requiredDocs = [
|
|
@@ -304,13 +309,14 @@ assertGate(distManifest?.version === RELEASE_VERSION, `dist/build-manifest versi
|
|
|
304
309
|
assertGate(distManifest?.package_version === RELEASE_VERSION, `dist/build-manifest package_version must be ${RELEASE_VERSION}`, { package_version: distManifest?.package_version || null });
|
|
305
310
|
assertGate(typeof distManifest?.source_digest === 'string' && distManifest.source_digest.length >= 32, 'dist/build-manifest must include source_digest', { source_digest: distManifest?.source_digest || null });
|
|
306
311
|
assertGate(pkg.scripts?.['release:metadata']?.includes('dist/scripts/release-metadata-check.js'), 'release:metadata must point to the generic release metadata check');
|
|
307
|
-
|
|
312
|
+
const releaseCheckScript = String(pkg.scripts?.['release:check'] || '');
|
|
313
|
+
assertGate(releaseCheckScript.startsWith('npm run release:check:parallel') || releaseCheckScript.includes('release-gate-dag-runner.js --preset release'), 'release:check must use release:check:parallel or the release gate DAG runner');
|
|
308
314
|
for (const script of requiredScripts)
|
|
309
315
|
assertGate(Boolean(pkg.scripts?.[script]), `missing package script: ${script}`);
|
|
310
316
|
for (const script of requiredRealScripts)
|
|
311
317
|
assertGate(Boolean(pkg.scripts?.[script]), `missing package real script: ${script}`);
|
|
312
318
|
for (const script of requiredScripts.filter((name) => name !== 'release:check:parallel')) {
|
|
313
|
-
assertGate(
|
|
319
|
+
assertGate(releaseCheckScriptSource.includes(`npm run ${script}`) || ['release:metadata', 'release:readiness'].includes(script), `release check coverage missing ${script}`);
|
|
314
320
|
}
|
|
315
321
|
for (const script of requiredRealScripts) {
|
|
316
322
|
assertGate(String(pkg.scripts?.['release:real-check'] || '').includes(`npm run ${script}`) || releaseRealCheckSource.includes(`'${script}'`) || releaseRealCheckSource.includes(`"${script}"`), `release:real-check missing ${script}`);
|
|
@@ -0,0 +1,79 @@
|
|
|
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 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;
|
|
21
|
+
const report = {
|
|
22
|
+
schema: 'sks.release-speed.v1',
|
|
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,
|
|
39
|
+
target_changed_file_wall_ms: 90 * 1000,
|
|
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
|
+
]
|
|
49
|
+
};
|
|
50
|
+
assertGate(report.blockers.length === 0, 'release DAG speed budget must use and pass actual run summary', report);
|
|
51
|
+
fs.mkdirSync(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
|
|
52
|
+
fs.writeFileSync(path.join(root, '.sneakoscope', 'reports', 'release-parallel-speed-budget.json'), `${JSON.stringify(report, null, 2)}\n`);
|
|
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
|
+
}
|
|
79
|
+
//# sourceMappingURL=release-parallel-speed-budget-check.js.map
|
|
@@ -216,7 +216,7 @@ const releaseMetadata = runNodeScript('dist/scripts/release-metadata-check.js');
|
|
|
216
216
|
const sideEffectRuntime = runNodeScript('dist/scripts/side-effect-runtime-report-check.js');
|
|
217
217
|
const releaseProvenance = runNodeScript('dist/scripts/release-provenance-check.js');
|
|
218
218
|
const imagegenCore = runNodeScript('dist/scripts/imagegen-capability-check.js');
|
|
219
|
-
const dynamicReleaseMode = process.env.SKS_RELEASE_DYNAMIC === '1';
|
|
219
|
+
const dynamicReleaseMode = process.env.SKS_RELEASE_DYNAMIC === '1' || Boolean(process.env.SKS_REPORT_DIR);
|
|
220
220
|
const runtimeReports = {
|
|
221
221
|
ppt_full_e2e_blackbox: readJson('.sneakoscope/reports/ppt-full-e2e-blackbox.json', null),
|
|
222
222
|
flagship_proof_graph_v3: readJson('.sneakoscope/reports/flagship-proof-graph-v3.json', null),
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
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 currentRunDir = process.env.SKS_REPORT_DIR ? path.dirname(process.env.SKS_REPORT_DIR) : null;
|
|
8
|
+
const latestReleaseRun = currentRunDir || latestDir(path.join(root, '.sneakoscope', 'reports', 'release-gates'));
|
|
9
|
+
const latestSummary = currentRunDir ? summarizeCurrentRun(currentRunDir) : latestReleaseRun ? readJsonIfExists(path.join(latestReleaseRun, 'summary.json')) : null;
|
|
10
|
+
const zellijReportPath = path.join(root, '.sneakoscope', 'reports', 'zellij-worker-pane-real-ui-blackbox.json');
|
|
11
|
+
const zellij = fs.existsSync(zellijReportPath) ? JSON.parse(fs.readFileSync(zellijReportPath, 'utf8')) : null;
|
|
12
|
+
const requiredGateIds = [
|
|
13
|
+
'release:dag-runner',
|
|
14
|
+
'release:parallel-speed-budget',
|
|
15
|
+
'git:worktree-manifest-append',
|
|
16
|
+
'git:worktree-dirty-main-detection',
|
|
17
|
+
'git:worktree-untracked-diff',
|
|
18
|
+
'git:worktree-diff-envelope',
|
|
19
|
+
'git:worktree-integration-primary',
|
|
20
|
+
'git:worktree-dirty-lock',
|
|
21
|
+
'naruto:worktree-coding:blackbox',
|
|
22
|
+
'release:version-truth'
|
|
23
|
+
];
|
|
24
|
+
const manifestIds = new Set(manifest.gates.map((gate) => gate.id));
|
|
25
|
+
const missing = requiredGateIds.filter((id) => !manifestIds.has(id));
|
|
26
|
+
const score = computeScore({ missing, latestSummary, zellij });
|
|
27
|
+
const report = {
|
|
28
|
+
schema: 'sks.release-stability-report.v1',
|
|
29
|
+
ok: score >= 9.5 && missing.length === 0 && latestSummary?.ok === true && zellij?.ok === true,
|
|
30
|
+
target_score: 9.5,
|
|
31
|
+
score,
|
|
32
|
+
manifest_gate_count: manifest.gates.length,
|
|
33
|
+
latest_release_summary: latestSummary ? path.relative(root, path.join(latestReleaseRun, 'summary.json')) : null,
|
|
34
|
+
release_check_ok: latestSummary?.ok === true,
|
|
35
|
+
release_check_passed: latestSummary?.completed || 0,
|
|
36
|
+
release_check_failed: latestSummary?.failed || 0,
|
|
37
|
+
zellij_real_worker_panes_ok: zellij?.ok === true,
|
|
38
|
+
zellij_real_worker_panes: zellij?.real_pane_ids || 0,
|
|
39
|
+
missing_required_gates: missing,
|
|
40
|
+
blockers: []
|
|
41
|
+
};
|
|
42
|
+
if (!report.ok) {
|
|
43
|
+
report.blockers = [
|
|
44
|
+
...(score >= 9.5 ? [] : ['stability_score_below_target']),
|
|
45
|
+
...(missing.length ? ['required_release_gate_missing'] : []),
|
|
46
|
+
...(latestSummary?.ok === true ? [] : ['latest_release_check_not_green']),
|
|
47
|
+
...(zellij?.ok === true ? [] : ['zellij_real_worker_panes_not_green'])
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
fs.mkdirSync(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
|
|
51
|
+
fs.writeFileSync(path.join(root, '.sneakoscope', 'reports', 'release-stability-report.json'), `${JSON.stringify(report, null, 2)}\n`);
|
|
52
|
+
assertGate(report.ok, 'release stability report must meet 9.5+ target', report);
|
|
53
|
+
emitGate('release:stability-report', report);
|
|
54
|
+
function computeScore({ missing, latestSummary, zellij }) {
|
|
55
|
+
let score = 10;
|
|
56
|
+
score -= missing.length * 0.25;
|
|
57
|
+
if (latestSummary?.ok !== true)
|
|
58
|
+
score -= 1.5;
|
|
59
|
+
if ((latestSummary?.failed || 0) > 0)
|
|
60
|
+
score -= 1;
|
|
61
|
+
if (zellij?.ok !== true)
|
|
62
|
+
score -= 1;
|
|
63
|
+
return Number(Math.max(0, score).toFixed(2));
|
|
64
|
+
}
|
|
65
|
+
function latestDir(dir) {
|
|
66
|
+
if (!fs.existsSync(dir))
|
|
67
|
+
return null;
|
|
68
|
+
const dirs = fs.readdirSync(dir)
|
|
69
|
+
.map((name) => path.join(dir, name))
|
|
70
|
+
.filter((candidate) => fs.statSync(candidate).isDirectory())
|
|
71
|
+
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
72
|
+
return dirs[0] || null;
|
|
73
|
+
}
|
|
74
|
+
function summarizeCurrentRun(runDir) {
|
|
75
|
+
const results = [];
|
|
76
|
+
for (const entry of fs.readdirSync(runDir)) {
|
|
77
|
+
const result = readJsonIfExists(path.join(runDir, entry, 'result.json'));
|
|
78
|
+
if (result && result.id !== 'release:stability-report')
|
|
79
|
+
results.push(result);
|
|
80
|
+
}
|
|
81
|
+
if (!results.length)
|
|
82
|
+
return null;
|
|
83
|
+
const failed = results.filter((result) => result.ok !== true);
|
|
84
|
+
return {
|
|
85
|
+
schema: 'sks.release-gate-current-run-summary.v1',
|
|
86
|
+
ok: failed.length === 0,
|
|
87
|
+
completed: results.filter((result) => result.ok === true).length,
|
|
88
|
+
failed: failed.length
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function readJsonIfExists(file) {
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=release-stability-report-check.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
|
|
6
|
+
import { ensureDistFresh } from './lib/ensure-dist-fresh.js';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
const requireReal = process.env.SKS_REQUIRE_ZELLIJ === '1' || process.argv.includes('--require-real');
|
|
9
|
+
const freshness = ensureDistFresh({ rebuild: false });
|
|
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');
|
|
12
|
+
const narutoSource = fs.readFileSync(path.join(root, 'src', 'core', 'commands', 'naruto-command.ts'), 'utf8');
|
|
13
|
+
const madSource = fs.readFileSync(path.join(root, 'src', 'core', 'commands', 'mad-sks-command.ts'), 'utf8');
|
|
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")
|
|
18
|
+
});
|
|
19
|
+
const dashboard = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-dashboard-pane.js')).href);
|
|
20
|
+
const command = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-command.js')).href);
|
|
21
|
+
const missionId = `M-zellij-dashboard-${Date.now()}`;
|
|
22
|
+
const sessionName = `sks-dashboard-${process.pid}`;
|
|
23
|
+
if (!requireReal) {
|
|
24
|
+
const snapshotMod = await import(pathToFileURL(path.join(root, 'dist', 'core', 'zellij', 'zellij-dashboard-renderer.js')).href);
|
|
25
|
+
const snapshot = snapshotMod.buildZellijDashboardSnapshot({ mission_id: missionId, active_workers: 4, visible_panes: 2, headless_workers: 2 });
|
|
26
|
+
const text = snapshotMod.renderZellijDashboardText(snapshot);
|
|
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 });
|
|
28
|
+
assertGate(fs.readFileSync(path.join(root, 'src', 'scripts', 'zellij-dashboard-watch.ts'), 'utf8').includes('--interval-ms')
|
|
29
|
+
&& fs.existsSync(path.join(root, 'dist', 'scripts', 'zellij-dashboard-watch.js')), 'dashboard watch script must support interval updates');
|
|
30
|
+
emitGate('zellij:dashboard-pane', { real_required: false, renderer_fields: true });
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
await command.runZellij(['kill-session', sessionName], { cwd: root, timeoutMs: 5000, optional: true });
|
|
34
|
+
try {
|
|
35
|
+
const record = await dashboard.openZellijDashboardPane({
|
|
36
|
+
root,
|
|
37
|
+
missionId,
|
|
38
|
+
sessionName,
|
|
39
|
+
cwd: root,
|
|
40
|
+
snapshot: {
|
|
41
|
+
mode: 'naruto',
|
|
42
|
+
backend_counts: { 'codex-sdk': 2, 'local-llm': 1 },
|
|
43
|
+
placement_counts: { 'zellij-pane': 2, headless: 1 },
|
|
44
|
+
active_workers: 3,
|
|
45
|
+
visible_panes: 2,
|
|
46
|
+
headless_workers: 1,
|
|
47
|
+
queue_depth: 7,
|
|
48
|
+
worktrees: { active: 2, completed: 1, retained: 0 },
|
|
49
|
+
local_llm: { tps: 12, queue: 1 },
|
|
50
|
+
gpt_final_status: 'pending',
|
|
51
|
+
gate_progress: 'release: 8/12'
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
const ok = record.ok === true && record.pane_kind === 'dashboard' && record.worker_pane === false && record.pane_id
|
|
55
|
+
&& String(record.command || '').includes('zellij-dashboard-watch.js')
|
|
56
|
+
&& String(record.command || '').includes('--interval-ms 1000');
|
|
57
|
+
assertGate(ok, 'real Zellij dashboard pane must open and not count as worker pane', record);
|
|
58
|
+
emitGate('zellij:dashboard-pane', {
|
|
59
|
+
real_required: true,
|
|
60
|
+
pane_id: record.pane_id,
|
|
61
|
+
pane_kind: record.pane_kind,
|
|
62
|
+
worker_pane: record.worker_pane,
|
|
63
|
+
mission_id: missionId,
|
|
64
|
+
session_name: sessionName
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
await command.runZellij(['kill-session', sessionName], { cwd: root, timeoutMs: 5000, optional: true });
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=zellij-dashboard-pane-check.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { buildZellijDashboardSnapshot, renderZellijDashboardText } from '../core/zellij/zellij-dashboard-renderer.js';
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const snapshotPath = path.resolve(String(readOption(args, '--snapshot', '') || ''));
|
|
7
|
+
const intervalMs = Math.max(250, Number(readOption(args, '--interval-ms', '1000')) || 1000);
|
|
8
|
+
const once = args.includes('--once');
|
|
9
|
+
if (!snapshotPath) {
|
|
10
|
+
console.error('Usage: zellij-dashboard-watch --snapshot <path> [--interval-ms 1000] [--once]');
|
|
11
|
+
process.exit(2);
|
|
12
|
+
}
|
|
13
|
+
render();
|
|
14
|
+
if (!once)
|
|
15
|
+
setInterval(render, intervalMs);
|
|
16
|
+
function render() {
|
|
17
|
+
const snapshot = readSnapshot(snapshotPath);
|
|
18
|
+
const text = renderZellijDashboardText(snapshot);
|
|
19
|
+
process.stdout.write(`\x1b[2J\x1b[H${text}\nUpdated: ${new Date().toISOString()}\n`);
|
|
20
|
+
}
|
|
21
|
+
function readSnapshot(file) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
24
|
+
return buildZellijDashboardSnapshot(parsed);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return buildZellijDashboardSnapshot({
|
|
28
|
+
mission_id: path.basename(path.dirname(file)) || 'unknown',
|
|
29
|
+
mode: 'dashboard-watch',
|
|
30
|
+
latest_blockers: [`snapshot_read_failed:${err?.code || err?.message || String(err)}`]
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function readOption(list, name, fallback) {
|
|
35
|
+
const index = list.indexOf(name);
|
|
36
|
+
if (index >= 0 && list[index + 1])
|
|
37
|
+
return list[index + 1];
|
|
38
|
+
const prefixed = list.find((arg) => arg.startsWith(`${name}=`));
|
|
39
|
+
return prefixed ? prefixed.slice(name.length + 1) : fallback;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=zellij-dashboard-watch.js.map
|
|
@@ -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
|