From 3aeaf7cb64fe2eaf950264f3565edefe91c7e3da Mon Sep 17 00:00:00 2001 From: Zhengshou Lai Date: Tue, 14 Apr 2026 18:39:09 +0800 Subject: [PATCH] init --- .gitignore | 2 +- Makefile | 30 +- README.md | 119 +++---- mycli/__pycache__/__init__.cpython-310.pyc | Bin 214 -> 0 bytes mycli/__pycache__/__init__.cpython-314.pyc | Bin 226 -> 0 bytes mycli/__pycache__/cli.cpython-310.pyc | Bin 960 -> 0 bytes mycli/__pycache__/cli.cpython-314.pyc | Bin 1669 -> 0 bytes mycli/__pycache__/config.cpython-310.pyc | Bin 3125 -> 0 bytes mycli/__pycache__/config.cpython-314.pyc | Bin 5437 -> 0 bytes mycli/__pycache__/utils.cpython-310.pyc | Bin 1510 -> 0 bytes mycli/__pycache__/utils.cpython-314.pyc | Bin 2429 -> 0 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 606 -> 0 bytes .../__pycache__/__init__.cpython-314.pyc | Bin 626 -> 0 bytes .../commands/__pycache__/bib.cpython-310.pyc | Bin 1702 -> 0 bytes .../commands/__pycache__/bib.cpython-314.pyc | Bin 2730 -> 0 bytes .../__pycache__/config_cmd.cpython-310.pyc | Bin 5364 -> 0 bytes .../__pycache__/config_cmd.cpython-314.pyc | Bin 9887 -> 0 bytes .../commands/__pycache__/env.cpython-310.pyc | Bin 5535 -> 0 bytes .../commands/__pycache__/env.cpython-314.pyc | Bin 10341 -> 0 bytes .../commands/__pycache__/git.cpython-310.pyc | Bin 2876 -> 0 bytes .../commands/__pycache__/git.cpython-314.pyc | Bin 4820 -> 0 bytes .../__pycache__/image.cpython-310.pyc | Bin 3282 -> 0 bytes .../__pycache__/image.cpython-314.pyc | Bin 6364 -> 0 bytes .../__pycache__/latex.cpython-310.pyc | Bin 1485 -> 0 bytes .../__pycache__/latex.cpython-314.pyc | Bin 2414 -> 0 bytes .../commands/__pycache__/pdf.cpython-310.pyc | Bin 2473 -> 0 bytes .../commands/__pycache__/pdf.cpython-314.pyc | Bin 4417 -> 0 bytes .../__pycache__/self_mgmt.cpython-310.pyc | Bin 1972 -> 0 bytes .../__pycache__/self_mgmt.cpython-314.pyc | Bin 3820 -> 0 bytes .../commands/__pycache__/ssh.cpython-310.pyc | Bin 2959 -> 0 bytes .../commands/__pycache__/ssh.cpython-314.pyc | Bin 5629 -> 0 bytes .../__pycache__/utils.cpython-310.pyc | Bin 970 -> 0 bytes .../__pycache__/utils.cpython-314.pyc | Bin 1446 -> 0 bytes .../__pycache__/video.cpython-310.pyc | Bin 1171 -> 0 bytes .../__pycache__/video.cpython-314.pyc | Bin 1805 -> 0 bytes mycli/commands/config_cmd.py | 198 ----------- mycli/commands/config_wizard.py | 324 ------------------ mycli/commands/env.py | 182 ---------- mycli/commands/git.py | 98 ------ mycli/commands/self_mgmt.py | 86 ----- mycli/config.py | 77 ----- {mycli => mytoolkit}/__init__.py | 0 {mycli => mytoolkit}/cli.py | 9 +- {mycli => mytoolkit}/commands/__init__.py | 6 +- {mycli => mytoolkit}/commands/bib.py | 10 +- mytoolkit/commands/env.py | 65 ++++ mytoolkit/commands/git.py | 116 +++++++ {mycli => mytoolkit}/commands/image.py | 2 +- {mycli => mytoolkit}/commands/latex.py | 2 +- {mycli => mytoolkit}/commands/pdf.py | 2 +- mytoolkit/commands/self_mgmt.py | 69 ++++ {mycli => mytoolkit}/commands/ssh.py | 17 +- {mycli => mytoolkit}/commands/utils.py | 2 +- {mycli => mytoolkit}/commands/video.py | 2 +- {mycli => mytoolkit}/config.json.example | 0 mytoolkit/config.py | 55 +++ {mycli => mytoolkit}/utils.py | 2 +- pyproject.toml | 4 +- uv.lock | 2 +- 59 files changed, 417 insertions(+), 1064 deletions(-) delete mode 100644 mycli/__pycache__/__init__.cpython-310.pyc delete mode 100644 mycli/__pycache__/__init__.cpython-314.pyc delete mode 100644 mycli/__pycache__/cli.cpython-310.pyc delete mode 100644 mycli/__pycache__/cli.cpython-314.pyc delete mode 100644 mycli/__pycache__/config.cpython-310.pyc delete mode 100644 mycli/__pycache__/config.cpython-314.pyc delete mode 100644 mycli/__pycache__/utils.cpython-310.pyc delete mode 100644 mycli/__pycache__/utils.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/__init__.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/__init__.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/bib.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/bib.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/config_cmd.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/config_cmd.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/env.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/env.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/git.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/git.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/image.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/image.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/latex.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/latex.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/pdf.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/pdf.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/self_mgmt.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/self_mgmt.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/ssh.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/ssh.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/utils.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/utils.cpython-314.pyc delete mode 100644 mycli/commands/__pycache__/video.cpython-310.pyc delete mode 100644 mycli/commands/__pycache__/video.cpython-314.pyc delete mode 100644 mycli/commands/config_cmd.py delete mode 100644 mycli/commands/config_wizard.py delete mode 100644 mycli/commands/env.py delete mode 100644 mycli/commands/git.py delete mode 100644 mycli/commands/self_mgmt.py delete mode 100644 mycli/config.py rename {mycli => mytoolkit}/__init__.py (100%) rename {mycli => mytoolkit}/cli.py (61%) rename {mycli => mytoolkit}/commands/__init__.py (55%) rename {mycli => mytoolkit}/commands/bib.py (87%) create mode 100644 mytoolkit/commands/env.py create mode 100644 mytoolkit/commands/git.py rename {mycli => mytoolkit}/commands/image.py (98%) rename {mycli => mytoolkit}/commands/latex.py (95%) rename {mycli => mytoolkit}/commands/pdf.py (98%) create mode 100644 mytoolkit/commands/self_mgmt.py rename {mycli => mytoolkit}/commands/ssh.py (80%) rename {mycli => mytoolkit}/commands/utils.py (94%) rename {mycli => mytoolkit}/commands/video.py (94%) rename {mycli => mytoolkit}/config.json.example (100%) create mode 100644 mytoolkit/config.py rename {mycli => mytoolkit}/utils.py (95%) diff --git a/.gitignore b/.gitignore index 8842f02..a961502 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,4 @@ build/ .mypy_cache/ # Config contains sensitive data (API keys) -mycli/config.json +mytoolkit/config.json diff --git a/Makefile b/Makefile index 0034b5f..c2256e5 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ ROOT_DIR := $(shell pwd) -VENV_MYCLI := $(ROOT_DIR)/.venv/bin/mycli -USER_LOCAL_MYCLI := $(HOME)/.local/bin/mycli +VENV_MYTOOLKIT := $(ROOT_DIR)/.venv/bin/mytoolkit +USER_LOCAL_MYTOOLKIT := $(HOME)/.local/bin/mytoolkit COMP_DIR := $(HOME)/.local/bin/completions # Use user's login shell for completion detection SHELL_NAME := $(notdir $(basename $(shell echo $$SHELL))) -.PHONY: help install uninstall _symlink-mycli _install-completions _uninstall-completions +.PHONY: help install uninstall _symlink-mytoolkit _install-completions _uninstall-completions help: @echo "Usage: make [target]" @@ -21,31 +21,31 @@ install: test -x .venv/bin/pip || python3 -m venv .venv; \ .venv/bin/pip install -e .; \ fi - @$(MAKE) _symlink-mycli + @$(MAKE) _symlink-mytoolkit @$(MAKE) _install-completions -_symlink-mycli: - @test -x "$(VENV_MYCLI)" || { echo "error: missing $(VENV_MYCLI)"; exit 1; } +_symlink-mytoolkit: + @test -x "$(VENV_MYTOOLKIT)" || { echo "error: missing $(VENV_MYTOOLKIT)"; exit 1; } @mkdir -p "$(HOME)/.local/bin" - @ln -sf "$(VENV_MYCLI)" "$(USER_LOCAL_MYCLI)" - @echo "Linked $(USER_LOCAL_MYCLI) -> $(VENV_MYCLI)" + @ln -sf "$(VENV_MYTOOLKIT)" "$(USER_LOCAL_MYTOOLKIT)" + @echo "Linked $(USER_LOCAL_MYTOOLKIT) -> $(VENV_MYTOOLKIT)" _install-completions: @mkdir -p "$(COMP_DIR)" ifeq ($(SHELL_NAME),zsh) - @_MYCLI_COMPLETE=zsh_source mycli > "$(COMP_DIR)/_mycli" 2>/dev/null && \ - echo "Installed zsh completion: $(COMP_DIR)/_mycli" || \ + @_MYTOOLKIT_COMPLETE=zsh_source "$(VENV_MYTOOLKIT)" > "$(COMP_DIR)/_mytoolkit" 2>/dev/null && \ + echo "Installed zsh completion: $(COMP_DIR)/_mytoolkit" || \ echo "Warning: failed to generate zsh completion" else ifeq ($(SHELL_NAME),bash) - @_MYCLI_COMPLETE=bash_source mycli > "$(COMP_DIR)/mycli.bash" 2>/dev/null && \ - echo "Installed bash completion: $(COMP_DIR)/mycli.bash" || \ + @_MYTOOLKIT_COMPLETE=bash_source "$(VENV_MYTOOLKIT)" > "$(COMP_DIR)/mytoolkit.bash" 2>/dev/null && \ + echo "Installed bash completion: $(COMP_DIR)/mytoolkit.bash" || \ echo "Warning: failed to generate bash completion" endif uninstall: _uninstall-completions - @rm -f "$(USER_LOCAL_MYCLI)" - @echo "Removed $(USER_LOCAL_MYCLI)" + @rm -f "$(USER_LOCAL_MYTOOLKIT)" + @echo "Removed $(USER_LOCAL_MYTOOLKIT)" _uninstall-completions: - @rm -f "$(COMP_DIR)/_mycli" "$(COMP_DIR)/mycli.bash" + @rm -f "$(COMP_DIR)/_mytoolkit" "$(COMP_DIR)/mytoolkit.bash" @echo "Removed completions" diff --git a/README.md b/README.md index d851dce..7ceb168 100644 --- a/README.md +++ b/README.md @@ -11,92 +11,93 @@ make install ## Commands ```bash -mycli --help +mytoolkit --help # PDF utilities -mycli pdf compress *.pdf -mycli pdf crop *.pdf -mycli pdf to-tiff *.pdf +mytoolkit pdf compress *.pdf +mytoolkit pdf crop *.pdf +mytoolkit pdf to-tiff *.pdf # Image utilities -mycli image eps-to-pdf *.eps -mycli image jpg-to-pdf *.jpg -o output.pdf -mycli image tiff-to-pdf *.tiff -mycli image tiff-compress *.tiff +mytoolkit image eps-to-pdf *.eps +mytoolkit image jpg-to-pdf *.jpg -o output.pdf +mytoolkit image tiff-to-pdf *.tiff +mytoolkit image tiff-compress *.tiff # LaTeX utilities -mycli latex compile *.tex -mycli latex count document.tex +mytoolkit latex compile *.tex +mytoolkit latex count document.tex # Video utilities -mycli video avi-to-mp4 *.avi +mytoolkit video avi-to-mp4 *.avi # BibTeX utilities -mycli bib to-markdown *.bib -mycli bib cv-update +mytoolkit bib to-markdown *.bib +mytoolkit bib cv-update # Utilities -mycli utils albany-cleanup +mytoolkit utils albany-cleanup # Environment & Navigation -mycli env list # List configured paths -mycli env goto research # Print path for cd -mycli env cd apaam # Start shell in path -mycli env status # Show environment status -cd $(mycli env goto study) # Use in scripts +mytoolkit env list # List configured paths +mytoolkit env goto research # Print path for cd +mytoolkit env cd apaam # Start shell in path +mytoolkit env status # Show environment status +cd $(mytoolkit env goto study) # Use in scripts # SSH Connections -mycli ssh list # List configured hosts -mycli ssh connect tianhe # SSH to host -mycli ssh connect starlight -mycli ssh tunnel tianhe # Create port tunnel -mycli ssh cmd tianhe "ls" # Run remote command +mytoolkit ssh list # List configured hosts +mytoolkit ssh connect tianhe # SSH to host +mytoolkit ssh connect starlight +mytoolkit ssh tunnel tianhe # Create port tunnel +mytoolkit ssh cmd tianhe "ls" # Run remote command # Git Proxy Management -mycli git proxy # Show proxy status -mycli git proxy fastgithub # Set proxy -mycli git proxy pandafan -mycli git proxy -u # Unset proxy -mycli git proxy-list # List available proxies +# Git Proxy Management +mytoolkit git proxy status # Show proxy status +mytoolkit git proxy set fastgithub # Set proxy +mytoolkit git proxy set pandafan +mytoolkit git proxy unset # Unset proxy +mytoolkit git proxy list # List available proxies # Self Management -mycli self update # Update mycli -mycli self uninstall # Uninstall mycli -mycli self info # Show installation info +mytoolkit self update # Update mytoolkit +mytoolkit self uninstall # Uninstall mytoolkit +mytoolkit self info # Show installation info # Configuration (config.json) - 增删改查 # 方式1: 交互式向导(推荐,无需记忆命令) -mycli wizard # 启动交互式配置向导 +mytoolkit wizard # 启动交互式配置向导 # 方式2: 命令行直接操作 -mycli config show # Show full config -mycli config list # List top-level sections -mycli config get paths # Get paths section -mycli config get paths.apaam # Get specific path -mycli config get api_keys.deepseek # Get API key -mycli config set paths.new ~/Documents/new # Set simple value -mycli config set api_keys.newkey abc123 # Set new API key -mycli config set --json ssh_hosts.new '{"host":"user@host","port":22}' -mycli config delete paths.old # Delete a key -mycli config delete api_keys.old -y # Delete without confirmation -mycli config paths # List all paths with existence check -mycli config where # Show config file location -mycli config edit # Edit config in $EDITOR -mycli config init # Create config from template +mytoolkit config show # Show full config +mytoolkit config list # List top-level sections +mytoolkit config get paths # Get paths section +mytoolkit config get paths.apaam # Get specific path +mytoolkit config get api_keys.deepseek # Get API key +mytoolkit config set paths.new ~/Documents/new # Set simple value +mytoolkit config set api_keys.newkey abc123 # Set new API key +mytoolkit config set --json ssh_hosts.new '{"host":"user@host","port":22}' +mytoolkit config delete paths.old # Delete a key +mytoolkit config delete api_keys.old -y # Delete without confirmation +mytoolkit config paths # List all paths with existence check +mytoolkit config where # Show config file location +mytoolkit config edit # Edit config in $EDITOR +mytoolkit config init # Create config from template # Environment Variables (API Keys) -mycli env status # Show paths, API keys, Feishu status -mycli env export # Print all export statements -mycli env export deepseek # Export specific API key -mycli env export qwen -mycli env export feishu # Export all Feishu apps -mycli env export claude # Export specific Feishu app -eval "$(mycli env export)" # Load all in current shell -mycli env init # Print shell init snippet +mytoolkit env status # Show paths, API keys, Feishu status +mytoolkit env export # Print all export statements +mytoolkit env export deepseek # Export specific API key +mytoolkit env export qwen +mytoolkit env export feishu # Export all Feishu apps +mytoolkit env export claude # Export specific Feishu app +eval "$(mytoolkit env export)" # Load all in current shell +mytoolkit env init # Print shell init snippet ``` ## Configuration -All settings are stored in `mycli/config.json`: +All settings are stored in `mytoolkit/config.json`: - `paths`: Quick navigation paths - `ssh_hosts`: SSH connection settings - `git_proxies`: Git proxy URLs @@ -113,17 +114,17 @@ The repository includes `config.json.example` as a template. 1. Copy the example config: ```bash - cp mycli/config.json.example mycli/config.json + cp mytoolkit/config.json.example mytoolkit/config.json ``` 2. Edit with your actual API keys: ```bash - mycli config edit + mytoolkit config edit ``` 3. Add to your `~/.zshrc` to auto-load: ```bash - eval "$(mycli env export 2>/dev/null)" + eval "$(mytoolkit env export 2>/dev/null)" ``` ## Uninstall diff --git a/mycli/__pycache__/__init__.cpython-310.pyc b/mycli/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index de2e24aa235ef7c606f7bcee22a604c2f3563112..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 zcmd1j<>g`kg1Y!Snbtu1F^Gc<7=auIATH(s5-AK(3@MCJj44dP44TYUvc8qhKAsA? z3IVA_#rb)OISL?dNq&A#c4moQ6{~@sp`L-CCetnU`1q9kTZlX-=wL5j)TrkV}hsfy4)9Mn=Y)49XAqM4PyaSb-t{JM}zL diff --git a/mycli/__pycache__/cli.cpython-310.pyc b/mycli/__pycache__/cli.cpython-310.pyc deleted file mode 100644 index a540f6861f46d0885d2230839d47192e37e854a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 960 zcmZ{iPjAyO7{=`+PSP|j`@_Ty^;!wF+l>Q4h;cz;6Vk-R7b}as)>#}^PFiSBNZXaK zfVLywgwJ4c_I3V4e)kai={_Dd0w1qn)B#3_ zBZ@fYUWqA&*)KiiQ(px%P=pc{(ojV-QZbEHkM>kT6V<1EmC{rV=s*qW5F>$a9^HZ# zJ3QcohhID%@%S2D;VVpc#qQ0X@C*MIL!{%N2s$PO={PLHj-w*#I4 zn}heTPghwva#w1!E-z&>IsJyr4g}rH@1yC58bYV#W?s+ra{5N+O9i*Drzh*zvYNI= z?i4Id7HjLn9J}-2VWA)}docaqlzWE_YEzBC8a^H4cE`PkE$u>_4P5e{0=556u-SL3 zF=K9>vGIY87~?u;j1q8>U(#V~aFT1KvWnNnc{08emks0Ixe1*_PMmGibK-27zLV6+ z0K}4+(aQxL-sPO>MFXjC-O_%>p+ehJI#;e7jQ#T_@e8H-vJ@{}b?Rpz0gAonUg)P7 Sdf2KXoIL2U9|s8z{`>`P8r>!U diff --git a/mycli/__pycache__/cli.cpython-314.pyc b/mycli/__pycache__/cli.cpython-314.pyc deleted file mode 100644 index 701647ee414ff3691bea7d7887ff5c10178fd2f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1669 zcmbVMOK;Oa5T5lTw(}}bqR^H{D#Rf|N?HkthY$x|awR}kBqR<5E5vSU5!=yvQ%J;t zhXfqq1Sjs?_!*obQp>704qQ|62bgsdnj(-9t7P^Y?|kELc6NO_pGyOd_ZvIjCkf!2 zaHb*M3Eb0)WmMZ>YOquLp{h)PfygqB| zvNf$^=J6Rac2LouS&F64gil~1OSR(N+|Nv8rL63JhVT+unw9?#mTn#R50;UrCY>0O zNsP!QM&uGB@_P|Atq5$sez>Ney93~0XO2RBe($WEz_WZZ{+Eq@@n-MJjkS{B@Pd*X zFxo41LN8#ITjea5JI*>+J-^X%x!P_p_Yqe&J;x2XeBZmz)h_ee5!c*c({B0>*P>`+ z3|bzGfgZW-^%$j_VX*GC#`vMvZ%{|zzPeIbt*mg>?={oEJOCv7~xY40u%MKd8 z+nnv2IKDD~G7@JSuO=2!mih$?Sz*vAB#SE%X=t9nt`4d}=MnGIB`zrHg3)3e zb$4>j@HnF{25vf_R&uLM;*_znI1fFH%Uls1phbk@J283Lj-tJ|76)Wx z<=oS`*YaEKjW&QI+aSlj`Zn_>Gk~N2>L>AMbN>zN16Y{8FFk;zS^OhKNP4J)l6}=5 S$O~T;{l)cN8I;AisXqZcnIqT$ diff --git a/mycli/__pycache__/config.cpython-310.pyc b/mycli/__pycache__/config.cpython-310.pyc deleted file mode 100644 index 93b9c171b075a9dd15248311f9f3e6c678e5d2da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3125 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

PM?!;nuVxjAa zg)O^2m!G^J@=8`d#inGRjtG>r=nSku4o1FhY5*R2(6@_Ie2PyAKXjk=vakDPLY!442Q{*c-ydpPD=PsRn^XyE^hn??r&JF$P(9OnYKbH?OaKIQ?AUm(% zlCfs|jDd$|DDC{2%tRqqVqZ_7=zG1S=G|XH_*KQER$ezWqX4RPnM|&b&1B3FPKITy zbFkcvqkY(+9nC}7J&)ZecCSEZw?cUdwWOZSsFr2wr%RSbVaDc~0yL|E2WDcNb8biX zJixM%i4MfNdKgd@y03o)yS^C0 zKC4{RjWevWW)IjtCjiY8XA=C#V9QTC81Fa7;THEsvA$mwIF7qbVqcNK7o`46((xr} ZTlXE{xM4VeI+r6n@i)EI@e3cD?Z5g@K(qh= diff --git a/mycli/__pycache__/utils.cpython-310.pyc b/mycli/__pycache__/utils.cpython-310.pyc deleted file mode 100644 index 24dfad971830db811a454dacee8da0334020a78e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1510 zcmZuxUuzsU5SMoM_V(6xYB$tPO6n?wK5R;$*;^fw zmg_B-Qc^?nl74|wh@mg}4*dlE2qJHN@>l3X>5TRqJEdAQ`m>{%(Qkeuxv>!wXn$sJ z@;3n?f8pYCYs2Cz=z1RnCj-JM_X;|oZuAD88~uULeIA^ULBQ8|C|V-CPIz0ic_h3^ zGzxi#$0w~phkK7mvR;4w*yKfS7Hm|NnaO3TSz2<&MJ82hq|$686`L-yBJZAoV{(vD z99GSP5rQQ?bo~(sLtfDro4}s%`zj|7#tOXWpX-|B@;@a zw_}xNVpJ8yqML!aw+$U2KA%9>e}Jf?7i39tvZTM$U+5F^2;wkg@fju0JWA>QWlOxGH&{Szif$n0VG39a|p| zIYX@LopaSuniqnzd2Yr`e4iV@jtiDhg(;{z@$QjSM)2<0b66*9c55H>52V>g^Y;*7 z+k!-9Pi;$!Y%Faw0);Z23LD%5dp6e9(M-uqXl>uWn-<{h+h*CEj+HQ#D$%VCwc!w= z4VnW)43a|cuj49JbO+4{<8O23#EHSJ=SAc_4Z^| zO+{&R@4@2hyzDu~tz-oh)!o^`w&yCH&4gNq>uCnU^ET-fdX2_3`f(G+kZ!v9I>?xM z|I|AT$%YUTu&aB!kXc&jJKdEbfV$&|FJ+-^3wL$msckT=uA}%6#Rn*^fv_9znCrln z4naiz6&k#!Zou@=`q`8N%wqvChbz3WOwJoJ8S`}?x<*fiOz6^;%aZ26SmZO5ipy}r6xCp(gsqWVqtx4fZazx4ZHc@0G*{vUN2lnx2KX< Ug}8&It1;w&L|#Op`=4(A3&W6+Pyhe` diff --git a/mycli/__pycache__/utils.cpython-314.pyc b/mycli/__pycache__/utils.cpython-314.pyc deleted file mode 100644 index dda4fdb3922c4f2d4420b5cdee50c4636b60d40d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2429 zcmbVNO>7fK6rR~#JBhuJA438mz$8I{Lt;aL5~Wcp^H%|C8kP`L)xz5BuH%LEt~EO@ zNz{WyE48ABAo@cpRVs%b!l_q!st`TUo*cD^vh|HidrO;0p!U)?yS5WZq*h&NXWq`f zdGF0P-+S-C=1ma<&yQNgtVjqw*hUQR}In*Uthm!n^W|@gm z4cFYm%p-tTT0RYe3NfVXKgWc+SQom{1$3mke*zuG3Wi7;k5vB`@C1)Xm>oD-^GujS zauADU5Y5Tw9h(@G@_?qOsu|g$Wz8hCx_J;9;N1=H@mFcyA!9U&RLA}Cl96!BQ~I(DNqwi?&(=th@u z4TKz4q=N9eVB)lY&0Kp-UcU$8eD^=b8G<-BueY#KoS@mVUUOe{N$=$z*PNwoy>2&0 zWdj?4NBCG3(f^6ZmYO#>dxA&uf}IUxQ5tHvzM#AD9bB*J=CFxg6L%sL#~Wv3CxB+0 z{Idw|V0VNXtVnI{(F?mwhsZq1x72#hn3;4`s-LkLtQHF_E_sqlr(7?5^_o9p z@WRvGsuZ~417;d64<278P zYN23IZ}8E^;rnHaVlO|{&SMD;)CwEF`L&r4`YlAC&-#5(4;lw zE6rpD2~DITx6Ylrajx7su%Lc(E|IL_WUd-J`YSs45PAsyDb(0L5i2(K3K)y(hj1oi5p2B93j4 zWl0grx%4|fmM3a?9r&IzfbZdexbcuDS*FW8(PhBgNq~iNo_H;gT?Na4ys7d%j=eCn zpuEalew3a7A~};$ZOBuV8JP^_!0^iN9)O{Qo}nmy^$$LLI{szvXKycY@oVN!-*-Mv zr596a|2ORdeXU;o;UffZls7frnEt(`1&wS1C-H<3bQox1zbQqVsAM&R{r<%Zi(e`< z=&^8e$gZHF1x?PhrxKA!3et2aLf`?&hDfc_@V$_^K}r(UB^n88>s>MwP?R_=W1TET;h~gKQY9udT2r+G!skUZBC;^aw z#s0;Kurn@FehvOQje+EH#_iqPA6!}#R5DsnWN9D#@$YOW2tev~B)89v+!&efU5p;R zbFmyfx{w8_EFJZ4DUQeEVXq;R(H#wLd^>FN{Zh_7KSg|tcag6h_-h=_J9^PFMkvo$ j&K{S*uq0xPpP)leQOmEW^(m77499TnS$~Z*zJ-4PJp>eP diff --git a/mycli/commands/__pycache__/__init__.cpython-310.pyc b/mycli/commands/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 4e0088d3bc1e42296207015a6028241ed26923ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 606 zcmaKpO>WyT5QQmGzqZvlZV!;HH_-)(wrINv&~y`IGaEt{Wtjj+3PdT5eS%z|7wE26 zBC_kMSLmu7#zwR15d8241l~Lh`=XdJSKoI}>M>yK7d0;{bj=5M&4Ytvz+@mp9bgC{ za^M(2gfYaJK!Pcx0ljmbVGg<1k)Gik=3d8ofdv#^C;Anh!I{^oUg8p#UT69oSFj3L z%Vho|fY)+%!`Ab|>U#g_%hiRMHg%6!b<$k^c6r%4vHVVMZLF|r8yo9tY#wZUuVm9( zzEK++PovUi9oV$#?nRA~q%pgbY}I&_nQ8R)sAqNGZB={fzNtesNZ&06+R4BP5g{fd zgp`mGasq93m=hL+!r|-sjZKA+eJzA#|97(71@?BpU0&}A+{N|Ako&aQ;`na{6vx=l zdHqP5S7|N8Pd2P52jS2A^42tiDfMAzcKuX-?&}GgZZzff{-f$j+}BzidD?g>gzDV3 b#O2-IW^b{VlWyM8FBtNS*hRPqUYzhR;DM3x diff --git a/mycli/commands/__pycache__/__init__.cpython-314.pyc b/mycli/commands/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 704ff36189a876a650486c9e22f66cd63a054978..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626 zcmaKq&x_MQ6vtmO`PnwRwF<7MiXs>m8rbu)f{IMQRVa9MNRzZ3$RtZ-`i<`LlGKB=?IU-*tnBUa3mt*ZhC}|#j$ZOo#LsO z8u!y%cqV3ZSimxTZHe2<;334L{p@o0>}7hNcdNW%EUOE?h&_p}inVkp%QmHSt4x&d zrF%__vXN*-SJLeSt$1unzpSrG&I+xZZwK8_(QClVYTf%NZ|XJO4Ancj&)Py)ui{Co zH_{>vN5j?dG<=OfBh=74ZO0lDjYuKBBYi@OCMQI~{~Jl90-J6Usl2A8L@KW7D?^i( zZJ78sLPmY;zj@6>Juj;&LcYL_3IOs+@`jf!PpbWvZ<{W8-sBxCYr&Jt-BVg8Y?oKG z=dkC55L&B6k;Tl>W>gtM=3c7T)Nn;+o80UrH! NVEn@V=(l&(<3Bg=otXdt diff --git a/mycli/commands/__pycache__/bib.cpython-310.pyc b/mycli/commands/__pycache__/bib.cpython-310.pyc deleted file mode 100644 index f2a7edbcda1886d282cbeb0120aedc7bbaf6c5e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1702 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 diff --git a/mycli/commands/__pycache__/config_cmd.cpython-310.pyc b/mycli/commands/__pycache__/config_cmd.cpython-310.pyc deleted file mode 100644 index 44e291fb5b8eb46ec604ceb223a16c6b83e52685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5364 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 Yx!!PRT~MQU6?2kG*!UkT-qJn!KNVReV*mgE diff --git a/mycli/commands/__pycache__/env.cpython-310.pyc b/mycli/commands/__pycache__/env.cpython-310.pyc deleted file mode 100644 index 07069eb4f16f9593dc42afdc75b7065d4a7031da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5535 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 A6#xJL diff --git a/mycli/commands/__pycache__/env.cpython-314.pyc b/mycli/commands/__pycache__/env.cpython-314.pyc deleted file mode 100644 index b69eba263d03d845b4af893d5307f48ef9ef65e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10341 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 diff --git a/mycli/commands/__pycache__/git.cpython-310.pyc b/mycli/commands/__pycache__/git.cpython-310.pyc deleted file mode 100644 index 41f1ba21c1616e1c48129b830a0d3102acc0370b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2876 zcmaJ@&2QT_6c;J#BevswwoBTs6V_s=i`m%*3>bo8Si5$;ti80ocr6S?R2(I;OU0{XfEPJN346fVF#%auR!OC&4ry$@fM6eveA$=W7N$e{B63y{#L@ zUnopJb0B;VKlvLp+~^vda2k^?(f_nd;opqS0qZhiaK^0{M%N1IuFY-k91`yGxfjNB z(se@T$mO*$fw?(e=M6r8NTFZjO}@Yv`4V3~WLjR~t0134nV;t$p?39l>wJx`gZ+lK zbzw~SMSe+JpXchq z*CM4Iq{(*F4^W!=jfXN6awE=nEsOXaIf!eW`P-``1}c|j%w?8@Z$s_DQ4HzyCqg=y=g{)SFLrCk`Z zUJzMV#&ZKe327EYTvKG1_6<&d2f%W6NQp5Sv8G1MU53ErF3zK-vYs0wvoH$tDG_&- z3BaB!jF-l*6s**=6&wRVA3242sw%F`6Qaj z_{z*U#%8BDQ@yK^eTvHi4>no>@MWh~^WeF??+=D?C^xl)BN|~- z3fsO^aK1a)7S3Mr?!!q2Lc9s-7sHj{U!CJFAqc_KG)!kq^3S%UKfaUGs>Ijf8M(L?&zP_pZG@vzAtD=FW%#SM9NJ%Xr*) zL`T-hE=Xa6?Hh$Pf{QF6Prg>pu8Y@K#qxrQ`^o_>*EI*}m_YqNxlw4opUU$EMgCVZ zSZJPFIPrLK;?XKFn|;0jc`S|`ZEdM=falAF#aCW3zF62`%SKyI67E2`Ud=Dh6h>g| zOmXbA*!v*$04}B_*x-_>a9;^TUOsm%Nfp+K*1I|gyn8dq)0KI%WWj--h*i`Frriis z^c3N|;CW}P+VoBbCX9gwp1Qnx=TBTM@Vt#1&ZA zZA>ng9^RDQT7_}!mnI;+YY%*}2fRJKvjyHYVjY@q;3qesVbmrRUi+UlYr1cnj4Tot zc|ho!CPN9|CdJkx?2WdQS5Dh;B-IQbOt6jhOY`9-bnqq{>H7*lyMPaHI~B%}sS&&g zcp@XJ$PweL08RjMY>h&uk<--3ar28mfgjI5sY0i{bHL<*p>@~y%k@8*lLzeugBA% z*Q>yQ2V6Gvh1ID(v~*#gfS@nZY*>AVIFnDM()C4Oe@~TmI#f}b=$fN9UAvfyO2?-^ nZ`^MODbM2YJEVuiY#4l1xwJuDvt~j4vKsmn;bcE?uQtiQ0Tjq< diff --git a/mycli/commands/__pycache__/git.cpython-314.pyc b/mycli/commands/__pycache__/git.cpython-314.pyc deleted file mode 100644 index 6c0b5c165724a6182745d43c0562a7c6dd9d0753..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4820 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 B9z*~D diff --git a/mycli/commands/__pycache__/image.cpython-314.pyc b/mycli/commands/__pycache__/image.cpython-314.pyc deleted file mode 100644 index 669988139a240e2934f75c0044d5b15dd2c7a819..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6364 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 m=LM}Y_Cm)?d(1^9 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 diff --git a/mycli/commands/__pycache__/self_mgmt.cpython-310.pyc b/mycli/commands/__pycache__/self_mgmt.cpython-310.pyc deleted file mode 100644 index dfe354ecc65f6dcabd257454bf6089e358eb51cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1972 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 O&R)9y?t{HB4EPTu|LVE` diff --git a/mycli/commands/__pycache__/utils.cpython-310.pyc b/mycli/commands/__pycache__/utils.cpython-310.pyc deleted file mode 100644 index 3139527208da2401f840c36fac7c5f98e97431c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 970 zcmZ`%&2G~`5Z+y{V<&AwTS3dw#|Dw)h=eKxwAWUMQXxe`#_?`z)3w*^+LT!7sa$!2 zs#0>~L3oK3Hx8(;z=>It(q0&AXJ=-|^YhKfZnuMgez70vcY@GQtK20Il;?2tdteNW z5yOlKoRKlXR(6ClcHpLhX71RuxS(Gz9yoSW6j}3hlmB|4J-307{hg>PCbZnpR z5(Z@#j;6pEhNz@|xS#5n3lZg9RywGf94XhsgKtP#zgzZuXLO{w(j!qPI+4|APsUZo z^HPuYr!UidlucuiF8NK7BO6fYxN$zrMjPDCBmf~)RDViM)kK`eNbS4G_(449e@ zRF&6ckiV(74ikA6oF!2ioXJYCV8R0?bKWP$OLcfGq7y?CE{fQ;cS8;cE}W*_V-OfV z$0cIq0?%PI3%rNkJvb*bq&7=3cNm?KOLRpR7^9Ev8JW`s!f1w>`vje1upqVF__eGD zYagOU^Je%GG5-qU{k8Tx_2XUJNKh5Qi>9%lg9smFU diff --git a/mycli/commands/__pycache__/utils.cpython-314.pyc b/mycli/commands/__pycache__/utils.cpython-314.pyc deleted file mode 100644 index 4b0e84e5202501d51c17c675ea13975adb30f494..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1446 zcma)5-EZ4e6hGG=aX#H-tCXR(i>pCLSd&OoB@mRM!G_jW?SjX$J#33y`>ru{Y|9@j zF)v{}Y*e5Y@jxDV9RCIq?~y=NXH{a-Hu2ih2VS|?wVP21!IgaOIrn_~cg_W|kOgx7 z(Dw9S7=Y(gNKQIt4u2+0A7t?09>{0`U1L0^LV0F^^;mMV3*0r{<128NZRQjA(LD`w zu^@BhW8M?)3eD2UD&b^)4ju6%+NtDqbWekvk_9;}XXNbLTx`k9xl!aKTXK6@nK=j5 zd{DaS>4xt0B-QG66;pHTRTOef#p|pPrqCfz25w`=u^d+&WdxuFu>jm*iZJ9?AQFxV z&MfP$iVZ_CvE{px9|hO3TVMGJ9G+Mn(iq`<vk{XBhH~=rR z$2S9}W_}u!Z*;5;X``cf(uU<5nzV`~%`$P72?gD4-#3)Ckn3Q>R^#7Jf&$R;qmJJp zuYCfxjqV)lWt2eFBsM3H%p}?(eEb1`&9vZrY@|&BOv0TQHh?B=;lv>Tvn?hM7mwpq zU}*-R#WXV~Oo^C)T!9w4hh_^S3mYw62FSo!cqRX9|0_S2bWj0VIQQT6@-37nV|kJN zr(ZQ4%zi{+k$hXa9Kj@cxNBRE;`F5Zx`AEkO}nFz3HrSKR<$0YdXPDm1MyabmxH_3 z1N^QOl&%mjf-4yg0vhdH7O|nOM;au?~u)gkXtjX)sQE%rmlw^Ry$Uh@=ZfG z*Q;zOkdbMV&_r+frWbNiaTMGcNpk4Sh4GxV<2iH2$zzdxu1!cE_OnnB`&ajhYDPDNY{hm9umoIHCZY~baKH+|RFf7-1@{MQt;?~mFOW!Q-=1be3e7m@L z^&khO*}p_ckL{%kTiMO*@bt`1`uvL{Vf*#~4{i-#e{Xntekc8YH2T$CD74#}rMBCl zV3RF2^wp?WN2CSkqQ$Bo?GJ4wN!2%wKU(r zmz)XWPv_tLjF5d6A@mf=FX7B{$iIX)_EW$Jk0u^Yd^L5zFer1#0yDNxIr3YGX6nnS w;aKHYB<-TqqsfPpkJkrtPsWFH%fF$OT_heb1#~I$q2xNEbo$Q}d5miL8v-&jivR!s diff --git a/mycli/commands/__pycache__/video.cpython-310.pyc b/mycli/commands/__pycache__/video.cpython-310.pyc deleted file mode 100644 index 1cf8c9009f97841e94f026cf6b59b727795c233c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1171 zcmZ8g&1>976xV#{V?VtKX;OSBI+gBWccGXbObBgb0zJe8(xxCNLe|W#6iXU;X5@{9 zd~&b8^cn)Y$Nn4nGlt%J%DK=(4^5x6HZgr--snBvoA>p5Vl?VoK=0Wf>0iXM{%nQ2 zPiI=p^76pg%QWNa!$+VWp*p*W`%DxZT-{WK%Pd+Mn((ZQ+km&!7Bz&^_2M`9 zX{;mbm!nIpp(|HtgBrX=pgFuG4S9_>1SX14iTvzr(2xyfWQ#6ogXCA*-Z+dlM5sbc>L6Ht6)u|Ml8sF7ve4kSnx90vm!vuh7Z^ER3&l>wAXT9!zFZfBCeViT1yH z^@HEF#n-}r{^G!|R9dY3G zA2>T_=pnex;=}X6&C-)MUw?DZiBUkJD1HVov*U!vr^nNtY#V6kDibHhQPpypzA<(t z)?AvwI@L*ds{;VUr-t%45wgXZAxg`sE!(v+E(|Y(;TgA#wC1u1Jjgt3t22(MbXn<7 zXp>Is(xM~OB81xRfvmm&<~jG#7-7^$6hDOfA;xGQZtq|GH~lF0!DKo%ZWuBVhoR}K z>ZFt+=1O&e6R5STM?PpH3_8@#+a*(yfM%Dsy^^9TJBS+h2F%6-Ja&kObW08E(gnMd nbGI;E;@;z2uqxwE+O<=k1EZFQhseVd?2tb4>@k`^(htyom^e9K diff --git a/mycli/commands/__pycache__/video.cpython-314.pyc b/mycli/commands/__pycache__/video.cpython-314.pyc deleted file mode 100644 index 45e2fd7af9935c34cc17cf4b57009f1190db6b56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1805 zcmah}O>7%Q6rTOJ9mjS=oF9@jTM-2evfW0et*TN9T182!25U=A1xZ)VdSkC*d(G@@ z+*n9W%b|fwD=q{fL8NjpCvwb-b%W47mb{}e3021_9)WZSJhsh4G`y|DZy zYy5>eLIvMYSQS$;)aZ-1Y{R7gZ{^i~&7hmNYIdQl)Io-5EQV@qY7E$mfl5cwUlGGL41l zL=dxZsaP!Ab5wTR`FZOOmCAPA#I&Psk&^Dq0RP4U6-}dLV+IB)I0Ppo%-Td1fUOR& zrAjSNh>5E-0Fmn~J1W~Qsky|FKyh?bRaG2dChSS*#MU7c94-S0;9%y$|nxdiQB`~X7-Hx7l7VF!I4?T@1p2QQ) z(XIH|mGS4%p50jdi_qtxRlRwuIkjHcIJfcI=D?Nh*i}&fJ>2zh>a(fU!L`!b2Tig* zzJ6h|_tJLwt=(|%PFMeG=G&LnZap4amp6hxp8Ms^ZSCe}Ze~lH-HhGd=^6M-5;`M? zanyeX=6ZL(_rU-72Ua3N6w7?T6UO(7mCRkGHtN9Zr65 z>i(%m$|`PN-R91+|H1o%D+{ZcX7^_1`ZhPc!$l7G7#HzeF!C str | None: - """Show numbered options and get user choice.""" - click.echo(f"\n{prompt}:") - for i, opt in enumerate(options, 1): - click.echo(f" {i}. {opt}") - click.echo(" 0. Cancel") - - while True: - choice = click.prompt("Enter number", type=int, default=0) - if choice == 0: - return None - if 1 <= choice <= len(options): - return options[choice - 1] - click.echo("Invalid choice, try again.") - - -def _prompt_confirm(message: str) -> bool: - """Prompt for yes/no confirmation.""" - return click.confirm(message, default=False) - - -@click.group(name="wizard", invoke_without_command=True) -@click.pass_context -def wizard_cmd(ctx): - """Interactive configuration wizard.""" - if ctx.invoked_subcommand is None: - # Show main wizard menu - show_main_menu() - - -def show_main_menu(): - """Show the main wizard menu.""" - click.clear() - click.secho("╔══════════════════════════════════════╗", fg="cyan") - click.secho("║ MyCLI Configuration Wizard ║", fg="cyan") - click.secho("╚══════════════════════════════════════╝", fg="cyan") - - options = { - "1": ("Manage Paths", manage_paths), - "2": ("Manage SSH Hosts", manage_ssh_hosts), - "3": ("Manage API Keys", manage_api_keys), - "4": ("Manage Feishu Apps", manage_feishu_apps), - "5": ("Manage Git Proxies", manage_git_proxies), - "0": ("Exit", lambda: click.echo("Goodbye!")), - } - - while True: - click.echo("\nMain Menu:") - for key, (label, _) in options.items(): - click.echo(f" [{key}] {label}") - - choice = click.prompt("\nSelect option", type=str, default="0") - - if choice in options: - _, func = options[choice] - func() - if choice == "0": - break - else: - click.echo("Invalid choice.") - - -def manage_paths(): - """Interactive path management.""" - click.secho("\n--- Path Management ---", fg="cyan") - - paths = config.get("paths", {}) - - # Show current paths - click.echo("\nCurrent paths:") - for name, path in sorted(paths.items()): - exists = "✓" if Path(path).expanduser().exists() else "✗" - click.echo(f" [{exists}] {name}: {path}") - - action = _prompt_choice(["Add new path", "Edit path", "Delete path", "Back"]) - - if action == "Add new path": - name = click.prompt("Path name (e.g., 'mynewproject')") - path = click.prompt("Path value (e.g., '~/Documents/project')") - _config_set(f"paths.{name}", path) - click.secho(f"Added path: {name} = {path}", fg="green") - - elif action == "Edit path": - if not paths: - click.echo("No paths to edit.") - return - name = _prompt_choice(list(paths.keys()), "Select path to edit") - if name: - new_path = click.prompt("New path value", default=paths[name]) - _config_set(f"paths.{name}", new_path) - click.secho(f"Updated path: {name}", fg="green") - - elif action == "Delete path": - if not paths: - click.echo("No paths to delete.") - return - name = _prompt_choice(list(paths.keys()), "Select path to delete") - if name and _prompt_confirm(f"Delete path '{name}'?"): - _config_delete(f"paths.{name}") - click.secho(f"Deleted path: {name}", fg="green") - - -def manage_ssh_hosts(): - """Interactive SSH host management.""" - click.secho("\n--- SSH Host Management ---", fg="cyan") - - hosts = config.get("ssh_hosts", {}) - - click.echo("\nCurrent SSH hosts:") - for name, host_config in sorted(hosts.items()): - click.echo(f" {name}: {host_config['host']}:{host_config['port']}") - - action = _prompt_choice(["Add new host", "Edit host", "Delete host", "Back"]) - - if action == "Add new host": - name = click.prompt("Host name (e.g., 'myserver')") - host = click.prompt("SSH connection (e.g., 'user@host')") - port = click.prompt("Port", type=int, default=22) - has_key = click.confirm("Use SSH key?", default=False) - - host_config = {"host": host, "port": port} - if has_key: - key_path = click.prompt("SSH key path (e.g., '~/.ssh/id_rsa')") - host_config["key"] = key_path - - _config_set(f"ssh_hosts.{name}", host_config) - click.secho(f"Added SSH host: {name}", fg="green") - - elif action == "Edit host": - if not hosts: - click.echo("No hosts to edit.") - return - name = _prompt_choice(list(hosts.keys()), "Select host to edit") - if name: - host_config = hosts[name] - host = click.prompt("Host", default=host_config["host"]) - port = click.prompt("Port", type=int, default=host_config["port"]) - - host_config["host"] = host - host_config["port"] = port - _config_set(f"ssh_hosts.{name}", host_config) - click.secho(f"Updated SSH host: {name}", fg="green") - - elif action == "Delete host": - if not hosts: - click.echo("No hosts to delete.") - return - name = _prompt_choice(list(hosts.keys()), "Select host to delete") - if name and _prompt_confirm(f"Delete host '{name}'?"): - _config_delete(f"ssh_hosts.{name}") - click.secho(f"Deleted SSH host: {name}", fg="green") - - -def manage_api_keys(): - """Interactive API key management.""" - click.secho("\n--- API Key Management ---", fg="cyan") - - api_keys = config.get("api_keys", {}) - - click.echo("\nCurrent API keys:") - for name in sorted(api_keys.keys()): - value = api_keys[name] - masked = value[:8] + "..." + value[-4:] if len(value) > 12 else "***" - click.echo(f" {name}: {masked}") - - action = _prompt_choice(["Add new API key", "Edit API key", "Delete API key", "Back"]) - - if action == "Add new API key": - name = click.prompt("API name (e.g., 'openai', 'anthropic')") - key = click.prompt("API key", hide_input=True) - _config_set(f"api_keys.{name}", key) - click.secho(f"Added API key: {name}", fg="green") - - elif action == "Edit API key": - if not api_keys: - click.echo("No API keys to edit.") - return - name = _prompt_choice(list(api_keys.keys()), "Select API key to edit") - if name: - key = click.prompt("New API key", hide_input=True) - _config_set(f"api_keys.{name}", key) - click.secho(f"Updated API key: {name}", fg="green") - - elif action == "Delete API key": - if not api_keys: - click.echo("No API keys to delete.") - return - name = _prompt_choice(list(api_keys.keys()), "Select API key to delete") - if name and _prompt_confirm(f"Delete API key '{name}'?"): - _config_delete(f"api_keys.{name}") - click.secho(f"Deleted API key: {name}", fg="green") - - -def manage_feishu_apps(): - """Interactive Feishu app management.""" - click.secho("\n--- Feishu App Management ---", fg="cyan") - - apps = config.get("feishu_apps", {}) - - click.echo("\nCurrent Feishu apps:") - for name in sorted(apps.keys()): - app = apps[name] - click.echo(f" {name}: {app['app_id']}") - - action = _prompt_choice(["Add new app", "Edit app", "Delete app", "Back"]) - - if action == "Add new app": - name = click.prompt("App name (e.g., 'mybot')") - app_id = click.prompt("App ID") - app_secret = click.prompt("App Secret", hide_input=True) - - app_config = {"app_id": app_id, "app_secret": app_secret} - _config_set(f"feishu_apps.{name}", app_config) - click.secho(f"Added Feishu app: {name}", fg="green") - - elif action == "Edit app": - if not apps: - click.echo("No apps to edit.") - return - name = _prompt_choice(list(apps.keys()), "Select app to edit") - if name: - app = apps[name] - app_id = click.prompt("App ID", default=app["app_id"]) - change_secret = click.confirm("Change app secret?", default=False) - - app["app_id"] = app_id - if change_secret: - app["app_secret"] = click.prompt("App Secret", hide_input=True) - - _config_set(f"feishu_apps.{name}", app) - click.secho(f"Updated Feishu app: {name}", fg="green") - - elif action == "Delete app": - if not apps: - click.echo("No apps to delete.") - return - name = _prompt_choice(list(apps.keys()), "Select app to delete") - if name and _prompt_confirm(f"Delete app '{name}'?"): - _config_delete(f"feishu_apps.{name}") - click.secho(f"Deleted Feishu app: {name}", fg="green") - - -def manage_git_proxies(): - """Interactive Git proxy management.""" - click.secho("\n--- Git Proxy Management ---", fg="cyan") - - proxies = config.get("git_proxies", {}) - - click.echo("\nCurrent Git proxies:") - for name, url in sorted(proxies.items()): - click.echo(f" {name}: {url}") - - action = _prompt_choice(["Add new proxy", "Edit proxy", "Delete proxy", "Back"]) - - if action == "Add new proxy": - name = click.prompt("Proxy name (e.g., 'fastgithub')") - url = click.prompt("Proxy URL (e.g., 'http://127.0.0.1:38457')") - _config_set(f"git_proxies.{name}", url) - click.secho(f"Added Git proxy: {name}", fg="green") - - elif action == "Edit proxy": - if not proxies: - click.echo("No proxies to edit.") - return - name = _prompt_choice(list(proxies.keys()), "Select proxy to edit") - if name: - url = click.prompt("Proxy URL", default=proxies[name]) - _config_set(f"git_proxies.{name}", url) - click.secho(f"Updated Git proxy: {name}", fg="green") - - elif action == "Delete proxy": - if not proxies: - click.echo("No proxies to delete.") - return - name = _prompt_choice(list(proxies.keys()), "Select proxy to delete") - if name and _prompt_confirm(f"Delete proxy '{name}'?"): - _config_delete(f"git_proxies.{name}") - click.secho(f"Deleted Git proxy: {name}", fg="green") - - -def _config_set(key: str, value): - """Set a config value directly in the JSON file.""" - config_path = config._config_path - with open(config_path) as f: - data = json.load(f) - - keys = key.split(".") - target = data - for k in keys[:-1]: - if k not in target: - target[k] = {} - target = target[k] - target[keys[-1]] = value - - with open(config_path, "w") as f: - json.dump(data, f, indent=2, ensure_ascii=False) - f.write("\n") - - -def _config_delete(key: str): - """Delete a config key directly from the JSON file.""" - config_path = config._config_path - with open(config_path) as f: - data = json.load(f) - - keys = key.split(".") - target = data - for k in keys[:-1]: - target = target[k] - del target[keys[-1]] - - with open(config_path, "w") as f: - json.dump(data, f, indent=2, ensure_ascii=False) - f.write("\n") diff --git a/mycli/commands/env.py b/mycli/commands/env.py deleted file mode 100644 index 79c3f00..0000000 --- a/mycli/commands/env.py +++ /dev/null @@ -1,182 +0,0 @@ -"""Environment paths and quick navigation.""" - -import functools -import os -import subprocess -from pathlib import Path - -import click - -from mycli.config import config -from mycli.utils import handle_errors - - -@functools.lru_cache(maxsize=1) -def _get_paths() -> dict[str, Path]: - """Lazy load paths from config.""" - return config.get_all_paths() - - -@click.group(name="env") -def env_cmd(): - """Environment paths and navigation.""" - pass - - -@env_cmd.command("goto") -@click.argument("name") -@handle_errors -def goto(name): - """Print path for cd (use: cd $(mycli env goto )).""" - paths = _get_paths() - if name not in paths: - click.echo(f"Unknown path: {name}", err=True) - click.echo(f"Available: {', '.join(paths.keys())}", err=True) - raise click.Exit(1) - click.echo(paths[name]) - - -@env_cmd.command("list") -@handle_errors -def list_paths(): - """List all configured paths.""" - paths = _get_paths() - max_len = max(len(k) for k in paths.keys()) - for name, path in sorted(paths.items()): - exists = "✓" if path.exists() else "✗" - click.echo(f"{name:{max_len}} {exists} {path}") - - -@env_cmd.command("cd") -@click.argument("name") -@handle_errors -def cd_path(name): - """Change directory (launches new shell).""" - paths = _get_paths() - if name not in paths: - click.echo(f"Unknown path: {name}", err=True) - raise click.Exit(1) - - target = paths[name] - if not target.exists(): - click.echo(f"Path does not exist: {target}", err=True) - raise click.Exit(1) - - shell = os.environ.get("SHELL", "/bin/zsh") - click.echo(f"Starting shell in: {target}") - subprocess.run([shell], cwd=target) - - -@env_cmd.command("status") -@handle_errors -def status(): - """Show environment status.""" - paths = _get_paths() - click.secho("=== Paths ===", fg="cyan") - for name, path in sorted(paths.items()): - exists = "✓" if path.exists() else "✗" - click.echo(f" {name:12} [{exists}] {path}") - - click.secho("\n=== OpenFOAM ===", fg="cyan") - openfoam_path = "/Volumes/OpenFOAM/openfoam/build" - if Path("/Volumes/OpenFOAM").exists(): - click.secho(f" Mounted: {openfoam_path}", fg="green") - else: - click.secho(" Not mounted", fg="red") - - # API Keys status (without showing actual values) - click.secho("\n=== API Keys ===", fg="cyan") - api_keys = config.get("api_keys", {}) - for name in api_keys.keys(): - env_var = f"{name.upper()}_API_KEY" - is_set = "✓" if os.environ.get(env_var) else "✗" - click.echo(f" {name:12} [{is_set}] {env_var}") - - # Feishu Apps status - click.secho("\n=== Feishu Apps ===", fg="cyan") - feishu_apps = config.get("feishu_apps", {}) - for app_name in feishu_apps.keys(): - app_id_var = f"{app_name.upper()}_APP_ID" - is_set = "✓" if os.environ.get(app_id_var) else "✗" - click.echo(f" {app_name:12} [{is_set}] {app_id_var}") - - -@env_cmd.command("export") -@click.argument("name", required=False) -def export_env(name): - """Print export statements for environment variables. - - Examples: - mycli env export # Export all - mycli env export deepseek # Export specific API key - mycli env export feishu # Export all Feishu apps - eval "$(mycli env export)" # Load in current shell - """ - if name is None: - # Export all - _export_api_keys() - _export_feishu_apps() - elif name == "feishu": - _export_feishu_apps() - elif name in config.get("api_keys", {}): - _export_api_key(name) - elif name in config.get("feishu_apps", {}): - _export_feishu_app(name) - else: - click.echo(f"Unknown export target: {name}", err=True) - click.echo(f"Available: api_keys ({', '.join(config.get('api_keys', {}).keys())}), " - f"feishu_apps ({', '.join(config.get('feishu_apps', {}).keys())})", err=True) - raise click.Exit(1) - - -def _export_api_key(name: str): - """Export a single API key.""" - api_keys = config.get("api_keys", {}) - if name not in api_keys: - return - env_var = f"{name.upper()}_API_KEY" - value = api_keys[name] - click.echo(f"export {env_var}={value}") - - -def _export_api_keys(): - """Export all API keys.""" - api_keys = config.get("api_keys", {}) - for name in api_keys.keys(): - _export_api_key(name) - - -def _export_feishu_app(name: str): - """Export a single Feishu app.""" - feishu_apps = config.get("feishu_apps", {}) - if name not in feishu_apps: - return - app = feishu_apps[name] - prefix = name.upper() - click.echo(f"export {prefix}_APP_ID={app['app_id']}") - click.echo(f"export {prefix}_APP_SECRET={app['app_secret']}") - - -def _export_feishu_apps(): - """Export all Feishu apps.""" - feishu_apps = config.get("feishu_apps", {}) - for name in feishu_apps.keys(): - _export_feishu_app(name) - - -@env_cmd.command("init") -@click.option("--shell", "-s", "shell_type", type=click.Choice(["bash", "zsh", "fish"]), default="zsh") -def init_shell(shell_type): - """Print shell initialization snippet. - - Add this to your ~/.zshrc or ~/.bashrc: - eval "$(mycli env init)" - """ - snippet = f"""# MyCLI environment initialization -# Add this line to your ~/.{shell_type}rc: -# eval "$(mycli env init)" - -# Export API keys and app credentials -eval "$(mycli env export 2>/dev/null)" -""" - click.echo(snippet) diff --git a/mycli/commands/git.py b/mycli/commands/git.py deleted file mode 100644 index fd3bd8b..0000000 --- a/mycli/commands/git.py +++ /dev/null @@ -1,98 +0,0 @@ -"""Git utilities including proxy management.""" - -import subprocess - -import click - -from mycli.config import config - - -def _get_proxies(): - """Get git proxies from config.""" - return config.get_all_git_proxies() - - -@click.group(name="git") -def git_cmd(): - """Git utilities.""" - pass - - -@git_cmd.command("proxy") -@click.argument("name", required=False) -@click.option("--unset", "-u", is_flag=True, help="Unset proxy") -@click.option("--status", "-s", is_flag=True, help="Show current proxy status") -def proxy_cmd(name, unset, status): - """Manage git proxy settings. - - Examples: - mycli git proxy fastgithub # Set fastgithub proxy - mycli git proxy pandafan # Set pandafan proxy - mycli git proxy -u # Unset proxy - mycli git proxy -s # Show status - """ - if status or (not name and not unset): - _show_status() - return - - if unset: - subprocess.run(["git", "config", "--global", "--unset", "http.proxy"], capture_output=True) - subprocess.run(["git", "config", "--global", "--unset", "https.proxy"], capture_output=True) - click.secho("Git proxy unset", fg="green") - return - - proxies = _get_proxies() - if name not in proxies: - click.echo(f"Unknown proxy: {name}", err=True) - click.echo(f"Available: {', '.join(proxies.keys())}", err=True) - raise click.Exit(1) - - proxy_url = proxies[name] - subprocess.run(["git", "config", "--global", "http.proxy", proxy_url], check=True) - subprocess.run(["git", "config", "--global", "https.proxy", proxy_url], check=True) - click.secho(f"Git proxy set to {name}: {proxy_url}", fg="green") - - -def _show_status(): - """Show current git proxy status.""" - result = subprocess.run( - ["git", "config", "--global", "http.proxy"], - capture_output=True, - text=True, - ) - http_proxy = result.stdout.strip() if result.returncode == 0 else "(not set)" - - result = subprocess.run( - ["git", "config", "--global", "https.proxy"], - capture_output=True, - text=True, - ) - https_proxy = result.stdout.strip() if result.returncode == 0 else "(not set)" - - # 检查当前设置的代理名称 - proxies = _get_proxies() - current_name = None - for proxy_name, url in proxies.items(): - if http_proxy == url: - current_name = proxy_name - break - - click.secho("Git proxy status:", fg="cyan") - if current_name: - click.echo(f" Active: {current_name}") - click.echo(f" http.proxy: {http_proxy}") - click.echo(f" https.proxy: {https_proxy}") - - click.secho("\nAvailable proxies:", fg="cyan") - for proxy_name, url in proxies.items(): - marker = "*" if proxy_name == current_name else " " - click.echo(f" [{marker}] {proxy_name:12} {url}") - - -@git_cmd.command("proxy-list") -def proxy_list(): - """List available git proxies.""" - proxies = _get_proxies() - click.secho("Available proxies:", fg="cyan") - for name, url in proxies.items(): - click.echo(f" {name:12} {url}") diff --git a/mycli/commands/self_mgmt.py b/mycli/commands/self_mgmt.py deleted file mode 100644 index a42c8e4..0000000 --- a/mycli/commands/self_mgmt.py +++ /dev/null @@ -1,86 +0,0 @@ -"""Self-management commands for mycli.""" - -import os -import subprocess -import sys -from pathlib import Path - -import click - - -def _get_project_root() -> Path: - """Get mycli project root.""" - # This file is at mycli/commands/self.py - return Path(__file__).parent.parent.parent - - -@click.group(name="self") -def self_cmd(): - """Manage mycli itself.""" - pass - - -@self_cmd.command("update") -def update(): - """Update mycli from the local repository.""" - root = _get_project_root() - - click.secho("Updating mycli...", fg="cyan") - - # Run make install - result = subprocess.run( - ["make", "install"], - cwd=str(root), - capture_output=True, - text=True, - ) - - if result.returncode == 0: - click.secho("mycli updated successfully.", fg="green") - else: - click.secho("Update failed:", fg="red", err=True) - click.echo(result.stderr, err=True) - raise click.Exit(1) - - -@self_cmd.command("uninstall") -def uninstall(): - """Uninstall mycli.""" - root = _get_project_root() - - click.secho("Uninstalling mycli...", fg="cyan") - - result = subprocess.run( - ["make", "uninstall"], - cwd=str(root), - capture_output=True, - text=True, - ) - - if result.returncode == 0: - click.secho("mycli uninstalled.", fg="green") - else: - click.secho("Uninstall failed:", fg="red", err=True) - click.echo(result.stderr, err=True) - raise click.Exit(1) - - -@self_cmd.command("info") -def info(): - """Show mycli installation info.""" - root = _get_project_root() - - click.secho("MyCLI Info:", fg="cyan") - click.echo(f" Project root: {root}") - click.echo(f" Commands dir: {Path(__file__).parent}") - - # Check if in PATH - mycli_path = subprocess.run( - ["which", "mycli"], - capture_output=True, - text=True, - ) - if mycli_path.returncode == 0: - click.echo(f" Executable: {mycli_path.stdout.strip()}") - else: - click.secho(" Executable: not in PATH", fg="yellow") diff --git a/mycli/config.py b/mycli/config.py deleted file mode 100644 index 793a2b3..0000000 --- a/mycli/config.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Configuration management for mycli.""" - -import json -import os -from pathlib import Path -from typing import Any - - -class Config: - """Configuration manager.""" - - def __init__(self): - self._data: dict = {} - self._config_path = Path(__file__).parent / "config.json" - self._load() - - def _load(self): - """Load configuration from JSON file.""" - if self._config_path.exists(): - with open(self._config_path) as f: - self._data = json.load(f) - else: - self._data = {} - - def get(self, key: str, default: Any = None) -> Any: - """Get configuration value by dot notation key. - - Examples: - config.get("paths.research") - config.get("ssh_hosts.tianhe.port") - """ - keys = key.split(".") - value = self._data - for k in keys: - if isinstance(value, dict) and k in value: - value = value[k] - else: - return default - return value - - def get_path(self, name: str) -> Path | None: - """Get a path and expand ~ to home directory.""" - path_str = self.get(f"paths.{name}") - if path_str: - return Path(path_str).expanduser() - return None - - def get_all_paths(self) -> dict[str, Path]: - """Get all paths as Path objects.""" - paths = self.get("paths", {}) - return {name: Path(path).expanduser() for name, path in paths.items()} - - def get_ssh_host(self, name: str) -> dict | None: - """Get SSH host configuration.""" - return self.get(f"ssh_hosts.{name}") - - def get_git_proxy(self, name: str) -> str | None: - """Get Git proxy URL.""" - return self.get(f"git_proxies.{name}") - - def get_all_git_proxies(self) -> dict[str, str]: - """Get all Git proxy configurations.""" - return self.get("git_proxies", {}) - - def edit(self): - """Open config file in default editor.""" - editor = os.environ.get("EDITOR", "vim") - os.system(f"{editor} {self._config_path}") - - def show(self): - """Display configuration.""" - import json - print(json.dumps(self._data, indent=2, ensure_ascii=False)) - - -# Global config instance -config = Config() diff --git a/mycli/__init__.py b/mytoolkit/__init__.py similarity index 100% rename from mycli/__init__.py rename to mytoolkit/__init__.py diff --git a/mycli/cli.py b/mytoolkit/cli.py similarity index 61% rename from mycli/cli.py rename to mytoolkit/cli.py index c95bf5e..453572a 100644 --- a/mycli/cli.py +++ b/mytoolkit/cli.py @@ -2,11 +2,12 @@ import click -from mycli.commands import pdf, image, latex, video, bib, utils, env_cmd, ssh_cmd, git_cmd, self_cmd, config_cmd, wizard_cmd +from mytoolkit.commands import pdf, image, latex, video, bib, utils, env_cmd, ssh_cmd, git_cmd +from mytoolkit.commands.self_mgmt import update_cmd, uninstall_cmd, self_cmd @click.group() -@click.version_option(version="0.1.0", prog_name="mycli") +@click.version_option(version="0.1.0", prog_name="mytoolkit") def cli(): """Personal CLI toolkit.""" pass @@ -22,9 +23,9 @@ cli.add_command(utils.utils) cli.add_command(env_cmd) cli.add_command(ssh_cmd) cli.add_command(git_cmd) +cli.add_command(update_cmd) +cli.add_command(uninstall_cmd) cli.add_command(self_cmd) -cli.add_command(config_cmd) -cli.add_command(wizard_cmd) def main(): diff --git a/mycli/commands/__init__.py b/mytoolkit/commands/__init__.py similarity index 55% rename from mycli/commands/__init__.py rename to mytoolkit/commands/__init__.py index 39e9eb7..ff87eda 100644 --- a/mycli/commands/__init__.py +++ b/mytoolkit/commands/__init__.py @@ -4,8 +4,6 @@ from . import pdf, image, latex, video, bib, utils from .env import env_cmd from .ssh import ssh_cmd from .git import git_cmd -from .self_mgmt import self_cmd -from .config_cmd import config_cmd -from .config_wizard import wizard_cmd +from .self_mgmt import self_cmd, update_cmd, uninstall_cmd -__all__ = ["pdf", "image", "latex", "video", "bib", "utils", "env_cmd", "ssh_cmd", "git_cmd", "self_cmd", "config_cmd", "wizard_cmd"] +__all__ = ["pdf", "image", "latex", "video", "bib", "utils", "env_cmd", "ssh_cmd", "git_cmd", "self_cmd", "update_cmd", "uninstall_cmd"] diff --git a/mycli/commands/bib.py b/mytoolkit/commands/bib.py similarity index 87% rename from mycli/commands/bib.py rename to mytoolkit/commands/bib.py index be0851a..aa465b3 100644 --- a/mycli/commands/bib.py +++ b/mytoolkit/commands/bib.py @@ -5,8 +5,8 @@ from pathlib import Path import click -from mycli.config import config -from mycli.utils import handle_errors, run_command +from mytoolkit.config import config +from mytoolkit.utils import handle_errors, run_command @click.group() @@ -41,8 +41,10 @@ def to_markdown(files, dry_run): @handle_errors def cv_update(): """Update CV bibliography using biber.""" - cv_path = config.get_path("cv") - if not cv_path: + cv_path_str = config.get("path_cv") + if cv_path_str: + cv_path = Path(cv_path_str).expanduser() + else: # Fallback to hardcoded path cv_path = Path.home() / "Documents/Personal/resume_cv/cv_lai_maintaining_latex/cv_lai_maintaining" diff --git a/mytoolkit/commands/env.py b/mytoolkit/commands/env.py new file mode 100644 index 0000000..d1a3629 --- /dev/null +++ b/mytoolkit/commands/env.py @@ -0,0 +1,65 @@ +"""Environment variables management.""" + +import click + +from mytoolkit.config import config + + +@click.group(name="env") +def env_cmd(): + """Manage environment variables.""" + pass + + +@env_cmd.command("list") +def env_list(): + """List all vars.""" + vars = config.get_all() + if not vars: + click.echo("No vars configured.") + return + for name, value in sorted(vars.items()): + masked = "***" if any(x in name.lower() for x in ["key", "secret", "token", "pass"]) else value + click.echo(f"{name:20} = {masked}") + + +@env_cmd.command("get") +@click.argument("name") +def env_get(name): + """Get a var value.""" + value = config.get(name) + if value is None: + click.echo(f"Var not found: {name}", err=True) + raise click.Exit(1) + click.echo(value) + + +@env_cmd.command("set") +@click.argument("name") +@click.argument("value", required=False) +@click.option("--secret", is_flag=True, help="Hide input for secrets") +def env_set(name, value, secret): + """Set a var. Prompts if value not provided.""" + if value is None: + value = click.prompt("Value", hide_input=secret) + config.set(name, value) + click.secho(f"Set: {name}", fg="green") + + +@env_cmd.command("remove") +@click.argument("name") +@click.confirmation_option(prompt="Remove this var?") +def env_remove(name): + """Remove a var.""" + if config.remove(name): + click.secho(f"Removed: {name}", fg="green") + else: + click.echo(f"Var not found: {name}", err=True) + raise click.Exit(1) + + +@env_cmd.command("export") +def env_export(): + """Print export statements for shell eval.""" + for name, value in config.export().items(): + click.echo(f"export {name}={value}") diff --git a/mytoolkit/commands/git.py b/mytoolkit/commands/git.py new file mode 100644 index 0000000..acd9bb1 --- /dev/null +++ b/mytoolkit/commands/git.py @@ -0,0 +1,116 @@ +"""Git utilities including proxy management.""" + +import subprocess + +import click + +from mytoolkit.config import config + + +def _get_proxies() -> dict[str, str]: + """Get git proxies from config.""" + proxies = {} + for key, value in config.get_all().items(): + if key.startswith("proxy_"): + name = key[6:] # Remove 'proxy_' prefix + proxies[name] = value + return proxies + + +def _get_git_proxy(key: str) -> str: + """Get a global git proxy config value.""" + result = subprocess.run( + ["git", "config", "--global", key], + capture_output=True, + text=True, + check=False, + ) + return result.stdout.strip() if result.returncode == 0 else "(not set)" + + +def _unset_git_proxy(key: str) -> None: + """Unset a global git proxy config value (no-op if not set).""" + subprocess.run( + ["git", "config", "--global", "--unset", key], + capture_output=True, + check=False, + ) + + +@click.group(name="git") +def git_cmd() -> None: + """Git utilities.""" + pass + + +@git_cmd.group(name="proxy") +def proxy_cmd() -> None: + """Manage git proxy settings.""" + pass + + +def _complete_proxy_names(_ctx, _param, incomplete): + """Shell completion for proxy names.""" + return [ + name for name in _get_proxies() if name.startswith(incomplete) + ] + + +@proxy_cmd.command("set") +@click.argument("name", shell_complete=_complete_proxy_names) +def proxy_set(name: str) -> None: + """Set git proxy by name.""" + proxies = _get_proxies() + if name not in proxies: + click.echo(f"Unknown proxy: {name}", err=True) + click.echo(f"Available: {', '.join(proxies.keys())}", err=True) + raise click.Exit(1) + + proxy_url = proxies[name] + subprocess.run( + ["git", "config", "--global", "http.proxy", proxy_url], check=True + ) + subprocess.run( + ["git", "config", "--global", "https.proxy", proxy_url], check=True + ) + click.secho(f"Git proxy set to {name}: {proxy_url}", fg="green") + + +@proxy_cmd.command("unset") +def proxy_unset() -> None: + """Unset git proxy.""" + _unset_git_proxy("http.proxy") + _unset_git_proxy("https.proxy") + click.secho("Git proxy unset", fg="green") + + +@proxy_cmd.command("status") +def proxy_status() -> None: + """Show current git proxy status.""" + http_proxy = _get_git_proxy("http.proxy") + https_proxy = _get_git_proxy("https.proxy") + + proxies = _get_proxies() + current_name = next( + (p for p, url in proxies.items() if url == http_proxy), None + ) + + click.secho("Git proxy status:", fg="cyan") + if current_name: + click.echo(f" Active: {current_name}") + click.echo(f" http.proxy: {http_proxy}") + click.echo(f" https.proxy: {https_proxy}") + + click.secho("\nAvailable proxies:", fg="cyan") + for proxy_name, url in proxies.items(): + marker = "*" if proxy_name == current_name else " " + click.echo(f" [{marker}] {proxy_name:12} {url}") + + +@proxy_cmd.command("list") +def proxy_list_cmd() -> None: + """List available git proxies.""" + proxies = _get_proxies() + click.secho("Available proxies:", fg="cyan") + for name, url in proxies.items(): + click.echo(f" {name:12} {url}") diff --git a/mycli/commands/image.py b/mytoolkit/commands/image.py similarity index 98% rename from mycli/commands/image.py rename to mytoolkit/commands/image.py index 2b5ac30..175e1ca 100644 --- a/mycli/commands/image.py +++ b/mytoolkit/commands/image.py @@ -5,7 +5,7 @@ from pathlib import Path import click -from mycli.utils import handle_errors, run_command +from mytoolkit.utils import handle_errors, run_command @click.group() diff --git a/mycli/commands/latex.py b/mytoolkit/commands/latex.py similarity index 95% rename from mycli/commands/latex.py rename to mytoolkit/commands/latex.py index e2cec03..6710d33 100644 --- a/mycli/commands/latex.py +++ b/mytoolkit/commands/latex.py @@ -5,7 +5,7 @@ from pathlib import Path import click -from mycli.utils import handle_errors, run_command +from mytoolkit.utils import handle_errors, run_command @click.group() diff --git a/mycli/commands/pdf.py b/mytoolkit/commands/pdf.py similarity index 98% rename from mycli/commands/pdf.py rename to mytoolkit/commands/pdf.py index 99e14be..3d39d60 100644 --- a/mycli/commands/pdf.py +++ b/mytoolkit/commands/pdf.py @@ -5,7 +5,7 @@ from pathlib import Path import click -from mycli.utils import handle_errors, run_command +from mytoolkit.utils import handle_errors, run_command @click.group() diff --git a/mytoolkit/commands/self_mgmt.py b/mytoolkit/commands/self_mgmt.py new file mode 100644 index 0000000..628b8d6 --- /dev/null +++ b/mytoolkit/commands/self_mgmt.py @@ -0,0 +1,69 @@ +"""Self-management commands for mytoolkit.""" + +import subprocess +from pathlib import Path + +import click + + +def _get_project_root() -> Path: + """Get mytoolkit project root.""" + # This file is at mytoolkit/commands/self_mgmt.py + return Path(__file__).parent.parent.parent + + +@click.command(name="update") +def update_cmd(): + """Update mytoolkit from the local repository.""" + root = _get_project_root() + + click.secho("Updating mytoolkit...", fg="cyan") + + # Run make install + result = subprocess.run( + ["make", "install"], + cwd=str(root), + capture_output=True, + text=True, + ) + + if result.returncode == 0: + click.secho("mytoolkit updated successfully.", fg="green") + else: + click.secho("Update failed:", fg="red", err=True) + click.echo(result.stderr, err=True) + raise click.Exit(1) + + +@click.command(name="uninstall") +def uninstall_cmd(): + """Uninstall mytoolkit.""" + root = _get_project_root() + + click.secho("Uninstalling mytoolkit...", fg="cyan") + + result = subprocess.run( + ["make", "uninstall"], + cwd=str(root), + capture_output=True, + text=True, + ) + + if result.returncode == 0: + click.secho("mytoolkit uninstalled.", fg="green") + else: + click.secho("Uninstall failed:", fg="red", err=True) + click.echo(result.stderr, err=True) + raise click.Exit(1) + + +# Backward compatibility: keep self_cmd group for any existing scripts +@click.group(name="self") +def self_cmd(): + """Manage mytoolkit itself (legacy, use 'update'/'uninstall' directly).""" + pass + + +# Register commands in the group for backward compatibility +self_cmd.add_command(update_cmd, name="update") +self_cmd.add_command(uninstall_cmd, name="uninstall") diff --git a/mycli/commands/ssh.py b/mytoolkit/commands/ssh.py similarity index 80% rename from mycli/commands/ssh.py rename to mytoolkit/commands/ssh.py index 8dd2378..ff19cf0 100644 --- a/mycli/commands/ssh.py +++ b/mytoolkit/commands/ssh.py @@ -5,13 +5,24 @@ from pathlib import Path import click -from mycli.config import config -from mycli.utils import handle_errors +from mytoolkit.config import config +from mytoolkit.utils import handle_errors def _get_hosts() -> dict: """Get SSH hosts from config.""" - return config.get("ssh_hosts", {}) + hosts = {} + for key in config.get_all().keys(): + if key.startswith("ssh_") and not key.endswith("_port") and not key.endswith("_key"): + name = key[4:] # Remove 'ssh_' prefix + host = config.get(f"ssh_{name}") + port = config.get(f"ssh_{name}_port") or "22" + key_file = config.get(f"ssh_{name}_key") + if host: + hosts[name] = {"host": host, "port": int(port)} + if key_file: + hosts[name]["key"] = key_file + return hosts def _build_ssh_base_cmd(host_config: dict) -> list[str]: diff --git a/mycli/commands/utils.py b/mytoolkit/commands/utils.py similarity index 94% rename from mycli/commands/utils.py rename to mytoolkit/commands/utils.py index f3e5bf6..445154f 100644 --- a/mycli/commands/utils.py +++ b/mytoolkit/commands/utils.py @@ -4,7 +4,7 @@ from pathlib import Path import click -from mycli.utils import handle_errors +from mytoolkit.utils import handle_errors @click.group() diff --git a/mycli/commands/video.py b/mytoolkit/commands/video.py similarity index 94% rename from mycli/commands/video.py rename to mytoolkit/commands/video.py index e9f8450..64766ef 100644 --- a/mycli/commands/video.py +++ b/mytoolkit/commands/video.py @@ -5,7 +5,7 @@ from pathlib import Path import click -from mycli.utils import handle_errors, run_command +from mytoolkit.utils import handle_errors, run_command @click.group() diff --git a/mycli/config.json.example b/mytoolkit/config.json.example similarity index 100% rename from mycli/config.json.example rename to mytoolkit/config.json.example diff --git a/mytoolkit/config.py b/mytoolkit/config.py new file mode 100644 index 0000000..6770186 --- /dev/null +++ b/mytoolkit/config.py @@ -0,0 +1,55 @@ +"""Configuration management for mytoolkit.""" + +import json +from pathlib import Path + + +class Config: + """Simple config manager for environment variables.""" + + def __init__(self): + self._config_path = Path(__file__).parent / "config.json" + self._data = self._load() + + def _load(self) -> dict: + if self._config_path.exists(): + with open(self._config_path) as f: + return json.load(f) + return {"vars": {}} + + def save(self): + """Save config to file.""" + with open(self._config_path, "w") as f: + json.dump(self._data, f, indent=2, ensure_ascii=False) + f.write("\n") + + def get(self, name: str) -> str | None: + """Get var by name.""" + return self._data.get("vars", {}).get(name) + + def get_all(self) -> dict[str, str]: + """Get all vars.""" + return self._data.get("vars", {}).copy() + + def set(self, name: str, value: str): + """Set a var.""" + if "vars" not in self._data: + self._data["vars"] = {} + self._data["vars"][name] = value + self.save() + + def remove(self, name: str) -> bool: + """Remove a var. Returns True if existed.""" + if name in self._data.get("vars", {}): + del self._data["vars"][name] + self.save() + return True + return False + + def export(self) -> dict[str, str]: + """Get all vars with env-compatible names.""" + return {f"MYCLI_{k.upper()}": v for k, v in self.get_all().items()} + + +# Global instance +config = Config() diff --git a/mycli/utils.py b/mytoolkit/utils.py similarity index 95% rename from mycli/utils.py rename to mytoolkit/utils.py index fc7022b..be7306c 100644 --- a/mycli/utils.py +++ b/mytoolkit/utils.py @@ -1,4 +1,4 @@ -"""Utility functions and decorators for mycli.""" +"""Utility functions and decorators for mytoolkit.""" import functools import subprocess diff --git a/pyproject.toml b/pyproject.toml index bc77df9..715bfdb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [project] -name = "mycli" +name = "mytoolkit" version = "0.1.0" description = "Personal CLI toolkit" requires-python = ">=3.9" @@ -8,7 +8,7 @@ dependencies = [ ] [project.scripts] -mycli = "mycli.cli:main" +mytoolkit = "mytoolkit.cli:main" [build-system] requires = ["hatchling"] diff --git a/uv.lock b/uv.lock index be2a933..18f0b58 100644 --- a/uv.lock +++ b/uv.lock @@ -46,7 +46,7 @@ wheels = [ ] [[package]] -name = "mycli" +name = "mytoolkit" version = "0.1.0" source = { editable = "." } dependencies = [