All source files · Workbench
scripts/export-public-repository.mjs
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { dirname, join, relative, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { spawnSync } from 'node:child_process';
// Explicit allowlist: credentials, runtime output, and internal drafts never enter the export.
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const staging = join(root, '.source-export');
const bare = join(root, 'public', 'deadline-loom.git');
const browse = join(root, 'public', 'code');
const allowed = ['src', 'sanity', 'data', 'scripts', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'astro.config.mjs', 'sanity.config.ts', 'sanity.cli.ts', 'tsconfig.json', '.env.example', '.gitignore', 'README.md', 'LICENSE', 'backend-notes.md'];
mkdirSync(staging, { recursive: true });
mkdirSync(browse, { recursive: true });
for (const item of allowed) {
if (!existsSync(join(root, item))) throw new Error(`Missing exported path: ${item}`);
cpSync(join(root, item), join(staging, item), { recursive: true, force: true });
}
function git(directory, ...args) {
const result = spawnSync('git', ['-C', directory, ...args], { encoding: 'utf8' });
if (result.status !== 0) throw new Error(`Git export failed: ${result.stderr}`);
return result.stdout.trim();
}
if (!existsSync(join(staging, '.git'))) git(staging, 'init', '-b', 'main');
git(staging, 'config', 'user.name', 'Deadline Loom AI-assisted build');
git(staging, 'config', 'user.email', 'build@deadline-loom.invalid');
git(staging, 'add', '--', ...allowed);
if (git(staging, 'status', '--porcelain')) git(staging, 'commit', '-m', 'Publish verified Deadline Loom source');
if (!existsSync(bare)) {
mkdirSync(bare, { recursive: true });
git(bare, 'init', '--bare');
}
git(staging, 'push', bare, 'main:main');
git(bare, 'symbolic-ref', 'HEAD', 'refs/heads/main');
git(bare, 'update-server-info');
const revision = git(staging, 'rev-parse', 'HEAD');
const escape = value => value.replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
const files = [];
function walk(path) {
for (const entry of readdirSync(path, { withFileTypes: true })) {
if (entry.name === '.git') continue;
const current = join(path, entry.name);
if (entry.isDirectory()) walk(current);
else files.push(relative(staging, current).replaceAll('\\', '/'));
}
}
walk(staging);
const style = '<style>body{max-width:1000px;margin:50px auto;padding:0 24px;background:#f5f2e9;color:#253b2c;font:17px/1.6 system-ui}a{color:#315c3c}pre{overflow:auto;padding:24px;border:1px solid #bec7b6;background:#fffdf8;font:13px/1.6 monospace}code{overflow-wrap:anywhere}</style>';
for (const file of files) {
const destination = join(browse, `${file}.html`);
mkdirSync(dirname(destination), { recursive: true });
writeFileSync(destination, `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${escape(file)} — Deadline Loom source</title>${style}<p><a href="/code/">All source files</a> · <a href="/">Workbench</a></p><h1>${escape(file)}</h1><pre>${escape(readFileSync(join(staging, file), 'utf8'))}</pre>`);
}
writeFileSync(join(browse, 'index.html'), `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Deadline Loom source repository</title>${style}<p><a href="/">Deadline Loom workbench</a></p><h1>Public source repository</h1><p>Original code: MIT license. This read-only repository contains the Astro application, Sanity schemas and Studio actions, seed data, planner checks, dependency lockfile, and documentation. Private environment files and account details are excluded.</p><p><a href="/deadline-loom-source.zip">Download source ZIP</a></p><p>Clone the repository through standard Git HTTP:</p><pre>git clone https://deadline-loom-jaye-2026.netlify.app/deadline-loom.git</pre><p>Revision: <code>${revision}</code></p><ul>${files.sort().map(file => `<li><a href="${file.split('/').map(encodeURIComponent).join('/')}.html">${escape(file)}</a></li>`).join('')}</ul>`);
console.log(`Exported ${files.length} source files. Git revision ${revision}.`);