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.
Files changed (75) hide show
  1. package/README.md +9 -3
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/build-manifest.json +27 -8
  8. package/dist/core/agents/agent-orchestrator.js +279 -1
  9. package/dist/core/agents/agent-scheduler.js +12 -1
  10. package/dist/core/agents/agent-slot-pane-binding-proof.js +3 -3
  11. package/dist/core/agents/agent-work-queue.js +26 -2
  12. package/dist/core/agents/agent-worker-pipeline.js +2 -0
  13. package/dist/core/agents/native-cli-session-swarm.js +2 -2
  14. package/dist/core/codex-control/codex-sdk-adapter.js +10 -0
  15. package/dist/core/codex-control/codex-task-runner.js +4 -2
  16. package/dist/core/commands/naruto-command.js +104 -51
  17. package/dist/core/commands/research-command.js +43 -4
  18. package/dist/core/fsx.js +1 -1
  19. package/dist/core/git/git-worktree-merge-queue.js +34 -14
  20. package/dist/core/naruto/naruto-rebalance-policy.js +15 -3
  21. package/dist/core/naruto/naruto-work-graph.js +13 -0
  22. package/dist/core/research/claim-evidence-matrix.js +160 -0
  23. package/dist/core/research/experiment-plan.js +53 -0
  24. package/dist/core/research/falsification.js +18 -0
  25. package/dist/core/research/implementation-blueprint-markdown.js +31 -0
  26. package/dist/core/research/implementation-blueprint.js +66 -0
  27. package/dist/core/research/replication-pack.js +50 -0
  28. package/dist/core/research/research-cycle-runner.js +25 -0
  29. package/dist/core/research/research-final-reviewer.js +58 -0
  30. package/dist/core/research/research-handoff.js +51 -0
  31. package/dist/core/research/research-prompt-contract.js +24 -0
  32. package/dist/core/research/research-quality-contract.js +61 -0
  33. package/dist/core/research/research-report-quality.js +67 -0
  34. package/dist/core/research/research-stage-runner.js +16 -0
  35. package/dist/core/research/research-work-graph.js +75 -0
  36. package/dist/core/research/source-quality-report.js +94 -0
  37. package/dist/core/research.js +344 -44
  38. package/dist/core/version.js +1 -1
  39. package/dist/core/zellij/zellij-slot-column-anchor.js +165 -4
  40. package/dist/core/zellij/zellij-slot-pane-renderer.js +259 -16
  41. package/dist/core/zellij/zellij-worker-pane-manager.js +13 -7
  42. package/dist/scripts/agent-real-codex-in-zellij-worker-pane-check.js +8 -2
  43. package/dist/scripts/agent-slot-pane-binding-proof-check.js +4 -4
  44. package/dist/scripts/codex-sdk-release-review-pipeline-check.js +2 -1
  45. package/dist/scripts/codex-sdk-research-pipeline-check.js +7 -0
  46. package/dist/scripts/codex-sdk-zellij-pane-binding-check.js +2 -2
  47. package/dist/scripts/git-worktree-cross-rebase-check.js +13 -1
  48. package/dist/scripts/git-worktree-merge-queue-check.js +1 -0
  49. package/dist/scripts/local-collab-worktree-gpt-final-apply-policy-check.js +63 -0
  50. package/dist/scripts/naruto-actual-worker-control-plane-check.js +30 -3
  51. package/dist/scripts/naruto-allocation-runtime-wiring-check.js +92 -0
  52. package/dist/scripts/naruto-orchestrator-runtime-source-check.js +65 -6
  53. package/dist/scripts/naruto-rebalance-policy-check.js +15 -2
  54. package/dist/scripts/naruto-shadow-clone-swarm-check.js +1 -1
  55. package/dist/scripts/packlist-performance-check.js +1 -1
  56. package/dist/scripts/release-dag-full-coverage-check.js +4 -0
  57. package/dist/scripts/release-real-check.js +258 -77
  58. package/dist/scripts/research-quality-gate-check.js +86 -0
  59. package/dist/scripts/zellij-first-slot-down-stack-check.js +1 -1
  60. package/dist/scripts/zellij-first-slot-down-stack-real-check.js +344 -4
  61. package/dist/scripts/zellij-right-column-manager-check.js +1 -1
  62. package/dist/scripts/zellij-slot-column-anchor-check.js +45 -3
  63. package/dist/scripts/zellij-slot-only-ui-check.js +3 -1
  64. package/dist/scripts/zellij-slot-pane-renderer-check.js +73 -5
  65. package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +59 -0
  66. package/dist/scripts/zellij-worker-pane-manager-check.js +23 -1
  67. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +21 -4
  68. package/package.json +17 -2
  69. package/schemas/research/claim-evidence-matrix.schema.json +37 -0
  70. package/schemas/research/experiment-plan.schema.json +17 -0
  71. package/schemas/research/implementation-blueprint.schema.json +30 -0
  72. package/schemas/research/replication-pack.schema.json +17 -0
  73. package/schemas/research/research-final-review.schema.json +16 -0
  74. package/schemas/research/research-quality-contract.schema.json +37 -0
  75. package/schemas/research/source-quality-report.schema.json +18 -0
@@ -1,2 +1,2 @@
1
- export const PACKAGE_VERSION = '2.0.11';
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
- return `SLOTS active ${active}/${visible} · headless ${headless} · q ${queue}`;
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 activeWorkers = Number(snapshot?.active_workers ?? rightColumn?.visible_worker_panes?.filter((row) => row?.status === 'running' || row?.status === 'launching').length ?? 0);
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 ?? rightColumn?.headless_workers?.filter((row) => !row?.status || row?.status === 'running').length ?? 0);
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' ? 5 : mode === 'dashboard-plus-slots' ? 8 : 20;
6
- const task = trimInline(input.currentFile || input.currentTask || '-', 56);
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
- `${input.slotId} gen-${Math.max(1, Math.floor(Number(input.generationIndex) || 1))}`,
14
- `${trimInline(input.role || 'worker', 18)} - ${trimInline(input.backend || 'codex-sdk', 18)} - ${trimInline(input.worktreeId || '-', 18)}`,
15
- `status: ${trimInline(input.status || 'running', 14)} ${task}`,
16
- `patch: ${trimInline(input.patchStatus || 'queued', 18)} verify: ${trimInline(input.verifyStatus || 'queued', 18)}`,
17
- `heartbeat: ${heartbeat}`
18
- ];
19
- return rows.slice(0, maxLines).join('\n');
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
- role: input.role || result?.persona_id || result?.agent_id || null,
31
- backend: input.backend || result?.backend || null,
32
- status: result?.status || (heartbeatMtime ? 'running' : 'launching'),
33
- currentTask: result?.summary || null,
34
- currentFile: Array.isArray(result?.changed_files) ? result.changed_files[0] : null,
35
- patchStatus: Array.isArray(result?.patch_envelopes) && result.patch_envelopes.length ? 'candidate' : 'queued',
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
- worktreeId: result?.worktree?.id || null,
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 directionRequested = input.directionRequested || 'right';
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: 'worker_codex_sdk',
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: input.scalingPrimitive || 'native_cli_process_in_zellij_worker_pane',
59
- command: String(input.workerCommand || '').includes('zellij-slot-pane') ? '<zellij-slot-pane-renderer-command>' : '<native-cli-worker-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 = rightColumn ? 'down' : 'right';
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: 'worker_codex_sdk',
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: 'native_cli_process_in_zellij_worker_pane',
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((row) => row.scaling_primitive === 'native_cli_process_in_zellij_worker_pane');
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: 'worker_codex_sdk',
38
+ pane_kind: record.pane_kind,
39
39
  persistent_slot_lane: false,
40
- scaling_primitive: 'native_cli_process_in_zellij_worker_pane',
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