chatup 0.2.11__tar.gz → 0.2.12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. {chatup-0.2.11/src/chatup.egg-info → chatup-0.2.12}/PKG-INFO +18 -8
  2. {chatup-0.2.11 → chatup-0.2.12}/README.md +7 -1
  3. {chatup-0.2.11 → chatup-0.2.12}/pyproject.toml +11 -6
  4. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/__init__.py +1 -1
  5. chatup-0.2.12/src/chatup/cli.py +38 -0
  6. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/service_credentials.py +10 -6
  7. {chatup-0.2.11 → chatup-0.2.12/src/chatup.egg-info}/PKG-INFO +18 -8
  8. chatup-0.2.12/src/chatup.egg-info/requires.txt +15 -0
  9. {chatup-0.2.11 → chatup-0.2.12}/tests/test_cli_tree_docs.py +2 -0
  10. {chatup-0.2.11 → chatup-0.2.12}/tests/test_publish_workflow.py +3 -0
  11. {chatup-0.2.11 → chatup-0.2.12}/tests/test_pyproject_metadata.py +5 -3
  12. {chatup-0.2.11 → chatup-0.2.12}/tests/test_service_installers.py +40 -0
  13. chatup-0.2.12/tests/test_version.py +64 -0
  14. chatup-0.2.11/src/chatup/cli.py +0 -111
  15. chatup-0.2.11/src/chatup.egg-info/requires.txt +0 -10
  16. chatup-0.2.11/tests/test_version.py +0 -45
  17. {chatup-0.2.11 → chatup-0.2.12}/LICENSE +0 -0
  18. {chatup-0.2.11 → chatup-0.2.12}/setup.cfg +0 -0
  19. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/chrome_for_testing.py +0 -0
  20. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/chromedriver.py +0 -0
  21. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/commands/__init__.py +0 -0
  22. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/commands/chrome_for_testing.py +0 -0
  23. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/commands/chromedriver.py +0 -0
  24. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/commands/playwright.py +0 -0
  25. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/config.py +0 -0
  26. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/const.py +0 -0
  27. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/interaction/__init__.py +0 -0
  28. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/interaction/command_schema.py +0 -0
  29. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/interaction/policy.py +0 -0
  30. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/interaction/warnings.py +0 -0
  31. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/playwright.py +0 -0
  32. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/runtime/__init__.py +0 -0
  33. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/runtime/_managed_artifact.py +0 -0
  34. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/runtime/chrome_for_testing.py +0 -0
  35. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/runtime/chromedriver.py +0 -0
  36. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/runtime/playwright.py +0 -0
  37. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/__init__.py +0 -0
  38. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/assets/hermes/install.sh +0 -0
  39. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/assets/nvm.sh +0 -0
  40. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/cc_connect.py +0 -0
  41. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/claude.py +0 -0
  42. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/cli.py +0 -0
  43. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/codex.py +0 -0
  44. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/crs.py +0 -0
  45. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/cursor_agent.py +0 -0
  46. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/discourse.py +0 -0
  47. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/docker.py +0 -0
  48. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/elements.py +0 -0
  49. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/frp.py +0 -0
  50. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/gitea.py +0 -0
  51. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/hermes.py +0 -0
  52. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/lark_cli.py +0 -0
  53. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/mode_prompt.py +0 -0
  54. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/mysql.py +0 -0
  55. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/nginx.py +0 -0
  56. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/nodejs.py +0 -0
  57. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/opencode.py +0 -0
  58. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/shell_rc.py +0 -0
  59. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/twikoo.py +0 -0
  60. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/uv.py +0 -0
  61. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/__init__.py +0 -0
  62. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/cli.py +0 -0
  63. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/core.py +0 -0
  64. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/options.py +0 -0
  65. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/render.py +0 -0
  66. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/templates/default/en/AGENTS.md +0 -0
  67. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/templates/default/en/discussion/README.md +0 -0
  68. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/templates/default/en/projects/README.md +0 -0
  69. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/templates/default/zh/AGENTS.md +0 -0
  70. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/templates/default/zh/discussion/README.md +0 -0
  71. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace/templates/default/zh/projects/README.md +0 -0
  72. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/workspace.py +0 -0
  73. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/zsh.py +0 -0
  74. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/setup/zulip.py +0 -0
  75. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/utils/__init__.py +0 -0
  76. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/utils/custom_logger.py +0 -0
  77. {chatup-0.2.11 → chatup-0.2.12}/src/chatup/utils/pathing.py +0 -0
  78. {chatup-0.2.11 → chatup-0.2.12}/src/chatup.egg-info/SOURCES.txt +0 -0
  79. {chatup-0.2.11 → chatup-0.2.12}/src/chatup.egg-info/dependency_links.txt +0 -0
  80. {chatup-0.2.11 → chatup-0.2.12}/src/chatup.egg-info/entry_points.txt +0 -0
  81. {chatup-0.2.11 → chatup-0.2.12}/src/chatup.egg-info/top_level.txt +0 -0
  82. {chatup-0.2.11 → chatup-0.2.12}/tests/test_browser_backend_cli.py +0 -0
  83. {chatup-0.2.11 → chatup-0.2.12}/tests/test_chrome_for_testing.py +0 -0
  84. {chatup-0.2.11 → chatup-0.2.12}/tests/test_chromedriver.py +0 -0
  85. {chatup-0.2.11 → chatup-0.2.12}/tests/test_crs_setup.py +0 -0
  86. {chatup-0.2.11 → chatup-0.2.12}/tests/test_cursor_agent_setup.py +0 -0
  87. {chatup-0.2.11 → chatup-0.2.12}/tests/test_playwright.py +0 -0
  88. {chatup-0.2.11 → chatup-0.2.12}/tests/test_playwright_cli.py +0 -0
  89. {chatup-0.2.11 → chatup-0.2.12}/tests/test_setup_cli.py +0 -0
  90. {chatup-0.2.11 → chatup-0.2.12}/tests/test_twikoo_setup.py +0 -0
  91. {chatup-0.2.11 → chatup-0.2.12}/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.11
3
+ Version: 0.2.12
4
4
  Summary: ChatArch setup CLI extracted from ChatTool
5
5
  Author-email: rexwzh <1073853456@qq.com>
6
6
  License-Expression: MIT
@@ -13,15 +13,19 @@ Classifier: Operating System :: OS Independent
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: click>=8.0
17
- Requires-Dist: chatstyle<0.2.0,>=0.1.1
18
- Requires-Dist: chatenv<0.3.0,>=0.2.0
16
+ Requires-Dist: click<9.0,>=8.0
17
+ Requires-Dist: chatstyle<0.3.0,>=0.2.0
18
+ Requires-Dist: chatenv<0.3.0,>=0.2.10
19
19
  Requires-Dist: colorama
20
+ Provides-Extra: dev
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: pytest; extra == "dev"
23
+ Requires-Dist: twine; extra == "dev"
20
24
  Provides-Extra: docs
21
25
  Requires-Dist: mkdocs<2.0,>=1.6; extra == "docs"
22
- Requires-Dist: mkdocs-material<10.0,>=9.5; extra == "docs"
23
- Requires-Dist: mkdocs-static-i18n<2.0,>=1.3; extra == "docs"
24
- Requires-Dist: mike<3.0,>=2.1; extra == "docs"
26
+ Requires-Dist: mkdocs-material<9.7,>=9.5; extra == "docs"
27
+ Requires-Dist: mkdocs-static-i18n<2.0,>=1.2; extra == "docs"
28
+ Requires-Dist: mike<3.0,>=2.0; extra == "docs"
25
29
  Dynamic: license-file
26
30
 
27
31
  # ChatUp
@@ -47,6 +51,9 @@ ChatUp 是 ChatArch 的独立环境与工具安装 CLI。它承接原来 `chatto
47
51
 
48
52
  ```bash
49
53
  chatup --help
54
+ chatup --version
55
+ chatup --tree
56
+ chatup --tree-brief
50
57
  chatup doctor
51
58
  chatup uv
52
59
  chatup chrome-for-testing install --channel stable -I
@@ -75,7 +82,7 @@ chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
75
82
  | 本地服务安装 | `gitea`、`discourse`、`zulip`、`mysql`、`nginx`、`crs` |
76
83
  | Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
77
84
 
78
- 所有新增安装项默认目录都收敛到 `~/.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 快速配置。更完整的能力边界见 `docs/capability-map.md`。
85
+ 所有新增安装项默认目录都收敛到 `~/.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`。
79
86
 
80
87
  ## 开发
81
88
 
@@ -84,6 +91,9 @@ python -m pytest -q
84
91
  python -m build
85
92
  python -m twine check dist/*
86
93
  mkdocs build --strict
94
+ chatup --version
95
+ chatup --tree
96
+ chatup --tree-brief
87
97
  ```
88
98
 
89
99
  更多使用说明见文档站的 [快速开始](https://arch.gh.wzhecnu.cn/ChatUp/quickstart/)、[命令参考](https://arch.gh.wzhecnu.cn/ChatUp/commands/) 和 [CLI 能力地图](https://arch.gh.wzhecnu.cn/ChatUp/capability-map/)。
@@ -21,6 +21,9 @@ ChatUp 是 ChatArch 的独立环境与工具安装 CLI。它承接原来 `chatto
21
21
 
22
22
  ```bash
23
23
  chatup --help
24
+ chatup --version
25
+ chatup --tree
26
+ chatup --tree-brief
24
27
  chatup doctor
25
28
  chatup uv
26
29
  chatup chrome-for-testing install --channel stable -I
@@ -49,7 +52,7 @@ chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
49
52
  | 本地服务安装 | `gitea`、`discourse`、`zulip`、`mysql`、`nginx`、`crs` |
50
53
  | Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
51
54
 
52
- 所有新增安装项默认目录都收敛到 `~/.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 快速配置。更完整的能力边界见 `docs/capability-map.md`。
55
+ 所有新增安装项默认目录都收敛到 `~/.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`。
53
56
 
54
57
  ## 开发
55
58
 
@@ -58,6 +61,9 @@ python -m pytest -q
58
61
  python -m build
59
62
  python -m twine check dist/*
60
63
  mkdocs build --strict
64
+ chatup --version
65
+ chatup --tree
66
+ chatup --tree-brief
61
67
  ```
62
68
 
63
69
  更多使用说明见文档站的 [快速开始](https://arch.gh.wzhecnu.cn/ChatUp/quickstart/)、[命令参考](https://arch.gh.wzhecnu.cn/ChatUp/commands/) 和 [CLI 能力地图](https://arch.gh.wzhecnu.cn/ChatUp/capability-map/)。
@@ -10,9 +10,9 @@ readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = "MIT"
12
12
  dependencies = [
13
- "click>=8.0",
14
- "chatstyle>=0.1.1,<0.2.0",
15
- "chatenv>=0.2.0,<0.3.0",
13
+ "click>=8.0,<9.0",
14
+ "chatstyle>=0.2.0,<0.3.0",
15
+ "chatenv>=0.2.10,<0.3.0",
16
16
  "colorama",
17
17
  ]
18
18
  authors = [{name = "rexwzh", email = "1073853456@qq.com"}]
@@ -28,11 +28,16 @@ Source = "https://github.com/ChatArch/ChatUp"
28
28
  Issues = "https://github.com/ChatArch/ChatUp/issues"
29
29
 
30
30
  [project.optional-dependencies]
31
+ dev = [
32
+ "build",
33
+ "pytest",
34
+ "twine",
35
+ ]
31
36
  docs = [
32
37
  "mkdocs>=1.6,<2.0",
33
- "mkdocs-material>=9.5,<10.0",
34
- "mkdocs-static-i18n>=1.3,<2.0",
35
- "mike>=2.1,<3.0",
38
+ "mkdocs-material>=9.5,<9.7",
39
+ "mkdocs-static-i18n>=1.2,<2.0",
40
+ "mike>=2.0,<3.0",
36
41
  ]
37
42
 
38
43
  [project.scripts]
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.2.11"
5
+ __version__ = "0.2.12"
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ import click
4
+ from chatstyle import add_tree_option
5
+
6
+ from chatup import __version__
7
+ from chatup.commands.chrome_for_testing import cli as chrome_for_testing_cli
8
+ from chatup.commands.chromedriver import cli as chromedriver_cli
9
+ from chatup.commands.playwright import cli as playwright_cli
10
+ from chatup.setup.cli import register_setup_commands
11
+
12
+
13
+ @click.group(
14
+ name="chatup",
15
+ context_settings={"help_option_names": ["-h", "--help"]},
16
+ invoke_without_command=True,
17
+ no_args_is_help=True,
18
+ )
19
+ @click.version_option(__version__, prog_name="chatup")
20
+ @add_tree_option(renderer_options={"root_name": "chatup"})
21
+ def main() -> None:
22
+ """ChatUp CLI for ChatArch bootstrap workflows."""
23
+
24
+
25
+ @main.command(name="doctor")
26
+ def doctor() -> None:
27
+ """Check that ChatUp is installed and callable."""
28
+ click.echo(f"chatup {__version__} ok")
29
+
30
+
31
+ register_setup_commands(main)
32
+ main.add_command(chrome_for_testing_cli)
33
+ main.add_command(chromedriver_cli)
34
+ main.add_command(playwright_cli)
35
+
36
+
37
+ if __name__ == "__main__":
38
+ main()
@@ -29,16 +29,19 @@ def load_chatenv_values(
29
29
  ) -> tuple[dict[str, str], str]:
30
30
  """Load service setup values without printing secrets.
31
31
 
32
- Precedence is current environment > explicit env file/profile values.
33
32
  The env_ref option mirrors Cursor Agent's `-e/--env`: an existing path is
34
33
  parsed as a dotenv-style file; otherwise it is treated as a ChatEnv profile.
34
+ Explicit files/profiles are isolated from process-environment credentials;
35
+ the process environment is used only when no explicit source is selected.
35
36
  """
36
37
 
37
38
  values: dict[str, str] = {}
38
39
  source = "environment"
39
40
  store = EnvStore(get_paths().envs_dir)
41
+ explicit_source = False
40
42
 
41
43
  if env_ref:
44
+ explicit_source = True
42
45
  candidate = Path(env_ref).expanduser()
43
46
  if candidate.exists():
44
47
  values.update(parse_env_file(candidate))
@@ -48,14 +51,15 @@ def load_chatenv_values(
48
51
  source = f"ChatEnv profile {env_ref}"
49
52
 
50
53
  if env_profile:
54
+ explicit_source = True
51
55
  values.update(store.load_profile(config_cls, env_profile))
52
56
  source = f"ChatEnv profile {env_profile}"
53
57
 
54
- for key in config_cls.get_fields():
55
- env_value = os.getenv(key)
56
- if env_value:
57
- values[key] = env_value
58
- source = "environment"
58
+ if not explicit_source:
59
+ for key in config_cls.get_fields():
60
+ env_value = os.getenv(key)
61
+ if env_value:
62
+ values[key] = env_value
59
63
  return values, source
60
64
 
61
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chatup
3
- Version: 0.2.11
3
+ Version: 0.2.12
4
4
  Summary: ChatArch setup CLI extracted from ChatTool
5
5
  Author-email: rexwzh <1073853456@qq.com>
6
6
  License-Expression: MIT
@@ -13,15 +13,19 @@ Classifier: Operating System :: OS Independent
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: click>=8.0
17
- Requires-Dist: chatstyle<0.2.0,>=0.1.1
18
- Requires-Dist: chatenv<0.3.0,>=0.2.0
16
+ Requires-Dist: click<9.0,>=8.0
17
+ Requires-Dist: chatstyle<0.3.0,>=0.2.0
18
+ Requires-Dist: chatenv<0.3.0,>=0.2.10
19
19
  Requires-Dist: colorama
20
+ Provides-Extra: dev
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: pytest; extra == "dev"
23
+ Requires-Dist: twine; extra == "dev"
20
24
  Provides-Extra: docs
21
25
  Requires-Dist: mkdocs<2.0,>=1.6; extra == "docs"
22
- Requires-Dist: mkdocs-material<10.0,>=9.5; extra == "docs"
23
- Requires-Dist: mkdocs-static-i18n<2.0,>=1.3; extra == "docs"
24
- Requires-Dist: mike<3.0,>=2.1; extra == "docs"
26
+ Requires-Dist: mkdocs-material<9.7,>=9.5; extra == "docs"
27
+ Requires-Dist: mkdocs-static-i18n<2.0,>=1.2; extra == "docs"
28
+ Requires-Dist: mike<3.0,>=2.0; extra == "docs"
25
29
  Dynamic: license-file
26
30
 
27
31
  # ChatUp
@@ -47,6 +51,9 @@ ChatUp 是 ChatArch 的独立环境与工具安装 CLI。它承接原来 `chatto
47
51
 
48
52
  ```bash
49
53
  chatup --help
54
+ chatup --version
55
+ chatup --tree
56
+ chatup --tree-brief
50
57
  chatup doctor
51
58
  chatup uv
52
59
  chatup chrome-for-testing install --channel stable -I
@@ -75,7 +82,7 @@ chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
75
82
  | 本地服务安装 | `gitea`、`discourse`、`zulip`、`mysql`、`nginx`、`crs` |
76
83
  | Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
77
84
 
78
- 所有新增安装项默认目录都收敛到 `~/.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 快速配置。更完整的能力边界见 `docs/capability-map.md`。
85
+ 所有新增安装项默认目录都收敛到 `~/.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`。
79
86
 
80
87
  ## 开发
81
88
 
@@ -84,6 +91,9 @@ python -m pytest -q
84
91
  python -m build
85
92
  python -m twine check dist/*
86
93
  mkdocs build --strict
94
+ chatup --version
95
+ chatup --tree
96
+ chatup --tree-brief
87
97
  ```
88
98
 
89
99
  更多使用说明见文档站的 [快速开始](https://arch.gh.wzhecnu.cn/ChatUp/quickstart/)、[命令参考](https://arch.gh.wzhecnu.cn/ChatUp/commands/) 和 [CLI 能力地图](https://arch.gh.wzhecnu.cn/ChatUp/capability-map/)。
@@ -0,0 +1,15 @@
1
+ click<9.0,>=8.0
2
+ chatstyle<0.3.0,>=0.2.0
3
+ chatenv<0.3.0,>=0.2.10
4
+ colorama
5
+
6
+ [dev]
7
+ build
8
+ pytest
9
+ twine
10
+
11
+ [docs]
12
+ mkdocs<2.0,>=1.6
13
+ mkdocs-material<9.7,>=9.5
14
+ mkdocs-static-i18n<2.0,>=1.2
15
+ mike<3.0,>=2.0
@@ -58,6 +58,8 @@ def test_cli_tree_is_in_mkdocs_nav_and_backend_contracts_are_complete():
58
58
  "remove",
59
59
  "gc",
60
60
  "--version",
61
+ "--tree",
62
+ "--tree-brief",
61
63
  "--channel",
62
64
  "--home",
63
65
  "--platform",
@@ -11,6 +11,9 @@ def test_publish_workflow_matches_active_any_environment_publisher():
11
11
  assert "id-token: write" in workflow
12
12
  assert "pypa/gh-action-pypi-publish@release/v1" in workflow
13
13
  assert "environment: pypi" not in workflow
14
+ assert "git merge-base --is-ancestor" in workflow
15
+ assert "refs/remotes/origin/main" in workflow
16
+ assert "workflow_dispatch" not in workflow
14
17
  assert "Release workflow must run from a tag ref" in workflow
15
18
  assert "GITHUB_REF_TYPE" in workflow
16
19
  assert "GITHUB_REF_NAME" in workflow
@@ -21,8 +21,9 @@ def test_chatup_depends_on_chatenv_and_registers_cursor_agent_config_provider():
21
21
  data = _pyproject()
22
22
 
23
23
  assert data["project"]["requires-python"] == ">=3.10"
24
- assert "chatstyle>=0.1.1,<0.2.0" in data["project"]["dependencies"]
25
- assert "chatenv>=0.2.0,<0.3.0" in data["project"]["dependencies"]
24
+ assert "click>=8.0,<9.0" in data["project"]["dependencies"]
25
+ assert "chatstyle>=0.2.0,<0.3.0" in data["project"]["dependencies"]
26
+ assert "chatenv>=0.2.10,<0.3.0" in data["project"]["dependencies"]
26
27
  entry_points = data["project"]["entry-points"]["chatenv.configs"]
27
28
  assert entry_points["cursor-agent"] == "chatup.config:CursorAgentConfig"
28
29
  assert entry_points["discourse"] == "chatup.config:DiscourseAdminConfig"
@@ -82,4 +83,5 @@ def test_project_metadata_points_to_chatup_docs_site():
82
83
 
83
84
  assert data["project"]["urls"]["Documentation"] == "https://arch.gh.wzhecnu.cn/ChatUp/"
84
85
  assert data["project"]["urls"]["Source"] == "https://github.com/ChatArch/ChatUp"
85
- assert "mkdocs-static-i18n>=1.3,<2.0" in data["project"]["optional-dependencies"]["docs"]
86
+ assert "mkdocs-material>=9.5,<9.7" in data["project"]["optional-dependencies"]["docs"]
87
+ assert "mkdocs-static-i18n>=1.2,<2.0" in data["project"]["optional-dependencies"]["docs"]
@@ -1,10 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from click.testing import CliRunner
4
+ from chatenv.paths import get_paths
5
+ from chatenv.store import EnvStore
4
6
 
5
7
  from chatup.cli import main
6
8
  from chatup.config import DiscourseAdminConfig, ZulipAdminConfig
7
9
  from chatup.setup.discourse import setup_discourse
10
+ from chatup.setup.service_credentials import load_chatenv_values
8
11
  from chatup.setup.zulip import setup_zulip
9
12
 
10
13
 
@@ -36,6 +39,43 @@ def test_zulip_admin_config_schema_supports_email_and_mail_alias():
36
39
  ZulipAdminConfig.test()
37
40
 
38
41
 
42
+ def test_explicit_chatenv_profile_isolated_from_process_credentials(tmp_path, monkeypatch):
43
+ monkeypatch.setenv("CHATARCH_HOME", str(tmp_path / "chatarch"))
44
+ monkeypatch.setenv("DISCOURSE_ADMIN_USERNAME", "process-admin")
45
+ monkeypatch.setenv("DISCOURSE_ADMIN_EMAIL", "process@example.com")
46
+ monkeypatch.setenv("DISCOURSE_ADMIN_PASSWORD", "process-password")
47
+ EnvStore(get_paths().envs_dir).save_profile(
48
+ DiscourseAdminConfig,
49
+ "selected",
50
+ {
51
+ "DISCOURSE_ADMIN_USERNAME": "profile-admin",
52
+ "DISCOURSE_ADMIN_PASSWORD": "profile-password",
53
+ },
54
+ )
55
+
56
+ values, source = load_chatenv_values(DiscourseAdminConfig, env_profile="selected")
57
+
58
+ assert source == "ChatEnv profile selected"
59
+ assert values["DISCOURSE_ADMIN_USERNAME"] == "profile-admin"
60
+ assert values["DISCOURSE_ADMIN_PASSWORD"] == "profile-password"
61
+ assert "DISCOURSE_ADMIN_EMAIL" not in values
62
+
63
+
64
+ def test_process_credentials_are_used_without_explicit_source(monkeypatch):
65
+ monkeypatch.setenv("DISCOURSE_ADMIN_USERNAME", "process-admin")
66
+ monkeypatch.setenv("DISCOURSE_ADMIN_EMAIL", "process@example.com")
67
+ monkeypatch.setenv("DISCOURSE_ADMIN_PASSWORD", "process-password")
68
+
69
+ values, source = load_chatenv_values(DiscourseAdminConfig)
70
+
71
+ assert source == "environment"
72
+ assert values == {
73
+ "DISCOURSE_ADMIN_USERNAME": "process-admin",
74
+ "DISCOURSE_ADMIN_EMAIL": "process@example.com",
75
+ "DISCOURSE_ADMIN_PASSWORD": "process-password",
76
+ }
77
+
78
+
39
79
  def test_discourse_setup_writes_admin_env_and_chatarc_internal_app_yml(tmp_path):
40
80
  env = tmp_path / "discourse.env"
41
81
  env.write_text(
@@ -0,0 +1,64 @@
1
+ from click.testing import CliRunner
2
+
3
+ from chatup import __version__
4
+ from chatup.cli import main
5
+
6
+
7
+ def test_version_present():
8
+ assert __version__ == "0.2.12"
9
+
10
+
11
+ def test_cli_help():
12
+ result = CliRunner().invoke(main, ["--help"])
13
+
14
+ assert result.exit_code == 0
15
+ assert main.name == "chatup"
16
+ assert "ChatUp CLI" in result.output
17
+ assert "doctor" in result.output
18
+ assert "--tree" in result.output
19
+ assert "--tree-brief" in result.output
20
+
21
+
22
+ def test_cli_tree_lists_registered_command_surface_with_signatures():
23
+ result = CliRunner().invoke(main, ["--tree"])
24
+
25
+ assert result.exit_code == 0, result.output
26
+ lines = result.output.splitlines()
27
+ assert lines[0] == "chatup"
28
+ assert lines.count("chatup") == 1
29
+ assert all(" # " in line for line in lines[1:])
30
+ assert "--version" in result.output
31
+ assert "--tree" in result.output
32
+ assert "--tree-brief" in result.output
33
+ for command in main.commands:
34
+ assert command in result.output
35
+ for leaf in ("install", "list", "show", "path", "doctor", "remove", "gc"):
36
+ assert leaf in result.output
37
+ assert "[--match-browser MATCH-BROWSER]" in result.output
38
+ assert "[--minimum-age-hours MINIMUM-AGE-HOURS]" in result.output
39
+ assert "Remove one exact managed installation." in result.output
40
+ assert "Install/configure Cursor Agent CLI auth and config files." in result.output
41
+
42
+
43
+ def test_cli_tree_brief_keeps_registered_nodes_and_omits_signatures():
44
+ result = CliRunner().invoke(main, ["--tree-brief"])
45
+
46
+ assert result.exit_code == 0, result.output
47
+ lines = result.output.splitlines()
48
+ assert lines[0] == "chatup"
49
+ assert lines.count("chatup") == 1
50
+ assert all(" # " in line for line in lines[1:])
51
+ for command in main.commands:
52
+ assert command in result.output
53
+ for expected in ("--version", "--tree", "--tree-brief", "install", "remove", "gc"):
54
+ assert expected in result.output
55
+ assert "[--match-browser MATCH-BROWSER]" not in result.output
56
+ assert "[--minimum-age-hours MINIMUM-AGE-HOURS]" not in result.output
57
+ assert "[VERSION]" not in result.output
58
+
59
+
60
+ def test_cli_doctor():
61
+ result = CliRunner().invoke(main, ["doctor"])
62
+
63
+ assert result.exit_code == 0
64
+ assert "chatup 0.2.12 ok" in result.output
@@ -1,111 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import inspect
4
-
5
- import click
6
-
7
- from chatup import __version__
8
- from chatup.commands.chrome_for_testing import cli as chrome_for_testing_cli
9
- from chatup.commands.chromedriver import cli as chromedriver_cli
10
- from chatup.commands.playwright import cli as playwright_cli
11
- from chatup.setup.cli import register_setup_commands
12
-
13
-
14
- def _purpose(command: click.Command) -> str:
15
- text = command.short_help or inspect.getdoc(command.callback) or ""
16
- return " ".join(text.strip().split()).rstrip(".")
17
-
18
-
19
- def _parameter_piece(parameter: click.Parameter) -> str | None:
20
- if getattr(parameter, "hidden", False) or parameter.name == "help":
21
- return None
22
- if isinstance(parameter, click.Argument):
23
- piece = parameter.name.upper().replace("_", "-")
24
- if not parameter.required:
25
- piece = f"[{piece}]"
26
- if parameter.nargs == -1:
27
- piece = f"{piece}..."
28
- return piece
29
- if not isinstance(parameter, click.Option):
30
- return None
31
- option_names = [name for name in (*parameter.opts, *parameter.secondary_opts) if name.startswith("--")]
32
- if not option_names:
33
- option_names = [name for name in (*parameter.opts, *parameter.secondary_opts) if name.startswith("-")]
34
- if not option_names:
35
- return None
36
- if parameter.is_flag or parameter.flag_value is not None:
37
- piece = "/".join(option_names)
38
- else:
39
- metavar = parameter.metavar or parameter.name.upper().replace("_", "-")
40
- piece = f"{'/'.join(option_names)} {metavar}"
41
- if not parameter.required:
42
- piece = f"[{piece}]"
43
- return piece
44
-
45
-
46
- def _command_signature(name: str, command: click.Command) -> str:
47
- pieces = [piece for piece in (_parameter_piece(parameter) for parameter in command.params) if piece]
48
- return " ".join([name, *pieces])
49
-
50
-
51
- def _render_command_tree(command: click.Command, name: str, prefix: str, is_last: bool, lines: list[str]) -> None:
52
- connector = "└── " if is_last else "├── "
53
- line = f"{prefix}{connector}{_command_signature(name, command)}"
54
- purpose = _purpose(command)
55
- if purpose:
56
- line = f"{line} # {purpose}"
57
- lines.append(line)
58
- if not isinstance(command, click.Group):
59
- return
60
- children = [(child_name, child) for child_name, child in command.commands.items() if not child.hidden]
61
- child_prefix = prefix + (" " if is_last else "│ ")
62
- for index, (child_name, child) in enumerate(children):
63
- _render_command_tree(child, child_name, child_prefix, index == len(children) - 1, lines)
64
-
65
-
66
- def _render_cli_tree(root: click.Group) -> str:
67
- children = [(name, command) for name, command in root.commands.items() if not command.hidden]
68
- lines = [f"chatup # {_purpose(root)}"]
69
- root_options = [
70
- ("--help", "Show help for the current command."),
71
- ("--version", "Show package version."),
72
- ("--tree", "Print the registered CLI tree."),
73
- ]
74
- for index, (option, purpose) in enumerate(root_options):
75
- is_last = not children and index == len(root_options) - 1
76
- lines.append(f"{'└──' if is_last else '├──'} {option} # {purpose}")
77
- for index, (child_name, child) in enumerate(children):
78
- _render_command_tree(child, child_name, "", index == len(children) - 1, lines)
79
- return "\n".join(lines)
80
-
81
-
82
- @click.group(
83
- context_settings={"help_option_names": ["-h", "--help"]},
84
- invoke_without_command=True,
85
- no_args_is_help=True,
86
- )
87
- @click.version_option(__version__, prog_name="chatup")
88
- @click.option("--tree", "show_tree", is_flag=True, is_eager=True, help="Print the registered CLI tree.")
89
- @click.pass_context
90
- def main(ctx: click.Context, show_tree: bool) -> None:
91
- """ChatUp CLI for ChatArch bootstrap workflows."""
92
-
93
- if show_tree:
94
- click.echo(_render_cli_tree(ctx.command))
95
- ctx.exit()
96
-
97
-
98
- @main.command(name="doctor")
99
- def doctor() -> None:
100
- """Check that ChatUp is installed and callable."""
101
- click.echo(f"chatup {__version__} ok")
102
-
103
-
104
- register_setup_commands(main)
105
- main.add_command(chrome_for_testing_cli)
106
- main.add_command(chromedriver_cli)
107
- main.add_command(playwright_cli)
108
-
109
-
110
- if __name__ == "__main__":
111
- main()
@@ -1,10 +0,0 @@
1
- click>=8.0
2
- chatstyle<0.2.0,>=0.1.1
3
- chatenv<0.3.0,>=0.2.0
4
- colorama
5
-
6
- [docs]
7
- mkdocs<2.0,>=1.6
8
- mkdocs-material<10.0,>=9.5
9
- mkdocs-static-i18n<2.0,>=1.3
10
- mike<3.0,>=2.1
@@ -1,45 +0,0 @@
1
- from click.testing import CliRunner
2
-
3
- from chatup import __version__
4
- from chatup.cli import main
5
-
6
-
7
- def test_version_present():
8
- assert __version__ == "0.2.11"
9
-
10
-
11
- def test_cli_help():
12
- result = CliRunner().invoke(main, ["--help"])
13
-
14
- assert result.exit_code == 0
15
- assert "ChatUp CLI" in result.output
16
- assert "doctor" in result.output
17
- assert "--tree" in result.output
18
-
19
-
20
- def test_cli_tree_lists_registered_command_surface():
21
- result = CliRunner().invoke(main, ["--tree"])
22
-
23
- assert result.exit_code == 0, result.output
24
- assert "chatup # ChatUp CLI for ChatArch bootstrap workflows" in result.output
25
- assert "├── --help # Show help for the current command." in result.output
26
- assert "├── --version # Show package version." in result.output
27
- assert "├── --tree # Print the registered CLI tree." in result.output
28
- for command in [
29
- "doctor",
30
- "workspace",
31
- "chrome-for-testing",
32
- "chromedriver",
33
- "playwright",
34
- ]:
35
- assert command in result.output
36
- assert "chrome-for-testing" in result.output
37
- assert "│ ├── install" in result.output
38
- assert "│ └── gc" in result.output
39
-
40
-
41
- def test_cli_doctor():
42
- result = CliRunner().invoke(main, ["doctor"])
43
-
44
- assert result.exit_code == 0
45
- assert "chatup 0.2.11 ok" in result.output
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