chatup 0.2.14__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.14/src/chatup.egg-info → chatup-0.2.16}/PKG-INFO +17 -2
- {chatup-0.2.14 → chatup-0.2.16}/README.md +16 -1
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/__init__.py +1 -1
- chatup-0.2.16/src/chatup/setup/chatgpt.py +132 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/claude.py +4 -2
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/codex.py +5 -4
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/crs.py +5 -3
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/cursor_agent.py +47 -11
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/discourse.py +6 -2
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/docker.py +19 -1
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/elements.py +55 -8
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/frp.py +42 -21
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/gitea.py +5 -3
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/hermes.py +13 -7
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/lark_cli.py +6 -3
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/mysql.py +94 -10
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/nginx.py +14 -12
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/nodejs.py +32 -4
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/opencode.py +2 -1
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/service_credentials.py +6 -2
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/twikoo.py +13 -7
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/uv.py +107 -10
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/zulip.py +6 -2
- chatup-0.2.16/src/chatup/utils/platforming.py +82 -0
- {chatup-0.2.14 → chatup-0.2.16/src/chatup.egg-info}/PKG-INFO +17 -2
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup.egg-info/SOURCES.txt +6 -0
- chatup-0.2.16/tests/test_chatgpt_setup.py +183 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_codex_setup.py +99 -10
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_crs_setup.py +1 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_cursor_agent_setup.py +45 -22
- chatup-0.2.16/tests/test_hermes_model_defaults.py +50 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_playwright.py +4 -4
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_service_installers.py +9 -3
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_setup_cli.py +13 -3
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_twikoo_setup.py +3 -2
- chatup-0.2.16/tests/test_uv_activation.py +259 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_version.py +2 -2
- chatup-0.2.16/tests/test_windows_compat.py +135 -0
- {chatup-0.2.14 → chatup-0.2.16}/LICENSE +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/pyproject.toml +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/setup.cfg +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/chrome_for_testing.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/chromedriver.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/cli.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/commands/__init__.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/commands/chrome_for_testing.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/commands/chromedriver.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/commands/playwright.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/config.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/const.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/interaction/__init__.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/interaction/command_schema.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/interaction/policy.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/interaction/warnings.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/playwright.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/runtime/__init__.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/runtime/_managed_artifact.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/runtime/chrome_for_testing.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/runtime/chromedriver.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/runtime/playwright.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/__init__.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/assets/hermes/install.sh +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/assets/nvm.sh +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/cc_connect.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/cli.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/mode_prompt.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/shell_rc.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/__init__.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/cli.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/core.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/options.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/render.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/en/AGENTS.md +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/en/discussion/README.md +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/en/projects/README.md +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/zh/AGENTS.md +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/zh/discussion/README.md +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace/templates/default/zh/projects/README.md +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/workspace.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/setup/zsh.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/utils/__init__.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/utils/custom_logger.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup/utils/pathing.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup.egg-info/dependency_links.txt +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup.egg-info/entry_points.txt +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup.egg-info/requires.txt +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/src/chatup.egg-info/top_level.txt +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_browser_backend_cli.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_chrome_for_testing.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_chromedriver.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_cli_tree_docs.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_playwright_cli.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_publish_workflow.py +0 -0
- {chatup-0.2.14 → chatup-0.2.16}/tests/test_pyproject_metadata.py +0 -0
- {chatup-0.2.14 → 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}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
+
from chatup.utils.platforming import chmod_private
|
|
5
|
+
|
|
4
6
|
DEFAULT_BASE_URL = "https://api.anthropic.com/v1"
|
|
5
7
|
DEFAULT_SMALL_FAST_MODEL = "claude-opus-4-6"
|
|
6
8
|
|
|
@@ -223,7 +225,7 @@ def setup_claude(
|
|
|
223
225
|
settings_path.write_text(
|
|
224
226
|
json.dumps(settings_json, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
|
225
227
|
)
|
|
226
|
-
settings_path
|
|
228
|
+
chmod_private(settings_path)
|
|
227
229
|
logger.info(f"Wrote settings file: {settings_path}")
|
|
228
230
|
|
|
229
231
|
config_json = {"primaryApiKey": primary_api_key}
|
|
@@ -231,7 +233,7 @@ def setup_claude(
|
|
|
231
233
|
config_path.write_text(
|
|
232
234
|
json.dumps(config_json, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
|
233
235
|
)
|
|
234
|
-
config_path
|
|
236
|
+
chmod_private(config_path)
|
|
235
237
|
logger.info(f"Wrote config file: {config_path}")
|
|
236
238
|
|
|
237
239
|
click.echo("Claude Code setup completed.")
|
|
@@ -28,8 +28,9 @@ from chatup.setup.nodejs import (
|
|
|
28
28
|
should_install_global_npm_package,
|
|
29
29
|
)
|
|
30
30
|
from chatup.utils.custom_logger import setup_logger
|
|
31
|
+
from chatup.utils.platforming import chmod_private
|
|
31
32
|
|
|
32
|
-
DEFAULT_MODEL = "gpt-5.
|
|
33
|
+
DEFAULT_MODEL = "gpt-5.6-terra"
|
|
33
34
|
DEFAULT_BASE_URL = "https://api.openai.com/v1"
|
|
34
35
|
DEFAULT_AUTH_METHOD = "apikey"
|
|
35
36
|
_ENV_VAR_REF_RE = re.compile(r"\$(?:\{[^}]+\}|[A-Za-z_][A-Za-z0-9_]*)")
|
|
@@ -207,7 +208,7 @@ def _write_codex_config(config_path: Path, *, model: str, base_url: str) -> list
|
|
|
207
208
|
)
|
|
208
209
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
209
210
|
config_path.write_text(content, encoding="utf-8")
|
|
210
|
-
config_path
|
|
211
|
+
chmod_private(config_path)
|
|
211
212
|
logger.info(f"Patched config file: {config_path}")
|
|
212
213
|
return changed_root + changed_provider
|
|
213
214
|
|
|
@@ -216,13 +217,13 @@ def _write_private_text(path: Path, content: str) -> None:
|
|
|
216
217
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
217
218
|
fd, tmp_name = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent)
|
|
218
219
|
try:
|
|
219
|
-
|
|
220
|
+
chmod_private(Path(tmp_name))
|
|
220
221
|
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
|
221
222
|
handle.write(content)
|
|
222
223
|
handle.flush()
|
|
223
224
|
os.fsync(handle.fileno())
|
|
224
225
|
os.replace(tmp_name, path)
|
|
225
|
-
path
|
|
226
|
+
chmod_private(path)
|
|
226
227
|
except Exception:
|
|
227
228
|
try:
|
|
228
229
|
os.close(fd)
|
|
@@ -12,6 +12,7 @@ import click
|
|
|
12
12
|
from chatup.interaction import abort_if_force_without_tty, resolve_interactive_mode
|
|
13
13
|
from chatup.setup.nodejs import ensure_nodejs_requirement
|
|
14
14
|
from chatup.utils.custom_logger import setup_logger
|
|
15
|
+
from chatup.utils.platforming import chmod_private, require_non_windows
|
|
15
16
|
|
|
16
17
|
logger = setup_logger("setup_crs")
|
|
17
18
|
|
|
@@ -146,7 +147,7 @@ def write_secret_file(path: Path) -> dict[str, str]:
|
|
|
146
147
|
old_umask = os.umask(0o077)
|
|
147
148
|
try:
|
|
148
149
|
path.write_text("".join(f"{key}={value}\n" for key, value in values.items()), encoding="utf-8")
|
|
149
|
-
path
|
|
150
|
+
chmod_private(path)
|
|
150
151
|
finally:
|
|
151
152
|
os.umask(old_umask)
|
|
152
153
|
return values
|
|
@@ -178,7 +179,7 @@ def write_env_file(crs_root: Path, *, port: int, redis_port: int, secrets_values
|
|
|
178
179
|
),
|
|
179
180
|
encoding="utf-8",
|
|
180
181
|
)
|
|
181
|
-
env_path
|
|
182
|
+
chmod_private(env_path)
|
|
182
183
|
return env_path
|
|
183
184
|
|
|
184
185
|
|
|
@@ -234,6 +235,7 @@ def setup_crs(
|
|
|
234
235
|
|
|
235
236
|
if smoke and not start:
|
|
236
237
|
raise click.ClickException("--smoke requires --start; pass --no-smoke when using --no-start.")
|
|
238
|
+
require_non_windows("chatup crs")
|
|
237
239
|
|
|
238
240
|
node_runtime = ensure_nodejs_requirement(
|
|
239
241
|
interactive=interactive,
|
|
@@ -302,7 +304,7 @@ def setup_crs(
|
|
|
302
304
|
stdout=log_file,
|
|
303
305
|
stderr=subprocess.STDOUT,
|
|
304
306
|
)
|
|
305
|
-
setup_log
|
|
307
|
+
chmod_private(setup_log)
|
|
306
308
|
|
|
307
309
|
run_command(npm_command(node_runtime, "run", "install:web"), cwd=crs_root, env=npm_env)
|
|
308
310
|
run_command(npm_command(node_runtime, "run", "build:web"), cwd=crs_root, env=npm_env)
|
|
@@ -5,7 +5,6 @@ import os
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import shutil
|
|
7
7
|
import shlex
|
|
8
|
-
import stat
|
|
9
8
|
import subprocess
|
|
10
9
|
from typing import Any
|
|
11
10
|
|
|
@@ -15,6 +14,7 @@ from chatenv.store import EnvStore
|
|
|
15
14
|
|
|
16
15
|
from chatup.config import CursorAgentConfig
|
|
17
16
|
from chatup.utils.custom_logger import setup_logger
|
|
17
|
+
from chatup.utils.platforming import chmod_executable, chmod_private, is_windows, user_bin_candidates
|
|
18
18
|
|
|
19
19
|
DEFAULT_INSTALL_URL = "https://cursor.com/install"
|
|
20
20
|
CREDENTIAL_STORE_CHOICES = ("native", "file-wrapper")
|
|
@@ -44,10 +44,7 @@ def _cursor_agent_state_path() -> Path:
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def _chmod_private(path: Path) -> None:
|
|
47
|
-
|
|
48
|
-
path.chmod(0o600)
|
|
49
|
-
except PermissionError:
|
|
50
|
-
logger.warning(f"Could not chmod private file: {path}")
|
|
47
|
+
chmod_private(path)
|
|
51
48
|
|
|
52
49
|
|
|
53
50
|
def _read_json_file(path: Path) -> dict[str, Any]:
|
|
@@ -168,9 +165,16 @@ def _resolve_command_or_user_bin(name: str) -> Path | None:
|
|
|
168
165
|
found = shutil.which(name)
|
|
169
166
|
if found:
|
|
170
167
|
candidates.append(Path(found).expanduser())
|
|
171
|
-
candidates.
|
|
168
|
+
candidates.extend(user_bin_candidates(name))
|
|
169
|
+
if is_windows():
|
|
170
|
+
candidates.extend(
|
|
171
|
+
[
|
|
172
|
+
Path.home() / ".local" / "bin" / f"{name}.cmd",
|
|
173
|
+
Path.home() / ".local" / "bin" / f"{name}.bat",
|
|
174
|
+
]
|
|
175
|
+
)
|
|
172
176
|
for candidate in candidates:
|
|
173
|
-
if candidate.exists() and os.access(candidate, os.X_OK):
|
|
177
|
+
if candidate.exists() and (is_windows() or os.access(candidate, os.X_OK)):
|
|
174
178
|
return candidate
|
|
175
179
|
return None
|
|
176
180
|
|
|
@@ -190,14 +194,19 @@ def _managed_wrapper_official_target(entrypoint: Path) -> Path | None:
|
|
|
190
194
|
if WRAPPER_MARKER not in text:
|
|
191
195
|
return None
|
|
192
196
|
for line in text.splitlines():
|
|
193
|
-
|
|
194
|
-
|
|
197
|
+
stripped = line.strip()
|
|
198
|
+
if stripped.startswith("CHATUP_CURSOR_AGENT_OFFICIAL="):
|
|
199
|
+
value = stripped.split("=", 1)[1]
|
|
195
200
|
try:
|
|
196
201
|
parts = shlex.split(value)
|
|
197
202
|
except ValueError:
|
|
198
203
|
return None
|
|
199
204
|
if parts:
|
|
200
205
|
return Path(parts[0])
|
|
206
|
+
if stripped.lower().startswith('set "chatup_cursor_agent_official=') and stripped.endswith('"'):
|
|
207
|
+
value = stripped.split("=", 1)[1][:-1]
|
|
208
|
+
if value:
|
|
209
|
+
return Path(value)
|
|
201
210
|
return None
|
|
202
211
|
|
|
203
212
|
|
|
@@ -231,7 +240,24 @@ def _write_file_credential_wrapper(entrypoint: Path, official_binary: Path, auth
|
|
|
231
240
|
if existing_target and existing_target == entrypoint:
|
|
232
241
|
raise click.ClickException(f"Refusing to wrap Cursor Agent entrypoint that resolves to itself: {entrypoint}")
|
|
233
242
|
official = official_binary.expanduser()
|
|
234
|
-
|
|
243
|
+
if is_windows():
|
|
244
|
+
script = f'''@echo off
|
|
245
|
+
rem {WRAPPER_MARKER}.
|
|
246
|
+
rem This wrapper does not store token values; it reads Cursor auth.json at runtime.
|
|
247
|
+
set "CHATUP_CURSOR_AGENT_OFFICIAL={official}"
|
|
248
|
+
if "%CURSOR_AGENT_AUTH_JSON%"=="" (
|
|
249
|
+
set "CHATUP_CURSOR_AGENT_AUTH_JSON={auth_path}"
|
|
250
|
+
) else (
|
|
251
|
+
set "CHATUP_CURSOR_AGENT_AUTH_JSON=%CURSOR_AGENT_AUTH_JSON%"
|
|
252
|
+
)
|
|
253
|
+
if "%AGENT_CLI_CREDENTIAL_STORE%"=="" set "AGENT_CLI_CREDENTIAL_STORE=file"
|
|
254
|
+
if "%CURSOR_AUTH_TOKEN%"=="" if exist "%CHATUP_CURSOR_AGENT_AUTH_JSON%" (
|
|
255
|
+
for /f "usebackq delims=" %%T in (`python -c "import json,sys; print(json.load(open(sys.argv[1], encoding='utf-8')).get('accessToken',''), end='')" "%CHATUP_CURSOR_AGENT_AUTH_JSON%"`) do set "CURSOR_AUTH_TOKEN=%%T"
|
|
256
|
+
)
|
|
257
|
+
"%CHATUP_CURSOR_AGENT_OFFICIAL%" %*
|
|
258
|
+
'''
|
|
259
|
+
else:
|
|
260
|
+
script = f'''#!/usr/bin/env bash
|
|
235
261
|
set -euo pipefail
|
|
236
262
|
# {WRAPPER_MARKER}.
|
|
237
263
|
# This wrapper does not store token values; it reads Cursor auth.json at runtime.
|
|
@@ -256,13 +282,19 @@ fi
|
|
|
256
282
|
exec -a "$0" "$CHATUP_CURSOR_AGENT_OFFICIAL" "$@"
|
|
257
283
|
'''
|
|
258
284
|
entrypoint.write_text(script, encoding="utf-8")
|
|
259
|
-
entrypoint
|
|
285
|
+
chmod_executable(entrypoint)
|
|
260
286
|
return True
|
|
261
287
|
|
|
262
288
|
|
|
263
289
|
def _write_file_credential_wrappers(binary: str) -> list[str]:
|
|
264
290
|
official = _resolve_official_cursor_agent_binary(binary)
|
|
265
291
|
written: list[str] = []
|
|
292
|
+
if is_windows():
|
|
293
|
+
for name in ("cursor-agent", "agent"):
|
|
294
|
+
entrypoint = official.parent / f"{name}.cmd"
|
|
295
|
+
if _write_file_credential_wrapper(entrypoint, official, _cursor_auth_path()):
|
|
296
|
+
written.append(str(entrypoint))
|
|
297
|
+
return written
|
|
266
298
|
for name in ("cursor-agent", "agent"):
|
|
267
299
|
entrypoint = _entrypoint_for(name)
|
|
268
300
|
if not entrypoint:
|
|
@@ -278,6 +310,10 @@ def _write_file_credential_wrappers(binary: str) -> list[str]:
|
|
|
278
310
|
def _install_cursor_agent_if_needed(*, install_url: str = DEFAULT_INSTALL_URL) -> bool:
|
|
279
311
|
if _resolve_cursor_agent_binary():
|
|
280
312
|
return False
|
|
313
|
+
if is_windows():
|
|
314
|
+
raise click.ClickException(
|
|
315
|
+
"Cursor Agent was not found on PATH. Install Cursor Agent for Windows first, then rerun ChatUp."
|
|
316
|
+
)
|
|
281
317
|
script = subprocess.run(
|
|
282
318
|
["bash", "-lc", f"curl -fsSL {install_url!r} | bash"],
|
|
283
319
|
text=True,
|
|
@@ -105,7 +105,9 @@ def ensure_directories(home: Path) -> dict[str, Path]:
|
|
|
105
105
|
}
|
|
106
106
|
for path in paths.values():
|
|
107
107
|
path.mkdir(parents=True, exist_ok=True)
|
|
108
|
-
|
|
108
|
+
from chatup.utils.platforming import chmod_private_dir
|
|
109
|
+
|
|
110
|
+
chmod_private_dir(paths["secrets"])
|
|
109
111
|
return paths
|
|
110
112
|
|
|
111
113
|
|
|
@@ -162,7 +164,9 @@ def setup_discourse(
|
|
|
162
164
|
render_app_yml(hostname=hostname, port=port, shared_dir=paths["shared"], with_ai=with_ai),
|
|
163
165
|
encoding="utf-8",
|
|
164
166
|
)
|
|
165
|
-
|
|
167
|
+
from chatup.utils.platforming import chmod_private
|
|
168
|
+
|
|
169
|
+
chmod_private(app_yml)
|
|
166
170
|
|
|
167
171
|
if clone:
|
|
168
172
|
clone_or_update_discourse_docker(paths["docker"], repo)
|
|
@@ -14,6 +14,7 @@ from chatup.interaction import (
|
|
|
14
14
|
resolve_interactive_mode,
|
|
15
15
|
)
|
|
16
16
|
from chatup.utils.custom_logger import setup_logger
|
|
17
|
+
from chatup.utils.platforming import is_windows
|
|
17
18
|
|
|
18
19
|
logger = setup_logger("setup_docker")
|
|
19
20
|
DOCKER_COMPOSE_VERSION = "v2.22.0"
|
|
@@ -26,7 +27,10 @@ def _configure_logger(log_level="INFO"):
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
def _run(command: list[str]) -> subprocess.CompletedProcess:
|
|
29
|
-
|
|
30
|
+
try:
|
|
31
|
+
return subprocess.run(command, capture_output=True, text=True)
|
|
32
|
+
except FileNotFoundError as exc:
|
|
33
|
+
return subprocess.CompletedProcess(command, 127, "", str(exc))
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
def _ensure_success(result: subprocess.CompletedProcess, step_name: str) -> None:
|
|
@@ -103,6 +107,20 @@ def setup_docker(interactive=None, use_sudo=False, log_level="INFO"):
|
|
|
103
107
|
)
|
|
104
108
|
abort_if_force_without_tty(force_interactive, can_prompt, usage)
|
|
105
109
|
|
|
110
|
+
if is_windows():
|
|
111
|
+
docker_version = _docker_version()
|
|
112
|
+
if docker_version:
|
|
113
|
+
click.echo(f"Docker already installed: {docker_version}")
|
|
114
|
+
else:
|
|
115
|
+
click.echo("Docker CLI not found. Install Docker Desktop for Windows and ensure `docker` is on PATH.")
|
|
116
|
+
compose_version = _docker_compose_version()
|
|
117
|
+
if compose_version:
|
|
118
|
+
click.echo(f"Docker Compose already installed: {compose_version}")
|
|
119
|
+
else:
|
|
120
|
+
click.echo("Docker Compose not found. Docker Desktop usually provides `docker compose`.")
|
|
121
|
+
click.echo("Docker group/systemd checks are skipped on Windows.")
|
|
122
|
+
return {"docker": docker_version, "compose": compose_version, "platform": "windows"}
|
|
123
|
+
|
|
106
124
|
logger.info("Start docker setup")
|
|
107
125
|
user_name = _get_user_name()
|
|
108
126
|
|
|
@@ -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,
|
|
@@ -62,7 +63,7 @@ from chatup.setup.twikoo import (
|
|
|
62
63
|
DEFAULT_TWIKOO_VERSION,
|
|
63
64
|
setup_twikoo,
|
|
64
65
|
)
|
|
65
|
-
from chatup.setup.uv import DEFAULT_PYTHON_VERSION,
|
|
66
|
+
from chatup.setup.uv import DEFAULT_PYTHON_VERSION, setup_uv
|
|
66
67
|
from chatup.setup.workspace import setup_workspace
|
|
67
68
|
from chatup.setup.zsh import setup_zsh
|
|
68
69
|
from chatup.setup.zulip import (
|
|
@@ -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,
|
|
@@ -1231,7 +1252,7 @@ SETUP_COMMAND_ELEMENTS = (
|
|
|
1231
1252
|
SetupOptionElement(
|
|
1232
1253
|
param_decls=("--venv", "--venv-path"),
|
|
1233
1254
|
kwargs={
|
|
1234
|
-
"default":
|
|
1255
|
+
"default": "~/.chatarch/venv",
|
|
1235
1256
|
"show_default": True,
|
|
1236
1257
|
"help": "Target ChatArch Python virtual environment path.",
|
|
1237
1258
|
},
|
|
@@ -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",),
|