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.
- package/README.md +8 -4
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/build-manifest.json +33 -8
- package/dist/cli/command-registry.js +1 -0
- package/dist/commands/doctor.js +18 -1
- package/dist/commands/zellij-slot-pane.js +26 -0
- package/dist/commands/zellij.js +144 -1
- package/dist/core/agents/agent-orchestrator.js +202 -9
- package/dist/core/agents/agent-role-config.js +92 -0
- package/dist/core/agents/native-cli-session-swarm.js +230 -48
- package/dist/core/commands/mad-sks-command.js +17 -26
- package/dist/core/commands/naruto-command.js +155 -37
- package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +4 -0
- package/dist/core/init.js +1 -0
- package/dist/core/naruto/naruto-active-pool.js +141 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +17 -2
- package/dist/core/naruto/naruto-real-worker-child.js +35 -0
- package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
- package/dist/core/naruto/naruto-work-graph.js +2 -1
- package/dist/core/release/release-gate-cache-v2.js +58 -4
- package/dist/core/release/release-gate-dag.js +36 -25
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-dashboard-renderer.js +22 -6
- package/dist/core/zellij/zellij-launcher.js +3 -3
- package/dist/core/zellij/zellij-layout-builder.js +1 -1
- package/dist/core/zellij/zellij-right-column-layout-proof.js +42 -0
- package/dist/core/zellij/zellij-right-column-manager.js +304 -0
- package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
- package/dist/core/zellij/zellij-ui-mode.js +16 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +152 -17
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- package/dist/scripts/codex-sdk-release-review-pipeline-check.js +5 -5
- package/dist/scripts/doctor-fix-proves-codex-read-check.js +26 -5
- package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
- package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
- package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
- package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +2 -2
- package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
- package/dist/scripts/naruto-concurrency-governor-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
- package/dist/scripts/naruto-real-active-pool-check.js +39 -0
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
- package/dist/scripts/naruto-work-graph-check.js +1 -1
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +48 -0
- package/dist/scripts/product-design-auto-install-check.js +3 -3
- package/dist/scripts/product-design-plugin-routing-check.js +3 -3
- package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
- package/dist/scripts/release-cache-glob-hashing-check.js +42 -0
- package/dist/scripts/release-check-dynamic-execute.js +27 -1
- package/dist/scripts/release-check-dynamic.js +38 -11
- package/dist/scripts/release-check-stamp.js +7 -2
- package/dist/scripts/release-dag-full-coverage-check.js +35 -0
- package/dist/scripts/release-dynamic-performance-check.js +31 -1
- package/dist/scripts/release-gate-existence-audit.js +29 -33
- package/dist/scripts/release-parallel-speed-budget-check.js +67 -13
- package/dist/scripts/release-readiness-report.js +14 -3
- package/dist/scripts/zellij-dashboard-pane-check.js +6 -4
- package/dist/scripts/zellij-developer-controls-check.js +20 -0
- package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +21 -0
- package/dist/scripts/zellij-initial-main-only-blackbox.js +28 -0
- package/dist/scripts/zellij-right-column-geometry-proof.js +162 -0
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
- package/dist/scripts/zellij-right-column-manager-check.js +22 -0
- package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +2 -1
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +7 -6
- package/package.json +23 -5
- 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
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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]) =>
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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),
|