sneakoscope 2.0.10 → 2.0.12

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 (65) hide show
  1. package/README.md +5 -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/cli/command-registry.js +1 -0
  9. package/dist/cli/install-helpers.js +8 -20
  10. package/dist/commands/doctor.js +5 -9
  11. package/dist/commands/zellij-slot-column-anchor.js +23 -0
  12. package/dist/core/agents/agent-orchestrator.js +338 -12
  13. package/dist/core/agents/agent-patch-schema.js +8 -1
  14. package/dist/core/agents/agent-scheduler.js +12 -1
  15. package/dist/core/agents/agent-slot-pane-binding-proof.js +3 -3
  16. package/dist/core/agents/agent-work-queue.js +26 -2
  17. package/dist/core/agents/agent-worker-pipeline.js +2 -0
  18. package/dist/core/agents/native-cli-session-swarm.js +2 -2
  19. package/dist/core/commands/naruto-command.js +191 -39
  20. package/dist/core/fsx.js +1 -1
  21. package/dist/core/git/git-worktree-checkpoint.js +52 -0
  22. package/dist/core/git/git-worktree-cross-rebase.js +54 -0
  23. package/dist/core/git/git-worktree-merge-queue.js +92 -3
  24. package/dist/core/git/git-worktree-patch-envelope.js +8 -1
  25. package/dist/core/init.js +2 -2
  26. package/dist/core/naruto/naruto-allocation-policy.js +99 -0
  27. package/dist/core/naruto/naruto-real-worker-child.js +110 -11
  28. package/dist/core/naruto/naruto-rebalance-policy.js +48 -0
  29. package/dist/core/naruto/naruto-task-hints.js +71 -0
  30. package/dist/core/naruto/naruto-work-graph.js +13 -0
  31. package/dist/core/pipeline/finalize-pipeline-result.js +3 -1
  32. package/dist/core/pipeline/gpt-final-required.js +22 -2
  33. package/dist/core/version.js +1 -1
  34. package/dist/core/zellij/zellij-right-column-manager.js +45 -2
  35. package/dist/core/zellij/zellij-slot-column-anchor.js +218 -0
  36. package/dist/core/zellij/zellij-worker-pane-manager.js +81 -14
  37. package/dist/scripts/agent-real-codex-in-zellij-worker-pane-check.js +8 -2
  38. package/dist/scripts/agent-slot-pane-binding-proof-check.js +4 -4
  39. package/dist/scripts/codex-sdk-release-review-pipeline-check.js +2 -1
  40. package/dist/scripts/codex-sdk-zellij-pane-binding-check.js +2 -2
  41. package/dist/scripts/git-worktree-checkpoint-check.js +20 -0
  42. package/dist/scripts/git-worktree-cross-rebase-check.js +39 -0
  43. package/dist/scripts/git-worktree-merge-queue-check.js +1 -0
  44. package/dist/scripts/local-collab-worktree-gpt-final-apply-policy-check.js +63 -0
  45. package/dist/scripts/naruto-actual-worker-control-plane-check.js +56 -0
  46. package/dist/scripts/naruto-allocation-policy-check.js +33 -0
  47. package/dist/scripts/naruto-allocation-runtime-wiring-check.js +92 -0
  48. package/dist/scripts/naruto-extreme-parallelism-real-check.js +5 -4
  49. package/dist/scripts/naruto-orchestrator-runtime-source-check.js +70 -0
  50. package/dist/scripts/naruto-real-active-pool-runtime-check.js +4 -2
  51. package/dist/scripts/naruto-rebalance-policy-check.js +41 -0
  52. package/dist/scripts/naruto-shadow-clone-swarm-check.js +8 -4
  53. package/dist/scripts/release-dag-full-coverage-check.js +19 -1
  54. package/dist/scripts/release-readiness-report.js +1 -1
  55. package/dist/scripts/release-real-check.js +258 -77
  56. package/dist/scripts/zellij-first-slot-down-stack-check.js +20 -0
  57. package/dist/scripts/zellij-first-slot-down-stack-real-check.js +356 -0
  58. package/dist/scripts/zellij-right-column-manager-check.js +7 -2
  59. package/dist/scripts/zellij-slot-column-anchor-check.js +45 -0
  60. package/dist/scripts/zellij-slot-only-ui-check.js +6 -2
  61. package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +59 -0
  62. package/dist/scripts/zellij-worker-pane-manager-check.js +23 -1
  63. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +11 -4
  64. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +21 -4
  65. package/package.json +15 -3
@@ -0,0 +1,218 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function renderZellijSlotColumnAnchor(input = {}) {
4
+ const active = nonNegativeInt(input.activeWorkers, 0);
5
+ const visible = Math.max(1, nonNegativeInt(input.visiblePaneCap, active || 1));
6
+ const headless = nonNegativeInt(input.headlessWorkers, 0);
7
+ const queue = nonNegativeInt(input.queueDepth, 0);
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;
12
+ const maxRows = Math.max(1, nonNegativeInt(input.maxWorkerRows, input.mode === 'full-debug' ? 24 : 12));
13
+ const visibleRows = workers.slice(0, maxRows);
14
+ const hidden = Math.max(0, workers.length - visibleRows.length);
15
+ return [
16
+ header,
17
+ ...visibleRows.map((row, index) => renderWorkerRow(row, index + 1)),
18
+ ...(hidden ? [`+${hidden} more worker${hidden === 1 ? '' : 's'}`] : [])
19
+ ].join('\n');
20
+ }
21
+ export async function renderZellijSlotColumnAnchorFromArtifacts(input) {
22
+ const root = path.resolve(input.artifactRoot);
23
+ const missionDir = inferMissionDir(root, input.missionId);
24
+ const snapshot = await readJson(path.join(missionDir, 'zellij-dashboard-snapshot.json'));
25
+ const rightColumn = await readJson(path.join(missionDir, 'zellij-right-column-state.json'));
26
+ const swarm = await readJson(path.join(root, 'agent-native-cli-session-swarm.json'))
27
+ || await readJson(path.join(missionDir, 'agents', 'agent-native-cli-session-swarm.json'));
28
+ const workerRows = await buildWorkerRows(root, missionDir, rightColumn, swarm);
29
+ const activeWorkers = Number(snapshot?.active_workers ?? workerRows.filter((row) => row.status === 'running' || row.status === 'launching').length ?? 0);
30
+ const visiblePaneCap = Number(snapshot?.visible_panes ?? Math.max(1, rightColumn?.visible_worker_panes?.length || activeWorkers || 1));
31
+ const headlessWorkers = Number(snapshot?.headless_workers ?? workerRows.filter((row) => row.placement === 'headless' && (!row.status || row.status === 'running')).length ?? 0);
32
+ const queueDepth = Number(snapshot?.queue_depth ?? 0);
33
+ const anchorInput = { activeWorkers, visiblePaneCap, headlessWorkers, queueDepth, workerRows };
34
+ if (input.mode !== undefined)
35
+ anchorInput.mode = input.mode;
36
+ return renderZellijSlotColumnAnchor(anchorInput);
37
+ }
38
+ export function buildZellijSlotColumnAnchorCommand(input) {
39
+ const args = [
40
+ input.cliPath,
41
+ 'zellij-slot-column-anchor',
42
+ '--mission', input.missionId,
43
+ '--mode', input.mode,
44
+ '--artifact-root', input.artifactRoot,
45
+ ...(input.watch ? ['--watch'] : [])
46
+ ];
47
+ return [input.nodePath || process.execPath, ...args].map(shellQuote).join(' ');
48
+ }
49
+ function inferMissionDir(root, missionId) {
50
+ if (path.basename(root) === 'agents' && path.basename(path.dirname(root)) === missionId)
51
+ return path.dirname(root);
52
+ if (path.basename(root) === missionId && path.basename(path.dirname(root)) === 'missions')
53
+ return root;
54
+ return path.join(root, '.sneakoscope', 'missions', missionId);
55
+ }
56
+ async function readJson(file) {
57
+ try {
58
+ return JSON.parse(await fs.promises.readFile(file, 'utf8'));
59
+ }
60
+ catch {
61
+ return null;
62
+ }
63
+ }
64
+ async function buildWorkerRows(root, missionDir, rightColumn, swarm) {
65
+ const byKey = new Map();
66
+ const records = Array.isArray(swarm?.records) ? swarm.records : [];
67
+ const recordByKey = new Map();
68
+ for (const record of records) {
69
+ const key = workerKey(record?.slot_id, record?.generation_index);
70
+ if (key)
71
+ recordByKey.set(key, record);
72
+ }
73
+ for (const pane of Array.isArray(rightColumn?.visible_worker_panes) ? rightColumn.visible_worker_panes : []) {
74
+ const key = workerKey(pane?.slot_id, pane?.generation_index);
75
+ if (!key)
76
+ continue;
77
+ const record = recordByKey.get(key);
78
+ byKey.set(key, await hydrateWorkerRow(root, missionDir, {
79
+ slotId: String(pane.slot_id),
80
+ generationIndex: Number(pane.generation_index || 1),
81
+ placement: 'zellij-pane',
82
+ status: pane.status || record?.status || 'running',
83
+ paneId: pane.pane_id || record?.zellij_pane_id || null,
84
+ yOrder: Number(pane.y_order || 0)
85
+ }, record));
86
+ }
87
+ for (const row of Array.isArray(rightColumn?.headless_workers) ? rightColumn.headless_workers : []) {
88
+ const key = workerKey(row?.slot_id, row?.generation_index);
89
+ if (!key)
90
+ continue;
91
+ const record = recordByKey.get(key);
92
+ byKey.set(key, await hydrateWorkerRow(root, missionDir, {
93
+ slotId: String(row.slot_id),
94
+ generationIndex: Number(row.generation_index || 1),
95
+ placement: 'headless',
96
+ status: row.status || record?.status || 'running',
97
+ reason: row.reason || record?.headless_reason || null,
98
+ yOrder: 9000
99
+ }, record));
100
+ }
101
+ for (const record of records) {
102
+ const key = workerKey(record?.slot_id, record?.generation_index);
103
+ if (!key || byKey.has(key))
104
+ continue;
105
+ byKey.set(key, await hydrateWorkerRow(root, missionDir, {
106
+ slotId: String(record.slot_id || record.agent_id || 'slot-?'),
107
+ generationIndex: Number(record.generation_index || 1),
108
+ placement: record.worker_placement || (record.zellij_pane_id ? 'zellij-pane' : 'process'),
109
+ status: record.status || 'running',
110
+ paneId: record.zellij_pane_id || null,
111
+ yOrder: 5000
112
+ }, record));
113
+ }
114
+ return [...byKey.values()].sort((a, b) => {
115
+ const statusDelta = statusWeight(a.status) - statusWeight(b.status);
116
+ if (statusDelta)
117
+ return statusDelta;
118
+ const yDelta = Number(a.yOrder || 0) - Number(b.yOrder || 0);
119
+ if (yDelta)
120
+ return yDelta;
121
+ return String(a.slotId).localeCompare(String(b.slotId));
122
+ });
123
+ }
124
+ async function hydrateWorkerRow(root, missionDir, base, record) {
125
+ const artifactDir = resolveArtifactDir(root, missionDir, record?.worker_artifact_dir);
126
+ const result = artifactDir ? await readJson(path.join(artifactDir, 'worker-result.json')) : null;
127
+ const intake = artifactDir ? await readJson(path.join(artifactDir, 'worker-intake.json')) : null;
128
+ const heartbeatPath = artifactDir ? path.join(artifactDir, 'worker-heartbeat.jsonl') : null;
129
+ return {
130
+ ...base,
131
+ status: result?.status || base.status || record?.status || 'running',
132
+ backend: result?.backend || record?.backend || intake?.backend || null,
133
+ role: result?.persona_id || intake?.agent?.naruto_role || intake?.agent?.role || intake?.agent?.persona_id || null,
134
+ task: firstText([
135
+ result?.summary,
136
+ Array.isArray(result?.changed_files) ? result.changed_files[0] : null,
137
+ intake?.slice?.description,
138
+ intake?.slice?.title,
139
+ intake?.slice?.id,
140
+ base.reason
141
+ ]),
142
+ worktreeId: result?.worktree?.id || record?.worktree?.id || intake?.worktree?.id || null,
143
+ heartbeatAgeMs: heartbeatPath ? await heartbeatAgeMs(heartbeatPath) : null
144
+ };
145
+ }
146
+ function renderWorkerRow(row, index) {
147
+ const slot = `${trimInline(row.slotId || 'slot-?', 12)} g${Math.max(1, Math.floor(Number(row.generationIndex) || 1))}`;
148
+ const status = trimInline(row.status || 'running', 9);
149
+ const backend = trimInline(row.backend || row.placement || '-', 12);
150
+ const worktree = trimInline(row.worktreeId || row.role || '-', 10);
151
+ const task = trimInline(row.task || row.reason || '-', 38);
152
+ return `${String(index).padStart(2, '0')} ${slot} ${status} ${backend} ${worktree} · ${task} · hb ${formatHeartbeat(row.heartbeatAgeMs)}`;
153
+ }
154
+ function resolveArtifactDir(root, missionDir, value) {
155
+ if (!value)
156
+ return null;
157
+ const text = String(value);
158
+ if (path.isAbsolute(text))
159
+ return text;
160
+ return path.join(root, text);
161
+ }
162
+ async function heartbeatAgeMs(file) {
163
+ try {
164
+ return Date.now() - (await fs.promises.stat(file)).mtimeMs;
165
+ }
166
+ catch {
167
+ return null;
168
+ }
169
+ }
170
+ function formatHeartbeat(ageMs) {
171
+ if (ageMs == null)
172
+ return '?';
173
+ if (ageMs < 1000)
174
+ return 'now';
175
+ return `${Math.max(1, Math.round(ageMs / 1000))}s`;
176
+ }
177
+ function firstText(values) {
178
+ for (const value of values) {
179
+ const text = String(value || '').replace(/\s+/g, ' ').trim();
180
+ if (text)
181
+ return text;
182
+ }
183
+ return null;
184
+ }
185
+ function workerKey(slotId, generationIndex) {
186
+ const slot = String(slotId || '').trim();
187
+ if (!slot)
188
+ return null;
189
+ return `${slot}:g${Math.max(1, Math.floor(Number(generationIndex) || 1))}`;
190
+ }
191
+ function statusWeight(status) {
192
+ const text = String(status || '').toLowerCase();
193
+ if (text === 'running' || text === 'launching')
194
+ return 0;
195
+ if (text === 'failed')
196
+ return 1;
197
+ if (text === 'draining')
198
+ return 2;
199
+ if (text === 'closed')
200
+ return 3;
201
+ return 4;
202
+ }
203
+ function nonNegativeInt(value, fallback) {
204
+ const parsed = Number(value);
205
+ if (!Number.isFinite(parsed) || parsed < 0)
206
+ return fallback;
207
+ return Math.floor(parsed);
208
+ }
209
+ function trimInline(value, max) {
210
+ const text = String(value || '').replace(/\s+/g, ' ').trim();
211
+ if (text.length <= max)
212
+ return text;
213
+ return text.slice(0, Math.max(1, max - 3)) + '...';
214
+ }
215
+ function shellQuote(value) {
216
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
217
+ }
218
+ //# sourceMappingURL=zellij-slot-column-anchor.js.map
@@ -4,7 +4,8 @@ import { providerPaneLabel } from '../provider/provider-badge.js';
4
4
  import { resolveProviderContext } from '../provider/provider-context.js';
5
5
  import { runZellij } from './zellij-command.js';
6
6
  import { extractZellijPaneIdFromOutput } from './zellij-lane-runtime.js';
7
- import { closeWorkerInRightColumn, prepareWorkerInRightColumn, recordWorkerPaneInRightColumn } from './zellij-right-column-manager.js';
7
+ import { buildZellijSlotColumnAnchorCommand } from './zellij-slot-column-anchor.js';
8
+ import { closeWorkerInRightColumn, prepareWorkerInRightColumn, recordSlotColumnAnchorInRightColumn, recordWorkerPaneInRightColumn } from './zellij-right-column-manager.js';
8
9
  export const ZELLIJ_WORKER_PANE_SCHEMA = 'sks.zellij-worker-pane.v1';
9
10
  export const ZELLIJ_WORKER_PANE_EVENT_SCHEMA = 'sks.zellij-worker-pane-event.v1';
10
11
  export function buildWorkerPaneName(slotId, generationIndex) {
@@ -25,6 +26,14 @@ export function buildWorkerPaneArtifact(input) {
25
26
  const blockers = input.blockers || [];
26
27
  const providerContext = normalizePaneProviderContext(input.providerContext, input.serviceTier);
27
28
  const paneTitle = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || input.status, input.worktree || null);
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';
36
+ const directionApplied = input.directionApplied || 'not_applied';
28
37
  return {
29
38
  schema: ZELLIJ_WORKER_PANE_SCHEMA,
30
39
  generated_at: now,
@@ -38,7 +47,7 @@ export function buildWorkerPaneArtifact(input) {
38
47
  session_id: input.sessionId,
39
48
  pane_name: paneTitle,
40
49
  pane_title: paneTitle,
41
- pane_kind: 'worker_codex_sdk',
50
+ pane_kind: paneKind,
42
51
  pane_id: input.paneId || null,
43
52
  pane_id_source: paneIdSource,
44
53
  provider: providerContext.provider,
@@ -52,16 +61,21 @@ export function buildWorkerPaneArtifact(input) {
52
61
  stdout_log: input.stdoutLog,
53
62
  stderr_log: input.stderrLog,
54
63
  parent_child_transport: 'worker-result-json-and-heartbeat',
55
- scaling_primitive: input.scalingPrimitive || 'native_cli_process_in_zellij_worker_pane',
56
- 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>',
57
66
  create_session: input.createSession || null,
58
67
  launch: input.launch || null,
59
68
  pane_reconciliation: input.paneReconciliation || null,
60
69
  opened_at: now,
61
70
  closed_at: null,
62
71
  close: null,
63
- direction_requested: input.directionRequested || 'right',
64
- direction_applied: input.directionApplied || 'not_applied',
72
+ direction_requested: directionRequested,
73
+ direction_applied: directionApplied,
74
+ column_creation_direction_requested: input.columnCreationDirectionRequested ?? null,
75
+ column_creation_direction_applied: input.columnCreationDirectionApplied ?? null,
76
+ worker_direction_requested: input.workerDirectionRequested || 'down',
77
+ worker_direction_applied: input.workerDirectionApplied || (directionApplied === 'down' ? 'down' : directionApplied === 'unknown' ? 'unknown' : 'not_applied'),
78
+ slot_column_anchor_pane_id: input.slotColumnAnchorPaneId || null,
65
79
  right_column: input.rightColumn || null,
66
80
  sdk_thread_id: input.sdkThreadId || null,
67
81
  sdk_run_id: input.sdkRunId || null,
@@ -113,12 +127,18 @@ export async function openWorkerPane(input) {
113
127
  createSession,
114
128
  launch: null,
115
129
  paneReconciliation: null,
116
- directionRequested: 'right',
130
+ directionRequested: 'down',
117
131
  directionApplied: 'not_applied',
132
+ columnCreationDirectionRequested: null,
133
+ columnCreationDirectionApplied: 'not_applied',
134
+ workerDirectionRequested: 'down',
135
+ workerDirectionApplied: 'not_applied',
136
+ slotColumnAnchorPaneId: rightColumn.state.slot_column_anchor_pane_id || null,
118
137
  rightColumn: {
119
138
  mode: 'spawn-on-first-worker',
120
139
  focus_pane_id: null,
121
- y_order: null
140
+ y_order: null,
141
+ slot_column_anchor_pane_id: rightColumn.state.slot_column_anchor_pane_id || null
122
142
  },
123
143
  status: 'running',
124
144
  providerContext,
@@ -135,9 +155,42 @@ export async function openWorkerPane(input) {
135
155
  return record;
136
156
  }
137
157
  const paneName = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || 'running', input.worktree || null);
138
- const directionRequested = rightColumn?.focusPaneId ? 'down' : 'right';
139
- const focus = rightColumn?.focusPaneId
140
- ? await focusZellijPaneById(input.sessionName, rightColumn.focusPaneId, cwd)
158
+ let slotColumnAnchorPaneId = rightColumn?.state.slot_column_anchor_pane_id || null;
159
+ let anchorLaunch = null;
160
+ let columnCreationDirectionRequested = null;
161
+ let columnCreationDirectionApplied = null;
162
+ if (rightColumn && !rightColumn.focusPaneId && !slotColumnAnchorPaneId) {
163
+ columnCreationDirectionRequested = 'right';
164
+ const anchorCommand = buildZellijSlotColumnAnchorCommand({
165
+ cliPath: path.join(packageRoot(), 'dist', 'bin', 'sks.js'),
166
+ missionId: input.missionId,
167
+ mode: input.uiMode || 'compact-slots',
168
+ artifactRoot: root,
169
+ watch: true
170
+ });
171
+ anchorLaunch = createSession.ok
172
+ ? await runZellij(['--session', input.sessionName, 'action', 'new-pane', '--direction', 'right', '--name', 'SLOTS', '--', 'sh', '-lc', anchorCommand], {
173
+ cwd,
174
+ timeoutMs: 5000,
175
+ optional: false
176
+ })
177
+ : null;
178
+ slotColumnAnchorPaneId = anchorLaunch?.ok ? extractZellijPaneIdFromOutput(anchorLaunch.stdout_tail) : null;
179
+ columnCreationDirectionApplied = anchorLaunch?.ok ? (slotColumnAnchorPaneId ? 'right' : 'unknown') : 'not_applied';
180
+ if (slotColumnAnchorPaneId) {
181
+ await recordSlotColumnAnchorInRightColumn({
182
+ root,
183
+ ...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
184
+ missionId: input.missionId,
185
+ sessionName: input.sessionName,
186
+ paneId: slotColumnAnchorPaneId
187
+ });
188
+ }
189
+ }
190
+ const focusPaneId = rightColumn?.focusPaneId || slotColumnAnchorPaneId || null;
191
+ const directionRequested = 'down';
192
+ const focus = focusPaneId
193
+ ? await focusZellijPaneById(input.sessionName, focusPaneId, cwd)
141
194
  : null;
142
195
  const newPaneArgs = ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, ...(directionRequested === 'down' ? ['--near-current-pane'] : []), '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
143
196
  let launch = createSession.ok
@@ -176,6 +229,8 @@ export async function openWorkerPane(input) {
176
229
  const blockers = [
177
230
  ...(createSession.ok ? [] : createSession.blockers.map((blocker) => `zellij_worker_session_${blocker}`)),
178
231
  ...(rightColumn && rightColumn.placement !== 'zellij-pane' ? [`zellij_worker_right_column_${rightColumn.placement}`] : []),
232
+ ...(rightColumn && columnCreationDirectionRequested === 'right' && columnCreationDirectionApplied !== 'right' ? ['zellij_worker_slot_column_anchor_not_created'] : []),
233
+ ...(anchorLaunch && !anchorLaunch.ok ? anchorLaunch.blockers.map((blocker) => `zellij_worker_slot_column_anchor_${blocker}`) : []),
179
234
  ...(launch && !launch.ok ? launch.blockers.map((blocker) => `zellij_worker_pane_${blocker}`) : []),
180
235
  ...(launch?.ok && !isRealZellijWorkerPaneIdSource(paneIdSource) ? ['zellij_worker_pane_id_real_source_missing'] : [])
181
236
  ];
@@ -189,11 +244,18 @@ export async function openWorkerPane(input) {
189
244
  ...(reconciledPane || {}),
190
245
  focus_pane: focus,
191
246
  focus_degraded: focus ? focus.ok !== true : false,
247
+ slot_column_anchor_pane_id: slotColumnAnchorPaneId,
248
+ slot_column_anchor_launch: anchorLaunch,
192
249
  rename_pane: renamePane
193
250
  },
194
251
  directionRequested,
195
252
  directionApplied,
196
- rightColumn: rightColumn ? { mode: 'spawn-on-first-worker', focus_pane_id: rightColumn.focusPaneId, y_order: rightColumn.yOrder } : null,
253
+ columnCreationDirectionRequested,
254
+ columnCreationDirectionApplied,
255
+ workerDirectionRequested: 'down',
256
+ workerDirectionApplied: directionApplied === 'down' ? 'down' : directionApplied === 'unknown' ? 'unknown' : 'not_applied',
257
+ slotColumnAnchorPaneId,
258
+ rightColumn: rightColumn ? { mode: 'spawn-on-first-worker', focus_pane_id: focusPaneId, y_order: rightColumn.yOrder, slot_column_anchor_pane_id: slotColumnAnchorPaneId } : null,
197
259
  status: blockers.length ? 'failed' : 'running',
198
260
  providerContext,
199
261
  serviceTier: input.serviceTier || providerContext.service_tier,
@@ -226,7 +288,7 @@ export async function openWorkerPane(input) {
226
288
  session_name: input.sessionName,
227
289
  pane_name: paneName,
228
290
  pane_title: paneName,
229
- pane_kind: 'worker_codex_sdk',
291
+ pane_kind: record.pane_kind,
230
292
  pane_id: record.pane_id,
231
293
  pane_id_source: record.pane_id_source,
232
294
  provider: record.provider,
@@ -234,6 +296,11 @@ export async function openWorkerPane(input) {
234
296
  provider_context: record.provider_context,
235
297
  direction_requested: record.direction_requested,
236
298
  direction_applied: record.direction_applied,
299
+ column_creation_direction_requested: record.column_creation_direction_requested || null,
300
+ column_creation_direction_applied: record.column_creation_direction_applied || null,
301
+ worker_direction_requested: record.worker_direction_requested,
302
+ worker_direction_applied: record.worker_direction_applied,
303
+ slot_column_anchor_pane_id: record.slot_column_anchor_pane_id || null,
237
304
  command: record.command,
238
305
  worker_artifact_dir: input.workerArtifactDir,
239
306
  worker_result_path: input.resultPath,
@@ -241,7 +308,7 @@ export async function openWorkerPane(input) {
241
308
  patch_envelope_path: input.patchEnvelopePath,
242
309
  parent_child_transport: 'worker-result-json-and-heartbeat',
243
310
  persistent_slot_lane: false,
244
- scaling_primitive: 'native_cli_process_in_zellij_worker_pane',
311
+ scaling_primitive: record.scaling_primitive,
245
312
  blockers
246
313
  });
247
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
@@ -7,7 +7,7 @@ const proofSource = readText('src/core/agents/agent-slot-pane-binding-proof.ts')
7
7
  const managerSource = readText('src/core/zellij/zellij-worker-pane-manager.ts');
8
8
  assertGate(fixture.proof.zellij_pane_id === 'pane-999', 'control proof must link zellij pane id', fixture.proof);
9
9
  assertGate(swarmSource.includes('codex_sdk_thread_started'), 'swarm must emit SDK thread event');
10
- assertGate(proofSource.includes('worker_codex_sdk'), 'slot-pane proof must require worker_codex_sdk pane kind');
11
- assertGate(managerSource.includes("pane_kind: 'worker_codex_sdk'"), 'worker pane manager must record worker_codex_sdk pane kind');
10
+ assertGate(proofSource.includes('worker_codex_sdk') && proofSource.includes('slot_status_renderer'), 'slot-pane proof must accept worker command panes and compact slot renderer panes');
11
+ assertGate(managerSource.includes('slot_status_renderer') && managerSource.includes('worker_codex_sdk'), 'worker pane manager must distinguish slot renderer and worker command pane kinds');
12
12
  emitGate('codex-sdk:zellij-pane-binding', { zellij_pane_id: fixture.proof.zellij_pane_id, sdk_thread_id: fixture.proof.sdk_thread_id });
13
13
  //# sourceMappingURL=codex-sdk-zellij-pane-binding-check.js.map
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
6
+ import { checkpointWorkerWorktree } from '../core/git/git-worktree-checkpoint.js';
7
+ import { runGitCommand } from '../core/git/git-worktree-runner.js';
8
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-worktree-checkpoint-'));
9
+ await runGitCommand(root, ['init']);
10
+ await runGitCommand(root, ['config', 'user.email', 'sks@example.test']);
11
+ await runGitCommand(root, ['config', 'user.name', 'SKS Test']);
12
+ fs.writeFileSync(path.join(root, 'a.txt'), 'a\n');
13
+ await runGitCommand(root, ['add', 'a.txt']);
14
+ await runGitCommand(root, ['commit', '-m', 'base']);
15
+ fs.writeFileSync(path.join(root, 'a.txt'), 'a2\n');
16
+ fs.writeFileSync(path.join(root, 'b.txt'), 'b\n');
17
+ const report = await checkpointWorkerWorktree({ worktreePath: root, repoRoot: root, workerId: 'W1', taskId: 'T1', mode: 'auto' });
18
+ assertGate(report.ok && report.mode_applied === 'checkpoint-commit' && Boolean(report.commit_hash), 'Git worktree checkpoint must create checkpoint commits for multi-file changes', report);
19
+ emitGate('git:worktree-checkpoint', report);
20
+ //# sourceMappingURL=git-worktree-checkpoint-check.js.map
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
6
+ import { crossRebaseIdleWorktrees } from '../core/git/git-worktree-cross-rebase.js';
7
+ import { runGitCommand, gitOutputLine } from '../core/git/git-worktree-runner.js';
8
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-worktree-cross-rebase-'));
9
+ await runGitCommand(root, ['init']);
10
+ await runGitCommand(root, ['config', 'user.email', 'sks@example.test']);
11
+ await runGitCommand(root, ['config', 'user.name', 'SKS Test']);
12
+ fs.writeFileSync(path.join(root, 'base.txt'), 'base\n');
13
+ await runGitCommand(root, ['add', 'base.txt']);
14
+ await runGitCommand(root, ['commit', '-m', 'base']);
15
+ const workerPath = path.join(root, '..', `worker-${process.pid}`);
16
+ const dirtyWorkerPath = path.join(root, '..', `worker-dirty-${process.pid}`);
17
+ const runningWorkerPath = path.join(root, '..', `worker-running-${process.pid}`);
18
+ await runGitCommand(root, ['worktree', 'add', workerPath, 'HEAD']);
19
+ await runGitCommand(root, ['worktree', 'add', dirtyWorkerPath, 'HEAD']);
20
+ await runGitCommand(root, ['worktree', 'add', runningWorkerPath, 'HEAD']);
21
+ fs.writeFileSync(path.join(dirtyWorkerPath, 'dirty.txt'), 'dirty\n');
22
+ fs.writeFileSync(path.join(root, 'integration.txt'), 'integration\n');
23
+ await runGitCommand(root, ['add', 'integration.txt']);
24
+ await runGitCommand(root, ['commit', '-m', 'integration']);
25
+ const head = gitOutputLine(await runGitCommand(root, ['rev-parse', 'HEAD']));
26
+ const report = await crossRebaseIdleWorktrees({
27
+ integrationHead: head,
28
+ workers: [
29
+ { worker_id: 'W1', worktree_path: workerPath, state: 'idle' },
30
+ { worker_id: 'W-dirty', worktree_path: dirtyWorkerPath, state: 'idle' },
31
+ { worker_id: 'W-running', worktree_path: runningWorkerPath, state: 'running' }
32
+ ]
33
+ });
34
+ assertGate(report.ok && report.applied_count === 1, 'Idle worktrees must cross-rebase to the integration head', report);
35
+ assertGate(report.skipped_count === 2, 'Dirty and running worktrees must be skipped during cross-rebase', report);
36
+ assertGate(report.records.some((row) => row.worker_id === 'W-dirty' && row.status === 'skipped' && row.reason === 'dirty_worktree_skipped'), 'Dirty worktree must skip cross-rebase', report);
37
+ assertGate(report.records.some((row) => row.worker_id === 'W-running' && row.status === 'skipped' && row.reason === 'worker_not_idle'), 'Running worktree must skip cross-rebase', report);
38
+ emitGate('git:worktree-cross-rebase', report);
39
+ //# sourceMappingURL=git-worktree-cross-rebase-check.js.map
@@ -20,6 +20,7 @@ const diffB = await diffMod.exportGitWorktreeDiff({ mainRepoRoot: repo, worktree
20
20
  const integration = await integrationMod.createGitIntegrationWorktree({ repoRoot: repo, missionId: 'M-merge' });
21
21
  const report = await queueMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: integration.worktree_path, diffs: [diffA, diffB] });
22
22
  assertGate(report.ok === true && report.applied_count === 2, 'merge queue must apply non-conflicting worktree diffs', report);
23
+ assertGate((report.strategy_results || []).every((row) => row.strategy === 'diff-apply-3way'), 'merge queue must record the diff apply strategy for worktree diffs', report.strategy_results || []);
23
24
  assertGate(fs.readFileSync(path.join(integration.worktree_path, 'a.txt'), 'utf8').includes('from-a'), 'integration worktree must include first diff');
24
25
  assertGate(fs.readFileSync(path.join(integration.worktree_path, 'b.txt'), 'utf8').includes('from-b'), 'integration worktree must include second diff');
25
26
  assertGate(fs.readFileSync(path.join(repo, 'a.txt'), 'utf8') === 'alpha\n', 'main worktree must remain unchanged before integration commit');
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ // @ts-nocheck
3
+ import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
4
+ import { gptFinalRequiredForPipeline } from '../core/pipeline/gpt-final-required.js';
5
+ import { finalizePipelineResult } from '../core/pipeline/finalize-pipeline-result.js';
6
+ import { selectFinalGptPatchSource } from '../core/pipeline/final-gpt-patch-stage.js';
7
+ const worktreeEnvelope = {
8
+ schema: 'sks.agent-patch-envelope.v1',
9
+ source: 'git-worktree-diff',
10
+ git_worktree: {
11
+ worktree_path: '/tmp/sks-worker',
12
+ changed_files: ['src/core/example.ts']
13
+ },
14
+ operations: [{ op: 'git_apply_patch', path: '.', diff: 'diff --git a/src/core/example.ts b/src/core/example.ts\n' }]
15
+ };
16
+ const requirement = gptFinalRequiredForPipeline({
17
+ localParticipated: false,
18
+ candidateResults: [{ backend: 'codex-sdk', patch_envelopes: [worktreeEnvelope] }],
19
+ candidatePatchEnvelopes: [worktreeEnvelope]
20
+ });
21
+ const blocked = await finalizePipelineResult({
22
+ route: '$Naruto',
23
+ missionId: 'M-worktree-gpt-final-policy',
24
+ localParticipated: false,
25
+ candidateResults: [{ backend: 'codex-sdk', patch_envelopes: [worktreeEnvelope] }],
26
+ candidatePatchEnvelopes: [worktreeEnvelope],
27
+ verificationResults: [],
28
+ sideEffectReport: {},
29
+ mutationLedger: {},
30
+ rollbackPlan: {},
31
+ applyPatches: true,
32
+ forceGptFinalUnavailable: true
33
+ });
34
+ const modified = selectFinalGptPatchSource({
35
+ result: {
36
+ status: 'modified',
37
+ modified_patch_envelopes: [{ ...worktreeEnvelope, source: 'model_authored', operations: [{ op: 'replace', path: 'src/core/example.ts', search: 'old', replace: 'new' }] }]
38
+ }
39
+ }, [worktreeEnvelope]);
40
+ const rejected = selectFinalGptPatchSource({ result: { status: 'rejected' } }, [worktreeEnvelope]);
41
+ const ok = requirement.gpt_final_required === true
42
+ && requirement.worktree_participated === true
43
+ && blocked.ok === false
44
+ && blocked.apply_allowed === false
45
+ && blocked.blockers.includes('gpt_final_arbiter_required_not_passed')
46
+ && modified.ok === true
47
+ && modified.final_patch_source === 'gpt_final_arbiter'
48
+ && modified.patch_envelopes[0]?.source === 'model_authored'
49
+ && rejected.ok === false
50
+ && rejected.final_patch_source === 'blocked';
51
+ assertGate(ok, 'Worktree/local candidate output must require GPT Final before apply, and GPT modified/rejected decisions must control final patch source', {
52
+ requirement,
53
+ blocked,
54
+ modified,
55
+ rejected
56
+ });
57
+ emitGate('local-collab:worktree-gpt-final-apply-policy', {
58
+ requirement,
59
+ blocked_apply_allowed: blocked.apply_allowed,
60
+ modified_source: modified.final_patch_source,
61
+ rejected_source: rejected.final_patch_source
62
+ });
63
+ //# sourceMappingURL=local-collab-worktree-gpt-final-apply-policy-check.js.map