← Files ForgeMindARCHIVED FILE

src/git.mjs

1.73 KB · Oct 3, 2026 · 06:33 UTC

↓ Download file

import { createHash } from 'node:crypto';

import { ForgeMindError } from './errors.mjs';
import { runProcess } from './process.mjs';

export async function getGitState(workspace) {
  const projectPathspec = ['--', '.', ':(exclude).codex-orchestrator/evidence/**', ':(exclude).codex-orchestrator/reports/**', ':(exclude).codex-orchestrator/dashboard/**'];
  const commitResult = await runProcess('git', ['rev-parse', 'HEAD'], { cwd: workspace });
  if (commitResult.exitCode !== 0) throw new ForgeMindError('FM_GIT_REQUIRED', 'Delivery proof requires a Git repository with at least one commit.');
  const statusResult = await runProcess('git', ['status', '--porcelain=v1', ...projectPathspec], { cwd: workspace });
  const diffResult = await runProcess('git', ['diff', '--binary', 'HEAD', ...projectPathspec], { cwd: workspace, maxOutputBytes: 2 * 1024 * 1024 });
  const dirty = Boolean(statusResult.stdout.trim());
  const filesResult = dirty
    ? await runProcess('git', ['status', '--porcelain=v1', ...projectPathspec], { cwd: workspace })
    : await runProcess('git', ['show', '--pretty=format:', '--name-only', 'HEAD'], { cwd: workspace });
  const changedFiles = dirty
    ? filesResult.stdout.split(/\r?\n/).filter(Boolean).map((line) => line.slice(3).trim().replaceAll('\\', '/')).sort()
    : filesResult.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => line.replaceAll('\\', '/')).sort();
  const commit = commitResult.stdout.trim();
  const snapshotHash = createHash('sha256')
    .update(commit)
    .update('\0')
    .update(statusResult.stdout)
    .update('\0')
    .update(diffResult.stdout)
    .digest('hex');
  return { commit, dirty, changedFiles: [...new Set(changedFiles)], snapshotHash };
}

SHA-256: fc54b816cdba1d7c357f6752daa72bc2fe434ad5c9bfedcc0ed34e9517f6b839