sneakoscope 2.0.9 → 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 +21 -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/core/agents/agent-orchestrator.js +198 -7
- package/dist/core/agents/agent-role-config.js +92 -0
- package/dist/core/agents/native-cli-session-swarm.js +186 -71
- package/dist/core/commands/naruto-command.js +59 -4
- 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 +35 -2
- package/dist/core/naruto/naruto-concurrency-governor.js +1 -1
- 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/version.js +1 -1
- package/dist/core/zellij/zellij-right-column-manager.js +66 -7
- 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 +38 -8
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- 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/mutation-callsite-coverage-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +1 -1
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
- package/dist/scripts/naruto-real-active-pool-check.js +3 -2
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +29 -2
- package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
- 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-dynamic-performance-check.js +31 -1
- package/dist/scripts/release-gate-existence-audit.js +29 -33
- package/dist/scripts/release-readiness-report.js +13 -2
- package/dist/scripts/zellij-right-column-geometry-proof.js +155 -22
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
- package/dist/scripts/zellij-right-column-manager-check.js +4 -4
- package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/package.json +12 -4
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { ensureDir, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
|
|
6
|
+
import { allocateWorkerWorktree } from '../git/git-worktree-manager.js';
|
|
7
|
+
import { cleanupGitWorktree } from '../git/git-worktree-cleanup.js';
|
|
8
|
+
export async function spawnActualNarutoWorker(input) {
|
|
9
|
+
const workerDir = path.join(input.root, '.sneakoscope', 'missions', input.missionId, 'agents', 'naruto-real-workers', input.item.id);
|
|
10
|
+
await ensureDir(workerDir);
|
|
11
|
+
let worktree = null;
|
|
12
|
+
if (input.worktreePolicy?.mode === 'git-worktree' && input.item.write_allowed === true) {
|
|
13
|
+
const allocation = await allocateWorkerWorktree({
|
|
14
|
+
repoRoot: input.worktreePolicy.main_repo_root || input.root,
|
|
15
|
+
missionId: input.missionId,
|
|
16
|
+
workerId: input.item.id,
|
|
17
|
+
slotId: input.item.id.replace(/[^A-Za-z0-9_-]/g, '-'),
|
|
18
|
+
generationIndex: 1
|
|
19
|
+
}).catch((err) => ({ ok: false, blockers: [`git_worktree_allocate_exception:${err?.message || String(err)}`] }));
|
|
20
|
+
await writeJsonAtomic(path.join(workerDir, 'git-worktree-allocation.json'), allocation);
|
|
21
|
+
if (allocation.ok)
|
|
22
|
+
worktree = allocation;
|
|
23
|
+
}
|
|
24
|
+
const resultPath = path.join(workerDir, 'worker-result.json');
|
|
25
|
+
const heartbeatPath = path.join(workerDir, 'worker-heartbeat.jsonl');
|
|
26
|
+
const intakePath = path.join(workerDir, 'worker-intake.json');
|
|
27
|
+
await writeJsonAtomic(intakePath, {
|
|
28
|
+
schema: 'sks.naruto-actual-worker-intake.v1',
|
|
29
|
+
generated_at: nowIso(),
|
|
30
|
+
mission_id: input.missionId,
|
|
31
|
+
item: input.item,
|
|
32
|
+
placement: input.placement,
|
|
33
|
+
backend: input.backend,
|
|
34
|
+
result_path: resultPath,
|
|
35
|
+
heartbeat_path: heartbeatPath,
|
|
36
|
+
worktree_path: worktree?.worktree_path || null,
|
|
37
|
+
zellij_session_name: input.zellijSessionName || null,
|
|
38
|
+
visible_pane_cap: input.visiblePaneCap
|
|
39
|
+
});
|
|
40
|
+
const child = spawn(process.execPath, [actualWorkerEntrypoint(), intakePath], {
|
|
41
|
+
cwd: worktree?.worktree_path || input.root,
|
|
42
|
+
stdio: ['ignore', 'ignore', 'ignore']
|
|
43
|
+
});
|
|
44
|
+
const exit = waitForExit(child, 30000);
|
|
45
|
+
return {
|
|
46
|
+
id: input.item.id,
|
|
47
|
+
item: input.item,
|
|
48
|
+
placement: input.placement,
|
|
49
|
+
started_at: Date.now(),
|
|
50
|
+
pid: child.pid || null,
|
|
51
|
+
child,
|
|
52
|
+
worker_artifact_dir: workerDir,
|
|
53
|
+
result_path: resultPath,
|
|
54
|
+
heartbeat_path: heartbeatPath,
|
|
55
|
+
worktree,
|
|
56
|
+
exit
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export async function collectActualNarutoWorker(handle) {
|
|
60
|
+
const exit = await handle.exit;
|
|
61
|
+
const result = await readJson(handle.result_path, null).catch(() => null);
|
|
62
|
+
const blockers = [
|
|
63
|
+
...(exit.code === 0 ? [] : [`naruto_actual_worker_exit_${exit.code ?? exit.signal ?? 'unknown'}`]),
|
|
64
|
+
...(result?.ok === false ? result.blockers || ['naruto_actual_worker_result_not_ok'] : []),
|
|
65
|
+
...(result ? [] : ['naruto_actual_worker_result_missing'])
|
|
66
|
+
];
|
|
67
|
+
if (handle.worktree?.worktree_path) {
|
|
68
|
+
const cleanup = await cleanupGitWorktree({
|
|
69
|
+
repoRoot: handle.worktree.main_repo_root || handle.worktree.repo_root || handle.worktree.repoRoot || '',
|
|
70
|
+
worktreePath: handle.worktree.worktree_path,
|
|
71
|
+
branch: handle.worktree.branch,
|
|
72
|
+
deleteBranch: true
|
|
73
|
+
}).catch((err) => ({ ok: false, blockers: [`git_worktree_cleanup_exception:${err?.message || String(err)}`] }));
|
|
74
|
+
await writeJsonAtomic(path.join(handle.worker_artifact_dir, 'git-worktree-cleanup.json'), cleanup);
|
|
75
|
+
blockers.push(...(cleanup.blockers || []));
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
id: handle.id,
|
|
79
|
+
ok: blockers.length === 0,
|
|
80
|
+
item: handle.item,
|
|
81
|
+
placement: handle.placement,
|
|
82
|
+
completed_at: Date.now(),
|
|
83
|
+
pid: handle.pid,
|
|
84
|
+
worker_artifact_dir: handle.worker_artifact_dir,
|
|
85
|
+
blockers
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function actualWorkerEntrypoint() {
|
|
89
|
+
return fileURLToPath(new URL('./naruto-real-worker-child.js', import.meta.url));
|
|
90
|
+
}
|
|
91
|
+
function waitForExit(child, timeoutMs) {
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
let settled = false;
|
|
94
|
+
let killTimer = null;
|
|
95
|
+
const finish = (code, signal) => {
|
|
96
|
+
if (settled)
|
|
97
|
+
return;
|
|
98
|
+
settled = true;
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
if (killTimer)
|
|
101
|
+
clearTimeout(killTimer);
|
|
102
|
+
resolve({ code, signal });
|
|
103
|
+
};
|
|
104
|
+
const timer = setTimeout(() => {
|
|
105
|
+
if (!child.killed)
|
|
106
|
+
child.kill();
|
|
107
|
+
killTimer = setTimeout(() => {
|
|
108
|
+
if (!settled)
|
|
109
|
+
child.kill('SIGKILL');
|
|
110
|
+
finish(null, 'SIGKILL');
|
|
111
|
+
}, 5000);
|
|
112
|
+
}, Math.max(1000, timeoutMs));
|
|
113
|
+
child.on('close', (code, signal) => {
|
|
114
|
+
finish(code, signal);
|
|
115
|
+
});
|
|
116
|
+
child.on('error', () => {
|
|
117
|
+
finish(1, null);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=naruto-real-worker-runtime.js.map
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '2.0.
|
|
1
|
+
export const PACKAGE_VERSION = '2.0.10';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { appendJsonl, ensureDir, nowIso, readJson, writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
import { openZellijDashboardPane } from './zellij-dashboard-pane.js';
|
|
4
|
+
import { zellijUiModeCreatesDashboard } from './zellij-ui-mode.js';
|
|
4
5
|
export const ZELLIJ_RIGHT_COLUMN_STATE_SCHEMA = 'sks.zellij-right-column-state.v1';
|
|
5
6
|
export async function ensureRightColumn(input) {
|
|
6
7
|
const paths = resolveRightColumnPaths(input.root, input.missionId, input.projectRoot);
|
|
7
8
|
await ensureDir(paths.missionDir);
|
|
9
|
+
const uiMode = input.uiMode || 'compact-slots';
|
|
10
|
+
const createDashboard = input.createDashboard ?? zellijUiModeCreatesDashboard(uiMode);
|
|
8
11
|
const existing = await readRightColumnState(input.root, input.missionId, input.projectRoot);
|
|
9
|
-
if (existing?.status === 'active'
|
|
10
|
-
return writeRightColumnState(paths.statePath, {
|
|
12
|
+
if (existing?.status === 'active') {
|
|
13
|
+
return writeRightColumnState(paths.statePath, {
|
|
14
|
+
...existing,
|
|
15
|
+
updated_at: nowIso(),
|
|
16
|
+
ui_mode: existing.ui_mode || uiMode
|
|
17
|
+
});
|
|
11
18
|
}
|
|
12
19
|
const creating = await writeRightColumnState(paths.statePath, {
|
|
13
20
|
schema: ZELLIJ_RIGHT_COLUMN_STATE_SCHEMA,
|
|
@@ -18,11 +25,29 @@ export async function ensureRightColumn(input) {
|
|
|
18
25
|
status: 'creating',
|
|
19
26
|
dashboard_pane_id: null,
|
|
20
27
|
right_anchor_pane_id: null,
|
|
28
|
+
ui_mode: uiMode,
|
|
21
29
|
visible_worker_panes: [],
|
|
22
30
|
headless_workers: [],
|
|
23
31
|
blockers: []
|
|
24
32
|
});
|
|
25
33
|
await appendRightColumnEvent(paths.eventsPath, 'right_column_creating', creating, {});
|
|
34
|
+
if (!createDashboard) {
|
|
35
|
+
const active = await writeRightColumnState(paths.statePath, {
|
|
36
|
+
...creating,
|
|
37
|
+
updated_at: nowIso(),
|
|
38
|
+
status: 'active',
|
|
39
|
+
dashboard_pane_id: null,
|
|
40
|
+
right_anchor_pane_id: null,
|
|
41
|
+
ui_mode: uiMode,
|
|
42
|
+
blockers: []
|
|
43
|
+
});
|
|
44
|
+
await appendRightColumnEvent(paths.eventsPath, 'right_column_created', active, {
|
|
45
|
+
ok: true,
|
|
46
|
+
dashboard_created: false,
|
|
47
|
+
ui_mode: uiMode
|
|
48
|
+
});
|
|
49
|
+
return active;
|
|
50
|
+
}
|
|
26
51
|
const dashboard = await openZellijDashboardPane({
|
|
27
52
|
root: paths.projectRoot,
|
|
28
53
|
missionId: input.missionId,
|
|
@@ -45,6 +70,7 @@ export async function ensureRightColumn(input) {
|
|
|
45
70
|
status: blockers.length ? 'creating' : 'active',
|
|
46
71
|
dashboard_pane_id: dashboard.pane_id ? String(dashboard.pane_id) : null,
|
|
47
72
|
right_anchor_pane_id: dashboard.pane_id ? String(dashboard.pane_id) : null,
|
|
73
|
+
ui_mode: uiMode,
|
|
48
74
|
blockers
|
|
49
75
|
});
|
|
50
76
|
await appendRightColumnEvent(paths.eventsPath, 'right_column_created', active, { ok: active.status === 'active' });
|
|
@@ -52,6 +78,9 @@ export async function ensureRightColumn(input) {
|
|
|
52
78
|
return active;
|
|
53
79
|
}
|
|
54
80
|
export async function prepareWorkerInRightColumn(input) {
|
|
81
|
+
return withRightColumnLock(input.root, input.missionId, async () => prepareWorkerInRightColumnUnlocked(input));
|
|
82
|
+
}
|
|
83
|
+
async function prepareWorkerInRightColumnUnlocked(input) {
|
|
55
84
|
const paths = resolveRightColumnPaths(input.root, input.missionId, input.projectRoot);
|
|
56
85
|
const state = await ensureRightColumn({
|
|
57
86
|
root: input.root,
|
|
@@ -59,12 +88,13 @@ export async function prepareWorkerInRightColumn(input) {
|
|
|
59
88
|
missionId: input.missionId,
|
|
60
89
|
sessionName: input.sessionName,
|
|
61
90
|
cwd: input.cwd,
|
|
62
|
-
dashboardSnapshot: input.dashboardSnapshot
|
|
91
|
+
dashboardSnapshot: input.dashboardSnapshot,
|
|
92
|
+
uiMode: input.uiMode || 'compact-slots'
|
|
63
93
|
});
|
|
64
94
|
const activeVisible = state.visible_worker_panes.filter((pane) => pane.status === 'launching' || pane.status === 'running');
|
|
65
95
|
const cap = Math.max(1, Math.floor(Number(input.visiblePaneCap || 1)));
|
|
66
96
|
if (activeVisible.length >= cap) {
|
|
67
|
-
const next = await
|
|
97
|
+
const next = await recordHeadlessWorkerInRightColumnUnlocked({
|
|
68
98
|
root: input.root,
|
|
69
99
|
...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
|
|
70
100
|
missionId: input.missionId,
|
|
@@ -134,6 +164,9 @@ export async function recordWorkerPaneInRightColumn(input) {
|
|
|
134
164
|
return next;
|
|
135
165
|
}
|
|
136
166
|
export async function recordHeadlessWorkerInRightColumn(input) {
|
|
167
|
+
return withRightColumnLock(input.root, input.missionId, async () => recordHeadlessWorkerInRightColumnUnlocked(input));
|
|
168
|
+
}
|
|
169
|
+
async function recordHeadlessWorkerInRightColumnUnlocked(input) {
|
|
137
170
|
const paths = resolveRightColumnPaths(input.root, input.missionId, input.projectRoot);
|
|
138
171
|
const state = await readRightColumnState(input.root, input.missionId, input.projectRoot) || {
|
|
139
172
|
schema: ZELLIJ_RIGHT_COLUMN_STATE_SCHEMA,
|
|
@@ -144,13 +177,14 @@ export async function recordHeadlessWorkerInRightColumn(input) {
|
|
|
144
177
|
status: 'absent',
|
|
145
178
|
dashboard_pane_id: null,
|
|
146
179
|
right_anchor_pane_id: null,
|
|
180
|
+
ui_mode: 'compact-slots',
|
|
147
181
|
visible_worker_panes: [],
|
|
148
182
|
headless_workers: [],
|
|
149
183
|
blockers: []
|
|
150
184
|
};
|
|
151
185
|
const headless = [
|
|
152
186
|
...state.headless_workers.filter((row) => !(row.slot_id === input.slotId && row.generation_index === input.generationIndex)),
|
|
153
|
-
{ slot_id: input.slotId, generation_index: input.generationIndex, reason: input.reason }
|
|
187
|
+
{ slot_id: input.slotId, generation_index: input.generationIndex, reason: input.reason, status: 'running', closed_at: null }
|
|
154
188
|
];
|
|
155
189
|
const next = await writeRightColumnState(paths.statePath, { ...state, updated_at: nowIso(), headless_workers: headless });
|
|
156
190
|
await appendRightColumnEvent(paths.eventsPath, 'worker_headless_overflow', next, {
|
|
@@ -169,13 +203,19 @@ export async function closeWorkerInRightColumn(input) {
|
|
|
169
203
|
const same = pane.slot_id === input.slotId && pane.generation_index === input.generationIndex;
|
|
170
204
|
return same ? { ...pane, pane_id: input.paneId || pane.pane_id, status: input.status } : pane;
|
|
171
205
|
});
|
|
206
|
+
const headless = state.headless_workers.map((row) => {
|
|
207
|
+
const same = row.slot_id === input.slotId && row.generation_index === input.generationIndex;
|
|
208
|
+
return same ? { ...row, status: input.status === 'draining' ? 'closed' : input.status, closed_at: nowIso() } : row;
|
|
209
|
+
});
|
|
172
210
|
const visibleStillActive = panes.filter((pane) => pane.status === 'launching' || pane.status === 'running');
|
|
211
|
+
const headlessStillActive = headless.filter((row) => !row.status || row.status === 'running');
|
|
173
212
|
const next = await writeRightColumnState(paths.statePath, {
|
|
174
213
|
...state,
|
|
175
214
|
updated_at: nowIso(),
|
|
176
|
-
status: visibleStillActive.length ||
|
|
215
|
+
status: visibleStillActive.length || headlessStillActive.length ? 'active' : 'draining',
|
|
177
216
|
right_anchor_pane_id: visibleStillActive[visibleStillActive.length - 1]?.pane_id || state.dashboard_pane_id,
|
|
178
|
-
visible_worker_panes: panes
|
|
217
|
+
visible_worker_panes: panes,
|
|
218
|
+
headless_workers: headless
|
|
179
219
|
});
|
|
180
220
|
await appendRightColumnEvent(paths.eventsPath, 'worker_pane_drained', next, {
|
|
181
221
|
slot_id: input.slotId,
|
|
@@ -242,4 +282,23 @@ function inferProjectRoot(root, missionId) {
|
|
|
242
282
|
}
|
|
243
283
|
return root;
|
|
244
284
|
}
|
|
285
|
+
const rightColumnLocks = new Map();
|
|
286
|
+
async function withRightColumnLock(root, missionId, fn) {
|
|
287
|
+
const key = `${path.resolve(root)}:${missionId}`;
|
|
288
|
+
const previous = rightColumnLocks.get(key) || Promise.resolve();
|
|
289
|
+
let release;
|
|
290
|
+
const current = new Promise((resolve) => {
|
|
291
|
+
release = resolve;
|
|
292
|
+
});
|
|
293
|
+
rightColumnLocks.set(key, previous.then(() => current, () => current));
|
|
294
|
+
await previous.catch(() => undefined);
|
|
295
|
+
try {
|
|
296
|
+
return await fn();
|
|
297
|
+
}
|
|
298
|
+
finally {
|
|
299
|
+
release();
|
|
300
|
+
if (rightColumnLocks.get(key) === current)
|
|
301
|
+
rightColumnLocks.delete(key);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
245
304
|
//# sourceMappingURL=zellij-right-column-manager.js.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export function renderZellijSlotPane(input) {
|
|
4
|
+
const mode = input.mode || 'compact-slots';
|
|
5
|
+
const maxLines = mode === 'compact-slots' ? 5 : mode === 'dashboard-plus-slots' ? 8 : 20;
|
|
6
|
+
const task = trimInline(input.currentFile || input.currentTask || '-', 56);
|
|
7
|
+
const heartbeat = input.heartbeatAgeMs == null
|
|
8
|
+
? 'unknown'
|
|
9
|
+
: input.heartbeatAgeMs < 1000
|
|
10
|
+
? 'now'
|
|
11
|
+
: `${Math.max(1, Math.round(input.heartbeatAgeMs / 1000))}s ago`;
|
|
12
|
+
const rows = [
|
|
13
|
+
`${input.slotId} gen-${Math.max(1, Math.floor(Number(input.generationIndex) || 1))}`,
|
|
14
|
+
`${trimInline(input.role || 'worker', 18)} - ${trimInline(input.backend || 'codex-sdk', 18)} - ${trimInline(input.worktreeId || '-', 18)}`,
|
|
15
|
+
`status: ${trimInline(input.status || 'running', 14)} ${task}`,
|
|
16
|
+
`patch: ${trimInline(input.patchStatus || 'queued', 18)} verify: ${trimInline(input.verifyStatus || 'queued', 18)}`,
|
|
17
|
+
`heartbeat: ${heartbeat}`
|
|
18
|
+
];
|
|
19
|
+
return rows.slice(0, maxLines).join('\n');
|
|
20
|
+
}
|
|
21
|
+
export async function renderZellijSlotPaneFromArtifacts(input) {
|
|
22
|
+
const artifactDir = path.resolve(input.artifactDir);
|
|
23
|
+
const result = await readJson(path.join(artifactDir, 'worker-result.json'));
|
|
24
|
+
const heartbeatPath = path.join(artifactDir, 'worker-heartbeat.jsonl');
|
|
25
|
+
const heartbeatMtime = await statMtimeMs(heartbeatPath);
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
return renderZellijSlotPane({
|
|
28
|
+
slotId: input.slotId,
|
|
29
|
+
generationIndex: input.generationIndex,
|
|
30
|
+
role: input.role || result?.persona_id || result?.agent_id || null,
|
|
31
|
+
backend: input.backend || result?.backend || null,
|
|
32
|
+
status: result?.status || (heartbeatMtime ? 'running' : 'launching'),
|
|
33
|
+
currentTask: result?.summary || null,
|
|
34
|
+
currentFile: Array.isArray(result?.changed_files) ? result.changed_files[0] : null,
|
|
35
|
+
patchStatus: Array.isArray(result?.patch_envelopes) && result.patch_envelopes.length ? 'candidate' : 'queued',
|
|
36
|
+
verifyStatus: result?.verification?.status || 'queued',
|
|
37
|
+
heartbeatAgeMs: heartbeatMtime ? now - heartbeatMtime : null,
|
|
38
|
+
worktreeId: result?.worktree?.id || null,
|
|
39
|
+
mode: input.mode || 'compact-slots'
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function buildZellijSlotPaneCommand(input) {
|
|
43
|
+
const args = [
|
|
44
|
+
input.cliPath,
|
|
45
|
+
'zellij-slot-pane',
|
|
46
|
+
'--mission', input.missionId,
|
|
47
|
+
'--slot', input.slotId,
|
|
48
|
+
'--generation', String(Math.max(1, Math.floor(Number(input.generationIndex) || 1))),
|
|
49
|
+
'--artifact-dir', input.artifactDir,
|
|
50
|
+
'--mode', input.mode || 'compact-slots',
|
|
51
|
+
...(input.backend ? ['--backend', input.backend] : []),
|
|
52
|
+
...(input.role ? ['--role', input.role] : []),
|
|
53
|
+
...(input.watch ? ['--watch'] : [])
|
|
54
|
+
];
|
|
55
|
+
return [input.nodePath || process.execPath, ...args].map(shellQuote).join(' ');
|
|
56
|
+
}
|
|
57
|
+
async function readJson(file) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(await fs.promises.readFile(file, 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function statMtimeMs(file) {
|
|
66
|
+
try {
|
|
67
|
+
return (await fs.promises.stat(file)).mtimeMs;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function trimInline(value, max) {
|
|
74
|
+
const text = String(value || '').replace(/\s+/g, ' ').trim();
|
|
75
|
+
if (text.length <= max)
|
|
76
|
+
return text;
|
|
77
|
+
return text.slice(0, Math.max(1, max - 3)) + '...';
|
|
78
|
+
}
|
|
79
|
+
function shellQuote(value) {
|
|
80
|
+
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=zellij-slot-pane-renderer.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function resolveZellijUiMode(args = [], env = process.env) {
|
|
2
|
+
const fromEnv = String(env.SKS_ZELLIJ_UI_MODE || '').trim();
|
|
3
|
+
if (fromEnv === 'full-debug')
|
|
4
|
+
return 'full-debug';
|
|
5
|
+
if (fromEnv === 'dashboard-plus-slots')
|
|
6
|
+
return 'dashboard-plus-slots';
|
|
7
|
+
if (args.includes('--zellij-dashboard'))
|
|
8
|
+
return 'dashboard-plus-slots';
|
|
9
|
+
if (args.includes('--zellij-full-debug'))
|
|
10
|
+
return 'full-debug';
|
|
11
|
+
return 'compact-slots';
|
|
12
|
+
}
|
|
13
|
+
export function zellijUiModeCreatesDashboard(mode) {
|
|
14
|
+
return mode !== 'compact-slots';
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=zellij-ui-mode.js.map
|
|
@@ -29,7 +29,7 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
29
29
|
schema: ZELLIJ_WORKER_PANE_SCHEMA,
|
|
30
30
|
generated_at: now,
|
|
31
31
|
updated_at: now,
|
|
32
|
-
ok: blockers.length === 0 && isRealZellijWorkerPaneIdSource(paneIdSource) && Boolean(input.paneId),
|
|
32
|
+
ok: blockers.length === 0 && (paneIdSource === 'zellij_worker_headless_overflow' || (isRealZellijWorkerPaneIdSource(paneIdSource) && Boolean(input.paneId))),
|
|
33
33
|
status: input.status || 'launching',
|
|
34
34
|
mission_id: input.missionId,
|
|
35
35
|
session_name: input.sessionName,
|
|
@@ -52,8 +52,8 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
52
52
|
stdout_log: input.stdoutLog,
|
|
53
53
|
stderr_log: input.stderrLog,
|
|
54
54
|
parent_child_transport: 'worker-result-json-and-heartbeat',
|
|
55
|
-
scaling_primitive: 'native_cli_process_in_zellij_worker_pane',
|
|
56
|
-
command: '<native-cli-worker-command>',
|
|
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>',
|
|
57
57
|
create_session: input.createSession || null,
|
|
58
58
|
launch: input.launch || null,
|
|
59
59
|
pane_reconciliation: input.paneReconciliation || null,
|
|
@@ -96,6 +96,7 @@ export async function openWorkerPane(input) {
|
|
|
96
96
|
cwd,
|
|
97
97
|
worker: { slotId: input.slotId, generationIndex: input.generationIndex },
|
|
98
98
|
visiblePaneCap: input.visiblePaneCap || 1,
|
|
99
|
+
uiMode: input.uiMode || 'compact-slots',
|
|
99
100
|
dashboardSnapshot: {
|
|
100
101
|
...(input.dashboardSnapshot || {}),
|
|
101
102
|
mode: String(input.dashboardSnapshot?.mode || 'naruto'),
|
|
@@ -104,12 +105,41 @@ export async function openWorkerPane(input) {
|
|
|
104
105
|
}
|
|
105
106
|
})
|
|
106
107
|
: null;
|
|
108
|
+
if (rightColumn?.placement === 'headless') {
|
|
109
|
+
const record = buildWorkerPaneArtifact({
|
|
110
|
+
...input,
|
|
111
|
+
paneId: null,
|
|
112
|
+
paneIdSource: 'zellij_worker_headless_overflow',
|
|
113
|
+
createSession,
|
|
114
|
+
launch: null,
|
|
115
|
+
paneReconciliation: null,
|
|
116
|
+
directionRequested: 'right',
|
|
117
|
+
directionApplied: 'not_applied',
|
|
118
|
+
rightColumn: {
|
|
119
|
+
mode: 'spawn-on-first-worker',
|
|
120
|
+
focus_pane_id: null,
|
|
121
|
+
y_order: null
|
|
122
|
+
},
|
|
123
|
+
status: 'running',
|
|
124
|
+
providerContext,
|
|
125
|
+
serviceTier: input.serviceTier || providerContext.service_tier,
|
|
126
|
+
scalingPrimitive: 'native_cli_process_headless_with_slot_dashboard',
|
|
127
|
+
blockers: []
|
|
128
|
+
});
|
|
129
|
+
await writeWorkerPaneArtifact(root, record);
|
|
130
|
+
await appendWorkerPaneEvent(root, 'worker_headless_overflow', input, {
|
|
131
|
+
slot_id: input.slotId,
|
|
132
|
+
generation_index: input.generationIndex,
|
|
133
|
+
reason: `visible_pane_cap:${input.visiblePaneCap || 1}`
|
|
134
|
+
});
|
|
135
|
+
return record;
|
|
136
|
+
}
|
|
107
137
|
const paneName = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || 'running', input.worktree || null);
|
|
108
|
-
const directionRequested = rightColumn ? 'down' : 'right';
|
|
138
|
+
const directionRequested = rightColumn?.focusPaneId ? 'down' : 'right';
|
|
109
139
|
const focus = rightColumn?.focusPaneId
|
|
110
140
|
? await focusZellijPaneById(input.sessionName, rightColumn.focusPaneId, cwd)
|
|
111
141
|
: null;
|
|
112
|
-
const newPaneArgs = ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, ...(
|
|
142
|
+
const newPaneArgs = ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, ...(directionRequested === 'down' ? ['--near-current-pane'] : []), '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
113
143
|
let launch = createSession.ok
|
|
114
144
|
? await runZellij(newPaneArgs, {
|
|
115
145
|
cwd,
|
|
@@ -119,9 +149,9 @@ export async function openWorkerPane(input) {
|
|
|
119
149
|
: null;
|
|
120
150
|
let directionApplied = launch?.ok ? directionRequested : 'not_applied';
|
|
121
151
|
if (createSession.ok && launch && !launch.ok) {
|
|
122
|
-
const fallbackArgs = rightColumn
|
|
152
|
+
const fallbackArgs = rightColumn && directionRequested === 'down'
|
|
123
153
|
? ['--session', input.sessionName, 'action', 'new-pane', '--direction', 'down', '--name', paneName, '--', 'sh', '-lc', input.workerCommand]
|
|
124
|
-
: ['--session', input.sessionName, 'action', 'new-pane', '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
154
|
+
: ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
125
155
|
const fallback = await runZellij(fallbackArgs, {
|
|
126
156
|
cwd,
|
|
127
157
|
timeoutMs: 5000,
|
|
@@ -204,7 +234,7 @@ export async function openWorkerPane(input) {
|
|
|
204
234
|
provider_context: record.provider_context,
|
|
205
235
|
direction_requested: record.direction_requested,
|
|
206
236
|
direction_applied: record.direction_applied,
|
|
207
|
-
command:
|
|
237
|
+
command: record.command,
|
|
208
238
|
worker_artifact_dir: input.workerArtifactDir,
|
|
209
239
|
worker_result_path: input.resultPath,
|
|
210
240
|
heartbeat_path: input.heartbeatPath,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate, importDist } from './sks-1-18-gate-lib.js';
|
|
7
|
+
const mod = await importDist('core/agents/agent-role-config.js');
|
|
8
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-role-repair-'));
|
|
9
|
+
fs.mkdirSync(path.join(root, '.sneakoscope', 'reports'), { recursive: true });
|
|
10
|
+
const plan = await mod.repairAgentRoleConfigs({ root, apply: false, codexHome: path.join(root, 'codex-home') });
|
|
11
|
+
const repair = await mod.repairAgentRoleConfigs({ root, apply: true, codexHome: path.join(root, 'codex-home'), reportPath: path.join(root, '.sneakoscope', 'reports', 'agent-role-config-repair.json') });
|
|
12
|
+
const analysisScout = path.join(root, '.codex', 'agents', 'analysis-scout.toml');
|
|
13
|
+
const staleRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-role-stale-'));
|
|
14
|
+
fs.mkdirSync(path.join(staleRoot, '.codex', 'agents'), { recursive: true });
|
|
15
|
+
fs.writeFileSync(path.join(staleRoot, '.codex', 'agents', 'analysis-scout.toml'), 'model = "gpt-5-codex"\nsandbox_mode = "read-only"\n');
|
|
16
|
+
const stalePlan = await mod.repairAgentRoleConfigs({ root: staleRoot, apply: false, codexHome: path.join(staleRoot, 'codex-home') });
|
|
17
|
+
const staleRepair = await mod.repairAgentRoleConfigs({ root: staleRoot, apply: true, codexHome: path.join(staleRoot, 'codex-home') });
|
|
18
|
+
const repairedText = fs.readFileSync(path.join(staleRoot, '.codex', 'agents', 'analysis-scout.toml'), 'utf8');
|
|
19
|
+
const report = {
|
|
20
|
+
schema: 'sks.agent-role-config-repair-check.v1',
|
|
21
|
+
plan_ok: plan.ok === true && plan.missing.includes('analysis-scout.toml'),
|
|
22
|
+
repair_ok: repair.ok === true,
|
|
23
|
+
analysis_scout_created: fs.existsSync(analysisScout),
|
|
24
|
+
created_matches_model: fs.readFileSync(analysisScout, 'utf8').includes('model = "gpt-5.5"'),
|
|
25
|
+
stale_detected: stalePlan.stale.includes('analysis-scout.toml'),
|
|
26
|
+
stale_repaired: staleRepair.repaired.includes('.codex/agents/analysis-scout.toml') && repairedText.includes('name = "analysis_scout"') && repairedText.includes('model = "gpt-5.5"'),
|
|
27
|
+
warnings_suppressed: repair.warnings_suppressed === true,
|
|
28
|
+
artifact_written: fs.existsSync(path.join(root, '.sneakoscope', 'reports', 'agent-role-config-repair.json'))
|
|
29
|
+
};
|
|
30
|
+
const ok = report.plan_ok && report.repair_ok && report.analysis_scout_created && report.created_matches_model && report.stale_detected && report.stale_repaired && report.warnings_suppressed && report.artifact_written;
|
|
31
|
+
assertGate(ok, 'doctor --fix must repair missing SKS-owned agent role configs', report);
|
|
32
|
+
emitGate('agent:role-config-repair', report);
|
|
33
|
+
//# sourceMappingURL=agent-role-config-repair-check.js.map
|
|
@@ -17,6 +17,8 @@ const integrationPath = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-integration-'
|
|
|
17
17
|
fs.rmSync(integrationPath, { recursive: true, force: true });
|
|
18
18
|
const integration = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-integrate', workerId: 'integration', slotId: 'integration' });
|
|
19
19
|
const report = await mergeMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: integration.worktree_path, diffs: [diff] });
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const mainReport = await mergeMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: repo, diffs: [diff] });
|
|
21
|
+
const mainContent = fs.readFileSync(path.join(repo, 'a.txt'), 'utf8');
|
|
22
|
+
assertGate(report.ok === true && report.applied_count === 1 && mainReport.ok === true && mainReport.applied_count === 1 && mainContent.includes('integrated'), 'git-worktree-diff must prevalidate in integration worktree and apply to main repo', { report, mainReport, mainContent });
|
|
23
|
+
emitGate('git:worktree-integration-primary', { applied_count: report.applied_count, main_applied_count: mainReport.applied_count });
|
|
22
24
|
//# sourceMappingURL=git-worktree-integration-primary-check.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { assertGate, emitGate, root } from './sks-1-18-gate-lib.js';
|
|
6
|
+
const orchestrator = fs.readFileSync(path.join(root, 'src/core/agents/agent-orchestrator.ts'), 'utf8');
|
|
7
|
+
const report = {
|
|
8
|
+
schema: 'sks.git-worktree-integration-primary-runtime-check.v1',
|
|
9
|
+
splits_worktree_entries: orchestrator.includes("entry.envelope?.source === 'git-worktree-diff'"),
|
|
10
|
+
uses_integration_worktree: orchestrator.includes('createGitIntegrationWorktree'),
|
|
11
|
+
uses_merge_queue: orchestrator.includes('applyGitWorktreeMergeQueue'),
|
|
12
|
+
applies_to_main_repo: orchestrator.includes('main_repo_apply') && orchestrator.includes('integrationWorktreePath: repoRoot'),
|
|
13
|
+
rollback_evidence: orchestrator.includes('rollback_evidence') && orchestrator.includes('captureGitWorktreeRollbackPlan') && orchestrator.includes('completeGitWorktreeRollbackPlan'),
|
|
14
|
+
bypasses_normal_apply: orchestrator.includes('const normalEntries') && orchestrator.includes('applyAgentPatchQueueEntry(root, entry') && orchestrator.includes('parallelEntries = disjointEntries'),
|
|
15
|
+
writes_report: orchestrator.includes('git-worktree-merge-queue-report.json')
|
|
16
|
+
};
|
|
17
|
+
const ok = report.splits_worktree_entries && report.uses_integration_worktree && report.uses_merge_queue && report.applies_to_main_repo && report.rollback_evidence && report.bypasses_normal_apply && report.writes_report;
|
|
18
|
+
assertGate(ok, 'git-worktree-diff entries must use integration merge queue primary path', report);
|
|
19
|
+
emitGate('git:worktree-integration-primary-runtime', report);
|
|
20
|
+
//# sourceMappingURL=git-worktree-integration-primary-runtime-check.js.map
|
|
@@ -17,6 +17,7 @@ const uncovered = [];
|
|
|
17
17
|
const GUARD_CALL = /\bguarded(WriteFile|Rm|Rename|Chmod|Xattr|Chflags|GlobalCodexConfigWrite|ProcessKill|PackageInstall|SkillSnapshotPromotion|Apply)\(/;
|
|
18
18
|
const RISKY = [
|
|
19
19
|
{ kind: 'write_file', token: 'fs.writeFile', re: /\bfs\.writeFile\(/ },
|
|
20
|
+
{ kind: 'write_file', token: 'fs.promises.writeFile', re: /\bfs\.promises\.writeFile\(/ },
|
|
20
21
|
{ kind: 'write_file', token: 'fsp.writeFile', re: /\bfsp\.writeFile\(/ },
|
|
21
22
|
{ kind: 'write_file', token: 'writeFileSync', re: /\b(?:fs\.)?writeFileSync\(/ },
|
|
22
23
|
{ kind: 'rm', token: 'fs.rm', re: /\bfs\.rm\(/ },
|
|
@@ -167,7 +168,7 @@ function processKillIsLivenessProbe(line) {
|
|
|
167
168
|
return /\bprocess\.kill\([^,\n]+,\s*0\s*\)/.test(line);
|
|
168
169
|
}
|
|
169
170
|
function codexHomeMutationOnLine(line) {
|
|
170
|
-
return /\b(?:writeTextAtomic|writeJsonAtomic|writeFileSync|fs\.writeFile|fsp\.writeFile|fs\.rm|fsp\.rm|fs\.rename|fsp\.rename|fs\.chmod|fsp\.chmod|copyFile|open)\b/.test(line)
|
|
171
|
+
return /\b(?:writeTextAtomic|writeJsonAtomic|writeFileSync|fs\.writeFile|fs\.promises\.writeFile|fsp\.writeFile|fs\.rm|fsp\.rm|fs\.rename|fsp\.rename|fs\.chmod|fsp\.chmod|copyFile|open)\b/.test(line)
|
|
171
172
|
&& /(?:~\/\.codex|CODEX_HOME|codexHome|codexLbHome|auth\.json|config\.toml)/.test(line);
|
|
172
173
|
}
|
|
173
174
|
function snippet(line) {
|
|
@@ -13,7 +13,7 @@ const governor = decideNarutoConcurrency({
|
|
|
13
13
|
});
|
|
14
14
|
const report = {
|
|
15
15
|
schema: 'sks.naruto-extreme-parallelism-check.v1',
|
|
16
|
-
ok: graph.total_work_items >= 200 && governor.safe_active_workers >= 16 && governor.safe_zellij_visible_panes <= governor.safe_active_workers && graph.mixed_work_kinds.length >= 6,
|
|
16
|
+
ok: graph.total_work_items >= 200 && governor.safe_active_workers >= 16 && governor.safe_zellij_visible_panes <= governor.safe_active_workers && governor.safe_zellij_visible_panes <= 8 && graph.mixed_work_kinds.length >= 6,
|
|
17
17
|
graph: { total_work_items: graph.total_work_items, mixed_work_kinds: graph.mixed_work_kinds, write_allowed_count: graph.write_allowed_count },
|
|
18
18
|
governor
|
|
19
19
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
7
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
8
|
+
import { decideNarutoConcurrency } from '../core/naruto/naruto-concurrency-governor.js';
|
|
9
|
+
import { runNarutoRealActivePool } from '../core/naruto/naruto-active-pool.js';
|
|
10
|
+
import { collectActualNarutoWorker, spawnActualNarutoWorker } from '../core/naruto/naruto-real-worker-runtime.js';
|
|
11
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 100, totalWorkItems: 200, writeCapable: true, maxActiveWorkers: 32 });
|
|
12
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-extreme-real-'));
|
|
13
|
+
const missionId = `M-naruto-extreme-real-${process.pid}`;
|
|
14
|
+
const governor = decideNarutoConcurrency({
|
|
15
|
+
requestedClones: 100,
|
|
16
|
+
totalWorkItems: graph.total_work_items,
|
|
17
|
+
pendingWorkQueueSize: graph.total_work_items,
|
|
18
|
+
backend: 'codex-sdk',
|
|
19
|
+
hardware: { cores: 16, loadAverage: [1, 1, 1], freeMemoryBytes: 64 * 1024 * 1024 * 1024, totalMemoryBytes: 128 * 1024 * 1024 * 1024, fileDescriptorLimit: 8192, processCount: 100, terminalRows: 48, remoteApiRateLimitBudget: 32, localLlmMaxParallelRequests: 8 }
|
|
20
|
+
});
|
|
21
|
+
const target = { ...governor, safe_active_workers: Math.min(32, governor.safe_active_workers), safe_zellij_visible_panes: Math.min(8, governor.safe_zellij_visible_panes) };
|
|
22
|
+
const report = await runNarutoRealActivePool({
|
|
23
|
+
graph,
|
|
24
|
+
governor: target,
|
|
25
|
+
spawnWorker: async (item, placement) => spawnActualNarutoWorker({
|
|
26
|
+
root: tempRoot,
|
|
27
|
+
missionId,
|
|
28
|
+
item,
|
|
29
|
+
placement,
|
|
30
|
+
backend: 'codex-sdk',
|
|
31
|
+
visiblePaneCap: target.safe_zellij_visible_panes,
|
|
32
|
+
zellijSessionName: `sks-${missionId}`
|
|
33
|
+
}),
|
|
34
|
+
collectWorker: async (handle) => collectActualNarutoWorker(handle),
|
|
35
|
+
enqueueVerification: async () => undefined,
|
|
36
|
+
updateDashboard: async () => undefined
|
|
37
|
+
});
|
|
38
|
+
const actualArtifacts = report.worker_lifecycle.every((row) => row.pid && row.worker_artifact_dir && fs.existsSync(path.join(row.worker_artifact_dir, 'worker-result.json')));
|
|
39
|
+
const ok = report.ok && report.max_observed_active_workers >= Math.ceil(target.safe_active_workers * 0.8) && report.active_pool_utilization >= 0.8 && report.headless_workers > 0 && report.visible_workers <= graph.total_work_items && actualArtifacts;
|
|
40
|
+
assertGate(ok, 'Naruto extreme parallelism must use actual child process active-pool lifecycle near cap with headless overflow', { report, target, actualArtifacts, tempRoot });
|
|
41
|
+
emitGate('naruto:extreme-parallelism-real', report);
|
|
42
|
+
//# sourceMappingURL=naruto-extreme-parallelism-real-check.js.map
|
|
@@ -32,7 +32,8 @@ const report = await runNarutoRealActivePool({
|
|
|
32
32
|
dashboardEvents += 1;
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
|
-
const
|
|
35
|
+
const processEvidence = report.worker_lifecycle.every((row) => row.pid == null || row.worker_artifact_dir != null);
|
|
36
|
+
const ok = report.ok && spawned === graph.total_work_items && collected === graph.total_work_items && report.max_observed_active_workers >= target.safe_active_workers && dashboardEvents > graph.total_work_items && report.active_cap === target.safe_active_workers && processEvidence;
|
|
36
37
|
assertGate(ok, 'Naruto real active pool must run spawn/collect lifecycle and refill to cap', { report, spawned, collected, dashboardEvents, target });
|
|
37
|
-
emitGate('naruto:real-active-pool', { spawned, collected, max_observed_active_workers: report.max_observed_active_workers, refill_latency_ms_p95: report.refill_latency_ms_p95 });
|
|
38
|
+
emitGate('naruto:real-active-pool', { spawned, collected, active_cap: report.active_cap, max_observed_active_workers: report.max_observed_active_workers, refill_latency_ms_p95: report.refill_latency_ms_p95, active_pool_utilization: report.active_pool_utilization });
|
|
38
39
|
//# sourceMappingURL=naruto-real-active-pool-check.js.map
|