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.
- 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 +33 -8
- package/dist/cli/command-registry.js +1 -0
- package/dist/commands/doctor.js +18 -1
- package/dist/commands/zellij-slot-pane.js +26 -0
- package/dist/commands/zellij.js +144 -1
- package/dist/core/agents/agent-orchestrator.js +202 -9
- package/dist/core/agents/agent-role-config.js +92 -0
- package/dist/core/agents/native-cli-session-swarm.js +230 -48
- package/dist/core/commands/mad-sks-command.js +17 -26
- package/dist/core/commands/naruto-command.js +155 -37
- package/dist/core/doctor/doctor-readiness-matrix.js +6 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +4 -0
- package/dist/core/init.js +1 -0
- package/dist/core/naruto/naruto-active-pool.js +141 -0
- package/dist/core/naruto/naruto-concurrency-governor.js +17 -2
- package/dist/core/naruto/naruto-real-worker-child.js +35 -0
- package/dist/core/naruto/naruto-real-worker-runtime.js +121 -0
- package/dist/core/naruto/naruto-work-graph.js +2 -1
- package/dist/core/release/release-gate-cache-v2.js +58 -4
- package/dist/core/release/release-gate-dag.js +36 -25
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-dashboard-renderer.js +22 -6
- package/dist/core/zellij/zellij-launcher.js +3 -3
- package/dist/core/zellij/zellij-layout-builder.js +1 -1
- package/dist/core/zellij/zellij-right-column-layout-proof.js +42 -0
- package/dist/core/zellij/zellij-right-column-manager.js +304 -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 +152 -17
- package/dist/scripts/agent-role-config-repair-check.js +33 -0
- package/dist/scripts/codex-sdk-release-review-pipeline-check.js +5 -5
- package/dist/scripts/doctor-fix-proves-codex-read-check.js +26 -5
- package/dist/scripts/git-worktree-integration-primary-check.js +4 -2
- package/dist/scripts/git-worktree-integration-primary-runtime-check.js +20 -0
- package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
- package/dist/scripts/mad-sks-zellij-default-pane-worker-check.js +2 -2
- package/dist/scripts/mutation-callsite-coverage-check.js +2 -1
- package/dist/scripts/naruto-concurrency-governor-check.js +2 -1
- package/dist/scripts/naruto-extreme-parallelism-check.js +22 -0
- package/dist/scripts/naruto-extreme-parallelism-real-check.js +42 -0
- package/dist/scripts/naruto-real-active-pool-check.js +39 -0
- package/dist/scripts/naruto-real-active-pool-runtime-check.js +53 -0
- package/dist/scripts/naruto-work-graph-check.js +1 -1
- package/dist/scripts/naruto-zellij-dynamic-right-column-check.js +48 -0
- package/dist/scripts/product-design-auto-install-check.js +3 -3
- package/dist/scripts/product-design-plugin-routing-check.js +3 -3
- package/dist/scripts/readme-architecture-imagegen-official-check.js +4 -3
- package/dist/scripts/release-cache-glob-hashing-check.js +42 -0
- 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 +35 -0
- package/dist/scripts/release-dynamic-performance-check.js +31 -1
- package/dist/scripts/release-gate-existence-audit.js +29 -33
- package/dist/scripts/release-parallel-speed-budget-check.js +67 -13
- package/dist/scripts/release-readiness-report.js +14 -3
- package/dist/scripts/zellij-dashboard-pane-check.js +6 -4
- package/dist/scripts/zellij-developer-controls-check.js +20 -0
- package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +21 -0
- package/dist/scripts/zellij-initial-main-only-blackbox.js +28 -0
- package/dist/scripts/zellij-right-column-geometry-proof.js +162 -0
- package/dist/scripts/zellij-right-column-headless-overflow-check.js +22 -0
- package/dist/scripts/zellij-right-column-manager-check.js +22 -0
- package/dist/scripts/zellij-slot-only-ui-check.js +22 -0
- package/dist/scripts/zellij-slot-pane-renderer-check.js +38 -0
- package/dist/scripts/zellij-worker-pane-manager-check.js +2 -1
- package/dist/scripts/zellij-worker-pane-manager-single-owner-check.js +7 -6
- package/package.json +23 -5
- 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
|
|
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,
|
|
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
|
|
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 =
|
|
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
|