sneakoscope 2.0.7 → 2.0.9
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 +1 -1
- 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 +44 -8
- package/dist/commands/zellij.js +144 -1
- package/dist/core/agents/agent-command-surface.js +4 -2
- package/dist/core/agents/agent-orchestrator.js +5 -2
- package/dist/core/agents/agent-patch-schema.js +4 -2
- package/dist/core/agents/native-cli-session-swarm.js +81 -9
- package/dist/core/commands/mad-sks-command.js +17 -1
- package/dist/core/commands/naruto-command.js +99 -7
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-repo-detection.js +7 -0
- package/dist/core/git/git-worktree-cleanup.js +14 -3
- package/dist/core/git/git-worktree-diff.js +7 -2
- package/dist/core/git/git-worktree-manager.js +9 -2
- package/dist/core/git/git-worktree-patch-envelope.js +5 -5
- package/dist/core/naruto/naruto-active-pool.js +108 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +16 -1
- package/dist/core/naruto/naruto-work-graph.js +2 -1
- package/dist/core/release/release-gate-cache-v2.js +117 -0
- package/dist/core/release/release-gate-dag.js +190 -0
- package/dist/core/release/release-gate-hermetic-env.js +32 -0
- package/dist/core/release/release-gate-node.js +62 -0
- package/dist/core/release/release-gate-report.js +11 -0
- package/dist/core/release/release-gate-resource-governor.js +54 -0
- package/dist/core/release/release-gate-scheduler.js +15 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-dashboard-pane.js +71 -0
- package/dist/core/zellij/zellij-dashboard-renderer.js +58 -0
- 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 +245 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +180 -15
- 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-diff-envelope-check.js +17 -0
- package/dist/scripts/git-worktree-dirty-lock-check.js +17 -0
- package/dist/scripts/git-worktree-dirty-main-detection-check.js +14 -0
- package/dist/scripts/git-worktree-integration-primary-check.js +22 -0
- package/dist/scripts/git-worktree-manifest-append-check.js +18 -0
- package/dist/scripts/git-worktree-untracked-diff-check.js +18 -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/naruto-concurrency-governor-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
- package/dist/scripts/naruto-real-active-pool-check.js +38 -0
- package/dist/scripts/naruto-work-graph-check.js +1 -1
- package/dist/scripts/naruto-worktree-coding-blackbox.js +29 -0
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +21 -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/release-cache-glob-hashing-check.js +42 -0
- package/dist/scripts/release-dag-full-coverage-check.js +35 -0
- package/dist/scripts/release-gate-dag-runner-check.js +17 -0
- package/dist/scripts/release-gate-dag-runner.js +32 -0
- package/dist/scripts/release-gate-worker.js +10 -0
- package/dist/scripts/release-metadata-1-19-check.js +8 -2
- package/dist/scripts/release-parallel-speed-budget-check.js +79 -0
- package/dist/scripts/release-readiness-report.js +1 -1
- package/dist/scripts/release-stability-report-check.js +99 -0
- package/dist/scripts/zellij-dashboard-pane-check.js +70 -0
- package/dist/scripts/zellij-dashboard-watch.js +41 -0
- 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 +29 -0
- package/dist/scripts/zellij-right-column-manager-check.js +22 -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/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +185 -0
- package/package.json +32 -5
- package/schemas/release/release-gate-node.schema.json +52 -0
- package/schemas/zellij/zellij-right-column-state.schema.json +41 -0
|
@@ -4,6 +4,7 @@ import { providerPaneLabel } from '../provider/provider-badge.js';
|
|
|
4
4
|
import { resolveProviderContext } from '../provider/provider-context.js';
|
|
5
5
|
import { runZellij } from './zellij-command.js';
|
|
6
6
|
import { extractZellijPaneIdFromOutput } from './zellij-lane-runtime.js';
|
|
7
|
+
import { closeWorkerInRightColumn, prepareWorkerInRightColumn, recordWorkerPaneInRightColumn } from './zellij-right-column-manager.js';
|
|
7
8
|
export const ZELLIJ_WORKER_PANE_SCHEMA = 'sks.zellij-worker-pane.v1';
|
|
8
9
|
export const ZELLIJ_WORKER_PANE_EVENT_SCHEMA = 'sks.zellij-worker-pane-event.v1';
|
|
9
10
|
export function buildWorkerPaneName(slotId, generationIndex) {
|
|
@@ -23,7 +24,7 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
23
24
|
const paneIdSource = input.paneIdSource || 'zellij_worker_pane_launch_failed';
|
|
24
25
|
const blockers = input.blockers || [];
|
|
25
26
|
const providerContext = normalizePaneProviderContext(input.providerContext, input.serviceTier);
|
|
26
|
-
const paneTitle = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.
|
|
27
|
+
const paneTitle = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || input.status, input.worktree || null);
|
|
27
28
|
return {
|
|
28
29
|
schema: ZELLIJ_WORKER_PANE_SCHEMA,
|
|
29
30
|
generated_at: now,
|
|
@@ -59,8 +60,9 @@ export function buildWorkerPaneArtifact(input) {
|
|
|
59
60
|
opened_at: now,
|
|
60
61
|
closed_at: null,
|
|
61
62
|
close: null,
|
|
62
|
-
direction_requested: 'right',
|
|
63
|
+
direction_requested: input.directionRequested || 'right',
|
|
63
64
|
direction_applied: input.directionApplied || 'not_applied',
|
|
65
|
+
right_column: input.rightColumn || null,
|
|
64
66
|
sdk_thread_id: input.sdkThreadId || null,
|
|
65
67
|
sdk_run_id: input.sdkRunId || null,
|
|
66
68
|
stream_event_count: Number(input.streamEventCount || 0),
|
|
@@ -79,34 +81,61 @@ export async function openWorkerPane(input) {
|
|
|
79
81
|
const workerDir = path.join(root, input.workerArtifactDir);
|
|
80
82
|
await ensureDir(workerDir);
|
|
81
83
|
await appendWorkerPaneEvent(root, 'session_launch_started', input, {});
|
|
82
|
-
const
|
|
84
|
+
const createSessionRaw = await runZellij(['attach', '--create-background', input.sessionName], {
|
|
83
85
|
cwd,
|
|
84
86
|
timeoutMs: 5000,
|
|
85
87
|
optional: false
|
|
86
88
|
});
|
|
89
|
+
const createSession = normalizeExistingZellijSession(input.sessionName, createSessionRaw);
|
|
90
|
+
const rightColumn = input.rightColumnMode === 'spawn-on-first-worker'
|
|
91
|
+
? await prepareWorkerInRightColumn({
|
|
92
|
+
root,
|
|
93
|
+
...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
|
|
94
|
+
missionId: input.missionId,
|
|
95
|
+
sessionName: input.sessionName,
|
|
96
|
+
cwd,
|
|
97
|
+
worker: { slotId: input.slotId, generationIndex: input.generationIndex },
|
|
98
|
+
visiblePaneCap: input.visiblePaneCap || 1,
|
|
99
|
+
dashboardSnapshot: {
|
|
100
|
+
...(input.dashboardSnapshot || {}),
|
|
101
|
+
mode: String(input.dashboardSnapshot?.mode || 'naruto'),
|
|
102
|
+
active_workers: Number(input.dashboardSnapshot?.active_workers || input.visiblePaneCap || 1),
|
|
103
|
+
visible_panes: Number(input.dashboardSnapshot?.visible_panes || input.visiblePaneCap || 1)
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
: null;
|
|
87
107
|
const paneName = buildWorkerPaneTitle(input.slotId, input.generationIndex, providerContext, input.serviceTier, input.backend, input.statusLabel || 'running', input.worktree || null);
|
|
108
|
+
const directionRequested = rightColumn ? 'down' : 'right';
|
|
109
|
+
const focus = rightColumn?.focusPaneId
|
|
110
|
+
? await focusZellijPaneById(input.sessionName, rightColumn.focusPaneId, cwd)
|
|
111
|
+
: null;
|
|
112
|
+
const newPaneArgs = ['--session', input.sessionName, 'action', 'new-pane', '--direction', directionRequested, ...(rightColumn ? ['--near-current-pane'] : []), '--name', paneName, '--', 'sh', '-lc', input.workerCommand];
|
|
88
113
|
let launch = createSession.ok
|
|
89
|
-
? await runZellij(
|
|
114
|
+
? await runZellij(newPaneArgs, {
|
|
90
115
|
cwd,
|
|
91
116
|
timeoutMs: 5000,
|
|
92
117
|
optional: false
|
|
93
118
|
})
|
|
94
119
|
: null;
|
|
95
|
-
let directionApplied = launch?.ok ?
|
|
120
|
+
let directionApplied = launch?.ok ? directionRequested : 'not_applied';
|
|
96
121
|
if (createSession.ok && launch && !launch.ok) {
|
|
97
|
-
const
|
|
122
|
+
const fallbackArgs = rightColumn
|
|
123
|
+
? ['--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];
|
|
125
|
+
const fallback = await runZellij(fallbackArgs, {
|
|
98
126
|
cwd,
|
|
99
127
|
timeoutMs: 5000,
|
|
100
128
|
optional: false
|
|
101
129
|
});
|
|
102
130
|
if (fallback.ok) {
|
|
103
131
|
launch = fallback;
|
|
104
|
-
directionApplied = 'unknown';
|
|
132
|
+
directionApplied = rightColumn ? 'down' : 'unknown';
|
|
105
133
|
}
|
|
106
134
|
}
|
|
107
135
|
const stdoutPaneId = launch?.ok ? extractZellijPaneIdFromOutput(launch.stdout_tail) : null;
|
|
108
136
|
const reconciledPane = stdoutPaneId ? null : launch?.ok ? await reconcileZellijWorkerPaneId(input.sessionName, paneName, path.join(root, input.resultPath), cwd) : null;
|
|
109
137
|
const paneId = stdoutPaneId || reconciledPane?.pane_id || null;
|
|
138
|
+
const renamePane = paneId ? await renameZellijPaneById(input.sessionName, paneId, paneName, cwd) : null;
|
|
110
139
|
const paneIdSource = stdoutPaneId
|
|
111
140
|
? 'zellij_worker_new_pane_stdout'
|
|
112
141
|
: reconciledPane?.pane_id
|
|
@@ -116,6 +145,7 @@ export async function openWorkerPane(input) {
|
|
|
116
145
|
: 'zellij_worker_pane_launch_failed';
|
|
117
146
|
const blockers = [
|
|
118
147
|
...(createSession.ok ? [] : createSession.blockers.map((blocker) => `zellij_worker_session_${blocker}`)),
|
|
148
|
+
...(rightColumn && rightColumn.placement !== 'zellij-pane' ? [`zellij_worker_right_column_${rightColumn.placement}`] : []),
|
|
119
149
|
...(launch && !launch.ok ? launch.blockers.map((blocker) => `zellij_worker_pane_${blocker}`) : []),
|
|
120
150
|
...(launch?.ok && !isRealZellijWorkerPaneIdSource(paneIdSource) ? ['zellij_worker_pane_id_real_source_missing'] : [])
|
|
121
151
|
];
|
|
@@ -125,14 +155,30 @@ export async function openWorkerPane(input) {
|
|
|
125
155
|
paneIdSource,
|
|
126
156
|
createSession,
|
|
127
157
|
launch,
|
|
128
|
-
paneReconciliation:
|
|
158
|
+
paneReconciliation: {
|
|
159
|
+
...(reconciledPane || {}),
|
|
160
|
+
focus_pane: focus,
|
|
161
|
+
focus_degraded: focus ? focus.ok !== true : false,
|
|
162
|
+
rename_pane: renamePane
|
|
163
|
+
},
|
|
164
|
+
directionRequested,
|
|
129
165
|
directionApplied,
|
|
166
|
+
rightColumn: rightColumn ? { mode: 'spawn-on-first-worker', focus_pane_id: rightColumn.focusPaneId, y_order: rightColumn.yOrder } : null,
|
|
130
167
|
status: blockers.length ? 'failed' : 'running',
|
|
131
168
|
providerContext,
|
|
132
169
|
serviceTier: input.serviceTier || providerContext.service_tier,
|
|
133
170
|
blockers
|
|
134
171
|
});
|
|
135
172
|
await writeWorkerPaneArtifact(root, record);
|
|
173
|
+
if (rightColumn) {
|
|
174
|
+
await recordWorkerPaneInRightColumn({
|
|
175
|
+
root,
|
|
176
|
+
...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
|
|
177
|
+
missionId: input.missionId,
|
|
178
|
+
record,
|
|
179
|
+
yOrder: rightColumn.yOrder
|
|
180
|
+
});
|
|
181
|
+
}
|
|
136
182
|
await appendWorkerPaneEvent(root, 'zellij_worker_pane_created', input, {
|
|
137
183
|
ok: record.ok,
|
|
138
184
|
pane_id: record.pane_id,
|
|
@@ -172,12 +218,16 @@ export async function openWorkerPane(input) {
|
|
|
172
218
|
}
|
|
173
219
|
export async function closeWorkerPane(input) {
|
|
174
220
|
const root = path.resolve(input.root);
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
221
|
+
const success = (input.status || 'closed') === 'closed' && !(input.blockers || []).length;
|
|
222
|
+
const closeSuccess = process.env.SKS_ZELLIJ_CLOSE_WORKER_PANE !== '0';
|
|
223
|
+
const closeFailed = process.env.SKS_ZELLIJ_CLOSE_FAILED_PANE === '1' || process.env.SKS_ZELLIJ_KEEP_FAILED_PANE === '0';
|
|
224
|
+
const paneId = input.paneRecord.pane_id;
|
|
225
|
+
const shouldClose = Boolean(paneId) && (success ? closeSuccess : closeFailed);
|
|
226
|
+
const close = shouldClose
|
|
227
|
+
? await closeZellijPaneById(input.paneRecord.session_name, paneId || '', input.cwd || packageRoot())
|
|
228
|
+
: null;
|
|
229
|
+
const rename = !shouldClose && paneId
|
|
230
|
+
? await renameZellijPaneById(input.paneRecord.session_name, paneId, `${input.paneRecord.pane_title} · ${success ? 'drained' : 'failed'}`, input.cwd || packageRoot())
|
|
181
231
|
: null;
|
|
182
232
|
const next = {
|
|
183
233
|
...input.paneRecord,
|
|
@@ -191,9 +241,25 @@ export async function closeWorkerPane(input) {
|
|
|
191
241
|
stream_event_count: Number(input.streamEventCount || input.paneRecord.stream_event_count || 0),
|
|
192
242
|
structured_output_valid: input.structuredOutputValid === true || input.paneRecord.structured_output_valid === true,
|
|
193
243
|
worker_result_path: input.workerResultPath || input.paneRecord.worker_result_path,
|
|
194
|
-
blockers: [
|
|
244
|
+
blockers: [
|
|
245
|
+
...input.paneRecord.blockers,
|
|
246
|
+
...(input.blockers || []),
|
|
247
|
+
...(close && !close.ok ? close.blockers.map((blocker) => `zellij_worker_close_${blocker}`) : []),
|
|
248
|
+
...(rename && !rename.ok ? rename.blockers.map((blocker) => `zellij_worker_rename_${blocker}`) : [])
|
|
249
|
+
]
|
|
195
250
|
};
|
|
196
251
|
await writeWorkerPaneArtifact(root, next);
|
|
252
|
+
if (next.right_column?.mode === 'spawn-on-first-worker') {
|
|
253
|
+
await closeWorkerInRightColumn({
|
|
254
|
+
root,
|
|
255
|
+
...(input.projectRoot ? { projectRoot: input.projectRoot } : {}),
|
|
256
|
+
missionId: next.mission_id,
|
|
257
|
+
slotId: next.slot_id,
|
|
258
|
+
generationIndex: next.generation_index,
|
|
259
|
+
paneId: next.pane_id,
|
|
260
|
+
status: next.status === 'failed' ? 'failed' : close?.ok ? 'closed' : 'draining'
|
|
261
|
+
});
|
|
262
|
+
}
|
|
197
263
|
await appendWorkerPaneEvent(root, 'pane_closed', {
|
|
198
264
|
root,
|
|
199
265
|
missionId: next.mission_id,
|
|
@@ -262,6 +328,11 @@ async function reconcileZellijWorkerPaneId(sessionName, paneName, resultPath, cw
|
|
|
262
328
|
timeoutMs: 5000,
|
|
263
329
|
optional: true
|
|
264
330
|
});
|
|
331
|
+
const screen = await runZellij(['--session', sessionName, 'action', 'dump-screen'], {
|
|
332
|
+
cwd,
|
|
333
|
+
timeoutMs: 5000,
|
|
334
|
+
optional: true
|
|
335
|
+
});
|
|
265
336
|
const rows = parsePaneRows(listed.stdout_tail);
|
|
266
337
|
const pane = rows.find((row) => {
|
|
267
338
|
const title = String(row.title || row.name || row.pane_name || '');
|
|
@@ -280,6 +351,7 @@ async function reconcileZellijWorkerPaneId(sessionName, paneName, resultPath, cw
|
|
|
280
351
|
pane_id: paneId == null ? null : String(paneId),
|
|
281
352
|
listed_count: rows.length,
|
|
282
353
|
command: listed,
|
|
354
|
+
dump_screen: screen,
|
|
283
355
|
blockers: paneId == null ? ['zellij_worker_pane_id_not_reconciled'] : []
|
|
284
356
|
};
|
|
285
357
|
}
|
|
@@ -330,4 +402,97 @@ function parsePaneRows(text) {
|
|
|
330
402
|
return [];
|
|
331
403
|
}
|
|
332
404
|
}
|
|
405
|
+
async function renameZellijPaneById(sessionName, paneId, paneName, cwd) {
|
|
406
|
+
const numeric = Number.parseInt(paneId.replace(/^terminal_/, ''), 10);
|
|
407
|
+
const numericCandidates = Number.isFinite(numeric)
|
|
408
|
+
? [numeric, numeric + 1, numeric - 1].filter((value) => value >= 0).map(String)
|
|
409
|
+
: [];
|
|
410
|
+
const candidates = [...new Set([paneId, paneId.replace(/^terminal_/, ''), ...numericCandidates].filter(Boolean))];
|
|
411
|
+
let last = null;
|
|
412
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
413
|
+
if (attempt > 0)
|
|
414
|
+
await sleep(200 * attempt);
|
|
415
|
+
for (const candidate of candidates) {
|
|
416
|
+
last = await runZellij(['--session', sessionName, 'action', 'rename-pane', '--pane-id', candidate, paneName], {
|
|
417
|
+
cwd,
|
|
418
|
+
timeoutMs: 5000,
|
|
419
|
+
optional: true
|
|
420
|
+
});
|
|
421
|
+
if (last.ok)
|
|
422
|
+
return last;
|
|
423
|
+
const focus = await runZellij(['--session', sessionName, 'action', 'focus-pane-id', candidate], {
|
|
424
|
+
cwd,
|
|
425
|
+
timeoutMs: 5000,
|
|
426
|
+
optional: true
|
|
427
|
+
});
|
|
428
|
+
if (focus.ok) {
|
|
429
|
+
last = await runZellij(['--session', sessionName, 'action', 'rename-pane', paneName], {
|
|
430
|
+
cwd,
|
|
431
|
+
timeoutMs: 5000,
|
|
432
|
+
optional: true
|
|
433
|
+
});
|
|
434
|
+
if (last.ok)
|
|
435
|
+
return last;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return last;
|
|
440
|
+
}
|
|
441
|
+
async function focusZellijPaneById(sessionName, paneId, cwd) {
|
|
442
|
+
const candidates = zellijPaneIdCandidates(paneId);
|
|
443
|
+
let last = null;
|
|
444
|
+
for (const candidate of candidates) {
|
|
445
|
+
const focus = await runZellij(['--session', sessionName, 'action', 'focus-pane-id', candidate], {
|
|
446
|
+
cwd,
|
|
447
|
+
timeoutMs: 5000,
|
|
448
|
+
optional: true
|
|
449
|
+
});
|
|
450
|
+
last = focus;
|
|
451
|
+
if (focus.ok)
|
|
452
|
+
return focus;
|
|
453
|
+
}
|
|
454
|
+
return last;
|
|
455
|
+
}
|
|
456
|
+
async function closeZellijPaneById(sessionName, paneId, cwd) {
|
|
457
|
+
const candidates = zellijPaneIdCandidates(paneId);
|
|
458
|
+
let last = null;
|
|
459
|
+
for (const candidate of candidates) {
|
|
460
|
+
const close = await runZellij(['--session', sessionName, 'action', 'close-pane', '--pane-id', candidate], {
|
|
461
|
+
cwd,
|
|
462
|
+
timeoutMs: 5000,
|
|
463
|
+
optional: true
|
|
464
|
+
});
|
|
465
|
+
last = close;
|
|
466
|
+
if (close.ok)
|
|
467
|
+
return close;
|
|
468
|
+
}
|
|
469
|
+
return last;
|
|
470
|
+
}
|
|
471
|
+
function zellijPaneIdCandidates(paneId) {
|
|
472
|
+
const raw = String(paneId || '').trim();
|
|
473
|
+
const numeric = raw.replace(/^terminal_/, '');
|
|
474
|
+
const parsed = Number.parseInt(numeric, 10);
|
|
475
|
+
return [...new Set([
|
|
476
|
+
raw,
|
|
477
|
+
numeric,
|
|
478
|
+
Number.isFinite(parsed) ? String(parsed) : '',
|
|
479
|
+
Number.isFinite(parsed) ? `terminal_${parsed}` : ''
|
|
480
|
+
].filter(Boolean))];
|
|
481
|
+
}
|
|
482
|
+
function sleep(ms) {
|
|
483
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
484
|
+
}
|
|
485
|
+
function normalizeExistingZellijSession(sessionName, result) {
|
|
486
|
+
if (result.ok)
|
|
487
|
+
return result;
|
|
488
|
+
if (/Session already exists/i.test(result.stderr_tail || '')) {
|
|
489
|
+
return {
|
|
490
|
+
...result,
|
|
491
|
+
ok: true,
|
|
492
|
+
blockers: [],
|
|
493
|
+
warnings: [...result.warnings, `zellij_session_already_exists:${sessionName}`]
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
return result;
|
|
497
|
+
}
|
|
333
498
|
//# sourceMappingURL=zellij-worker-pane-manager.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @ts-nocheck
|
|
3
|
-
import { assertGate, emitGate, packageScripts, readText } from './lib/codex-sdk-gate-lib.js';
|
|
3
|
+
import { assertGate, emitGate, packageScripts, readText, releaseGateIds } from './lib/codex-sdk-gate-lib.js';
|
|
4
4
|
const scripts = packageScripts();
|
|
5
|
-
const releaseCheck = String(scripts['release:check'] || '');
|
|
6
5
|
const releaseRealCheck = String(scripts['release:real-check'] || '');
|
|
7
|
-
|
|
8
|
-
assertGate(
|
|
6
|
+
const releaseGates = releaseGateIds();
|
|
7
|
+
assertGate(releaseGates.has('codex-sdk:capability'), 'release gate DAG must include Codex SDK capability gate');
|
|
8
|
+
assertGate(releaseGates.has('codex-sdk:all-pipelines'), 'release gate DAG must include Codex SDK all-pipelines gate');
|
|
9
9
|
assertGate(releaseRealCheck.includes('codex-sdk:real-smoke'), 'release:real-check must include Codex SDK real smoke');
|
|
10
10
|
assertGate(readText('src/core/agents/agent-orchestrator.ts').includes('legacy_codex_exec_runtime_removed'), 'orchestrator must block legacy codex-exec requests');
|
|
11
|
-
emitGate('codex-sdk:release-review-pipeline', {
|
|
11
|
+
emitGate('codex-sdk:release-review-pipeline', { release_gate_dag_contains_sdk: true });
|
|
12
12
|
//# sourceMappingURL=codex-sdk-release-review-pipeline-check.js.map
|
|
@@ -25,19 +25,40 @@ const run = spawnSync(process.execPath, [
|
|
|
25
25
|
SKS_DISABLE_UPDATE_CHECK: '1'
|
|
26
26
|
},
|
|
27
27
|
encoding: 'utf8',
|
|
28
|
-
timeout:
|
|
28
|
+
timeout: 180000
|
|
29
29
|
});
|
|
30
30
|
const parsed = parseLastJson(run.stdout || '{}');
|
|
31
31
|
const ok = run.status !== 0
|
|
32
32
|
&& parsed.ready?.ready === false
|
|
33
33
|
&& parsed.ready?.blockers?.includes('codex_cli_config_eperm')
|
|
34
34
|
&& parsed.ready?.next_actions?.length > 0;
|
|
35
|
-
console.log(JSON.stringify({
|
|
35
|
+
console.log(JSON.stringify({
|
|
36
|
+
schema: 'sks.doctor-fix-proves-codex-read-check.v1',
|
|
37
|
+
ok,
|
|
38
|
+
status: run.status,
|
|
39
|
+
signal: run.signal,
|
|
40
|
+
error: run.error ? String(run.error.message || run.error) : null,
|
|
41
|
+
parsed,
|
|
42
|
+
stdout_tail: String(run.stdout || '').slice(-1000),
|
|
43
|
+
stderr_tail: String(run.stderr || '').slice(-1000)
|
|
44
|
+
}, null, 2));
|
|
36
45
|
if (!ok)
|
|
37
46
|
process.exitCode = 1;
|
|
38
47
|
function parseLastJson(text) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
const source = String(text || '').trim();
|
|
49
|
+
if (!source)
|
|
50
|
+
return {};
|
|
51
|
+
const starts = [];
|
|
52
|
+
for (let index = source.indexOf('{'); index >= 0; index = source.indexOf('{', index + 1))
|
|
53
|
+
starts.push(index);
|
|
54
|
+
for (let i = starts.length - 1; i >= 0; i -= 1) {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(source.slice(starts[i]));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Continue searching for the outer JSON object; pretty JSON may contain nested objects.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {};
|
|
42
63
|
}
|
|
43
64
|
//# sourceMappingURL=doctor-fix-proves-codex-read-check.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { assertGate, emitGate, importDist } from './sks-1-18-gate-lib.js';
|
|
4
|
+
const envelopeMod = await importDist('core/git/git-worktree-patch-envelope.js');
|
|
5
|
+
const schemaMod = await importDist('core/agents/agent-patch-schema.js');
|
|
6
|
+
const envelope = envelopeMod.buildGitWorktreePatchEnvelope({
|
|
7
|
+
diff: { schema: 'sks.git-worktree-diff.v1', mission_id: 'M-env', worker_id: 'worker-1', main_repo_root: '.', worktree_path: '.', branch: null, base_head: null, worktree_head: null, changed_files: ['a.txt', 'b.txt'], diff_bytes: 12, diff: 'diff --git a/a.txt b/a.txt\n', clean: false },
|
|
8
|
+
agentId: 'agent-1',
|
|
9
|
+
sessionId: 'session-1',
|
|
10
|
+
slotId: 'slot-001',
|
|
11
|
+
generationIndex: 1
|
|
12
|
+
});
|
|
13
|
+
const validation = schemaMod.validateAgentPatchEnvelope(schemaMod.normalizeAgentPatchEnvelope(envelope));
|
|
14
|
+
assertGate(envelope.operations.length === 1 && envelope.operations[0].op === 'git_apply_patch', 'git worktree envelope must use one git_apply_patch operation', envelope);
|
|
15
|
+
assertGate(validation.ok === true, 'git_apply_patch envelope must validate', validation);
|
|
16
|
+
emitGate('git:worktree-diff-envelope', { operations: envelope.operations.length, op: envelope.operations[0].op });
|
|
17
|
+
//# sourceMappingURL=git-worktree-diff-envelope-check.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
import { makeGitFixture } from './lib/git-worktree-fixture.js';
|
|
8
|
+
const managerMod = await importDist('core/git/git-worktree-manager.js');
|
|
9
|
+
const cleanupMod = await importDist('core/git/git-worktree-cleanup.js');
|
|
10
|
+
const repo = makeGitFixture('dirty-lock');
|
|
11
|
+
process.env.SKS_WORKTREE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-wt-lock-'));
|
|
12
|
+
const allocation = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-lock', workerId: 'worker-1', slotId: 'slot-001' });
|
|
13
|
+
fs.writeFileSync(path.join(allocation.worktree_path, 'a.txt'), 'dirty\n');
|
|
14
|
+
const cleanup = await cleanupMod.cleanupGitWorktree({ repoRoot: repo, worktreePath: allocation.worktree_path, branch: allocation.branch });
|
|
15
|
+
assertGate(cleanup.action === 'retained_dirty' && cleanup.git_locked === true, 'dirty retained worktree must be git locked', cleanup);
|
|
16
|
+
emitGate('git:worktree-dirty-lock', { git_locked: cleanup.git_locked, unlock_command: cleanup.unlock_command });
|
|
17
|
+
//# sourceMappingURL=git-worktree-dirty-lock-check.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { assertGate, emitGate, importDist } from './sks-1-18-gate-lib.js';
|
|
6
|
+
import { makeGitFixture } from './lib/git-worktree-fixture.js';
|
|
7
|
+
const detectionMod = await importDist('core/git/git-repo-detection.js');
|
|
8
|
+
const repo = makeGitFixture('dirty-main-detection');
|
|
9
|
+
fs.writeFileSync(path.join(repo, 'dirty.txt'), 'dirty\n');
|
|
10
|
+
const detection = await detectionMod.detectGitRepo(repo);
|
|
11
|
+
assertGate(detection.main_worktree_dirty === true, 'dirty main worktree must be detected', detection);
|
|
12
|
+
assertGate(String(detection.status_porcelain).includes('dirty.txt'), 'status_porcelain must include dirty file', detection);
|
|
13
|
+
emitGate('git:worktree-dirty-main-detection', { dirty: detection.main_worktree_dirty });
|
|
14
|
+
//# sourceMappingURL=git-worktree-dirty-main-detection-check.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
import { makeGitFixture } from './lib/git-worktree-fixture.js';
|
|
8
|
+
const managerMod = await importDist('core/git/git-worktree-manager.js');
|
|
9
|
+
const diffMod = await importDist('core/git/git-worktree-diff.js');
|
|
10
|
+
const mergeMod = await importDist('core/git/git-worktree-merge-queue.js');
|
|
11
|
+
const repo = makeGitFixture('integration-primary');
|
|
12
|
+
process.env.SKS_WORKTREE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-wt-integration-'));
|
|
13
|
+
const allocation = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-integrate', workerId: 'worker-1', slotId: 'slot-001' });
|
|
14
|
+
fs.writeFileSync(path.join(allocation.worktree_path, 'a.txt'), 'alpha\nintegrated\n');
|
|
15
|
+
const diff = await diffMod.exportGitWorktreeDiff({ mainRepoRoot: repo, worktreePath: allocation.worktree_path, missionId: 'M-integrate', workerId: 'worker-1' });
|
|
16
|
+
const integrationPath = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-integration-'));
|
|
17
|
+
fs.rmSync(integrationPath, { recursive: true, force: true });
|
|
18
|
+
const integration = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-integrate', workerId: 'integration', slotId: 'integration' });
|
|
19
|
+
const report = await mergeMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: integration.worktree_path, diffs: [diff] });
|
|
20
|
+
assertGate(report.ok === true && report.applied_count === 1, 'git-worktree-diff must apply through merge queue', report);
|
|
21
|
+
emitGate('git:worktree-integration-primary', { applied_count: report.applied_count });
|
|
22
|
+
//# sourceMappingURL=git-worktree-integration-primary-check.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
import { makeGitFixture } from './lib/git-worktree-fixture.js';
|
|
8
|
+
const managerMod = await importDist('core/git/git-worktree-manager.js');
|
|
9
|
+
const repo = makeGitFixture('worktree-manifest-append');
|
|
10
|
+
process.env.SKS_WORKTREE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-wt-manifest-'));
|
|
11
|
+
const allocations = [];
|
|
12
|
+
for (let index = 0; index < 4; index += 1) {
|
|
13
|
+
allocations.push(await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-manifest', workerId: `worker-${index}`, slotId: `slot-${index}` }));
|
|
14
|
+
}
|
|
15
|
+
const manifest = JSON.parse(fs.readFileSync(allocations[0].manifest_path, 'utf8'));
|
|
16
|
+
assertGate(manifest.allocations.length >= allocations.length, 'manifest append must preserve allocations', manifest);
|
|
17
|
+
emitGate('git:worktree-manifest-append', { allocations: manifest.allocations.length });
|
|
18
|
+
//# sourceMappingURL=git-worktree-manifest-append-check.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
import { makeGitFixture } from './lib/git-worktree-fixture.js';
|
|
8
|
+
const managerMod = await importDist('core/git/git-worktree-manager.js');
|
|
9
|
+
const diffMod = await importDist('core/git/git-worktree-diff.js');
|
|
10
|
+
const repo = makeGitFixture('untracked-diff');
|
|
11
|
+
process.env.SKS_WORKTREE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-wt-untracked-'));
|
|
12
|
+
const allocation = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-untracked', workerId: 'worker-1', slotId: 'slot-001' });
|
|
13
|
+
fs.writeFileSync(path.join(allocation.worktree_path, 'new-file.txt'), 'new content\n');
|
|
14
|
+
const diff = await diffMod.exportGitWorktreeDiff({ mainRepoRoot: repo, worktreePath: allocation.worktree_path, missionId: 'M-untracked', workerId: 'worker-1' });
|
|
15
|
+
assertGate(diff.changed_files.includes('new-file.txt'), 'changed files must include untracked file', diff);
|
|
16
|
+
assertGate(diff.diff.includes('new file mode') && diff.diff.includes('+new content'), 'git diff must include untracked file content', { diff: diff.diff });
|
|
17
|
+
emitGate('git:worktree-untracked-diff', { changed_files: diff.changed_files });
|
|
18
|
+
//# sourceMappingURL=git-worktree-untracked-diff-check.js.map
|
|
@@ -59,6 +59,10 @@ export async function runFakeCodexSdkTaskFixture(label = 'fixture', extra = {})
|
|
|
59
59
|
export function packageScripts() {
|
|
60
60
|
return readJson('package.json').scripts || {};
|
|
61
61
|
}
|
|
62
|
+
export function releaseGateIds() {
|
|
63
|
+
const manifest = readJson('release-gates.v2.json');
|
|
64
|
+
return new Set((manifest.gates || []).map((gate) => gate.id));
|
|
65
|
+
}
|
|
62
66
|
export function assertSourceIncludes(file, tokens) {
|
|
63
67
|
const text = readText(file);
|
|
64
68
|
for (const token of tokens)
|
|
@@ -17,10 +17,10 @@ const checks = {
|
|
|
17
17
|
zellij_session_before_swarm: launchIndex >= 0 && swarmIndex >= 0 && launchIndex < swarmIndex,
|
|
18
18
|
main_only_session: mad.includes('slotCount: 0'),
|
|
19
19
|
zellij_default_backend: /return 'zellij'/.test(mad) && mad.includes("list.includes('--json')") && mad.includes("list.includes('--no-attach')"),
|
|
20
|
-
worker_command_real_zellij: mad.includes("command.push('--real')") && mad.includes("command.push('--zellij-session-name'") && mad.includes("command.push('--zellij-pane-worker')"),
|
|
20
|
+
worker_command_real_zellij: mad.includes("command.push('--real')") && mad.includes("command.push('--zellij-session-name'") && mad.includes("command.push('--zellij-pane-worker')") && mad.includes("command.push('--worker-placement'"),
|
|
21
21
|
parser_accepts_worker_flags: parser.includes('--zellij-session-name') && parser.includes('--zellij-pane-worker') && parser.includes('--no-zellij-pane-worker'),
|
|
22
22
|
native_worker_pane_path: swarm.includes("this.input.backend === 'zellij'") && swarm.includes('ctx.opts.zellijPaneWorker !== false') && swarm.includes('openWorkerPane({'),
|
|
23
|
-
right_pane_requested: manager.includes("'--direction', '
|
|
23
|
+
right_pane_requested: manager.includes("'--direction', directionRequested") && manager.includes("'--near-current-pane'")
|
|
24
24
|
};
|
|
25
25
|
const ok = Object.values(checks).every(Boolean);
|
|
26
26
|
emit({
|
|
@@ -10,6 +10,7 @@ const normal = governorMod.decideNarutoConcurrency({
|
|
|
10
10
|
zellijVisiblePaneCap: 12,
|
|
11
11
|
hardware: {
|
|
12
12
|
cores: 32,
|
|
13
|
+
loadAverage: [0, 0, 0],
|
|
13
14
|
freeMemoryBytes: 48 * 1024 * 1024 * 1024,
|
|
14
15
|
totalMemoryBytes: 64 * 1024 * 1024 * 1024,
|
|
15
16
|
fileDescriptorLimit: 4096,
|
|
@@ -37,7 +38,7 @@ const pressure = governorMod.decideNarutoConcurrency({
|
|
|
37
38
|
diskIoPressure: 0.9
|
|
38
39
|
}
|
|
39
40
|
});
|
|
40
|
-
assertGate(normal.safe_active_workers <=
|
|
41
|
+
assertGate(normal.safe_active_workers >= 32 && normal.safe_active_workers <= 100, 'requested_clones=200 fixture must cap active workers safely while allowing aggressive process-pool fanout', { normal });
|
|
41
42
|
assertGate(normal.safe_zellij_visible_panes === 12 && normal.headless_workers === normal.safe_active_workers - 12, 'zellij visible panes must stay within UI cap', { normal });
|
|
42
43
|
assertGate(normal.local_llm_parallel <= 4, 'local LLM active requests must respect max_parallel_requests=4', { normal });
|
|
43
44
|
assertGate(pressure.safe_active_workers < normal.safe_active_workers, 'memory/load pressure fixture must decrease active workers', { normal: normal.safe_active_workers, pressure: pressure.safe_active_workers });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
4
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
5
|
+
import { decideNarutoConcurrency } from '../core/naruto/naruto-concurrency-governor.js';
|
|
6
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 100, writeCapable: true, maxActiveWorkers: 32 });
|
|
7
|
+
const governor = decideNarutoConcurrency({
|
|
8
|
+
requestedClones: 100,
|
|
9
|
+
totalWorkItems: graph.total_work_items,
|
|
10
|
+
pendingWorkQueueSize: graph.total_work_items,
|
|
11
|
+
backend: 'codex-sdk',
|
|
12
|
+
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 }
|
|
13
|
+
});
|
|
14
|
+
const report = {
|
|
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,
|
|
17
|
+
graph: { total_work_items: graph.total_work_items, mixed_work_kinds: graph.mixed_work_kinds, write_allowed_count: graph.write_allowed_count },
|
|
18
|
+
governor
|
|
19
|
+
};
|
|
20
|
+
assertGate(report.ok, 'Naruto extreme parallelism must fan out >=2x clones and keep a high safe active pool', report);
|
|
21
|
+
emitGate('naruto:extreme-parallelism', report);
|
|
22
|
+
//# sourceMappingURL=naruto-extreme-parallelism-check.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
4
|
+
import { buildNarutoWorkGraph } from '../core/naruto/naruto-work-graph.js';
|
|
5
|
+
import { decideNarutoConcurrency } from '../core/naruto/naruto-concurrency-governor.js';
|
|
6
|
+
import { runNarutoRealActivePool } from '../core/naruto/naruto-active-pool.js';
|
|
7
|
+
const graph = buildNarutoWorkGraph({ requestedClones: 12, totalWorkItems: 24, writeCapable: true, maxActiveWorkers: 6 });
|
|
8
|
+
const governor = decideNarutoConcurrency({
|
|
9
|
+
requestedClones: 12,
|
|
10
|
+
totalWorkItems: graph.total_work_items,
|
|
11
|
+
pendingWorkQueueSize: graph.total_work_items,
|
|
12
|
+
backend: 'codex-sdk',
|
|
13
|
+
hardware: { cpuCoreCount: 8, freeMemoryBytes: 32 * 1024 * 1024 * 1024, totalMemoryBytes: 64 * 1024 * 1024 * 1024, fileDescriptorLimit: 4096, processCount: 100, terminalRows: 40, remoteApiRateLimitBudget: 8 }
|
|
14
|
+
});
|
|
15
|
+
const target = { ...governor, safe_active_workers: Math.min(6, governor.safe_active_workers), safe_zellij_visible_panes: 3 };
|
|
16
|
+
let spawned = 0;
|
|
17
|
+
let collected = 0;
|
|
18
|
+
let dashboardEvents = 0;
|
|
19
|
+
const report = await runNarutoRealActivePool({
|
|
20
|
+
graph,
|
|
21
|
+
governor: target,
|
|
22
|
+
spawnWorker: async (item, placement) => {
|
|
23
|
+
spawned += 1;
|
|
24
|
+
return { id: item.id, item, placement, started_at: Date.now() };
|
|
25
|
+
},
|
|
26
|
+
collectWorker: async (handle) => {
|
|
27
|
+
collected += 1;
|
|
28
|
+
return { id: handle.id, ok: true, item: handle.item, placement: handle.placement, completed_at: Date.now() };
|
|
29
|
+
},
|
|
30
|
+
enqueueVerification: async () => undefined,
|
|
31
|
+
updateDashboard: async () => {
|
|
32
|
+
dashboardEvents += 1;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
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;
|
|
36
|
+
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
|
+
//# sourceMappingURL=naruto-real-active-pool-check.js.map
|
|
@@ -11,7 +11,7 @@ const graph = workGraph.buildNarutoWorkGraph({
|
|
|
11
11
|
});
|
|
12
12
|
const validation = workGraph.validateNarutoWorkGraph(graph);
|
|
13
13
|
assertGate(graph.ok === true && validation.ok === true, 'Naruto work graph must validate', { graph_blockers: graph.blockers, validation });
|
|
14
|
-
assertGate(graph.total_work_items >= graph.requested_clones, 'work graph must create at least requested clone count', { total: graph.total_work_items, requested: graph.requested_clones });
|
|
14
|
+
assertGate(graph.total_work_items >= graph.requested_clones * 2, 'write-capable work graph must create at least 2x requested clone count', { total: graph.total_work_items, requested: graph.requested_clones });
|
|
15
15
|
assertGate(graph.mixed_work_kinds.length > 4, 'work graph must contain mixed work kinds, not only verification', { kinds: graph.mixed_work_kinds });
|
|
16
16
|
assertGate(graph.write_allowed_count > 0, 'write-capable Naruto graph must include write_allowed work items', { write_allowed_count: graph.write_allowed_count });
|
|
17
17
|
assertGate(graph.active_waves.every((wave) => wave.conflict_count === 0), 'active waves must not overlap write leases', { waves: graph.active_waves });
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
import { makeGitFixture, run } from './lib/git-worktree-fixture.js';
|
|
8
|
+
const managerMod = await importDist('core/git/git-worktree-manager.js');
|
|
9
|
+
const diffMod = await importDist('core/git/git-worktree-diff.js');
|
|
10
|
+
const mergeMod = await importDist('core/git/git-worktree-merge-queue.js');
|
|
11
|
+
const repo = makeGitFixture('naruto-worktree-blackbox');
|
|
12
|
+
process.env.SKS_WORKTREE_ROOT = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-naruto-blackbox-'));
|
|
13
|
+
const allocations = [];
|
|
14
|
+
for (const file of ['a.txt', 'b.txt']) {
|
|
15
|
+
const allocation = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-naruto-blackbox', workerId: file.replace('.txt', ''), slotId: file.replace('.txt', '') });
|
|
16
|
+
fs.writeFileSync(path.join(allocation.worktree_path, file), `${file}\nworker-change\n`);
|
|
17
|
+
allocations.push(allocation);
|
|
18
|
+
}
|
|
19
|
+
assertGate(run('git', ['status', '--porcelain=v1'], repo).trim() === '', 'main worktree must remain unchanged before integration');
|
|
20
|
+
const diffs = [];
|
|
21
|
+
for (const allocation of allocations) {
|
|
22
|
+
diffs.push(await diffMod.exportGitWorktreeDiff({ mainRepoRoot: repo, worktreePath: allocation.worktree_path, missionId: 'M-naruto-blackbox', workerId: allocation.worker_id }));
|
|
23
|
+
}
|
|
24
|
+
const integration = await managerMod.allocateWorkerWorktree({ repoRoot: repo, missionId: 'M-naruto-blackbox', workerId: 'integration', slotId: 'integration' });
|
|
25
|
+
const report = await mergeMod.applyGitWorktreeMergeQueue({ integrationWorktreePath: integration.worktree_path, diffs });
|
|
26
|
+
assertGate(report.ok === true && report.applied_count === 2, 'integration worktree merge report must apply worker diffs', report);
|
|
27
|
+
assertGate(run('git', ['status', '--porcelain=v1'], repo).trim() === '', 'main worktree must remain unchanged after integration queue');
|
|
28
|
+
emitGate('naruto:worktree-coding:blackbox', { allocations: allocations.length, applied_count: report.applied_count });
|
|
29
|
+
//# sourceMappingURL=naruto-worktree-coding-blackbox.js.map
|