import { AGENDA, BLOCKING_SUFFIX, VENUE_ARCHIVE } from "../constants/blocking.constants.ts"; import { CONVERGE_NEEDS_OPERANDS, archiveNameTaken, archiveRootMissing, convergeAbsent, convergeHelp, convergeNotVenue, convergePreview, converged, orderingsBlock, } from "../strings/converge.strings.ts"; import { basename, resolve } from "node:path"; import { existsSync, readFileSync, readdirSync } from "node:fs"; import { historyPath, projectRoot, slotText, surfacePath, surfacePrefix } from "../../../config/surface.config.ts"; import { BOARD_PATH } from "../constants/board.constants.ts"; import { NO_FIX_FLAG } from "../constants/path.constants.ts"; import { convergenceEdges } from "../validators/converge.validator.ts"; import { plannedInvariants } from "../runners/venue.runner.ts"; import { runArchiveMove } from "../runners/converge.runner.ts"; const REPO_ROOT = projectRoot(); export const RESTATES: readonly string[] = [ "a_venue_accumulates_and_the_board_is_swept", "a_venue_is_absorbed_before_it_is_archived", "an_undecided_half_names_its_receiver", ]; const argumentValue = function argumentValue(flag: string): string | null { const at = process.argv.indexOf(flag); if (at === -1 || at + 1 >= process.argv.length) { return null; } const value = process.argv[at + 1] ?? ""; return value.startsWith("--") ? null : value; }; const venueNames = function venueNames(): string[] { const prefix = surfacePrefix(); const root = resolve(REPO_ROOT, prefix); if (!existsSync(root)) { return []; } const out: string[] = []; for (const entry of readdirSync(root, { withFileTypes: true })) { if (!entry.isFile() || !entry.name.endsWith(BLOCKING_SUFFIX)) { continue; } out.push(prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`); } return out; }; const resolveTarget = function resolveTarget(named: string): string { if (existsSync(resolve(REPO_ROOT, named))) { return named; } const prefix = surfacePrefix(); const prefixed = prefix.length === 0 ? named : `${prefix}/${named}`; return existsSync(resolve(REPO_ROOT, prefixed)) ? prefixed : named; }; const main = function main(): void { if (process.argv.includes("--help")) { process.stdout.write(convergeHelp(slotText("execution", "converge_command"))); process.exit(0); } const agent = argumentValue("--agent"); const named = argumentValue("--file"); if (agent === null || named === null) { process.stdout.write(CONVERGE_NEEDS_OPERANDS); process.exit(2); } const target = resolveTarget(named); const absolute = resolve(REPO_ROOT, target); if (!absolute.endsWith(BLOCKING_SUFFIX)) { process.stdout.write(convergeNotVenue(target)); process.exit(2); } if (!existsSync(absolute)) { process.stdout.write(convergeAbsent(target)); process.exit(2); } const board = resolve(REPO_ROOT, BOARD_PATH); const index = resolve(REPO_ROOT, surfacePath("agent_index")); const archivePath = resolve(REPO_ROOT, historyPath()); const edges = convergenceEdges( REPO_ROOT, target, readFileSync(absolute, "utf8"), existsSync(board) ? readFileSync(board, "utf8") : "", existsSync(index) ? readFileSync(index, "utf8") : "", existsSync(archivePath) ? readFileSync(archivePath, "utf8") : "", venueNames(), plannedInvariants( existsSync(resolve(REPO_ROOT, AGENDA)) ? readFileSync(resolve(REPO_ROOT, AGENDA), "utf8") : "", ), ); for (const edge of edges) { process.stdout.write(` ${edge.holds ? "holds " : "BLOCKS "} ${edge.edge}\n ${edge.detail}\n`); } const blocking = edges.filter((edge) => !edge.holds); if (blocking.length > 0) { process.stdout.write(orderingsBlock(blocking.length, edges.length, target)); process.exit(2); } const archiveRoot = resolve(REPO_ROOT, VENUE_ARCHIVE); const destination = resolve(archiveRoot, basename(target)); if (!existsSync(archiveRoot)) { process.stdout.write(archiveRootMissing(target)); process.exit(2); } if (existsSync(destination)) { process.stdout.write(archiveNameTaken(basename(target), target)); process.exit(2); } if (process.argv.includes(NO_FIX_FLAG)) { process.stdout.write(convergePreview(target, agent)); process.exit(0); } const moved = runArchiveMove(absolute, destination, target); if (moved.code !== 0) { process.stdout.write(moved.message); process.exit(moved.code); } process.stdout.write(converged(target, agent)); process.exit(0); }; main();