feat(02-01): replace PAPERCLIP ASCII art with NEXUS in banners

- Replace PAPERCLIP art with NEXUS art in server/src/startup-banner.ts
- Replace full cli/src/utils/banner.ts with NEXUS art and updated tagline
- Rename printPaperclipCliBanner to printNexusCliBanner
- Update tagline to 'Open-source orchestration for your agents'
- Update all 5 CLI command callers: onboard, configure, db-backup, worktree, doctor
- Satisfies BRND-02
This commit is contained in:
Mikkel Georgsen 2026-03-30 23:10:23 +02:00
parent 4b670431f3
commit 8ecae05b7d
7 changed files with 32 additions and 28 deletions

View file

@ -15,7 +15,7 @@ import {
resolveDefaultLogsDir, resolveDefaultLogsDir,
resolvePaperclipInstanceId, resolvePaperclipInstanceId,
} from "../config/home.js"; } from "../config/home.js";
import { printPaperclipCliBanner } from "../utils/banner.js"; import { printNexusCliBanner } from "../utils/banner.js";
type Section = "llm" | "database" | "logging" | "server" | "storage" | "secrets"; type Section = "llm" | "database" | "logging" | "server" | "storage" | "secrets";
@ -72,7 +72,7 @@ export async function configure(opts: {
config?: string; config?: string;
section?: string; section?: string;
}): Promise<void> { }): Promise<void> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclip configure "))); p.intro(pc.bgCyan(pc.black(" paperclip configure ")));
const configPath = resolveConfigPath(opts.config); const configPath = resolveConfigPath(opts.config);

View file

@ -8,7 +8,7 @@ import {
resolvePaperclipInstanceId, resolvePaperclipInstanceId,
} from "../config/home.js"; } from "../config/home.js";
import { readConfig, resolveConfigPath } from "../config/store.js"; import { readConfig, resolveConfigPath } from "../config/store.js";
import { printPaperclipCliBanner } from "../utils/banner.js"; import { printNexusCliBanner } from "../utils/banner.js";
type DbBackupOptions = { type DbBackupOptions = {
config?: string; config?: string;
@ -47,7 +47,7 @@ function resolveBackupDir(raw: string): string {
} }
export async function dbBackupCommand(opts: DbBackupOptions): Promise<void> { export async function dbBackupCommand(opts: DbBackupOptions): Promise<void> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclip db:backup "))); p.intro(pc.bgCyan(pc.black(" paperclip db:backup ")));
const configPath = resolveConfigPath(opts.config); const configPath = resolveConfigPath(opts.config);

View file

@ -15,7 +15,7 @@ import {
type CheckResult, type CheckResult,
} from "../checks/index.js"; } from "../checks/index.js";
import { loadPaperclipEnvFile } from "../config/env.js"; import { loadPaperclipEnvFile } from "../config/env.js";
import { printPaperclipCliBanner } from "../utils/banner.js"; import { printNexusCliBanner } from "../utils/banner.js";
const STATUS_ICON = { const STATUS_ICON = {
pass: pc.green("✓"), pass: pc.green("✓"),
@ -28,7 +28,7 @@ export async function doctor(opts: {
repair?: boolean; repair?: boolean;
yes?: boolean; yes?: boolean;
}): Promise<{ passed: number; warned: number; failed: number }> { }): Promise<{ passed: number; warned: number; failed: number }> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclip doctor "))); p.intro(pc.bgCyan(pc.black(" paperclip doctor ")));
const configPath = resolveConfigPath(opts.config); const configPath = resolveConfigPath(opts.config);

View file

@ -32,7 +32,7 @@ import {
resolvePaperclipInstanceId, resolvePaperclipInstanceId,
} from "../config/home.js"; } from "../config/home.js";
import { bootstrapCeoInvite } from "./auth-bootstrap-ceo.js"; import { bootstrapCeoInvite } from "./auth-bootstrap-ceo.js";
import { printPaperclipCliBanner } from "../utils/banner.js"; import { printNexusCliBanner } from "../utils/banner.js";
type SetupMode = "quickstart" | "advanced"; type SetupMode = "quickstart" | "advanced";
@ -234,7 +234,7 @@ function canCreateBootstrapInviteImmediately(config: Pick<PaperclipConfig, "data
} }
export async function onboard(opts: OnboardOptions): Promise<void> { export async function onboard(opts: OnboardOptions): Promise<void> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclipai onboard "))); p.intro(pc.bgCyan(pc.black(" paperclipai onboard ")));
const configPath = resolveConfigPath(opts.config); const configPath = resolveConfigPath(opts.config);
const instance = describeLocalInstancePaths(resolvePaperclipInstanceId()); const instance = describeLocalInstancePaths(resolvePaperclipInstanceId());

View file

@ -49,7 +49,7 @@ import { ensureAgentJwtSecret, loadPaperclipEnvFile, mergePaperclipEnvEntries, r
import { expandHomePrefix } from "../config/home.js"; import { expandHomePrefix } from "../config/home.js";
import type { PaperclipConfig } from "../config/schema.js"; import type { PaperclipConfig } from "../config/schema.js";
import { readConfig, resolveConfigPath, writeConfig } from "../config/store.js"; import { readConfig, resolveConfigPath, writeConfig } from "../config/store.js";
import { printPaperclipCliBanner } from "../utils/banner.js"; import { printNexusCliBanner } from "../utils/banner.js";
import { resolveRuntimeLikePath } from "../utils/path-resolver.js"; import { resolveRuntimeLikePath } from "../utils/path-resolver.js";
import { import {
buildWorktreeConfig, buildWorktreeConfig,
@ -1046,13 +1046,13 @@ async function runWorktreeInit(opts: WorktreeInitOptions): Promise<void> {
} }
export async function worktreeInitCommand(opts: WorktreeInitOptions): Promise<void> { export async function worktreeInitCommand(opts: WorktreeInitOptions): Promise<void> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclipai worktree init "))); p.intro(pc.bgCyan(pc.black(" paperclipai worktree init ")));
await runWorktreeInit(opts); await runWorktreeInit(opts);
} }
export async function worktreeMakeCommand(nameArg: string, opts: WorktreeMakeOptions): Promise<void> { export async function worktreeMakeCommand(nameArg: string, opts: WorktreeMakeOptions): Promise<void> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclipai worktree:make "))); p.intro(pc.bgCyan(pc.black(" paperclipai worktree:make ")));
const name = resolveWorktreeMakeName(nameArg); const name = resolveWorktreeMakeName(nameArg);
@ -1248,7 +1248,7 @@ function worktreePathHasUncommittedChanges(worktreePath: string): boolean {
} }
export async function worktreeCleanupCommand(nameArg: string, opts: WorktreeCleanupOptions): Promise<void> { export async function worktreeCleanupCommand(nameArg: string, opts: WorktreeCleanupOptions): Promise<void> {
printPaperclipCliBanner(); printNexusCliBanner();
p.intro(pc.bgCyan(pc.black(" paperclipai worktree:cleanup "))); p.intro(pc.bgCyan(pc.black(" paperclipai worktree:cleanup ")));
const name = resolveWorktreeMakeName(nameArg); const name = resolveWorktreeMakeName(nameArg);

View file

@ -1,20 +1,23 @@
import pc from "picocolors"; import pc from "picocolors";
const PAPERCLIP_ART = [ // [nexus] replaced PAPERCLIP_ART with NEXUS_ART
"██████╗ █████╗ ██████╗ ███████╗██████╗ ██████╗██╗ ██╗██████╗ ", const NEXUS_ART = [
"██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔════╝██║ ██║██╔══██╗", "███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗",
"██████╔╝███████║██████╔╝█████╗ ██████╔╝██║ ██║ ██║██████╔╝", "████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝",
"██╔═══╝ ██╔══██║██╔═══╝ ██╔══╝ ██╔══██╗██║ ██║ ██║██╔═══╝ ", "██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗",
"██║ ██║ ██║██║ ███████╗██║ ██║╚██████╗███████╗██║██║ ", "██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║",
"╚═╝ ╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝╚═╝ ", "██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║",
"╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝",
] as const; ] as const;
const TAGLINE = "Open-source orchestration for zero-human companies"; // [nexus] updated tagline
const TAGLINE = "Open-source orchestration for your agents";
export function printPaperclipCliBanner(): void { // [nexus] renamed from printPaperclipCliBanner
export function printNexusCliBanner(): void {
const lines = [ const lines = [
"", "",
...PAPERCLIP_ART.map((line) => pc.cyan(line)), ...NEXUS_ART.map((line) => pc.cyan(line)),
pc.blue(" ───────────────────────────────────────────────────────"), pc.blue(" ───────────────────────────────────────────────────────"),
pc.bold(pc.white(` ${TAGLINE}`)), pc.bold(pc.white(` ${TAGLINE}`)),
"", "",

View file

@ -133,13 +133,14 @@ export function printStartupBanner(opts: StartupBannerOptions): void {
? `enabled ${color(`(every ${opts.databaseBackupIntervalMinutes}m, keep ${opts.databaseBackupRetentionDays}d)`, "dim")}` ? `enabled ${color(`(every ${opts.databaseBackupIntervalMinutes}m, keep ${opts.databaseBackupRetentionDays}d)`, "dim")}`
: color("disabled", "yellow"); : color("disabled", "yellow");
// [nexus] replaced PAPERCLIP art with NEXUS art
const art = [ const art = [
color("██████╗ █████╗ ██████╗ ███████╗██████╗ ██████╗██╗ ██╗██████╗ ", "cyan"), color("███╗ ██╗███████╗██╗ ██╗██╗ ██╗███████╗", "cyan"),
color("██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔════╝██║ ██║██╔══██╗", "cyan"), color("████╗ ██║██╔════╝╚██╗██╔╝██║ ██║██╔════╝", "cyan"),
color("██████╔╝███████║██████╔╝█████╗ ██████╔╝██║ ██║ ██║██████╔╝", "cyan"), color("██╔██╗ ██║█████╗ ╚███╔╝ ██║ ██║███████╗", "cyan"),
color("██╔═══╝ ██╔══██║██╔═══╝ ██╔══╝ ██╔══██╗██║ ██║ ██║██╔═══╝ ", "cyan"), color("██║╚██╗██║██╔══╝ ██╔██╗ ██║ ██║╚════██║", "cyan"),
color("██║ ██║ ██║██║ ███████╗██║ ██║╚██████╗███████╗██║██║ ", "cyan"), color("██║ ╚████║███████╗██╔╝ ██╗╚██████╔╝███████║", "cyan"),
color("╚═╝ ╚═╝ ╚═╝╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝╚══════╝╚═╝╚═╝ ", "cyan"), color("╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝", "cyan"),
]; ];
const lines = [ const lines = [