sneakoscope 2.0.4 → 2.0.5

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 (104) hide show
  1. package/README.md +12 -8
  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/build-manifest.json +73 -8
  8. package/dist/commands/doctor.js +14 -0
  9. package/dist/core/agents/agent-proof-evidence.js +35 -0
  10. package/dist/core/agents/agent-roster.js +35 -6
  11. package/dist/core/agents/agent-schema.js +1 -1
  12. package/dist/core/agents/native-worker-backend-router.js +31 -9
  13. package/dist/core/agents/ollama-worker-config.js +164 -15
  14. package/dist/core/codex/codex-0-137-compat.js +119 -0
  15. package/dist/core/codex-control/codex-control-proof.js +4 -1
  16. package/dist/core/codex-control/codex-sdk-capability.js +1 -1
  17. package/dist/core/codex-control/codex-task-runner.js +329 -5
  18. package/dist/core/codex-control/python-codex-sdk-adapter.js +197 -0
  19. package/dist/core/codex-control/python-codex-sdk-event-translator.js +14 -0
  20. package/dist/core/commands/local-model-command.js +65 -19
  21. package/dist/core/commands/naruto-command.js +118 -7
  22. package/dist/core/commands/run-command.js +1 -1
  23. package/dist/core/doctor/doctor-readiness-matrix.js +21 -2
  24. package/dist/core/fsx.js +1 -1
  25. package/dist/core/local-llm/local-llm-backpressure.js +20 -0
  26. package/dist/core/local-llm/local-llm-capability.js +29 -0
  27. package/dist/core/local-llm/local-llm-client.js +100 -0
  28. package/dist/core/local-llm/local-llm-config.js +6 -1
  29. package/dist/core/local-llm/local-llm-context-cache.js +21 -0
  30. package/dist/core/local-llm/local-llm-control-adapter.js +101 -0
  31. package/dist/core/local-llm/local-llm-json-repair.js +52 -0
  32. package/dist/core/local-llm/local-llm-metrics.js +42 -0
  33. package/dist/core/local-llm/local-llm-ollama-client.js +67 -0
  34. package/dist/core/local-llm/local-llm-openai-compatible-client.js +30 -0
  35. package/dist/core/local-llm/local-llm-prompt-cache.js +12 -0
  36. package/dist/core/local-llm/local-llm-scheduler.js +29 -0
  37. package/dist/core/local-llm/local-llm-schema-enforcer.js +15 -0
  38. package/dist/core/local-llm/local-llm-smoke.js +83 -0
  39. package/dist/core/local-llm/local-llm-warmup.js +20 -0
  40. package/dist/core/local-llm/local-worker-eligibility.js +27 -0
  41. package/dist/core/naruto/hardware-capacity-probe.js +36 -0
  42. package/dist/core/naruto/naruto-active-pool.js +118 -0
  43. package/dist/core/naruto/naruto-backpressure.js +13 -0
  44. package/dist/core/naruto/naruto-concurrency-governor.js +65 -0
  45. package/dist/core/naruto/naruto-finalizer.js +18 -0
  46. package/dist/core/naruto/naruto-generation-scheduler.js +18 -0
  47. package/dist/core/naruto/naruto-gpt-final-pack.js +49 -0
  48. package/dist/core/naruto/naruto-parallel-patch-apply.js +95 -0
  49. package/dist/core/naruto/naruto-patch-transaction-batch.js +42 -0
  50. package/dist/core/naruto/naruto-role-policy.js +107 -0
  51. package/dist/core/naruto/naruto-verification-dag.js +42 -0
  52. package/dist/core/naruto/naruto-verification-pool.js +18 -0
  53. package/dist/core/naruto/naruto-work-graph.js +198 -0
  54. package/dist/core/naruto/naruto-work-item.js +40 -0
  55. package/dist/core/naruto/naruto-work-stealing.js +11 -0
  56. package/dist/core/naruto/resource-pressure-monitor.js +32 -0
  57. package/dist/core/pipeline/finalize-pipeline-result.js +58 -0
  58. package/dist/core/pipeline/gpt-final-required.js +12 -0
  59. package/dist/core/prompt/prompt-placeholder-guard.js +30 -0
  60. package/dist/core/router/capability-card.js +13 -0
  61. package/dist/core/router/route-cache.js +3 -0
  62. package/dist/core/router/ultra-router.js +2 -1
  63. package/dist/core/routes.js +4 -4
  64. package/dist/core/version.js +1 -1
  65. package/dist/core/zellij/zellij-lane-runtime.js +2 -2
  66. package/dist/core/zellij/zellij-naruto-dashboard.js +36 -0
  67. package/dist/core/zellij/zellij-worker-pane-manager.js +4 -4
  68. package/dist/scripts/blackbox-command-import-smoke.js +10 -1
  69. package/dist/scripts/check-package-boundary.js +12 -3
  70. package/dist/scripts/codex-0-137-compat-check.js +27 -0
  71. package/dist/scripts/codex-environment-scoped-approvals-check.js +10 -0
  72. package/dist/scripts/codex-plugin-list-json-check.js +8 -0
  73. package/dist/scripts/codex-thread-runtime-choice-check.js +10 -0
  74. package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +21 -0
  75. package/dist/scripts/local-llm-all-pipelines-check.js +11 -0
  76. package/dist/scripts/local-llm-cache-performance-check.js +10 -0
  77. package/dist/scripts/local-llm-capability-check.js +14 -0
  78. package/dist/scripts/local-llm-smoke-check.js +23 -0
  79. package/dist/scripts/local-llm-structured-output-check.js +11 -0
  80. package/dist/scripts/local-llm-throughput-check.js +10 -0
  81. package/dist/scripts/local-llm-tool-call-repair-check.js +10 -0
  82. package/dist/scripts/local-llm-warmup-check.js +11 -0
  83. package/dist/scripts/naruto-active-pool-check.js +27 -0
  84. package/dist/scripts/naruto-concurrency-governor-check.js +52 -0
  85. package/dist/scripts/naruto-gpt-final-pack-check.js +34 -0
  86. package/dist/scripts/naruto-parallel-patch-apply-check.js +41 -0
  87. package/dist/scripts/naruto-real-local-gpt-final-smoke.js +16 -0
  88. package/dist/scripts/naruto-role-distribution-check.js +23 -0
  89. package/dist/scripts/naruto-shadow-clone-swarm-check.js +6 -0
  90. package/dist/scripts/naruto-verification-pool-check.js +36 -0
  91. package/dist/scripts/naruto-work-graph-check.js +24 -0
  92. package/dist/scripts/naruto-zellij-massive-ui-check.js +23 -0
  93. package/dist/scripts/prompt-placeholder-guard-check.js +33 -0
  94. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +47 -0
  95. package/dist/scripts/python-codex-sdk-capability-check.js +75 -0
  96. package/dist/scripts/python-codex-sdk-sandbox-policy-check.js +10 -0
  97. package/dist/scripts/python-codex-sdk-stream-bridge-check.js +12 -0
  98. package/dist/scripts/release-parallel-check.js +1 -1
  99. package/dist/scripts/release-real-check.js +5 -0
  100. package/dist/scripts/zellij-worker-pane-manager-check.js +1 -1
  101. package/package.json +33 -4
  102. package/schemas/local-llm/local-model-config.schema.json +74 -0
  103. package/schemas/naruto/naruto-concurrency-governor.schema.json +21 -0
  104. package/schemas/naruto/naruto-work-graph.schema.json +22 -0
@@ -2,12 +2,16 @@ import os from 'node:os';
2
2
  import path from 'node:path';
3
3
  import { ensureDir, exists, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
4
4
  export const LOCAL_MODEL_CONFIG_SCHEMA = 'sks.local-model-config.v1';
5
+ export const LOCAL_MODEL_CONFIG_SCHEMA_V2 = 'sks.local-model-config.v2';
5
6
  export const OLLAMA_WORKER_CONFIG_SCHEMA = 'sks.ollama-worker-config.v1';
6
7
  export const DEFAULT_OLLAMA_CODER_MODEL = 'rafw007/qwen36-a3b-claude-coder:q4_K_M';
7
8
  export const DEFAULT_OLLAMA_BASE_URL = 'http://127.0.0.1:11434';
9
+ export const DEFAULT_MLX_LM_MODEL = 'mlx-community/Qwen3.6-35B-A3B-4bit';
10
+ export const DEFAULT_MLX_LM_BASE_URL = 'http://127.0.0.1:8080';
8
11
  export const DEFAULT_OLLAMA_KEEP_ALIVE = '30m';
9
12
  export const DEFAULT_OLLAMA_TIMEOUT_MS = 120_000;
10
13
  export const DEFAULT_OLLAMA_THINK = false;
14
+ export const LOCAL_LLM_SMOKE_TTL_MS = 24 * 60 * 60 * 1000;
11
15
  export function localModelConfigPath() {
12
16
  return process.env.SKS_LOCAL_MODEL_CONFIG
13
17
  ? path.resolve(process.env.SKS_LOCAL_MODEL_CONFIG)
@@ -30,28 +34,38 @@ export async function resolveOllamaWorkerConfig(input = {}) {
30
34
  const explicitDisable = boolEnv(process.env.SKS_OLLAMA_WORKERS) === false;
31
35
  const explicitEnable = boolEnv(process.env.SKS_OLLAMA_WORKERS) === true || input.ollamaEnabled === true || input.backend === 'ollama';
32
36
  const enabled = explicitDisable ? false : explicitEnable || stored.enabled === true;
33
- const model = firstText(process.env.SKS_OLLAMA_MODEL, input.model, stored.model, DEFAULT_OLLAMA_CODER_MODEL);
34
- const baseUrl = trimTrailingSlash(firstText(process.env.SKS_OLLAMA_BASE_URL, input.baseUrl, stored.base_url, DEFAULT_OLLAMA_BASE_URL));
37
+ const explicitProvider = firstText(process.env.SKS_LOCAL_LLM_PROVIDER, input.provider, input.backend === 'ollama' ? 'ollama' : '');
38
+ const provider = explicitProvider ? normalizeProvider(explicitProvider) : normalizeProvider(stored.provider);
39
+ const storedMatchesProvider = stored.provider === provider;
40
+ const model = firstText(process.env.SKS_LOCAL_LLM_MODEL, process.env.SKS_OLLAMA_MODEL, input.model, storedMatchesProvider ? stored.model : '', defaultModelForProvider(provider));
41
+ const baseUrl = trimTrailingSlash(firstText(process.env.SKS_LOCAL_LLM_BASE_URL, process.env.SKS_OLLAMA_BASE_URL, input.baseUrl, storedMatchesProvider ? stored.base_url : '', defaultBaseUrlForProvider(provider)));
35
42
  const keepAlive = firstText(process.env.SKS_OLLAMA_KEEP_ALIVE, input.keepAlive, stored.keep_alive, DEFAULT_OLLAMA_KEEP_ALIVE);
36
43
  const timeoutMs = positiveNumber(process.env.SKS_OLLAMA_TIMEOUT_MS, input.timeoutMs, stored.timeout_ms, DEFAULT_OLLAMA_TIMEOUT_MS);
37
44
  const temperature = finiteNumber(process.env.SKS_OLLAMA_TEMPERATURE, input.temperature, stored.temperature, 0.1);
38
45
  const think = boolEnv(process.env.SKS_OLLAMA_THINK) ?? input.think ?? stored.think ?? DEFAULT_OLLAMA_THINK;
46
+ const status = enabled ? resolveEnabledStatus(stored) : 'disabled';
39
47
  const blockers = [
40
48
  ...(enabled ? [] : ['ollama_workers_disabled']),
41
- ...(!model ? ['ollama_model_missing'] : []),
42
- ...(!baseUrl ? ['ollama_base_url_missing'] : [])
49
+ ...(enabled && status !== 'verified' ? [`local_llm_${status}`] : []),
50
+ ...(!model ? ['local_model_missing'] : []),
51
+ ...(!baseUrl ? ['local_model_base_url_missing'] : [])
43
52
  ];
44
53
  return {
45
54
  schema: OLLAMA_WORKER_CONFIG_SCHEMA,
46
55
  ok: blockers.length === 0,
47
56
  enabled,
48
- provider: 'ollama',
57
+ status,
58
+ provider,
49
59
  model,
50
60
  base_url: baseUrl,
61
+ endpoint: baseUrl,
51
62
  keep_alive: keepAlive,
52
63
  timeout_ms: timeoutMs,
53
64
  temperature,
54
65
  think,
66
+ policy: stored.policy,
67
+ capability: stored.capability,
68
+ last_smoke: stored.last_smoke,
55
69
  config_path: localModelConfigPath(),
56
70
  explicit_disable: explicitDisable,
57
71
  explicit_enable: explicitEnable,
@@ -59,25 +73,62 @@ export async function resolveOllamaWorkerConfig(input = {}) {
59
73
  };
60
74
  }
61
75
  export function normalizeLocalModelConfig(raw = {}) {
76
+ const enabled = raw.enabled === true;
77
+ const lastSmoke = normalizeSmoke(raw.last_smoke || raw.lastSmoke || null);
78
+ const status = enabled ? normalizeStatus(raw.status, lastSmoke) : 'disabled';
79
+ const provider = normalizeProvider(raw.provider);
80
+ const baseUrl = trimTrailingSlash(firstText(raw.base_url, raw.baseUrl, raw.endpoint, defaultBaseUrlForProvider(provider)));
62
81
  return {
63
- schema: LOCAL_MODEL_CONFIG_SCHEMA,
82
+ schema: LOCAL_MODEL_CONFIG_SCHEMA_V2,
64
83
  ...(raw.generated_at ? { generated_at: String(raw.generated_at) } : { generated_at: nowIso() }),
65
84
  ...(raw.updated_at ? { updated_at: String(raw.updated_at) } : {}),
66
- enabled: raw.enabled === true,
67
- provider: 'ollama',
68
- model: firstText(raw.model, DEFAULT_OLLAMA_CODER_MODEL),
69
- base_url: trimTrailingSlash(firstText(raw.base_url, raw.baseUrl, DEFAULT_OLLAMA_BASE_URL)),
85
+ enabled,
86
+ status,
87
+ provider,
88
+ model: firstText(raw.model, defaultModelForProvider(provider)),
89
+ endpoint: baseUrl,
90
+ base_url: baseUrl,
70
91
  keep_alive: firstText(raw.keep_alive, raw.keepAlive, DEFAULT_OLLAMA_KEEP_ALIVE),
71
92
  timeout_ms: positiveNumber(raw.timeout_ms, raw.timeoutMs, DEFAULT_OLLAMA_TIMEOUT_MS),
72
93
  temperature: finiteNumber(raw.temperature, 0.1),
73
94
  think: typeof raw.think === 'boolean' ? raw.think : DEFAULT_OLLAMA_THINK,
74
- policy: {
75
- worker_only: true,
76
- no_strategy_planning_design: true,
77
- allowed_work: ['simple_code_patch_envelopes', 'read_only_collection']
78
- }
95
+ policy: normalizePolicy(raw.policy),
96
+ capability: normalizeCapability(raw.capability),
97
+ last_smoke: lastSmoke,
98
+ blockers: Array.isArray(raw.blockers) ? raw.blockers.map(String) : status === 'blocked' ? ['local_llm_smoke_failed'] : []
79
99
  };
80
100
  }
101
+ export function applyLocalLlmSmokeResult(config, smoke) {
102
+ const blockers = Array.isArray(smoke.blockers) ? smoke.blockers.map(String) : [];
103
+ const status = smoke.skipped
104
+ ? 'enabled_unverified'
105
+ : smoke.ok && smoke.schema_valid !== false
106
+ ? 'verified'
107
+ : smoke.status === 'degraded'
108
+ ? 'degraded'
109
+ : 'blocked';
110
+ return normalizeLocalModelConfig({
111
+ ...config,
112
+ enabled: true,
113
+ status,
114
+ capability: {
115
+ ...config.capability,
116
+ api_reachable: smoke.ok !== false,
117
+ model_installed: smoke.ok !== false
118
+ },
119
+ last_smoke: {
120
+ ...smoke,
121
+ status
122
+ },
123
+ blockers
124
+ });
125
+ }
126
+ export function localModelSmokeFresh(smoke, now = Date.now()) {
127
+ if (!smoke?.ok || smoke.schema_valid === false || !smoke.ran_at)
128
+ return false;
129
+ const ranAt = Date.parse(smoke.ran_at);
130
+ return Number.isFinite(ranAt) && now - ranAt <= LOCAL_LLM_SMOKE_TTL_MS;
131
+ }
81
132
  export function boolEnv(value) {
82
133
  const text = String(value ?? '').trim().toLowerCase();
83
134
  if (!text)
@@ -99,6 +150,104 @@ function firstText(...values) {
99
150
  function trimTrailingSlash(value) {
100
151
  return value.replace(/\/+$/, '');
101
152
  }
153
+ export function normalizeProvider(...values) {
154
+ for (const value of values) {
155
+ const text = String(value ?? '').trim().toLowerCase();
156
+ if (!text)
157
+ continue;
158
+ if (['ollama'].includes(text))
159
+ return 'ollama';
160
+ if (['mlx', 'mlx-lm', 'mlx_lm', 'mlxlm'].includes(text))
161
+ return 'mlx-lm';
162
+ if (['openai-compatible', 'openai_compatible', 'openai', 'openai-compatible-local'].includes(text))
163
+ return 'openai-compatible';
164
+ }
165
+ return 'ollama';
166
+ }
167
+ export function defaultModelForProvider(provider) {
168
+ if (provider === 'mlx-lm')
169
+ return DEFAULT_MLX_LM_MODEL;
170
+ if (provider === 'openai-compatible')
171
+ return '';
172
+ return DEFAULT_OLLAMA_CODER_MODEL;
173
+ }
174
+ export function defaultBaseUrlForProvider(provider) {
175
+ if (provider === 'mlx-lm')
176
+ return DEFAULT_MLX_LM_BASE_URL;
177
+ if (provider === 'openai-compatible')
178
+ return '';
179
+ return DEFAULT_OLLAMA_BASE_URL;
180
+ }
181
+ function resolveEnabledStatus(config) {
182
+ if (config.status === 'verified' && !localModelSmokeFresh(config.last_smoke))
183
+ return 'enabled_unverified';
184
+ return config.status === 'disabled' ? 'enabled_unverified' : config.status;
185
+ }
186
+ function normalizeStatus(value, smoke) {
187
+ const text = String(value ?? '').trim();
188
+ const known = ['disabled', 'enabled_unverified', 'verified', 'degraded', 'blocked'];
189
+ if (known.includes(text)) {
190
+ if (text === 'verified' && !localModelSmokeFresh(smoke))
191
+ return 'enabled_unverified';
192
+ return text;
193
+ }
194
+ return localModelSmokeFresh(smoke) ? 'verified' : 'enabled_unverified';
195
+ }
196
+ function normalizePolicy(value) {
197
+ const defaultAllowed = ['simple_patch_envelope', 'read_only_collection', 'grep_like_qa', 'test_generation_draft'];
198
+ const allowed = [
199
+ ...defaultAllowed,
200
+ ...(Array.isArray(value?.allowed_task_classes) ? value.allowed_task_classes : []),
201
+ ...(Array.isArray(value?.allowed_work) ? value.allowed_work : [])
202
+ ];
203
+ const forbidden = Array.isArray(value?.forbidden_task_classes) ? value.forbidden_task_classes : [
204
+ 'planning',
205
+ 'strategy',
206
+ 'final_review',
207
+ 'verification_authority',
208
+ 'safety_authority',
209
+ 'integration_authority'
210
+ ];
211
+ return {
212
+ role: 'worker_only',
213
+ allowed_task_classes: [...new Set(allowed.map(String))],
214
+ forbidden_task_classes: forbidden.map(String),
215
+ requires_gpt_final: value?.requires_gpt_final !== false
216
+ };
217
+ }
218
+ function normalizeCapability(value) {
219
+ return {
220
+ api_reachable: value?.api_reachable === true,
221
+ model_installed: value?.model_installed === true,
222
+ supports_streaming: value?.supports_streaming !== false,
223
+ supports_json_schema: value?.supports_json_schema === true,
224
+ supports_tools: value?.supports_tools === true,
225
+ supports_images: value?.supports_images === true,
226
+ context_window: positiveNumber(value?.context_window, 32768),
227
+ max_parallel_requests: Math.max(1, Math.min(16, positiveNumber(value?.max_parallel_requests, 4)))
228
+ };
229
+ }
230
+ function normalizeSmoke(value) {
231
+ if (!value || typeof value !== 'object')
232
+ return null;
233
+ return {
234
+ ok: value.ok === true,
235
+ ...(value.skipped === true ? { skipped: true } : {}),
236
+ ...(value.ran_at ? { ran_at: String(value.ran_at) } : {}),
237
+ ...(value.prompt_hash ? { prompt_hash: String(value.prompt_hash) } : {}),
238
+ ...(Number.isFinite(Number(value.latency_ms)) ? { latency_ms: Number(value.latency_ms) } : {}),
239
+ ...(Number.isFinite(Number(value.tokens_per_second)) ? { tokens_per_second: Number(value.tokens_per_second) } : {}),
240
+ ...(typeof value.schema_valid === 'boolean' ? { schema_valid: value.schema_valid } : {}),
241
+ ...(value.result_path ? { result_path: String(value.result_path) } : {}),
242
+ ...(normalizeKnownStatus(value.status) ? { status: normalizeKnownStatus(value.status) } : {}),
243
+ ...(value.reason ? { reason: String(value.reason) } : {}),
244
+ ...(Array.isArray(value.blockers) ? { blockers: value.blockers.map(String) } : {})
245
+ };
246
+ }
247
+ function normalizeKnownStatus(value) {
248
+ const text = String(value ?? '').trim();
249
+ return ['disabled', 'enabled_unverified', 'verified', 'degraded', 'blocked'].includes(text) ? text : undefined;
250
+ }
102
251
  function positiveNumber(...values) {
103
252
  for (const value of values) {
104
253
  const n = Number(value);
@@ -0,0 +1,119 @@
1
+ import { runProcess, which } from '../fsx.js';
2
+ import { compareSemverLike, parseCodexVersionText } from '../codex-compat/codex-version-policy.js';
3
+ import { createHash } from 'node:crypto';
4
+ export const CODEX_0_137_BASELINE_TAG = 'rust-v0.137.0';
5
+ export const CODEX_0_137_VERSION = '0.137.0';
6
+ export const CODEX_0_137_SCHEMA = 'sks.codex-0.137-compat.v1';
7
+ export function codex0137Matrix(input = {}) {
8
+ const version = parseCodexVersionText(input.version) || input.version || null;
9
+ const available = input.available !== false && Boolean(version);
10
+ const meets = available && compareSemverLike(version, CODEX_0_137_VERSION) >= 0;
11
+ const pluginJsonDetected = looksLikeJson(input.pluginListText || '');
12
+ const runtimeDetected = /runtime|model|provider|thread/i.test(input.debugModelsText || '');
13
+ const approvalsDetected = /approval|environment|sandbox|profile|permission/i.test(input.doctorText || '');
14
+ const localOrBaseline = (detected) => detected ? 'detected' : meets ? 'release_baseline' : available ? 'blocked' : 'unavailable';
15
+ const capabilities = [
16
+ capability('plugin_list_json', 'P0', localOrBaseline(pluginJsonDetected), '`codex plugin list --json` parses as JSON or 0.137 baseline records it.'),
17
+ capability('thread_runtime_choice', 'P0', localOrBaseline(runtimeDetected), 'Thread/runtime choice is tracked by SKS per-thread proof and Codex runtime evidence.'),
18
+ capability('environment_scoped_approvals', 'P0', localOrBaseline(approvalsDetected), 'Approval proof carries environment identity and sandbox scope.'),
19
+ capability('managed_proxy_ca_bundle_child_commands', 'P1', meets ? 'release_baseline' : available ? 'blocked' : 'unavailable', 'Managed proxy CA bundle propagation is release-baseline plus SKS env proof.'),
20
+ capability('python_sdk_app_server_json_rpc', 'P0', meets ? 'release_baseline' : available ? 'blocked' : 'unavailable', 'Python SDK controls local app-server over JSON-RPC per current Codex manual.')
21
+ ];
22
+ const below = available && version ? compareSemverLike(version, CODEX_0_137_VERSION) < 0 : false;
23
+ const blockers = [
24
+ ...(input.requireReal && (!version || below) ? ['codex_0_137_required_but_not_detected'] : []),
25
+ ...capabilities
26
+ .filter((row) => input.requireReal && row.priority === 'P0' && (row.status === 'blocked' || row.status === 'unavailable'))
27
+ .map((row) => `codex_0_137_capability_unavailable:${row.id}`)
28
+ ];
29
+ return {
30
+ schema: CODEX_0_137_SCHEMA,
31
+ baseline: CODEX_0_137_BASELINE_TAG,
32
+ required_version: CODEX_0_137_VERSION,
33
+ release_evidence: {
34
+ upstream: 'openai/codex',
35
+ npm_package: '@openai/codex-sdk',
36
+ npm_version: '0.137.0',
37
+ manual_source: 'https://developers.openai.com/codex/codex-manual.md',
38
+ checked_topics: ['Codex SDK TypeScript', 'Codex SDK Python', 'CLI plugin/json/runtime/approval surfaces']
39
+ },
40
+ inherited_baselines: ['rust-v0.136.0', 'rust-v0.135.0', 'rust-v0.134.0'],
41
+ detected_version: version,
42
+ available,
43
+ require_real: input.requireReal === true,
44
+ capabilities,
45
+ plugin_list_json_supported: supported(capabilities, 'plugin_list_json'),
46
+ thread_runtime_choice_supported: supported(capabilities, 'thread_runtime_choice'),
47
+ environment_scoped_approvals_supported: supported(capabilities, 'environment_scoped_approvals'),
48
+ ok: blockers.length === 0,
49
+ warnings: !input.requireReal && (!version || below) ? [`Codex ${CODEX_0_137_BASELINE_TAG} not detected; release:check treats this as warning-only.`] : [],
50
+ blockers
51
+ };
52
+ }
53
+ export async function collectCodex0137LocalEvidence(opts = {}) {
54
+ const bin = opts.codexBin || await which('codex');
55
+ if (!bin) {
56
+ return {
57
+ available: false,
58
+ versionText: '',
59
+ pluginListText: '',
60
+ debugModelsText: '',
61
+ doctorText: '',
62
+ warnings: ['codex_binary_missing']
63
+ };
64
+ }
65
+ const run = async (args) => runProcess(bin, args, { timeoutMs: 10000, maxOutputBytes: 64 * 1024 }).catch((err) => ({
66
+ code: 1,
67
+ stdout: '',
68
+ stderr: err.message || String(err)
69
+ }));
70
+ const [version, pluginList, debugModels, doctor] = await Promise.all([
71
+ run(['--version']),
72
+ run(['plugin', 'list', '--json']),
73
+ run(['debug', 'models', '--bundled']),
74
+ run(['doctor', '--json'])
75
+ ]);
76
+ return {
77
+ available: version.code === 0,
78
+ versionText: `${version.stdout || ''}${version.stderr || ''}`.trim(),
79
+ pluginListText: `${pluginList.stdout || ''}${pluginList.stderr || ''}`,
80
+ debugModelsText: summarizeCodexCommandOutput(`${debugModels.stdout || ''}${debugModels.stderr || ''}`, ['runtime', 'model', 'provider', 'thread']),
81
+ doctorText: summarizeCodexCommandOutput(`${doctor.stdout || ''}${doctor.stderr || ''}`, ['approval', 'environment', 'sandbox', 'profile', 'permission']),
82
+ warnings: [
83
+ ...(pluginList.code === 0 ? [] : ['codex_plugin_list_json_unavailable']),
84
+ ...(debugModels.code === 0 ? [] : ['codex_debug_models_unavailable']),
85
+ ...(doctor.code === 0 ? [] : ['codex_doctor_json_unavailable'])
86
+ ]
87
+ };
88
+ }
89
+ function capability(id, priority, status, detector) {
90
+ return { id, priority, status, detector, notes: [] };
91
+ }
92
+ function supported(capabilities, id) {
93
+ const status = capabilities.find((capability) => capability.id === id)?.status;
94
+ return status === 'detected' || status === 'release_baseline';
95
+ }
96
+ function looksLikeJson(value) {
97
+ const text = String(value || '').trim();
98
+ if (!text)
99
+ return false;
100
+ try {
101
+ JSON.parse(text);
102
+ return true;
103
+ }
104
+ catch {
105
+ return false;
106
+ }
107
+ }
108
+ function summarizeCodexCommandOutput(value, keywords) {
109
+ const text = String(value || '');
110
+ const lower = text.toLowerCase();
111
+ const matched = keywords.filter((keyword) => lower.includes(keyword.toLowerCase()));
112
+ return [
113
+ `raw_output_redacted=true`,
114
+ `bytes=${Buffer.byteLength(text, 'utf8')}`,
115
+ `sha256=${createHash('sha256').update(text).digest('hex')}`,
116
+ `matched_keywords=${matched.join(',') || 'none'}`
117
+ ].join(' ');
118
+ }
119
+ //# sourceMappingURL=codex-0-137-compat.js.map
@@ -7,7 +7,8 @@ export async function writeCodexControlProof(root, input) {
7
7
  schema: CODEX_CONTROL_PROOF_SCHEMA,
8
8
  generated_at: nowIso(),
9
9
  ok: input.result.ok === true,
10
- backend: 'codex-sdk',
10
+ backend: input.result.backend,
11
+ backend_family: input.result.backend_family,
11
12
  route: input.task.route,
12
13
  mission_id: input.task.missionId,
13
14
  work_item_id: input.task.workItemId || null,
@@ -22,6 +23,8 @@ export async function writeCodexControlProof(root, input) {
22
23
  output_schema_id: input.task.outputSchemaId,
23
24
  worker_result_path: input.result.workerResultPath,
24
25
  patch_envelope_path: input.result.patchEnvelopePath || null,
26
+ local_llm_proof_path: input.result.localLlmProofPath || null,
27
+ python_sdk_proof_path: input.result.pythonSdkProofPath || null,
25
28
  sandbox: input.sandbox || null,
26
29
  env: input.envProof || null,
27
30
  config: input.config ? redactCodexSdkConfig(input.config) : null,
@@ -37,7 +37,7 @@ export async function detectCodexSdkCapability(input = {}) {
37
37
  node_compatible: nodeCompatible,
38
38
  dynamic_import_ok: dynamicImportOk,
39
39
  structured_output_fake_smoke: structuredFake,
40
- setup_action: blockers.includes('codex_sdk_unavailable') ? 'npm install @openai/codex-sdk@0.136.0' : null,
40
+ setup_action: blockers.includes('codex_sdk_unavailable') ? 'npm install @openai/codex-sdk@0.137.0' : null,
41
41
  blockers
42
42
  };
43
43
  }