alex-c-line 2.11.2 → 2.12.0

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/dist/index.cjs CHANGED
@@ -386,12 +386,78 @@ async function getLicenseCheck(program) {
386
386
  `;
387
387
  }
388
388
  //#endregion
389
+ //#region src/configs/helpers/preCommit/definePreCommitConfig.ts
390
+ const preCommitStepOptionsSchema = zod.default.strictObject({ arguments: zod.default.array(zod.default.string()).optional() });
391
+ const preCommitConfigSchema = zod.default.strictObject({
392
+ packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager).optional(),
393
+ allowNoStagedChanges: zod.default.boolean().optional(),
394
+ steps: zod.default.array(zod.default.union([
395
+ zod.default.function({
396
+ input: [zod.default.function()],
397
+ output: zod.default.any()
398
+ }),
399
+ zod.default.string(),
400
+ zod.default.tuple([zod.default.string(), preCommitStepOptionsSchema])
401
+ ])),
402
+ updateIndex: zod.default.boolean().optional()
403
+ });
404
+ //#endregion
405
+ //#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
406
+ const templatePullRequestBaseSchema = zod.default.strictObject({ projectName: zod.default.string().optional() });
407
+ const templatePullRequestSchema = zod.default.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
408
+ category: zod.default.literal("general"),
409
+ projectType: zod.default.string()
410
+ }), templatePullRequestBaseSchema.extend({
411
+ category: zod.default.literal("infrastructure"),
412
+ infrastructureProvider: zod.default.string(),
413
+ requireConfirmationFrom: zod.default.string()
414
+ })]);
415
+ function parseTemplatePullRequestConfig(input) {
416
+ return _alextheman_utility.az.with(templatePullRequestSchema).parse(input);
417
+ }
418
+ //#endregion
419
+ //#region src/configs/helpers/defineAlexCLineConfig.ts
420
+ const alexCLineConfigSchema = zod.default.strictObject({
421
+ preCommit: preCommitConfigSchema,
422
+ template: zod.default.object({ pullRequest: templatePullRequestSchema })
423
+ }).partial();
424
+ async function parseAlexCLineConfig(input) {
425
+ return await _alextheman_utility.az.with(alexCLineConfigSchema).parseAsync(input);
426
+ }
427
+ //#endregion
428
+ //#region src/configs/types/ConfigFileName.ts
429
+ const ConfigFileName = {
430
+ STANDARD_JAVASCRIPT: "alex-c-line.config.js",
431
+ ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
432
+ COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
433
+ };
434
+ const PrivateConfigFileName = {
435
+ STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
436
+ ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
437
+ COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
438
+ };
439
+ //#endregion
389
440
  //#region src/configs/types/template/pullRequest/PullRequestTemplateCategory.ts
390
441
  const PullRequestTemplateCategory = {
391
442
  GENERAL: "general",
392
443
  INFRASTRUCTURE: "infrastructure"
393
444
  };
394
445
  //#endregion
446
+ //#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
447
+ const alexCLinePrivateConfigSchema = zod.default.object({ localPackage: zod.default.strictObject({
448
+ enableCache: zod.default.boolean().optional(),
449
+ localPackages: zod.default.record(zod.default.string(), zod.default.strictObject({
450
+ packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager),
451
+ path: zod.default.string(),
452
+ prepareScript: zod.default.string().optional(),
453
+ dependencyGroup: zod.default.enum(_alextheman_utility_internal.DependencyGroup).optional(),
454
+ keepOldTarballs: zod.default.boolean().optional()
455
+ }))
456
+ }) });
457
+ function parseAlexCLinePrivateConfig(data) {
458
+ return _alextheman_utility.az.with(alexCLinePrivateConfigSchema).parse(data);
459
+ }
460
+ //#endregion
395
461
  //#region src/cli/commands/internal/dependency-audit/helpers/getOutdatedDependencies.ts
396
462
  const pnpmOutdatedSchema = zod.default.record(zod.default.string(), zod.default.object({
397
463
  current: _alextheman_utility.az.versionNumber(),
@@ -716,18 +782,6 @@ async function loadAlexCLineProjectCache(cachePath = node_path.default.join(".al
716
782
  }
717
783
  }
718
784
  //#endregion
719
- //#region src/configs/types/ConfigFileName.ts
720
- const ConfigFileName = {
721
- STANDARD_JAVASCRIPT: "alex-c-line.config.js",
722
- ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
723
- COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
724
- };
725
- const PrivateConfigFileName = {
726
- STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
727
- ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
728
- COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
729
- };
730
- //#endregion
731
785
  //#region src/utility/fileSystem/doesFileExist.ts
732
786
  async function doesFileExist(filePath) {
733
787
  try {
@@ -751,21 +805,6 @@ async function findAlexCLineConfig(cwd, validConfigFileNames = [
751
805
  }
752
806
  }
753
807
  //#endregion
754
- //#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
755
- const alexCLinePrivateConfigSchema = zod.default.object({ localPackage: zod.default.strictObject({
756
- enableCache: zod.default.boolean().optional(),
757
- localPackages: zod.default.record(zod.default.string(), zod.default.strictObject({
758
- packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager),
759
- path: zod.default.string(),
760
- prepareScript: zod.default.string().optional(),
761
- dependencyGroup: zod.default.enum(_alextheman_utility_internal.DependencyGroup).optional(),
762
- keepOldTarballs: zod.default.boolean().optional()
763
- }))
764
- }) });
765
- function parseAlexCLinePrivateConfig(data) {
766
- return _alextheman_utility.az.with(alexCLinePrivateConfigSchema).parse(data);
767
- }
768
- //#endregion
769
808
  //#region src/utility/configs/loadAlexCLinePrivateConfig.ts
770
809
  const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
771
810
  async function loadAlexCLinePrivateConfig(filePath) {
@@ -1000,45 +1039,6 @@ function getCommandArguments(program, script, scripts, args) {
1000
1039
  return result;
1001
1040
  }
1002
1041
  //#endregion
1003
- //#region src/configs/helpers/preCommit/definePreCommitConfig.ts
1004
- const preCommitStepOptionsSchema = zod.default.strictObject({ arguments: zod.default.array(zod.default.string()).optional() });
1005
- const preCommitConfigSchema = zod.default.strictObject({
1006
- packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager).optional(),
1007
- allowNoStagedChanges: zod.default.boolean().optional(),
1008
- steps: zod.default.array(zod.default.union([
1009
- zod.default.function({
1010
- input: [zod.default.function()],
1011
- output: zod.default.any()
1012
- }),
1013
- zod.default.string(),
1014
- zod.default.tuple([zod.default.string(), preCommitStepOptionsSchema])
1015
- ])),
1016
- updateIndex: zod.default.boolean().optional()
1017
- });
1018
- //#endregion
1019
- //#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
1020
- const templatePullRequestBaseSchema = zod.default.strictObject({ projectName: zod.default.string().optional() });
1021
- const templatePullRequestSchema = zod.default.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
1022
- category: zod.default.literal("general"),
1023
- projectType: zod.default.string()
1024
- }), templatePullRequestBaseSchema.extend({
1025
- category: zod.default.literal("infrastructure"),
1026
- infrastructureProvider: zod.default.string(),
1027
- requireConfirmationFrom: zod.default.string()
1028
- })]);
1029
- function parseTemplatePullRequestConfig(input) {
1030
- return _alextheman_utility.az.with(templatePullRequestSchema).parse(input);
1031
- }
1032
- //#endregion
1033
- //#region src/configs/helpers/defineAlexCLineConfig.ts
1034
- const alexCLineConfigSchema = zod.default.strictObject({
1035
- preCommit: preCommitConfigSchema,
1036
- template: zod.default.object({ pullRequest: templatePullRequestSchema })
1037
- }).partial();
1038
- async function parseAlexCLineConfig(input) {
1039
- return await _alextheman_utility.az.with(alexCLineConfigSchema).parseAsync(input);
1040
- }
1041
- //#endregion
1042
1042
  //#region src/utility/configs/loadAlexCLineConfig.ts
1043
1043
  const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
1044
1044
  async function loadAlexCLineConfig(filePath) {
@@ -1485,10 +1485,10 @@ function template(program) {
1485
1485
  //#endregion
1486
1486
  //#region package.json
1487
1487
  var name = "alex-c-line";
1488
- var version$1 = "2.11.2";
1488
+ var version$1 = "2.12.0";
1489
1489
  var description = "Command-line tool with commands to streamline the developer workflow.";
1490
1490
  //#endregion
1491
- //#region src/utility/updates/checkUpdate.ts
1491
+ //#region src/cli/notifications/updates/checkUpdate.ts
1492
1492
  async function checkUpdate(options) {
1493
1493
  const currentVersion = new _alextheman_utility.VersionNumber(version$1);
1494
1494
  const { data } = await axios.default.get("https://registry.npmjs.org/alex-c-line/latest", { timeout: 5e3 });
@@ -1708,49 +1708,6 @@ function createCommands(program) {
1708
1708
  });
1709
1709
  }
1710
1710
  //#endregion
1711
- //#region src/utility/errors/formatError.ts
1712
- function formatError(error) {
1713
- if (error instanceof execa.ExecaError) {
1714
- const dataError = new _alextheman_utility_v6.DataError({
1715
- cwd: error.cwd,
1716
- command: error.command,
1717
- exitCode: error.exitCode,
1718
- stderr: error.stderr,
1719
- stdout: error.stdout
1720
- }, error.code ?? "COMMAND_ERROR", error.message);
1721
- if (typeof error.stack === "string") {
1722
- const execaLines = error.stack.split("\n");
1723
- execaLines[0] = `${dataError.name}: ${dataError.message}`;
1724
- dataError.stack = execaLines.join("\n");
1725
- }
1726
- Object.defineProperty(dataError, "originalError", {
1727
- value: error,
1728
- enumerable: false
1729
- });
1730
- throw dataError;
1731
- }
1732
- throw error;
1733
- }
1734
- //#endregion
1735
- //#region src/utility/updates/pendingUpdateMessage.ts
1736
- let pendingUpdateMessage = null;
1737
- let registered = false;
1738
- function setPendingUpdateMessage(message) {
1739
- pendingUpdateMessage = message;
1740
- }
1741
- function registerUpdateMessagePrinter() {
1742
- if (registered) return;
1743
- registered = true;
1744
- function print() {
1745
- if (pendingUpdateMessage) {
1746
- console.info(`\n${pendingUpdateMessage}`);
1747
- pendingUpdateMessage = null;
1748
- }
1749
- }
1750
- process.once("beforeExit", print);
1751
- process.once("exit", print);
1752
- }
1753
- //#endregion
1754
1711
  //#region src/cache/global/createAlexCLineGlobalCache.ts
1755
1712
  async function createAlexCLineGlobalCache(cacheData) {
1756
1713
  await (0, node_fs_promises.mkdir)(ALEX_C_LINE_GLOBAL_CACHE_DIRECTORY, { recursive: true });
@@ -1758,7 +1715,10 @@ async function createAlexCLineGlobalCache(cacheData) {
1758
1715
  }
1759
1716
  //#endregion
1760
1717
  //#region src/cache/global/types/AlexCLineGlobalCache.ts
1761
- const alexCLineGlobalCacheSchema = zod.default.looseObject({ updateChecks: zod.default.record(zod.default.string(), zod.default.string()).optional() });
1718
+ const alexCLineGlobalCacheSchema = zod.default.looseObject({
1719
+ updateChecks: zod.default.record(zod.default.string(), zod.default.string()).optional(),
1720
+ birthdayChecks: zod.default.record(zod.default.string(), zod.default.string()).optional()
1721
+ });
1762
1722
  //#endregion
1763
1723
  //#region src/cache/global/parseAlexCLineGlobalCache.ts
1764
1724
  function parseAlexCLineGlobalCache(input) {
@@ -1775,7 +1735,86 @@ async function loadAlexCLineGlobalCache() {
1775
1735
  }
1776
1736
  }
1777
1737
  //#endregion
1778
- //#region src/utility/updates/runAutomatedUpdateCheck.ts
1738
+ //#region src/cli/notifications/birthday/sendBirthdayNotification.ts
1739
+ async function sendBirthdayNotification(message) {
1740
+ const width = Math.max(...message.split("\n").map((line) => {
1741
+ return line.length;
1742
+ }));
1743
+ const messageWithArtwork = await createAlexCLineArtwork({
1744
+ includeColors: Boolean(supports_color.default.stdout),
1745
+ subtitleColor: chalk.default.white,
1746
+ subtitleText: message.split("\n").map((line) => {
1747
+ return centerLine(line, width);
1748
+ }).join("\n")
1749
+ });
1750
+ console.info(messageWithArtwork);
1751
+ }
1752
+ //#endregion
1753
+ //#region src/cli/notifications/helpers/birthdays.ts
1754
+ const birthdays = [{
1755
+ id: "alex",
1756
+ date: /* @__PURE__ */ new Date("2003-07-16T00:00:00.000Z"),
1757
+ getMessage: (age) => {
1758
+ return _alextheman_utility.normaliseIndents`
1759
+ Happy birthday to AlexMan123456, my creator! 🎉
1760
+ He has turned ${age} years old today!
1761
+ `;
1762
+ }
1763
+ }, {
1764
+ id: "alex-c-line",
1765
+ date: /* @__PURE__ */ new Date("2025-07-20T00:00:00.000Z"),
1766
+ getMessage: (age) => {
1767
+ return _alextheman_utility.normaliseIndents`
1768
+ Happy birthday to me, alex-c-line! 🎉
1769
+ I have turned ${age} years old today!
1770
+ `;
1771
+ }
1772
+ }];
1773
+ //#endregion
1774
+ //#region src/cli/notifications/birthday/maybeSendBirthdayNotification.ts
1775
+ async function maybeSendBirthdayNotification() {
1776
+ try {
1777
+ const cacheData = await loadAlexCLineGlobalCache();
1778
+ const currentDate = /* @__PURE__ */ new Date();
1779
+ for (const birthday of birthdays) {
1780
+ const lastChecked = cacheData?.birthdayChecks?.[birthday.id] ? new Date(cacheData.birthdayChecks[birthday.id]) : void 0;
1781
+ if ((lastChecked === void 0 || lastChecked.getFullYear() !== currentDate.getFullYear()) && (0, _alextheman_utility.isAnniversary)(currentDate, birthday.date)) {
1782
+ await sendBirthdayNotification(birthday.getMessage(currentDate.getFullYear() - birthday.date.getFullYear()));
1783
+ await createAlexCLineGlobalCache({
1784
+ ...cacheData ?? {},
1785
+ birthdayChecks: {
1786
+ ...cacheData?.birthdayChecks ?? {},
1787
+ [birthday.id]: currentDate.toISOString()
1788
+ }
1789
+ });
1790
+ }
1791
+ }
1792
+ } catch {}
1793
+ }
1794
+ //#endregion
1795
+ //#region src/cli/notifications/shouldShowNotifications.ts
1796
+ const shouldShowNotifications = !(process.env.NODE_ENV === "test" || (0, _alextheman_utility.parseBoolean)(process.env.RUN_END_TO_END ?? "false") || (0, _alextheman_utility.parseBoolean)(process.env.CI ?? "false"));
1797
+ //#endregion
1798
+ //#region src/cli/notifications/updates/pendingUpdateMessage.ts
1799
+ let pendingUpdateMessage = null;
1800
+ let registered = false;
1801
+ function setPendingUpdateMessage(message) {
1802
+ pendingUpdateMessage = message;
1803
+ }
1804
+ function registerUpdateMessagePrinter() {
1805
+ if (registered) return;
1806
+ registered = true;
1807
+ function print() {
1808
+ if (pendingUpdateMessage) {
1809
+ console.info(`\n${pendingUpdateMessage}`);
1810
+ pendingUpdateMessage = null;
1811
+ }
1812
+ }
1813
+ process.once("beforeExit", print);
1814
+ process.once("exit", print);
1815
+ }
1816
+ //#endregion
1817
+ //#region src/cli/notifications/updates/runAutomatedUpdateCheck.ts
1779
1818
  async function runAutomatedUpdateCheck() {
1780
1819
  try {
1781
1820
  const cacheData = await loadAlexCLineGlobalCache();
@@ -1797,8 +1836,29 @@ async function runAutomatedUpdateCheck() {
1797
1836
  } catch {}
1798
1837
  }
1799
1838
  //#endregion
1800
- //#region src/utility/updates/shouldRunAutomatedUpdateCheck.ts
1801
- const shouldRunAutomatedUpdateCheck = !(process.env.NODE_ENV === "test" || (0, _alextheman_utility.parseBoolean)(process.env.RUN_END_TO_END ?? "false") || (0, _alextheman_utility.parseBoolean)(process.env.CI ?? "false"));
1839
+ //#region src/utility/errors/formatError.ts
1840
+ function formatError(error) {
1841
+ if (error instanceof execa.ExecaError) {
1842
+ const dataError = new _alextheman_utility_v6.DataError({
1843
+ cwd: error.cwd,
1844
+ command: error.command,
1845
+ exitCode: error.exitCode,
1846
+ stderr: error.stderr,
1847
+ stdout: error.stdout
1848
+ }, error.code ?? "COMMAND_ERROR", error.message);
1849
+ if (typeof error.stack === "string") {
1850
+ const execaLines = error.stack.split("\n");
1851
+ execaLines[0] = `${dataError.name}: ${dataError.message}`;
1852
+ dataError.stack = execaLines.join("\n");
1853
+ }
1854
+ Object.defineProperty(dataError, "originalError", {
1855
+ value: error,
1856
+ enumerable: false
1857
+ });
1858
+ throw dataError;
1859
+ }
1860
+ throw error;
1861
+ }
1802
1862
  //#endregion
1803
1863
  //#region src/cli/index.ts
1804
1864
  (async () => {
@@ -1806,8 +1866,9 @@ const shouldRunAutomatedUpdateCheck = !(process.env.NODE_ENV === "test" || (0, _
1806
1866
  const program = new commander.Command();
1807
1867
  program.name(name).description(description).version(version$1);
1808
1868
  registerUpdateMessagePrinter();
1809
- if (shouldRunAutomatedUpdateCheck) setTimeout(() => {
1869
+ if (shouldShowNotifications) setTimeout(() => {
1810
1870
  runAutomatedUpdateCheck();
1871
+ maybeSendBirthdayNotification();
1811
1872
  }, 0);
1812
1873
  createCommands(program);
1813
1874
  await program.parseAsync(process.argv);
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import boxen from "boxen";
7
7
  import figlet from "figlet";
8
8
  import envPaths from "env-paths";
9
9
  import path from "node:path";
10
- import { ONE_DAY_IN_MILLISECONDS, VersionNumber, az, escapeHTML, escapeRegexPattern, fillArray, getStringsAndInterpolations, interpolate, isTemplateStringsArray, kebabToCamel, normaliseIndents, omitProperties, parseBoolean, parseIntStrict, parseVersionType, removeDuplicates, removeUndefinedFromObject, sortBy, stringifyDotenv } from "@alextheman/utility";
10
+ import { ONE_DAY_IN_MILLISECONDS, VersionNumber, az, escapeHTML, escapeRegexPattern, fillArray, getStringsAndInterpolations, interpolate, isAnniversary, isTemplateStringsArray, kebabToCamel, normaliseIndents, omitProperties, parseBoolean, parseIntStrict, parseVersionType, removeDuplicates, removeUndefinedFromObject, sortBy, stringifyDotenv } from "@alextheman/utility";
11
11
  import { confirm, input, password, select } from "@inquirer/prompts";
12
12
  import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
13
13
  import { parse } from "dotenv";
@@ -355,12 +355,78 @@ async function getLicenseCheck(program) {
355
355
  `;
356
356
  }
357
357
  //#endregion
358
+ //#region src/configs/helpers/preCommit/definePreCommitConfig.ts
359
+ const preCommitStepOptionsSchema = z.strictObject({ arguments: z.array(z.string()).optional() });
360
+ const preCommitConfigSchema = z.strictObject({
361
+ packageManager: z.enum(PackageManager).optional(),
362
+ allowNoStagedChanges: z.boolean().optional(),
363
+ steps: z.array(z.union([
364
+ z.function({
365
+ input: [z.function()],
366
+ output: z.any()
367
+ }),
368
+ z.string(),
369
+ z.tuple([z.string(), preCommitStepOptionsSchema])
370
+ ])),
371
+ updateIndex: z.boolean().optional()
372
+ });
373
+ //#endregion
374
+ //#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
375
+ const templatePullRequestBaseSchema = z.strictObject({ projectName: z.string().optional() });
376
+ const templatePullRequestSchema = z.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
377
+ category: z.literal("general"),
378
+ projectType: z.string()
379
+ }), templatePullRequestBaseSchema.extend({
380
+ category: z.literal("infrastructure"),
381
+ infrastructureProvider: z.string(),
382
+ requireConfirmationFrom: z.string()
383
+ })]);
384
+ function parseTemplatePullRequestConfig(input) {
385
+ return az.with(templatePullRequestSchema).parse(input);
386
+ }
387
+ //#endregion
388
+ //#region src/configs/helpers/defineAlexCLineConfig.ts
389
+ const alexCLineConfigSchema = z.strictObject({
390
+ preCommit: preCommitConfigSchema,
391
+ template: z.object({ pullRequest: templatePullRequestSchema })
392
+ }).partial();
393
+ async function parseAlexCLineConfig(input) {
394
+ return await az.with(alexCLineConfigSchema).parseAsync(input);
395
+ }
396
+ //#endregion
397
+ //#region src/configs/types/ConfigFileName.ts
398
+ const ConfigFileName = {
399
+ STANDARD_JAVASCRIPT: "alex-c-line.config.js",
400
+ ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
401
+ COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
402
+ };
403
+ const PrivateConfigFileName = {
404
+ STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
405
+ ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
406
+ COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
407
+ };
408
+ //#endregion
358
409
  //#region src/configs/types/template/pullRequest/PullRequestTemplateCategory.ts
359
410
  const PullRequestTemplateCategory = {
360
411
  GENERAL: "general",
361
412
  INFRASTRUCTURE: "infrastructure"
362
413
  };
363
414
  //#endregion
415
+ //#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
416
+ const alexCLinePrivateConfigSchema = z.object({ localPackage: z.strictObject({
417
+ enableCache: z.boolean().optional(),
418
+ localPackages: z.record(z.string(), z.strictObject({
419
+ packageManager: z.enum(PackageManager),
420
+ path: z.string(),
421
+ prepareScript: z.string().optional(),
422
+ dependencyGroup: z.enum(DependencyGroup).optional(),
423
+ keepOldTarballs: z.boolean().optional()
424
+ }))
425
+ }) });
426
+ function parseAlexCLinePrivateConfig(data) {
427
+ return az.with(alexCLinePrivateConfigSchema).parse(data);
428
+ }
429
+ //#endregion
364
430
  //#region src/cli/commands/internal/dependency-audit/helpers/getOutdatedDependencies.ts
365
431
  const pnpmOutdatedSchema = z.record(z.string(), z.object({
366
432
  current: az.versionNumber(),
@@ -685,18 +751,6 @@ async function loadAlexCLineProjectCache(cachePath = path.join(".alex-c-line", "
685
751
  }
686
752
  }
687
753
  //#endregion
688
- //#region src/configs/types/ConfigFileName.ts
689
- const ConfigFileName = {
690
- STANDARD_JAVASCRIPT: "alex-c-line.config.js",
691
- ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
692
- COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
693
- };
694
- const PrivateConfigFileName = {
695
- STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
696
- ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
697
- COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
698
- };
699
- //#endregion
700
754
  //#region src/utility/fileSystem/doesFileExist.ts
701
755
  async function doesFileExist(filePath) {
702
756
  try {
@@ -720,21 +774,6 @@ async function findAlexCLineConfig(cwd, validConfigFileNames = [
720
774
  }
721
775
  }
722
776
  //#endregion
723
- //#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
724
- const alexCLinePrivateConfigSchema = z.object({ localPackage: z.strictObject({
725
- enableCache: z.boolean().optional(),
726
- localPackages: z.record(z.string(), z.strictObject({
727
- packageManager: z.enum(PackageManager),
728
- path: z.string(),
729
- prepareScript: z.string().optional(),
730
- dependencyGroup: z.enum(DependencyGroup).optional(),
731
- keepOldTarballs: z.boolean().optional()
732
- }))
733
- }) });
734
- function parseAlexCLinePrivateConfig(data) {
735
- return az.with(alexCLinePrivateConfigSchema).parse(data);
736
- }
737
- //#endregion
738
777
  //#region src/utility/configs/loadAlexCLinePrivateConfig.ts
739
778
  const require$1 = createRequire(import.meta.url);
740
779
  async function loadAlexCLinePrivateConfig(filePath) {
@@ -969,45 +1008,6 @@ function getCommandArguments(program, script, scripts, args) {
969
1008
  return result;
970
1009
  }
971
1010
  //#endregion
972
- //#region src/configs/helpers/preCommit/definePreCommitConfig.ts
973
- const preCommitStepOptionsSchema = z.strictObject({ arguments: z.array(z.string()).optional() });
974
- const preCommitConfigSchema = z.strictObject({
975
- packageManager: z.enum(PackageManager).optional(),
976
- allowNoStagedChanges: z.boolean().optional(),
977
- steps: z.array(z.union([
978
- z.function({
979
- input: [z.function()],
980
- output: z.any()
981
- }),
982
- z.string(),
983
- z.tuple([z.string(), preCommitStepOptionsSchema])
984
- ])),
985
- updateIndex: z.boolean().optional()
986
- });
987
- //#endregion
988
- //#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
989
- const templatePullRequestBaseSchema = z.strictObject({ projectName: z.string().optional() });
990
- const templatePullRequestSchema = z.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
991
- category: z.literal("general"),
992
- projectType: z.string()
993
- }), templatePullRequestBaseSchema.extend({
994
- category: z.literal("infrastructure"),
995
- infrastructureProvider: z.string(),
996
- requireConfirmationFrom: z.string()
997
- })]);
998
- function parseTemplatePullRequestConfig(input) {
999
- return az.with(templatePullRequestSchema).parse(input);
1000
- }
1001
- //#endregion
1002
- //#region src/configs/helpers/defineAlexCLineConfig.ts
1003
- const alexCLineConfigSchema = z.strictObject({
1004
- preCommit: preCommitConfigSchema,
1005
- template: z.object({ pullRequest: templatePullRequestSchema })
1006
- }).partial();
1007
- async function parseAlexCLineConfig(input) {
1008
- return await az.with(alexCLineConfigSchema).parseAsync(input);
1009
- }
1010
- //#endregion
1011
1011
  //#region src/utility/configs/loadAlexCLineConfig.ts
1012
1012
  const require = createRequire(import.meta.url);
1013
1013
  async function loadAlexCLineConfig(filePath) {
@@ -1454,10 +1454,10 @@ function template(program) {
1454
1454
  //#endregion
1455
1455
  //#region package.json
1456
1456
  var name = "alex-c-line";
1457
- var version$1 = "2.11.2";
1457
+ var version$1 = "2.12.0";
1458
1458
  var description = "Command-line tool with commands to streamline the developer workflow.";
1459
1459
  //#endregion
1460
- //#region src/utility/updates/checkUpdate.ts
1460
+ //#region src/cli/notifications/updates/checkUpdate.ts
1461
1461
  async function checkUpdate(options) {
1462
1462
  const currentVersion = new VersionNumber(version$1);
1463
1463
  const { data } = await axios.get("https://registry.npmjs.org/alex-c-line/latest", { timeout: 5e3 });
@@ -1677,49 +1677,6 @@ function createCommands(program) {
1677
1677
  });
1678
1678
  }
1679
1679
  //#endregion
1680
- //#region src/utility/errors/formatError.ts
1681
- function formatError(error) {
1682
- if (error instanceof ExecaError) {
1683
- const dataError = new DataError({
1684
- cwd: error.cwd,
1685
- command: error.command,
1686
- exitCode: error.exitCode,
1687
- stderr: error.stderr,
1688
- stdout: error.stdout
1689
- }, error.code ?? "COMMAND_ERROR", error.message);
1690
- if (typeof error.stack === "string") {
1691
- const execaLines = error.stack.split("\n");
1692
- execaLines[0] = `${dataError.name}: ${dataError.message}`;
1693
- dataError.stack = execaLines.join("\n");
1694
- }
1695
- Object.defineProperty(dataError, "originalError", {
1696
- value: error,
1697
- enumerable: false
1698
- });
1699
- throw dataError;
1700
- }
1701
- throw error;
1702
- }
1703
- //#endregion
1704
- //#region src/utility/updates/pendingUpdateMessage.ts
1705
- let pendingUpdateMessage = null;
1706
- let registered = false;
1707
- function setPendingUpdateMessage(message) {
1708
- pendingUpdateMessage = message;
1709
- }
1710
- function registerUpdateMessagePrinter() {
1711
- if (registered) return;
1712
- registered = true;
1713
- function print() {
1714
- if (pendingUpdateMessage) {
1715
- console.info(`\n${pendingUpdateMessage}`);
1716
- pendingUpdateMessage = null;
1717
- }
1718
- }
1719
- process.once("beforeExit", print);
1720
- process.once("exit", print);
1721
- }
1722
- //#endregion
1723
1680
  //#region src/cache/global/createAlexCLineGlobalCache.ts
1724
1681
  async function createAlexCLineGlobalCache(cacheData) {
1725
1682
  await mkdir(ALEX_C_LINE_GLOBAL_CACHE_DIRECTORY, { recursive: true });
@@ -1727,7 +1684,10 @@ async function createAlexCLineGlobalCache(cacheData) {
1727
1684
  }
1728
1685
  //#endregion
1729
1686
  //#region src/cache/global/types/AlexCLineGlobalCache.ts
1730
- const alexCLineGlobalCacheSchema = z.looseObject({ updateChecks: z.record(z.string(), z.string()).optional() });
1687
+ const alexCLineGlobalCacheSchema = z.looseObject({
1688
+ updateChecks: z.record(z.string(), z.string()).optional(),
1689
+ birthdayChecks: z.record(z.string(), z.string()).optional()
1690
+ });
1731
1691
  //#endregion
1732
1692
  //#region src/cache/global/parseAlexCLineGlobalCache.ts
1733
1693
  function parseAlexCLineGlobalCache(input) {
@@ -1744,7 +1704,86 @@ async function loadAlexCLineGlobalCache() {
1744
1704
  }
1745
1705
  }
1746
1706
  //#endregion
1747
- //#region src/utility/updates/runAutomatedUpdateCheck.ts
1707
+ //#region src/cli/notifications/birthday/sendBirthdayNotification.ts
1708
+ async function sendBirthdayNotification(message) {
1709
+ const width = Math.max(...message.split("\n").map((line) => {
1710
+ return line.length;
1711
+ }));
1712
+ const messageWithArtwork = await createAlexCLineArtwork({
1713
+ includeColors: Boolean(supportsColor.stdout),
1714
+ subtitleColor: chalk.white,
1715
+ subtitleText: message.split("\n").map((line) => {
1716
+ return centerLine(line, width);
1717
+ }).join("\n")
1718
+ });
1719
+ console.info(messageWithArtwork);
1720
+ }
1721
+ //#endregion
1722
+ //#region src/cli/notifications/helpers/birthdays.ts
1723
+ const birthdays = [{
1724
+ id: "alex",
1725
+ date: /* @__PURE__ */ new Date("2003-07-16T00:00:00.000Z"),
1726
+ getMessage: (age) => {
1727
+ return normaliseIndents`
1728
+ Happy birthday to AlexMan123456, my creator! 🎉
1729
+ He has turned ${age} years old today!
1730
+ `;
1731
+ }
1732
+ }, {
1733
+ id: "alex-c-line",
1734
+ date: /* @__PURE__ */ new Date("2025-07-20T00:00:00.000Z"),
1735
+ getMessage: (age) => {
1736
+ return normaliseIndents`
1737
+ Happy birthday to me, alex-c-line! 🎉
1738
+ I have turned ${age} years old today!
1739
+ `;
1740
+ }
1741
+ }];
1742
+ //#endregion
1743
+ //#region src/cli/notifications/birthday/maybeSendBirthdayNotification.ts
1744
+ async function maybeSendBirthdayNotification() {
1745
+ try {
1746
+ const cacheData = await loadAlexCLineGlobalCache();
1747
+ const currentDate = /* @__PURE__ */ new Date();
1748
+ for (const birthday of birthdays) {
1749
+ const lastChecked = cacheData?.birthdayChecks?.[birthday.id] ? new Date(cacheData.birthdayChecks[birthday.id]) : void 0;
1750
+ if ((lastChecked === void 0 || lastChecked.getFullYear() !== currentDate.getFullYear()) && isAnniversary(currentDate, birthday.date)) {
1751
+ await sendBirthdayNotification(birthday.getMessage(currentDate.getFullYear() - birthday.date.getFullYear()));
1752
+ await createAlexCLineGlobalCache({
1753
+ ...cacheData ?? {},
1754
+ birthdayChecks: {
1755
+ ...cacheData?.birthdayChecks ?? {},
1756
+ [birthday.id]: currentDate.toISOString()
1757
+ }
1758
+ });
1759
+ }
1760
+ }
1761
+ } catch {}
1762
+ }
1763
+ //#endregion
1764
+ //#region src/cli/notifications/shouldShowNotifications.ts
1765
+ const shouldShowNotifications = !(process.env.NODE_ENV === "test" || parseBoolean(process.env.RUN_END_TO_END ?? "false") || parseBoolean(process.env.CI ?? "false"));
1766
+ //#endregion
1767
+ //#region src/cli/notifications/updates/pendingUpdateMessage.ts
1768
+ let pendingUpdateMessage = null;
1769
+ let registered = false;
1770
+ function setPendingUpdateMessage(message) {
1771
+ pendingUpdateMessage = message;
1772
+ }
1773
+ function registerUpdateMessagePrinter() {
1774
+ if (registered) return;
1775
+ registered = true;
1776
+ function print() {
1777
+ if (pendingUpdateMessage) {
1778
+ console.info(`\n${pendingUpdateMessage}`);
1779
+ pendingUpdateMessage = null;
1780
+ }
1781
+ }
1782
+ process.once("beforeExit", print);
1783
+ process.once("exit", print);
1784
+ }
1785
+ //#endregion
1786
+ //#region src/cli/notifications/updates/runAutomatedUpdateCheck.ts
1748
1787
  async function runAutomatedUpdateCheck() {
1749
1788
  try {
1750
1789
  const cacheData = await loadAlexCLineGlobalCache();
@@ -1766,8 +1805,29 @@ async function runAutomatedUpdateCheck() {
1766
1805
  } catch {}
1767
1806
  }
1768
1807
  //#endregion
1769
- //#region src/utility/updates/shouldRunAutomatedUpdateCheck.ts
1770
- const shouldRunAutomatedUpdateCheck = !(process.env.NODE_ENV === "test" || parseBoolean(process.env.RUN_END_TO_END ?? "false") || parseBoolean(process.env.CI ?? "false"));
1808
+ //#region src/utility/errors/formatError.ts
1809
+ function formatError(error) {
1810
+ if (error instanceof ExecaError) {
1811
+ const dataError = new DataError({
1812
+ cwd: error.cwd,
1813
+ command: error.command,
1814
+ exitCode: error.exitCode,
1815
+ stderr: error.stderr,
1816
+ stdout: error.stdout
1817
+ }, error.code ?? "COMMAND_ERROR", error.message);
1818
+ if (typeof error.stack === "string") {
1819
+ const execaLines = error.stack.split("\n");
1820
+ execaLines[0] = `${dataError.name}: ${dataError.message}`;
1821
+ dataError.stack = execaLines.join("\n");
1822
+ }
1823
+ Object.defineProperty(dataError, "originalError", {
1824
+ value: error,
1825
+ enumerable: false
1826
+ });
1827
+ throw dataError;
1828
+ }
1829
+ throw error;
1830
+ }
1771
1831
  //#endregion
1772
1832
  //#region src/cli/index.ts
1773
1833
  (async () => {
@@ -1775,8 +1835,9 @@ const shouldRunAutomatedUpdateCheck = !(process.env.NODE_ENV === "test" || parse
1775
1835
  const program = new Command();
1776
1836
  program.name(name).description(description).version(version$1);
1777
1837
  registerUpdateMessagePrinter();
1778
- if (shouldRunAutomatedUpdateCheck) setTimeout(() => {
1838
+ if (shouldShowNotifications) setTimeout(() => {
1779
1839
  runAutomatedUpdateCheck();
1840
+ maybeSendBirthdayNotification();
1780
1841
  }, 0);
1781
1842
  createCommands(program);
1782
1843
  await program.parseAsync(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alex-c-line",
3
- "version": "2.11.2",
3
+ "version": "2.12.0",
4
4
  "description": "Command-line tool with commands to streamline the developer workflow.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "templates"
35
35
  ],
36
36
  "dependencies": {
37
- "@alextheman/utility": "5.23.0",
37
+ "@alextheman/utility": "5.23.1",
38
38
  "@inquirer/prompts": "8.5.2",
39
39
  "axios": "1.18.1",
40
40
  "boxen": "8.0.1",
@@ -48,7 +48,7 @@
48
48
  "gray-matter": "4.0.3",
49
49
  "semver": "7.8.5",
50
50
  "supports-color": "10.2.2",
51
- "toml": "4.1.1",
51
+ "toml": "4.1.2",
52
52
  "zod": "4.4.3"
53
53
  },
54
54
  "devDependencies": {
@@ -56,22 +56,22 @@
56
56
  "@commander-js/extra-typings": "15.0.0",
57
57
  "@faker-js/faker": "10.5.0",
58
58
  "@types/eslint": "9.6.1",
59
- "@types/node": "26.0.1",
59
+ "@types/node": "26.1.0",
60
60
  "@types/semver": "7.7.1",
61
61
  "@types/update-notifier": "6.0.8",
62
62
  "cross-env": "10.1.0",
63
63
  "dotenv-cli": "11.0.0",
64
- "eslint": "10.5.0",
64
+ "eslint": "10.6.0",
65
65
  "husky": "9.1.7",
66
- "markdownlint-cli2": "0.22.1",
67
- "prettier": "3.8.4",
66
+ "markdownlint-cli2": "0.23.0",
67
+ "prettier": "3.9.4",
68
68
  "tempy": "3.2.0",
69
69
  "ts-node": "10.9.2",
70
70
  "tsdown": "0.22.3",
71
- "tsx": "4.22.4",
71
+ "tsx": "4.23.0",
72
72
  "typescript": "6.0.3",
73
- "typescript-eslint": "8.62.0",
74
- "vite": "8.1.0",
73
+ "typescript-eslint": "8.62.1",
74
+ "vite": "8.1.3",
75
75
  "vitest": "4.1.9"
76
76
  },
77
77
  "engines": {
@@ -7,7 +7,7 @@ placeholders:
7
7
  ---
8
8
  # Change Request
9
9
 
10
- This is a request for a change to {{projectName}} by {{requestedBy}}. If this gets accepted it will trigger a new deployment to apply the change. Please see more details below
10
+ This is a request for a change to {{projectName}} by {{requestedBy}}. If this gets accepted it will trigger a new deployment to apply the change. Please see more details below.
11
11
 
12
12
  ## Change reason
13
13