sneakoscope 4.0.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +2 -2
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/bin/sks.js +1 -1
  6. package/dist/core/build/build-once-runner.js +5 -1
  7. package/dist/core/commands/check-command.js +3 -1
  8. package/dist/core/commands/mad-sks-command.js +7 -2
  9. package/dist/core/daemon/sksd-ipc.js +9 -0
  10. package/dist/core/daemon/sksd.js +37 -5
  11. package/dist/core/doctor/doctor-dirty-planner.js +70 -5
  12. package/dist/core/fsx.js +1 -1
  13. package/dist/core/probes/probe-memoization.js +40 -2
  14. package/dist/core/release/critical-path-ledger.js +12 -0
  15. package/dist/core/release/extreme-parallel-scheduler.js +53 -0
  16. package/dist/core/release/gate-pack-fixture-cache.js +39 -0
  17. package/dist/core/release/gate-pack-runner.js +145 -1
  18. package/dist/core/release/release-gate-cache-v2.js +6 -1
  19. package/dist/core/release/release-gate-dag.js +9 -2
  20. package/dist/core/triwiki/triwiki-affected-graph.js +63 -7
  21. package/dist/core/triwiki/triwiki-cache-key.js +27 -7
  22. package/dist/core/triwiki/triwiki-gate-impact-map.js +47 -2
  23. package/dist/core/triwiki/triwiki-invalidation.js +81 -0
  24. package/dist/core/triwiki/triwiki-module-card.js +48 -11
  25. package/dist/core/triwiki/triwiki-proof-bank.js +82 -4
  26. package/dist/core/triwiki/triwiki-proof-card.js +34 -3
  27. package/dist/core/triwiki/triwiki-sla-certificate.js +25 -2
  28. package/dist/core/version.js +1 -1
  29. package/dist/core/zellij/zellij-launcher.js +13 -0
  30. package/dist/core/zellij/zellij-worker-pane-manager.js +68 -17
  31. package/dist/scripts/release-4001-required-gates.js +13 -0
  32. package/dist/scripts/sizecheck.js +4 -2
  33. package/package.json +11 -2
@@ -1,15 +1,32 @@
1
1
  export const TRIWIKI_MODULE_CARD_SCHEMA = 'sks.triwiki-module-card.v1';
2
2
  export const DEFAULT_TRIWIKI_MODULE_CARDS = [
3
3
  moduleCard('triwiki', ['src/core/triwiki/**', 'src/scripts/triwiki-*.ts'], ['triwiki:'], ['triwiki'], 'high'),
4
- moduleCard('release', ['src/core/release/**', 'release-gates.v2.json', 'src/scripts/release-*.ts'], ['release:', 'gate-pack:', 'scheduler:', 'certificate:'], ['release-parity'], 'high'),
5
- moduleCard('build', ['src/core/build/**', 'src/scripts/build-once-*.ts', 'tsconfig.json'], ['build-once:'], ['doctor-production'], 'medium'),
6
- moduleCard('daemon', ['src/core/daemon/**', 'src/core/probes/**', 'src/scripts/sksd-*.ts', 'src/scripts/probe-*.ts'], ['sksd:', 'probes:'], ['startup-mcp'], 'medium'),
7
- moduleCard('doctor', ['src/core/doctor/**', 'src/commands/doctor.ts', 'src/scripts/doctor-*.ts'], ['doctor:'], ['doctor-production'], 'high'),
8
- moduleCard('legacy', ['src/scripts/legacy-*.ts', 'src/scripts/orphan-*.ts', 'src/commands/tmux.ts'], ['legacy:', 'orphan:'], ['zellij'], 'medium'),
9
- moduleCard('cli', ['src/cli/**', 'src/core/commands/**', 'src/commands/**'], ['cli:', 'sks:'], ['native-capability'], 'high'),
10
- moduleCard('codex', ['src/core/codex*/**', 'src/scripts/codex-*.ts'], ['codex:', 'pipeline:codex'], ['codex-0140'], 'medium'),
11
- moduleCard('skills', ['.agents/skills/**', 'src/core/skills/**', 'src/scripts/skill-*.ts', 'src/scripts/core-skill-*.ts'], ['skill:', 'core-skill:'], ['core-skill', 'skill-dedupe'], 'medium'),
12
- moduleCard('qa-research-image', ['src/core/qa/**', 'src/core/research/**', 'src/core/image/**', 'src/scripts/qa-*.ts', 'src/scripts/research-*.ts', 'src/scripts/image-*.ts'], ['qa-', 'research:', 'image:'], ['qa-research-image'], 'medium')
4
+ moduleCard('release-parity', ['package.json', 'package-lock.json', 'release-gates.v2.json'], ['release:'], ['release-parity'], 'high'),
5
+ moduleCard('release-dag', ['src/core/release/release-gate-*.ts', 'src/scripts/release-*.ts'], ['release:'], ['release-parity'], 'high'),
6
+ moduleCard('triwiki-proof-bank', ['src/core/triwiki/triwiki-proof-*.ts', 'src/core/triwiki/triwiki-cache-key.ts', 'src/core/triwiki/triwiki-invalidation.ts', 'src/scripts/triwiki-proof-*.ts', 'src/scripts/triwiki-cache-*.ts', 'src/scripts/triwiki-stale-*.ts'], ['triwiki:proof', 'triwiki:cache', 'triwiki:stale'], ['triwiki'], 'high'),
7
+ moduleCard('triwiki-affected-graph', ['src/core/triwiki/triwiki-module-card.ts', 'src/core/triwiki/triwiki-gate-impact-map.ts', 'src/core/triwiki/triwiki-affected-graph.ts', 'src/scripts/triwiki-affected-*.ts', 'src/scripts/triwiki-module-*.ts'], ['triwiki:affected', 'triwiki:module', 'triwiki:gate-impact'], ['triwiki'], 'high'),
8
+ moduleCard('gate-pack-runner', ['src/core/release/gate-pack-*.ts', 'src/scripts/gate-pack-*.ts'], ['gate-pack:'], ['release-parity'], 'high'),
9
+ moduleCard('extreme-scheduler', ['src/core/release/*scheduler.ts', 'src/core/release/resource-class-budget.ts', 'src/core/release/critical-path-ledger.ts', 'src/scripts/scheduler-*.ts'], ['scheduler:'], ['release-parity'], 'high'),
10
+ moduleCard('build-once', ['src/core/build/**', 'src/scripts/build-once-*.ts', 'tsconfig.json'], ['build-once:'], ['doctor-production'], 'medium'),
11
+ moduleCard('sksd-daemon', ['src/core/daemon/**', 'src/scripts/sksd-*.ts'], ['sksd:'], ['startup-mcp'], 'medium'),
12
+ moduleCard('probe-memoization', ['src/core/probes/**', 'src/scripts/probe-*.ts'], ['probes:'], ['startup-mcp'], 'medium'),
13
+ moduleCard('doctor-transaction', ['src/core/doctor/doctor-transaction.ts', 'src/commands/doctor.ts', 'src/scripts/doctor-transaction-*.ts'], ['doctor:transaction'], ['doctor-production'], 'high'),
14
+ moduleCard('doctor-dirty-repair', ['src/core/doctor/doctor-dirty-planner.ts', 'src/core/doctor/doctor-repair-postcheck.ts', 'src/scripts/doctor-dirty-*.ts'], ['doctor:dirty'], ['doctor-production'], 'high'),
15
+ moduleCard('startup-config-repair', ['src/core/doctor/*startup*.ts', 'src/scripts/doctor-startup-*.ts'], ['doctor:startup'], ['doctor-production'], 'high'),
16
+ moduleCard('context7-mcp', ['src/core/doctor/*context7*.ts', 'src/commands/context7.ts'], ['doctor:context7', 'context7:'], ['startup-mcp'], 'critical'),
17
+ moduleCard('supabase-mcp', ['src/core/doctor/*supabase*.ts', 'src/commands/db.ts'], ['doctor:supabase', 'db:'], ['startup-mcp'], 'critical'),
18
+ moduleCard('native-capability', ['src/core/codex-native/**', 'src/scripts/native-*.ts'], ['native:', 'codex-native:'], ['native-capability'], 'high'),
19
+ moduleCard('secret-preservation', ['src/core/**/secret*.ts', 'src/scripts/secret-*.ts', 'safety-mutation-allowlist.json'], ['secret:', 'supabase-secret'], ['doctor-production'], 'critical'),
20
+ moduleCard('core-skill', ['.agents/skills/**', 'src/scripts/core-skill-*.ts'], ['core-skill:'], ['core-skill'], 'high'),
21
+ moduleCard('skill-dedupe', ['src/scripts/skill-*.ts', '.sneakoscope/skills/**'], ['skill:'], ['skill-dedupe'], 'medium'),
22
+ moduleCard('zellij-runtime', ['src/core/zellij/**', 'src/commands/zellij*.ts', 'templates/zellij/**'], ['zellij:'], ['zellij'], 'high'),
23
+ moduleCard('codex-0140', ['src/scripts/codex-0140-*.ts', 'src/vendor/openai-codex/**'], ['codex:0140'], ['codex-0140'], 'medium'),
24
+ moduleCard('loop-mesh', ['src/core/loops/**', 'src/scripts/loop-*.ts'], ['loop:'], ['loop-mesh'], 'medium'),
25
+ moduleCard('qa-loop', ['src/commands/qa-loop.ts', 'src/scripts/qa-*.ts'], ['qa-', 'qa:'], ['qa-research-image'], 'medium'),
26
+ moduleCard('research', ['src/commands/research.ts', 'src/scripts/research-*.ts'], ['research:'], ['qa-research-image'], 'medium'),
27
+ moduleCard('image-path', ['src/commands/image-ux-review.ts', 'src/scripts/*image*.ts', 'src/scripts/ux-review-*.ts'], ['image:', 'ux-review:'], ['qa-research-image'], 'medium'),
28
+ moduleCard('legacy-purge', ['src/scripts/legacy-*.ts', 'src/scripts/orphan-*.ts', 'docs/sks-4-migration.md'], ['legacy:', 'orphan:'], ['zellij'], 'high'),
29
+ moduleCard('cli-check', ['src/core/commands/check-command.ts', 'src/commands/**/*.ts', 'src/cli/**'], ['cli:', 'sks:', 'check:'], ['native-capability'], 'high')
13
30
  ];
14
31
  export function moduleCard(moduleId, paths, ownsGatePrefixes, gatePacks, risk) {
15
32
  return {
@@ -18,7 +35,9 @@ export function moduleCard(moduleId, paths, ownsGatePrefixes, gatePacks, risk) {
18
35
  paths,
19
36
  owns_gate_prefixes: ownsGatePrefixes,
20
37
  gate_packs: gatePacks,
21
- risk
38
+ risk,
39
+ invariants: [`${moduleId}:release-equivalent-proof-required`],
40
+ required_proof_type: risk === 'critical' ? 'real-postcheck-plus-release-gate' : 'release-gate'
22
41
  };
23
42
  }
24
43
  export function moduleIdsForPath(file, cards = DEFAULT_TRIWIKI_MODULE_CARDS) {
@@ -31,7 +50,25 @@ export function pathMatches(pattern, file) {
31
50
  return file === pattern.slice(0, -3) || file.startsWith(pattern.slice(0, -2));
32
51
  if (!pattern.includes('*'))
33
52
  return file === pattern || file.startsWith(`${pattern}/`);
34
- const re = new RegExp(`^${pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\\\*\\\*/g, '.*').replace(/\\\*/g, '[^/]*')}$`);
53
+ const re = new RegExp(`^${globToRegexSource(pattern)}$`);
35
54
  return re.test(file);
36
55
  }
56
+ function globToRegexSource(pattern) {
57
+ let out = '';
58
+ for (let i = 0; i < pattern.length; i += 1) {
59
+ const char = pattern[i];
60
+ if (char === '*') {
61
+ if (pattern[i + 1] === '*') {
62
+ out += '.*';
63
+ i += 1;
64
+ }
65
+ else {
66
+ out += '[^/]*';
67
+ }
68
+ continue;
69
+ }
70
+ out += /[\\^$+?.()|{}[\]]/.test(char || '') ? `\\${char}` : char;
71
+ }
72
+ return out;
73
+ }
37
74
  //# sourceMappingURL=triwiki-module-card.js.map
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { TRIWIKI_PROOF_CARD_SCHEMA, isReusableTriWikiProofCard } from './triwiki-proof-card.js';
3
+ import { TRIWIKI_PROOF_CARD_SCHEMA, classifyTriWikiProofCardSchema, isReusableTriWikiProofCard } from './triwiki-proof-card.js';
4
4
  export const TRIWIKI_PROOF_BANK_SCHEMA = 'sks.triwiki-proof-bank.v1';
5
5
  export function triWikiProofBankDir(root) {
6
6
  return path.join(root, '.sneakoscope', 'triwiki', 'proof-bank');
@@ -9,8 +9,10 @@ export function writeTriWikiProofCard(root, card, subjectType = pluralSubject(ca
9
9
  const dir = path.join(triWikiProofBankDir(root), subjectType, safeId(card.subject_id));
10
10
  fs.mkdirSync(dir, { recursive: true });
11
11
  const file = path.join(dir, `${safeId(card.proof_id)}.json`);
12
- fs.writeFileSync(file, `${JSON.stringify(card, null, 2)}\n`);
13
- return file;
12
+ return withSubjectLock(root, subjectType, card.subject_id, () => {
13
+ atomicWriteJson(file, card);
14
+ return file;
15
+ });
14
16
  }
15
17
  export function readReusableTriWikiProofCard(input) {
16
18
  const dir = path.join(triWikiProofBankDir(input.root), input.subjectType || 'gates', safeId(input.subjectId));
@@ -25,6 +27,11 @@ export function readReusableTriWikiProofCard(input) {
25
27
  reasons.push(`corrupt:${file}`);
26
28
  continue;
27
29
  }
30
+ const schemaClass = classifyTriWikiProofCardSchema(card);
31
+ if (schemaClass === 'legacy_proof_card_schema') {
32
+ reasons.push(`legacy_proof_card_schema:${file}`);
33
+ continue;
34
+ }
28
35
  if (card.cache_key !== input.cacheKey) {
29
36
  reasons.push(`cache_key_mismatch:${file}`);
30
37
  continue;
@@ -45,7 +52,7 @@ export function markTriWikiProofInvalidated(root, subjectId, proofId, reason, su
45
52
  reusable: false,
46
53
  invalidation_reasons: [...new Set([...(card.invalidation_reasons || []), reason])]
47
54
  };
48
- fs.writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`);
55
+ atomicWriteJson(file, next);
49
56
  return true;
50
57
  }
51
58
  export function summarizeTriWikiProofBank(root) {
@@ -100,6 +107,77 @@ function backupCorruptProof(file) {
100
107
  const backup = `${file}.corrupt-${Date.now()}.bak`;
101
108
  fs.renameSync(file, backup);
102
109
  }
110
+ function atomicWriteJson(file, value) {
111
+ fs.mkdirSync(path.dirname(file), { recursive: true });
112
+ const temp = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${Date.now()}.tmp`);
113
+ const fd = fs.openSync(temp, 'w');
114
+ try {
115
+ fs.writeFileSync(fd, `${JSON.stringify(value, null, 2)}\n`);
116
+ try {
117
+ fs.fsyncSync(fd);
118
+ }
119
+ catch {
120
+ // fsync can be unavailable on some virtual filesystems; rename remains atomic.
121
+ }
122
+ }
123
+ finally {
124
+ fs.closeSync(fd);
125
+ }
126
+ fs.renameSync(temp, file);
127
+ }
128
+ function withSubjectLock(root, subjectType, subjectId, fn) {
129
+ const lockDir = path.join(triWikiProofBankDir(root), '.locks', subjectType);
130
+ fs.mkdirSync(lockDir, { recursive: true });
131
+ const lockFile = path.join(lockDir, `${safeId(subjectId)}.lock`);
132
+ const staleAfterMs = 30_000;
133
+ const started = Date.now();
134
+ while (true) {
135
+ try {
136
+ const fd = fs.openSync(lockFile, 'wx');
137
+ fs.writeFileSync(fd, `${JSON.stringify({ schema: 'sks.triwiki-proof-bank-lock.v1', pid: process.pid, acquired_at: new Date().toISOString(), stale_after_ms: staleAfterMs }, null, 2)}\n`);
138
+ fs.closeSync(fd);
139
+ break;
140
+ }
141
+ catch (err) {
142
+ if (isLockStale(lockFile, staleAfterMs)) {
143
+ try {
144
+ fs.rmSync(lockFile, { force: true });
145
+ }
146
+ catch { }
147
+ continue;
148
+ }
149
+ if (Date.now() - started > staleAfterMs * 2)
150
+ throw err;
151
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
152
+ }
153
+ }
154
+ try {
155
+ return fn();
156
+ }
157
+ finally {
158
+ try {
159
+ fs.rmSync(lockFile, { force: true });
160
+ }
161
+ catch { }
162
+ }
163
+ }
164
+ function isLockStale(file, staleAfterMs) {
165
+ try {
166
+ const stat = fs.statSync(file);
167
+ const raw = JSON.parse(fs.readFileSync(file, 'utf8'));
168
+ const pidAlive = typeof raw.pid === 'number' && process.kill(raw.pid, 0) !== undefined;
169
+ return !pidAlive || Date.now() - stat.mtimeMs > staleAfterMs;
170
+ }
171
+ catch {
172
+ try {
173
+ const stat = fs.statSync(file);
174
+ return Date.now() - stat.mtimeMs > staleAfterMs;
175
+ }
176
+ catch {
177
+ return true;
178
+ }
179
+ }
180
+ }
103
181
  function walkJson(dir) {
104
182
  const out = [];
105
183
  const stack = [dir];
@@ -7,8 +7,13 @@ export function createTriWikiProofCard(input) {
7
7
  subject_id: input.subject_id,
8
8
  cache_key: input.cache_key,
9
9
  input_hash: input.input_hash,
10
- implementation_hash: input.implementation_hash,
11
- tool_version: input.tool_version,
10
+ implementation_hash: input.implementation_hash || input.gate_impl_hash || 'unknown',
11
+ gate_impl_hash: input.gate_impl_hash || input.implementation_hash || 'unknown',
12
+ package_lock_hash: input.package_lock_hash || 'legacy-missing',
13
+ release_gates_hash: input.release_gates_hash || 'legacy-missing',
14
+ env_allowlist_hash: input.env_allowlist_hash || 'legacy-missing',
15
+ tool_versions: input.tool_versions || (input.tool_version ? { sks: input.tool_version } : {}),
16
+ tool_version: input.tool_version || input.tool_versions?.sks || 'unknown',
12
17
  fixture_version: input.fixture_version,
13
18
  result: input.result,
14
19
  reusable: input.reusable,
@@ -24,11 +29,24 @@ export function createTriWikiProofCard(input) {
24
29
  };
25
30
  }
26
31
  export function proofIdFor(value) {
27
- return `proof-${hashJson(value).slice(0, 24)}`;
32
+ return `proof-${hashJson({
33
+ subject_type: value.subject_type,
34
+ subject_id: value.subject_id,
35
+ cache_key: value.cache_key,
36
+ input_hash: value.input_hash,
37
+ gate_impl_hash: value.gate_impl_hash || value.implementation_hash,
38
+ package_lock_hash: value.package_lock_hash,
39
+ release_gates_hash: value.release_gates_hash,
40
+ env_allowlist_hash: value.env_allowlist_hash,
41
+ tool_versions: value.tool_versions,
42
+ fixture_version: value.fixture_version
43
+ }).slice(0, 24)}`;
28
44
  }
29
45
  export function isReusableTriWikiProofCard(card, now = new Date()) {
30
46
  if (card.schema !== TRIWIKI_PROOF_CARD_SCHEMA)
31
47
  return false;
48
+ if (!hasV401InvalidationMaterial(card))
49
+ return false;
32
50
  if (card.reusable !== true)
33
51
  return false;
34
52
  if (card.result !== 'passed')
@@ -39,4 +57,17 @@ export function isReusableTriWikiProofCard(card, now = new Date()) {
39
57
  return false;
40
58
  return true;
41
59
  }
60
+ export function classifyTriWikiProofCardSchema(card) {
61
+ if (card.schema !== TRIWIKI_PROOF_CARD_SCHEMA)
62
+ return 'invalid';
63
+ return hasV401InvalidationMaterial(card) ? 'current' : 'legacy_proof_card_schema';
64
+ }
65
+ function hasV401InvalidationMaterial(card) {
66
+ return Boolean(card.gate_impl_hash &&
67
+ card.package_lock_hash &&
68
+ card.release_gates_hash &&
69
+ card.env_allowlist_hash &&
70
+ card.tool_versions &&
71
+ Object.keys(card.tool_versions).length > 0);
72
+ }
42
73
  //# sourceMappingURL=triwiki-proof-card.js.map
@@ -4,9 +4,12 @@ export const TRIWIKI_SLA_CERTIFICATE_SCHEMA = 'sks.triwiki-sla-certificate.v1';
4
4
  export function buildTriWikiSlaCertificate(input) {
5
5
  const reductionRatio = input.estimatedSequentialMs <= 0 ? 1 : input.estimatedCriticalPathMs / input.estimatedSequentialMs;
6
6
  const blockers = input.blockers || [];
7
+ const mode = input.mode || 'plan';
7
8
  if (input.estimatedCriticalPathMs > input.slaMs)
8
9
  blockers.push('sla_estimate_exceeds_budget');
9
- return {
10
+ if (mode === 'actual' && input.actualDurationMs === undefined)
11
+ blockers.push('actual_mode_missing_execution_stats');
12
+ const certificate = {
10
13
  schema: TRIWIKI_SLA_CERTIFICATE_SCHEMA,
11
14
  ok: blockers.length === 0,
12
15
  created_at: new Date().toISOString(),
@@ -18,8 +21,28 @@ export function buildTriWikiSlaCertificate(input) {
18
21
  release_equivalent_within_scope: input.graph.release_equivalent_within_scope,
19
22
  gates: input.graph.gates.length,
20
23
  gate_packs: input.graph.gate_packs,
21
- blockers
24
+ blockers,
25
+ mode
22
26
  };
27
+ if (input.actualDurationMs !== undefined)
28
+ certificate.actual_duration_ms = input.actualDurationMs;
29
+ if (input.executedGates !== undefined)
30
+ certificate.executed_gates = input.executedGates;
31
+ if (input.executedPacks !== undefined)
32
+ certificate.executed_packs = input.executedPacks;
33
+ if (input.reusedProofs !== undefined)
34
+ certificate.reused_proofs = input.reusedProofs;
35
+ if (input.invalidatedProofs !== undefined)
36
+ certificate.invalidated_proofs = input.invalidatedProofs;
37
+ if (input.newProofs !== undefined)
38
+ certificate.new_proofs = input.newProofs;
39
+ if (input.skippedAsValidCache !== undefined)
40
+ certificate.skipped_as_valid_cache = input.skippedAsValidCache;
41
+ if (input.skippedAsUnaffected !== undefined)
42
+ certificate.skipped_as_unaffected = input.skippedAsUnaffected;
43
+ if (input.backgroundFullRelease !== undefined)
44
+ certificate.background_full_release = input.backgroundFullRelease;
45
+ return certificate;
23
46
  }
24
47
  export function writeTriWikiSlaCertificate(root, certificate) {
25
48
  const file = path.join(root, '.sneakoscope', 'reports', 'triwiki-sla-certificate.json');
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '4.0.0';
1
+ export const PACKAGE_VERSION = '4.0.1';
2
2
  //# sourceMappingURL=version.js.map
@@ -37,6 +37,18 @@ export async function launchZellijLayout(opts = {}) {
37
37
  const createCommand = ['attach', '--create-background', sessionName, 'options', '--default-layout', layout.layout_path, ...clipboard.optionFlags];
38
38
  const attachCommand = ['attach', sessionName];
39
39
  const zellijEnv = resolveZellijProcessEnvMeta();
40
+ // Reset a stale same-named session before recreating it so the launch starts
41
+ // main-only. `attach --create-background` is idempotent and otherwise reuses an
42
+ // existing session, causing each run to pile another right-split SLOTS column
43
+ // onto leftover panes from prior missions. Skipped on dry-run, when zellij is
44
+ // unavailable, or when the user opts out with SKS_ZELLIJ_KEEP_SESSION=1.
45
+ const resetSession = opts.freshSession === true
46
+ && opts.dryRun !== true
47
+ && capability.status === 'ok'
48
+ && process.env.SKS_ZELLIJ_KEEP_SESSION !== '1';
49
+ const sessionReset = resetSession
50
+ ? await runZellij(['kill-session', sessionName], { cwd: opts.cwd || root, timeoutMs: 5000, optional: true })
51
+ : null;
40
52
  const launch = opts.dryRun === true || capability.status !== 'ok'
41
53
  ? null
42
54
  : {
@@ -104,6 +116,7 @@ export async function launchZellijLayout(opts = {}) {
104
116
  dry_run: opts.dryRun === true,
105
117
  capability,
106
118
  launch,
119
+ session_reset: sessionReset,
107
120
  blockers,
108
121
  warnings: [
109
122
  ...capability.warnings,
@@ -227,24 +227,19 @@ export async function openWorkerPane(input) {
227
227
  let columnCreationDirectionRequested = null;
228
228
  let columnCreationDirectionApplied = null;
229
229
  if (rightColumn && !freshFocusCandidate) {
230
- columnCreationDirectionRequested = 'right';
231
- const anchorCommand = buildZellijSlotColumnAnchorCommand({
232
- cliPath: path.join(packageRoot(), 'dist', 'bin', 'sks.js'),
233
- missionId: input.missionId,
234
- mode: input.uiMode || 'compact-slots',
235
- artifactRoot: root,
236
- watch: true
237
- });
238
- anchorLaunch = createSession.ok
239
- ? await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--direction', 'right', '--name', 'SLOTS', '--', 'sh', '-lc', anchorCommand], {
240
- cwd,
241
- timeoutMs: 5000,
242
- optional: false
243
- })
230
+ // Single right-column invariant: if this zellij session was reused (stable
231
+ // per-cwd name) and already carries a SLOTS anchor from a prior mission, adopt
232
+ // it and stack workers underneath instead of splitting ANOTHER `--direction
233
+ // right` column — repeated right-splits are exactly what fragments the screen
234
+ // into side-by-side columns. A fresh column is only split when none exists yet.
235
+ const adoptedAnchorPaneId = createSession.ok
236
+ ? await findExistingSlotsAnchorPaneId(input.sessionName, cwd).catch(() => null)
244
237
  : null;
245
- slotColumnAnchorPaneId = anchorLaunch?.ok ? extractZellijPaneIdFromOutput(anchorLaunch.stdout_tail) : null;
246
- columnCreationDirectionApplied = anchorLaunch?.ok ? (slotColumnAnchorPaneId ? 'right' : 'unknown') : 'not_applied';
247
- if (slotColumnAnchorPaneId) {
238
+ if (adoptedAnchorPaneId) {
239
+ // Adopted an existing column: no creation was requested, so leave the
240
+ // column-creation direction fields null (avoids a false
241
+ // `zellij_worker_slot_column_anchor_not_created` blocker).
242
+ slotColumnAnchorPaneId = adoptedAnchorPaneId;
248
243
  await recordSlotColumnAnchorInRightColumn({
249
244
  root,
250
245
  ...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
@@ -253,6 +248,34 @@ export async function openWorkerPane(input) {
253
248
  paneId: slotColumnAnchorPaneId
254
249
  });
255
250
  }
251
+ else {
252
+ columnCreationDirectionRequested = 'right';
253
+ const anchorCommand = buildZellijSlotColumnAnchorCommand({
254
+ cliPath: path.join(packageRoot(), 'dist', 'bin', 'sks.js'),
255
+ missionId: input.missionId,
256
+ mode: input.uiMode || 'compact-slots',
257
+ artifactRoot: root,
258
+ watch: true
259
+ });
260
+ anchorLaunch = createSession.ok
261
+ ? await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--direction', 'right', '--name', 'SLOTS', '--', 'sh', '-lc', anchorCommand], {
262
+ cwd,
263
+ timeoutMs: 5000,
264
+ optional: false
265
+ })
266
+ : null;
267
+ slotColumnAnchorPaneId = anchorLaunch?.ok ? extractZellijPaneIdFromOutput(anchorLaunch.stdout_tail) : null;
268
+ columnCreationDirectionApplied = anchorLaunch?.ok ? (slotColumnAnchorPaneId ? 'right' : 'unknown') : 'not_applied';
269
+ if (slotColumnAnchorPaneId) {
270
+ await recordSlotColumnAnchorInRightColumn({
271
+ root,
272
+ ...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
273
+ missionId: input.missionId,
274
+ sessionName: input.sessionName,
275
+ paneId: slotColumnAnchorPaneId
276
+ });
277
+ }
278
+ }
256
279
  }
257
280
  const focusPaneId = lastVisibleWorkerPaneId || slotColumnAnchorPaneId || freshFocusCandidate || null;
258
281
  const directionRequested = 'down';
@@ -595,6 +618,34 @@ async function reconcileZellijWorkerPaneId(sessionName, paneName, resultPath, cw
595
618
  blockers: paneId == null ? ['zellij_worker_pane_id_not_reconciled'] : []
596
619
  };
597
620
  }
621
+ // Look up an already-open SLOTS anchor pane in a (possibly reused) session so a
622
+ // new mission can stack its workers under the existing right column instead of
623
+ // splitting another one. Returns the live pane id (terminal_<n>) or null.
624
+ async function findExistingSlotsAnchorPaneId(sessionName, cwd) {
625
+ const listed = await runZellij(['--session', sessionName, 'action', 'list-panes', '--json', '--all'], {
626
+ cwd,
627
+ timeoutMs: 5000,
628
+ optional: true
629
+ });
630
+ if (!listed.ok)
631
+ return null;
632
+ const rows = parsePaneRows(listed.stdout_tail);
633
+ const pane = rows.find((row) => {
634
+ if (row?.is_plugin === true)
635
+ return false;
636
+ const exited = row?.exited === true || row?.is_exited === true || row?.exit_status != null;
637
+ if (exited)
638
+ return false;
639
+ const title = String(row?.title || row?.name || row?.pane_name || '');
640
+ return title === 'SLOTS';
641
+ });
642
+ if (!pane)
643
+ return null;
644
+ const rawPaneId = pane.pane_id ?? pane.paneId;
645
+ if (rawPaneId != null && String(rawPaneId).trim())
646
+ return String(rawPaneId).trim();
647
+ return pane.id == null ? null : `terminal_${pane.id}`;
648
+ }
598
649
  function normalizePaneProviderContext(context, serviceTier) {
599
650
  const tier = normalizeServiceTier(serviceTier || context?.service_tier);
600
651
  return context
@@ -0,0 +1,13 @@
1
+ export const REQUIRED_4001_RELEASE_IDS = [
2
+ 'triwiki:stale-proof-rejection',
3
+ 'gate-pack:fixture-cache',
4
+ 'release:triwiki-first-runner',
5
+ 'release:cache-bridge',
6
+ 'doctor:dirty-semantic',
7
+ 'legacy:strong-inventory',
8
+ 'orphan:strong-detection',
9
+ 'sks:401-five-minute-actual-blackbox',
10
+ 'sks:401-all-feature-regression'
11
+ ];
12
+ export const REQUIRED_4001_REAL_CHECK_IDS = [];
13
+ //# sourceMappingURL=release-4001-required-gates.js.map
@@ -8,13 +8,15 @@ import { fileURLToPath } from 'node:url';
8
8
  const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
9
9
  const limits = {
10
10
  packedBytes: Number(process.env.SKS_MAX_PACK_BYTES || 1536 * 1024),
11
- unpackedBytes: Number(process.env.SKS_MAX_UNPACKED_BYTES || 6 * 1024 * 1024),
11
+ unpackedBytes: Number(process.env.SKS_MAX_UNPACKED_BYTES || 6400 * 1024),
12
12
  packFiles: Number(process.env.SKS_MAX_PACK_FILES || 1200),
13
13
  trackedFileBytes: Number(process.env.SKS_MAX_TRACKED_FILE_BYTES || 384 * 1024)
14
14
  };
15
15
  const trackedFileSizeAllowlist = new Set([
16
16
  // Historical source documentation export; not included in the npm package payload.
17
- 'docs/sks-local-llm-mode/exports/sks-local-llm-mode-deck.pdf'
17
+ 'docs/sks-local-llm-mode/exports/sks-local-llm-mode-deck.pdf',
18
+ // Central release DAG manifest; package footprint limits still apply below.
19
+ 'release-gates.v2.json'
18
20
  ]);
19
21
  const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
20
22
  function fail(message, detail = '') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "4.0.0",
4
+ "version": "4.0.1",
5
5
  "description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
@@ -994,7 +994,16 @@
994
994
  "cli:check-tiers": "node ./dist/scripts/cli-check-tiers-check.js",
995
995
  "cli:five-minute-task": "node ./dist/scripts/cli-five-minute-task-check.js",
996
996
  "certificate:sla": "node ./dist/scripts/certificate-sla-check.js",
997
- "sks:400-all-feature-regression": "node ./dist/scripts/sks-400-all-feature-regression-blackbox.js"
997
+ "sks:400-all-feature-regression": "node ./dist/scripts/sks-400-all-feature-regression-blackbox.js",
998
+ "triwiki:stale-proof-rejection": "node ./dist/scripts/triwiki-stale-proof-rejection-check.js",
999
+ "gate-pack:fixture-cache": "node ./dist/scripts/gate-pack-fixture-cache-check.js",
1000
+ "release:triwiki-first-runner": "node ./dist/scripts/release-triwiki-first-runner-check.js",
1001
+ "release:cache-bridge": "node ./dist/scripts/release-cache-bridge-check.js",
1002
+ "doctor:dirty-semantic": "node ./dist/scripts/doctor-dirty-semantic-check.js",
1003
+ "legacy:strong-inventory": "node ./dist/scripts/legacy-strong-inventory-check.js",
1004
+ "orphan:strong-detection": "node ./dist/scripts/orphan-strong-detection-check.js",
1005
+ "sks:401-five-minute-actual-blackbox": "node ./dist/scripts/sks-401-five-minute-actual-blackbox.js",
1006
+ "sks:401-all-feature-regression": "node ./dist/scripts/sks-401-all-feature-regression-blackbox.js"
998
1007
  },
999
1008
  "keywords": [
1000
1009
  "sneakoscope",