chattool 5.3.0__tar.gz → 5.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. {chattool-5.3.0/src/chattool.egg-info → chattool-5.4.0}/PKG-INFO +37 -9
  2. {chattool-5.3.0 → chattool-5.4.0}/README.md +21 -3
  3. {chattool-5.3.0 → chattool-5.4.0}/pyproject.toml +17 -4
  4. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/__init__.py +2 -2
  5. chattool-5.4.0/src/chattool/cli/__init__.py +11 -0
  6. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/chatenv.py +194 -5
  7. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/client/__init__.py +8 -0
  8. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/client/cert_client.py +4 -2
  9. chattool-5.4.0/src/chattool/cli/client/github.py +261 -0
  10. chattool-5.4.0/src/chattool/cli/client/image.py +265 -0
  11. chattool-5.4.0/src/chattool/cli/client/mcp.py +80 -0
  12. chattool-5.4.0/src/chattool/cli/client/network.py +197 -0
  13. chattool-5.4.0/src/chattool/cli/client/tplogin.py +331 -0
  14. chattool-5.4.0/src/chattool/cli/client/zulip.py +368 -0
  15. chattool-5.4.0/src/chattool/cli/main.py +87 -0
  16. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/service/cert_server.py +3 -2
  17. chattool-5.4.0/src/chattool/cli/skill.py +206 -0
  18. chattool-5.4.0/src/chattool/config/__init__.py +25 -0
  19. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/config/elements.py +1 -1
  20. chattool-5.4.0/src/chattool/config/github.py +20 -0
  21. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/config/main.py +135 -0
  22. chattool-5.4.0/src/chattool/docker/__init__.py +3 -0
  23. chattool-5.4.0/src/chattool/docker/cli.py +26 -0
  24. chattool-5.4.0/src/chattool/docker/elements.py +111 -0
  25. chattool-5.4.0/src/chattool/docker/main.py +64 -0
  26. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/llm/chattype.py +7 -4
  27. chattool-5.4.0/src/chattool/mcp/catalog.py +48 -0
  28. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/mcp/server.py +5 -12
  29. chattool-5.4.0/src/chattool/serve/__init__.py +1 -0
  30. chattool-5.4.0/src/chattool/serve/chrome.py +84 -0
  31. chattool-5.4.0/src/chattool/setup/__init__.py +0 -0
  32. chattool-5.4.0/src/chattool/setup/chrome.py +148 -0
  33. chattool-5.4.0/src/chattool/setup/cli.py +4 -0
  34. chattool-5.4.0/src/chattool/setup/codex.py +72 -0
  35. chattool-5.4.0/src/chattool/setup/elements.py +83 -0
  36. chattool-5.4.0/src/chattool/setup/frp.py +224 -0
  37. chattool-5.4.0/src/chattool/setup/main.py +25 -0
  38. chattool-5.4.0/src/chattool/setup/nodejs.py +66 -0
  39. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/__init__.py +4 -2
  40. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/cert/acme_dns_tiny.py +4 -4
  41. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/cert/cert_updater.py +10 -5
  42. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/dns/base.py +1 -1
  43. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/dns/ip_updater.py +2 -2
  44. chattool-5.4.0/src/chattool/tools/github/__init__.py +3 -0
  45. chattool-5.3.0/src/chattool/tools/githubclient.py → chattool-5.4.0/src/chattool/tools/github/client.py +3 -8
  46. chattool-5.4.0/src/chattool/tools/image/__init__.py +40 -0
  47. chattool-5.4.0/src/chattool/tools/image/base.py +30 -0
  48. chattool-5.4.0/src/chattool/tools/image/huggingface.py +44 -0
  49. chattool-5.4.0/src/chattool/tools/image/liblib.py +150 -0
  50. chattool-5.4.0/src/chattool/tools/image/pollinations.py +56 -0
  51. chattool-5.4.0/src/chattool/tools/image/siliconflow.py +92 -0
  52. chattool-5.4.0/src/chattool/tools/image/tongyi.py +61 -0
  53. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/lark/bot.py +47 -29
  54. chattool-5.4.0/src/chattool/tools/network/link_check.py +168 -0
  55. chattool-5.4.0/src/chattool/tools/tplogin.py +242 -0
  56. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/zulip/client.py +13 -2
  57. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/utils/basic.py +1 -1
  58. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/utils/fastobj.py +6 -3
  59. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/utils/httpclient.py +23 -17
  60. chattool-5.4.0/src/chattool/utils/tui.py +91 -0
  61. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/utils/urltool.py +6 -3
  62. {chattool-5.3.0 → chattool-5.4.0/src/chattool.egg-info}/PKG-INFO +37 -9
  63. {chattool-5.3.0 → chattool-5.4.0}/src/chattool.egg-info/SOURCES.txt +33 -1
  64. {chattool-5.3.0 → chattool-5.4.0}/src/chattool.egg-info/entry_points.txt +1 -0
  65. {chattool-5.3.0 → chattool-5.4.0}/src/chattool.egg-info/requires.txt +20 -6
  66. chattool-5.4.0/tests/test_import.py +5 -0
  67. chattool-5.3.0/src/chattool/cli/__init__.py +0 -5
  68. chattool-5.3.0/src/chattool/cli/client/mcp.py +0 -43
  69. chattool-5.3.0/src/chattool/cli/client/network.py +0 -49
  70. chattool-5.3.0/src/chattool/cli/main.py +0 -52
  71. chattool-5.3.0/src/chattool/config/__init__.py +0 -15
  72. chattool-5.3.0/tests/test_import.py +0 -1
  73. {chattool-5.3.0 → chattool-5.4.0}/LICENSE +0 -0
  74. {chattool-5.3.0 → chattool-5.4.0}/setup.cfg +0 -0
  75. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/_all.py +0 -0
  76. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/application/kb/__init__.py +0 -0
  77. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/application/kb/cli.py +0 -0
  78. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/application/kb/ingest.py +0 -0
  79. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/application/kb/manager.py +0 -0
  80. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/application/kb/storage.py +0 -0
  81. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/client/cert_updater.py +0 -0
  82. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/client/dns_updater.py +0 -0
  83. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/client/lark.py +0 -0
  84. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/service/__init__.py +0 -0
  85. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/service/capture.py +0 -0
  86. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/service/lark_serve.py +0 -0
  87. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/cli/test_cmd.py +0 -0
  88. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/const.py +0 -0
  89. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/llm/__init__.py +0 -0
  90. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/llm/response.py +0 -0
  91. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/mcp/__init__.py +0 -0
  92. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/mcp/dns.py +0 -0
  93. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/mcp/network.py +0 -0
  94. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/mcp/zulip.py +0 -0
  95. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/cert/__init__.py +0 -0
  96. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/cert/cert_server.py +0 -0
  97. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/dns/__init__.py +0 -0
  98. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/dns/aliyun.py +0 -0
  99. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/dns/tencent.py +0 -0
  100. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/dns/utils.py +0 -0
  101. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/interact.py +0 -0
  102. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/lark/__init__.py +0 -0
  103. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/lark/context.py +0 -0
  104. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/lark/elements.py +0 -0
  105. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/lark/session.py +0 -0
  106. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/network/__init__.py +0 -0
  107. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/network/scanner.py +0 -0
  108. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/zulip/__init__.py +0 -0
  109. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/tools/zulip/legacy.py +0 -0
  110. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/utils/__init__.py +0 -0
  111. {chattool-5.3.0 → chattool-5.4.0}/src/chattool/utils/custom_logger.py +0 -0
  112. {chattool-5.3.0 → chattool-5.4.0}/src/chattool.egg-info/dependency_links.txt +0 -0
  113. {chattool-5.3.0 → chattool-5.4.0}/src/chattool.egg-info/top_level.txt +0 -0
  114. {chattool-5.3.0 → chattool-5.4.0}/tests/test_chatenv.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chattool
3
- Version: 5.3.0
3
+ Version: 5.4.0
4
4
  Summary: Toolkit for Chat API
5
5
  Author-email: Rex Wang <1073853456@qq.com>
6
6
  License: MIT license
@@ -19,6 +19,7 @@ Requires-Python: >=3.9
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE
21
21
  Requires-Dist: Click>=7.0
22
+ Requires-Dist: questionary>=2.1.0
22
23
  Requires-Dist: requests>=2.20
23
24
  Requires-Dist: aiohttp>=3.8
24
25
  Requires-Dist: tqdm>=4.60
@@ -35,13 +36,22 @@ Requires-Dist: httpx
35
36
  Requires-Dist: gitpython
36
37
  Requires-Dist: PyGithub
37
38
  Requires-Dist: filelock
39
+ Provides-Extra: dns
40
+ Requires-Dist: netifaces; extra == "dns"
41
+ Requires-Dist: alibabacloud_alidns20150109>=3.5.10; extra == "dns"
42
+ Requires-Dist: alibabacloud_tea_openapi>=0.3.0; extra == "dns"
43
+ Requires-Dist: tencentcloud-sdk-python; extra == "dns"
44
+ Provides-Extra: lark
45
+ Requires-Dist: lark-oapi==1.5.3; extra == "lark"
46
+ Requires-Dist: flask; extra == "lark"
47
+ Provides-Extra: images
48
+ Requires-Dist: dashscope; extra == "images"
49
+ Provides-Extra: screenshot
50
+ Requires-Dist: selenium; extra == "screenshot"
51
+ Requires-Dist: pillow; extra == "screenshot"
52
+ Requires-Dist: imageio; extra == "screenshot"
38
53
  Provides-Extra: tools
39
- Requires-Dist: alibabacloud_alidns20150109>=3.5.10; extra == "tools"
40
- Requires-Dist: alibabacloud_tea_openapi>=0.3.0; extra == "tools"
41
- Requires-Dist: tencentcloud-sdk-python; extra == "tools"
42
- Requires-Dist: netifaces; extra == "tools"
43
- Requires-Dist: lark-oapi==1.5.3; extra == "tools"
44
- Requires-Dist: flask; extra == "tools"
54
+ Requires-Dist: chattool[dns,images,lark,screenshot]; extra == "tools"
45
55
  Provides-Extra: tests
46
56
  Requires-Dist: coverage; extra == "tests"
47
57
  Requires-Dist: pytest>=3; extra == "tests"
@@ -197,14 +207,32 @@ chattool dns ddns -d example.com -r nas --ip-type local --local-ip-cidr 192.168.
197
207
  chattool dns cert-update -d example.com -e admin@example.com --cert-dir ./certs
198
208
  ```
199
209
 
200
- ### 5. 其他工具
210
+ ### 5. AI 绘图 (`chattool image`)
211
+
212
+ 支持 Tongyi、Hugging Face、LiblibAI、Pollinations.ai、SiliconFlow 等平台。
213
+
214
+ ```bash
215
+ # 安装图像依赖
216
+ pip install "chattool[images]"
217
+
218
+ # Pollinations(需配置 POLLINATIONS_API_KEY)
219
+ chattool image pollinations list-models
220
+ chattool image pollinations generate "a cat in space" -o cat.png
221
+
222
+ # SiliconFlow(需配置 SILICONFLOW_API_KEY)
223
+ chattool image siliconflow list-models
224
+ chattool image siliconflow generate "a cute dog" -o dog.png
225
+ ```
226
+
227
+ ### 6. 其他工具
201
228
 
202
229
  | 工具 | 命令 | 说明 |
203
230
  |------|------|------|
204
231
  | 网络扫描 | `chattool network scan` | 扫描局域网活跃主机和 SSH 端口 |
205
- | MCP 服务 | `chattool mcp inspect` | MCP Server 能力检查 |
232
+ | MCP 服务 | `chattool mcp info` / `chattool mcp inspect` | MCP Server 能力检查(支持 JSON 输出) |
206
233
  | 截图服务 | `chattool serve capture` | 本地网页截图服务 |
207
234
  | 证书分发 | `chattool serve cert` / `chattool client cert` | SSL 证书集中管理与客户端拉取 |
235
+ | Skills 管理 | `chattool skill install` / `chatskill install` | 安装 ChatTool skills 到 Codex / Claude Code |
208
236
 
209
237
  ## 开源协议
210
238
 
@@ -133,14 +133,32 @@ chattool dns ddns -d example.com -r nas --ip-type local --local-ip-cidr 192.168.
133
133
  chattool dns cert-update -d example.com -e admin@example.com --cert-dir ./certs
134
134
  ```
135
135
 
136
- ### 5. 其他工具
136
+ ### 5. AI 绘图 (`chattool image`)
137
+
138
+ 支持 Tongyi、Hugging Face、LiblibAI、Pollinations.ai、SiliconFlow 等平台。
139
+
140
+ ```bash
141
+ # 安装图像依赖
142
+ pip install "chattool[images]"
143
+
144
+ # Pollinations(需配置 POLLINATIONS_API_KEY)
145
+ chattool image pollinations list-models
146
+ chattool image pollinations generate "a cat in space" -o cat.png
147
+
148
+ # SiliconFlow(需配置 SILICONFLOW_API_KEY)
149
+ chattool image siliconflow list-models
150
+ chattool image siliconflow generate "a cute dog" -o dog.png
151
+ ```
152
+
153
+ ### 6. 其他工具
137
154
 
138
155
  | 工具 | 命令 | 说明 |
139
156
  |------|------|------|
140
157
  | 网络扫描 | `chattool network scan` | 扫描局域网活跃主机和 SSH 端口 |
141
- | MCP 服务 | `chattool mcp inspect` | MCP Server 能力检查 |
158
+ | MCP 服务 | `chattool mcp info` / `chattool mcp inspect` | MCP Server 能力检查(支持 JSON 输出) |
142
159
  | 截图服务 | `chattool serve capture` | 本地网页截图服务 |
143
160
  | 证书分发 | `chattool serve cert` / `chattool client cert` | SSL 证书集中管理与客户端拉取 |
161
+ | Skills 管理 | `chattool skill install` / `chatskill install` | 安装 ChatTool skills 到 Codex / Claude Code |
144
162
 
145
163
  ## 开源协议
146
164
 
@@ -151,4 +169,4 @@ MIT License
151
169
  - `5.3.0` — 飞书机器人(消息收发、事件路由、AI 对话)、CLI 工具链(`chattool lark`、`chattool serve lark`)
152
170
  - `5.0.0` — DNS 管理(阿里云/腾讯云)、DDNS、SSL 证书自动续期、环境变量集中管理
153
171
  - `4.1.0` — 统一 `Chat` API(同步/异步/流式),默认环境变量配置
154
- - 更早版本请参考仓库提交记录
172
+ - 更早版本请参考仓库提交记录
@@ -25,6 +25,7 @@ keywords = ["chattool"]
25
25
  license = {text = "MIT license"}
26
26
  dependencies = [
27
27
  "Click>=7.0",
28
+ "questionary>=2.1.0",
28
29
  "requests>=2.20",
29
30
  "aiohttp>=3.8",
30
31
  "tqdm>=4.60",
@@ -45,14 +46,27 @@ dependencies = [
45
46
  ]
46
47
 
47
48
  [project.optional-dependencies]
48
- tools = [
49
+ dns = [
50
+ "netifaces",
49
51
  "alibabacloud_alidns20150109>=3.5.10",
50
52
  "alibabacloud_tea_openapi>=0.3.0",
51
53
  "tencentcloud-sdk-python",
52
- "netifaces",
54
+ ]
55
+ lark = [
53
56
  "lark-oapi==1.5.3",
54
57
  "flask",
55
58
  ]
59
+ images = [
60
+ "dashscope"
61
+ ]
62
+ screenshot = [
63
+ "selenium",
64
+ "pillow",
65
+ "imageio"
66
+ ]
67
+ tools = [
68
+ "chattool[dns, lark, images, screenshot]",
69
+ ]
56
70
  tests = [
57
71
  "coverage",
58
72
  "pytest>=3",
@@ -74,7 +88,6 @@ dev = [
74
88
  "twine",
75
89
  "chattool[docs,tests,tools]",
76
90
  ]
77
-
78
91
  [project.urls]
79
92
  Homepage = "https://github.com/cubenlp/chattool"
80
93
  Repository = "https://github.com/cubenlp/chattool"
@@ -83,6 +96,7 @@ Repository = "https://github.com/cubenlp/chattool"
83
96
  chattool = "chattool.cli:main_cli"
84
97
  chatenv = "chattool.cli.chatenv:cli"
85
98
  mcp-server-chattool = "chattool.mcp:main"
99
+ chatskill = "chattool.cli.skill:main"
86
100
 
87
101
  [tool.setuptools.dynamic]
88
102
  version = {attr = "chattool.__version__"}
@@ -107,4 +121,3 @@ filterwarnings = [
107
121
  "ignore:websockets.legacy is deprecated:DeprecationWarning",
108
122
  "ignore:websockets.server.WebSocketServerProtocol is deprecated:DeprecationWarning"
109
123
  ]
110
-
@@ -2,7 +2,7 @@
2
2
 
3
3
  __author__ = """Rex Wang"""
4
4
  __email__ = '1073853456@qq.com'
5
- __version__ = '5.3.0'
5
+ __version__ = '5.4.0'
6
6
 
7
7
  from dotenv import load_dotenv
8
8
 
@@ -40,4 +40,4 @@ __all__ = [
40
40
  "TencentDNSClient",
41
41
  "DynamicIPUpdater",
42
42
  "SSLCertUpdater",
43
- ]
43
+ ]
@@ -0,0 +1,11 @@
1
+ import warnings
2
+ # Filter specific DeprecationWarning from third-party libraries
3
+ warnings.filterwarnings("ignore", category=DeprecationWarning, message=".*")
4
+
5
+ def main_cli():
6
+ from .main import cli
7
+ cli()
8
+
9
+ __all__ = [
10
+ "main_cli",
11
+ ]
@@ -1,11 +1,20 @@
1
1
  import click
2
2
  import shutil
3
3
  import os
4
+ import sys
5
+ import warnings
6
+ warnings.filterwarnings("ignore", message=".*pkg_resources is deprecated.*")
7
+ # Filter DeprecationWarning from lark_oapi (asyncio.get_event_loop)
8
+ warnings.filterwarnings("ignore", category=DeprecationWarning, module="lark_oapi.*")
4
9
 
5
10
  from chattool.config import BaseEnvConfig
6
11
  from chattool.const import CHATTOOL_ENV_FILE, CHATTOOL_ENV_DIR
7
12
  from chattool import __version__
8
13
  from chattool.utils import mask_secret
14
+ from chattool.utils.tui import (
15
+ ask_select, ask_text, ask_confirm, get_separator,
16
+ create_choice, is_interactive_available, BACK_VALUE
17
+ )
9
18
 
10
19
  from .test_cmd import test_cmd
11
20
 
@@ -31,13 +40,141 @@ def _resolve_config_types(config_types):
31
40
  if not config_types:
32
41
  return None
33
42
  normalized = [t.lower() for t in config_types]
34
- matched = [
35
- cls for cls in BaseEnvConfig._registry
36
- if cls._title.lower() in normalized
37
- or any(a.lower() in normalized for a in getattr(cls, '_aliases', []))
38
- ]
43
+
44
+ matched = []
45
+
46
+ for cls in BaseEnvConfig._registry:
47
+ is_match = False
48
+
49
+ for t in normalized:
50
+ # Check title (case-insensitive prefix)
51
+ if cls._title.lower().startswith(t):
52
+ is_match = True
53
+
54
+ # Check aliases (case-insensitive prefix)
55
+ if not is_match:
56
+ aliases = getattr(cls, '_aliases', [])
57
+ for alias in aliases:
58
+ if alias.lower().startswith(t):
59
+ is_match = True
60
+ break
61
+
62
+ if is_match:
63
+ break
64
+
65
+ if is_match:
66
+ matched.append(cls)
67
+
39
68
  return matched
40
69
 
70
+ def _group_configs(configs):
71
+ groups = {
72
+ "Model": [],
73
+ "DNS": [],
74
+ "Image": [],
75
+ "Other": [],
76
+ }
77
+ for cfg in configs:
78
+ name = cfg.__name__
79
+ if name in ("OpenAIConfig", "AzureConfig", "SiliconFlowConfig"):
80
+ groups["Model"].append(cfg)
81
+ elif name in ("AliyunConfig", "TencentConfig"):
82
+ groups["DNS"].append(cfg)
83
+ elif name in ("TongyiConfig", "HuggingFaceConfig", "PollinationsConfig", "LiblibConfig"):
84
+ groups["Image"].append(cfg)
85
+ else:
86
+ groups["Other"].append(cfg)
87
+ return groups
88
+
89
+
90
+ def _configure_provider(config_cls):
91
+ """Interactively configure a single provider."""
92
+ click.echo(f"\nConfiguring {config_cls._title}...")
93
+ for name, field in config_cls.get_fields().items():
94
+ prompt_text = f"{name}"
95
+ if field.desc:
96
+ prompt_text += f" ({field.desc})"
97
+
98
+ default_val = field.value if field.value is not None else field.default
99
+
100
+ if field.is_sensitive:
101
+ hint = mask_secret(default_val) if default_val else ""
102
+ message = f"{prompt_text}"
103
+ if hint:
104
+ message += f" [current: {hint}]"
105
+ message += " (leave blank to keep current)"
106
+
107
+ new_val = ask_text(message, password=True)
108
+ if new_val == BACK_VALUE:
109
+ return
110
+ if new_val:
111
+ field.value = new_val
112
+ else:
113
+ new_val = ask_text(
114
+ prompt_text,
115
+ default=str(default_val) if default_val is not None else ""
116
+ )
117
+ if new_val == BACK_VALUE:
118
+ return
119
+ if new_val:
120
+ field.value = new_val
121
+
122
+
123
+ def _interactive_config_loop(grouped_configs):
124
+ """Main loop for interactive configuration using questionary."""
125
+ while True:
126
+ # Main Menu
127
+ main_choices = []
128
+ for section, configs in grouped_configs.items():
129
+ if configs:
130
+ main_choices.append(section)
131
+
132
+ main_choices.append(get_separator())
133
+ main_choices.append("Save & Exit")
134
+ main_choices.append("Exit without Saving")
135
+
136
+ selected_section = ask_select(
137
+ "Select a category to configure (Arrow keys to move, Enter to select):",
138
+ choices=main_choices
139
+ )
140
+
141
+ if selected_section == "Save & Exit":
142
+ BaseEnvConfig.save_env_file(str(CHATTOOL_ENV_FILE), __version__)
143
+ click.echo(f"Configuration saved to {CHATTOOL_ENV_FILE}")
144
+ break
145
+ elif selected_section == "Exit without Saving":
146
+ if ask_confirm("Are you sure you want to exit without saving changes?", default=False):
147
+ break
148
+ continue
149
+ elif selected_section == BACK_VALUE:
150
+ continue
151
+
152
+ # Sub Menu
153
+ while True:
154
+ configs = grouped_configs[selected_section]
155
+ sub_choices = []
156
+ for cfg in configs:
157
+ aliases = getattr(cfg, '_aliases', [])
158
+ alias_text = f" ({', '.join(aliases)})" if aliases else ""
159
+ sub_choices.append(create_choice(
160
+ title=f"{cfg._title}{alias_text}",
161
+ value=cfg
162
+ ))
163
+
164
+ sub_choices.append(get_separator())
165
+ sub_choices.append(create_choice(title="Back", value="Back"))
166
+
167
+ selected_config = ask_select(
168
+ f"[{selected_section}] Select a provider to configure (Esc to back):",
169
+ choices=sub_choices
170
+ )
171
+
172
+ if selected_config == "Back" or selected_config == BACK_VALUE:
173
+ break
174
+
175
+ # Configure Provider
176
+ _configure_provider(selected_config)
177
+
41
178
 
42
179
  @cli.command(name='cat')
43
180
  @click.argument('name', required=False)
@@ -179,6 +316,11 @@ def init(interactive, config_types):
179
316
  - Tencent: tencent, tx, tencent-dns
180
317
  - Zulip: zulip
181
318
  - Feishu: feishu, lark
319
+ - Tongyi: tongyi, dashscope
320
+ - HuggingFace: hf, huggingface
321
+ - Pollinations: pollinations, poll
322
+ - Liblib: liblib
323
+ - SiliconFlow: siliconflow (Model & Image)
182
324
  """
183
325
 
184
326
  target_configs = BaseEnvConfig._registry
@@ -197,8 +339,55 @@ def init(interactive, config_types):
197
339
  if CHATTOOL_ENV_FILE.exists():
198
340
  BaseEnvConfig.load_all(CHATTOOL_ENV_FILE)
199
341
 
342
+ if not interactive:
343
+ interactive = True
344
+
200
345
  if interactive:
201
346
  click.echo("Starting interactive configuration...")
347
+ use_questionary = is_interactive_available()
348
+
349
+ if use_questionary:
350
+ if not config_types:
351
+ grouped = _group_configs(target_configs)
352
+ _interactive_config_loop(grouped)
353
+ return
354
+ else:
355
+ # Linear config for specific types
356
+ for config_cls in target_configs:
357
+ _configure_provider(config_cls)
358
+
359
+ BaseEnvConfig.save_env_file(str(CHATTOOL_ENV_FILE), __version__)
360
+ click.echo(f"Configuration saved to {CHATTOOL_ENV_FILE}")
361
+ return
362
+
363
+ # Fallback for non-questionary environment (pure click)
364
+ if not config_types:
365
+ grouped = _group_configs(target_configs)
366
+ selected_sections = []
367
+ click.echo("\nSelect sections to configure:")
368
+ for section, configs in grouped.items():
369
+ if not configs:
370
+ continue
371
+ if click.confirm(section, default=section == "Model"):
372
+ selected_sections.append(section)
373
+
374
+ if not selected_sections:
375
+ click.echo("No section selected. Nothing to update.")
376
+ return
377
+
378
+ selected_configs = []
379
+ for section in selected_sections:
380
+ click.echo(f"\n[{section}]")
381
+ for config_cls in grouped[section]:
382
+ aliases = getattr(config_cls, '_aliases', [])
383
+ alias_text = f" ({', '.join(aliases)})" if aliases else ""
384
+ if click.confirm(f"Configure {config_cls._title}{alias_text}", default=False):
385
+ selected_configs.append(config_cls)
386
+
387
+ if not selected_configs:
388
+ click.echo("No provider selected. Nothing to update.")
389
+ return
390
+ target_configs = selected_configs
202
391
 
203
392
  for config_cls in target_configs:
204
393
  click.echo(f"\n[{config_cls._title}]")
@@ -4,6 +4,10 @@ from .dns_updater import cli as dns_updater_cli
4
4
  from .mcp import cli as mcp_cli
5
5
  from .network import network as network_cli
6
6
  from .lark import cli as lark_cli
7
+ from .image import cli as image_cli
8
+ from .tplogin import cli as tplogin_cli
9
+ from .github import cli as github_cli
10
+ from .zulip import cli as zulip_cli
7
11
 
8
12
  __all__ = [
9
13
  "cert_client",
@@ -12,4 +16,8 @@ __all__ = [
12
16
  "mcp_cli",
13
17
  "network_cli",
14
18
  "lark_cli",
19
+ "image_cli",
20
+ "tplogin_cli",
21
+ "github_cli",
22
+ "zulip_cli",
15
23
  ]
@@ -1,7 +1,5 @@
1
1
  import click
2
- import requests
3
2
  import os
4
- import git
5
3
  from rich.console import Console
6
4
  from rich.table import Table
7
5
 
@@ -9,6 +7,7 @@ console = Console()
9
7
 
10
8
  def get_git_email():
11
9
  """Get email from git config"""
10
+ import git
12
11
  try:
13
12
  email = git.Git().config("--get", "user.email")
14
13
  if email:
@@ -44,6 +43,7 @@ def cert_client():
44
43
  @common_options
45
44
  def apply(server, token, domains, email, provider, secret_id, secret_key):
46
45
  """申请 SSL 证书"""
46
+ import requests
47
47
  server, token = get_config(server, token)
48
48
  headers = {"X-ChatTool-Token": token} if token else {}
49
49
 
@@ -77,6 +77,7 @@ def apply(server, token, domains, email, provider, secret_id, secret_key):
77
77
  @common_options
78
78
  def list_certs(server, token):
79
79
  """列出已申请的证书"""
80
+ import requests
80
81
  server, token = get_config(server, token)
81
82
  headers = {"X-ChatTool-Token": token} if token else {}
82
83
 
@@ -117,6 +118,7 @@ def list_certs(server, token):
117
118
  @common_options
118
119
  def download(server, token, domain, output_dir):
119
120
  """下载证书文件 (cert.pem, privkey.pem)"""
121
+ import requests
120
122
  server, token = get_config(server, token)
121
123
  headers = {"X-ChatTool-Token": token} if token else {}
122
124