sneakoscope 2.0.11 → 2.0.13
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 +9 -3
- 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/build-manifest.json +27 -8
- package/dist/core/agents/agent-orchestrator.js +279 -1
- package/dist/core/agents/agent-scheduler.js +12 -1
- package/dist/core/agents/agent-slot-pane-binding-proof.js +3 -3
- package/dist/core/agents/agent-work-queue.js +26 -2
- package/dist/core/agents/agent-worker-pipeline.js +2 -0
- package/dist/core/agents/native-cli-session-swarm.js +2 -2
- package/dist/core/codex-control/codex-sdk-adapter.js +10 -0
- package/dist/core/codex-control/codex-task-runner.js +4 -2
- package/dist/core/commands/naruto-command.js +104 -51
- package/dist/core/commands/research-command.js +43 -4
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-worktree-merge-queue.js +34 -14
- package/dist/core/naruto/naruto-rebalance-policy.js +15 -3
- package/dist/core/naruto/naruto-work-graph.js +13 -0
- package/dist/core/research/claim-evidence-matrix.js +160 -0
- package/dist/core/research/experiment-plan.js +53 -0
- package/dist/core/research/falsification.js +18 -0
- package/dist/core/research/implementation-blueprint-markdown.js +31 -0
- package/dist/core/research/implementation-blueprint.js +66 -0
- package/dist/core/research/replication-pack.js +50 -0
- package/dist/core/research/research-cycle-runner.js +25 -0
- package/dist/core/research/research-final-reviewer.js +58 -0
- package/dist/core/research/research-handoff.js +51 -0
- package/dist/core/research/research-prompt-contract.js +24 -0
- package/dist/core/research/research-quality-contract.js +61 -0
- package/dist/core/research/research-report-quality.js +67 -0
- package/dist/core/research/research-stage-runner.js +16 -0
- package/dist/core/research/research-work-graph.js +75 -0
- package/dist/core/research/source-quality-report.js +94 -0
- package/dist/core/research.js +344 -44
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-slot-column-anchor.js +165 -4
- package/dist/core/zellij/zellij-slot-pane-renderer.js +259 -16
- package/dist/core/zellij/zellij-worker-pane-manager.js +13 -7
- package/dist/scripts/agent-real-codex-in-zellij-worker-pane-check.js +8 -2
- package/dist/scripts/agent-slot-pane-binding-proof-check.js +4 -4
- package/dist/scripts/codex-sdk-release-review-pipeline-check.js +2 -1
- package/dist/scripts/codex-sdk-research-pipeline-check.js +7 -0
- package/dist/scripts/codex-sdk-zellij-pane-binding-check.js +2 -2
- package/dist/scripts/git-worktree-cross-rebase-check.js +13 -1
- package/dist/scripts/git-worktree-merge-queue-check.js +1 -0
- package/dist/scripts/local-collab-worktree-gpt-final-apply-policy-check.js +63 -0
- package/dist/scripts/naruto-actual-worker-control-plane-check.js +30 -3
- package/dist/scripts/naruto-allocation-runtime-wiring-check.js +92 -0
- package/dist/scripts/naruto-orchestrator-runtime-source-check.js +65 -6
- package/dist/scripts/naruto-rebalance-policy-check.js +15 -2
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +1 -1
- package/dist/scripts/packlist-performance-check.js +1 -1
- package/dist/scripts/release-dag-full-coverage-check.js +4 -0
- package/dist/scripts/release-real-check.js +258 -77
- package/dist/scripts/research-quality-gate-check.js +86 -0
- package/dist/scripts/zellij-first-slot-down-stack-check.js +1 -1
- package/dist/scripts/zellij-first-slot-down-stack-real-check.js +344 -4
- package/dist/scripts/zellij-right-column-manager-check.js +1 -1
- package/dist/scripts/zellij-slot-column-anchor-check.js +45 -3
- package/dist/scripts/zellij-slot-only-ui-check.js +3 -1
- package/dist/scripts/zellij-slot-pane-renderer-check.js +73 -5
- package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +59 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +23 -1
- package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +21 -4
- package/package.json +17 -2
- package/schemas/research/claim-evidence-matrix.schema.json +37 -0
- package/schemas/research/experiment-plan.schema.json +17 -0
- package/schemas/research/implementation-blueprint.schema.json +30 -0
- package/schemas/research/replication-pack.schema.json +17 -0
- package/schemas/research/research-final-review.schema.json +16 -0
- package/schemas/research/research-quality-contract.schema.json +37 -0
- package/schemas/research/source-quality-report.schema.json +18 -0
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '2.0.
|
|
1
|
+
export const PACKAGE_VERSION = '2.0.13';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -5,18 +5,34 @@ export function renderZellijSlotColumnAnchor(input = {}) {
|
|
|
5
5
|
const visible = Math.max(1, nonNegativeInt(input.visiblePaneCap, active || 1));
|
|
6
6
|
const headless = nonNegativeInt(input.headlessWorkers, 0);
|
|
7
7
|
const queue = nonNegativeInt(input.queueDepth, 0);
|
|
8
|
-
|
|
8
|
+
const header = `SLOTS active ${active}/${visible} · headless ${headless} · q ${queue}`;
|
|
9
|
+
const workers = Array.isArray(input.workerRows) ? input.workerRows : [];
|
|
10
|
+
if (!workers.length)
|
|
11
|
+
return `${header}\nvisible slot panes stack below this anchor`;
|
|
12
|
+
const maxRows = Math.max(1, nonNegativeInt(input.maxWorkerRows, input.mode === 'full-debug' ? 24 : 12));
|
|
13
|
+
const overflowRows = workers.filter((row) => row.placement === 'headless').slice(0, maxRows);
|
|
14
|
+
const visibleRows = overflowRows.length ? overflowRows : workers.filter((row) => row.placement !== 'zellij-pane').slice(0, maxRows);
|
|
15
|
+
const hidden = Math.max(0, workers.length - visibleRows.length);
|
|
16
|
+
return [
|
|
17
|
+
header,
|
|
18
|
+
`visible slot panes stack below this anchor`,
|
|
19
|
+
...visibleRows.map((row, index) => renderWorkerRow(row, index + 1)),
|
|
20
|
+
...(hidden && visibleRows.length ? [`+${hidden} worker${hidden === 1 ? '' : 's'} in dedicated panes or overflow`] : [])
|
|
21
|
+
].join('\n');
|
|
9
22
|
}
|
|
10
23
|
export async function renderZellijSlotColumnAnchorFromArtifacts(input) {
|
|
11
24
|
const root = path.resolve(input.artifactRoot);
|
|
12
25
|
const missionDir = inferMissionDir(root, input.missionId);
|
|
13
26
|
const snapshot = await readJson(path.join(missionDir, 'zellij-dashboard-snapshot.json'));
|
|
14
27
|
const rightColumn = await readJson(path.join(missionDir, 'zellij-right-column-state.json'));
|
|
15
|
-
const
|
|
28
|
+
const swarm = await readJson(path.join(root, 'agent-native-cli-session-swarm.json'))
|
|
29
|
+
|| await readJson(path.join(missionDir, 'agents', 'agent-native-cli-session-swarm.json'));
|
|
30
|
+
const workerRows = await buildWorkerRows(root, missionDir, rightColumn, swarm);
|
|
31
|
+
const activeWorkers = Number(snapshot?.active_workers ?? workerRows.filter((row) => row.status === 'running' || row.status === 'launching').length ?? 0);
|
|
16
32
|
const visiblePaneCap = Number(snapshot?.visible_panes ?? Math.max(1, rightColumn?.visible_worker_panes?.length || activeWorkers || 1));
|
|
17
|
-
const headlessWorkers = Number(snapshot?.headless_workers ??
|
|
33
|
+
const headlessWorkers = Number(snapshot?.headless_workers ?? workerRows.filter((row) => row.placement === 'headless' && (!row.status || row.status === 'running')).length ?? 0);
|
|
18
34
|
const queueDepth = Number(snapshot?.queue_depth ?? 0);
|
|
19
|
-
const anchorInput = { activeWorkers, visiblePaneCap, headlessWorkers, queueDepth };
|
|
35
|
+
const anchorInput = { activeWorkers, visiblePaneCap, headlessWorkers, queueDepth, workerRows };
|
|
20
36
|
if (input.mode !== undefined)
|
|
21
37
|
anchorInput.mode = input.mode;
|
|
22
38
|
return renderZellijSlotColumnAnchor(anchorInput);
|
|
@@ -47,12 +63,157 @@ async function readJson(file) {
|
|
|
47
63
|
return null;
|
|
48
64
|
}
|
|
49
65
|
}
|
|
66
|
+
async function buildWorkerRows(root, missionDir, rightColumn, swarm) {
|
|
67
|
+
const byKey = new Map();
|
|
68
|
+
const records = Array.isArray(swarm?.records) ? swarm.records : [];
|
|
69
|
+
const recordByKey = new Map();
|
|
70
|
+
for (const record of records) {
|
|
71
|
+
const key = workerKey(record?.slot_id, record?.generation_index);
|
|
72
|
+
if (key)
|
|
73
|
+
recordByKey.set(key, record);
|
|
74
|
+
}
|
|
75
|
+
for (const pane of Array.isArray(rightColumn?.visible_worker_panes) ? rightColumn.visible_worker_panes : []) {
|
|
76
|
+
const key = workerKey(pane?.slot_id, pane?.generation_index);
|
|
77
|
+
if (!key)
|
|
78
|
+
continue;
|
|
79
|
+
const record = recordByKey.get(key);
|
|
80
|
+
byKey.set(key, await hydrateWorkerRow(root, missionDir, {
|
|
81
|
+
slotId: String(pane.slot_id),
|
|
82
|
+
generationIndex: Number(pane.generation_index || 1),
|
|
83
|
+
placement: 'zellij-pane',
|
|
84
|
+
status: pane.status || record?.status || 'running',
|
|
85
|
+
paneId: pane.pane_id || record?.zellij_pane_id || null,
|
|
86
|
+
yOrder: Number(pane.y_order || 0)
|
|
87
|
+
}, record));
|
|
88
|
+
}
|
|
89
|
+
for (const row of Array.isArray(rightColumn?.headless_workers) ? rightColumn.headless_workers : []) {
|
|
90
|
+
const key = workerKey(row?.slot_id, row?.generation_index);
|
|
91
|
+
if (!key)
|
|
92
|
+
continue;
|
|
93
|
+
const record = recordByKey.get(key);
|
|
94
|
+
byKey.set(key, await hydrateWorkerRow(root, missionDir, {
|
|
95
|
+
slotId: String(row.slot_id),
|
|
96
|
+
generationIndex: Number(row.generation_index || 1),
|
|
97
|
+
placement: 'headless',
|
|
98
|
+
status: row.status || record?.status || 'running',
|
|
99
|
+
reason: row.reason || record?.headless_reason || null,
|
|
100
|
+
yOrder: 9000
|
|
101
|
+
}, record));
|
|
102
|
+
}
|
|
103
|
+
for (const record of records) {
|
|
104
|
+
const key = workerKey(record?.slot_id, record?.generation_index);
|
|
105
|
+
if (!key || byKey.has(key))
|
|
106
|
+
continue;
|
|
107
|
+
byKey.set(key, await hydrateWorkerRow(root, missionDir, {
|
|
108
|
+
slotId: String(record.slot_id || record.agent_id || 'slot-?'),
|
|
109
|
+
generationIndex: Number(record.generation_index || 1),
|
|
110
|
+
placement: record.worker_placement || (record.zellij_pane_id ? 'zellij-pane' : 'process'),
|
|
111
|
+
status: record.status || 'running',
|
|
112
|
+
paneId: record.zellij_pane_id || null,
|
|
113
|
+
yOrder: 5000
|
|
114
|
+
}, record));
|
|
115
|
+
}
|
|
116
|
+
return [...byKey.values()].sort((a, b) => {
|
|
117
|
+
const statusDelta = statusWeight(a.status) - statusWeight(b.status);
|
|
118
|
+
if (statusDelta)
|
|
119
|
+
return statusDelta;
|
|
120
|
+
const yDelta = Number(a.yOrder || 0) - Number(b.yOrder || 0);
|
|
121
|
+
if (yDelta)
|
|
122
|
+
return yDelta;
|
|
123
|
+
return String(a.slotId).localeCompare(String(b.slotId));
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async function hydrateWorkerRow(root, missionDir, base, record) {
|
|
127
|
+
const artifactDir = resolveArtifactDir(root, missionDir, record?.worker_artifact_dir);
|
|
128
|
+
const result = artifactDir ? await readJson(path.join(artifactDir, 'worker-result.json')) : null;
|
|
129
|
+
const intake = artifactDir ? await readJson(path.join(artifactDir, 'worker-intake.json')) : null;
|
|
130
|
+
const heartbeatPath = artifactDir ? path.join(artifactDir, 'worker-heartbeat.jsonl') : null;
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
status: result?.status || base.status || record?.status || 'running',
|
|
134
|
+
backend: result?.backend || record?.backend || intake?.backend || null,
|
|
135
|
+
role: result?.persona_id || intake?.agent?.naruto_role || intake?.agent?.role || intake?.agent?.persona_id || null,
|
|
136
|
+
task: firstText([
|
|
137
|
+
result?.summary,
|
|
138
|
+
Array.isArray(result?.changed_files) ? result.changed_files[0] : null,
|
|
139
|
+
intake?.slice?.description,
|
|
140
|
+
intake?.slice?.title,
|
|
141
|
+
intake?.slice?.id,
|
|
142
|
+
base.reason
|
|
143
|
+
]),
|
|
144
|
+
worktreeId: result?.worktree?.id || record?.worktree?.id || intake?.worktree?.id || null,
|
|
145
|
+
heartbeatAgeMs: heartbeatPath ? await heartbeatAgeMs(heartbeatPath) : null
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function renderWorkerRow(row, index) {
|
|
149
|
+
const slot = `${trimInline(row.slotId || 'slot-?', 12)} g${Math.max(1, Math.floor(Number(row.generationIndex) || 1))}`;
|
|
150
|
+
const status = trimInline(row.status || 'running', 9);
|
|
151
|
+
const backend = trimInline(row.backend || row.placement || '-', 12);
|
|
152
|
+
const worktree = trimInline(row.worktreeId || row.role || '-', 10);
|
|
153
|
+
const task = trimInline(row.task || row.reason || '-', 38);
|
|
154
|
+
return `${String(index).padStart(2, '0')} ${slot} ${status} ${backend} ${worktree} · ${task} · hb ${formatHeartbeat(row.heartbeatAgeMs)}`;
|
|
155
|
+
}
|
|
156
|
+
function resolveArtifactDir(root, missionDir, value) {
|
|
157
|
+
if (!value)
|
|
158
|
+
return null;
|
|
159
|
+
const text = String(value);
|
|
160
|
+
if (path.isAbsolute(text))
|
|
161
|
+
return text;
|
|
162
|
+
return path.join(root, text);
|
|
163
|
+
}
|
|
164
|
+
async function heartbeatAgeMs(file) {
|
|
165
|
+
try {
|
|
166
|
+
return Date.now() - (await fs.promises.stat(file)).mtimeMs;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function formatHeartbeat(ageMs) {
|
|
173
|
+
if (ageMs == null)
|
|
174
|
+
return '?';
|
|
175
|
+
if (ageMs < 1000)
|
|
176
|
+
return 'now';
|
|
177
|
+
return `${Math.max(1, Math.round(ageMs / 1000))}s`;
|
|
178
|
+
}
|
|
179
|
+
function firstText(values) {
|
|
180
|
+
for (const value of values) {
|
|
181
|
+
const text = String(value || '').replace(/\s+/g, ' ').trim();
|
|
182
|
+
if (text)
|
|
183
|
+
return text;
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
function workerKey(slotId, generationIndex) {
|
|
188
|
+
const slot = String(slotId || '').trim();
|
|
189
|
+
if (!slot)
|
|
190
|
+
return null;
|
|
191
|
+
return `${slot}:g${Math.max(1, Math.floor(Number(generationIndex) || 1))}`;
|
|
192
|
+
}
|
|
193
|
+
function statusWeight(status) {
|
|
194
|
+
const text = String(status || '').toLowerCase();
|
|
195
|
+
if (text === 'running' || text === 'launching')
|
|
196
|
+
return 0;
|
|
197
|
+
if (text === 'failed')
|
|
198
|
+
return 1;
|
|
199
|
+
if (text === 'draining')
|
|
200
|
+
return 2;
|
|
201
|
+
if (text === 'closed')
|
|
202
|
+
return 3;
|
|
203
|
+
return 4;
|
|
204
|
+
}
|
|
50
205
|
function nonNegativeInt(value, fallback) {
|
|
51
206
|
const parsed = Number(value);
|
|
52
207
|
if (!Number.isFinite(parsed) || parsed < 0)
|
|
53
208
|
return fallback;
|
|
54
209
|
return Math.floor(parsed);
|
|
55
210
|
}
|
|
211
|
+
function trimInline(value, max) {
|
|
212
|
+
const text = String(value || '').replace(/\s+/g, ' ').trim();
|
|
213
|
+
if (text.length <= max)
|
|
214
|
+
return text;
|
|
215
|
+
return text.slice(0, Math.max(1, max - 3)) + '...';
|
|
216
|
+
}
|
|
56
217
|
function shellQuote(value) {
|
|
57
218
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
58
219
|
}
|
|
@@ -2,40 +2,121 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
export function renderZellijSlotPane(input) {
|
|
4
4
|
const mode = input.mode || 'compact-slots';
|
|
5
|
-
const maxLines = mode === 'compact-slots' ?
|
|
6
|
-
const task = trimInline(input.
|
|
5
|
+
const maxLines = mode === 'compact-slots' ? 17 : mode === 'dashboard-plus-slots' ? 20 : 32;
|
|
6
|
+
const task = trimInline(input.currentTask || input.currentFile || 'waiting for worker intake', 78);
|
|
7
7
|
const heartbeat = input.heartbeatAgeMs == null
|
|
8
8
|
? 'unknown'
|
|
9
9
|
: input.heartbeatAgeMs < 1000
|
|
10
10
|
? 'now'
|
|
11
11
|
: `${Math.max(1, Math.round(input.heartbeatAgeMs / 1000))}s ago`;
|
|
12
|
+
const files = firstNonEmptyList(input.changedFiles, input.patchFiles, input.plannedFiles, input.currentFile ? [input.currentFile] : []);
|
|
13
|
+
const events = (input.eventLines || []).filter(Boolean).slice(-3);
|
|
14
|
+
const stdout = (input.stdoutTail || []).filter(Boolean).slice(-2);
|
|
15
|
+
const stderr = (input.stderrTail || []).filter(Boolean).slice(-1);
|
|
12
16
|
const rows = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
`
|
|
17
|
-
`
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
`slot: ${input.slotId} / gen-${Math.max(1, Math.floor(Number(input.generationIndex) || 1))} / ${trimInline(input.status || 'running', 18)}`,
|
|
18
|
+
`role: ${trimInline(input.role || 'worker', 18)} backend: ${trimInline(input.backend || 'codex-sdk', 20)} worktree: ${trimInline(input.worktreeId || '-', 18)}`,
|
|
19
|
+
`runtime: fast ${formatFastMode(input.fastMode, input.serviceTier)} tier: ${trimInline(input.serviceTier || 'unknown', 12)} provider: ${trimInline(input.provider || 'unknown', 18)}`,
|
|
20
|
+
`model: ${trimInline(input.model || 'unknown', 28)} reasoning: ${trimInline(input.reasoningEffort || 'unknown', 16)}${input.authMode ? ` auth: ${trimInline(input.authMode, 14)}` : ''}`,
|
|
21
|
+
input.sessionId ? `session: ${trimInline(input.sessionId, 62)}` : null,
|
|
22
|
+
`heartbeat: ${heartbeat}${input.heartbeatEvent ? ` event: ${trimInline(input.heartbeatEvent, 40)}` : ''}`,
|
|
23
|
+
`doing: ${task}`,
|
|
24
|
+
`files: ${trimInline(files.length ? files.join(', ') : 'no changed file yet', 78)}`,
|
|
25
|
+
`patch: ${trimInline(input.patchStatus || 'queued', 24)} verify: ${trimInline(input.verifyStatus || 'queued', 24)}`,
|
|
26
|
+
...events.map((event) => `event: ${trimInline(event, 78)}`),
|
|
27
|
+
...stdout.map((line) => `out: ${trimInline(line, 79)}`),
|
|
28
|
+
...stderr.map((line) => `err: ${trimInline(line, 79)}`)
|
|
29
|
+
].filter((row) => Boolean(row));
|
|
30
|
+
return frameSlotPane(`LIVE SLOT ${input.slotId}`, rows.slice(0, Math.max(1, maxLines - 2)));
|
|
20
31
|
}
|
|
21
32
|
export async function renderZellijSlotPaneFromArtifacts(input) {
|
|
22
33
|
const artifactDir = path.resolve(input.artifactDir);
|
|
23
34
|
const result = await readJson(path.join(artifactDir, 'worker-result.json'));
|
|
35
|
+
const intake = await readJson(path.join(artifactDir, 'worker-intake.json'));
|
|
36
|
+
const backendReport = await readJson(path.join(artifactDir, 'worker-backend-router-report.json'));
|
|
37
|
+
const fastReport = await readJson(path.join(artifactDir, 'worker-fast-mode.json'));
|
|
38
|
+
const paneReport = await readJson(path.join(artifactDir, 'zellij-worker-pane.json'));
|
|
39
|
+
const codexProof = await readJson(path.join(artifactDir, 'codex-control-proof.json'));
|
|
40
|
+
const localProof = await readJson(path.join(artifactDir, 'local-llm-proof.json'));
|
|
41
|
+
const patch = await firstJson([
|
|
42
|
+
path.join(artifactDir, 'worker-patch-envelope.json'),
|
|
43
|
+
path.join(artifactDir, 'codex-sdk-patch-envelope.json'),
|
|
44
|
+
path.join(artifactDir, 'python-codex-sdk-patch-envelope.json'),
|
|
45
|
+
path.join(artifactDir, 'local-llm-patch-envelope.json')
|
|
46
|
+
]);
|
|
24
47
|
const heartbeatPath = path.join(artifactDir, 'worker-heartbeat.jsonl');
|
|
25
48
|
const heartbeatMtime = await statMtimeMs(heartbeatPath);
|
|
49
|
+
const heartbeatRows = await readJsonlTail(heartbeatPath, 2);
|
|
50
|
+
const eventRows = await readJsonlTails([
|
|
51
|
+
path.join(artifactDir, 'codex-sdk-events.jsonl'),
|
|
52
|
+
path.join(artifactDir, 'python-codex-sdk-events.jsonl'),
|
|
53
|
+
path.join(artifactDir, 'local-llm-events.jsonl'),
|
|
54
|
+
path.join(artifactDir, 'zellij-worker-pane-events.jsonl')
|
|
55
|
+
], 6);
|
|
56
|
+
const patchFiles = patchPaths(patch || result);
|
|
57
|
+
const changedFiles = normalizeList(result?.changed_files);
|
|
58
|
+
const plannedFiles = normalizeList([
|
|
59
|
+
...(Array.isArray(intake?.slice?.write_paths) ? intake.slice.write_paths : []),
|
|
60
|
+
...(Array.isArray(intake?.slice?.readonly_paths) ? intake.slice.readonly_paths : []),
|
|
61
|
+
...(Array.isArray(intake?.input_files) ? intake.input_files : [])
|
|
62
|
+
]);
|
|
26
63
|
const now = Date.now();
|
|
27
64
|
return renderZellijSlotPane({
|
|
28
65
|
slotId: input.slotId,
|
|
29
66
|
generationIndex: input.generationIndex,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
67
|
+
sessionId: result?.session_id || intake?.agent?.session_id || backendReport?.session_id || null,
|
|
68
|
+
role: input.role || result?.persona_id || intake?.agent?.naruto_role || intake?.agent?.role || intake?.agent?.persona_id || result?.agent_id || null,
|
|
69
|
+
backend: input.backend || result?.backend || backendReport?.selected_backend || intake?.backend || null,
|
|
70
|
+
status: result?.status || statusFromEvents(eventRows) || (heartbeatMtime ? 'running' : 'launching'),
|
|
71
|
+
fastMode: firstDefined(fastReport?.fast_mode, backendReport?.fast_mode, result?.fast_mode, intake?.fast_mode),
|
|
72
|
+
serviceTier: firstText([
|
|
73
|
+
fastReport?.service_tier,
|
|
74
|
+
paneReport?.service_tier,
|
|
75
|
+
backendReport?.service_tier,
|
|
76
|
+
codexProof?.config?.service_tier,
|
|
77
|
+
result?.service_tier,
|
|
78
|
+
intake?.service_tier
|
|
79
|
+
]),
|
|
80
|
+
provider: firstText([
|
|
81
|
+
paneReport?.provider_context?.provider,
|
|
82
|
+
paneReport?.provider,
|
|
83
|
+
codexProof?.config?.model_provider,
|
|
84
|
+
localProof?.provider
|
|
85
|
+
]),
|
|
86
|
+
authMode: firstText([
|
|
87
|
+
paneReport?.provider_context?.auth_mode,
|
|
88
|
+
codexProof?.config?.model_provider ? 'api_key' : null
|
|
89
|
+
]),
|
|
90
|
+
model: firstText([
|
|
91
|
+
codexProof?.config?.model,
|
|
92
|
+
localProof?.model,
|
|
93
|
+
intake?.ollama_model,
|
|
94
|
+
intake?.local_model_model
|
|
95
|
+
]),
|
|
96
|
+
reasoningEffort: firstText([
|
|
97
|
+
codexProof?.config?.model_reasoning_effort,
|
|
98
|
+
intake?.agent?.model_reasoning_effort,
|
|
99
|
+
intake?.agent?.reasoning_effort
|
|
100
|
+
]),
|
|
101
|
+
currentTask: firstText([
|
|
102
|
+
result?.summary,
|
|
103
|
+
intake?.slice?.description,
|
|
104
|
+
intake?.slice?.title,
|
|
105
|
+
intake?.slice?.id,
|
|
106
|
+
lastEventLine(eventRows)
|
|
107
|
+
]),
|
|
108
|
+
currentFile: changedFiles[0] || patchFiles[0] || plannedFiles[0] || null,
|
|
109
|
+
changedFiles,
|
|
110
|
+
plannedFiles,
|
|
111
|
+
patchFiles,
|
|
112
|
+
patchStatus: patchStatus(result, patch, patchFiles),
|
|
36
113
|
verifyStatus: result?.verification?.status || 'queued',
|
|
37
114
|
heartbeatAgeMs: heartbeatMtime ? now - heartbeatMtime : null,
|
|
38
|
-
|
|
115
|
+
heartbeatEvent: heartbeatRows.length ? formatArtifactEvent(heartbeatRows[heartbeatRows.length - 1]) : null,
|
|
116
|
+
worktreeId: result?.worktree?.id || intake?.worktree?.id || null,
|
|
117
|
+
eventLines: eventRows.map(formatArtifactEvent).filter(Boolean),
|
|
118
|
+
stdoutTail: await readTextTailLines(path.join(artifactDir, 'worker.stdout.log'), 2),
|
|
119
|
+
stderrTail: await readTextTailLines(path.join(artifactDir, 'worker.stderr.log'), 1),
|
|
39
120
|
mode: input.mode || 'compact-slots'
|
|
40
121
|
});
|
|
41
122
|
}
|
|
@@ -62,6 +143,14 @@ async function readJson(file) {
|
|
|
62
143
|
return null;
|
|
63
144
|
}
|
|
64
145
|
}
|
|
146
|
+
async function firstJson(files) {
|
|
147
|
+
for (const file of files) {
|
|
148
|
+
const value = await readJson(file);
|
|
149
|
+
if (value)
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
65
154
|
async function statMtimeMs(file) {
|
|
66
155
|
try {
|
|
67
156
|
return (await fs.promises.stat(file)).mtimeMs;
|
|
@@ -70,12 +159,166 @@ async function statMtimeMs(file) {
|
|
|
70
159
|
return null;
|
|
71
160
|
}
|
|
72
161
|
}
|
|
162
|
+
async function readJsonlTails(files, max) {
|
|
163
|
+
const rows = [];
|
|
164
|
+
for (const file of files)
|
|
165
|
+
rows.push(...await readJsonlTail(file, max));
|
|
166
|
+
return rows
|
|
167
|
+
.sort((a, b) => timestampMs(a) - timestampMs(b))
|
|
168
|
+
.slice(-max);
|
|
169
|
+
}
|
|
170
|
+
async function readJsonlTail(file, max) {
|
|
171
|
+
try {
|
|
172
|
+
const lines = (await fs.promises.readFile(file, 'utf8')).split(/\r?\n/).filter((line) => line.trim());
|
|
173
|
+
return lines.slice(-Math.max(1, max)).map((line) => {
|
|
174
|
+
try {
|
|
175
|
+
return JSON.parse(line);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return { message: line };
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async function readTextTailLines(file, max) {
|
|
187
|
+
try {
|
|
188
|
+
const lines = (await fs.promises.readFile(file, 'utf8')).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
189
|
+
return lines.slice(-Math.max(1, max));
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return [];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function patchStatus(result, patch, files) {
|
|
196
|
+
const resultCount = Array.isArray(result?.patch_envelopes) ? result.patch_envelopes.length : 0;
|
|
197
|
+
const patchCount = Number(patch?.envelope_count || (Array.isArray(patch?.envelopes) ? patch.envelopes.length : 0));
|
|
198
|
+
const count = Math.max(resultCount, Number.isFinite(patchCount) ? patchCount : 0);
|
|
199
|
+
if (count > 0)
|
|
200
|
+
return `candidate (${count})`;
|
|
201
|
+
if (files.length)
|
|
202
|
+
return 'candidate';
|
|
203
|
+
return 'queued';
|
|
204
|
+
}
|
|
205
|
+
function patchPaths(value) {
|
|
206
|
+
const envelopes = [
|
|
207
|
+
...(Array.isArray(value?.envelopes) ? value.envelopes : []),
|
|
208
|
+
...(Array.isArray(value?.patch_envelopes) ? value.patch_envelopes : [])
|
|
209
|
+
];
|
|
210
|
+
return normalizeList(envelopes.flatMap((envelope) => {
|
|
211
|
+
const paths = [
|
|
212
|
+
...(Array.isArray(envelope?.operations) ? envelope.operations.map((operation) => operation?.path) : []),
|
|
213
|
+
...(Array.isArray(envelope?.allowed_paths) ? envelope.allowed_paths : [])
|
|
214
|
+
];
|
|
215
|
+
return paths;
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
function statusFromEvents(rows) {
|
|
219
|
+
const last = rows[rows.length - 1];
|
|
220
|
+
const status = String(last?.lane_status || last?.status || '').trim();
|
|
221
|
+
if (status)
|
|
222
|
+
return status;
|
|
223
|
+
const type = String(last?.event_type || last?.type || '').trim();
|
|
224
|
+
if (/failed|blocked/i.test(type))
|
|
225
|
+
return 'blocked';
|
|
226
|
+
if (/completed|finished|closed/i.test(type))
|
|
227
|
+
return 'done';
|
|
228
|
+
if (type)
|
|
229
|
+
return 'running';
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
function lastEventLine(rows) {
|
|
233
|
+
for (const row of [...rows].reverse()) {
|
|
234
|
+
const text = formatArtifactEvent(row);
|
|
235
|
+
if (text)
|
|
236
|
+
return text;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
function formatArtifactEvent(row) {
|
|
241
|
+
if (!row)
|
|
242
|
+
return '';
|
|
243
|
+
const status = trimInline(row.lane_status || row.status || row.event || row.event_type || row.type || row.sdk_event_type || 'event', 18);
|
|
244
|
+
const detail = firstText([
|
|
245
|
+
row.current_tool && row.current_file ? `tool ${row.current_tool} file ${row.current_file}` : null,
|
|
246
|
+
row.current_file ? `file ${row.current_file}` : null,
|
|
247
|
+
row.current_tool ? `tool ${row.current_tool}` : null,
|
|
248
|
+
row.message_tail,
|
|
249
|
+
row.blocker ? `blocker ${row.blocker}` : null,
|
|
250
|
+
row.request_id,
|
|
251
|
+
row.pane_id ? `pane ${row.pane_id}` : null,
|
|
252
|
+
row.message,
|
|
253
|
+
row.reason
|
|
254
|
+
]);
|
|
255
|
+
return trimInline(detail ? `${status}: ${detail}` : status, 96);
|
|
256
|
+
}
|
|
257
|
+
function timestampMs(row) {
|
|
258
|
+
const raw = row?.ts || row?.generated_at || row?.updated_at || row?.created_at;
|
|
259
|
+
const parsed = raw ? Date.parse(String(raw)) : NaN;
|
|
260
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
261
|
+
}
|
|
262
|
+
function firstText(values) {
|
|
263
|
+
for (const value of values) {
|
|
264
|
+
const text = String(value || '').replace(/\s+/g, ' ').trim();
|
|
265
|
+
if (text)
|
|
266
|
+
return text;
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
function firstDefined(...values) {
|
|
271
|
+
for (const value of values) {
|
|
272
|
+
if (value === true || value === false)
|
|
273
|
+
return value;
|
|
274
|
+
if (typeof value === 'string' && value.trim())
|
|
275
|
+
return value;
|
|
276
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
277
|
+
return String(value);
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
function firstNonEmptyList(...values) {
|
|
282
|
+
for (const value of values) {
|
|
283
|
+
const normalized = normalizeList(value || []);
|
|
284
|
+
if (normalized.length)
|
|
285
|
+
return normalized;
|
|
286
|
+
}
|
|
287
|
+
return [];
|
|
288
|
+
}
|
|
289
|
+
function normalizeList(values) {
|
|
290
|
+
return [...new Set((Array.isArray(values) ? values : [values]).map((value) => String(value || '').trim()).filter(Boolean))];
|
|
291
|
+
}
|
|
73
292
|
function trimInline(value, max) {
|
|
74
293
|
const text = String(value || '').replace(/\s+/g, ' ').trim();
|
|
75
294
|
if (text.length <= max)
|
|
76
295
|
return text;
|
|
77
296
|
return text.slice(0, Math.max(1, max - 3)) + '...';
|
|
78
297
|
}
|
|
298
|
+
function formatFastMode(value, serviceTier) {
|
|
299
|
+
const text = String(value ?? '').trim().toLowerCase();
|
|
300
|
+
if (value === true || text === 'true' || text === '1' || text === 'on' || text === 'fast')
|
|
301
|
+
return 'on';
|
|
302
|
+
if (value === false || text === 'false' || text === '0' || text === 'off' || text === 'standard')
|
|
303
|
+
return 'off';
|
|
304
|
+
const tier = String(serviceTier || '').trim().toLowerCase();
|
|
305
|
+
if (tier === 'fast' || tier === 'priority')
|
|
306
|
+
return 'on';
|
|
307
|
+
if (tier === 'standard' || tier === 'default')
|
|
308
|
+
return 'off';
|
|
309
|
+
return 'unknown';
|
|
310
|
+
}
|
|
311
|
+
function frameSlotPane(title, rows) {
|
|
312
|
+
const width = Math.min(96, Math.max(44, title.length + 6, ...rows.map((row) => row.length + 4)));
|
|
313
|
+
const line = '+' + '-'.repeat(width - 2) + '+';
|
|
314
|
+
const label = ` ${trimInline(title, width - 4)} `;
|
|
315
|
+
const titleLine = '|' + label.padEnd(width - 2, ' ') + '|';
|
|
316
|
+
const body = rows.map((row) => {
|
|
317
|
+
const text = ` ${trimInline(row, width - 4)} `;
|
|
318
|
+
return '|' + text.padEnd(width - 2, ' ') + '|';
|
|
319
|
+
});
|
|
320
|
+
return [line, titleLine, line, ...body, line].join('\n');
|
|
321
|
+
}
|
|
79
322
|
function shellQuote(value) {
|
|
80
323
|
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
81
324
|
}
|
|
@@ -26,7 +26,13 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
26
26
|
const blockers = input.blockers || [];
|
|
27
27
|
const providerContext = normalizePaneProviderContext(input.providerContext, input.serviceTier);
|
|
28
28
|
const paneTitle = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || input.status, input.worktree || null);
|
|
29
|
-
const
|
|
29
|
+
const commandText = String(input.workerCommand || '');
|
|
30
|
+
const isSlotRenderer = commandText.includes('zellij-slot-pane');
|
|
31
|
+
const paneKind = input.paneKind || (isSlotRenderer ? 'slot_status_renderer' : 'worker_codex_sdk');
|
|
32
|
+
const scalingPrimitive = input.scalingPrimitive || (isSlotRenderer
|
|
33
|
+
? 'native_cli_process_with_zellij_slot_renderer'
|
|
34
|
+
: 'native_cli_process_in_zellij_worker_pane');
|
|
35
|
+
const directionRequested = input.directionRequested || 'down';
|
|
30
36
|
const directionApplied = input.directionApplied || 'not_applied';
|
|
31
37
|
return {
|
|
32
38
|
schema: ZELLIJ_WORKER_PANE_SCHEMA,
|
|
@@ -41,7 +47,7 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
41
47
|
session_id: input.sessionId,
|
|
42
48
|
pane_name: paneTitle,
|
|
43
49
|
pane_title: paneTitle,
|
|
44
|
-
pane_kind:
|
|
50
|
+
pane_kind: paneKind,
|
|
45
51
|
pane_id: input.paneId || null,
|
|
46
52
|
pane_id_source: paneIdSource,
|
|
47
53
|
provider: providerContext.provider,
|
|
@@ -55,8 +61,8 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
55
61
|
stdout_log: input.stdoutLog,
|
|
56
62
|
stderr_log: input.stderrLog,
|
|
57
63
|
parent_child_transport: 'worker-result-json-and-heartbeat',
|
|
58
|
-
scaling_primitive:
|
|
59
|
-
command:
|
|
64
|
+
scaling_primitive: scalingPrimitive,
|
|
65
|
+
command: isSlotRenderer ? '<zellij-slot-pane-renderer-command>' : '<native-cli-worker-command>',
|
|
60
66
|
create_session: input.createSession || null,
|
|
61
67
|
launch: input.launch || null,
|
|
62
68
|
pane_reconciliation: input.paneReconciliation || null,
|
|
@@ -182,7 +188,7 @@ export async function openWorkerPane(input) {
|
|
|
182
188
|
}
|
|
183
189
|
}
|
|
184
190
|
const focusPaneId = rightColumn?.focusPaneId || slotColumnAnchorPaneId || null;
|
|
185
|
-
const directionRequested =
|
|
191
|
+
const directionRequested = 'down';
|
|
186
192
|
const focus = focusPaneId
|
|
187
193
|
? await focusZellijPaneById(input.sessionName, focusPaneId, cwd)
|
|
188
194
|
: null;
|
|
@@ -282,7 +288,7 @@ export async function openWorkerPane(input) {
|
|
|
282
288
|
session_name: input.sessionName,
|
|
283
289
|
pane_name: paneName,
|
|
284
290
|
pane_title: paneName,
|
|
285
|
-
pane_kind:
|
|
291
|
+
pane_kind: record.pane_kind,
|
|
286
292
|
pane_id: record.pane_id,
|
|
287
293
|
pane_id_source: record.pane_id_source,
|
|
288
294
|
provider: record.provider,
|
|
@@ -302,7 +308,7 @@ export async function openWorkerPane(input) {
|
|
|
302
308
|
patch_envelope_path: input.patchEnvelopePath,
|
|
303
309
|
parent_child_transport: 'worker-result-json-and-heartbeat',
|
|
304
310
|
persistent_slot_lane: false,
|
|
305
|
-
scaling_primitive:
|
|
311
|
+
scaling_primitive: record.scaling_primitive,
|
|
306
312
|
blockers
|
|
307
313
|
});
|
|
308
314
|
return record;
|
|
@@ -123,7 +123,7 @@ async function runRealGate({ sourceOk, eventProof }) {
|
|
|
123
123
|
async function inspectRealLedger(ledgerRoot) {
|
|
124
124
|
const swarm = await readJson(path.join(ledgerRoot, 'agent-native-cli-session-swarm.json'), null);
|
|
125
125
|
const records = Array.isArray(swarm?.records) ? swarm.records : [];
|
|
126
|
-
const workerRecords = records.filter(
|
|
126
|
+
const workerRecords = records.filter(isZellijCodexWorkerRecord);
|
|
127
127
|
const eventsByWorker = [];
|
|
128
128
|
for (const record of workerRecords) {
|
|
129
129
|
const workerDir = String(record.worker_artifact_dir || '');
|
|
@@ -137,7 +137,7 @@ async function inspectRealLedger(ledgerRoot) {
|
|
|
137
137
|
const blockers = [
|
|
138
138
|
...(swarm?.ok === true ? [] : ['real_codex_zellij_swarm_not_ok']),
|
|
139
139
|
...(workerRecords.length >= 1 ? [] : ['real_codex_zellij_worker_record_missing']),
|
|
140
|
-
...(workerRecords.some((row) => row.pane_kind === 'worker_codex_sdk') ? [] : ['real_codex_zellij_worker_pane_kind_missing']),
|
|
140
|
+
...(workerRecords.some((row) => row.pane_kind === 'worker_codex_sdk' || row.pane_kind === 'slot_status_renderer') ? [] : ['real_codex_zellij_worker_pane_kind_missing']),
|
|
141
141
|
...(workerRecords.every((row) => manager.isRealZellijWorkerPaneIdSource(row.zellij_pane_id_source)) ? [] : ['real_codex_zellij_pane_id_source_not_real']),
|
|
142
142
|
...(workerRecords.every((row) => row.zellij_pane_id) ? [] : ['real_codex_zellij_pane_id_missing']),
|
|
143
143
|
...(workerRecords.every((row) => row.sdk_thread_id) ? [] : ['real_codex_zellij_sdk_thread_missing']),
|
|
@@ -171,6 +171,12 @@ async function inspectRealLedger(ledgerRoot) {
|
|
|
171
171
|
blockers
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
|
+
function isZellijCodexWorkerRecord(row) {
|
|
175
|
+
return row?.scaling_primitive === 'native_cli_process_in_zellij_worker_pane'
|
|
176
|
+
|| row?.scaling_primitive === 'native_cli_process_with_zellij_slot_renderer'
|
|
177
|
+
|| row?.pane_kind === 'worker_codex_sdk'
|
|
178
|
+
|| row?.pane_kind === 'slot_status_renderer';
|
|
179
|
+
}
|
|
174
180
|
async function emit(report) {
|
|
175
181
|
await fs.mkdir(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
|
|
176
182
|
await fs.writeFile(path.join(root, '.sneakoscope', 'reports', 'agent-real-codex-in-zellij-worker-pane.json'), `${JSON.stringify(report, null, 2)}\n`);
|
|
@@ -14,10 +14,10 @@ const records = [1, 2, 3].map((index) => ({
|
|
|
14
14
|
session_id: `slot-001-gen-${index}`,
|
|
15
15
|
slot_id: 'slot-001',
|
|
16
16
|
generation_index: index,
|
|
17
|
-
pane_kind: 'worker_codex_sdk',
|
|
17
|
+
pane_kind: index === 1 ? 'slot_status_renderer' : 'worker_codex_sdk',
|
|
18
18
|
zellij_pane_id: String(100 + index),
|
|
19
19
|
zellij_pane_id_source: index % 2 ? 'zellij_worker_new_pane_stdout' : 'zellij_worker_list_panes',
|
|
20
|
-
scaling_primitive: 'native_cli_process_in_zellij_worker_pane',
|
|
20
|
+
scaling_primitive: index === 1 ? 'native_cli_process_with_zellij_slot_renderer' : 'native_cli_process_in_zellij_worker_pane',
|
|
21
21
|
sdk_thread_id: `sdk-thread-${index}`,
|
|
22
22
|
sdk_run_id: `sdk-run-${index}`,
|
|
23
23
|
stream_event_count: 4,
|
|
@@ -35,9 +35,9 @@ await fs.writeFile(path.join(tmp, 'agent-native-cli-session-swarm.json'), `${JSO
|
|
|
35
35
|
}, null, 2)}\n`);
|
|
36
36
|
await fs.writeFile(path.join(tmp, 'agent-zellij-pane-launch-ledger.jsonl'), records.map((record) => JSON.stringify({
|
|
37
37
|
schema: 'sks.agent-zellij-pane-launch.v1',
|
|
38
|
-
pane_kind:
|
|
38
|
+
pane_kind: record.pane_kind,
|
|
39
39
|
persistent_slot_lane: false,
|
|
40
|
-
scaling_primitive:
|
|
40
|
+
scaling_primitive: record.scaling_primitive,
|
|
41
41
|
slot_id: record.slot_id,
|
|
42
42
|
generation_index: record.generation_index,
|
|
43
43
|
pane_id: record.zellij_pane_id,
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
import { assertGate, emitGate, packageScripts, readText, releaseGateIds } from './lib/codex-sdk-gate-lib.js';
|
|
4
4
|
const scripts = packageScripts();
|
|
5
5
|
const releaseRealCheck = String(scripts['release:real-check'] || '');
|
|
6
|
+
const releaseRealCheckSource = readText('src/scripts/release-real-check.ts');
|
|
6
7
|
const releaseGates = releaseGateIds();
|
|
7
8
|
assertGate(releaseGates.has('codex-sdk:capability'), 'release gate DAG must include Codex SDK capability gate');
|
|
8
9
|
assertGate(releaseGates.has('codex-sdk:all-pipelines'), 'release gate DAG must include Codex SDK all-pipelines gate');
|
|
9
|
-
assertGate(releaseRealCheck.includes('codex-sdk:real-smoke'), 'release:real-check must include Codex SDK real smoke');
|
|
10
|
+
assertGate(releaseRealCheck.includes('codex-sdk:real-smoke') || releaseRealCheckSource.includes('codex-sdk:real-smoke'), 'release:real-check must include Codex SDK real smoke');
|
|
10
11
|
assertGate(readText('src/core/agents/agent-orchestrator.ts').includes('legacy_codex_exec_runtime_removed'), 'orchestrator must block legacy codex-exec requests');
|
|
11
12
|
emitGate('codex-sdk:release-review-pipeline', { release_gate_dag_contains_sdk: true });
|
|
12
13
|
//# sourceMappingURL=codex-sdk-release-review-pipeline-check.js.map
|