chatup 0.2.0__tar.gz → 0.2.1__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.0/src/chatup.egg-info → chatup-0.2.1}/PKG-INFO +5 -2
- {chatup-0.2.0 → chatup-0.2.1}/README.md +3 -0
- {chatup-0.2.0 → chatup-0.2.1}/pyproject.toml +1 -1
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/__init__.py +1 -1
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/elements.py +36 -0
- chatup-0.2.1/src/chatup/setup/uv.py +195 -0
- {chatup-0.2.0 → chatup-0.2.1/src/chatup.egg-info}/PKG-INFO +5 -2
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup.egg-info/SOURCES.txt +1 -0
- {chatup-0.2.0 → chatup-0.2.1}/tests/test_pyproject_metadata.py +1 -0
- chatup-0.2.1/tests/test_setup_cli.py +218 -0
- {chatup-0.2.0 → chatup-0.2.1}/tests/test_version.py +2 -2
- chatup-0.2.0/tests/test_setup_cli.py +0 -104
- {chatup-0.2.0 → chatup-0.2.1}/LICENSE +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/setup.cfg +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/cli.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/const.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/interaction/__init__.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/interaction/command_schema.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/interaction/policy.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/interaction/warnings.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/__init__.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/assets/hermes/install.sh +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/assets/nvm.sh +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/cc_connect.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/chrome.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/claude.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/cli.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/codex.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/docker.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/frp.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/hermes.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/lark_cli.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/mode_prompt.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/nodejs.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/opencode.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/shell_rc.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/__init__.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/cli.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/core.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/options.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/render.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/templates/default/en/AGENTS.md +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/templates/default/en/projects/README.md +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/templates/default/zh/AGENTS.md +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/templates/default/zh/projects/README.md +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/zsh.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/utils/__init__.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/utils/custom_logger.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup/utils/pathing.py +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup.egg-info/dependency_links.txt +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup.egg-info/entry_points.txt +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup.egg-info/requires.txt +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/src/chatup.egg-info/top_level.txt +0 -0
- {chatup-0.2.0 → chatup-0.2.1}/tests/test_workspace_setup.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: ChatArch setup CLI extracted from ChatTool
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Keywords: chatup,chatarch,setup,cli
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
13
|
Requires-Dist: click>=8.0
|
|
@@ -25,8 +25,11 @@ ChatUp is the standalone ChatArch setup CLI. It is the first-level replacement f
|
|
|
25
25
|
```bash
|
|
26
26
|
chatup --help
|
|
27
27
|
chatup doctor
|
|
28
|
+
chatup uv
|
|
28
29
|
```
|
|
29
30
|
|
|
31
|
+
`chatup uv` installs `uv` through the official installer when needed, then creates the ChatArch Python environment with pip. Defaults are `--venv ~/.chatarch/venv` and `--python 3.12`; override them when a different runtime path or Python minor version is required.
|
|
32
|
+
|
|
30
33
|
## Development
|
|
31
34
|
|
|
32
35
|
```bash
|
|
@@ -7,8 +7,11 @@ ChatUp is the standalone ChatArch setup CLI. It is the first-level replacement f
|
|
|
7
7
|
```bash
|
|
8
8
|
chatup --help
|
|
9
9
|
chatup doctor
|
|
10
|
+
chatup uv
|
|
10
11
|
```
|
|
11
12
|
|
|
13
|
+
`chatup uv` installs `uv` through the official installer when needed, then creates the ChatArch Python environment with pip. Defaults are `--venv ~/.chatarch/venv` and `--python 3.12`; override them when a different runtime path or Python minor version is required.
|
|
14
|
+
|
|
12
15
|
## Development
|
|
13
16
|
|
|
14
17
|
```bash
|
|
@@ -14,6 +14,7 @@ from chatup.setup.lark_cli import setup_lark_cli
|
|
|
14
14
|
from chatup.setup.opencode import setup_opencode
|
|
15
15
|
from chatup.setup.zsh import setup_zsh
|
|
16
16
|
from chatup.setup.nodejs import setup_nodejs
|
|
17
|
+
from chatup.setup.uv import DEFAULT_PYTHON_VERSION, DEFAULT_VENV_PATH, setup_uv
|
|
17
18
|
from chatup.setup.workspace import setup_workspace
|
|
18
19
|
|
|
19
20
|
|
|
@@ -47,6 +48,10 @@ def nodejs_setup(interactive, log_level):
|
|
|
47
48
|
setup_nodejs(interactive=interactive, log_level=log_level)
|
|
48
49
|
|
|
49
50
|
|
|
51
|
+
def uv_setup(venv, python_version, force, log_level):
|
|
52
|
+
setup_uv(venv=venv, python_version=python_version, force=force, log_level=log_level)
|
|
53
|
+
|
|
54
|
+
|
|
50
55
|
def docker_setup(sudo, interactive, log_level):
|
|
51
56
|
setup_docker(interactive=interactive, use_sudo=sudo, log_level=log_level)
|
|
52
57
|
|
|
@@ -379,6 +384,37 @@ SETUP_COMMAND_ELEMENTS = (
|
|
|
379
384
|
),
|
|
380
385
|
),
|
|
381
386
|
),
|
|
387
|
+
SetupCommandElement(
|
|
388
|
+
name="uv",
|
|
389
|
+
help="Install uv and create the ChatArch Python 3.12 environment with pip.",
|
|
390
|
+
callback=uv_setup,
|
|
391
|
+
options=(
|
|
392
|
+
LOG_LEVEL_OPTION,
|
|
393
|
+
SetupOptionElement(
|
|
394
|
+
param_decls=("--venv", "--venv-path"),
|
|
395
|
+
kwargs={
|
|
396
|
+
"default": str(DEFAULT_VENV_PATH),
|
|
397
|
+
"show_default": True,
|
|
398
|
+
"help": "Target ChatArch Python virtual environment path.",
|
|
399
|
+
},
|
|
400
|
+
),
|
|
401
|
+
SetupOptionElement(
|
|
402
|
+
param_decls=("--python", "--python-version", "python_version"),
|
|
403
|
+
kwargs={
|
|
404
|
+
"default": DEFAULT_PYTHON_VERSION,
|
|
405
|
+
"show_default": True,
|
|
406
|
+
"help": "Python version to install through uv and use for the venv.",
|
|
407
|
+
},
|
|
408
|
+
),
|
|
409
|
+
SetupOptionElement(
|
|
410
|
+
param_decls=("--force", "-f"),
|
|
411
|
+
kwargs={
|
|
412
|
+
"is_flag": True,
|
|
413
|
+
"help": "Clear and recreate the target environment if it already exists.",
|
|
414
|
+
},
|
|
415
|
+
),
|
|
416
|
+
),
|
|
417
|
+
),
|
|
382
418
|
SetupCommandElement(
|
|
383
419
|
name="codex",
|
|
384
420
|
help="Configure Codex CLI and config files.",
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shlex
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import click
|
|
10
|
+
|
|
11
|
+
from chatup.utils.custom_logger import setup_logger
|
|
12
|
+
|
|
13
|
+
DEFAULT_PYTHON_VERSION = "3.12"
|
|
14
|
+
DEFAULT_VENV_PATH = Path("~/.chatarch/venv")
|
|
15
|
+
UV_INSTALLER_URL = "https://astral.sh/uv/install.sh"
|
|
16
|
+
|
|
17
|
+
logger = setup_logger("setup_uv")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _configure_logger(log_level: str = "INFO"):
|
|
21
|
+
global logger
|
|
22
|
+
logger = setup_logger("setup_uv", log_level=str(log_level).upper())
|
|
23
|
+
return logger
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _display_command(command: list[str] | tuple[str, ...]) -> str:
|
|
27
|
+
return " ".join(shlex.quote(str(part)) for part in command)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _run_command(command: list[str], **kwargs) -> subprocess.CompletedProcess[str]:
|
|
31
|
+
click.echo(f"Running: {_display_command(command)}")
|
|
32
|
+
return subprocess.run(command, capture_output=True, text=True, **kwargs)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _candidate_uv_paths() -> tuple[Path, ...]:
|
|
36
|
+
return (
|
|
37
|
+
Path.home() / ".local" / "bin" / "uv",
|
|
38
|
+
Path.home() / ".cargo" / "bin" / "uv",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def find_uv() -> str | None:
|
|
43
|
+
uv = shutil.which("uv")
|
|
44
|
+
if uv:
|
|
45
|
+
return uv
|
|
46
|
+
for candidate in _candidate_uv_paths():
|
|
47
|
+
if candidate.is_file() and os.access(candidate, os.X_OK):
|
|
48
|
+
return str(candidate)
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def install_uv_with_official_script() -> str:
|
|
53
|
+
command = ["sh", "-c", f"curl -LsSf {shlex.quote(UV_INSTALLER_URL)} | sh"]
|
|
54
|
+
result = _run_command(command)
|
|
55
|
+
if result.returncode != 0:
|
|
56
|
+
message = (result.stderr or result.stdout or "uv installer failed").strip()
|
|
57
|
+
raise click.ClickException(f"Failed to install uv: {message}")
|
|
58
|
+
|
|
59
|
+
uv = find_uv()
|
|
60
|
+
if not uv:
|
|
61
|
+
raise click.ClickException(
|
|
62
|
+
"uv installer finished, but `uv` was not found on PATH or in ~/.local/bin. "
|
|
63
|
+
"Open a new shell or add the installer bin directory to PATH."
|
|
64
|
+
)
|
|
65
|
+
return uv
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def ensure_uv_installed() -> str:
|
|
69
|
+
uv = find_uv()
|
|
70
|
+
if uv:
|
|
71
|
+
click.echo(f"uv found: {uv}")
|
|
72
|
+
return uv
|
|
73
|
+
|
|
74
|
+
click.echo("uv not found; installing via the official uv installer script.")
|
|
75
|
+
uv = install_uv_with_official_script()
|
|
76
|
+
click.echo(f"uv installed: {uv}")
|
|
77
|
+
return uv
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _venv_python_path(venv_path: Path) -> Path:
|
|
81
|
+
if os.name == "nt":
|
|
82
|
+
return venv_path / "Scripts" / "python.exe"
|
|
83
|
+
return venv_path / "bin" / "python"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _python_minor_version(python_bin: Path) -> str | None:
|
|
87
|
+
if not python_bin.exists():
|
|
88
|
+
return None
|
|
89
|
+
result = subprocess.run(
|
|
90
|
+
[str(python_bin), "-c", "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"],
|
|
91
|
+
capture_output=True,
|
|
92
|
+
text=True,
|
|
93
|
+
)
|
|
94
|
+
if result.returncode != 0:
|
|
95
|
+
return None
|
|
96
|
+
return result.stdout.strip()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _venv_has_pip(python_bin: Path) -> bool:
|
|
100
|
+
if not python_bin.exists():
|
|
101
|
+
return False
|
|
102
|
+
result = subprocess.run(
|
|
103
|
+
[str(python_bin), "-m", "pip", "--version"], capture_output=True, text=True
|
|
104
|
+
)
|
|
105
|
+
return result.returncode == 0
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def is_chatarch_python_ready(venv_path: Path, python_version: str) -> bool:
|
|
109
|
+
python_bin = _venv_python_path(venv_path)
|
|
110
|
+
current_version = _python_minor_version(python_bin)
|
|
111
|
+
return current_version == python_version and _venv_has_pip(python_bin)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def create_chatarch_python_env(
|
|
115
|
+
uv_bin: str, venv_path: Path, python_version: str, *, force: bool = False
|
|
116
|
+
) -> None:
|
|
117
|
+
install_result = _run_command([uv_bin, "python", "install", python_version])
|
|
118
|
+
if install_result.returncode != 0:
|
|
119
|
+
message = (install_result.stderr or install_result.stdout).strip()
|
|
120
|
+
raise click.ClickException(f"Failed to install Python {python_version} via uv: {message}")
|
|
121
|
+
|
|
122
|
+
command = [uv_bin, "venv", "--python", python_version, "--seed"]
|
|
123
|
+
if force:
|
|
124
|
+
command.extend(("--clear", "--force"))
|
|
125
|
+
elif venv_path.exists():
|
|
126
|
+
command.append("--allow-existing")
|
|
127
|
+
command.append(str(venv_path))
|
|
128
|
+
venv_result = _run_command(command)
|
|
129
|
+
if venv_result.returncode != 0:
|
|
130
|
+
message = (venv_result.stderr or venv_result.stdout).strip()
|
|
131
|
+
raise click.ClickException(f"Failed to create ChatArch Python env at {venv_path}: {message}")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def setup_uv(
|
|
135
|
+
venv: str | None = None,
|
|
136
|
+
python_version: str = DEFAULT_PYTHON_VERSION,
|
|
137
|
+
force: bool = False,
|
|
138
|
+
log_level: str = "INFO",
|
|
139
|
+
) -> dict[str, str]:
|
|
140
|
+
_configure_logger(log_level)
|
|
141
|
+
target = Path(venv or str(DEFAULT_VENV_PATH)).expanduser()
|
|
142
|
+
python_version = str(python_version).strip() or DEFAULT_PYTHON_VERSION
|
|
143
|
+
|
|
144
|
+
uv_bin = ensure_uv_installed()
|
|
145
|
+
click.echo(f"ChatArch Python env: {target}")
|
|
146
|
+
click.echo(f"Requested Python: {python_version}")
|
|
147
|
+
|
|
148
|
+
if is_chatarch_python_ready(target, python_version) and not force:
|
|
149
|
+
click.echo("ChatArch Python environment already ready.")
|
|
150
|
+
return {
|
|
151
|
+
"uv": uv_bin,
|
|
152
|
+
"venv": str(target),
|
|
153
|
+
"python": str(_venv_python_path(target)),
|
|
154
|
+
"python_version": python_version,
|
|
155
|
+
"status": "ready",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
python_bin = _venv_python_path(target)
|
|
159
|
+
current_version = _python_minor_version(python_bin)
|
|
160
|
+
if target.exists() and not force:
|
|
161
|
+
if current_version is None:
|
|
162
|
+
raise click.ClickException(
|
|
163
|
+
f"Target path exists but is not a Python virtual environment: {target}. "
|
|
164
|
+
"Pass --force to clear it or choose another --venv path."
|
|
165
|
+
)
|
|
166
|
+
if current_version != python_version:
|
|
167
|
+
raise click.ClickException(
|
|
168
|
+
f"Existing ChatArch Python env at {target} uses Python {current_version}, "
|
|
169
|
+
f"but Python {python_version} was requested. Pass --force to recreate it "
|
|
170
|
+
"or choose another --venv path."
|
|
171
|
+
)
|
|
172
|
+
click.echo("ChatArch Python environment exists but pip is missing; seeding pip with uv.")
|
|
173
|
+
elif target.exists() and force:
|
|
174
|
+
click.echo("Recreating existing ChatArch Python environment with uv.")
|
|
175
|
+
else:
|
|
176
|
+
click.echo("ChatArch Python environment not found; creating it with uv.")
|
|
177
|
+
|
|
178
|
+
create_chatarch_python_env(uv_bin, target, python_version, force=force)
|
|
179
|
+
|
|
180
|
+
if not is_chatarch_python_ready(target, python_version):
|
|
181
|
+
raise click.ClickException(
|
|
182
|
+
f"ChatArch Python env was created at {target}, but Python {python_version} with pip was not verified."
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
python_bin = _venv_python_path(target)
|
|
186
|
+
click.echo(f"ChatArch Python environment ready: {target}")
|
|
187
|
+
click.echo(f"Activate with: source {shlex.quote(str(target / 'bin' / 'activate'))}")
|
|
188
|
+
click.echo(f"Verified pip: {python_bin} -m pip --version")
|
|
189
|
+
return {
|
|
190
|
+
"uv": uv_bin,
|
|
191
|
+
"venv": str(target),
|
|
192
|
+
"python": str(python_bin),
|
|
193
|
+
"python_version": python_version,
|
|
194
|
+
"status": "created",
|
|
195
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: ChatArch setup CLI extracted from ChatTool
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Keywords: chatup,chatarch,setup,cli
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
13
|
Requires-Dist: click>=8.0
|
|
@@ -25,8 +25,11 @@ ChatUp is the standalone ChatArch setup CLI. It is the first-level replacement f
|
|
|
25
25
|
```bash
|
|
26
26
|
chatup --help
|
|
27
27
|
chatup doctor
|
|
28
|
+
chatup uv
|
|
28
29
|
```
|
|
29
30
|
|
|
31
|
+
`chatup uv` installs `uv` through the official installer when needed, then creates the ChatArch Python environment with pip. Defaults are `--venv ~/.chatarch/venv` and `--python 3.12`; override them when a different runtime path or Python minor version is required.
|
|
32
|
+
|
|
30
33
|
## Development
|
|
31
34
|
|
|
32
35
|
```bash
|
|
@@ -18,6 +18,7 @@ def _pyproject() -> dict:
|
|
|
18
18
|
def test_chatup_depends_on_chatenv_without_registering_config_provider():
|
|
19
19
|
data = _pyproject()
|
|
20
20
|
|
|
21
|
+
assert data["project"]["requires-python"] == ">=3.10"
|
|
21
22
|
assert "chatstyle>=0.1.0,<0.2.0" in data["project"]["dependencies"]
|
|
22
23
|
assert "chatenv>=0.2.0,<0.3.0" in data["project"]["dependencies"]
|
|
23
24
|
assert "entry-points" not in data["project"] or "chatenv.configs" not in data["project"]["entry-points"]
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
from click.testing import CliRunner
|
|
2
|
+
|
|
3
|
+
from chatup.cli import main
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_chatup_root_help_lists_setup_commands_without_setup_group_or_alias():
|
|
7
|
+
result = CliRunner().invoke(main, ["--help"])
|
|
8
|
+
|
|
9
|
+
assert result.exit_code == 0
|
|
10
|
+
for command in [
|
|
11
|
+
"workspace",
|
|
12
|
+
"nodejs",
|
|
13
|
+
"uv",
|
|
14
|
+
"codex",
|
|
15
|
+
"claude",
|
|
16
|
+
"opencode",
|
|
17
|
+
"hermes",
|
|
18
|
+
"lark-cli",
|
|
19
|
+
"docker",
|
|
20
|
+
"zsh",
|
|
21
|
+
]:
|
|
22
|
+
assert command in result.output
|
|
23
|
+
assert "setup" not in result.output
|
|
24
|
+
assert "\n alias " not in result.output
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_chatup_workspace_help_keeps_interactive_flags():
|
|
28
|
+
result = CliRunner().invoke(main, ["workspace", "--help"])
|
|
29
|
+
|
|
30
|
+
assert result.exit_code == 0
|
|
31
|
+
assert "--with-chattool" in result.output
|
|
32
|
+
assert "--with-chatblog" in result.output
|
|
33
|
+
assert "--with-memory" in result.output
|
|
34
|
+
assert "-i, --interactive" in result.output
|
|
35
|
+
assert "-I, --no-interactive" in result.output
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_top_level_setup_commands_expose_help():
|
|
39
|
+
commands = [
|
|
40
|
+
"cc-connect",
|
|
41
|
+
"chrome",
|
|
42
|
+
"claude",
|
|
43
|
+
"codex",
|
|
44
|
+
"docker",
|
|
45
|
+
"frp",
|
|
46
|
+
"hermes",
|
|
47
|
+
"lark-cli",
|
|
48
|
+
"nodejs",
|
|
49
|
+
"opencode",
|
|
50
|
+
"uv",
|
|
51
|
+
"workspace",
|
|
52
|
+
"zsh",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
for command in commands:
|
|
56
|
+
result = CliRunner().invoke(main, [command, "--help"])
|
|
57
|
+
assert result.exit_code == 0, command
|
|
58
|
+
assert "--help" in result.output
|
|
59
|
+
assert "Usage: chatup setup" not in result.output
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_setup_group_and_alias_command_are_not_registered():
|
|
63
|
+
setup_result = CliRunner().invoke(main, ["setup", "--help"])
|
|
64
|
+
alias_result = CliRunner().invoke(main, ["alias", "--help"])
|
|
65
|
+
|
|
66
|
+
assert setup_result.exit_code != 0
|
|
67
|
+
assert "No such command" in setup_result.output
|
|
68
|
+
assert alias_result.exit_code != 0
|
|
69
|
+
assert "No such command" in alias_result.output
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_opencode_no_longer_exposes_legacy_chatloop_preset():
|
|
73
|
+
result = CliRunner().invoke(main, ["opencode", "--help"])
|
|
74
|
+
|
|
75
|
+
assert result.exit_code == 0
|
|
76
|
+
assert "auto-loop" in result.output
|
|
77
|
+
assert "chatloop" not in result.output.lower()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_cc_connect_installs_chatarch_package(monkeypatch):
|
|
81
|
+
import chatup.setup.cc_connect as cc_connect
|
|
82
|
+
|
|
83
|
+
commands = []
|
|
84
|
+
monkeypatch.setattr(cc_connect, "ensure_nodejs_requirement", lambda **kwargs: None)
|
|
85
|
+
monkeypatch.setattr(
|
|
86
|
+
cc_connect,
|
|
87
|
+
"should_install_global_npm_package",
|
|
88
|
+
lambda package_name, display_name, **kwargs: (
|
|
89
|
+
package_name == "@chatarch/cc-connect" and display_name == "cc-connect"
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
class Result:
|
|
94
|
+
returncode = 0
|
|
95
|
+
stderr = ""
|
|
96
|
+
|
|
97
|
+
def fake_run_npm_command(args):
|
|
98
|
+
commands.append(args)
|
|
99
|
+
return Result()
|
|
100
|
+
|
|
101
|
+
monkeypatch.setattr(cc_connect, "run_npm_command", fake_run_npm_command)
|
|
102
|
+
|
|
103
|
+
result = CliRunner().invoke(main, ["cc-connect", "-I"])
|
|
104
|
+
|
|
105
|
+
assert result.exit_code == 0, result.output
|
|
106
|
+
assert commands == [["install", "-g", "@chatarch/cc-connect"]]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_uv_help_exposes_defaults():
|
|
110
|
+
result = CliRunner().invoke(main, ["uv", "--help"])
|
|
111
|
+
|
|
112
|
+
assert result.exit_code == 0
|
|
113
|
+
assert "--venv" in result.output
|
|
114
|
+
assert "--python" in result.output
|
|
115
|
+
assert "~/.chatarch/venv" in result.output or "/.chatarch/venv" in result.output
|
|
116
|
+
assert "3.12" in result.output
|
|
117
|
+
assert "--force" in result.output
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_uv_setup_creates_default_chatarch_python_env(monkeypatch, tmp_path):
|
|
121
|
+
import chatup.setup.uv as uv_setup
|
|
122
|
+
|
|
123
|
+
created = []
|
|
124
|
+
readiness = iter([False, True])
|
|
125
|
+
monkeypatch.setattr(uv_setup, "DEFAULT_VENV_PATH", tmp_path / "default-venv")
|
|
126
|
+
monkeypatch.setattr(uv_setup, "ensure_uv_installed", lambda: "/usr/local/bin/uv")
|
|
127
|
+
monkeypatch.setattr(uv_setup, "is_chatarch_python_ready", lambda path, version: next(readiness))
|
|
128
|
+
monkeypatch.setattr(
|
|
129
|
+
uv_setup,
|
|
130
|
+
"create_chatarch_python_env",
|
|
131
|
+
lambda uv_bin, path, version, *, force=False: created.append((uv_bin, path, version, force)),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
result = uv_setup.setup_uv()
|
|
135
|
+
|
|
136
|
+
assert result["status"] == "created"
|
|
137
|
+
assert result["venv"] == str(tmp_path / "default-venv")
|
|
138
|
+
assert result["python_version"] == "3.12"
|
|
139
|
+
assert created == [("/usr/local/bin/uv", tmp_path / "default-venv", "3.12", False)]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_uv_setup_accepts_custom_path_python_and_force(monkeypatch, tmp_path):
|
|
143
|
+
import chatup.setup.uv as uv_setup
|
|
144
|
+
|
|
145
|
+
target = tmp_path / "custom-venv"
|
|
146
|
+
created = []
|
|
147
|
+
readiness = iter([False, True])
|
|
148
|
+
monkeypatch.setattr(uv_setup, "ensure_uv_installed", lambda: "/opt/bin/uv")
|
|
149
|
+
monkeypatch.setattr(uv_setup, "is_chatarch_python_ready", lambda path, version: next(readiness))
|
|
150
|
+
monkeypatch.setattr(
|
|
151
|
+
uv_setup,
|
|
152
|
+
"create_chatarch_python_env",
|
|
153
|
+
lambda uv_bin, path, version, *, force=False: created.append((uv_bin, path, version, force)),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
result = CliRunner().invoke(main, ["uv", "--venv", str(target), "--python", "3.11", "--force"])
|
|
157
|
+
|
|
158
|
+
assert result.exit_code == 0, result.output
|
|
159
|
+
assert created == [("/opt/bin/uv", target, "3.11", True)]
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_ensure_uv_installed_uses_official_installer_when_missing(monkeypatch):
|
|
163
|
+
import chatup.setup.uv as uv_setup
|
|
164
|
+
|
|
165
|
+
monkeypatch.setattr(uv_setup, "find_uv", lambda: None)
|
|
166
|
+
monkeypatch.setattr(uv_setup, "install_uv_with_official_script", lambda: "/home/me/.local/bin/uv")
|
|
167
|
+
|
|
168
|
+
assert uv_setup.ensure_uv_installed() == "/home/me/.local/bin/uv"
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_create_chatarch_python_env_seeds_pip_and_force_clears(monkeypatch, tmp_path):
|
|
172
|
+
import chatup.setup.uv as uv_setup
|
|
173
|
+
|
|
174
|
+
commands = []
|
|
175
|
+
|
|
176
|
+
class Result:
|
|
177
|
+
returncode = 0
|
|
178
|
+
stdout = ""
|
|
179
|
+
stderr = ""
|
|
180
|
+
|
|
181
|
+
def fake_run_command(command, **kwargs):
|
|
182
|
+
commands.append(command)
|
|
183
|
+
return Result()
|
|
184
|
+
|
|
185
|
+
monkeypatch.setattr(uv_setup, "_run_command", fake_run_command)
|
|
186
|
+
|
|
187
|
+
uv_setup.create_chatarch_python_env("uv", tmp_path / "venv", "3.12", force=True)
|
|
188
|
+
|
|
189
|
+
assert commands == [
|
|
190
|
+
["uv", "python", "install", "3.12"],
|
|
191
|
+
["uv", "venv", "--python", "3.12", "--seed", "--clear", "--force", str(tmp_path / "venv")],
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_create_chatarch_python_env_allows_existing_same_version_venv(monkeypatch, tmp_path):
|
|
196
|
+
import chatup.setup.uv as uv_setup
|
|
197
|
+
|
|
198
|
+
target = tmp_path / "venv"
|
|
199
|
+
target.mkdir()
|
|
200
|
+
commands = []
|
|
201
|
+
|
|
202
|
+
class Result:
|
|
203
|
+
returncode = 0
|
|
204
|
+
stdout = ""
|
|
205
|
+
stderr = ""
|
|
206
|
+
|
|
207
|
+
def fake_run_command(command, **kwargs):
|
|
208
|
+
commands.append(command)
|
|
209
|
+
return Result()
|
|
210
|
+
|
|
211
|
+
monkeypatch.setattr(uv_setup, "_run_command", fake_run_command)
|
|
212
|
+
|
|
213
|
+
uv_setup.create_chatarch_python_env("uv", target, "3.12", force=False)
|
|
214
|
+
|
|
215
|
+
assert commands == [
|
|
216
|
+
["uv", "python", "install", "3.12"],
|
|
217
|
+
["uv", "venv", "--python", "3.12", "--seed", "--allow-existing", str(target)],
|
|
218
|
+
]
|
|
@@ -5,7 +5,7 @@ from chatup.cli import main
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def test_version_present():
|
|
8
|
-
assert __version__ == "0.2.
|
|
8
|
+
assert __version__ == "0.2.1"
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def test_cli_help():
|
|
@@ -20,4 +20,4 @@ def test_cli_doctor():
|
|
|
20
20
|
result = CliRunner().invoke(main, ["doctor"])
|
|
21
21
|
|
|
22
22
|
assert result.exit_code == 0
|
|
23
|
-
assert "chatup 0.2.
|
|
23
|
+
assert "chatup 0.2.1 ok" in result.output
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
from click.testing import CliRunner
|
|
2
|
-
|
|
3
|
-
from chatup.cli import main
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def test_chatup_root_help_lists_setup_commands_without_setup_group_or_alias():
|
|
7
|
-
result = CliRunner().invoke(main, ["--help"])
|
|
8
|
-
|
|
9
|
-
assert result.exit_code == 0
|
|
10
|
-
for command in [
|
|
11
|
-
"workspace",
|
|
12
|
-
"nodejs",
|
|
13
|
-
"codex",
|
|
14
|
-
"claude",
|
|
15
|
-
"opencode",
|
|
16
|
-
"hermes",
|
|
17
|
-
"lark-cli",
|
|
18
|
-
"docker",
|
|
19
|
-
"zsh",
|
|
20
|
-
]:
|
|
21
|
-
assert command in result.output
|
|
22
|
-
assert "setup" not in result.output
|
|
23
|
-
assert "\n alias " not in result.output
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def test_chatup_workspace_help_keeps_interactive_flags():
|
|
27
|
-
result = CliRunner().invoke(main, ["workspace", "--help"])
|
|
28
|
-
|
|
29
|
-
assert result.exit_code == 0
|
|
30
|
-
assert "--with-chattool" in result.output
|
|
31
|
-
assert "--with-chatblog" in result.output
|
|
32
|
-
assert "--with-memory" in result.output
|
|
33
|
-
assert "-i, --interactive" in result.output
|
|
34
|
-
assert "-I, --no-interactive" in result.output
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def test_top_level_setup_commands_expose_help():
|
|
38
|
-
commands = [
|
|
39
|
-
"cc-connect",
|
|
40
|
-
"chrome",
|
|
41
|
-
"claude",
|
|
42
|
-
"codex",
|
|
43
|
-
"docker",
|
|
44
|
-
"frp",
|
|
45
|
-
"hermes",
|
|
46
|
-
"lark-cli",
|
|
47
|
-
"nodejs",
|
|
48
|
-
"opencode",
|
|
49
|
-
"workspace",
|
|
50
|
-
"zsh",
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
for command in commands:
|
|
54
|
-
result = CliRunner().invoke(main, [command, "--help"])
|
|
55
|
-
assert result.exit_code == 0, command
|
|
56
|
-
assert "--help" in result.output
|
|
57
|
-
assert "Usage: chatup setup" not in result.output
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def test_setup_group_and_alias_command_are_not_registered():
|
|
61
|
-
setup_result = CliRunner().invoke(main, ["setup", "--help"])
|
|
62
|
-
alias_result = CliRunner().invoke(main, ["alias", "--help"])
|
|
63
|
-
|
|
64
|
-
assert setup_result.exit_code != 0
|
|
65
|
-
assert "No such command" in setup_result.output
|
|
66
|
-
assert alias_result.exit_code != 0
|
|
67
|
-
assert "No such command" in alias_result.output
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def test_opencode_no_longer_exposes_legacy_chatloop_preset():
|
|
71
|
-
result = CliRunner().invoke(main, ["opencode", "--help"])
|
|
72
|
-
|
|
73
|
-
assert result.exit_code == 0
|
|
74
|
-
assert "auto-loop" in result.output
|
|
75
|
-
assert "chatloop" not in result.output.lower()
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def test_cc_connect_installs_chatarch_package(monkeypatch):
|
|
79
|
-
import chatup.setup.cc_connect as cc_connect
|
|
80
|
-
|
|
81
|
-
commands = []
|
|
82
|
-
monkeypatch.setattr(cc_connect, "ensure_nodejs_requirement", lambda **kwargs: None)
|
|
83
|
-
monkeypatch.setattr(
|
|
84
|
-
cc_connect,
|
|
85
|
-
"should_install_global_npm_package",
|
|
86
|
-
lambda package_name, display_name, **kwargs: (
|
|
87
|
-
package_name == "@chatarch/cc-connect" and display_name == "cc-connect"
|
|
88
|
-
),
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
class Result:
|
|
92
|
-
returncode = 0
|
|
93
|
-
stderr = ""
|
|
94
|
-
|
|
95
|
-
def fake_run_npm_command(args):
|
|
96
|
-
commands.append(args)
|
|
97
|
-
return Result()
|
|
98
|
-
|
|
99
|
-
monkeypatch.setattr(cc_connect, "run_npm_command", fake_run_npm_command)
|
|
100
|
-
|
|
101
|
-
result = CliRunner().invoke(main, ["cc-connect", "-I"])
|
|
102
|
-
|
|
103
|
-
assert result.exit_code == 0, result.output
|
|
104
|
-
assert commands == [["install", "-g", "@chatarch/cc-connect"]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/templates/default/en/projects/README.md
RENAMED
|
File without changes
|
|
File without changes
|
{chatup-0.2.0 → chatup-0.2.1}/src/chatup/setup/workspace/templates/default/zh/projects/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|