braeburn 1.2.0 → 1.2.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.
@@ -4,6 +4,7 @@ type RunConfigCommandOptions = {
4
4
  };
5
5
  type RunConfigUpdateCommandOptions = {
6
6
  stepUpdates: Record<string, boolean>;
7
+ logoUpdate: boolean | undefined;
7
8
  allSteps: Step[];
8
9
  };
9
10
  export declare function runConfigCommand(options: RunConfigCommandOptions): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import chalk from "chalk";
2
- import { readConfig, writeConfig, resolveConfigPath, isStepEnabled, PROTECTED_STEP_IDS, } from "../config.js";
2
+ import { readConfig, writeConfig, resolveConfigPath, isStepEnabled, isLogoEnabled, PROTECTED_STEP_IDS, } from "../config.js";
3
3
  export async function runConfigCommand(options) {
4
4
  const { allSteps } = options;
5
5
  const config = await readConfig();
@@ -9,6 +9,9 @@ export async function runConfigCommand(options) {
9
9
  process.stdout.write(`Config: ${chalk.dim(configPath)}\n\n`);
10
10
  process.stdout.write(`${"Step".padEnd(STEP_COL)}Status\n`);
11
11
  process.stdout.write(`${DIVIDER}\n`);
12
+ const logoEnabled = isLogoEnabled(config);
13
+ process.stdout.write(`${"logo".padEnd(STEP_COL)}${logoEnabled ? chalk.green("enabled") : chalk.red("disabled")}\n`);
14
+ process.stdout.write(`${DIVIDER}\n`);
12
15
  for (const step of allSteps) {
13
16
  const isProtected = PROTECTED_STEP_IDS.has(step.id);
14
17
  const enabled = isStepEnabled(config, step.id);
@@ -27,10 +30,13 @@ export async function runConfigCommand(options) {
27
30
  process.stdout.write(`\n`);
28
31
  }
29
32
  export async function runConfigUpdateCommand(options) {
30
- const { stepUpdates, allSteps } = options;
31
- if (Object.keys(stepUpdates).length === 0) {
33
+ const { stepUpdates, logoUpdate, allSteps } = options;
34
+ if (Object.keys(stepUpdates).length === 0 && logoUpdate === undefined) {
32
35
  const configurableSteps = allSteps.filter((s) => !PROTECTED_STEP_IDS.has(s.id));
33
36
  process.stdout.write("No changes — pass flags to enable or disable steps:\n\n");
37
+ process.stdout.write(` ${"--no-logo".padEnd(18)} hide the logo\n`);
38
+ process.stdout.write(` ${"--logo".padEnd(18)} show the logo\n`);
39
+ process.stdout.write("\n");
34
40
  for (const step of configurableSteps) {
35
41
  process.stdout.write(` ${`--no-${step.id}`.padEnd(18)} disable ${step.name}\n`);
36
42
  }
@@ -43,10 +49,22 @@ export async function runConfigUpdateCommand(options) {
43
49
  }
44
50
  const config = await readConfig();
45
51
  const changes = [];
52
+ if (logoUpdate !== undefined) {
53
+ const currentlyEnabled = isLogoEnabled(config);
54
+ if (currentlyEnabled !== logoUpdate) {
55
+ changes.push({ label: "logo", from: currentlyEnabled, to: logoUpdate });
56
+ }
57
+ if (logoUpdate) {
58
+ delete config.logo;
59
+ }
60
+ else {
61
+ config.logo = false;
62
+ }
63
+ }
46
64
  for (const [stepId, newEnabled] of Object.entries(stepUpdates)) {
47
65
  const currentlyEnabled = isStepEnabled(config, stepId);
48
66
  if (currentlyEnabled !== newEnabled) {
49
- changes.push({ stepId, from: currentlyEnabled, to: newEnabled });
67
+ changes.push({ label: stepId, from: currentlyEnabled, to: newEnabled });
50
68
  }
51
69
  if (newEnabled) {
52
70
  // Re-enabling: remove from config so absent = enabled (keeps file minimal)
@@ -62,10 +80,10 @@ export async function runConfigUpdateCommand(options) {
62
80
  process.stdout.write("No changes — already set as requested.\n");
63
81
  return;
64
82
  }
65
- for (const { stepId, from, to } of changes) {
83
+ for (const { label, from, to } of changes) {
66
84
  const fromLabel = from ? chalk.green("enabled") : chalk.red("disabled");
67
85
  const toLabel = to ? chalk.green("enabled") : chalk.red("disabled");
68
- process.stdout.write(` ${stepId.padEnd(12)} ${fromLabel} → ${toLabel}\n`);
86
+ process.stdout.write(` ${label.padEnd(12)} ${fromLabel} → ${toLabel}\n`);
69
87
  }
70
88
  const configPath = await resolveConfigPath();
71
89
  process.stdout.write(`\nConfig saved to ${chalk.dim(configPath)}\n`);
@@ -77,5 +95,8 @@ async function writeCleanConfig(config) {
77
95
  cleaned.steps[stepId] = false;
78
96
  }
79
97
  }
98
+ if (config.logo === false) {
99
+ cleaned.logo = false;
100
+ }
80
101
  await writeConfig(cleaned);
81
102
  }
@@ -2,6 +2,7 @@ import type { Step } from "../steps/index.js";
2
2
  type RunUpdateCommandOptions = {
3
3
  steps: Step[];
4
4
  autoYes: boolean;
5
+ showLogo: boolean;
5
6
  version: string;
6
7
  };
7
8
  export declare function runUpdateCommand(options: RunUpdateCommandOptions): Promise<void>;
@@ -7,7 +7,7 @@ import { buildScreen, renderScreen } from "../ui/screen.js";
7
7
  export async function runUpdateCommand(options) {
8
8
  const { steps, version } = options;
9
9
  let autoYes = options.autoYes;
10
- const state = createInitialAppState(steps, version);
10
+ const state = createInitialAppState(steps, version, options.showLogo);
11
11
  process.stdout.write("\x1b[?25l");
12
12
  process.on("exit", () => process.stdout.write("\x1b[?25h"));
13
13
  process.on("SIGINT", () => {
package/dist/config.d.ts CHANGED
@@ -2,9 +2,11 @@
2
2
  export declare const PROTECTED_STEP_IDS: Set<string>;
3
3
  export type BraeburnConfig = {
4
4
  steps: Record<string, boolean>;
5
+ logo?: boolean;
5
6
  };
6
7
  export declare function resolveConfigPath(): Promise<string>;
7
8
  export declare function configFileExists(): Promise<boolean>;
8
9
  export declare function readConfig(): Promise<BraeburnConfig>;
9
10
  export declare function writeConfig(config: BraeburnConfig): Promise<void>;
10
11
  export declare function isStepEnabled(config: BraeburnConfig, stepId: string): boolean;
12
+ export declare function isLogoEnabled(config: BraeburnConfig): boolean;
package/dist/config.js CHANGED
@@ -30,7 +30,7 @@ export async function readConfig() {
30
30
  try {
31
31
  const raw = await readFile(configPath, "utf-8");
32
32
  const parsed = parse(raw);
33
- return { steps: parsed.steps ?? {} };
33
+ return { steps: parsed.steps ?? {}, logo: parsed.logo };
34
34
  }
35
35
  catch {
36
36
  return structuredClone(EMPTY_CONFIG);
@@ -47,3 +47,7 @@ export function isStepEnabled(config, stepId) {
47
47
  // Absent from config means enabled (opt-out model)
48
48
  return config.steps[stepId] !== false;
49
49
  }
50
+ export function isLogoEnabled(config) {
51
+ // Absent from config means enabled (opt-out model)
52
+ return config.logo !== false;
53
+ }
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { runUpdateCommand } from "./commands/update.js";
8
8
  import { runLogCommand, runLogListCommand } from "./commands/log.js";
9
9
  import { runConfigCommand, runConfigUpdateCommand } from "./commands/config.js";
10
10
  import { runSetupCommand } from "./commands/setup.js";
11
- import { readConfig, isStepEnabled, PROTECTED_STEP_IDS, configFileExists } from "./config.js";
11
+ import { readConfig, isStepEnabled, isLogoEnabled, PROTECTED_STEP_IDS, configFileExists } from "./config.js";
12
12
  const ALL_STEPS = [
13
13
  homebrewStep,
14
14
  masStep,
@@ -37,6 +37,7 @@ program
37
37
  .argument("[steps...]", `Steps to run — omit to run all.\nAvailable: ${ALL_STEPS.map((s) => s.id).join(", ")}`)
38
38
  .option("-y, --yes", "Auto-accept all prompts (default yes to everything)")
39
39
  .option("-f, --force", "Alias for --yes")
40
+ .option("--no-logo", "Hide the logo")
40
41
  .addHelpText("after", `
41
42
  Step descriptions:
42
43
  homebrew Update Homebrew itself and all installed formulae
@@ -63,18 +64,21 @@ Examples:
63
64
  if (!(await configFileExists())) {
64
65
  await runSetupCommand(ALL_STEPS);
65
66
  }
67
+ const config = await readConfig();
66
68
  let stepsToRun = stepArguments.length === 0
67
69
  ? ALL_STEPS
68
70
  : resolveStepsByIds(stepArguments);
69
71
  // When no explicit steps are requested, filter out steps disabled in config.
70
72
  // Explicit step arguments always bypass config (user knows what they want).
71
73
  if (stepArguments.length === 0) {
72
- const config = await readConfig();
73
74
  stepsToRun = stepsToRun.filter((step) => isStepEnabled(config, step.id));
74
75
  }
76
+ // CLI --no-logo overrides config; otherwise defer to config preference.
77
+ const showLogo = options.logo !== false && isLogoEnabled(config);
75
78
  await runUpdateCommand({
76
79
  steps: stepsToRun,
77
80
  autoYes,
81
+ showLogo,
78
82
  version: BRAEBURN_VERSION,
79
83
  });
80
84
  });
@@ -120,10 +124,13 @@ const configUpdateCommand = configCommand
120
124
  .description("Enable or disable individual update steps")
121
125
  .addHelpText("after", `
122
126
  Examples:
127
+ braeburn config update --no-logo Hide the logo
123
128
  braeburn config update --no-ohmyzsh Disable Oh My Zsh updates
124
129
  braeburn config update --no-pip --no-nvm Disable pip and nvm updates
125
130
  braeburn config update --ohmyzsh Re-enable Oh My Zsh updates
126
131
  `);
132
+ configUpdateCommand.option(`--no-logo`, `Hide the logo`);
133
+ configUpdateCommand.option(`--logo`, `Show the logo`);
127
134
  for (const step of configurableSteps) {
128
135
  configUpdateCommand.option(`--no-${step.id}`, `Disable ${step.name} updates`);
129
136
  configUpdateCommand.option(`--${step.id}`, `Enable ${step.name} updates`);
@@ -138,7 +145,11 @@ configUpdateCommand.action(function () {
138
145
  stepUpdates[step.id] = configUpdateCommand.opts()[step.id];
139
146
  }
140
147
  }
141
- runConfigUpdateCommand({ stepUpdates, allSteps: ALL_STEPS });
148
+ const logoSource = configUpdateCommand.getOptionValueSource("logo");
149
+ const logoUpdate = logoSource === "cli"
150
+ ? configUpdateCommand.opts().logo
151
+ : undefined;
152
+ runConfigUpdateCommand({ stepUpdates, logoUpdate, allSteps: ALL_STEPS });
142
153
  });
143
154
  function resolveStepsByIds(stepIds) {
144
155
  const resolvedSteps = [];
package/dist/logo.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const LOGO_ART = " ; \n :x : \n .x$+x \n x+x; XXX& \n :xx&&& &&& \n +X +X x+ .::: \n ; X$$; :X$: \n $+ ;+ \n .x: : . \n :: ;+X \n +$ \n :";
1
+ export declare const LOGO_ART = " ;\n :x : \n .x$+x \n x+x; XXX& \n :xx&&& &&& \n +X +X x+ .::: \n ; X$$; :X$: \n $+ ;+ \n .x: : . \n :: ;+X \n +$ \n :";
package/dist/logo.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // The ASCII art is intentionally left-aligned with spaces as part of the design.
2
2
  // Keep the template literal formatting exactly as-is.
3
- export const LOGO_ART = ` ;
3
+ export const LOGO_ART = ` ;
4
4
  :x :
5
5
  .x\$+x
6
6
  x+x; XXX&
@@ -3,6 +3,7 @@ import type { StepPhase, CompletedStepRecord } from "./state.js";
3
3
  type BuildHeaderOptions = {
4
4
  steps: Step[];
5
5
  version: string;
6
+ showLogo: boolean;
6
7
  currentStepIndex: number;
7
8
  currentPhase: StepPhase;
8
9
  completedStepRecords: CompletedStepRecord[];
package/dist/ui/header.js CHANGED
@@ -2,6 +2,19 @@ import chalk from "chalk";
2
2
  import { LOGO_ART } from "../logo.js";
3
3
  const LOGO_COLUMN_WIDTH = 32;
4
4
  const LOGO_SEPARATOR = " ";
5
+ const MIN_SIDE_BY_SIDE_COLS = LOGO_COLUMN_WIDTH + LOGO_SEPARATOR.length + 20; // 56
6
+ function determineLogoLayout(logoLines) {
7
+ const cols = process.stdout.columns ?? 80;
8
+ const rows = process.stdout.rows ?? 24;
9
+ if (cols >= MIN_SIDE_BY_SIDE_COLS) {
10
+ return "side-by-side";
11
+ }
12
+ // Not wide enough for side-by-side — stack if there are enough rows.
13
+ if (rows >= logoLines.length + 6) {
14
+ return "stacked";
15
+ }
16
+ return "none";
17
+ }
5
18
  function stepTrackerIcon(phase) {
6
19
  if (phase === "complete")
7
20
  return chalk.green("✓ ");
@@ -34,9 +47,8 @@ function deriveAllStepPhases(steps, currentStepIndex, currentPhase, completedSte
34
47
  });
35
48
  }
36
49
  export function buildHeaderLines(options) {
37
- const { steps, version, currentStepIndex, currentPhase, completedStepRecords } = options;
50
+ const { steps, version, showLogo, currentStepIndex, currentPhase, completedStepRecords } = options;
38
51
  const phases = deriveAllStepPhases(steps, currentStepIndex, currentPhase, completedStepRecords);
39
- const logoLines = LOGO_ART.split("\n");
40
52
  const rightColumnLines = [
41
53
  `${chalk.bold.white("braeburn")} ${chalk.dim("v" + version)}`,
42
54
  chalk.dim("macOS system updater"),
@@ -47,6 +59,22 @@ export function buildHeaderLines(options) {
47
59
  return `${icon}${name}`;
48
60
  }),
49
61
  ];
62
+ if (!showLogo) {
63
+ return rightColumnLines;
64
+ }
65
+ const logoLines = LOGO_ART.split("\n");
66
+ const layout = determineLogoLayout(logoLines);
67
+ if (layout === "none") {
68
+ return rightColumnLines;
69
+ }
70
+ if (layout === "stacked") {
71
+ return [
72
+ ...logoLines.map((line) => chalk.yellow(line)),
73
+ "",
74
+ ...rightColumnLines,
75
+ ];
76
+ }
77
+ // side-by-side
50
78
  const totalLines = Math.max(logoLines.length, rightColumnLines.length);
51
79
  const result = [];
52
80
  for (let i = 0; i < totalLines; i++) {
package/dist/ui/screen.js CHANGED
@@ -16,6 +16,7 @@ export function buildScreen(state) {
16
16
  lines.push(...buildHeaderLines({
17
17
  steps: state.steps,
18
18
  version: state.version,
19
+ showLogo: state.showLogo,
19
20
  currentStepIndex: state.currentStepIndex,
20
21
  currentPhase: state.currentPhase,
21
22
  completedStepRecords: state.completedStepRecords,
@@ -16,6 +16,7 @@ export type ResolvedVersion = {
16
16
  export type AppState = {
17
17
  steps: Step[];
18
18
  version: string;
19
+ showLogo: boolean;
19
20
  currentStepIndex: number;
20
21
  currentPhase: StepPhase;
21
22
  completedStepRecords: CompletedStepRecord[];
@@ -24,4 +25,4 @@ export type AppState = {
24
25
  isFinished: boolean;
25
26
  versionReport: ResolvedVersion[] | undefined;
26
27
  };
27
- export declare function createInitialAppState(steps: Step[], version: string): AppState;
28
+ export declare function createInitialAppState(steps: Step[], version: string, showLogo: boolean): AppState;
package/dist/ui/state.js CHANGED
@@ -1,7 +1,8 @@
1
- export function createInitialAppState(steps, version) {
1
+ export function createInitialAppState(steps, version, showLogo) {
2
2
  return {
3
3
  steps,
4
4
  version,
5
+ showLogo,
5
6
  currentStepIndex: 0,
6
7
  currentPhase: "checking-availability",
7
8
  completedStepRecords: [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braeburn",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "macOS system updater CLI",
5
5
  "type": "module",
6
6
  "bin": {