sneakoscope 2.0.8 → 2.0.10

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 (76) hide show
  1. package/README.md +8 -4
  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 +33 -8
  8. package/dist/cli/command-registry.js +1 -0
  9. package/dist/commands/doctor.js +18 -1
  10. package/dist/commands/zellij-slot-pane.js +26 -0
  11. package/dist/commands/zellij.js +144 -1
  12. package/dist/core/agents/agent-orchestrator.js +202 -9
  13. package/dist/core/agents/agent-role-config.js +92 -0
  14. package/dist/core/agents/native-cli-session-swarm.js +230 -48
  15. package/dist/core/commands/mad-sks-command.js +17 -26
  16. package/dist/core/commands/naruto-command.js +155 -37
  17. package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
  18. package/dist/core/fsx.js +1 -1
  19. package/dist/core/hooks-runtime.js +4 -0
  20. package/dist/core/init.js +1 -0
  21. package/dist/core/naruto/naruto-active-pool.js +141 -0
  22. package/dist/core/naruto/naruto-concurrency-governor.js +17 -2
  23. package/dist/core/naruto/naruto-real-worker-child.js +35 -0
  24. package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
  25. package/dist/core/naruto/naruto-work-graph.js +2 -1
  26. package/dist/core/release/release-gate-cache-v2.js +58 -4
  27. package/dist/core/release/release-gate-dag.js +36 -25
  28. package/dist/core/version.js +1 -1
  29. package/dist/core/zellij/zellij-dashboard-renderer.js +22 -6
  30. package/dist/core/zellij/zellij-launcher.js +3 -3
  31. package/dist/core/zellij/zellij-layout-builder.js +1 -1
  32. package/dist/core/zellij/zellij-right-column-layout-proof.js +42 -0
  33. package/dist/core/zellij/zellij-right-column-manager.js +304 -0
  34. package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
  35. package/dist/core/zellij/zellij-ui-mode.js +16 -0
  36. package/dist/core/zellij/zellij-worker-pane-manager.js +152 -17
  37. package/dist/scripts/agent-role-config-repair-check.js +33 -0
  38. package/dist/scripts/codex-sdk-release-review-pipeline-check.js +5 -5
  39. package/dist/scripts/doctor-fix-proves-codex-read-check.js +26 -5
  40. package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
  41. package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
  42. package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
  43. package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +2 -2
  44. package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
  45. package/dist/scripts/naruto-concurrency-governor-check.js +2 -1
  46. package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
  47. package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
  48. package/dist/scripts/naruto-real-active-pool-check.js +39 -0
  49. package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
  50. package/dist/scripts/naruto-work-graph-check.js +1 -1
  51. package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +48 -0
  52. package/dist/scripts/product-design-auto-install-check.js +3 -3
  53. package/dist/scripts/product-design-plugin-routing-check.js +3 -3
  54. package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
  55. package/dist/scripts/release-cache-glob-hashing-check.js +42 -0
  56. package/dist/scripts/release-check-dynamic-execute.js +27 -1
  57. package/dist/scripts/release-check-dynamic.js +38 -11
  58. package/dist/scripts/release-check-stamp.js +7 -2
  59. package/dist/scripts/release-dag-full-coverage-check.js +35 -0
  60. package/dist/scripts/release-dynamic-performance-check.js +31 -1
  61. package/dist/scripts/release-gate-existence-audit.js +29 -33
  62. package/dist/scripts/release-parallel-speed-budget-check.js +67 -13
  63. package/dist/scripts/release-readiness-report.js +14 -3
  64. package/dist/scripts/zellij-dashboard-pane-check.js +6 -4
  65. package/dist/scripts/zellij-developer-controls-check.js +20 -0
  66. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +21 -0
  67. package/dist/scripts/zellij-initial-main-only-blackbox.js +28 -0
  68. package/dist/scripts/zellij-right-column-geometry-proof.js +162 -0
  69. package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
  70. package/dist/scripts/zellij-right-column-manager-check.js +22 -0
  71. package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
  72. package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
  73. package/dist/scripts/zellij-worker-pane-manager-check.js +2 -1
  74. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +7 -6
  75. package/package.json +23 -5
  76. package/schemas/zellij/zellij-right-column-state.schema.json +41 -0
@@ -5,7 +5,10 @@ import { appendJsonl, ensureDir, exists, nowIso, packageRoot, readJson, writeJso
5
5
  import { fastModeEnv } from './fast-mode-policy.js';
6
6
  import { validateAgentWorkerResult } from './agent-worker-pipeline.js';
7
7
  import { closeWorkerPane, openWorkerPane } from '../zellij/zellij-worker-pane-manager.js';
8
+ import { closeWorkerInRightColumn, recordHeadlessWorkerInRightColumn } from '../zellij/zellij-right-column-manager.js';
8
9
  import { resolveProviderContext } from '../provider/provider-context.js';
10
+ import { buildZellijSlotPaneCommand } from '../zellij/zellij-slot-pane-renderer.js';
11
+ import { resolveZellijUiMode } from '../zellij/zellij-ui-mode.js';
9
12
  export const NATIVE_CLI_SESSION_SWARM_SCHEMA = 'sks.agent-native-cli-session-swarm.v1';
10
13
  export function createNativeCliSessionSwarmRecorder(root, input) {
11
14
  return new NativeCliSessionSwarmRecorder(root, input);
@@ -18,6 +21,7 @@ class NativeCliSessionSwarmRecorder {
18
21
  maxObserved = 0;
19
22
  writeLock = Promise.resolve();
20
23
  nextPaneToken = -1;
24
+ visibleZellijReservations = new Set();
21
25
  constructor(root, input) {
22
26
  this.root = root;
23
27
  this.input = input;
@@ -102,9 +106,12 @@ class NativeCliSessionSwarmRecorder {
102
106
  const stdout = fs.createWriteStream(path.join(this.root, stdoutRel), { flags: 'a' });
103
107
  const stderr = fs.createWriteStream(path.join(this.root, stderrRel), { flags: 'a' });
104
108
  const placement = String(ctx.opts.workerPlacement || this.input.workerPlacement || (this.input.backend === 'zellij' ? 'zellij-pane' : 'process'));
105
- const useZellijPane = placement === 'zellij-pane'
109
+ const zellijReservation = placement === 'zellij-pane'
106
110
  && ctx.opts.zellijPaneWorker !== false
107
- && (ctx.opts.zellijSessionName || this.input.missionId);
111
+ && (ctx.opts.zellijSessionName || this.input.missionId)
112
+ ? this.reserveVisibleZellijPane(ctx.opts, String(ctx.agent.session_id || ctx.agent.id || `${Date.now()}:${Math.random()}`))
113
+ : null;
114
+ const useZellijPane = Boolean(zellijReservation);
108
115
  if (useZellijPane) {
109
116
  stdout.end();
110
117
  stderr.end();
@@ -116,9 +123,26 @@ class NativeCliSessionSwarmRecorder {
116
123
  stdoutRel,
117
124
  stderrRel,
118
125
  heartbeatRel,
119
- workerDirRel
126
+ workerDirRel,
127
+ zellijReservation
120
128
  });
121
129
  }
130
+ if (placement === 'zellij-pane' && ctx.opts.zellijPaneWorker !== false && !useZellijPane) {
131
+ record.worker_placement = 'headless';
132
+ record.headless_reason = `visible_pane_cap:${this.zellijVisiblePaneCap(ctx.opts)}`;
133
+ await recordHeadlessWorkerInRightColumn({
134
+ root: this.root,
135
+ projectRoot: ctx.opts.projectRoot || this.input.projectRoot || ctx.opts.cwd,
136
+ missionId: this.input.missionId,
137
+ sessionName: String(ctx.opts.zellijSessionName || (this.input.missionId ? `sks-${this.input.missionId}` : 'sks-agent-runtime')),
138
+ slotId: String(ctx.agent.slot_id || ctx.agent.id || 'slot-001'),
139
+ generationIndex: Number(ctx.agent.generation_index || 1),
140
+ reason: record.headless_reason
141
+ }).catch(() => null);
142
+ }
143
+ else {
144
+ record.worker_placement = placement === 'zellij-pane' ? 'zellij-pane' : 'process';
145
+ }
122
146
  const child = spawn(process.execPath, args, {
123
147
  cwd: workerCwd,
124
148
  env: {
@@ -156,6 +180,17 @@ class NativeCliSessionSwarmRecorder {
156
180
  record.exit_code = exit.code;
157
181
  record.signal = exit.signal;
158
182
  record.status = exit.code === 0 ? 'closed' : 'failed';
183
+ if (record.worker_placement === 'headless') {
184
+ await closeWorkerInRightColumn({
185
+ root: this.root,
186
+ projectRoot: ctx.opts.projectRoot || this.input.projectRoot || ctx.opts.cwd,
187
+ missionId: this.input.missionId,
188
+ slotId: String(ctx.agent.slot_id || ctx.agent.id || 'slot-001'),
189
+ generationIndex: Number(ctx.agent.generation_index || 1),
190
+ paneId: null,
191
+ status: record.status === 'closed' ? 'closed' : 'failed'
192
+ }).catch(() => null);
193
+ }
159
194
  const parsed = await readJson(path.join(this.root, resultRel), null).catch(() => null);
160
195
  if (!parsed) {
161
196
  record.blockers = ['native_cli_worker_result_missing'];
@@ -194,54 +229,107 @@ class NativeCliSessionSwarmRecorder {
194
229
  const activeToken = this.nextPaneToken--;
195
230
  this.active.add(activeToken);
196
231
  this.maxObserved = Math.max(this.maxObserved, this.active.size);
197
- const workerCommand = buildPaneWorkerCommand({
198
- args: input.args,
199
- stdoutPath: path.join(this.root, input.stdoutRel),
200
- stderrPath: path.join(this.root, input.stderrRel),
201
- heartbeatPath: path.join(this.root, input.heartbeatRel),
202
- env: {
203
- ...(input.ctx.opts.env || {}),
204
- ...fastModeEnv(this.input.fastModePolicy),
205
- SKS_AGENT_WORKER: '1',
206
- SKS_PIPELINE_MODE: 'agent-worker',
207
- SKS_DISABLE_ROUTE_RECURSION: '1',
208
- SKS_PARENT_MISSION_ID: this.input.missionId,
209
- SKS_AGENT_SESSION_ID: String(input.ctx.agent.session_id || ''),
210
- SKS_AGENT_SLOT_ID: slotId,
211
- SKS_AGENT_GENERATION_INDEX: String(input.ctx.agent.generation_index || 1),
212
- ...(input.ctx.opts.ollamaModel ? { SKS_OLLAMA_MODEL: String(input.ctx.opts.ollamaModel) } : {}),
213
- ...(input.ctx.opts.ollamaBaseUrl ? { SKS_OLLAMA_BASE_URL: String(input.ctx.opts.ollamaBaseUrl) } : {}),
214
- SKS_ZELLIJ_WORKER_PANE: '1',
215
- SKS_ZELLIJ_SESSION_NAME: sessionName
216
- }
217
- });
218
232
  const providerContext = await resolveProviderContext({
219
233
  root: this.root,
220
234
  route: this.input.route,
221
235
  serviceTier: this.input.fastModePolicy.service_tier
222
236
  });
223
- let paneRecord = await openWorkerPane({
224
- root: this.root,
225
- missionId: this.input.missionId,
226
- sessionName,
227
- slotId,
228
- generationIndex: Number(input.ctx.agent.generation_index || 1),
229
- sessionId: String(input.ctx.agent.session_id || ''),
230
- workerArtifactDir: input.workerDirRel,
231
- workerCommand,
232
- resultPath: input.resultRel,
233
- heartbeatPath: input.heartbeatRel,
234
- patchEnvelopePath: input.record.patch_envelope_path,
235
- stdoutLog: input.stdoutRel,
236
- stderrLog: input.stderrRel,
237
- cwd: workerCwd,
238
- providerContext,
239
- serviceTier: this.input.fastModePolicy.service_tier,
240
- worktree: worktree ? { id: worktree.id, path: worktree.path, branch: worktree.branch } : null,
241
- backend: this.input.backend
242
- });
237
+ const uiMode = resolveZellijUiMode(Array.isArray(input.ctx.opts.args) ? input.ctx.opts.args : [], process.env);
238
+ const workerEnv = {
239
+ ...(input.ctx.opts.env || {}),
240
+ ...fastModeEnv(this.input.fastModePolicy),
241
+ SKS_AGENT_WORKER: '1',
242
+ SKS_PIPELINE_MODE: 'agent-worker',
243
+ SKS_DISABLE_ROUTE_RECURSION: '1',
244
+ SKS_PARENT_MISSION_ID: this.input.missionId,
245
+ SKS_AGENT_SESSION_ID: String(input.ctx.agent.session_id || ''),
246
+ SKS_AGENT_SLOT_ID: slotId,
247
+ SKS_AGENT_GENERATION_INDEX: String(input.ctx.agent.generation_index || 1),
248
+ ...(input.ctx.opts.ollamaModel ? { SKS_OLLAMA_MODEL: String(input.ctx.opts.ollamaModel) } : {}),
249
+ ...(input.ctx.opts.ollamaBaseUrl ? { SKS_OLLAMA_BASE_URL: String(input.ctx.opts.ollamaBaseUrl) } : {}),
250
+ SKS_ZELLIJ_SESSION_NAME: sessionName
251
+ };
252
+ const role = String(input.ctx.agent.naruto_role || input.ctx.agent.role || input.ctx.agent.persona_id || 'worker');
253
+ const workerCommand = uiMode === 'full-debug'
254
+ ? buildPaneWorkerCommand({
255
+ args: input.args,
256
+ stdoutPath: path.join(this.root, input.stdoutRel),
257
+ stderrPath: path.join(this.root, input.stderrRel),
258
+ heartbeatPath: path.join(this.root, input.heartbeatRel),
259
+ header: buildPaneWorkerHeader({
260
+ slotId,
261
+ generationIndex: Number(input.ctx.agent.generation_index || 1),
262
+ role,
263
+ backend: this.input.backend,
264
+ provider: providerContext.provider,
265
+ serviceTier: this.input.fastModePolicy.service_tier,
266
+ worktree,
267
+ task: input.ctx.slice?.description || input.ctx.slice?.title || input.ctx.slice?.id || ''
268
+ }),
269
+ env: {
270
+ ...workerEnv,
271
+ SKS_ZELLIJ_WORKER_PANE: '1'
272
+ }
273
+ })
274
+ : buildZellijSlotPaneCommand({
275
+ cliPath: String(input.args[0] || ''),
276
+ missionId: this.input.missionId,
277
+ slotId,
278
+ generationIndex: Number(input.ctx.agent.generation_index || 1),
279
+ artifactDir: path.join(this.root, input.workerDirRel),
280
+ backend: this.input.backend,
281
+ role,
282
+ mode: uiMode,
283
+ watch: true
284
+ });
285
+ let paneRecord;
286
+ try {
287
+ paneRecord = await openWorkerPane({
288
+ root: this.root,
289
+ missionId: this.input.missionId,
290
+ sessionName,
291
+ slotId,
292
+ generationIndex: Number(input.ctx.agent.generation_index || 1),
293
+ sessionId: String(input.ctx.agent.session_id || ''),
294
+ workerArtifactDir: input.workerDirRel,
295
+ workerCommand,
296
+ resultPath: input.resultRel,
297
+ heartbeatPath: input.heartbeatRel,
298
+ patchEnvelopePath: input.record.patch_envelope_path,
299
+ stdoutLog: input.stdoutRel,
300
+ stderrLog: input.stderrRel,
301
+ cwd: workerCwd,
302
+ providerContext,
303
+ serviceTier: this.input.fastModePolicy.service_tier,
304
+ worktree: worktree ? { id: worktree.id, path: worktree.path, branch: worktree.branch } : null,
305
+ backend: this.input.backend,
306
+ uiMode,
307
+ projectRoot: input.ctx.opts.projectRoot || this.input.projectRoot || input.ctx.opts.cwd,
308
+ rightColumnMode: 'spawn-on-first-worker',
309
+ visiblePaneCap: this.zellijVisiblePaneCap(input.ctx.opts),
310
+ dashboardSnapshot: {
311
+ mode: this.input.route || '$Agent',
312
+ backend_counts: { [this.input.backend]: this.input.targetActiveSlots },
313
+ placement_counts: {
314
+ 'zellij-pane': this.zellijVisiblePaneCap(input.ctx.opts),
315
+ headless: Math.max(0, this.input.targetActiveSlots - this.zellijVisiblePaneCap(input.ctx.opts))
316
+ },
317
+ active_workers: this.input.targetActiveSlots,
318
+ visible_panes: this.zellijVisiblePaneCap(input.ctx.opts),
319
+ headless_workers: Math.max(0, this.input.targetActiveSlots - this.zellijVisiblePaneCap(input.ctx.opts)),
320
+ queue_depth: Math.max(0, this.input.requestedAgents - this.input.targetActiveSlots),
321
+ local_llm: { tps: 0, queue: 0 },
322
+ gpt_final_status: 'pending',
323
+ gate_progress: 'worker-spawn'
324
+ }
325
+ });
326
+ }
327
+ finally {
328
+ if (input.zellijReservation)
329
+ this.releaseVisibleZellijReservation(input.zellijReservation);
330
+ }
243
331
  const launchBlockers = paneRecord.blockers || [];
244
- input.record.command_line = ['zellij', '--session', sessionName, 'action', 'new-pane', '--direction', paneRecord.direction_applied, '--name', paneRecord.pane_name, '--', 'sh', '-lc', '<native-cli-worker-command>'];
332
+ input.record.command_line = ['zellij', '--session', sessionName, 'action', 'new-pane', '--direction', paneRecord.direction_applied, '--name', paneRecord.pane_name, '--', 'sh', '-lc', uiMode === 'full-debug' ? '<native-cli-worker-command>' : '<zellij-slot-pane-renderer-command>'];
245
333
  input.record.zellij_session_name = sessionName;
246
334
  input.record.zellij_pane_id = paneRecord.pane_id || null;
247
335
  input.record.zellij_pane_id_source = paneRecord.pane_id_source;
@@ -254,6 +342,8 @@ class NativeCliSessionSwarmRecorder {
254
342
  input.record.service_tier = paneRecord.service_tier;
255
343
  input.record.provider_context = paneRecord.provider_context;
256
344
  input.record.worktree = worktree;
345
+ input.record.zellij_ui_mode = uiMode;
346
+ input.record.slot_visualization = uiMode === 'full-debug' ? 'worker-command-pane' : 'zellij-slot-pane-renderer';
257
347
  input.record.status = launchBlockers.length ? 'failed' : 'running';
258
348
  input.record.blockers = launchBlockers;
259
349
  await this.record(input.record);
@@ -279,6 +369,20 @@ class NativeCliSessionSwarmRecorder {
279
369
  goal_mode_ref: input.ctx.agent.goal_mode_ref || null
280
370
  });
281
371
  }
372
+ const processRun = uiMode === 'full-debug'
373
+ ? null
374
+ : await this.spawnCompactSlotWorkerProcess({
375
+ args: input.args,
376
+ cwd: workerCwd,
377
+ env: workerEnv,
378
+ stdoutRel: input.stdoutRel,
379
+ stderrRel: input.stderrRel
380
+ });
381
+ if (processRun?.pid) {
382
+ input.record.pid = processRun.pid;
383
+ input.record.process_id = processRun.pid;
384
+ await this.record(input.record);
385
+ }
282
386
  await waitForWorkerHeartbeat(path.join(this.root, input.heartbeatRel), Number(process.env.SKS_ZELLIJ_WORKER_HEARTBEAT_TIMEOUT_MS || 30000));
283
387
  await appendJsonl(path.join(this.root, input.workerDirRel, 'zellij-worker-pane-events.jsonl'), {
284
388
  schema: 'sks.zellij-worker-pane-event.v1',
@@ -291,6 +395,7 @@ class NativeCliSessionSwarmRecorder {
291
395
  worker_artifact_dir: input.workerDirRel
292
396
  });
293
397
  const parsed = await waitForWorkerResult(path.join(this.root, input.resultRel), Number(process.env.SKS_ZELLIJ_WORKER_RESULT_TIMEOUT_MS || 120000));
398
+ const compactExit = processRun ? await processRun.wait(parsed ? 10000 : 1000) : null;
294
399
  this.active.delete(activeToken);
295
400
  input.record.closed_at = nowIso();
296
401
  const workerProcessReport = await readJson(path.join(this.root, input.workerDirRel, 'worker-process-report.json'), null).catch(() => null);
@@ -322,8 +427,10 @@ class NativeCliSessionSwarmRecorder {
322
427
  result_path: input.resultRel
323
428
  });
324
429
  }
325
- input.record.pid = Number(workerProcessReport?.pid) || null;
430
+ input.record.pid = Number(workerProcessReport?.pid || processRun?.pid) || null;
326
431
  input.record.process_id = input.record.pid;
432
+ input.record.compact_worker_exit_code = compactExit?.code ?? null;
433
+ input.record.compact_worker_signal = compactExit?.signal ?? null;
327
434
  input.record.sdk_thread_id = sdkThreadId;
328
435
  input.record.sdk_run_id = sdkRunId;
329
436
  input.record.stream_event_count = Number(workerProcessReport?.stream_event_count || workerProcessReport?.backend_router_report?.stream_event_count || 0);
@@ -339,6 +446,7 @@ class NativeCliSessionSwarmRecorder {
339
446
  root: this.root,
340
447
  paneRecord,
341
448
  cwd: workerCwd,
449
+ projectRoot: input.ctx.opts.projectRoot || this.input.projectRoot || input.ctx.opts.cwd,
342
450
  status: input.record.status === 'closed' ? 'closed' : 'failed',
343
451
  blockers: input.record.blockers,
344
452
  sdkThreadId,
@@ -409,6 +517,8 @@ class NativeCliSessionSwarmRecorder {
409
517
  closed_worker_process_count: closed.length,
410
518
  max_observed_worker_process_count: this.maxObserved,
411
519
  active_worker_process_count: this.active.size,
520
+ visible_zellij_pane_cap: this.input.zellijVisiblePaneCap || null,
521
+ headless_overflow_worker_count: this.records.filter((row) => row.worker_placement === 'headless').length,
412
522
  unique_worker_session_count: new Set(this.records.map((row) => row.session_id).filter(Boolean)).size,
413
523
  unique_slot_count: new Set(this.records.map((row) => row.slot_id).filter(Boolean)).size,
414
524
  unique_generation_count: new Set(this.records.map((row) => `${row.slot_id}:${row.generation_index}`).filter(Boolean)).size,
@@ -423,17 +533,75 @@ class NativeCliSessionSwarmRecorder {
423
533
  blockers: this.records.flatMap((row) => row.blockers || [])
424
534
  };
425
535
  }
536
+ zellijVisiblePaneCap(opts = {}) {
537
+ const raw = Number(opts.zellijVisiblePaneCap || this.input.zellijVisiblePaneCap || this.input.targetActiveSlots || 1);
538
+ return Math.max(1, Math.floor(Number.isFinite(raw) ? raw : 1));
539
+ }
540
+ visibleZellijPaneCount() {
541
+ return this.records.filter((row) => row.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' && (row.status === 'launching' || row.status === 'running')).length;
542
+ }
543
+ reserveVisibleZellijPane(opts = {}, token) {
544
+ const cap = this.zellijVisiblePaneCap(opts);
545
+ if (this.visibleZellijPaneCount() + this.visibleZellijReservations.size >= cap)
546
+ return null;
547
+ this.visibleZellijReservations.add(token);
548
+ return token;
549
+ }
550
+ releaseVisibleZellijReservation(token) {
551
+ this.visibleZellijReservations.delete(token);
552
+ }
553
+ async spawnCompactSlotWorkerProcess(input) {
554
+ const stdout = fs.createWriteStream(path.join(this.root, input.stdoutRel), { flags: 'a' });
555
+ const stderr = fs.createWriteStream(path.join(this.root, input.stderrRel), { flags: 'a' });
556
+ const child = spawn(process.execPath, input.args, {
557
+ cwd: input.cwd,
558
+ env: {
559
+ ...process.env,
560
+ ...Object.fromEntries(Object.entries(input.env).filter(([, value]) => value != null).map(([key, value]) => [key, String(value)]))
561
+ },
562
+ stdio: ['ignore', 'pipe', 'pipe']
563
+ });
564
+ child.stdout?.pipe(stdout);
565
+ child.stderr?.pipe(stderr);
566
+ const exitPromise = new Promise((resolve) => {
567
+ child.on('close', (code, signal) => {
568
+ stdout.end();
569
+ stderr.end();
570
+ resolve({ code, signal });
571
+ });
572
+ child.on('error', () => {
573
+ stdout.end();
574
+ stderr.end();
575
+ resolve({ code: 1, signal: null });
576
+ });
577
+ });
578
+ return {
579
+ pid: child.pid || null,
580
+ wait: async (timeoutMs) => waitForChildExit(child, exitPromise, timeoutMs)
581
+ };
582
+ }
426
583
  }
427
584
  export function buildPaneWorkerCommand(input) {
428
585
  const envPrefix = Object.entries(input.env)
429
586
  .filter(([key, value]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key) && value != null)
430
- .map(([key, value]) => `${key}=${shellQuote(String(value))}`)
587
+ .map(([key, value]) => `export ${key}=${shellQuote(String(value))};`)
431
588
  .sort();
432
589
  const command = [shellQuote(process.execPath), ...input.args.map(shellQuote)].join(' ');
433
590
  const heartbeat = `printf '%s\\n' ${shellQuote(JSON.stringify({ schema: 'sks.zellij-worker-pane-event.v1', event: 'worker_command_exited' }))} >> ${shellQuote(input.heartbeatPath)}`;
434
591
  const holdMs = Math.max(0, Number(process.env.SKS_ZELLIJ_WORKER_PANE_HOLD_MS || 1500));
435
592
  const hold = holdMs > 0 ? `sleep ${shellQuote(String(Math.min(30, holdMs / 1000)))}` : ':';
436
- return `${envPrefix.join(' ')} ${command} > ${shellQuote(input.stdoutPath)} 2> ${shellQuote(input.stderrPath)}; code=$?; ${heartbeat}; ${hold}; exit $code`.trim();
593
+ const header = input.header ? `printf '%s\\n' ${shellQuote(input.header)} | tee -a ${shellQuote(input.stdoutPath)};` : '';
594
+ return `${envPrefix.join(' ')} ${header} ${command} >> ${shellQuote(input.stdoutPath)} 2>> ${shellQuote(input.stderrPath)}; code=$?; ${heartbeat}; ${hold}; exit $code`.trim();
595
+ }
596
+ function buildPaneWorkerHeader(input) {
597
+ return [
598
+ 'SKS Worker',
599
+ `slot: ${input.slotId} gen: ${input.generationIndex} role: ${input.role}`,
600
+ `backend: ${input.backend} provider: ${input.provider} service: ${input.serviceTier}`,
601
+ `worktree: ${input.worktree ? `${input.worktree.id} branch: ${input.worktree.branch}` : '-'}`,
602
+ `task: ${String(input.task || '').slice(0, 160)}`,
603
+ 'status: running'
604
+ ].join('\n');
437
605
  }
438
606
  async function waitForWorkerResult(file, timeoutMs) {
439
607
  const deadline = Date.now() + Math.max(1000, timeoutMs);
@@ -488,4 +656,18 @@ function normalizeWorkerWorktree(value) {
488
656
  main_repo_root: value?.main_repo_root == null ? null : String(value.main_repo_root)
489
657
  };
490
658
  }
659
+ async function waitForChildExit(child, exitPromise, timeoutMs) {
660
+ let timer = null;
661
+ const timeout = new Promise((resolve) => {
662
+ timer = setTimeout(() => {
663
+ if (!child.killed)
664
+ child.kill();
665
+ resolve({ code: null, signal: 'SIGTERM' });
666
+ }, Math.max(1000, timeoutMs));
667
+ });
668
+ const result = await Promise.race([exitPromise, timeout]);
669
+ if (timer)
670
+ clearTimeout(timer);
671
+ return result;
672
+ }
491
673
  //# sourceMappingURL=native-cli-session-swarm.js.map
@@ -7,7 +7,6 @@ import { createMission, setCurrent } from '../mission.js';
7
7
  import { buildMadHighLaunchProfileNoWrite, madHighProfileName } from '../auto-review.js';
8
8
  import { permissionGateSummary } from '../permission-gates.js';
9
9
  import { attachZellijSessionInteractive, launchMadZellijUi, sanitizeZellijSessionName } from '../zellij/zellij-launcher.js';
10
- import { openZellijDashboardPane } from '../zellij/zellij-dashboard-pane.js';
11
10
  import { createMadSksAuthorizationManifest, validateMadSksAuthorizationManifest } from '../mad-sks/authorization-manifest.js';
12
11
  import { createMadSksAuditLedger, madSksAuditAction, writeMadSksAuditLedger } from '../mad-sks/audit-ledger.js';
13
12
  import { compareProtectedCoreSnapshots, evaluateMadSksWrite, resolveProtectedCore, snapshotProtectedCore } from '../mad-sks/immutable-harness-guard.js';
@@ -114,36 +113,24 @@ export async function madHighCommand(args = [], deps = {}) {
114
113
  console.log(`MAD Zellij action: ${formatMadZellijAction(launch)}`);
115
114
  return launch;
116
115
  }
117
- launch.dashboard_pane = await openZellijDashboardPane({
118
- root: madLaunch.root,
119
- missionId: madLaunch.mission_id,
120
- sessionName: launch.session_name,
121
- cwd: process.cwd(),
122
- snapshot: {
123
- mode: 'mad-sks',
124
- backend_counts: { zellij: 1 },
125
- placement_counts: { 'zellij-pane': 1, headless: 0 },
126
- active_workers: 1,
127
- visible_panes: 1,
128
- headless_workers: 0,
129
- queue_depth: 0,
130
- worktrees: { active: 0, completed: 0, retained: 0 },
131
- local_llm: { tps: 0, queue: 0 },
132
- gpt_final_status: 'pending',
133
- gate_progress: 'mad-sks:session-open'
134
- }
135
- }).catch((err) => ({
136
- ok: false,
137
- pane_kind: 'dashboard',
138
- worker_pane: false,
139
- blockers: [`zellij_dashboard_exception:${err?.message || String(err)}`]
140
- }));
116
+ await writeJsonAtomic(path.join(madLaunch.dir, 'zellij-initial-ui.json'), {
117
+ schema: 'sks.zellij-initial-ui.v1',
118
+ ok: true,
119
+ mission_id: madLaunch.mission_id,
120
+ session_name: launch.session_name,
121
+ initial_panes: 'main-only',
122
+ dashboard_created: false,
123
+ worker_panes_created: 0,
124
+ right_column_mode: 'spawn-on-first-worker'
125
+ });
141
126
  const madNativeSwarm = await startMadNativeSwarm(madLaunch.root, madLaunch, args, profile, {
142
127
  env: {
143
128
  ...madSksEnv,
144
129
  SKS_ZELLIJ_SESSION_NAME: launch.session_name
145
130
  },
146
- zellijSessionName: launch.session_name
131
+ zellijSessionName: launch.session_name,
132
+ workerPlacement: shouldAutoAttachZellij(args) ? 'zellij-pane' : 'process',
133
+ zellijVisiblePaneCap: Number(process.env.SKS_ZELLIJ_VISIBLE_PANE_CAP || 8)
147
134
  });
148
135
  // The launcher only creates a detached background session. In an interactive
149
136
  // terminal, immediately attach so the session actually opens for the user
@@ -218,6 +205,8 @@ export async function startMadNativeSwarm(root, madLaunch, args = [], profile =
218
205
  command.push('--real');
219
206
  command.push('--zellij-session-name', opts.zellijSessionName || `sks-${madLaunch.mission_id}`);
220
207
  command.push('--zellij-pane-worker');
208
+ command.push('--worker-placement', opts.workerPlacement || 'zellij-pane');
209
+ command.push('--zellij-visible-pane-cap', String(opts.zellijVisiblePaneCap || swarm.agents));
221
210
  }
222
211
  const baseReport = {
223
212
  schema: 'sks.mad-sks-native-swarm.v1',
@@ -234,6 +223,8 @@ export async function startMadNativeSwarm(root, madLaunch, args = [], profile =
234
223
  work_items: swarm.workItems,
235
224
  backend: swarm.backend,
236
225
  zellij_session_name: opts.zellijSessionName || null,
226
+ worker_placement: opts.workerPlacement || (swarm.backend === 'zellij' ? 'zellij-pane' : 'process'),
227
+ zellij_visible_pane_cap: opts.zellijVisiblePaneCap || null,
237
228
  readonly: true,
238
229
  command,
239
230
  stdout_log: path.relative(root, stdoutLog),