@fredlackey/devutils 0.0.1

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.
Files changed (200) hide show
  1. package/README.md +156 -0
  2. package/bin/dev.js +16 -0
  3. package/files/README.md +0 -0
  4. package/files/claude/.claude/commands/setup-context.md +3 -0
  5. package/files/monorepos/_archive/README.md +36 -0
  6. package/files/monorepos/_legacy/README.md +36 -0
  7. package/files/monorepos/ai-docs/README.md +33 -0
  8. package/files/monorepos/apps/README.md +24 -0
  9. package/files/monorepos/docs/README.md +40 -0
  10. package/files/monorepos/packages/README.md +25 -0
  11. package/files/monorepos/research/README.md +29 -0
  12. package/files/monorepos/scripts/README.md +24 -0
  13. package/package.json +39 -0
  14. package/src/cli.js +68 -0
  15. package/src/commands/README.md +41 -0
  16. package/src/commands/configure.js +199 -0
  17. package/src/commands/identity.js +1630 -0
  18. package/src/commands/ignore.js +247 -0
  19. package/src/commands/install.js +173 -0
  20. package/src/commands/setup.js +212 -0
  21. package/src/commands/status.js +223 -0
  22. package/src/completion.js +284 -0
  23. package/src/constants.js +45 -0
  24. package/src/ignore/claude-code.txt +10 -0
  25. package/src/ignore/docker.txt +18 -0
  26. package/src/ignore/linux.txt +23 -0
  27. package/src/ignore/macos.txt +36 -0
  28. package/src/ignore/node.txt +55 -0
  29. package/src/ignore/terraform.txt +37 -0
  30. package/src/ignore/vscode.txt +18 -0
  31. package/src/ignore/windows.txt +35 -0
  32. package/src/index.js +0 -0
  33. package/src/installs/README.md +399 -0
  34. package/src/installs/adobe-creative-cloud.js +44 -0
  35. package/src/installs/appcleaner.js +44 -0
  36. package/src/installs/atomicparsley.js +44 -0
  37. package/src/installs/aws-cli.js +44 -0
  38. package/src/installs/balena-etcher.js +44 -0
  39. package/src/installs/bambu-studio.js +44 -0
  40. package/src/installs/bash-completion.js +44 -0
  41. package/src/installs/bash.js +44 -0
  42. package/src/installs/beyond-compare.js +44 -0
  43. package/src/installs/build-essential.js +44 -0
  44. package/src/installs/caffeine.js +44 -0
  45. package/src/installs/camtasia.js +44 -0
  46. package/src/installs/chatgpt.js +44 -0
  47. package/src/installs/chrome-canary.js +44 -0
  48. package/src/installs/chromium.js +44 -0
  49. package/src/installs/claude-code.js +44 -0
  50. package/src/installs/curl.js +44 -0
  51. package/src/installs/cursor.js +44 -0
  52. package/src/installs/dbschema.js +44 -0
  53. package/src/installs/docker.js +44 -0
  54. package/src/installs/drawio.js +44 -0
  55. package/src/installs/elmedia-player.js +44 -0
  56. package/src/installs/ffmpeg.js +44 -0
  57. package/src/installs/gemini-cli.js +44 -0
  58. package/src/installs/git.js +44 -0
  59. package/src/installs/gitego.js +44 -0
  60. package/src/installs/go.js +44 -0
  61. package/src/installs/google-chrome.js +44 -0
  62. package/src/installs/gpg.js +141 -0
  63. package/src/installs/homebrew.js +44 -0
  64. package/src/installs/imageoptim.js +44 -0
  65. package/src/installs/jq.js +44 -0
  66. package/src/installs/keyboard-maestro.js +44 -0
  67. package/src/installs/latex.js +44 -0
  68. package/src/installs/lftp.js +44 -0
  69. package/src/installs/messenger.js +44 -0
  70. package/src/installs/microsoft-office.js +44 -0
  71. package/src/installs/microsoft-teams.js +44 -0
  72. package/src/installs/node.js +44 -0
  73. package/src/installs/nordpass.js +44 -0
  74. package/src/installs/nvm.js +44 -0
  75. package/src/installs/openssh.js +134 -0
  76. package/src/installs/pandoc.js +44 -0
  77. package/src/installs/pinentry.js +44 -0
  78. package/src/installs/pngyu.js +44 -0
  79. package/src/installs/postman.js +44 -0
  80. package/src/installs/safari-tech-preview.js +44 -0
  81. package/src/installs/sfnt2woff.js +44 -0
  82. package/src/installs/shellcheck.js +44 -0
  83. package/src/installs/slack.js +44 -0
  84. package/src/installs/snagit.js +44 -0
  85. package/src/installs/spotify.js +44 -0
  86. package/src/installs/studio-3t.js +44 -0
  87. package/src/installs/sublime-text.js +44 -0
  88. package/src/installs/superwhisper.js +44 -0
  89. package/src/installs/tailscale.js +44 -0
  90. package/src/installs/termius.js +44 -0
  91. package/src/installs/terraform.js +44 -0
  92. package/src/installs/tidal.js +44 -0
  93. package/src/installs/tmux.js +44 -0
  94. package/src/installs/tree.js +44 -0
  95. package/src/installs/vim.js +44 -0
  96. package/src/installs/vlc.js +44 -0
  97. package/src/installs/vscode.js +44 -0
  98. package/src/installs/whatsapp.js +44 -0
  99. package/src/installs/woff2.js +44 -0
  100. package/src/installs/xcode.js +44 -0
  101. package/src/installs/yarn.js +44 -0
  102. package/src/installs/yq.js +44 -0
  103. package/src/installs/yt-dlp.js +44 -0
  104. package/src/installs/zoom.js +44 -0
  105. package/src/scripts/README.md +95 -0
  106. package/src/scripts/afk.js +23 -0
  107. package/src/scripts/backup-all.js +24 -0
  108. package/src/scripts/backup-source.js +24 -0
  109. package/src/scripts/brewd.js +23 -0
  110. package/src/scripts/brewi.js +24 -0
  111. package/src/scripts/brewr.js +24 -0
  112. package/src/scripts/brews.js +24 -0
  113. package/src/scripts/brewu.js +23 -0
  114. package/src/scripts/c.js +23 -0
  115. package/src/scripts/ccurl.js +24 -0
  116. package/src/scripts/certbot-crontab-init.js +24 -0
  117. package/src/scripts/certbot-init.js +25 -0
  118. package/src/scripts/ch.js +23 -0
  119. package/src/scripts/claude-danger.js +23 -0
  120. package/src/scripts/clean-dev.js +24 -0
  121. package/src/scripts/clear-dns-cache.js +23 -0
  122. package/src/scripts/clone.js +25 -0
  123. package/src/scripts/code-all.js +24 -0
  124. package/src/scripts/count-files.js +24 -0
  125. package/src/scripts/count-folders.js +24 -0
  126. package/src/scripts/count.js +24 -0
  127. package/src/scripts/d.js +23 -0
  128. package/src/scripts/datauri.js +24 -0
  129. package/src/scripts/delete-files.js +24 -0
  130. package/src/scripts/docker-clean.js +24 -0
  131. package/src/scripts/dp.js +23 -0
  132. package/src/scripts/e.js +24 -0
  133. package/src/scripts/empty-trash.js +23 -0
  134. package/src/scripts/evm.js +25 -0
  135. package/src/scripts/fetch-github-repos.js +25 -0
  136. package/src/scripts/get-channel.js +24 -0
  137. package/src/scripts/get-course.js +26 -0
  138. package/src/scripts/get-dependencies.js +25 -0
  139. package/src/scripts/get-folder.js +26 -0
  140. package/src/scripts/get-tunes.js +25 -0
  141. package/src/scripts/get-video.js +24 -0
  142. package/src/scripts/git-backup.js +25 -0
  143. package/src/scripts/git-clone.js +25 -0
  144. package/src/scripts/git-pup.js +23 -0
  145. package/src/scripts/git-push.js +24 -0
  146. package/src/scripts/h.js +24 -0
  147. package/src/scripts/hide-desktop-icons.js +23 -0
  148. package/src/scripts/hide-hidden-files.js +23 -0
  149. package/src/scripts/install-dependencies-from.js +25 -0
  150. package/src/scripts/ips.js +26 -0
  151. package/src/scripts/iso.js +24 -0
  152. package/src/scripts/killni.js +23 -0
  153. package/src/scripts/ll.js +24 -0
  154. package/src/scripts/local-ip.js +23 -0
  155. package/src/scripts/m.js +24 -0
  156. package/src/scripts/map.js +24 -0
  157. package/src/scripts/mkd.js +24 -0
  158. package/src/scripts/ncu-update-all.js +24 -0
  159. package/src/scripts/nginx-init.js +28 -0
  160. package/src/scripts/npmi.js +23 -0
  161. package/src/scripts/o.js +24 -0
  162. package/src/scripts/org-by-date.js +24 -0
  163. package/src/scripts/p.js +23 -0
  164. package/src/scripts/packages.js +25 -0
  165. package/src/scripts/path.js +23 -0
  166. package/src/scripts/ports.js +23 -0
  167. package/src/scripts/q.js +23 -0
  168. package/src/scripts/refresh-files.js +26 -0
  169. package/src/scripts/remove-smaller-files.js +24 -0
  170. package/src/scripts/rename-files-with-date.js +25 -0
  171. package/src/scripts/resize-image.js +25 -0
  172. package/src/scripts/rm-safe.js +24 -0
  173. package/src/scripts/s.js +24 -0
  174. package/src/scripts/set-git-public.js +23 -0
  175. package/src/scripts/show-desktop-icons.js +23 -0
  176. package/src/scripts/show-hidden-files.js +23 -0
  177. package/src/scripts/tpa.js +23 -0
  178. package/src/scripts/tpo.js +23 -0
  179. package/src/scripts/u.js +23 -0
  180. package/src/scripts/vpush.js +23 -0
  181. package/src/scripts/y.js +23 -0
  182. package/src/utils/README.md +95 -0
  183. package/src/utils/common/apps.js +143 -0
  184. package/src/utils/common/display.js +157 -0
  185. package/src/utils/common/network.js +185 -0
  186. package/src/utils/common/os.js +202 -0
  187. package/src/utils/common/package-manager.js +301 -0
  188. package/src/utils/common/privileges.js +138 -0
  189. package/src/utils/common/shell.js +195 -0
  190. package/src/utils/macos/apps.js +228 -0
  191. package/src/utils/macos/brew.js +315 -0
  192. package/src/utils/ubuntu/apt.js +301 -0
  193. package/src/utils/ubuntu/desktop.js +292 -0
  194. package/src/utils/ubuntu/snap.js +302 -0
  195. package/src/utils/ubuntu/systemd.js +286 -0
  196. package/src/utils/windows/choco.js +327 -0
  197. package/src/utils/windows/env.js +246 -0
  198. package/src/utils/windows/registry.js +269 -0
  199. package/src/utils/windows/shell.js +240 -0
  200. package/src/utils/windows/winget.js +378 -0
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Chocolatey Package Manager Utilities
5
+ *
6
+ * Windows-specific utilities for interacting with Chocolatey.
7
+ */
8
+
9
+ const shell = require('../common/shell');
10
+
11
+ /**
12
+ * Checks if Chocolatey is installed
13
+ * @returns {boolean}
14
+ */
15
+ function isInstalled() {
16
+ return shell.commandExists('choco');
17
+ }
18
+
19
+ /**
20
+ * Returns the installed Chocolatey version
21
+ * @returns {Promise<string|null>}
22
+ */
23
+ async function getVersion() {
24
+ if (!isInstalled()) {
25
+ return null;
26
+ }
27
+
28
+ const result = await shell.exec('choco --version');
29
+ if (result.code === 0) {
30
+ return result.stdout.trim();
31
+ }
32
+ return null;
33
+ }
34
+
35
+ /**
36
+ * Installs a Chocolatey package
37
+ * @param {string} packageName - The package name to install
38
+ * @param {Object} [options] - Installation options
39
+ * @param {boolean} [options.force=false] - Force reinstall if already installed
40
+ * @param {string} [options.version] - Specific version to install
41
+ * @returns {Promise<{ success: boolean, output: string }>}
42
+ */
43
+ async function install(packageName, options = {}) {
44
+ if (!isInstalled()) {
45
+ return {
46
+ success: false,
47
+ output: 'Chocolatey is not installed'
48
+ };
49
+ }
50
+
51
+ let command = `choco install ${packageName} -y`;
52
+
53
+ if (options.force) {
54
+ command += ' --force';
55
+ }
56
+
57
+ if (options.version) {
58
+ command += ` --version=${options.version}`;
59
+ }
60
+
61
+ const result = await shell.exec(command);
62
+ return {
63
+ success: result.code === 0,
64
+ output: result.stdout || result.stderr
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Removes a Chocolatey package
70
+ * @param {string} packageName - The package name to remove
71
+ * @returns {Promise<{ success: boolean, output: string }>}
72
+ */
73
+ async function uninstall(packageName) {
74
+ if (!isInstalled()) {
75
+ return {
76
+ success: false,
77
+ output: 'Chocolatey is not installed'
78
+ };
79
+ }
80
+
81
+ const result = await shell.exec(`choco uninstall ${packageName} -y`);
82
+ return {
83
+ success: result.code === 0,
84
+ output: result.stdout || result.stderr
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Checks if a package is installed via Chocolatey
90
+ * @param {string} packageName - The package name to check
91
+ * @returns {Promise<boolean>}
92
+ */
93
+ async function isPackageInstalled(packageName) {
94
+ if (!isInstalled()) {
95
+ return false;
96
+ }
97
+
98
+ const result = await shell.exec(`choco list --local-only --exact ${packageName}`);
99
+ // Output contains the package name if installed
100
+ return result.code === 0 && result.stdout.toLowerCase().includes(packageName.toLowerCase());
101
+ }
102
+
103
+ /**
104
+ * Returns the installed version of a package
105
+ * @param {string} packageName - The package name
106
+ * @returns {Promise<string|null>}
107
+ */
108
+ async function getPackageVersion(packageName) {
109
+ if (!isInstalled()) {
110
+ return null;
111
+ }
112
+
113
+ const result = await shell.exec(`choco list --local-only --exact ${packageName}`);
114
+ if (result.code !== 0) {
115
+ return null;
116
+ }
117
+
118
+ // Output format: "packageName version"
119
+ const lines = result.stdout.split('\n').filter(Boolean);
120
+ for (const line of lines) {
121
+ const parts = line.trim().split(/\s+/);
122
+ if (parts[0] && parts[0].toLowerCase() === packageName.toLowerCase()) {
123
+ return parts[1] || null;
124
+ }
125
+ }
126
+
127
+ return null;
128
+ }
129
+
130
+ /**
131
+ * Upgrades a package or all packages
132
+ * @param {string} [packageName] - The package to upgrade (all if omitted)
133
+ * @returns {Promise<{ success: boolean, output: string }>}
134
+ */
135
+ async function upgrade(packageName) {
136
+ if (!isInstalled()) {
137
+ return {
138
+ success: false,
139
+ output: 'Chocolatey is not installed'
140
+ };
141
+ }
142
+
143
+ const target = packageName || 'all';
144
+ const result = await shell.exec(`choco upgrade ${target} -y`);
145
+ return {
146
+ success: result.code === 0,
147
+ output: result.stdout || result.stderr
148
+ };
149
+ }
150
+
151
+ /**
152
+ * Searches the Chocolatey repository
153
+ * @param {string} query - The search query
154
+ * @returns {Promise<Array<{ name: string, version: string }>>}
155
+ */
156
+ async function search(query) {
157
+ if (!isInstalled()) {
158
+ return [];
159
+ }
160
+
161
+ const result = await shell.exec(`choco search "${query}"`);
162
+ if (result.code !== 0) {
163
+ return [];
164
+ }
165
+
166
+ const packages = [];
167
+ const lines = result.stdout.split('\n').filter(Boolean);
168
+
169
+ for (const line of lines) {
170
+ // Skip header and summary lines
171
+ if (line.includes('packages found') || line.includes('Chocolatey')) {
172
+ continue;
173
+ }
174
+
175
+ const parts = line.trim().split(/\s+/);
176
+ if (parts.length >= 2 && !parts[0].includes('=')) {
177
+ packages.push({
178
+ name: parts[0],
179
+ version: parts[1]
180
+ });
181
+ }
182
+ }
183
+
184
+ return packages;
185
+ }
186
+
187
+ /**
188
+ * Gets information about a package
189
+ * @param {string} packageName - The package name
190
+ * @returns {Promise<string|null>}
191
+ */
192
+ async function info(packageName) {
193
+ if (!isInstalled()) {
194
+ return null;
195
+ }
196
+
197
+ const result = await shell.exec(`choco info ${packageName}`);
198
+ if (result.code === 0) {
199
+ return result.stdout;
200
+ }
201
+ return null;
202
+ }
203
+
204
+ /**
205
+ * Lists all locally installed packages
206
+ * @returns {Promise<Array<{ name: string, version: string }>>}
207
+ */
208
+ async function listInstalled() {
209
+ if (!isInstalled()) {
210
+ return [];
211
+ }
212
+
213
+ const result = await shell.exec('choco list --local-only');
214
+ if (result.code !== 0) {
215
+ return [];
216
+ }
217
+
218
+ const packages = [];
219
+ const lines = result.stdout.split('\n').filter(Boolean);
220
+
221
+ for (const line of lines) {
222
+ // Skip summary line
223
+ if (line.includes('packages installed')) {
224
+ continue;
225
+ }
226
+
227
+ const parts = line.trim().split(/\s+/);
228
+ if (parts.length >= 2) {
229
+ packages.push({
230
+ name: parts[0],
231
+ version: parts[1]
232
+ });
233
+ }
234
+ }
235
+
236
+ return packages;
237
+ }
238
+
239
+ /**
240
+ * Lists outdated packages
241
+ * @returns {Promise<Array<{ name: string, currentVersion: string, availableVersion: string }>>}
242
+ */
243
+ async function listOutdated() {
244
+ if (!isInstalled()) {
245
+ return [];
246
+ }
247
+
248
+ const result = await shell.exec('choco outdated');
249
+ if (result.code !== 0) {
250
+ return [];
251
+ }
252
+
253
+ const packages = [];
254
+ const lines = result.stdout.split('\n').filter(Boolean);
255
+
256
+ for (const line of lines) {
257
+ // Lines with outdated packages have format: "name|currentVer|availableVer|pinned"
258
+ if (line.includes('|')) {
259
+ const parts = line.split('|');
260
+ if (parts.length >= 3) {
261
+ packages.push({
262
+ name: parts[0].trim(),
263
+ currentVersion: parts[1].trim(),
264
+ availableVersion: parts[2].trim()
265
+ });
266
+ }
267
+ }
268
+ }
269
+
270
+ return packages;
271
+ }
272
+
273
+ /**
274
+ * Pins a package to prevent upgrades
275
+ * @param {string} packageName - The package name
276
+ * @returns {Promise<{ success: boolean, output: string }>}
277
+ */
278
+ async function pin(packageName) {
279
+ if (!isInstalled()) {
280
+ return {
281
+ success: false,
282
+ output: 'Chocolatey is not installed'
283
+ };
284
+ }
285
+
286
+ const result = await shell.exec(`choco pin add -n="${packageName}"`);
287
+ return {
288
+ success: result.code === 0,
289
+ output: result.stdout || result.stderr
290
+ };
291
+ }
292
+
293
+ /**
294
+ * Unpins a package to allow upgrades
295
+ * @param {string} packageName - The package name
296
+ * @returns {Promise<{ success: boolean, output: string }>}
297
+ */
298
+ async function unpin(packageName) {
299
+ if (!isInstalled()) {
300
+ return {
301
+ success: false,
302
+ output: 'Chocolatey is not installed'
303
+ };
304
+ }
305
+
306
+ const result = await shell.exec(`choco pin remove -n="${packageName}"`);
307
+ return {
308
+ success: result.code === 0,
309
+ output: result.stdout || result.stderr
310
+ };
311
+ }
312
+
313
+ module.exports = {
314
+ isInstalled,
315
+ getVersion,
316
+ install,
317
+ uninstall,
318
+ isPackageInstalled,
319
+ getPackageVersion,
320
+ upgrade,
321
+ search,
322
+ info,
323
+ listInstalled,
324
+ listOutdated,
325
+ pin,
326
+ unpin
327
+ };
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Windows Environment Variables Utilities
5
+ *
6
+ * Windows-specific utilities for managing environment variables.
7
+ */
8
+
9
+ const shell = require('../common/shell');
10
+ const path = require('path');
11
+
12
+ /**
13
+ * Returns the system PATH as an array
14
+ * @returns {string[]}
15
+ */
16
+ function getPath() {
17
+ const pathEnv = process.env.PATH || process.env.Path || '';
18
+ return pathEnv.split(';').filter(Boolean);
19
+ }
20
+
21
+ /**
22
+ * Adds a directory to the user PATH
23
+ * Note: Changes take effect in new processes, not the current one
24
+ * @param {string} directory - The directory to add to PATH
25
+ * @returns {Promise<{ success: boolean, output: string }>}
26
+ */
27
+ async function addToPath(directory) {
28
+ // Normalize the path
29
+ const normalizedDir = path.resolve(directory);
30
+
31
+ // Check if already in PATH
32
+ const currentPath = getPath();
33
+ if (currentPath.some((p) => path.resolve(p).toLowerCase() === normalizedDir.toLowerCase())) {
34
+ return {
35
+ success: true,
36
+ output: 'Directory is already in PATH'
37
+ };
38
+ }
39
+
40
+ // Use PowerShell to modify user PATH
41
+ const command = `
42
+ $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User')
43
+ $newPath = "$currentPath;${normalizedDir}"
44
+ [Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
45
+ `.replace(/\n/g, ' ');
46
+
47
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
48
+ return {
49
+ success: result.code === 0,
50
+ output: result.code === 0
51
+ ? `Added ${normalizedDir} to user PATH. Restart your terminal for changes to take effect.`
52
+ : result.stderr
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Removes a directory from the user PATH
58
+ * @param {string} directory - The directory to remove from PATH
59
+ * @returns {Promise<{ success: boolean, output: string }>}
60
+ */
61
+ async function removeFromPath(directory) {
62
+ const normalizedDir = path.resolve(directory);
63
+
64
+ // Use PowerShell to modify user PATH
65
+ const command = `
66
+ $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User')
67
+ $paths = $currentPath -split ';' | Where-Object { $_.Trim() -ne '' -and [System.IO.Path]::GetFullPath($_).ToLower() -ne '${normalizedDir.toLowerCase().replace(/\\/g, '\\\\')}' }
68
+ $newPath = $paths -join ';'
69
+ [Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
70
+ `.replace(/\n/g, ' ');
71
+
72
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
73
+ return {
74
+ success: result.code === 0,
75
+ output: result.code === 0
76
+ ? `Removed ${normalizedDir} from user PATH. Restart your terminal for changes to take effect.`
77
+ : result.stderr
78
+ };
79
+ }
80
+
81
+ /**
82
+ * Gets an environment variable value
83
+ * @param {string} varName - The variable name
84
+ * @param {'User'|'Machine'|'Process'} [scope='Process'] - The scope to check
85
+ * @returns {Promise<string|null>}
86
+ */
87
+ async function get(varName, scope = 'Process') {
88
+ if (scope === 'Process') {
89
+ return process.env[varName] || null;
90
+ }
91
+
92
+ const command = `[Environment]::GetEnvironmentVariable('${varName}', '${scope}')`;
93
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
94
+
95
+ if (result.code === 0 && result.stdout.trim()) {
96
+ return result.stdout.trim();
97
+ }
98
+ return null;
99
+ }
100
+
101
+ /**
102
+ * Sets a user environment variable
103
+ * @param {string} varName - The variable name
104
+ * @param {string} value - The value to set
105
+ * @param {'User'|'Machine'} [scope='User'] - The scope (Machine requires admin)
106
+ * @returns {Promise<{ success: boolean, output: string }>}
107
+ */
108
+ async function set(varName, value, scope = 'User') {
109
+ const command = `[Environment]::SetEnvironmentVariable('${varName}', '${value}', '${scope}')`;
110
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
111
+
112
+ return {
113
+ success: result.code === 0,
114
+ output: result.code === 0
115
+ ? `Set ${varName}=${value} in ${scope} scope. Restart your terminal for changes to take effect.`
116
+ : result.stderr
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Removes a user environment variable
122
+ * @param {string} varName - The variable name
123
+ * @param {'User'|'Machine'} [scope='User'] - The scope
124
+ * @returns {Promise<{ success: boolean, output: string }>}
125
+ */
126
+ async function remove(varName, scope = 'User') {
127
+ const command = `[Environment]::SetEnvironmentVariable('${varName}', $null, '${scope}')`;
128
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
129
+
130
+ return {
131
+ success: result.code === 0,
132
+ output: result.code === 0
133
+ ? `Removed ${varName} from ${scope} scope. Restart your terminal for changes to take effect.`
134
+ : result.stderr
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Gets all user environment variables
140
+ * @returns {Promise<Object<string, string>>}
141
+ */
142
+ async function getUserVariables() {
143
+ const command = '[Environment]::GetEnvironmentVariables("User") | ConvertTo-Json';
144
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
145
+
146
+ if (result.code === 0 && result.stdout.trim()) {
147
+ try {
148
+ return JSON.parse(result.stdout);
149
+ } catch {
150
+ return {};
151
+ }
152
+ }
153
+ return {};
154
+ }
155
+
156
+ /**
157
+ * Gets all machine (system) environment variables
158
+ * @returns {Promise<Object<string, string>>}
159
+ */
160
+ async function getMachineVariables() {
161
+ const command = '[Environment]::GetEnvironmentVariables("Machine") | ConvertTo-Json';
162
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
163
+
164
+ if (result.code === 0 && result.stdout.trim()) {
165
+ try {
166
+ return JSON.parse(result.stdout);
167
+ } catch {
168
+ return {};
169
+ }
170
+ }
171
+ return {};
172
+ }
173
+
174
+ /**
175
+ * Expands environment variables in a string
176
+ * @param {string} str - The string containing variables like %VAR%
177
+ * @returns {string}
178
+ */
179
+ function expand(str) {
180
+ return str.replace(/%([^%]+)%/g, (_, varName) => {
181
+ return process.env[varName] || `%${varName}%`;
182
+ });
183
+ }
184
+
185
+ /**
186
+ * Broadcasts a WM_SETTINGCHANGE message to notify other applications
187
+ * of environment variable changes
188
+ * @returns {Promise<{ success: boolean, output: string }>}
189
+ */
190
+ async function broadcastChange() {
191
+ const command = `
192
+ Add-Type -TypeDefinition @"
193
+ using System;
194
+ using System.Runtime.InteropServices;
195
+ public class Win32 {
196
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
197
+ public static extern IntPtr SendMessageTimeout(
198
+ IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
199
+ uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
200
+ }
201
+ "@
202
+ $HWND_BROADCAST = [IntPtr]0xffff
203
+ $WM_SETTINGCHANGE = 0x1a
204
+ $result = [UIntPtr]::Zero
205
+ [Win32]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 5000, [ref]$result)
206
+ `.replace(/\n/g, ' ');
207
+
208
+ const result = await shell.exec(`powershell -NoProfile -Command "${command}"`);
209
+ return {
210
+ success: result.code === 0,
211
+ output: result.code === 0
212
+ ? 'Broadcasted environment change notification'
213
+ : result.stderr
214
+ };
215
+ }
216
+
217
+ /**
218
+ * Refreshes the current process's environment from the registry
219
+ * Note: This only affects the current Node.js process
220
+ * @returns {Promise<void>}
221
+ */
222
+ async function refresh() {
223
+ // Get updated PATH from both User and Machine scopes
224
+ const userPath = await get('Path', 'User');
225
+ const machinePath = await get('Path', 'Machine');
226
+
227
+ if (userPath || machinePath) {
228
+ const combined = [machinePath, userPath].filter(Boolean).join(';');
229
+ process.env.PATH = combined;
230
+ process.env.Path = combined;
231
+ }
232
+ }
233
+
234
+ module.exports = {
235
+ getPath,
236
+ addToPath,
237
+ removeFromPath,
238
+ get,
239
+ set,
240
+ remove,
241
+ getUserVariables,
242
+ getMachineVariables,
243
+ expand,
244
+ broadcastChange,
245
+ refresh
246
+ };