/* RFC-0658: installBordbuchPreCommitHook — writes a combined pre-commit guard to the cache clone that: 1. Blocks direct git commit (RFC-0821 cache-clone commit guard) unless MISSION_GIT_COMMIT=1 is set. 2. Rejects commits deleting bordbuch/events.ndjson (RFC-0658 bordbuch integrity guard). Does not validate bordbuch content — that is bordbuch.validate's responsibility. Does not install hooks in workpiece clones — git clone does not copy hooks. RFC-0658: initial installBordbuchPreCommitHook implementation. RFC-0821: add cache-clone commit guard to block direct git commit in cache clones. RFC-1254: drop unused io-migration leftovers */ import path from "node:path"; import { writeFileIfChanged } from "@warpgogol/werkstatt-engine/kernel"; import { CACHE_CLONE_COMMIT_GUARD_SCRIPT } from "../mission/cache-clone-commit-guard.ts"; import { type WorkspaceIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io"; export interface BordbuchHookResult { installed: boolean; hookPath: string; systemId: string; } const HOOK_SCRIPT = `#!/bin/sh # Warpgogol cache-clone pre-commit hook (RFC-0658 + RFC-0821) # Combined guards: commit guard + bordbuch integrity guard. ${CACHE_CLONE_COMMIT_GUARD_SCRIPT} # Warpgogol bordbuch integrity guard (RFC-0658) # Rejects commits that delete bordbuch/events.ndjson if git diff --cached --name-status --diff-filter=D | grep -q 'bordbuch/events.ndjson$'; then echo "ERROR: refusing to delete bordbuch/events.ndjson (RFC-0658)" >&2 echo "If you need to reset bordbuch, use bordbuch.repair instead." >&2 exit 1 fi `; export async function installBordbuchPreCommitHook( cacheClonePath: string, systemId: string, io: WorkspaceIO, ): Promise { const hooksDir = path.join(cacheClonePath, ".git", "hooks"); const hookPath = path.join(hooksDir, "pre-commit"); if (!(await io.exists(path.join(cacheClonePath, ".git")))) { return { installed: false, hookPath, systemId }; } if (!(await io.exists(hooksDir))) { await io.mkdir(hooksDir); } await writeFileIfChanged(hookPath, HOOK_SCRIPT); const chmodResult = await io.exec("chmod", ["755", hookPath]); if (chmodResult.exitCode !== 0) { throw new Error( `chmod ${hookPath} exited ${chmodResult.exitCode}: ${chmodResult.stderr.slice(0, 200)}`, ); } return { installed: true, hookPath, systemId }; }