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.
Files changed (74) hide show
  1. package/README.md +8 -4
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/crates/sks-core/src/main.rs +1 -1
  5. package/dist/.sks-build-stamp.json +4 -4
  6. package/dist/bin/sks.js +1 -1
  7. package/dist/build-manifest.json +37 -8
  8. package/dist/cli/command-registry.js +2 -0
  9. package/dist/cli/install-helpers.js +8 -20
  10. package/dist/commands/doctor.js +23 -10
  11. package/dist/commands/zellij-slot-column-anchor.js +23 -0
  12. package/dist/commands/zellij-slot-pane.js +26 -0
  13. package/dist/core/agents/agent-orchestrator.js +255 -16
  14. package/dist/core/agents/agent-patch-schema.js +8 -1
  15. package/dist/core/agents/agent-role-config.js +92 -0
  16. package/dist/core/agents/native-cli-session-swarm.js +186 -71
  17. package/dist/core/commands/naruto-command.js +165 -11
  18. package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
  19. package/dist/core/fsx.js +1 -1
  20. package/dist/core/git/git-worktree-checkpoint.js +52 -0
  21. package/dist/core/git/git-worktree-cross-rebase.js +54 -0
  22. package/dist/core/git/git-worktree-merge-queue.js +69 -0
  23. package/dist/core/git/git-worktree-patch-envelope.js +8 -1
  24. package/dist/core/hooks-runtime.js +4 -0
  25. package/dist/core/init.js +3 -2
  26. package/dist/core/naruto/naruto-active-pool.js +35 -2
  27. package/dist/core/naruto/naruto-allocation-policy.js +99 -0
  28. package/dist/core/naruto/naruto-concurrency-governor.js +1 -1
  29. package/dist/core/naruto/naruto-real-worker-child.js +134 -0
  30. package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
  31. package/dist/core/naruto/naruto-rebalance-policy.js +36 -0
  32. package/dist/core/naruto/naruto-task-hints.js +71 -0
  33. package/dist/core/pipeline/finalize-pipeline-result.js +3 -1
  34. package/dist/core/pipeline/gpt-final-required.js +22 -2
  35. package/dist/core/version.js +1 -1
  36. package/dist/core/zellij/zellij-right-column-manager.js +111 -9
  37. package/dist/core/zellij/zellij-slot-column-anchor.js +59 -0
  38. package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
  39. package/dist/core/zellij/zellij-ui-mode.js +16 -0
  40. package/dist/core/zellij/zellij-worker-pane-manager.js +104 -13
  41. package/dist/scripts/agent-role-config-repair-check.js +33 -0
  42. package/dist/scripts/git-worktree-checkpoint-check.js +20 -0
  43. package/dist/scripts/git-worktree-cross-rebase-check.js +27 -0
  44. package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
  45. package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
  46. package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
  47. package/dist/scripts/naruto-actual-worker-control-plane-check.js +29 -0
  48. package/dist/scripts/naruto-allocation-policy-check.js +33 -0
  49. package/dist/scripts/naruto-extreme-parallelism-check.js +1 -1
  50. package/dist/scripts/naruto-extreme-parallelism-real-check.js +43 -0
  51. package/dist/scripts/naruto-orchestrator-runtime-source-check.js +11 -0
  52. package/dist/scripts/naruto-real-active-pool-check.js +3 -2
  53. package/dist/scripts/naruto-real-active-pool-runtime-check.js +55 -0
  54. package/dist/scripts/naruto-rebalance-policy-check.js +28 -0
  55. package/dist/scripts/naruto-shadow-clone-swarm-check.js +7 -3
  56. package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +29 -2
  57. package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
  58. package/dist/scripts/release-check-dynamic-execute.js +27 -1
  59. package/dist/scripts/release-check-dynamic.js +38 -11
  60. package/dist/scripts/release-check-stamp.js +7 -2
  61. package/dist/scripts/release-dag-full-coverage-check.js +15 -1
  62. package/dist/scripts/release-dynamic-performance-check.js +31 -1
  63. package/dist/scripts/release-gate-existence-audit.js +29 -33
  64. package/dist/scripts/release-readiness-report.js +14 -3
  65. package/dist/scripts/zellij-first-slot-down-stack-check.js +20 -0
  66. package/dist/scripts/zellij-first-slot-down-stack-real-check.js +16 -0
  67. package/dist/scripts/zellij-right-column-geometry-proof.js +155 -22
  68. package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
  69. package/dist/scripts/zellij-right-column-manager-check.js +9 -4
  70. package/dist/scripts/zellij-slot-column-anchor-check.js +24 -0
  71. package/dist/scripts/zellij-slot-only-ui-check.js +24 -0
  72. package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
  73. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +11 -4
  74. 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 gptFinalArbiter = localParticipated
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 = localParticipated
456
+ const finalGptPatchStage = gptFinalRequired
450
457
  ? selectFinalGptPatchSource(gptFinalArbiter, candidatePatchEnvelopes)
451
458
  : null;
452
- const resultsForPatchSwarm = localParticipated && finalGptPatchStage?.ok === true && gptFinalArbiter?.result?.status === 'modified'
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 || (localParticipated && gptFinalArbiter?.ok !== 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
- ...(localParticipated && gptFinalArbiter?.ok !== true ? gptFinalArbiter?.blockers || ['gpt_final_arbiter_not_ok'] : []),
493
- ...(localParticipated && finalGptPatchStage?.ok === false ? finalGptPatchStage.blockers || ['final_gpt_patch_stage_not_ok'] : []),
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 merge = coordinateAgentPatchMerge(pendingEntries);
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, pendingEntries, merge, { dryRun: input.dryRun, artifactsDir: ledgerRoot });
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 pendingEntries) {
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 = pendingEntries.filter((entry) => !conflictedEntryIds.has(entry.id));
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