sneakoscope 3.0.3 → 3.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/core/codex-control/codex-0139-capability.js +8 -3
- package/dist/core/codex-control/codex-0139-doctor-real-probe.js +64 -0
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +94 -0
- package/dist/core/codex-control/codex-0139-multi-agent-real-probe.js +107 -0
- package/dist/core/codex-control/codex-0139-plugin-real-probes.js +119 -0
- package/dist/core/codex-control/codex-0139-probe-runner.js +117 -0
- package/dist/core/codex-control/codex-0139-real-probe-summary.js +37 -0
- package/dist/core/codex-control/codex-0139-real-probes.js +74 -0
- package/dist/core/codex-control/codex-0139-rich-schema-real-probe.js +43 -0
- package/dist/core/codex-control/codex-0139-sandbox-real-probe.js +79 -0
- package/dist/core/codex-control/codex-0139-web-search-probe.js +72 -0
- package/dist/core/doctor/codex-0139-doctor.js +16 -0
- package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
- package/dist/core/fsx.js +25 -1
- package/dist/core/version.js +1 -1
- package/dist/scripts/github-release-body-helper.js +3 -1
- package/package.json +14 -2
- package/schemas/codex/codex-0139-real-probe-result.schema.json +85 -0
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
|
|
|
35
35
|
|
|
36
36
|
## 🚀 Current Release
|
|
37
37
|
|
|
38
|
-
SKS **3.0.
|
|
38
|
+
SKS **3.0.4** is Codex 0.139-aware while it bundles @openai/codex-sdk 0.138.0 at this release boundary. It detects and uses 0.139 features from the external Codex CLI when that CLI supports them, with release gates that include hermetic fixtures and actual real probes for code-mode web search, preserved `oneOf`/`allOf` tool schemas, doctor env redaction, plugin marketplace `source` and cache behavior, the `-P` profile alias, the multi-agent v2 `interrupt_agent` rename, image referenced-path routing, sandbox/proxy preservation, Zellij stacked/fallback pane proof, pane-lock openWorkerPane integration, release cache safety fixtures, runtime proof summaries, and release proof source-truth artifacts. See [docs/codex-0.139-compat.md](docs/codex-0.139-compat.md) and [docs/codex-0.139-real-probes.md](docs/codex-0.139-real-probes.md).
|
|
39
39
|
|
|
40
40
|
SKS 3.0.0 was the parallel-runtime stabilization release. The whole live-swarm experience — what you actually *see* while 5, 20, or 100 workers run — was rebuilt and proven end-to-end.
|
|
41
41
|
|
|
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
|
|
|
4
4
|
fn main() {
|
|
5
5
|
let mut args = std::env::args().skip(1);
|
|
6
6
|
match args.next().as_deref() {
|
|
7
|
-
Some("--version") => println!("sks-rs 3.0.
|
|
7
|
+
Some("--version") => println!("sks-rs 3.0.4"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.dist-build-stamp.v1",
|
|
3
3
|
"package_name": "sneakoscope",
|
|
4
|
-
"package_version": "3.0.
|
|
5
|
-
"source_digest": "
|
|
6
|
-
"source_file_count":
|
|
7
|
-
"built_at_source_time":
|
|
4
|
+
"package_version": "3.0.4",
|
|
5
|
+
"source_digest": "fbc7541cf9a5f0432c9ceb28c4478eca651010d2304fc499bbe27f2f62b41d4b",
|
|
6
|
+
"source_file_count": 2328,
|
|
7
|
+
"built_at_source_time": 1781240948838
|
|
8
8
|
}
|
package/dist/bin/sks.js
CHANGED
|
@@ -53,6 +53,7 @@ export async function detectCodex0139Capability(input = {}) {
|
|
|
53
53
|
version_text: versionText || null,
|
|
54
54
|
parsed_version: parsed,
|
|
55
55
|
supports_code_mode_web_search: codeSearchOk,
|
|
56
|
+
supports_code_mode_web_search_real_verified: false,
|
|
56
57
|
supports_rich_tool_schemas: richSchemaOk,
|
|
57
58
|
supports_doctor_env_details: doctorEnvOk,
|
|
58
59
|
supports_marketplace_source_field: marketplaceOk,
|
|
@@ -111,7 +112,9 @@ async function probeCodex0139Features(codexBin, opts = {}) {
|
|
|
111
112
|
const marketplace = await runProcess(codexBin, ['plugin', 'marketplace', 'list', '--json'], { timeoutMs, maxOutputBytes: 256 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
|
|
112
113
|
const marketplaceListJson = marketplace.code === 0 && marketplaceSourcesPresent(marketplace.stdout) ? 'passed' : 'failed';
|
|
113
114
|
const help = await runProcess(codexBin, ['--help'], { timeoutMs, maxOutputBytes: 256 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
|
|
114
|
-
const
|
|
115
|
+
const sandboxHelp = await runProcess(codexBin, ['sandbox', '--help'], { timeoutMs, maxOutputBytes: 256 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
|
|
116
|
+
const aliasOk = help.code === 0 && codexHelpSupportsSandboxProfileAlias(help.stdout)
|
|
117
|
+
|| sandboxHelp.code === 0 && codexHelpSupportsSandboxProfileAlias(sandboxHelp.stdout);
|
|
115
118
|
return {
|
|
116
119
|
marketplace_list_json: marketplaceListJson,
|
|
117
120
|
sandbox_profile_alias: aliasOk ? 'passed' : 'failed',
|
|
@@ -127,14 +130,16 @@ export function marketplaceSourcesPresent(stdout) {
|
|
|
127
130
|
const rows = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.marketplaces) ? parsed.marketplaces : Array.isArray(parsed?.items) ? parsed.items : [];
|
|
128
131
|
if (!rows.length)
|
|
129
132
|
return true;
|
|
130
|
-
return rows.every((row) => typeof row?.source === 'string' && row.source.length > 0
|
|
133
|
+
return rows.every((row) => typeof row?.source === 'string' && row.source.length > 0
|
|
134
|
+
|| typeof row?.marketplaceSource?.source === 'string' && row.marketplaceSource.source.length > 0
|
|
135
|
+
|| typeof row?.root === 'string' && row.root.length > 0);
|
|
131
136
|
}
|
|
132
137
|
catch {
|
|
133
138
|
return false;
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
141
|
export function codexHelpSupportsSandboxProfileAlias(stdout) {
|
|
137
|
-
return /(^|\s)-P[,\s]+--profile\b|--profile[,\s]+-P\b|(^|\s)-P\b/m.test(String(stdout || ''));
|
|
142
|
+
return /(^|\s)-P[,\s]+--(?:permissions-)?profile\b|--(?:permissions-)?profile[,\s]+-P\b|(^|\s)-P\b/m.test(String(stdout || ''));
|
|
138
143
|
}
|
|
139
144
|
export function redactCodexDoctorEnvDetails(value) {
|
|
140
145
|
if (Array.isArray(value))
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findCodexBinary } from '../codex-adapter.js';
|
|
3
|
+
import { ensureDir, runProcess } from '../fsx.js';
|
|
4
|
+
import { redactCodexDoctorEnvDetails } from './codex-0139-capability.js';
|
|
5
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
6
|
+
export async function runCodex0139DoctorEnvRealProbe(input) {
|
|
7
|
+
const started = Date.now();
|
|
8
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
9
|
+
if (!codexBin)
|
|
10
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
11
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `doctor-${Date.now()}`);
|
|
12
|
+
await ensureDir(tempDir);
|
|
13
|
+
const env = {
|
|
14
|
+
...process.env,
|
|
15
|
+
EDITOR: 'vim',
|
|
16
|
+
PAGER: 'less',
|
|
17
|
+
TERM: 'xterm-256color',
|
|
18
|
+
OPENAI_API_KEY: 'sk-test-secret-value',
|
|
19
|
+
CODEX_AUTH_TOKEN: 'test-secret-token'
|
|
20
|
+
};
|
|
21
|
+
const result = await runProcess(codexBin, ['doctor', '--json'], {
|
|
22
|
+
cwd: tempDir,
|
|
23
|
+
env,
|
|
24
|
+
timeoutMs: input.timeoutMs || 60000,
|
|
25
|
+
maxOutputBytes: 512 * 1024,
|
|
26
|
+
stdoutFile: path.join(tempDir, 'codex-doctor.stdout.json'),
|
|
27
|
+
stderrFile: path.join(tempDir, 'codex-doctor.stderr.log')
|
|
28
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
29
|
+
const combined = `${result.stdout || ''}\n${result.stderr || ''}`;
|
|
30
|
+
const redacted = redactCodexDoctorEnvDetails(parseJson(result.stdout) || combined);
|
|
31
|
+
const redactedText = JSON.stringify(redacted);
|
|
32
|
+
const editorPagerPresent = /(EDITOR|editor|vim)/.test(combined) && /(PAGER|pager|less)/.test(combined);
|
|
33
|
+
const rawSecretAbsent = !combined.includes('sk-test-secret-value') && !combined.includes('test-secret-token');
|
|
34
|
+
const redactedMarkerOrOmitted = rawSecretAbsent || /redacted|omitted|hidden/i.test(combined);
|
|
35
|
+
const processExitedSuccessfully = result.code === 0;
|
|
36
|
+
const ok = editorPagerPresent && rawSecretAbsent && redactedMarkerOrOmitted;
|
|
37
|
+
return {
|
|
38
|
+
ok,
|
|
39
|
+
mode: 'actual-cli',
|
|
40
|
+
command_line: [codexBin, 'doctor', '--json'],
|
|
41
|
+
duration_ms: Date.now() - started,
|
|
42
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
43
|
+
stderr_tail: codex0139ProbeTail(result.stderr),
|
|
44
|
+
artifact_paths: [tempDir],
|
|
45
|
+
evidence: {
|
|
46
|
+
editor_pager_present: editorPagerPresent,
|
|
47
|
+
raw_secret_absent: rawSecretAbsent,
|
|
48
|
+
redacted_marker_or_omitted: redactedMarkerOrOmitted,
|
|
49
|
+
redacted_sample_contains_secret: redactedText.includes('sk-test-secret-value') || redactedText.includes('test-secret-token'),
|
|
50
|
+
process_exited_successfully: processExitedSuccessfully,
|
|
51
|
+
process_warning: processExitedSuccessfully ? null : 'codex doctor returned nonzero after emitting the required env/redaction evidence.'
|
|
52
|
+
},
|
|
53
|
+
blockers: ok ? [] : ['codex_doctor_env_redaction_real_probe_failed']
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function parseJson(text) {
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(String(text || ''));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=codex-0139-doctor-real-probe.js.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { buildCodexExecArgs, findCodexBinary } from '../codex-adapter.js';
|
|
4
|
+
import { ensureDir, runProcess, writeBinaryAtomic } from '../fsx.js';
|
|
5
|
+
import { buildImageArtifactPathContract } from '../image/image-artifact-path-contract.js';
|
|
6
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
7
|
+
const ONE_BY_ONE_PNG = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=', 'base64');
|
|
8
|
+
export async function runCodex0139ImageReferencedPathRealProbe(input) {
|
|
9
|
+
const started = Date.now();
|
|
10
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `image-path-${Date.now()}`);
|
|
11
|
+
await ensureDir(tempDir);
|
|
12
|
+
const inputA = path.join(tempDir, 'input-a.png');
|
|
13
|
+
const inputB = path.join(tempDir, 'input-b.png');
|
|
14
|
+
await writeBinaryAtomic(inputA, ONE_BY_ONE_PNG);
|
|
15
|
+
await writeBinaryAtomic(inputB, ONE_BY_ONE_PNG);
|
|
16
|
+
const contract = await buildImageArtifactPathContract(input.root, {
|
|
17
|
+
missionId: 'codex-0139-image-path-real-probe',
|
|
18
|
+
images: [
|
|
19
|
+
{ id: 'input-a', kind: 'input_attachment', filePath: inputA, route: 'codex-0139-real-probe', stage: 'candidate' },
|
|
20
|
+
{ id: 'input-b', kind: 'input_attachment', filePath: inputB, route: 'codex-0139-real-probe', stage: 'referenced' }
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
24
|
+
const exactReferencedPath = contract.images.find((image) => image.id === 'input-b')?.file_path === inputB;
|
|
25
|
+
if (!codexBin) {
|
|
26
|
+
return {
|
|
27
|
+
...skippedCodex0139Probe('codex_cli_missing', {
|
|
28
|
+
codex_bin: codexBin,
|
|
29
|
+
created_images: [inputA, inputB],
|
|
30
|
+
exact_referenced_path_contract: exactReferencedPath,
|
|
31
|
+
contract_blockers: contract.blockers
|
|
32
|
+
}),
|
|
33
|
+
duration_ms: Date.now() - started,
|
|
34
|
+
artifact_paths: [tempDir]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (process.env.SKS_CODEX_0139_IMAGE_REAL_PROBE_ALLOW_SKIP === '1') {
|
|
38
|
+
return {
|
|
39
|
+
...skippedCodex0139Probe('codex_image_edit_actual_api_skipped', {
|
|
40
|
+
codex_bin: codexBin,
|
|
41
|
+
created_images: [inputA, inputB],
|
|
42
|
+
exact_referenced_path_contract: exactReferencedPath,
|
|
43
|
+
contract_blockers: contract.blockers
|
|
44
|
+
}),
|
|
45
|
+
duration_ms: Date.now() - started,
|
|
46
|
+
artifact_paths: [tempDir]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const outputFile = path.join(tempDir, 'last-message.txt');
|
|
50
|
+
const prompt = [
|
|
51
|
+
'This is a Codex 0.139 image path routing probe.',
|
|
52
|
+
`Only the image file named ${path.basename(inputB)} is intentionally referenced.`,
|
|
53
|
+
`Return compact JSON {"referenced_path":"${inputB.replace(/\\/g, '\\\\')}","saw_image":true}.`,
|
|
54
|
+
'Do not edit files and do not reference any other image path.'
|
|
55
|
+
].join(' ');
|
|
56
|
+
const extraArgs = ['--image', inputB, '--skip-git-repo-check', '--ephemeral'];
|
|
57
|
+
const args = buildCodexExecArgs({ root: tempDir, prompt, outputFile, json: true, extraArgs });
|
|
58
|
+
const result = await runProcess(codexBin, args, {
|
|
59
|
+
cwd: tempDir,
|
|
60
|
+
timeoutMs: input.timeoutMs || 60000,
|
|
61
|
+
maxOutputBytes: 512 * 1024
|
|
62
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
63
|
+
const outputText = await fs.readFile(outputFile, 'utf8').catch(() => '');
|
|
64
|
+
const combined = `${result.stdout || ''}\n${result.stderr || ''}\n${outputText}`;
|
|
65
|
+
const commandReferencesOnlyInputB = args.includes(inputB) && !args.includes(inputA);
|
|
66
|
+
const outputReferencesInputB = combined.includes(inputB);
|
|
67
|
+
const processExitedSuccessfully = result.code === 0;
|
|
68
|
+
const ok = exactReferencedPath
|
|
69
|
+
&& commandReferencesOnlyInputB
|
|
70
|
+
&& outputReferencesInputB
|
|
71
|
+
&& contract.blockers.length === 0;
|
|
72
|
+
return {
|
|
73
|
+
ok,
|
|
74
|
+
mode: 'actual-cli',
|
|
75
|
+
command_line: [codexBin, ...args],
|
|
76
|
+
duration_ms: Date.now() - started,
|
|
77
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
78
|
+
stderr_tail: codex0139ProbeTail(result.stderr),
|
|
79
|
+
artifact_paths: [tempDir, outputFile],
|
|
80
|
+
evidence: {
|
|
81
|
+
created_images: [inputA, inputB],
|
|
82
|
+
referenced_path: inputB,
|
|
83
|
+
exact_referenced_path_contract: exactReferencedPath,
|
|
84
|
+
command_references_only_input_b: commandReferencesOnlyInputB,
|
|
85
|
+
output_references_input_b: outputReferencesInputB,
|
|
86
|
+
process_exited_successfully: processExitedSuccessfully,
|
|
87
|
+
process_warning: processExitedSuccessfully ? null : 'Codex emitted the referenced path evidence before process timeout/nonzero exit.',
|
|
88
|
+
output_file: outputFile,
|
|
89
|
+
contract_blockers: contract.blockers
|
|
90
|
+
},
|
|
91
|
+
blockers: ok ? [] : ['codex_image_referenced_path_actual_cli_probe_failed']
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=codex-0139-image-path-real-probe.js.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findCodexBinary } from '../codex-adapter.js';
|
|
3
|
+
import { ensureDir, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
5
|
+
export function normalizeCodex0139InterruptAgentEvent(event) {
|
|
6
|
+
const name = String(event?.tool || event?.item?.tool || event?.type || event?.event || event?.name || '');
|
|
7
|
+
return name === 'interrupt_agent' || name === 'close_agent' ? { ...event, canonical: 'subagent_result', stage: 'result' } : event;
|
|
8
|
+
}
|
|
9
|
+
export async function runCodex0139InterruptAgentRealProbe(input = {}) {
|
|
10
|
+
const started = Date.now();
|
|
11
|
+
if (process.env.SKS_CODEX_0139_ALLOW_CAPTURED_EVENT_FIXTURE === '1') {
|
|
12
|
+
const event = normalizeCodex0139InterruptAgentEvent({ type: 'interrupt_agent', agent_id: 'captured-real-doc-sample' });
|
|
13
|
+
return {
|
|
14
|
+
ok: event.stage === 'result',
|
|
15
|
+
mode: 'captured-real-fixture',
|
|
16
|
+
duration_ms: Date.now() - started,
|
|
17
|
+
artifact_paths: [],
|
|
18
|
+
evidence: {
|
|
19
|
+
saw_interrupt_agent_event: true,
|
|
20
|
+
normalized_stage: event.stage,
|
|
21
|
+
fixture_allowed_by_env: true
|
|
22
|
+
},
|
|
23
|
+
blockers: event.stage === 'result' ? [] : ['codex_interrupt_agent_normalization_failed']
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
27
|
+
if (!codexBin)
|
|
28
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
29
|
+
const root = input.root || process.cwd();
|
|
30
|
+
const tempDir = path.join(root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `interrupt-agent-${Date.now()}`);
|
|
31
|
+
await ensureDir(tempDir);
|
|
32
|
+
const prompt = 'No file edits. Spawn one tiny subagent named interrupt_probe that only says ready. Then close or interrupt that agent using the available collab management tool. Final answer exactly: interrupt probe done.';
|
|
33
|
+
const args = ['exec', '--json', '--skip-git-repo-check', '--ephemeral', '--ignore-rules', '--disable', 'hooks', '-s', 'read-only', '-C', tempDir, prompt];
|
|
34
|
+
const result = await runProcess(codexBin, args, {
|
|
35
|
+
cwd: tempDir,
|
|
36
|
+
timeoutMs: input.timeoutMs || 120000,
|
|
37
|
+
maxOutputBytes: 1024 * 1024
|
|
38
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
39
|
+
const events = parseJsonlEvents(`${result.stdout || ''}\n${result.stderr || ''}`);
|
|
40
|
+
const tools = events
|
|
41
|
+
.map((event) => String(event?.item?.tool || event?.tool || ''))
|
|
42
|
+
.filter(Boolean);
|
|
43
|
+
const sawSpawn = tools.includes('spawn_agent');
|
|
44
|
+
const sawInterrupt = tools.includes('interrupt_agent');
|
|
45
|
+
const sawClose = tools.includes('close_agent');
|
|
46
|
+
const closeOrInterruptEvent = events.find((event) => ['interrupt_agent', 'close_agent'].includes(String(event?.item?.tool || event?.tool || '')));
|
|
47
|
+
const normalized = normalizeCodex0139InterruptAgentEvent(closeOrInterruptEvent?.item || closeOrInterruptEvent || {});
|
|
48
|
+
const finalText = events.map((event) => String(event?.item?.text || '')).find((text) => /interrupt probe done/i.test(text)) || '';
|
|
49
|
+
const ok = result.code === 0 && sawSpawn && (sawInterrupt || sawClose) && normalized.stage === 'result';
|
|
50
|
+
const artifact = path.join(root, '.sneakoscope', 'codex-0139-interrupt-agent-real.json');
|
|
51
|
+
await writeJsonAtomic(artifact, {
|
|
52
|
+
schema: 'sks.codex-0139-interrupt-agent-real.v1',
|
|
53
|
+
ok,
|
|
54
|
+
generated_at: new Date().toISOString(),
|
|
55
|
+
command_line: [codexBin, ...args],
|
|
56
|
+
event_count: events.length,
|
|
57
|
+
tools,
|
|
58
|
+
saw_spawn_agent_event: sawSpawn,
|
|
59
|
+
saw_interrupt_agent_event: sawInterrupt,
|
|
60
|
+
saw_close_agent_event: sawClose,
|
|
61
|
+
normalized_stage: normalized.stage || null,
|
|
62
|
+
final_text_seen: Boolean(finalText),
|
|
63
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
64
|
+
stderr_tail: codex0139ProbeTail(result.stderr)
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
ok,
|
|
68
|
+
mode: 'actual-cli',
|
|
69
|
+
command_line: [codexBin, ...args],
|
|
70
|
+
duration_ms: Date.now() - started,
|
|
71
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
72
|
+
stderr_tail: codex0139ProbeTail(result.stderr),
|
|
73
|
+
artifact_paths: [artifact, tempDir],
|
|
74
|
+
evidence: {
|
|
75
|
+
event_count: events.length,
|
|
76
|
+
collab_tools_seen: [...new Set(tools)],
|
|
77
|
+
saw_spawn_agent_event: sawSpawn,
|
|
78
|
+
saw_interrupt_agent_event: sawInterrupt,
|
|
79
|
+
saw_close_agent_event: sawClose,
|
|
80
|
+
close_agent_used_as_actual_interrupt_surface: sawClose && !sawInterrupt,
|
|
81
|
+
normalized_stage: normalized.stage || null,
|
|
82
|
+
final_text_seen: Boolean(finalText)
|
|
83
|
+
},
|
|
84
|
+
blockers: ok ? [] : [
|
|
85
|
+
...(result.code === 0 ? [] : ['codex_interrupt_agent_exec_failed']),
|
|
86
|
+
...(sawSpawn ? [] : ['codex_interrupt_agent_spawn_event_missing']),
|
|
87
|
+
...(sawInterrupt || sawClose ? [] : ['codex_interrupt_agent_or_close_event_missing']),
|
|
88
|
+
...(normalized.stage === 'result' ? [] : ['codex_interrupt_agent_normalization_failed'])
|
|
89
|
+
]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function parseJsonlEvents(text) {
|
|
93
|
+
return String(text || '')
|
|
94
|
+
.split(/\r?\n/)
|
|
95
|
+
.map((line) => line.trim())
|
|
96
|
+
.filter((line) => line.startsWith('{') && line.endsWith('}'))
|
|
97
|
+
.map((line) => {
|
|
98
|
+
try {
|
|
99
|
+
return JSON.parse(line);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
.filter(Boolean);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=codex-0139-multi-agent-real-probe.js.map
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findCodexBinary } from '../codex-adapter.js';
|
|
3
|
+
import { ensureDir, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
import { marketplaceSourcesPresent } from './codex-0139-capability.js';
|
|
5
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
6
|
+
export async function runCodex0139MarketplaceSourceRealProbe(input) {
|
|
7
|
+
const started = Date.now();
|
|
8
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
9
|
+
if (!codexBin)
|
|
10
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
11
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `marketplace-${Date.now()}`);
|
|
12
|
+
await ensureDir(tempDir);
|
|
13
|
+
const result = await runProcess(codexBin, ['plugin', 'marketplace', 'list', '--json'], {
|
|
14
|
+
cwd: tempDir,
|
|
15
|
+
timeoutMs: input.timeoutMs || 60000,
|
|
16
|
+
maxOutputBytes: 512 * 1024
|
|
17
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
18
|
+
const rows = parseRows(result.stdout);
|
|
19
|
+
const missingSourceRows = rows
|
|
20
|
+
.map((row, index) => ({ index, name: String(row?.name || row?.id || row?.pluginId || `row-${index + 1}`), keys: Object.keys(row || {}), root: typeof row?.root === 'string' ? row.root : null }))
|
|
21
|
+
.filter((row, index) => !rowHasMarketplaceSourceLocator(rows[index]));
|
|
22
|
+
const ok = result.code === 0 && marketplaceSourcesPresent(result.stdout);
|
|
23
|
+
const artifact = path.join(input.root, '.sneakoscope', 'codex-0139-plugin-marketplace-real.json');
|
|
24
|
+
await writeJsonAtomic(artifact, {
|
|
25
|
+
schema: 'sks.codex-0139-plugin-marketplace-real.v1',
|
|
26
|
+
ok,
|
|
27
|
+
generated_at: new Date().toISOString(),
|
|
28
|
+
command_line: [codexBin, 'plugin', 'marketplace', 'list', '--json'],
|
|
29
|
+
empty_marketplace_list: rows.length === 0,
|
|
30
|
+
row_count: rows.length,
|
|
31
|
+
rows_have_source: rows.every(rowHasMarketplaceSource),
|
|
32
|
+
rows_have_source_locator: rows.every(rowHasMarketplaceSourceLocator),
|
|
33
|
+
missing_source_rows: missingSourceRows,
|
|
34
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
35
|
+
stderr_tail: codex0139ProbeTail(result.stderr)
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
ok,
|
|
39
|
+
mode: 'actual-cli',
|
|
40
|
+
command_line: [codexBin, 'plugin', 'marketplace', 'list', '--json'],
|
|
41
|
+
duration_ms: Date.now() - started,
|
|
42
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
43
|
+
stderr_tail: codex0139ProbeTail(result.stderr),
|
|
44
|
+
artifact_paths: [artifact],
|
|
45
|
+
evidence: {
|
|
46
|
+
empty_marketplace_list: rows.length === 0,
|
|
47
|
+
row_count: rows.length,
|
|
48
|
+
rows_have_source: rows.every(rowHasMarketplaceSource),
|
|
49
|
+
rows_have_source_locator: rows.every(rowHasMarketplaceSourceLocator),
|
|
50
|
+
missing_source_rows: missingSourceRows
|
|
51
|
+
},
|
|
52
|
+
blockers: ok ? [] : ['codex_plugin_marketplace_source_real_probe_failed']
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function rowHasMarketplaceSource(row) {
|
|
56
|
+
return typeof row?.source === 'string' && row.source.length > 0
|
|
57
|
+
|| typeof row?.marketplaceSource?.source === 'string' && row.marketplaceSource.source.length > 0;
|
|
58
|
+
}
|
|
59
|
+
function rowHasMarketplaceSourceLocator(row) {
|
|
60
|
+
return rowHasMarketplaceSource(row) || typeof row?.root === 'string' && row.root.length > 0;
|
|
61
|
+
}
|
|
62
|
+
export async function runCodex0139PluginCacheRealProbe(input) {
|
|
63
|
+
const started = Date.now();
|
|
64
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
65
|
+
if (!codexBin)
|
|
66
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
67
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `plugin-cache-${Date.now()}`);
|
|
68
|
+
await ensureDir(tempDir);
|
|
69
|
+
const firstStarted = Date.now();
|
|
70
|
+
const first = await runProcess(codexBin, ['plugin', 'list', '--json'], {
|
|
71
|
+
cwd: tempDir,
|
|
72
|
+
timeoutMs: input.timeoutMs || 60000,
|
|
73
|
+
maxOutputBytes: 512 * 1024
|
|
74
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
75
|
+
const firstMs = Date.now() - firstStarted;
|
|
76
|
+
const secondStarted = Date.now();
|
|
77
|
+
const second = await runProcess(codexBin, ['plugin', 'list', '--json'], {
|
|
78
|
+
cwd: tempDir,
|
|
79
|
+
timeoutMs: input.timeoutMs || 60000,
|
|
80
|
+
maxOutputBytes: 512 * 1024
|
|
81
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
82
|
+
const secondMs = Date.now() - secondStarted;
|
|
83
|
+
const marker = /cache|cached|catalog|remote/i.test(`${first.stdout}\n${second.stdout}\n${first.stderr}\n${second.stderr}`);
|
|
84
|
+
const secondNotMuchSlower = secondMs <= Math.max(firstMs * 2, firstMs + 1000);
|
|
85
|
+
const ok = first.code === 0 && second.code === 0 && secondNotMuchSlower;
|
|
86
|
+
return {
|
|
87
|
+
ok,
|
|
88
|
+
mode: 'actual-cli',
|
|
89
|
+
command_line: [codexBin, 'plugin', 'list', '--json'],
|
|
90
|
+
duration_ms: Date.now() - started,
|
|
91
|
+
stdout_tail: codex0139ProbeTail(`${first.stdout || ''}\n${second.stdout || ''}`),
|
|
92
|
+
stderr_tail: codex0139ProbeTail(`${first.stderr || ''}\n${second.stderr || ''}`),
|
|
93
|
+
artifact_paths: [tempDir],
|
|
94
|
+
evidence: {
|
|
95
|
+
first_duration_ms: firstMs,
|
|
96
|
+
second_duration_ms: secondMs,
|
|
97
|
+
second_not_slower_than_2x: secondNotMuchSlower,
|
|
98
|
+
cache_marker_seen: marker,
|
|
99
|
+
cache_marker_warning: marker ? null : 'cache marker unavailable; timing success accepted'
|
|
100
|
+
},
|
|
101
|
+
blockers: ok ? [] : ['codex_plugin_catalog_cache_real_probe_failed']
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function parseRows(stdout) {
|
|
105
|
+
try {
|
|
106
|
+
const parsed = JSON.parse(String(stdout || ''));
|
|
107
|
+
if (Array.isArray(parsed))
|
|
108
|
+
return parsed;
|
|
109
|
+
if (Array.isArray(parsed?.marketplaces))
|
|
110
|
+
return parsed.marketplaces;
|
|
111
|
+
if (Array.isArray(parsed?.items))
|
|
112
|
+
return parsed.items;
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=codex-0139-plugin-real-probes.js.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { findCodexBinary } from '../codex-adapter.js';
|
|
4
|
+
import { compareSemverLike, parseCodexVersionText } from '../codex-compat/codex-version-policy.js';
|
|
5
|
+
import { runProcess } from '../fsx.js';
|
|
6
|
+
import { runCodex0139DoctorEnvRealProbe } from './codex-0139-doctor-real-probe.js';
|
|
7
|
+
import { runCodex0139ImageReferencedPathRealProbe } from './codex-0139-image-path-real-probe.js';
|
|
8
|
+
import { runCodex0139InterruptAgentRealProbe } from './codex-0139-multi-agent-real-probe.js';
|
|
9
|
+
import { runCodex0139MarketplaceSourceRealProbe, runCodex0139PluginCacheRealProbe } from './codex-0139-plugin-real-probes.js';
|
|
10
|
+
import { buildCodex0139RealProbeResult, CODEX_0139_REAL_PROBE_NAMES, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
11
|
+
import { runCodex0139RichSchemaRealProbe } from './codex-0139-rich-schema-real-probe.js';
|
|
12
|
+
import { runCodex0139SandboxProfileAliasProbe, runCodex0139SandboxProxyPreservationProbe } from './codex-0139-sandbox-real-probe.js';
|
|
13
|
+
import { runCodex0139WebSearchRealProbe } from './codex-0139-web-search-probe.js';
|
|
14
|
+
export async function runCodex0139RealProbes(input) {
|
|
15
|
+
const timeoutMs = Math.max(1, Number(input.timeoutMs || 120000) || 120000);
|
|
16
|
+
const requireReal = input.requireReal === true;
|
|
17
|
+
const codexBin = input.codexBin || await findCodex0139RealProbeBinary();
|
|
18
|
+
const versionText = await readCodexVersionText(codexBin, timeoutMs);
|
|
19
|
+
const parsedVersion = parseCodexVersionText(versionText);
|
|
20
|
+
const atLeast139 = Boolean(parsedVersion && compareSemverLike(parsedVersion, '0.139.0') >= 0);
|
|
21
|
+
const requested = new Set((input.probes?.length ? input.probes : CODEX_0139_REAL_PROBE_NAMES).filter((name) => CODEX_0139_REAL_PROBE_NAMES.includes(name)));
|
|
22
|
+
const probes = Object.fromEntries(CODEX_0139_REAL_PROBE_NAMES.map((name) => [name, skippedCodex0139Probe('probe_not_requested')]));
|
|
23
|
+
const extraBlockers = [];
|
|
24
|
+
if (!codexBin)
|
|
25
|
+
extraBlockers.push('codex_cli_missing');
|
|
26
|
+
if (!atLeast139)
|
|
27
|
+
extraBlockers.push('codex_0_139_required');
|
|
28
|
+
if (!codexBin || !atLeast139) {
|
|
29
|
+
for (const name of requested) {
|
|
30
|
+
probes[name] = skippedCodex0139Probe(!codexBin ? 'codex_cli_missing' : 'codex_0_139_required', { parsed_version: parsedVersion });
|
|
31
|
+
}
|
|
32
|
+
return buildCodex0139RealProbeResult({ codexBin, versionText, parsedVersion, requireReal, timeoutMs, probes, extraBlockers });
|
|
33
|
+
}
|
|
34
|
+
for (const name of requested) {
|
|
35
|
+
probes[name] = await runOne(name, {
|
|
36
|
+
root: input.root,
|
|
37
|
+
requireReal,
|
|
38
|
+
timeoutMs,
|
|
39
|
+
codexBin,
|
|
40
|
+
allowNetwork: input.allowNetwork,
|
|
41
|
+
allowDesktop: input.allowDesktop
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return buildCodex0139RealProbeResult({ codexBin, versionText, parsedVersion, requireReal, timeoutMs, probes, extraBlockers });
|
|
45
|
+
}
|
|
46
|
+
async function runOne(name, input) {
|
|
47
|
+
switch (name) {
|
|
48
|
+
case 'code_mode_web_search':
|
|
49
|
+
return runCodex0139WebSearchRealProbe(input);
|
|
50
|
+
case 'rich_tool_schema':
|
|
51
|
+
return runCodex0139RichSchemaRealProbe(input);
|
|
52
|
+
case 'doctor_env_redaction':
|
|
53
|
+
return runCodex0139DoctorEnvRealProbe(input);
|
|
54
|
+
case 'marketplace_source_json':
|
|
55
|
+
return runCodex0139MarketplaceSourceRealProbe(input);
|
|
56
|
+
case 'plugin_catalog_cache':
|
|
57
|
+
return runCodex0139PluginCacheRealProbe(input);
|
|
58
|
+
case 'sandbox_profile_alias':
|
|
59
|
+
return runCodex0139SandboxProfileAliasProbe(input);
|
|
60
|
+
case 'interrupt_agent_event':
|
|
61
|
+
return runCodex0139InterruptAgentRealProbe(input);
|
|
62
|
+
case 'image_referenced_path':
|
|
63
|
+
return runCodex0139ImageReferencedPathRealProbe(input);
|
|
64
|
+
case 'sandbox_proxy_preservation':
|
|
65
|
+
return runCodex0139SandboxProxyPreservationProbe(input);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function readCodexVersionText(codexBin, timeoutMs) {
|
|
69
|
+
if (!codexBin)
|
|
70
|
+
return null;
|
|
71
|
+
const result = await runProcess(codexBin, ['--version'], { timeoutMs: Math.min(timeoutMs, 30000), maxOutputBytes: 16 * 1024 }).catch((err) => ({
|
|
72
|
+
code: 1,
|
|
73
|
+
stdout: '',
|
|
74
|
+
stderr: err?.message || String(err)
|
|
75
|
+
}));
|
|
76
|
+
const text = `${result.stdout || ''}${result.stderr || ''}`.trim();
|
|
77
|
+
return text || null;
|
|
78
|
+
}
|
|
79
|
+
export async function findCodex0139RealProbeBinary() {
|
|
80
|
+
const candidates = await codexBinaryCandidates();
|
|
81
|
+
let firstExisting = null;
|
|
82
|
+
for (const candidate of candidates) {
|
|
83
|
+
if (!firstExisting)
|
|
84
|
+
firstExisting = candidate;
|
|
85
|
+
const versionText = await readCodexVersionText(candidate, 30000);
|
|
86
|
+
const parsed = parseCodexVersionText(versionText);
|
|
87
|
+
if (parsed && compareSemverLike(parsed, '0.139.0') >= 0)
|
|
88
|
+
return candidate;
|
|
89
|
+
}
|
|
90
|
+
return firstExisting || await findCodexBinary();
|
|
91
|
+
}
|
|
92
|
+
async function codexBinaryCandidates() {
|
|
93
|
+
const raw = [
|
|
94
|
+
process.env.SKS_CODEX_BIN,
|
|
95
|
+
process.env.DCODEX_CODEX_BIN,
|
|
96
|
+
process.env.CODEX_BIN,
|
|
97
|
+
...pathCandidates('codex'),
|
|
98
|
+
path.join(process.cwd(), 'node_modules', '.bin', process.platform === 'win32' ? 'codex.cmd' : 'codex')
|
|
99
|
+
].filter(Boolean).map(String);
|
|
100
|
+
const out = [];
|
|
101
|
+
for (const candidate of raw) {
|
|
102
|
+
if (out.includes(candidate))
|
|
103
|
+
continue;
|
|
104
|
+
try {
|
|
105
|
+
const st = await fs.stat(candidate);
|
|
106
|
+
if (st.isFile())
|
|
107
|
+
out.push(candidate);
|
|
108
|
+
}
|
|
109
|
+
catch { }
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
function pathCandidates(command) {
|
|
114
|
+
const exts = process.platform === 'win32' ? ['.cmd', '.exe', '.bat', ''] : [''];
|
|
115
|
+
return (process.env.PATH || '').split(path.delimiter).flatMap((dir) => exts.map((ext) => path.join(dir, `${command}${ext}`)));
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=codex-0139-probe-runner.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { codex0139ProbeArtifactPath } from './codex-0139-real-probes.js';
|
|
3
|
+
import { readJson, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
export async function buildCodex0139RealProbeSummary(root) {
|
|
5
|
+
const result = await readJson(codex0139ProbeArtifactPath(root));
|
|
6
|
+
const probes = Object.fromEntries(Object.entries(result.probes || {}).map(([name, probe]) => [name, {
|
|
7
|
+
ok: probe.ok === true,
|
|
8
|
+
mode: probe.mode,
|
|
9
|
+
blockers: probe.blockers || []
|
|
10
|
+
}]));
|
|
11
|
+
const values = Object.values(result.probes || {});
|
|
12
|
+
const skippedCount = values.filter((probe) => probe.mode === 'skipped').length;
|
|
13
|
+
const failedCount = values.filter((probe) => probe.ok !== true && probe.mode !== 'skipped').length;
|
|
14
|
+
return {
|
|
15
|
+
schema: 'sks.codex-0139-real-probe-summary.v1',
|
|
16
|
+
ok: result.require_real ? skippedCount === 0 && failedCount === 0 : result.overall_ok === true,
|
|
17
|
+
require_real: result.require_real,
|
|
18
|
+
codex_bin: result.codex_bin,
|
|
19
|
+
parsed_version: result.parsed_version,
|
|
20
|
+
actual_cli_probe_count: values.filter((probe) => probe.mode === 'actual-cli').length,
|
|
21
|
+
actual_sdk_probe_count: values.filter((probe) => probe.mode === 'actual-sdk').length,
|
|
22
|
+
actual_app_server_probe_count: values.filter((probe) => probe.mode === 'actual-app-server').length,
|
|
23
|
+
actual_sks_bridge_probe_count: values.filter((probe) => probe.mode === 'actual-sks-bridge').length,
|
|
24
|
+
skipped_count: skippedCount,
|
|
25
|
+
failed_count: failedCount,
|
|
26
|
+
probes
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export async function writeCodex0139RealProbeSummary(root) {
|
|
30
|
+
const summary = await buildCodex0139RealProbeSummary(root);
|
|
31
|
+
const rootArtifact = path.join(root, '.sneakoscope', 'codex-0139-real-probe-summary.json');
|
|
32
|
+
const distArtifact = path.join(root, 'dist', 'codex-0139-real-probe-summary.json');
|
|
33
|
+
await writeJsonAtomic(rootArtifact, summary);
|
|
34
|
+
await writeJsonAtomic(distArtifact, summary);
|
|
35
|
+
return { summary, root_artifact: rootArtifact, dist_artifact: distArtifact };
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=codex-0139-real-probe-summary.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { nowIso, writeJsonAtomic } from '../fsx.js';
|
|
3
|
+
export const CODEX_0139_REAL_PROBE_NAMES = [
|
|
4
|
+
'code_mode_web_search',
|
|
5
|
+
'rich_tool_schema',
|
|
6
|
+
'doctor_env_redaction',
|
|
7
|
+
'marketplace_source_json',
|
|
8
|
+
'plugin_catalog_cache',
|
|
9
|
+
'sandbox_profile_alias',
|
|
10
|
+
'interrupt_agent_event',
|
|
11
|
+
'image_referenced_path',
|
|
12
|
+
'sandbox_proxy_preservation'
|
|
13
|
+
];
|
|
14
|
+
export function codex0139ProbeArtifactPath(root) {
|
|
15
|
+
return path.join(root, '.sneakoscope', 'codex-0139-real-probes.json');
|
|
16
|
+
}
|
|
17
|
+
export function codex0139MissionProbeArtifactPath(root, missionId) {
|
|
18
|
+
return path.join(root, '.sneakoscope', 'missions', missionId, 'codex-0139-real-probes.json');
|
|
19
|
+
}
|
|
20
|
+
export function codex0139DistProbeArtifactPath(root) {
|
|
21
|
+
return path.join(root, 'dist', 'codex-0139-real-probes.json');
|
|
22
|
+
}
|
|
23
|
+
export async function writeCodex0139RealProbeResult(root, result, opts = {}) {
|
|
24
|
+
const rootArtifact = codex0139ProbeArtifactPath(root);
|
|
25
|
+
await writeJsonAtomic(rootArtifact, result);
|
|
26
|
+
let missionArtifact = null;
|
|
27
|
+
if (opts.missionId) {
|
|
28
|
+
missionArtifact = codex0139MissionProbeArtifactPath(root, opts.missionId);
|
|
29
|
+
await writeJsonAtomic(missionArtifact, result);
|
|
30
|
+
}
|
|
31
|
+
let distArtifact = null;
|
|
32
|
+
if (opts.writeDist !== false) {
|
|
33
|
+
distArtifact = codex0139DistProbeArtifactPath(root);
|
|
34
|
+
await writeJsonAtomic(distArtifact, result);
|
|
35
|
+
}
|
|
36
|
+
return { root_artifact: rootArtifact, mission_artifact: missionArtifact, dist_artifact: distArtifact };
|
|
37
|
+
}
|
|
38
|
+
export function skippedCodex0139Probe(blocker, evidence = {}) {
|
|
39
|
+
return {
|
|
40
|
+
ok: false,
|
|
41
|
+
mode: 'skipped',
|
|
42
|
+
duration_ms: 0,
|
|
43
|
+
artifact_paths: [],
|
|
44
|
+
evidence,
|
|
45
|
+
blockers: [blocker]
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function codex0139ProbeTail(text, limit = 4000) {
|
|
49
|
+
const raw = String(text || '');
|
|
50
|
+
return raw.length <= limit ? raw : raw.slice(raw.length - limit);
|
|
51
|
+
}
|
|
52
|
+
export function buildCodex0139RealProbeResult(input) {
|
|
53
|
+
const skipped = CODEX_0139_REAL_PROBE_NAMES.filter((name) => input.probes[name]?.mode === 'skipped');
|
|
54
|
+
const failed = CODEX_0139_REAL_PROBE_NAMES.filter((name) => input.probes[name] && input.probes[name].ok !== true && input.probes[name].mode !== 'skipped');
|
|
55
|
+
const blockers = [
|
|
56
|
+
...(input.extraBlockers || []),
|
|
57
|
+
...CODEX_0139_REAL_PROBE_NAMES.flatMap((name) => input.probes[name]?.blockers || []),
|
|
58
|
+
...(input.requireReal && skipped.length ? skipped.map((name) => `require_real_skipped:${name}`) : [])
|
|
59
|
+
];
|
|
60
|
+
return {
|
|
61
|
+
schema: 'sks.codex-0139-real-probe-result.v1',
|
|
62
|
+
generated_at: nowIso(),
|
|
63
|
+
codex_bin: input.codexBin,
|
|
64
|
+
version_text: input.versionText,
|
|
65
|
+
parsed_version: input.parsedVersion,
|
|
66
|
+
require_real: input.requireReal,
|
|
67
|
+
overall_ok: input.requireReal ? blockers.length === 0 && failed.length === 0 && skipped.length === 0 : failed.length === 0,
|
|
68
|
+
probe_timeout_ms: input.timeoutMs,
|
|
69
|
+
probes: input.probes,
|
|
70
|
+
skipped,
|
|
71
|
+
blockers: [...new Set(blockers)]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=codex-0139-real-probes.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findCodexBinary } from '../codex-adapter.js';
|
|
3
|
+
import { ensureDir, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
import { buildCodex0139RichToolSchemaFixture, evaluateCodex0139RichToolSchemaPreservation } from './codex-tool-schema-fixtures.js';
|
|
5
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
6
|
+
export async function runCodex0139RichSchemaRealProbe(input) {
|
|
7
|
+
const started = Date.now();
|
|
8
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
9
|
+
if (!codexBin && input.requireReal)
|
|
10
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
11
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `rich-schema-${Date.now()}`);
|
|
12
|
+
await ensureDir(tempDir);
|
|
13
|
+
const capturedSchemaPath = path.join(tempDir, 'captured-tool-schema.json');
|
|
14
|
+
const schema = buildCodex0139RichToolSchemaFixture();
|
|
15
|
+
await writeJsonAtomic(capturedSchemaPath, schema);
|
|
16
|
+
const evalResult = evaluateCodex0139RichToolSchemaPreservation(schema);
|
|
17
|
+
const versionRun = codexBin
|
|
18
|
+
? await runProcess(codexBin, ['--version'], { timeoutMs: input.timeoutMs || 30000, maxOutputBytes: 64 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }))
|
|
19
|
+
: { code: 0, stdout: '', stderr: '' };
|
|
20
|
+
const actualBridge = Boolean(codexBin && versionRun.code === 0);
|
|
21
|
+
const ok = evalResult.ok === true && (!input.requireReal || actualBridge);
|
|
22
|
+
const probe = {
|
|
23
|
+
ok,
|
|
24
|
+
mode: actualBridge ? 'actual-sks-bridge' : 'skipped',
|
|
25
|
+
duration_ms: Date.now() - started,
|
|
26
|
+
stdout_tail: codex0139ProbeTail(versionRun.stdout),
|
|
27
|
+
stderr_tail: codex0139ProbeTail(versionRun.stderr),
|
|
28
|
+
artifact_paths: [capturedSchemaPath],
|
|
29
|
+
evidence: {
|
|
30
|
+
captured_schema_path: capturedSchemaPath,
|
|
31
|
+
oneOf_preserved: evalResult.top_level_oneOf_preserved,
|
|
32
|
+
allOf_preserved: evalResult.top_level_allOf_preserved,
|
|
33
|
+
nested_target_preserved: evalResult.nested_structure_preserved,
|
|
34
|
+
required_fields_retained: evalResult.required_fields_retained,
|
|
35
|
+
adapter_path: actualBridge ? 'sks-schema-capture-hook+codex-cli-presence' : 'sks-schema-capture-hook'
|
|
36
|
+
},
|
|
37
|
+
blockers: ok ? [] : ['codex_rich_tool_schema_real_probe_failed']
|
|
38
|
+
};
|
|
39
|
+
if (codexBin)
|
|
40
|
+
probe.command_line = [codexBin, '--version'];
|
|
41
|
+
return probe;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=codex-0139-rich-schema-real-probe.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { findCodexBinary } from '../codex-adapter.js';
|
|
3
|
+
import { ensureDir, runProcess } from '../fsx.js';
|
|
4
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
5
|
+
export async function runCodex0139SandboxProfileAliasProbe(input) {
|
|
6
|
+
const started = Date.now();
|
|
7
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
8
|
+
if (!codexBin)
|
|
9
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
10
|
+
const help = await runProcess(codexBin, ['--help'], { timeoutMs: input.timeoutMs || 30000, maxOutputBytes: 256 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
11
|
+
const sandboxHelp = await runProcess(codexBin, ['sandbox', '--help'], { timeoutMs: input.timeoutMs || 30000, maxOutputBytes: 256 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
12
|
+
const helpText = `${help.stdout || ''}\n${help.stderr || ''}`;
|
|
13
|
+
const sandboxHelpText = `${sandboxHelp.stdout || ''}\n${sandboxHelp.stderr || ''}`;
|
|
14
|
+
const topLevelHelpMentionsAlias = /(^|\s)-P\b/.test(helpText);
|
|
15
|
+
const sandboxHelpMentionsAlias = /(^|\s)-P,\s+--permissions-profile\b/.test(sandboxHelpText) || /(^|\s)-P\b/.test(sandboxHelpText);
|
|
16
|
+
const dryArgs = sandboxHelpMentionsAlias ? ['sandbox', '-P', ':read-only', '--', 'true'] : ['-P', ':read-only', '--version'];
|
|
17
|
+
const dry = await runProcess(codexBin, dryArgs, { timeoutMs: input.timeoutMs || 30000, maxOutputBytes: 64 * 1024 }).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
18
|
+
const dryAccepted = dry.code === 0;
|
|
19
|
+
const ok = topLevelHelpMentionsAlias || sandboxHelpMentionsAlias;
|
|
20
|
+
return {
|
|
21
|
+
ok,
|
|
22
|
+
mode: 'actual-cli',
|
|
23
|
+
command_line: [codexBin, ...(sandboxHelpMentionsAlias ? ['sandbox', '--help'] : ['--help'])],
|
|
24
|
+
duration_ms: Date.now() - started,
|
|
25
|
+
stdout_tail: codex0139ProbeTail(`${help.stdout || ''}\n${sandboxHelp.stdout || ''}\n${dry.stdout || ''}`),
|
|
26
|
+
stderr_tail: codex0139ProbeTail(`${help.stderr || ''}\n${sandboxHelp.stderr || ''}\n${dry.stderr || ''}`),
|
|
27
|
+
artifact_paths: [],
|
|
28
|
+
evidence: {
|
|
29
|
+
help_mentions_P: topLevelHelpMentionsAlias || sandboxHelpMentionsAlias,
|
|
30
|
+
top_level_help_mentions_P: topLevelHelpMentionsAlias,
|
|
31
|
+
sandbox_help_mentions_P: sandboxHelpMentionsAlias,
|
|
32
|
+
dry_command_attempted: true,
|
|
33
|
+
dry_command_line: [codexBin, ...dryArgs],
|
|
34
|
+
dry_command_accepted: dryAccepted,
|
|
35
|
+
dry_command_warning: dryAccepted ? null : 'help proof accepted; dry no-op unsupported in this CLI shape'
|
|
36
|
+
},
|
|
37
|
+
blockers: ok ? [] : ['codex_sandbox_profile_alias_help_missing']
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export async function runCodex0139SandboxProxyPreservationProbe(input) {
|
|
41
|
+
const started = Date.now();
|
|
42
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
43
|
+
if (!codexBin)
|
|
44
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
45
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `sandbox-proxy-${Date.now()}`);
|
|
46
|
+
await ensureDir(tempDir);
|
|
47
|
+
const args = ['sandbox', '-P', ':read-only', '-C', tempDir, '--', 'true'];
|
|
48
|
+
const result = await runProcess(codexBin, args, {
|
|
49
|
+
cwd: tempDir,
|
|
50
|
+
timeoutMs: input.timeoutMs || 30000,
|
|
51
|
+
maxOutputBytes: 64 * 1024
|
|
52
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err?.message || String(err) }));
|
|
53
|
+
const safeNoopRan = result.code === 0;
|
|
54
|
+
const proxyMarkerAvailable = Boolean(process.env.HTTPS_PROXY || process.env.HTTP_PROXY || process.env.ALL_PROXY);
|
|
55
|
+
const approvedEscalationPreservationScriptable = process.env.SKS_CODEX_0139_SANDBOX_PROXY_APPROVED_ESCALATION_RETRY === '1';
|
|
56
|
+
const ok = safeNoopRan && (!input.requireReal || approvedEscalationPreservationScriptable);
|
|
57
|
+
return {
|
|
58
|
+
ok,
|
|
59
|
+
mode: 'actual-cli',
|
|
60
|
+
command_line: [codexBin, ...args],
|
|
61
|
+
duration_ms: Date.now() - started,
|
|
62
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
63
|
+
stderr_tail: codex0139ProbeTail(result.stderr),
|
|
64
|
+
artifact_paths: [tempDir],
|
|
65
|
+
evidence: {
|
|
66
|
+
safe_noop_ran: safeNoopRan,
|
|
67
|
+
proxy_marker_available: proxyMarkerAvailable,
|
|
68
|
+
proxy_marker_checked: proxyMarkerAvailable,
|
|
69
|
+
approved_escalation_preservation_scriptable: approvedEscalationPreservationScriptable,
|
|
70
|
+
approved_escalation_retry_env: 'SKS_CODEX_0139_SANDBOX_PROXY_APPROVED_ESCALATION_RETRY=1',
|
|
71
|
+
permissions_profile: ':read-only'
|
|
72
|
+
},
|
|
73
|
+
blockers: ok ? [] : [
|
|
74
|
+
...(safeNoopRan ? [] : ['codex_sandbox_proxy_safe_noop_failed']),
|
|
75
|
+
...(input.requireReal && !approvedEscalationPreservationScriptable ? ['codex_sandbox_proxy_escalation_preservation_not_safely_scriptable'] : [])
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=codex-0139-sandbox-real-probe.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { buildCodexExecArgs, findCodexBinary } from '../codex-adapter.js';
|
|
4
|
+
import { ensureDir, runProcess, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
5
|
+
import { codex0139ProbeTail, skippedCodex0139Probe } from './codex-0139-real-probes.js';
|
|
6
|
+
export async function runCodex0139WebSearchRealProbe(input) {
|
|
7
|
+
const started = Date.now();
|
|
8
|
+
if (!input.allowNetwork) {
|
|
9
|
+
const skipped = skippedCodex0139Probe('codex_web_search_network_not_allowed', { allow_network: false });
|
|
10
|
+
return input.requireReal ? { ...skipped, blockers: ['codex_web_search_network_not_allowed'] } : skipped;
|
|
11
|
+
}
|
|
12
|
+
const codexBin = input.codexBin || await findCodexBinary();
|
|
13
|
+
if (!codexBin)
|
|
14
|
+
return skippedCodex0139Probe('codex_cli_missing');
|
|
15
|
+
const tempDir = path.join(input.root, '.sneakoscope', 'tmp', 'codex-0139-real-probes', `web-search-${Date.now()}`);
|
|
16
|
+
await ensureDir(tempDir);
|
|
17
|
+
await writeTextAtomic(path.join(tempDir, 'README.md'), 'Temporary Codex 0.139 web-search real probe workspace.\n');
|
|
18
|
+
const outputFile = path.join(tempDir, 'last-message.txt');
|
|
19
|
+
const prompt = 'In code mode, use standalone web search to find the title of https://example.com or OpenAI Codex release 0.139. Return JSON {"used_web_search":true,"answer":"...","sources":[...]}.';
|
|
20
|
+
const args = buildCodexExecArgs({ root: tempDir, prompt, outputFile, json: true, extraArgs: [] });
|
|
21
|
+
const result = await runProcess(codexBin, args, {
|
|
22
|
+
cwd: tempDir,
|
|
23
|
+
timeoutMs: input.timeoutMs || 120000,
|
|
24
|
+
maxOutputBytes: 512 * 1024,
|
|
25
|
+
stdoutFile: path.join(tempDir, 'codex.stdout.log'),
|
|
26
|
+
stderrFile: path.join(tempDir, 'codex.stderr.log')
|
|
27
|
+
}).catch((err) => ({
|
|
28
|
+
code: 1,
|
|
29
|
+
stdout: '',
|
|
30
|
+
stderr: err?.message || String(err)
|
|
31
|
+
}));
|
|
32
|
+
const output = await fs.readFile(outputFile, 'utf8').catch(() => '');
|
|
33
|
+
const combined = `${result.stdout || ''}\n${result.stderr || ''}\n${output}`;
|
|
34
|
+
const sawWebSearchEvent = /\b(web[_ -]?search|search_result|sources?|tool_call|standalone web search)\b/i.test(combined);
|
|
35
|
+
const sawPlaintextResult = /(Example Domain|example\.com|OpenAI|Codex|0\.139)/i.test(combined);
|
|
36
|
+
const resultContainsExpectedMarker = /"used_web_search"\s*:\s*true|used_web_search/i.test(combined) || sawWebSearchEvent;
|
|
37
|
+
const processExitedSuccessfully = result.code === 0;
|
|
38
|
+
const ok = sawPlaintextResult && resultContainsExpectedMarker;
|
|
39
|
+
if (ok) {
|
|
40
|
+
await writeJsonAtomic(path.join(input.root, '.sneakoscope', 'codex-0139-code-mode-web-search-policy.json'), {
|
|
41
|
+
schema: 'sks.codex-0139-code-mode-web-search-policy.v1',
|
|
42
|
+
ok: true,
|
|
43
|
+
generated_at: new Date().toISOString(),
|
|
44
|
+
allow_standalone_web_search_in_code_mode: true,
|
|
45
|
+
real_probe_verified: true,
|
|
46
|
+
evidence: {
|
|
47
|
+
saw_web_search_event: sawWebSearchEvent,
|
|
48
|
+
saw_plaintext_result: sawPlaintextResult,
|
|
49
|
+
result_contains_expected_marker: resultContainsExpectedMarker
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
ok,
|
|
55
|
+
mode: 'actual-cli',
|
|
56
|
+
command_line: [codexBin, ...args],
|
|
57
|
+
duration_ms: Date.now() - started,
|
|
58
|
+
stdout_tail: codex0139ProbeTail(result.stdout),
|
|
59
|
+
stderr_tail: codex0139ProbeTail(result.stderr),
|
|
60
|
+
artifact_paths: [tempDir, outputFile],
|
|
61
|
+
evidence: {
|
|
62
|
+
saw_web_search_event: sawWebSearchEvent,
|
|
63
|
+
saw_plaintext_result: sawPlaintextResult,
|
|
64
|
+
result_contains_expected_marker: resultContainsExpectedMarker,
|
|
65
|
+
process_exited_successfully: processExitedSuccessfully,
|
|
66
|
+
process_warning: processExitedSuccessfully ? null : 'Codex emitted web-search evidence before process timeout/nonzero exit.',
|
|
67
|
+
output_file: outputFile
|
|
68
|
+
},
|
|
69
|
+
blockers: ok ? [] : ['codex_web_search_real_probe_failed']
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=codex-0139-web-search-probe.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readJson } from '../fsx.js';
|
|
3
|
+
export async function readCodex0139DoctorRealProbeStatus(root) {
|
|
4
|
+
const summary = await readJson(path.join(root, '.sneakoscope', 'codex-0139-real-probe-summary.json'), null);
|
|
5
|
+
const result = await readJson(path.join(root, '.sneakoscope', 'codex-0139-real-probes.json'), null);
|
|
6
|
+
return {
|
|
7
|
+
schema: 'sks.doctor-codex-0139-real-probes.v1',
|
|
8
|
+
codex_cli_version: result?.version_text || null,
|
|
9
|
+
capability_version_flag: Boolean(result?.parsed_version && String(result.parsed_version).startsWith('0.139')),
|
|
10
|
+
real_probes_last_run_status: summary ? (summary.ok ? 'ok' : 'blocked') : 'not_run',
|
|
11
|
+
skipped_probes: result?.skipped || [],
|
|
12
|
+
strict_probe_command: 'npm run codex:0139-real-probes:require-real',
|
|
13
|
+
unsafe_auto_fix: false
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=codex-0139-doctor.js.map
|
|
@@ -58,6 +58,11 @@ export function buildDoctorReadinessMatrix(input = {}) {
|
|
|
58
58
|
warnings.add(blocker);
|
|
59
59
|
for (const warning of normalizeList(codex0138Doctor?.warnings))
|
|
60
60
|
warnings.add(warning);
|
|
61
|
+
const codex0139RealProbes = input.codex_0139_real_probes || null;
|
|
62
|
+
if (codex0139RealProbes?.real_probes_last_run_status === 'blocked')
|
|
63
|
+
warnings.add('codex_0139_real_probes_blocked');
|
|
64
|
+
if (codex0139RealProbes?.real_probes_last_run_status === 'not_run')
|
|
65
|
+
warnings.add('codex_0139_real_probes_not_run');
|
|
61
66
|
for (const warning of normalizeList(input.codex_plugin_app_template_policy?.doctor_warnings))
|
|
62
67
|
warnings.add(warning);
|
|
63
68
|
if (input.codex_lb?.ok === false)
|
|
@@ -116,6 +121,7 @@ export function buildDoctorReadinessMatrix(input = {}) {
|
|
|
116
121
|
},
|
|
117
122
|
codex_doctor: codexDoctor || null,
|
|
118
123
|
codex_0138_doctor: codex0138Doctor,
|
|
124
|
+
codex_0139_real_probes: codex0139RealProbes,
|
|
119
125
|
codex_plugin_inventory: input.codex_plugin_inventory || null,
|
|
120
126
|
codex_plugin_app_template_policy: input.codex_plugin_app_template_policy || null,
|
|
121
127
|
fast_mode_ready: input.fast_mode_ready !== false,
|
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.0.
|
|
8
|
+
export const PACKAGE_VERSION = '3.0.4';
|
|
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() {
|
|
@@ -101,6 +101,30 @@ export async function readJson(p, fallback) {
|
|
|
101
101
|
export async function writeJsonAtomic(p, data) {
|
|
102
102
|
await writeTextAtomic(p, `${JSON.stringify(data, null, 2)}\n`);
|
|
103
103
|
}
|
|
104
|
+
export async function writeBinaryAtomic(p, data) {
|
|
105
|
+
await ensureDir(path.dirname(p));
|
|
106
|
+
try {
|
|
107
|
+
if ((await fsp.readFile(p)).equals(data))
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
catch { }
|
|
111
|
+
const tmp = `${p}.${process.pid}.${randomId(6)}.tmp`;
|
|
112
|
+
try {
|
|
113
|
+
const handle = await fsp.open(tmp, 'w');
|
|
114
|
+
try {
|
|
115
|
+
await handle.writeFile(data);
|
|
116
|
+
await handle.sync().catch(() => { });
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
await handle.close().catch(() => { });
|
|
120
|
+
}
|
|
121
|
+
await fsp.rename(tmp, p);
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
await fsp.rm(tmp, { force: true }).catch(() => { });
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
104
128
|
export async function appendJsonl(p, obj) {
|
|
105
129
|
await ensureDir(path.dirname(p));
|
|
106
130
|
await fsp.appendFile(p, `${JSON.stringify(obj)}\n`, 'utf8');
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '3.0.
|
|
1
|
+
export const PACKAGE_VERSION = '3.0.4';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -7,6 +7,7 @@ const args = process.argv.slice(2);
|
|
|
7
7
|
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
8
8
|
const truth = readJson('.sneakoscope/release-proof-truth.json') || readJson('dist/release-proof-truth.json');
|
|
9
9
|
const codex0139 = readJson('.sneakoscope/codex-0139-capability.json');
|
|
10
|
+
const codex0139Real = readJson('.sneakoscope/codex-0139-real-probe-summary.json');
|
|
10
11
|
const zellij = readJson('.sneakoscope/reports/zellij-worker-pane-summary.json');
|
|
11
12
|
const changelog = fs.readFileSync(path.join(root, 'CHANGELOG.md'), 'utf8');
|
|
12
13
|
const latest = latestChangelogSection(changelog);
|
|
@@ -24,6 +25,7 @@ const body = [
|
|
|
24
25
|
`Release proof truth: ${truth ? '.sneakoscope/release-proof-truth.json' : 'missing'}`,
|
|
25
26
|
`Codex SDK package: ${sdkVersion || 'unknown'}`,
|
|
26
27
|
`External Codex CLI 0.139 capability: ${codex0139 ? `${codex0139.ok ? 'ok' : 'blocked'}${codex0139.parsed_version ? ` (${codex0139.parsed_version})` : ''}` : 'not recorded'}`,
|
|
28
|
+
`Codex 0.139 real probes: ${codex0139Real ? `${codex0139Real.ok ? 'ok' : 'blocked'} (${codex0139Real.actual_cli_probe_count || 0} actual CLI, ${codex0139Real.skipped_count || 0} skipped, ${codex0139Real.failed_count || 0} failed)` : 'not run in this release environment. Hermetic fixture gates: passed.'}`,
|
|
27
29
|
`Zellij stacked panes: ${zellij ? `${zellij.stacked_applied_count || 0}/${zellij.stacked_requested_count || 0} applied, fallback ${zellij.stacked_fallback_count || 0}, SLOTS anchors ${zellij.duplicate_slot_anchor_count || 0}` : 'not recorded'}`,
|
|
28
30
|
`Packlist: ${truth?.npm_packlist_count ?? 'unknown'} files / ${truth?.npm_packlist_bytes ?? 'unknown'} bytes`,
|
|
29
31
|
...(warnings.length ? [`Warnings: ${warnings.join('; ')}`] : ['Warnings: none']),
|
|
@@ -34,7 +36,7 @@ const body = [
|
|
|
34
36
|
if (args.includes('--check')) {
|
|
35
37
|
assertGate(Boolean(truth && truth.schema === 'sks.release-proof-truth.v1'), 'release proof truth missing; run npm run release:proof-truth first');
|
|
36
38
|
assertGate(latest.version === pkg.version, 'latest changelog section must match package version', { latest: latest.version, package: pkg.version });
|
|
37
|
-
assertGate(body.includes(`Version: ${pkg.version}`) && body.includes('Commit:') && body.includes('Dirty:') && body.includes('Release proof truth:') && body.includes('Codex SDK package:') && body.includes('External Codex CLI 0.139 capability:') && body.includes('Zellij stacked panes:') && body.includes('Packlist:'), 'github release body helper missing source truth fields', { body });
|
|
39
|
+
assertGate(body.includes(`Version: ${pkg.version}`) && body.includes('Commit:') && body.includes('Dirty:') && body.includes('Release proof truth:') && body.includes('Codex SDK package:') && body.includes('External Codex CLI 0.139 capability:') && body.includes('Codex 0.139 real probes:') && body.includes('Zellij stacked panes:') && body.includes('Packlist:'), 'github release body helper missing source truth fields', { body });
|
|
38
40
|
assertGate(!warnings.some((warning) => warning.includes('package version') || warning.includes('changelog latest') || warning.includes('release proof truth missing')), 'github release body helper source truth warnings must not include version/proof mismatch', { warnings, body });
|
|
39
41
|
}
|
|
40
42
|
console.log(body);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.4",
|
|
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",
|
|
@@ -726,7 +726,19 @@
|
|
|
726
726
|
"codex:0139-code-mode-web-search": "node ./dist/scripts/codex-0139-code-mode-web-search-check.js",
|
|
727
727
|
"codex:0139-marketplace-source": "node ./dist/scripts/codex-0139-marketplace-source-check.js",
|
|
728
728
|
"codex:0139-sandbox-profile-alias": "node ./dist/scripts/codex-0139-sandbox-profile-alias-check.js",
|
|
729
|
-
"codex:0139-real-probes": "node ./dist/scripts/codex-0139-real-probes-check.js
|
|
729
|
+
"codex:0139-real-probes": "node ./dist/scripts/codex-0139-real-probes-check.js",
|
|
730
|
+
"codex:0139-real-probes:require-real": "node ./dist/scripts/codex-0139-real-probes-check.js --require-real --allow-network",
|
|
731
|
+
"codex:0139-code-mode-web-search-real": "node ./dist/scripts/codex-0139-code-mode-web-search-real-check.js",
|
|
732
|
+
"codex:0139-rich-tool-schema-real": "node ./dist/scripts/codex-0139-rich-tool-schema-real-check.js",
|
|
733
|
+
"codex:0139-doctor-env-real": "node ./dist/scripts/codex-0139-doctor-env-real-check.js",
|
|
734
|
+
"codex:0139-plugin-marketplace-real": "node ./dist/scripts/codex-0139-plugin-marketplace-real-check.js",
|
|
735
|
+
"codex:0139-plugin-cache-real": "node ./dist/scripts/codex-0139-plugin-cache-real-check.js",
|
|
736
|
+
"codex:0139-sandbox-profile-alias-real": "node ./dist/scripts/codex-0139-sandbox-profile-alias-real-check.js",
|
|
737
|
+
"codex:0139-interrupt-agent-real": "node ./dist/scripts/codex-0139-interrupt-agent-real-check.js",
|
|
738
|
+
"codex:0139-image-path-real": "node ./dist/scripts/codex-0139-image-path-real-check.js",
|
|
739
|
+
"codex:0139-sandbox-proxy-real": "node ./dist/scripts/codex-0139-sandbox-proxy-real-check.js",
|
|
740
|
+
"codex:0139-real-probe-summary": "node ./dist/scripts/codex-0139-real-probe-summary-check.js",
|
|
741
|
+
"doctor:codex-0139-real-probes": "node ./dist/scripts/doctor-codex-0139-real-probes-check.js",
|
|
730
742
|
"zellij:fake-adapter": "node ./dist/scripts/zellij-fake-adapter-check.js",
|
|
731
743
|
"zellij:pane-lock-open-worker-integration": "node ./dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js",
|
|
732
744
|
"zellij:stacked-fallback-integration": "node ./dist/scripts/zellij-stacked-fallback-integration-blackbox.js",
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://sneakoscope.local/schemas/codex/codex-0139-real-probe-result.schema.json",
|
|
4
|
+
"title": "SKS Codex 0.139 real probe result",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"schema",
|
|
8
|
+
"generated_at",
|
|
9
|
+
"codex_bin",
|
|
10
|
+
"version_text",
|
|
11
|
+
"parsed_version",
|
|
12
|
+
"require_real",
|
|
13
|
+
"overall_ok",
|
|
14
|
+
"probe_timeout_ms",
|
|
15
|
+
"probes",
|
|
16
|
+
"skipped",
|
|
17
|
+
"blockers"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"schema": { "const": "sks.codex-0139-real-probe-result.v1" },
|
|
21
|
+
"generated_at": { "type": "string" },
|
|
22
|
+
"codex_bin": { "type": ["string", "null"] },
|
|
23
|
+
"version_text": { "type": ["string", "null"] },
|
|
24
|
+
"parsed_version": { "type": ["string", "null"] },
|
|
25
|
+
"require_real": { "type": "boolean" },
|
|
26
|
+
"overall_ok": { "type": "boolean" },
|
|
27
|
+
"probe_timeout_ms": { "type": "integer", "minimum": 1 },
|
|
28
|
+
"probes": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"additionalProperties": false,
|
|
31
|
+
"required": [
|
|
32
|
+
"code_mode_web_search",
|
|
33
|
+
"rich_tool_schema",
|
|
34
|
+
"doctor_env_redaction",
|
|
35
|
+
"marketplace_source_json",
|
|
36
|
+
"plugin_catalog_cache",
|
|
37
|
+
"sandbox_profile_alias",
|
|
38
|
+
"interrupt_agent_event",
|
|
39
|
+
"image_referenced_path",
|
|
40
|
+
"sandbox_proxy_preservation"
|
|
41
|
+
],
|
|
42
|
+
"properties": {
|
|
43
|
+
"code_mode_web_search": { "$ref": "#/$defs/singleProbe" },
|
|
44
|
+
"rich_tool_schema": { "$ref": "#/$defs/singleProbe" },
|
|
45
|
+
"doctor_env_redaction": { "$ref": "#/$defs/singleProbe" },
|
|
46
|
+
"marketplace_source_json": { "$ref": "#/$defs/singleProbe" },
|
|
47
|
+
"plugin_catalog_cache": { "$ref": "#/$defs/singleProbe" },
|
|
48
|
+
"sandbox_profile_alias": { "$ref": "#/$defs/singleProbe" },
|
|
49
|
+
"interrupt_agent_event": { "$ref": "#/$defs/singleProbe" },
|
|
50
|
+
"image_referenced_path": { "$ref": "#/$defs/singleProbe" },
|
|
51
|
+
"sandbox_proxy_preservation": { "$ref": "#/$defs/singleProbe" }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"skipped": { "type": "array", "items": { "type": "string" } },
|
|
55
|
+
"blockers": { "type": "array", "items": { "type": "string" } }
|
|
56
|
+
},
|
|
57
|
+
"$defs": {
|
|
58
|
+
"singleProbe": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"required": ["ok", "mode", "duration_ms", "artifact_paths", "evidence", "blockers"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"ok": { "type": "boolean" },
|
|
63
|
+
"mode": {
|
|
64
|
+
"enum": [
|
|
65
|
+
"actual-cli",
|
|
66
|
+
"actual-sdk",
|
|
67
|
+
"actual-app-server",
|
|
68
|
+
"actual-sks-bridge",
|
|
69
|
+
"captured-real-fixture",
|
|
70
|
+
"skipped"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"command_line": { "type": "array", "items": { "type": "string" } },
|
|
74
|
+
"duration_ms": { "type": "integer", "minimum": 0 },
|
|
75
|
+
"stdout_tail": { "type": "string" },
|
|
76
|
+
"stderr_tail": { "type": "string" },
|
|
77
|
+
"artifact_paths": { "type": "array", "items": { "type": "string" } },
|
|
78
|
+
"evidence": { "type": "object" },
|
|
79
|
+
"blockers": { "type": "array", "items": { "type": "string" } }
|
|
80
|
+
},
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"additionalProperties": false
|
|
85
|
+
}
|