chatup 0.2.15__tar.gz → 0.2.16__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.
- {chatup-0.2.15/src/chatup.egg-info → chatup-0.2.16}/PKG-INFO +17 -2
- {chatup-0.2.15 → chatup-0.2.16}/README.md +16 -1
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/__init__.py +1 -1
- chatup-0.2.16/src/chatup/setup/chatgpt.py +132 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/codex.py +1 -1
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/elements.py +53 -6
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/hermes.py +1 -1
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/uv.py +89 -1
- {chatup-0.2.15 → chatup-0.2.16/src/chatup.egg-info}/PKG-INFO +17 -2
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup.egg-info/SOURCES.txt +4 -0
- chatup-0.2.16/tests/test_chatgpt_setup.py +183 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_codex_setup.py +85 -3
- chatup-0.2.16/tests/test_hermes_model_defaults.py +50 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_setup_cli.py +6 -0
- chatup-0.2.16/tests/test_uv_activation.py +259 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_version.py +1 -1
- {chatup-0.2.15 → chatup-0.2.16}/LICENSE +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/pyproject.toml +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/setup.cfg +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/chrome_for_testing.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/chromedriver.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/cli.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/commands/__init__.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/commands/chrome_for_testing.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/commands/chromedriver.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/commands/playwright.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/config.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/const.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/interaction/__init__.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/interaction/command_schema.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/interaction/policy.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/interaction/warnings.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/playwright.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/runtime/__init__.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/runtime/_managed_artifact.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/runtime/chrome_for_testing.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/runtime/chromedriver.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/runtime/playwright.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/__init__.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/assets/hermes/install.sh +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/assets/nvm.sh +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/cc_connect.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/claude.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/cli.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/crs.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/cursor_agent.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/discourse.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/docker.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/frp.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/gitea.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/lark_cli.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/mode_prompt.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/mysql.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/nginx.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/nodejs.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/opencode.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/service_credentials.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/shell_rc.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/twikoo.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/__init__.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/cli.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/core.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/options.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/render.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/en/AGENTS.md +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/en/discussion/README.md +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/en/projects/README.md +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/zh/AGENTS.md +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/zh/discussion/README.md +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/zh/projects/README.md +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/workspace.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/zsh.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/setup/zulip.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/utils/__init__.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/utils/custom_logger.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/utils/pathing.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup/utils/platforming.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup.egg-info/dependency_links.txt +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup.egg-info/entry_points.txt +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup.egg-info/requires.txt +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/src/chatup.egg-info/top_level.txt +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_browser_backend_cli.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_chrome_for_testing.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_chromedriver.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_cli_tree_docs.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_crs_setup.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_cursor_agent_setup.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_playwright.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_playwright_cli.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_publish_workflow.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_pyproject_metadata.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_service_installers.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_twikoo_setup.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_windows_compat.py +0 -0
- {chatup-0.2.15 → chatup-0.2.16}/tests/test_workspace_setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: ChatArch setup CLI extracted from ChatTool
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -62,6 +62,8 @@ chatup playwright install 1.61.1 -I
|
|
|
62
62
|
chatup workspace default ~/Playground
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
`chatup uv` 默认更新已有 `~/.bashrc`、`~/.zshrc` 的自动激活块;使用 `chatup uv --no-activate` 可保持启动配置不变。不会创建缺失的 rc 文件,Windows 跳过此项。
|
|
66
|
+
|
|
65
67
|
常见安装命令:
|
|
66
68
|
|
|
67
69
|
```bash
|
|
@@ -74,16 +76,29 @@ chatup nginx proxy-pass ./gitea-local.conf --set SERVER_NAME=gitea.local.example
|
|
|
74
76
|
chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
|
|
75
77
|
```
|
|
76
78
|
|
|
79
|
+
## ChatGPT / Codex 桌面应用
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
chatup chatgpt --dry-run
|
|
83
|
+
chatup chatgpt
|
|
84
|
+
chatup chatgpt --yes # Windows 首次安装时接受 Store 协议
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
安装包含 Codex 的新版官方 ChatGPT 桌面应用。macOS 需要 Homebrew,Windows 需要 WinGet;Linux preview 暂按[官方说明](https://learn.chatgpt.com/docs/linux/linux-app)手动安装。现有 `chatup codex` 仍安装/配置 Codex CLI。不会自动启动、登录或升级已有应用;[完整约定](https://arch.gh.wzhecnu.cn/ChatUp/commands/#chatgpt-desktop)。
|
|
88
|
+
|
|
89
|
+
`chatup codex`、`chatup hermes` 未配置模型时默认使用 `gpt-5.6-terra`;用户指定的模型和已有配置仍优先。
|
|
90
|
+
|
|
77
91
|
## 当前能力
|
|
78
92
|
|
|
79
93
|
| 能力组 | 命令 |
|
|
80
94
|
| --- | --- |
|
|
81
95
|
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`playwright`、`frp` |
|
|
82
96
|
| 工作区脚手架 | `workspace` |
|
|
97
|
+
| 官方桌面应用 | `chatgpt`(含 Codex) |
|
|
83
98
|
| 本地服务安装 | `gitea`、`discourse`、`zulip`、`mysql`、`nginx`、`crs` |
|
|
84
99
|
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
|
|
85
100
|
|
|
86
|
-
|
|
101
|
+
桌面应用使用系统包管理器的原生目录;ChatArch 自管安装项默认目录收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/playwright`、`~/.chatarch/chattea`、`~/.chatarch/discourse`、`~/.chatarch/zulip`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local`。`cursor-agent` 额外注册 ChatEnv `CursorAgent` profile,`discourse`/`zulip` 注册管理员凭据 profile,并支持 `-e/--env` 从 env 文件或 profile 快速配置;显式选择 profile 时不会混入进程环境中的其他账号凭据。CLI 树由 ChatStyle 的注册表渲染。更完整的能力边界见 `docs/capability-map.md`。
|
|
87
102
|
|
|
88
103
|
## 开发
|
|
89
104
|
|
|
@@ -31,6 +31,8 @@ chatup playwright install 1.61.1 -I
|
|
|
31
31
|
chatup workspace default ~/Playground
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
`chatup uv` 默认更新已有 `~/.bashrc`、`~/.zshrc` 的自动激活块;使用 `chatup uv --no-activate` 可保持启动配置不变。不会创建缺失的 rc 文件,Windows 跳过此项。
|
|
35
|
+
|
|
34
36
|
常见安装命令:
|
|
35
37
|
|
|
36
38
|
```bash
|
|
@@ -43,16 +45,29 @@ chatup nginx proxy-pass ./gitea-local.conf --set SERVER_NAME=gitea.local.example
|
|
|
43
45
|
chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
|
|
44
46
|
```
|
|
45
47
|
|
|
48
|
+
## ChatGPT / Codex 桌面应用
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
chatup chatgpt --dry-run
|
|
52
|
+
chatup chatgpt
|
|
53
|
+
chatup chatgpt --yes # Windows 首次安装时接受 Store 协议
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
安装包含 Codex 的新版官方 ChatGPT 桌面应用。macOS 需要 Homebrew,Windows 需要 WinGet;Linux preview 暂按[官方说明](https://learn.chatgpt.com/docs/linux/linux-app)手动安装。现有 `chatup codex` 仍安装/配置 Codex CLI。不会自动启动、登录或升级已有应用;[完整约定](https://arch.gh.wzhecnu.cn/ChatUp/commands/#chatgpt-desktop)。
|
|
57
|
+
|
|
58
|
+
`chatup codex`、`chatup hermes` 未配置模型时默认使用 `gpt-5.6-terra`;用户指定的模型和已有配置仍优先。
|
|
59
|
+
|
|
46
60
|
## 当前能力
|
|
47
61
|
|
|
48
62
|
| 能力组 | 命令 |
|
|
49
63
|
| --- | --- |
|
|
50
64
|
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`playwright`、`frp` |
|
|
51
65
|
| 工作区脚手架 | `workspace` |
|
|
66
|
+
| 官方桌面应用 | `chatgpt`(含 Codex) |
|
|
52
67
|
| 本地服务安装 | `gitea`、`discourse`、`zulip`、`mysql`、`nginx`、`crs` |
|
|
53
68
|
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
|
|
54
69
|
|
|
55
|
-
|
|
70
|
+
桌面应用使用系统包管理器的原生目录;ChatArch 自管安装项默认目录收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/playwright`、`~/.chatarch/chattea`、`~/.chatarch/discourse`、`~/.chatarch/zulip`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local`。`cursor-agent` 额外注册 ChatEnv `CursorAgent` profile,`discourse`/`zulip` 注册管理员凭据 profile,并支持 `-e/--env` 从 env 文件或 profile 快速配置;显式选择 profile 时不会混入进程环境中的其他账号凭据。CLI 树由 ChatStyle 的注册表渲染。更完整的能力边界见 `docs/capability-map.md`。
|
|
56
71
|
|
|
57
72
|
## 开发
|
|
58
73
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Install the official ChatGPT desktop app (the successor to Codex App).
|
|
2
|
+
|
|
3
|
+
The OS package manager owns downloads, signatures, application paths and state.
|
|
4
|
+
This module never launches the app or changes Codex CLI configuration/auth.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import platform
|
|
9
|
+
import shutil
|
|
10
|
+
import subprocess
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
CHATGPT_CASK = "homebrew/cask/chatgpt"
|
|
14
|
+
CHATGPT_STORE_ID = "9PLM9XGG6VKS"
|
|
15
|
+
DOWNLOAD_URL = "https://chatgpt.com/download/"
|
|
16
|
+
LINUX_GUIDE_URL = "https://learn.chatgpt.com/docs/linux/linux-app"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def plan_chatgpt_install(*, yes: bool = False) -> dict[str, Any]:
|
|
20
|
+
"""Return a side-effect-free install plan for the current OS.
|
|
21
|
+
|
|
22
|
+
``yes`` explicitly accepts Microsoft Store source/package agreements.
|
|
23
|
+
Homebrew/WinGet resolve the current release and enforce OS/CPU requirements.
|
|
24
|
+
Linux preview installation is deliberately not automated here.
|
|
25
|
+
"""
|
|
26
|
+
system = platform.system()
|
|
27
|
+
if system == "Darwin":
|
|
28
|
+
manager = "brew"
|
|
29
|
+
package = CHATGPT_CASK
|
|
30
|
+
command = [manager, "install", "--cask", package]
|
|
31
|
+
verify_command = [manager, "list", "--cask", "--versions", package]
|
|
32
|
+
manager_url = "https://brew.sh/"
|
|
33
|
+
elif system == "Windows":
|
|
34
|
+
manager = "winget"
|
|
35
|
+
package = CHATGPT_STORE_ID
|
|
36
|
+
selector = ["--id", package, "--exact", "--source", "msstore", "--disable-interactivity"]
|
|
37
|
+
command = [manager, "install", *selector, "--no-upgrade"]
|
|
38
|
+
verify_command = [manager, "list", *selector]
|
|
39
|
+
if yes:
|
|
40
|
+
command += ["--accept-package-agreements", "--accept-source-agreements"]
|
|
41
|
+
verify_command += ["--accept-source-agreements"]
|
|
42
|
+
manager_url = "https://aka.ms/getwinget"
|
|
43
|
+
else:
|
|
44
|
+
guide = LINUX_GUIDE_URL if system == "Linux" else DOWNLOAD_URL
|
|
45
|
+
raise RuntimeError(
|
|
46
|
+
f"ChatUp automates ChatGPT desktop installation on macOS and Windows only; "
|
|
47
|
+
f"current platform: {system}. Official downloads/instructions: {guide}"
|
|
48
|
+
)
|
|
49
|
+
return {
|
|
50
|
+
"app": "ChatGPT (includes Codex)",
|
|
51
|
+
"platform": system,
|
|
52
|
+
"manager": manager,
|
|
53
|
+
"manager_url": manager_url,
|
|
54
|
+
"package": package,
|
|
55
|
+
"command": command,
|
|
56
|
+
"verify_command": verify_command,
|
|
57
|
+
"download_url": DOWNLOAD_URL,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _is_installed(plan: dict[str, Any], executable: str) -> bool:
|
|
62
|
+
result = subprocess.run(
|
|
63
|
+
[executable, *plan["verify_command"][1:]],
|
|
64
|
+
capture_output=True,
|
|
65
|
+
text=True,
|
|
66
|
+
encoding="utf-8",
|
|
67
|
+
errors="replace",
|
|
68
|
+
check=False,
|
|
69
|
+
timeout=60,
|
|
70
|
+
)
|
|
71
|
+
if result.returncode != 0 or not result.stdout.strip():
|
|
72
|
+
return False
|
|
73
|
+
if plan["manager"] == "brew":
|
|
74
|
+
for line in result.stdout.splitlines():
|
|
75
|
+
parts = line.split()
|
|
76
|
+
if len(parts) < 2 or parts[0] != "chatgpt":
|
|
77
|
+
continue
|
|
78
|
+
if any(version.startswith("1.") for version in parts[1:]):
|
|
79
|
+
raise RuntimeError(
|
|
80
|
+
"An older ChatGPT Classic cask is registered as chatgpt. "
|
|
81
|
+
"Migrate it manually with Homebrew before installing the new "
|
|
82
|
+
f"ChatGPT/Codex app: {DOWNLOAD_URL}"
|
|
83
|
+
)
|
|
84
|
+
return True
|
|
85
|
+
return False
|
|
86
|
+
# WinGet's exact Store selector exits zero only when a matching package exists.
|
|
87
|
+
return True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def setup_chatgpt(*, dry_run: bool = False, yes: bool = False) -> dict[str, Any]:
|
|
91
|
+
"""Install if absent, then verify registration with the package manager.
|
|
92
|
+
|
|
93
|
+
Returns the plan plus ``status`` (planned/already_installed/installed) and
|
|
94
|
+
``verified``. Dry-run does not require or invoke a package manager. Existing
|
|
95
|
+
installations are not upgraded, overwritten or migrated; authentication and
|
|
96
|
+
launching remain user actions. Raises RuntimeError on failed/unknown results.
|
|
97
|
+
"""
|
|
98
|
+
plan = plan_chatgpt_install(yes=yes)
|
|
99
|
+
result = {**plan, "status": "planned", "verified": False}
|
|
100
|
+
if dry_run:
|
|
101
|
+
return result
|
|
102
|
+
executable = shutil.which(plan["manager"])
|
|
103
|
+
if not executable:
|
|
104
|
+
raise RuntimeError(
|
|
105
|
+
f"Required package manager {plan['manager']} is not on PATH. "
|
|
106
|
+
f"Install it first: {plan['manager_url']} or download manually: {DOWNLOAD_URL}"
|
|
107
|
+
)
|
|
108
|
+
try:
|
|
109
|
+
if _is_installed(plan, executable):
|
|
110
|
+
return {**result, "status": "already_installed", "verified": True}
|
|
111
|
+
installed = subprocess.run(
|
|
112
|
+
[executable, *plan["command"][1:]], check=False, timeout=1800,
|
|
113
|
+
)
|
|
114
|
+
if installed.returncode != 0:
|
|
115
|
+
hint = " Use --yes to accept Store agreements." if plan["manager"] == "winget" and not yes else ""
|
|
116
|
+
raise RuntimeError(
|
|
117
|
+
f"ChatGPT installer failed (exit {installed.returncode}). "
|
|
118
|
+
f"Check the package manager output above.{hint}"
|
|
119
|
+
)
|
|
120
|
+
if not _is_installed(plan, executable):
|
|
121
|
+
raise RuntimeError(
|
|
122
|
+
"ChatGPT installation verification failed. Check the package manager "
|
|
123
|
+
"state before retrying; installation success is not confirmed."
|
|
124
|
+
)
|
|
125
|
+
except subprocess.TimeoutExpired as exc:
|
|
126
|
+
raise RuntimeError(
|
|
127
|
+
"ChatGPT package manager timed out; the installation state is unknown. "
|
|
128
|
+
"Check the package manager before retrying."
|
|
129
|
+
) from exc
|
|
130
|
+
except OSError as exc:
|
|
131
|
+
raise RuntimeError(f"Cannot execute {plan['manager']}: {exc}") from exc
|
|
132
|
+
return {**result, "status": "installed", "verified": True}
|
|
@@ -30,7 +30,7 @@ from chatup.setup.nodejs import (
|
|
|
30
30
|
from chatup.utils.custom_logger import setup_logger
|
|
31
31
|
from chatup.utils.platforming import chmod_private
|
|
32
32
|
|
|
33
|
-
DEFAULT_MODEL = "gpt-5.
|
|
33
|
+
DEFAULT_MODEL = "gpt-5.6-terra"
|
|
34
34
|
DEFAULT_BASE_URL = "https://api.openai.com/v1"
|
|
35
35
|
DEFAULT_AUTH_METHOD = "apikey"
|
|
36
36
|
_ENV_VAR_REF_RE = re.compile(r"\$(?:\{[^}]+\}|[A-Za-z_][A-Za-z0-9_]*)")
|
|
@@ -6,7 +6,8 @@ import click
|
|
|
6
6
|
from chatstyle import INTERACTIVE_OPTION_HELP
|
|
7
7
|
|
|
8
8
|
from chatup.setup.claude import setup_claude
|
|
9
|
-
from chatup.setup.codex import setup_codex
|
|
9
|
+
from chatup.setup.codex import DEFAULT_MODEL as DEFAULT_CODEX_MODEL, setup_codex
|
|
10
|
+
from chatup.setup.chatgpt import setup_chatgpt
|
|
10
11
|
from chatup.setup.cursor_agent import CREDENTIAL_STORE_CHOICES, setup_cursor_agent
|
|
11
12
|
from chatup.setup.cc_connect import setup_cc_connect
|
|
12
13
|
import chatup.setup.crs as crs_module
|
|
@@ -37,7 +38,7 @@ from chatup.setup.gitea import (
|
|
|
37
38
|
DEFAULT_WORK_DIR as DEFAULT_GITEA_WORK_DIR,
|
|
38
39
|
setup_gitea,
|
|
39
40
|
)
|
|
40
|
-
from chatup.setup.hermes import setup_hermes
|
|
41
|
+
from chatup.setup.hermes import DEFAULT_MODEL as DEFAULT_HERMES_MODEL, setup_hermes
|
|
41
42
|
from chatup.setup.lark_cli import setup_lark_cli
|
|
42
43
|
from chatup.setup.mysql import (
|
|
43
44
|
DEFAULT_MYSQL_BIND_ADDRESS,
|
|
@@ -102,8 +103,14 @@ def nodejs_setup(interactive, log_level):
|
|
|
102
103
|
setup_nodejs(interactive=interactive, log_level=log_level)
|
|
103
104
|
|
|
104
105
|
|
|
105
|
-
def uv_setup(venv, python_version, force, log_level):
|
|
106
|
-
setup_uv(
|
|
106
|
+
def uv_setup(venv, python_version, force, log_level, shell_activate):
|
|
107
|
+
setup_uv(
|
|
108
|
+
venv=venv,
|
|
109
|
+
python_version=python_version,
|
|
110
|
+
force=force,
|
|
111
|
+
log_level=log_level,
|
|
112
|
+
shell_activate=shell_activate,
|
|
113
|
+
)
|
|
107
114
|
|
|
108
115
|
|
|
109
116
|
def docker_setup(sudo, interactive, log_level):
|
|
@@ -120,6 +127,20 @@ def zsh_setup(omz, aliases, login_shell, interactive, log_level):
|
|
|
120
127
|
)
|
|
121
128
|
|
|
122
129
|
|
|
130
|
+
def chatgpt_setup(dry_run, yes):
|
|
131
|
+
try:
|
|
132
|
+
result = setup_chatgpt(dry_run=dry_run, yes=yes)
|
|
133
|
+
except RuntimeError as exc:
|
|
134
|
+
raise click.ClickException(str(exc)) from exc
|
|
135
|
+
click.echo(result["app"])
|
|
136
|
+
if result["status"] == "planned":
|
|
137
|
+
click.echo("预览安装命令(未执行):" + " ".join(result["command"]))
|
|
138
|
+
elif result["status"] == "already_installed":
|
|
139
|
+
click.echo("已安装,并已通过包管理器回读确认;未升级或启动应用。")
|
|
140
|
+
else:
|
|
141
|
+
click.echo("安装完成,已通过包管理器回读确认。请手动打开 ChatGPT 并登录。")
|
|
142
|
+
|
|
143
|
+
|
|
123
144
|
def codex_setup(api_key, base_url, model, env, interactive, install_only, log_level):
|
|
124
145
|
setup_codex(
|
|
125
146
|
api_key=api_key,
|
|
@@ -1251,6 +1272,29 @@ SETUP_COMMAND_ELEMENTS = (
|
|
|
1251
1272
|
"help": "Clear and recreate the target environment if it already exists.",
|
|
1252
1273
|
},
|
|
1253
1274
|
),
|
|
1275
|
+
SetupOptionElement(
|
|
1276
|
+
param_decls=("--activate/--no-activate", "shell_activate"),
|
|
1277
|
+
kwargs={
|
|
1278
|
+
"default": True,
|
|
1279
|
+
"show_default": True,
|
|
1280
|
+
"help": "Update auto-activation in existing ~/.bashrc and ~/.zshrc (POSIX only).",
|
|
1281
|
+
},
|
|
1282
|
+
),
|
|
1283
|
+
),
|
|
1284
|
+
),
|
|
1285
|
+
SetupCommandElement(
|
|
1286
|
+
name="chatgpt",
|
|
1287
|
+
help="Install the official ChatGPT desktop app (includes Codex), not the Codex CLI.",
|
|
1288
|
+
callback=chatgpt_setup,
|
|
1289
|
+
options=(
|
|
1290
|
+
SetupOptionElement(
|
|
1291
|
+
param_decls=("--dry-run",),
|
|
1292
|
+
kwargs={"is_flag": True, "help": "Show the install plan without executing or downloading anything."},
|
|
1293
|
+
),
|
|
1294
|
+
SetupOptionElement(
|
|
1295
|
+
param_decls=("--yes", "-y"),
|
|
1296
|
+
kwargs={"is_flag": True, "help": "Accept Microsoft Store source/package agreements on Windows."},
|
|
1297
|
+
),
|
|
1254
1298
|
),
|
|
1255
1299
|
),
|
|
1256
1300
|
SetupCommandElement(
|
|
@@ -1282,7 +1326,10 @@ SETUP_COMMAND_ELEMENTS = (
|
|
|
1282
1326
|
),
|
|
1283
1327
|
SetupOptionElement(
|
|
1284
1328
|
param_decls=("--model",),
|
|
1285
|
-
kwargs={
|
|
1329
|
+
kwargs={
|
|
1330
|
+
"default": None,
|
|
1331
|
+
"help": f"Optional model override; fallback: {DEFAULT_CODEX_MODEL}.",
|
|
1332
|
+
},
|
|
1286
1333
|
),
|
|
1287
1334
|
SetupOptionElement(
|
|
1288
1335
|
param_decls=("-e", "--env"),
|
|
@@ -1545,7 +1592,7 @@ SETUP_COMMAND_ELEMENTS = (
|
|
|
1545
1592
|
),
|
|
1546
1593
|
SetupOptionElement(
|
|
1547
1594
|
param_decls=("--model",),
|
|
1548
|
-
kwargs={"default": None, "help": "Hermes
|
|
1595
|
+
kwargs={"default": None, "help": f"Hermes model override; fallback: {DEFAULT_HERMES_MODEL}."},
|
|
1549
1596
|
),
|
|
1550
1597
|
SetupOptionElement(
|
|
1551
1598
|
param_decls=("--with-webui-env",),
|
|
@@ -23,7 +23,7 @@ logger = setup_logger("setup_hermes")
|
|
|
23
23
|
CHATARCH_HERMES_INSTALLER_URL = (
|
|
24
24
|
"https://raw.githubusercontent.com/ChatArch/hermes-agent/main/scripts/install.sh"
|
|
25
25
|
)
|
|
26
|
-
DEFAULT_MODEL = "gpt-5.
|
|
26
|
+
DEFAULT_MODEL = "gpt-5.6-terra"
|
|
27
27
|
DEFAULT_BASE_URL = "https://api.openai.com/v1"
|
|
28
28
|
DEFAULT_WEBUI_HOST = "127.0.0.1"
|
|
29
29
|
DEFAULT_WEBUI_PORT = 8787
|
|
@@ -3,8 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
import os
|
|
4
4
|
import shlex
|
|
5
5
|
import shutil
|
|
6
|
+
import stat
|
|
6
7
|
import subprocess
|
|
8
|
+
import tempfile
|
|
7
9
|
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
8
11
|
|
|
9
12
|
import click
|
|
10
13
|
|
|
@@ -16,6 +19,11 @@ DEFAULT_VENV_PATH = Path("~/.chatarch/venv")
|
|
|
16
19
|
UV_INSTALLER_URL = "https://astral.sh/uv/install.sh"
|
|
17
20
|
UV_WINDOWS_INSTALLER_URL = "https://astral.sh/uv/install.ps1"
|
|
18
21
|
|
|
22
|
+
# Share ChatUV's markers so switching bootstrap tools replaces the same block.
|
|
23
|
+
SHELL_ACTIVATE_BEGIN = "# >>> chatuv activate >>>"
|
|
24
|
+
SHELL_ACTIVATE_END = "# <<< chatuv activate <<<"
|
|
25
|
+
SHELL_RC_NAMES = (".zshrc", ".bashrc")
|
|
26
|
+
|
|
19
27
|
logger = setup_logger("setup_uv")
|
|
20
28
|
|
|
21
29
|
|
|
@@ -140,12 +148,88 @@ def create_chatarch_python_env(
|
|
|
140
148
|
raise click.ClickException(f"Failed to create ChatArch Python env at {venv_path}: {message}")
|
|
141
149
|
|
|
142
150
|
|
|
151
|
+
def _upsert_activation_block(text: str, block: str) -> str:
|
|
152
|
+
lines = text.splitlines(keepends=True)
|
|
153
|
+
starts = [i for i, line in enumerate(lines) if line.rstrip("\r\n") == SHELL_ACTIVATE_BEGIN]
|
|
154
|
+
ends = [i for i, line in enumerate(lines) if line.rstrip("\r\n") == SHELL_ACTIVATE_END]
|
|
155
|
+
if starts or ends:
|
|
156
|
+
if len(starts) != 1 or len(ends) != 1 or starts[0] >= ends[0]:
|
|
157
|
+
raise ValueError("Incomplete or duplicate activation block; repair the marked block first")
|
|
158
|
+
return "".join(lines[:starts[0]]) + block + "".join(lines[ends[0] + 1:])
|
|
159
|
+
separator = "" if not text else ("\n" if text.endswith("\n") else "\n\n")
|
|
160
|
+
return text + separator + block
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _atomic_write_rc(rc_path: Path, text: str) -> None:
|
|
164
|
+
# Replace the resolved target, not a dotfiles symlink itself.
|
|
165
|
+
target = rc_path.resolve(strict=True)
|
|
166
|
+
mode = stat.S_IMODE(target.stat().st_mode)
|
|
167
|
+
fd, name = tempfile.mkstemp(prefix=f".{target.name}.chatup-", dir=target.parent)
|
|
168
|
+
temporary = Path(name)
|
|
169
|
+
try:
|
|
170
|
+
with os.fdopen(fd, "w", encoding="utf-8", newline="") as rc:
|
|
171
|
+
rc.write(text)
|
|
172
|
+
rc.flush()
|
|
173
|
+
temporary.chmod(mode)
|
|
174
|
+
os.fsync(rc.fileno())
|
|
175
|
+
os.replace(temporary, target)
|
|
176
|
+
finally:
|
|
177
|
+
temporary.unlink(missing_ok=True)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def configure_shell_activation(venv_path: Path, *, home: Path | None = None) -> dict[str, Any]:
|
|
181
|
+
"""Update existing Bash/Zsh rc files without creating missing ones.
|
|
182
|
+
|
|
183
|
+
Reuse ChatUV's managed markers; preserve all text outside the block and
|
|
184
|
+
leave unchanged files untouched. Paths are absolute and shell-quoted.
|
|
185
|
+
"""
|
|
186
|
+
result: dict[str, Any] = {"updated": [], "unchanged": [], "missing": [], "skipped": False}
|
|
187
|
+
if is_windows():
|
|
188
|
+
click.echo("Shell activation update is skipped on Windows.")
|
|
189
|
+
result["skipped"] = True
|
|
190
|
+
return result
|
|
191
|
+
|
|
192
|
+
activate = shlex.quote(str(venv_path.expanduser().absolute() / "bin" / "activate"))
|
|
193
|
+
block = "\n".join((
|
|
194
|
+
SHELL_ACTIVATE_BEGIN,
|
|
195
|
+
"# Managed by ChatUV / ChatUp. Remove this block to stop auto-activation.",
|
|
196
|
+
f"if [ -f {activate} ]; then",
|
|
197
|
+
f" source {activate}",
|
|
198
|
+
"fi",
|
|
199
|
+
SHELL_ACTIVATE_END,
|
|
200
|
+
"",
|
|
201
|
+
))
|
|
202
|
+
home_path = Path(home).expanduser() if home is not None else Path.home()
|
|
203
|
+
for name in SHELL_RC_NAMES:
|
|
204
|
+
rc_path = home_path / name
|
|
205
|
+
if not rc_path.is_file():
|
|
206
|
+
result["missing"].append(str(rc_path))
|
|
207
|
+
continue
|
|
208
|
+
try:
|
|
209
|
+
with rc_path.open("r", encoding="utf-8", newline="") as rc:
|
|
210
|
+
text = rc.read()
|
|
211
|
+
updated = _upsert_activation_block(text, block)
|
|
212
|
+
if updated == text:
|
|
213
|
+
result["unchanged"].append(str(rc_path))
|
|
214
|
+
continue
|
|
215
|
+
_atomic_write_rc(rc_path, updated)
|
|
216
|
+
except (OSError, ValueError) as exc:
|
|
217
|
+
raise click.ClickException(f"Cannot update shell activation block in {rc_path}: {exc}") from exc
|
|
218
|
+
result["updated"].append(str(rc_path))
|
|
219
|
+
click.echo(f"Updated shell activation: {rc_path}")
|
|
220
|
+
if not result["updated"] and not result["unchanged"]:
|
|
221
|
+
click.echo("No existing shell rc file found; skipped auto-activation update.")
|
|
222
|
+
return result
|
|
223
|
+
|
|
224
|
+
|
|
143
225
|
def setup_uv(
|
|
144
226
|
venv: str | None = None,
|
|
145
227
|
python_version: str = DEFAULT_PYTHON_VERSION,
|
|
146
228
|
force: bool = False,
|
|
147
229
|
log_level: str = "INFO",
|
|
148
|
-
|
|
230
|
+
*,
|
|
231
|
+
shell_activate: bool = True,
|
|
232
|
+
) -> dict[str, Any]:
|
|
149
233
|
_configure_logger(log_level)
|
|
150
234
|
target = Path(venv or str(DEFAULT_VENV_PATH)).expanduser()
|
|
151
235
|
python_version = str(python_version).strip() or DEFAULT_PYTHON_VERSION
|
|
@@ -156,12 +240,14 @@ def setup_uv(
|
|
|
156
240
|
|
|
157
241
|
if is_chatarch_python_ready(target, python_version) and not force:
|
|
158
242
|
click.echo("ChatArch Python environment already ready.")
|
|
243
|
+
activation = configure_shell_activation(target) if shell_activate else None
|
|
159
244
|
return {
|
|
160
245
|
"uv": uv_bin,
|
|
161
246
|
"venv": str(target),
|
|
162
247
|
"python": str(_venv_python_path(target)),
|
|
163
248
|
"python_version": python_version,
|
|
164
249
|
"status": "ready",
|
|
250
|
+
"activation": activation,
|
|
165
251
|
}
|
|
166
252
|
|
|
167
253
|
python_bin = _venv_python_path(target)
|
|
@@ -191,6 +277,7 @@ def setup_uv(
|
|
|
191
277
|
f"ChatArch Python env was created at {target}, but Python {python_version} with pip was not verified."
|
|
192
278
|
)
|
|
193
279
|
|
|
280
|
+
activation = configure_shell_activation(target) if shell_activate else None
|
|
194
281
|
python_bin = _venv_python_path(target)
|
|
195
282
|
click.echo(f"ChatArch Python environment ready: {target}")
|
|
196
283
|
click.echo(f"Activate with: {venv_activate_hint(target)}")
|
|
@@ -201,4 +288,5 @@ def setup_uv(
|
|
|
201
288
|
"python": str(python_bin),
|
|
202
289
|
"python_version": python_version,
|
|
203
290
|
"status": "created",
|
|
291
|
+
"activation": activation,
|
|
204
292
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.16
|
|
4
4
|
Summary: ChatArch setup CLI extracted from ChatTool
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -62,6 +62,8 @@ chatup playwright install 1.61.1 -I
|
|
|
62
62
|
chatup workspace default ~/Playground
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
+
`chatup uv` 默认更新已有 `~/.bashrc`、`~/.zshrc` 的自动激活块;使用 `chatup uv --no-activate` 可保持启动配置不变。不会创建缺失的 rc 文件,Windows 跳过此项。
|
|
66
|
+
|
|
65
67
|
常见安装命令:
|
|
66
68
|
|
|
67
69
|
```bash
|
|
@@ -74,16 +76,29 @@ chatup nginx proxy-pass ./gitea-local.conf --set SERVER_NAME=gitea.local.example
|
|
|
74
76
|
chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
|
|
75
77
|
```
|
|
76
78
|
|
|
79
|
+
## ChatGPT / Codex 桌面应用
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
chatup chatgpt --dry-run
|
|
83
|
+
chatup chatgpt
|
|
84
|
+
chatup chatgpt --yes # Windows 首次安装时接受 Store 协议
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
安装包含 Codex 的新版官方 ChatGPT 桌面应用。macOS 需要 Homebrew,Windows 需要 WinGet;Linux preview 暂按[官方说明](https://learn.chatgpt.com/docs/linux/linux-app)手动安装。现有 `chatup codex` 仍安装/配置 Codex CLI。不会自动启动、登录或升级已有应用;[完整约定](https://arch.gh.wzhecnu.cn/ChatUp/commands/#chatgpt-desktop)。
|
|
88
|
+
|
|
89
|
+
`chatup codex`、`chatup hermes` 未配置模型时默认使用 `gpt-5.6-terra`;用户指定的模型和已有配置仍优先。
|
|
90
|
+
|
|
77
91
|
## 当前能力
|
|
78
92
|
|
|
79
93
|
| 能力组 | 命令 |
|
|
80
94
|
| --- | --- |
|
|
81
95
|
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`playwright`、`frp` |
|
|
82
96
|
| 工作区脚手架 | `workspace` |
|
|
97
|
+
| 官方桌面应用 | `chatgpt`(含 Codex) |
|
|
83
98
|
| 本地服务安装 | `gitea`、`discourse`、`zulip`、`mysql`、`nginx`、`crs` |
|
|
84
99
|
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
|
|
85
100
|
|
|
86
|
-
|
|
101
|
+
桌面应用使用系统包管理器的原生目录;ChatArch 自管安装项默认目录收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/playwright`、`~/.chatarch/chattea`、`~/.chatarch/discourse`、`~/.chatarch/zulip`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local`。`cursor-agent` 额外注册 ChatEnv `CursorAgent` profile,`discourse`/`zulip` 注册管理员凭据 profile,并支持 `-e/--env` 从 env 文件或 profile 快速配置;显式选择 profile 时不会混入进程环境中的其他账号凭据。CLI 树由 ChatStyle 的注册表渲染。更完整的能力边界见 `docs/capability-map.md`。
|
|
87
102
|
|
|
88
103
|
## 开发
|
|
89
104
|
|
|
@@ -29,6 +29,7 @@ src/chatup/runtime/chromedriver.py
|
|
|
29
29
|
src/chatup/runtime/playwright.py
|
|
30
30
|
src/chatup/setup/__init__.py
|
|
31
31
|
src/chatup/setup/cc_connect.py
|
|
32
|
+
src/chatup/setup/chatgpt.py
|
|
32
33
|
src/chatup/setup/claude.py
|
|
33
34
|
src/chatup/setup/cli.py
|
|
34
35
|
src/chatup/setup/codex.py
|
|
@@ -71,12 +72,14 @@ src/chatup/utils/custom_logger.py
|
|
|
71
72
|
src/chatup/utils/pathing.py
|
|
72
73
|
src/chatup/utils/platforming.py
|
|
73
74
|
tests/test_browser_backend_cli.py
|
|
75
|
+
tests/test_chatgpt_setup.py
|
|
74
76
|
tests/test_chrome_for_testing.py
|
|
75
77
|
tests/test_chromedriver.py
|
|
76
78
|
tests/test_cli_tree_docs.py
|
|
77
79
|
tests/test_codex_setup.py
|
|
78
80
|
tests/test_crs_setup.py
|
|
79
81
|
tests/test_cursor_agent_setup.py
|
|
82
|
+
tests/test_hermes_model_defaults.py
|
|
80
83
|
tests/test_playwright.py
|
|
81
84
|
tests/test_playwright_cli.py
|
|
82
85
|
tests/test_publish_workflow.py
|
|
@@ -84,6 +87,7 @@ tests/test_pyproject_metadata.py
|
|
|
84
87
|
tests/test_service_installers.py
|
|
85
88
|
tests/test_setup_cli.py
|
|
86
89
|
tests/test_twikoo_setup.py
|
|
90
|
+
tests/test_uv_activation.py
|
|
87
91
|
tests/test_version.py
|
|
88
92
|
tests/test_windows_compat.py
|
|
89
93
|
tests/test_workspace_setup.py
|