sneakoscope 2.0.8 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) 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 +33 -8
  8. package/dist/cli/command-registry.js +1 -0
  9. package/dist/commands/doctor.js +18 -1
  10. package/dist/commands/zellij-slot-pane.js +26 -0
  11. package/dist/commands/zellij.js +144 -1
  12. package/dist/core/agents/agent-orchestrator.js +202 -9
  13. package/dist/core/agents/agent-role-config.js +92 -0
  14. package/dist/core/agents/native-cli-session-swarm.js +230 -48
  15. package/dist/core/commands/mad-sks-command.js +17 -26
  16. package/dist/core/commands/naruto-command.js +155 -37
  17. package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
  18. package/dist/core/fsx.js +1 -1
  19. package/dist/core/hooks-runtime.js +4 -0
  20. package/dist/core/init.js +1 -0
  21. package/dist/core/naruto/naruto-active-pool.js +141 -0
  22. package/dist/core/naruto/naruto-concurrency-governor.js +17 -2
  23. package/dist/core/naruto/naruto-real-worker-child.js +35 -0
  24. package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
  25. package/dist/core/naruto/naruto-work-graph.js +2 -1
  26. package/dist/core/release/release-gate-cache-v2.js +58 -4
  27. package/dist/core/release/release-gate-dag.js +36 -25
  28. package/dist/core/version.js +1 -1
  29. package/dist/core/zellij/zellij-dashboard-renderer.js +22 -6
  30. package/dist/core/zellij/zellij-launcher.js +3 -3
  31. package/dist/core/zellij/zellij-layout-builder.js +1 -1
  32. package/dist/core/zellij/zellij-right-column-layout-proof.js +42 -0
  33. package/dist/core/zellij/zellij-right-column-manager.js +304 -0
  34. package/dist/core/zellij/zellij-slot-pane-renderer.js +82 -0
  35. package/dist/core/zellij/zellij-ui-mode.js +16 -0
  36. package/dist/core/zellij/zellij-worker-pane-manager.js +152 -17
  37. package/dist/scripts/agent-role-config-repair-check.js +33 -0
  38. package/dist/scripts/codex-sdk-release-review-pipeline-check.js +5 -5
  39. package/dist/scripts/doctor-fix-proves-codex-read-check.js +26 -5
  40. package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
  41. package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
  42. package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
  43. package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +2 -2
  44. package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
  45. package/dist/scripts/naruto-concurrency-governor-check.js +2 -1
  46. package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
  47. package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
  48. package/dist/scripts/naruto-real-active-pool-check.js +39 -0
  49. package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
  50. package/dist/scripts/naruto-work-graph-check.js +1 -1
  51. package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +48 -0
  52. package/dist/scripts/product-design-auto-install-check.js +3 -3
  53. package/dist/scripts/product-design-plugin-routing-check.js +3 -3
  54. package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
  55. package/dist/scripts/release-cache-glob-hashing-check.js +42 -0
  56. package/dist/scripts/release-check-dynamic-execute.js +27 -1
  57. package/dist/scripts/release-check-dynamic.js +38 -11
  58. package/dist/scripts/release-check-stamp.js +7 -2
  59. package/dist/scripts/release-dag-full-coverage-check.js +35 -0
  60. package/dist/scripts/release-dynamic-performance-check.js +31 -1
  61. package/dist/scripts/release-gate-existence-audit.js +29 -33
  62. package/dist/scripts/release-parallel-speed-budget-check.js +67 -13
  63. package/dist/scripts/release-readiness-report.js +14 -3
  64. package/dist/scripts/zellij-dashboard-pane-check.js +6 -4
  65. package/dist/scripts/zellij-developer-controls-check.js +20 -0
  66. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +21 -0
  67. package/dist/scripts/zellij-initial-main-only-blackbox.js +28 -0
  68. package/dist/scripts/zellij-right-column-geometry-proof.js +162 -0
  69. package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
  70. package/dist/scripts/zellij-right-column-manager-check.js +22 -0
  71. package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
  72. package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
  73. package/dist/scripts/zellij-worker-pane-manager-check.js +2 -1
  74. package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +7 -6
  75. package/package.json +23 -5
  76. package/schemas/zellij/zellij-right-column-state.schema.json +41 -0
@@ -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';
@@ -56,6 +56,8 @@ 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
58
  import { cleanupGitWorktree } from '../git/git-worktree-cleanup.js';
59
+ import { createGitIntegrationWorktree } from '../git/git-integration-worktree.js';
60
+ import { applyGitWorktreeMergeQueue } from '../git/git-worktree-merge-queue.js';
59
61
  export async function runNativeAgentOrchestrator(opts = {}) {
60
62
  const root = path.resolve(opts.root || process.cwd());
61
63
  const prompt = String(opts.prompt || 'Native agent run');
@@ -281,7 +283,9 @@ export async function runNativeAgentOrchestrator(opts = {}) {
281
283
  noOllama: opts.noOllama === true,
282
284
  route,
283
285
  fastModePolicy,
284
- ...(opts.workerPlacement === undefined ? {} : { workerPlacement: String(opts.workerPlacement) })
286
+ ...(opts.workerPlacement === undefined ? {} : { workerPlacement: String(opts.workerPlacement) }),
287
+ zellijVisiblePaneCap: Number(opts.zellijVisiblePaneCap || visualLaneCount || targetActiveSlots),
288
+ projectRoot: root
285
289
  });
286
290
  await nativeCliSwarm.initialize();
287
291
  await setCurrent(root, { mission_id: missionId, mode: 'AGENT', phase: 'AGENT_NATIVE_KERNEL_RUNNING', route_command: routeCommand, native_agent_backend: backend });
@@ -334,7 +338,7 @@ export async function runNativeAgentOrchestrator(opts = {}) {
334
338
  generationIndex: agent.generation_index,
335
339
  requireGeneration: true
336
340
  });
337
- const backendOpts = { ...opts, missionId, agentRoot: ledgerRoot, cwd: workerWorktree?.context.path || root, route, prompt, fastMode: fastModePolicy.fast_mode, serviceTier: fastModePolicy.service_tier, ...(workerWorktree ? { worktree: workerWorktree.context } : {}) };
341
+ const backendOpts = { ...opts, missionId, agentRoot: ledgerRoot, cwd: workerWorktree?.context.path || root, projectRoot: root, route, prompt, fastMode: fastModePolicy.fast_mode, serviceTier: fastModePolicy.service_tier, ...(workerWorktree ? { worktree: workerWorktree.context } : {}) };
338
342
  const result = opts.nativeCliSwarm === false
339
343
  ? await runAgentByBackend(backend, runtimeAgent, runtimeSlice, backendOpts)
340
344
  : await nativeCliSwarm.launchWorker({ agent: runtimeAgent, slice: runtimeSlice, opts: backendOpts });
@@ -751,9 +755,18 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
751
755
  }
752
756
  }
753
757
  const pendingEntries = queueStore.queue.queued();
754
- const merge = coordinateAgentPatchMerge(pendingEntries);
758
+ const worktreeEntries = pendingEntries.filter((entry) => entry.envelope?.source === 'git-worktree-diff');
759
+ const normalEntries = pendingEntries.filter((entry) => entry.envelope?.source !== 'git-worktree-diff');
760
+ let worktreeMergeReport = null;
761
+ const worktreeApplyResults = [];
762
+ if (worktreeEntries.length) {
763
+ worktreeMergeReport = await runGitWorktreeIntegrationPrimary(root, ledgerRoot, input.missionId, worktreeEntries, queueStore);
764
+ for (const row of worktreeMergeReport.apply_results || [])
765
+ worktreeApplyResults.push(row);
766
+ }
767
+ const merge = coordinateAgentPatchMerge(normalEntries);
755
768
  await writeAgentMergeCoordinatorArtifacts(ledgerRoot, merge);
756
- const conflictRebase = await executeAgentPatchConflictRebase(root, pendingEntries, merge, { dryRun: input.dryRun, artifactsDir: ledgerRoot });
769
+ const conflictRebase = await executeAgentPatchConflictRebase(root, normalEntries, merge, { dryRun: input.dryRun, artifactsDir: ledgerRoot });
757
770
  merge.conflict_rebase_results = 'agent-patch-conflict-rebase-results.json';
758
771
  merge.rebase_success_count = conflictRebase.succeeded_entry_ids.length;
759
772
  merge.rebase_blocker_count = conflictRebase.blockers.length;
@@ -763,11 +776,11 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
763
776
  merge.unresolved_conflict_entry_ids = [...conflictedEntryIds];
764
777
  merge.ok = conflictedEntryIds.size === 0 && (conflictRebase.failed_entry_ids || []).length === 0 && (conflictRebase.blocked_entry_ids || []).length === 0;
765
778
  merge.blockers = merge.ok ? [] : merge.blockers || [];
766
- for (const entry of pendingEntries) {
779
+ for (const entry of normalEntries) {
767
780
  if (conflictedEntryIds.has(entry.id))
768
781
  await queueStore.markConflicted(entry.id, merge.blockers || ['patch_conflict']);
769
782
  }
770
- const disjointEntries = pendingEntries.filter((entry) => !conflictedEntryIds.has(entry.id));
783
+ const disjointEntries = normalEntries.filter((entry) => !conflictedEntryIds.has(entry.id));
771
784
  const startedAt = nowIso();
772
785
  for (const entryId of rebaseSucceededEntryIds) {
773
786
  await queueStore.markApplying(entryId);
@@ -795,6 +808,7 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
795
808
  return { entry_id: entry.id, started_at, finished_at, ...applyResult };
796
809
  }));
797
810
  const applyResults = [
811
+ ...worktreeApplyResults,
798
812
  ...parallelApplyResults,
799
813
  ...(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 }))
800
814
  ];
@@ -910,7 +924,8 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
910
924
  conflictRebase,
911
925
  verificationRollbackDag: input.verificationRollbackDag,
912
926
  gptFinalArbiter: input.gptFinalArbiter,
913
- finalGptPatchStage: input.finalGptPatchStage
927
+ finalGptPatchStage: input.finalGptPatchStage,
928
+ worktreeMergeReport
914
929
  };
915
930
  const initialProof = buildAgentPatchProof(proofInput);
916
931
  await writeJsonAtomic(path.join(ledgerRoot, 'agent-patch-proof.json'), initialProof);
@@ -940,6 +955,8 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
940
955
  apply_finished_at: finishedAt,
941
956
  apply_latency_ms: Math.max(0, Date.parse(finishedAt) - Date.parse(startedAt)),
942
957
  parallel_apply_count: parallelEntries.length,
958
+ worktree_integration_primary_count: worktreeEntries.length,
959
+ worktree_merge_queue: worktreeMergeReport,
943
960
  parallel_apply_groups: merge.parallel_apply_groups || [],
944
961
  serial_merge_groups: merge.serial_merge_groups || [],
945
962
  conflict_rebase: {
@@ -969,7 +986,8 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
969
986
  proof: 'agent-patch-proof.json',
970
987
  transaction_journal: 'agent-patch-transaction-journal.jsonl',
971
988
  transaction_journal_summary: 'agent-patch-transaction-journal-summary.json',
972
- conflict_rebase: 'agent-patch-conflict-rebase-results.json'
989
+ conflict_rebase: 'agent-patch-conflict-rebase-results.json',
990
+ git_worktree_merge_queue: worktreeMergeReport ? 'git-worktree-merge-queue-report.json' : null
973
991
  },
974
992
  blockers
975
993
  };
@@ -983,6 +1001,181 @@ async function runAgentPatchSwarmRuntime(root, ledgerRoot, input) {
983
1001
  await writeJsonAtomic(path.join(ledgerRoot, 'agent-patch-swarm-runtime.json'), report);
984
1002
  return report;
985
1003
  }
1004
+ async function runGitWorktreeIntegrationPrimary(root, ledgerRoot, missionId, entries, queueStore) {
1005
+ const diffs = entries.map((entry) => gitWorktreeDiffFromQueueEntry(entry)).filter(Boolean);
1006
+ const repoRoot = diffs[0]?.main_repo_root || root;
1007
+ const baseRef = diffs.find((diff) => diff.base_head)?.base_head || undefined;
1008
+ const integration = await createGitIntegrationWorktree({ repoRoot, missionId, ...(baseRef ? { baseRef } : {}) });
1009
+ const applyResults = [];
1010
+ if (!integration.ok) {
1011
+ for (const entry of entries) {
1012
+ await queueStore.markConflicted(entry.id, integration.blockers || ['git_worktree_integration_allocation_failed']);
1013
+ applyResults.push({
1014
+ entry_id: entry.id,
1015
+ started_at: nowIso(),
1016
+ finished_at: nowIso(),
1017
+ ok: false,
1018
+ changed_files: entry.write_paths || entry.envelope?.git_worktree?.changed_files || [],
1019
+ verification: { checks: ['git-worktree-integration-primary'] },
1020
+ violations: integration.blockers || ['git_worktree_integration_allocation_failed']
1021
+ });
1022
+ }
1023
+ const blockedReport = {
1024
+ schema: 'sks.git-worktree-integration-primary-runtime.v1',
1025
+ ok: false,
1026
+ generated_at: nowIso(),
1027
+ integration,
1028
+ integration_worktree_path: integration.worktree_path || null,
1029
+ applied_entry_ids: [],
1030
+ conflicted_entry_ids: entries.map((entry) => entry.id),
1031
+ apply_results: applyResults,
1032
+ blockers: integration.blockers || ['git_worktree_integration_allocation_failed']
1033
+ };
1034
+ await writeJsonAtomic(path.join(ledgerRoot, 'git-worktree-merge-queue-report.json'), blockedReport);
1035
+ return blockedReport;
1036
+ }
1037
+ const startedAt = nowIso();
1038
+ for (const entry of entries)
1039
+ await queueStore.markApplying(entry.id);
1040
+ const queueReport = await applyGitWorktreeMergeQueue({
1041
+ integrationWorktreePath: integration.worktree_path,
1042
+ diffs
1043
+ });
1044
+ const rollbackPlan = queueReport.ok ? await captureGitWorktreeRollbackPlan(repoRoot, queueReport.changed_files || []) : { ok: false, rollback: [], blockers: ['git_worktree_integration_prevalidation_failed'] };
1045
+ const mainApplyReport = queueReport.ok && rollbackPlan.ok
1046
+ ? await applyGitWorktreeMergeQueue({
1047
+ integrationWorktreePath: repoRoot,
1048
+ diffs
1049
+ })
1050
+ : null;
1051
+ const rollbackEvidence = mainApplyReport?.ok
1052
+ ? await completeGitWorktreeRollbackPlan(repoRoot, rollbackPlan.rollback)
1053
+ : rollbackPlan;
1054
+ const finishedAt = nowIso();
1055
+ const conflictsByWorker = new Set([
1056
+ ...(queueReport.conflicts || []).map((row) => String(row.worker_id || row.workerId || '')),
1057
+ ...(mainApplyReport?.conflicts || []).map((row) => String(row.worker_id || row.workerId || ''))
1058
+ ]);
1059
+ const appliedEntryIds = [];
1060
+ const conflictedEntryIds = [];
1061
+ for (const entry of entries) {
1062
+ const workerId = String(entry.envelope?.git_worktree?.worker_id || entry.envelope?.agent_id || entry.agent_id || '');
1063
+ const changedFiles = entry.write_paths || entry.envelope?.git_worktree?.changed_files || [];
1064
+ const ok = queueReport.ok && mainApplyReport?.ok === true && rollbackEvidence.ok === true && !conflictsByWorker.has(workerId);
1065
+ if (ok) {
1066
+ await queueStore.markApplied(entry.id);
1067
+ appliedEntryIds.push(entry.id);
1068
+ }
1069
+ else {
1070
+ await queueStore.markConflicted(entry.id, queueReport.blockers || ['git_worktree_merge_failed']);
1071
+ conflictedEntryIds.push(entry.id);
1072
+ }
1073
+ applyResults.push({
1074
+ entry_id: entry.id,
1075
+ started_at: startedAt,
1076
+ finished_at: finishedAt,
1077
+ ok,
1078
+ changed_files: changedFiles,
1079
+ rollback: ok ? rollbackEvidence.rollback.filter((row) => changedFiles.includes(row.path)) : [],
1080
+ rollback_digest: ok ? `git-worktree-integration:${entry.id}:${sha256(JSON.stringify(rollbackEvidence.rollback.filter((row) => changedFiles.includes(row.path))))}` : null,
1081
+ verification: { checks: ['git-worktree-integration-primary', 'git-apply-3way', 'main-repo-apply', 'rollback-hashes'] },
1082
+ violations: ok ? [] : [...(queueReport.blockers || []), ...(mainApplyReport?.blockers || []), ...(rollbackEvidence.blockers || []), 'git_worktree_main_repo_apply_failed'].filter(Boolean)
1083
+ });
1084
+ }
1085
+ const reportBlockers = [...(queueReport.blockers || []), ...(mainApplyReport?.blockers || []), ...(rollbackEvidence.blockers || [])];
1086
+ const report = {
1087
+ schema: 'sks.git-worktree-integration-primary-runtime.v1',
1088
+ ok: reportBlockers.length === 0 && appliedEntryIds.length === entries.length,
1089
+ generated_at: nowIso(),
1090
+ integration,
1091
+ integration_worktree_path: integration.worktree_path,
1092
+ applied_entry_ids: appliedEntryIds,
1093
+ conflicted_entry_ids: conflictedEntryIds,
1094
+ merge_queue: queueReport,
1095
+ main_repo_apply: mainApplyReport,
1096
+ rollback_evidence: rollbackEvidence,
1097
+ apply_results: applyResults,
1098
+ blockers: reportBlockers
1099
+ };
1100
+ await writeJsonAtomic(path.join(ledgerRoot, 'git-worktree-merge-queue-report.json'), report);
1101
+ return report;
1102
+ }
1103
+ async function captureGitWorktreeRollbackPlan(root, changedFiles) {
1104
+ const rootResolved = path.resolve(root);
1105
+ const rollback = [];
1106
+ const blockers = [];
1107
+ for (const file of [...new Set(changedFiles.map((row) => String(row || '').trim()).filter(Boolean))]) {
1108
+ const rel = normalizeWorktreeRelPath(file);
1109
+ const absolute = path.resolve(rootResolved, rel);
1110
+ if (!absolute.startsWith(rootResolved + path.sep)) {
1111
+ blockers.push(`git_worktree_rollback_path_outside_root:${rel}`);
1112
+ continue;
1113
+ }
1114
+ const beforeExists = await exists(absolute);
1115
+ const before = beforeExists ? await readText(absolute, '') : '';
1116
+ rollback.push({
1117
+ path: rel,
1118
+ existed: beforeExists,
1119
+ sha256_before: beforeExists ? sha256(String(before)) : null,
1120
+ content_before: beforeExists ? String(before) : null
1121
+ });
1122
+ }
1123
+ return { ok: blockers.length === 0, rollback, blockers };
1124
+ }
1125
+ async function completeGitWorktreeRollbackPlan(root, rollback) {
1126
+ const rootResolved = path.resolve(root);
1127
+ const blockers = [];
1128
+ const completed = [];
1129
+ for (const row of rollback) {
1130
+ const rel = normalizeWorktreeRelPath(row.path);
1131
+ const absolute = path.resolve(rootResolved, rel);
1132
+ if (!absolute.startsWith(rootResolved + path.sep)) {
1133
+ blockers.push(`git_worktree_rollback_path_outside_root:${rel}`);
1134
+ continue;
1135
+ }
1136
+ const afterExists = await exists(absolute);
1137
+ if (!afterExists) {
1138
+ blockers.push(`git_worktree_rollback_after_missing:${rel}`);
1139
+ completed.push({ ...row, path: rel, sha256_after: null });
1140
+ continue;
1141
+ }
1142
+ const after = await readText(absolute, '');
1143
+ completed.push({
1144
+ ...row,
1145
+ path: rel,
1146
+ sha256_after: sha256(String(after))
1147
+ });
1148
+ }
1149
+ return { ok: blockers.length === 0, rollback: completed, blockers };
1150
+ }
1151
+ function normalizeWorktreeRelPath(file) {
1152
+ return String(file || '').replace(/\\/g, '/').replace(/^\/+/, '');
1153
+ }
1154
+ function gitWorktreeDiffFromQueueEntry(entry) {
1155
+ const envelope = entry?.envelope || {};
1156
+ const meta = envelope.git_worktree || {};
1157
+ const operation = Array.isArray(envelope.operations) ? envelope.operations.find((row) => row?.op === 'git_apply_patch') : null;
1158
+ const diff = String(operation?.diff || '');
1159
+ return {
1160
+ schema: 'sks.git-worktree-diff.v1',
1161
+ ok: true,
1162
+ generated_at: nowIso(),
1163
+ mission_id: String(envelope.mission_id || ''),
1164
+ worker_id: String(envelope.agent_id || entry.agent_id || entry.id),
1165
+ main_repo_root: String(meta.main_repo_root || ''),
1166
+ worktree_path: String(meta.worktree_path || ''),
1167
+ branch: meta.branch == null ? null : String(meta.branch),
1168
+ base_head: meta.base_head == null ? null : String(meta.base_head),
1169
+ worktree_head: meta.worktree_head == null ? null : String(meta.worktree_head),
1170
+ status_porcelain: '',
1171
+ changed_files: Array.isArray(meta.changed_files) ? meta.changed_files.map(String) : entry.write_paths || [],
1172
+ untracked_files: [],
1173
+ diff,
1174
+ diff_bytes: Buffer.byteLength(diff),
1175
+ clean: diff.trim().length === 0,
1176
+ blockers: []
1177
+ };
1178
+ }
986
1179
  function normalizeDesiredWorkItemCount(value, minimumValue, targetActiveSlots) {
987
1180
  const parsed = Number(value);
988
1181
  const minimum = Number(minimumValue);
@@ -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