@fredlackey/devutils 0.0.18 → 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.
Files changed (447) hide show
  1. package/README.md +214 -141
  2. package/package.json +8 -83
  3. package/src/api/loader.js +229 -0
  4. package/src/api/registry.json +62 -0
  5. package/src/cli.js +293 -60
  6. package/src/commands/ai/index.js +16 -0
  7. package/src/commands/ai/launch.js +112 -0
  8. package/src/commands/ai/list.js +54 -0
  9. package/src/commands/ai/resume.js +70 -0
  10. package/src/commands/ai/sessions.js +121 -0
  11. package/src/commands/ai/set.js +131 -0
  12. package/src/commands/ai/show.js +74 -0
  13. package/src/commands/ai/tools.js +46 -0
  14. package/src/commands/alias/add.js +93 -0
  15. package/src/commands/alias/helpers.js +107 -0
  16. package/src/commands/alias/index.js +14 -0
  17. package/src/commands/alias/list.js +55 -0
  18. package/src/commands/alias/remove.js +62 -0
  19. package/src/commands/alias/sync.js +109 -0
  20. package/src/commands/api/disable.js +73 -0
  21. package/src/commands/api/enable.js +148 -0
  22. package/src/commands/api/index.js +15 -0
  23. package/src/commands/api/list.js +66 -0
  24. package/src/commands/api/update.js +87 -0
  25. package/src/commands/auth/index.js +15 -0
  26. package/src/commands/auth/list.js +49 -0
  27. package/src/commands/auth/login.js +384 -0
  28. package/src/commands/auth/logout.js +111 -0
  29. package/src/commands/auth/refresh.js +184 -0
  30. package/src/commands/auth/services.js +169 -0
  31. package/src/commands/auth/status.js +104 -0
  32. package/src/commands/config/export.js +224 -0
  33. package/src/commands/config/get.js +52 -0
  34. package/src/commands/config/import.js +308 -0
  35. package/src/commands/config/index.js +17 -0
  36. package/src/commands/config/init.js +143 -0
  37. package/src/commands/config/reset.js +57 -0
  38. package/src/commands/config/set.js +93 -0
  39. package/src/commands/config/show.js +35 -0
  40. package/src/commands/help.js +338 -0
  41. package/src/commands/identity/add.js +133 -0
  42. package/src/commands/identity/index.js +17 -0
  43. package/src/commands/identity/link.js +76 -0
  44. package/src/commands/identity/list.js +48 -0
  45. package/src/commands/identity/remove.js +72 -0
  46. package/src/commands/identity/show.js +65 -0
  47. package/src/commands/identity/sync.js +172 -0
  48. package/src/commands/identity/unlink.js +57 -0
  49. package/src/commands/ignore/add.js +165 -0
  50. package/src/commands/ignore/index.js +14 -0
  51. package/src/commands/ignore/list.js +89 -0
  52. package/src/commands/ignore/markers.js +43 -0
  53. package/src/commands/ignore/remove.js +164 -0
  54. package/src/commands/ignore/show.js +169 -0
  55. package/src/commands/machine/detect.js +122 -0
  56. package/src/commands/machine/index.js +14 -0
  57. package/src/commands/machine/list.js +74 -0
  58. package/src/commands/machine/set.js +106 -0
  59. package/src/commands/machine/show.js +35 -0
  60. package/src/commands/schema.js +152 -0
  61. package/src/commands/search/collections.js +134 -0
  62. package/src/commands/search/get.js +71 -0
  63. package/src/commands/search/index-cmd.js +54 -0
  64. package/src/commands/search/index.js +21 -0
  65. package/src/commands/search/keyword.js +60 -0
  66. package/src/commands/search/qmd.js +70 -0
  67. package/src/commands/search/query.js +64 -0
  68. package/src/commands/search/semantic.js +62 -0
  69. package/src/commands/search/status.js +46 -0
  70. package/src/commands/status.js +224 -171
  71. package/src/commands/tools/check.js +79 -0
  72. package/src/commands/tools/index.js +14 -0
  73. package/src/commands/tools/install.js +110 -0
  74. package/src/commands/tools/list.js +91 -0
  75. package/src/commands/tools/search.js +60 -0
  76. package/src/commands/update.js +83 -112
  77. package/src/commands/util/add.js +151 -0
  78. package/src/commands/util/index.js +15 -0
  79. package/src/commands/util/list.js +97 -0
  80. package/src/commands/util/remove.js +76 -0
  81. package/src/commands/util/run.js +79 -0
  82. package/src/commands/util/show.js +67 -0
  83. package/src/commands/version.js +21 -88
  84. package/src/installers/_template.js +104 -0
  85. package/src/installers/git.js +150 -0
  86. package/src/installers/homebrew.js +190 -0
  87. package/src/installers/node.js +223 -0
  88. package/src/installers/registry.json +29 -0
  89. package/src/lib/config.js +125 -0
  90. package/src/lib/detect.js +74 -0
  91. package/src/lib/errors.js +114 -0
  92. package/src/lib/github.js +315 -0
  93. package/src/lib/installer.js +225 -0
  94. package/src/lib/output.js +239 -0
  95. package/src/lib/platform.js +112 -0
  96. package/src/lib/platforms/amazon-linux.js +41 -0
  97. package/src/lib/platforms/gitbash.js +46 -0
  98. package/src/lib/platforms/macos.js +45 -0
  99. package/src/lib/platforms/raspbian.js +41 -0
  100. package/src/lib/platforms/ubuntu.js +39 -0
  101. package/src/lib/platforms/windows.js +45 -0
  102. package/src/lib/prompt.js +161 -0
  103. package/src/lib/schema.js +211 -0
  104. package/src/lib/shell.js +75 -0
  105. package/src/patterns/gitignore/claude-code.txt +25 -0
  106. package/src/patterns/gitignore/docker.txt +15 -0
  107. package/src/patterns/gitignore/go.txt +24 -0
  108. package/src/patterns/gitignore/java.txt +38 -0
  109. package/src/patterns/gitignore/jetbrains.txt +26 -0
  110. package/src/patterns/gitignore/linux.txt +18 -0
  111. package/src/patterns/gitignore/macos.txt +27 -0
  112. package/src/patterns/gitignore/node.txt +51 -0
  113. package/src/patterns/gitignore/python.txt +55 -0
  114. package/src/patterns/gitignore/rust.txt +14 -0
  115. package/src/patterns/gitignore/terraform.txt +30 -0
  116. package/src/patterns/gitignore/vscode.txt +15 -0
  117. package/src/patterns/gitignore/windows.txt +25 -0
  118. package/src/utils/clone/index.js +165 -0
  119. package/src/utils/git-push/index.js +230 -0
  120. package/src/utils/git-status/index.js +116 -0
  121. package/src/utils/git-status/unix.sh +75 -0
  122. package/src/utils/registry.json +41 -0
  123. package/bin/dev.js +0 -16
  124. package/files/README.md +0 -0
  125. package/files/claude/.claude/commands/setup-context.md +0 -3
  126. package/files/monorepos/_archive/README.md +0 -36
  127. package/files/monorepos/_legacy/README.md +0 -36
  128. package/files/monorepos/ai-docs/README.md +0 -33
  129. package/files/monorepos/apps/README.md +0 -24
  130. package/files/monorepos/docs/README.md +0 -40
  131. package/files/monorepos/packages/README.md +0 -25
  132. package/files/monorepos/research/README.md +0 -29
  133. package/files/monorepos/scripts/README.md +0 -24
  134. package/src/commands/README.md +0 -41
  135. package/src/commands/configure.js +0 -199
  136. package/src/commands/identity.js +0 -1630
  137. package/src/commands/ignore.js +0 -247
  138. package/src/commands/install.js +0 -526
  139. package/src/commands/setup.js +0 -246
  140. package/src/completion.js +0 -284
  141. package/src/constants.js +0 -45
  142. package/src/ignore/claude-code.txt +0 -10
  143. package/src/ignore/docker.txt +0 -18
  144. package/src/ignore/linux.txt +0 -23
  145. package/src/ignore/macos.txt +0 -36
  146. package/src/ignore/node.txt +0 -55
  147. package/src/ignore/terraform.txt +0 -37
  148. package/src/ignore/vscode.txt +0 -18
  149. package/src/ignore/windows.txt +0 -35
  150. package/src/index.js +0 -0
  151. package/src/installs/README.md +0 -399
  152. package/src/installs/adobe-creative-cloud.js +0 -546
  153. package/src/installs/adobe-creative-cloud.md +0 -605
  154. package/src/installs/appcleaner.js +0 -321
  155. package/src/installs/appcleaner.md +0 -699
  156. package/src/installs/apt-transport-https.js +0 -390
  157. package/src/installs/apt-transport-https.md +0 -678
  158. package/src/installs/atomicparsley.js +0 -642
  159. package/src/installs/atomicparsley.md +0 -795
  160. package/src/installs/aws-cli.js +0 -797
  161. package/src/installs/aws-cli.md +0 -727
  162. package/src/installs/balena-etcher.js +0 -710
  163. package/src/installs/balena-etcher.md +0 -761
  164. package/src/installs/bambu-studio.js +0 -1143
  165. package/src/installs/bambu-studio.md +0 -780
  166. package/src/installs/bash-completion.js +0 -575
  167. package/src/installs/bash-completion.md +0 -833
  168. package/src/installs/bash.js +0 -417
  169. package/src/installs/bash.md +0 -993
  170. package/src/installs/beyond-compare.js +0 -603
  171. package/src/installs/beyond-compare.md +0 -813
  172. package/src/installs/brave-browser.js +0 -968
  173. package/src/installs/brave-browser.md +0 -650
  174. package/src/installs/build-essential.js +0 -529
  175. package/src/installs/build-essential.md +0 -977
  176. package/src/installs/ca-certificates.js +0 -618
  177. package/src/installs/ca-certificates.md +0 -937
  178. package/src/installs/caffeine.js +0 -508
  179. package/src/installs/caffeine.md +0 -839
  180. package/src/installs/camtasia.js +0 -596
  181. package/src/installs/camtasia.md +0 -762
  182. package/src/installs/chatgpt.js +0 -476
  183. package/src/installs/chatgpt.md +0 -814
  184. package/src/installs/chocolatey.js +0 -456
  185. package/src/installs/chocolatey.md +0 -661
  186. package/src/installs/chrome-canary.js +0 -419
  187. package/src/installs/chrome-canary.md +0 -641
  188. package/src/installs/chromium.js +0 -667
  189. package/src/installs/chromium.md +0 -838
  190. package/src/installs/claude-code.js +0 -576
  191. package/src/installs/claude-code.md +0 -1173
  192. package/src/installs/cloudflare-warp.js +0 -900
  193. package/src/installs/cloudflare-warp.md +0 -1047
  194. package/src/installs/comet-browser.js +0 -588
  195. package/src/installs/comet-browser.md +0 -731
  196. package/src/installs/curl.js +0 -379
  197. package/src/installs/curl.md +0 -714
  198. package/src/installs/cursor.js +0 -579
  199. package/src/installs/cursor.md +0 -970
  200. package/src/installs/dbeaver.js +0 -924
  201. package/src/installs/dbeaver.md +0 -939
  202. package/src/installs/dbschema.js +0 -692
  203. package/src/installs/dbschema.md +0 -925
  204. package/src/installs/dependencies.md +0 -453
  205. package/src/installs/development-tools.js +0 -600
  206. package/src/installs/development-tools.md +0 -977
  207. package/src/installs/docker.js +0 -1029
  208. package/src/installs/docker.md +0 -1109
  209. package/src/installs/drawio.js +0 -1019
  210. package/src/installs/drawio.md +0 -795
  211. package/src/installs/elmedia-player.js +0 -347
  212. package/src/installs/elmedia-player.md +0 -556
  213. package/src/installs/ffmpeg.js +0 -889
  214. package/src/installs/ffmpeg.md +0 -852
  215. package/src/installs/file.js +0 -464
  216. package/src/installs/file.md +0 -987
  217. package/src/installs/gemini-cli.js +0 -811
  218. package/src/installs/gemini-cli.md +0 -1153
  219. package/src/installs/git.js +0 -400
  220. package/src/installs/git.md +0 -907
  221. package/src/installs/gitego.js +0 -949
  222. package/src/installs/gitego.md +0 -1172
  223. package/src/installs/go.js +0 -931
  224. package/src/installs/go.md +0 -958
  225. package/src/installs/google-antigravity.js +0 -913
  226. package/src/installs/google-antigravity.md +0 -1075
  227. package/src/installs/google-chrome.js +0 -833
  228. package/src/installs/google-chrome.md +0 -862
  229. package/src/installs/gpg.js +0 -480
  230. package/src/installs/gpg.md +0 -1056
  231. package/src/installs/homebrew.js +0 -1028
  232. package/src/installs/homebrew.md +0 -988
  233. package/src/installs/imageoptim.js +0 -968
  234. package/src/installs/imageoptim.md +0 -1119
  235. package/src/installs/installers.json +0 -4032
  236. package/src/installs/installers.json.tmp +0 -3953
  237. package/src/installs/jq.js +0 -400
  238. package/src/installs/jq.md +0 -809
  239. package/src/installs/keyboard-maestro.js +0 -719
  240. package/src/installs/keyboard-maestro.md +0 -825
  241. package/src/installs/kiro.js +0 -864
  242. package/src/installs/kiro.md +0 -1015
  243. package/src/installs/latex.js +0 -789
  244. package/src/installs/latex.md +0 -1095
  245. package/src/installs/lftp.js +0 -356
  246. package/src/installs/lftp.md +0 -907
  247. package/src/installs/lsb-release.js +0 -346
  248. package/src/installs/lsb-release.md +0 -814
  249. package/src/installs/messenger.js +0 -847
  250. package/src/installs/messenger.md +0 -900
  251. package/src/installs/microsoft-office.js +0 -568
  252. package/src/installs/microsoft-office.md +0 -760
  253. package/src/installs/microsoft-teams.js +0 -801
  254. package/src/installs/microsoft-teams.md +0 -886
  255. package/src/installs/moom.js +0 -326
  256. package/src/installs/moom.md +0 -570
  257. package/src/installs/node.js +0 -904
  258. package/src/installs/node.md +0 -1153
  259. package/src/installs/nordpass.js +0 -716
  260. package/src/installs/nordpass.md +0 -921
  261. package/src/installs/nordvpn.js +0 -892
  262. package/src/installs/nordvpn.md +0 -1052
  263. package/src/installs/nvm.js +0 -995
  264. package/src/installs/nvm.md +0 -1057
  265. package/src/installs/ohmyzsh.js +0 -529
  266. package/src/installs/ohmyzsh.md +0 -1094
  267. package/src/installs/openssh.js +0 -804
  268. package/src/installs/openssh.md +0 -1056
  269. package/src/installs/pandoc.js +0 -662
  270. package/src/installs/pandoc.md +0 -1036
  271. package/src/installs/parallels-desktop.js +0 -431
  272. package/src/installs/parallels-desktop.md +0 -446
  273. package/src/installs/pinentry.js +0 -510
  274. package/src/installs/pinentry.md +0 -1142
  275. package/src/installs/pngyu.js +0 -869
  276. package/src/installs/pngyu.md +0 -896
  277. package/src/installs/postman.js +0 -799
  278. package/src/installs/postman.md +0 -940
  279. package/src/installs/procps.js +0 -425
  280. package/src/installs/procps.md +0 -851
  281. package/src/installs/safari-tech-preview.js +0 -374
  282. package/src/installs/safari-tech-preview.md +0 -533
  283. package/src/installs/sfnt2woff.js +0 -658
  284. package/src/installs/sfnt2woff.md +0 -795
  285. package/src/installs/shellcheck.js +0 -481
  286. package/src/installs/shellcheck.md +0 -1005
  287. package/src/installs/slack.js +0 -741
  288. package/src/installs/slack.md +0 -865
  289. package/src/installs/snagit.js +0 -585
  290. package/src/installs/snagit.md +0 -844
  291. package/src/installs/software-properties-common.js +0 -372
  292. package/src/installs/software-properties-common.md +0 -805
  293. package/src/installs/spotify.js +0 -877
  294. package/src/installs/spotify.md +0 -901
  295. package/src/installs/studio-3t.js +0 -823
  296. package/src/installs/studio-3t.md +0 -918
  297. package/src/installs/sublime-text.js +0 -804
  298. package/src/installs/sublime-text.md +0 -914
  299. package/src/installs/superwhisper.js +0 -706
  300. package/src/installs/superwhisper.md +0 -630
  301. package/src/installs/tailscale.js +0 -745
  302. package/src/installs/tailscale.md +0 -1100
  303. package/src/installs/tar.js +0 -389
  304. package/src/installs/tar.md +0 -946
  305. package/src/installs/termius.js +0 -798
  306. package/src/installs/termius.md +0 -844
  307. package/src/installs/terraform.js +0 -779
  308. package/src/installs/terraform.md +0 -899
  309. package/src/installs/tfenv.js +0 -778
  310. package/src/installs/tfenv.md +0 -1091
  311. package/src/installs/tidal.js +0 -771
  312. package/src/installs/tidal.md +0 -864
  313. package/src/installs/tmux.js +0 -346
  314. package/src/installs/tmux.md +0 -1030
  315. package/src/installs/tree.js +0 -411
  316. package/src/installs/tree.md +0 -833
  317. package/src/installs/unzip.js +0 -460
  318. package/src/installs/unzip.md +0 -879
  319. package/src/installs/vim.js +0 -421
  320. package/src/installs/vim.md +0 -1040
  321. package/src/installs/vlc.js +0 -821
  322. package/src/installs/vlc.md +0 -927
  323. package/src/installs/vscode.js +0 -843
  324. package/src/installs/vscode.md +0 -1002
  325. package/src/installs/wget.js +0 -420
  326. package/src/installs/wget.md +0 -791
  327. package/src/installs/whatsapp.js +0 -729
  328. package/src/installs/whatsapp.md +0 -854
  329. package/src/installs/winpty.js +0 -352
  330. package/src/installs/winpty.md +0 -620
  331. package/src/installs/woff2.js +0 -553
  332. package/src/installs/woff2.md +0 -977
  333. package/src/installs/wsl.js +0 -572
  334. package/src/installs/wsl.md +0 -699
  335. package/src/installs/xcode-clt.js +0 -520
  336. package/src/installs/xcode-clt.md +0 -351
  337. package/src/installs/xcode.js +0 -560
  338. package/src/installs/xcode.md +0 -573
  339. package/src/installs/yarn.js +0 -824
  340. package/src/installs/yarn.md +0 -1074
  341. package/src/installs/yq.js +0 -654
  342. package/src/installs/yq.md +0 -944
  343. package/src/installs/yt-dlp.js +0 -701
  344. package/src/installs/yt-dlp.md +0 -946
  345. package/src/installs/yum-utils.js +0 -297
  346. package/src/installs/yum-utils.md +0 -648
  347. package/src/installs/zoom.js +0 -759
  348. package/src/installs/zoom.md +0 -884
  349. package/src/installs/zsh.js +0 -455
  350. package/src/installs/zsh.md +0 -1008
  351. package/src/scripts/README.md +0 -617
  352. package/src/scripts/STATUS.md +0 -208
  353. package/src/scripts/afk.js +0 -411
  354. package/src/scripts/backup-all.js +0 -746
  355. package/src/scripts/backup-source.js +0 -727
  356. package/src/scripts/brewd.js +0 -389
  357. package/src/scripts/brewi.js +0 -520
  358. package/src/scripts/brewr.js +0 -527
  359. package/src/scripts/brews.js +0 -477
  360. package/src/scripts/brewu.js +0 -504
  361. package/src/scripts/c.js +0 -201
  362. package/src/scripts/ccurl.js +0 -341
  363. package/src/scripts/certbot-crontab-init.js +0 -504
  364. package/src/scripts/certbot-init.js +0 -657
  365. package/src/scripts/ch.js +0 -355
  366. package/src/scripts/claude-danger.js +0 -268
  367. package/src/scripts/clean-dev.js +0 -435
  368. package/src/scripts/clear-dns-cache.js +0 -541
  369. package/src/scripts/clone.js +0 -435
  370. package/src/scripts/code-all.js +0 -437
  371. package/src/scripts/count-files.js +0 -211
  372. package/src/scripts/count-folders.js +0 -211
  373. package/src/scripts/count.js +0 -264
  374. package/src/scripts/d.js +0 -219
  375. package/src/scripts/datauri.js +0 -389
  376. package/src/scripts/delete-files.js +0 -380
  377. package/src/scripts/docker-clean.js +0 -426
  378. package/src/scripts/dp.js +0 -442
  379. package/src/scripts/e.js +0 -390
  380. package/src/scripts/empty-trash.js +0 -513
  381. package/src/scripts/evm.js +0 -444
  382. package/src/scripts/fetch-github-repos.js +0 -456
  383. package/src/scripts/get-channel.js +0 -345
  384. package/src/scripts/get-course.js +0 -399
  385. package/src/scripts/get-dependencies.js +0 -306
  386. package/src/scripts/get-folder.js +0 -799
  387. package/src/scripts/get-tunes.js +0 -426
  388. package/src/scripts/get-video.js +0 -367
  389. package/src/scripts/git-backup.js +0 -577
  390. package/src/scripts/git-clone.js +0 -493
  391. package/src/scripts/git-pup.js +0 -319
  392. package/src/scripts/git-push.js +0 -396
  393. package/src/scripts/h.js +0 -622
  394. package/src/scripts/hide-desktop-icons.js +0 -499
  395. package/src/scripts/hide-hidden-files.js +0 -538
  396. package/src/scripts/install-dependencies-from.js +0 -456
  397. package/src/scripts/ips.js +0 -663
  398. package/src/scripts/iso.js +0 -370
  399. package/src/scripts/killni.js +0 -577
  400. package/src/scripts/ll.js +0 -467
  401. package/src/scripts/local-ip.js +0 -325
  402. package/src/scripts/m.js +0 -524
  403. package/src/scripts/map.js +0 -309
  404. package/src/scripts/mkd.js +0 -351
  405. package/src/scripts/ncu-update-all.js +0 -457
  406. package/src/scripts/nginx-init.js +0 -718
  407. package/src/scripts/npmi.js +0 -382
  408. package/src/scripts/o.js +0 -511
  409. package/src/scripts/org-by-date.js +0 -338
  410. package/src/scripts/p.js +0 -224
  411. package/src/scripts/packages.js +0 -330
  412. package/src/scripts/path.js +0 -225
  413. package/src/scripts/ports.js +0 -597
  414. package/src/scripts/q.js +0 -305
  415. package/src/scripts/refresh-files.js +0 -394
  416. package/src/scripts/remove-smaller-files.js +0 -516
  417. package/src/scripts/rename-files-with-date.js +0 -533
  418. package/src/scripts/resize-image.js +0 -539
  419. package/src/scripts/rm-safe.js +0 -669
  420. package/src/scripts/s.js +0 -540
  421. package/src/scripts/set-git-public.js +0 -365
  422. package/src/scripts/show-desktop-icons.js +0 -475
  423. package/src/scripts/show-hidden-files.js +0 -472
  424. package/src/scripts/tpa.js +0 -280
  425. package/src/scripts/tpo.js +0 -280
  426. package/src/scripts/u.js +0 -505
  427. package/src/scripts/vpush.js +0 -437
  428. package/src/scripts/y.js +0 -283
  429. package/src/utils/README.md +0 -95
  430. package/src/utils/common/apps.js +0 -143
  431. package/src/utils/common/display.js +0 -157
  432. package/src/utils/common/network.js +0 -185
  433. package/src/utils/common/os.js +0 -294
  434. package/src/utils/common/package-manager.js +0 -301
  435. package/src/utils/common/privileges.js +0 -138
  436. package/src/utils/common/shell.js +0 -261
  437. package/src/utils/macos/apps.js +0 -228
  438. package/src/utils/macos/brew.js +0 -315
  439. package/src/utils/ubuntu/apt.js +0 -307
  440. package/src/utils/ubuntu/desktop.js +0 -292
  441. package/src/utils/ubuntu/snap.js +0 -344
  442. package/src/utils/ubuntu/systemd.js +0 -286
  443. package/src/utils/windows/choco.js +0 -465
  444. package/src/utils/windows/env.js +0 -246
  445. package/src/utils/windows/registry.js +0 -269
  446. package/src/utils/windows/shell.js +0 -240
  447. package/src/utils/windows/winget.js +0 -489
@@ -0,0 +1,229 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const DEVUTILS_DIR = path.join(os.homedir(), '.devutils');
8
+ const PLUGINS_FILE = path.join(DEVUTILS_DIR, 'plugins.json');
9
+ const PLUGINS_DIR = path.join(DEVUTILS_DIR, 'plugins');
10
+
11
+ /**
12
+ * Reads and parses ~/.devutils/plugins.json.
13
+ * Returns an empty object if the file does not exist or is unreadable.
14
+ * Logs a warning to stderr if the file exists but contains invalid JSON.
15
+ *
16
+ * @returns {object} A map of plugin names to their entries, or {}.
17
+ */
18
+ function readPluginsJson() {
19
+ try {
20
+ const raw = fs.readFileSync(PLUGINS_FILE, 'utf8');
21
+ return JSON.parse(raw);
22
+ } catch (err) {
23
+ // If the file exists but JSON is invalid, warn the user
24
+ if (err instanceof SyntaxError && fs.existsSync(PLUGINS_FILE)) {
25
+ process.stderr.write(`Warning: ${PLUGINS_FILE} contains invalid JSON. Treating as empty.\n`);
26
+ }
27
+ return {};
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Validates that a plugin module exports the required contract fields.
33
+ * Returns null if valid, or a structured error object if something is missing.
34
+ *
35
+ * @param {object} pluginModule - The required plugin module.
36
+ * @param {string} pluginName - The plugin name (for error messages).
37
+ * @returns {object|null} Null if valid, or { error, code, message } if invalid.
38
+ */
39
+ function validateContract(pluginModule, pluginName) {
40
+ const required = ['name', 'description', 'version', 'auth', 'resources'];
41
+ const missing = required.filter(field => !pluginModule[field]);
42
+
43
+ if (missing.length > 0) {
44
+ return {
45
+ error: true,
46
+ code: 'INVALID_CONTRACT',
47
+ message: `Plugin "${pluginName}" is missing required fields: ${missing.join(', ')}.\nThe plugin may be outdated or incorrectly built.`
48
+ };
49
+ }
50
+
51
+ if (typeof pluginModule.resources !== 'object') {
52
+ return {
53
+ error: true,
54
+ code: 'INVALID_CONTRACT',
55
+ message: `Plugin "${pluginName}" has an invalid resources export. Expected an object.`
56
+ };
57
+ }
58
+
59
+ return null;
60
+ }
61
+
62
+ /**
63
+ * Loads a plugin by name from the installed plugins directory.
64
+ * Reads plugins.json, requires the package, and validates the contract.
65
+ *
66
+ * @param {string} pluginName - The short plugin name (e.g., 'gmail').
67
+ * @returns {object} { error: false, plugin } on success, or { error: true, code, message } on failure.
68
+ */
69
+ function loadPlugin(pluginName) {
70
+ const plugins = readPluginsJson();
71
+ const entry = plugins[pluginName];
72
+
73
+ if (!entry) {
74
+ return {
75
+ error: true,
76
+ code: 'NOT_INSTALLED',
77
+ message: `API plugin "${pluginName}" is not installed.\nRun "dev api enable ${pluginName}" to install it.`
78
+ };
79
+ }
80
+
81
+ const packagePath = path.join(PLUGINS_DIR, 'node_modules', entry.package);
82
+
83
+ let pluginModule;
84
+ try {
85
+ pluginModule = require(packagePath);
86
+ } catch (err) {
87
+ return {
88
+ error: true,
89
+ code: 'LOAD_FAILED',
90
+ message: `Failed to load plugin "${pluginName}" from ${packagePath}.\nThe package may be corrupted. Try "dev api disable ${pluginName}" then "dev api enable ${pluginName}".`
91
+ };
92
+ }
93
+
94
+ // Validate the plugin contract
95
+ const validation = validateContract(pluginModule, pluginName);
96
+ if (validation) {
97
+ return validation;
98
+ }
99
+
100
+ return { error: false, plugin: pluginModule };
101
+ }
102
+
103
+ /**
104
+ * Resolves a specific command from a plugin's resource tree.
105
+ * Given a plugin name, resource name, and command name, loads the plugin
106
+ * and walks the resource/command tree to find the command module.
107
+ *
108
+ * @param {string} pluginName - The plugin name (e.g., 'gmail').
109
+ * @param {string} resourceName - The resource name (e.g., 'messages').
110
+ * @param {string} commandName - The command name (e.g., 'list').
111
+ * @returns {object} { error: false, command, plugin } on success, or { error: true, code, message } on failure.
112
+ */
113
+ function resolveCommand(pluginName, resourceName, commandName) {
114
+ const result = loadPlugin(pluginName);
115
+ if (result.error) return result;
116
+
117
+ const plugin = result.plugin;
118
+ const resource = plugin.resources[resourceName];
119
+
120
+ if (!resource) {
121
+ const available = Object.keys(plugin.resources).join(', ');
122
+ return {
123
+ error: true,
124
+ code: 'UNKNOWN_RESOURCE',
125
+ message: `Plugin "${pluginName}" has no resource "${resourceName}".\nAvailable resources: ${available}`
126
+ };
127
+ }
128
+
129
+ const commandLoader = resource.commands[commandName];
130
+ if (!commandLoader) {
131
+ const available = Object.keys(resource.commands).join(', ');
132
+ return {
133
+ error: true,
134
+ code: 'UNKNOWN_COMMAND',
135
+ message: `Resource "${resourceName}" in plugin "${pluginName}" has no command "${commandName}".\nAvailable commands: ${available}`
136
+ };
137
+ }
138
+
139
+ let commandModule;
140
+ try {
141
+ commandModule = typeof commandLoader === 'function' ? commandLoader() : commandLoader;
142
+ } catch (err) {
143
+ return {
144
+ error: true,
145
+ code: 'COMMAND_LOAD_FAILED',
146
+ message: `Failed to load command "${commandName}" from plugin "${pluginName}": ${err.message}`
147
+ };
148
+ }
149
+
150
+ return {
151
+ error: false,
152
+ command: commandModule,
153
+ plugin: plugin
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Builds the context object that plugin commands receive.
159
+ * Reads the auth credential for the plugin's declared auth service
160
+ * and unwraps the credential envelope so plugins get flat access.
161
+ *
162
+ * @param {object} plugin - The plugin's contract object (must have an auth field).
163
+ * @param {object} coreContext - The core CLI context (output, errors, config, shell, platform).
164
+ * @returns {object} The enriched plugin context with auth, output, errors, config, shell, platform.
165
+ */
166
+ function buildPluginContext(plugin, coreContext) {
167
+ const authService = plugin.auth;
168
+
169
+ // Read the auth credential for this plugin's declared service
170
+ const authFilePath = path.join(DEVUTILS_DIR, 'auth', `${authService}.json`);
171
+ let authCredential = null;
172
+ try {
173
+ const raw = fs.readFileSync(authFilePath, 'utf8');
174
+ const credentialFile = JSON.parse(raw);
175
+
176
+ // Unwrap the credential envelope. The auth system stores files as:
177
+ // { service, type, credentials: { ... } }
178
+ // Plugins expect flat access (e.g., context.auth.accessKeyId), so we
179
+ // pass credentialFile.credentials directly instead of the full envelope.
180
+ authCredential = credentialFile.credentials || credentialFile;
181
+ } catch (err) {
182
+ // Auth not available - plugin commands will get null
183
+ }
184
+
185
+ return {
186
+ auth: authCredential,
187
+ output: coreContext.output,
188
+ errors: coreContext.errors,
189
+ config: coreContext.config,
190
+ shell: coreContext.shell,
191
+ platform: coreContext.platform
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Returns all installed plugins from plugins.json.
197
+ * Returns an empty object if no plugins are installed.
198
+ *
199
+ * @returns {object} A map of plugin names to their entries.
200
+ */
201
+ function getInstalledPlugins() {
202
+ return readPluginsJson();
203
+ }
204
+
205
+ /**
206
+ * Returns the list of available plugins from the bundled registry.
207
+ * Returns an empty array if the registry file is missing or unreadable.
208
+ *
209
+ * @returns {Array<object>} An array of registry plugin entries.
210
+ */
211
+ function getRegistryPlugins() {
212
+ try {
213
+ return require('./registry.json');
214
+ } catch (err) {
215
+ return [];
216
+ }
217
+ }
218
+
219
+ module.exports = {
220
+ resolveCommand,
221
+ loadPlugin,
222
+ buildPluginContext,
223
+ validateContract,
224
+ getInstalledPlugins,
225
+ getRegistryPlugins,
226
+ readPluginsJson,
227
+ PLUGINS_FILE,
228
+ PLUGINS_DIR
229
+ };
@@ -0,0 +1,62 @@
1
+ [
2
+ {
3
+ "name": "gmail",
4
+ "package": "@fredlackey/devutils-api-gmail",
5
+ "description": "Google Gmail (messages, labels, drafts, threads)",
6
+ "auth": "google"
7
+ },
8
+ {
9
+ "name": "drive",
10
+ "package": "@fredlackey/devutils-api-drive",
11
+ "description": "Google Drive (files, folders, permissions)",
12
+ "auth": "google"
13
+ },
14
+ {
15
+ "name": "sheets",
16
+ "package": "@fredlackey/devutils-api-sheets",
17
+ "description": "Google Sheets (spreadsheets, values, sheets)",
18
+ "auth": "google"
19
+ },
20
+ {
21
+ "name": "docs",
22
+ "package": "@fredlackey/devutils-api-docs",
23
+ "description": "Google Docs (documents)",
24
+ "auth": "google"
25
+ },
26
+ {
27
+ "name": "aws",
28
+ "package": "@fredlackey/devutils-api-aws",
29
+ "description": "Amazon Web Services (compute, storage, functions, groups)",
30
+ "auth": "aws"
31
+ },
32
+ {
33
+ "name": "cloudflare",
34
+ "package": "@fredlackey/devutils-api-cloudflare",
35
+ "description": "Cloudflare (zones, DNS records, API tokens)",
36
+ "auth": "cloudflare"
37
+ },
38
+ {
39
+ "name": "dokploy",
40
+ "package": "@fredlackey/devutils-api-dokploy",
41
+ "description": "Dokploy (applications, projects, domains, servers)",
42
+ "auth": "dokploy"
43
+ },
44
+ {
45
+ "name": "namecheap",
46
+ "package": "@fredlackey/devutils-api-namecheap",
47
+ "description": "Namecheap (domains, DNS, SSL certificates)",
48
+ "auth": "namecheap"
49
+ },
50
+ {
51
+ "name": "flowroute",
52
+ "package": "@fredlackey/devutils-api-flowroute",
53
+ "description": "Flowroute (SMS, MMS, phone numbers)",
54
+ "auth": "flowroute"
55
+ },
56
+ {
57
+ "name": "mailu",
58
+ "package": "@fredlackey/devutils-api-mailu",
59
+ "description": "Mailu (email users, aliases, domains)",
60
+ "auth": "mailu"
61
+ }
62
+ ]
package/src/cli.js CHANGED
@@ -1,72 +1,305 @@
1
1
  #!/usr/bin/env node
2
+ 'use strict';
2
3
 
3
4
  /**
4
- * @fileoverview CLI setup using Commander.js
5
- * Registers all commands and handles program execution.
5
+ * Command router. Parses arguments, resolves the service and method, applies
6
+ * global flags, runs output format detection, and dispatches to the right
7
+ * command file.
8
+ *
9
+ * This file should not contain business logic. It's routing only.
6
10
  */
7
11
 
8
- const { program } = require('commander');
9
- const pkg = require('../package.json');
12
+ const TOP_LEVEL_COMMANDS = ['status', 'update', 'version', 'schema', 'help'];
10
13
 
11
- const configureCommand = require('./commands/configure');
12
- const statusCommand = require('./commands/status');
13
- const identityCommand = require('./commands/identity');
14
- const ignoreCommand = require('./commands/ignore');
15
- const installCommand = require('./commands/install');
16
- const versionCommand = require('./commands/version');
17
- const updateCommand = require('./commands/update');
18
- const { installCompletion, uninstallCompletion } = require('./completion');
14
+ /**
15
+ * Extracts global flags from the argument list and returns the remaining args.
16
+ * Global flags can appear anywhere in the argument list.
17
+ *
18
+ * @param {string[]} args - Raw arguments from process.argv.slice(2).
19
+ * @returns {{ flags: object, remaining: string[] }}
20
+ */
21
+ function parseGlobalFlags(args) {
22
+ const flags = {
23
+ format: null,
24
+ dryRun: false,
25
+ verbose: false,
26
+ quiet: false,
27
+ help: false,
28
+ version: false,
29
+ jsonInput: null,
30
+ };
31
+
32
+ const remaining = [];
33
+ let i = 0;
34
+
35
+ while (i < args.length) {
36
+ const arg = args[i];
37
+
38
+ if (arg === '--format' && i + 1 < args.length) {
39
+ flags.format = args[i + 1];
40
+ i += 2;
41
+ } else if (arg === '--dry-run') {
42
+ flags.dryRun = true;
43
+ i++;
44
+ } else if (arg === '--verbose') {
45
+ flags.verbose = true;
46
+ i++;
47
+ } else if (arg === '--quiet') {
48
+ flags.quiet = true;
49
+ i++;
50
+ } else if (arg === '--help' || arg === '-h') {
51
+ flags.help = true;
52
+ i++;
53
+ } else if (arg === '--version' || arg === '-v') {
54
+ flags.version = true;
55
+ i++;
56
+ } else if (arg === '--json' && i + 1 < args.length) {
57
+ flags.jsonInput = args[i + 1];
58
+ i += 2;
59
+ } else {
60
+ remaining.push(arg);
61
+ i++;
62
+ }
63
+ }
64
+
65
+ return { flags, remaining };
66
+ }
67
+
68
+ /**
69
+ * Parses remaining command arguments into a structured object.
70
+ * --key value pairs go into flags, everything else into positional.
71
+ *
72
+ * @param {string[]} rawArgs - Arguments after service/method have been stripped.
73
+ * @returns {{ positional: string[], flags: object }}
74
+ */
75
+ function parseCommandArgs(rawArgs) {
76
+ const positional = [];
77
+ const flags = {};
78
+ let i = 0;
79
+
80
+ while (i < rawArgs.length) {
81
+ const arg = rawArgs[i];
82
+
83
+ if (arg.startsWith('--')) {
84
+ const key = arg.slice(2);
85
+
86
+ // Check if next arg exists and is not itself a flag
87
+ if (i + 1 < rawArgs.length && !rawArgs[i + 1].startsWith('--')) {
88
+ flags[key] = rawArgs[i + 1];
89
+ i += 2;
90
+ } else {
91
+ flags[key] = true;
92
+ i++;
93
+ }
94
+ } else {
95
+ positional.push(arg);
96
+ i++;
97
+ }
98
+ }
99
+
100
+ return { positional, flags };
101
+ }
19
102
 
20
103
  /**
21
- * Run the CLI program
104
+ * Displays the CLI help message listing all services, commands, and global flags.
22
105
  */
23
- function run() {
24
- program
25
- .name('dev')
26
- .description('CLI toolkit for bootstrapping development environments')
27
- .version(pkg.version, '-v, --version', 'Display version number');
28
-
29
- // Global options
30
- program
31
- .option('--verbose', 'Enable verbose output')
32
- .option('-q, --quiet', 'Suppress non-essential output')
33
- .option('--no-color', 'Disable colored output');
34
-
35
- // Add commands
36
- program.addCommand(configureCommand);
37
- program.addCommand(statusCommand);
38
- program.addCommand(identityCommand);
39
- program.addCommand(ignoreCommand);
40
- program.addCommand(installCommand);
41
- program.addCommand(versionCommand);
42
- program.addCommand(updateCommand);
43
-
44
- // Setup command - install essential tools
45
- const setupCommand = require('./commands/setup');
46
- program.addCommand(setupCommand);
47
-
48
- // Completion management
49
- const completion = program
50
- .command('completion')
51
- .description('Manage shell tab completion');
52
-
53
- completion
54
- .command('install')
55
- .description('Install tab completion for your shell')
56
- .action(installCompletion);
57
-
58
- completion
59
- .command('uninstall')
60
- .description('Remove tab completion')
61
- .action(uninstallCompletion);
62
-
63
- // Parse and execute
64
- program.parse(process.argv);
65
-
66
- // If no command specified, show help
67
- if (process.argv.length === 2) {
68
- program.help();
106
+ function showHelp() {
107
+ const pkg = require('../package.json');
108
+ console.log(`DevUtils CLI v${pkg.version}`);
109
+ console.log('');
110
+ console.log('Usage: dev <service> <method> [arguments] [flags]');
111
+ console.log('');
112
+ console.log('Services:');
113
+ console.log(' config User configuration and onboarding');
114
+ console.log(' machine Machine profiles and detection');
115
+ console.log(' identity Git identities, SSH keys, GPG signing');
116
+ console.log(' tools Tool installation and management');
117
+ console.log(' ignore .gitignore pattern management');
118
+ console.log(' util Utility functions');
119
+ console.log(' alias Shorthand bin entries');
120
+ console.log(' auth OAuth and credential management');
121
+ console.log(' api API plugin system');
122
+ console.log(' ai AI coding assistant launcher');
123
+ console.log(' search Markdown search');
124
+ console.log('');
125
+ console.log('Commands:');
126
+ console.log(' status Overall health check');
127
+ console.log(' version Show current version');
128
+ console.log(' help Show this help message');
129
+ console.log('');
130
+ console.log('Global Flags:');
131
+ console.log(' --format <json|table|yaml|csv> Output format');
132
+ console.log(' --dry-run Show what would happen');
133
+ console.log(' --verbose Increase output detail');
134
+ console.log(' --quiet Suppress non-essential output');
135
+ console.log(' --json <data> Pass structured input as JSON');
136
+ console.log(' --help, -h Show help');
137
+ console.log(' --version, -v Show version');
138
+ }
139
+
140
+ /**
141
+ * Resolves a command from the remaining arguments.
142
+ * Checks top-level commands first, then service/method routing.
143
+ *
144
+ * @param {string[]} remaining - Arguments with global flags stripped.
145
+ * @returns {object|null} The resolved command, args, and optional service.
146
+ */
147
+ function resolveCommand(remaining) {
148
+ const serviceName = remaining[0];
149
+ const methodName = remaining[1];
150
+ const commandArgs = remaining.slice(2);
151
+
152
+ // Check for top-level command first
153
+ if (TOP_LEVEL_COMMANDS.includes(serviceName)) {
154
+ try {
155
+ const cmd = require(`./commands/${serviceName}`);
156
+ return { command: cmd, args: parseCommandArgs(remaining.slice(1)) };
157
+ } catch {
158
+ return null;
159
+ }
160
+ }
161
+
162
+ // Try to load the service index
163
+ let service;
164
+ try {
165
+ service = require(`./commands/${serviceName}/index`);
166
+ } catch {
167
+ return null;
168
+ }
169
+
170
+ // If no method specified, show service help
171
+ if (!methodName) {
172
+ return { service, command: null, args: parseCommandArgs([]) };
173
+ }
174
+
175
+ // Look up the method in the service's commands
176
+ if (!service.commands || !service.commands[methodName]) {
177
+ return { service, command: null, unknownMethod: methodName, args: parseCommandArgs(commandArgs) };
178
+ }
179
+
180
+ // Lazy-load the command
181
+ const command = service.commands[methodName]();
182
+ return { command, args: parseCommandArgs(commandArgs), service };
183
+ }
184
+
185
+ /**
186
+ * Builds the context object that every command receives.
187
+ * Contains all foundation modules pre-configured for the current invocation.
188
+ *
189
+ * @param {object} flags - The parsed global flags.
190
+ * @returns {object} The context object.
191
+ */
192
+ function buildContext(flags) {
193
+ const detect = require('./lib/detect');
194
+ const output = require('./lib/output');
195
+ const errors = require('./lib/errors');
196
+ const platform = require('./lib/platform');
197
+ const shell = require('./lib/shell');
198
+ const config = require('./lib/config');
199
+ const prompt = require('./lib/prompt');
200
+
201
+ // Determine output format: flag override > detection
202
+ const detected = detect.detectOutputMode();
203
+ const format = flags.format || detected.format;
204
+ const caller = detected.caller;
205
+
206
+ // Create pre-configured formatter
207
+ const formatter = output.createFormatter({ format, caller });
208
+
209
+ let jsonInput = null;
210
+ if (flags.jsonInput) {
211
+ try {
212
+ jsonInput = JSON.parse(flags.jsonInput);
213
+ } catch {
214
+ jsonInput = null;
215
+ }
216
+ }
217
+
218
+ return {
219
+ platform,
220
+ shell,
221
+ config,
222
+ prompt,
223
+ errors,
224
+ output: formatter,
225
+ flags: {
226
+ format,
227
+ caller,
228
+ dryRun: flags.dryRun,
229
+ verbose: flags.verbose,
230
+ quiet: flags.quiet,
231
+ jsonInput,
232
+ },
233
+ };
234
+ }
235
+
236
+ /**
237
+ * Main entry point. Parses args, resolves the command, builds context, and runs.
238
+ */
239
+ async function main() {
240
+ const { flags, remaining } = parseGlobalFlags(process.argv.slice(2));
241
+
242
+ // Handle --version
243
+ if (flags.version) {
244
+ const pkg = require('../package.json');
245
+ console.log(pkg.version);
246
+ return;
247
+ }
248
+
249
+ // Handle --help or no arguments
250
+ if (flags.help || remaining.length === 0) {
251
+ showHelp();
252
+ return;
253
+ }
254
+
255
+ // Resolve the command
256
+ const resolved = resolveCommand(remaining);
257
+
258
+ if (!resolved || !resolved.command) {
259
+ const errors = require('./lib/errors');
260
+ if (resolved && resolved.unknownMethod) {
261
+ const methods = Object.keys(resolved.service.commands || {}).join(', ');
262
+ errors.throwError(
263
+ 404,
264
+ `Unknown method "${resolved.unknownMethod}" for service "${resolved.service.name}". Available methods: ${methods}`,
265
+ resolved.service.name
266
+ );
267
+ } else if (resolved && resolved.service && !resolved.command) {
268
+ // Service exists but no method given -- show service commands
269
+ const methods = Object.keys(resolved.service.commands || {});
270
+ console.log(`${resolved.service.name}: ${resolved.service.description}`);
271
+ console.log('');
272
+ console.log('Methods:');
273
+ for (const method of methods) {
274
+ console.log(` dev ${resolved.service.name} ${method}`);
275
+ }
276
+ return;
277
+ } else {
278
+ const serviceName = remaining[0];
279
+ errors.throwError(
280
+ 404,
281
+ `Unknown command "${serviceName}". Run "dev help" to see available commands.`,
282
+ 'cli'
283
+ );
284
+ }
285
+ return;
286
+ }
287
+
288
+ // Build context and run
289
+ const context = buildContext(flags);
290
+ try {
291
+ await resolved.command.run(resolved.args, context);
292
+ } catch (err) {
293
+ const errors = require('./lib/errors');
294
+ if (errors.isDevUtilsError(err)) {
295
+ context.output.err(err);
296
+ } else {
297
+ errors.throwError(500, err.message || 'An unexpected error occurred', 'cli');
298
+ }
69
299
  }
70
300
  }
71
301
 
72
- module.exports = { run };
302
+ main().catch(err => {
303
+ console.error(err);
304
+ process.exit(1);
305
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * AI service registration.
3
+ * AI coding assistant launcher and session management.
4
+ */
5
+ module.exports = {
6
+ name: 'ai',
7
+ description: 'AI coding assistant launcher and session management',
8
+ commands: {
9
+ launch: () => require('./launch'),
10
+ resume: () => require('./resume'),
11
+ list: () => require('./list'),
12
+ sessions: () => require('./sessions'),
13
+ show: () => require('./show'),
14
+ set: () => require('./set'),
15
+ }
16
+ };