@next-generation-collective/factory 0.3.1 → 0.3.2

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/lib/banner.js ADDED
@@ -0,0 +1,86 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { basename, join } from "node:path";
5
+ import { colors } from "./util.js";
6
+
7
+ // The Next-Gen mark in the terminal: an N whose diagonal runs into a G, in the brand gold.
8
+ const MARK = [
9
+ "█▄ █ ▄▀▀▀▀",
10
+ "█ ▀▄█ █ ▄▄",
11
+ "█ █ ▀▄▄▄▀",
12
+ ];
13
+
14
+ const truecolor = /truecolor|24bit/i.test(process.env.COLORTERM ?? "");
15
+ const gold = (t) => colors.paint(truecolor ? "38;2;245;166;35" : "38;5;214", t);
16
+ const cream = (t) => colors.paint(truecolor ? "38;2;253;251;247" : "97", t);
17
+
18
+ const width = (text) => [...text.replace(/\u001b\[[0-9;]*m/g, "")].length;
19
+
20
+ // The builder's first name, from their git identity or, on a Mac, their account's full
21
+ // name. Nothing is sent anywhere.
22
+ export function firstName() {
23
+ const ask = (cmd, args) => {
24
+ try {
25
+ return execFileSync(cmd, args, { encoding: "utf8", timeout: 1000, stdio: ["ignore", "pipe", "ignore"] }).trim();
26
+ } catch {
27
+ return "";
28
+ }
29
+ };
30
+ const full = ask("git", ["config", "user.name"]) || (process.platform === "darwin" ? ask("id", ["-F"]) : "");
31
+ return full.split(/\s+/)[0] || null;
32
+ }
33
+
34
+ // One small file in the builder's own settings folder, so the first welcome happens once.
35
+ function welcomeFile() {
36
+ const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
37
+ return join(base, "next-gen", "welcomed");
38
+ }
39
+
40
+ export function isFirstVisit() {
41
+ try {
42
+ return !existsSync(welcomeFile());
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ export function rememberVisit() {
49
+ try {
50
+ const file = welcomeFile();
51
+ mkdirSync(join(file, ".."), { recursive: true });
52
+ writeFileSync(file, `${new Date().toISOString().slice(0, 10)}\n`);
53
+ } catch {
54
+ // A read-only home folder only means the long welcome shows again.
55
+ }
56
+ }
57
+
58
+ export function welcomeLines({ name, first, version }) {
59
+ const you = name ? `, ${name}` : "";
60
+ return first
61
+ ? [
62
+ colors.bold(cream(`Welcome to Next-Gen Factory${you}.`)),
63
+ cream("You are one of the builders of the AI economy."),
64
+ `${gold("Africa builds.")} ${colors.dim(`v${version}`)}`,
65
+ ]
66
+ : [
67
+ colors.bold(cream(`Welcome back${you}.`)),
68
+ cream("Every build you prove makes every builder stronger."),
69
+ `${gold("Africa builds.")} ${colors.dim(`v${version}`)}`,
70
+ ];
71
+ }
72
+
73
+ export function banner(version, root, { name = firstName(), first = isFirstVisit() } = {}) {
74
+ const lines = welcomeLines({ name, first, version });
75
+ const rows = lines.map((line, i) => ` ${gold(MARK[i] ?? " ".repeat(width(MARK[0])))} ${line}`);
76
+ const inner = Math.max(...rows.map(width)) + 2;
77
+ const edge = (l, r) => colors.dim(`${l}${"─".repeat(inner)}${r}`);
78
+ if (first) rememberVisit();
79
+ return [
80
+ edge("╭", "╮"),
81
+ ...rows.map((row) => `${colors.dim("│")}${row}${" ".repeat(inner - width(row))}${colors.dim("│")}`),
82
+ edge("╰", "╯"),
83
+ colors.dim(` Reading ${basename(root) || root}...`),
84
+ "",
85
+ ].join("\n");
86
+ }
package/lib/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { homedir } from "node:os";
2
+ import { banner } from "./banner.js";
2
3
  import { parse as parse_, resolve } from "node:path";
3
4
  import { createRequire } from "node:module";
4
5
  import {
@@ -132,7 +133,7 @@ export async function main(argv) {
132
133
  console.error(refusal);
133
134
  return 1;
134
135
  }
135
- if (process.stderr.isTTY) process.stderr.write("Reading your project...\n\n");
136
+ if (process.stdout.isTTY) console.log(banner(VERSION, root));
136
137
  }
137
138
 
138
139
  if (!command) return start(root, flags);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next-generation-collective/factory",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Checks the work you build with AI, proves it works, and learns from every builder. Built in the open, in Africa.",
5
5
  "type": "module",
6
6
  "bin": {