import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs"; import { basename, join, relative } from "node:path"; import { execSync } from "node:child_process"; import * as readline from "node:readline/promises"; import { stdin, stdout } from "node:process"; import type { Readable, Writable } from "node:stream"; import { TEMPLATES, getTemplate, isFielded, isPrivateOnly, type Template, } from "./templates.js"; import { renderAar, docFilename, type AarMeta, type Answers, } from "./renderAar.js"; import { ensureIgnored, forkPrivate, hasPrivate, privateCompanionPath, privateStoreDir, privateName, uniquePath, wrapPrivate, writePrivateDoc, } from "./private.js"; export type NewOptions = { type?: string; title?: string; dir?: string; private?: boolean; // route the whole doc to the gitignored private store root?: string; // repo root for the private store / .gitignore (defaults to cwd) }; function todayIso(): string { return new Date().toISOString().slice(0, 10); } function gitValue(args: string): string { try { return execSync(`git ${args}`, { stdio: ["ignore", "pipe", "ignore"], }) .toString() .trim(); } catch { return ""; } } /** Read a possibly multi-line answer for one section. */ async function readSection( rl: readline.Interface, out: Writable, heading: string, guidance: string, ): Promise { out.write(`\n## ${heading}\n ${guidance}\n`); out.write( ` (write as many lines as you like; finish with a line containing just "." or press Enter now to skip)\n`, ); const lines: string[] = []; for (;;) { const line = await rl.question(" > "); if (line.trim() === ".") break; if (lines.length === 0 && line.trim() === "") break; // immediate Enter = skip lines.push(line); } return lines.join("\n").trim(); } async function chooseTemplate( rl: readline.Interface, out: Writable, preset?: string, ): Promise