sneakoscope 3.1.12 → 3.1.13

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 (38) hide show
  1. package/README.md +10 -12
  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/commands/doctor.js +62 -32
  7. package/dist/core/agents/agent-role-config.js +12 -1
  8. package/dist/core/codex/agent-config-file-repair.js +115 -19
  9. package/dist/core/codex/codex-startup-config-postcheck.js +57 -4
  10. package/dist/core/codex-control/codex-0140-capability.js +72 -7
  11. package/dist/core/codex-control/codex-0140-feature-probes.js +174 -16
  12. package/dist/core/codex-control/codex-0140-real-probes.js +43 -3
  13. package/dist/core/codex-control/codex-0140-usage-parser.js +81 -0
  14. package/dist/core/codex-native/native-capability-postcheck.js +5 -2
  15. package/dist/core/codex-native/native-capability-repair-matrix.js +4 -4
  16. package/dist/core/config/secret-preservation.js +107 -10
  17. package/dist/core/doctor/context7-mcp-repair.js +15 -0
  18. package/dist/core/doctor/doctor-repair-postcheck.js +9 -3
  19. package/dist/core/doctor/doctor-transaction.js +98 -2
  20. package/dist/core/doctor/supabase-mcp-repair.js +36 -6
  21. package/dist/core/fsx.js +1 -1
  22. package/dist/core/loops/loop-concurrency-budget.js +22 -0
  23. package/dist/core/mcp/mcp-config-preservation.js +30 -7
  24. package/dist/core/naruto/naruto-loop-mesh.js +5 -1
  25. package/dist/core/version.js +1 -1
  26. package/dist/core/zellij/zellij-fake-adapter.js +8 -2
  27. package/dist/core/zellij/zellij-launcher.js +16 -0
  28. package/dist/scripts/codex-0140-feature-gate-lib.js +4 -2
  29. package/dist/scripts/release-3113-required-gates.js +25 -0
  30. package/package.json +11 -3
  31. package/dist/scripts/loop-directive-check-lib.js +0 -388
  32. package/dist/scripts/loop-hardening-check-lib.js +0 -289
  33. package/dist/scripts/sks-1-12-real-execution-check-lib.js +0 -27
  34. package/dist/scripts/sks-3-1-4-directive-check-lib.js +0 -212
  35. package/dist/scripts/sks-3-1-5-directive-check-lib.js +0 -318
  36. package/dist/scripts/sks-3-1-6-directive-check-lib.js +0 -522
  37. package/dist/scripts/sks-3-1-7-directive-check-lib.js +0 -58
  38. package/dist/scripts/sks-3-1-8-check-lib.js +0 -30
@@ -1,11 +1,17 @@
1
1
  import {} from './doctor-transaction.js';
2
2
  export function doctorRepairPostcheck(transaction) {
3
+ const phases = transaction?.phases || [];
4
+ const requiredBlockers = phases
5
+ .filter((phase) => phase.required_for_ready !== false && phase.ok !== true)
6
+ .flatMap((phase) => phase.blockers.length ? phase.blockers : [`required_phase_not_ready:${phase.id}`]);
3
7
  return {
4
8
  schema: 'sks.doctor-repair-postcheck.v1',
5
- ok: transaction?.postcheck_ok === true,
9
+ ok: transaction?.postcheck_ok === true && requiredBlockers.length === 0,
6
10
  transaction_ok: transaction?.ok === true,
7
- manual_required: (transaction?.phases || []).filter((phase) => phase.manual_required).map((phase) => phase.id),
8
- blockers: (transaction?.phases || []).flatMap((phase) => phase.blockers)
11
+ required_ready: requiredBlockers.length === 0,
12
+ manual_required: phases.filter((phase) => phase.manual_required).map((phase) => phase.id),
13
+ optional_manual_required: phases.filter((phase) => phase.manual_required && phase.required_for_ready === false).map((phase) => phase.id),
14
+ blockers: [...new Set([...requiredBlockers, ...phases.flatMap((phase) => phase.blockers)])]
9
15
  };
10
16
  }
11
17
  //# sourceMappingURL=doctor-repair-postcheck.js.map
@@ -1,5 +1,65 @@
1
1
  import path from 'node:path';
2
2
  import { nowIso, writeJsonAtomic } from '../fsx.js';
3
+ export async function runDoctorFixTransaction(input) {
4
+ const startedAt = nowIso();
5
+ const phases = [];
6
+ let rollbackPerformed = false;
7
+ for (const definition of input.phases) {
8
+ const phaseStarted = nowIso();
9
+ const startedMs = Date.now();
10
+ let phase = {
11
+ id: definition.id,
12
+ ok: false,
13
+ repaired: false,
14
+ manual_required: false,
15
+ required_for_ready: definition.required_for_ready !== false,
16
+ blockers: [],
17
+ warnings: [],
18
+ artifact_path: null,
19
+ started_at: phaseStarted
20
+ };
21
+ try {
22
+ const result = await definition.run();
23
+ phase = normalizePhase(definition, result, phase, startedMs);
24
+ if (definition.postcheck) {
25
+ const postcheck = await definition.postcheck(phase);
26
+ if (postcheck)
27
+ phase = mergePhase(phase, postcheck);
28
+ }
29
+ }
30
+ catch (err) {
31
+ phase = normalizePhase(definition, {
32
+ id: definition.id,
33
+ ok: false,
34
+ blockers: [messageOf(err)]
35
+ }, phase, startedMs);
36
+ }
37
+ if (!phase.ok && definition.rollback) {
38
+ try {
39
+ await definition.rollback(phase);
40
+ phase.rollback_performed = true;
41
+ rollbackPerformed = true;
42
+ }
43
+ catch (err) {
44
+ phase.rollback_performed = true;
45
+ rollbackPerformed = true;
46
+ phase.blockers = [...(phase.blockers || []), `rollback_failed:${messageOf(err)}`];
47
+ }
48
+ }
49
+ phase.completed_at = phase.completed_at || nowIso();
50
+ phase.duration_ms = phase.duration_ms ?? Math.max(0, Date.now() - startedMs);
51
+ phases.push(phase);
52
+ }
53
+ const writeInput = {
54
+ root: input.root,
55
+ startedAt,
56
+ phases,
57
+ rollbackPerformed
58
+ };
59
+ if (input.reportPath !== undefined)
60
+ writeInput.reportPath = input.reportPath;
61
+ return writeDoctorFixTransaction(writeInput);
62
+ }
3
63
  export async function writeDoctorFixTransaction(input) {
4
64
  const root = path.resolve(input.root);
5
65
  const phases = input.phases.map((phase) => ({
@@ -7,11 +67,16 @@ export async function writeDoctorFixTransaction(input) {
7
67
  ok: phase.ok === true,
8
68
  repaired: phase.repaired === true,
9
69
  manual_required: phase.manual_required === true,
70
+ required_for_ready: phase.required_for_ready !== false,
10
71
  blockers: phase.blockers || [],
11
72
  warnings: phase.warnings || [],
12
- artifact_path: phase.artifact_path || null
73
+ artifact_path: phase.artifact_path || null,
74
+ started_at: phase.started_at || null,
75
+ completed_at: phase.completed_at || null,
76
+ duration_ms: Number.isFinite(phase.duration_ms) ? Number(phase.duration_ms) : null,
77
+ rollback_performed: phase.rollback_performed === true
13
78
  }));
14
- const postcheckOk = phases.every((phase) => phase.ok || phase.manual_required);
79
+ const postcheckOk = phases.every((phase) => phase.ok || (phase.manual_required && !phase.required_for_ready));
15
80
  const report = {
16
81
  schema: 'sks.doctor-fix-transaction.v1',
17
82
  ok: postcheckOk,
@@ -27,4 +92,35 @@ export async function writeDoctorFixTransaction(input) {
27
92
  await writeJsonAtomic(input.reportPath || path.join(root, '.sneakoscope', 'reports', 'doctor-fix-transaction.json'), report).catch(() => undefined);
28
93
  return report;
29
94
  }
95
+ function normalizePhase(definition, result, fallback, startedMs) {
96
+ const phase = result || fallback;
97
+ return {
98
+ id: phase.id || definition.id,
99
+ ok: phase.ok === true,
100
+ repaired: phase.repaired === true,
101
+ manual_required: phase.manual_required === true,
102
+ required_for_ready: phase.required_for_ready ?? definition.required_for_ready !== false,
103
+ blockers: phase.blockers || [],
104
+ warnings: phase.warnings || [],
105
+ artifact_path: phase.artifact_path || null,
106
+ started_at: phase.started_at || fallback.started_at || nowIso(),
107
+ completed_at: phase.completed_at || nowIso(),
108
+ duration_ms: phase.duration_ms ?? Math.max(0, Date.now() - startedMs),
109
+ rollback_performed: phase.rollback_performed === true
110
+ };
111
+ }
112
+ function mergePhase(phase, update) {
113
+ return {
114
+ ...phase,
115
+ ...update,
116
+ ok: phase.ok === true && update.ok !== false,
117
+ repaired: phase.repaired === true || update.repaired === true,
118
+ manual_required: phase.manual_required === true || update.manual_required === true,
119
+ blockers: [...(phase.blockers || []), ...(update.blockers || [])],
120
+ warnings: [...(phase.warnings || []), ...(update.warnings || [])]
121
+ };
122
+ }
123
+ function messageOf(err) {
124
+ return err instanceof Error ? err.message : String(err);
125
+ }
30
126
  //# sourceMappingURL=doctor-transaction.js.map
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
- import { nowIso, writeJsonAtomic } from '../fsx.js';
3
- import { mcpServerBlock, mcpServerExplicitlyDisabled, readProjectCodexConfig } from '../mcp/mcp-config-preservation.js';
2
+ import { nowIso, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
3
+ import { mcpServerBlock, mcpServerExplicitlyDisabled, readProjectCodexConfig, replaceOrAppendMcpServerBlock } from '../mcp/mcp-config-preservation.js';
4
4
  export async function repairSupabaseMcp(input) {
5
5
  const root = path.resolve(input.root);
6
6
  const config = await readProjectCodexConfig(root);
@@ -8,8 +8,22 @@ export async function repairSupabaseMcp(input) {
8
8
  const block = mcpServerBlock(config.text, 'supabase') || '';
9
9
  const configured = Boolean(block);
10
10
  const tokenEnvPresent = Boolean(process.env.SUPABASE_ACCESS_TOKEN);
11
- const unsafeWriteAccess = configured && !/read[_-]?only\s*=\s*true|access_mode\s*=\s*"read-only"|--read-only/.test(block) && /write|service_role|SUPABASE_ACCESS_TOKEN/.test(block);
12
- const manualRequired = configured && !disabled && (!tokenEnvPresent || unsafeWriteAccess);
11
+ const readOnlyBefore = /read[_-]?only\s*=\s*true|access_mode\s*=\s*"read-only"|--read-only/.test(block);
12
+ const unsafeWriteAccessBefore = configured && !disabled && !readOnlyBefore && /write|service_role|SUPABASE_ACCESS_TOKEN/.test(block);
13
+ let afterText = config.text;
14
+ let readOnlyMigrated = false;
15
+ if (configured && !disabled && !readOnlyBefore && input.apply) {
16
+ afterText = replaceOrAppendMcpServerBlock(config.text, 'supabase', setReadOnly(block));
17
+ readOnlyMigrated = afterText !== config.text;
18
+ if (readOnlyMigrated)
19
+ await writeTextAtomic(config.path, afterText);
20
+ }
21
+ const afterBlock = readOnlyMigrated ? mcpServerBlock(afterText, 'supabase') || '' : block;
22
+ const readOnlyAfter = /read[_-]?only\s*=\s*true|access_mode\s*=\s*"read-only"|--read-only/.test(afterBlock);
23
+ const unsafeWriteAccess = configured && !disabled && !readOnlyAfter && /write|service_role|SUPABASE_ACCESS_TOKEN/.test(afterBlock);
24
+ const writeScopeRequiresConfirmation = configured && !disabled && (unsafeWriteAccessBefore || !readOnlyAfter);
25
+ const readyBlocking = unsafeWriteAccess;
26
+ const manualRequired = configured && !disabled && (!tokenEnvPresent || writeScopeRequiresConfirmation);
13
27
  const report = {
14
28
  schema: 'sks.doctor-supabase-mcp-repair.v1',
15
29
  generated_at: nowIso(),
@@ -17,20 +31,36 @@ export async function repairSupabaseMcp(input) {
17
31
  apply: input.apply === true,
18
32
  configured,
19
33
  disabled,
34
+ disabled_preserved: disabled,
20
35
  token_env_present: tokenEnvPresent,
21
36
  unsafe_write_access: unsafeWriteAccess,
37
+ read_only_migrated: readOnlyMigrated,
38
+ write_scope_requires_confirmation: writeScopeRequiresConfirmation,
39
+ ready_blocking: readyBlocking,
22
40
  manual_required: manualRequired,
23
41
  next_action: manualRequired
24
42
  ? tokenEnvPresent
25
43
  ? 'Set Supabase MCP to read-only or explicitly approve write-scoped MCP use.'
26
44
  : 'Set SUPABASE_ACCESS_TOKEN only if Supabase write MCP features are required; otherwise keep Supabase MCP disabled/read-only.'
27
45
  : null,
28
- blockers: unsafeWriteAccess ? ['supabase_mcp_write_access_not_safe_by_default'] : [],
29
- warnings: configured && !tokenEnvPresent ? ['supabase_access_token_unset_write_features_manual_required'] : [],
46
+ blockers: readyBlocking ? ['supabase_mcp_write_access_not_safe_by_default'] : [],
47
+ warnings: [
48
+ ...(configured && !tokenEnvPresent ? ['supabase_access_token_unset_write_features_manual_required'] : []),
49
+ ...(readOnlyMigrated ? ['supabase_mcp_migrated_to_read_only'] : [])
50
+ ],
30
51
  raw_secret_values_recorded: false
31
52
  };
32
53
  if (input.reportPath !== null)
33
54
  await writeJsonAtomic(input.reportPath || path.join(root, '.sneakoscope', 'reports', 'doctor-supabase-mcp-repair.json'), report).catch(() => undefined);
34
55
  return report;
35
56
  }
57
+ function setReadOnly(block) {
58
+ const lines = String(block || '').replace(/\s*$/, '').split(/\r?\n/);
59
+ const index = lines.findIndex((line) => /^\s*read[_-]?only\s*=/.test(line));
60
+ if (index >= 0)
61
+ lines[index] = 'read_only = true';
62
+ else
63
+ lines.push('read_only = true');
64
+ return `${lines.join('\n')}\n`;
65
+ }
36
66
  //# sourceMappingURL=supabase-mcp-repair.js.map
package/dist/core/fsx.js CHANGED
@@ -5,7 +5,7 @@ import os from 'node:os';
5
5
  import crypto from 'node:crypto';
6
6
  import { spawn } from 'node:child_process';
7
7
  import { fileURLToPath } from 'node:url';
8
- export const PACKAGE_VERSION = '3.1.12';
8
+ export const PACKAGE_VERSION = '3.1.13';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
  export function nowIso() {
@@ -3,6 +3,10 @@ import { writeJsonAtomic } from '../fsx.js';
3
3
  import { loopConcurrencyBudgetPath } from './loop-artifacts.js';
4
4
  export function computeLoopConcurrencyBudget(input) {
5
5
  const env = input.env || process.env;
6
+ const codexUsageSignal = input.codexUsageSignal || codexUsageSignalFromEnv(env);
7
+ const usageBudgetSource = codexUsageSignal.available && (codexUsageSignal.certainty === 'actual' || codexUsageSignal.certainty === 'discovered')
8
+ ? 'codex-0140-usage'
9
+ : 'sks-local-estimate';
6
10
  const cores = Math.max(1, os.cpus().length || 1);
7
11
  const requestedLoops = input.parallelism === 'safe' ? 2 : input.parallelism === 'extreme' ? Math.min(16, cores) : Math.min(8, cores);
8
12
  const envLoops = positiveInt(env.SKS_LOOP_MAX_ACTIVE_LOOPS);
@@ -32,6 +36,8 @@ export function computeLoopConcurrencyBudget(input) {
32
36
  return {
33
37
  schema: 'sks.loop-concurrency-budget.v1',
34
38
  mission_id: input.plan.mission_id,
39
+ usage_budget_source: usageBudgetSource,
40
+ codex_usage_signal: codexUsageSignal,
35
41
  max_active_loops: maxActiveLoops,
36
42
  max_active_workers: maxActiveWorkers,
37
43
  max_model_calls: maxModelCalls,
@@ -52,4 +58,20 @@ function positiveInt(value) {
52
58
  const number = Number(value);
53
59
  return Number.isFinite(number) && number >= 1 ? Math.floor(number) : null;
54
60
  }
61
+ function codexUsageSignalFromEnv(env) {
62
+ const certainty = normalizeUsageCertainty(env.SKS_CODEX_0140_USAGE_CERTAINTY);
63
+ const available = env.SKS_CODEX_0140_USAGE_AVAILABLE === '1' || certainty === 'actual' || certainty === 'discovered';
64
+ return {
65
+ available,
66
+ certainty,
67
+ source: available ? 'env' : 'none',
68
+ evidence: env.SKS_CODEX_0140_USAGE_EVIDENCE ? [env.SKS_CODEX_0140_USAGE_EVIDENCE] : [],
69
+ warnings: available ? [] : ['codex_0140_usage_signal_unavailable_using_local_estimate']
70
+ };
71
+ }
72
+ function normalizeUsageCertainty(value) {
73
+ if (value === 'actual' || value === 'discovered' || value === 'fixture' || value === 'assumed_by_version')
74
+ return value;
75
+ return 'unverified';
76
+ }
55
77
  //# sourceMappingURL=loop-concurrency-budget.js.map
@@ -7,24 +7,47 @@ export async function readProjectCodexConfig(root) {
7
7
  return { path: file, text };
8
8
  }
9
9
  export function mcpServerBlock(text, serverName) {
10
- const escaped = serverName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
11
- const re = new RegExp(`(^\\[mcp_servers\\.${escaped}\\]\\n[\\s\\S]*?)(?=^\\[|(?![\\s\\S]))`, 'm');
12
- return String(text || '').match(re)?.[1] || null;
10
+ const range = tomlTableRange(text, `mcp_servers.${serverName}`, false);
11
+ return range ? String(text || '').slice(range.start, range.end) : null;
12
+ }
13
+ export function mcpServerBlockWithChildren(text, serverName) {
14
+ const range = tomlTableRange(text, `mcp_servers.${serverName}`, true);
15
+ return range ? String(text || '').slice(range.start, range.end) : null;
13
16
  }
14
17
  export function mcpServerExplicitlyDisabled(text, serverName) {
15
18
  const block = mcpServerBlock(text, serverName);
16
19
  return Boolean(block && /^\s*disabled\s*=\s*true\s*$/m.test(block));
17
20
  }
18
21
  export function replaceOrAppendMcpServerBlock(text, serverName, block) {
19
- const escaped = serverName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
20
22
  const normalizedBlock = block.endsWith('\n') ? block : `${block}\n`;
21
- const re = new RegExp(`(^\\[mcp_servers\\.${escaped}\\]\\n[\\s\\S]*?)(?=^\\[|(?![\\s\\S]))`, 'm');
22
- if (re.test(text))
23
- return text.replace(re, normalizedBlock);
23
+ const range = tomlTableRange(text, `mcp_servers.${serverName}`, true);
24
+ if (range)
25
+ return `${text.slice(0, range.start)}${normalizedBlock}${text.slice(range.end).replace(/^\n+/, '')}`;
24
26
  const prefix = text.trim() ? `${text.replace(/\s*$/, '\n\n')}` : '';
25
27
  return `${prefix}${normalizedBlock}`;
26
28
  }
29
+ export function removeMcpServerBlock(text, serverName) {
30
+ const range = tomlTableRange(text, `mcp_servers.${serverName}`, true);
31
+ if (!range)
32
+ return text;
33
+ return `${text.slice(0, range.start).trimEnd()}${range.start > 0 ? '\n\n' : ''}${text.slice(range.end).replace(/^\n+/, '')}`;
34
+ }
27
35
  export function redactedMcpText(text) {
28
36
  return String(text || '').replace(/(token|access_token|api_key|secret)\s*=\s*"[^"]*"/gi, '$1 = "<redacted>"');
29
37
  }
38
+ export function tomlTableRange(text, table, includeChildren) {
39
+ const source = String(text || '');
40
+ const escaped = table.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
41
+ const header = new RegExp(`(^|\\n)\\s*\\[${escaped}\\]\\s*(?:#.*)?(?:\\n|$)`, 'g');
42
+ const match = header.exec(source);
43
+ if (!match)
44
+ return null;
45
+ const start = Number(match.index || 0) + (match[1] ? 1 : 0);
46
+ const rest = source.slice(header.lastIndex);
47
+ const nextHeader = includeChildren
48
+ ? rest.search(new RegExp(`\\n\\s*\\[(?!${escaped}(?:\\.|\\]))[^\\]]+\\]\\s*(?:#.*)?(?:\\n|$)`))
49
+ : rest.search(/\n\s*\[[^\]]+\]\s*(?:#.*)?(?:\n|$)/);
50
+ const end = nextHeader >= 0 ? header.lastIndex + nextHeader : source.length;
51
+ return { start, end };
52
+ }
30
53
  //# sourceMappingURL=mcp-config-preservation.js.map
@@ -10,7 +10,11 @@ export async function runNarutoLoopMesh(input) {
10
10
  await writeJsonAtomic(`${loopRoot(input.root, input.plan.mission_id)}/naruto-loop-worker-routes.json`, {
11
11
  schema: 'sks.naruto-loop-worker-routes.v1',
12
12
  mission_id: input.plan.mission_id,
13
- active_worker_budget: activeWorkerBudget,
13
+ active_worker_budget: {
14
+ ...activeWorkerBudget,
15
+ usage_budget_source: loopConcurrencyBudget.usage_budget_source,
16
+ codex_usage_signal: loopConcurrencyBudget.codex_usage_signal
17
+ },
14
18
  loop_concurrency_budget: loopConcurrencyBudget,
15
19
  routes
16
20
  });
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '3.1.12';
1
+ export const PACKAGE_VERSION = '3.1.13';
2
2
  //# sourceMappingURL=version.js.map
@@ -13,8 +13,14 @@ export async function runFakeZellij(args = [], opts = {}) {
13
13
  result = ok(`zellij ${version}\n`);
14
14
  }
15
15
  else if (args[0] === 'attach' && args[1] === '--create-background') {
16
- getSession(String(args[2] || 'default'));
17
- result = ok('');
16
+ const name = String(args[2] || 'default');
17
+ if (env.SKS_ZELLIJ_FAKE_CREATE_BACKGROUND_EXISTS === '1' && sessions.has(name)) {
18
+ result = fail(`Session already exists: ${name}`);
19
+ }
20
+ else {
21
+ getSession(name);
22
+ result = ok('');
23
+ }
18
24
  }
19
25
  else if (args.includes('new-pane')) {
20
26
  if (args.includes('--stacked') && !supportsStacked(version)) {
@@ -57,6 +57,9 @@ export async function launchZellijLayout(opts = {}) {
57
57
  ok: false,
58
58
  blockers: [`zellij_pane_proof_exception:${err?.message || String(err)}`]
59
59
  }));
60
+ if (launch?.create_background) {
61
+ launch.create_background = normalizeExistingZellijSession(sessionName, launch.create_background);
62
+ }
60
63
  const launchOk = launch?.create_background?.ok === true;
61
64
  const ok = capability.ok && (opts.dryRun === true || capability.status !== 'ok' || launchOk) && (opts.requireZellij === true ? paneProof.ok === true : true);
62
65
  const blockers = [
@@ -192,4 +195,17 @@ function readOption(args, name, fallback) {
192
195
  const index = list.indexOf(name);
193
196
  return index >= 0 && list[index + 1] ? String(list[index + 1]) : fallback;
194
197
  }
198
+ function normalizeExistingZellijSession(sessionName, result) {
199
+ if (result.ok)
200
+ return result;
201
+ if (/Session already exists/i.test(result.stderr_tail || '')) {
202
+ return {
203
+ ...result,
204
+ ok: true,
205
+ blockers: [],
206
+ warnings: [...result.warnings, `zellij_session_already_exists:${sessionName}`]
207
+ };
208
+ }
209
+ return result;
210
+ }
195
211
  //# sourceMappingURL=zellij-launcher.js.map
@@ -6,7 +6,9 @@ export async function runCodex0140FeatureGate(gate, feature) {
6
6
  process.env.SKS_CODEX_0140_PROBE = '1';
7
7
  const cap = await detectCodex0140Capability({ codexBin: 'codex' });
8
8
  assertGate(cap.ok === true && cap.supports_0140 === true, `${gate} requires passing Codex 0.140 capability fixture`, cap);
9
- assertGate(cap.features[feature] === true, `${gate} requires feature ${feature}`, cap);
10
- emitGate(gate, { feature, schema: cap.schema });
9
+ const state = cap.feature_states[feature];
10
+ assertGate(cap.features[feature] === true && state?.supported === true, `${gate} requires feature ${feature}`, cap);
11
+ assertGate(state.certainty !== 'assumed_by_version' && state.certainty !== 'unverified' && state.certainty !== 'failed', `${gate} requires probed feature certainty for ${feature}`, state);
12
+ emitGate(gate, { feature, schema: cap.schema, certainty: state.certainty });
11
13
  }
12
14
  //# sourceMappingURL=codex-0140-feature-gate-lib.js.map
@@ -0,0 +1,25 @@
1
+ export const REQUIRED_3113_RELEASE_IDS = [
2
+ 'release:gate-script-parity',
3
+ 'release:wiring-3113-blackbox',
4
+ 'codex:0140-deep-probes',
5
+ 'codex:0140-goal-attachment-roundtrip',
6
+ 'codex:0140-usage-real-parser',
7
+ 'pipeline:codex-0140-integration',
8
+ 'doctor:transaction-engine',
9
+ 'doctor:transaction-engine-blackbox',
10
+ 'doctor:fix-production-blackbox',
11
+ 'doctor:startup-config-repair',
12
+ 'doctor:startup-config-repair-blackbox',
13
+ 'doctor:context7-mcp-repair',
14
+ 'doctor:context7-mcp-repair-blackbox',
15
+ 'doctor:supabase-mcp-repair',
16
+ 'doctor:supabase-mcp-repair-blackbox',
17
+ 'native-capability:postcheck',
18
+ 'secret:line-rollback',
19
+ 'secret:preservation-guard',
20
+ 'sks:3113-all-feature-regression'
21
+ ];
22
+ export const REQUIRED_3113_REAL_CHECK_IDS = [
23
+ 'codex:0140-real-probes:require-real'
24
+ ];
25
+ //# sourceMappingURL=release-3113-required-gates.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "3.1.12",
4
+ "version": "3.1.13",
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",
@@ -33,6 +33,7 @@
33
33
  "!dist/vendor/openai-codex/rust-v0.131.0",
34
34
  "!dist/scripts/*-blackbox.js",
35
35
  "!dist/scripts/*-check.js",
36
+ "!dist/scripts/*-check-lib.js",
36
37
  "!dist/scripts/*-report.js",
37
38
  "!dist/scripts/release-readiness-report.js",
38
39
  "schemas",
@@ -925,12 +926,15 @@
925
926
  "doctor:codex-native-repair-actions": "node ./dist/scripts/doctor-codex-native-repair-actions-check.js",
926
927
  "codex-native:feature-broker-blackbox": "node ./dist/scripts/codex-native-feature-broker-blackbox.js",
927
928
  "pipeline:codex-native-e2e-blackbox": "node ./dist/scripts/pipeline-codex-native-e2e-blackbox.js",
928
- "release:gate-script-parity": "node ./dist/scripts/release-gate-script-parity-check.js",
929
929
  "release:wiring-3112-blackbox": "node ./dist/scripts/release-wiring-3112-blackbox.js",
930
+ "release:wiring-3113-blackbox": "node ./dist/scripts/release-wiring-3113-blackbox.js",
930
931
  "codex:0140-capability": "node ./dist/scripts/codex-0140-capability-check.js",
931
932
  "codex:0140-feature-probes": "node ./dist/scripts/codex-0140-feature-probes-check.js",
933
+ "codex:0140-deep-probes": "node ./dist/scripts/codex-0140-deep-probes-check.js",
932
934
  "codex:0140-usage": "node ./dist/scripts/codex-0140-usage-check.js",
935
+ "codex:0140-usage-real-parser": "node ./dist/scripts/codex-0140-usage-real-parser-check.js",
933
936
  "codex:0140-goal-attachment-preservation": "node ./dist/scripts/codex-0140-goal-attachment-preservation-check.js",
937
+ "codex:0140-goal-attachment-roundtrip": "node ./dist/scripts/codex-0140-goal-attachment-roundtrip-check.js",
934
938
  "codex:0140-session-delete": "node ./dist/scripts/codex-0140-session-delete-check.js",
935
939
  "codex:0140-import": "node ./dist/scripts/codex-0140-import-check.js",
936
940
  "codex:0140-unified-mentions": "node ./dist/scripts/codex-0140-unified-mentions-check.js",
@@ -943,6 +947,8 @@
943
947
  "codex:0140-real-probes:require-real": "node ./dist/scripts/codex-0140-real-probes-check.js --require-real --allow-network",
944
948
  "pipeline:codex-0140-integration": "node ./dist/scripts/pipeline-codex-0140-integration-check.js",
945
949
  "codex:0140-integration-blackbox": "node ./dist/scripts/codex-0140-integration-blackbox.js",
950
+ "doctor:transaction-engine": "node ./dist/scripts/doctor-transaction-engine-check.js",
951
+ "doctor:transaction-engine-blackbox": "node ./dist/scripts/doctor-transaction-engine-blackbox.js",
946
952
  "doctor:fix-production-blackbox": "node ./dist/scripts/doctor-fix-production-blackbox.js",
947
953
  "doctor:startup-config-repair": "node ./dist/scripts/doctor-startup-config-repair-check.js",
948
954
  "doctor:startup-config-repair-blackbox": "node ./dist/scripts/doctor-startup-config-repair-blackbox.js",
@@ -950,7 +956,9 @@
950
956
  "doctor:context7-mcp-repair-blackbox": "node ./dist/scripts/doctor-context7-mcp-repair-blackbox.js",
951
957
  "doctor:supabase-mcp-repair": "node ./dist/scripts/doctor-supabase-mcp-repair-check.js",
952
958
  "doctor:supabase-mcp-repair-blackbox": "node ./dist/scripts/doctor-supabase-mcp-repair-blackbox.js",
953
- "sks:3112-all-feature-regression": "node ./dist/scripts/sks-3112-all-feature-regression-blackbox.js"
959
+ "secret:line-rollback": "node ./dist/scripts/secret-line-rollback-check.js",
960
+ "sks:3112-all-feature-regression": "node ./dist/scripts/sks-3112-all-feature-regression-blackbox.js",
961
+ "sks:3113-all-feature-regression": "node ./dist/scripts/sks-3113-all-feature-regression-blackbox.js"
954
962
  },
955
963
  "keywords": [
956
964
  "sneakoscope",