braeburn 1.2.3 → 1.3.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/README.md +15 -2
- package/dist/commands/config.js +6 -3
- package/dist/commands/setup.js +14 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +12 -0
- package/dist/index.js +10 -6
- package/dist/steps/cleanup.js +1 -0
- package/dist/steps/dotnet.js +1 -0
- package/dist/steps/homebrew.js +1 -0
- package/dist/steps/index.d.ts +2 -0
- package/dist/steps/macos.js +1 -0
- package/dist/steps/mas.js +1 -0
- package/dist/steps/npm.js +1 -0
- package/dist/steps/nvm.js +1 -0
- package/dist/steps/ohmyzsh.js +1 -0
- package/dist/steps/pip.js +1 -0
- package/dist/steps/pyenv.js +1 -0
- package/dist/ui/header.js +21 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/braeburn)
|
|
4
4
|
|
|
5
|
-
A macOS system updater CLI.
|
|
5
|
+
A macOS system updater CLI. Keeps tools installed via Homebrew, npm, pip, .NET, and others up to date.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -30,7 +30,20 @@ braeburn homebrew npm # run specific steps only
|
|
|
30
30
|
|
|
31
31
|
## Steps
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Steps run in two stages. The runtime stage runs first and is **off by default** — upgrading a runtime is a larger change than upgrading a tool, and is best done intentionally.
|
|
34
|
+
|
|
35
|
+
| Step | Stage | Default | Requires |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| `pyenv` | runtime | off | `pyenv` or Homebrew |
|
|
38
|
+
| `nvm` | runtime | off | `~/.nvm` |
|
|
39
|
+
| `homebrew` | tools | on | `brew` (required) |
|
|
40
|
+
| `mas` | tools | on | `mas` |
|
|
41
|
+
| `ohmyzsh` | tools | on | `~/.oh-my-zsh` |
|
|
42
|
+
| `npm` | tools | on | `npm` |
|
|
43
|
+
| `pip` | tools | on | `pip3` |
|
|
44
|
+
| `dotnet` | tools | on | `dotnet` |
|
|
45
|
+
| `macos` | tools | on | — |
|
|
46
|
+
| `cleanup` | tools | on | `brew` |
|
|
34
47
|
|
|
35
48
|
## Requirements
|
|
36
49
|
|
package/dist/commands/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { readConfig, writeConfig, resolveConfigPath, isSettingEnabled, isStepEnabled, isLogoEnabled, applySettingToConfig, PROTECTED_STEP_IDS, } from "../config.js";
|
|
2
|
+
import { readConfig, writeConfig, resolveConfigPath, isSettingEnabled, isStepEnabled, isLogoEnabled, applySettingToConfig, PROTECTED_STEP_IDS, DEFAULT_OFF_STEP_IDS, } from "../config.js";
|
|
3
3
|
export async function runConfigCommand(options) {
|
|
4
4
|
const { allSteps } = options;
|
|
5
5
|
const config = await readConfig();
|
|
@@ -76,10 +76,13 @@ export async function runConfigUpdateCommand(options) {
|
|
|
76
76
|
}
|
|
77
77
|
async function writeCleanConfig(config) {
|
|
78
78
|
const cleaned = { steps: {} };
|
|
79
|
-
for (const [stepId,
|
|
80
|
-
if (
|
|
79
|
+
for (const [stepId, value] of Object.entries(config.steps)) {
|
|
80
|
+
if (value === false && !DEFAULT_OFF_STEP_IDS.has(stepId)) {
|
|
81
81
|
cleaned.steps[stepId] = false;
|
|
82
82
|
}
|
|
83
|
+
else if (value === true && DEFAULT_OFF_STEP_IDS.has(stepId)) {
|
|
84
|
+
cleaned.steps[stepId] = true;
|
|
85
|
+
}
|
|
83
86
|
}
|
|
84
87
|
if (config.logo === false) {
|
|
85
88
|
cleaned.logo = false;
|
package/dist/commands/setup.js
CHANGED
|
@@ -27,9 +27,22 @@ export function buildSetupScreen(items, cursorIndex) {
|
|
|
27
27
|
` ${chalk.dim("\u2191\u2193 navigate Space toggle Return confirm")}`,
|
|
28
28
|
"",
|
|
29
29
|
];
|
|
30
|
+
const hasRuntimeItems = items.some((item) => item.step.stage === "runtime");
|
|
31
|
+
const hasToolsItems = items.some((item) => item.step.stage === "tools");
|
|
32
|
+
const showStageLabels = hasRuntimeItems && hasToolsItems;
|
|
30
33
|
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
|
|
31
34
|
const item = items[itemIndex];
|
|
32
35
|
const isCursor = itemIndex === cursorIndex;
|
|
36
|
+
if (showStageLabels) {
|
|
37
|
+
const isFirstRuntime = item.step.stage === "runtime" && (itemIndex === 0 || items[itemIndex - 1].step.stage !== "runtime");
|
|
38
|
+
const isFirstTools = item.step.stage === "tools" && (itemIndex === 0 || items[itemIndex - 1].step.stage !== "tools");
|
|
39
|
+
if (isFirstRuntime) {
|
|
40
|
+
lines.push(` ${chalk.dim("── Runtimes ─────────────────────────────────────────────────────────")}`);
|
|
41
|
+
}
|
|
42
|
+
else if (isFirstTools) {
|
|
43
|
+
lines.push(` ${chalk.dim("── Tools ────────────────────────────────────────────────────────────")}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
33
46
|
const cursor = isCursor ? chalk.cyan("\u203a") : " ";
|
|
34
47
|
const checkbox = item.selection === "selected" ? chalk.green("\u25cf") : chalk.dim("\u25cb");
|
|
35
48
|
const namePadded = item.step.name.padEnd(18);
|
|
@@ -65,7 +78,7 @@ export async function runSetupCommand(allSteps) {
|
|
|
65
78
|
const availabilityResults = await Promise.all(allSteps.map((step) => step.checkIsAvailable()));
|
|
66
79
|
const items = allSteps.map((step, stepIndex) => ({
|
|
67
80
|
step,
|
|
68
|
-
selection: "selected",
|
|
81
|
+
selection: PROTECTED_STEP_IDS.has(step.id) || step.stage === "tools" ? "selected" : "deselected",
|
|
69
82
|
protection: PROTECTED_STEP_IDS.has(step.id) ? "protected" : "configurable",
|
|
70
83
|
availability: availabilityResults[stepIndex] ? "available" : "unavailable",
|
|
71
84
|
}));
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { parse, stringify } from "smol-toml";
|
|
5
5
|
export const PROTECTED_STEP_IDS = new Set(["homebrew"]);
|
|
6
|
+
export const DEFAULT_OFF_STEP_IDS = new Set(["nvm", "pyenv"]);
|
|
6
7
|
const EMPTY_CONFIG = { steps: {} };
|
|
7
8
|
const LOGO_SETTING_ID = "logo";
|
|
8
9
|
async function pathExists(targetPath) {
|
|
@@ -46,6 +47,8 @@ export function isSettingEnabled(config, settingId) {
|
|
|
46
47
|
return true;
|
|
47
48
|
if (settingId === LOGO_SETTING_ID)
|
|
48
49
|
return config.logo !== false;
|
|
50
|
+
if (DEFAULT_OFF_STEP_IDS.has(settingId))
|
|
51
|
+
return config.steps[settingId] === true;
|
|
49
52
|
return config.steps[settingId] !== false;
|
|
50
53
|
}
|
|
51
54
|
export function isStepEnabled(config, stepId) {
|
|
@@ -65,6 +68,15 @@ export function applySettingToConfig(config, settingId, desiredState) {
|
|
|
65
68
|
}
|
|
66
69
|
return updatedConfig;
|
|
67
70
|
}
|
|
71
|
+
if (DEFAULT_OFF_STEP_IDS.has(settingId)) {
|
|
72
|
+
if (desiredState === "enable") {
|
|
73
|
+
updatedConfig.steps[settingId] = true;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
delete updatedConfig.steps[settingId];
|
|
77
|
+
}
|
|
78
|
+
return updatedConfig;
|
|
79
|
+
}
|
|
68
80
|
if (desiredState === "enable") {
|
|
69
81
|
delete updatedConfig.steps[settingId];
|
|
70
82
|
}
|
package/dist/index.js
CHANGED
|
@@ -10,13 +10,13 @@ import { runConfigCommand, runConfigUpdateCommand } from "./commands/config.js";
|
|
|
10
10
|
import { runSetupCommand } from "./commands/setup.js";
|
|
11
11
|
import { readConfig, isStepEnabled, isLogoEnabled, PROTECTED_STEP_IDS, configFileExists } from "./config.js";
|
|
12
12
|
const ALL_STEPS = [
|
|
13
|
+
pyenvStep,
|
|
14
|
+
nvmStep,
|
|
13
15
|
homebrewStep,
|
|
14
16
|
masStep,
|
|
15
17
|
ohmyzshStep,
|
|
16
18
|
npmStep,
|
|
17
19
|
pipStep,
|
|
18
|
-
pyenvStep,
|
|
19
|
-
nvmStep,
|
|
20
20
|
dotnetStep,
|
|
21
21
|
macosStep,
|
|
22
22
|
cleanupStep,
|
|
@@ -40,23 +40,27 @@ program
|
|
|
40
40
|
.option("--no-logo", "Hide the logo")
|
|
41
41
|
.addHelpText("after", `
|
|
42
42
|
Step descriptions:
|
|
43
|
+
Runtime stage (default: off — update the version managers and runtimes themselves):
|
|
44
|
+
pyenv Upgrade pyenv, install latest Python 3.x (requires: pyenv or brew)
|
|
45
|
+
nvm Install latest Node.js via nvm (requires: ~/.nvm)
|
|
46
|
+
|
|
47
|
+
Tools stage (default: on — update packages installed via the managers above):
|
|
43
48
|
homebrew Update Homebrew itself and all installed formulae
|
|
44
49
|
mas Upgrade Mac App Store apps (requires: mas)
|
|
45
50
|
ohmyzsh Update Oh My Zsh (requires: ~/.oh-my-zsh)
|
|
46
51
|
npm Update global npm packages (requires: npm)
|
|
47
52
|
pip Update global pip3 packages (requires: pip3) ⚠ may be fragile
|
|
48
|
-
pyenv Upgrade pyenv, install latest Python 3.x (requires: pyenv or brew)
|
|
49
|
-
nvm Update Node.js via nvm (requires: ~/.nvm)
|
|
50
53
|
dotnet Update .NET global tools (requires: dotnet)
|
|
51
54
|
macos Check for macOS updates, prompt to install
|
|
52
55
|
cleanup Clean up Homebrew cache and old downloads
|
|
53
56
|
|
|
54
57
|
Examples:
|
|
55
|
-
braeburn Run all steps interactively
|
|
56
|
-
braeburn -y Run all steps, auto-accept everything
|
|
58
|
+
braeburn Run all enabled steps interactively
|
|
59
|
+
braeburn -y Run all enabled steps, auto-accept everything
|
|
57
60
|
braeburn -fy Same as above
|
|
58
61
|
braeburn homebrew npm Run only the homebrew and npm steps
|
|
59
62
|
braeburn homebrew -y Run only homebrew, auto-accept
|
|
63
|
+
braeburn nvm pyenv Run only the runtime-stage steps
|
|
60
64
|
`)
|
|
61
65
|
.action(async (stepArguments, options) => {
|
|
62
66
|
const autoYes = options.yes === true || options.force === true;
|
package/dist/steps/cleanup.js
CHANGED
package/dist/steps/dotnet.js
CHANGED
package/dist/steps/homebrew.js
CHANGED
|
@@ -2,6 +2,7 @@ import { checkCommandExists } from "./index.js";
|
|
|
2
2
|
const homebrewStep = {
|
|
3
3
|
id: "homebrew",
|
|
4
4
|
name: "Homebrew",
|
|
5
|
+
stage: "tools",
|
|
5
6
|
description: "Update Homebrew itself and upgrade all installed formulae",
|
|
6
7
|
async checkIsAvailable() {
|
|
7
8
|
return checkCommandExists("brew");
|
package/dist/steps/index.d.ts
CHANGED
|
@@ -8,10 +8,12 @@ export type StepRunContext = {
|
|
|
8
8
|
shellCommand: string;
|
|
9
9
|
}) => Promise<string>;
|
|
10
10
|
};
|
|
11
|
+
export type StepStage = "runtime" | "tools";
|
|
11
12
|
export type Step = {
|
|
12
13
|
id: string;
|
|
13
14
|
name: string;
|
|
14
15
|
description: string;
|
|
16
|
+
stage: StepStage;
|
|
15
17
|
warning?: string;
|
|
16
18
|
brewPackageToInstall?: string;
|
|
17
19
|
checkIsAvailable: () => Promise<boolean>;
|
package/dist/steps/macos.js
CHANGED
package/dist/steps/mas.js
CHANGED
package/dist/steps/npm.js
CHANGED
package/dist/steps/nvm.js
CHANGED
|
@@ -8,6 +8,7 @@ const NVM_SOURCE_PREFIX = `export NVM_DIR="${NVM_DIRECTORY}" && source "$NVM_DIR
|
|
|
8
8
|
const nvmStep = {
|
|
9
9
|
id: "nvm",
|
|
10
10
|
name: "Node.js (nvm)",
|
|
11
|
+
stage: "runtime",
|
|
11
12
|
description: "Install the latest Node.js via nvm, migrating packages from the current version",
|
|
12
13
|
async checkIsAvailable() {
|
|
13
14
|
return checkPathExists(NVM_DIRECTORY);
|
package/dist/steps/ohmyzsh.js
CHANGED
|
@@ -5,6 +5,7 @@ const OH_MY_ZSH_UPGRADE_SCRIPT_PATH = join(homedir(), ".oh-my-zsh", "tools", "up
|
|
|
5
5
|
const ohmyzshStep = {
|
|
6
6
|
id: "ohmyzsh",
|
|
7
7
|
name: "Oh My Zsh",
|
|
8
|
+
stage: "tools",
|
|
8
9
|
description: "Update Oh My Zsh to the latest version",
|
|
9
10
|
async checkIsAvailable() {
|
|
10
11
|
return checkPathExists(OH_MY_ZSH_UPGRADE_SCRIPT_PATH);
|
package/dist/steps/pip.js
CHANGED
|
@@ -3,6 +3,7 @@ const PIP_UPDATE_ALL_OUTDATED_SHELL_COMMAND = "pip3 list --outdated --format=col
|
|
|
3
3
|
const pipStep = {
|
|
4
4
|
id: "pip",
|
|
5
5
|
name: "pip3",
|
|
6
|
+
stage: "tools",
|
|
6
7
|
description: "Update all globally installed pip3 packages",
|
|
7
8
|
warning: "This updates all global pip3 packages, which can occasionally break tools.",
|
|
8
9
|
async checkIsAvailable() {
|
package/dist/steps/pyenv.js
CHANGED
|
@@ -3,6 +3,7 @@ const FIND_LATEST_STABLE_PYTHON_SHELL_COMMAND = "pyenv install -l | grep -E '^\\
|
|
|
3
3
|
const pyenvStep = {
|
|
4
4
|
id: "pyenv",
|
|
5
5
|
name: "pyenv",
|
|
6
|
+
stage: "runtime",
|
|
6
7
|
description: "Upgrade pyenv via Homebrew and install the latest Python 3.x",
|
|
7
8
|
brewPackageToInstall: "pyenv",
|
|
8
9
|
async checkIsAvailable() {
|
package/dist/ui/header.js
CHANGED
|
@@ -48,15 +48,31 @@ export function deriveAllStepPhases(steps, currentStepIndex, currentPhase, compl
|
|
|
48
48
|
export function buildHeaderLines(options) {
|
|
49
49
|
const { steps, version, logoVisibility, currentStepIndex, currentPhase, completedStepRecords } = options;
|
|
50
50
|
const phases = deriveAllStepPhases(steps, currentStepIndex, currentPhase, completedStepRecords);
|
|
51
|
+
const hasRuntimeSteps = steps.some((step) => step.stage === "runtime");
|
|
52
|
+
const hasToolsSteps = steps.some((step) => step.stage === "tools");
|
|
53
|
+
const showStageLabels = hasRuntimeSteps && hasToolsSteps;
|
|
54
|
+
const stepLines = [];
|
|
55
|
+
for (let stepIndex = 0; stepIndex < steps.length; stepIndex++) {
|
|
56
|
+
const step = steps[stepIndex];
|
|
57
|
+
if (showStageLabels) {
|
|
58
|
+
const isFirstRuntime = step.stage === "runtime" && (stepIndex === 0 || steps[stepIndex - 1].stage !== "runtime");
|
|
59
|
+
const isFirstTools = step.stage === "tools" && (stepIndex === 0 || steps[stepIndex - 1].stage !== "tools");
|
|
60
|
+
if (isFirstRuntime) {
|
|
61
|
+
stepLines.push(chalk.dim("Runtimes"));
|
|
62
|
+
}
|
|
63
|
+
else if (isFirstTools) {
|
|
64
|
+
stepLines.push(chalk.dim("Tools"));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const icon = stepTrackerIcon(phases[stepIndex]);
|
|
68
|
+
const name = isActivePhase(phases[stepIndex]) ? chalk.white(step.name) : chalk.dim(step.name);
|
|
69
|
+
stepLines.push(`${icon}${name}`);
|
|
70
|
+
}
|
|
51
71
|
const rightColumnLines = [
|
|
52
72
|
`${chalk.bold.white("braeburn")} ${chalk.dim("v" + version)}`,
|
|
53
73
|
chalk.dim("macOS system updater"),
|
|
54
74
|
"",
|
|
55
|
-
...
|
|
56
|
-
const icon = stepTrackerIcon(phases[index]);
|
|
57
|
-
const name = isActivePhase(phases[index]) ? chalk.white(step.name) : chalk.dim(step.name);
|
|
58
|
-
return `${icon}${name}`;
|
|
59
|
-
}),
|
|
75
|
+
...stepLines,
|
|
60
76
|
];
|
|
61
77
|
if (logoVisibility === "hidden") {
|
|
62
78
|
return rightColumnLines;
|