From 280fa3e6a736b1dbdac8c344d85b3e0ebe534768 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 09:29:51 +0000 Subject: [PATCH 1/4] Initial plan From 7aab63cc88f55cbd006aad458efaedd33e0f0a33 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 09:34:07 +0000 Subject: [PATCH 2/4] feat: add ascii logo to setup welcome message Co-authored-by: ChangeHow <23733347+ChangeHow@users.noreply.github.com> Agent-Logs-Url: https://github.com/ChangeHow/suitup/sessions/96fcf2d5-9b7a-4503-aacc-4f5f5d9cdac1 --- src/setup.js | 15 ++++++++++++++- tests/setup.test.js | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/setup.js b/src/setup.js index 56ba6c5..f931490 100644 --- a/src/setup.js +++ b/src/setup.js @@ -19,6 +19,19 @@ import { commandExists } from "./utils/shell.js"; import { isZshShell } from "./utils/shell-context.js"; export { isZshShell } from "./utils/shell-context.js"; +export const SUITUP_ASCII_LOGO = String.raw` + _____ _ __ + / ___/__ __(_) /___ ______ + \__ \/ / / / / __/ / / / __ \ + ___/ / /_/ / / /_/ /_/ / /_/ / +/____/\__,_/_/\__/\__,_/ .___/ + /_/ +`.trim(); + +export function getWelcomeMessage() { + return `${pc.cyan(SUITUP_ASCII_LOGO)}\n${pc.bgCyan(pc.black(" Suit up! "))}`; +} + export function getRecommendedCliToolValues() { return [...CLI_TOOLS.essentials, ...CLI_TOOLS.shell].map((tool) => tool.value); } @@ -126,7 +139,7 @@ export function getInitialStepValues(opts = {}) { } export async function runSetup({ defaults = false } = {}) { - p.intro(pc.bgCyan(pc.black(" Suit up! "))); + p.intro(getWelcomeMessage()); if (!isZshShell()) { p.log.error("Suitup setup must be run from zsh."); diff --git a/tests/setup.test.js b/tests/setup.test.js index 9583d4c..8be6d4b 100644 --- a/tests/setup.test.js +++ b/tests/setup.test.js @@ -17,6 +17,7 @@ import { getInitialStepValues, getRecommendedAppValues, getRecommendedCliToolValues, + getWelcomeMessage, isZshShell, } from "../src/setup.js"; @@ -163,6 +164,15 @@ describe("Setup simulation in sandbox", () => { ]); }); + test("welcome message includes the ASCII suitup mark", () => { + const message = getWelcomeMessage(); + + expect(message).toContain("_____ _ __"); + expect(message).toContain("/ ___/__ __(_) /___ ______"); + expect(message).toContain("/____/\\__,_/_/\\__/\\__,_/ .___/"); + expect(message).toContain("Suit up!"); + }); + test("detects completed suitup-managed setup steps", () => { mkdirSync(join(sandbox, ".config", "zsh", "core"), { recursive: true }); mkdirSync(join(sandbox, ".config", "zsh", "shared"), { recursive: true }); From fb92bec83951fa5583471430e38a38a6cfe40604 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:43:56 +0000 Subject: [PATCH 3/4] feat: match welcome banner to provided pixel art Co-authored-by: ChangeHow <23733347+ChangeHow@users.noreply.github.com> Agent-Logs-Url: https://github.com/ChangeHow/suitup/sessions/bfe1710a-bb2a-4949-9f4a-b18a8817da35 --- src/setup.js | 51 +++++++++++++++++++++++++++++++++++++-------- tests/setup.test.js | 26 ++++++++++++++++++----- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/setup.js b/src/setup.js index f931490..76e4ad2 100644 --- a/src/setup.js +++ b/src/setup.js @@ -19,17 +19,50 @@ import { commandExists } from "./utils/shell.js"; import { isZshShell } from "./utils/shell-context.js"; export { isZshShell } from "./utils/shell-context.js"; -export const SUITUP_ASCII_LOGO = String.raw` - _____ _ __ - / ___/__ __(_) /___ ______ - \__ \/ / / / / __/ / / / __ \ - ___/ / /_/ / / /_/ /_/ / /_/ / -/____/\__,_/_/\__/\__,_/ .___/ - /_/ -`.trim(); +export const SUITUP_PIXEL_LOGO = [ + "gddwwddwwddg", + "gddwwwwwwddg", + "ggdwwdwwddgg", + "ggdwwrwwddgg", + "ggdwrwrwddgg", + "ggdwwrwwddgg", + "ggdwrwrwddgg", + "gggdwwrwddgg", + "gggdwrpppwgg", + "gggdrrpppwgs", + "gggddrpppwgg", +]; + +function colorize256(code, text) { + return `\x1b[38;5;${code}m${text}\x1b[0m`; +} + +function renderPixel(pixel) { + switch (pixel) { + case "g": + return colorize256(245, "██"); + case "d": + return colorize256(236, "██"); + case "w": + return colorize256(255, "██"); + case "r": + return colorize256(202, "██"); + case "p": + return colorize256(224, "██"); + case "s": + return colorize256(255, "● "); + default: + return " "; + } +} + +export function getWelcomeLogo() { + const renderRow = (row) => [...row].map(renderPixel).join(""); + return SUITUP_PIXEL_LOGO.map(renderRow).join("\n"); +} export function getWelcomeMessage() { - return `${pc.cyan(SUITUP_ASCII_LOGO)}\n${pc.bgCyan(pc.black(" Suit up! "))}`; + return `${getWelcomeLogo()}\n${pc.bgCyan(pc.black(" Suit up! "))}`; } export function getRecommendedCliToolValues() { diff --git a/tests/setup.test.js b/tests/setup.test.js index 8be6d4b..5f7c633 100644 --- a/tests/setup.test.js +++ b/tests/setup.test.js @@ -17,7 +17,9 @@ import { getInitialStepValues, getRecommendedAppValues, getRecommendedCliToolValues, + getWelcomeLogo, getWelcomeMessage, + SUITUP_PIXEL_LOGO, isZshShell, } from "../src/setup.js"; @@ -164,12 +166,26 @@ describe("Setup simulation in sandbox", () => { ]); }); - test("welcome message includes the ASCII suitup mark", () => { - const message = getWelcomeMessage(); + test("pixel-art welcome logo uses the expected template", () => { + expect(SUITUP_PIXEL_LOGO).toHaveLength(11); + expect(SUITUP_PIXEL_LOGO.every((row) => row.length === 12)).toBe(true); + expect(SUITUP_PIXEL_LOGO.join("")).toMatch(/^[gdwrps]+$/); + expect(SUITUP_PIXEL_LOGO.some((row) => row.includes("s"))).toBe(true); + expect(SUITUP_PIXEL_LOGO.some((row) => row.includes("ppp"))).toBe(true); + expect(SUITUP_PIXEL_LOGO.some((row) => row.includes("rr"))).toBe(true); + }); - expect(message).toContain("_____ _ __"); - expect(message).toContain("/ ___/__ __(_) /___ ______"); - expect(message).toContain("/____/\\__,_/_/\\__/\\__,_/ .___/"); + test("pixel-art welcome logo renders colored blocks and the status dot", () => { + const logo = getWelcomeLogo(); + expect(logo).toContain("\u001b[38;5;255m"); + expect(logo).toContain("\u001b[38;5;236m"); + expect(logo).toContain("\u001b[38;5;202m"); + expect(logo).toContain("\u001b[38;5;224m"); + expect(logo).toContain("\u001b[38;5;255m● "); + }); + + test("welcome message displays the suit up badge below the logo", () => { + const message = getWelcomeMessage(); expect(message).toContain("Suit up!"); }); From e4f5df3453c8f3a5ce178691f0f5a8661f8abe9a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:00:16 +0000 Subject: [PATCH 4/4] test: use inline snapshots for welcome logo Co-authored-by: ChangeHow <23733347+ChangeHow@users.noreply.github.com> Agent-Logs-Url: https://github.com/ChangeHow/suitup/sessions/c4e7b073-da73-448f-9d4a-fed78817c3ea --- tests/setup.test.js | 53 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/tests/setup.test.js b/tests/setup.test.js index 5f7c633..8e52e6d 100644 --- a/tests/setup.test.js +++ b/tests/setup.test.js @@ -24,6 +24,7 @@ import { } from "../src/setup.js"; const CONFIGS_DIR = join(import.meta.dirname, "..", "configs"); +const ANSI_COLOR_CODE_PATTERN = /\u001b\[[0-9;]*m/g; describe("Setup simulation in sandbox", () => { let sandbox; @@ -167,21 +168,51 @@ describe("Setup simulation in sandbox", () => { }); test("pixel-art welcome logo uses the expected template", () => { - expect(SUITUP_PIXEL_LOGO).toHaveLength(11); - expect(SUITUP_PIXEL_LOGO.every((row) => row.length === 12)).toBe(true); - expect(SUITUP_PIXEL_LOGO.join("")).toMatch(/^[gdwrps]+$/); - expect(SUITUP_PIXEL_LOGO.some((row) => row.includes("s"))).toBe(true); - expect(SUITUP_PIXEL_LOGO.some((row) => row.includes("ppp"))).toBe(true); - expect(SUITUP_PIXEL_LOGO.some((row) => row.includes("rr"))).toBe(true); + expect(SUITUP_PIXEL_LOGO).toMatchInlineSnapshot(` + [ + "gddwwddwwddg", + "gddwwwwwwddg", + "ggdwwdwwddgg", + "ggdwwrwwddgg", + "ggdwrwrwddgg", + "ggdwwrwwddgg", + "ggdwrwrwddgg", + "gggdwwrwddgg", + "gggdwrpppwgg", + "gggdrrpppwgs", + "gggddrpppwgg", + ] + `); }); test("pixel-art welcome logo renders colored blocks and the status dot", () => { const logo = getWelcomeLogo(); - expect(logo).toContain("\u001b[38;5;255m"); - expect(logo).toContain("\u001b[38;5;236m"); - expect(logo).toContain("\u001b[38;5;202m"); - expect(logo).toContain("\u001b[38;5;224m"); - expect(logo).toContain("\u001b[38;5;255m● "); + const expectedPixels = [ + "\u001b[38;5;245m██\u001b[0m", + "\u001b[38;5;236m██\u001b[0m", + "\u001b[38;5;255m██\u001b[0m", + "\u001b[38;5;202m██\u001b[0m", + "\u001b[38;5;224m██\u001b[0m", + "\u001b[38;5;255m● \u001b[0m", + ]; + + expect(logo.replace(ANSI_COLOR_CODE_PATTERN, "")).toMatchInlineSnapshot(` + "████████████████████████ + ████████████████████████ + ████████████████████████ + ████████████████████████ + ████████████████████████ + ████████████████████████ + ████████████████████████ + ████████████████████████ + ████████████████████████ + ██████████████████████● + ████████████████████████" + `); + + for (const pixel of expectedPixels) { + expect(logo).toContain(pixel); + } }); test("welcome message displays the suit up badge below the logo", () => {