import { execFile } from 'node:child_process'; import path from 'node:path'; import * as vscode from 'vscode'; import { log } from '../util/log'; import { RuntimeOptions } from './cli'; const gitRoots = new Map>(); function gitTopLevel(dir: string): Promise { let pending = gitRoots.get(dir); if (!pending) { pending = new Promise((resolve) => { execFile('git', ['rev-parse', '--show-toplevel'], { cwd: dir, timeout: 10_000 }, (error, stdout) => { resolve(error ? undefined : path.resolve(stdout.trim())); }); }); gitRoots.set(dir, pending); } return pending; } export function clearGitRootCache(): void { gitRoots.clear(); } /** The checkout used to verify source evidence for a file, if any. */ export async function repoRootFor(uri: vscode.Uri | undefined): Promise { const configured = vscode.workspace.getConfiguration('archify', uri).get('repoRoot', '').trim(); if (configured) { if (path.isAbsolute(configured)) return configured; const folder = (uri && vscode.workspace.getWorkspaceFolder(uri)) ?? vscode.workspace.workspaceFolders?.[0]; return folder ? path.resolve(folder.uri.fsPath, configured) : path.resolve(configured); } if (!uri || uri.scheme !== 'file') return undefined; return gitTopLevel(path.dirname(uri.fsPath)); } export async function runtimeFor(context: vscode.ExtensionContext, uri: vscode.Uri | undefined): Promise { const config = vscode.workspace.getConfiguration('archify', uri); const nodePath = config.get('nodePath', '').trim(); const quality = config.get('quality', ''); return { cliPath: context.asAbsolutePath(path.join('vendor', 'archify', 'bin', 'archify.mjs')), nodePath: nodePath || process.execPath, runAsNode: !nodePath, workDir: path.join(context.globalStorageUri.fsPath, 'renders'), quality: quality || undefined, repoRoot: await repoRootFor(uri), log: (line) => log().debug(line), }; } export function evidenceMode(uri: vscode.Uri | undefined): 'fallback' | 'strict' { return vscode.workspace.getConfiguration('archify', uri).get<'fallback' | 'strict'>('sourceEvidence', 'fallback'); }