sneakoscope 2.0.9 → 2.0.11
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 +37 -8
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers.js +8 -20
- package/dist/commands/doctor.js +23 -10
- package/dist/commands/zellij-slot-column-anchor.js +23 -0
- package/dist/commands/zellij-slot-pane.js +26 -0
- package/dist/core/agents/agent-orchestrator.js +255 -16
- package/dist/core/agents/agent-patch-schema.js +8 -1
- 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 +165 -11
- package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
- 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 +69 -0
- package/dist/core/git/git-worktree-patch-envelope.js +8 -1
- package/dist/core/hooks-runtime.js +4 -0
- package/dist/core/init.js +3 -2
- package/dist/core/naruto/naruto-active-pool.js +35 -2
- package/dist/core/naruto/naruto-allocation-policy.js +99 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +1 -1
- package/dist/core/naruto/naruto-real-worker-child.js +134 -0
- package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
- package/dist/core/naruto/naruto-rebalance-policy.js +36 -0
- package/dist/core/naruto/naruto-task-hints.js +71 -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 +111 -9
- package/dist/core/zellij/zellij-slot-column-anchor.js +59 -0
- package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
- package/dist/core/zellij/zellij-ui-mode.js +16 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +104 -13
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- package/dist/scripts/git-worktree-checkpoint-check.js +20 -0
- package/dist/scripts/git-worktree-cross-rebase-check.js +27 -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-actual-worker-control-plane-check.js +29 -0
- package/dist/scripts/naruto-allocation-policy-check.js +33 -0
- package/dist/scripts/naruto-extreme-parallelism-check.js +1 -1
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +43 -0
- package/dist/scripts/naruto-orchestrator-runtime-source-check.js +11 -0
- package/dist/scripts/naruto-real-active-pool-check.js +3 -2
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +55 -0
- package/dist/scripts/naruto-rebalance-policy-check.js +28 -0
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +7 -3
- 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-dag-full-coverage-check.js +15 -1
- 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 +14 -3
- package/dist/scripts/zellij-first-slot-down-stack-check.js +20 -0
- package/dist/scripts/zellij-first-slot-down-stack-real-check.js +16 -0
- 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 +9 -4
- package/dist/scripts/zellij-slot-column-anchor-check.js +24 -0
- package/dist/scripts/zellij-slot-only-ui-check.js +24 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +11 -4
- package/package.json +22 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { createMission, missionDir, setCurrent } from '../mission.js';
|
|
3
|
-
import { nowIso, readJson, readText, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
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
6
|
import { initializeAgentCentralLedger, appendAgentLedgerEvent, compactAgentLedger } from './agent-central-ledger.js';
|
|
@@ -55,7 +55,10 @@ import { selectFinalGptPatchSource } from '../pipeline/final-gpt-patch-stage.js'
|
|
|
55
55
|
import { allocateWorkerWorktree } from '../git/git-worktree-manager.js';
|
|
56
56
|
import { exportGitWorktreeDiff } from '../git/git-worktree-diff.js';
|
|
57
57
|
import { buildGitWorktreePatchEnvelope } from '../git/git-worktree-patch-envelope.js';
|
|
58
|
+
import { checkpointWorkerWorktree } from '../git/git-worktree-checkpoint.js';
|
|
58
59
|
import { cleanupGitWorktree } from '../git/git-worktree-cleanup.js';
|
|
60
|
+
import { createGitIntegrationWorktree } from '../git/git-integration-worktree.js';
|
|
61
|
+
import { applyGitWorktreeMergeQueue } from '../git/git-worktree-merge-queue.js';
|
|
59
62
|
export async function runNativeAgentOrchestrator(opts = {}) {
|
|
60
63
|
const root = path.resolve(opts.root || process.cwd());
|
|
61
64
|
const prompt = String(opts.prompt || 'Native agent run');
|
|
@@ -268,6 +271,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
268
271
|
worktree_root: gitWorktreePolicy?.worktree_root || null,
|
|
269
272
|
allocations: [],
|
|
270
273
|
diffs: [],
|
|
274
|
+
checkpoints: [],
|
|
271
275
|
cleanup: [],
|
|
272
276
|
blockers: []
|
|
273
277
|
};
|
|
@@ -422,7 +426,10 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
422
426
|
await writeJsonAtomic(path.join(ledgerRoot, 'local-collaboration-policy.json'), localCollaborationPolicy);
|
|
423
427
|
const localParticipated = localCollaborationParticipated(results);
|
|
424
428
|
const candidatePatchEnvelopes = results.flatMap((result) => Array.isArray(result.patch_envelopes) ? result.patch_envelopes : []);
|
|
425
|
-
const
|
|
429
|
+
const worktreeParticipated = candidatePatchEnvelopes.some((envelope) => envelope?.source === 'git-worktree-diff' || envelope?.git_worktree?.worktree_path)
|
|
430
|
+
|| results.some((result) => result?.git_worktree_diff || result?.git_worktree_checkpoint);
|
|
431
|
+
const gptFinalRequired = localParticipated || worktreeParticipated;
|
|
432
|
+
const gptFinalArbiter = gptFinalRequired
|
|
426
433
|
? await runFinalGptReviewStage({
|
|
427
434
|
schema: 'sks.gpt-final-arbiter-input.v1',
|
|
428
435
|
route,
|
|
@@ -446,10 +453,10 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
446
453
|
rollback_plan: { verification_rollback_dag: strategyCompiled.verification_rollback_dag || null }
|
|
447
454
|
}, { cwd: root, mutationLedgerRoot: path.join(ledgerRoot, 'gpt-final-arbiter') })
|
|
448
455
|
: null;
|
|
449
|
-
const finalGptPatchStage =
|
|
456
|
+
const finalGptPatchStage = gptFinalRequired
|
|
450
457
|
? selectFinalGptPatchSource(gptFinalArbiter, candidatePatchEnvelopes)
|
|
451
458
|
: null;
|
|
452
|
-
const resultsForPatchSwarm =
|
|
459
|
+
const resultsForPatchSwarm = gptFinalRequired && finalGptPatchStage?.ok === true && gptFinalArbiter?.result?.status === 'modified'
|
|
453
460
|
? withFinalGptPatchEnvelopes(results, finalGptPatchStage.patch_envelopes)
|
|
454
461
|
: results;
|
|
455
462
|
const patchSwarm = await runAgentPatchSwarmRuntime(root, ledgerRoot, {
|
|
@@ -460,7 +467,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
460
467
|
results: resultsForPatchSwarm,
|
|
461
468
|
parallelWritePolicy,
|
|
462
469
|
verificationRollbackDag: strategyCompiled.verification_rollback_dag,
|
|
463
|
-
dryRun: opts.dryRunPatches === true || opts.applyPatches !== true || (
|
|
470
|
+
dryRun: opts.dryRunPatches === true || opts.applyPatches !== true || (gptFinalRequired && gptFinalArbiter?.ok !== true),
|
|
464
471
|
gptFinalArbiter,
|
|
465
472
|
finalGptPatchStage
|
|
466
473
|
});
|
|
@@ -489,8 +496,8 @@ export async function runNativeAgentOrchestrator(opts = {}) {
|
|
|
489
496
|
...(noSubagentScalingPolicy.ok ? [] : noSubagentScalingPolicy.blockers),
|
|
490
497
|
...(fastModePropagation.ok ? [] : fastModePropagation.blockers),
|
|
491
498
|
...(gitWorktreeRuntime.required === true && gitWorktreeRuntime.ok === false ? gitWorktreeRuntime.blockers || ['git_worktree_runtime_not_ok'] : []),
|
|
492
|
-
...(
|
|
493
|
-
...(
|
|
499
|
+
...(gptFinalRequired && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
|
|
500
|
+
...(gptFinalRequired && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
|
|
494
501
|
...(patchSwarm.ok ? [] : patchSwarm.blockers),
|
|
495
502
|
...(janitor.ok ? [] : janitor.blockers)
|
|
496
503
|
];
|
|
@@ -645,6 +652,14 @@ async function finalizeWorkerGitWorktree(input) {
|
|
|
645
652
|
workerId: String(input.agent.id || input.slice.id || 'worker')
|
|
646
653
|
});
|
|
647
654
|
await writeJsonAtomic(path.join(input.workerWorktree.artifactDir, 'git-worktree-diff.json'), diff);
|
|
655
|
+
const checkpoint = await checkpointWorkerWorktree({
|
|
656
|
+
worktreePath: allocation.worktree_path,
|
|
657
|
+
repoRoot: allocation.main_repo_root || input.root,
|
|
658
|
+
workerId: String(input.agent.id || input.slice.id || 'worker'),
|
|
659
|
+
taskId: String(input.slice.id || input.agent.id || 'task'),
|
|
660
|
+
mode: 'auto'
|
|
661
|
+
});
|
|
662
|
+
await writeJsonAtomic(path.join(input.workerWorktree.artifactDir, 'git-worktree-checkpoint.json'), checkpoint);
|
|
648
663
|
input.runtime.diffs.push({
|
|
649
664
|
agent_id: input.agent.id,
|
|
650
665
|
slice_id: input.slice.id,
|
|
@@ -654,18 +669,29 @@ async function finalizeWorkerGitWorktree(input) {
|
|
|
654
669
|
diff_bytes: diff.diff_bytes,
|
|
655
670
|
blockers: diff.blockers
|
|
656
671
|
});
|
|
672
|
+
input.runtime.checkpoints.push({
|
|
673
|
+
agent_id: input.agent.id,
|
|
674
|
+
slice_id: input.slice.id,
|
|
675
|
+
ok: checkpoint.ok,
|
|
676
|
+
mode_applied: checkpoint.mode_applied,
|
|
677
|
+
commit_hash: checkpoint.commit_hash,
|
|
678
|
+
changed_files: checkpoint.changed_files,
|
|
679
|
+
blockers: checkpoint.blockers
|
|
680
|
+
});
|
|
657
681
|
if (!diff.clean && diff.ok) {
|
|
658
682
|
const envelope = buildGitWorktreePatchEnvelope({
|
|
659
683
|
diff,
|
|
660
684
|
agentId: String(input.agent.id || 'agent'),
|
|
661
685
|
sessionId: String(input.agent.session_id || ''),
|
|
662
686
|
slotId: String(input.agent.slot_id || ''),
|
|
663
|
-
generationIndex: Math.max(1, Math.floor(Number(input.agent.generation_index || 1)))
|
|
687
|
+
generationIndex: Math.max(1, Math.floor(Number(input.agent.generation_index || 1))),
|
|
688
|
+
checkpoint
|
|
664
689
|
});
|
|
665
690
|
input.result.patch_envelopes = [...(Array.isArray(input.result.patch_envelopes) ? input.result.patch_envelopes : []), envelope];
|
|
666
691
|
input.result.changed_files = [...new Set([...(input.result.changed_files || []), ...diff.changed_files])];
|
|
667
|
-
input.result.artifacts = [...new Set([...(input.result.artifacts || []), path.relative(input.ledgerRoot, path.join(input.workerWorktree.artifactDir, 'git-worktree-diff.json'))])];
|
|
692
|
+
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'))])];
|
|
668
693
|
input.result.git_worktree_diff = diff;
|
|
694
|
+
input.result.git_worktree_checkpoint = checkpoint;
|
|
669
695
|
}
|
|
670
696
|
const cleanup = await cleanupGitWorktree({
|
|
671
697
|
repoRoot: allocation.main_repo_root || input.root,
|
|
@@ -682,7 +708,7 @@ async function finalizeWorkerGitWorktree(input) {
|
|
|
682
708
|
retention_lock_path: cleanup.retention_lock_path,
|
|
683
709
|
blockers: cleanup.blockers
|
|
684
710
|
});
|
|
685
|
-
input.runtime.blockers.push(...diff.blockers, ...cleanup.blockers);
|
|
711
|
+
input.runtime.blockers.push(...diff.blockers, ...checkpoint.blockers, ...cleanup.blockers);
|
|
686
712
|
input.runtime.ok = input.runtime.blockers.length === 0;
|
|
687
713
|
await writeJsonAtomic(path.join(input.ledgerRoot, 'agent-git-worktree-runtime.json'), input.runtime);
|
|
688
714
|
}
|
|
@@ -753,9 +779,18 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
753
779
|
}
|
|
754
780
|
}
|
|
755
781
|
const pendingEntries = queueStore.queue.queued();
|
|
756
|
-
const
|
|
782
|
+
const worktreeEntries = pendingEntries.filter((entry) => entry.envelope?.source === 'git-worktree-diff');
|
|
783
|
+
const normalEntries = pendingEntries.filter((entry) => entry.envelope?.source !== 'git-worktree-diff');
|
|
784
|
+
let worktreeMergeReport = null;
|
|
785
|
+
const worktreeApplyResults = [];
|
|
786
|
+
if (worktreeEntries.length) {
|
|
787
|
+
worktreeMergeReport = await runGitWorktreeIntegrationPrimary(root, ledgerRoot, input.missionId, worktreeEntries, queueStore);
|
|
788
|
+
for (const row of worktreeMergeReport.apply_results || [])
|
|
789
|
+
worktreeApplyResults.push(row);
|
|
790
|
+
}
|
|
791
|
+
const merge = coordinateAgentPatchMerge(normalEntries);
|
|
757
792
|
await writeAgentMergeCoordinatorArtifacts(ledgerRoot, merge);
|
|
758
|
-
const conflictRebase = await executeAgentPatchConflictRebase(root,
|
|
793
|
+
const conflictRebase = await executeAgentPatchConflictRebase(root, normalEntries, merge, { dryRun: input.dryRun, artifactsDir: ledgerRoot });
|
|
759
794
|
merge.conflict_rebase_results = 'agent-patch-conflict-rebase-results.json';
|
|
760
795
|
merge.rebase_success_count = conflictRebase.succeeded_entry_ids.length;
|
|
761
796
|
merge.rebase_blocker_count = conflictRebase.blockers.length;
|
|
@@ -765,11 +800,11 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
765
800
|
merge.unresolved_conflict_entry_ids = [...conflictedEntryIds];
|
|
766
801
|
merge.ok = conflictedEntryIds.size === 0 && (conflictRebase.failed_entry_ids || []).length === 0 && (conflictRebase.blocked_entry_ids || []).length === 0;
|
|
767
802
|
merge.blockers = merge.ok ? [] : merge.blockers || [];
|
|
768
|
-
for (const entry of
|
|
803
|
+
for (const entry of normalEntries) {
|
|
769
804
|
if (conflictedEntryIds.has(entry.id))
|
|
770
805
|
await queueStore.markConflicted(entry.id, merge.blockers || ['patch_conflict']);
|
|
771
806
|
}
|
|
772
|
-
const disjointEntries =
|
|
807
|
+
const disjointEntries = normalEntries.filter((entry) => !conflictedEntryIds.has(entry.id));
|
|
773
808
|
const startedAt = nowIso();
|
|
774
809
|
for (const entryId of rebaseSucceededEntryIds) {
|
|
775
810
|
await queueStore.markApplying(entryId);
|
|
@@ -797,6 +832,7 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
797
832
|
return { entry_id: entry.id, started_at, finished_at, ...applyResult };
|
|
798
833
|
}));
|
|
799
834
|
const applyResults = [
|
|
835
|
+
...worktreeApplyResults,
|
|
800
836
|
...parallelApplyResults,
|
|
801
837
|
...(conflictRebase.apply_results || []).map((row) => ({ entry_id: row.entry_id, started_at: row.apply_started_at || nowIso(), finished_at: row.apply_ended_at || nowIso(), ...row }))
|
|
802
838
|
];
|
|
@@ -912,7 +948,8 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
912
948
|
conflictRebase,
|
|
913
949
|
verificationRollbackDag: input.verificationRollbackDag,
|
|
914
950
|
gptFinalArbiter: input.gptFinalArbiter,
|
|
915
|
-
finalGptPatchStage: input.finalGptPatchStage
|
|
951
|
+
finalGptPatchStage: input.finalGptPatchStage,
|
|
952
|
+
worktreeMergeReport
|
|
916
953
|
};
|
|
917
954
|
const initialProof = buildAgentPatchProof(proofInput);
|
|
918
955
|
await writeJsonAtomic(path.join(ledgerRoot, 'agent-patch-proof.json'), initialProof);
|
|
@@ -942,6 +979,8 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
942
979
|
apply_finished_at: finishedAt,
|
|
943
980
|
apply_latency_ms: Math.max(0, Date.parse(finishedAt) - Date.parse(startedAt)),
|
|
944
981
|
parallel_apply_count: parallelEntries.length,
|
|
982
|
+
worktree_integration_primary_count: worktreeEntries.length,
|
|
983
|
+
worktree_merge_queue: worktreeMergeReport,
|
|
945
984
|
parallel_apply_groups: merge.parallel_apply_groups || [],
|
|
946
985
|
serial_merge_groups: merge.serial_merge_groups || [],
|
|
947
986
|
conflict_rebase: {
|
|
@@ -971,7 +1010,8 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
971
1010
|
proof: 'agent-patch-proof.json',
|
|
972
1011
|
transaction_journal: 'agent-patch-transaction-journal.jsonl',
|
|
973
1012
|
transaction_journal_summary: 'agent-patch-transaction-journal-summary.json',
|
|
974
|
-
conflict_rebase: 'agent-patch-conflict-rebase-results.json'
|
|
1013
|
+
conflict_rebase: 'agent-patch-conflict-rebase-results.json',
|
|
1014
|
+
git_worktree_merge_queue: worktreeMergeReport ? 'git-worktree-merge-queue-report.json' : null
|
|
975
1015
|
},
|
|
976
1016
|
blockers
|
|
977
1017
|
};
|
|
@@ -985,6 +1025,205 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
|
|
|
985
1025
|
await writeJsonAtomic(path.join(ledgerRoot, 'agent-patch-swarm-runtime.json'), report);
|
|
986
1026
|
return report;
|
|
987
1027
|
}
|
|
1028
|
+
async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, entries, queueStore) {
|
|
1029
|
+
const diffs = entries.map((entry) => gitWorktreeDiffFromQueueEntry(entry)).filter(Boolean);
|
|
1030
|
+
const checkpoints = entries.map((entry) => gitWorktreeCheckpointFromQueueEntry(entry)).filter(Boolean);
|
|
1031
|
+
const repoRoot = diffs[0]?.main_repo_root || root;
|
|
1032
|
+
const baseRef = diffs.find((diff) => diff.base_head)?.base_head || undefined;
|
|
1033
|
+
const integration = await createGitIntegrationWorktree({ repoRoot, missionId, ...(baseRef ? { baseRef } : {}) });
|
|
1034
|
+
const applyResults = [];
|
|
1035
|
+
if (!integration.ok) {
|
|
1036
|
+
for (const entry of entries) {
|
|
1037
|
+
await queueStore.markConflicted(entry.id, integration.blockers || ['git_worktree_integration_allocation_failed']);
|
|
1038
|
+
applyResults.push({
|
|
1039
|
+
entry_id: entry.id,
|
|
1040
|
+
started_at: nowIso(),
|
|
1041
|
+
finished_at: nowIso(),
|
|
1042
|
+
ok: false,
|
|
1043
|
+
changed_files: entry.write_paths || entry.envelope?.git_worktree?.changed_files || [],
|
|
1044
|
+
verification: { checks: ['git-worktree-integration-primary'] },
|
|
1045
|
+
violations: integration.blockers || ['git_worktree_integration_allocation_failed']
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
const blockedReport = {
|
|
1049
|
+
schema: 'sks.git-worktree-integration-primary-runtime.v1',
|
|
1050
|
+
ok: false,
|
|
1051
|
+
generated_at: nowIso(),
|
|
1052
|
+
integration,
|
|
1053
|
+
integration_worktree_path: integration.worktree_path || null,
|
|
1054
|
+
applied_entry_ids: [],
|
|
1055
|
+
conflicted_entry_ids: entries.map((entry) => entry.id),
|
|
1056
|
+
apply_results: applyResults,
|
|
1057
|
+
blockers: integration.blockers || ['git_worktree_integration_allocation_failed']
|
|
1058
|
+
};
|
|
1059
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'git-worktree-merge-queue-report.json'), blockedReport);
|
|
1060
|
+
return blockedReport;
|
|
1061
|
+
}
|
|
1062
|
+
const startedAt = nowIso();
|
|
1063
|
+
for (const entry of entries)
|
|
1064
|
+
await queueStore.markApplying(entry.id);
|
|
1065
|
+
const queueReport = await applyGitWorktreeMergeQueue({
|
|
1066
|
+
integrationWorktreePath: integration.worktree_path,
|
|
1067
|
+
diffs,
|
|
1068
|
+
checkpoints
|
|
1069
|
+
});
|
|
1070
|
+
const rollbackPlan = queueReport.ok ? await captureGitWorktreeRollbackPlan(repoRoot, queueReport.changed_files || []) : { ok: false, rollback: [], blockers: ['git_worktree_integration_prevalidation_failed'] };
|
|
1071
|
+
const mainApplyReport = queueReport.ok && rollbackPlan.ok
|
|
1072
|
+
? await applyGitWorktreeMergeQueue({
|
|
1073
|
+
integrationWorktreePath: repoRoot,
|
|
1074
|
+
diffs,
|
|
1075
|
+
checkpoints
|
|
1076
|
+
})
|
|
1077
|
+
: null;
|
|
1078
|
+
const rollbackEvidence = mainApplyReport?.ok
|
|
1079
|
+
? await completeGitWorktreeRollbackPlan(repoRoot, rollbackPlan.rollback)
|
|
1080
|
+
: rollbackPlan;
|
|
1081
|
+
const finishedAt = nowIso();
|
|
1082
|
+
const conflictsByWorker = new Set([
|
|
1083
|
+
...(queueReport.conflicts || []).map((row) => String(row.worker_id || row.workerId || '')),
|
|
1084
|
+
...(mainApplyReport?.conflicts || []).map((row) => String(row.worker_id || row.workerId || ''))
|
|
1085
|
+
]);
|
|
1086
|
+
const appliedEntryIds = [];
|
|
1087
|
+
const conflictedEntryIds = [];
|
|
1088
|
+
for (const entry of entries) {
|
|
1089
|
+
const workerId = String(entry.envelope?.git_worktree?.worker_id || entry.envelope?.agent_id || entry.agent_id || '');
|
|
1090
|
+
const changedFiles = entry.write_paths || entry.envelope?.git_worktree?.changed_files || [];
|
|
1091
|
+
const ok = queueReport.ok && mainApplyReport?.ok === true && rollbackEvidence.ok === true && !conflictsByWorker.has(workerId);
|
|
1092
|
+
if (ok) {
|
|
1093
|
+
await queueStore.markApplied(entry.id);
|
|
1094
|
+
appliedEntryIds.push(entry.id);
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
await queueStore.markConflicted(entry.id, queueReport.blockers || ['git_worktree_merge_failed']);
|
|
1098
|
+
conflictedEntryIds.push(entry.id);
|
|
1099
|
+
}
|
|
1100
|
+
applyResults.push({
|
|
1101
|
+
entry_id: entry.id,
|
|
1102
|
+
started_at: startedAt,
|
|
1103
|
+
finished_at: finishedAt,
|
|
1104
|
+
ok,
|
|
1105
|
+
changed_files: changedFiles,
|
|
1106
|
+
rollback: ok ? rollbackEvidence.rollback.filter((row) => changedFiles.includes(row.path)) : [],
|
|
1107
|
+
rollback_digest: ok ? `git-worktree-integration:${entry.id}:${sha256(JSON.stringify(rollbackEvidence.rollback.filter((row) => changedFiles.includes(row.path))))}` : null,
|
|
1108
|
+
verification: { checks: ['git-worktree-integration-primary', 'git-apply-3way', 'main-repo-apply', 'rollback-hashes'] },
|
|
1109
|
+
violations: ok ? [] : [...(queueReport.blockers || []), ...(mainApplyReport?.blockers || []), ...(rollbackEvidence.blockers || []), 'git_worktree_main_repo_apply_failed'].filter(Boolean)
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
const reportBlockers = [...(queueReport.blockers || []), ...(mainApplyReport?.blockers || []), ...(rollbackEvidence.blockers || [])];
|
|
1113
|
+
const report = {
|
|
1114
|
+
schema: 'sks.git-worktree-integration-primary-runtime.v1',
|
|
1115
|
+
ok: reportBlockers.length === 0 && appliedEntryIds.length === entries.length,
|
|
1116
|
+
generated_at: nowIso(),
|
|
1117
|
+
integration,
|
|
1118
|
+
integration_worktree_path: integration.worktree_path,
|
|
1119
|
+
applied_entry_ids: appliedEntryIds,
|
|
1120
|
+
conflicted_entry_ids: conflictedEntryIds,
|
|
1121
|
+
merge_queue: queueReport,
|
|
1122
|
+
main_repo_apply: mainApplyReport,
|
|
1123
|
+
rollback_evidence: rollbackEvidence,
|
|
1124
|
+
apply_results: applyResults,
|
|
1125
|
+
blockers: reportBlockers
|
|
1126
|
+
};
|
|
1127
|
+
await writeJsonAtomic(path.join(ledgerRoot, 'git-worktree-merge-queue-report.json'), report);
|
|
1128
|
+
return report;
|
|
1129
|
+
}
|
|
1130
|
+
async function captureGitWorktreeRollbackPlan(root, changedFiles) {
|
|
1131
|
+
const rootResolved = path.resolve(root);
|
|
1132
|
+
const rollback = [];
|
|
1133
|
+
const blockers = [];
|
|
1134
|
+
for (const file of [...new Set(changedFiles.map((row) => String(row || '').trim()).filter(Boolean))]) {
|
|
1135
|
+
const rel = normalizeWorktreeRelPath(file);
|
|
1136
|
+
const absolute = path.resolve(rootResolved, rel);
|
|
1137
|
+
if (!absolute.startsWith(rootResolved + path.sep)) {
|
|
1138
|
+
blockers.push(`git_worktree_rollback_path_outside_root:${rel}`);
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
const beforeExists = await exists(absolute);
|
|
1142
|
+
const before = beforeExists ? await readText(absolute, '') : '';
|
|
1143
|
+
rollback.push({
|
|
1144
|
+
path: rel,
|
|
1145
|
+
existed: beforeExists,
|
|
1146
|
+
sha256_before: beforeExists ? sha256(String(before)) : null,
|
|
1147
|
+
content_before: beforeExists ? String(before) : null
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
return { ok: blockers.length === 0, rollback, blockers };
|
|
1151
|
+
}
|
|
1152
|
+
async function completeGitWorktreeRollbackPlan(root, rollback) {
|
|
1153
|
+
const rootResolved = path.resolve(root);
|
|
1154
|
+
const blockers = [];
|
|
1155
|
+
const completed = [];
|
|
1156
|
+
for (const row of rollback) {
|
|
1157
|
+
const rel = normalizeWorktreeRelPath(row.path);
|
|
1158
|
+
const absolute = path.resolve(rootResolved, rel);
|
|
1159
|
+
if (!absolute.startsWith(rootResolved + path.sep)) {
|
|
1160
|
+
blockers.push(`git_worktree_rollback_path_outside_root:${rel}`);
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
const afterExists = await exists(absolute);
|
|
1164
|
+
if (!afterExists) {
|
|
1165
|
+
blockers.push(`git_worktree_rollback_after_missing:${rel}`);
|
|
1166
|
+
completed.push({ ...row, path: rel, sha256_after: null });
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
const after = await readText(absolute, '');
|
|
1170
|
+
completed.push({
|
|
1171
|
+
...row,
|
|
1172
|
+
path: rel,
|
|
1173
|
+
sha256_after: sha256(String(after))
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
return { ok: blockers.length === 0, rollback: completed, blockers };
|
|
1177
|
+
}
|
|
1178
|
+
function normalizeWorktreeRelPath(file) {
|
|
1179
|
+
return String(file || '').replace(/\\/g, '/').replace(/^\/+/, '');
|
|
1180
|
+
}
|
|
1181
|
+
function gitWorktreeDiffFromQueueEntry(entry) {
|
|
1182
|
+
const envelope = entry?.envelope || {};
|
|
1183
|
+
const meta = envelope.git_worktree || {};
|
|
1184
|
+
const operation = Array.isArray(envelope.operations) ? envelope.operations.find((row) => row?.op === 'git_apply_patch') : null;
|
|
1185
|
+
const diff = String(operation?.diff || '');
|
|
1186
|
+
return {
|
|
1187
|
+
schema: 'sks.git-worktree-diff.v1',
|
|
1188
|
+
ok: true,
|
|
1189
|
+
generated_at: nowIso(),
|
|
1190
|
+
mission_id: String(envelope.mission_id || ''),
|
|
1191
|
+
worker_id: String(envelope.agent_id || entry.agent_id || entry.id),
|
|
1192
|
+
main_repo_root: String(meta.main_repo_root || ''),
|
|
1193
|
+
worktree_path: String(meta.worktree_path || ''),
|
|
1194
|
+
branch: meta.branch == null ? null : String(meta.branch),
|
|
1195
|
+
base_head: meta.base_head == null ? null : String(meta.base_head),
|
|
1196
|
+
worktree_head: meta.worktree_head == null ? null : String(meta.worktree_head),
|
|
1197
|
+
status_porcelain: '',
|
|
1198
|
+
changed_files: Array.isArray(meta.changed_files) ? meta.changed_files.map(String) : entry.write_paths || [],
|
|
1199
|
+
untracked_files: [],
|
|
1200
|
+
diff,
|
|
1201
|
+
diff_bytes: Buffer.byteLength(diff),
|
|
1202
|
+
clean: diff.trim().length === 0,
|
|
1203
|
+
blockers: []
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
function gitWorktreeCheckpointFromQueueEntry(entry) {
|
|
1207
|
+
const envelope = entry?.envelope || {};
|
|
1208
|
+
const meta = envelope.git_worktree || {};
|
|
1209
|
+
const checkpoint = meta.checkpoint || null;
|
|
1210
|
+
if (!checkpoint || checkpoint.mode_applied !== 'checkpoint-commit' || !checkpoint.commit_hash)
|
|
1211
|
+
return null;
|
|
1212
|
+
return {
|
|
1213
|
+
schema: 'sks.git-worktree-checkpoint.v1',
|
|
1214
|
+
ok: Array.isArray(checkpoint.blockers) ? checkpoint.blockers.length === 0 : true,
|
|
1215
|
+
generated_at: nowIso(),
|
|
1216
|
+
worktree_path: String(meta.worktree_path || ''),
|
|
1217
|
+
repo_root: String(meta.main_repo_root || ''),
|
|
1218
|
+
worker_id: String(envelope.agent_id || entry.agent_id || entry.id),
|
|
1219
|
+
task_id: String(envelope.task_slice_id || entry.id || ''),
|
|
1220
|
+
mode_requested: 'auto',
|
|
1221
|
+
mode_applied: 'checkpoint-commit',
|
|
1222
|
+
commit_hash: String(checkpoint.commit_hash),
|
|
1223
|
+
changed_files: Array.isArray(checkpoint.changed_files) ? checkpoint.changed_files.map(String) : Array.isArray(meta.changed_files) ? meta.changed_files.map(String) : [],
|
|
1224
|
+
blockers: Array.isArray(checkpoint.blockers) ? checkpoint.blockers.map(String) : []
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
988
1227
|
function normalizeDesiredWorkItemCount(value, minimumValue, targetActiveSlots) {
|
|
989
1228
|
const parsed = Number(value);
|
|
990
1229
|
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) {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ensureDir, nowIso, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
4
|
+
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
5
|
+
export const AGENT_ROLE_CONFIG_REPAIR_SCHEMA = 'sks.agent-role-config-repair.v1';
|
|
6
|
+
const SKS_OWNED_AGENT_CONFIGS = new Map([
|
|
7
|
+
['analysis-scout.toml', roleConfig('analysis_scout', 'Read-only SKS analysis scout retained for stale Codex agent-role config repair.', 'read-only')],
|
|
8
|
+
['native-agent-intake.toml', roleConfig('native_agent', 'Read-only Team native agent for repository/docs/tests/API/risk slices.', 'read-only')],
|
|
9
|
+
['team-consensus.toml', roleConfig('team_consensus', 'Planning and debate specialist for SKS Team mode.', 'read-only')],
|
|
10
|
+
['implementation-worker.toml', roleConfig('implementation_worker', 'Implementation specialist for bounded SKS Team write sets.', 'workspace-write')],
|
|
11
|
+
['db-safety-reviewer.toml', roleConfig('db_safety_reviewer', 'Read-only database safety reviewer for SQL, migrations, Supabase, and rollback safety.', 'read-only')],
|
|
12
|
+
['qa-reviewer.toml', roleConfig('qa_reviewer', 'Strict read-only verification reviewer for correctness, regressions, and final evidence.', 'read-only')]
|
|
13
|
+
]);
|
|
14
|
+
export async function repairAgentRoleConfigs(input) {
|
|
15
|
+
const root = path.resolve(input.root);
|
|
16
|
+
const codexHome = input.codexHome || process.env.CODEX_HOME || path.join(process.env.HOME || '', '.codex');
|
|
17
|
+
const candidates = [path.join(root, '.codex', 'agents'), path.join(codexHome, 'agents')];
|
|
18
|
+
const missing = [];
|
|
19
|
+
const stale = [];
|
|
20
|
+
const created = [];
|
|
21
|
+
const repaired = [];
|
|
22
|
+
const existing = [];
|
|
23
|
+
for (const [file, config] of SKS_OWNED_AGENT_CONFIGS) {
|
|
24
|
+
const found = candidates.find((dir) => fs.existsSync(path.join(dir, file)));
|
|
25
|
+
if (found) {
|
|
26
|
+
const foundPath = path.join(found, file);
|
|
27
|
+
const text = fs.readFileSync(foundPath, 'utf8');
|
|
28
|
+
if (isValidRoleConfig(text, config)) {
|
|
29
|
+
existing.push(path.relative(root, foundPath) || foundPath);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
stale.push(file);
|
|
33
|
+
if (input.apply) {
|
|
34
|
+
const target = foundPath.startsWith(path.join(root, '.codex', 'agents')) ? foundPath : path.join(root, '.codex', 'agents', file);
|
|
35
|
+
await ensureDir(path.dirname(target));
|
|
36
|
+
await writeTextAtomic(target, config.content);
|
|
37
|
+
repaired.push(path.relative(root, target));
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
missing.push(file);
|
|
42
|
+
if (input.apply) {
|
|
43
|
+
const target = path.join(root, '.codex', 'agents', file);
|
|
44
|
+
await ensureDir(path.dirname(target));
|
|
45
|
+
await writeTextAtomic(target, config.content);
|
|
46
|
+
created.push(path.relative(root, target));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const requiredFixes = missing.length + stale.length;
|
|
50
|
+
const appliedFixes = created.length + repaired.length;
|
|
51
|
+
const report = {
|
|
52
|
+
schema: AGENT_ROLE_CONFIG_REPAIR_SCHEMA,
|
|
53
|
+
generated_at: nowIso(),
|
|
54
|
+
ok: input.apply ? requiredFixes === appliedFixes : true,
|
|
55
|
+
apply: input.apply === true,
|
|
56
|
+
missing,
|
|
57
|
+
stale,
|
|
58
|
+
existing,
|
|
59
|
+
created,
|
|
60
|
+
repaired,
|
|
61
|
+
warnings_suppressed: true,
|
|
62
|
+
blockers: input.apply && requiredFixes !== appliedFixes ? ['agent_role_config_repair_incomplete'] : []
|
|
63
|
+
};
|
|
64
|
+
if (input.reportPath)
|
|
65
|
+
await writeJsonAtomic(input.reportPath, report);
|
|
66
|
+
return report;
|
|
67
|
+
}
|
|
68
|
+
function roleConfig(name, description, sandbox) {
|
|
69
|
+
const content = [
|
|
70
|
+
`name = "${name}"`,
|
|
71
|
+
`description = "${description}"`,
|
|
72
|
+
`model = "${REQUIRED_CODEX_MODEL}"`,
|
|
73
|
+
'model_reasoning_effort = "medium"',
|
|
74
|
+
`sandbox_mode = "${sandbox}"`,
|
|
75
|
+
'approval_policy = "never"',
|
|
76
|
+
'developer_instructions = """',
|
|
77
|
+
`You are the SKS ${name} role.`,
|
|
78
|
+
sandbox === 'read-only' ? 'Do not edit files.' : 'Only edit the bounded files assigned by the parent orchestrator.',
|
|
79
|
+
'Return concise source-backed findings and LIVE_EVENT lines when applicable.',
|
|
80
|
+
'"""',
|
|
81
|
+
''
|
|
82
|
+
].join('\n');
|
|
83
|
+
return { name, sandbox, content };
|
|
84
|
+
}
|
|
85
|
+
function isValidRoleConfig(text, config) {
|
|
86
|
+
return text.includes(`name = "${config.name}"`)
|
|
87
|
+
&& text.includes('description = "')
|
|
88
|
+
&& text.includes(`model = "${REQUIRED_CODEX_MODEL}"`)
|
|
89
|
+
&& text.includes(`sandbox_mode = "${config.sandbox}"`)
|
|
90
|
+
&& text.includes('developer_instructions = """');
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=agent-role-config.js.map
|