@fredlackey/devutils 0.0.19 → 0.1.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 +223 -32
- package/package.json +7 -5
- package/src/api/loader.js +229 -0
- package/src/api/registry.json +62 -0
- package/src/cli.js +305 -0
- package/src/commands/ai/index.js +16 -0
- package/src/commands/ai/launch.js +112 -0
- package/src/commands/ai/list.js +54 -0
- package/src/commands/ai/resume.js +70 -0
- package/src/commands/ai/sessions.js +121 -0
- package/src/commands/ai/set.js +131 -0
- package/src/commands/ai/show.js +74 -0
- package/src/commands/ai/tools.js +46 -0
- package/src/commands/alias/add.js +93 -0
- package/src/commands/alias/helpers.js +107 -0
- package/src/commands/alias/index.js +14 -0
- package/src/commands/alias/list.js +55 -0
- package/src/commands/alias/remove.js +62 -0
- package/src/commands/alias/sync.js +109 -0
- package/src/commands/api/disable.js +73 -0
- package/src/commands/api/enable.js +148 -0
- package/src/commands/api/index.js +15 -0
- package/src/commands/api/list.js +66 -0
- package/src/commands/api/update.js +87 -0
- package/src/commands/auth/index.js +15 -0
- package/src/commands/auth/list.js +49 -0
- package/src/commands/auth/login.js +384 -0
- package/src/commands/auth/logout.js +111 -0
- package/src/commands/auth/refresh.js +184 -0
- package/src/commands/auth/services.js +169 -0
- package/src/commands/auth/status.js +104 -0
- package/src/commands/config/export.js +224 -0
- package/src/commands/config/get.js +52 -0
- package/src/commands/config/import.js +308 -0
- package/src/commands/config/index.js +17 -0
- package/src/commands/config/init.js +143 -0
- package/src/commands/config/reset.js +57 -0
- package/src/commands/config/set.js +93 -0
- package/src/commands/config/show.js +35 -0
- package/src/commands/help.js +338 -0
- package/src/commands/identity/add.js +133 -0
- package/src/commands/identity/index.js +17 -0
- package/src/commands/identity/link.js +76 -0
- package/src/commands/identity/list.js +48 -0
- package/src/commands/identity/remove.js +72 -0
- package/src/commands/identity/show.js +65 -0
- package/src/commands/identity/sync.js +172 -0
- package/src/commands/identity/unlink.js +57 -0
- package/src/commands/ignore/add.js +165 -0
- package/src/commands/ignore/index.js +14 -0
- package/src/commands/ignore/list.js +89 -0
- package/src/commands/ignore/markers.js +43 -0
- package/src/commands/ignore/remove.js +164 -0
- package/src/commands/ignore/show.js +169 -0
- package/src/commands/machine/detect.js +122 -0
- package/src/commands/machine/index.js +14 -0
- package/src/commands/machine/list.js +74 -0
- package/src/commands/machine/set.js +106 -0
- package/src/commands/machine/show.js +35 -0
- package/src/commands/schema.js +152 -0
- package/src/commands/search/collections.js +134 -0
- package/src/commands/search/get.js +71 -0
- package/src/commands/search/index-cmd.js +54 -0
- package/src/commands/search/index.js +21 -0
- package/src/commands/search/keyword.js +60 -0
- package/src/commands/search/qmd.js +70 -0
- package/src/commands/search/query.js +64 -0
- package/src/commands/search/semantic.js +62 -0
- package/src/commands/search/status.js +46 -0
- package/src/commands/status.js +276 -0
- package/src/commands/tools/check.js +79 -0
- package/src/commands/tools/index.js +14 -0
- package/src/commands/tools/install.js +110 -0
- package/src/commands/tools/list.js +91 -0
- package/src/commands/tools/search.js +60 -0
- package/src/commands/update.js +113 -0
- package/src/commands/util/add.js +151 -0
- package/src/commands/util/index.js +15 -0
- package/src/commands/util/list.js +97 -0
- package/src/commands/util/remove.js +76 -0
- package/src/commands/util/run.js +79 -0
- package/src/commands/util/show.js +67 -0
- package/src/commands/version.js +33 -0
- package/src/installers/_template.js +104 -0
- package/src/installers/git.js +150 -0
- package/src/installers/homebrew.js +190 -0
- package/src/installers/node.js +223 -0
- package/src/installers/registry.json +29 -0
- package/src/lib/config.js +125 -0
- package/src/lib/detect.js +74 -0
- package/src/lib/errors.js +114 -0
- package/src/lib/github.js +315 -0
- package/src/lib/installer.js +225 -0
- package/src/lib/output.js +239 -0
- package/src/lib/platform.js +112 -0
- package/src/lib/platforms/amazon-linux.js +41 -0
- package/src/lib/platforms/gitbash.js +46 -0
- package/src/lib/platforms/macos.js +45 -0
- package/src/lib/platforms/raspbian.js +41 -0
- package/src/lib/platforms/ubuntu.js +39 -0
- package/src/lib/platforms/windows.js +45 -0
- package/src/lib/prompt.js +161 -0
- package/src/lib/schema.js +211 -0
- package/src/lib/shell.js +75 -0
- package/src/patterns/gitignore/claude-code.txt +25 -0
- package/src/patterns/gitignore/docker.txt +15 -0
- package/src/patterns/gitignore/go.txt +24 -0
- package/src/patterns/gitignore/java.txt +38 -0
- package/src/patterns/gitignore/jetbrains.txt +26 -0
- package/src/patterns/gitignore/linux.txt +18 -0
- package/src/patterns/gitignore/macos.txt +27 -0
- package/src/patterns/gitignore/node.txt +51 -0
- package/src/patterns/gitignore/python.txt +55 -0
- package/src/patterns/gitignore/rust.txt +14 -0
- package/src/patterns/gitignore/terraform.txt +30 -0
- package/src/patterns/gitignore/vscode.txt +15 -0
- package/src/patterns/gitignore/windows.txt +25 -0
- package/src/utils/clone/index.js +165 -0
- package/src/utils/git-push/index.js +230 -0
- package/src/utils/git-status/index.js +116 -0
- package/src/utils/git-status/unix.sh +75 -0
- package/src/utils/registry.json +41 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Installer: <TOOL_NAME>
|
|
6
|
+
*
|
|
7
|
+
* Installs <TOOL_NAME> on supported platforms.
|
|
8
|
+
* See registry.json for platform support and dependencies.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if <TOOL_NAME> is already installed.
|
|
13
|
+
* @param {object} context - The CLI context object (has platform, shell, output, etc.)
|
|
14
|
+
* @returns {Promise<boolean>} true if the tool is available on the system
|
|
15
|
+
*/
|
|
16
|
+
async function isInstalled(context) {
|
|
17
|
+
// Use context.shell to check if the binary exists on the PATH.
|
|
18
|
+
// Example: return context.shell.commandExists('<binary-name>');
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Install on macOS using Homebrew.
|
|
24
|
+
* @param {object} context - The CLI context object
|
|
25
|
+
*/
|
|
26
|
+
async function install_macos(context) {
|
|
27
|
+
// Example: await context.shell.exec('brew install <tool>');
|
|
28
|
+
throw new Error('install_macos not implemented');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Install on Ubuntu using apt.
|
|
33
|
+
* @param {object} context - The CLI context object
|
|
34
|
+
*/
|
|
35
|
+
async function install_ubuntu(context) {
|
|
36
|
+
throw new Error('install_ubuntu not implemented');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Install on Raspberry Pi OS using apt.
|
|
41
|
+
* @param {object} context - The CLI context object
|
|
42
|
+
*/
|
|
43
|
+
async function install_raspbian(context) {
|
|
44
|
+
throw new Error('install_raspbian not implemented');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Install on Amazon Linux using dnf/yum.
|
|
49
|
+
* @param {object} context - The CLI context object
|
|
50
|
+
*/
|
|
51
|
+
async function install_amazon_linux(context) {
|
|
52
|
+
throw new Error('install_amazon_linux not implemented');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Install on Windows using Chocolatey or winget.
|
|
57
|
+
* @param {object} context - The CLI context object
|
|
58
|
+
*/
|
|
59
|
+
async function install_windows(context) {
|
|
60
|
+
throw new Error('install_windows not implemented');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Install in Git Bash (manual or portable install).
|
|
65
|
+
* @param {object} context - The CLI context object
|
|
66
|
+
*/
|
|
67
|
+
async function install_gitbash(context) {
|
|
68
|
+
throw new Error('install_gitbash not implemented');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Main install dispatcher. Detects the platform and calls the right function.
|
|
73
|
+
* The framework calls this -- you don't need to call it directly.
|
|
74
|
+
* @param {object} context - The CLI context object
|
|
75
|
+
*/
|
|
76
|
+
async function install(context) {
|
|
77
|
+
const platformType = context.platform.detect().type;
|
|
78
|
+
const installers = {
|
|
79
|
+
'macos': install_macos,
|
|
80
|
+
'ubuntu': install_ubuntu,
|
|
81
|
+
'raspbian': install_raspbian,
|
|
82
|
+
'amazon-linux': install_amazon_linux,
|
|
83
|
+
'windows': install_windows,
|
|
84
|
+
'gitbash': install_gitbash,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const fn = installers[platformType];
|
|
88
|
+
if (!fn) {
|
|
89
|
+
throw new Error(`No installer for platform: ${platformType}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await fn(context);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = {
|
|
96
|
+
isInstalled,
|
|
97
|
+
install,
|
|
98
|
+
install_macos,
|
|
99
|
+
install_ubuntu,
|
|
100
|
+
install_raspbian,
|
|
101
|
+
install_amazon_linux,
|
|
102
|
+
install_windows,
|
|
103
|
+
install_gitbash,
|
|
104
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Installer: git
|
|
6
|
+
*
|
|
7
|
+
* Installs git on all supported platforms.
|
|
8
|
+
* See registry.json for platform support and dependencies.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if git is already installed.
|
|
13
|
+
* @param {object} context - The CLI context object (has platform, shell, output, etc.)
|
|
14
|
+
* @returns {Promise<boolean>} true if git is available on the system
|
|
15
|
+
*/
|
|
16
|
+
async function isInstalled(context) {
|
|
17
|
+
return context.shell.commandExists('git');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the installed git version.
|
|
22
|
+
* @param {object} context - The CLI context object
|
|
23
|
+
* @returns {Promise<string|null>} Version string like '2.43.0', or null if unavailable.
|
|
24
|
+
*/
|
|
25
|
+
async function getVersion(context) {
|
|
26
|
+
try {
|
|
27
|
+
const result = await context.shell.exec('git --version');
|
|
28
|
+
// Output looks like: "git version 2.43.0" or "git version 2.43.0.windows.1"
|
|
29
|
+
const match = result.stdout.trim().match(/(\d+\.\d+\.\d+)/);
|
|
30
|
+
return match ? match[1] : null;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Install git on macOS using Homebrew.
|
|
38
|
+
* @param {object} context - The CLI context object
|
|
39
|
+
*/
|
|
40
|
+
async function install_macos(context) {
|
|
41
|
+
if (!context.shell.commandExists('brew')) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
'Homebrew is not installed. Run "dev tools install homebrew" first, or install git manually.'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
await context.shell.exec('brew install git');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Install git on Ubuntu using apt.
|
|
51
|
+
* @param {object} context - The CLI context object
|
|
52
|
+
*/
|
|
53
|
+
async function install_ubuntu(context) {
|
|
54
|
+
await context.shell.exec('sudo apt-get update');
|
|
55
|
+
await context.shell.exec('sudo apt-get install -y git');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Install git on Raspberry Pi OS using apt.
|
|
60
|
+
* @param {object} context - The CLI context object
|
|
61
|
+
*/
|
|
62
|
+
async function install_raspbian(context) {
|
|
63
|
+
await context.shell.exec('sudo apt-get update');
|
|
64
|
+
await context.shell.exec('sudo apt-get install -y git');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Install git on Amazon Linux using dnf or yum.
|
|
69
|
+
* @param {object} context - The CLI context object
|
|
70
|
+
*/
|
|
71
|
+
async function install_amazon_linux(context) {
|
|
72
|
+
const hasDnf = context.shell.commandExists('dnf');
|
|
73
|
+
if (hasDnf) {
|
|
74
|
+
await context.shell.exec('sudo dnf install -y git');
|
|
75
|
+
} else {
|
|
76
|
+
await context.shell.exec('sudo yum install -y git');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Install git on Windows using Chocolatey or winget.
|
|
82
|
+
* @param {object} context - The CLI context object
|
|
83
|
+
*/
|
|
84
|
+
async function install_windows(context) {
|
|
85
|
+
const hasChoco = context.shell.commandExists('choco');
|
|
86
|
+
const hasWinget = context.shell.commandExists('winget');
|
|
87
|
+
|
|
88
|
+
if (hasChoco) {
|
|
89
|
+
await context.shell.exec('choco install git -y');
|
|
90
|
+
} else if (hasWinget) {
|
|
91
|
+
await context.shell.exec(
|
|
92
|
+
'winget install --id Git.Git --accept-package-agreements --accept-source-agreements'
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
throw new Error(
|
|
96
|
+
'Neither Chocolatey nor winget is available. Install one of them first, or download git from https://git-scm.com'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Install git in Git Bash. Git Bash ships with git, so this is a no-op.
|
|
103
|
+
* @param {object} context - The CLI context object
|
|
104
|
+
*/
|
|
105
|
+
async function install_gitbash(context) {
|
|
106
|
+
if (await isInstalled(context)) {
|
|
107
|
+
context.output.info('Git is already available in Git Bash.');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// This shouldn't happen -- Git Bash IS git. But just in case:
|
|
111
|
+
throw new Error(
|
|
112
|
+
'Git not found in Git Bash environment. This is unexpected. Reinstall Git for Windows from https://git-scm.com'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Main install dispatcher. Detects the platform and calls the right function.
|
|
118
|
+
* The framework calls this -- you don't need to call it directly.
|
|
119
|
+
* @param {object} context - The CLI context object
|
|
120
|
+
*/
|
|
121
|
+
async function install(context) {
|
|
122
|
+
const platformType = context.platform.detect().type;
|
|
123
|
+
const installers = {
|
|
124
|
+
'macos': install_macos,
|
|
125
|
+
'ubuntu': install_ubuntu,
|
|
126
|
+
'raspbian': install_raspbian,
|
|
127
|
+
'amazon-linux': install_amazon_linux,
|
|
128
|
+
'windows': install_windows,
|
|
129
|
+
'gitbash': install_gitbash,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const fn = installers[platformType];
|
|
133
|
+
if (!fn) {
|
|
134
|
+
throw new Error(`No installer for platform: ${platformType}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
await fn(context);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
isInstalled,
|
|
142
|
+
install,
|
|
143
|
+
getVersion,
|
|
144
|
+
install_macos,
|
|
145
|
+
install_ubuntu,
|
|
146
|
+
install_raspbian,
|
|
147
|
+
install_amazon_linux,
|
|
148
|
+
install_windows,
|
|
149
|
+
install_gitbash,
|
|
150
|
+
};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Installer: homebrew
|
|
6
|
+
*
|
|
7
|
+
* Installs Homebrew on macOS. This is a macOS-only installer.
|
|
8
|
+
* All other platforms get a clear error explaining what package manager to use instead.
|
|
9
|
+
* See registry.json for platform support and dependencies.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the path to the user's shell profile file.
|
|
18
|
+
* Checks the SHELL environment variable to pick between .zshrc and .bashrc.
|
|
19
|
+
* @returns {string} Absolute path to the shell profile.
|
|
20
|
+
*/
|
|
21
|
+
function getShellProfile() {
|
|
22
|
+
const shell = process.env.SHELL || '';
|
|
23
|
+
if (shell.includes('zsh')) {
|
|
24
|
+
return path.join(os.homedir(), '.zshrc');
|
|
25
|
+
}
|
|
26
|
+
return path.join(os.homedir(), '.bashrc');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Check if Homebrew is already installed.
|
|
31
|
+
* @param {object} context - The CLI context object (has platform, shell, output, etc.)
|
|
32
|
+
* @returns {Promise<boolean>} true if brew is available on the system
|
|
33
|
+
*/
|
|
34
|
+
async function isInstalled(context) {
|
|
35
|
+
return context.shell.commandExists('brew');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the installed Homebrew version.
|
|
40
|
+
* @param {object} context - The CLI context object
|
|
41
|
+
* @returns {Promise<string|null>} Version string like '4.2.5', or null if unavailable.
|
|
42
|
+
*/
|
|
43
|
+
async function getVersion(context) {
|
|
44
|
+
try {
|
|
45
|
+
const result = await context.shell.exec('brew --version');
|
|
46
|
+
// Output looks like: "Homebrew 4.2.5"
|
|
47
|
+
const match = result.stdout.trim().match(/Homebrew\s+(\d+\.\d+\.\d+)/);
|
|
48
|
+
return match ? match[1] : null;
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Install Homebrew on macOS.
|
|
56
|
+
* Uses the official install script with NONINTERACTIVE=1 to avoid prompts.
|
|
57
|
+
* Handles Apple Silicon PATH setup automatically.
|
|
58
|
+
* @param {object} context - The CLI context object
|
|
59
|
+
*/
|
|
60
|
+
async function install_macos(context) {
|
|
61
|
+
context.output.info('Installing Homebrew...');
|
|
62
|
+
context.output.info('This may prompt for your password and take a few minutes.');
|
|
63
|
+
|
|
64
|
+
// The official Homebrew install script.
|
|
65
|
+
// NONINTERACTIVE=1 suppresses the "Press RETURN to continue" prompt.
|
|
66
|
+
await context.shell.exec(
|
|
67
|
+
'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// On Apple Silicon Macs, brew installs to /opt/homebrew and the install script
|
|
71
|
+
// tells the user to add it to their PATH. We do that here if needed.
|
|
72
|
+
const platform = context.platform.detect();
|
|
73
|
+
if (platform.arch === 'arm64') {
|
|
74
|
+
if (!context.shell.commandExists('brew')) {
|
|
75
|
+
context.output.info('Adding Homebrew to PATH for Apple Silicon...');
|
|
76
|
+
const profilePath = getShellProfile();
|
|
77
|
+
const brewInitLine = 'eval "$(/opt/homebrew/bin/brew shellenv)"';
|
|
78
|
+
|
|
79
|
+
const existing = fs.existsSync(profilePath) ? fs.readFileSync(profilePath, 'utf8') : '';
|
|
80
|
+
if (!existing.includes(brewInitLine)) {
|
|
81
|
+
fs.appendFileSync(profilePath, `\n# Homebrew\n${brewInitLine}\n`);
|
|
82
|
+
context.output.info(`Added Homebrew PATH to ${profilePath}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Verify it worked
|
|
88
|
+
if (!context.shell.commandExists('brew')) {
|
|
89
|
+
// Try the known paths directly
|
|
90
|
+
if (fs.existsSync('/opt/homebrew/bin/brew') || fs.existsSync('/usr/local/bin/brew')) {
|
|
91
|
+
context.output.info(
|
|
92
|
+
'Homebrew installed, but "brew" is not on your PATH yet. Open a new terminal or run: eval "$(/opt/homebrew/bin/brew shellenv)"'
|
|
93
|
+
);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
throw new Error('Homebrew installation failed. Check the output above for errors.');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
context.output.info('Homebrew installed successfully.');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Install on Ubuntu -- not supported. Throws a helpful error.
|
|
104
|
+
* @param {object} context - The CLI context object
|
|
105
|
+
*/
|
|
106
|
+
async function install_ubuntu(context) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
'Homebrew is only available on macOS. On Ubuntu, packages are managed with apt. ' +
|
|
109
|
+
'DevUtils uses apt automatically for Ubuntu installations.'
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Install on Raspberry Pi OS -- not supported. Throws a helpful error.
|
|
115
|
+
* @param {object} context - The CLI context object
|
|
116
|
+
*/
|
|
117
|
+
async function install_raspbian(context) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
'Homebrew is only available on macOS. On Raspberry Pi OS, packages are managed with apt. ' +
|
|
120
|
+
'DevUtils uses apt automatically for Raspberry Pi installations.'
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Install on Amazon Linux -- not supported. Throws a helpful error.
|
|
126
|
+
* @param {object} context - The CLI context object
|
|
127
|
+
*/
|
|
128
|
+
async function install_amazon_linux(context) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
'Homebrew is only available on macOS. On Amazon Linux, packages are managed with dnf/yum. ' +
|
|
131
|
+
'DevUtils uses dnf/yum automatically for Amazon Linux installations.'
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Install on Windows -- not supported. Throws a helpful error.
|
|
137
|
+
* @param {object} context - The CLI context object
|
|
138
|
+
*/
|
|
139
|
+
async function install_windows(context) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
'Homebrew is only available on macOS. On Windows, packages are managed with Chocolatey or winget. ' +
|
|
142
|
+
'DevUtils uses those automatically for Windows installations.'
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Install in Git Bash -- not supported. Throws a helpful error.
|
|
148
|
+
* @param {object} context - The CLI context object
|
|
149
|
+
*/
|
|
150
|
+
async function install_gitbash(context) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
'Homebrew is only available on macOS. In Git Bash, use the Windows package managers (Chocolatey or winget) instead.'
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Main install dispatcher. Detects the platform and calls the right function.
|
|
158
|
+
* The framework calls this -- you don't need to call it directly.
|
|
159
|
+
* @param {object} context - The CLI context object
|
|
160
|
+
*/
|
|
161
|
+
async function install(context) {
|
|
162
|
+
const platformType = context.platform.detect().type;
|
|
163
|
+
const installers = {
|
|
164
|
+
'macos': install_macos,
|
|
165
|
+
'ubuntu': install_ubuntu,
|
|
166
|
+
'raspbian': install_raspbian,
|
|
167
|
+
'amazon-linux': install_amazon_linux,
|
|
168
|
+
'windows': install_windows,
|
|
169
|
+
'gitbash': install_gitbash,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const fn = installers[platformType];
|
|
173
|
+
if (!fn) {
|
|
174
|
+
throw new Error(`No installer for platform: ${platformType}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
await fn(context);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
isInstalled,
|
|
182
|
+
install,
|
|
183
|
+
getVersion,
|
|
184
|
+
install_macos,
|
|
185
|
+
install_ubuntu,
|
|
186
|
+
install_raspbian,
|
|
187
|
+
install_amazon_linux,
|
|
188
|
+
install_windows,
|
|
189
|
+
install_gitbash,
|
|
190
|
+
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Installer: node
|
|
6
|
+
*
|
|
7
|
+
* Installs Node.js on all supported platforms.
|
|
8
|
+
* On Unix-like systems, installs via nvm (Node Version Manager).
|
|
9
|
+
* On Windows, installs directly via Chocolatey or winget.
|
|
10
|
+
* See registry.json for platform support and dependencies.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns the nvm directory path.
|
|
19
|
+
* Checks the NVM_DIR environment variable first, falls back to ~/.nvm.
|
|
20
|
+
* @returns {string} The nvm directory path.
|
|
21
|
+
*/
|
|
22
|
+
function getNvmDir() {
|
|
23
|
+
return process.env.NVM_DIR || path.join(os.homedir(), '.nvm');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Checks if nvm is installed by looking for the nvm.sh script.
|
|
28
|
+
* nvm is a shell function, not a binary, so `which nvm` won't find it.
|
|
29
|
+
* @returns {boolean} true if nvm is installed.
|
|
30
|
+
*/
|
|
31
|
+
function isNvmInstalled() {
|
|
32
|
+
const nvmDir = getNvmDir();
|
|
33
|
+
return fs.existsSync(path.join(nvmDir, 'nvm.sh'));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Installs nvm using the official install script.
|
|
38
|
+
* The script clones the nvm repo (which is why git is a dependency).
|
|
39
|
+
* @param {object} context - The CLI context object
|
|
40
|
+
*/
|
|
41
|
+
async function installNvm(context) {
|
|
42
|
+
await context.shell.exec(
|
|
43
|
+
'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a command so that nvm is sourced in the subshell before it runs.
|
|
49
|
+
* Since nvm is a shell function (not a binary), we need to source it
|
|
50
|
+
* in the same subshell that will call nvm commands.
|
|
51
|
+
* @param {string} command - The nvm command to run (e.g. 'nvm install --lts').
|
|
52
|
+
* @returns {string} A bash command string that sources nvm first.
|
|
53
|
+
*/
|
|
54
|
+
function buildNvmCommand(command) {
|
|
55
|
+
const nvmDir = getNvmDir();
|
|
56
|
+
return `export NVM_DIR="${nvmDir}" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" && ${command}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Shared Unix install logic: installs nvm (if missing) then Node LTS via nvm.
|
|
61
|
+
* Used by macOS, Ubuntu, Raspbian, and Amazon Linux installers.
|
|
62
|
+
* @param {object} context - The CLI context object
|
|
63
|
+
*/
|
|
64
|
+
async function installViaUnixNvm(context) {
|
|
65
|
+
if (!isNvmInstalled()) {
|
|
66
|
+
context.output.info('Installing nvm...');
|
|
67
|
+
await installNvm(context);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
context.output.info('Installing Node.js LTS via nvm...');
|
|
71
|
+
await context.shell.exec(buildNvmCommand('nvm install --lts'));
|
|
72
|
+
await context.shell.exec(buildNvmCommand('nvm alias default lts/*'));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if Node.js is already installed.
|
|
77
|
+
* @param {object} context - The CLI context object (has platform, shell, output, etc.)
|
|
78
|
+
* @returns {Promise<boolean>} true if node is available on the system
|
|
79
|
+
*/
|
|
80
|
+
async function isInstalled(context) {
|
|
81
|
+
return context.shell.commandExists('node');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get the installed Node.js version.
|
|
86
|
+
* @param {object} context - The CLI context object
|
|
87
|
+
* @returns {Promise<string|null>} Version string like '20.11.0', or null if unavailable.
|
|
88
|
+
*/
|
|
89
|
+
async function getVersion(context) {
|
|
90
|
+
try {
|
|
91
|
+
const result = await context.shell.exec('node --version');
|
|
92
|
+
// Output looks like: "v20.11.0"
|
|
93
|
+
const match = result.stdout.trim().match(/v?(\d+\.\d+\.\d+)/);
|
|
94
|
+
return match ? match[1] : null;
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Install Node.js on macOS via nvm.
|
|
102
|
+
* @param {object} context - The CLI context object
|
|
103
|
+
*/
|
|
104
|
+
async function install_macos(context) {
|
|
105
|
+
await installViaUnixNvm(context);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Install Node.js on Ubuntu via nvm.
|
|
110
|
+
* Ensures curl is available first (needed to download the nvm install script).
|
|
111
|
+
* @param {object} context - The CLI context object
|
|
112
|
+
*/
|
|
113
|
+
async function install_ubuntu(context) {
|
|
114
|
+
if (!context.shell.commandExists('curl')) {
|
|
115
|
+
context.output.info('Installing curl...');
|
|
116
|
+
await context.shell.exec('sudo apt-get update && sudo apt-get install -y curl');
|
|
117
|
+
}
|
|
118
|
+
await installViaUnixNvm(context);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Install Node.js on Raspberry Pi OS via nvm.
|
|
123
|
+
* Ensures curl is available first.
|
|
124
|
+
* @param {object} context - The CLI context object
|
|
125
|
+
*/
|
|
126
|
+
async function install_raspbian(context) {
|
|
127
|
+
if (!context.shell.commandExists('curl')) {
|
|
128
|
+
context.output.info('Installing curl...');
|
|
129
|
+
await context.shell.exec('sudo apt-get update && sudo apt-get install -y curl');
|
|
130
|
+
}
|
|
131
|
+
await installViaUnixNvm(context);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Install Node.js on Amazon Linux via nvm.
|
|
136
|
+
* Ensures curl is available first, using dnf or yum.
|
|
137
|
+
* @param {object} context - The CLI context object
|
|
138
|
+
*/
|
|
139
|
+
async function install_amazon_linux(context) {
|
|
140
|
+
if (!context.shell.commandExists('curl')) {
|
|
141
|
+
const hasDnf = context.shell.commandExists('dnf');
|
|
142
|
+
if (hasDnf) {
|
|
143
|
+
await context.shell.exec('sudo dnf install -y curl');
|
|
144
|
+
} else {
|
|
145
|
+
await context.shell.exec('sudo yum install -y curl');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
await installViaUnixNvm(context);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Install Node.js on Windows using Chocolatey or winget.
|
|
153
|
+
* Installs Node directly (not via nvm-windows) for simplicity.
|
|
154
|
+
* @param {object} context - The CLI context object
|
|
155
|
+
*/
|
|
156
|
+
async function install_windows(context) {
|
|
157
|
+
const hasChoco = context.shell.commandExists('choco');
|
|
158
|
+
const hasWinget = context.shell.commandExists('winget');
|
|
159
|
+
|
|
160
|
+
if (hasChoco) {
|
|
161
|
+
await context.shell.exec('choco install nodejs-lts -y');
|
|
162
|
+
} else if (hasWinget) {
|
|
163
|
+
await context.shell.exec(
|
|
164
|
+
'winget install --id OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements'
|
|
165
|
+
);
|
|
166
|
+
} else {
|
|
167
|
+
throw new Error(
|
|
168
|
+
'Neither Chocolatey nor winget is available. Install one of them first, or download Node.js from https://nodejs.org'
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Install Node.js in Git Bash.
|
|
175
|
+
* Git Bash runs on Windows, so Node must be installed on the Windows host.
|
|
176
|
+
* @param {object} context - The CLI context object
|
|
177
|
+
*/
|
|
178
|
+
async function install_gitbash(context) {
|
|
179
|
+
if (await isInstalled(context)) {
|
|
180
|
+
context.output.info('Node.js is already available in Git Bash.');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
throw new Error(
|
|
185
|
+
'Node.js must be installed on the Windows host. Download from https://nodejs.org or run the installer from a Windows shell.'
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Main install dispatcher. Detects the platform and calls the right function.
|
|
191
|
+
* The framework calls this -- you don't need to call it directly.
|
|
192
|
+
* @param {object} context - The CLI context object
|
|
193
|
+
*/
|
|
194
|
+
async function install(context) {
|
|
195
|
+
const platformType = context.platform.detect().type;
|
|
196
|
+
const installers = {
|
|
197
|
+
'macos': install_macos,
|
|
198
|
+
'ubuntu': install_ubuntu,
|
|
199
|
+
'raspbian': install_raspbian,
|
|
200
|
+
'amazon-linux': install_amazon_linux,
|
|
201
|
+
'windows': install_windows,
|
|
202
|
+
'gitbash': install_gitbash,
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const fn = installers[platformType];
|
|
206
|
+
if (!fn) {
|
|
207
|
+
throw new Error(`No installer for platform: ${platformType}`);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
await fn(context);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
module.exports = {
|
|
214
|
+
isInstalled,
|
|
215
|
+
install,
|
|
216
|
+
getVersion,
|
|
217
|
+
install_macos,
|
|
218
|
+
install_ubuntu,
|
|
219
|
+
install_raspbian,
|
|
220
|
+
install_amazon_linux,
|
|
221
|
+
install_windows,
|
|
222
|
+
install_gitbash,
|
|
223
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Tool installer metadata. Dependencies, platforms, desktop flag, and status for each tool.",
|
|
3
|
+
"tools": [
|
|
4
|
+
{
|
|
5
|
+
"name": "git",
|
|
6
|
+
"description": "Distributed version control system",
|
|
7
|
+
"platforms": ["macos", "ubuntu", "raspbian", "amazon-linux", "windows", "gitbash"],
|
|
8
|
+
"dependencies": [],
|
|
9
|
+
"desktop": false,
|
|
10
|
+
"installer": "git.js"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "node",
|
|
14
|
+
"description": "JavaScript runtime (installed via nvm on Unix)",
|
|
15
|
+
"platforms": ["macos", "ubuntu", "raspbian", "amazon-linux", "windows", "gitbash"],
|
|
16
|
+
"dependencies": ["git"],
|
|
17
|
+
"desktop": false,
|
|
18
|
+
"installer": "node.js"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "homebrew",
|
|
22
|
+
"description": "Package manager for macOS",
|
|
23
|
+
"platforms": ["macos"],
|
|
24
|
+
"dependencies": [],
|
|
25
|
+
"desktop": false,
|
|
26
|
+
"installer": "homebrew.js"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|