sneakoscope 2.0.16 → 2.0.18

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 (63) hide show
  1. package/README.md +23 -30
  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/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/cli/command-registry.js +1 -1
  8. package/dist/commands/doctor.js +39 -1
  9. package/dist/commands/proof.js +21 -0
  10. package/dist/commands/zellij-slot-pane.js +7 -1
  11. package/dist/core/agents/agent-effort-policy.js +7 -1
  12. package/dist/core/agents/agent-orchestrator.js +3 -1
  13. package/dist/core/agents/agent-scheduler.js +14 -1
  14. package/dist/core/agents/native-cli-session-swarm.js +11 -7
  15. package/dist/core/agents/native-cli-worker.js +56 -7
  16. package/dist/core/agents/parallel-runtime-proof.js +68 -9
  17. package/dist/core/agents/runtime-proof-summary.js +75 -0
  18. package/dist/core/codex-app/codex-app-handoff.js +77 -0
  19. package/dist/core/codex-control/codex-0138-capability.js +64 -0
  20. package/dist/core/codex-control/codex-model-capabilities.js +41 -0
  21. package/dist/core/codex-control/codex-sdk-config-policy.js +1 -1
  22. package/dist/core/codex-control/codex-task-runner.js +1 -1
  23. package/dist/core/codex-plugins/codex-plugin-json.js +152 -0
  24. package/dist/core/commands/mad-sks-command.js +4 -0
  25. package/dist/core/commands/naruto-command.js +20 -4
  26. package/dist/core/commands/qa-loop-command.js +111 -4
  27. package/dist/core/commands/team-command.js +6 -311
  28. package/dist/core/commands/team-legacy-observe-command.js +182 -0
  29. package/dist/core/db-safety.js +15 -0
  30. package/dist/core/doctor/codex-0138-doctor.js +104 -0
  31. package/dist/core/doctor/doctor-readiness-matrix.js +11 -0
  32. package/dist/core/effort-orchestrator.js +9 -0
  33. package/dist/core/feature-registry.js +4 -2
  34. package/dist/core/fsx.js +1 -1
  35. package/dist/core/hooks-runtime.js +38 -4
  36. package/dist/core/image/image-artifact-path-contract.js +99 -0
  37. package/dist/core/image-ux-review/imagegen-adapter.js +24 -3
  38. package/dist/core/init.js +1 -0
  39. package/dist/core/mad-db/mad-db-capability.js +9 -1
  40. package/dist/core/mad-db/mad-db-result-lifecycle.js +207 -0
  41. package/dist/core/mcp/mcp-plugin-inventory.js +29 -0
  42. package/dist/core/mcp/mcp-server-policy.js +24 -0
  43. package/dist/core/qa-loop/qa-loop-budget-policy.js +37 -0
  44. package/dist/core/qa-loop.js +28 -2
  45. package/dist/core/release/release-gate-affected-selector.js +47 -5
  46. package/dist/core/release/release-gate-dag.js +5 -1
  47. package/dist/core/release/release-gate-scheduler.js +2 -1
  48. package/dist/core/routes.js +3 -1
  49. package/dist/core/usage/codex-account-usage.js +78 -0
  50. package/dist/core/version.js +1 -1
  51. package/dist/core/zellij/zellij-slot-column-anchor.js +16 -7
  52. package/dist/core/zellij/zellij-slot-pane-renderer.js +92 -1
  53. package/dist/core/zellij/zellij-slot-telemetry.js +29 -6
  54. package/dist/core/zellij/zellij-ui-mode.js +12 -2
  55. package/dist/scripts/prepublish-release-check-or-fast.js +3 -3
  56. package/dist/scripts/release-gate-existence-audit.js +5 -1
  57. package/dist/scripts/release-speed-summary.js +22 -2
  58. package/package.json +38 -4
  59. package/schemas/agents/parallel-runtime-proof.schema.json +31 -0
  60. package/schemas/codex-app/codex-app-handoff.schema.json +20 -0
  61. package/schemas/codex-plugins/codex-plugin-inventory.schema.json +32 -0
  62. package/schemas/image/image-artifact-path-contract.schema.json +32 -0
  63. package/schemas/usage/codex-account-usage.schema.json +27 -0
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { appendJsonlBounded, ensureDir, nowIso, readText, writeJsonAtomic } from '../fsx.js';
2
+ import { appendJsonlBounded, ensureDir, nowIso, readJson, readText, writeJsonAtomic } from '../fsx.js';
3
3
  export const PARALLEL_RUNTIME_EVENT_SCHEMA = 'sks.parallel-runtime-event.v1';
4
4
  export const PARALLEL_RUNTIME_PROOF_SCHEMA = 'sks.parallel-runtime-proof.v1';
5
5
  export function parallelRuntimeEventPath(root, missionId) {
@@ -92,6 +92,9 @@ export async function buildParallelRuntimeProof(root, missionId, opts = {}) {
92
92
  }
93
93
  const requestedWorkers = positiveInt(opts.requestedWorkers, workerStarts.size || workerPids.size || maxWorkers);
94
94
  const targetActiveSlots = positiveInt(opts.targetActiveSlots, requestedWorkers);
95
+ const proofMode = opts.proofMode || 'production';
96
+ const allowMissingPids = proofMode === 'in-process-fixture' && opts.allowMissingPids === true;
97
+ const requireWorkerPids = opts.requireWorkerPids ?? (proofMode === 'production' && requestedWorkers >= 16);
95
98
  const wallMs = Math.max(0, lastMs - firstMs);
96
99
  const sequentialEstimateMs = workerDurations.length
97
100
  ? workerDurations.reduce((sum, value) => sum + value, 0)
@@ -107,17 +110,33 @@ export async function buildParallelRuntimeProof(root, missionId, opts = {}) {
107
110
  const launchEvents = sorted.filter((event) => event.event_type === 'worker_launch_invoked' || event.event_type === 'worker_process_spawned');
108
111
  const launchSpanMs = launchEvents.length ? Math.max(...launchEvents.map((event) => event.ms)) - Math.min(...launchEvents.map((event) => event.ms)) : 0;
109
112
  const firstBatchLimit = positiveInt(opts.firstBatchLaunchSpanLimitMs, requestedWorkers >= 16 ? 2500 : 30000);
110
- const blockers = [
111
- ...(sorted.length ? [] : ['parallel_runtime_events_missing']),
112
- ...(minActiveWorkers <= 0 || maxWorkers >= minActiveWorkers ? [] : ['max_observed_active_workers_below_target']),
113
- ...(requestedWorkers >= 16 && workerPids.size && workerPids.size < minActiveWorkers ? ['unique_worker_pids_below_target'] : []),
114
- ...(speedupRatio >= minSpeedup ? [] : ['speedup_ratio_below_target']),
115
- ...(firstBatchLaunchSpanMs <= firstBatchLimit ? [] : ['first_batch_launch_span_above_limit'])
116
- ];
113
+ const schedulerState = await readJson(path.join(root, 'agent-scheduler-state.json'), null).catch(() => null);
114
+ const coalescedOverlapWindows = coalesceOverlapWindows(overlapWindows);
115
+ const utilizationProofConsistency = buildUtilizationProofConsistency(schedulerState, {
116
+ proofMaxActive: maxWorkers,
117
+ proofWallMs: wallMs,
118
+ proofActiveSlotTimeMs: activeSlotTimeMsFromWindows(coalescedOverlapWindows)
119
+ });
120
+ const blockers = [];
121
+ if (!sorted.length)
122
+ blockers.push('parallel_runtime_events_missing');
123
+ if (minActiveWorkers > 0 && maxWorkers < minActiveWorkers)
124
+ blockers.push('max_observed_active_workers_below_target');
125
+ if (requireWorkerPids && workerPids.size < minActiveWorkers)
126
+ blockers.push('unique_worker_pids_below_target');
127
+ if (requireWorkerPids && workerPids.size === 0)
128
+ blockers.push('unique_worker_pids_missing_in_production_proof');
129
+ if (speedupRatio < minSpeedup)
130
+ blockers.push('speedup_ratio_below_target');
131
+ if (firstBatchLaunchSpanMs > firstBatchLimit)
132
+ blockers.push('first_batch_launch_span_above_limit');
117
133
  return {
118
134
  schema: PARALLEL_RUNTIME_PROOF_SCHEMA,
119
135
  mission_id: missionId,
120
136
  generated_at: nowIso(),
137
+ proof_mode: proofMode,
138
+ require_worker_pids: requireWorkerPids,
139
+ allow_missing_pids: allowMissingPids,
121
140
  requested_workers: requestedWorkers,
122
141
  target_active_slots: targetActiveSlots,
123
142
  max_observed_active_workers: maxWorkers,
@@ -130,9 +149,10 @@ export async function buildParallelRuntimeProof(root, missionId, opts = {}) {
130
149
  wall_ms: wallMs,
131
150
  sequential_estimate_ms: sequentialEstimateMs,
132
151
  speedup_ratio: speedupRatio,
133
- overlap_windows: coalesceOverlapWindows(overlapWindows),
152
+ overlap_windows: coalescedOverlapWindows,
134
153
  visible_panes: visiblePanes,
135
154
  headless_workers: headlessWorkers,
155
+ utilization_proof_consistency: utilizationProofConsistency,
136
156
  passed: blockers.length === 0,
137
157
  blockers
138
158
  };
@@ -196,6 +216,45 @@ function nonNegativeInt(value, fallback) {
196
216
  return Math.max(0, Math.floor(fallback || 0));
197
217
  return Math.floor(parsed);
198
218
  }
219
+ function buildUtilizationProofConsistency(state, input) {
220
+ if (!state || typeof state !== 'object') {
221
+ return {
222
+ ok: true,
223
+ scheduler_max_active: 0,
224
+ proof_max_active: input.proofMaxActive,
225
+ wall_ms_delta: 0,
226
+ scheduler_active_slot_time_ms: 0,
227
+ proof_active_slot_time_ms: input.proofActiveSlotTimeMs,
228
+ active_slot_time_ms_delta: 0,
229
+ scheduler_observation_delay_tolerance_ms: 0
230
+ };
231
+ }
232
+ const schedulerMaxActive = nonNegativeInt(state.max_observed_active_slots, 0);
233
+ const schedulerWallMs = nonNegativeInt(state.wall_time_ms, 0);
234
+ const schedulerActiveSlotTimeMs = nonNegativeInt(state.active_slot_time_ms, 0);
235
+ const wallDelta = Math.abs(schedulerWallMs - input.proofWallMs);
236
+ const activeSlotDelta = Math.abs(schedulerActiveSlotTimeMs - input.proofActiveSlotTimeMs);
237
+ const maxActiveDelta = Math.abs(schedulerMaxActive - input.proofMaxActive);
238
+ const wallToleranceMs = Math.max(500, Math.round(Math.max(schedulerWallMs, input.proofWallMs) * 0.25));
239
+ const activeSlotToleranceMs = Math.max(500, Math.round(Math.max(schedulerActiveSlotTimeMs, input.proofActiveSlotTimeMs) * 0.25));
240
+ const observationDelayToleranceMs = Math.max(activeSlotToleranceMs, wallDelta * Math.max(1, schedulerMaxActive));
241
+ const wallConsistent = wallDelta <= wallToleranceMs;
242
+ const activeSlotConsistent = schedulerActiveSlotTimeMs > 0 && input.proofActiveSlotTimeMs > 0 && (activeSlotDelta <= activeSlotToleranceMs
243
+ || (schedulerActiveSlotTimeMs >= input.proofActiveSlotTimeMs && activeSlotDelta <= observationDelayToleranceMs));
244
+ return {
245
+ ok: maxActiveDelta <= 1 && (wallConsistent || activeSlotConsistent),
246
+ scheduler_max_active: schedulerMaxActive,
247
+ proof_max_active: input.proofMaxActive,
248
+ wall_ms_delta: wallDelta,
249
+ scheduler_active_slot_time_ms: schedulerActiveSlotTimeMs,
250
+ proof_active_slot_time_ms: input.proofActiveSlotTimeMs,
251
+ active_slot_time_ms_delta: activeSlotDelta,
252
+ scheduler_observation_delay_tolerance_ms: observationDelayToleranceMs
253
+ };
254
+ }
255
+ function activeSlotTimeMsFromWindows(windows) {
256
+ return windows.reduce((sum, window) => sum + Math.max(0, window.end_ms - window.start_ms) * Math.max(0, window.active_workers), 0);
257
+ }
199
258
  function coalesceOverlapWindows(windows) {
200
259
  return windows
201
260
  .filter((window) => window.end_ms > window.start_ms)
@@ -0,0 +1,75 @@
1
+ import path from 'node:path';
2
+ import { findLatestMission, missionDir } from '../mission.js';
3
+ import { readJson, writeJsonAtomic } from '../fsx.js';
4
+ export const RUNTIME_PROOF_SUMMARY_SCHEMA = 'sks.runtime-proof-summary.v1';
5
+ export async function buildRuntimeProofSummary(root, missionIdInput = 'latest') {
6
+ const missionId = missionIdInput === 'latest' ? await findLatestMission(root) : missionIdInput;
7
+ if (!missionId)
8
+ throw new Error('runtime_proof_summary_mission_missing');
9
+ const dir = missionDir(root, missionId);
10
+ const agentsDir = path.join(dir, 'agents');
11
+ const parallel = await readJson(path.join(agentsDir, 'parallel-runtime-proof.json'), null);
12
+ const scheduler = await readJson(path.join(agentsDir, 'agent-scheduler-state.json'), null);
13
+ const swarm = await readJson(path.join(agentsDir, 'agent-native-cli-session-swarm.json'), null);
14
+ const telemetry = await readJson(path.join(dir, 'zellij', 'slot-telemetry.snapshot.json'), null);
15
+ const governor = await readJson(path.join(agentsDir, 'naruto-concurrency-governor.json'), null);
16
+ const telemetryAgeMs = telemetry?.updated_at ? Math.max(0, Date.now() - Date.parse(telemetry.updated_at)) : Number.MAX_SAFE_INTEGER;
17
+ const visiblePanes = Number(parallel?.visible_panes ?? swarm?.zellij_pane_worker_sessions ?? telemetryVisiblePaneCount(telemetry) ?? 0);
18
+ const targetActive = Number(scheduler?.target_active_slots ?? parallel?.target_active_slots ?? swarm?.target_active_slots ?? governor?.target_active_slots ?? 0);
19
+ const headlessWorkers = Number(parallel?.headless_workers ?? swarm?.headless_overflow_worker_count ?? Math.max(0, targetActive - visiblePanes));
20
+ const blockers = [
21
+ ...(!parallel ? ['parallel_runtime_proof_missing'] : []),
22
+ ...(!scheduler ? ['agent_scheduler_state_missing'] : []),
23
+ ...(parallel?.passed === false ? parallel.blockers || ['parallel_runtime_proof_failed'] : []),
24
+ ...(telemetryAgeMs > 3000 ? ['zellij_telemetry_stale'] : [])
25
+ ].map(String);
26
+ const summary = {
27
+ schema: RUNTIME_PROOF_SUMMARY_SCHEMA,
28
+ ok: blockers.length === 0,
29
+ mission_id: missionId,
30
+ generated_at: new Date().toISOString(),
31
+ parallel: {
32
+ max_active_workers: Number(parallel?.max_observed_active_workers || scheduler?.max_observed_active_slots || 0),
33
+ unique_worker_pids: Number(parallel?.unique_worker_pids || uniqueNumbers(swarm?.process_ids).length || 0),
34
+ speedup_ratio: Number(parallel?.speedup_ratio || 0),
35
+ proof_passed: parallel?.passed === true
36
+ },
37
+ ui: {
38
+ visible_panes: visiblePanes,
39
+ headless_workers: headlessWorkers,
40
+ telemetry_age_ms: telemetryAgeMs,
41
+ stale: telemetryAgeMs > 3000
42
+ },
43
+ model_calls: {
44
+ max_observed: Number(parallel?.max_observed_model_calls || 0),
45
+ unique_model_call_ids: Number(parallel?.unique_model_call_ids || 0)
46
+ },
47
+ scheduler: {
48
+ largest_batch_size: Number(scheduler?.largest_batch_size || 0),
49
+ utilization: Number(scheduler?.scheduler_utilization || 0)
50
+ },
51
+ blockers
52
+ };
53
+ await writeJsonAtomic(path.join(agentsDir, 'runtime-proof-summary.json'), summary);
54
+ return summary;
55
+ }
56
+ export function renderRuntimeProofSummary(summary) {
57
+ return [
58
+ `Parallel proof: ${summary.parallel.proof_passed ? 'passed' : 'blocked'}`,
59
+ `Active workers: ${summary.parallel.max_active_workers}`,
60
+ `Unique PIDs: ${summary.parallel.unique_worker_pids}`,
61
+ `Speedup: ${summary.parallel.speedup_ratio}x`,
62
+ `Visible/headless: ${summary.ui.visible_panes} / ${summary.ui.headless_workers}`,
63
+ `Telemetry: ${summary.ui.stale ? `stale ${(summary.ui.telemetry_age_ms / 1000).toFixed(1)}s` : `fresh ${(summary.ui.telemetry_age_ms / 1000).toFixed(1)}s`}`,
64
+ `Model calls max: ${summary.model_calls.max_observed}`,
65
+ ...(summary.blockers.length ? [`Blockers: ${summary.blockers.join(', ')}`] : [])
66
+ ].join('\n');
67
+ }
68
+ function telemetryVisiblePaneCount(snapshot) {
69
+ const slots = snapshot?.slots && typeof snapshot.slots === 'object' ? Object.values(snapshot.slots) : [];
70
+ return slots.filter((row) => row?.status && row.status !== 'headless').length;
71
+ }
72
+ function uniqueNumbers(values) {
73
+ return [...new Set((Array.isArray(values) ? values : []).map((value) => Number(value)).filter((value) => Number.isFinite(value)))];
74
+ }
75
+ //# sourceMappingURL=runtime-proof-summary.js.map
@@ -0,0 +1,77 @@
1
+ import path from 'node:path';
2
+ import { detectCodex0138Capability } from '../codex-control/codex-0138-capability.js';
3
+ import { nowIso, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
4
+ export function buildCodexAppHandoffPrompt(request) {
5
+ return [
6
+ 'SKS Codex Desktop /app handoff request',
7
+ `Mission: ${request.mission_id}`,
8
+ `Route: ${request.route}`,
9
+ `Reason: ${request.reason}`,
10
+ `Workspace: ${request.workspace_path}`,
11
+ request.thread_ref ? `Thread: ${request.thread_ref}` : '',
12
+ '',
13
+ 'Artifacts:',
14
+ ...(request.artifacts || []).map((artifact) => `- ${artifact}`),
15
+ '',
16
+ 'Prompt:',
17
+ request.prompt,
18
+ '',
19
+ 'Operator instruction: open Codex Desktop with `codex /app` and continue this mission using the artifacts above. Do not treat this handoff artifact as web UI verification evidence.'
20
+ ].filter((line) => line !== '').join('\n');
21
+ }
22
+ export async function runCodexAppHandoff(root, request) {
23
+ const capability = await detectCodex0138Capability();
24
+ const platformSupported = process.platform === 'darwin' || process.platform === 'win32';
25
+ const desktopSupported = capability.supports_app_handoff === true && platformSupported;
26
+ const dir = path.join(root, '.sneakoscope', 'missions', request.mission_id, 'qa-loop');
27
+ const artifactPath = path.join(dir, 'app-handoff.json');
28
+ const promptArtifactPath = path.join(dir, 'app-handoff-prompt.md');
29
+ const blockers = [
30
+ ...(capability.supports_app_handoff ? [] : ['codex_0_138_app_handoff_unavailable']),
31
+ ...(platformSupported ? [] : ['codex_app_handoff_platform_unsupported'])
32
+ ];
33
+ const prompt = buildCodexAppHandoffPrompt(request);
34
+ await writeTextAtomic(promptArtifactPath, prompt);
35
+ const status = request.require_desktop && !desktopSupported
36
+ ? 'blocked_for_desktop_review'
37
+ : desktopSupported
38
+ ? 'pending'
39
+ : 'skipped';
40
+ const result = {
41
+ schema: 'sks.codex-app-handoff-result.v1',
42
+ ok: request.require_desktop ? desktopSupported : true,
43
+ attempted: false,
44
+ launched: false,
45
+ status,
46
+ codex_0138_capability: capability,
47
+ command_line: ['codex', '/app'],
48
+ desktop_handoff_supported: desktopSupported,
49
+ fallback_reason: desktopSupported
50
+ ? 'interactive_tui_handoff_pending_operator'
51
+ : blockers.join(';') || null,
52
+ artifact_path: artifactPath,
53
+ prompt_artifact_path: promptArtifactPath,
54
+ blockers: request.require_desktop ? blockers : []
55
+ };
56
+ await writeJsonAtomic(artifactPath, {
57
+ ...result,
58
+ request,
59
+ operator_instruction: {
60
+ open: 'codex /app',
61
+ prompt_artifact: path.relative(root, promptArtifactPath),
62
+ created_at: nowIso()
63
+ }
64
+ });
65
+ return result;
66
+ }
67
+ export function qaLoopShouldRequestAppHandoff(input = {}) {
68
+ const args = input.args || [];
69
+ return args.includes('--app-handoff')
70
+ || process.env.SKS_QA_LOOP_APP_HANDOFF === '1'
71
+ || input.visualArtifactsPresent === true
72
+ || input.zellijUiBlocked === true
73
+ || input.pluginAppTemplateUnavailable === true
74
+ || input.userRequestedDesktopReview === true
75
+ || input.uiRequired === true && process.env.SKS_QA_LOOP_APP_HANDOFF_FOR_VISUAL === '1';
76
+ }
77
+ //# sourceMappingURL=codex-app-handoff.js.map
@@ -0,0 +1,64 @@
1
+ import path from 'node:path';
2
+ import { findCodexBinary } from '../codex-adapter.js';
3
+ import { compareSemverLike, parseCodexVersionText } from '../codex-compat/codex-version-policy.js';
4
+ import { nowIso, runProcess, writeJsonAtomic } from '../fsx.js';
5
+ export async function detectCodex0138Capability(input = {}) {
6
+ const fake = process.env.SKS_CODEX_0138_FAKE === '1';
7
+ const codexBin = fake
8
+ ? input.codexBin || process.env.CODEX_BIN || 'codex'
9
+ : input.codexBin || process.env.CODEX_BIN || await findCodexBinary();
10
+ const versionText = fake
11
+ ? String(process.env.SKS_CODEX_VERSION_FAKE || 'codex-cli 0.138.0')
12
+ : await readCodexVersionText(codexBin);
13
+ const parsed = parseCodexVersion(versionText);
14
+ const atLeast138 = Boolean(parsed && semverGte(parsed, '0.138.0'));
15
+ const blockers = [
16
+ ...(!codexBin ? ['codex_cli_missing'] : []),
17
+ ...(atLeast138 ? [] : ['codex_0_138_required_for_app_plugin_features'])
18
+ ];
19
+ return {
20
+ schema: 'sks.codex-0138-capability.v1',
21
+ ok: atLeast138,
22
+ codex_bin: codexBin || null,
23
+ version_text: versionText || null,
24
+ parsed_version: parsed,
25
+ supports_app_handoff: atLeast138,
26
+ supports_plugin_json: atLeast138,
27
+ supports_image_path_exposure: atLeast138,
28
+ supports_model_defined_efforts: atLeast138,
29
+ supports_app_server_token_usage: atLeast138,
30
+ supports_v2_pat_auth: atLeast138,
31
+ supports_oauth_mcp_prerefresh: atLeast138,
32
+ blockers
33
+ };
34
+ }
35
+ export async function writeCodex0138CapabilityArtifacts(root, input = {}) {
36
+ const capability = await detectCodex0138Capability({ codexBin: input.codexBin || null });
37
+ const report = { ...capability, generated_at: nowIso() };
38
+ const rootArtifact = path.join(root, '.sneakoscope', 'codex-0138-capability.json');
39
+ await writeJsonAtomic(rootArtifact, report);
40
+ let missionArtifact = null;
41
+ if (input.missionId) {
42
+ missionArtifact = path.join(root, '.sneakoscope', 'missions', input.missionId, 'codex-0138-capability.json');
43
+ await writeJsonAtomic(missionArtifact, report);
44
+ }
45
+ return { report, root_artifact: rootArtifact, mission_artifact: missionArtifact };
46
+ }
47
+ export function parseCodexVersion(text) {
48
+ return parseCodexVersionText(text);
49
+ }
50
+ export function semverGte(actual, minimum) {
51
+ return compareSemverLike(actual, minimum) >= 0;
52
+ }
53
+ async function readCodexVersionText(codexBin) {
54
+ if (!codexBin)
55
+ return null;
56
+ const result = await runProcess(codexBin, ['--version'], { timeoutMs: 10_000, maxOutputBytes: 16 * 1024 }).catch((err) => ({
57
+ code: 1,
58
+ stdout: '',
59
+ stderr: err?.message || String(err)
60
+ }));
61
+ const text = `${result.stdout || ''}${result.stderr || ''}`.trim();
62
+ return result.code === 0 ? text : text || null;
63
+ }
64
+ //# sourceMappingURL=codex-0138-capability.js.map
@@ -0,0 +1,41 @@
1
+ export const SKS_FALLBACK_EFFORT_ORDER = ['minimal', 'low', 'medium', 'high', 'xhigh'];
2
+ export function codexModelEffortCapability(input = {}) {
3
+ const advertised = normalizeAdvertisedEfforts(input.advertisedEfforts);
4
+ const order = advertised.length ? advertised : SKS_FALLBACK_EFFORT_ORDER;
5
+ const defaultEffort = order.includes(String(input.defaultEffort || '')) ? String(input.defaultEffort) : order.includes('medium') ? 'medium' : order[0] || 'medium';
6
+ return {
7
+ model: String(input.model || process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || 'gpt-5.5'),
8
+ advertised_efforts: order,
9
+ default_effort: defaultEffort,
10
+ order_source: advertised.length ? 'model-advertised' : 'sks-fallback'
11
+ };
12
+ }
13
+ export function normalizeAdvertisedEfforts(value) {
14
+ const rows = Array.isArray(value) ? value : String(value || '').split(',');
15
+ const seen = new Set();
16
+ const out = [];
17
+ for (const row of rows) {
18
+ const effort = String(row || '').trim().toLowerCase();
19
+ if (!effort || seen.has(effort))
20
+ continue;
21
+ seen.add(effort);
22
+ out.push(effort);
23
+ }
24
+ return out;
25
+ }
26
+ export function nextAdvertisedEffort(current, capability = codexModelEffortCapability()) {
27
+ const order = capability.advertised_efforts.length ? capability.advertised_efforts : SKS_FALLBACK_EFFORT_ORDER;
28
+ const index = Math.max(0, order.indexOf(current));
29
+ return order[Math.min(order.length - 1, index + 1)] || current || capability.default_effort;
30
+ }
31
+ export function modelEffortAtLeast(target, capability = codexModelEffortCapability()) {
32
+ const order = capability.advertised_efforts.length ? capability.advertised_efforts : SKS_FALLBACK_EFFORT_ORDER;
33
+ if (order.includes(target))
34
+ return target;
35
+ if (target === 'recovery')
36
+ return order.includes('high') ? 'high' : order[order.length - 1];
37
+ if (target === 'forensic_vision')
38
+ return order.includes('xhigh') ? 'xhigh' : order[order.length - 1];
39
+ return capability.default_effort;
40
+ }
41
+ //# sourceMappingURL=codex-model-capabilities.js.map
@@ -2,7 +2,7 @@ export function buildCodexSdkConfig(input) {
2
2
  const config = {
3
3
  model: String(process.env.SKS_CODEX_MODEL || process.env.CODEX_MODEL || 'gpt-5.5'),
4
4
  service_tier: 'fast',
5
- model_reasoning_effort: 'medium',
5
+ model_reasoning_effort: String(input.modelReasoningEffort || input.reasoningEffort || process.env.SKS_CODEX_REASONING || process.env.CODEX_MODEL_REASONING_EFFORT || 'medium'),
6
6
  mcp_servers: {},
7
7
  sks: {
8
8
  route: input.route,
@@ -445,7 +445,7 @@ async function ensurePythonCodexLbConfig(env, config) {
445
445
  `model = ${tomlQuote(model)}`,
446
446
  'model_provider = "codex-lb"',
447
447
  'service_tier = "fast"',
448
- 'model_reasoning_effort = "minimal"',
448
+ `model_reasoning_effort = ${tomlQuote(String(config.model_reasoning_effort || env.SKS_CODEX_REASONING || env.CODEX_MODEL_REASONING_EFFORT || 'minimal'))}`,
449
449
  'approval_policy = "never"',
450
450
  '',
451
451
  '[model_providers.codex-lb]',
@@ -0,0 +1,152 @@
1
+ import path from 'node:path';
2
+ import { findCodexBinary } from '../codex-adapter.js';
3
+ import { detectCodex0138Capability } from '../codex-control/codex-0138-capability.js';
4
+ import { nowIso, runProcess, writeJsonAtomic } from '../fsx.js';
5
+ export async function runCodexPluginListJson() {
6
+ if (process.env.SKS_CODEX_PLUGIN_JSON_FAKE === '1')
7
+ return fakePluginList();
8
+ const bin = await findCodexBinary();
9
+ if (!bin)
10
+ return { plugins: [], blockers: ['codex_cli_missing'] };
11
+ return runCodexJson(bin, ['plugin', 'list', '--json']);
12
+ }
13
+ export async function runCodexPluginDetailJson(pluginId) {
14
+ if (process.env.SKS_CODEX_PLUGIN_JSON_FAKE === '1')
15
+ return fakePluginDetail(pluginId);
16
+ const bin = await findCodexBinary();
17
+ if (!bin)
18
+ return { blockers: ['codex_cli_missing'] };
19
+ return runCodexJson(bin, ['plugin', 'detail', pluginId, '--json']);
20
+ }
21
+ export async function buildCodexPluginInventory() {
22
+ const capability = await detectCodex0138Capability();
23
+ const listJson = await runCodexPluginListJson();
24
+ const summaries = normalizePluginList(listJson);
25
+ const plugins = [];
26
+ for (const summary of summaries) {
27
+ const detail = await runCodexPluginDetailJson(summary.id || summary.name).catch((err) => ({ error: err?.message || String(err) }));
28
+ plugins.push(normalizePlugin(summary, detail));
29
+ }
30
+ const blockers = [
31
+ ...(capability.supports_plugin_json ? [] : ['codex_0_138_plugin_json_unavailable']),
32
+ ...normalizeList(listJson?.blockers)
33
+ ];
34
+ return {
35
+ schema: 'sks.codex-plugin-inventory.v1',
36
+ generated_at: nowIso(),
37
+ codex_0138_capability: capability,
38
+ plugins,
39
+ marketplace_available: plugins.some((plugin) => plugin.source === 'marketplace' || plugin.source === 'remote') || Boolean(listJson?.marketplace_available || listJson?.marketplaceAvailable),
40
+ blockers
41
+ };
42
+ }
43
+ export async function writeCodexPluginInventoryArtifacts(root, inventory = null) {
44
+ const report = inventory || await buildCodexPluginInventory();
45
+ const artifact = path.join(root, '.sneakoscope', 'codex-plugin-inventory.json');
46
+ await writeJsonAtomic(artifact, report);
47
+ return { report, artifact };
48
+ }
49
+ export function pluginAppTemplatePolicy(inventory) {
50
+ const unavailable = inventory.plugins.flatMap((plugin) => plugin.unavailable_app_templates.map((template) => ({
51
+ plugin: plugin.id,
52
+ template
53
+ })));
54
+ return {
55
+ schema: 'sks.codex-plugin-app-template-policy.v1',
56
+ ok: true,
57
+ unavailable_app_templates: unavailable,
58
+ qa_loop_app_handoff_recommended: unavailable.length > 0,
59
+ doctor_warnings: unavailable.map((row) => `plugin_app_template_unavailable:${row.plugin}`)
60
+ };
61
+ }
62
+ async function runCodexJson(bin, args) {
63
+ const result = await runProcess(bin, args, { timeoutMs: 20_000, maxOutputBytes: 256 * 1024 }).catch((err) => ({
64
+ code: 1,
65
+ stdout: '',
66
+ stderr: err?.message || String(err)
67
+ }));
68
+ const text = `${result.stdout || ''}${result.stderr || ''}`.trim();
69
+ try {
70
+ return text ? JSON.parse(text) : {};
71
+ }
72
+ catch {
73
+ return { raw_text: text, blockers: [`codex_plugin_json_parse_failed:${args.join(' ')}`] };
74
+ }
75
+ }
76
+ function normalizePluginList(value) {
77
+ if (Array.isArray(value))
78
+ return value;
79
+ for (const key of ['plugins', 'installed_plugins', 'installedPlugins', 'items']) {
80
+ if (Array.isArray(value?.[key]))
81
+ return value[key];
82
+ }
83
+ return [];
84
+ }
85
+ function normalizePlugin(summary, detail) {
86
+ const raw = { summary, detail };
87
+ const id = String(detail?.id || summary?.id || summary?.plugin_id || summary?.name || 'unknown');
88
+ const name = String(detail?.name || summary?.name || id);
89
+ const sourceText = String(detail?.source || detail?.marketplaceSource || summary?.source || summary?.marketplaceSource || '').toLowerCase();
90
+ const source = sourceText.includes('marketplace') ? 'marketplace'
91
+ : sourceText.includes('remote') ? 'remote'
92
+ : sourceText.includes('local') ? 'local'
93
+ : 'unknown';
94
+ return {
95
+ id,
96
+ name,
97
+ source,
98
+ installed: boolish(detail?.installed ?? summary?.installed, true),
99
+ enabled: boolish(detail?.enabled ?? summary?.enabled, true),
100
+ default_prompts: normalizeList(detail?.default_prompts || detail?.defaultPrompts || detail?.prompts),
101
+ remote_mcp_servers: normalizeMcpServers(detail?.remote_mcp_servers || detail?.remoteMcpServers || detail?.mcp_servers || detail?.mcpServers),
102
+ unavailable_app_templates: normalizeList(detail?.unavailable_app_templates || detail?.unavailableAppTemplates || detail?.app_templates_unavailable),
103
+ raw
104
+ };
105
+ }
106
+ function normalizeMcpServers(value) {
107
+ const rows = Array.isArray(value) ? value : value && typeof value === 'object' ? Object.entries(value).map(([name, row]) => ({ name, ...(row || {}) })) : [];
108
+ return rows.map((row, index) => ({
109
+ name: String(row?.name || row?.id || `remote-mcp-${index + 1}`),
110
+ url: stringOrNull(row?.url || row?.endpoint),
111
+ auth_type: stringOrNull(row?.auth_type || row?.authType || row?.auth)
112
+ }));
113
+ }
114
+ function normalizeList(value) {
115
+ return Array.isArray(value) ? value.filter(Boolean).map(String) : value ? [String(value)] : [];
116
+ }
117
+ function stringOrNull(value) {
118
+ const text = String(value || '').trim();
119
+ return text ? text : null;
120
+ }
121
+ function boolish(value, fallback = false) {
122
+ if (value === true || value === 'true')
123
+ return true;
124
+ if (value === false || value === 'false')
125
+ return false;
126
+ return fallback;
127
+ }
128
+ function fakePluginList() {
129
+ return {
130
+ marketplace_available: true,
131
+ plugins: [{
132
+ id: 'fixture-plugin',
133
+ name: 'Fixture Plugin',
134
+ source: 'marketplace',
135
+ installed: true,
136
+ enabled: true
137
+ }]
138
+ };
139
+ }
140
+ function fakePluginDetail(pluginId) {
141
+ return {
142
+ id: pluginId,
143
+ name: pluginId,
144
+ source: 'marketplace',
145
+ installed: true,
146
+ enabled: true,
147
+ default_prompts: ['Use the fixture plugin safely.'],
148
+ remote_mcp_servers: [{ name: 'fixture-db-docs', url: 'https://mcp.example.test', auth_type: 'oauth' }],
149
+ unavailable_app_templates: ['fixture-desktop-template']
150
+ };
151
+ }
152
+ //# sourceMappingURL=codex-plugin-json.js.map
@@ -20,6 +20,7 @@ import { runCodexLaunchPreflight } from '../preflight/parallel-preflight-engine.
20
20
  import { diffCodexAppUiSnapshots, writeCodexAppUiSnapshot } from '../codex-app/codex-app-ui-state-snapshot.js';
21
21
  import { checkSksUpdateNotice } from '../update/update-notice.js';
22
22
  import { createMadDbCapability, MAD_DB_ACK } from '../mad-db/mad-db-capability.js';
23
+ import { writeCodex0138CapabilityArtifacts } from '../codex-control/codex-0138-capability.js';
23
24
  export async function madHighCommand(args = [], deps = {}) {
24
25
  const subcommand = firstSubcommand(args);
25
26
  if (subcommand)
@@ -379,6 +380,7 @@ async function activateMadZellijPermissionState(cwd = process.cwd(), args = [])
379
380
  const has = (scope) => allowedScopes.has(scope);
380
381
  const dbWriteAllowed = has('db_write');
381
382
  const { id, dir } = await createMission(root, { mode: 'mad-sks', prompt: 'sks --mad Zellij scoped high-power maintenance session' });
383
+ await writeCodex0138CapabilityArtifacts(root, { missionId: id }).catch(() => null);
382
384
  const protectedCore = resolveProtectedCore({ packageRoot: packageRoot(), targetRoot: cwd });
383
385
  // The interactive launch 'before' snapshot is only persisted (env + policy json)
384
386
  // and is never compared against an 'after' snapshot during the session, so the
@@ -564,6 +566,7 @@ function codexLbImmediateLaunchOpts(args = [], lb = {}, opts = {}) {
564
566
  }
565
567
  export async function madSksFixture(root) {
566
568
  const { id, dir } = await createMission(root, { mode: 'mad-sks', prompt: '$MAD-SKS fixture permission gate' });
569
+ await writeCodex0138CapabilityArtifacts(root, { missionId: id }).catch(() => null);
567
570
  const gate = { schema_version: 1, passed: true, mad_sks_permission_active: true, permissions_deactivated: true, catastrophic_safety_guard_active: true, permission_profile: permissionGateSummary(), fixture: true };
568
571
  await writeJsonAtomic(path.join(dir, 'mad-sks-gate.json'), gate);
569
572
  return { mission_id: id, dir, gate };
@@ -738,6 +741,7 @@ async function materializeMadSksRun(root, targetRoot, permission, userIntent, js
738
741
  if (!(await exists(path.join(root, '.sneakoscope'))))
739
742
  await initProject(root, {});
740
743
  const { id, dir } = await createMission(root, { mode: 'mad-sks', prompt: userIntent });
744
+ await writeCodex0138CapabilityArtifacts(root, { missionId: id }).catch(() => null);
741
745
  const before = await snapshotProtectedCore(packageRoot(), 'before');
742
746
  const authorization = opts.authorizationManifest || createMadSksAuthorizationManifest({ permission, userIntent });
743
747
  const authorizationPath = opts.authorizationManifestPath || path.join(dir, 'mad-sks-authorization.json');
@@ -19,6 +19,8 @@ import { buildNarutoGptFinalPack } from '../naruto/naruto-gpt-final-pack.js';
19
19
  import { planNarutoZellijDashboard } from '../zellij/zellij-naruto-dashboard.js';
20
20
  import { checkPromptPlaceholders } from '../prompt/prompt-placeholder-guard.js';
21
21
  import { evaluateGitWorktreeCapability } from '../git/git-worktree-capability.js';
22
+ import { buildRuntimeProofSummary, renderRuntimeProofSummary } from '../agents/runtime-proof-summary.js';
23
+ import { writeCodex0138CapabilityArtifacts } from '../codex-control/codex-0138-capability.js';
22
24
  const NARUTO_RESULT_SCHEMA = 'sks.naruto-command-result.v1';
23
25
  const NARUTO_ROUTE = '$Naruto';
24
26
  // $Naruto — Shadow Clone Swarm (影分身 / Kage Bunshin no Jutsu).
@@ -37,6 +39,8 @@ export async function narutoCommand(commandOrArgs = 'naruto', maybeArgs = []) {
37
39
  return narutoDashboard(parsed);
38
40
  if (parsed.action === 'workers')
39
41
  return narutoWorkers(parsed);
42
+ if (parsed.action === 'proof')
43
+ return narutoProof(parsed);
40
44
  return narutoRun(parsed);
41
45
  }
42
46
  async function narutoRun(parsed) {
@@ -70,6 +74,7 @@ async function narutoRun(parsed) {
70
74
  maxAgentCount: MAX_NARUTO_AGENT_COUNT
71
75
  });
72
76
  const mission = await createMission(root, { mode: 'naruto', prompt: parsed.prompt });
77
+ await writeCodex0138CapabilityArtifacts(root, { missionId: mission.id }).catch(() => null);
73
78
  const gitWorktreeCapability = writeCapable
74
79
  ? await evaluateGitWorktreeCapability({ root, missionId: mission.id })
75
80
  : null;
@@ -379,7 +384,7 @@ async function narutoRun(parsed) {
379
384
  && Number(parallelRuntime.max_observed_active_workers || 0) >= Math.min(16, activeSlots));
380
385
  await writeJsonAtomic(path.join(mission.dir, 'naruto-gate.json'), {
381
386
  schema: 'sks.naruto-gate.v1',
382
- passed: result.ok === true && nativeProofOk && finalAccepted,
387
+ passed: result.ok === true && nativeProofOk && finalAccepted && parallelRuntimeOk,
383
388
  mission_id: mission.id,
384
389
  clone_roster_built: true,
385
390
  clone_count: roster.agent_count,
@@ -702,6 +707,16 @@ async function narutoWorkers(parsed) {
702
707
  console.log(`Active ${summary.active} · completed ${summary.completed} · failed ${summary.failed} · visible ${summary.visible_worker_panes.length} · headless ${summary.headless_workers.length}`);
703
708
  });
704
709
  }
710
+ async function narutoProof(parsed) {
711
+ const root = await sksRoot();
712
+ const id = parsed.missionId && parsed.missionId !== 'latest' ? parsed.missionId : await findLatestMission(root);
713
+ if (!id)
714
+ return emit(parsed, { schema: NARUTO_RESULT_SCHEMA, ok: false, action: 'proof', status: 'missing_mission' }, () => console.log('No Naruto mission found.'));
715
+ const summary = await buildRuntimeProofSummary(root, id);
716
+ return emit(parsed, { ...summary, action: 'proof' }, () => {
717
+ console.log(renderRuntimeProofSummary(summary));
718
+ });
719
+ }
705
720
  async function narutoHelp(parsed) {
706
721
  const help = {
707
722
  schema: NARUTO_RESULT_SCHEMA,
@@ -711,7 +726,8 @@ async function narutoHelp(parsed) {
711
726
  description: 'Shadow Clone Swarm: fan out up to ' + MAX_NARUTO_AGENT_COUNT + ' parallel clone sessions.',
712
727
  usage: [
713
728
  'sks naruto run "<task>" [--clones N] [--backend codex-sdk|fake|ollama] [--local-model|--no-ollama] [--work-items N] [--real] [--readonly] [--json]',
714
- 'sks naruto status [--mission <id>] [--json]'
729
+ 'sks naruto status [--mission <id>] [--json]',
730
+ 'sks naruto proof latest [--json]'
715
731
  ],
716
732
  defaults: { clones: DEFAULT_NARUTO_CLONES, max_clones: MAX_NARUTO_AGENT_COUNT, backend: 'codex-sdk' }
717
733
  };
@@ -726,7 +742,7 @@ function parseNarutoArgs(args = []) {
726
742
  if (hasFlag(args, '--help') || hasFlag(args, '-h'))
727
743
  args = ['help', ...args.filter((arg) => arg !== '--help' && arg !== '-h')];
728
744
  const first = args[0] && !String(args[0]).startsWith('--') ? String(args[0]) : '';
729
- const actions = new Set(['run', 'status', 'help', 'dashboard', 'workers']);
745
+ const actions = new Set(['run', 'status', 'help', 'dashboard', 'workers', 'proof']);
730
746
  const action = (actions.has(first) ? first : 'run');
731
747
  const rest = action === first ? args.slice(1) : args;
732
748
  const json = hasFlag(args, '--json');
@@ -743,7 +759,7 @@ function parseNarutoArgs(args = []) {
743
759
  const readonly = hasFlag(args, '--readonly') || hasFlag(args, '--read-only');
744
760
  const writeModeRaw = String(readOption(args, '--write-mode', hasFlag(args, '--parallel-write') ? 'parallel' : '') || '');
745
761
  const writeMode = (['proof-safe', 'parallel', 'serial', 'off'].includes(writeModeRaw) ? writeModeRaw : null);
746
- const positionalMission = action === 'dashboard' || action === 'workers' || action === 'status'
762
+ const positionalMission = action === 'dashboard' || action === 'workers' || action === 'status' || action === 'proof'
747
763
  ? positionalArgs(rest, new Set()).find((arg) => /^latest$|^M-/.test(arg))
748
764
  : null;
749
765
  const missionId = String(readOption(args, '--mission', readOption(args, '--mission-id', positionalMission || 'latest')));