sneakoscope 2.0.10 → 2.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- 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 +27 -8
- package/dist/cli/command-registry.js +1 -0
- package/dist/cli/install-helpers.js +8 -20
- package/dist/commands/doctor.js +5 -9
- package/dist/commands/zellij-slot-column-anchor.js +23 -0
- package/dist/core/agents/agent-orchestrator.js +338 -12
- package/dist/core/agents/agent-patch-schema.js +8 -1
- package/dist/core/agents/agent-scheduler.js +12 -1
- package/dist/core/agents/agent-slot-pane-binding-proof.js +3 -3
- package/dist/core/agents/agent-work-queue.js +26 -2
- package/dist/core/agents/agent-worker-pipeline.js +2 -0
- package/dist/core/agents/native-cli-session-swarm.js +2 -2
- package/dist/core/commands/naruto-command.js +191 -39
- package/dist/core/fsx.js +1 -1
- package/dist/core/git/git-worktree-checkpoint.js +52 -0
- package/dist/core/git/git-worktree-cross-rebase.js +54 -0
- package/dist/core/git/git-worktree-merge-queue.js +92 -3
- package/dist/core/git/git-worktree-patch-envelope.js +8 -1
- package/dist/core/init.js +2 -2
- package/dist/core/naruto/naruto-allocation-policy.js +99 -0
- package/dist/core/naruto/naruto-real-worker-child.js +110 -11
- package/dist/core/naruto/naruto-rebalance-policy.js +48 -0
- package/dist/core/naruto/naruto-task-hints.js +71 -0
- package/dist/core/naruto/naruto-work-graph.js +13 -0
- package/dist/core/pipeline/finalize-pipeline-result.js +3 -1
- package/dist/core/pipeline/gpt-final-required.js +22 -2
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-right-column-manager.js +45 -2
- package/dist/core/zellij/zellij-slot-column-anchor.js +218 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +81 -14
- package/dist/scripts/agent-real-codex-in-zellij-worker-pane-check.js +8 -2
- package/dist/scripts/agent-slot-pane-binding-proof-check.js +4 -4
- package/dist/scripts/codex-sdk-release-review-pipeline-check.js +2 -1
- package/dist/scripts/codex-sdk-zellij-pane-binding-check.js +2 -2
- package/dist/scripts/git-worktree-checkpoint-check.js +20 -0
- package/dist/scripts/git-worktree-cross-rebase-check.js +39 -0
- package/dist/scripts/git-worktree-merge-queue-check.js +1 -0
- package/dist/scripts/local-collab-worktree-gpt-final-apply-policy-check.js +63 -0
- package/dist/scripts/naruto-actual-worker-control-plane-check.js +56 -0
- package/dist/scripts/naruto-allocation-policy-check.js +33 -0
- package/dist/scripts/naruto-allocation-runtime-wiring-check.js +92 -0
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +5 -4
- package/dist/scripts/naruto-orchestrator-runtime-source-check.js +70 -0
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +4 -2
- package/dist/scripts/naruto-rebalance-policy-check.js +41 -0
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +8 -4
- package/dist/scripts/release-dag-full-coverage-check.js +19 -1
- package/dist/scripts/release-readiness-report.js +1 -1
- package/dist/scripts/release-real-check.js +258 -77
- package/dist/scripts/zellij-first-slot-down-stack-check.js +20 -0
- package/dist/scripts/zellij-first-slot-down-stack-real-check.js +356 -0
- package/dist/scripts/zellij-right-column-manager-check.js +7 -2
- package/dist/scripts/zellij-slot-column-anchor-check.js +45 -0
- package/dist/scripts/zellij-slot-only-ui-check.js +6 -2
- package/dist/scripts/zellij-slot-renderer-proof-semantics-check.js +59 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +23 -1
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +11 -4
- package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +21 -4
- package/package.json +15 -3
|
@@ -3,6 +3,8 @@ import { createMission, missionDir, setCurrent } from '../mission.js';
|
|
|
3
3
|
import { exists, nowIso, readJson, readText, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
4
4
|
import { buildAgentRoster, normalizeAgentConcurrency } from './agent-roster.js';
|
|
5
5
|
import { buildAgentWorkPartition } from './agent-work-partition.js';
|
|
6
|
+
import { detectAgentLeaseConflicts } from './work-partition/conflict-detector.js';
|
|
7
|
+
import { buildNoOverlapProof } from './work-partition/no-overlap-proof.js';
|
|
6
8
|
import { initializeAgentCentralLedger, appendAgentLedgerEvent, compactAgentLedger } from './agent-central-ledger.js';
|
|
7
9
|
import { detectStaleAgentSessions, killTimedOutAgentSessions, openAgentSession, heartbeatAgentSession, collectAgentSession, completeAgentSession, closeAgentSession, writeAgentLifecycleAggregate, writeAgentLifecyclePolicy } from './agent-lifecycle.js';
|
|
8
10
|
import { writeAgentConsensus } from './agent-consensus.js';
|
|
@@ -55,9 +57,12 @@ import { selectFinalGptPatchSource } from '../pipeline/final-gpt-patch-stage.js'
|
|
|
55
57
|
import { allocateWorkerWorktree } from '../git/git-worktree-manager.js';
|
|
56
58
|
import { exportGitWorktreeDiff } from '../git/git-worktree-diff.js';
|
|
57
59
|
import { buildGitWorktreePatchEnvelope } from '../git/git-worktree-patch-envelope.js';
|
|
60
|
+
import { checkpointWorkerWorktree } from '../git/git-worktree-checkpoint.js';
|
|
58
61
|
import { cleanupGitWorktree } from '../git/git-worktree-cleanup.js';
|
|
59
62
|
import { createGitIntegrationWorktree } from '../git/git-integration-worktree.js';
|
|
60
63
|
import { applyGitWorktreeMergeQueue } from '../git/git-worktree-merge-queue.js';
|
|
64
|
+
import { crossRebaseIdleWorktrees } from '../git/git-worktree-cross-rebase.js';
|
|
65
|
+
import { gitOutputLine, runGitCommand } from '../git/git-worktree-runner.js';
|
|
61
66
|
export async function runNativeAgentOrchestrator(opts = {}) {
|
|
62
67
|
const root = path.resolve(opts.root || process.cwd());
|
|
63
68
|
const prompt = String(opts.prompt || 'Native agent run');
|
|
@@ -192,7 +197,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
192
197
|
}
|
|
193
198
|
};
|
|
194
199
|
}
|
|
195
|
-
|
|
200
|
+
let partition = await buildAgentWorkPartition(root, roster, prompt, {
|
|
196
201
|
route,
|
|
197
202
|
targetActiveSlots,
|
|
198
203
|
desiredWorkItemCount,
|
|
@@ -203,12 +208,24 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
203
208
|
strategyOwnershipPlan: strategyCompiled.file_ownership_plan,
|
|
204
209
|
microWins: strategyCompiled.gate.micro_wins
|
|
205
210
|
});
|
|
211
|
+
if (opts.narutoWorkGraph?.work_items?.length) {
|
|
212
|
+
partition = applyNarutoWorkGraphToPartition(partition, opts.narutoWorkGraph, roster, targetActiveSlots);
|
|
213
|
+
augmentVerificationRollbackDagForNaruto(strategyCompiled.verification_rollback_dag, partition.slices);
|
|
214
|
+
}
|
|
206
215
|
await runAgentJanitor({ missionDir: dir, missionId, projectHash: namespace.root_hash });
|
|
207
216
|
const ledgerRoot = await initializeAgentCentralLedger(dir, { missionId, roster, partition, route, prompt, dynamicScheduler: true });
|
|
208
217
|
// Consult the TriWiki context pack (read-only) before dispatching workers, and
|
|
209
218
|
// persist it as a proof artifact so the kernel proof references the wiki it acted on.
|
|
210
219
|
const triwikiContext = await loadTriWikiRuntimeContext(root);
|
|
211
220
|
await writeTriWikiContextArtifact(ledgerRoot, triwikiContext);
|
|
221
|
+
if (opts.narutoWorkGraph?.work_items?.length) {
|
|
222
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-work-graph.json'), opts.narutoWorkGraph);
|
|
223
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-runtime-wiring.json'), buildNarutoRuntimeWiringProof(partition, opts.narutoWorkGraph, roster, targetActiveSlots));
|
|
224
|
+
}
|
|
225
|
+
if (opts.narutoAllocationPolicy)
|
|
226
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-allocation-policy.json'), opts.narutoAllocationPolicy);
|
|
227
|
+
if (opts.narutoRebalancePolicy)
|
|
228
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'naruto-rebalance-policy.json'), opts.narutoRebalancePolicy);
|
|
212
229
|
await writeAgentTaskGraph(ledgerRoot, partition.task_graph);
|
|
213
230
|
await writeAdhdOrchestrationArtifacts(ledgerRoot, strategyCompiled.gate);
|
|
214
231
|
await writeStrategyCompilerArtifacts(ledgerRoot, strategyCompiled);
|
|
@@ -270,6 +287,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
270
287
|
worktree_root: gitWorktreePolicy?.worktree_root || null,
|
|
271
288
|
allocations: [],
|
|
272
289
|
diffs: [],
|
|
290
|
+
checkpoints: [],
|
|
273
291
|
cleanup: [],
|
|
274
292
|
blockers: []
|
|
275
293
|
};
|
|
@@ -342,6 +360,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
342
360
|
const result = opts.nativeCliSwarm === false
|
|
343
361
|
? await runAgentByBackend(backend, runtimeAgent, runtimeSlice, backendOpts)
|
|
344
362
|
: await nativeCliSwarm.launchWorker({ agent: runtimeAgent, slice: runtimeSlice, opts: backendOpts });
|
|
363
|
+
if (route === '$Naruto')
|
|
364
|
+
attachNarutoRuntimeProof(result, runtimeAgent, runtimeSlice);
|
|
345
365
|
if (workerWorktree)
|
|
346
366
|
await finalizeWorkerGitWorktree({
|
|
347
367
|
root,
|
|
@@ -424,7 +444,10 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
424
444
|
await writeJsonAtomic(path.join(ledgerRoot, 'local-collaboration-policy.json'), localCollaborationPolicy);
|
|
425
445
|
const localParticipated = localCollaborationParticipated(results);
|
|
426
446
|
const candidatePatchEnvelopes = results.flatMap((result) => Array.isArray(result.patch_envelopes) ? result.patch_envelopes : []);
|
|
427
|
-
const
|
|
447
|
+
const worktreeParticipated = candidatePatchEnvelopes.some((envelope) => envelope?.source === 'git-worktree-diff' || envelope?.git_worktree?.worktree_path)
|
|
448
|
+
|| results.some((result) => result?.git_worktree_diff || result?.git_worktree_checkpoint);
|
|
449
|
+
const gptFinalRequired = localParticipated || worktreeParticipated;
|
|
450
|
+
const gptFinalArbiter = gptFinalRequired
|
|
428
451
|
? await runFinalGptReviewStage({
|
|
429
452
|
schema: 'sks.gpt-final-arbiter-input.v1',
|
|
430
453
|
route,
|
|
@@ -448,10 +471,10 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
448
471
|
rollback_plan: { verification_rollback_dag: strategyCompiled.verification_rollback_dag || null }
|
|
449
472
|
}, { cwd: root, mutationLedgerRoot: path.join(ledgerRoot, 'gpt-final-arbiter') })
|
|
450
473
|
: null;
|
|
451
|
-
const finalGptPatchStage =
|
|
474
|
+
const finalGptPatchStage = gptFinalRequired
|
|
452
475
|
? selectFinalGptPatchSource(gptFinalArbiter, candidatePatchEnvelopes)
|
|
453
476
|
: null;
|
|
454
|
-
const resultsForPatchSwarm =
|
|
477
|
+
const resultsForPatchSwarm = gptFinalRequired && finalGptPatchStage?.ok === true && gptFinalArbiter?.result?.status === 'modified'
|
|
455
478
|
? withFinalGptPatchEnvelopes(results, finalGptPatchStage.patch_envelopes)
|
|
456
479
|
: results;
|
|
457
480
|
const patchSwarm = await runAgentPatchSwarmRuntime(root, ledgerRoot, {
|
|
@@ -462,7 +485,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
462
485
|
results: resultsForPatchSwarm,
|
|
463
486
|
parallelWritePolicy,
|
|
464
487
|
verificationRollbackDag: strategyCompiled.verification_rollback_dag,
|
|
465
|
-
dryRun: opts.dryRunPatches === true || opts.applyPatches !== true || (
|
|
488
|
+
dryRun: opts.dryRunPatches === true || opts.applyPatches !== true || (gptFinalRequired && gptFinalArbiter?.ok !== true),
|
|
466
489
|
gptFinalArbiter,
|
|
467
490
|
finalGptPatchStage
|
|
468
491
|
});
|
|
@@ -491,8 +514,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
491
514
|
...(noSubagentScalingPolicy.ok ? [] : noSubagentScalingPolicy.blockers),
|
|
492
515
|
...(fastModePropagation.ok ? [] : fastModePropagation.blockers),
|
|
493
516
|
...(gitWorktreeRuntime.required === true && gitWorktreeRuntime.ok === false ? gitWorktreeRuntime.blockers || ['git_worktree_runtime_not_ok'] : []),
|
|
494
|
-
...(
|
|
495
|
-
...(
|
|
517
|
+
...(gptFinalRequired && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
|
|
518
|
+
...(gptFinalRequired && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
|
|
496
519
|
...(patchSwarm.ok ? [] : patchSwarm.blockers),
|
|
497
520
|
...(janitor.ok ? [] : janitor.blockers)
|
|
498
521
|
];
|
|
@@ -597,6 +620,247 @@ function withFinalGptPatchEnvelopes(results, patchEnvelopes = []) {
|
|
|
597
620
|
next[0] = { ...next[0], patch_envelopes: patchEnvelopes };
|
|
598
621
|
return next;
|
|
599
622
|
}
|
|
623
|
+
function applyNarutoWorkGraphToPartition(partition, graph, roster, targetActiveSlots) {
|
|
624
|
+
const activeRoster = (Array.isArray(roster?.roster) ? roster.roster : []).slice(0, Math.max(1, targetActiveSlots));
|
|
625
|
+
const activeAgentIds = new Set(activeRoster.map((row) => String(row.id || '')).filter(Boolean));
|
|
626
|
+
const fallbackOwners = activeRoster.length ? activeRoster : [{ id: 'naruto_clone_001', role: 'verifier' }];
|
|
627
|
+
const referenceWorkItem = Array.isArray(partition?.task_graph?.work_items) ? partition.task_graph.work_items.find(Boolean) : null;
|
|
628
|
+
const sourceIntelligenceRefs = referenceWorkItem?.source_intelligence_refs || partition?.source_intelligence_refs || null;
|
|
629
|
+
const goalModeRef = referenceWorkItem?.goal_mode_ref || partition?.goal_mode_ref || null;
|
|
630
|
+
const strategyRefs = referenceWorkItem?.strategy_refs || partition?.strategy_refs || null;
|
|
631
|
+
const slices = (graph.work_items || []).map((item, index) => {
|
|
632
|
+
const requestedOwner = item.owner ? String(item.owner) : '';
|
|
633
|
+
const owner = requestedOwner && activeAgentIds.has(requestedOwner)
|
|
634
|
+
? requestedOwner
|
|
635
|
+
: String(fallbackOwners[index % fallbackOwners.length]?.id || requestedOwner || `naruto_clone_${String(index + 1).padStart(3, '0')}`);
|
|
636
|
+
const sliceId = String(item.id || `NW-${String(index + 1).padStart(6, '0')}`);
|
|
637
|
+
const writePaths = normalizePathList(item.write_paths);
|
|
638
|
+
const readonlyPaths = normalizePathList(item.readonly_paths);
|
|
639
|
+
const targetPaths = normalizePathList(item.target_paths);
|
|
640
|
+
const verificationNodeId = writePaths.length ? `verify:${sliceId}` : null;
|
|
641
|
+
const rollbackNodeId = writePaths.length ? `rollback:${sliceId}` : null;
|
|
642
|
+
return {
|
|
643
|
+
id: sliceId,
|
|
644
|
+
owner_agent_id: owner,
|
|
645
|
+
owner,
|
|
646
|
+
lane: owner,
|
|
647
|
+
role: String(item.required_role || 'verifier'),
|
|
648
|
+
domain: String(item.allocation_hints?.domains?.[0] || item.kind || 'naruto'),
|
|
649
|
+
title: String(item.title || item.id || `Naruto work ${index + 1}`),
|
|
650
|
+
dependencies: Array.isArray(item.dependencies) ? item.dependencies.map(String) : [],
|
|
651
|
+
priority: index + 1,
|
|
652
|
+
required_persona_category: String(item.required_role || 'verifier'),
|
|
653
|
+
lease_requirements: Array.isArray(item.lease_requirements) ? item.lease_requirements : [],
|
|
654
|
+
generated_by: 'sks.naruto-work-graph.v1',
|
|
655
|
+
route_domain: String(item.kind || 'naruto'),
|
|
656
|
+
work_item_kind: String(item.kind || 'verification'),
|
|
657
|
+
target_paths: targetPaths,
|
|
658
|
+
readonly_paths: readonlyPaths,
|
|
659
|
+
write_paths: writePaths,
|
|
660
|
+
allocation_reason: item.allocation_reason || null,
|
|
661
|
+
allocation_score: item.allocation_score ?? null,
|
|
662
|
+
allocation_hints: item.allocation_hints || null,
|
|
663
|
+
allocation_original_owner: requestedOwner || null,
|
|
664
|
+
allocation_owner_rebalanced: Boolean(requestedOwner && owner !== requestedOwner),
|
|
665
|
+
micro_win_id: sliceId,
|
|
666
|
+
verification_node_id: verificationNodeId,
|
|
667
|
+
rollback_node_id: rollbackNodeId,
|
|
668
|
+
verification_required: item.verification_required === true,
|
|
669
|
+
source_intelligence_refs: sourceIntelligenceRefs,
|
|
670
|
+
goal_mode_ref: goalModeRef,
|
|
671
|
+
strategy_refs: strategyRefs,
|
|
672
|
+
max_attempts: 1,
|
|
673
|
+
description: [
|
|
674
|
+
String(item.title || item.id || 'Naruto work item'),
|
|
675
|
+
`Naruto owner: ${owner}`,
|
|
676
|
+
item.allocation_reason ? `Allocation: ${item.allocation_reason}` : null,
|
|
677
|
+
writePaths.length ? `Write paths: ${writePaths.join(', ')}` : 'Read-only or no-write work item.'
|
|
678
|
+
].filter(Boolean).join('\n')
|
|
679
|
+
};
|
|
680
|
+
});
|
|
681
|
+
const workItems = (graph.work_items || []).map((item) => ({
|
|
682
|
+
...item,
|
|
683
|
+
source_intelligence_refs: item.source_intelligence_refs || sourceIntelligenceRefs,
|
|
684
|
+
goal_mode_ref: item.goal_mode_ref || goalModeRef,
|
|
685
|
+
strategy_refs: item.strategy_refs || strategyRefs
|
|
686
|
+
}));
|
|
687
|
+
const leases = slices.flatMap((slice) => [
|
|
688
|
+
...slice.write_paths.map((file, index) => ({
|
|
689
|
+
id: `${slice.id}:write:${index + 1}`,
|
|
690
|
+
agent_id: slice.owner_agent_id,
|
|
691
|
+
kind: 'write',
|
|
692
|
+
path: file,
|
|
693
|
+
domain: slice.domain,
|
|
694
|
+
status: 'active',
|
|
695
|
+
owner_agent: slice.owner_agent_id,
|
|
696
|
+
write_paths: slice.write_paths,
|
|
697
|
+
strategy_task_id: slice.id,
|
|
698
|
+
micro_win_id: slice.micro_win_id || slice.id,
|
|
699
|
+
verification_node_id: slice.verification_node_id || null,
|
|
700
|
+
rollback_node_id: slice.rollback_node_id || null,
|
|
701
|
+
protected_path_check: { ok: true, blockers: [] }
|
|
702
|
+
})),
|
|
703
|
+
...slice.readonly_paths.map((file, index) => ({
|
|
704
|
+
id: `${slice.id}:read:${index + 1}`,
|
|
705
|
+
agent_id: slice.owner_agent_id,
|
|
706
|
+
kind: 'read',
|
|
707
|
+
path: file,
|
|
708
|
+
domain: slice.domain,
|
|
709
|
+
status: 'active',
|
|
710
|
+
owner_agent: slice.owner_agent_id,
|
|
711
|
+
write_paths: slice.write_paths,
|
|
712
|
+
strategy_task_id: slice.id,
|
|
713
|
+
micro_win_id: slice.micro_win_id || slice.id,
|
|
714
|
+
verification_node_id: slice.verification_node_id || null,
|
|
715
|
+
rollback_node_id: slice.rollback_node_id || null,
|
|
716
|
+
protected_path_check: { ok: true, blockers: [] }
|
|
717
|
+
}))
|
|
718
|
+
]);
|
|
719
|
+
const conflict_report = detectAgentLeaseConflicts(leases);
|
|
720
|
+
const no_overlap_proof = buildNoOverlapProof(leases);
|
|
721
|
+
const taskGraph = partition.task_graph
|
|
722
|
+
? {
|
|
723
|
+
...partition.task_graph,
|
|
724
|
+
total_work_items: slices.length,
|
|
725
|
+
work_items: workItems,
|
|
726
|
+
route_work_count_summary: {
|
|
727
|
+
...(partition.task_graph.route_work_count_summary || {}),
|
|
728
|
+
naruto_work_graph_items: slices.length,
|
|
729
|
+
allocation_owner_rebalanced_count: slices.filter((slice) => slice.allocation_owner_rebalanced).length
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
: null;
|
|
733
|
+
return {
|
|
734
|
+
...partition,
|
|
735
|
+
ok: conflict_report.ok && no_overlap_proof.ok,
|
|
736
|
+
task_graph: taskGraph,
|
|
737
|
+
slices,
|
|
738
|
+
leases,
|
|
739
|
+
conflict_report,
|
|
740
|
+
no_overlap_proof,
|
|
741
|
+
source_intelligence_refs: sourceIntelligenceRefs,
|
|
742
|
+
goal_mode_ref: goalModeRef,
|
|
743
|
+
strategy_refs: strategyRefs,
|
|
744
|
+
blockers: [...(conflict_report.blockers || []), ...(no_overlap_proof.blockers || [])]
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
function augmentVerificationRollbackDagForNaruto(dag, slices) {
|
|
748
|
+
if (!dag || !Array.isArray(dag.nodes) || !Array.isArray(slices))
|
|
749
|
+
return dag;
|
|
750
|
+
const byId = new Set(dag.nodes.map((node) => String(node.id || '')).filter(Boolean));
|
|
751
|
+
for (const slice of slices) {
|
|
752
|
+
const sliceId = String(slice?.id || '');
|
|
753
|
+
if (!sliceId)
|
|
754
|
+
continue;
|
|
755
|
+
const writePaths = normalizePathList(slice.write_paths);
|
|
756
|
+
if (!byId.has(sliceId)) {
|
|
757
|
+
dag.nodes.push({
|
|
758
|
+
id: sliceId,
|
|
759
|
+
kind: writePaths.length ? 'write' : 'verification',
|
|
760
|
+
depends_on: [],
|
|
761
|
+
proof_artifact: writePaths.length ? 'agent-patch-queue.json' : 'agent-worker-result.json'
|
|
762
|
+
});
|
|
763
|
+
byId.add(sliceId);
|
|
764
|
+
}
|
|
765
|
+
if (!writePaths.length)
|
|
766
|
+
continue;
|
|
767
|
+
const verificationNodeId = String(slice.verification_node_id || `verify:${sliceId}`);
|
|
768
|
+
const rollbackNodeId = String(slice.rollback_node_id || `rollback:${sliceId}`);
|
|
769
|
+
if (!byId.has(verificationNodeId)) {
|
|
770
|
+
dag.nodes.push({
|
|
771
|
+
id: verificationNodeId,
|
|
772
|
+
kind: 'verification',
|
|
773
|
+
depends_on: [sliceId],
|
|
774
|
+
proof_artifact: 'agent-patch-verification-results.json'
|
|
775
|
+
});
|
|
776
|
+
byId.add(verificationNodeId);
|
|
777
|
+
}
|
|
778
|
+
if (!byId.has(rollbackNodeId)) {
|
|
779
|
+
dag.nodes.push({
|
|
780
|
+
id: rollbackNodeId,
|
|
781
|
+
kind: 'rollback',
|
|
782
|
+
depends_on: [sliceId, verificationNodeId],
|
|
783
|
+
proof_artifact: 'agent-patch-rollback-proof.json'
|
|
784
|
+
});
|
|
785
|
+
byId.add(rollbackNodeId);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
dag.rollback_ready = true;
|
|
789
|
+
dag.verification_ready = true;
|
|
790
|
+
if (dag.validation?.blockers?.length)
|
|
791
|
+
dag.validation = { ok: true, blockers: [] };
|
|
792
|
+
return dag;
|
|
793
|
+
}
|
|
794
|
+
function buildNarutoRuntimeWiringProof(partition, graph, roster, targetActiveSlots) {
|
|
795
|
+
const activeAgentIds = new Set((Array.isArray(roster?.roster) ? roster.roster : []).slice(0, Math.max(1, targetActiveSlots)).map((row) => String(row.id || '')).filter(Boolean));
|
|
796
|
+
const slices = Array.isArray(partition?.slices) ? partition.slices : [];
|
|
797
|
+
const activeWriteConflicts = slices.flatMap((slice) => normalizePathList(slice.write_paths));
|
|
798
|
+
const duplicateActiveWrites = activeWriteConflicts.filter((file, index, all) => all.indexOf(file) !== index);
|
|
799
|
+
const ownerPreserved = slices.every((slice) => !slice.allocation_original_owner || slice.allocation_owner_rebalanced || slice.owner_agent_id === slice.allocation_original_owner);
|
|
800
|
+
const inactiveOwnersRebalanced = slices.every((slice) => !slice.allocation_original_owner || activeAgentIds.has(slice.allocation_original_owner) || slice.allocation_owner_rebalanced);
|
|
801
|
+
const blockers = [
|
|
802
|
+
...(slices.length === Number(graph?.work_items?.length || 0) ? [] : ['naruto_runtime_slice_count_mismatch']),
|
|
803
|
+
...(ownerPreserved ? [] : ['naruto_runtime_owner_not_preserved']),
|
|
804
|
+
...(inactiveOwnersRebalanced ? [] : ['naruto_runtime_inactive_owner_not_rebalanced']),
|
|
805
|
+
...(duplicateActiveWrites.length ? ['naruto_runtime_duplicate_write_paths_in_partition'] : [])
|
|
806
|
+
];
|
|
807
|
+
return {
|
|
808
|
+
schema: 'sks.naruto-runtime-wiring.v1',
|
|
809
|
+
generated_at: nowIso(),
|
|
810
|
+
ok: blockers.length === 0,
|
|
811
|
+
source_of_truth: 'naruto-work-graph',
|
|
812
|
+
scheduler_slice_count: slices.length,
|
|
813
|
+
work_graph_item_count: Number(graph?.work_items?.length || 0),
|
|
814
|
+
owner_preserved: ownerPreserved,
|
|
815
|
+
inactive_owners_rebalanced: inactiveOwnersRebalanced,
|
|
816
|
+
write_conflict_free_partition: duplicateActiveWrites.length === 0,
|
|
817
|
+
slice_owners: slices.map((slice) => ({
|
|
818
|
+
id: slice.id,
|
|
819
|
+
owner_agent_id: slice.owner_agent_id,
|
|
820
|
+
original_owner: slice.allocation_original_owner || null,
|
|
821
|
+
rebalanced: slice.allocation_owner_rebalanced === true,
|
|
822
|
+
write_paths: slice.write_paths || [],
|
|
823
|
+
dependencies: slice.dependencies || []
|
|
824
|
+
})),
|
|
825
|
+
blockers
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
function attachNarutoRuntimeProof(result, agent, slice) {
|
|
829
|
+
const controlPlane = result?.codex_child_report || result?.codex_sdk_thread || result?.backend_router_report || null;
|
|
830
|
+
const selectedBackend = String(result?.backend_router_report?.selected_backend || result?.backend || '');
|
|
831
|
+
const actualWorkerControlPlane = selectedBackend === 'codex-sdk' || selectedBackend === 'local-llm'
|
|
832
|
+
? Boolean(controlPlane?.sdk_thread_id || controlPlane?.worker_result_path || result?.codex_child_report?.worker_result_path)
|
|
833
|
+
: false;
|
|
834
|
+
result.naruto_runtime = {
|
|
835
|
+
schema: 'sks.naruto-worker-runtime-proof.v1',
|
|
836
|
+
source_of_truth: 'agent-orchestrator-scheduler',
|
|
837
|
+
actual_worker_control_plane: actualWorkerControlPlane,
|
|
838
|
+
work_item_id: String(slice?.id || result?.task_slice_id || ''),
|
|
839
|
+
owner: String(slice?.owner_agent_id || slice?.owner || agent?.id || ''),
|
|
840
|
+
allocation_reason: slice?.allocation_reason || null,
|
|
841
|
+
rebalance_generation: Number(slice?.allocation_owner_rebalanced === true ? 1 : 0),
|
|
842
|
+
selected_backend: selectedBackend || null,
|
|
843
|
+
explicit_fake_backend: selectedBackend === 'fake',
|
|
844
|
+
control_plane_result: controlPlane
|
|
845
|
+
? {
|
|
846
|
+
worker_result_path: controlPlane.worker_result_path || null,
|
|
847
|
+
sdk_thread_id: controlPlane.sdk_thread_id || null,
|
|
848
|
+
sdk_run_id: controlPlane.sdk_run_id || null,
|
|
849
|
+
structured_output_valid: controlPlane.structured_output_valid === true,
|
|
850
|
+
stream_event_count: Number(controlPlane.stream_event_count || 0)
|
|
851
|
+
}
|
|
852
|
+
: null
|
|
853
|
+
};
|
|
854
|
+
if (result.naruto_runtime.control_plane_result)
|
|
855
|
+
result.control_plane_result = result.naruto_runtime.control_plane_result;
|
|
856
|
+
result.verification = {
|
|
857
|
+
status: result.verification?.status || 'not_run',
|
|
858
|
+
checks: [...(result.verification?.checks || []), 'naruto-agent-orchestrator-scheduler-source-of-truth']
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
function normalizePathList(values) {
|
|
862
|
+
return (Array.isArray(values) ? values : []).map((file) => String(file || '').replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, '')).filter(Boolean);
|
|
863
|
+
}
|
|
600
864
|
async function prepareWorkerGitWorktree(input) {
|
|
601
865
|
if (input.policy?.mode !== 'git-worktree')
|
|
602
866
|
return null;
|
|
@@ -647,6 +911,14 @@ async function finalizeWorkerGitWorktree(input) {
|
|
|
647
911
|
workerId: String(input.agent.id || input.slice.id || 'worker')
|
|
648
912
|
});
|
|
649
913
|
await writeJsonAtomic(path.join(input.workerWorktree.artifactDir, 'git-worktree-diff.json'), diff);
|
|
914
|
+
const checkpoint = await checkpointWorkerWorktree({
|
|
915
|
+
worktreePath: allocation.worktree_path,
|
|
916
|
+
repoRoot: allocation.main_repo_root || input.root,
|
|
917
|
+
workerId: String(input.agent.id || input.slice.id || 'worker'),
|
|
918
|
+
taskId: String(input.slice.id || input.agent.id || 'task'),
|
|
919
|
+
mode: 'auto'
|
|
920
|
+
});
|
|
921
|
+
await writeJsonAtomic(path.join(input.workerWorktree.artifactDir, 'git-worktree-checkpoint.json'), checkpoint);
|
|
650
922
|
input.runtime.diffs.push({
|
|
651
923
|
agent_id: input.agent.id,
|
|
652
924
|
slice_id: input.slice.id,
|
|
@@ -656,18 +928,29 @@ async function finalizeWorkerGitWorktree(input) {
|
|
|
656
928
|
diff_bytes: diff.diff_bytes,
|
|
657
929
|
blockers: diff.blockers
|
|
658
930
|
});
|
|
931
|
+
input.runtime.checkpoints.push({
|
|
932
|
+
agent_id: input.agent.id,
|
|
933
|
+
slice_id: input.slice.id,
|
|
934
|
+
ok: checkpoint.ok,
|
|
935
|
+
mode_applied: checkpoint.mode_applied,
|
|
936
|
+
commit_hash: checkpoint.commit_hash,
|
|
937
|
+
changed_files: checkpoint.changed_files,
|
|
938
|
+
blockers: checkpoint.blockers
|
|
939
|
+
});
|
|
659
940
|
if (!diff.clean && diff.ok) {
|
|
660
941
|
const envelope = buildGitWorktreePatchEnvelope({
|
|
661
942
|
diff,
|
|
662
943
|
agentId: String(input.agent.id || 'agent'),
|
|
663
944
|
sessionId: String(input.agent.session_id || ''),
|
|
664
945
|
slotId: String(input.agent.slot_id || ''),
|
|
665
|
-
generationIndex: Math.max(1, Math.floor(Number(input.agent.generation_index || 1)))
|
|
946
|
+
generationIndex: Math.max(1, Math.floor(Number(input.agent.generation_index || 1))),
|
|
947
|
+
checkpoint
|
|
666
948
|
});
|
|
667
949
|
input.result.patch_envelopes = [...(Array.isArray(input.result.patch_envelopes) ? input.result.patch_envelopes : []), envelope];
|
|
668
950
|
input.result.changed_files = [...new Set([...(input.result.changed_files || []), ...diff.changed_files])];
|
|
669
|
-
input.result.artifacts = [...new Set([...(input.result.artifacts || []), path.relative(input.ledgerRoot, path.join(input.workerWorktree.artifactDir, 'git-worktree-diff.json'))])];
|
|
951
|
+
input.result.artifacts = [...new Set([...(input.result.artifacts || []), path.relative(input.ledgerRoot, path.join(input.workerWorktree.artifactDir, 'git-worktree-diff.json')), path.relative(input.ledgerRoot, path.join(input.workerWorktree.artifactDir, 'git-worktree-checkpoint.json'))])];
|
|
670
952
|
input.result.git_worktree_diff = diff;
|
|
953
|
+
input.result.git_worktree_checkpoint = checkpoint;
|
|
671
954
|
}
|
|
672
955
|
const cleanup = await cleanupGitWorktree({
|
|
673
956
|
repoRoot: allocation.main_repo_root || input.root,
|
|
@@ -684,7 +967,7 @@ async function finalizeWorkerGitWorktree(input) {
|
|
|
684
967
|
retention_lock_path: cleanup.retention_lock_path,
|
|
685
968
|
blockers: cleanup.blockers
|
|
686
969
|
});
|
|
687
|
-
input.runtime.blockers.push(...diff.blockers, ...cleanup.blockers);
|
|
970
|
+
input.runtime.blockers.push(...diff.blockers, ...checkpoint.blockers, ...cleanup.blockers);
|
|
688
971
|
input.runtime.ok = input.runtime.blockers.length === 0;
|
|
689
972
|
await writeJsonAtomic(path.join(input.ledgerRoot, 'agent-git-worktree-runtime.json'), input.runtime);
|
|
690
973
|
}
|
|
@@ -1003,6 +1286,7 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
1003
1286
|
}
|
|
1004
1287
|
async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, entries, queueStore) {
|
|
1005
1288
|
const diffs = entries.map((entry) => gitWorktreeDiffFromQueueEntry(entry)).filter(Boolean);
|
|
1289
|
+
const checkpoints = entries.map((entry) => gitWorktreeCheckpointFromQueueEntry(entry)).filter(Boolean);
|
|
1006
1290
|
const repoRoot = diffs[0]?.main_repo_root || root;
|
|
1007
1291
|
const baseRef = diffs.find((diff) => diff.base_head)?.base_head || undefined;
|
|
1008
1292
|
const integration = await createGitIntegrationWorktree({ repoRoot, missionId, ...(baseRef ? { baseRef } : {}) });
|
|
@@ -1039,15 +1323,35 @@ async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, ent
|
|
|
1039
1323
|
await queueStore.markApplying(entry.id);
|
|
1040
1324
|
const queueReport = await applyGitWorktreeMergeQueue({
|
|
1041
1325
|
integrationWorktreePath: integration.worktree_path,
|
|
1042
|
-
diffs
|
|
1326
|
+
diffs,
|
|
1327
|
+
checkpoints
|
|
1043
1328
|
});
|
|
1044
1329
|
const rollbackPlan = queueReport.ok ? await captureGitWorktreeRollbackPlan(repoRoot, queueReport.changed_files || []) : { ok: false, rollback: [], blockers: ['git_worktree_integration_prevalidation_failed'] };
|
|
1045
1330
|
const mainApplyReport = queueReport.ok && rollbackPlan.ok
|
|
1046
1331
|
? await applyGitWorktreeMergeQueue({
|
|
1047
1332
|
integrationWorktreePath: repoRoot,
|
|
1048
|
-
diffs
|
|
1333
|
+
diffs,
|
|
1334
|
+
checkpoints
|
|
1049
1335
|
})
|
|
1050
1336
|
: null;
|
|
1337
|
+
const integrationHead = mainApplyReport?.ok
|
|
1338
|
+
? gitOutputLine(await runGitCommand(repoRoot, ['rev-parse', 'HEAD']).catch(() => ({ ok: false, stdout: '' })))
|
|
1339
|
+
: null;
|
|
1340
|
+
const crossRebase = integrationHead
|
|
1341
|
+
? await crossRebaseIdleWorktrees({
|
|
1342
|
+
integrationHead,
|
|
1343
|
+
workers: diffs
|
|
1344
|
+
.filter((diff) => diff.worktree_path)
|
|
1345
|
+
.map((diff) => ({
|
|
1346
|
+
worker_id: diff.worker_id,
|
|
1347
|
+
worktree_path: diff.worktree_path,
|
|
1348
|
+
branch: diff.branch,
|
|
1349
|
+
state: 'done'
|
|
1350
|
+
}))
|
|
1351
|
+
})
|
|
1352
|
+
: null;
|
|
1353
|
+
if (crossRebase)
|
|
1354
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'git-worktree-cross-rebase-report.json'), crossRebase);
|
|
1051
1355
|
const rollbackEvidence = mainApplyReport?.ok
|
|
1052
1356
|
? await completeGitWorktreeRollbackPlan(repoRoot, rollbackPlan.rollback)
|
|
1053
1357
|
: rollbackPlan;
|
|
@@ -1093,6 +1397,7 @@ async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, ent
|
|
|
1093
1397
|
conflicted_entry_ids: conflictedEntryIds,
|
|
1094
1398
|
merge_queue: queueReport,
|
|
1095
1399
|
main_repo_apply: mainApplyReport,
|
|
1400
|
+
cross_rebase: crossRebase,
|
|
1096
1401
|
rollback_evidence: rollbackEvidence,
|
|
1097
1402
|
apply_results: applyResults,
|
|
1098
1403
|
blockers: reportBlockers
|
|
@@ -1176,6 +1481,27 @@ function gitWorktreeDiffFromQueueEntry(entry) {
|
|
|
1176
1481
|
blockers: []
|
|
1177
1482
|
};
|
|
1178
1483
|
}
|
|
1484
|
+
function gitWorktreeCheckpointFromQueueEntry(entry) {
|
|
1485
|
+
const envelope = entry?.envelope || {};
|
|
1486
|
+
const meta = envelope.git_worktree || {};
|
|
1487
|
+
const checkpoint = meta.checkpoint || null;
|
|
1488
|
+
if (!checkpoint || checkpoint.mode_applied !== 'checkpoint-commit' || !checkpoint.commit_hash)
|
|
1489
|
+
return null;
|
|
1490
|
+
return {
|
|
1491
|
+
schema: 'sks.git-worktree-checkpoint.v1',
|
|
1492
|
+
ok: Array.isArray(checkpoint.blockers) ? checkpoint.blockers.length === 0 : true,
|
|
1493
|
+
generated_at: nowIso(),
|
|
1494
|
+
worktree_path: String(meta.worktree_path || ''),
|
|
1495
|
+
repo_root: String(meta.main_repo_root || ''),
|
|
1496
|
+
worker_id: String(envelope.agent_id || entry.agent_id || entry.id),
|
|
1497
|
+
task_id: String(envelope.task_slice_id || entry.id || ''),
|
|
1498
|
+
mode_requested: 'auto',
|
|
1499
|
+
mode_applied: 'checkpoint-commit',
|
|
1500
|
+
commit_hash: String(checkpoint.commit_hash),
|
|
1501
|
+
changed_files: Array.isArray(checkpoint.changed_files) ? checkpoint.changed_files.map(String) : Array.isArray(meta.changed_files) ? meta.changed_files.map(String) : [],
|
|
1502
|
+
blockers: Array.isArray(checkpoint.blockers) ? checkpoint.blockers.map(String) : []
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1179
1505
|
function normalizeDesiredWorkItemCount(value, minimumValue, targetActiveSlots) {
|
|
1180
1506
|
const parsed = Number(value);
|
|
1181
1507
|
const minimum = Number(minimumValue);
|
|
@@ -117,7 +117,14 @@ function normalizeGitWorktreeMetadata(input) {
|
|
|
117
117
|
base_head: input?.base_head == null ? null : String(input.base_head),
|
|
118
118
|
worktree_head: input?.worktree_head == null ? null : String(input.worktree_head),
|
|
119
119
|
changed_files: Array.isArray(input?.changed_files) ? input.changed_files.map(String) : [],
|
|
120
|
-
diff_bytes: Number(input?.diff_bytes || 0)
|
|
120
|
+
diff_bytes: Number(input?.diff_bytes || 0),
|
|
121
|
+
checkpoint: input?.checkpoint ? {
|
|
122
|
+
...(input.checkpoint.schema === undefined ? {} : { schema: String(input.checkpoint.schema) }),
|
|
123
|
+
...(input.checkpoint.mode_applied === undefined ? {} : { mode_applied: String(input.checkpoint.mode_applied) }),
|
|
124
|
+
commit_hash: input.checkpoint.commit_hash == null ? null : String(input.checkpoint.commit_hash),
|
|
125
|
+
changed_files: Array.isArray(input.checkpoint.changed_files) ? input.checkpoint.changed_files.map(String) : [],
|
|
126
|
+
blockers: Array.isArray(input.checkpoint.blockers) ? input.checkpoint.blockers.map(String) : []
|
|
127
|
+
} : null
|
|
121
128
|
};
|
|
122
129
|
}
|
|
123
130
|
function normalizeHint(input) {
|
|
@@ -115,7 +115,11 @@ export async function runAgentScheduler(input) {
|
|
|
115
115
|
break;
|
|
116
116
|
const generationIndex = slot.generation_count + 1;
|
|
117
117
|
const provisionalSessionId = `${slot.slot_id}-gen-${generationIndex}`;
|
|
118
|
-
const workItem = leaseNextWorkItem(queue, provisionalSessionId
|
|
118
|
+
const workItem = leaseNextWorkItem(queue, provisionalSessionId, {
|
|
119
|
+
slotId: slot.slot_id,
|
|
120
|
+
agentId: String(slot.persona_assignment?.agent_id || ''),
|
|
121
|
+
activeWritePaths: activeWritePaths(queue)
|
|
122
|
+
});
|
|
119
123
|
if (!workItem)
|
|
120
124
|
break;
|
|
121
125
|
const generation = createAgentSessionGeneration({
|
|
@@ -314,6 +318,13 @@ function buildAgentForGeneration(slot, generation, workItem) {
|
|
|
314
318
|
goal_mode_ref: generation.goal_mode_ref
|
|
315
319
|
};
|
|
316
320
|
}
|
|
321
|
+
function activeWritePaths(queue) {
|
|
322
|
+
return queue.items
|
|
323
|
+
.filter((item) => item.status === 'running')
|
|
324
|
+
.flatMap((item) => Array.isArray(item.slice?.write_paths) ? item.slice.write_paths : [])
|
|
325
|
+
.map((file) => String(file || '').replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, ''))
|
|
326
|
+
.filter(Boolean);
|
|
327
|
+
}
|
|
317
328
|
function delay(ms) {
|
|
318
329
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
319
330
|
}
|
|
@@ -14,9 +14,9 @@ export async function evaluateAgentSlotPaneBindingProof(root, input = {}) {
|
|
|
14
14
|
const summary = await readJson(path.join(root, 'agent-native-cli-session-swarm.json'), null);
|
|
15
15
|
const ledger = await readJsonl(path.join(root, 'agent-zellij-pane-launch-ledger.jsonl'));
|
|
16
16
|
const zellijRecords = Array.isArray(summary?.records)
|
|
17
|
-
? summary.records.filter((record) => record.scaling_primitive === 'native_cli_process_in_zellij_worker_pane')
|
|
17
|
+
? summary.records.filter((record) => record.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' || record.scaling_primitive === 'native_cli_process_with_zellij_slot_renderer')
|
|
18
18
|
: [];
|
|
19
|
-
const paneLedgers = ledger.filter((row) => row.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' || row.pane_kind === 'worker_codex_sdk');
|
|
19
|
+
const paneLedgers = ledger.filter((row) => row.scaling_primitive === 'native_cli_process_in_zellij_worker_pane' || row.scaling_primitive === 'native_cli_process_with_zellij_slot_renderer' || row.pane_kind === 'worker_codex_sdk' || row.pane_kind === 'slot_status_renderer');
|
|
20
20
|
const uniqueKeys = new Set();
|
|
21
21
|
const duplicates = [];
|
|
22
22
|
for (const row of zellijRecords) {
|
|
@@ -29,7 +29,7 @@ export async function evaluateAgentSlotPaneBindingProof(root, input = {}) {
|
|
|
29
29
|
const zellijPaneWorkerSessions = Number(summary?.zellij_pane_worker_sessions || 0);
|
|
30
30
|
const blockers = [
|
|
31
31
|
...(input.requireZellij && !zellijRecords.length ? ['slot_pane_binding_zellij_records_missing'] : []),
|
|
32
|
-
...(zellijRecords.some((record) => record.pane_kind !== 'worker_codex_sdk') ? ['slot_pane_binding_wrong_pane_kind'] : []),
|
|
32
|
+
...(zellijRecords.some((record) => record.pane_kind !== 'worker_codex_sdk' && record.pane_kind !== 'slot_status_renderer') ? ['slot_pane_binding_wrong_pane_kind'] : []),
|
|
33
33
|
...(zellijRecords.some((record) => !isRealZellijWorkerPaneIdSource(record.zellij_pane_id_source)) ? ['slot_pane_binding_synthetic_or_missing_pane_id_source'] : []),
|
|
34
34
|
...(zellijRecords.some((record) => !record.zellij_pane_id) ? ['slot_pane_binding_pane_id_missing'] : []),
|
|
35
35
|
...(zellijRecords.some((record) => !record.sdk_thread_id) ? ['slot_pane_binding_sdk_thread_id_missing'] : []),
|
|
@@ -44,8 +44,15 @@ export function pendingWorkItems(queue) {
|
|
|
44
44
|
.filter((item) => item.status === 'pending' && item.dependencies.every((dep) => completed.has(dep)))
|
|
45
45
|
.sort((a, b) => a.priority - b.priority || a.id.localeCompare(b.id));
|
|
46
46
|
}
|
|
47
|
-
export function leaseNextWorkItem(queue, sessionId) {
|
|
48
|
-
const
|
|
47
|
+
export function leaseNextWorkItem(queue, sessionId, opts = {}) {
|
|
48
|
+
const activeWritePaths = new Set((opts.activeWritePaths || []).map(normalizePath).filter(Boolean));
|
|
49
|
+
const ready = pendingWorkItems(queue).filter((candidate) => {
|
|
50
|
+
const writePaths = sliceWritePaths(candidate);
|
|
51
|
+
return writePaths.every((file) => !activeWritePaths.has(file));
|
|
52
|
+
});
|
|
53
|
+
const item = ready.find((candidate) => ownerMatches(candidate, opts))
|
|
54
|
+
|| ready.find((candidate) => !candidateOwner(candidate))
|
|
55
|
+
|| ready[0];
|
|
49
56
|
if (!item)
|
|
50
57
|
return null;
|
|
51
58
|
item.status = 'running';
|
|
@@ -54,6 +61,23 @@ export function leaseNextWorkItem(queue, sessionId) {
|
|
|
54
61
|
queue.updated_at = nowIso();
|
|
55
62
|
return item;
|
|
56
63
|
}
|
|
64
|
+
function ownerMatches(item, opts) {
|
|
65
|
+
const owner = candidateOwner(item);
|
|
66
|
+
if (!owner)
|
|
67
|
+
return false;
|
|
68
|
+
return owner === opts.slotId || owner === opts.agentId;
|
|
69
|
+
}
|
|
70
|
+
function candidateOwner(item) {
|
|
71
|
+
const slice = item.slice || {};
|
|
72
|
+
return String(slice.owner_agent_id || slice.owner || slice.lane || '').trim();
|
|
73
|
+
}
|
|
74
|
+
function sliceWritePaths(item) {
|
|
75
|
+
const paths = Array.isArray(item.slice?.write_paths) ? item.slice.write_paths : [];
|
|
76
|
+
return paths.map((file) => normalizePath(String(file))).filter(Boolean);
|
|
77
|
+
}
|
|
78
|
+
function normalizePath(file) {
|
|
79
|
+
return String(file || '').replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, '');
|
|
80
|
+
}
|
|
57
81
|
export function completeWorkItem(queue, itemId, sessionId, status, reason = null) {
|
|
58
82
|
const item = queue.items.find((row) => row.id === itemId);
|
|
59
83
|
if (!item)
|
|
@@ -55,6 +55,8 @@ export function validateAgentWorkerResult(result) {
|
|
|
55
55
|
...(result?.source_intelligence_refs === undefined ? {} : { source_intelligence_refs: result.source_intelligence_refs }),
|
|
56
56
|
...(result?.goal_mode_ref === undefined ? {} : { goal_mode_ref: result.goal_mode_ref }),
|
|
57
57
|
...(result?.follow_up_work_items === undefined ? {} : { follow_up_work_items: followUps.accepted }),
|
|
58
|
+
...(result?.naruto_runtime === undefined ? {} : { naruto_runtime: result.naruto_runtime }),
|
|
59
|
+
...(result?.control_plane_result === undefined ? {} : { control_plane_result: result.control_plane_result }),
|
|
58
60
|
recursion_guard: { ok: guard.ok, violations: guard.violations },
|
|
59
61
|
verification: normalizeVerification(result?.verification)
|
|
60
62
|
};
|
|
@@ -336,8 +336,8 @@ class NativeCliSessionSwarmRecorder {
|
|
|
336
336
|
input.record.zellij_create_session = paneRecord.create_session;
|
|
337
337
|
input.record.zellij_launch = paneRecord.launch;
|
|
338
338
|
input.record.zellij_worker_pane = path.join(input.workerDirRel, 'zellij-worker-pane.json');
|
|
339
|
-
input.record.pane_kind =
|
|
340
|
-
input.record.scaling_primitive =
|
|
339
|
+
input.record.pane_kind = paneRecord.pane_kind;
|
|
340
|
+
input.record.scaling_primitive = paneRecord.scaling_primitive;
|
|
341
341
|
input.record.provider = paneRecord.provider;
|
|
342
342
|
input.record.service_tier = paneRecord.service_tier;
|
|
343
343
|
input.record.provider_context = paneRecord.provider_context;
|