import crypto from "node:crypto"; import fs from "node:fs"; import path from "node:path"; import { resolveAppRoot } from "../lib/paths"; const DEFAULT_CONFIG_NAME = "triggershell.yml"; export interface InitOptions { port: number; auth: boolean; force: boolean; } export async function initCommand( targetPath: string | undefined, opts: InitOptions, ): Promise { const targetDir = path.resolve(process.cwd(), targetPath ?? "."); fs.mkdirSync(targetDir, { recursive: true }); const configPath = path.join(targetDir, DEFAULT_CONFIG_NAME); if (fs.existsSync(configPath) && !opts.force) { console.error(`${configPath} already exists. Use --force to overwrite.`); process.exitCode = 1; return; } const templatePath = path.join( resolveAppRoot(), "templates", DEFAULT_CONFIG_NAME, ); const template = fs.readFileSync(templatePath, "utf-8"); const rendered = template .replace("__PORT__", String(opts.port)) .replace("__AUTH_ENABLED__", opts.auth ? "true" : "false"); fs.writeFileSync(configPath, rendered); console.log(`Created ${configPath}`); const envPath = path.join(targetDir, ".env"); if (opts.auth) { if (fs.existsSync(envPath)) { console.log( `${envPath} already exists - make sure it sets TRIGGERSHELL_SESSION_SECRET (>= 32 chars).`, ); } else { const sessionSecret = crypto.randomBytes(32).toString("hex"); fs.writeFileSync( envPath, `TRIGGERSHELL_SESSION_SECRET=${sessionSecret}\n`, ); console.log(`Created ${envPath} (keep this out of version control)`); } console.log( "\nAuth is enabled but no users are configured yet. Add one with:", ); console.log(` triggershell users add --config ${configPath}`); } console.log("\nStart the app with:"); console.log(` triggershell start --config ${configPath}`); }