@rm-industries/create-forge 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,21 @@ complete input contract. Unless disabled with `--no-install` or `--no-git`, it
13
13
  runs `npm install` and initializes a `main`-branch Git repository after files are
14
14
  created. It never stages files, reads Git identity, or creates a commit.
15
15
 
16
+ By default, the destination is both the generated project root and repository
17
+ root. To add a Forge site to an existing repository without replacing unrelated
18
+ files, pass the site directory as the destination and identify the repository
19
+ root separately:
20
+
21
+ ```sh
22
+ npm create @rm-industries/forge website -- --repository-root .
23
+ ```
24
+
25
+ Forge writes the application into `website/`, places repository-owned GitHub
26
+ configuration in the root `.github/` directory, installs dependencies inside
27
+ `website/`, and initializes Git at the repository root when needed. Generated
28
+ workflow filters, working directories, artifact paths, and Dependabot settings
29
+ are adjusted for the nested project automatically.
30
+
16
31
  The selected template is copied with dotfiles and file modes intact. Forge
17
32
  customizes only reviewed metadata files and refuses parent-traversal paths,
18
33
  symbolic-link collisions, filesystem roots, and unconfirmed non-empty
@@ -54,12 +69,14 @@ To exercise the packed CLI across the complete generator fixture matrix:
54
69
  npm run test:generator:e2e
55
70
  ```
56
71
 
57
- This generates default, fully specified, scoped-package-name, current-directory,
58
- no-install, and conflict fixtures in an OS temporary directory. The default
59
- fixture installs and runs the complete generated-project quality pipeline
60
- outside the Forge workspace. The conflict fixture also proves that a failed
61
- invocation leaves existing files unchanged. Every fixture is removed after the
62
- run.
72
+ This generates default, fully specified, scoped-package-name,
73
+ current-directory, nested-project, no-install, and conflict fixtures in an OS
74
+ temporary directory. The default and nested fixtures install dependencies
75
+ outside the Forge workspace. The nested fixture also runs the generated
76
+ project's core quality and production-build pipeline, verifies its Pages
77
+ artifact location, and checks its repository-level CI and Dependabot paths. The
78
+ conflict fixture proves that a failed invocation leaves existing files
79
+ unchanged. Every fixture is removed after the run.
63
80
 
64
81
  The release compatibility matrix runs the same packed fixtures with the
65
82
  generated project's core quality gate on every supported Node line on Ubuntu
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { chmod, copyFile, lstat, mkdir, mkdtemp, readFile, readdir, rm, rmdir, stat, writeFile } from "node:fs/promises";
3
3
  import { confirm, isCancel, text } from "@clack/prompts";
4
4
  import { Command, CommanderError, Option } from "commander";
5
- import { basename, dirname, isAbsolute, join, parse, relative, resolve } from "node:path";
5
+ import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
6
6
  import validateNpmPackageName from "validate-npm-package-name";
7
7
  import { tmpdir } from "node:os";
8
8
  import { fileURLToPath } from "node:url";
@@ -102,6 +102,7 @@ const resolveOptions = async (provided, { interactive, prompts }) => {
102
102
  initialValue: ".",
103
103
  validate: textValidation(validateDestination)
104
104
  })));
105
+ const repositoryRoot = validateDestination(provided.repositoryRoot ?? destination);
105
106
  const derivedPackageName = derivePackageName(destination);
106
107
  const packageName = validatePackageName(provided.packageName ?? (useDefaults ? derivedPackageName : await promptText(prompts, {
107
108
  message: "What should the npm package be named?",
@@ -111,6 +112,7 @@ const resolveOptions = async (provided, { interactive, prompts }) => {
111
112
  const defaultSiteName = humanizePackageName(packageName);
112
113
  return {
113
114
  destination,
115
+ repositoryRoot,
114
116
  packageName,
115
117
  siteName: validatePlainText("--site-name", provided.siteName ?? (useDefaults ? defaultSiteName : await promptText(prompts, {
116
118
  message: "What should the site be called?",
@@ -146,7 +148,7 @@ const resolveOptions = async (provided, { interactive, prompts }) => {
146
148
  const hasBoth = (args, positive, negative) => args.includes(positive) && args.includes(negative);
147
149
  const parseArguments = (args, version) => {
148
150
  let output = "";
149
- const program = new Command().name("create-forge").description("Create a content-driven Forge website").argument("[destination]", "directory where the project will be created").option("--name <name>", "npm package name (defaults to the directory basename)").option("--site-name <name>", "site name").option("--description <text>", "site description").option("--author <name>", "site author").option("--url <url>", "absolute canonical HTTP(S) URL").option("--repository <owner/repository>", "GitHub repository or an empty value").addOption(new Option("--install", "install dependencies")).addOption(new Option("--no-install", "do not install dependencies")).addOption(new Option("--git", "initialize a Git repository")).addOption(new Option("--no-git", "do not initialize a Git repository")).option("-y, --yes", "use documented defaults without prompting", false).version(version, "-v, --version", "show the installed package version").helpOption("-h, --help", "show this help message").showHelpAfterError().allowExcessArguments(false).exitOverride().configureOutput({
151
+ const program = new Command().name("create-forge").description("Create a content-driven Forge website").argument("[destination]", "directory where the project will be created").option("--repository-root <path>", "repository root (defaults to the project directory)").option("--name <name>", "npm package name (defaults to the directory basename)").option("--site-name <name>", "site name").option("--description <text>", "site description").option("--author <name>", "site author").option("--url <url>", "absolute canonical HTTP(S) URL").option("--repository <owner/repository>", "GitHub repository or an empty value").addOption(new Option("--install", "install dependencies")).addOption(new Option("--no-install", "do not install dependencies")).addOption(new Option("--git", "initialize a Git repository")).addOption(new Option("--no-git", "do not initialize a Git repository")).option("-y, --yes", "use documented defaults without prompting", false).version(version, "-v, --version", "show the installed package version").helpOption("-h, --help", "show this help message").showHelpAfterError().allowExcessArguments(false).exitOverride().configureOutput({
150
152
  writeOut: (value) => {
151
153
  output += value;
152
154
  },
@@ -174,6 +176,7 @@ const parseArguments = (args, version) => {
174
176
  const raw = program.opts();
175
177
  return { provided: {
176
178
  destination: program.args[0],
179
+ repositoryRoot: raw.repositoryRoot,
177
180
  packageName: raw.name,
178
181
  siteName: raw.siteName,
179
182
  description: raw.description,
@@ -230,7 +233,10 @@ const templateTokens = Object.freeze({
230
233
  url: `${prefix}URL__`,
231
234
  repository: `${prefix}REPOSITORY__`,
232
235
  securityScheduleMinute: `${prefix}SECURITY_SCHEDULE_MINUTE__`,
233
- automationScheduleMinute: `${prefix}AUTOMATION_SCHEDULE_MINUTE__`
236
+ automationScheduleMinute: `${prefix}AUTOMATION_SCHEDULE_MINUTE__`,
237
+ projectDirectory: `${prefix}PROJECT_DIRECTORY__`,
238
+ projectPathFilter: `${prefix}PROJECT_PATH_FILTER__`,
239
+ dependabotDirectory: `${prefix}DEPENDABOT_DIRECTORY__`
234
240
  });
235
241
  const templateTokenPrefix = prefix;
236
242
  //#endregion
@@ -304,9 +310,12 @@ const replaceRawToken = (source, token, value, field) => {
304
310
  if (!source.includes(token)) throw new Error(`Packaged template is missing the ${field} token.`);
305
311
  return source.replaceAll(token, value);
306
312
  };
307
- const customizeTemplate = async (destination, options) => {
308
- const packagePath = join(destination, "package.json");
309
- const packageLockPath = join(destination, "package-lock.json");
313
+ const customizeTemplate = async (projectRoot, repositoryRoot, options) => {
314
+ const projectDirectory = relative(repositoryRoot, projectRoot).split(sep).join("/") || ".";
315
+ const projectPathFilter = projectDirectory === "." ? "**" : `${projectDirectory}/**`;
316
+ const dependabotDirectory = projectDirectory === "." ? "/" : `/${projectDirectory}`;
317
+ const packagePath = join(projectRoot, "package.json");
318
+ const packageLockPath = join(projectRoot, "package-lock.json");
310
319
  const packageMetadata = JSON.parse(await readFile(packagePath, "utf8"));
311
320
  const packageLock = JSON.parse(await readFile(packageLockPath, "utf8"));
312
321
  if (packageMetadata.name !== templateTokens.packageName || packageLock.name !== templateTokens.packageName || packageLock.packages?.[""]?.name !== templateTokens.packageName) throw new Error("Packaged template contains unexpected package metadata tokens.");
@@ -319,7 +328,7 @@ const customizeTemplate = async (destination, options) => {
319
328
  packageLock.packages[""].version = "0.0.0";
320
329
  await writeFile(packagePath, `${JSON.stringify(packageMetadata, void 0, 2)}\n`);
321
330
  await writeFile(packageLockPath, `${JSON.stringify(packageLock, void 0, 2)}\n`);
322
- const siteConfigPath = join(destination, "src", "config", "site.ts");
331
+ const siteConfigPath = join(projectRoot, "src", "config", "site.ts");
323
332
  let siteConfig = await readFile(siteConfigPath, "utf8");
324
333
  siteConfig = replaceToken(siteConfig, templateTokens.siteName, options.siteName, "site name");
325
334
  siteConfig = replaceToken(siteConfig, templateTokens.description, options.description, "description");
@@ -329,39 +338,98 @@ const customizeTemplate = async (destination, options) => {
329
338
  if (siteConfig.includes("__RM_INDUSTRIES_FORGE_TEMPLATE_V1_")) throw new Error("Packaged template contains unresolved tokens.");
330
339
  await writeFile(siteConfigPath, siteConfig);
331
340
  const scheduleMinutes = deriveScheduleMinutes(options.packageName);
332
- const securityWorkflowPath = join(destination, ".github", "workflows", "security.yml");
333
- const automationWorkflowPath = join(destination, ".github", "workflows", "automation.yml");
341
+ const securityWorkflowPath = join(repositoryRoot, ".github", "workflows", "security.yml");
342
+ const automationWorkflowPath = join(repositoryRoot, ".github", "workflows", "automation.yml");
334
343
  let securityWorkflow = await readFile(securityWorkflowPath, "utf8");
335
344
  let automationWorkflow = await readFile(automationWorkflowPath, "utf8");
336
345
  securityWorkflow = replaceRawToken(securityWorkflow, templateTokens.securityScheduleMinute, String(scheduleMinutes.security), "security schedule minute");
337
346
  automationWorkflow = replaceRawToken(automationWorkflow, templateTokens.automationScheduleMinute, String(scheduleMinutes.automation), "automation schedule minute");
338
347
  await writeFile(securityWorkflowPath, securityWorkflow);
339
348
  await writeFile(automationWorkflowPath, automationWorkflow);
349
+ const tokenizedFiles = [
350
+ {
351
+ path: join(repositoryRoot, ".github", "workflows", "project.yml"),
352
+ replacements: [[
353
+ templateTokens.projectDirectory,
354
+ projectDirectory,
355
+ "project directory"
356
+ ], [
357
+ templateTokens.projectPathFilter,
358
+ projectPathFilter,
359
+ "project path filter"
360
+ ]]
361
+ },
362
+ {
363
+ path: securityWorkflowPath,
364
+ replacements: [[
365
+ templateTokens.projectPathFilter,
366
+ projectPathFilter,
367
+ "project path filter"
368
+ ]]
369
+ },
370
+ {
371
+ path: join(repositoryRoot, ".github", "actions", "setup-project", "action.yml"),
372
+ replacements: [[
373
+ templateTokens.projectDirectory,
374
+ projectDirectory,
375
+ "project directory"
376
+ ]]
377
+ },
378
+ {
379
+ path: join(repositoryRoot, ".github", "dependabot.yml"),
380
+ replacements: [[
381
+ templateTokens.dependabotDirectory,
382
+ dependabotDirectory,
383
+ "Dependabot directory"
384
+ ]]
385
+ }
386
+ ];
387
+ for (const file of tokenizedFiles) {
388
+ let source = await readFile(file.path, "utf8");
389
+ for (const [token, value, field] of file.replacements) source = replaceRawToken(source, token, value, field);
390
+ await writeFile(file.path, source);
391
+ }
340
392
  };
341
393
  const materializeProject = async (options, context) => {
342
394
  const cwd = context.cwd ?? process.cwd();
343
- const destination = resolveDestination(options.destination, cwd);
395
+ const projectRoot = resolveDestination(options.destination, cwd);
396
+ const repositoryRoot = resolveDestination(options.repositoryRoot, cwd);
397
+ const projectPath = relative(repositoryRoot, projectRoot);
398
+ if (projectPath.startsWith("..") || isAbsolute(projectPath)) throw new MaterializationError(`Project root ${projectRoot} must be inside repository root ${repositoryRoot}.`);
344
399
  const templateDirectory = resolveTemplateDirectory(context.templateDirectory);
345
- const destinationExisted = await pathExists(destination);
400
+ const repositoryStat = await getPathStat(repositoryRoot);
401
+ if (repositoryStat && (repositoryStat.isSymbolicLink() || !repositoryStat.isDirectory())) throw new MaterializationError(`Unsafe repository root ${repositoryRoot}: expected a regular directory.`);
402
+ const files = await listTemplateFiles(templateDirectory);
403
+ const destinationExisted = await pathExists(projectRoot);
346
404
  if (destinationExisted) {
347
- const destinationStat = await lstat(destination);
348
- if (destinationStat.isSymbolicLink() || !destinationStat.isDirectory()) throw new MaterializationError(`Unsafe destination ${destination}: expected a regular directory.`);
405
+ const destinationStat = await lstat(projectRoot);
406
+ if (destinationStat.isSymbolicLink() || !destinationStat.isDirectory()) throw new MaterializationError(`Unsafe destination ${projectRoot}: expected a regular directory.`);
349
407
  }
350
- if (destinationExisted && !await isDirectoryEmpty(destination)) {
351
- if (!await context.confirmOverwrite?.(destination)) throw new MaterializationError(`Destination ${destination} is not empty. No files were changed.`);
408
+ if (destinationExisted && !await isDirectoryEmpty(projectRoot)) {
409
+ if (!await context.confirmOverwrite?.(projectRoot)) throw new MaterializationError(`Destination ${projectRoot} is not empty. No files were changed.`);
410
+ }
411
+ if (projectRoot !== repositoryRoot) {
412
+ const repositoryFiles = files.filter((file) => file.relativePath.startsWith(`.github${sep}`));
413
+ let hasRepositoryConflict = false;
414
+ for (const file of repositoryFiles) if (await pathExists(join(repositoryRoot, file.relativePath))) {
415
+ hasRepositoryConflict = true;
416
+ break;
417
+ }
418
+ if (hasRepositoryConflict && !await context.confirmOverwrite?.(repositoryRoot)) throw new MaterializationError(`Repository root ${repositoryRoot} contains conflicting files. No files were changed.`);
352
419
  }
353
- const files = await listTemplateFiles(templateDirectory);
354
420
  const backupDirectory = await mkdtemp(join(tmpdir(), "create-forge-backup-"));
355
421
  const createdFiles = /* @__PURE__ */ new Set();
356
422
  const createdDirectories = /* @__PURE__ */ new Set();
357
423
  const backups = /* @__PURE__ */ new Map();
358
424
  try {
359
425
  assertNotAborted(context.signal);
360
- await ensureDirectory(destination, createdDirectories);
426
+ await ensureDirectory(repositoryRoot, createdDirectories);
427
+ await ensureDirectory(projectRoot, createdDirectories);
361
428
  for (const file of files) {
362
429
  assertNotAborted(context.signal);
363
- const target = join(destination, file.relativePath);
364
- const targetRelative = relative(destination, target);
430
+ const targetRoot = file.relativePath.startsWith(`.github${sep}`) ? repositoryRoot : projectRoot;
431
+ const target = join(targetRoot, file.relativePath);
432
+ const targetRelative = relative(targetRoot, target);
365
433
  if (targetRelative.startsWith("..") || isAbsolute(targetRelative)) throw new Error(`Unsafe template path ${file.relativePath}.`);
366
434
  await ensureDirectory(dirname(target), createdDirectories);
367
435
  const targetStat = await getPathStat(target);
@@ -377,14 +445,17 @@ const materializeProject = async (options, context) => {
377
445
  context.onFileCopied?.(target);
378
446
  }
379
447
  assertNotAborted(context.signal);
380
- await customizeTemplate(destination, options);
448
+ await customizeTemplate(projectRoot, repositoryRoot, options);
381
449
  const tokenBytes = Buffer.from(templateTokenPrefix);
382
450
  for (const file of files) {
383
451
  assertNotAborted(context.signal);
384
- if ((await readFile(join(destination, file.relativePath))).includes(tokenBytes)) throw new Error(`Generated file ${file.relativePath} contains an unresolved template token.`);
452
+ const targetRoot = file.relativePath.startsWith(`.github${sep}`) ? repositoryRoot : projectRoot;
453
+ if ((await readFile(join(targetRoot, file.relativePath))).includes(tokenBytes)) throw new Error(`Generated file ${file.relativePath} contains an unresolved template token.`);
385
454
  }
386
455
  return {
387
- destination,
456
+ destination: projectRoot,
457
+ projectRoot,
458
+ repositoryRoot,
388
459
  filesCopied: files.length
389
460
  };
390
461
  } catch (error) {
@@ -404,7 +475,7 @@ const materializeProject = async (options, context) => {
404
475
  } catch (cleanupError) {
405
476
  if (!["ENOENT", "ENOTEMPTY"].includes(cleanupError.code ?? "")) cleanupErrors.push(cleanupError);
406
477
  }
407
- throw new MaterializationError(`${error instanceof Error ? error.message : String(error)} ${cleanupErrors.length ? `Recovery: review ${destination}; some changes could not be rolled back automatically.` : `Recovery: changes from this invocation were rolled back; resolve the error and retry.`}`, { cause: error });
478
+ throw new MaterializationError(`${error instanceof Error ? error.message : String(error)} ${cleanupErrors.length ? `Recovery: review ${repositoryRoot}; some changes could not be rolled back automatically.` : `Recovery: changes from this invocation were rolled back; resolve the error and retry.`}`, { cause: error });
408
479
  } finally {
409
480
  await rm(backupDirectory, {
410
481
  recursive: true,
@@ -450,12 +521,18 @@ const runProjectSetup = async (options, context) => {
450
521
  const command = (executable, args) => execute({
451
522
  executable,
452
523
  arguments: args,
453
- cwd: context.destination,
524
+ cwd: context.projectRoot,
454
525
  ...context.signal ? { signal: context.signal } : {},
455
526
  ...context.environment ? { environment: context.environment } : {}
456
527
  });
457
528
  if (options.install) await command("npm", ["install"]);
458
- if (options.git) await command("git", ["init", "--initial-branch=main"]);
529
+ if (options.git) await execute({
530
+ executable: "git",
531
+ arguments: ["init", "--initial-branch=main"],
532
+ cwd: context.repositoryRoot,
533
+ ...context.signal ? { signal: context.signal } : {},
534
+ ...context.environment ? { environment: context.environment } : {}
535
+ });
459
536
  };
460
537
  //#endregion
461
538
  //#region src/reporter.ts
@@ -519,10 +596,11 @@ if (result.options) {
519
596
  } } : {}
520
597
  });
521
598
  await runProjectSetup(result.options, {
522
- destination: materialized.destination,
599
+ projectRoot: materialized.projectRoot,
600
+ repositoryRoot: materialized.repositoryRoot,
523
601
  signal: controller.signal
524
602
  });
525
- result.output = formatCompletion(result.options, { destination: materialized.destination });
603
+ result.output = formatCompletion(result.options, { destination: materialized.projectRoot });
526
604
  } catch (error) {
527
605
  result.output = `error: ${error instanceof Error ? error.message : String(error)}\n`;
528
606
  result.exitCode = interruptedExitCode ?? (error instanceof ProcessStepError ? error.exitCode : 1);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/prompts.ts","../src/options.ts","../src/validation.ts","../src/resolve-options.ts","../src/cli.ts","../src/schedule.ts","../src/template-tokens.ts","../src/materialize.ts","../src/process.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["import { confirm, isCancel, text } from '@clack/prompts';\n\nexport type TextPrompt = {\n message: string;\n initialValue?: string;\n placeholder?: string;\n validate?: (value: string | undefined) => string | Error | undefined;\n};\n\nexport type ConfirmPrompt = { message: string; initialValue: boolean };\n\nexport type PromptAdapter = {\n text(options: TextPrompt): Promise<string | symbol>;\n confirm(options: ConfirmPrompt): Promise<boolean | symbol>;\n isCancel(value: unknown): boolean;\n};\n\nexport const clackPrompts: PromptAdapter = {\n text: (options) =>\n text({\n message: options.message,\n ...(options.initialValue === undefined ? {} : { initialValue: options.initialValue }),\n ...(options.placeholder === undefined ? {} : { placeholder: options.placeholder }),\n ...(options.validate === undefined ? {} : { validate: options.validate }),\n }),\n confirm,\n isCancel,\n};\n","export type GeneratorOptions = {\n destination: string;\n packageName: string;\n siteName: string;\n description: string;\n author: string;\n url: string;\n repository: string;\n install: boolean;\n git: boolean;\n};\n\nexport type ProvidedOptions = {\n [Key in keyof GeneratorOptions]?: GeneratorOptions[Key] | undefined;\n} & { yes: boolean };\n\nexport const defaultDescription = 'A content-driven website built with Forge';\nexport const defaultUrl = 'https://example.com';\n\nexport const derivePackageName = (destination: string) => {\n return basename(resolve(destination)) || 'forge-site';\n};\n\nexport const humanizePackageName = (packageName: string) => {\n const unscopedName = packageName.split('/').at(-1) ?? packageName;\n return unscopedName\n .split(/[-_\\s]+/u)\n .filter(Boolean)\n .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)\n .join(' ');\n};\nimport { basename, resolve } from 'node:path';\n","import validateNpmPackageName from 'validate-npm-package-name';\n\nexport class InputError extends Error {}\n\nconst invalid = (option: string, value: string, reason: string): never => {\n throw new InputError(`Invalid ${option} value ${JSON.stringify(value)}: ${reason}`);\n};\n\nexport const validateDestination = (value: string) => {\n const destination = value.trim();\n if (!destination) invalid('destination', value, 'provide a non-empty path');\n if (destination.includes('\\0')) invalid('destination', value, 'paths cannot contain null bytes');\n return destination;\n};\n\nexport const validatePackageName = (value: string) => {\n const packageName = value.trim();\n const result = validateNpmPackageName(packageName);\n if (!result.validForNewPackages) {\n const reason = [...(result.errors ?? []), ...(result.warnings ?? [])].join('; ');\n invalid('--name', value, reason || 'provide a valid npm package name');\n }\n return packageName;\n};\n\nexport const validatePlainText = (option: string, value: string, required = false) => {\n const text = value.trim();\n if (required && !text) invalid(option, value, 'provide non-empty text');\n if (/\\p{Cc}/u.test(text)) invalid(option, value, 'control characters are not allowed');\n return text;\n};\n\nexport const validateUrl = (value: string) => {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n if (!['http:', 'https:'].includes(url.protocol)) {\n invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n return url.toString();\n};\n\nexport const validateRepository = (value: string) => {\n const repository = value.trim();\n if (!repository) return repository;\n if (!/^[\\w.-]+\\/[\\w.-]+$/u.test(repository)) {\n invalid('--repository', value, 'use the GitHub owner/repository format or leave it empty');\n }\n return repository;\n};\n","import {\n defaultDescription,\n defaultUrl,\n derivePackageName,\n humanizePackageName,\n type GeneratorOptions,\n type ProvidedOptions,\n} from './options';\nimport type { PromptAdapter, TextPrompt } from './prompts';\nimport {\n InputError,\n validateDestination,\n validatePackageName,\n validatePlainText,\n validateRepository,\n validateUrl,\n} from './validation';\n\nexport class CancellationError extends Error {}\n\ntype ResolutionContext = { interactive: boolean; prompts: PromptAdapter };\n\nconst textValidation = (validator: (value: string) => string) => (value: string | undefined) => {\n try {\n validator(value ?? '');\n return undefined;\n } catch (error) {\n return error instanceof Error ? error.message : 'Invalid value';\n }\n};\n\nconst promptText = async (prompts: PromptAdapter, options: TextPrompt) => {\n const value = await prompts.text(options);\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return String(value);\n};\n\nconst promptConfirm = async (prompts: PromptAdapter, message: string) => {\n const value = await prompts.confirm({ message, initialValue: true });\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return Boolean(value);\n};\n\nconst hasEveryExplicitValue = (options: ProvidedOptions) =>\n options.destination !== undefined &&\n options.packageName !== undefined &&\n options.siteName !== undefined &&\n options.description !== undefined &&\n options.author !== undefined &&\n options.url !== undefined &&\n options.repository !== undefined &&\n options.install !== undefined &&\n options.git !== undefined;\n\nexport const resolveOptions = async (\n provided: ProvidedOptions,\n { interactive, prompts }: ResolutionContext,\n): Promise<GeneratorOptions> => {\n const useDefaults = provided.yes;\n if (!interactive && !useDefaults && !hasEveryExplicitValue(provided)) {\n throw new InputError(\n 'Non-interactive use requires --yes or explicit values for every generator option. Run create-forge --help for details.',\n );\n }\n\n const destination = validateDestination(\n provided.destination ??\n (useDefaults\n ? '.'\n : await promptText(prompts, {\n message: 'Where should we create your project?',\n placeholder: '.',\n initialValue: '.',\n validate: textValidation(validateDestination),\n })),\n );\n const derivedPackageName = derivePackageName(destination);\n const packageName = validatePackageName(\n provided.packageName ??\n (useDefaults\n ? derivedPackageName\n : await promptText(prompts, {\n message: 'What should the npm package be named?',\n initialValue: derivedPackageName,\n validate: textValidation(validatePackageName),\n })),\n );\n const defaultSiteName = humanizePackageName(packageName);\n const siteName = validatePlainText(\n '--site-name',\n provided.siteName ??\n (useDefaults\n ? defaultSiteName\n : await promptText(prompts, {\n message: 'What should the site be called?',\n initialValue: defaultSiteName,\n validate: textValidation((value) => validatePlainText('--site-name', value, true)),\n })),\n true,\n );\n const description = validatePlainText(\n '--description',\n provided.description ??\n (useDefaults\n ? defaultDescription\n : await promptText(prompts, {\n message: 'How would you describe the site?',\n initialValue: defaultDescription,\n validate: textValidation((value) => validatePlainText('--description', value)),\n })),\n );\n const author = validatePlainText(\n '--author',\n provided.author ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'Who is the site author?',\n placeholder: 'Optional',\n validate: textValidation((value) => validatePlainText('--author', value)),\n })),\n );\n const url = validateUrl(\n provided.url ??\n (useDefaults\n ? defaultUrl\n : await promptText(prompts, {\n message: 'What is the canonical site URL?',\n initialValue: defaultUrl,\n validate: textValidation(validateUrl),\n })),\n );\n const repository = validateRepository(\n provided.repository ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'What is the GitHub repository?',\n placeholder: 'owner/repository (optional)',\n validate: textValidation(validateRepository),\n })),\n );\n const install = provided.install ?? (useDefaults ? true : await promptConfirm(prompts, 'Install dependencies?'));\n const git = provided.git ?? (useDefaults ? true : await promptConfirm(prompts, 'Initialize a Git repository?'));\n\n return { destination, packageName, siteName, description, author, url, repository, install, git };\n};\n","import { Command, CommanderError, Option } from 'commander';\n\nimport type { GeneratorOptions, ProvidedOptions } from './options';\nimport { clackPrompts, type PromptAdapter } from './prompts';\nimport { CancellationError, resolveOptions } from './resolve-options';\n\nexport type CliResult = { output: string; exitCode: number; options?: GeneratorOptions };\nexport type CliContext = { interactive?: boolean; prompts?: PromptAdapter };\n\nconst hasBoth = (args: readonly string[], positive: string, negative: string) =>\n args.includes(positive) && args.includes(negative);\n\nconst parseArguments = (args: readonly string[], version: string) => {\n let output = '';\n const program = new Command()\n .name('create-forge')\n .description('Create a content-driven Forge website')\n .argument('[destination]', 'directory where the project will be created')\n .option('--name <name>', 'npm package name (defaults to the directory basename)')\n .option('--site-name <name>', 'site name')\n .option('--description <text>', 'site description')\n .option('--author <name>', 'site author')\n .option('--url <url>', 'absolute canonical HTTP(S) URL')\n .option('--repository <owner/repository>', 'GitHub repository or an empty value')\n .addOption(new Option('--install', 'install dependencies'))\n .addOption(new Option('--no-install', 'do not install dependencies'))\n .addOption(new Option('--git', 'initialize a Git repository'))\n .addOption(new Option('--no-git', 'do not initialize a Git repository'))\n .option('-y, --yes', 'use documented defaults without prompting', false)\n .version(version, '-v, --version', 'show the installed package version')\n .helpOption('-h, --help', 'show this help message')\n .showHelpAfterError()\n .allowExcessArguments(false)\n .exitOverride()\n .configureOutput({\n writeOut: (value) => {\n output += value;\n },\n writeErr: (value) => {\n output += value;\n },\n });\n\n try {\n program.parse(args, { from: 'user' });\n } catch (error) {\n if (error instanceof CommanderError) return { output, exitCode: error.exitCode } as const;\n throw error;\n }\n\n if (hasBoth(args, '--install', '--no-install')) {\n return { output: 'error: --install cannot be used with --no-install\\n', exitCode: 1 } as const;\n }\n if (hasBoth(args, '--git', '--no-git')) {\n return { output: 'error: --git cannot be used with --no-git\\n', exitCode: 1 } as const;\n }\n\n const raw = program.opts();\n const provided: ProvidedOptions = {\n destination: program.args[0],\n packageName: raw.name,\n siteName: raw.siteName,\n description: raw.description,\n author: raw.author,\n url: raw.url,\n repository: raw.repository,\n install: raw.install,\n git: raw.git,\n yes: raw.yes,\n };\n return { provided } as const;\n};\n\nexport const runCli = async (\n args: readonly string[],\n version: string,\n context: CliContext = {},\n): Promise<CliResult> => {\n const parsed = parseArguments(args, version);\n if (!('provided' in parsed)) return parsed;\n\n try {\n const options = await resolveOptions(parsed.provided, {\n interactive: context.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY),\n prompts: context.prompts ?? clackPrompts,\n });\n return { output: '', exitCode: 0, options };\n } catch (error) {\n if (error instanceof CancellationError) return { output: `${error.message}\\n`, exitCode: 1 };\n if (error instanceof Error) return { output: `error: ${error.message}\\n`, exitCode: 1 };\n throw error;\n }\n};\n","import { createHash } from 'node:crypto';\n\nexport const deriveScheduleMinutes = (packageName: string) => {\n const digest = createHash('sha256').update(packageName).digest();\n const security = 1 + (digest.readUInt8(0) % 59);\n const automation = 1 + ((security - 1 + 17 + (digest.readUInt8(1) % 29)) % 59);\n return { security, automation };\n};\n","const prefix = '__RM_INDUSTRIES_FORGE_TEMPLATE_V1_';\n\nexport const templateTokens = Object.freeze({\n packageName: `${prefix}PACKAGE_NAME__`,\n siteName: `${prefix}SITE_NAME__`,\n description: `${prefix}DESCRIPTION__`,\n author: `${prefix}AUTHOR__`,\n url: `${prefix}URL__`,\n repository: `${prefix}REPOSITORY__`,\n securityScheduleMinute: `${prefix}SECURITY_SCHEDULE_MINUTE__`,\n automationScheduleMinute: `${prefix}AUTOMATION_SCHEDULE_MINUTE__`,\n});\n\nexport const templateTokenPrefix = prefix;\n","import {\n chmod,\n copyFile,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rm,\n rmdir,\n stat,\n writeFile,\n} from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, isAbsolute, join, parse, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { GeneratorOptions } from './options';\nimport { deriveScheduleMinutes } from './schedule';\nimport { templateTokenPrefix, templateTokens } from './template-tokens';\n\nexport class MaterializationError extends Error {}\n\ntype MaterializationContext = {\n templateDirectory: string | URL;\n cwd?: string;\n signal?: AbortSignal;\n confirmOverwrite?: (destination: string) => Promise<boolean>;\n onFileCopied?: (path: string) => void;\n};\n\ntype TemplateFile = { source: string; relativePath: string; mode: number };\n\nconst pathExists = async (path: string) => {\n try {\n await lstat(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n};\n\nconst getPathStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n};\n\nconst assertNotAborted = (signal?: AbortSignal) => {\n if (signal?.aborted) throw new Error('Project creation was interrupted.');\n};\n\nconst resolveTemplateDirectory = (directory: string | URL) =>\n directory instanceof URL ? fileURLToPath(directory) : resolve(directory);\n\nconst resolveDestination = (destination: string, cwd: string) => {\n const segments = destination.split(/[\\\\/]/u);\n if (segments.includes('..')) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: parent traversal is not allowed.`,\n );\n }\n const resolved = isAbsolute(destination) ? resolve(destination) : resolve(cwd, destination);\n if (resolved === parse(resolved).root) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: a filesystem root is not allowed.`,\n );\n }\n return resolved;\n};\n\nconst listTemplateFiles = async (root: string, directory = root): Promise<TemplateFile[]> => {\n const entries = await readdir(directory, { withFileTypes: true });\n const files: TemplateFile[] = [];\n for (const entry of entries) {\n const source = join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await listTemplateFiles(root, source)));\n continue;\n }\n if (!entry.isFile()) throw new MaterializationError(`Template entry ${source} is not a regular file.`);\n const relativePath = relative(root, source);\n files.push({\n source,\n relativePath: relativePath === '.gitignore.template' ? '.gitignore' : relativePath,\n mode: (await stat(source)).mode,\n });\n }\n return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n};\n\nconst isDirectoryEmpty = async (directory: string) => (await readdir(directory)).length === 0;\n\nconst ensureDirectory = async (directory: string, created: Set<string>) => {\n const existing = await getPathStat(directory);\n if (existing) {\n if (existing.isSymbolicLink() || !existing.isDirectory()) {\n throw new Error(`Unsafe destination entry ${directory}: expected a regular directory.`);\n }\n return;\n }\n const parent = dirname(directory);\n if (parent !== directory) await ensureDirectory(parent, created);\n await mkdir(directory);\n created.add(directory);\n};\n\nconst quoteTypeScriptString = (value: string) =>\n `'${value\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", \"\\\\'\")\n .replaceAll('\\u2028', '\\\\u2028')\n .replaceAll('\\u2029', '\\\\u2029')}'`;\n\nconst replaceToken = (source: string, token: string, value: string, field: string) => {\n const quotedToken = `'${token}'`;\n if (!source.includes(quotedToken)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(quotedToken, quoteTypeScriptString(value));\n};\n\nconst replaceRawToken = (source: string, token: string, value: string, field: string) => {\n if (!source.includes(token)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(token, value);\n};\n\nconst customizeTemplate = async (destination: string, options: GeneratorOptions) => {\n const packagePath = join(destination, 'package.json');\n const packageLockPath = join(destination, 'package-lock.json');\n const packageMetadata = JSON.parse(await readFile(packagePath, 'utf8')) as Record<string, unknown>;\n const packageLock = JSON.parse(await readFile(packageLockPath, 'utf8')) as {\n name?: string;\n packages?: Record<string, Record<string, unknown>>;\n };\n if (\n packageMetadata.name !== templateTokens.packageName ||\n packageLock.name !== templateTokens.packageName ||\n packageLock.packages?.['']?.name !== templateTokens.packageName\n ) {\n throw new Error('Packaged template contains unexpected package metadata tokens.');\n }\n packageMetadata.name = options.packageName;\n packageMetadata.version = '0.0.0';\n packageMetadata.private = true;\n packageLock.name = options.packageName;\n if (!packageLock.packages?.['']) throw new Error('Packaged template lockfile is missing its root package metadata.');\n packageLock.packages[''].name = options.packageName;\n packageLock.packages[''].version = '0.0.0';\n await writeFile(packagePath, `${JSON.stringify(packageMetadata, undefined, 2)}\\n`);\n await writeFile(packageLockPath, `${JSON.stringify(packageLock, undefined, 2)}\\n`);\n\n const siteConfigPath = join(destination, 'src', 'config', 'site.ts');\n let siteConfig = await readFile(siteConfigPath, 'utf8');\n siteConfig = replaceToken(siteConfig, templateTokens.siteName, options.siteName, 'site name');\n siteConfig = replaceToken(siteConfig, templateTokens.description, options.description, 'description');\n siteConfig = replaceToken(siteConfig, templateTokens.author, options.author, 'author');\n siteConfig = replaceToken(siteConfig, templateTokens.url, options.url, 'URL');\n siteConfig = replaceToken(siteConfig, templateTokens.repository, options.repository, 'repository');\n if (siteConfig.includes(templateTokenPrefix)) throw new Error('Packaged template contains unresolved tokens.');\n await writeFile(siteConfigPath, siteConfig);\n\n const scheduleMinutes = deriveScheduleMinutes(options.packageName);\n const securityWorkflowPath = join(destination, '.github', 'workflows', 'security.yml');\n const automationWorkflowPath = join(destination, '.github', 'workflows', 'automation.yml');\n let securityWorkflow = await readFile(securityWorkflowPath, 'utf8');\n let automationWorkflow = await readFile(automationWorkflowPath, 'utf8');\n securityWorkflow = replaceRawToken(\n securityWorkflow,\n templateTokens.securityScheduleMinute,\n String(scheduleMinutes.security),\n 'security schedule minute',\n );\n automationWorkflow = replaceRawToken(\n automationWorkflow,\n templateTokens.automationScheduleMinute,\n String(scheduleMinutes.automation),\n 'automation schedule minute',\n );\n await writeFile(securityWorkflowPath, securityWorkflow);\n await writeFile(automationWorkflowPath, automationWorkflow);\n};\n\nexport const materializeProject = async (options: GeneratorOptions, context: MaterializationContext) => {\n const cwd = context.cwd ?? process.cwd();\n const destination = resolveDestination(options.destination, cwd);\n const templateDirectory = resolveTemplateDirectory(context.templateDirectory);\n const destinationExisted = await pathExists(destination);\n if (destinationExisted) {\n const destinationStat = await lstat(destination);\n if (destinationStat.isSymbolicLink() || !destinationStat.isDirectory()) {\n throw new MaterializationError(`Unsafe destination ${destination}: expected a regular directory.`);\n }\n }\n if (destinationExisted && !(await isDirectoryEmpty(destination))) {\n const confirmed = await context.confirmOverwrite?.(destination);\n if (!confirmed) {\n throw new MaterializationError(`Destination ${destination} is not empty. No files were changed.`);\n }\n }\n\n const files = await listTemplateFiles(templateDirectory);\n const backupDirectory = await mkdtemp(join(tmpdir(), 'create-forge-backup-'));\n const createdFiles = new Set<string>();\n const createdDirectories = new Set<string>();\n const backups = new Map<string, string>();\n\n try {\n assertNotAborted(context.signal);\n await ensureDirectory(destination, createdDirectories);\n for (const file of files) {\n assertNotAborted(context.signal);\n const target = join(destination, file.relativePath);\n const targetRelative = relative(destination, target);\n if (targetRelative.startsWith('..') || isAbsolute(targetRelative))\n throw new Error(`Unsafe template path ${file.relativePath}.`);\n await ensureDirectory(dirname(target), createdDirectories);\n const targetStat = await getPathStat(target);\n if (targetStat) {\n if (targetStat.isSymbolicLink() || !targetStat.isFile()) {\n throw new Error(`Unsafe destination entry ${target}: expected a regular file.`);\n }\n const backup = join(backupDirectory, file.relativePath);\n await mkdir(dirname(backup), { recursive: true });\n await copyFile(target, backup);\n backups.set(target, backup);\n } else {\n createdFiles.add(target);\n }\n await copyFile(file.source, target);\n await chmod(target, file.mode);\n context.onFileCopied?.(target);\n }\n assertNotAborted(context.signal);\n await customizeTemplate(destination, options);\n const tokenBytes = Buffer.from(templateTokenPrefix);\n for (const file of files) {\n assertNotAborted(context.signal);\n if ((await readFile(join(destination, file.relativePath))).includes(tokenBytes)) {\n throw new Error(`Generated file ${file.relativePath} contains an unresolved template token.`);\n }\n }\n return { destination, filesCopied: files.length };\n } catch (error) {\n const cleanupErrors: unknown[] = [];\n for (const [target, backup] of backups) {\n try {\n await copyFile(backup, target);\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const file of createdFiles) {\n try {\n await rm(file, { force: true });\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const directory of [...createdDirectories].sort((left, right) => right.length - left.length)) {\n try {\n await rmdir(directory);\n } catch (cleanupError) {\n if (!['ENOENT', 'ENOTEMPTY'].includes((cleanupError as NodeJS.ErrnoException).code ?? '')) {\n cleanupErrors.push(cleanupError);\n }\n }\n }\n const reason = error instanceof Error ? error.message : String(error);\n const recovery = cleanupErrors.length\n ? `Recovery: review ${destination}; some changes could not be rolled back automatically.`\n : `Recovery: changes from this invocation were rolled back; resolve the error and retry.`;\n throw new MaterializationError(`${reason} ${recovery}`, { cause: error });\n } finally {\n await rm(backupDirectory, { recursive: true, force: true });\n }\n};\n","import { spawn } from 'node:child_process';\n\nimport type { GeneratorOptions } from './options';\n\nexport class ProcessStepError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1, options?: ErrorOptions) {\n super(message, options);\n this.exitCode = exitCode;\n }\n}\n\nexport type Command = {\n executable: string;\n arguments: readonly string[];\n cwd: string;\n signal?: AbortSignal;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport type CommandExecutor = (command: Command) => Promise<void>;\n\nconst signalExitCode = (signal: NodeJS.Signals | null) => {\n if (signal === 'SIGINT') return 130;\n if (signal === 'SIGTERM') return 143;\n return 1;\n};\n\nexport const executeCommand: CommandExecutor = ({ executable, arguments: args, cwd, signal, environment }) =>\n new Promise((resolve, reject) => {\n const child = spawn(executable, args, {\n cwd,\n stdio: 'inherit',\n ...(signal ? { signal } : {}),\n ...(environment ? { env: environment } : {}),\n });\n\n child.once('error', (error) => {\n const interrupted = signal?.aborted;\n reject(\n new ProcessStepError(\n interrupted\n ? `${executable} was interrupted. The generated project remains at ${cwd}.`\n : `Could not start ${executable}: ${error.message}. The generated project remains at ${cwd}.`,\n interrupted ? 130 : 1,\n { cause: error },\n ),\n );\n });\n child.once('close', (code, processSignal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const detail = processSignal ? `signal ${processSignal}` : `exit code ${code ?? 'unknown'}`;\n reject(\n new ProcessStepError(\n `${executable} failed with ${detail}. The generated project remains at ${cwd}; review the output above and retry the command there.`,\n processSignal ? signalExitCode(processSignal) : (code ?? 1),\n ),\n );\n });\n });\n\ntype ProjectSetupContext = {\n destination: string;\n signal?: AbortSignal;\n execute?: CommandExecutor;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport const runProjectSetup = async (options: GeneratorOptions, context: ProjectSetupContext) => {\n const execute = context.execute ?? executeCommand;\n const command = (executable: string, args: readonly string[]) =>\n execute({\n executable,\n arguments: args,\n cwd: context.destination,\n ...(context.signal ? { signal: context.signal } : {}),\n ...(context.environment ? { environment: context.environment } : {}),\n });\n\n if (options.install) await command('npm', ['install']);\n if (options.git) await command('git', ['init', '--initial-branch=main']);\n};\n","import { isAbsolute, relative } from 'node:path';\n\nimport type { GeneratorOptions } from './options';\n\ntype CompletionContext = {\n destination: string;\n cwd?: string;\n color?: boolean;\n};\n\nconst ansi = {\n bold: (value: string) => `\\u001B[1m${value}\\u001B[22m`,\n green: (value: string) => `\\u001B[32m${value}\\u001B[39m`,\n};\n\nconst commandPath = (path: string) => {\n if (/^[\\w./@-]+$/u.test(path)) return path;\n return `\"${path.replaceAll('\"', '\\\\\"')}\"`;\n};\n\nconst displayDestination = (destination: string, cwd: string) => {\n const path = relative(cwd, destination);\n if (!path) return '.';\n return isAbsolute(path) ? destination : path;\n};\n\nexport const supportsColor = (environment: NodeJS.ProcessEnv = process.env, terminal = Boolean(process.stdout.isTTY)) =>\n terminal && environment.NO_COLOR === undefined;\n\nexport const formatCompletion = (options: GeneratorOptions, context: CompletionContext) => {\n const cwd = context.cwd ?? process.cwd();\n const color = context.color ?? supportsColor();\n const decorate = color ? ansi : { bold: (value: string) => value, green: (value: string) => value };\n const destination = displayDestination(context.destination, cwd);\n const commands = [\n ...(destination === '.' ? [] : [`cd ${commandPath(destination)}`]),\n ...(options.install ? [] : ['npm install']),\n 'npm run dev',\n ];\n\n return `${decorate.green('✓')} Created ${options.siteName} in ${destination}\\n\\n${decorate.bold('Setup')}\\n Dependencies: ${options.install ? 'installed' : 'skipped'}\\n Git repository: ${options.git ? 'initialized' : 'skipped'}\\n\\n${decorate.bold('Next steps')}\\n${commands.map((command) => ` ${command}`).join('\\n')}\\n`;\n};\n","#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises';\n\nimport { confirm, isCancel } from '@clack/prompts';\n\nimport { runCli } from './cli';\nimport { materializeProject } from './materialize';\nimport { ProcessStepError, runProjectSetup } from './process';\nimport { formatCompletion } from './reporter';\n\ntype PackageMetadata = {\n version: string;\n};\n\nconst packageJson = new URL('../package.json', import.meta.url);\nconst metadata = JSON.parse(await readFile(packageJson, 'utf8')) as PackageMetadata;\nconst interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);\nconst result = await runCli(process.argv.slice(2), metadata.version, { interactive });\n\nif (result.options) {\n const controller = new AbortController();\n let interruptedExitCode: number | undefined;\n const interrupt = () => {\n interruptedExitCode = 130;\n controller.abort();\n };\n const terminate = () => {\n interruptedExitCode = 143;\n controller.abort();\n };\n process.once('SIGINT', interrupt);\n process.once('SIGTERM', terminate);\n try {\n const materialized = await materializeProject(result.options, {\n templateDirectory: new URL('./template/', import.meta.url),\n signal: controller.signal,\n ...(interactive\n ? {\n confirmOverwrite: async (destination: string) => {\n const answer = await confirm({\n message: `${destination} is not empty. Continue and overwrite conflicting template files?`,\n initialValue: false,\n });\n return !isCancel(answer) && answer;\n },\n }\n : {}),\n });\n await runProjectSetup(result.options, {\n destination: materialized.destination,\n signal: controller.signal,\n });\n result.output = formatCompletion(result.options, { destination: materialized.destination });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n result.output = `error: ${message}\\n`;\n result.exitCode = interruptedExitCode ?? (error instanceof ProcessStepError ? error.exitCode : 1);\n } finally {\n process.off('SIGINT', interrupt);\n process.off('SIGTERM', terminate);\n }\n}\n\nprocess.stdout.write(result.output);\nprocess.exitCode = result.exitCode;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/prompts.ts","../src/options.ts","../src/validation.ts","../src/resolve-options.ts","../src/cli.ts","../src/schedule.ts","../src/template-tokens.ts","../src/materialize.ts","../src/process.ts","../src/reporter.ts","../src/index.ts"],"sourcesContent":["import { confirm, isCancel, text } from '@clack/prompts';\n\nexport type TextPrompt = {\n message: string;\n initialValue?: string;\n placeholder?: string;\n validate?: (value: string | undefined) => string | Error | undefined;\n};\n\nexport type ConfirmPrompt = { message: string; initialValue: boolean };\n\nexport type PromptAdapter = {\n text(options: TextPrompt): Promise<string | symbol>;\n confirm(options: ConfirmPrompt): Promise<boolean | symbol>;\n isCancel(value: unknown): boolean;\n};\n\nexport const clackPrompts: PromptAdapter = {\n text: (options) =>\n text({\n message: options.message,\n ...(options.initialValue === undefined ? {} : { initialValue: options.initialValue }),\n ...(options.placeholder === undefined ? {} : { placeholder: options.placeholder }),\n ...(options.validate === undefined ? {} : { validate: options.validate }),\n }),\n confirm,\n isCancel,\n};\n","export type GeneratorOptions = {\n destination: string;\n repositoryRoot: string;\n packageName: string;\n siteName: string;\n description: string;\n author: string;\n url: string;\n repository: string;\n install: boolean;\n git: boolean;\n};\n\nexport type ProvidedOptions = {\n [Key in keyof GeneratorOptions]?: GeneratorOptions[Key] | undefined;\n} & { yes: boolean };\n\nexport const defaultDescription = 'A content-driven website built with Forge';\nexport const defaultUrl = 'https://example.com';\n\nexport const derivePackageName = (destination: string) => {\n return basename(resolve(destination)) || 'forge-site';\n};\n\nexport const humanizePackageName = (packageName: string) => {\n const unscopedName = packageName.split('/').at(-1) ?? packageName;\n return unscopedName\n .split(/[-_\\s]+/u)\n .filter(Boolean)\n .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)\n .join(' ');\n};\nimport { basename, resolve } from 'node:path';\n","import validateNpmPackageName from 'validate-npm-package-name';\n\nexport class InputError extends Error {}\n\nconst invalid = (option: string, value: string, reason: string): never => {\n throw new InputError(`Invalid ${option} value ${JSON.stringify(value)}: ${reason}`);\n};\n\nexport const validateDestination = (value: string) => {\n const destination = value.trim();\n if (!destination) invalid('destination', value, 'provide a non-empty path');\n if (destination.includes('\\0')) invalid('destination', value, 'paths cannot contain null bytes');\n return destination;\n};\n\nexport const validatePackageName = (value: string) => {\n const packageName = value.trim();\n const result = validateNpmPackageName(packageName);\n if (!result.validForNewPackages) {\n const reason = [...(result.errors ?? []), ...(result.warnings ?? [])].join('; ');\n invalid('--name', value, reason || 'provide a valid npm package name');\n }\n return packageName;\n};\n\nexport const validatePlainText = (option: string, value: string, required = false) => {\n const text = value.trim();\n if (required && !text) invalid(option, value, 'provide non-empty text');\n if (/\\p{Cc}/u.test(text)) invalid(option, value, 'control characters are not allowed');\n return text;\n};\n\nexport const validateUrl = (value: string) => {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n if (!['http:', 'https:'].includes(url.protocol)) {\n invalid('--url', value, 'provide an absolute HTTP(S) URL');\n }\n return url.toString();\n};\n\nexport const validateRepository = (value: string) => {\n const repository = value.trim();\n if (!repository) return repository;\n if (!/^[\\w.-]+\\/[\\w.-]+$/u.test(repository)) {\n invalid('--repository', value, 'use the GitHub owner/repository format or leave it empty');\n }\n return repository;\n};\n","import {\n defaultDescription,\n defaultUrl,\n derivePackageName,\n humanizePackageName,\n type GeneratorOptions,\n type ProvidedOptions,\n} from './options';\nimport type { PromptAdapter, TextPrompt } from './prompts';\nimport {\n InputError,\n validateDestination,\n validatePackageName,\n validatePlainText,\n validateRepository,\n validateUrl,\n} from './validation';\n\nexport class CancellationError extends Error {}\n\ntype ResolutionContext = { interactive: boolean; prompts: PromptAdapter };\n\nconst textValidation = (validator: (value: string) => string) => (value: string | undefined) => {\n try {\n validator(value ?? '');\n return undefined;\n } catch (error) {\n return error instanceof Error ? error.message : 'Invalid value';\n }\n};\n\nconst promptText = async (prompts: PromptAdapter, options: TextPrompt) => {\n const value = await prompts.text(options);\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return String(value);\n};\n\nconst promptConfirm = async (prompts: PromptAdapter, message: string) => {\n const value = await prompts.confirm({ message, initialValue: true });\n if (prompts.isCancel(value)) throw new CancellationError('Project creation cancelled.');\n return Boolean(value);\n};\n\nconst hasEveryExplicitValue = (options: ProvidedOptions) =>\n options.destination !== undefined &&\n options.packageName !== undefined &&\n options.siteName !== undefined &&\n options.description !== undefined &&\n options.author !== undefined &&\n options.url !== undefined &&\n options.repository !== undefined &&\n options.install !== undefined &&\n options.git !== undefined;\n\nexport const resolveOptions = async (\n provided: ProvidedOptions,\n { interactive, prompts }: ResolutionContext,\n): Promise<GeneratorOptions> => {\n const useDefaults = provided.yes;\n if (!interactive && !useDefaults && !hasEveryExplicitValue(provided)) {\n throw new InputError(\n 'Non-interactive use requires --yes or explicit values for every generator option. Run create-forge --help for details.',\n );\n }\n\n const destination = validateDestination(\n provided.destination ??\n (useDefaults\n ? '.'\n : await promptText(prompts, {\n message: 'Where should we create your project?',\n placeholder: '.',\n initialValue: '.',\n validate: textValidation(validateDestination),\n })),\n );\n const repositoryRoot = validateDestination(provided.repositoryRoot ?? destination);\n const derivedPackageName = derivePackageName(destination);\n const packageName = validatePackageName(\n provided.packageName ??\n (useDefaults\n ? derivedPackageName\n : await promptText(prompts, {\n message: 'What should the npm package be named?',\n initialValue: derivedPackageName,\n validate: textValidation(validatePackageName),\n })),\n );\n const defaultSiteName = humanizePackageName(packageName);\n const siteName = validatePlainText(\n '--site-name',\n provided.siteName ??\n (useDefaults\n ? defaultSiteName\n : await promptText(prompts, {\n message: 'What should the site be called?',\n initialValue: defaultSiteName,\n validate: textValidation((value) => validatePlainText('--site-name', value, true)),\n })),\n true,\n );\n const description = validatePlainText(\n '--description',\n provided.description ??\n (useDefaults\n ? defaultDescription\n : await promptText(prompts, {\n message: 'How would you describe the site?',\n initialValue: defaultDescription,\n validate: textValidation((value) => validatePlainText('--description', value)),\n })),\n );\n const author = validatePlainText(\n '--author',\n provided.author ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'Who is the site author?',\n placeholder: 'Optional',\n validate: textValidation((value) => validatePlainText('--author', value)),\n })),\n );\n const url = validateUrl(\n provided.url ??\n (useDefaults\n ? defaultUrl\n : await promptText(prompts, {\n message: 'What is the canonical site URL?',\n initialValue: defaultUrl,\n validate: textValidation(validateUrl),\n })),\n );\n const repository = validateRepository(\n provided.repository ??\n (useDefaults\n ? ''\n : await promptText(prompts, {\n message: 'What is the GitHub repository?',\n placeholder: 'owner/repository (optional)',\n validate: textValidation(validateRepository),\n })),\n );\n const install = provided.install ?? (useDefaults ? true : await promptConfirm(prompts, 'Install dependencies?'));\n const git = provided.git ?? (useDefaults ? true : await promptConfirm(prompts, 'Initialize a Git repository?'));\n\n return { destination, repositoryRoot, packageName, siteName, description, author, url, repository, install, git };\n};\n","import { Command, CommanderError, Option } from 'commander';\n\nimport type { GeneratorOptions, ProvidedOptions } from './options';\nimport { clackPrompts, type PromptAdapter } from './prompts';\nimport { CancellationError, resolveOptions } from './resolve-options';\n\nexport type CliResult = { output: string; exitCode: number; options?: GeneratorOptions };\nexport type CliContext = { interactive?: boolean; prompts?: PromptAdapter };\n\nconst hasBoth = (args: readonly string[], positive: string, negative: string) =>\n args.includes(positive) && args.includes(negative);\n\nconst parseArguments = (args: readonly string[], version: string) => {\n let output = '';\n const program = new Command()\n .name('create-forge')\n .description('Create a content-driven Forge website')\n .argument('[destination]', 'directory where the project will be created')\n .option('--repository-root <path>', 'repository root (defaults to the project directory)')\n .option('--name <name>', 'npm package name (defaults to the directory basename)')\n .option('--site-name <name>', 'site name')\n .option('--description <text>', 'site description')\n .option('--author <name>', 'site author')\n .option('--url <url>', 'absolute canonical HTTP(S) URL')\n .option('--repository <owner/repository>', 'GitHub repository or an empty value')\n .addOption(new Option('--install', 'install dependencies'))\n .addOption(new Option('--no-install', 'do not install dependencies'))\n .addOption(new Option('--git', 'initialize a Git repository'))\n .addOption(new Option('--no-git', 'do not initialize a Git repository'))\n .option('-y, --yes', 'use documented defaults without prompting', false)\n .version(version, '-v, --version', 'show the installed package version')\n .helpOption('-h, --help', 'show this help message')\n .showHelpAfterError()\n .allowExcessArguments(false)\n .exitOverride()\n .configureOutput({\n writeOut: (value) => {\n output += value;\n },\n writeErr: (value) => {\n output += value;\n },\n });\n\n try {\n program.parse(args, { from: 'user' });\n } catch (error) {\n if (error instanceof CommanderError) return { output, exitCode: error.exitCode } as const;\n throw error;\n }\n\n if (hasBoth(args, '--install', '--no-install')) {\n return { output: 'error: --install cannot be used with --no-install\\n', exitCode: 1 } as const;\n }\n if (hasBoth(args, '--git', '--no-git')) {\n return { output: 'error: --git cannot be used with --no-git\\n', exitCode: 1 } as const;\n }\n\n const raw = program.opts();\n const provided: ProvidedOptions = {\n destination: program.args[0],\n repositoryRoot: raw.repositoryRoot,\n packageName: raw.name,\n siteName: raw.siteName,\n description: raw.description,\n author: raw.author,\n url: raw.url,\n repository: raw.repository,\n install: raw.install,\n git: raw.git,\n yes: raw.yes,\n };\n return { provided } as const;\n};\n\nexport const runCli = async (\n args: readonly string[],\n version: string,\n context: CliContext = {},\n): Promise<CliResult> => {\n const parsed = parseArguments(args, version);\n if (!('provided' in parsed)) return parsed;\n\n try {\n const options = await resolveOptions(parsed.provided, {\n interactive: context.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY),\n prompts: context.prompts ?? clackPrompts,\n });\n return { output: '', exitCode: 0, options };\n } catch (error) {\n if (error instanceof CancellationError) return { output: `${error.message}\\n`, exitCode: 1 };\n if (error instanceof Error) return { output: `error: ${error.message}\\n`, exitCode: 1 };\n throw error;\n }\n};\n","import { createHash } from 'node:crypto';\n\nexport const deriveScheduleMinutes = (packageName: string) => {\n const digest = createHash('sha256').update(packageName).digest();\n const security = 1 + (digest.readUInt8(0) % 59);\n const automation = 1 + ((security - 1 + 17 + (digest.readUInt8(1) % 29)) % 59);\n return { security, automation };\n};\n","const prefix = '__RM_INDUSTRIES_FORGE_TEMPLATE_V1_';\n\nexport const templateTokens = Object.freeze({\n packageName: `${prefix}PACKAGE_NAME__`,\n siteName: `${prefix}SITE_NAME__`,\n description: `${prefix}DESCRIPTION__`,\n author: `${prefix}AUTHOR__`,\n url: `${prefix}URL__`,\n repository: `${prefix}REPOSITORY__`,\n securityScheduleMinute: `${prefix}SECURITY_SCHEDULE_MINUTE__`,\n automationScheduleMinute: `${prefix}AUTOMATION_SCHEDULE_MINUTE__`,\n projectDirectory: `${prefix}PROJECT_DIRECTORY__`,\n projectPathFilter: `${prefix}PROJECT_PATH_FILTER__`,\n dependabotDirectory: `${prefix}DEPENDABOT_DIRECTORY__`,\n});\n\nexport const templateTokenPrefix = prefix;\n","import {\n chmod,\n copyFile,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rm,\n rmdir,\n stat,\n writeFile,\n} from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, isAbsolute, join, parse, relative, resolve, sep } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { GeneratorOptions } from './options';\nimport { deriveScheduleMinutes } from './schedule';\nimport { templateTokenPrefix, templateTokens } from './template-tokens';\n\nexport class MaterializationError extends Error {}\n\ntype MaterializationContext = {\n templateDirectory: string | URL;\n cwd?: string;\n signal?: AbortSignal;\n confirmOverwrite?: (destination: string) => Promise<boolean>;\n onFileCopied?: (path: string) => void;\n};\n\ntype TemplateFile = { source: string; relativePath: string; mode: number };\n\nconst pathExists = async (path: string) => {\n try {\n await lstat(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n};\n\nconst getPathStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw error;\n }\n};\n\nconst assertNotAborted = (signal?: AbortSignal) => {\n if (signal?.aborted) throw new Error('Project creation was interrupted.');\n};\n\nconst resolveTemplateDirectory = (directory: string | URL) =>\n directory instanceof URL ? fileURLToPath(directory) : resolve(directory);\n\nconst resolveDestination = (destination: string, cwd: string) => {\n const segments = destination.split(/[\\\\/]/u);\n if (segments.includes('..')) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: parent traversal is not allowed.`,\n );\n }\n const resolved = isAbsolute(destination) ? resolve(destination) : resolve(cwd, destination);\n if (resolved === parse(resolved).root) {\n throw new MaterializationError(\n `Unsafe destination ${JSON.stringify(destination)}: a filesystem root is not allowed.`,\n );\n }\n return resolved;\n};\n\nconst listTemplateFiles = async (root: string, directory = root): Promise<TemplateFile[]> => {\n const entries = await readdir(directory, { withFileTypes: true });\n const files: TemplateFile[] = [];\n for (const entry of entries) {\n const source = join(directory, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await listTemplateFiles(root, source)));\n continue;\n }\n if (!entry.isFile()) throw new MaterializationError(`Template entry ${source} is not a regular file.`);\n const relativePath = relative(root, source);\n files.push({\n source,\n relativePath: relativePath === '.gitignore.template' ? '.gitignore' : relativePath,\n mode: (await stat(source)).mode,\n });\n }\n return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));\n};\n\nconst isDirectoryEmpty = async (directory: string) => (await readdir(directory)).length === 0;\n\nconst ensureDirectory = async (directory: string, created: Set<string>) => {\n const existing = await getPathStat(directory);\n if (existing) {\n if (existing.isSymbolicLink() || !existing.isDirectory()) {\n throw new Error(`Unsafe destination entry ${directory}: expected a regular directory.`);\n }\n return;\n }\n const parent = dirname(directory);\n if (parent !== directory) await ensureDirectory(parent, created);\n await mkdir(directory);\n created.add(directory);\n};\n\nconst quoteTypeScriptString = (value: string) =>\n `'${value\n .replaceAll('\\\\', '\\\\\\\\')\n .replaceAll(\"'\", \"\\\\'\")\n .replaceAll('\\u2028', '\\\\u2028')\n .replaceAll('\\u2029', '\\\\u2029')}'`;\n\nconst replaceToken = (source: string, token: string, value: string, field: string) => {\n const quotedToken = `'${token}'`;\n if (!source.includes(quotedToken)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(quotedToken, quoteTypeScriptString(value));\n};\n\nconst replaceRawToken = (source: string, token: string, value: string, field: string) => {\n if (!source.includes(token)) throw new Error(`Packaged template is missing the ${field} token.`);\n return source.replaceAll(token, value);\n};\n\nconst customizeTemplate = async (projectRoot: string, repositoryRoot: string, options: GeneratorOptions) => {\n const relativeProjectDirectory = relative(repositoryRoot, projectRoot);\n const projectDirectory = relativeProjectDirectory.split(sep).join('/') || '.';\n const projectPathFilter = projectDirectory === '.' ? '**' : `${projectDirectory}/**`;\n const dependabotDirectory = projectDirectory === '.' ? '/' : `/${projectDirectory}`;\n const packagePath = join(projectRoot, 'package.json');\n const packageLockPath = join(projectRoot, 'package-lock.json');\n const packageMetadata = JSON.parse(await readFile(packagePath, 'utf8')) as Record<string, unknown>;\n const packageLock = JSON.parse(await readFile(packageLockPath, 'utf8')) as {\n name?: string;\n packages?: Record<string, Record<string, unknown>>;\n };\n if (\n packageMetadata.name !== templateTokens.packageName ||\n packageLock.name !== templateTokens.packageName ||\n packageLock.packages?.['']?.name !== templateTokens.packageName\n ) {\n throw new Error('Packaged template contains unexpected package metadata tokens.');\n }\n packageMetadata.name = options.packageName;\n packageMetadata.version = '0.0.0';\n packageMetadata.private = true;\n packageLock.name = options.packageName;\n if (!packageLock.packages?.['']) throw new Error('Packaged template lockfile is missing its root package metadata.');\n packageLock.packages[''].name = options.packageName;\n packageLock.packages[''].version = '0.0.0';\n await writeFile(packagePath, `${JSON.stringify(packageMetadata, undefined, 2)}\\n`);\n await writeFile(packageLockPath, `${JSON.stringify(packageLock, undefined, 2)}\\n`);\n\n const siteConfigPath = join(projectRoot, 'src', 'config', 'site.ts');\n let siteConfig = await readFile(siteConfigPath, 'utf8');\n siteConfig = replaceToken(siteConfig, templateTokens.siteName, options.siteName, 'site name');\n siteConfig = replaceToken(siteConfig, templateTokens.description, options.description, 'description');\n siteConfig = replaceToken(siteConfig, templateTokens.author, options.author, 'author');\n siteConfig = replaceToken(siteConfig, templateTokens.url, options.url, 'URL');\n siteConfig = replaceToken(siteConfig, templateTokens.repository, options.repository, 'repository');\n if (siteConfig.includes(templateTokenPrefix)) throw new Error('Packaged template contains unresolved tokens.');\n await writeFile(siteConfigPath, siteConfig);\n\n const scheduleMinutes = deriveScheduleMinutes(options.packageName);\n const securityWorkflowPath = join(repositoryRoot, '.github', 'workflows', 'security.yml');\n const automationWorkflowPath = join(repositoryRoot, '.github', 'workflows', 'automation.yml');\n let securityWorkflow = await readFile(securityWorkflowPath, 'utf8');\n let automationWorkflow = await readFile(automationWorkflowPath, 'utf8');\n securityWorkflow = replaceRawToken(\n securityWorkflow,\n templateTokens.securityScheduleMinute,\n String(scheduleMinutes.security),\n 'security schedule minute',\n );\n automationWorkflow = replaceRawToken(\n automationWorkflow,\n templateTokens.automationScheduleMinute,\n String(scheduleMinutes.automation),\n 'automation schedule minute',\n );\n await writeFile(securityWorkflowPath, securityWorkflow);\n await writeFile(automationWorkflowPath, automationWorkflow);\n\n const tokenizedFiles = [\n {\n path: join(repositoryRoot, '.github', 'workflows', 'project.yml'),\n replacements: [\n [templateTokens.projectDirectory, projectDirectory, 'project directory'],\n [templateTokens.projectPathFilter, projectPathFilter, 'project path filter'],\n ],\n },\n {\n path: securityWorkflowPath,\n replacements: [[templateTokens.projectPathFilter, projectPathFilter, 'project path filter']],\n },\n {\n path: join(repositoryRoot, '.github', 'actions', 'setup-project', 'action.yml'),\n replacements: [[templateTokens.projectDirectory, projectDirectory, 'project directory']],\n },\n {\n path: join(repositoryRoot, '.github', 'dependabot.yml'),\n replacements: [[templateTokens.dependabotDirectory, dependabotDirectory, 'Dependabot directory']],\n },\n ] as const;\n for (const file of tokenizedFiles) {\n let source = await readFile(file.path, 'utf8');\n for (const [token, value, field] of file.replacements) source = replaceRawToken(source, token, value, field);\n await writeFile(file.path, source);\n }\n};\n\nexport const materializeProject = async (options: GeneratorOptions, context: MaterializationContext) => {\n const cwd = context.cwd ?? process.cwd();\n const projectRoot = resolveDestination(options.destination, cwd);\n const repositoryRoot = resolveDestination(options.repositoryRoot, cwd);\n const projectPath = relative(repositoryRoot, projectRoot);\n if (projectPath.startsWith('..') || isAbsolute(projectPath)) {\n throw new MaterializationError(`Project root ${projectRoot} must be inside repository root ${repositoryRoot}.`);\n }\n const templateDirectory = resolveTemplateDirectory(context.templateDirectory);\n const repositoryStat = await getPathStat(repositoryRoot);\n if (repositoryStat && (repositoryStat.isSymbolicLink() || !repositoryStat.isDirectory())) {\n throw new MaterializationError(`Unsafe repository root ${repositoryRoot}: expected a regular directory.`);\n }\n const files = await listTemplateFiles(templateDirectory);\n const destinationExisted = await pathExists(projectRoot);\n if (destinationExisted) {\n const destinationStat = await lstat(projectRoot);\n if (destinationStat.isSymbolicLink() || !destinationStat.isDirectory()) {\n throw new MaterializationError(`Unsafe destination ${projectRoot}: expected a regular directory.`);\n }\n }\n if (destinationExisted && !(await isDirectoryEmpty(projectRoot))) {\n const confirmed = await context.confirmOverwrite?.(projectRoot);\n if (!confirmed) {\n throw new MaterializationError(`Destination ${projectRoot} is not empty. No files were changed.`);\n }\n }\n if (projectRoot !== repositoryRoot) {\n const repositoryFiles = files.filter((file) => file.relativePath.startsWith(`.github${sep}`));\n let hasRepositoryConflict = false;\n for (const file of repositoryFiles) {\n if (await pathExists(join(repositoryRoot, file.relativePath))) {\n hasRepositoryConflict = true;\n break;\n }\n }\n if (hasRepositoryConflict && !(await context.confirmOverwrite?.(repositoryRoot))) {\n throw new MaterializationError(\n `Repository root ${repositoryRoot} contains conflicting files. No files were changed.`,\n );\n }\n }\n const backupDirectory = await mkdtemp(join(tmpdir(), 'create-forge-backup-'));\n const createdFiles = new Set<string>();\n const createdDirectories = new Set<string>();\n const backups = new Map<string, string>();\n\n try {\n assertNotAborted(context.signal);\n await ensureDirectory(repositoryRoot, createdDirectories);\n await ensureDirectory(projectRoot, createdDirectories);\n for (const file of files) {\n assertNotAborted(context.signal);\n const targetRoot = file.relativePath.startsWith(`.github${sep}`) ? repositoryRoot : projectRoot;\n const target = join(targetRoot, file.relativePath);\n const targetRelative = relative(targetRoot, target);\n if (targetRelative.startsWith('..') || isAbsolute(targetRelative))\n throw new Error(`Unsafe template path ${file.relativePath}.`);\n await ensureDirectory(dirname(target), createdDirectories);\n const targetStat = await getPathStat(target);\n if (targetStat) {\n if (targetStat.isSymbolicLink() || !targetStat.isFile()) {\n throw new Error(`Unsafe destination entry ${target}: expected a regular file.`);\n }\n const backup = join(backupDirectory, file.relativePath);\n await mkdir(dirname(backup), { recursive: true });\n await copyFile(target, backup);\n backups.set(target, backup);\n } else {\n createdFiles.add(target);\n }\n await copyFile(file.source, target);\n await chmod(target, file.mode);\n context.onFileCopied?.(target);\n }\n assertNotAborted(context.signal);\n await customizeTemplate(projectRoot, repositoryRoot, options);\n const tokenBytes = Buffer.from(templateTokenPrefix);\n for (const file of files) {\n assertNotAborted(context.signal);\n const targetRoot = file.relativePath.startsWith(`.github${sep}`) ? repositoryRoot : projectRoot;\n if ((await readFile(join(targetRoot, file.relativePath))).includes(tokenBytes)) {\n throw new Error(`Generated file ${file.relativePath} contains an unresolved template token.`);\n }\n }\n return { destination: projectRoot, projectRoot, repositoryRoot, filesCopied: files.length };\n } catch (error) {\n const cleanupErrors: unknown[] = [];\n for (const [target, backup] of backups) {\n try {\n await copyFile(backup, target);\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const file of createdFiles) {\n try {\n await rm(file, { force: true });\n } catch (cleanupError) {\n cleanupErrors.push(cleanupError);\n }\n }\n for (const directory of [...createdDirectories].sort((left, right) => right.length - left.length)) {\n try {\n await rmdir(directory);\n } catch (cleanupError) {\n if (!['ENOENT', 'ENOTEMPTY'].includes((cleanupError as NodeJS.ErrnoException).code ?? '')) {\n cleanupErrors.push(cleanupError);\n }\n }\n }\n const reason = error instanceof Error ? error.message : String(error);\n const recovery = cleanupErrors.length\n ? `Recovery: review ${repositoryRoot}; some changes could not be rolled back automatically.`\n : `Recovery: changes from this invocation were rolled back; resolve the error and retry.`;\n throw new MaterializationError(`${reason} ${recovery}`, { cause: error });\n } finally {\n await rm(backupDirectory, { recursive: true, force: true });\n }\n};\n","import { spawn } from 'node:child_process';\n\nimport type { GeneratorOptions } from './options';\n\nexport class ProcessStepError extends Error {\n readonly exitCode: number;\n\n constructor(message: string, exitCode = 1, options?: ErrorOptions) {\n super(message, options);\n this.exitCode = exitCode;\n }\n}\n\nexport type Command = {\n executable: string;\n arguments: readonly string[];\n cwd: string;\n signal?: AbortSignal;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport type CommandExecutor = (command: Command) => Promise<void>;\n\nconst signalExitCode = (signal: NodeJS.Signals | null) => {\n if (signal === 'SIGINT') return 130;\n if (signal === 'SIGTERM') return 143;\n return 1;\n};\n\nexport const executeCommand: CommandExecutor = ({ executable, arguments: args, cwd, signal, environment }) =>\n new Promise((resolve, reject) => {\n const child = spawn(executable, args, {\n cwd,\n stdio: 'inherit',\n ...(signal ? { signal } : {}),\n ...(environment ? { env: environment } : {}),\n });\n\n child.once('error', (error) => {\n const interrupted = signal?.aborted;\n reject(\n new ProcessStepError(\n interrupted\n ? `${executable} was interrupted. The generated project remains at ${cwd}.`\n : `Could not start ${executable}: ${error.message}. The generated project remains at ${cwd}.`,\n interrupted ? 130 : 1,\n { cause: error },\n ),\n );\n });\n child.once('close', (code, processSignal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const detail = processSignal ? `signal ${processSignal}` : `exit code ${code ?? 'unknown'}`;\n reject(\n new ProcessStepError(\n `${executable} failed with ${detail}. The generated project remains at ${cwd}; review the output above and retry the command there.`,\n processSignal ? signalExitCode(processSignal) : (code ?? 1),\n ),\n );\n });\n });\n\ntype ProjectSetupContext = {\n projectRoot: string;\n repositoryRoot: string;\n signal?: AbortSignal;\n execute?: CommandExecutor;\n environment?: NodeJS.ProcessEnv;\n};\n\nexport const runProjectSetup = async (options: GeneratorOptions, context: ProjectSetupContext) => {\n const execute = context.execute ?? executeCommand;\n const command = (executable: string, args: readonly string[]) =>\n execute({\n executable,\n arguments: args,\n cwd: context.projectRoot,\n ...(context.signal ? { signal: context.signal } : {}),\n ...(context.environment ? { environment: context.environment } : {}),\n });\n\n if (options.install) await command('npm', ['install']);\n if (options.git) {\n await execute({\n executable: 'git',\n arguments: ['init', '--initial-branch=main'],\n cwd: context.repositoryRoot,\n ...(context.signal ? { signal: context.signal } : {}),\n ...(context.environment ? { environment: context.environment } : {}),\n });\n }\n};\n","import { isAbsolute, relative } from 'node:path';\n\nimport type { GeneratorOptions } from './options';\n\ntype CompletionContext = {\n destination: string;\n cwd?: string;\n color?: boolean;\n};\n\nconst ansi = {\n bold: (value: string) => `\\u001B[1m${value}\\u001B[22m`,\n green: (value: string) => `\\u001B[32m${value}\\u001B[39m`,\n};\n\nconst commandPath = (path: string) => {\n if (/^[\\w./@-]+$/u.test(path)) return path;\n return `\"${path.replaceAll('\"', '\\\\\"')}\"`;\n};\n\nconst displayDestination = (destination: string, cwd: string) => {\n const path = relative(cwd, destination);\n if (!path) return '.';\n return isAbsolute(path) ? destination : path;\n};\n\nexport const supportsColor = (environment: NodeJS.ProcessEnv = process.env, terminal = Boolean(process.stdout.isTTY)) =>\n terminal && environment.NO_COLOR === undefined;\n\nexport const formatCompletion = (options: GeneratorOptions, context: CompletionContext) => {\n const cwd = context.cwd ?? process.cwd();\n const color = context.color ?? supportsColor();\n const decorate = color ? ansi : { bold: (value: string) => value, green: (value: string) => value };\n const destination = displayDestination(context.destination, cwd);\n const commands = [\n ...(destination === '.' ? [] : [`cd ${commandPath(destination)}`]),\n ...(options.install ? [] : ['npm install']),\n 'npm run dev',\n ];\n\n return `${decorate.green('✓')} Created ${options.siteName} in ${destination}\\n\\n${decorate.bold('Setup')}\\n Dependencies: ${options.install ? 'installed' : 'skipped'}\\n Git repository: ${options.git ? 'initialized' : 'skipped'}\\n\\n${decorate.bold('Next steps')}\\n${commands.map((command) => ` ${command}`).join('\\n')}\\n`;\n};\n","#!/usr/bin/env node\n\nimport { readFile } from 'node:fs/promises';\n\nimport { confirm, isCancel } from '@clack/prompts';\n\nimport { runCli } from './cli';\nimport { materializeProject } from './materialize';\nimport { ProcessStepError, runProjectSetup } from './process';\nimport { formatCompletion } from './reporter';\n\ntype PackageMetadata = {\n version: string;\n};\n\nconst packageJson = new URL('../package.json', import.meta.url);\nconst metadata = JSON.parse(await readFile(packageJson, 'utf8')) as PackageMetadata;\nconst interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);\nconst result = await runCli(process.argv.slice(2), metadata.version, { interactive });\n\nif (result.options) {\n const controller = new AbortController();\n let interruptedExitCode: number | undefined;\n const interrupt = () => {\n interruptedExitCode = 130;\n controller.abort();\n };\n const terminate = () => {\n interruptedExitCode = 143;\n controller.abort();\n };\n process.once('SIGINT', interrupt);\n process.once('SIGTERM', terminate);\n try {\n const materialized = await materializeProject(result.options, {\n templateDirectory: new URL('./template/', import.meta.url),\n signal: controller.signal,\n ...(interactive\n ? {\n confirmOverwrite: async (destination: string) => {\n const answer = await confirm({\n message: `${destination} is not empty. Continue and overwrite conflicting template files?`,\n initialValue: false,\n });\n return !isCancel(answer) && answer;\n },\n }\n : {}),\n });\n await runProjectSetup(result.options, {\n projectRoot: materialized.projectRoot,\n repositoryRoot: materialized.repositoryRoot,\n signal: controller.signal,\n });\n result.output = formatCompletion(result.options, { destination: materialized.projectRoot });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n result.output = `error: ${message}\\n`;\n result.exitCode = interruptedExitCode ?? (error instanceof ProcessStepError ? error.exitCode : 1);\n } finally {\n process.off('SIGINT', interrupt);\n process.off('SIGTERM', terminate);\n }\n}\n\nprocess.stdout.write(result.output);\nprocess.exitCode = result.exitCode;\n"],"mappings":"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"}
@@ -7,6 +7,10 @@ inputs:
7
7
  description: Node.js version to install
8
8
  required: false
9
9
  default: '26.x'
10
+ project-directory:
11
+ description: Project directory relative to the repository root
12
+ required: false
13
+ default: __RM_INDUSTRIES_FORGE_TEMPLATE_V1_PROJECT_DIRECTORY__
10
14
 
11
15
  runs:
12
16
  using: composite
@@ -17,8 +21,9 @@ runs:
17
21
  with:
18
22
  node-version: ${{ inputs.node-version }}
19
23
  cache: npm
20
- cache-dependency-path: package-lock.json
24
+ cache-dependency-path: ${{ inputs.project-directory }}/package-lock.json
21
25
 
22
26
  - name: Install dependencies
23
27
  shell: bash
24
28
  run: npm ci
29
+ working-directory: ${{ inputs.project-directory }}
@@ -21,7 +21,7 @@ updates:
21
21
  - '*'
22
22
 
23
23
  - package-ecosystem: npm
24
- directory: /
24
+ directory: __RM_INDUSTRIES_FORGE_TEMPLATE_V1_DEPENDABOT_DIRECTORY__
25
25
  schedule:
26
26
  interval: weekly
27
27
  day: monday
@@ -57,23 +57,3 @@ jobs:
57
57
 
58
58
  - name: Validate workflows
59
59
  uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2
60
-
61
- automation:
62
- name: Automation
63
- needs:
64
- - security
65
- - syntax
66
- if: always()
67
- runs-on: ubuntu-latest
68
-
69
- steps:
70
- - name: Confirm automation checks
71
- env:
72
- SECURITY_RESULT: ${{ needs.security.result }}
73
- SYNTAX_RESULT: ${{ needs.syntax.result }}
74
- run: |
75
- if [[ "$SECURITY_RESULT" != 'success' || "$SYNTAX_RESULT" != 'success' ]]; then
76
- echo '::error title=Automation validation failed::Workflow security and syntax checks must both pass.'
77
- exit 1
78
- fi
79
- echo 'Workflow security and syntax checks passed.'