@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,301 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * APT Package Manager Utilities
5
+ *
6
+ * Ubuntu/Debian-specific utilities for interacting with APT.
7
+ */
8
+
9
+ const shell = require('../common/shell');
10
+
11
+ /**
12
+ * Checks if apt is available
13
+ * @returns {boolean}
14
+ */
15
+ function isInstalled() {
16
+ return shell.commandExists('apt-get');
17
+ }
18
+
19
+ /**
20
+ * Installs a package via apt-get
21
+ * @param {string} packageName - The package name to install
22
+ * @param {Object} [options] - Installation options
23
+ * @param {boolean} [options.autoConfirm=true] - Automatically confirm installation
24
+ * @returns {Promise<{ success: boolean, output: string }>}
25
+ */
26
+ async function install(packageName, options = {}) {
27
+ if (!isInstalled()) {
28
+ return {
29
+ success: false,
30
+ output: 'apt-get is not available'
31
+ };
32
+ }
33
+
34
+ const autoConfirm = options.autoConfirm !== false ? '-y' : '';
35
+ const result = await shell.exec(`sudo apt-get install ${autoConfirm} ${packageName}`);
36
+ return {
37
+ success: result.code === 0,
38
+ output: result.stdout || result.stderr
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Removes an installed package
44
+ * @param {string} packageName - The package name to remove
45
+ * @param {Object} [options] - Removal options
46
+ * @param {boolean} [options.purge=false] - Also remove configuration files
47
+ * @returns {Promise<{ success: boolean, output: string }>}
48
+ */
49
+ async function remove(packageName, options = {}) {
50
+ if (!isInstalled()) {
51
+ return {
52
+ success: false,
53
+ output: 'apt-get is not available'
54
+ };
55
+ }
56
+
57
+ const command = options.purge ? 'purge' : 'remove';
58
+ const result = await shell.exec(`sudo apt-get ${command} -y ${packageName}`);
59
+ return {
60
+ success: result.code === 0,
61
+ output: result.stdout || result.stderr
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Runs apt-get update to refresh package lists
67
+ * @returns {Promise<{ success: boolean, output: string }>}
68
+ */
69
+ async function update() {
70
+ if (!isInstalled()) {
71
+ return {
72
+ success: false,
73
+ output: 'apt-get is not available'
74
+ };
75
+ }
76
+
77
+ const result = await shell.exec('sudo apt-get update');
78
+ return {
79
+ success: result.code === 0,
80
+ output: result.stdout || result.stderr
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Upgrades a specific package or all packages
86
+ * @param {string} [packageName] - The package to upgrade (all if omitted)
87
+ * @returns {Promise<{ success: boolean, output: string }>}
88
+ */
89
+ async function upgrade(packageName) {
90
+ if (!isInstalled()) {
91
+ return {
92
+ success: false,
93
+ output: 'apt-get is not available'
94
+ };
95
+ }
96
+
97
+ const command = packageName
98
+ ? `sudo apt-get install -y --only-upgrade ${packageName}`
99
+ : 'sudo apt-get upgrade -y';
100
+
101
+ const result = await shell.exec(command);
102
+ return {
103
+ success: result.code === 0,
104
+ output: result.stdout || result.stderr
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Queries dpkg to check if a package is installed
110
+ * @param {string} packageName - The package name to check
111
+ * @returns {Promise<boolean>}
112
+ */
113
+ async function isPackageInstalled(packageName) {
114
+ const result = await shell.exec(`dpkg -l ${packageName} 2>/dev/null | grep -q "^ii"`);
115
+ return result.code === 0;
116
+ }
117
+
118
+ /**
119
+ * Returns the installed version of a package
120
+ * @param {string} packageName - The package name
121
+ * @returns {Promise<string|null>}
122
+ */
123
+ async function getPackageVersion(packageName) {
124
+ const result = await shell.exec(
125
+ `dpkg -l ${packageName} 2>/dev/null | grep "^ii" | awk '{print $3}'`
126
+ );
127
+ if (result.code === 0 && result.stdout.trim()) {
128
+ return result.stdout.trim();
129
+ }
130
+ return null;
131
+ }
132
+
133
+ /**
134
+ * Adds an APT repository to sources
135
+ * @param {string} repo - The repository specification
136
+ * @returns {Promise<{ success: boolean, output: string }>}
137
+ */
138
+ async function addRepository(repo) {
139
+ if (!shell.commandExists('add-apt-repository')) {
140
+ // Try to install software-properties-common first
141
+ const installResult = await shell.exec('sudo apt-get install -y software-properties-common');
142
+ if (installResult.code !== 0) {
143
+ return {
144
+ success: false,
145
+ output: 'add-apt-repository is not available and could not be installed'
146
+ };
147
+ }
148
+ }
149
+
150
+ const result = await shell.exec(`sudo add-apt-repository -y "${repo}"`);
151
+ return {
152
+ success: result.code === 0,
153
+ output: result.stdout || result.stderr
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Removes an APT repository
159
+ * @param {string} repo - The repository specification
160
+ * @returns {Promise<{ success: boolean, output: string }>}
161
+ */
162
+ async function removeRepository(repo) {
163
+ if (!shell.commandExists('add-apt-repository')) {
164
+ return {
165
+ success: false,
166
+ output: 'add-apt-repository is not available'
167
+ };
168
+ }
169
+
170
+ const result = await shell.exec(`sudo add-apt-repository --remove -y "${repo}"`);
171
+ return {
172
+ success: result.code === 0,
173
+ output: result.stdout || result.stderr
174
+ };
175
+ }
176
+
177
+ /**
178
+ * Imports a GPG key for package verification from a URL
179
+ * @param {string} keyUrl - The URL of the GPG key
180
+ * @param {string} [keyringPath] - Optional path for the keyring file
181
+ * @returns {Promise<{ success: boolean, output: string }>}
182
+ */
183
+ async function addKey(keyUrl, keyringPath) {
184
+ // Modern method using signed-by (recommended for Ubuntu 22.04+)
185
+ if (keyringPath) {
186
+ const result = await shell.exec(
187
+ `curl -fsSL "${keyUrl}" | sudo gpg --dearmor -o "${keyringPath}"`
188
+ );
189
+ return {
190
+ success: result.code === 0,
191
+ output: result.stdout || result.stderr
192
+ };
193
+ }
194
+
195
+ // Legacy method using apt-key (deprecated but still works)
196
+ const result = await shell.exec(
197
+ `curl -fsSL "${keyUrl}" | sudo apt-key add -`
198
+ );
199
+ return {
200
+ success: result.code === 0,
201
+ output: result.stdout || result.stderr
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Imports a GPG key from a keyserver
207
+ * @param {string} keyId - The GPG key ID
208
+ * @param {string} [keyserver='keyserver.ubuntu.com'] - The keyserver to use
209
+ * @returns {Promise<{ success: boolean, output: string }>}
210
+ */
211
+ async function addKeyFromKeyserver(keyId, keyserver = 'keyserver.ubuntu.com') {
212
+ const result = await shell.exec(
213
+ `sudo apt-key adv --keyserver ${keyserver} --recv-keys ${keyId}`
214
+ );
215
+ return {
216
+ success: result.code === 0,
217
+ output: result.stdout || result.stderr
218
+ };
219
+ }
220
+
221
+ /**
222
+ * Searches apt cache for packages
223
+ * @param {string} query - The search query
224
+ * @returns {Promise<string[]>}
225
+ */
226
+ async function search(query) {
227
+ const result = await shell.exec(`apt-cache search "${query}"`);
228
+ if (result.code !== 0) {
229
+ return [];
230
+ }
231
+
232
+ return result.stdout
233
+ .split('\n')
234
+ .filter(Boolean)
235
+ .map((line) => {
236
+ // Format: "package-name - description"
237
+ const match = line.match(/^(\S+)\s+-\s+/);
238
+ return match ? match[1] : line.split(' ')[0];
239
+ })
240
+ .filter(Boolean);
241
+ }
242
+
243
+ /**
244
+ * Gets detailed information about a package
245
+ * @param {string} packageName - The package name
246
+ * @returns {Promise<string|null>}
247
+ */
248
+ async function info(packageName) {
249
+ const result = await shell.exec(`apt-cache show ${packageName}`);
250
+ if (result.code === 0) {
251
+ return result.stdout;
252
+ }
253
+ return null;
254
+ }
255
+
256
+ /**
257
+ * Lists all installed packages
258
+ * @returns {Promise<string[]>}
259
+ */
260
+ async function listInstalled() {
261
+ const result = await shell.exec('dpkg --get-selections | grep -v deinstall');
262
+ if (result.code !== 0) {
263
+ return [];
264
+ }
265
+
266
+ return result.stdout
267
+ .split('\n')
268
+ .filter(Boolean)
269
+ .map((line) => line.split('\t')[0])
270
+ .filter(Boolean);
271
+ }
272
+
273
+ /**
274
+ * Cleans up apt cache
275
+ * @returns {Promise<{ success: boolean, output: string }>}
276
+ */
277
+ async function clean() {
278
+ const result = await shell.exec('sudo apt-get clean && sudo apt-get autoremove -y');
279
+ return {
280
+ success: result.code === 0,
281
+ output: result.stdout || result.stderr
282
+ };
283
+ }
284
+
285
+ module.exports = {
286
+ isInstalled,
287
+ install,
288
+ remove,
289
+ update,
290
+ upgrade,
291
+ isPackageInstalled,
292
+ getPackageVersion,
293
+ addRepository,
294
+ removeRepository,
295
+ addKey,
296
+ addKeyFromKeyserver,
297
+ search,
298
+ info,
299
+ listInstalled,
300
+ clean
301
+ };
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Desktop Environment Detection Utilities
5
+ *
6
+ * Linux-specific utilities for detecting desktop environments and display servers.
7
+ * These functions address a Linux-specific concern: Linux has multiple display
8
+ * servers (X11, Wayland) and desktop environments (GNOME, KDE, XFCE, etc.).
9
+ * macOS always uses Aqua/Quartz, and Windows always uses the Windows Desktop.
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const shell = require('../common/shell');
14
+
15
+ /**
16
+ * Checks if a desktop environment is installed and running
17
+ * @returns {boolean}
18
+ */
19
+ function hasDesktop() {
20
+ // Check if any display server is available
21
+ if (isX11() || isWayland()) {
22
+ return true;
23
+ }
24
+
25
+ // Check for common desktop environment indicators
26
+ if (process.env.XDG_CURRENT_DESKTOP) {
27
+ return true;
28
+ }
29
+
30
+ if (process.env.DESKTOP_SESSION) {
31
+ return true;
32
+ }
33
+
34
+ // Check if any desktop environment package is installed
35
+ const desktopPackages = [
36
+ 'ubuntu-desktop',
37
+ 'kubuntu-desktop',
38
+ 'xubuntu-desktop',
39
+ 'lubuntu-desktop',
40
+ 'gnome-shell',
41
+ 'plasma-desktop',
42
+ 'xfce4',
43
+ 'lxde',
44
+ 'mate-desktop'
45
+ ];
46
+
47
+ for (const pkg of desktopPackages) {
48
+ const result = shell.execSync(`dpkg -l ${pkg} 2>/dev/null | grep -q "^ii"`);
49
+ if (result !== '') {
50
+ return true;
51
+ }
52
+ }
53
+
54
+ return false;
55
+ }
56
+
57
+ /**
58
+ * Returns the desktop environment name
59
+ * @returns {string|null} - Desktop name (gnome, kde, xfce, etc.) or null
60
+ */
61
+ function getDesktopEnvironment() {
62
+ // XDG_CURRENT_DESKTOP is the most reliable indicator
63
+ if (process.env.XDG_CURRENT_DESKTOP) {
64
+ const desktop = process.env.XDG_CURRENT_DESKTOP.toLowerCase();
65
+
66
+ // Normalize common values
67
+ if (desktop.includes('gnome')) return 'gnome';
68
+ if (desktop.includes('kde') || desktop.includes('plasma')) return 'kde';
69
+ if (desktop.includes('xfce')) return 'xfce';
70
+ if (desktop.includes('lxde')) return 'lxde';
71
+ if (desktop.includes('lxqt')) return 'lxqt';
72
+ if (desktop.includes('mate')) return 'mate';
73
+ if (desktop.includes('cinnamon')) return 'cinnamon';
74
+ if (desktop.includes('unity')) return 'unity';
75
+ if (desktop.includes('budgie')) return 'budgie';
76
+ if (desktop.includes('pantheon')) return 'pantheon';
77
+
78
+ return desktop.split(':')[0]; // Take first if multiple (e.g., "ubuntu:GNOME")
79
+ }
80
+
81
+ // Check DESKTOP_SESSION as fallback
82
+ if (process.env.DESKTOP_SESSION) {
83
+ const session = process.env.DESKTOP_SESSION.toLowerCase();
84
+
85
+ if (session.includes('gnome')) return 'gnome';
86
+ if (session.includes('kde') || session.includes('plasma')) return 'kde';
87
+ if (session.includes('xfce')) return 'xfce';
88
+ if (session.includes('lxde')) return 'lxde';
89
+ if (session.includes('mate')) return 'mate';
90
+
91
+ return session;
92
+ }
93
+
94
+ // Check GNOME_DESKTOP_SESSION_ID (older GNOME)
95
+ if (process.env.GNOME_DESKTOP_SESSION_ID) {
96
+ return 'gnome';
97
+ }
98
+
99
+ // Check KDE_FULL_SESSION
100
+ if (process.env.KDE_FULL_SESSION) {
101
+ return 'kde';
102
+ }
103
+
104
+ return null;
105
+ }
106
+
107
+ /**
108
+ * Returns the display server type
109
+ * @returns {'x11'|'wayland'|null}
110
+ */
111
+ function getDisplayServer() {
112
+ if (isWayland()) {
113
+ return 'wayland';
114
+ }
115
+ if (isX11()) {
116
+ return 'x11';
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Checks if running under X11
123
+ * @returns {boolean}
124
+ */
125
+ function isX11() {
126
+ // Check XDG_SESSION_TYPE first (most reliable on modern systems)
127
+ if (process.env.XDG_SESSION_TYPE === 'x11') {
128
+ return true;
129
+ }
130
+
131
+ // Check DISPLAY environment variable
132
+ if (process.env.DISPLAY) {
133
+ // Make sure we're not in Wayland with XWayland
134
+ if (process.env.WAYLAND_DISPLAY) {
135
+ return false; // We're in Wayland, DISPLAY is for XWayland compatibility
136
+ }
137
+ return true;
138
+ }
139
+
140
+ return false;
141
+ }
142
+
143
+ /**
144
+ * Checks if running under Wayland
145
+ * @returns {boolean}
146
+ */
147
+ function isWayland() {
148
+ // Check XDG_SESSION_TYPE first
149
+ if (process.env.XDG_SESSION_TYPE === 'wayland') {
150
+ return true;
151
+ }
152
+
153
+ // Check WAYLAND_DISPLAY
154
+ if (process.env.WAYLAND_DISPLAY) {
155
+ return true;
156
+ }
157
+
158
+ return false;
159
+ }
160
+
161
+ /**
162
+ * Returns the DISPLAY or WAYLAND_DISPLAY environment value
163
+ * @returns {string|null}
164
+ */
165
+ function getDisplayVariable() {
166
+ if (process.env.WAYLAND_DISPLAY) {
167
+ return process.env.WAYLAND_DISPLAY;
168
+ }
169
+ if (process.env.DISPLAY) {
170
+ return process.env.DISPLAY;
171
+ }
172
+ return null;
173
+ }
174
+
175
+ /**
176
+ * Gets the XDG session type
177
+ * @returns {string|null}
178
+ */
179
+ function getSessionType() {
180
+ return process.env.XDG_SESSION_TYPE || null;
181
+ }
182
+
183
+ /**
184
+ * Gets the current session ID
185
+ * @returns {string|null}
186
+ */
187
+ function getSessionId() {
188
+ return process.env.XDG_SESSION_ID || null;
189
+ }
190
+
191
+ /**
192
+ * Checks if running in a virtual terminal (TTY) without GUI
193
+ * @returns {boolean}
194
+ */
195
+ function isTTY() {
196
+ // XDG_SESSION_TYPE is 'tty' for virtual terminals
197
+ if (process.env.XDG_SESSION_TYPE === 'tty') {
198
+ return true;
199
+ }
200
+
201
+ // Check if TERM indicates a TTY
202
+ const term = process.env.TERM || '';
203
+ if (term === 'linux' || term.startsWith('vt')) {
204
+ return true;
205
+ }
206
+
207
+ return false;
208
+ }
209
+
210
+ /**
211
+ * Gets the screen resolution (requires xrandr or similar)
212
+ * @returns {Promise<{ width: number, height: number }|null>}
213
+ */
214
+ async function getScreenResolution() {
215
+ if (isX11()) {
216
+ const result = await shell.exec('xrandr 2>/dev/null | grep "\\*" | head -1');
217
+ if (result.code === 0 && result.stdout) {
218
+ const match = result.stdout.match(/(\d+)x(\d+)/);
219
+ if (match) {
220
+ return {
221
+ width: parseInt(match[1], 10),
222
+ height: parseInt(match[2], 10)
223
+ };
224
+ }
225
+ }
226
+ }
227
+
228
+ if (isWayland()) {
229
+ // Try wlr-randr for wlroots-based compositors
230
+ const result = await shell.exec('wlr-randr 2>/dev/null | grep "current" | head -1');
231
+ if (result.code === 0 && result.stdout) {
232
+ const match = result.stdout.match(/(\d+)x(\d+)/);
233
+ if (match) {
234
+ return {
235
+ width: parseInt(match[1], 10),
236
+ height: parseInt(match[2], 10)
237
+ };
238
+ }
239
+ }
240
+ }
241
+
242
+ return null;
243
+ }
244
+
245
+ /**
246
+ * Gets the GNOME Shell version (if running GNOME)
247
+ * @returns {Promise<string|null>}
248
+ */
249
+ async function getGnomeVersion() {
250
+ if (getDesktopEnvironment() !== 'gnome') {
251
+ return null;
252
+ }
253
+
254
+ const result = await shell.exec('gnome-shell --version 2>/dev/null');
255
+ if (result.code === 0) {
256
+ const match = result.stdout.match(/GNOME Shell (\d+\.\d+\.?\d*)/);
257
+ return match ? match[1] : null;
258
+ }
259
+ return null;
260
+ }
261
+
262
+ /**
263
+ * Gets the KDE Plasma version (if running KDE)
264
+ * @returns {Promise<string|null>}
265
+ */
266
+ async function getKdeVersion() {
267
+ if (getDesktopEnvironment() !== 'kde') {
268
+ return null;
269
+ }
270
+
271
+ const result = await shell.exec('plasmashell --version 2>/dev/null');
272
+ if (result.code === 0) {
273
+ const match = result.stdout.match(/plasmashell (\d+\.\d+\.?\d*)/);
274
+ return match ? match[1] : null;
275
+ }
276
+ return null;
277
+ }
278
+
279
+ module.exports = {
280
+ hasDesktop,
281
+ getDesktopEnvironment,
282
+ getDisplayServer,
283
+ isX11,
284
+ isWayland,
285
+ getDisplayVariable,
286
+ getSessionType,
287
+ getSessionId,
288
+ isTTY,
289
+ getScreenResolution,
290
+ getGnomeVersion,
291
+ getKdeVersion
292
+ };