sneakoscope 3.0.1 → 3.0.3
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/agents/agent-message-bus.js +89 -2
- package/dist/core/agents/runtime-proof-summary.js +46 -2
- package/dist/core/codex/codex-cli-syntax-builder.js +4 -1
- package/dist/core/codex-control/codex-0139-capability.js +68 -12
- package/dist/core/codex-control/codex-multi-agent-event-normalizer.js +15 -0
- package/dist/core/codex-control/codex-tool-schema-fixtures.js +57 -0
- package/dist/core/commands/naruto-command.js +9 -4
- package/dist/core/fsx.js +1 -1
- package/dist/core/mcp/mcp-0-134-policy.js +3 -0
- package/dist/core/pipeline-internals/runtime-core.js +6 -1
- package/dist/core/release/release-cache-key.js +128 -0
- package/dist/core/release/release-gate-cache-v2.js +6 -7
- package/dist/core/release/release-proof-truth.js +63 -0
- package/dist/core/safety/side-effect-runtime-report.js +19 -4
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-capability.js +41 -0
- package/dist/core/zellij/zellij-command.js +14 -2
- package/dist/core/zellij/zellij-fake-adapter.js +163 -0
- package/dist/core/zellij/zellij-update.js +28 -3
- package/dist/core/zellij/zellij-worker-pane-manager.js +116 -5
- package/dist/core/zellij/zellij-worker-pane-summary.js +65 -0
- package/dist/scripts/github-release-body-helper.js +63 -0
- package/dist/scripts/release-speed-summary.js +11 -0
- package/package.json +33 -2
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.3** 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 optional real probes for code-mode web search markers, preserved `oneOf`/`allOf` tool schemas, plugin marketplace `source`, the `-P` profile alias, the multi-agent v2 `interrupt_agent` rename, 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).
|
|
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.3"),
|
|
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.3",
|
|
5
|
+
"source_digest": "4630d65c17e3297a1a79b5b96be0b849ee4ada4ac1ff010a4e024b06d8b7b750",
|
|
6
|
+
"source_file_count": 2304,
|
|
7
|
+
"built_at_source_time": 1781142991546
|
|
8
8
|
}
|
package/dist/bin/sks.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { appendJsonl, nowIso } from '../fsx.js';
|
|
3
4
|
import { appendAgentLedgerEvent } from './agent-central-ledger.js';
|
|
4
5
|
export async function appendAgentMessage(root, message) {
|
|
6
|
+
const eventType = normalizeAgentMessageEventType(message.event_type || message.type);
|
|
5
7
|
const entry = {
|
|
6
8
|
schema: 'sks.agent-message.v1',
|
|
9
|
+
ts: nowIso(),
|
|
10
|
+
mission_id: message.mission_id || inferMissionIdFromAgentRoot(root),
|
|
11
|
+
worker_id: message.worker_id || message.from,
|
|
12
|
+
slot_id: message.slot_id ?? message.from ?? null,
|
|
13
|
+
session_id: message.session_id || null,
|
|
14
|
+
level: message.level || (eventType === 'worker_failed' || eventType === 'blocker' ? 'error' : 'info'),
|
|
15
|
+
event_type: eventType,
|
|
16
|
+
message: message.body,
|
|
17
|
+
artifact_paths: message.artifact_paths || [],
|
|
7
18
|
from: message.from,
|
|
8
|
-
session_id: message.session_id,
|
|
9
19
|
to: message.to || 'orchestrator',
|
|
10
20
|
type: message.type || 'note',
|
|
11
21
|
body: message.body
|
|
@@ -14,4 +24,81 @@ export async function appendAgentMessage(root, message) {
|
|
|
14
24
|
await appendAgentLedgerEvent(root, { agent_id: message.from, session_id: message.session_id, event_type: 'message_appended', payload: { to: entry.to, type: entry.type } });
|
|
15
25
|
return entry;
|
|
16
26
|
}
|
|
27
|
+
export async function readAgentMessageBus(root, missionId, opts = {}) {
|
|
28
|
+
const file = agentMessageBusPath(root, missionId);
|
|
29
|
+
let text = '';
|
|
30
|
+
try {
|
|
31
|
+
text = await fs.readFile(file, 'utf8');
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const levels = new Set((opts.levels || []).map((level) => String(level)));
|
|
37
|
+
const rows = text.split(/\n+/)
|
|
38
|
+
.map((line) => line.trim())
|
|
39
|
+
.filter(Boolean)
|
|
40
|
+
.map((line) => {
|
|
41
|
+
try {
|
|
42
|
+
return normalizeAgentMessageBusEntry(JSON.parse(line), missionId);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.filter((row) => Boolean(row))
|
|
49
|
+
.filter((row) => !levels.size || levels.has(row.level));
|
|
50
|
+
const max = Math.max(0, Math.floor(Number(opts.max || rows.length)));
|
|
51
|
+
return max > 0 ? rows.slice(-max) : rows;
|
|
52
|
+
}
|
|
53
|
+
export function agentMessageBusPath(root, missionId) {
|
|
54
|
+
const resolved = path.resolve(root);
|
|
55
|
+
if (path.basename(resolved) === 'agents')
|
|
56
|
+
return path.join(resolved, 'agent-messages.jsonl');
|
|
57
|
+
if (path.basename(resolved) === missionId)
|
|
58
|
+
return path.join(resolved, 'agents', 'agent-messages.jsonl');
|
|
59
|
+
return path.join(resolved, '.sneakoscope', 'missions', missionId, 'agents', 'agent-messages.jsonl');
|
|
60
|
+
}
|
|
61
|
+
function normalizeAgentMessageBusEntry(value, missionId) {
|
|
62
|
+
const eventType = normalizeAgentMessageEventType(value.event_type || value.type);
|
|
63
|
+
return {
|
|
64
|
+
schema: 'sks.agent-message.v1',
|
|
65
|
+
ts: String(value.ts || value.generated_at || nowIso()),
|
|
66
|
+
mission_id: String(value.mission_id || missionId),
|
|
67
|
+
worker_id: String(value.worker_id || value.from || value.slot_id || 'worker'),
|
|
68
|
+
slot_id: value.slot_id == null ? value.from == null ? null : String(value.from) : String(value.slot_id),
|
|
69
|
+
session_id: value.session_id == null ? null : String(value.session_id),
|
|
70
|
+
level: normalizeAgentMessageLevel(value.level, eventType),
|
|
71
|
+
event_type: eventType,
|
|
72
|
+
message: String(value.message || value.body || ''),
|
|
73
|
+
artifact_paths: Array.isArray(value.artifact_paths) ? value.artifact_paths.map(String) : [],
|
|
74
|
+
from: value.from == null ? undefined : String(value.from),
|
|
75
|
+
to: value.to == null ? undefined : String(value.to),
|
|
76
|
+
type: value.type == null ? undefined : String(value.type),
|
|
77
|
+
body: value.body == null ? undefined : String(value.body)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function normalizeAgentMessageEventType(value) {
|
|
81
|
+
const text = String(value || '').toLowerCase();
|
|
82
|
+
if (text === 'worker_completed' || text === 'completed' || text === 'done')
|
|
83
|
+
return 'worker_completed';
|
|
84
|
+
if (text === 'worker_failed' || text === 'failed' || text === 'error')
|
|
85
|
+
return 'worker_failed';
|
|
86
|
+
if (text === 'blocker')
|
|
87
|
+
return 'blocker';
|
|
88
|
+
if (text === 'handoff')
|
|
89
|
+
return 'handoff';
|
|
90
|
+
return 'status';
|
|
91
|
+
}
|
|
92
|
+
function normalizeAgentMessageLevel(value, eventType) {
|
|
93
|
+
const text = String(value || '').toLowerCase();
|
|
94
|
+
if (text === 'info' || text === 'warning' || text === 'error')
|
|
95
|
+
return text;
|
|
96
|
+
if (eventType === 'worker_failed' || eventType === 'blocker')
|
|
97
|
+
return 'error';
|
|
98
|
+
return 'info';
|
|
99
|
+
}
|
|
100
|
+
function inferMissionIdFromAgentRoot(root) {
|
|
101
|
+
const resolved = path.resolve(root);
|
|
102
|
+
return path.basename(resolved) === 'agents' ? path.basename(path.dirname(resolved)) : 'unknown';
|
|
103
|
+
}
|
|
17
104
|
//# sourceMappingURL=agent-message-bus.js.map
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { findLatestMission, missionDir } from '../mission.js';
|
|
3
3
|
import { readJson, writeJsonAtomic } from '../fsx.js';
|
|
4
|
+
import { readAgentMessageBus } from './agent-message-bus.js';
|
|
5
|
+
import { buildZellijWorkerPaneSummary } from '../zellij/zellij-worker-pane-summary.js';
|
|
4
6
|
export const RUNTIME_PROOF_SUMMARY_SCHEMA = 'sks.runtime-proof-summary.v1';
|
|
5
|
-
export async function buildRuntimeProofSummary(root, missionIdInput = 'latest') {
|
|
7
|
+
export async function buildRuntimeProofSummary(root, missionIdInput = 'latest', opts = {}) {
|
|
6
8
|
const missionId = missionIdInput === 'latest' ? await findLatestMission(root) : missionIdInput;
|
|
7
9
|
if (!missionId)
|
|
8
10
|
throw new Error('runtime_proof_summary_mission_missing');
|
|
@@ -13,6 +15,11 @@ export async function buildRuntimeProofSummary(root, missionIdInput = 'latest')
|
|
|
13
15
|
const swarm = await readJson(path.join(agentsDir, 'agent-native-cli-session-swarm.json'), null);
|
|
14
16
|
const telemetry = await readJson(path.join(dir, 'zellij', 'slot-telemetry.snapshot.json'), null);
|
|
15
17
|
const governor = await readJson(path.join(agentsDir, 'naruto-concurrency-governor.json'), null);
|
|
18
|
+
const messagesAll = await readAgentMessageBus(root, missionId, { max: 500 });
|
|
19
|
+
const recentMessages = await readAgentMessageBus(root, missionId, { max: opts.maxMessages || 8 });
|
|
20
|
+
const zellijSummary = await buildZellijWorkerPaneSummary(root, missionId).catch(() => null);
|
|
21
|
+
const failedMessages = messagesAll.filter((row) => row.event_type === 'worker_failed');
|
|
22
|
+
const errorMessages = messagesAll.filter((row) => row.level === 'error');
|
|
16
23
|
const telemetryAgeMs = telemetry?.updated_at ? Math.max(0, Date.now() - Date.parse(telemetry.updated_at)) : Number.MAX_SAFE_INTEGER;
|
|
17
24
|
const visiblePanes = Number(parallel?.visible_panes ?? swarm?.zellij_pane_worker_sessions ?? telemetryVisiblePaneCount(telemetry) ?? 0);
|
|
18
25
|
const targetActive = Number(scheduler?.target_active_slots ?? parallel?.target_active_slots ?? swarm?.target_active_slots ?? governor?.target_active_slots ?? 0);
|
|
@@ -21,7 +28,9 @@ export async function buildRuntimeProofSummary(root, missionIdInput = 'latest')
|
|
|
21
28
|
...(!parallel ? ['parallel_runtime_proof_missing'] : []),
|
|
22
29
|
...(!scheduler ? ['agent_scheduler_state_missing'] : []),
|
|
23
30
|
...(parallel?.passed === false ? parallel.blockers || ['parallel_runtime_proof_failed'] : []),
|
|
24
|
-
...(
|
|
31
|
+
...(errorMessages.length ? ['agent_message_bus_error_blockers'] : []),
|
|
32
|
+
...(telemetryAgeMs > 3000 ? ['zellij_telemetry_stale'] : []),
|
|
33
|
+
...(zellijSummary?.blockers || [])
|
|
25
34
|
].map(String);
|
|
26
35
|
const summary = {
|
|
27
36
|
schema: RUNTIME_PROOF_SUMMARY_SCHEMA,
|
|
@@ -48,6 +57,22 @@ export async function buildRuntimeProofSummary(root, missionIdInput = 'latest')
|
|
|
48
57
|
largest_batch_size: Number(scheduler?.largest_batch_size || 0),
|
|
49
58
|
utilization: Number(scheduler?.scheduler_utilization || 0)
|
|
50
59
|
},
|
|
60
|
+
messages: {
|
|
61
|
+
recent: recentMessages,
|
|
62
|
+
completed_count: messagesAll.filter((row) => row.event_type === 'worker_completed').length,
|
|
63
|
+
failed_count: failedMessages.length,
|
|
64
|
+
warning_count: messagesAll.filter((row) => row.level === 'warning').length,
|
|
65
|
+
error_count: errorMessages.length
|
|
66
|
+
},
|
|
67
|
+
zellij: {
|
|
68
|
+
stacked_requested_count: Number(zellijSummary?.stacked_requested_count || 0),
|
|
69
|
+
stacked_applied_count: Number(zellijSummary?.stacked_applied_count || 0),
|
|
70
|
+
stacked_fallback_count: Number(zellijSummary?.stacked_fallback_count || 0),
|
|
71
|
+
fallback_modes: zellijSummary?.fallback_modes || {},
|
|
72
|
+
pane_lock_wait_p95_ms: Number(zellijSummary?.pane_lock_wait_p95_ms || 0),
|
|
73
|
+
pane_lock_held_p95_ms: Number(zellijSummary?.pane_lock_held_p95_ms || 0),
|
|
74
|
+
duplicate_slot_anchor_count: Number(zellijSummary?.duplicate_slot_anchor_count || 0)
|
|
75
|
+
},
|
|
51
76
|
blockers
|
|
52
77
|
};
|
|
53
78
|
await writeJsonAtomic(path.join(agentsDir, 'runtime-proof-summary.json'), summary);
|
|
@@ -62,9 +87,28 @@ export function renderRuntimeProofSummary(summary) {
|
|
|
62
87
|
`Visible/headless: ${summary.ui.visible_panes} / ${summary.ui.headless_workers}`,
|
|
63
88
|
`Telemetry: ${summary.ui.stale ? `stale ${(summary.ui.telemetry_age_ms / 1000).toFixed(1)}s` : `fresh ${(summary.ui.telemetry_age_ms / 1000).toFixed(1)}s`}`,
|
|
64
89
|
`Model calls max: ${summary.model_calls.max_observed}`,
|
|
90
|
+
`Zellij stacked panes: ${summary.zellij.stacked_applied_count}/${summary.zellij.stacked_requested_count} applied`,
|
|
91
|
+
`Stack fallback: ${summary.zellij.stacked_fallback_count}`,
|
|
92
|
+
`Pane lock wait p95: ${summary.zellij.pane_lock_wait_p95_ms}ms`,
|
|
93
|
+
`SLOTS anchors: ${summary.zellij.duplicate_slot_anchor_count}`,
|
|
94
|
+
...(summary.messages.recent.length ? [
|
|
95
|
+
'Recent worker messages:',
|
|
96
|
+
...summary.messages.recent.map((row) => ` ${messageStatusLabel(row)} ${row.slot_id || row.worker_id}: ${row.message}`)
|
|
97
|
+
] : []),
|
|
65
98
|
...(summary.blockers.length ? [`Blockers: ${summary.blockers.join(', ')}`] : [])
|
|
66
99
|
].join('\n');
|
|
67
100
|
}
|
|
101
|
+
function messageStatusLabel(row) {
|
|
102
|
+
if (row.event_type === 'worker_completed')
|
|
103
|
+
return '[done]';
|
|
104
|
+
if (row.event_type === 'worker_failed')
|
|
105
|
+
return '[fail]';
|
|
106
|
+
if (row.level === 'warning')
|
|
107
|
+
return '[warn]';
|
|
108
|
+
if (row.level === 'error')
|
|
109
|
+
return '[err]';
|
|
110
|
+
return '[info]';
|
|
111
|
+
}
|
|
68
112
|
function telemetryVisiblePaneCount(snapshot) {
|
|
69
113
|
const slots = snapshot?.slots && typeof snapshot.slots === 'object' ? Object.values(snapshot.slots) : [];
|
|
70
114
|
return slots.filter((row) => row?.status && row.status !== 'headless').length;
|
|
@@ -23,7 +23,7 @@ export function buildCodexExecArgs(opts) {
|
|
|
23
23
|
if (opts.skipGitRepoCheck)
|
|
24
24
|
args.push('--skip-git-repo-check');
|
|
25
25
|
if (opts.profile)
|
|
26
|
-
args.push(
|
|
26
|
+
args.push(...buildCodexProfileArgs(opts.profile, opts.profileAlias));
|
|
27
27
|
else if (opts.ignoreUserConfig)
|
|
28
28
|
args.push('--ignore-user-config');
|
|
29
29
|
if (opts.ignoreRules)
|
|
@@ -40,6 +40,9 @@ export function buildCodexExecArgs(opts) {
|
|
|
40
40
|
args.push(opts.prompt);
|
|
41
41
|
return args;
|
|
42
42
|
}
|
|
43
|
+
export function buildCodexProfileArgs(profile, alias = 'long') {
|
|
44
|
+
return alias === 'short' ? ['-P', profile] : ['--profile', profile];
|
|
45
|
+
}
|
|
43
46
|
function normalizeCodexServiceTier(value) {
|
|
44
47
|
const text = String(value || '').toLowerCase();
|
|
45
48
|
if (text === 'fast' || text === 'priority')
|
|
@@ -13,33 +13,52 @@ export async function detectCodex0139Capability(input = {}) {
|
|
|
13
13
|
const parsed = parseCodexVersionText(versionText);
|
|
14
14
|
const atLeast139 = Boolean(parsed && compareSemverLike(parsed, '0.139.0') >= 0);
|
|
15
15
|
const probeMode = process.env.SKS_CODEX_0139_PROBE === '1' ? 'feature-probe' : 'version-only';
|
|
16
|
+
const probeTimeoutMs = Math.max(1, Number(process.env.SKS_CODEX_0139_PROBE_TIMEOUT_MS || 3000) || 3000);
|
|
16
17
|
const featureProbeResults = probeMode === 'feature-probe'
|
|
17
|
-
? await probeCodex0139Features(codexBin, { fake })
|
|
18
|
+
? await probeCodex0139Features(codexBin, { fake, timeoutMs: probeTimeoutMs })
|
|
18
19
|
: {
|
|
19
20
|
marketplace_list_json: 'skipped',
|
|
20
|
-
sandbox_profile_alias: 'skipped'
|
|
21
|
+
sandbox_profile_alias: 'skipped',
|
|
22
|
+
interrupt_agent_event_mapping: 'skipped',
|
|
23
|
+
rich_tool_schema_preservation: 'skipped',
|
|
24
|
+
doctor_env_redaction: 'skipped',
|
|
25
|
+
code_mode_web_search: 'skipped'
|
|
21
26
|
};
|
|
22
27
|
const marketplaceOk = atLeast139 && (probeMode === 'version-only' || featureProbeResults.marketplace_list_json !== 'failed');
|
|
23
28
|
const profileAliasOk = atLeast139 && (probeMode === 'version-only' || featureProbeResults.sandbox_profile_alias !== 'failed');
|
|
29
|
+
const interruptAgentOk = atLeast139 && (probeMode === 'version-only' || featureProbeResults.interrupt_agent_event_mapping !== 'failed');
|
|
30
|
+
const richSchemaOk = atLeast139 && (probeMode === 'version-only' || featureProbeResults.rich_tool_schema_preservation !== 'failed');
|
|
31
|
+
const doctorEnvOk = atLeast139 && (probeMode === 'version-only' || featureProbeResults.doctor_env_redaction !== 'failed');
|
|
32
|
+
const codeSearchOk = atLeast139 && (probeMode === 'version-only' || featureProbeResults.code_mode_web_search !== 'failed');
|
|
33
|
+
const probeErrorSummary = Object.entries(featureProbeResults)
|
|
34
|
+
.filter(([, status]) => status === 'failed')
|
|
35
|
+
.map(([name]) => `${name}:failed`);
|
|
24
36
|
const blockers = [
|
|
25
37
|
...(!codexBin ? ['codex_cli_missing'] : []),
|
|
26
38
|
...(atLeast139 ? [] : ['codex_0_139_required_for_search_schema_marketplace_features']),
|
|
27
|
-
...(probeMode === 'feature-probe' && featureProbeResults.marketplace_list_json === 'failed' ? ['codex_marketplace_list_json_probe_failed'] : [])
|
|
39
|
+
...(probeMode === 'feature-probe' && featureProbeResults.marketplace_list_json === 'failed' ? ['codex_marketplace_list_json_probe_failed'] : []),
|
|
40
|
+
...(probeMode === 'feature-probe' && featureProbeResults.sandbox_profile_alias === 'failed' ? ['codex_sandbox_profile_alias_probe_failed'] : []),
|
|
41
|
+
...(probeMode === 'feature-probe' && featureProbeResults.interrupt_agent_event_mapping === 'failed' ? ['codex_interrupt_agent_probe_failed'] : []),
|
|
42
|
+
...(probeMode === 'feature-probe' && featureProbeResults.rich_tool_schema_preservation === 'failed' ? ['codex_rich_tool_schema_probe_failed'] : []),
|
|
43
|
+
...(probeMode === 'feature-probe' && featureProbeResults.doctor_env_redaction === 'failed' ? ['codex_doctor_env_redaction_probe_failed'] : []),
|
|
44
|
+
...(probeMode === 'feature-probe' && featureProbeResults.code_mode_web_search === 'failed' ? ['codex_code_mode_web_search_probe_failed'] : [])
|
|
28
45
|
];
|
|
29
46
|
return {
|
|
30
47
|
schema: 'sks.codex-0139-capability.v1',
|
|
31
48
|
ok: atLeast139 && blockers.length === 0,
|
|
32
49
|
probe_mode: probeMode,
|
|
50
|
+
probe_timeout_ms: probeTimeoutMs,
|
|
51
|
+
probe_error_summary: probeErrorSummary,
|
|
33
52
|
codex_bin: codexBin || null,
|
|
34
53
|
version_text: versionText || null,
|
|
35
54
|
parsed_version: parsed,
|
|
36
|
-
supports_code_mode_web_search:
|
|
37
|
-
supports_rich_tool_schemas:
|
|
38
|
-
supports_doctor_env_details:
|
|
55
|
+
supports_code_mode_web_search: codeSearchOk,
|
|
56
|
+
supports_rich_tool_schemas: richSchemaOk,
|
|
57
|
+
supports_doctor_env_details: doctorEnvOk,
|
|
39
58
|
supports_marketplace_source_field: marketplaceOk,
|
|
40
59
|
supports_plugin_catalog_cache: atLeast139,
|
|
41
60
|
supports_sandbox_profile_alias: profileAliasOk,
|
|
42
|
-
supports_interrupt_agent_rename:
|
|
61
|
+
supports_interrupt_agent_rename: interruptAgentOk,
|
|
43
62
|
feature_probe_results: featureProbeResults,
|
|
44
63
|
blockers
|
|
45
64
|
};
|
|
@@ -71,12 +90,23 @@ async function probeCodex0139Features(codexBin, opts = {}) {
|
|
|
71
90
|
if (opts.fake) {
|
|
72
91
|
return {
|
|
73
92
|
marketplace_list_json: process.env.SKS_CODEX_0139_FAKE_MARKETPLACE_FAIL === '1' ? 'failed' : 'passed',
|
|
74
|
-
sandbox_profile_alias: 'passed'
|
|
93
|
+
sandbox_profile_alias: process.env.SKS_CODEX_0139_FAKE_PROFILE_ALIAS_FAIL === '1' ? 'failed' : 'passed',
|
|
94
|
+
interrupt_agent_event_mapping: process.env.SKS_CODEX_0139_FAKE_INTERRUPT_FAIL === '1' ? 'failed' : 'passed',
|
|
95
|
+
rich_tool_schema_preservation: process.env.SKS_CODEX_0139_FAKE_RICH_SCHEMA_FAIL === '1' ? 'failed' : 'passed',
|
|
96
|
+
doctor_env_redaction: process.env.SKS_CODEX_0139_FAKE_DOCTOR_ENV_FAIL === '1' ? 'failed' : 'passed',
|
|
97
|
+
code_mode_web_search: process.env.SKS_CODEX_0139_FAKE_WEB_SEARCH_FAIL === '1' ? 'failed' : 'passed'
|
|
75
98
|
};
|
|
76
99
|
}
|
|
77
|
-
const timeoutMs = Math.max(1, Number(process.env.SKS_CODEX_0139_PROBE_TIMEOUT_MS || 3000) || 3000);
|
|
100
|
+
const timeoutMs = Math.max(1, Number(opts.timeoutMs || process.env.SKS_CODEX_0139_PROBE_TIMEOUT_MS || 3000) || 3000);
|
|
78
101
|
if (!codexBin) {
|
|
79
|
-
return {
|
|
102
|
+
return {
|
|
103
|
+
marketplace_list_json: 'failed',
|
|
104
|
+
sandbox_profile_alias: 'failed',
|
|
105
|
+
interrupt_agent_event_mapping: 'skipped',
|
|
106
|
+
rich_tool_schema_preservation: 'skipped',
|
|
107
|
+
doctor_env_redaction: 'skipped',
|
|
108
|
+
code_mode_web_search: 'skipped'
|
|
109
|
+
};
|
|
80
110
|
}
|
|
81
111
|
const marketplace = await runProcess(codexBin, ['plugin', 'marketplace', 'list', '--json'], { timeoutMs, maxOutputBytes: 256 * 1024 }).catch(() => ({ code: 1, stdout: '' }));
|
|
82
112
|
const marketplaceListJson = marketplace.code === 0 && marketplaceSourcesPresent(marketplace.stdout) ? 'passed' : 'failed';
|
|
@@ -84,7 +114,11 @@ async function probeCodex0139Features(codexBin, opts = {}) {
|
|
|
84
114
|
const aliasOk = help.code === 0 && /(^|\s)-P[,\s]/m.test(String(help.stdout || ''));
|
|
85
115
|
return {
|
|
86
116
|
marketplace_list_json: marketplaceListJson,
|
|
87
|
-
sandbox_profile_alias: aliasOk ? 'passed' : 'failed'
|
|
117
|
+
sandbox_profile_alias: aliasOk ? 'passed' : 'failed',
|
|
118
|
+
interrupt_agent_event_mapping: 'skipped',
|
|
119
|
+
rich_tool_schema_preservation: 'skipped',
|
|
120
|
+
doctor_env_redaction: 'skipped',
|
|
121
|
+
code_mode_web_search: 'skipped'
|
|
88
122
|
};
|
|
89
123
|
}
|
|
90
124
|
export function marketplaceSourcesPresent(stdout) {
|
|
@@ -93,10 +127,32 @@ export function marketplaceSourcesPresent(stdout) {
|
|
|
93
127
|
const rows = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.marketplaces) ? parsed.marketplaces : Array.isArray(parsed?.items) ? parsed.items : [];
|
|
94
128
|
if (!rows.length)
|
|
95
129
|
return true;
|
|
96
|
-
return rows.
|
|
130
|
+
return rows.every((row) => typeof row?.source === 'string' && row.source.length > 0);
|
|
97
131
|
}
|
|
98
132
|
catch {
|
|
99
133
|
return false;
|
|
100
134
|
}
|
|
101
135
|
}
|
|
136
|
+
export function codexHelpSupportsSandboxProfileAlias(stdout) {
|
|
137
|
+
return /(^|\s)-P[,\s]+--profile\b|--profile[,\s]+-P\b|(^|\s)-P\b/m.test(String(stdout || ''));
|
|
138
|
+
}
|
|
139
|
+
export function redactCodexDoctorEnvDetails(value) {
|
|
140
|
+
if (Array.isArray(value))
|
|
141
|
+
return value.map((item) => redactCodexDoctorEnvDetails(item));
|
|
142
|
+
if (!value || typeof value !== 'object') {
|
|
143
|
+
return secretLikeValue(value) ? '<redacted>' : value;
|
|
144
|
+
}
|
|
145
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => {
|
|
146
|
+
if (secretLikeKey(key) || secretLikeValue(entry))
|
|
147
|
+
return [key, '<redacted>'];
|
|
148
|
+
return [key, redactCodexDoctorEnvDetails(entry)];
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
function secretLikeKey(key) {
|
|
152
|
+
return /(?:api[_-]?key|auth[_-]?token|secret|password|credential|bearer|session[_-]?token)/i.test(key);
|
|
153
|
+
}
|
|
154
|
+
function secretLikeValue(value) {
|
|
155
|
+
const text = typeof value === 'string' ? value : '';
|
|
156
|
+
return /(?:sk-[A-Za-z0-9_-]{6,}|Bearer\s+[A-Za-z0-9._-]{8,}|[A-Za-z0-9._-]{12,}\.[A-Za-z0-9._-]{12,}\.[A-Za-z0-9._-]{12,})/.test(text);
|
|
157
|
+
}
|
|
102
158
|
//# sourceMappingURL=codex-0139-capability.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function normalizeCodexMultiAgentEventName(name) {
|
|
2
|
+
const sourceName = String(name || '');
|
|
3
|
+
const normalized = sourceName.trim().toLowerCase().replace(/[-.\s]+/g, '_');
|
|
4
|
+
if (normalized === 'start_agent' || normalized === 'spawn_agent' || normalized === 'subagent_start') {
|
|
5
|
+
return { canonical: 'start_agent', stage: 'start', source_name: sourceName };
|
|
6
|
+
}
|
|
7
|
+
if (normalized === 'interrupt_agent') {
|
|
8
|
+
return { canonical: 'interrupt_agent', stage: 'result', source_name: sourceName };
|
|
9
|
+
}
|
|
10
|
+
if (normalized === 'close_agent' || normalized === 'subagent_stop') {
|
|
11
|
+
return { canonical: 'close_agent', stage: 'result', source_name: sourceName };
|
|
12
|
+
}
|
|
13
|
+
return { canonical: 'unknown', stage: 'unknown', source_name: sourceName };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=codex-multi-agent-event-normalizer.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { compactMcpToolSchema } from '../mcp/mcp-0-134-policy.js';
|
|
2
|
+
export function buildCodex0139RichToolSchemaFixture() {
|
|
3
|
+
return {
|
|
4
|
+
type: 'object',
|
|
5
|
+
description: 'Codex 0.139 rich tool schema preservation fixture',
|
|
6
|
+
oneOf: [
|
|
7
|
+
{ required: ['mode'], properties: { mode: { const: 'guided' } } },
|
|
8
|
+
{ required: ['query'], properties: { query: { type: 'string' } } }
|
|
9
|
+
],
|
|
10
|
+
allOf: [
|
|
11
|
+
{ required: ['kind'] },
|
|
12
|
+
{ properties: { kind: { enum: ['search', 'inspect'] } } }
|
|
13
|
+
],
|
|
14
|
+
required: ['kind', 'payload'],
|
|
15
|
+
properties: {
|
|
16
|
+
kind: { enum: ['search', 'inspect'] },
|
|
17
|
+
payload: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
required: ['target'],
|
|
20
|
+
properties: {
|
|
21
|
+
target: { type: 'string' },
|
|
22
|
+
filters: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
depth: { enum: ['shallow', 'deep'] }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function passCodex0139RichToolSchemaThroughBridge(schema = buildCodex0139RichToolSchemaFixture()) {
|
|
34
|
+
return compactMcpToolSchema(schema, 128).schema;
|
|
35
|
+
}
|
|
36
|
+
export function evaluateCodex0139RichToolSchemaPreservation(schema = buildCodex0139RichToolSchemaFixture()) {
|
|
37
|
+
const bridged = passCodex0139RichToolSchemaThroughBridge(schema);
|
|
38
|
+
const required = Array.isArray(bridged?.required) ? bridged.required : [];
|
|
39
|
+
const result = {
|
|
40
|
+
schema: 'sks.codex-0139-rich-tool-schema-preservation.v1',
|
|
41
|
+
ok: Array.isArray(bridged?.oneOf)
|
|
42
|
+
&& Array.isArray(bridged?.allOf)
|
|
43
|
+
&& Boolean(bridged?.properties?.payload?.properties?.target)
|
|
44
|
+
&& required.includes('kind')
|
|
45
|
+
&& required.includes('payload'),
|
|
46
|
+
top_level_oneOf_preserved: Array.isArray(bridged?.oneOf),
|
|
47
|
+
top_level_allOf_preserved: Array.isArray(bridged?.allOf),
|
|
48
|
+
nested_structure_preserved: Boolean(bridged?.properties?.payload?.properties?.target),
|
|
49
|
+
required_fields_retained: required.includes('kind') && required.includes('payload'),
|
|
50
|
+
bridged_schema: bridged
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
...result,
|
|
54
|
+
blockers: result.ok ? [] : ['codex_rich_tool_schema_preservation_failed']
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=codex-tool-schema-fixtures.js.map
|
|
@@ -741,7 +741,7 @@ async function narutoProof(parsed) {
|
|
|
741
741
|
const id = parsed.missionId && parsed.missionId !== 'latest' ? parsed.missionId : await findLatestMission(root);
|
|
742
742
|
if (!id)
|
|
743
743
|
return emit(parsed, { schema: NARUTO_RESULT_SCHEMA, ok: false, action: 'proof', status: 'missing_mission' }, () => console.log('No Naruto mission found.'));
|
|
744
|
-
const summary = await buildRuntimeProofSummary(root, id);
|
|
744
|
+
const summary = await buildRuntimeProofSummary(root, id, { maxMessages: parsed.messages });
|
|
745
745
|
return emit(parsed, { ...summary, action: 'proof' }, () => {
|
|
746
746
|
console.log(renderRuntimeProofSummary(summary));
|
|
747
747
|
});
|
|
@@ -756,7 +756,7 @@ async function narutoHelp(parsed) {
|
|
|
756
756
|
usage: [
|
|
757
757
|
'sks naruto run "<task>" [--clones N] [--backend codex-sdk|fake|ollama] [--local-model|--no-ollama] [--work-items N] [--real] [--readonly] [--json]',
|
|
758
758
|
'sks naruto status [--mission <id>] [--json]',
|
|
759
|
-
'sks naruto proof latest [--json]'
|
|
759
|
+
'sks naruto proof latest [--messages 20] [--json]'
|
|
760
760
|
],
|
|
761
761
|
defaults: { clones: DEFAULT_NARUTO_CLONES, max_clones: MAX_NARUTO_AGENT_COUNT, backend: 'codex-sdk' }
|
|
762
762
|
};
|
|
@@ -798,9 +798,10 @@ function parseNarutoArgs(args = []) {
|
|
|
798
798
|
const attach = hasFlag(args, '--attach');
|
|
799
799
|
const smoke = hasFlag(args, '--smoke');
|
|
800
800
|
const parallelism = normalizeParallelism(readOption(args, '--parallelism', 'extreme'));
|
|
801
|
-
const
|
|
801
|
+
const messages = normalizeMessages(readOption(args, '--messages', '8'));
|
|
802
|
+
const valueFlags = new Set(['--clones', '--agents', '--work-items', '--concurrency', '--target-active-slots', '--backend', '--write-mode', '--mission', '--mission-id', '--ollama-model', '--local-model-model', '--ollama-base-url', '--local-model-base-url', '--parallelism', '--messages']);
|
|
802
803
|
const prompt = positionalArgs(rest, valueFlags).join(' ').trim() || 'Naruto shadow clone swarm run';
|
|
803
|
-
return { action, prompt, clones, workItems, concurrency, backend, backendExplicit, mock, real, readonly, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, writeMode, json, missionId, noOpenZellij, attach, smoke, parallelism };
|
|
804
|
+
return { action, prompt, clones, workItems, concurrency, backend, backendExplicit, mock, real, readonly, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, writeMode, json, missionId, noOpenZellij, attach, smoke, parallelism, messages };
|
|
804
805
|
}
|
|
805
806
|
function normalizeParallelism(value) {
|
|
806
807
|
const text = String(value || 'extreme').toLowerCase();
|
|
@@ -808,6 +809,10 @@ function normalizeParallelism(value) {
|
|
|
808
809
|
return text;
|
|
809
810
|
return 'extreme';
|
|
810
811
|
}
|
|
812
|
+
function normalizeMessages(value) {
|
|
813
|
+
const parsed = Number(value);
|
|
814
|
+
return Math.max(0, Math.min(100, Math.floor(Number.isFinite(parsed) ? parsed : 8)));
|
|
815
|
+
}
|
|
811
816
|
async function writeNarutoArtifacts(ledgerRoot, artifacts) {
|
|
812
817
|
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-work-graph.json'), artifacts.workGraph);
|
|
813
818
|
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-role-distribution.json'), artifacts.roleDistribution);
|
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.3';
|
|
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() {
|
|
@@ -63,6 +63,9 @@ export function compactMcpToolSchema(schema, maxBytes = 8192) {
|
|
|
63
63
|
type: schema?.type || 'object',
|
|
64
64
|
description: String(schema?.description || '').slice(0, 512),
|
|
65
65
|
properties: Object.fromEntries(Object.entries(schema?.properties || {}).slice(0, 50)),
|
|
66
|
+
...(Array.isArray(schema?.oneOf) ? { oneOf: schema.oneOf } : {}),
|
|
67
|
+
...(Array.isArray(schema?.allOf) ? { allOf: schema.allOf } : {}),
|
|
68
|
+
...(Array.isArray(schema?.required) ? { required: schema.required } : {}),
|
|
66
69
|
...preservedDefs,
|
|
67
70
|
...(refs.length ? { refs } : {})
|
|
68
71
|
},
|
|
@@ -29,6 +29,7 @@ import { CODEX_APP_IMAGE_GENERATION_DOC_URL, CODEX_COMPUTER_USE_EVIDENCE_SOURCE,
|
|
|
29
29
|
import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, validateTeamRuntimeArtifacts, writeTeamRuntimeArtifacts } from '../team-dag.js';
|
|
30
30
|
import { formatAgentReasoning, formatRoleCounts, initTeamLive, parseTeamSpecText, teamReasoningPolicy } from '../team-live.js';
|
|
31
31
|
import { evaluateTeamReviewPolicyGate, MIN_TEAM_REVIEWER_LANES, MIN_TEAM_REVIEW_POLICY_TEXT, teamReviewPolicy } from '../team-review-policy.js';
|
|
32
|
+
import { normalizeCodexMultiAgentEventName } from '../codex-control/codex-multi-agent-event-normalizer.js';
|
|
32
33
|
export { routePrompt };
|
|
33
34
|
export const PIPELINE_PLAN_ARTIFACT = 'pipeline-plan.json';
|
|
34
35
|
export const PIPELINE_PLAN_SCHEMA_VERSION = 1;
|
|
@@ -1257,7 +1258,11 @@ function subagentStage(payload) {
|
|
|
1257
1258
|
return 'exception';
|
|
1258
1259
|
if (/spawn_agent/i.test(hay))
|
|
1259
1260
|
return 'spawn_agent';
|
|
1260
|
-
|
|
1261
|
+
for (const name of ['interrupt_agent', 'close_agent']) {
|
|
1262
|
+
if (hay.includes(name) && normalizeCodexMultiAgentEventName(name).stage === 'result')
|
|
1263
|
+
return 'result';
|
|
1264
|
+
}
|
|
1265
|
+
if (/wait_agent|completed|final/i.test(hay))
|
|
1261
1266
|
return 'result';
|
|
1262
1267
|
return 'subagent';
|
|
1263
1268
|
}
|