sneakoscope 3.0.3 → 3.1.0
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/cli/command-registry.js +1 -0
- package/dist/cli/context7-command.js +29 -5
- package/dist/cli/install-helpers.js +15 -7
- package/dist/core/agents/runtime-proof-summary.js +4 -0
- 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/commands/goal-command.js +19 -1
- package/dist/core/commands/loop-command.js +135 -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/init.js +6 -1
- package/dist/core/loops/goal-to-loop-compat.js +23 -0
- package/dist/core/loops/loop-artifacts.js +41 -0
- package/dist/core/loops/loop-decomposer.js +56 -0
- package/dist/core/loops/loop-finalizer.js +28 -0
- package/dist/core/loops/loop-gate-ladder.js +16 -0
- package/dist/core/loops/loop-gate-runner.js +29 -0
- package/dist/core/loops/loop-gate-selector.js +52 -0
- package/dist/core/loops/loop-iteration-runner.js +2 -0
- package/dist/core/loops/loop-lease.js +76 -0
- package/dist/core/loops/loop-observability.js +19 -0
- package/dist/core/loops/loop-owner-inference.js +57 -0
- package/dist/core/loops/loop-owner-ledger.js +2 -0
- package/dist/core/loops/loop-planner.js +139 -0
- package/dist/core/loops/loop-proof-summary.js +10 -0
- package/dist/core/loops/loop-proof.js +2 -0
- package/dist/core/loops/loop-risk-classifier.js +42 -0
- package/dist/core/loops/loop-runtime.js +159 -0
- package/dist/core/loops/loop-scheduler.js +60 -0
- package/dist/core/loops/loop-schema.js +63 -0
- package/dist/core/loops/loop-state.js +61 -0
- package/dist/core/naruto/naruto-loop-mesh.js +33 -0
- package/dist/core/naruto/naruto-loop-worker-router.js +38 -0
- package/dist/core/pipeline-internals/runtime-core.js +82 -2
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-slot-column-anchor.js +5 -2
- package/dist/core/zellij/zellij-slot-pane-renderer.js +2 -0
- package/dist/scripts/github-release-body-helper.js +3 -1
- package/dist/scripts/loop-directive-check-lib.js +165 -0
- package/package.json +47 -3
- package/schemas/codex/codex-0139-real-probe-result.schema.json +85 -0
- package/schemas/loops/loop-node.schema.json +21 -0
- package/schemas/loops/loop-plan.schema.json +21 -0
- package/schemas/loops/loop-proof.schema.json +20 -0
- package/schemas/loops/loop-state.schema.json +19 -0
|
@@ -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
|
|
@@ -4,6 +4,8 @@ import { initProject } from '../init.js';
|
|
|
4
4
|
import { createMission, loadMission, setCurrent, stateFile } from '../mission.js';
|
|
5
5
|
import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, writeGoalWorkflow } from '../goal-workflow.js';
|
|
6
6
|
import { flag, promptOf, resolveMissionId } from './command-utils.js';
|
|
7
|
+
import { compileGoalToLoopPlan } from '../loops/goal-to-loop-compat.js';
|
|
8
|
+
import { runLoopPlan } from '../loops/loop-runtime.js';
|
|
7
9
|
export async function goalCommand(sub, args = []) {
|
|
8
10
|
const known = new Set(['create', 'pause', 'resume', 'clear', 'status', 'help', '--help', '-h']);
|
|
9
11
|
const action = known.has(sub) ? sub : 'create';
|
|
@@ -31,11 +33,27 @@ async function goalCreate(args) {
|
|
|
31
33
|
const prompt = promptOf(args);
|
|
32
34
|
if (!prompt)
|
|
33
35
|
throw new Error('Missing goal task prompt.');
|
|
36
|
+
if (flag(args, '--legacy-goal-runtime') || process.env.SKS_LEGACY_GOAL_RUNTIME === '1')
|
|
37
|
+
return legacyGoalCreate(root, prompt, args);
|
|
38
|
+
const { id, dir, mission } = await createMission(root, { mode: 'goal', prompt });
|
|
39
|
+
const workflow = await writeGoalWorkflow(dir, mission, { action: 'create', prompt });
|
|
40
|
+
const plan = await compileGoalToLoopPlan({ root, missionId: id, goalText: prompt, legacyGoalOptions: { native_goal: workflow.native_goal } });
|
|
41
|
+
const result = await runLoopPlan({ root, plan, parallelism: 'balanced' });
|
|
42
|
+
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: result.ok ? 'GOAL_LOOP_COMPLETED' : 'GOAL_LOOP_BLOCKED', questions_allowed: true, implementation_allowed: true, native_goal: workflow.native_goal, stop_gate: 'loop-graph-proof.json' }, { replace: true });
|
|
43
|
+
if (flag(args, '--json'))
|
|
44
|
+
return console.log(JSON.stringify({ schema: 'sks.goal-create.v1', ok: result.ok, mission_id: id, workflow, loop_plan: plan, loop_result: result }, null, 2));
|
|
45
|
+
console.log(`Goal compiled to Loop Graph: ${id}`);
|
|
46
|
+
console.log('Use `sks loop status latest` to inspect.');
|
|
47
|
+
console.log(`Artifact: ${path.relative(root, path.join(dir, GOAL_WORKFLOW_ARTIFACT))}`);
|
|
48
|
+
console.log(`Bridge: ${path.relative(root, path.join(dir, GOAL_BRIDGE_ARTIFACT))}`);
|
|
49
|
+
console.log(`Native Codex control: ${workflow.native_goal.slash_command}`);
|
|
50
|
+
}
|
|
51
|
+
async function legacyGoalCreate(root, prompt, args) {
|
|
34
52
|
const { id, dir, mission } = await createMission(root, { mode: 'goal', prompt });
|
|
35
53
|
const workflow = await writeGoalWorkflow(dir, mission, { action: 'create', prompt });
|
|
36
54
|
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: 'GOAL_READY', questions_allowed: true, implementation_allowed: true, native_goal: workflow.native_goal, stop_gate: 'none' }, { replace: true });
|
|
37
55
|
if (flag(args, '--json'))
|
|
38
|
-
return console.log(JSON.stringify({ schema: 'sks.goal-create.v1', ok: true, mission_id: id, workflow }, null, 2));
|
|
56
|
+
return console.log(JSON.stringify({ schema: 'sks.goal-create.v1', ok: true, mission_id: id, workflow, runtime: 'legacy-goal' }, null, 2));
|
|
39
57
|
console.log(`Goal mission created: ${id}`);
|
|
40
58
|
console.log(`Artifact: ${path.relative(root, path.join(dir, GOAL_WORKFLOW_ARTIFACT))}`);
|
|
41
59
|
console.log(`Bridge: ${path.relative(root, path.join(dir, GOAL_BRIDGE_ARTIFACT))}`);
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { printJson } from '../../cli/output.js';
|
|
3
|
+
import { createMission, findLatestMission, loadMission, setCurrent } from '../mission.js';
|
|
4
|
+
import { readJson, sksRoot, writeJsonAtomic } from '../fsx.js';
|
|
5
|
+
import { loopGraphProofPath, loopPlanPath, loopRoot } from '../loops/loop-artifacts.js';
|
|
6
|
+
import { readLoopGraphProof } from '../loops/loop-observability.js';
|
|
7
|
+
import { planLoopsFromRequest } from '../loops/loop-planner.js';
|
|
8
|
+
import { renderLoopProofSummary } from '../loops/loop-proof-summary.js';
|
|
9
|
+
import { runLoopPlan } from '../loops/loop-runtime.js';
|
|
10
|
+
import { flag, promptOf, readFlagValue } from './command-utils.js';
|
|
11
|
+
export async function loopCommand(subcommand = 'help', args = []) {
|
|
12
|
+
const action = subcommand || 'help';
|
|
13
|
+
if (action === 'plan')
|
|
14
|
+
return loopPlan(args);
|
|
15
|
+
if (action === 'run')
|
|
16
|
+
return loopRun(args);
|
|
17
|
+
if (action === 'status')
|
|
18
|
+
return loopStatus(args);
|
|
19
|
+
if (action === 'proof')
|
|
20
|
+
return loopProof(args);
|
|
21
|
+
if (action === 'kill')
|
|
22
|
+
return loopKill(args);
|
|
23
|
+
if (action === 'resume')
|
|
24
|
+
return loopRun(args);
|
|
25
|
+
if (action === 'graph')
|
|
26
|
+
return loopGraph(args);
|
|
27
|
+
console.log(`SKS Loop
|
|
28
|
+
|
|
29
|
+
Usage:
|
|
30
|
+
sks loop plan "<request>" [--json]
|
|
31
|
+
sks loop run latest [--parallelism safe|balanced|extreme] [--json]
|
|
32
|
+
sks loop status latest [--json]
|
|
33
|
+
sks loop proof latest [--json]
|
|
34
|
+
sks loop kill <loop-id|all>
|
|
35
|
+
sks loop resume latest
|
|
36
|
+
sks loop graph latest
|
|
37
|
+
`);
|
|
38
|
+
}
|
|
39
|
+
async function loopPlan(args) {
|
|
40
|
+
const root = await sksRoot();
|
|
41
|
+
const request = promptOf(args);
|
|
42
|
+
if (!request)
|
|
43
|
+
throw new Error('Usage: sks loop plan "<request>" [--json]');
|
|
44
|
+
const { id } = await createMission(root, { mode: 'loop', prompt: request });
|
|
45
|
+
const plan = await planLoopsFromRequest({ root, missionId: id, request, sourceCommand: 'loop' });
|
|
46
|
+
await setCurrent(root, { mission_id: id, mode: 'LOOP', route: 'Loop', route_command: '$Loop', phase: 'LOOP_PLANNED', stop_gate: 'loop-graph-proof.json' }, { replace: true });
|
|
47
|
+
if (flag(args, '--json'))
|
|
48
|
+
return printJson({ schema: 'sks.loop-plan-command.v1', ok: plan.blockers.length === 0, mission_id: id, plan });
|
|
49
|
+
console.log(`Loop plan: ${id}`);
|
|
50
|
+
console.log('Loops:');
|
|
51
|
+
for (const node of plan.graph.nodes) {
|
|
52
|
+
const owner = [...node.owner_scope.files, ...node.owner_scope.directories][0] || 'integration';
|
|
53
|
+
console.log(` ${node.loop_id.padEnd(18)} ${node.level.padEnd(12)} owner ${owner.padEnd(28)} gates ${[...node.gates.triage, ...node.gates.local, ...node.gates.checker, ...node.gates.integration, ...node.gates.final].length}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function loopRun(args) {
|
|
57
|
+
const root = await sksRoot();
|
|
58
|
+
const missionId = await resolveLoopMission(root, args[0]);
|
|
59
|
+
if (!missionId)
|
|
60
|
+
throw new Error('No loop plan exists. Run: sks loop plan "<request>"');
|
|
61
|
+
const plan = await readJson(loopPlanPath(root, missionId));
|
|
62
|
+
if (plan.blockers.length) {
|
|
63
|
+
console.log(`Loop plan blocked: ${plan.blockers.join(', ')}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const parallelism = normalizeParallelism(readFlagValue(args, '--parallelism', 'balanced'));
|
|
67
|
+
const result = await runLoopPlan({ root, plan, parallelism });
|
|
68
|
+
await setCurrent(root, { mission_id: missionId, mode: 'LOOP', route: 'Loop', route_command: '$Loop', phase: result.ok ? 'LOOP_COMPLETED' : 'LOOP_BLOCKED', stop_gate: 'loop-graph-proof.json' });
|
|
69
|
+
if (flag(args, '--json'))
|
|
70
|
+
return printJson({ schema: 'sks.loop-run-command.v1', ...result });
|
|
71
|
+
console.log(renderLoopProofSummary(result.graph_proof));
|
|
72
|
+
}
|
|
73
|
+
async function loopStatus(args) {
|
|
74
|
+
const root = await sksRoot();
|
|
75
|
+
const missionId = await resolveLoopMission(root, args[0]);
|
|
76
|
+
if (!missionId)
|
|
77
|
+
throw new Error('Usage: sks loop status <mission-id|latest>');
|
|
78
|
+
const plan = await readJson(loopPlanPath(root, missionId), null);
|
|
79
|
+
const proof = await readLoopGraphProof(root, missionId);
|
|
80
|
+
const states = await Promise.all((plan?.graph.nodes || []).map((node) => readJson(path.join(loopRoot(root, missionId), node.loop_id, 'loop-state.json'), null)));
|
|
81
|
+
const result = { schema: 'sks.loop-status-command.v1', mission_id: missionId, plan_ok: Boolean(plan && plan.blockers.length === 0), graph: proof, states };
|
|
82
|
+
if (flag(args, '--json'))
|
|
83
|
+
return printJson(result);
|
|
84
|
+
console.log(`Loop status: ${missionId}`);
|
|
85
|
+
for (const state of states.filter(Boolean)) {
|
|
86
|
+
console.log(` ${String(state.loop_id).padEnd(18)} ${String(state.status).padEnd(10)} iter ${state.iteration} owner ${(Array.isArray(state.acting_on?.files) ? state.acting_on.files.join(', ') : '-')}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function loopProof(args) {
|
|
90
|
+
const root = await sksRoot();
|
|
91
|
+
const missionId = await resolveLoopMission(root, args[0]);
|
|
92
|
+
if (!missionId)
|
|
93
|
+
throw new Error('Usage: sks loop proof <mission-id|latest>');
|
|
94
|
+
const proof = await readLoopGraphProof(root, missionId);
|
|
95
|
+
if (!proof)
|
|
96
|
+
throw new Error(`Loop graph proof missing: ${missionId}`);
|
|
97
|
+
if (flag(args, '--json'))
|
|
98
|
+
return printJson(proof);
|
|
99
|
+
console.log(renderLoopProofSummary(proof));
|
|
100
|
+
}
|
|
101
|
+
async function loopGraph(args) {
|
|
102
|
+
const root = await sksRoot();
|
|
103
|
+
const missionId = await resolveLoopMission(root, args[0]);
|
|
104
|
+
if (!missionId)
|
|
105
|
+
throw new Error('Usage: sks loop graph <mission-id|latest>');
|
|
106
|
+
const plan = await readJson(loopPlanPath(root, missionId));
|
|
107
|
+
printJson({ schema: 'sks.loop-graph-command.v1', mission_id: missionId, graph: plan.graph });
|
|
108
|
+
}
|
|
109
|
+
async function loopKill(args) {
|
|
110
|
+
const root = await sksRoot();
|
|
111
|
+
const missionId = await findLatestMission(root);
|
|
112
|
+
const target = args[0];
|
|
113
|
+
if (!missionId || !target)
|
|
114
|
+
throw new Error('Usage: sks loop kill <loop-id|all>');
|
|
115
|
+
await writeJsonAtomic(path.join(loopRoot(root, missionId), 'kill-request.json'), {
|
|
116
|
+
schema: 'sks.loop-kill-request.v1',
|
|
117
|
+
mission_id: missionId,
|
|
118
|
+
target,
|
|
119
|
+
requested_at: new Date().toISOString()
|
|
120
|
+
});
|
|
121
|
+
console.log(`Loop kill requested: ${target}`);
|
|
122
|
+
}
|
|
123
|
+
async function resolveLoopMission(root, arg) {
|
|
124
|
+
if (arg && arg !== 'latest')
|
|
125
|
+
return arg;
|
|
126
|
+
const latest = await findLatestMission(root);
|
|
127
|
+
if (!latest)
|
|
128
|
+
return null;
|
|
129
|
+
const loaded = await loadMission(root, latest).catch(() => null);
|
|
130
|
+
return loaded?.mission?.mode === 'loop' || await readJson(loopPlanPath(root, latest), null) ? latest : null;
|
|
131
|
+
}
|
|
132
|
+
function normalizeParallelism(value) {
|
|
133
|
+
return value === 'safe' || value === 'extreme' ? value : 'balanced';
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=loop-command.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,
|