@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.
- package/README.md +214 -141
- package/package.json +8 -83
- package/src/api/loader.js +229 -0
- package/src/api/registry.json +62 -0
- package/src/cli.js +293 -60
- package/src/commands/ai/index.js +16 -0
- package/src/commands/ai/launch.js +112 -0
- package/src/commands/ai/list.js +54 -0
- package/src/commands/ai/resume.js +70 -0
- package/src/commands/ai/sessions.js +121 -0
- package/src/commands/ai/set.js +131 -0
- package/src/commands/ai/show.js +74 -0
- package/src/commands/ai/tools.js +46 -0
- package/src/commands/alias/add.js +93 -0
- package/src/commands/alias/helpers.js +107 -0
- package/src/commands/alias/index.js +14 -0
- package/src/commands/alias/list.js +55 -0
- package/src/commands/alias/remove.js +62 -0
- package/src/commands/alias/sync.js +109 -0
- package/src/commands/api/disable.js +73 -0
- package/src/commands/api/enable.js +148 -0
- package/src/commands/api/index.js +15 -0
- package/src/commands/api/list.js +66 -0
- package/src/commands/api/update.js +87 -0
- package/src/commands/auth/index.js +15 -0
- package/src/commands/auth/list.js +49 -0
- package/src/commands/auth/login.js +384 -0
- package/src/commands/auth/logout.js +111 -0
- package/src/commands/auth/refresh.js +184 -0
- package/src/commands/auth/services.js +169 -0
- package/src/commands/auth/status.js +104 -0
- package/src/commands/config/export.js +224 -0
- package/src/commands/config/get.js +52 -0
- package/src/commands/config/import.js +308 -0
- package/src/commands/config/index.js +17 -0
- package/src/commands/config/init.js +143 -0
- package/src/commands/config/reset.js +57 -0
- package/src/commands/config/set.js +93 -0
- package/src/commands/config/show.js +35 -0
- package/src/commands/help.js +338 -0
- package/src/commands/identity/add.js +133 -0
- package/src/commands/identity/index.js +17 -0
- package/src/commands/identity/link.js +76 -0
- package/src/commands/identity/list.js +48 -0
- package/src/commands/identity/remove.js +72 -0
- package/src/commands/identity/show.js +65 -0
- package/src/commands/identity/sync.js +172 -0
- package/src/commands/identity/unlink.js +57 -0
- package/src/commands/ignore/add.js +165 -0
- package/src/commands/ignore/index.js +14 -0
- package/src/commands/ignore/list.js +89 -0
- package/src/commands/ignore/markers.js +43 -0
- package/src/commands/ignore/remove.js +164 -0
- package/src/commands/ignore/show.js +169 -0
- package/src/commands/machine/detect.js +122 -0
- package/src/commands/machine/index.js +14 -0
- package/src/commands/machine/list.js +74 -0
- package/src/commands/machine/set.js +106 -0
- package/src/commands/machine/show.js +35 -0
- package/src/commands/schema.js +152 -0
- package/src/commands/search/collections.js +134 -0
- package/src/commands/search/get.js +71 -0
- package/src/commands/search/index-cmd.js +54 -0
- package/src/commands/search/index.js +21 -0
- package/src/commands/search/keyword.js +60 -0
- package/src/commands/search/qmd.js +70 -0
- package/src/commands/search/query.js +64 -0
- package/src/commands/search/semantic.js +62 -0
- package/src/commands/search/status.js +46 -0
- package/src/commands/status.js +224 -171
- package/src/commands/tools/check.js +79 -0
- package/src/commands/tools/index.js +14 -0
- package/src/commands/tools/install.js +110 -0
- package/src/commands/tools/list.js +91 -0
- package/src/commands/tools/search.js +60 -0
- package/src/commands/update.js +83 -112
- package/src/commands/util/add.js +151 -0
- package/src/commands/util/index.js +15 -0
- package/src/commands/util/list.js +97 -0
- package/src/commands/util/remove.js +76 -0
- package/src/commands/util/run.js +79 -0
- package/src/commands/util/show.js +67 -0
- package/src/commands/version.js +21 -88
- package/src/installers/_template.js +104 -0
- package/src/installers/git.js +150 -0
- package/src/installers/homebrew.js +190 -0
- package/src/installers/node.js +223 -0
- package/src/installers/registry.json +29 -0
- package/src/lib/config.js +125 -0
- package/src/lib/detect.js +74 -0
- package/src/lib/errors.js +114 -0
- package/src/lib/github.js +315 -0
- package/src/lib/installer.js +225 -0
- package/src/lib/output.js +239 -0
- package/src/lib/platform.js +112 -0
- package/src/lib/platforms/amazon-linux.js +41 -0
- package/src/lib/platforms/gitbash.js +46 -0
- package/src/lib/platforms/macos.js +45 -0
- package/src/lib/platforms/raspbian.js +41 -0
- package/src/lib/platforms/ubuntu.js +39 -0
- package/src/lib/platforms/windows.js +45 -0
- package/src/lib/prompt.js +161 -0
- package/src/lib/schema.js +211 -0
- package/src/lib/shell.js +75 -0
- package/src/patterns/gitignore/claude-code.txt +25 -0
- package/src/patterns/gitignore/docker.txt +15 -0
- package/src/patterns/gitignore/go.txt +24 -0
- package/src/patterns/gitignore/java.txt +38 -0
- package/src/patterns/gitignore/jetbrains.txt +26 -0
- package/src/patterns/gitignore/linux.txt +18 -0
- package/src/patterns/gitignore/macos.txt +27 -0
- package/src/patterns/gitignore/node.txt +51 -0
- package/src/patterns/gitignore/python.txt +55 -0
- package/src/patterns/gitignore/rust.txt +14 -0
- package/src/patterns/gitignore/terraform.txt +30 -0
- package/src/patterns/gitignore/vscode.txt +15 -0
- package/src/patterns/gitignore/windows.txt +25 -0
- package/src/utils/clone/index.js +165 -0
- package/src/utils/git-push/index.js +230 -0
- package/src/utils/git-status/index.js +116 -0
- package/src/utils/git-status/unix.sh +75 -0
- package/src/utils/registry.json +41 -0
- package/bin/dev.js +0 -16
- package/files/README.md +0 -0
- package/files/claude/.claude/commands/setup-context.md +0 -3
- package/files/monorepos/_archive/README.md +0 -36
- package/files/monorepos/_legacy/README.md +0 -36
- package/files/monorepos/ai-docs/README.md +0 -33
- package/files/monorepos/apps/README.md +0 -24
- package/files/monorepos/docs/README.md +0 -40
- package/files/monorepos/packages/README.md +0 -25
- package/files/monorepos/research/README.md +0 -29
- package/files/monorepos/scripts/README.md +0 -24
- package/src/commands/README.md +0 -41
- package/src/commands/configure.js +0 -199
- package/src/commands/identity.js +0 -1630
- package/src/commands/ignore.js +0 -247
- package/src/commands/install.js +0 -526
- package/src/commands/setup.js +0 -246
- package/src/completion.js +0 -284
- package/src/constants.js +0 -45
- package/src/ignore/claude-code.txt +0 -10
- package/src/ignore/docker.txt +0 -18
- package/src/ignore/linux.txt +0 -23
- package/src/ignore/macos.txt +0 -36
- package/src/ignore/node.txt +0 -55
- package/src/ignore/terraform.txt +0 -37
- package/src/ignore/vscode.txt +0 -18
- package/src/ignore/windows.txt +0 -35
- package/src/index.js +0 -0
- package/src/installs/README.md +0 -399
- package/src/installs/adobe-creative-cloud.js +0 -546
- package/src/installs/adobe-creative-cloud.md +0 -605
- package/src/installs/appcleaner.js +0 -321
- package/src/installs/appcleaner.md +0 -699
- package/src/installs/apt-transport-https.js +0 -390
- package/src/installs/apt-transport-https.md +0 -678
- package/src/installs/atomicparsley.js +0 -642
- package/src/installs/atomicparsley.md +0 -795
- package/src/installs/aws-cli.js +0 -797
- package/src/installs/aws-cli.md +0 -727
- package/src/installs/balena-etcher.js +0 -710
- package/src/installs/balena-etcher.md +0 -761
- package/src/installs/bambu-studio.js +0 -1143
- package/src/installs/bambu-studio.md +0 -780
- package/src/installs/bash-completion.js +0 -575
- package/src/installs/bash-completion.md +0 -833
- package/src/installs/bash.js +0 -417
- package/src/installs/bash.md +0 -993
- package/src/installs/beyond-compare.js +0 -603
- package/src/installs/beyond-compare.md +0 -813
- package/src/installs/brave-browser.js +0 -968
- package/src/installs/brave-browser.md +0 -650
- package/src/installs/build-essential.js +0 -529
- package/src/installs/build-essential.md +0 -977
- package/src/installs/ca-certificates.js +0 -618
- package/src/installs/ca-certificates.md +0 -937
- package/src/installs/caffeine.js +0 -508
- package/src/installs/caffeine.md +0 -839
- package/src/installs/camtasia.js +0 -596
- package/src/installs/camtasia.md +0 -762
- package/src/installs/chatgpt.js +0 -476
- package/src/installs/chatgpt.md +0 -814
- package/src/installs/chocolatey.js +0 -456
- package/src/installs/chocolatey.md +0 -661
- package/src/installs/chrome-canary.js +0 -419
- package/src/installs/chrome-canary.md +0 -641
- package/src/installs/chromium.js +0 -667
- package/src/installs/chromium.md +0 -838
- package/src/installs/claude-code.js +0 -576
- package/src/installs/claude-code.md +0 -1173
- package/src/installs/cloudflare-warp.js +0 -900
- package/src/installs/cloudflare-warp.md +0 -1047
- package/src/installs/comet-browser.js +0 -588
- package/src/installs/comet-browser.md +0 -731
- package/src/installs/curl.js +0 -379
- package/src/installs/curl.md +0 -714
- package/src/installs/cursor.js +0 -579
- package/src/installs/cursor.md +0 -970
- package/src/installs/dbeaver.js +0 -924
- package/src/installs/dbeaver.md +0 -939
- package/src/installs/dbschema.js +0 -692
- package/src/installs/dbschema.md +0 -925
- package/src/installs/dependencies.md +0 -453
- package/src/installs/development-tools.js +0 -600
- package/src/installs/development-tools.md +0 -977
- package/src/installs/docker.js +0 -1029
- package/src/installs/docker.md +0 -1109
- package/src/installs/drawio.js +0 -1019
- package/src/installs/drawio.md +0 -795
- package/src/installs/elmedia-player.js +0 -347
- package/src/installs/elmedia-player.md +0 -556
- package/src/installs/ffmpeg.js +0 -889
- package/src/installs/ffmpeg.md +0 -852
- package/src/installs/file.js +0 -464
- package/src/installs/file.md +0 -987
- package/src/installs/gemini-cli.js +0 -811
- package/src/installs/gemini-cli.md +0 -1153
- package/src/installs/git.js +0 -400
- package/src/installs/git.md +0 -907
- package/src/installs/gitego.js +0 -949
- package/src/installs/gitego.md +0 -1172
- package/src/installs/go.js +0 -931
- package/src/installs/go.md +0 -958
- package/src/installs/google-antigravity.js +0 -913
- package/src/installs/google-antigravity.md +0 -1075
- package/src/installs/google-chrome.js +0 -833
- package/src/installs/google-chrome.md +0 -862
- package/src/installs/gpg.js +0 -480
- package/src/installs/gpg.md +0 -1056
- package/src/installs/homebrew.js +0 -1028
- package/src/installs/homebrew.md +0 -988
- package/src/installs/imageoptim.js +0 -968
- package/src/installs/imageoptim.md +0 -1119
- package/src/installs/installers.json +0 -4032
- package/src/installs/installers.json.tmp +0 -3953
- package/src/installs/jq.js +0 -400
- package/src/installs/jq.md +0 -809
- package/src/installs/keyboard-maestro.js +0 -719
- package/src/installs/keyboard-maestro.md +0 -825
- package/src/installs/kiro.js +0 -864
- package/src/installs/kiro.md +0 -1015
- package/src/installs/latex.js +0 -789
- package/src/installs/latex.md +0 -1095
- package/src/installs/lftp.js +0 -356
- package/src/installs/lftp.md +0 -907
- package/src/installs/lsb-release.js +0 -346
- package/src/installs/lsb-release.md +0 -814
- package/src/installs/messenger.js +0 -847
- package/src/installs/messenger.md +0 -900
- package/src/installs/microsoft-office.js +0 -568
- package/src/installs/microsoft-office.md +0 -760
- package/src/installs/microsoft-teams.js +0 -801
- package/src/installs/microsoft-teams.md +0 -886
- package/src/installs/moom.js +0 -326
- package/src/installs/moom.md +0 -570
- package/src/installs/node.js +0 -904
- package/src/installs/node.md +0 -1153
- package/src/installs/nordpass.js +0 -716
- package/src/installs/nordpass.md +0 -921
- package/src/installs/nordvpn.js +0 -892
- package/src/installs/nordvpn.md +0 -1052
- package/src/installs/nvm.js +0 -995
- package/src/installs/nvm.md +0 -1057
- package/src/installs/ohmyzsh.js +0 -529
- package/src/installs/ohmyzsh.md +0 -1094
- package/src/installs/openssh.js +0 -804
- package/src/installs/openssh.md +0 -1056
- package/src/installs/pandoc.js +0 -662
- package/src/installs/pandoc.md +0 -1036
- package/src/installs/parallels-desktop.js +0 -431
- package/src/installs/parallels-desktop.md +0 -446
- package/src/installs/pinentry.js +0 -510
- package/src/installs/pinentry.md +0 -1142
- package/src/installs/pngyu.js +0 -869
- package/src/installs/pngyu.md +0 -896
- package/src/installs/postman.js +0 -799
- package/src/installs/postman.md +0 -940
- package/src/installs/procps.js +0 -425
- package/src/installs/procps.md +0 -851
- package/src/installs/safari-tech-preview.js +0 -374
- package/src/installs/safari-tech-preview.md +0 -533
- package/src/installs/sfnt2woff.js +0 -658
- package/src/installs/sfnt2woff.md +0 -795
- package/src/installs/shellcheck.js +0 -481
- package/src/installs/shellcheck.md +0 -1005
- package/src/installs/slack.js +0 -741
- package/src/installs/slack.md +0 -865
- package/src/installs/snagit.js +0 -585
- package/src/installs/snagit.md +0 -844
- package/src/installs/software-properties-common.js +0 -372
- package/src/installs/software-properties-common.md +0 -805
- package/src/installs/spotify.js +0 -877
- package/src/installs/spotify.md +0 -901
- package/src/installs/studio-3t.js +0 -823
- package/src/installs/studio-3t.md +0 -918
- package/src/installs/sublime-text.js +0 -804
- package/src/installs/sublime-text.md +0 -914
- package/src/installs/superwhisper.js +0 -706
- package/src/installs/superwhisper.md +0 -630
- package/src/installs/tailscale.js +0 -745
- package/src/installs/tailscale.md +0 -1100
- package/src/installs/tar.js +0 -389
- package/src/installs/tar.md +0 -946
- package/src/installs/termius.js +0 -798
- package/src/installs/termius.md +0 -844
- package/src/installs/terraform.js +0 -779
- package/src/installs/terraform.md +0 -899
- package/src/installs/tfenv.js +0 -778
- package/src/installs/tfenv.md +0 -1091
- package/src/installs/tidal.js +0 -771
- package/src/installs/tidal.md +0 -864
- package/src/installs/tmux.js +0 -346
- package/src/installs/tmux.md +0 -1030
- package/src/installs/tree.js +0 -411
- package/src/installs/tree.md +0 -833
- package/src/installs/unzip.js +0 -460
- package/src/installs/unzip.md +0 -879
- package/src/installs/vim.js +0 -421
- package/src/installs/vim.md +0 -1040
- package/src/installs/vlc.js +0 -821
- package/src/installs/vlc.md +0 -927
- package/src/installs/vscode.js +0 -843
- package/src/installs/vscode.md +0 -1002
- package/src/installs/wget.js +0 -420
- package/src/installs/wget.md +0 -791
- package/src/installs/whatsapp.js +0 -729
- package/src/installs/whatsapp.md +0 -854
- package/src/installs/winpty.js +0 -352
- package/src/installs/winpty.md +0 -620
- package/src/installs/woff2.js +0 -553
- package/src/installs/woff2.md +0 -977
- package/src/installs/wsl.js +0 -572
- package/src/installs/wsl.md +0 -699
- package/src/installs/xcode-clt.js +0 -520
- package/src/installs/xcode-clt.md +0 -351
- package/src/installs/xcode.js +0 -560
- package/src/installs/xcode.md +0 -573
- package/src/installs/yarn.js +0 -824
- package/src/installs/yarn.md +0 -1074
- package/src/installs/yq.js +0 -654
- package/src/installs/yq.md +0 -944
- package/src/installs/yt-dlp.js +0 -701
- package/src/installs/yt-dlp.md +0 -946
- package/src/installs/yum-utils.js +0 -297
- package/src/installs/yum-utils.md +0 -648
- package/src/installs/zoom.js +0 -759
- package/src/installs/zoom.md +0 -884
- package/src/installs/zsh.js +0 -455
- package/src/installs/zsh.md +0 -1008
- package/src/scripts/README.md +0 -617
- package/src/scripts/STATUS.md +0 -208
- package/src/scripts/afk.js +0 -411
- package/src/scripts/backup-all.js +0 -746
- package/src/scripts/backup-source.js +0 -727
- package/src/scripts/brewd.js +0 -389
- package/src/scripts/brewi.js +0 -520
- package/src/scripts/brewr.js +0 -527
- package/src/scripts/brews.js +0 -477
- package/src/scripts/brewu.js +0 -504
- package/src/scripts/c.js +0 -201
- package/src/scripts/ccurl.js +0 -341
- package/src/scripts/certbot-crontab-init.js +0 -504
- package/src/scripts/certbot-init.js +0 -657
- package/src/scripts/ch.js +0 -355
- package/src/scripts/claude-danger.js +0 -268
- package/src/scripts/clean-dev.js +0 -435
- package/src/scripts/clear-dns-cache.js +0 -541
- package/src/scripts/clone.js +0 -435
- package/src/scripts/code-all.js +0 -437
- package/src/scripts/count-files.js +0 -211
- package/src/scripts/count-folders.js +0 -211
- package/src/scripts/count.js +0 -264
- package/src/scripts/d.js +0 -219
- package/src/scripts/datauri.js +0 -389
- package/src/scripts/delete-files.js +0 -380
- package/src/scripts/docker-clean.js +0 -426
- package/src/scripts/dp.js +0 -442
- package/src/scripts/e.js +0 -390
- package/src/scripts/empty-trash.js +0 -513
- package/src/scripts/evm.js +0 -444
- package/src/scripts/fetch-github-repos.js +0 -456
- package/src/scripts/get-channel.js +0 -345
- package/src/scripts/get-course.js +0 -399
- package/src/scripts/get-dependencies.js +0 -306
- package/src/scripts/get-folder.js +0 -799
- package/src/scripts/get-tunes.js +0 -426
- package/src/scripts/get-video.js +0 -367
- package/src/scripts/git-backup.js +0 -577
- package/src/scripts/git-clone.js +0 -493
- package/src/scripts/git-pup.js +0 -319
- package/src/scripts/git-push.js +0 -396
- package/src/scripts/h.js +0 -622
- package/src/scripts/hide-desktop-icons.js +0 -499
- package/src/scripts/hide-hidden-files.js +0 -538
- package/src/scripts/install-dependencies-from.js +0 -456
- package/src/scripts/ips.js +0 -663
- package/src/scripts/iso.js +0 -370
- package/src/scripts/killni.js +0 -577
- package/src/scripts/ll.js +0 -467
- package/src/scripts/local-ip.js +0 -325
- package/src/scripts/m.js +0 -524
- package/src/scripts/map.js +0 -309
- package/src/scripts/mkd.js +0 -351
- package/src/scripts/ncu-update-all.js +0 -457
- package/src/scripts/nginx-init.js +0 -718
- package/src/scripts/npmi.js +0 -382
- package/src/scripts/o.js +0 -511
- package/src/scripts/org-by-date.js +0 -338
- package/src/scripts/p.js +0 -224
- package/src/scripts/packages.js +0 -330
- package/src/scripts/path.js +0 -225
- package/src/scripts/ports.js +0 -597
- package/src/scripts/q.js +0 -305
- package/src/scripts/refresh-files.js +0 -394
- package/src/scripts/remove-smaller-files.js +0 -516
- package/src/scripts/rename-files-with-date.js +0 -533
- package/src/scripts/resize-image.js +0 -539
- package/src/scripts/rm-safe.js +0 -669
- package/src/scripts/s.js +0 -540
- package/src/scripts/set-git-public.js +0 -365
- package/src/scripts/show-desktop-icons.js +0 -475
- package/src/scripts/show-hidden-files.js +0 -472
- package/src/scripts/tpa.js +0 -280
- package/src/scripts/tpo.js +0 -280
- package/src/scripts/u.js +0 -505
- package/src/scripts/vpush.js +0 -437
- package/src/scripts/y.js +0 -283
- package/src/utils/README.md +0 -95
- package/src/utils/common/apps.js +0 -143
- package/src/utils/common/display.js +0 -157
- package/src/utils/common/network.js +0 -185
- package/src/utils/common/os.js +0 -294
- package/src/utils/common/package-manager.js +0 -301
- package/src/utils/common/privileges.js +0 -138
- package/src/utils/common/shell.js +0 -261
- package/src/utils/macos/apps.js +0 -228
- package/src/utils/macos/brew.js +0 -315
- package/src/utils/ubuntu/apt.js +0 -307
- package/src/utils/ubuntu/desktop.js +0 -292
- package/src/utils/ubuntu/snap.js +0 -344
- package/src/utils/ubuntu/systemd.js +0 -286
- package/src/utils/windows/choco.js +0 -465
- package/src/utils/windows/env.js +0 -246
- package/src/utils/windows/registry.js +0 -269
- package/src/utils/windows/shell.js +0 -240
- 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
|
-
*
|
|
5
|
-
*
|
|
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
|
|
9
|
-
const pkg = require('../package.json');
|
|
12
|
+
const TOP_LEVEL_COMMANDS = ['status', 'update', 'version', 'schema', 'help'];
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
*
|
|
104
|
+
* Displays the CLI help message listing all services, commands, and global flags.
|
|
22
105
|
*/
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
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
|
+
};
|